Skip to content

Commit c55d240

Browse files
authoredJan 5, 2022
Fix for issue #474, and a few other bugs in MODGenerator (#478)
Fixes #474 This bug was already present in stellaplayer. Obviously "effectNumber" must be checked, because "effectParameterX" just holds the "upper nibble" of effectParameter - 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
·
2.1.01.9.7
1 parent fe7a1f7 commit c55d240

File tree

2 files changed

+42
-17
lines changed

2 files changed

+42
-17
lines changed
 

‎src/AudioGeneratorMOD.cpp‎

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,11 @@ bool AudioGeneratorMOD::LoadHeader()
232232
Mod.numberOfChannels = (temp[0] - '0') * 10 + temp[1] - '0';
233233
else
234234
Mod.numberOfChannels = 4;
235+
236+
if (Mod.numberOfChannels > CHANNELS) {
237+
audioLogger->printf("\nAudioGeneratorMOD::LoadHeader abort - too many channels (configured: %d, needed: %d)\n", CHANNELS, Mod.numberOfChannels);
238+
return(false);
239+
}
235240

236241
return true;
237242
}
@@ -417,7 +422,7 @@ bool AudioGeneratorMOD::ProcessRow()
417422

418423
if (sampleNumber) {
419424
Player.lastSampleNumber[channel] = sampleNumber - 1;
420-
if (!(effectParameter == 0xE && effectParameterX == NOTEDELAY))
425+
if (!(effectNumber == 0xE && effectParameterX == NOTEDELAY))
421426
Player.volume[channel] = Mod.samples[Player.lastSampleNumber[channel]].volume;
422427
}
423428

@@ -735,13 +740,14 @@ bool AudioGeneratorMOD::RunPlayer()
735740

736741
void AudioGeneratorMOD::GetSample(int16_t sample[2])
737742
{
738-
int16_t sumL;
739-
int16_t sumR;
743+
int32_t sumL;
744+
int32_t sumR;
740745
uint8_t channel;
741746
uint32_t samplePointer;
742747
int8_t current;
743748
int8_t next;
744749
int16_t out;
750+
int32_t out32;
745751

746752
if (!running) return;
747753

@@ -779,7 +785,7 @@ void AudioGeneratorMOD::GetSample(int16_t sample[2])
779785
samplePointer >= FatBuffer.samplePointer[channel] + fatBufferSize - 1 ||
780786
Mixer.channelSampleNumber[channel] != FatBuffer.channelSampleNumber[channel]) {
781787

782-
uint16_t toRead = Mixer.sampleEnd[Mixer.channelSampleNumber[channel]] - samplePointer + 1;
788+
uint32_t toRead = Mixer.sampleEnd[Mixer.channelSampleNumber[channel]] - samplePointer + 1;
783789
if (toRead > fatBufferSize) toRead = fatBufferSize;
784790

785791
if (!file->seek(samplePointer, SEEK_SET)) {
@@ -800,27 +806,46 @@ void AudioGeneratorMOD::GetSample(int16_t sample[2])
800806

801807
out = current;
802808

803-
// Integer linear interpolation
809+
// Integer linear interpolation - only works correctly in 16bit
804810
out += (next - current) * (Mixer.channelSampleOffset[channel] & ((1 << FIXED_DIVIDER) - 1)) >> FIXED_DIVIDER;
805811

806812
// Upscale to BITDEPTH
807-
out <<= BITDEPTH - 8;
813+
out32 = (int32_t)out << (BITDEPTH - 8);
808814

809815
// Channel volume
810-
out = out * Mixer.channelVolume[channel] >> 6;
816+
out32 = out32 * Mixer.channelVolume[channel] >> 6;
811817

812818
// Channel panning
813-
sumL += out * min(128 - Mixer.channelPanning[channel], 64) >> 6;
814-
sumR += out * min(Mixer.channelPanning[channel], 64) >> 6;
819+
sumL += out32 * min(128 - Mixer.channelPanning[channel], 64) >> 6;
820+
sumR += out32 * min(Mixer.channelPanning[channel], 64) >> 6;
821+
}
822+
823+
// Downscale to BITDEPTH - a bit faster because the compiler can replaced division by constants with proper "right shift" + correct handling of sign bit
824+
if (Mod.numberOfChannels <= 4) {
825+
// up to 4 channels
826+
sumL /= 4;
827+
sumR /= 4;
828+
} else {
829+
if (Mod.numberOfChannels <= 6) {
830+
// 5 or 6 channels - pre-multiply be 1.5, then divide by 8 -> same as division by 6
831+
sumL = (sumL + (sumL/2)) / 8;
832+
sumR = (sumR + (sumR/2)) / 8;
833+
} else {
834+
// 7,8, or more channels
835+
sumL /= 8;
836+
sumR /= 8;
837+
}
815838
}
816839

817-
// Downscale to BITDEPTH
818-
sumL /= Mod.numberOfChannels;
819-
sumR /= Mod.numberOfChannels;
820-
821-
// Fill the sound buffer with unsigned values
822-
sample[AudioOutput::LEFTCHANNEL] = sumL + (1 << (BITDEPTH - 1));
823-
sample[AudioOutput::RIGHTCHANNEL] = sumR + (1 << (BITDEPTH - 1));
840+
// clip samples to 16bit (with saturation in case of overflow)
841+
if(sumL <= INT16_MIN) sumL = INT16_MIN;
842+
else if (sumL >= INT16_MAX) sumL = INT16_MAX;
843+
if(sumR <= INT16_MIN) sumR = INT16_MIN;
844+
else if (sumR >= INT16_MAX) sumR = INT16_MAX;
845+
846+
// Fill the sound buffer with signed values
847+
sample[AudioOutput::LEFTCHANNEL] = sumL;
848+
sample[AudioOutput::RIGHTCHANNEL] = sumR;
824849
}
825850

826851
bool AudioGeneratorMOD::LoadMOD()

‎src/AudioOutputI2S.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ bool AudioOutputI2S::ConsumeSample(int16_t sample[2])
300300
{
301301
int16_t l = Amplify(ms[LEFTCHANNEL]) + 0x8000;
302302
int16_t r = Amplify(ms[RIGHTCHANNEL]) + 0x8000;
303-
s32 = (r << 16) | (l & 0xffff);
303+
s32 = ((r & 0xffff) << 16) | (l & 0xffff);
304304
}
305305
else
306306
{

0 commit comments

Comments
 (0)
Please sign in to comment.