commit 28afa0b69e88eb2fb9971338896d0a78e88e3977
parent 873935c041099850da2ae29fc1109ed329ce71a4
Author: Olav Sørensen <olav.sorensen@live.no>
Date: Sun, 3 Nov 2024 19:28:06 +0100
Some scope changes
Diffstat:
4 files changed, 323 insertions(+), 212 deletions(-)
diff --git a/src/scopes/ft2_scope_macros.h b/src/scopes/ft2_scope_macros.h
@@ -1,6 +1,8 @@
#pragma once
#include <stdint.h>
+#include "../ft2_header.h"
+#include "../mixer/ft2_windowed_sinc.h"
#include "ft2_scopes.h"
/* ----------------------------------------------------------------------- */
@@ -10,113 +12,72 @@
#define SCOPE_REGS_NO_LOOP \
const int32_t volume = s->volume; \
const int32_t sampleEnd = s->sampleEnd; \
- const uint32_t delta = s->drawDelta; \
+ const uint64_t delta = s->drawDelta; \
const uint32_t color = video.palette[PAL_PATTEXT]; \
- const uint32_t width = x + w; \
+ uint32_t width = x + w; \
int32_t sample; \
int32_t position = s->position; \
- uint32_t positionFrac = 0;
+ uint64_t positionFrac = 0;
#define SCOPE_REGS_LOOP \
const int32_t volume = s->volume; \
const int32_t sampleEnd = s->sampleEnd; \
const int32_t loopStart = s->loopStart; \
const int32_t loopLength = s->loopLength; \
- const uint32_t delta = s->drawDelta; \
+ const uint64_t delta = s->drawDelta; \
const uint32_t color = video.palette[PAL_PATTEXT]; \
- const uint32_t width = x + w; \
+ uint32_t width = x + w; \
int32_t sample; \
int32_t position = s->position; \
- uint32_t positionFrac = 0;
+ uint64_t positionFrac = 0;
-#define SCOPE_REGS_PINGPONG \
+#define SCOPE_REGS_BIDI \
const int32_t volume = s->volume; \
const int32_t sampleEnd = s->sampleEnd; \
const int32_t loopStart = s->loopStart; \
const int32_t loopLength = s->loopLength; \
- const uint32_t delta = s->drawDelta; \
+ const uint64_t delta = s->drawDelta; \
const uint32_t color = video.palette[PAL_PATTEXT]; \
- const uint32_t width = x + w; \
+ uint32_t width = x + w; \
int32_t sample; \
- int32_t position = s->position; \
- uint32_t positionFrac = 0; \
- int32_t direction = s->direction;
+ int32_t actualPos, position = s->position; \
+ uint64_t positionFrac = 0; \
+ bool samplingBackwards = s->samplingBackwards;
#define LINED_SCOPE_REGS_NO_LOOP \
- const int32_t volume = s->volume; \
- const int32_t sampleEnd = s->sampleEnd; \
- const uint32_t delta = (uint32_t)(s->delta >> (SCOPE_FRAC_BITS-10)); \
- const uint32_t width = (x + w) - 1; \
- int32_t sample, sample2; \
- int32_t y1, y2; \
- int32_t position = s->position; \
- uint32_t positionFrac = 0;
+ SCOPE_REGS_NO_LOOP \
+ int32_t smpY1, smpY2; \
+ width--;
#define LINED_SCOPE_REGS_LOOP \
- const int32_t volume = s->volume; \
- const int32_t sampleEnd = s->sampleEnd; \
- const int32_t loopStart = s->loopStart; \
- const int32_t loopLength = s->loopLength; \
- const uint32_t delta = (uint32_t)(s->delta >> (SCOPE_FRAC_BITS-10)); \
- const uint32_t width = (x + w) - 1; \
- int32_t sample, sample2; \
- int32_t y1, y2; \
- int32_t position = s->position; \
- uint32_t positionFrac = 0;
+ SCOPE_REGS_LOOP \
+ int32_t smpY1, smpY2; \
+ width--;
-#define LINED_SCOPE_REGS_PINGPONG \
- const int32_t volume = s->volume; \
- const int32_t sampleEnd = s->sampleEnd; \
- const int32_t loopStart = s->loopStart; \
- const int32_t loopLength = s->loopLength; \
- const uint32_t delta = (uint32_t)(s->delta >> (SCOPE_FRAC_BITS-10)); \
- const uint32_t width = (x + w) - 1; \
- int32_t sample, sample2; \
- int32_t y1, y2; \
- int32_t position = s->position; \
- uint32_t positionFrac = 0; \
- int32_t direction = s->direction;
+#define LINED_SCOPE_REGS_BIDI \
+ SCOPE_REGS_BIDI \
+ int32_t smpY1, smpY2; \
+ width--;
-/* Note: Sample data already has a fixed tap samples at the end of the sample,
-** so that an out-of-bounds read is OK and reads the correct interpolation tap.
+/* Note: Sample data already has fixed tap samples at the end of the sample,
+** so that out-of-bounds reads get the correct interpolation tap data.
*/
-#define COLLECT_LERP_SAMPLES8 \
- sample = s->base8[position+0] << 8; \
- sample2 = s->base8[position+1] << 8;
-
-#define COLLECT_LERP_SAMPLES16 \
- sample = s->base16[position+0]; \
- sample2 = s->base16[position+1];
-
-#define DO_LERP \
- const int32_t frac = (uint32_t)positionFrac >> 1; /* 0..32767 */ \
- sample2 -= sample; \
- sample2 = (sample2 * frac) >> 15; \
- sample += sample2; \
-
-#define DO_LERP_BIDI \
- int32_t frac = (uint32_t)positionFrac >> 1; /* 0..32767 */ \
- if (direction == -1) frac ^= 32767; /* negate frac */ \
- sample2 -= sample; \
- sample2 = (sample2 * frac) >> 15; \
- sample += sample2;
-
-#define GET_LERP_SMP8 \
- COLLECT_LERP_SAMPLES8 \
- DO_LERP
-
-#define GET_LERP_SMP16 \
- COLLECT_LERP_SAMPLES16 \
- DO_LERP
-
-#define GET_LERP_SMP8_BIDI \
- COLLECT_LERP_SAMPLES8 \
- DO_LERP_BIDI
-
-#define GET_LERP_SMP16_BIDI \
- COLLECT_LERP_SAMPLES16 \
- DO_LERP_BIDI
+#define INTERPOLATE_SMP8(pos, frac) \
+ const int8_t *s8 = s->base8 + pos; \
+ const int16_t *t = scopeGaussianLUT + (((frac) >> (SCOPE_FRAC_BITS-8)) << 2); \
+ sample = ((s8[0] * t[0]) + \
+ (s8[1] * t[1]) + \
+ (s8[2] * t[2]) + \
+ (s8[3] * t[3])) >> (15-8);
+
+#define INTERPOLATE_SMP16(pos, frac) \
+ const int16_t *s16 = s->base16 + pos; \
+ const int16_t *t = scopeGaussianLUT + (((frac) >> (SCOPE_FRAC_BITS-8)) << 2); \
+ sample = ((s16[0] * t[0]) + \
+ (s16[1] * t[1]) + \
+ (s16[2] * t[2]) + \
+ (s16[3] * t[3])) >> 15;
#define SCOPE_GET_SMP8 \
if (s->active) \
@@ -130,21 +91,32 @@
else \
sample = 0;
-#define SCOPE_GET_LERP_SMP8 \
+#define SCOPE_GET_SMP8_BIDI \
if (s->active) \
{ \
- GET_LERP_SMP8 \
- sample = (sample * volume) >> 16; \
+ GET_BIDI_POSITION \
+ sample = (s->base8[actualPos] * volume) >> 8; \
+ } \
+ else \
+ { \
+ sample = 0; \
+ }
+
+#define SCOPE_GET_SMP16_BIDI \
+ if (s->active) \
+ { \
+ GET_BIDI_POSITION \
+ sample = (s->base16[actualPos] * volume) >> 16; \
} \
else \
{ \
sample = 0; \
}
-#define SCOPE_GET_LERP_SMP16 \
+#define SCOPE_GET_INTERPOLATED_SMP8 \
if (s->active) \
{ \
- GET_LERP_SMP16 \
+ INTERPOLATE_SMP8(position, (uint32_t)positionFrac) \
sample = (sample * volume) >> 16; \
} \
else \
@@ -152,10 +124,10 @@
sample = 0; \
}
-#define SCOPE_GET_LERP_SMP8_BIDI \
+#define SCOPE_GET_INTERPOLATED_SMP16 \
if (s->active) \
{ \
- GET_LERP_SMP8_BIDI \
+ INTERPOLATE_SMP16(position, (uint32_t)positionFrac) \
sample = (sample * volume) >> 16; \
} \
else \
@@ -163,10 +135,17 @@
sample = 0; \
}
-#define SCOPE_GET_LERP_SMP16_BIDI \
+#define GET_BIDI_POSITION \
+ if (samplingBackwards) \
+ actualPos = (sampleEnd - 1) - (position - loopStart); \
+ else \
+ actualPos = position;
+
+#define SCOPE_GET_INTERPOLATED_SMP8_BIDI \
if (s->active) \
{ \
- GET_LERP_SMP16_BIDI \
+ GET_BIDI_POSITION \
+ INTERPOLATE_SMP8(actualPos, samplingBackwards ? ((uint32_t)positionFrac ^ UINT32_MAX) : positionFrac) \
sample = (sample * volume) >> 16; \
} \
else \
@@ -174,43 +153,50 @@
sample = 0; \
}
-#define SCOPE_UPDATE_DRAWPOS \
- positionFrac += delta; \
- position += positionFrac >> 16; \
- positionFrac &= 0xFFFF;
+#define SCOPE_GET_INTERPOLATED_SMP16_BIDI \
+ if (s->active) \
+ { \
+ GET_BIDI_POSITION \
+ INTERPOLATE_SMP16(actualPos, samplingBackwards ? ((uint32_t)positionFrac ^ UINT32_MAX) : positionFrac) \
+ sample = (sample * volume) >> 16; \
+ } \
+ else \
+ { \
+ sample = 0; \
+ }
-#define SCOPE_UPDATE_DRAWPOS_PINGPONG \
+#define SCOPE_UPDATE_READPOS \
positionFrac += delta; \
- position += (int32_t)(positionFrac >> 16) * direction; \
- positionFrac &= 0xFFFF;
+ position += positionFrac >> 32; \
+ positionFrac &= UINT32_MAX;
#define SCOPE_DRAW_SMP \
video.frameBuffer[((lineY - sample) * SCREEN_W) + x] = color;
-#define LINED_SCOPE_PREPARE_LERP_SMP8 \
- SCOPE_GET_LERP_SMP8 \
- y1 = lineY - sample; \
- SCOPE_UPDATE_DRAWPOS
+#define LINED_SCOPE_PREPARE_SMP8 \
+ SCOPE_GET_INTERPOLATED_SMP8 \
+ smpY1 = lineY - sample; \
+ SCOPE_UPDATE_READPOS
-#define LINED_SCOPE_PREPARE_LERP_SMP16 \
- SCOPE_GET_LERP_SMP16 \
- y1 = lineY - sample; \
- SCOPE_UPDATE_DRAWPOS
+#define LINED_SCOPE_PREPARE_SMP16 \
+ SCOPE_GET_INTERPOLATED_SMP16 \
+ smpY1 = lineY - sample; \
+ SCOPE_UPDATE_READPOS
-#define LINED_SCOPE_PREPARE_LERP_SMP8_BIDI \
- SCOPE_GET_LERP_SMP8_BIDI \
- y1 = lineY - sample; \
- SCOPE_UPDATE_DRAWPOS
+#define LINED_SCOPE_PREPARE_SMP8_BIDI \
+ SCOPE_GET_INTERPOLATED_SMP8_BIDI \
+ smpY1 = lineY - sample; \
+ SCOPE_UPDATE_READPOS
-#define LINED_SCOPE_PREPARE_LERP_SMP16_BIDI \
- SCOPE_GET_LERP_SMP16_BIDI \
- y1 = lineY - sample; \
- SCOPE_UPDATE_DRAWPOS
+#define LINED_SCOPE_PREPARE_SMP16_BIDI \
+ SCOPE_GET_INTERPOLATED_SMP16_BIDI \
+ smpY1 = lineY - sample; \
+ SCOPE_UPDATE_READPOS
#define LINED_SCOPE_DRAW_SMP \
- y2 = lineY - sample; \
- scopeLine(x, y1, y2); \
- y1 = y2; \
+ smpY2 = lineY - sample; \
+ scopeLine(x, smpY1, smpY2, color); \
+ smpY1 = smpY2;
#define SCOPE_HANDLE_POS_NO_LOOP \
if (position >= sampleEnd) \
@@ -225,22 +211,19 @@
position = loopStart; \
}
-#define SCOPE_HANDLE_POS_PINGPONG \
- if (direction == -1 && position < loopStart) \
+#define SCOPE_HANDLE_POS_BIDI \
+ if (position >= sampleEnd) \
{ \
- direction = 1; /* change direction to forwards */ \
- \
if (loopLength >= 2) \
- position = loopStart + ((loopStart - position - 1) % loopLength); \
+ { \
+ const uint32_t overflow = position - sampleEnd; \
+ const uint32_t cycles = overflow / loopLength; \
+ const uint32_t phase = overflow % loopLength; \
+ position = loopStart + phase; \
+ samplingBackwards ^= !(cycles & 1); \
+ } \
else \
+ { \
position = loopStart; \
- } \
- else if (position >= sampleEnd) \
- { \
- direction = -1; /* change direction to backwards */ \
- \
- if (loopLength >= 2) \
- position = (sampleEnd - 1) - ((position - sampleEnd) % loopLength); \
- else \
- position = sampleEnd - 1; \
+ } \
}
diff --git a/src/scopes/ft2_scopedraw.c b/src/scopes/ft2_scopedraw.c
@@ -1,10 +1,146 @@
#include "../ft2_video.h"
#include "../ft2_palette.h"
+#include "../mixer/ft2_gaussian.h"
#include "ft2_scopes.h"
#include "ft2_scopedraw.h"
#include "ft2_scope_macros.h"
-static void scopeLine(int32_t x1, int32_t y1, int32_t y2);
+/* 15-bit Gaussian interpolation LUT with no overshoot (sum <= 1.0).
+** Suitable for tracker scopes.
+*/
+static const int16_t scopeGaussianLUT[4 * 256] =
+{
+ 4807,22963, 4871, -1, 4744,22962, 4935, -1,
+ 4681,22960, 5000, -1, 4619,22957, 5065, -1,
+ 4557,22953, 5131, -1, 4495,22948, 5197, -1,
+ 4435,22942, 5264, -1, 4374,22935, 5332, -1,
+ 4315,22927, 5399, -1, 4255,22918, 5468, -1,
+ 4197,22908, 5536, -1, 4138,22897, 5606, -1,
+ 4081,22885, 5676, -1, 4023,22872, 5746, -1,
+ 3967,22857, 5817, -1, 3910,22842, 5888, -1,
+ 3855,22826, 5959, 0, 3799,22809, 6032, 0,
+ 3745,22791, 6104, 0, 3691,22772, 6177, 0,
+ 3637,22752, 6251, 0, 3584,22731, 6325, 0,
+ 3531,22709, 6400, 0, 3479,22686, 6475, 1,
+ 3427,22662, 6550, 1, 3376,22637, 6626, 1,
+ 3325,22611, 6702, 1, 3275,22584, 6779, 2,
+ 3225,22556, 6856, 2, 3176,22527, 6934, 2,
+ 3128,22498, 7012, 3, 3079,22467, 7091, 3,
+ 3032,22435, 7170, 3, 2985,22402, 7249, 4,
+ 2938,22369, 7329, 4, 2892,22334, 7409, 5,
+ 2846,22299, 7490, 5, 2801,22262, 7571, 6,
+ 2756,22225, 7653, 7, 2712,22187, 7735, 7,
+ 2668,22148, 7817, 8, 2624,22107, 7900, 9,
+ 2582,22066, 7983, 9, 2539,22025, 8066, 10,
+ 2497,21982, 8150, 11, 2456,21938, 8234, 12,
+ 2415,21893, 8319, 13, 2374,21848, 8404, 14,
+ 2334,21801, 8489, 15, 2295,21754, 8575, 16,
+ 2256,21706, 8661, 17, 2217,21657, 8748, 18,
+ 2179,21607, 8834, 19, 2141,21556, 8922, 21,
+ 2104,21505, 9009, 22, 2067,21452, 9097, 24,
+ 2031,21399, 9185, 25, 1995,21345, 9273, 27,
+ 1959,21290, 9362, 28, 1924,21235, 9451, 30,
+ 1890,21178, 9541, 32, 1856,21121, 9630, 33,
+ 1822,21063, 9720, 35, 1789,21004, 9811, 37,
+ 1756,20944, 9901, 39, 1723,20884, 9992, 41,
+ 1691,20822,10083, 44, 1660,20760,10174, 46,
+ 1628,20698,10266, 48, 1598,20634,10358, 51,
+ 1567,20570,10450, 53, 1537,20505,10542, 56,
+ 1508,20439,10635, 58, 1479,20373,10727, 61,
+ 1450,20306,10820, 64, 1422,20238,10913, 67,
+ 1394,20169,11007, 70, 1366,20100,11100, 73,
+ 1339,20030,11194, 77, 1312,19959,11288, 80,
+ 1286,19888,11382, 84, 1260,19816,11476, 87,
+ 1234,19744,11571, 91, 1209,19671,11665, 95,
+ 1184,19597,11760, 99, 1160,19522,11855, 103,
+ 1136,19447,11950, 107, 1112,19372,12045, 111,
+ 1089,19295,12140, 116, 1066,19219,12236, 120,
+ 1043,19141,12331, 125, 1020,19063,12427, 130,
+ 999,18985,12522, 135, 977,18905,12618, 140,
+ 956,18826,12714, 145, 935,18746,12809, 150,
+ 914,18665,12905, 156, 894,18584,13001, 161,
+ 874,18502,13097, 167, 854,18420,13193, 173,
+ 835,18337,13289, 179, 816,18254,13385, 186,
+ 797,18170,13481, 192, 779,18086,13577, 199,
+ 761,18001,13673, 205, 743,17916,13769, 212,
+ 726,17830,13865, 219, 708,17744,13961, 227,
+ 692,17658,14056, 234, 675,17571,14152, 242,
+ 659,17484,14248, 250, 643,17396,14343, 257,
+ 627,17308,14439, 266, 612,17220,14534, 274,
+ 597,17131,14630, 283, 582,17042,14725, 291,
+ 567,16953,14820, 300, 553,16863,14915, 309,
+ 539,16773,15010, 319, 525,16682,15104, 328,
+ 512,16592,15199, 338, 498,16500,15293, 348,
+ 485,16409,15387, 358, 473,16317,15481, 369,
+ 460,16226,15575, 379, 448,16133,15669, 390,
+ 436,16041,15762, 401, 424,15948,15855, 412,
+ 412,15855,15948, 424, 401,15762,16041, 436,
+ 390,15669,16133, 448, 379,15575,16226, 460,
+ 369,15481,16317, 473, 358,15387,16409, 485,
+ 348,15293,16500, 498, 338,15199,16592, 512,
+ 328,15104,16682, 525, 319,15010,16773, 539,
+ 309,14915,16863, 553, 300,14820,16953, 567,
+ 291,14725,17042, 582, 283,14630,17131, 597,
+ 274,14534,17220, 612, 266,14439,17308, 627,
+ 257,14343,17396, 643, 250,14248,17484, 659,
+ 242,14152,17571, 675, 234,14056,17658, 692,
+ 227,13961,17744, 708, 219,13865,17830, 726,
+ 212,13769,17916, 743, 205,13673,18001, 761,
+ 199,13577,18086, 779, 192,13481,18170, 797,
+ 186,13385,18254, 816, 179,13289,18337, 835,
+ 173,13193,18420, 854, 167,13097,18502, 874,
+ 161,13001,18584, 894, 156,12905,18665, 914,
+ 150,12809,18746, 935, 145,12714,18826, 956,
+ 140,12618,18905, 977, 135,12522,18985, 999,
+ 130,12427,19063, 1020, 125,12331,19141, 1043,
+ 120,12236,19219, 1066, 116,12140,19295, 1089,
+ 111,12045,19372, 1112, 107,11950,19447, 1136,
+ 103,11855,19522, 1160, 99,11760,19597, 1184,
+ 95,11665,19671, 1209, 91,11571,19744, 1234,
+ 87,11476,19816, 1260, 84,11382,19888, 1286,
+ 80,11288,19959, 1312, 77,11194,20030, 1339,
+ 73,11100,20100, 1366, 70,11007,20169, 1394,
+ 67,10913,20238, 1422, 64,10820,20306, 1450,
+ 61,10727,20373, 1479, 58,10635,20439, 1508,
+ 56,10542,20505, 1537, 53,10450,20570, 1567,
+ 51,10358,20634, 1598, 48,10266,20698, 1628,
+ 46,10174,20760, 1660, 44,10083,20822, 1691,
+ 41, 9992,20884, 1723, 39, 9901,20944, 1756,
+ 37, 9811,21004, 1789, 35, 9720,21063, 1822,
+ 33, 9630,21121, 1856, 32, 9541,21178, 1890,
+ 30, 9451,21235, 1924, 28, 9362,21290, 1959,
+ 27, 9273,21345, 1995, 25, 9185,21399, 2031,
+ 24, 9097,21452, 2067, 22, 9009,21505, 2104,
+ 21, 8922,21556, 2141, 19, 8834,21607, 2179,
+ 18, 8748,21657, 2217, 17, 8661,21706, 2256,
+ 16, 8575,21754, 2295, 15, 8489,21801, 2334,
+ 14, 8404,21848, 2374, 13, 8319,21893, 2415,
+ 12, 8234,21938, 2456, 11, 8150,21982, 2497,
+ 10, 8066,22025, 2539, 9, 7983,22066, 2582,
+ 9, 7900,22107, 2624, 8, 7817,22148, 2668,
+ 7, 7735,22187, 2712, 7, 7653,22225, 2756,
+ 6, 7571,22262, 2801, 5, 7490,22299, 2846,
+ 5, 7409,22334, 2892, 4, 7329,22369, 2938,
+ 4, 7249,22402, 2985, 3, 7170,22435, 3032,
+ 3, 7091,22467, 3079, 3, 7012,22498, 3128,
+ 2, 6934,22527, 3176, 2, 6856,22556, 3225,
+ 2, 6779,22584, 3275, 1, 6702,22611, 3325,
+ 1, 6626,22637, 3376, 1, 6550,22662, 3427,
+ 1, 6475,22686, 3479, 0, 6400,22709, 3531,
+ 0, 6325,22731, 3584, 0, 6251,22752, 3637,
+ 0, 6177,22772, 3691, 0, 6104,22791, 3745,
+ 0, 6032,22809, 3799, 0, 5959,22826, 3855,
+ -1, 5888,22842, 3910, -1, 5817,22857, 3967,
+ -1, 5746,22872, 4023, -1, 5676,22885, 4081,
+ -1, 5606,22897, 4138, -1, 5536,22908, 4197,
+ -1, 5468,22918, 4255, -1, 5399,22927, 4315,
+ -1, 5332,22935, 4374, -1, 5264,22942, 4435,
+ -1, 5197,22948, 4495, -1, 5131,22953, 4557,
+ -1, 5065,22957, 4619, -1, 5000,22960, 4681,
+ -1, 4935,22962, 4744, -1, 4871,22963, 4807
+};
+
+static void scopeLine(int32_t x1, int32_t y1, int32_t y2, uint32_t color);
/* ----------------------------------------------------------------------- */
/* SCOPE DRAWING ROUTINES */
@@ -18,7 +154,7 @@ static void scopeDrawNoLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_
{
SCOPE_GET_SMP8
SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS
+ SCOPE_UPDATE_READPOS
SCOPE_HANDLE_POS_NO_LOOP
}
}
@@ -31,21 +167,21 @@ static void scopeDrawLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t
{
SCOPE_GET_SMP8
SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS
+ SCOPE_UPDATE_READPOS
SCOPE_HANDLE_POS_LOOP
}
}
static void scopeDrawPingPong_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
{
- SCOPE_REGS_PINGPONG
+ SCOPE_REGS_BIDI
for (; x < width; x++)
{
- SCOPE_GET_SMP8
+ SCOPE_GET_SMP8_BIDI
SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS_PINGPONG
- SCOPE_HANDLE_POS_PINGPONG
+ SCOPE_UPDATE_READPOS
+ SCOPE_HANDLE_POS_BIDI
}
}
@@ -57,7 +193,7 @@ static void scopeDrawNoLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32
{
SCOPE_GET_SMP16
SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS
+ SCOPE_UPDATE_READPOS
SCOPE_HANDLE_POS_NO_LOOP
}
}
@@ -70,21 +206,21 @@ static void scopeDrawLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t
{
SCOPE_GET_SMP16
SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS
+ SCOPE_UPDATE_READPOS
SCOPE_HANDLE_POS_LOOP
}
}
static void scopeDrawPingPong_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
{
- SCOPE_REGS_PINGPONG
+ SCOPE_REGS_BIDI
for (; x < width; x++)
{
- SCOPE_GET_SMP16
+ SCOPE_GET_SMP16_BIDI
SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS_PINGPONG
- SCOPE_HANDLE_POS_PINGPONG
+ SCOPE_UPDATE_READPOS
+ SCOPE_HANDLE_POS_BIDI
}
}
@@ -95,14 +231,14 @@ static void scopeDrawPingPong_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint
static void linedScopeDrawNoLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
{
LINED_SCOPE_REGS_NO_LOOP
- LINED_SCOPE_PREPARE_LERP_SMP8
+ LINED_SCOPE_PREPARE_SMP8
SCOPE_HANDLE_POS_NO_LOOP
for (; x < width; x++)
{
- SCOPE_GET_LERP_SMP8
+ SCOPE_GET_INTERPOLATED_SMP8
LINED_SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS
+ SCOPE_UPDATE_READPOS
SCOPE_HANDLE_POS_NO_LOOP
}
}
@@ -110,44 +246,44 @@ static void linedScopeDrawNoLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, ui
static void linedScopeDrawLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
{
LINED_SCOPE_REGS_LOOP
- LINED_SCOPE_PREPARE_LERP_SMP8
+ LINED_SCOPE_PREPARE_SMP8
SCOPE_HANDLE_POS_LOOP
for (; x < width; x++)
{
- SCOPE_GET_LERP_SMP8
+ SCOPE_GET_INTERPOLATED_SMP8
LINED_SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS
+ SCOPE_UPDATE_READPOS
SCOPE_HANDLE_POS_LOOP
}
}
static void linedScopeDrawPingPong_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
{
- LINED_SCOPE_REGS_PINGPONG
- LINED_SCOPE_PREPARE_LERP_SMP8_BIDI
- SCOPE_HANDLE_POS_PINGPONG
+ LINED_SCOPE_REGS_BIDI
+ LINED_SCOPE_PREPARE_SMP8_BIDI
+ SCOPE_HANDLE_POS_BIDI
for (; x < width; x++)
{
- SCOPE_GET_LERP_SMP8_BIDI
+ SCOPE_GET_INTERPOLATED_SMP8_BIDI
LINED_SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS_PINGPONG
- SCOPE_HANDLE_POS_PINGPONG
+ SCOPE_UPDATE_READPOS
+ SCOPE_HANDLE_POS_BIDI
}
}
static void linedScopeDrawNoLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
{
LINED_SCOPE_REGS_NO_LOOP
- LINED_SCOPE_PREPARE_LERP_SMP16
+ LINED_SCOPE_PREPARE_SMP16
SCOPE_HANDLE_POS_NO_LOOP
for (; x < width; x++)
{
- SCOPE_GET_LERP_SMP16
+ SCOPE_GET_INTERPOLATED_SMP16
LINED_SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS
+ SCOPE_UPDATE_READPOS
SCOPE_HANDLE_POS_NO_LOOP
}
}
@@ -155,40 +291,39 @@ static void linedScopeDrawNoLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, u
static void linedScopeDrawLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
{
LINED_SCOPE_REGS_LOOP
- LINED_SCOPE_PREPARE_LERP_SMP16
+ LINED_SCOPE_PREPARE_SMP16
SCOPE_HANDLE_POS_LOOP
for (; x < width; x++)
{
- SCOPE_GET_LERP_SMP16
+ SCOPE_GET_INTERPOLATED_SMP16
LINED_SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS
+ SCOPE_UPDATE_READPOS
SCOPE_HANDLE_POS_LOOP
}
}
static void linedScopeDrawPingPong_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w)
{
- LINED_SCOPE_REGS_PINGPONG
- LINED_SCOPE_PREPARE_LERP_SMP16_BIDI
- SCOPE_HANDLE_POS_PINGPONG
+ LINED_SCOPE_REGS_BIDI
+ LINED_SCOPE_PREPARE_SMP16_BIDI
+ SCOPE_HANDLE_POS_BIDI
for (; x < width; x++)
{
- SCOPE_GET_LERP_SMP16_BIDI
+ SCOPE_GET_INTERPOLATED_SMP16_BIDI
LINED_SCOPE_DRAW_SMP
- SCOPE_UPDATE_DRAWPOS_PINGPONG
- SCOPE_HANDLE_POS_PINGPONG
+ SCOPE_UPDATE_READPOS
+ SCOPE_HANDLE_POS_BIDI
}
}
// -----------------------------------------------------------------------
-static void scopeLine(int32_t x1, int32_t y1, int32_t y2)
+static void scopeLine(int32_t x1, int32_t y1, int32_t y2, uint32_t color)
{
const int32_t dy = y2 - y1;
const int32_t sy = SGN(dy);
- const uint32_t color = video.palette[PAL_PATTEXT];
const int32_t pitch = sy * SCREEN_W;
uint32_t *dst32 = &video.frameBuffer[(y1 * SCREEN_W) + x1];
diff --git a/src/scopes/ft2_scopes.c b/src/scopes/ft2_scopes.c
@@ -40,14 +40,21 @@ int32_t getSamplePosition(uint8_t ch)
// cache some stuff
volatile bool active = sc->active;
+ volatile bool samplingBackwards = sc->samplingBackwards;
volatile int32_t position = sc->position;
+ volatile int32_t loopStart = sc->loopStart;
volatile int32_t sampleEnd = sc->sampleEnd;
if (!active || sampleEnd == 0)
return -1;
if (position >= 0 && position < sampleEnd)
+ {
+ if (samplingBackwards) // get actual bidi pos when in backwards mode
+ position = (sampleEnd - 1) - (position - loopStart);
+
return position;
+ }
return -1; // not active or overflown
}
@@ -307,7 +314,7 @@ static void scopeTrigger(int32_t ch, const sample_t *s, int32_t playOffset)
tempState.sample16Bit = sample16Bit;
tempState.loopType = loopType;
- tempState.direction = 1; // forwards
+ tempState.samplingBackwards = false;
tempState.sampleEnd = (loopType == LOOP_OFF) ? length : loopEnd;
tempState.loopStart = loopStart;
tempState.loopLength = loopLength;
@@ -347,52 +354,41 @@ static void updateScopes(void)
// scope position update
s.positionFrac += s.delta;
- const uint32_t wholeSamples = (uint32_t)(s.positionFrac >> SCOPE_FRAC_BITS);
+ s.position += s.positionFrac >> SCOPE_FRAC_BITS;
s.positionFrac &= SCOPE_FRAC_MASK;
- if (s.direction == 1)
- s.position += wholeSamples; // forwards
- else
- s.position -= wholeSamples; // backwards
-
- // handle loop wrapping or sample end
- if (s.direction == -1 && s.position < s.loopStart) // sampling backwards (definitely pingpong loop)
- {
- s.direction = 1; // change direction to forwards
-
- if (s.loopLength >= 2)
- s.position = s.loopStart + ((s.loopStart - s.position - 1) % s.loopLength);
- else
- s.position = s.loopStart;
-
- assert(s.position >= s.loopStart && s.position < s.sampleEnd);
- }
- else if (s.position >= s.sampleEnd)
+ if (s.position >= s.sampleEnd)
{
- uint32_t loopOverflowVal;
-
- if (s.loopLength >= 2)
- loopOverflowVal = (s.position - s.sampleEnd) % s.loopLength;
- else
- loopOverflowVal = 0;
-
- if (s.loopType == LOOP_DISABLED)
+ if (s.loopType == LOOP_BIDI)
{
- s.active = false;
+ if (s.loopLength >= 2)
+ {
+ // wrap as forward loop (position is inverted if sampling backwards, when needed)
+
+ const uint32_t overflow = s.position - s.sampleEnd;
+ const uint32_t cycles = overflow / s.loopLength;
+ const uint32_t phase = overflow % s.loopLength;
+
+ s.position = s.loopStart + phase;
+ s.samplingBackwards ^= !(cycles & 1);
+ }
+ else
+ {
+ s.position = s.loopStart;
+ }
}
else if (s.loopType == LOOP_FORWARD)
{
- s.position = s.loopStart + loopOverflowVal;
- assert(s.position >= s.loopStart && s.position < s.sampleEnd);
+ if (s.loopLength >= 2)
+ s.position = s.loopStart + ((s.position - s.sampleEnd) % s.loopLength);
+ else
+ s.position = s.loopStart;
}
- else // pingpong loop
+ else // no loop
{
- s.direction = -1; // change direction to backwards
- s.position = (s.sampleEnd - 1) - loopOverflowVal;
- assert(s.position >= s.loopStart && s.position < s.sampleEnd);
+ s.active = false;
}
}
- assert(s.position >= 0);
*sc = s; // set new scope state
}
@@ -432,10 +428,8 @@ void drawScopes(void)
// scope is active
scope[i].wasCleared = false;
- // get relative voice Hz (in relation to middle-C rate), and scale to 16.16fp
- const uint32_t relHz16 = (uint32_t)(scope[i].delta * (((double)SCOPE_HZ / SCOPE_FRAC_SCALE) / (C4_FREQ / 65536.0)));
-
- scope[i].drawDelta = relHz16 << 1; // FT2 does this to the final 16.16fp value
+ // get relative voice Hz (in relation to C4/2 rate)
+ scope[i].drawDelta = (uint64_t)(scope[i].delta * ((double)SCOPE_HZ / ((double)C4_FREQ / 2.0)));
// clear scope background
clearRect(scopeXOffs, scopeYOffs, scopeDrawLen, SCOPE_HEIGHT);
diff --git a/src/scopes/ft2_scopes.h b/src/scopes/ft2_scopes.h
@@ -25,11 +25,10 @@ typedef struct scope_t
volatile bool active;
const int8_t *base8;
const int16_t *base16;
- bool wasCleared, sample16Bit;
+ bool wasCleared, sample16Bit, samplingBackwards;
uint8_t loopType;
- int32_t volume, direction, loopStart, loopLength, sampleEnd, position;
- uint32_t drawDelta;
- uint64_t delta, positionFrac;
+ int32_t volume, loopStart, loopLength, sampleEnd, position;
+ uint64_t delta, drawDelta, positionFrac;
} scope_t;
typedef struct lastChInstr_t