shithub: ft²

Download patch

ref: 525505abf8d09aac0cc7e0518a0c6d268d040dc2
parent: aa1481048c9a0e969ebb944cbbc01978003fc1d3
author: Olav Sørensen <olav.sorensen@live.no>
date: Wed May 21 09:16:17 EDT 2025

Faster scopes (and reverted to previous scaling behavior)

--- a/src/ft2_audio.c
+++ b/src/ft2_audio.c
@@ -368,7 +368,7 @@
 		if (status & IS_Vol)
 		{
 			v->fVolume = ch->fFinalVol; // 0.0f .. 1.0f
-			v->scopeVolume = (uint8_t)((ch->fFinalVol * 255.0f) + 0.5f); // 0..255, rounded
+			v->scopeVolume = (uint8_t)((ch->fFinalVol * (SCOPE_HEIGHT*4.0f)) + 0.5f);
 		}
 
 		if (status & IS_Pan)
--- a/src/scopes/ft2_scope_macros.h
+++ b/src/scopes/ft2_scope_macros.h
@@ -109,8 +109,7 @@
 		LINEAR_INTERPOLATION8(frac) \
 	else \
 		CUBIC_INTERPOLATION8(frac) \
-	sample = (int32_t)roundf((float)sample * s->fVolume); \
-	if (sample > (SCOPE_HEIGHT/2)-1) sample = (SCOPE_HEIGHT/2)-1; /* upper-clamp needed */
+	sample = (sample * s->volume) >> (16+2);
 
 #define INTERPOLATE_SMP16(pos, frac) \
 	const int16_t *s16 = s->base16 + pos; \
@@ -120,8 +119,7 @@
 		LINEAR_INTERPOLATION16(frac) \
 	else \
 		CUBIC_INTERPOLATION16(frac) \
-	sample = (int32_t)roundf((float)sample * s->fVolume); \
-	if (sample > (SCOPE_HEIGHT/2)-1) sample = (SCOPE_HEIGHT/2)-1; /* upper-clamp needed */
+	sample = (sample * s->volume) >> (16+2);
 
 #define INTERPOLATE_SMP8_LOOP(pos, frac) \
 	const int8_t *s8 = s->base8 + pos; \
@@ -131,8 +129,7 @@
 		LINEAR_INTERPOLATION8(frac) \
 	else \
 		CUBIC_INTERPOLATION8_LOOP(pos, frac) \
-	sample = (int32_t)roundf((float)sample * s->fVolume); \
-	if (sample > (SCOPE_HEIGHT/2)-1) sample = (SCOPE_HEIGHT/2)-1; /* upper-clamp needed */
+	sample = (sample * s->volume) >> (16+2);
 
 #define INTERPOLATE_SMP16_LOOP(pos, frac) \
 	const int16_t *s16 = s->base16 + pos; \
@@ -142,37 +139,25 @@
 		LINEAR_INTERPOLATION16(frac) \
 	else \
 		CUBIC_INTERPOLATION16_LOOP(pos, frac) \
-	sample = (int32_t)roundf((float)sample * s->fVolume); \
-	if (sample > (SCOPE_HEIGHT/2)-1) sample = (SCOPE_HEIGHT/2)-1; /* upper-clamp needed */
+	sample = (sample * s->volume) >> (16+2);
 
 #define SCOPE_GET_SMP8 \
 	if (s->active) \
-	{ \
-		sample = (int32_t)roundf((float)(s->base8[position] << 8) * s->fVolume); \
-		if (sample > (SCOPE_HEIGHT/2)-1) sample = (SCOPE_HEIGHT/2)-1; /* upper-clamp needed */ \
-	} \
+		sample = (s->base8[position] * s->volume) >> (8+2); \
 	else \
-	{ \
-		sample = 0; \
-	}
+		sample = 0;
 
 #define SCOPE_GET_SMP16 \
 	if (s->active) \
-	{ \
-		sample = (int32_t)roundf((float)s->base16[position] * s->fVolume); \
-		if (sample > (SCOPE_HEIGHT/2)-1) sample = (SCOPE_HEIGHT/2)-1; /* upper-clamp needed */ \
-	} \
+		sample = (s->base16[position] * s->volume) >> (16+2); \
 	else \
