diff --git a/src/common/SoundSDL2.cxx b/src/common/SoundSDL2.cxx index 4c5b638c8..e8d27e92e 100644 --- a/src/common/SoundSDL2.cxx +++ b/src/common/SoundSDL2.cxx @@ -28,12 +28,15 @@ #include "OSystem.hxx" #include "Console.hxx" #include "SoundSDL2.hxx" +#include "AudioQueue.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SoundSDL2::SoundSDL2(OSystem& osystem) : Sound(osystem), myIsInitializedFlag(false), - myVolume(100) + myVolume(100), + myAudioQueue(0), + myCurrentFragment(0) { myOSystem.logMessage("SoundSDL2::SoundSDL2 started ...", 2); @@ -96,7 +99,7 @@ void SoundSDL2::setEnabled(bool state) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void SoundSDL2::open() +void SoundSDL2::open(AudioQueue* audioQueue) { myOSystem.logMessage("SoundSDL2::open started ...", 2); mute(true); @@ -107,6 +110,12 @@ void SoundSDL2::open() return; } + myAudioQueue = audioQueue; + myUnderrun = true; + myCurrentFragment = 0; + myTimeIndex = 0; + myFragmentIndex = 0; + // Adjust volume to that defined in settings setVolume(myOSystem.settings().getInt("volume")); @@ -131,6 +140,9 @@ void SoundSDL2::close() { if(!myIsInitializedFlag) return; + myAudioQueue = 0; + myCurrentFragment = 0; + mute(true); myOSystem.logMessage("SoundSDL2::close", 2); @@ -189,12 +201,70 @@ void SoundSDL2::adjustVolume(Int8 direction) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL2::processFragment(Int16* stream, uInt32 length) -{} +{ + if (myUnderrun && myAudioQueue->size() > 1) { + myUnderrun = false; + myCurrentFragment = myAudioQueue->dequeue(myCurrentFragment); + myFragmentIndex = 0; + } + + if (!myCurrentFragment) { + memset(stream, 0, 2 * length); + return; + } + + bool isStereoTIA = myAudioQueue->isStereo(); + bool isStereo = myHardwareSpec.channels == 2; + uInt32 sampleRateTIA = myAudioQueue->sampleRate(); + uInt32 sampleRate = myHardwareSpec.freq; + uInt32 fragmentSize = myAudioQueue->fragmentSize(); + uInt32 outputSamples = isStereo ? (length >> 1) : length; + + for (uInt32 i = 0; i < outputSamples; i++) { + myTimeIndex += sampleRateTIA; + + if (myTimeIndex > sampleRate) { + myFragmentIndex += myTimeIndex / sampleRate; + myTimeIndex %= sampleRate; + } + + if (myFragmentIndex >= fragmentSize) { + myFragmentIndex %= fragmentSize; + + Int16* nextFragment = myAudioQueue->dequeue(myCurrentFragment); + if (nextFragment) + myCurrentFragment = nextFragment; + else + myUnderrun = true; + } + + if (isStereo) { + if (isStereoTIA) { + stream[2*i] = myCurrentFragment[2*myFragmentIndex]; + stream[2*i + 1] = myCurrentFragment[2*myFragmentIndex + 1]; + } else { + stream[2*i] = stream[2*i + 1] = myCurrentFragment[myFragmentIndex]; + } + } else { + if (isStereoTIA) { + stream[i] = + ((myCurrentFragment[2*myFragmentIndex] / 2) + (myCurrentFragment[2*myFragmentIndex + 1] / 2)); + } else { + stream[i] = myCurrentFragment[myFragmentIndex]; + } + } + } +} // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL2::callback(void* udata, uInt8* stream, int len) { - SDL_memset(stream, 0, len); // Write 'silence' + SoundSDL2* self = static_cast(udata); + + if (self->myAudioQueue) + self->processFragment(reinterpret_cast(stream), len >> 1); + else + SDL_memset(stream, 0, len); } #endif // SOUND_SUPPORT diff --git a/src/common/SoundSDL2.hxx b/src/common/SoundSDL2.hxx index ba40b67c1..b216b5a41 100644 --- a/src/common/SoundSDL2.hxx +++ b/src/common/SoundSDL2.hxx @@ -21,6 +21,7 @@ #define SOUND_SDL2_HXX class OSystem; +class AudioQueue; #include "SDL_lib.hxx" @@ -58,7 +59,7 @@ class SoundSDL2 : public Sound Initializes the sound device. This must be called before any calls are made to derived methods. */ - void open() override; + void open(AudioQueue* audioQueue) override; /** Should be called to close the sound device. Once called the sound @@ -116,6 +117,13 @@ class SoundSDL2 : public Sound // Audio specification structure SDL_AudioSpec myHardwareSpec; + AudioQueue* myAudioQueue; + + Int16* myCurrentFragment; + uInt32 myTimeIndex; + uInt32 myFragmentIndex; + bool myUnderrun; + private: // Callback function invoked by the SDL Audio library when it needs data static void callback(void* udata, uInt8* stream, int len); diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index b56d8fc56..a420cb15f 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -580,7 +580,7 @@ void Console::initializeAudio() // const string& sound = myProperties.get(Cartridge_Sound); // myOSystem.sound().setChannels(sound == "STEREO" ? 2 : 1); - myOSystem.sound().open(); + myOSystem.sound().open(myAudioQueue.get()); // Make sure auto-frame calculation is only enabled when necessary myTIA->enableAutoFrame(framerate <= 0); diff --git a/src/emucore/Sound.hxx b/src/emucore/Sound.hxx index 904c0ea19..3aa4726e4 100644 --- a/src/emucore/Sound.hxx +++ b/src/emucore/Sound.hxx @@ -19,6 +19,7 @@ #define SOUND_HXX class OSystem; +class AudioQueue; #include "bspf.hxx" @@ -50,7 +51,7 @@ class Sound Start the sound system, initializing it if necessary. This must be called before any calls are made to derived methods. */ - virtual void open() = 0; + virtual void open(AudioQueue* audioQueue) = 0; /** Should be called to stop the sound system. Once called the sound