Skip to content

Commit

Permalink
change all INT16 mixing/intermediate clamping to floats
Browse files Browse the repository at this point in the history
also fixes 3 bugs:
1) mpeg right channel volume was always using the left channel volume, too
2) too high MusicVolume setting was not clamped to 0..200
3) too high SoundVolume setting was not clamped to 0..200
  • Loading branch information
toxieainc authored and trzy committed Nov 6, 2022
1 parent 121f81c commit 4c727ab
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 205 deletions.
8 changes: 4 additions & 4 deletions Src/Inputs/Input.cpp
Expand Up @@ -91,7 +91,7 @@ const char* CInput::GetInputGroup()
case Game::INPUT_JOYSTICK1: // Fall through to below
case Game::INPUT_JOYSTICK2: return "4-Way Joysticks";
case Game::INPUT_FIGHTING: return "Fighting Game Buttons";
case Game::INPUT_SPIKEOUT: return "Spikeout Buttons";
case Game::INPUT_SPIKEOUT: return "Spikeout Buttons";
case Game::INPUT_SOCCER: return "Virtua Striker Buttons";
case Game::INPUT_VEHICLE: return "Racing Game Steering Controls";
case Game::INPUT_SHIFT4: return "Racing Game Gear 4-Way Shift";
Expand All @@ -108,8 +108,8 @@ const char* CInput::GetInputGroup()
case Game::INPUT_ANALOG_GUN2: return "Analog Guns";
case Game::INPUT_SKI: return "Ski Controls";
case Game::INPUT_MAGTRUCK: return "Magical Truck Controls";
case Game::INPUT_FISHING: return "Fishing Controls";
default: return "Misc";
case Game::INPUT_FISHING: return "Fishing Controls";
default: return "Misc";
}
}

Expand Down Expand Up @@ -138,7 +138,7 @@ void CInput::AppendMapping(const char *mapping)
else
{
// Otherwise, append to mapping string and recreate source from new mapping string
int size = MAX_MAPPING_LENGTH - strlen(m_mapping);
size_t size = MAX_MAPPING_LENGTH - strlen(m_mapping);
strncat(m_mapping, ",", size--);
strncat(m_mapping, mapping, size);
CreateSource();
Expand Down
63 changes: 20 additions & 43 deletions Src/Model3/DSB.cpp
Expand Up @@ -125,52 +125,31 @@ void CDSBResampler::Reset(void)
pFrac = 1<<8; // previous sample (1.0->0 as x moves p->n)
}

// Mixes 16-bit samples (sign extended in a and b)
static inline INT16 MixAndClip(INT32 a, INT32 b)
{
a += b;
if (a > 32767)
a = 32767;
else if (a < -32768)
a = -32768;
return (INT16) a;
}

