ft2-clone

Fasttracker 2 clone
Log | Files | Refs | README | LICENSE

commit 95112aa96abb49f3cd58750e36897236f834e4b7
parent 60a3dd36bb82179a0768a4ebeb4f7c632cdd59bf
Author: Olav Sørensen <olav.sorensen@live.no>
Date:   Sun, 23 Aug 2020 20:16:01 +0200

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

Diffstat:
Msrc/ft2_audio.c | 90++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/ft2_audio.h | 2+-
Msrc/ft2_header.h | 2+-
Msrc/ft2_replayer.c | 9++++-----
Msrc/ft2_wav_renderer.c | 22++++++++++++++++++----
Msrc/ft2_wav_renderer.h | 2++
6 files changed, 74 insertions(+), 53 deletions(-)

diff --git 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 @@ bool setNewAudioSettings(void) // only call this from the main input/video threa } 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 mix_UpdateChannelVolPanFrq(void) 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 @@ static void sendSamples16BitStereo(uint8_t *stream, uint32_t sampleBlockLength, 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 @@ static void sendSamples16BitMultiChan(uint8_t *stream, uint32_t sampleBlockLengt 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 sendSamples16BitMultiChan(uint8_t *stream, uint32_t sampleBlockLengt 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 sendSamples16BitDitherStereo(uint8_t *stream, uint32_t sampleBlockLe 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 @@ static void sendSamples32BitStereo(uint8_t *stream, uint32_t sampleBlockLength, 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 @@ static void sendSamples32BitMultiChan(uint8_t *stream, uint32_t sampleBlockLengt 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; @@ -1248,6 +1251,9 @@ bool setupAudio(bool showErrorMsg) updateSendAudSamplesRoutine(false); audio.resetSyncTickTimeFlag = true; + setWavRenderFrequency(audio.freq); + setWavRenderBitDepth((config.specialFlags & BITDEPTH_32) ? 32 : 16); + return true; } diff --git a/src/ft2_audio.h b/src/ft2_audio.h @@ -117,7 +117,7 @@ chSyncData_t *chQueuePeek(void); 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); diff --git 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... diff --git a/src/ft2_replayer.c b/src/ft2_replayer.c @@ -357,8 +357,8 @@ void calcReplayRate(int32_t audioFreq) 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 @@ void calcReplayRate(int32_t audioFreq) { 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 @@ void calcReplayRate(int32_t audioFreq) 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 } } diff --git a/src/ft2_wav_renderer.c b/src/ft2_wav_renderer.c @@ -39,11 +39,7 @@ typedef struct wavHeader_t 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) @@ -67,6 +63,24 @@ static void updateWavRenderer(void) 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 { WDAmp = config.boostLevel; diff --git 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);