This commit is contained in:
Ian Curtis 2022-11-07 21:33:08 +00:00
commit 9348fd852d
10 changed files with 164 additions and 205 deletions

View file

@ -91,7 +91,7 @@ const char* CInput::GetInputGroup()
case Game::INPUT_JOYSTICK1: // Fall through to below case Game::INPUT_JOYSTICK1: // Fall through to below
case Game::INPUT_JOYSTICK2: return "4-Way Joysticks"; case Game::INPUT_JOYSTICK2: return "4-Way Joysticks";
case Game::INPUT_FIGHTING: return "Fighting Game Buttons"; 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_SOCCER: return "Virtua Striker Buttons";
case Game::INPUT_VEHICLE: return "Racing Game Steering Controls"; case Game::INPUT_VEHICLE: return "Racing Game Steering Controls";
case Game::INPUT_SHIFT4: return "Racing Game Gear 4-Way Shift"; case Game::INPUT_SHIFT4: return "Racing Game Gear 4-Way Shift";
@ -108,8 +108,8 @@ const char* CInput::GetInputGroup()
case Game::INPUT_ANALOG_GUN2: return "Analog Guns"; case Game::INPUT_ANALOG_GUN2: return "Analog Guns";
case Game::INPUT_SKI: return "Ski Controls"; case Game::INPUT_SKI: return "Ski Controls";
case Game::INPUT_MAGTRUCK: return "Magical Truck Controls"; case Game::INPUT_MAGTRUCK: return "Magical Truck Controls";
case Game::INPUT_FISHING: return "Fishing Controls"; case Game::INPUT_FISHING: return "Fishing Controls";
default: return "Misc"; default: return "Misc";
} }
} }
@ -138,7 +138,7 @@ void CInput::AppendMapping(const char *mapping)
else else
{ {
// Otherwise, append to mapping string and recreate source from new mapping string // 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, ",", size--);
strncat(m_mapping, mapping, size); strncat(m_mapping, mapping, size);
CreateSource(); CreateSource();

View file

@ -125,52 +125,31 @@ void CDSBResampler::Reset(void)
pFrac = 1<<8; // previous sample (1.0->0 as x moves p->n) 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) // 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 delta = (inRate<<8)/outRate; // (1/fout)/(1/fin)=fin/fout, 24.8 fixed point
int outIdx = 0; int outIdx = 0;
int inIdx = 0; int inIdx = 0;
INT32 leftSample, rightSample, leftSoundSample, rightSoundSample; float v[2], musicVol;
INT32 v[2], musicVol;
// Obtain program volume settings and convert to 24.8 fixed point (0-200 -> 0x00-0x200) // Obtain program volume settings
musicVol = m_config["MusicVolume"].ValueAs<int>(); musicVol = (float)std::max(0,std::min(200,m_config["MusicVolume"].ValueAs<int>()));
musicVol = (INT32) ((float) 0x100 * (float) musicVol / 100.0f); musicVol = musicVol * (float) (1.0 / 100.0);
// Scale volume from 0x00-0xFF -> 0x00-0x100 (24.8 fixed point) v[0] = musicVol * (float) volumeL * (float) (1.0 / (255.0*256.0)); // 256 is there to correct for fixed point interpolation below
v[0] = (INT16) ((float) 0x100 * (float) volumeL / 255.0f); v[1] = musicVol * (float) volumeR * (float) (1.0 / (255.0*256.0));
v[1] = (INT16) ((float) 0x100 * (float) volumeR / 255.0f);
// Up-sample and mix! // Up-sample and mix!
while (outIdx < sizeOut) while (outIdx < sizeOut)
{ {
// nFrac, pFrac will never exceed 1.0 (0x100) (only true if delta does not exceed 1) // 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 INT32 leftSample = (int)inL[inIdx]*pFrac+(int)inL[inIdx+1]*nFrac; // left channel
rightSample = ((int)inR[inIdx]*pFrac+(int)inR[inIdx+1]*nFrac) >> 8; // right channel INT32 rightSample = (int)inR[inIdx]*pFrac+(int)inR[inIdx+1]*nFrac; // right channel
// Apply DSB volume and then overall music volume setting // Apply DSB volume+overall music volume setting, and mix into output
leftSample = (leftSample*v[0]*musicVol) >> 16; // multiplied by two 24.8 numbers, shift back by 16 outL[outIdx] += (float)leftSample * v[0];
rightSample = (rightSample*v[0]*musicVol) >> 16; outR[outIdx] += (float)rightSample * v[1];
// Apply sound volume setting
leftSoundSample = outL[outIdx];
rightSoundSample = outR[outIdx];
// Mix and output
outL[outIdx] = MixAndClip(leftSoundSample, leftSample);
outR[outIdx] = MixAndClip(rightSoundSample, rightSample);
outIdx++; outIdx++;
// Time step // Time step
@ -422,11 +401,8 @@ void CDSB1::SendCommand(UINT8 data)
#endif #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>()) if (!m_config["EmulateDSB"].ValueAs<bool>())
{ {
// DSB code applies SCSP volume, too, so we must still mix // DSB code applies SCSP volume, too, so we must still mix
@ -436,6 +412,7 @@ void CDSB1::RunFrame(INT16 *audioL, INT16 *audioR)
return; return;
} }
int cycles;
// While FIFO not empty, fire interrupts, run for up to one frame // While FIFO not empty, fire interrupts, run for up to one frame
for (cycles = (4000000/60); (cycles > 0) && (fifoIdxR != fifoIdxW); ) for (cycles = (4000000/60); (cycles > 0) && (fifoIdxR != fifoIdxW); )
{ {
@ -450,7 +427,7 @@ void CDSB1::RunFrame(INT16 *audioL, INT16 *audioR)
//printf("VOLUME=%02X STEREO=%02X\n", volume, stereo); //printf("VOLUME=%02X STEREO=%02X\n", volume, stereo);
// Convert volume from 0x00-0x7F -> 0x00-0xFF // 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 // Decode MPEG for this frame
MpegDec::DecodeAudio(&mpegL[retainedSamples], &mpegR[retainedSamples], 32000 / 60 - retainedSamples + 2); MpegDec::DecodeAudio(&mpegL[retainedSamples], &mpegR[retainedSamples], 32000 / 60 - retainedSamples + 2);
@ -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>()) if (!m_config["EmulateDSB"].ValueAs<bool>())
{ {
// DSB code applies SCSP volume, too, so we must still mix // DSB code applies SCSP volume, too, so we must still mix
memset(mpegL, 0, (32000 / 60 + 2) * sizeof(INT16)); memset(mpegL, 0, (32000/60+2) * sizeof(INT16));
memset(mpegR, 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); retainedSamples = Resampler.UpSampleAndMix(audioL, audioR, mpegL, mpegR, 0, 0, NUM_SAMPLES_PER_FRAME, 32000/60+2, 44100, 32000);
return; return;
} }
@ -1069,7 +1046,7 @@ void CDSB2::RunFrame(INT16 *audioL, INT16 *audioR)
break; 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) void CDSB2::Reset(void)

View file

@ -71,7 +71,7 @@
class CDSBResampler class CDSBResampler
{ {
public: 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); void Reset(void);
CDSBResampler(const Util::Config::Node &config) CDSBResampler(const Util::Config::Node &config)
: m_config(config) : m_config(config)
@ -114,7 +114,7 @@ public:
* audioL Left audio channel, one frame (44 KHz, 1/60th second). * audioL Left audio channel, one frame (44 KHz, 1/60th second).
* audioR Right audio channel. * audioR Right audio channel.
*/ */
virtual void RunFrame(INT16 *audioL, INT16 *audioR) = 0; virtual void RunFrame(float *audioL, float *audioR) = 0;
/* /*
* Reset(void): * Reset(void):
@ -187,7 +187,7 @@ public:
// DSB interface (see CDSB definition) // DSB interface (see CDSB definition)
void SendCommand(UINT8 data); void SendCommand(UINT8 data);
void RunFrame(INT16 *audioL, INT16 *audioR); void RunFrame(float *audioL, float *audioR);
void Reset(void); void Reset(void);
void SaveState(CBlockFile *StateFile); void SaveState(CBlockFile *StateFile);
void LoadState(CBlockFile *StateFile); void LoadState(CBlockFile *StateFile);
@ -264,7 +264,7 @@ public:
// DSB interface (see definition of CDSB) // DSB interface (see definition of CDSB)
void SendCommand(UINT8 data); void SendCommand(UINT8 data);
void RunFrame(INT16 *audioL, INT16 *audioR); void RunFrame(float *audioL, float *audioR);
void Reset(void); void Reset(void);
void SaveState(CBlockFile *StateFile); void SaveState(CBlockFile *StateFile);
void LoadState(CBlockFile *StateFile); void LoadState(CBlockFile *StateFile);

View file

@ -70,11 +70,11 @@ static FILE *soundFP;
// Offsets of memory regions within sound board's pool // Offsets of memory regions within sound board's pool
#define OFFSET_RAM1 0 // 1 MB SCSP1 RAM #define OFFSET_RAM1 0 // 1 MB SCSP1 RAM
#define OFFSET_RAM2 0x100000 // 1 MB SCSP2 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 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 // 1470 bytes (16 bits, 44.1 KHz, 1/60th second) left audio channel #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) // 1470 bytes right 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) // 1470 bytes (16 bits, 44.1 KHz, 1/60th second) left 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) // 1470 bytes right 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) #define MEMORY_POOL_SIZE (0x100000 + 0x100000 + 4*LENGTH_CHANNEL_BUFFER)
@ -351,6 +351,18 @@ void CSoundBoard::WriteMIDIPort(UINT8 data)
DSB->SendCommand(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) bool CSoundBoard::RunFrame(void)
{ {
// Run sound board first to generate SCSP audio // Run sound board first to generate SCSP audio
@ -369,15 +381,15 @@ bool CSoundBoard::RunFrame(void)
} }
// Compute sound volume as // Compute sound volume as
INT32 soundVol = m_config["SoundVolume"].ValueAs<int>(); float soundVol = (float)std::max(0,std::min(200,m_config["SoundVolume"].ValueAs<int>()));
soundVol = (INT32)((float)0x100 * (float)soundVol / 100.0f); soundVol = soundVol * (float)(1.0 / 100.0);
// Apply sound volume setting to SCSP channels only // Apply sound volume setting to SCSP channels only
for (int i = 0; i < NUM_SAMPLES_PER_FRAME; i++) { for (int i = 0; i < NUM_SAMPLES_PER_FRAME; i++) {
audioFL[i] = (audioFL[i]*soundVol) >> 8; audioFL[i] *= soundVol;
audioFR[i] = (audioFR[i]*soundVol) >> 8; audioFR[i] *= soundVol;
audioRL[i] = (audioRL[i]*soundVol) >> 8; audioRL[i] *= soundVol;
audioRR[i] = (audioRR[i]*soundVol) >> 8; audioRR[i] *= soundVol;
} }
// Run DSB and mix with existing audio, apply music volume // Run DSB and mix with existing audio, apply music volume
@ -399,9 +411,13 @@ bool CSoundBoard::RunFrame(void)
INT16 s; INT16 s;
for (int i = 0; i < NUM_SAMPLES_PER_FRAME; i++) 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 fwrite(&s, sizeof(INT16), 1, soundFP); // left channel
s = audioR[i]; 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 = ClampINT16(audioRR[i]);
fwrite(&s, sizeof(INT16), 1, soundFP); // right channel fwrite(&s, sizeof(INT16), 1, soundFP); // right channel
} }
#endif // SUPERMODEL_LOG_AUDIO #endif // SUPERMODEL_LOG_AUDIO
@ -496,10 +512,10 @@ bool CSoundBoard::Init(const UINT8 *soundROMPtr, const UINT8 *sampleROMPtr)
// Set up memory pointers // Set up memory pointers
ram1 = &memoryPool[OFFSET_RAM1]; ram1 = &memoryPool[OFFSET_RAM1];
ram2 = &memoryPool[OFFSET_RAM2]; ram2 = &memoryPool[OFFSET_RAM2];
audioFL = (INT16*)&memoryPool[OFFSET_AUDIO_FRONTLEFT]; audioFL = (float*)&memoryPool[OFFSET_AUDIO_FRONTLEFT];
audioFR = (INT16*)&memoryPool[OFFSET_AUDIO_FRONTRIGHT]; audioFR = (float*)&memoryPool[OFFSET_AUDIO_FRONTRIGHT];
audioRL = (INT16*)&memoryPool[OFFSET_AUDIO_REARLEFT]; audioRL = (float*)&memoryPool[OFFSET_AUDIO_REARLEFT];
audioRR = (INT16*)&memoryPool[OFFSET_AUDIO_REARRIGHT]; audioRR = (float*)&memoryPool[OFFSET_AUDIO_REARRIGHT];
// Initialize 68K core // Initialize 68K core
M68KSetContext(&M68K); M68KSetContext(&M68K);

View file

@ -203,8 +203,8 @@ private:
UINT8 ctrlReg; // control register: ROM banking UINT8 ctrlReg; // control register: ROM banking
// Audio // Audio
INT16* audioFL, * audioFR; // left and right front audio channels (1/60th second, 44.1 KHz) float* 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* audioRL, * audioRR; // left and right rear audio channels (1/60th second, 44.1 KHz)
}; };

View file

@ -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. * 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() * CloseAudio()

View file

@ -166,6 +166,35 @@ static INT16 MixINT16(INT32 x, INT32 y)
return (INT16)sum; return (INT16)sum;
} }
static INT16 MixINT16(float x, float y)
{
INT32 sum = (INT32)((x + y)*0.5f); //!! dither
if (sum > INT16_MAX) {
sum = INT16_MAX;
}
if (sum < INT16_MIN) {
sum = INT16_MIN;
}
return (INT16)sum;
}
static float MixFloat(float x, float y)
{
return (x + y)*0.5f;
}
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;
}
static void PlayCallback(void* data, Uint8* stream, int len) static void PlayCallback(void* data, Uint8* stream, int len)
{ {
//printf("PlayCallback(%d) [writePos = %u, writeWrapped = %s, playPos = %u, audioBufferSize = %u]\n", //printf("PlayCallback(%d) [writePos = %u, writeWrapped = %s, playPos = %u, audioBufferSize = %u]\n",
@ -271,15 +300,15 @@ static void PlayCallback(void* data, Uint8* stream, int len)
callback(callbackData); callback(callbackData);
} }
static void MixChannels(unsigned numSamples, INT16* leftFrontBuffer, INT16* rightFrontBuffer, INT16* leftRearBuffer, INT16* rightRearBuffer, void* dest, bool flipStereo) static void MixChannels(unsigned numSamples, const float* leftFrontBuffer, const float* rightFrontBuffer, const float* leftRearBuffer, const float* rightRearBuffer, void* dest, bool flipStereo)
{ {
INT16* p = (INT16*)dest; INT16* p = (INT16*)dest;
if (nbHostAudioChannels == 1) { if (nbHostAudioChannels == 1) {
for (unsigned i = 0; i < numSamples; i++) { for (unsigned i = 0; i < numSamples; i++) {
INT16 monovalue = MixINT16( INT16 monovalue = MixINT16(
MixINT16((INT32)(leftFrontBuffer[i] * balanceFactorFrontLeft), (INT32)(rightFrontBuffer[i] * balanceFactorFrontRight)), MixFloat(leftFrontBuffer[i] * balanceFactorFrontLeft,rightFrontBuffer[i] * balanceFactorFrontRight),
MixINT16((INT32)(leftRearBuffer[i] * balanceFactorRearLeft), (INT32)(rightRearBuffer[i] * balanceFactorRearRight))); MixFloat(leftRearBuffer[i] * balanceFactorRearLeft, rightRearBuffer[i] * balanceFactorRearRight));
*p++ = monovalue; *p++ = monovalue;
} }
} else { } else {
@ -295,8 +324,8 @@ static void MixChannels(unsigned numSamples, INT16* leftFrontBuffer, INT16* righ
// Now order channels according to audio type // Now order channels according to audio type
if (nbHostAudioChannels == 2) { if (nbHostAudioChannels == 2) {
for (unsigned i = 0; i < numSamples; i++) { for (unsigned i = 0; i < numSamples; i++) {
INT16 leftvalue = MixINT16((INT32)(leftFrontBuffer[i] * balanceFactorFrontLeft), (INT32)(leftRearBuffer[i] * balanceFactorRearLeft)); INT16 leftvalue = MixINT16(leftFrontBuffer[i] * balanceFactorFrontLeft, leftRearBuffer[i] * balanceFactorRearLeft);
INT16 rightvalue = MixINT16((INT32)(rightFrontBuffer[i]*balanceFactorFrontRight), (INT32)(rightRearBuffer[i]*balanceFactorRearRight)); INT16 rightvalue = MixINT16(rightFrontBuffer[i]*balanceFactorFrontRight, rightRearBuffer[i]*balanceFactorRearRight);
if (flipStereo) // swap left and right channels if (flipStereo) // swap left and right channels
{ {
*p++ = rightvalue; *p++ = rightvalue;
@ -308,15 +337,15 @@ static void MixChannels(unsigned numSamples, INT16* leftFrontBuffer, INT16* righ
} }
} else if (nbHostAudioChannels == 4) { } else if (nbHostAudioChannels == 4) {
for (unsigned i = 0; i < numSamples; i++) { for (unsigned i = 0; i < numSamples; i++) {
INT16 frontLeftValue = (INT16)(leftFrontBuffer[i]*balanceFactorFrontLeft); float frontLeftValue = leftFrontBuffer[i]*balanceFactorFrontLeft;
INT16 frontRightValue = (INT16)(rightFrontBuffer[i]*balanceFactorFrontRight); float frontRightValue = rightFrontBuffer[i]*balanceFactorFrontRight;
INT16 rearLeftValue = (INT16)(leftRearBuffer[i]*balanceFactorRearLeft); float rearLeftValue = leftRearBuffer[i]*balanceFactorRearLeft;
INT16 rearRightValue = (INT16)(rightRearBuffer[i]*balanceFactorRearRight); float rearRightValue = rightRearBuffer[i]*balanceFactorRearRight;
// Check game audio type // Check game audio type
switch (AudioType) { switch (AudioType) {
case Game::MONO: { case Game::MONO: {
INT16 monovalue = MixINT16(MixINT16(frontLeftValue, frontRightValue), MixINT16(rearLeftValue, rearRightValue)); INT16 monovalue = MixINT16(MixFloat(frontLeftValue, frontRightValue), MixFloat(rearLeftValue, rearRightValue));
*p++ = monovalue; *p++ = monovalue;
*p++ = monovalue; *p++ = monovalue;
*p++ = monovalue; *p++ = monovalue;
@ -346,15 +375,15 @@ static void MixChannels(unsigned numSamples, INT16* leftFrontBuffer, INT16* righ
// Normal channels Front Left/Right then Rear Left/Right // Normal channels Front Left/Right then Rear Left/Right
if (flipStereo) // swap left and right channels if (flipStereo) // swap left and right channels
{ {
*p++ = frontRightValue; *p++ = ClampINT16(frontRightValue);
*p++ = frontLeftValue; *p++ = ClampINT16(frontLeftValue);
*p++ = rearRightValue; *p++ = ClampINT16(rearRightValue);
*p++ = rearLeftValue; *p++ = ClampINT16(rearLeftValue);
} else { } else {
*p++ = frontLeftValue; *p++ = ClampINT16(frontLeftValue);
*p++ = frontRightValue; *p++ = ClampINT16(frontRightValue);
*p++ = rearLeftValue; *p++ = ClampINT16(rearLeftValue);
*p++ = rearRightValue; *p++ = ClampINT16(rearRightValue);
} }
} break; } break;
@ -363,15 +392,15 @@ static void MixChannels(unsigned numSamples, INT16* leftFrontBuffer, INT16* righ
// Reversed channels Front/Rear Left then Front/Rear Right // Reversed channels Front/Rear Left then Front/Rear Right
if (flipStereo) // swap left and right channels if (flipStereo) // swap left and right channels
{ {
*p++ = rearRightValue; *p++ = ClampINT16(rearRightValue);
*p++ = rearLeftValue; *p++ = ClampINT16(rearLeftValue);
*p++ = frontRightValue; *p++ = ClampINT16(frontRightValue);
*p++ = frontLeftValue; *p++ = ClampINT16(frontLeftValue);
} else { } else {
*p++ = rearLeftValue; *p++ = ClampINT16(rearLeftValue);
*p++ = rearRightValue; *p++ = ClampINT16(rearRightValue);
*p++ = frontLeftValue; *p++ = ClampINT16(frontLeftValue);
*p++ = frontRightValue; *p++ = ClampINT16(frontRightValue);
} }
break; break;
@ -440,19 +469,11 @@ bool OpenAudio(const Util::Config::Node& config)
break; break;
} }
// Mixer Balance // Mixer Balance
float balancelr = (float)s_config->Get("BalanceLeftRight").ValueAs<float>(); float balancelr = std::max(-100.f, std::min(100.f, s_config->Get("BalanceLeftRight").ValueAs<float>()));
if (balancelr < -100.0f)
balancelr = -100.0f;
else if (balancelr > 100.0f)
balancelr = 100.0f;
balancelr *= 0.01f; balancelr *= 0.01f;
BalanceLeftRight = balancelr; BalanceLeftRight = balancelr;
float balancefr = (float)s_config->Get("BalanceFrontRear").ValueAs<float>(); float balancefr = std::max(-100.f, std::min(100.f, s_config->Get("BalanceFrontRear").ValueAs<float>()));
if (balancefr < -100.0f)
balancefr = -100.0f;
else if (balancefr > 100.0f)
balancefr = 100.0f;
balancefr *= 0.01f; balancefr *= 0.01f;
BalanceFrontRear = balancefr; BalanceFrontRear = balancefr;
@ -462,8 +483,7 @@ bool OpenAudio(const Util::Config::Node& config)
balanceFactorRearRight = (BalanceLeftRight > 0.f ? 1.f - BalanceLeftRight : 1.f) * (BalanceFrontRear > 0 ? 1.f - BalanceFrontRear : 1.f); balanceFactorRearRight = (BalanceLeftRight > 0.f ? 1.f - BalanceLeftRight : 1.f) * (BalanceFrontRear > 0 ? 1.f - BalanceFrontRear : 1.f);
// Set up audio specification // Set up audio specification
SDL_AudioSpec desired; SDL_AudioSpec desired{};
memset(&desired, 0, sizeof(SDL_AudioSpec));
desired.freq = SAMPLE_RATE_M3; desired.freq = SAMPLE_RATE_M3;
// Number of host channels to use (choice limited to 1,2,4) // Number of host channels to use (choice limited to 1,2,4)
desired.channels = nbHostAudioChannels; desired.channels = nbHostAudioChannels;
@ -533,7 +553,7 @@ bool OpenAudio(const Util::Config::Node& config)
return OKAY; return OKAY;
} }
bool OutputAudio(unsigned numSamples, INT16* leftFrontBuffer, INT16* rightFrontBuffer, INT16* leftRearBuffer, INT16* rightRearBuffer, bool flipStereo) bool OutputAudio(unsigned numSamples, const float* leftFrontBuffer, const float* rightFrontBuffer, const float* leftRearBuffer, const float* rightRearBuffer, bool flipStereo)
{ {
//printf("OutputAudio(%u) [writePos = %u, writeWrapped = %s, playPos = %u, audioBufferSize = %u]\n", //printf("OutputAudio(%u) [writePos = %u, writeWrapped = %s, playPos = %u, audioBufferSize = %u]\n",
// numSamples, writePos, (writeWrapped ? "true" : "false"), playPos, audioBufferSize); // numSamples, writePos, (writeWrapped ? "true" : "false"), playPos, audioBufferSize);
@ -559,7 +579,7 @@ bool OutputAudio(unsigned numSamples, INT16* leftFrontBuffer, INT16* rightFrontB
// Get end of current play region (writing must occur past this point) // Get end of current play region (writing must occur past this point)
UINT32 playEndPos = playPos + bytes_per_frame_host; UINT32 playEndPos = playPos + bytes_per_frame_host;
// Undo any wrap-around of the write position that may have occured to create following ordering: playPos < playEndPos < writePos // Undo any wrap-around of the write position that may have occurred to create following ordering: playPos < playEndPos < writePos
if (playEndPos > writePos && writeWrapped) if (playEndPos > writePos && writeWrapped)
writePos += audioBufferSize; writePos += audioBufferSize;
@ -619,9 +639,9 @@ bool OutputAudio(unsigned numSamples, INT16* leftFrontBuffer, INT16* rightFrontB
bufferFull = true; bufferFull = true;
// Discard current chunk of data // Discard current chunk of data
goto Finish;
} }
else
{
src = mixBuffer; src = mixBuffer;
INT8* dst1; INT8* dst1;
INT8* dst2; INT8* dst2;
@ -641,9 +661,9 @@ bool OutputAudio(unsigned numSamples, INT16* leftFrontBuffer, INT16* rightFrontB
{ {
// Otherwise, just copy whole region // Otherwise, just copy whole region
dst1 = audioBuffer + writePos; dst1 = audioBuffer + writePos;
dst2 = 0; dst2 = NULL;
len1 = numBytes; len1 = numBytes;
len2 = 0; len2 = NULL;
} }
// Copy chunk to write position in buffer // Copy chunk to write position in buffer
@ -672,8 +692,8 @@ bool OutputAudio(unsigned numSamples, INT16* leftFrontBuffer, INT16* rightFrontB
writePos -= audioBufferSize; writePos -= audioBufferSize;
writeWrapped = true; writeWrapped = true;
} }
}
Finish:
// Unlock SDL audio callback // Unlock SDL audio callback
SDL_UnlockAudio(); SDL_UnlockAudio();

View file

@ -118,7 +118,7 @@ static bool SetGLGeometry(unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned *
float yRes = float(*yResPtr); float yRes = float(*yResPtr);
if (keepAspectRatio) if (keepAspectRatio)
{ {
float model3Ratio = 496.0f/384.0f; float model3Ratio = 496.0/384.0;
if (yRes < (xRes/model3Ratio)) if (yRes < (xRes/model3Ratio))
xRes = yRes*model3Ratio; xRes = yRes*model3Ratio;
if (xRes < (yRes*model3Ratio)) if (xRes < (yRes*model3Ratio))
@ -154,7 +154,7 @@ static bool SetGLGeometry(unsigned *xOffsetPtr, unsigned *yOffsetPtr, unsigned *
*xResPtr = (unsigned) xRes; *xResPtr = (unsigned) xRes;
*yResPtr = (unsigned) yRes; *yResPtr = (unsigned) yRes;
UINT32 correction = (UINT32)(((yRes / 384.f) * 2) + 0.5f); UINT32 correction = (UINT32)(((yRes / 384.f) * 2.f) + 0.5f);
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
@ -1522,7 +1522,7 @@ static void PrintGameList(const std::string &xml_file, const std::map<std::strin
{ {
const Game &game = v.second; const Game &game = v.second;
printf(" %s", game.name.c_str()); printf(" %s", game.name.c_str());
for (int i = game.name.length(); i < 9; i++) // pad for alignment (no game ID should be more than 9 letters) for (size_t i = game.name.length(); i < 9; i++) // pad for alignment (no game ID should be more than 9 letters)
printf(" "); printf(" ");
if (!game.version.empty()) if (!game.version.empty())
printf(" %s (%s)\n", game.title.c_str(), game.version.c_str()); printf(" %s (%s)\n", game.title.c_str(), game.version.c_str());
@ -1563,9 +1563,9 @@ static Util::Config::Node DefaultConfig()
config.Set("FragmentShader2D", ""); config.Set("FragmentShader2D", "");
// CSoundBoard // CSoundBoard
config.Set("EmulateSound", true); config.Set("EmulateSound", true);
config.Set("Balance", "0"); config.Set("Balance", "0.0");
config.Set("BalanceLeftRight", "0"); config.Set("BalanceLeftRight", "0.0");
config.Set("BalanceFrontRear", "0"); config.Set("BalanceFrontRear", "0.0");
config.Set("NbSoundChannels", "4"); config.Set("NbSoundChannels", "4");
config.Set("SoundFreq", "57.6"); // 60.0f? 57.524160f? config.Set("SoundFreq", "57.6"); // 60.0f? 57.524160f?
// CDSB // CDSB

View file

@ -87,23 +87,19 @@ bool legacySound; // For LegacySound (SCSP DSP) config option.
// These globals control the operation of the SCSP, they are no longer extern and are set through SCSP_SetBuffers(). --Bart // These globals control the operation of the SCSP, they are no longer extern and are set through SCSP_SetBuffers(). --Bart
float SoundClock; // Originally titled SysFPS; seems to be for the sound CPU. static double SoundClock; // Originally titled SysFPS; seems to be for the sound CPU.
const float Freq = 76; static const double Freq = 76;
signed short* bufferfl; static float* bufferfl;
signed short* bufferfr; static float* bufferfr;
signed short* bufferrl; static float* bufferrl;
signed short* bufferrr; static float* bufferrr;
int length; static int length;
int cnts;
signed int* buffertmpfl, * buffertmpfr; // these are allocated inside this file static const double srate=44100;
signed int* buffertmprl, * buffertmprr; // these are allocated inside this file
unsigned int srate=44100;
#define ICLIP16(x) (x<-32768)?-32768:((x>32767)?32767:x) #define ICLIP16(x) (((x)<-32768)?-32768:(((x)>32767)?32767:(x)))
#define ICLIP18(x) (x<-131072)?-131072:((x>131071)?131071:x) #define ICLIP18(x) (((x)<-131072)?-131072:(((x)>131071)?131071:(x)))
@ -740,7 +736,7 @@ bool SCSP_Init(const Util::Config::Node &config, int n)
t=ARTimes[i]; //In ms t=ARTimes[i]; //In ms
if(t!=0.0) if(t!=0.0)
{ {
step=(1023*1000.0)/((float) srate*t); step=(1023*1000.0)/(srate*t);
scale=(double) (1<<EG_SHIFT); scale=(double) (1<<EG_SHIFT);
ARTABLE[i]=(int) (step*scale); ARTABLE[i]=(int) (step*scale);
} }
@ -748,7 +744,7 @@ bool SCSP_Init(const Util::Config::Node &config, int n)
ARTABLE[i]=1024<<EG_SHIFT; ARTABLE[i]=1024<<EG_SHIFT;
t=DRTimes[i]; //In ms t=DRTimes[i]; //In ms
step=(1023*1000.0)/((float) srate*t); step=(1023*1000.0)/(srate*t);
scale=(double) (1<<EG_SHIFT); scale=(double) (1<<EG_SHIFT);
DRTABLE[i]=(int) (step*scale); DRTABLE[i]=(int) (step*scale);
} }
@ -762,34 +758,7 @@ bool SCSP_Init(const Util::Config::Node &config, int n)
#endif #endif
LFO_Init(); LFO_Init();
buffertmpfl = NULL;
buffertmpfr = NULL;
buffertmprl = NULL;
buffertmprr = NULL;
buffertmpfl=(signed int*) malloc(44100*sizeof(signed int));
if (NULL == buffertmpfl)
return ErrorLog("Insufficient memory for internal SCSP buffers.");
buffertmpfr=(signed int*) malloc(44100*sizeof(signed int));
if (NULL == buffertmpfr)
{
free(buffertmpfl);
return ErrorLog("Insufficient memory for internal SCSP buffers.");
}
buffertmprl=(signed int*)malloc(44100*sizeof(signed int));
if (NULL == buffertmprl)
return ErrorLog("Insufficient memory for internal SCSP buffers.");
buffertmprr=(signed int*)malloc(44100*sizeof(signed int));
if (NULL == buffertmprr)
{
free(buffertmprl);
return ErrorLog("Insufficient memory for internal SCSP buffers.");
}
memset(buffertmpfl, 0, 44100*sizeof(signed int));
memset(buffertmpfr, 0, 44100*sizeof(signed int));
memset(buffertmprl, 0, 44100*sizeof(signed int));
memset(buffertmprr, 0, 44100*sizeof(signed int));
SCSPs->data[0x20 / 2] = 0; SCSPs->data[0x20 / 2] = 0;
TimCnt[0] = 0xffff; TimCnt[0] = 0xffff;
TimCnt[1] = 0xffff; TimCnt[1] = 0xffff;
@ -799,10 +768,6 @@ bool SCSP_Init(const Util::Config::Node &config, int n)
MIDILock = CThread::CreateMutex(); MIDILock = CThread::CreateMutex();
if (NULL == MIDILock) if (NULL == MIDILock)
{ {
free(buffertmpfl);
free(buffertmpfr);
free(buffertmprl);
free(buffertmprr);
return ErrorLog("Unable to create MIDI mutex!"); return ErrorLog("Unable to create MIDI mutex!");
} }
@ -1547,7 +1512,7 @@ void SCSP_CpuRunScanline()
void SCSP_DoMasterSamples(int nsamples) void SCSP_DoMasterSamples(int nsamples)
{ {
int slice = (int)(12000000 / (SoundClock*nsamples)); // 68K cycles/sample int slice = (int)(12000000. / (SoundClock*nsamples)); // 68K cycles/sample
static int lastdiff = 0; static int lastdiff = 0;
/* /*
@ -1556,33 +1521,25 @@ void SCSP_DoMasterSamples(int nsamples)
* When one SCSP is fully attenuated, the other's samples will be multiplied * When one SCSP is fully attenuated, the other's samples will be multiplied
* by 2. * by 2.
*/ */
float balance = (float)s_config->Get("Balance").ValueAs<float>(); float balance = std::max(-100.f,std::min(100.f,s_config->Get("Balance").ValueAs<float>()));
if (balance < -100.0f) balance *= 0.01f;
balance = -100.0f;
else if (balance > 100.0f)
balance = 100.0f;
balance /= 100.0f;
float masterBalance = 1.0f + balance; float masterBalance = 1.0f + balance;
float slaveBalance = 1.0f - balance; float slaveBalance = 1.0f - balance;
signed short* buffl, * buffr;
signed short* bufrl, * bufrr;
INT32 sl, s, i; float* buffl = bufferfl;
float* buffr = bufferfr;
buffl = bufferfl; float* bufrl = bufferrl;
buffr = bufferfr; float* bufrr = bufferrr;
bufrl = bufferrl;
bufrr = bufferrr;
/* /*
* Generate samples * Generate samples
*/ */
for (s = 0; s < nsamples; ++s) for (INT32 s = 0; s < nsamples; ++s)
{ {
signed int smpfl = 0, smpfr = 0; signed int smpfl = 0, smpfr = 0;
signed int smprl = 0, smprr = 0; signed int smprl = 0, smprr = 0;
for (sl = 0; sl < 32; ++sl) for (INT32 sl = 0; sl < 32; ++sl)
{ {
#if FM_DELAY #if FM_DELAY
RBUFDST = SCSPs[0].DELAYBUF + SCSPs[0].DELAYPTR; RBUFDST = SCSPs[0].DELAYBUF + SCSPs[0].DELAYPTR;
@ -1596,8 +1553,6 @@ void SCSP_DoMasterSamples(int nsamples)
signed int sample = (int)(masterBalance*(float)SCSP_UpdateSlot(slot)); signed int sample = (int)(masterBalance*(float)SCSP_UpdateSlot(slot));
Enc = ((TL(slot)) << 0x0) | ((IMXL(slot)) << 0xd); Enc = ((TL(slot)) << 0x0) | ((IMXL(slot)) << 0xd);
SCSPDSP_SetSample(&SCSPs[0].DSP, (sample*LPANTABLE[Enc]) >> (SHIFT - 2), ISEL(slot), IMXL(slot)); SCSPDSP_SetSample(&SCSPs[0].DSP, (sample*LPANTABLE[Enc]) >> (SHIFT - 2), ISEL(slot), IMXL(slot));
Enc = ((TL(slot)) << 0x0) | ((DIPAN(slot)) << 0x8) | ((DISDL(slot)) << 0xd); Enc = ((TL(slot)) << 0x0) | ((DIPAN(slot)) << 0x8) | ((DISDL(slot)) << 0xd);
@ -1666,7 +1621,7 @@ void SCSP_DoMasterSamples(int nsamples)
// smpl=0; // smpl=0;
// smpr=0; // smpr=0;
for (i = 0; i < 16; ++i) for (INT32 i = 0; i < 16; ++i)
{ {
_SLOT *slot = SCSPs[0].Slots + i; _SLOT *slot = SCSPs[0].Slots + i;
if (legacySound == true) { if (legacySound == true) {
@ -1718,8 +1673,8 @@ void SCSP_DoMasterSamples(int nsamples)
smpfl = ICLIP16(smpfl >> 2); smpfl = ICLIP16(smpfl >> 2);
smpfr = ICLIP16(smpfr >> 2); smpfr = ICLIP16(smpfr >> 2);
} }
*buffl++ = ICLIP16(smpfl); *buffl++ = (float)smpfl;
*buffr++ = ICLIP16(smpfr); *buffr++ = (float)smpfr;
if (HasSlaveSCSP) if (HasSlaveSCSP)
{ {
@ -1734,8 +1689,8 @@ void SCSP_DoMasterSamples(int nsamples)
smprr = ICLIP16(smprr >> 2); smprr = ICLIP16(smprr >> 2);
} }
} }
*bufrl++ = ICLIP16(smprl); *bufrl++ = (float)smprl;
*bufrr++ = ICLIP16(smprr); *bufrr++ = (float)smprr;
SCSP_TimersAddTicks(1); SCSP_TimersAddTicks(1);
CheckPendingIRQ(); CheckPendingIRQ();
@ -2146,16 +2101,15 @@ void SCSP_LoadState(CBlockFile *StateFile)
} }
} }
void SCSP_SetBuffers(INT16 *leftBufferPtr, INT16 *rightBufferPtr, INT16* leftRearBufferPtr, INT16* rightRearBufferPtr, int bufferLength) void SCSP_SetBuffers(float *leftBufferPtr, float *rightBufferPtr, float* leftRearBufferPtr, float* rightRearBufferPtr, int bufferLength)
{ {
SoundClock = 76; SoundClock = Freq;
bufferfl = leftBufferPtr; bufferfl = leftBufferPtr;
bufferfr = rightBufferPtr; bufferfr = rightBufferPtr;
bufferrl = leftRearBufferPtr; bufferrl = leftRearBufferPtr;
bufferrr = rightRearBufferPtr; bufferrr = rightRearBufferPtr;
length = bufferLength; length = bufferLength;
cnts = 0; // what is this for? seems unimportant but need to find out
} }
void SCSP_Deinit(void) void SCSP_Deinit(void)
@ -2163,14 +2117,6 @@ void SCSP_Deinit(void)
#ifdef USEDSP #ifdef USEDSP
free(SCSP->MIXBuf); free(SCSP->MIXBuf);
#endif #endif
free(buffertmpfl);
free(buffertmpfr);
free(buffertmprl);
free(buffertmprr);
delete MIDILock; delete MIDILock;
buffertmpfl = NULL;
buffertmpfr = NULL;
buffertmprl = NULL;
buffertmprr = NULL;
MIDILock = NULL; MIDILock = NULL;
} }

View file

@ -83,7 +83,7 @@ UINT32 SCSP_Slave_r32(UINT32 addr);
// Supermodel interface functions // Supermodel interface functions
void SCSP_SaveState(CBlockFile *StateFile); void SCSP_SaveState(CBlockFile *StateFile);
void SCSP_LoadState(CBlockFile *StateFile); void SCSP_LoadState(CBlockFile *StateFile);
void SCSP_SetBuffers(INT16 *leftBufferPtr, INT16 *rightBufferPtr, INT16* leftRearBufferPtr, INT16* rightRearBufferPtr, int bufferLength); void SCSP_SetBuffers(float *leftBufferPtr, float *rightBufferPtr, float* leftRearBufferPtr, float* rightRearBufferPtr, int bufferLength);
void SCSP_Deinit(void); void SCSP_Deinit(void);