shithub: ft2-clone

Download patch

ref: 95112aa96abb49f3cd58750e36897236f834e4b7
parent: 60a3dd36bb82179a0768a4ebeb4f7c632cdd59bf
author: Olav Sørensen <olav.sorensen@live.no>
date: Sun Aug 23 16:16:28 EDT 2020

Pushed v1.30 code

- Fixed an off-by-one issue when dithering is enabled in 16-bit audio mode
- The WAV renderer now defaults to the same frequency/bitdepth as the ones selected in the "I/O devices" config screen

--- a/src/ft2_audio.c
+++ b/src/ft2_audio.c
@@ -24,10 +24,9 @@
 
 static int8_t pmpCountDiv, pmpChannels = 2;
 static uint16_t smpBuffSize;
-static int32_t masterVol, oldAudioFreq, randSeed = INITIAL_DITHER_SEED;
-static int32_t prngStateL, prngStateR;
+static int32_t oldAudioFreq, randSeed = INITIAL_DITHER_SEED;
 static uint32_t tickTimeLen, tickTimeLenFrac;
-static double dAudioAmpMul, dPanningTab[256+1];
+static double dAudioNormalizeMul, dPanningTab[256+1], dPrngStateL, dPrngStateR;
 static voice_t voice[MAX_VOICES * 2];
 static void (*sendAudSamplesFunc)(uint8_t *, uint32_t, uint8_t); // "send mixed samples" routines
 
@@ -114,27 +113,25 @@
 	}
 
 	resumeAudio();
+
+	setWavRenderFrequency(audio.freq);
+	setWavRenderBitDepth((config.specialFlags & BITDEPTH_32) ? 32 : 16);
 	return true;
 }
 
-// ampFactor = 1..32, masterVol = 0..256
-void setAudioAmp(int16_t ampFactor, int16_t master, bool bitDepth32Flag)
+// amp = 1..32, masterVol = 0..256
+void setAudioAmp(int16_t amp, int16_t masterVol, bool bitDepth32Flag)
 {
-	ampFactor = CLAMP(ampFactor, 1, 32);
-	master = CLAMP(master, 0, 256);
+	amp = CLAMP(amp, 1, 32);
+	masterVol = CLAMP(masterVol, 0, 256);
 
-	const double dAudioNorm = 1.0 / (1UL << 25); // 2^25 = internal voice mixing range (per voice)
+	const double dAmp = (amp * masterVol) / (32.0 * 256.0);
 
-	if (bitDepth32Flag)
-	{
-		// 32-bit floating point mixing mode
-		dAudioAmpMul = dAudioNorm * (master / 256.0) * (ampFactor / 32.0);
-	}
-	else
-	{
-		// 16-bit integer mixing mode
-		masterVol = (master * ampFactor) * 512;
-	}
+	int32_t normalizeBits = 25; // 2^25 = mixing bits per voice
+	if (!bitDepth32Flag)
+		normalizeBits -= 16-1; // change scale from -1.0..1.0 to signed 16-bit
+
+	dAudioNormalizeMul = dAmp / (1UL << normalizeBits);
 }
 
 void setNewAudioFreq(uint32_t freq) // for song to WAV rendering
@@ -410,8 +407,8 @@
 void resetAudioDither(void)
 {
 	randSeed = INITIAL_DITHER_SEED;
-	prngStateL = 0;
-	prngStateR = 0;
+	dPrngStateL = 0.0;
+	dPrngStateR = 0.0;
 }
 
 static inline uint32_t random32(void)
@@ -431,12 +428,12 @@
 	for (uint32_t i = 0; i < sampleBlockLength; i++)
 	{
 		// left channel
-		out32 = ((int64_t)audio.mixBufferL[i] * masterVol) >> 32;
+		out32 = (int32_t)(audio.mixBufferL[i] * dAudioNormalizeMul);
 		CLAMP16(out32);
 		*streamPointer16++ = (int16_t)out32;
 
 		// right channel
-		out32 = ((int64_t)audio.mixBufferR[i] * masterVol) >> 32;
+		out32 = (int32_t)(audio.mixBufferR[i] * dAudioNormalizeMul);
 		CLAMP16(out32);
 		*streamPointer16++ = (int16_t)out32;
 	}