-	{ \
-		sample = 0; \
-	}
+		sample = 0;
 
 #define SCOPE_GET_SMP8_BIDI \
 	if (s->active) \
 	{ \
 		GET_BIDI_POSITION \
-		sample = (int32_t)roundf((float)(s->base8[actualPos] << 8) * s->fVolume); \
-		if (sample > (SCOPE_HEIGHT/2)-1) sample = (SCOPE_HEIGHT/2)-1; /* upper-clamp needed */ \
+		sample = (s->base8[actualPos] * s->volume) >> (8+2); \
 	} \
 	else \
 	{ \
@@ -183,8 +168,7 @@
 	if (s->active) \
 	{ \
 		GET_BIDI_POSITION \
-		sample = (int32_t)roundf((float)s->base16[actualPos] * s->fVolume); \
-		if (sample > (SCOPE_HEIGHT/2)-1) sample = (SCOPE_HEIGHT/2)-1; /* upper-clamp needed */ \
+		sample = (s->base16[actualPos] * s->volume) >> (16+2); \
 	} \
 	else \
 	{ \
--- a/src/scopes/ft2_scopedraw.c
+++ b/src/scopes/ft2_scopedraw.c
@@ -40,11 +40,11 @@
 		double t3 = (-(1.0/2.0) * x3) + ( (1.0/2.0) * x2) + ( (1.0/2.0) * x1) + (1.0/6.0);
 		double t4 =   (1.0/6.0) * x3;
 
-		// rounding here would make the scopes clip, but we clamp the scopes for another reason anyway
-		*ptr16++ = (int16_t)round(t1 * SCOPE_INTRP_SCALE);
-		*ptr16++ = (int16_t)round(t2 * SCOPE_INTRP_SCALE);
-		*ptr16++ = (int16_t)round(t3 * SCOPE_INTRP_SCALE);
-		*ptr16++ = (int16_t)round(t4 * SCOPE_INTRP_SCALE);
+		// truncate, do not round!
+		*ptr16++ = (int16_t)(t1 * SCOPE_INTRP_SCALE);
+		*ptr16++ = (int16_t)(t2 * SCOPE_INTRP_SCALE);
+		*ptr16++ = (int16_t)(t3 * SCOPE_INTRP_SCALE);
+		*ptr16++ = (int16_t)(t4 * SCOPE_INTRP_SCALE);
 	}
 
 	return true;
--- a/src/scopes/ft2_scopes.c
+++ b/src/scopes/ft2_scopes.c
@@ -428,7 +428,7 @@
 		}
 
 		volatile scope_t s = scope[i]; // cache scope to lower thread race condition issues
-		if (s.active && s.fVolume > 0.0f && !audio.locked)
+		if (s.active && s.volume > 0 && !audio.locked)
 		{
 			// scope is active
 			scope[i].wasCleared = false;
@@ -489,7 +489,7 @@
 		const uint8_t status = scopeUpdateStatus[i];
 
 		if (status & IS_Vol)
-			sc->fVolume = ch->scopeVolume * (1.0f / (255.0f / (SCOPE_HEIGHT/2) * 32768.0f));
+			sc->volume = ch->scopeVolume;
 
 		if (status & IS_Period)
 			sc->delta = (uint64_t)(dPeriod2Hz(ch->period) * (SCOPE_FRAC_SCALE / (double)SCOPE_HZ));
--- a/src/scopes/ft2_scopes.h
+++ b/src/scopes/ft2_scopes.h
@@ -21,8 +21,8 @@
 #define SCOPE_INTRP_WIDTH_BITS 2 /* log2(SCOPE_INTRP_WIDTH) */
 #define SCOPE_INTRP_SCALE 32768
 #define SCOPE_INTRP_SCALE_BITS 15 /* log2(SCOPE_INTRP_SCALE) */
-#define SCOPE_INTRP_PHASES 512 /* plentiful for FT2-styled scopes */
-#define SCOPE_INTRP_PHASES_BITS 9 /* log2(SCOPE_INTRP_PHASES) */
+#define SCOPE_INTRP_PHASES 256 /* enough for the scopes */
+#define SCOPE_INTRP_PHASES_BITS 8 /* log2(SCOPE_INTRP_PHASES) */
 
 int32_t getSamplePositionFromScopes(uint8_t ch);
 void stopAllScopes(void);
@@ -40,9 +40,9 @@
 	const int16_t *base16;
 	bool wasCleared, sample16Bit, samplingBackwards, hasLooped;
 	uint8_t loopType;
+	int16_t volume;
 	int32_t loopStart, loopLength, loopEnd, sampleEnd, position;
 	uint64_t delta, drawDelta, positionFrac;
-	float fVolume;
 
 	// if (loopEnabled && hasLooped && samplingPos <= loopStart+MAX_LEFT_TAPS) readFixedTapsFromThisPointer();
 	const int8_t *leftEdgeTaps8;
--