mirror of https://github.com/stella-emu/stella.git
Major audio settings overhaul.
This commit is contained in:
parent
d127865dee
commit
ef5261689a
|
@ -53,6 +53,11 @@
|
|||
"typeinfo": "cpp",
|
||||
"__mutex_base": "cpp",
|
||||
"mutex": "cpp",
|
||||
"condition_variable": "cpp"
|
||||
"condition_variable": "cpp",
|
||||
"*.ins": "cpp",
|
||||
"cstring": "cpp",
|
||||
"iostream": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"ostream": "cpp"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,262 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include "AudioSettings.hxx"
|
||||
#include "Settings.hxx"
|
||||
|
||||
namespace {
|
||||
uInt32 convertInt(int x, int defaultValue)
|
||||
{
|
||||
return x <= defaultValue ? defaultValue : x;
|
||||
}
|
||||
|
||||
AudioSettings::Preset normalizedPreset(int numericPreset)
|
||||
{
|
||||
return (
|
||||
numericPreset >= static_cast<int>(AudioSettings::Preset::custom) &&
|
||||
numericPreset <= static_cast<int>(AudioSettings::Preset::veryHighQualityVeryLowLag)
|
||||
) ? static_cast<AudioSettings::Preset>(numericPreset) : AudioSettings::DEFAULT_PRESET;
|
||||
}
|
||||
|
||||
AudioSettings::ResamplingQuality normalizeResamplingQuality(int numericResamplingQuality)
|
||||
{
|
||||
return (
|
||||
numericResamplingQuality >= static_cast<int>(AudioSettings::ResamplingQuality::nearestNeightbour) &&
|
||||
numericResamplingQuality <= static_cast<int>(AudioSettings::ResamplingQuality::lanczos_3)
|
||||
) ? static_cast<AudioSettings::ResamplingQuality>(numericResamplingQuality) : AudioSettings::DEFAULT_RESAMPLING_QUALITY;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
AudioSettings::AudioSettings(Settings* settings)
|
||||
: mySettings(settings)
|
||||
{
|
||||
setPreset(normalizedPreset(mySettings->getInt(SETTING_PRESET)));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AudioSettings::normalize(Settings& settings)
|
||||
{
|
||||
int settingPreset = settings.getInt(SETTING_PRESET);
|
||||
Preset preset = normalizedPreset(settingPreset);
|
||||
if (static_cast<int>(preset) != settingPreset) settings.setValue(SETTING_PRESET, static_cast<int>(DEFAULT_PRESET));
|
||||
|
||||
switch (settings.getInt(SETTING_SAMPLE_RATE)) {
|
||||
case 44100:
|
||||
case 48000:
|
||||
case 96000:
|
||||
break;
|
||||
|
||||
default:
|
||||
settings.setValue(SETTING_SAMPLE_RATE, DEFAULT_SAMPLE_RATE);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (settings.getInt(SETTING_FRAGMENT_SIZE)) {
|
||||
case 128:
|
||||
case 256:
|
||||
case 512:
|
||||
case 1024:
|
||||
case 2048:
|
||||
case 4096:
|
||||
break;
|
||||
|
||||
default:
|
||||
settings.setValue(SETTING_FRAGMENT_SIZE, DEFAULT_FRAGMENT_SIZE);
|
||||
break;
|
||||
}
|
||||
|
||||
int settingBufferSize = settings.getInt(SETTING_BUFFER_SIZE);
|
||||
if (settingBufferSize < 0 || settingBufferSize > 20) settings.setValue(SETTING_BUFFER_SIZE, DEFAULT_BUFFER_SIZE);
|
||||
|
||||
int settingHeadroom = settings.getInt(SETTING_HEADROOM);
|
||||
if (settingHeadroom < 0 || settingHeadroom > 20) settings.setValue(SETTING_HEADROOM, DEFAULT_HEADROOM);
|
||||
|
||||
int settingResamplingQuality = settings.getInt(SETTING_RESAMPLING_QUALITY);
|
||||
ResamplingQuality resamplingQuality = normalizeResamplingQuality(settingResamplingQuality);
|
||||
if (static_cast<int>(resamplingQuality) != settingResamplingQuality)
|
||||
settings.setValue(SETTING_RESAMPLING_QUALITY, static_cast<int>(DEFAULT_RESAMPLING_QUALITY));
|
||||
|
||||
int settingVolume = settings.getInt(SETTING_VOLUME);
|
||||
if (settingVolume < 0 || settingVolume > 100) settings.setValue(SETTING_VOLUME, DEFAULT_VOLUME);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
AudioSettings::Preset AudioSettings::preset()
|
||||
{
|
||||
updatePresetFromSettings();
|
||||
return myPreset;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 AudioSettings::sampleRate()
|
||||
{
|
||||
updatePresetFromSettings();
|
||||
return customSettings() ? convertInt(mySettings->getInt(SETTING_SAMPLE_RATE), DEFAULT_SAMPLE_RATE) : myPresetSampleRate;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 AudioSettings::fragmentSize()
|
||||
{
|
||||
updatePresetFromSettings();
|
||||
return customSettings() ? convertInt(mySettings->getInt(SETTING_FRAGMENT_SIZE), DEFAULT_FRAGMENT_SIZE) : myPresetFragmentSize;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 AudioSettings::bufferSize()
|
||||
{
|
||||
updatePresetFromSettings();
|
||||
// 0 is a valid value -> keep it
|
||||
return customSettings() ? convertInt(mySettings->getInt(SETTING_BUFFER_SIZE), 0) : myPresetBufferSize;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 AudioSettings::headroom()
|
||||
{
|
||||
updatePresetFromSettings();
|
||||
// 0 is a valid value -> keep it
|
||||
return customSettings() ? convertInt(mySettings->getInt(SETTING_HEADROOM), 0) : myPresetHeadroom;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
AudioSettings::ResamplingQuality AudioSettings::resamplingQuality()
|
||||
{
|
||||
updatePresetFromSettings();
|
||||
return customSettings() ? normalizeResamplingQuality(mySettings->getInt(SETTING_RESAMPLING_QUALITY)) : myPresetResamplingQuality;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 AudioSettings::volume() const
|
||||
{
|
||||
// 0 is a valid value -> keep it
|
||||
return convertInt(mySettings->getInt(SETTING_VOLUME), 0);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool AudioSettings::enabled() const
|
||||
{
|
||||
return mySettings->getBool(SETTING_ENABLED);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AudioSettings::setPreset(AudioSettings::Preset preset)
|
||||
{
|
||||
if (preset == myPreset) return;
|
||||
myPreset = preset;
|
||||
|
||||
switch (myPreset) {
|
||||
case Preset::custom:
|
||||
break;
|
||||
|
||||
case Preset::lowQualityMediumLag:
|
||||
myPresetSampleRate = 44100;
|
||||
myPresetFragmentSize = 1024;
|
||||
myPresetBufferSize = 4;
|
||||
myPresetHeadroom = 3;
|
||||
myPresetResamplingQuality = ResamplingQuality::nearestNeightbour;
|
||||
break;
|
||||
|
||||
case Preset::highQualityMediumLag:
|
||||
myPresetSampleRate = 44100;
|
||||
myPresetFragmentSize = 1024;
|
||||
myPresetBufferSize = 4;
|
||||
myPresetHeadroom = 3;
|
||||
myPresetResamplingQuality = ResamplingQuality::lanczos_2;
|
||||
break;
|
||||
|
||||
case Preset::highQualityLowLag:
|
||||
myPresetSampleRate = 48000;
|
||||
myPresetFragmentSize = 512;
|
||||
myPresetBufferSize = 2;
|
||||
myPresetHeadroom = 1;
|
||||
myPresetResamplingQuality = ResamplingQuality::lanczos_2;
|
||||
break;
|
||||
|
||||
case Preset::veryHighQualityVeryLowLag:
|
||||
myPresetSampleRate = 96000;
|
||||
myPresetFragmentSize = 128;
|
||||
myPresetBufferSize = 0;
|
||||
myPresetHeadroom = 0;
|
||||
myPresetResamplingQuality = ResamplingQuality::lanczos_3;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw runtime_error("invalid preset");
|
||||
}
|
||||
|
||||
mySettings->setValue(SETTING_PRESET, static_cast<int>(myPreset));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AudioSettings::setSampleRate(uInt32 sampleRate)
|
||||
{
|
||||
mySettings->setValue(SETTING_SAMPLE_RATE, sampleRate);
|
||||
normalize(*mySettings);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AudioSettings::setFragmentSize(uInt32 fragmentSize)
|
||||
{
|
||||
mySettings->setValue(SETTING_FRAGMENT_SIZE, fragmentSize);
|
||||
normalize(*mySettings);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AudioSettings::setBufferSize(uInt32 bufferSize)
|
||||
{
|
||||
mySettings->setValue(SETTING_BUFFER_SIZE, bufferSize);
|
||||
normalize(*mySettings);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AudioSettings::setHeadroom(uInt32 headroom)
|
||||
{
|
||||
mySettings->setValue(SETTING_HEADROOM, headroom);
|
||||
normalize(*mySettings);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AudioSettings::setResamplingQuality(AudioSettings::ResamplingQuality resamplingQuality)
|
||||
{
|
||||
mySettings->setValue(SETTING_RESAMPLING_QUALITY, static_cast<int>(resamplingQuality));
|
||||
normalize(*mySettings);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AudioSettings::setVolume(uInt32 volume)
|
||||
{
|
||||
mySettings->setValue(SETTING_VOLUME, volume);
|
||||
normalize(*mySettings);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AudioSettings::setEnabled(bool isEnabled)
|
||||
{
|
||||
mySettings->setValue(SETTING_ENABLED, isEnabled);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool AudioSettings::customSettings() const
|
||||
{
|
||||
return myPreset == Preset::custom;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AudioSettings::updatePresetFromSettings()
|
||||
{
|
||||
setPreset(normalizedPreset(mySettings->getInt(SETTING_PRESET)));
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifndef AUDIO_PARAMTERS_HXX
|
||||
#define AUDIO_PARAMTERS_HXX
|
||||
|
||||
#include "bspf.hxx"
|
||||
|
||||
class Settings;
|
||||
|
||||
class AudioSettings
|
||||
{
|
||||
public:
|
||||
|
||||
enum class Preset {
|
||||
custom = 1,
|
||||
lowQualityMediumLag = 2,
|
||||
highQualityMediumLag = 3,
|
||||
highQualityLowLag = 4,
|
||||
veryHighQualityVeryLowLag = 5
|
||||
};
|
||||
|
||||
enum class ResamplingQuality {
|
||||
nearestNeightbour = 1,
|
||||
lanczos_2 = 2,
|
||||
lanczos_3 = 3
|
||||
};
|
||||
|
||||
static constexpr const char* SETTING_PRESET = "audio.preset";
|
||||
static constexpr const char* SETTING_SAMPLE_RATE = "audio.sample_rate";
|
||||
static constexpr const char* SETTING_FRAGMENT_SIZE = "audio.fragment_size";
|
||||
static constexpr const char* SETTING_BUFFER_SIZE = "audio.buffer_size";
|
||||
static constexpr const char* SETTING_HEADROOM = "audio.headroom";
|
||||
static constexpr const char* SETTING_RESAMPLING_QUALITY = "audio.resampling_quality";
|
||||
static constexpr const char* SETTING_VOLUME = "audio.volume";
|
||||
static constexpr const char* SETTING_ENABLED = "audio.enabled";
|
||||
|
||||
static constexpr Preset DEFAULT_PRESET = Preset::highQualityMediumLag;
|
||||
static constexpr uInt32 DEFAULT_SAMPLE_RATE = 44100;
|
||||
static constexpr uInt32 DEFAULT_FRAGMENT_SIZE = 512;
|
||||
static constexpr uInt32 DEFAULT_BUFFER_SIZE = 3;
|
||||
static constexpr uInt32 DEFAULT_HEADROOM = 2;
|
||||
static constexpr ResamplingQuality DEFAULT_RESAMPLING_QUALITY = ResamplingQuality::lanczos_2;
|
||||
static constexpr uInt32 DEFAULT_VOLUME = 80;
|
||||
static constexpr bool DEFAULT_ENABLED = true;
|
||||
|
||||
public:
|
||||
|
||||
AudioSettings() = default;
|
||||
|
||||
AudioSettings(Settings* mySettings);
|
||||
|
||||
static void initialize(Settings& settings);
|
||||
|
||||
static void normalize(Settings& settings);
|
||||
|
||||
Preset preset();
|
||||
|
||||
uInt32 sampleRate();
|
||||
|
||||
uInt32 fragmentSize();
|
||||
|
||||
uInt32 bufferSize();
|
||||
|
||||
uInt32 headroom();
|
||||
|
||||
ResamplingQuality resamplingQuality();
|
||||
|
||||
uInt32 volume() const;
|
||||
|
||||
bool enabled() const;
|
||||
|
||||
void setPreset(Preset preset);
|
||||
|
||||
void setSampleRate(uInt32 sampleRate);
|
||||
|
||||
void setFragmentSize(uInt32 fragmentSize);
|
||||
|
||||
void setBufferSize(uInt32 bufferSize);
|
||||
|
||||
void setHeadroom(uInt32 headroom);
|
||||
|
||||
void setResamplingQuality(ResamplingQuality resamplingQuality);
|
||||
|
||||
void setVolume(uInt32 volume);
|
||||
|
||||
void setEnabled(bool isEnabled);
|
||||
|
||||
private:
|
||||
|
||||
bool customSettings() const;
|
||||
|
||||
void updatePresetFromSettings();
|
||||
|
||||
private:
|
||||
|
||||
Settings* mySettings;
|
||||
|
||||
Preset myPreset;
|
||||
|
||||
uInt32 myPresetSampleRate;
|
||||
uInt32 myPresetFragmentSize;
|
||||
uInt32 myPresetBufferSize;
|
||||
uInt32 myPresetHeadroom;
|
||||
ResamplingQuality myPresetResamplingQuality;
|
||||
};
|
||||
|
||||
#endif // AUDIO_PARAMTERS_HXX
|
|
@ -50,6 +50,8 @@
|
|||
#include "SoundNull.hxx"
|
||||
#endif
|
||||
|
||||
class AudioSettings;
|
||||
|
||||
/**
|
||||
This class deals with the different framebuffer/sound/event
|
||||
implementations for the various ports of Stella, and always returns a
|
||||
|
@ -108,10 +110,10 @@ class MediaFactory
|
|||
return make_unique<FrameBufferSDL2>(osystem);
|
||||
}
|
||||
|
||||
static unique_ptr<Sound> createAudio(OSystem& osystem)
|
||||
static unique_ptr<Sound> createAudio(OSystem& osystem, AudioSettings& audioSettings)
|
||||
{
|
||||
#ifdef SOUND_SUPPORT
|
||||
return make_unique<SoundSDL2>(osystem);
|
||||
return make_unique<SoundSDL2>(osystem, audioSettings);
|
||||
#else
|
||||
return make_unique<SoundNull>(osystem);
|
||||
#endif
|
||||
|
|
|
@ -86,7 +86,7 @@ class SoundNull : public Sound
|
|||
|
||||
@param percent The new volume percentage level for the sound device
|
||||
*/
|
||||
void setVolume(Int32 percent) override { }
|
||||
void setVolume(uInt32 percent) override { }
|
||||
|
||||
/**
|
||||
Adjusts the volume of the sound device based on the given direction.
|
||||
|
|
|
@ -30,16 +30,18 @@
|
|||
#include "SoundSDL2.hxx"
|
||||
#include "AudioQueue.hxx"
|
||||
#include "EmulationTiming.hxx"
|
||||
#include "AudioSettings.hxx"
|
||||
#include "audio/SimpleResampler.hxx"
|
||||
#include "audio/LanczosResampler.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundSDL2::SoundSDL2(OSystem& osystem)
|
||||
SoundSDL2::SoundSDL2(OSystem& osystem, AudioSettings& audioSettings)
|
||||
: Sound(osystem),
|
||||
myIsInitializedFlag(false),
|
||||
myVolume(100),
|
||||
myVolumeFactor(0xffff),
|
||||
myCurrentFragment(nullptr)
|
||||
myCurrentFragment(nullptr),
|
||||
myAudioSettings(audioSettings)
|
||||
{
|
||||
myOSystem.logMessage("SoundSDL2::SoundSDL2 started ...", 2);
|
||||
|
||||
|
@ -48,10 +50,10 @@ SoundSDL2::SoundSDL2(OSystem& osystem)
|
|||
// 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 = myOSystem.settings().getInt("freq");
|
||||
desired.freq = myAudioSettings.sampleRate();
|
||||
desired.format = AUDIO_F32SYS;
|
||||
desired.channels = 2;
|
||||
desired.samples = myOSystem.settings().getInt("fragsize");
|
||||
desired.samples = myAudioSettings.fragmentSize();
|
||||
desired.callback = callback;
|
||||
desired.userdata = static_cast<void*>(this);
|
||||
|
||||
|
@ -95,7 +97,7 @@ SoundSDL2::~SoundSDL2()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL2::setEnabled(bool state)
|
||||
{
|
||||
myOSystem.settings().setValue("sound", state);
|
||||
myAudioSettings.setEnabled(state);
|
||||
|
||||
myOSystem.logMessage(state ? "SoundSDL2::setEnabled(true)" :
|
||||
"SoundSDL2::setEnabled(false)", 2);
|
||||
|
@ -110,7 +112,7 @@ void SoundSDL2::open(shared_ptr<AudioQueue> audioQueue,
|
|||
myOSystem.logMessage("SoundSDL2::open started ...", 2);
|
||||
mute(true);
|
||||
|
||||
if(!myOSystem.settings().getBool("sound"))
|
||||
if(!myAudioSettings.enabled())
|
||||
{
|
||||
myOSystem.logMessage("Sound disabled\n", 1);
|
||||
return;
|
||||
|
@ -121,7 +123,7 @@ void SoundSDL2::open(shared_ptr<AudioQueue> audioQueue,
|
|||
myCurrentFragment = nullptr;
|
||||
|
||||
// Adjust volume to that defined in settings
|
||||
setVolume(myOSystem.settings().getInt("volume"));
|
||||
setVolume(myAudioSettings.volume());
|
||||
|
||||
// Show some info
|
||||
ostringstream buf;
|
||||
|
@ -171,11 +173,11 @@ void SoundSDL2::reset()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL2::setVolume(Int32 percent)
|
||||
void SoundSDL2::setVolume(uInt32 percent)
|
||||
{
|
||||
if(myIsInitializedFlag && (percent >= 0) && (percent <= 100))
|
||||
if(myIsInitializedFlag && (percent <= 100))
|
||||
{
|
||||
myOSystem.settings().setValue("volume", percent);
|
||||
myAudioSettings.setVolume(percent);
|
||||
myVolume = percent;
|
||||
|
||||
SDL_LockAudio();
|
||||
|
@ -213,7 +215,7 @@ void SoundSDL2::adjustVolume(Int8 direction)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 SoundSDL2::getFragmentSize() const
|
||||
{
|
||||
return myHardwareSpec.size;
|
||||
return myHardwareSpec.samples;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -253,24 +255,26 @@ void SoundSDL2::initResampler()
|
|||
Resampler::Format formatTo =
|
||||
Resampler::Format(myHardwareSpec.freq, myHardwareSpec.samples, myHardwareSpec.channels > 1);
|
||||
|
||||
int quality = myOSystem.settings().getInt("resampling.quality");
|
||||
|
||||
switch (quality) {
|
||||
case 1:
|
||||
switch (myAudioSettings.resamplingQuality()) {
|
||||
case AudioSettings::ResamplingQuality::nearestNeightbour:
|
||||
myResampler = make_unique<SimpleResampler>(formatFrom, formatTo, nextFragmentCallback);
|
||||
(cerr << "resampling quality 1: using nearest neighbor resampling\n").flush();
|
||||
break;
|
||||
|
||||
default:
|
||||
case 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);
|
||||
break;
|
||||
|
||||
case 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);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw runtime_error("invalid resampling quality");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
class OSystem;
|
||||
class AudioQueue;
|
||||
class EmulationTiming;
|
||||
class AudioSettings;
|
||||
|
||||
#include "SDL_lib.hxx"
|
||||
|
||||
|
@ -42,7 +43,7 @@ class SoundSDL2 : public Sound
|
|||
Create a new sound object. The init method must be invoked before
|
||||
using the object.
|
||||
*/
|
||||
SoundSDL2(OSystem& osystem);
|
||||
SoundSDL2(OSystem& osystem, AudioSettings& audioSettings);
|
||||
|
||||
/**
|
||||
Destructor
|
||||
|
@ -88,7 +89,7 @@ class SoundSDL2 : public Sound
|
|||
|
||||
@param percent The new volume percentage level for the sound device
|
||||
*/
|
||||
void setVolume(Int32 percent) override;
|
||||
void setVolume(uInt32 percent) override;
|
||||
|
||||
/**
|
||||
Adjusts the volume of the sound device based on the given direction.
|
||||
|
@ -137,6 +138,8 @@ class SoundSDL2 : public Sound
|
|||
|
||||
unique_ptr<Resampler> myResampler;
|
||||
|
||||
AudioSettings& myAudioSettings;
|
||||
|
||||
private:
|
||||
// Callback function invoked by the SDL Audio library when it needs data
|
||||
static void callback(void* udata, uInt8* stream, int len);
|
||||
|
|
|
@ -16,7 +16,8 @@ MODULE_OBJS := \
|
|||
src/common/SoundSDL2.o \
|
||||
src/common/StateManager.o \
|
||||
src/common/ZipHandler.o \
|
||||
src/common/AudioQueue.o
|
||||
src/common/AudioQueue.o \
|
||||
src/common/AudioSettings.o
|
||||
|
||||
MODULE_DIRS += \
|
||||
src/common
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include "TIAConstants.hxx"
|
||||
#include "FrameLayout.hxx"
|
||||
#include "AudioQueue.hxx"
|
||||
#include "AudioSettings.hxx"
|
||||
#include "frame-manager/FrameManager.hxx"
|
||||
#include "frame-manager/FrameLayoutDetector.hxx"
|
||||
#include "frame-manager/YStartDetector.hxx"
|
||||
|
@ -76,7 +77,7 @@ namespace {
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Console::Console(OSystem& osystem, unique_ptr<Cartridge>& cart,
|
||||
const Properties& props)
|
||||
const Properties& props, AudioSettings& audioSettings)
|
||||
: myOSystem(osystem),
|
||||
myEvent(osystem.eventHandler().event()),
|
||||
myProperties(props),
|
||||
|
@ -85,7 +86,8 @@ Console::Console(OSystem& osystem, unique_ptr<Cartridge>& cart,
|
|||
myCurrentFormat(0), // Unknown format @ start,
|
||||
myAutodetectedYstart(0),
|
||||
myUserPaletteDefined(false),
|
||||
myConsoleTiming(ConsoleTiming::ntsc)
|
||||
myConsoleTiming(ConsoleTiming::ntsc),
|
||||
myAudioSettings(audioSettings)
|
||||
{
|
||||
// Load user-defined palette for this ROM
|
||||
loadUserPalette();
|
||||
|
@ -553,8 +555,15 @@ void Console::initializeAudio()
|
|||
{
|
||||
myOSystem.sound().close();
|
||||
|
||||
myEmulationTiming.updatePlaybackPeriod(myOSystem.sound().getSampleRate());
|
||||
myEmulationTiming.updatePlaybackPeriod(myOSystem.sound().getFragmentSize());
|
||||
myEmulationTiming
|
||||
.updatePlaybackRate(myOSystem.sound().getSampleRate())
|
||||
.updatePlaybackPeriod(myOSystem.sound().getFragmentSize())
|
||||
.updateAudioQueueExtraFragments(myAudioSettings.bufferSize())
|
||||
.updateAudioQueueHeadroom(myAudioSettings.headroom());
|
||||
|
||||
(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();
|
||||
myTIA->setAudioQueue(myAudioQueue);
|
||||
|
|
|
@ -28,6 +28,7 @@ class Cartridge;
|
|||
class CompuMate;
|
||||
class Debugger;
|
||||
class AudioQueue;
|
||||
class AudioSettings;
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "Control.hxx"
|
||||
|
@ -80,7 +81,7 @@ class Console : public Serializable
|
|||
@param props The properties for the cartridge
|
||||
*/
|
||||
Console(OSystem& osystem, unique_ptr<Cartridge>& cart,
|
||||
const Properties& props);
|
||||
const Properties& props, AudioSettings& audioSettings);
|
||||
|
||||
/**
|
||||
Destructor
|
||||
|
@ -423,9 +424,12 @@ class Console : public Serializable
|
|||
ConsoleTiming myConsoleTiming;
|
||||
|
||||
// Emulation timing provider. This ties together the timing of the core emulation loop
|
||||
// and the audio synthesis parameters
|
||||
// and the parameters that govern audio synthesis
|
||||
EmulationTiming myEmulationTiming;
|
||||
|
||||
// The audio settings
|
||||
AudioSettings& myAudioSettings;
|
||||
|
||||
// Table of RGB values for NTSC, PAL and SECAM
|
||||
static uInt32 ourNTSCPalette[256];
|
||||
static uInt32 ourPALPalette[256];
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
|
||||
namespace {
|
||||
constexpr uInt32 AUDIO_HALF_FRAMES_PER_FRAGMENT = 1;
|
||||
constexpr uInt32 QUEUE_CAPACITY_EXTRA_FRAGMENTS = 1;
|
||||
constexpr uInt32 PREBUFFER_EXTRA_FRAGMENT_COUNT = 2;
|
||||
|
||||
uInt32 discreteDivCeil(uInt32 n, uInt32 d)
|
||||
{
|
||||
|
@ -32,25 +30,44 @@ namespace {
|
|||
EmulationTiming::EmulationTiming(FrameLayout frameLayout) :
|
||||
myFrameLayout(frameLayout),
|
||||
myPlaybackRate(44100),
|
||||
myPlaybackPeriod(512)
|
||||
myPlaybackPeriod(512),
|
||||
myAudioQueueExtraFragments(1),
|
||||
myAudioQueueHeadroom(2)
|
||||
{}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EmulationTiming::updateFrameLayout(FrameLayout frameLayout)
|
||||
EmulationTiming& EmulationTiming::updateFrameLayout(FrameLayout frameLayout)
|
||||
{
|
||||
myFrameLayout = frameLayout;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EmulationTiming::updatePlaybackRate(uInt32 playbackRate)
|
||||
EmulationTiming& EmulationTiming::updatePlaybackRate(uInt32 playbackRate)
|
||||
{
|
||||
myPlaybackRate = playbackRate;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EmulationTiming::updatePlaybackPeriod(uInt32 playbackPeriod)
|
||||
EmulationTiming& EmulationTiming::updatePlaybackPeriod(uInt32 playbackPeriod)
|
||||
{
|
||||
myPlaybackPeriod = playbackPeriod;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EmulationTiming& EmulationTiming::updateAudioQueueExtraFragments(uInt32 audioQueueExtraFragments)
|
||||
{
|
||||
myAudioQueueExtraFragments = audioQueueExtraFragments;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EmulationTiming& EmulationTiming::updateAudioQueueHeadroom(uInt32 audioQueueHeadroom)
|
||||
{
|
||||
myAudioQueueHeadroom = audioQueueHeadroom;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -124,11 +141,11 @@ uInt32 EmulationTiming::audioQueueCapacity() const
|
|||
{
|
||||
uInt32 minCapacity = discreteDivCeil(maxCyclesPerTimeslice() * audioSampleRate(), audioFragmentSize() * cyclesPerSecond());
|
||||
|
||||
return std::max(prebufferFragmentCount(), minCapacity) + QUEUE_CAPACITY_EXTRA_FRAGMENTS;
|
||||
return std::max(prebufferFragmentCount(), minCapacity) + myAudioQueueExtraFragments;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 EmulationTiming::prebufferFragmentCount() const
|
||||
{
|
||||
return discreteDivCeil(myPlaybackPeriod * audioSampleRate(), audioFragmentSize() * myPlaybackRate) + PREBUFFER_EXTRA_FRAGMENT_COUNT;
|
||||
return discreteDivCeil(myPlaybackPeriod * audioSampleRate(), audioFragmentSize() * myPlaybackRate) + myAudioQueueHeadroom;
|
||||
}
|
||||
|
|
|
@ -26,11 +26,15 @@ class EmulationTiming {
|
|||
|
||||
EmulationTiming(FrameLayout frameLayout = FrameLayout::ntsc);
|
||||
|
||||
void updateFrameLayout(FrameLayout frameLayout);
|
||||
EmulationTiming& updateFrameLayout(FrameLayout frameLayout);
|
||||
|
||||
void updatePlaybackRate(uInt32 playbackRate);
|
||||
EmulationTiming& updatePlaybackRate(uInt32 playbackRate);
|
||||
|
||||
void updatePlaybackPeriod(uInt32 period);
|
||||
EmulationTiming& updatePlaybackPeriod(uInt32 period);
|
||||
|
||||
EmulationTiming& updateAudioQueueExtraFragments(uInt32 audioQueueExtraFragments);
|
||||
|
||||
EmulationTiming& updateAudioQueueHeadroom(uInt32 audioQueueHeadroom);
|
||||
|
||||
uInt32 maxCyclesPerTimeslice() const;
|
||||
|
||||
|
@ -60,6 +64,9 @@ class EmulationTiming {
|
|||
|
||||
uInt32 myPlaybackPeriod;
|
||||
|
||||
uInt32 myAudioQueueExtraFragments;
|
||||
uInt32 myAudioQueueHeadroom;
|
||||
|
||||
private:
|
||||
|
||||
EmulationTiming(const EmulationTiming&) = delete;
|
||||
|
|
|
@ -90,6 +90,7 @@ OSystem::OSystem()
|
|||
myBuildInfo = info.str();
|
||||
|
||||
mySettings = MediaFactory::createSettings(*this);
|
||||
myAudioSettings = AudioSettings(mySettings.get());
|
||||
myRandom = make_unique<Random>(*this);
|
||||
}
|
||||
|
||||
|
@ -321,9 +322,9 @@ FBInitStatus OSystem::createFrameBuffer()
|
|||
void OSystem::createSound()
|
||||
{
|
||||
if(!mySound)
|
||||
mySound = MediaFactory::createAudio(*this);
|
||||
mySound = MediaFactory::createAudio(*this, myAudioSettings);
|
||||
#ifndef SOUND_SUPPORT
|
||||
mySettings->setValue("sound", false);
|
||||
myAudioSettings.setEnabled(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -549,7 +550,7 @@ unique_ptr<Console> OSystem::openConsole(const FilesystemNode& romfile, string&
|
|||
|
||||
// Finally, create the cart with the correct properties
|
||||
if(cart)
|
||||
console = make_unique<Console>(*this, cart, props);
|
||||
console = make_unique<Console>(*this, cart, props, myAudioSettings);
|
||||
}
|
||||
|
||||
return console;
|
||||
|
|
|
@ -44,6 +44,7 @@ class EmulationWorker;
|
|||
#include "FrameBufferConstants.hxx"
|
||||
#include "EventHandlerConstants.hxx"
|
||||
#include "bspf.hxx"
|
||||
#include "AudioSettings.hxx"
|
||||
|
||||
/**
|
||||
This class provides an interface for accessing operating system specific
|
||||
|
@ -481,6 +482,9 @@ class OSystem
|
|||
// Indicates whether to stop the main loop
|
||||
bool myQuitLoop;
|
||||
|
||||
// Audio settings
|
||||
AudioSettings myAudioSettings;
|
||||
|
||||
private:
|
||||
string myBaseDir;
|
||||
string myStateDir;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "OSystem.hxx"
|
||||
#include "Version.hxx"
|
||||
#include "AudioSettings.hxx"
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
#include "DebuggerDialog.hxx"
|
||||
|
@ -69,12 +70,14 @@ Settings::Settings(OSystem& osystem)
|
|||
setInternal("tv.bleed", "0.0");
|
||||
|
||||
// Sound options
|
||||
setInternal("sound", "true");
|
||||
setInternal("aud.mode", "balanced");
|
||||
setInternal("fragsize", "512");
|
||||
setInternal("freq", "44100");
|
||||
setInternal("volume", "100");
|
||||
setInternal("resampling.quality", "2");
|
||||
setInternal(AudioSettings::SETTING_ENABLED, AudioSettings::DEFAULT_ENABLED);
|
||||
setInternal(AudioSettings::SETTING_PRESET, static_cast<int>(AudioSettings::DEFAULT_PRESET));
|
||||
setInternal(AudioSettings::SETTING_SAMPLE_RATE, AudioSettings::DEFAULT_SAMPLE_RATE);
|
||||
setInternal(AudioSettings::SETTING_FRAGMENT_SIZE, AudioSettings::DEFAULT_FRAGMENT_SIZE);
|
||||
setInternal(AudioSettings::SETTING_BUFFER_SIZE, AudioSettings::DEFAULT_BUFFER_SIZE);
|
||||
setInternal(AudioSettings::SETTING_HEADROOM, AudioSettings::DEFAULT_HEADROOM);
|
||||
setInternal(AudioSettings::SETTING_RESAMPLING_QUALITY, static_cast<int>(AudioSettings::DEFAULT_RESAMPLING_QUALITY));
|
||||
setInternal(AudioSettings::SETTING_VOLUME, AudioSettings::DEFAULT_VOLUME);
|
||||
|
||||
// Input event options
|
||||
setInternal("keymap", "");
|
||||
|
@ -361,13 +364,7 @@ void Settings::validate()
|
|||
if(i < 0 || i > 6) setInternal("plr.tm.horizon", 5);*/
|
||||
|
||||
#ifdef SOUND_SUPPORT
|
||||
i = getInt("volume");
|
||||
if(i < 0 || i > 100) setInternal("volume", "100");
|
||||
i = getInt("freq");
|
||||
if(!(i == 44100 || i == 48000 || i == 96000))
|
||||
setInternal("freq", "44100");
|
||||
i = getInt("resampling.quality");
|
||||
if (i < 1 || i > 3) setInternal("resampling.quality", 2);
|
||||
AudioSettings::normalize(*this);
|
||||
#endif
|
||||
|
||||
i = getInt("joydeadzone");
|
||||
|
@ -447,11 +444,14 @@ void Settings::usage() const
|
|||
<< " -uimessages <1|0> Show onscreen UI messages for different events\n"
|
||||
<< endl
|
||||
#ifdef SOUND_SUPPORT
|
||||
<< " -sound <1|0> Enable sound generation\n"
|
||||
<< " -fragsize <number> The size of sound fragments (must be a power of two)\n"
|
||||
<< " -freq <number> Set sound sample output frequency (44100|48000|96000)\n"
|
||||
<< " -resampling.quality <number> Resampling quality (1 -3), default: 2\n"
|
||||
<< " -volume <number> Set the volume (0 - 100)\n"
|
||||
<< " -audio.enabled <1|0> Enable audio\n"
|
||||
<< " -audio.preset <1-5> Audio preset (or 1 for custom)\n"
|
||||
<< " -audio.sample_rate <number> Output sample rate (44100|48000|96000)\n"
|
||||
<< " -audio.fragment_size <number> Fragment size (128|256|512|1024|2048|4096)\n"
|
||||
<< " -audio.buffer_size <number> Max. number of additional half-frames to buffer (0 -- 20)\n"
|
||||
<< " -audio.headroom <number> Additional half-frames to prebuffer (0 -- 20)\n"
|
||||
<< " -audio.resampling_quality <1-3> Resampling quality\n"
|
||||
<< " -audio.volume <number> Vokume (0 -- 100)\n"
|
||||
<< endl
|
||||
#endif
|
||||
<< " -tia.zoom <zoom> Use the specified zoom level (windowed mode) for TIA image\n"
|
||||
|
|
|
@ -89,7 +89,7 @@ class Sound
|
|||
|
||||
@param percent The new volume percentage level for the sound device
|
||||
*/
|
||||
virtual void setVolume(Int32 percent) = 0;
|
||||
virtual void setVolume(uInt32 percent) = 0;
|
||||
|
||||
/**
|
||||
Adjusts the volume of the sound device based on the given direction.
|
||||
|
|
|
@ -20,6 +20,4 @@
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SettingsWINDOWS::SettingsWINDOWS(OSystem& osystem)
|
||||
: Settings(osystem)
|
||||
{
|
||||
setInternal("fragsize", "1024");
|
||||
}
|
||||
{}
|
||||
|
|
Loading…
Reference in New Issue