// Mixes audio and returns number of samples copied back to start of buffer (ie. offset at which new samples should be written)
int CDSBResampler::UpSampleAndMix(INT16 *outL, INT16 *outR, INT16 *inL, INT16 *inR, UINT8 volumeL, UINT8 volumeR, int sizeOut, int sizeIn, int outRate, int inRate)
int CDSBResampler::UpSampleAndMix(float *outL, float *outR, INT16 *inL, INT16 *inR, UINT8 volumeL, UINT8 volumeR, int sizeOut, int sizeIn, int outRate, int inRate)
{
int delta = (inRate<<8)/outRate; // (1/fout)/(1/fin)=fin/fout, 24.8 fixed point
int outIdx = 0;
int inIdx = 0;
INT32 leftSample, rightSample, leftSoundSample, rightSoundSample;
INT32 v[2], musicVol;
float v[2], musicVol;

// Obtain program volume settings and convert to 24.8 fixed point (0-200 -> 0x00-0x200)
musicVol = m_config["MusicVolume"].ValueAs<int>();
musicVol = (INT32) ((float) 0x100 * (float) musicVol / 100.0f);
// Obtain program volume settings
musicVol = (float)std::max(0,std::min(200,m_config["MusicVolume"].ValueAs<int>()));
musicVol = musicVol * (float) (1.0 / 100.0);

// Scale volume from 0x00-0xFF -> 0x00-0x100 (24.8 fixed point)
v[0] = (INT16) ((float) 0x100 * (float) volumeL / 255.0f);
v[1] = (INT16) ((float) 0x100 * (float) volumeR / 255.0f);
v[0] = musicVol * (float) volumeL * (float) (1.0 / (255.0*256.0)); // 256 is there to correct for fixed point interpolation below
v[1] = musicVol * (float) volumeR * (float) (1.0 / (255.0*256.0));

// Up-sample and mix!
while (outIdx < sizeOut)
{
// nFrac, pFrac will never exceed 1.0 (0x100) (only true if delta does not exceed 1)
leftSample = ((int)inL[inIdx]*pFrac+(int)inL[inIdx+1]*nFrac) >> 8; // left channel
rightSample = ((int)inR[inIdx]*pFrac+(int)inR[inIdx+1]*nFrac) >> 8; // right channel

// Apply DSB volume and then overall music volume setting
leftSample = (leftSample*v[0]*musicVol) >> 16; // multiplied by two 24.8 numbers, shift back by 16
rightSample = (rightSample*v[0]*musicVol) >> 16;
INT32 leftSample = (int)inL[inIdx]*pFrac+(int)inL[inIdx+1]*nFrac; // left channel
INT32 rightSample = (int)inR[inIdx]*pFrac+(int)inR[inIdx+1]*nFrac; // right channel

// Apply sound volume setting
leftSoundSample = outL[outIdx];
rightSoundSample = outR[outIdx];

// Mix and output
outL[outIdx] = MixAndClip(leftSoundSample, leftSample);
outR[outIdx] = MixAndClip(rightSoundSample, rightSample);
// Apply DSB volume+overall music volume setting, and mix into output
outL[outIdx] += (float)leftSample * v[0];
outR[outIdx] += (float)rightSample * v[1];
outIdx++;

// Time step
Expand Down Expand Up @@ -422,11 +401,8 @@ void CDSB1::SendCommand(UINT8 data)
#endif
}

void CDSB1::RunFrame(INT16 *audioL, INT16 *audioR)
void CDSB1::RunFrame(float *audioL, float *audioR)
{
int cycles;
UINT8 v;

if (!m_config["EmulateDSB"].ValueAs<bool>())
{
// DSB code applies SCSP volume, too, so we must still mix
Expand All @@ -436,6 +412,7 @@ void CDSB1::RunFrame(INT16 *audioL, INT16 *audioR)
return;
}

int cycles;
// While FIFO not empty, fire interrupts, run for up to one frame
for (cycles = (4000000/60); (cycles > 0) && (fifoIdxR != fifoIdxW); )
{
Expand All @@ -450,7 +427,7 @@ void CDSB1::RunFrame(INT16 *audioL, INT16 *audioR)
//printf("VOLUME=%02X STEREO=%02X\n", volume, stereo);

// Convert volume from 0x00-0x7F -> 0x00-0xFF
v = (UINT8) ((float) 255.0f * (float) volume /127.0f);
UINT8 v = (UINT8) ((float) volume * (float)(255.0/127.0));

// Decode MPEG for this frame
MpegDec::DecodeAudio(&mpegL[retainedSamples], &mpegR[retainedSamples], 32000 / 60 - retainedSamples + 2);
Expand Down Expand Up @@ -991,14 +968,14 @@ void CDSB2::SendCommand(UINT8 data)
}


void CDSB2::RunFrame(INT16 *audioL, INT16 *audioR)
void CDSB2::RunFrame(float *audioL, float *audioR)
{
if (!m_config["EmulateDSB"].ValueAs<bool>())
{
// DSB code applies SCSP volume, too, so we must still mix
memset(mpegL, 0, (32000 / 60 + 2) * sizeof(INT16));
memset(mpegR, 0, (32000 / 60 + 2) * sizeof(INT16));
retainedSamples = Resampler.UpSampleAndMix(audioL, audioR, mpegL, mpegR, volume[0], volume[1], NUM_SAMPLES_PER_FRAME, 32000 / 60 + 2, 44100, 32000);
memset(mpegL, 0, (32000/60+2) * sizeof(INT16));
memset(mpegR, 0, (32000/60+2) * sizeof(INT16));
retainedSamples = Resampler.UpSampleAndMix(audioL, audioR, mpegL, mpegR, 0, 0, NUM_SAMPLES_PER_FRAME, 32000/60+2, 44100, 32000);
return;
}

Expand Down Expand Up @@ -1069,7 +1046,7 @@ void CDSB2::RunFrame(INT16 *audioL, INT16 *audioR)
break;
}

retainedSamples = Resampler.UpSampleAndMix(audioL, audioR, leftChannelSource, rightChannelSource, volL, volR, NUM_SAMPLES_PER_FRAME, 32000 / 60 + 2, 44100, 32000);
retainedSamples = Resampler.UpSampleAndMix(audioL, audioR, leftChannelSource, rightChannelSource, volL, volR, NUM_SAMPLES_PER_FRAME, 32000/60+2, 44100, 32000);
}

void CDSB2::Reset(void)
Expand Down
8 changes: 4 additions & 4 deletions Src/Model3/DSB.h
Expand Up @@ -71,7 +71,7 @@
class CDSBResampler
{
public:
int UpSampleAndMix(INT16 *outL, INT16 *outR, INT16 *inL, INT16 *inR, UINT8 volumeL, UINT8 volumeR, int sizeOut, int sizeIn, int outRate, int inRate);
int UpSampleAndMix(float *outL, float *outR, INT16 *inL, INT16 *inR, UINT8 volumeL, UINT8 volumeR, int sizeOut, int sizeIn, int outRate, int inRate);
void Reset(void);
CDSBResampler(const Util::Config::Node &config)
: m_config(config)
Expand Down Expand Up @@ -114,7 +114,7 @@ class CDSB: public IBus
* audioL Left audio channel, one frame (44 KHz, 1/60th second).
* audioR Right audio channel.
*/
virtual void RunFrame(INT16 *audioL, INT16 *audioR) = 0;
virtual void RunFrame(float *audioL, float *audioR) = 0;

/*
* Reset(void):
Expand Down Expand Up @@ -187,7 +187,7 @@ class CDSB1: public CDSB

// DSB interface (see CDSB definition)
void SendCommand(UINT8 data);
void RunFrame(INT16 *audioL, INT16 *audioR);
void RunFrame(float *audioL, float *audioR);
void Reset(void);
void SaveState(CBlockFile *StateFile);
void LoadState(CBlockFile *StateFile);
Expand Down Expand Up @@ -264,7 +264,7 @@ class CDSB2: public CDSB

// DSB interface (see definition of CDSB)
void SendCommand(UINT8 data);
void RunFrame(INT16 *audioL, INT16 *audioR);
void RunFrame(float *audioL, float *audioR);
void Reset(void);
void SaveState(CBlockFile *StateFile);
void LoadState(CBlockFile *StateFile);
Expand Down
50 changes: 33 additions & 17 deletions Src/Model3/SoundBoard.cpp
Expand Up @@ -70,11 +70,11 @@ static FILE *soundFP;
// Offsets of memory regions within sound board's pool
#define OFFSET_RAM1 0 // 1 MB SCSP1 RAM
#define OFFSET_RAM2 0x100000 // 1 MB SCSP2 RAM
#define LENGTH_CHANNEL_BUFFER (sizeof(INT16)*NUM_SAMPLES_PER_FRAME) // 1470 bytes (16 bits x 44.1 KHz x 1/60th second)
#define OFFSET_AUDIO_FRONTLEFT 0x200000 // 1470 bytes (16 bits, 44.1 KHz, 1/60th second) left audio channel
#define OFFSET_AUDIO_FRONTRIGHT (OFFSET_AUDIO_FRONTLEFT + LENGTH_CHANNEL_BUFFER) // 1470 bytes right audio channel
#define OFFSET_AUDIO_REARLEFT (OFFSET_AUDIO_FRONTRIGHT + LENGTH_CHANNEL_BUFFER) // 1470 bytes (16 bits, 44.1 KHz, 1/60th second) left audio channel
#define OFFSET_AUDIO_REARRIGHT (OFFSET_AUDIO_REARLEFT + LENGTH_CHANNEL_BUFFER) // 1470 bytes right audio channel
#define LENGTH_CHANNEL_BUFFER (sizeof(float)*NUM_SAMPLES_PER_FRAME) // 2940 bytes (32 bits x 44.1 KHz x 1/60th second)
#define OFFSET_AUDIO_FRONTLEFT 0x200000 // 2940 bytes (32 bits, 44.1 KHz, 1/60th second) left audio channel
#define OFFSET_AUDIO_FRONTRIGHT (OFFSET_AUDIO_FRONTLEFT + LENGTH_CHANNEL_BUFFER) // 2940 bytes right audio channel
#define OFFSET_AUDIO_REARLEFT (OFFSET_AUDIO_FRONTRIGHT + LENGTH_CHANNEL_BUFFER) // 2940 bytes (32 bits, 44.1 KHz, 1/60th second) left audio channel
#define OFFSET_AUDIO_REARRIGHT (OFFSET_AUDIO_REARLEFT + LENGTH_CHANNEL_BUFFER) // 2940 bytes right audio channel

#define MEMORY_POOL_SIZE (0x100000 + 0x100000 + 4*LENGTH_CHANNEL_BUFFER)

Expand Down Expand Up @@ -351,6 +351,18 @@ void CSoundBoard::WriteMIDIPort(UINT8 data)
DSB->SendCommand(data);
}

static INT16 ClampINT16(float x)
{
INT32 xi = (INT32)x;
if (xi > INT16_MAX) {
xi = INT16_MAX;
}
if (xi < INT16_MIN) {
xi = INT16_MIN;
}
return (INT16)xi;
}

bool CSoundBoard::RunFrame(void)
{
// Run sound board first to generate SCSP audio
Expand All @@ -369,15 +381,15 @@ bool CSoundBoard::RunFrame(void)
}

// Compute sound volume as
INT32 soundVol = m_config["SoundVolume"].ValueAs<int>();
soundVol = (INT32)((float)0x100 * (float)soundVol / 100.0f);
float soundVol = (float)std::max(0,std::min(200,m_config["SoundVolume"].ValueAs<int>()));
soundVol = soundVol * (float)(1.0 / 100.0);

// Apply sound volume setting to SCSP channels only
for (int i = 0; i < NUM_SAMPLES_PER_FRAME; i++) {
audioFL[i] = (audioFL[i]*soundVol) >> 8;
audioFR[i] = (audioFR[i]*soundVol) >> 8;
audioRL[i] = (audioRL[i]*soundVol) >> 8;
audioRR[i] = (audioRR[i]*soundVol) >> 8;
audioFL[i] *= soundVol;
audioFR[i] *= soundVol;
audioRL[i] *= soundVol;
audioRR[i] *= soundVol;
}

// Run DSB and mix with existing audio, apply music volume
Expand All @@ -399,9 +411,13 @@ bool CSoundBoard::RunFrame(void)
INT16 s;
for (int i = 0; i < NUM_SAMPLES_PER_FRAME; i++)
{
s = audioL[i];
s = ClampINT16(audioFL[i]);
fwrite(&s, sizeof(INT16), 1, soundFP); // left channel
s = ClampINT16(audioFR[i]);
fwrite(&s, sizeof(INT16), 1, soundFP); // right channel
s = ClampINT16(audioRL[i]);
fwrite(&s, sizeof(INT16), 1, soundFP); // left channel
s = audioR[i];
s = ClampINT16(audioRR[i]);
fwrite(&s, sizeof(INT16), 1, soundFP); // right channel
}
#endif // SUPERMODEL_LOG_AUDIO
Expand Down Expand Up @@ -496,10 +512,10 @@ bool CSoundBoard::Init(const UINT8 *soundROMPtr, const UINT8 *sampleROMPtr)
// Set up memory pointers
ram1 = &memoryPool[OFFSET_RAM1];
ram2 = &memoryPool[OFFSET_RAM2];
audioFL = (INT16*)&memoryPool[OFFSET_AUDIO_FRONTLEFT];
audioFR = (INT16*)&memoryPool[OFFSET_AUDIO_FRONTRIGHT];
audioRL = (INT16*)&memoryPool[OFFSET_AUDIO_REARLEFT];
audioRR = (INT16*)&memoryPool[OFFSET_AUDIO_REARRIGHT];
audioFL = (float*)&memoryPool[OFFSET_AUDIO_FRONTLEFT];
audioFR = (float*)&memoryPool[OFFSET_AUDIO_FRONTRIGHT];
audioRL = (float*)&memoryPool[OFFSET_AUDIO_REARLEFT];
audioRR = (float*)&memoryPool[OFFSET_AUDIO_REARRIGHT];

// Initialize 68K core
M68KSetContext(&M68K);
Expand Down
4 changes: 2 additions & 2 deletions Src/Model3/SoundBoard.h
Expand Up @@ -203,8 +203,8 @@ class CSoundBoard: public IBus
UINT8 ctrlReg; // control register: ROM banking

// Audio
INT16* audioFL, * audioFR; // left and right front audio channels (1/60th second, 44.1 KHz)
INT16* audioRL, * audioRR; // left and right rear audio channels (1/60th second, 44.1 KHz)
float* audioFL, * audioFR; // left and right front audio channels (1/60th second, 44.1 KHz)
float* audioRL, * audioRR; // left and right rear audio channels (1/60th second, 44.1 KHz)
};


Expand Down
2 changes: 1 addition & 1 deletion Src/OSD/Audio.h
Expand Up @@ -51,7 +51,7 @@ extern bool OpenAudio(const Util::Config::Node& config);
*
* Sends a chunk of two-channel audio with the given number of samples to the audio system.
*/
extern bool OutputAudio(unsigned numSamples, INT16* leftFrontBuffer, INT16* rightFrontBuffer, INT16* leftRearBuffer, INT16* rightRearBuffer, bool flipStereo);
extern bool OutputAudio(unsigned numSamples, const float* leftFrontBuffer, const float* rightFrontBuffer, const float* leftRearBuffer, const float* rightRearBuffer, bool flipStereo);

/*
* CloseAudio()
Expand Down

0 comments on commit 4c727ab

Please sign in to comment.