@@ -452,12 +449,12 @@
 	for (uint32_t i = 0; i < sampleBlockLength; i++)
 	{
 		// left channel
-		out32 = ((int64_t)audio.mixBufferL[i] * masterVol) >> 32;
+		out32 = (int32_t)(audio.mixBufferL[i] * dAudioNormalizeMul);
 		CLAMP16(out32);
 		*streamPointer16++ = (int16_t)out32;
 
 		// right channel
-		out32 = ((int64_t)audio.mixBufferR[i] * masterVol) >> 32;
+		out32 = (int32_t)(audio.mixBufferR[i] * dAudioNormalizeMul);
 		CLAMP16(out32);
 		*streamPointer16++ = (int16_t)out32;
 
@@ -469,22 +466,25 @@
 
 static void sendSamples16BitDitherStereo(uint8_t *stream, uint32_t sampleBlockLength, uint8_t numAudioChannels)
 {
-	int32_t prng, out32;
+	int32_t out32;
+	double dOut, dPrng;
 
 	int16_t *streamPointer16 = (int16_t *)stream;
 	for (uint32_t i = 0; i < sampleBlockLength; i++)
 	{
 		// left channel - 1-bit triangular dithering
-		prng = random32();
-		out32 = ((((int64_t)audio.mixBufferL[i] * masterVol) + prng) - prngStateL) >> 32;
-		prngStateL = prng;
+		dPrng = random32() * (0.5 / INT32_MAX); // -0.5..0.5
+		dOut = ((audio.mixBufferL[i] * dAudioNormalizeMul) + dPrng) - dPrngStateL;
+		dPrngStateL = dPrng;
+		out32 = (int32_t)dOut;
 		CLAMP16(out32);
 		*streamPointer16++ = (int16_t)out32;
 
 		// right channel - 1-bit triangular dithering
-		prng = random32();
-		out32 = ((((int64_t)audio.mixBufferR[i] * masterVol) + prng) - prngStateR) >> 32;
-		prngStateR = prng;
+		dPrng = random32() * (0.5 / INT32_MAX); // -0.5..0.5
+		dOut = ((audio.mixBufferR[i] * dAudioNormalizeMul) + dPrng) - dPrngStateR;
+		dPrngStateR = dPrng;
+		out32 = (int32_t)dOut;
 		CLAMP16(out32);
 		*streamPointer16++ = (int16_t)out32;
 	}
@@ -494,22 +494,25 @@
 
 static void sendSamples16BitDitherMultiChan(uint8_t *stream, uint32_t sampleBlockLength, uint8_t numAudioChannels)
 {
-	int32_t prng, out32;
+	int32_t out32;
+	double dOut, dPrng;
 
 	int16_t *streamPointer16 = (int16_t *)stream;
 	for (uint32_t i = 0; i < sampleBlockLength; i++)
 	{
 		// left channel - 1-bit triangular dithering
-		prng = random32();
-		out32 = ((((int64_t)audio.mixBufferL[i] * masterVol) + prng) - prngStateL) >> 32;
-		prngStateL = prng;
+		dPrng = random32() * (0.5 / INT32_MAX); // -0.5..0.5
+		dOut = ((audio.mixBufferL[i] * dAudioNormalizeMul) + dPrng) - dPrngStateL;
+		dPrngStateL = dPrng;
+		out32 = (int32_t)dOut;
 		CLAMP16(out32);
 		*streamPointer16++ = (int16_t)out32;
 
 		// right channel - 1-bit triangular dithering
-		prng = random32();
-		out32 = ((((int64_t)audio.mixBufferR[i] * masterVol) + prng) - prngStateR) >> 32;
-		prngStateR = prng;
+		dPrng = random32() * (0.5 / INT32_MAX); // -0.5..0.5
+		dOut = ((audio.mixBufferR[i] * dAudioNormalizeMul) + dPrng) - dPrngStateR;
+		dPrngStateR = dPrng;
+		out32 = (int32_t)dOut;
 		CLAMP16(out32);
 		*streamPointer16++ = (int16_t)out32;
 
@@ -527,12 +530,12 @@
 	for (uint32_t i = 0; i < sampleBlockLength; i++)
 	{
 		// left channel
-		dOut = audio.mixBufferL[i] * dAudioAmpMul;
+		dOut = audio.mixBufferL[i] * dAudioNormalizeMul;
 		dOut = CLAMP(dOut, -1.0, 1.0);
 		*fStreamPointer32++ = (float)dOut;
 
 		// right channel
-		dOut = audio.mixBufferR[i] * dAudioAmpMul;
+		dOut = audio.mixBufferR[i] * dAudioNormalizeMul;
 		dOut = CLAMP(dOut, -1.0, 1.0);
 		*fStreamPointer32++ = (float)dOut;
 	}
@@ -548,12 +551,12 @@
 	for (uint32_t i = 0; i < sampleBlockLength; i++)
 	{
 		// left channel
-		dOut = audio.mixBufferL[i] * dAudioAmpMul;
+		dOut = audio.mixBufferL[i] * dAudioNormalizeMul;
 		dOut = CLAMP(dOut, -1.0, 1.0);
 		*fStreamPointer32++ = (float)dOut;
 
 		// right channel
-		dOut = audio.mixBufferR[i] * dAudioAmpMul;
+		dOut = audio.mixBufferR[i] * dAudioNormalizeMul;
 		dOut = CLAMP(dOut, -1.0, 1.0);
 		*fStreamPointer32++ = (float)dOut;
 
@@ -1247,6 +1250,9 @@
 
 	updateSendAudSamplesRoutine(false);
 	audio.resetSyncTickTimeFlag = true;
+
+	setWavRenderFrequency(audio.freq);
+	setWavRenderBitDepth((config.specialFlags & BITDEPTH_32) ? 32 : 16);
 
 	return true;
 }
--- a/src/ft2_audio.h
+++ b/src/ft2_audio.h
@@ -117,7 +117,7 @@
 uint64_t getChQueueTimestamp(void);
 
 void calcPanningTable(void);
-void setAudioAmp(int16_t ampFactor, int16_t master, bool bitDepth32Flag);
+void setAudioAmp(int16_t amp, int16_t masterVol, bool bitDepth32Flag);
 void setNewAudioFreq(uint32_t freq);
 void setBackOldAudioFreq(void);
 void setSpeed(uint16_t bpm);
--- a/src/ft2_header.h
+++ b/src/ft2_header.h
@@ -12,7 +12,7 @@
 #endif
 #include "ft2_replayer.h"
 
-#define PROG_VER_STR "1.29"
+#define PROG_VER_STR "1.30"
 
 // do NOT change these! It will only mess things up...
 
--- a/src/ft2_replayer.c
+++ b/src/ft2_replayer.c
@@ -357,8 +357,8 @@
 
 	dHz2MixDeltaMul = (double)MIXER_FRAC_SCALE / audioFreq;
 
-	audio.quickVolSizeVal = (int32_t)((audioFreq / 200.0) + 0.5);
-	audio.rampQuickVolMul = (int32_t)(((UINT32_MAX + 1.0) / audio.quickVolSizeVal) + 0.5);
+	audio.quickVolSizeVal = (int32_t)((audioFreq / 200.0) + 0.5); // rounded
+	audio.rampQuickVolMul = (int32_t)(((UINT32_MAX + 1.0) / audio.quickVolSizeVal) + 0.5); // rounded
 
 	/* Calculate tables to prevent floating point operations on systems that
 	** might have a slow FPU. This is quite hackish and not really needed,
@@ -373,8 +373,6 @@
 	{
 		const double dBpmHz = i / 2.5;
 		const double dSamplesPerTick = audioFreq / dBpmHz;
-		const int32_t samplesPerTick = (int32_t)(dSamplesPerTick + 0.5); // rounded
-
 		audio.dSpeedValTab[i] = dSamplesPerTick;
 
 		// BPM -> Hz -> tick length for performance counter (syncing visuals to audio)
@@ -387,7 +385,8 @@
 		audio.tickTimeLengthTab[i] = ((uint64_t)timeInt << 32) | (uint32_t)dTimeFrac;
 
 		// for calculating volume ramp length for "tick" ramps
-		audio.rampSpeedValMulTab[i] = (int32_t)(((UINT32_MAX + 1.0) / samplesPerTick) + 0.5);
+		const int32_t samplesPerTick = (int32_t)(dSamplesPerTick + 0.5); // this has to be rounded
+		audio.rampSpeedValMulTab[i] = (int32_t)(((UINT32_MAX + 1.0) / samplesPerTick) + 0.5); // rounded
 	}
 }
 
--- a/src/ft2_wav_renderer.c
+++ b/src/ft2_wav_renderer.c
@@ -39,11 +39,7 @@
 static char WAV_SysReqText[192];
 static uint8_t WDBitDepth = 16, WDStartPos, WDStopPos, *wavRenderBuffer;
 static int16_t WDAmp;
-#if defined __amd64__ || defined _WIN64
-static uint32_t WDFrequency = 96000;
-#else
 static uint32_t WDFrequency = 48000;
-#endif
 static SDL_Thread *thread;
 
 static void updateWavRenderer(void)
@@ -65,6 +61,24 @@
 
 	hexOut(237, 144, PAL_FORGRND, WDStartPos, 2);
 	hexOut(237, 158, PAL_FORGRND, WDStopPos,  2);
+}
+
+void setWavRenderFrequency(int32_t freq)
+{
+	WDFrequency = CLAMP(freq, MIN_WAV_RENDER_FREQ, MAX_WAV_RENDER_FREQ);
+	if (ui.wavRendererShown)
+		updateWavRenderer();
+}
+
+void setWavRenderBitDepth(uint8_t bitDepth)
+{
+	if (bitDepth == 16)
+		WDBitDepth = 16;
+	else if (bitDepth == 32)
+		WDBitDepth = 32;
+
+	if (ui.wavRendererShown)
+		updateWavRenderer();
 }
 
 void updateWavRendererSettings(void) // called when changing config.boostLevel
--- a/src/ft2_wav_renderer.h
+++ b/src/ft2_wav_renderer.h
@@ -17,6 +17,8 @@
 
 #define MAX_WAV_RENDER_SAMPLES_PER_TICK (((MAX_WAV_RENDER_FREQ * 5) / 2) / MIN_BPM)
 
+void setWavRenderFrequency(int32_t freq);
+void setWavRenderBitDepth(uint8_t bitDepth);
 void updateWavRendererSettings(void);
 void drawWavRenderer(void);
 void showWavRenderer(void);