From 7a82ba2ab3401ddb6c350a0a26b9faa23a816468 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sun, 9 Jan 2022 17:39:34 +0100 Subject: [PATCH] AudiogeneratorMOD: use full 16bit with slightly better accuracy (#479) * Fix a tricky bug that causes delays in playback ... this bug was already present in stellaplayer. Obviously "effectNumber" must be checked, because "effectParameterX" just holds the "upper nibble" of effectParameter * fix for issue #474 - do channel mixing in 32bit, to avoid noise from over/underflow - write audio output as "signed int" (not unsigned) - add int16 saturation check ("clipping") * avoid crash when MOD file has to many CHANNELS - avoid guru meditation, by logging an error and refusing playback in case MOD.numberOfChannels > CHANNELS - correct small typo * internal DAC: avoid possible overflow in conversion int16 -> uint16 * update constants .. we can do 16bit and 8 channels, so let's do it ;-) This adds some debugging code to better understand what is going on inside the mixer code (AudioGeneratorMOD::GetSample). And it also prints out some usefull information from the MOD file. Only active when do_MIXER_DEBUG is defined. * MOD generator: 12 bits of "real" resolution (instead of 10) With this change, we gain 2 additional bits of "real resolution" from the sample interpolation step. Still need some testing to be sure that nothing get "lost" at the same time. * limit to 4 channels on ESP8266 As discussed in https://github.com/earlephilhower/ESP8266Audio/pull/479#issuecomment-1007708703 --- src/AudioGeneratorMOD.cpp | 23 +++++++++++++++++------ src/AudioGeneratorMOD.h | 10 ++++++++-- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/AudioGeneratorMOD.cpp b/src/AudioGeneratorMOD.cpp index 588ac51e..6a3a07c3 100644 --- a/src/AudioGeneratorMOD.cpp +++ b/src/AudioGeneratorMOD.cpp @@ -69,6 +69,11 @@ bool AudioGeneratorMOD::stop() free(FatBuffer.channels[i]); FatBuffer.channels[i] = NULL; } + + if(running && (file != NULL) && (file->isOpen() == true)) { + output->flush(); //flush I2S output buffer, if the player was actually running before. + } + if (file) file->close(); running = false; output->stop(); @@ -803,14 +808,20 @@ void AudioGeneratorMOD::GetSample(int16_t sample[2]) current = FatBuffer.channels[channel][(samplePointer - FatBuffer.samplePointer[channel]) /*& (FATBUFFERSIZE - 1)*/]; next = FatBuffer.channels[channel][(samplePointer + 1 - FatBuffer.samplePointer[channel]) /*& (FATBUFFERSIZE - 1)*/]; - - out = current; + + // preserve a few more bits from sample interpolation, by upscaling input values. + // This does (slightly) reduce quantization noise in higher frequencies, typically above 8kHz. + // Actually we could could even gain more bits, I was just not sure if more bits would cause overflows in other conputations. + int16_t current16 = (int16_t) current << 2; + int16_t next16 = (int16_t) next << 2; + + out = current16; // Integer linear interpolation - only works correctly in 16bit - out += (next - current) * (Mixer.channelSampleOffset[channel] & ((1 << FIXED_DIVIDER) - 1)) >> FIXED_DIVIDER; + out += (next16 - current16) * (Mixer.channelSampleOffset[channel] & ((1 << FIXED_DIVIDER) - 1)) >> FIXED_DIVIDER; - // Upscale to BITDEPTH - out32 = (int32_t)out << (BITDEPTH - 8); + // Upscale to BITDEPTH, considering the we already gained two bits in the previous step + out32 = (int32_t)out << (BITDEPTH - 10); // Channel volume out32 = out32 * Mixer.channelVolume[channel] >> 6; @@ -819,7 +830,7 @@ void AudioGeneratorMOD::GetSample(int16_t sample[2]) sumL += out32 * min(128 - Mixer.channelPanning[channel], 64) >> 6; sumR += out32 * min(Mixer.channelPanning[channel], 64) >> 6; } - + // Downscale to BITDEPTH - a bit faster because the compiler can replaced division by constants with proper "right shift" + correct handling of sign bit if (Mod.numberOfChannels <= 4) { // up to 4 channels diff --git a/src/AudioGeneratorMOD.h b/src/AudioGeneratorMOD.h index 06003775..e2b5b27a 100644 --- a/src/AudioGeneratorMOD.h +++ b/src/AudioGeneratorMOD.h @@ -53,7 +53,7 @@ class AudioGeneratorMOD : public AudioGenerator protected: int mixerTick; - enum {BITDEPTH = 15}; + enum {BITDEPTH = 16}; int sampleRate; int fatBufferSize; //(6*1024) // File system buffers per-CHANNEL (i.e. total mem required is 4 * FATBUFFERSIZE) enum {FIXED_DIVIDER = 10}; // Fixed-point mantissa used for integer arithmetic @@ -64,8 +64,14 @@ class AudioGeneratorMOD : public AudioGenerator // Hz = 7159091 / (amigaPeriod * 2) for NTSC int AMIGA; void UpdateAmiga() { AMIGA = ((usePAL?7159091:7093789) / 2 / sampleRate << FIXED_DIVIDER); } - + +#ifdef ESP8266 // Not sure if C3/C2 have RAM constraints, maybe add them here? + // support max 4 channels enum {ROWS = 64, SAMPLES = 31, CHANNELS = 4, NONOTE = 0xFFFF, NONOTE8 = 0xff }; +#else + // support max 8 channels + enum {ROWS = 64, SAMPLES = 31, CHANNELS = 8, NONOTE = 0xFFFF, NONOTE8 = 0xff }; +#endif typedef struct Sample { uint16_t length;