mirror of https://github.com/stella-emu/stella.git
Allow sound sample rate/fragment size to change dynamically.
- Move sound debugging output to logging facilities - This should fix issue #348, but more testing is required Bumped version # for beta release.
This commit is contained in:
parent
13b9bbe5a4
commit
e5fb010631
|
@ -84,11 +84,6 @@ class SoundNull : public Sound
|
||||||
*/
|
*/
|
||||||
uInt32 getSampleRate() const override { return 31400; }
|
uInt32 getSampleRate() const override { return 31400; }
|
||||||
|
|
||||||
/**
|
|
||||||
Reset the sound device.
|
|
||||||
*/
|
|
||||||
void reset() override { }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Sets the volume of the sound device to the specified level. The
|
Sets the volume of the sound device to the specified level. The
|
||||||
volume is given as a percentage from 0 to 100. Values outside
|
volume is given as a percentage from 0 to 100. Values outside
|
||||||
|
|
|
@ -54,32 +54,9 @@ SoundSDL2::SoundSDL2(OSystem& osystem, AudioSettings& audioSettings)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The sound system is opened only once per program run, to eliminate
|
SDL_zero(myHardwareSpec);
|
||||||
// issues with opening and closing it multiple times
|
if(!openDevice())
|
||||||
// This fixes a bug most prevalent with ATI video cards in Windows,
|
|
||||||
// whereby sound stopped working after the first video change
|
|
||||||
SDL_AudioSpec desired;
|
|
||||||
desired.freq = myAudioSettings.sampleRate();
|
|
||||||
desired.format = AUDIO_F32SYS;
|
|
||||||
desired.channels = 2;
|
|
||||||
desired.samples = static_cast<Uint16>(myAudioSettings.fragmentSize());
|
|
||||||
desired.callback = callback;
|
|
||||||
desired.userdata = static_cast<void*>(this);
|
|
||||||
|
|
||||||
myDevice = SDL_OpenAudioDevice(nullptr, 0, &desired, &myHardwareSpec,
|
|
||||||
SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
|
|
||||||
|
|
||||||
if(myDevice == 0)
|
|
||||||
{
|
|
||||||
ostringstream buf;
|
|
||||||
|
|
||||||
buf << "WARNING: Couldn't open SDL audio device! " << endl
|
|
||||||
<< " " << SDL_GetError() << endl;
|
|
||||||
myOSystem.logMessage(buf.str(), 0);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
myIsInitializedFlag = true;
|
|
||||||
|
|
||||||
mute(true);
|
mute(true);
|
||||||
|
|
||||||
|
@ -95,6 +72,35 @@ SoundSDL2::~SoundSDL2()
|
||||||
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool SoundSDL2::openDevice()
|
||||||
|
{
|
||||||
|
SDL_AudioSpec desired;
|
||||||
|
desired.freq = myAudioSettings.sampleRate();
|
||||||
|
desired.format = AUDIO_F32SYS;
|
||||||
|
desired.channels = 2;
|
||||||
|
desired.samples = static_cast<Uint16>(myAudioSettings.fragmentSize());
|
||||||
|
desired.callback = callback;
|
||||||
|
desired.userdata = static_cast<void*>(this);
|
||||||
|
|
||||||
|
if(myIsInitializedFlag)
|
||||||
|
SDL_CloseAudioDevice(myDevice);
|
||||||
|
myDevice = SDL_OpenAudioDevice(nullptr, 0, &desired, &myHardwareSpec,
|
||||||
|
SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
|
||||||
|
|
||||||
|
if(myDevice == 0)
|
||||||
|
{
|
||||||
|
ostringstream buf;
|
||||||
|
|
||||||
|
buf << "WARNING: Couldn't open SDL audio device! " << endl
|
||||||
|
<< " " << SDL_GetError() << endl;
|
||||||
|
myOSystem.logMessage(buf.str(), 0);
|
||||||
|
|
||||||
|
return myIsInitializedFlag = false;
|
||||||
|
}
|
||||||
|
return myIsInitializedFlag = true;
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void SoundSDL2::setEnabled(bool state)
|
void SoundSDL2::setEnabled(bool state)
|
||||||
{
|
{
|
||||||
|
@ -109,6 +115,12 @@ void SoundSDL2::setEnabled(bool state)
|
||||||
void SoundSDL2::open(shared_ptr<AudioQueue> audioQueue,
|
void SoundSDL2::open(shared_ptr<AudioQueue> audioQueue,
|
||||||
EmulationTiming* emulationTiming)
|
EmulationTiming* emulationTiming)
|
||||||
{
|
{
|
||||||
|
// Do we need to re-open the sound device?
|
||||||
|
// Only do this when absolutely necessary
|
||||||
|
if(myAudioSettings.sampleRate() != uInt32(myHardwareSpec.freq) ||
|
||||||
|
myAudioSettings.fragmentSize() != uInt32(myHardwareSpec.samples))
|
||||||
|
openDevice();
|
||||||
|
|
||||||
myEmulationTiming = emulationTiming;
|
myEmulationTiming = emulationTiming;
|
||||||
|
|
||||||
myOSystem.logMessage("SoundSDL2::open started ...", 2);
|
myOSystem.logMessage("SoundSDL2::open started ...", 2);
|
||||||
|
@ -128,18 +140,32 @@ void SoundSDL2::open(shared_ptr<AudioQueue> audioQueue,
|
||||||
// Adjust volume to that defined in settings
|
// Adjust volume to that defined in settings
|
||||||
setVolume(myAudioSettings.volume());
|
setVolume(myAudioSettings.volume());
|
||||||
|
|
||||||
|
initResampler();
|
||||||
|
|
||||||
// Show some info
|
// Show some info
|
||||||
ostringstream buf;
|
ostringstream buf;
|
||||||
buf << "Sound enabled:" << endl
|
buf << "Sound enabled:" << endl
|
||||||
<< " Volume: " << myVolume << endl
|
<< " Volume: " << myVolume << endl
|
||||||
<< " Frag size: " << uInt32(myHardwareSpec.samples) << endl
|
<< " Frag size: " << uInt32(myHardwareSpec.samples) << endl
|
||||||
<< " Frequency: " << uInt32(myHardwareSpec.freq) << endl
|
<< " Frequency: " << uInt32(myHardwareSpec.freq) << endl
|
||||||
<< " Channels: " << uInt32(myHardwareSpec.channels)
|
<< " Channels: " << uInt32(myHardwareSpec.channels) << endl
|
||||||
<< endl;
|
<< " Resampling: ";
|
||||||
|
switch (myAudioSettings.resamplingQuality()) {
|
||||||
|
case AudioSettings::ResamplingQuality::nearestNeightbour:
|
||||||
|
buf << "quality 1, nearest neighbor" << endl;
|
||||||
|
break;
|
||||||
|
case AudioSettings::ResamplingQuality::lanczos_2:
|
||||||
|
buf << "quality 2, nearest Lanczos (a = 2)" << endl;
|
||||||
|
break;
|
||||||
|
case AudioSettings::ResamplingQuality::lanczos_3:
|
||||||
|
buf << "quality 3, nearest Lanczos (a = 3)" << endl;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
buf << "unknown resampler" << endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
myOSystem.logMessage(buf.str(), 1);
|
myOSystem.logMessage(buf.str(), 1);
|
||||||
|
|
||||||
initResampler();
|
|
||||||
|
|
||||||
// And start the SDL sound subsystem ...
|
// And start the SDL sound subsystem ...
|
||||||
mute(false);
|
mute(false);
|
||||||
|
|
||||||
|
@ -158,7 +184,6 @@ void SoundSDL2::close()
|
||||||
myCurrentFragment = nullptr;
|
myCurrentFragment = nullptr;
|
||||||
|
|
||||||
myOSystem.logMessage("SoundSDL2::close", 2);
|
myOSystem.logMessage("SoundSDL2::close", 2);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -170,11 +195,6 @@ void SoundSDL2::mute(bool state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
void SoundSDL2::reset()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void SoundSDL2::setVolume(uInt32 percent)
|
void SoundSDL2::setVolume(uInt32 percent)
|
||||||
{
|
{
|
||||||
|
@ -262,16 +282,13 @@ void SoundSDL2::initResampler()
|
||||||
switch (myAudioSettings.resamplingQuality()) {
|
switch (myAudioSettings.resamplingQuality()) {
|
||||||
case AudioSettings::ResamplingQuality::nearestNeightbour:
|
case AudioSettings::ResamplingQuality::nearestNeightbour:
|
||||||
myResampler = make_unique<SimpleResampler>(formatFrom, formatTo, nextFragmentCallback);
|
myResampler = make_unique<SimpleResampler>(formatFrom, formatTo, nextFragmentCallback);
|
||||||
(cerr << "resampling quality 1: using nearest neighbor resampling\n").flush();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AudioSettings::ResamplingQuality::lanczos_2:
|
case AudioSettings::ResamplingQuality::lanczos_2:
|
||||||
(cerr << "resampling quality 2: using nearest Lanczos resampling, a = 2\n").flush();
|
|
||||||
myResampler = make_unique<LanczosResampler>(formatFrom, formatTo, nextFragmentCallback, 2);
|
myResampler = make_unique<LanczosResampler>(formatFrom, formatTo, nextFragmentCallback, 2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AudioSettings::ResamplingQuality::lanczos_3:
|
case AudioSettings::ResamplingQuality::lanczos_3:
|
||||||
(cerr << "resampling quality 3: using nearest Lanczos resampling, a = 3\n").flush();
|
|
||||||
myResampler = make_unique<LanczosResampler>(formatFrom, formatTo, nextFragmentCallback, 3);
|
myResampler = make_unique<LanczosResampler>(formatFrom, formatTo, nextFragmentCallback, 3);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -77,11 +77,6 @@ class SoundSDL2 : public Sound
|
||||||
*/
|
*/
|
||||||
void mute(bool state) override;
|
void mute(bool state) override;
|
||||||
|
|
||||||
/**
|
|
||||||
Reset the sound device.
|
|
||||||
*/
|
|
||||||
void reset() override;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Sets the volume of the sound device to the specified level. The
|
Sets the volume of the sound device to the specified level. The
|
||||||
volume is given as a percentage from 0 to 100. Values outside
|
volume is given as a percentage from 0 to 100. Values outside
|
||||||
|
@ -115,6 +110,12 @@ class SoundSDL2 : public Sound
|
||||||
void processFragment(float* stream, uInt32 length);
|
void processFragment(float* stream, uInt32 length);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
The actual sound device is opened only when absolutely necessary.
|
||||||
|
Typically this will only happen once per program run, but it can also
|
||||||
|
happen dynamically when changing sample rate and/or fragment size.
|
||||||
|
*/
|
||||||
|
bool openDevice();
|
||||||
|
|
||||||
void initResampler();
|
void initResampler();
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
#include "StateManager.hxx"
|
#include "StateManager.hxx"
|
||||||
|
|
||||||
#define STATE_HEADER "05099000state"
|
#define STATE_HEADER "05099100state"
|
||||||
// #define MOVIE_HEADER "03030000movie"
|
// #define MOVIE_HEADER "03030000movie"
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#ifndef VERSION_HXX
|
#ifndef VERSION_HXX
|
||||||
#define VERSION_HXX
|
#define VERSION_HXX
|
||||||
|
|
||||||
#define STELLA_VERSION "6.0_pre1"
|
#define STELLA_VERSION "6.0_beta1"
|
||||||
#define STELLA_BUILD "4434"
|
#define STELLA_BUILD "4514"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -589,16 +589,12 @@ void Console::initializeAudio()
|
||||||
myOSystem.sound().close();
|
myOSystem.sound().close();
|
||||||
|
|
||||||
myEmulationTiming
|
myEmulationTiming
|
||||||
.updatePlaybackRate(myOSystem.sound().getSampleRate())
|
.updatePlaybackRate(myAudioSettings.sampleRate())
|
||||||
.updatePlaybackPeriod(myOSystem.sound().getFragmentSize())
|
.updatePlaybackPeriod(myAudioSettings.fragmentSize())
|
||||||
.updateAudioQueueExtraFragments(myAudioSettings.bufferSize())
|
.updateAudioQueueExtraFragments(myAudioSettings.bufferSize())
|
||||||
.updateAudioQueueHeadroom(myAudioSettings.headroom())
|
.updateAudioQueueHeadroom(myAudioSettings.headroom())
|
||||||
.updateSpeedFactor(myOSystem.settings().getFloat("speed"));
|
.updateSpeedFactor(myOSystem.settings().getFloat("speed"));
|
||||||
|
|
||||||
(cout << "sample rate: " << myOSystem.sound().getSampleRate() << std::endl).flush();
|
|
||||||
(cout << "fragment size: " << myOSystem.sound().getFragmentSize() << std::endl).flush();
|
|
||||||
(cout << "prebuffer fragment count: " << myEmulationTiming.prebufferFragmentCount() << std::endl).flush();
|
|
||||||
|
|
||||||
createAudioQueue();
|
createAudioQueue();
|
||||||
myTIA->setAudioQueue(myAudioQueue);
|
myTIA->setAudioQueue(myAudioQueue);
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ class Sound
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
Create a new sound object. The init method must be invoked before
|
Create a new sound object. The open method must be invoked before
|
||||||
using the object.
|
using the object.
|
||||||
*/
|
*/
|
||||||
Sound(OSystem& osystem) : myOSystem(osystem) { }
|
Sound(OSystem& osystem) : myOSystem(osystem) { }
|
||||||
|
@ -77,11 +77,6 @@ class Sound
|
||||||
*/
|
*/
|
||||||
virtual uInt32 getSampleRate() const = 0;
|
virtual uInt32 getSampleRate() const = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
Reset the sound device.
|
|
||||||
*/
|
|
||||||
virtual void reset() = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Sets the volume of the sound device to the specified level. The
|
Sets the volume of the sound device to the specified level. The
|
||||||
volume is given as a percentage from 0 to 100. Values outside
|
volume is given as a percentage from 0 to 100. Values outside
|
||||||
|
|
Loading…
Reference in New Issue