mirror of https://github.com/stella-emu/stella.git
added option to select audio device (resolves #682)
This commit is contained in:
parent
598e039001
commit
75a74e0be5
|
@ -20,9 +20,9 @@
|
|||
|
||||
* Extended global hotkeys for debug options.
|
||||
|
||||
* Added option to playback a game using the Time Machine
|
||||
* Added option to playback a game using the Time Machine.
|
||||
|
||||
* Allow taking snapshots from within Time Machine dialog
|
||||
* Allow taking snapshots from within Time Machine dialog.
|
||||
|
||||
* Added ability to access most files that Stella uses from within a ZIP
|
||||
file. This includes the following:
|
||||
|
@ -33,7 +33,9 @@
|
|||
Basically, you are now able to put many files that Stella uses inside
|
||||
one ZIP file, and distribute just that file.
|
||||
|
||||
* Replaced "Re-disassemble" with "Disassemble @ current line" in debugger
|
||||
* Added option to select the audio device.
|
||||
|
||||
* Replaced "Re-disassemble" with "Disassemble @ current line" in debugger.
|
||||
|
||||
* Fix bug when taking fullscreen snapshots; the dimensions were sometimes
|
||||
cut off.
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 4.0 KiB |
|
@ -2201,6 +2201,11 @@
|
|||
<td>Set the volume.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-audio.device <number></pre></td>
|
||||
<td>Set the audio device (0 = default).</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-audio.preset <1 - 5></pre></td>
|
||||
<td>Set an audio preset. Numbers in sequence represent presets for
|
||||
|
@ -3084,7 +3089,8 @@
|
|||
<tr><th>Item</th><th>Brief description</th><th>For more information,<br>see <a href="#CommandLine">CommandLine</a></th></tr>
|
||||
<tr><td>Enable audio</td><td>Self-explanatory</td><td>-audio.enabled</td></tr>
|
||||
<tr><td>Volume</td><td>Self-explanatory</td><td>-audio.volume</td></tr>
|
||||
<tr><td>Mode</td><td>Select an audio preset or choose 'custom' for manual configuration</td><td>-audio.preset</td></tr>
|
||||
<tr><td>Device</td><td>Use the specified audio device.</td><td>-audio.device</td></tr>
|
||||
<tr><td>Mode</td><td>Select an audio preset or choose 'Custom' for manual configuration.</td><td>-audio.preset</td></tr>
|
||||
<tr><td>Fragment size</td><td>The number of samples in a single fragment processed by the audio driver. Smaller values mean less latency, but may lead to dropouts (depending on OS and hardware).</td><td>-audio.fragment_size</td></tr>
|
||||
<tr><td>Sample rate</td><td>
|
||||
Output samples per second. Higher values reduce artifacts from resampling and decrease latency,
|
||||
|
@ -3097,7 +3103,7 @@
|
|||
some games (notably Quadrun).
|
||||
</td><td>-audio.resampling_quality</td></tr>
|
||||
<tr><td>Headroom</td><td>Number of frames to buffer before playback starts. Higher values increase latency, but reduce the potential for dropouts.</td><td>-audio.headroom</td></tr>
|
||||
<tr><td>Buffer size</td><td>Maximum size of the audio buffer. Higher values increase maximum latency, but reduce the potential for dropouts</td><td>-audio.buffer_size</td></tr>
|
||||
<tr><td>Buffer size</td><td>Maximum size of the audio buffer. Higher values increase maximum latency, but reduce the potential for dropouts.</td><td>-audio.buffer_size</td></tr>
|
||||
<tr><td>Stereo for all ROMs</td><td>Enable stereo mode for all ROMs.</td><td>-audio.stereo</td></tr>
|
||||
<tr><td>Pitfall II music pitch</td><td>Defines the pitch of Pitfall II music (which may vary between carts).</td><td>-audio.dpc_pitch</td></tr>
|
||||
</table>
|
||||
|
|
|
@ -154,6 +154,12 @@ uInt32 AudioSettings::volume() const
|
|||
return lboundInt(mySettings.getInt(SETTING_VOLUME), 0);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 AudioSettings::device() const
|
||||
{
|
||||
return mySettings.getInt(SETTING_DEVICE);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool AudioSettings::enabled() const
|
||||
{
|
||||
|
@ -285,6 +291,14 @@ void AudioSettings::setVolume(uInt32 volume)
|
|||
normalize(mySettings);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AudioSettings::setDevice(uInt32 device)
|
||||
{
|
||||
if(!myIsPersistent) return;
|
||||
|
||||
mySettings.setValue(SETTING_DEVICE, device);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AudioSettings::setEnabled(bool isEnabled)
|
||||
{
|
||||
|
|
|
@ -48,6 +48,7 @@ class AudioSettings
|
|||
static constexpr const char* SETTING_RESAMPLING_QUALITY = "audio.resampling_quality";
|
||||
static constexpr const char* SETTING_STEREO = "audio.stereo";
|
||||
static constexpr const char* SETTING_VOLUME = "audio.volume";
|
||||
static constexpr const char* SETTING_DEVICE = "audio.device";
|
||||
static constexpr const char* SETTING_ENABLED = "audio.enabled";
|
||||
static constexpr const char* SETTING_DPC_PITCH = "audio.dpc_pitch";
|
||||
|
||||
|
@ -59,6 +60,7 @@ class AudioSettings
|
|||
static constexpr ResamplingQuality DEFAULT_RESAMPLING_QUALITY = ResamplingQuality::lanczos_2;
|
||||
static constexpr bool DEFAULT_STEREO = false;
|
||||
static constexpr uInt32 DEFAULT_VOLUME = 80;
|
||||
static constexpr uInt32 DEFAULT_DEVICE = 0;
|
||||
static constexpr bool DEFAULT_ENABLED = true;
|
||||
static constexpr uInt32 DEFAULT_DPC_PITCH = 20000;
|
||||
|
||||
|
@ -87,6 +89,8 @@ class AudioSettings
|
|||
|
||||
uInt32 volume() const;
|
||||
|
||||
uInt32 device() const;
|
||||
|
||||
bool enabled() const;
|
||||
|
||||
uInt32 dpcPitch() const;
|
||||
|
@ -109,6 +113,8 @@ class AudioSettings
|
|||
|
||||
void setVolume(uInt32 volume);
|
||||
|
||||
void setDevice(uInt32 device);
|
||||
|
||||
void setEnabled(bool isEnabled);
|
||||
|
||||
void setPersistent(bool isPersistent);
|
||||
|
|
|
@ -118,7 +118,7 @@ void FrameBufferSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
|
|||
Logger::debug(s.str());
|
||||
s.str("");
|
||||
lastRes = res.str();
|
||||
s << lastRes << ": ";
|
||||
s << " " << lastRes << ": ";
|
||||
}
|
||||
s << mode.refresh_rate << "Hz";
|
||||
if(mode.w == display.w && mode.h == display.h && mode.refresh_rate == display.refresh_rate)
|
||||
|
|
|
@ -101,6 +101,13 @@ class SoundNull : public Sound
|
|||
*/
|
||||
void adjustVolume(int direction = 1) override { }
|
||||
|
||||
/**
|
||||
Sets the audio device.
|
||||
|
||||
@param device The number of the device to select (0 = default).
|
||||
*/
|
||||
void setDevice(uInt32 device) override { };
|
||||
|
||||
/**
|
||||
This method is called to provide information about the sound device.
|
||||
*/
|
||||
|
|
|
@ -56,6 +56,9 @@ SoundSDL2::SoundSDL2(OSystem& osystem, AudioSettings& audioSettings)
|
|||
return;
|
||||
}
|
||||
|
||||
queryHardware(myDevices);
|
||||
|
||||
|
||||
SDL_zero(myHardwareSpec);
|
||||
if(!openDevice())
|
||||
return;
|
||||
|
@ -76,6 +79,29 @@ SoundSDL2::~SoundSDL2()
|
|||
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL2::queryHardware(VariantList& devices)
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
int numDevices = SDL_GetNumAudioDevices(0);
|
||||
|
||||
// log the available audio devices
|
||||
ostringstream s;
|
||||
s << "Supported audio devices (" << numDevices << "):";
|
||||
Logger::debug(s.str());
|
||||
|
||||
VarList::push_back(devices, "Default", 0);
|
||||
for(int i = 0; i < numDevices; ++i) {
|
||||
ostringstream ss;
|
||||
|
||||
ss << " " << i + 1 << ": " << SDL_GetAudioDeviceName(i, 0);
|
||||
Logger::debug(ss.str());
|
||||
|
||||
VarList::push_back(devices, SDL_GetAudioDeviceName(i, 0), i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool SoundSDL2::openDevice()
|
||||
{
|
||||
|
@ -91,7 +117,11 @@ bool SoundSDL2::openDevice()
|
|||
|
||||
if(myIsInitializedFlag)
|
||||
SDL_CloseAudioDevice(myDevice);
|
||||
myDevice = SDL_OpenAudioDevice(nullptr, 0, &desired, &myHardwareSpec,
|
||||
|
||||
myDeviceId = BSPF::clamp(myAudioSettings.device(), 0u, uInt32(myDevices.size() - 1));
|
||||
const char* device = myDeviceId ? myDevices.at(myDeviceId).first.c_str() : nullptr;
|
||||
|
||||
myDevice = SDL_OpenAudioDevice(device, 0, &desired, &myHardwareSpec,
|
||||
SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
|
||||
|
||||
if(myDevice == 0)
|
||||
|
@ -126,7 +156,8 @@ void SoundSDL2::open(shared_ptr<AudioQueue> audioQueue,
|
|||
// 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))
|
||||
myAudioSettings.fragmentSize() != uInt32(myHardwareSpec.samples) ||
|
||||
myAudioSettings.device() != myDeviceId)
|
||||
openDevice();
|
||||
|
||||
myEmulationTiming = emulationTiming;
|
||||
|
@ -261,6 +292,7 @@ string SoundSDL2::about() const
|
|||
ostringstream buf;
|
||||
buf << "Sound enabled:" << endl
|
||||
<< " Volume: " << myVolume << "%" << endl
|
||||
<< " Device: " << myDevices.at(myDeviceId).first << endl
|
||||
<< " Channels: " << uInt32(myHardwareSpec.channels)
|
||||
<< (myAudioQueue->isStereo() ? " (Stereo)" : " (Mono)") << endl
|
||||
<< " Preset: ";
|
||||
|
|
|
@ -108,6 +108,13 @@ class SoundSDL2 : public Sound
|
|||
string about() const override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
This method is called to query the audio devices.
|
||||
|
||||
@param devices List of device names
|
||||
*/
|
||||
void queryHardware(VariantList& devices);
|
||||
|
||||
/**
|
||||
Invoked by the sound callback to process the next sound fragment.
|
||||
The stream is 16-bits (even though the callback is 8-bits), since
|
||||
|
@ -139,6 +146,8 @@ class SoundSDL2 : public Sound
|
|||
// Audio specification structure
|
||||
SDL_AudioSpec myHardwareSpec;
|
||||
|
||||
uInt32 myDeviceId{0};
|
||||
|
||||
SDL_AudioDeviceID myDevice{0};
|
||||
|
||||
shared_ptr<AudioQueue> myAudioQueue;
|
||||
|
|
|
@ -80,6 +80,7 @@ Settings::Settings()
|
|||
// Sound options
|
||||
setPermanent(AudioSettings::SETTING_ENABLED, AudioSettings::DEFAULT_ENABLED);
|
||||
setPermanent(AudioSettings::SETTING_VOLUME, AudioSettings::DEFAULT_VOLUME);
|
||||
setPermanent(AudioSettings::SETTING_DEVICE, AudioSettings::DEFAULT_DEVICE);
|
||||
setPermanent(AudioSettings::SETTING_PRESET, static_cast<int>(AudioSettings::DEFAULT_PRESET));
|
||||
setPermanent(AudioSettings::SETTING_FRAGMENT_SIZE, AudioSettings::DEFAULT_FRAGMENT_SIZE);
|
||||
setPermanent(AudioSettings::SETTING_SAMPLE_RATE, AudioSettings::DEFAULT_SAMPLE_RATE);
|
||||
|
@ -426,6 +427,7 @@ void Settings::usage() const
|
|||
#ifdef SOUND_SUPPORT
|
||||
<< " -audio.enabled <1|0> Enable audio\n"
|
||||
<< " -audio.volume <0-100> Volume\n"
|
||||
<< " -audio.device <number> ID of the audio device (0 = default)\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|\n"
|
||||
|
|
|
@ -97,10 +97,28 @@ class Sound
|
|||
*/
|
||||
virtual string about() const = 0;
|
||||
|
||||
/**
|
||||
Get the supported devices for the audio hardware.
|
||||
|
||||
@return An array of supported devices
|
||||
*/
|
||||
const VariantList& supportedDevices() const {return myDevices;}
|
||||
|
||||
protected:
|
||||
/**
|
||||
This method is called to query the audio devices.
|
||||
|
||||
@param devices List of device names
|
||||
*/
|
||||
virtual void queryHardware(VariantList& devices) = 0;
|
||||
|
||||
protected:
|
||||
// The OSystem for this sound object
|
||||
OSystem& myOSystem;
|
||||
|
||||
// Supported device
|
||||
VariantList myDevices;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
Sound() = delete;
|
||||
|
|
|
@ -68,7 +68,7 @@ VideoAudioDialog::VideoAudioDialog(OSystem& osystem, DialogContainer& parent,
|
|||
|
||||
// Set real dimensions
|
||||
setSize(44 * fontWidth + HBORDER * 2 + PopUpWidget::dropDownWidth(font) * 2,
|
||||
_th + VGAP * 6 + lineHeight + 10 * (lineHeight + VGAP) + buttonHeight + VBORDER * 3,
|
||||
_th + VGAP * 3 + lineHeight + 11 * (lineHeight + VGAP) + buttonHeight + VBORDER * 3,
|
||||
max_w, max_h);
|
||||
|
||||
// The tab widget
|
||||
|
@ -365,6 +365,14 @@ void VideoAudioDialog::addAudioTab()
|
|||
wid.push_back(myVolumeSlider);
|
||||
ypos += lineHeight + VGAP;
|
||||
|
||||
// Device
|
||||
myDevicePopup = new PopUpWidget(myTab, _font, xpos, ypos,
|
||||
_w - xpos - lwidth - HBORDER - PopUpWidget::dropDownWidth(_font) - 2, lineHeight,
|
||||
instance().sound().supportedDevices(),
|
||||
"Device", lwidth, kDeviceChanged);
|
||||
wid.push_back(myDevicePopup);
|
||||
ypos += lineHeight + VGAP;
|
||||
|
||||
// Mode
|
||||
items.clear();
|
||||
VarList::push_back(items, "Low quality, medium lag", static_cast<int>(AudioSettings::Preset::lowQualityMediumLag));
|
||||
|
@ -542,6 +550,11 @@ void VideoAudioDialog::loadConfig()
|
|||
// Volume
|
||||
myVolumeSlider->setValue(audioSettings.volume());
|
||||
|
||||
// Device
|
||||
uInt32 deviceId = BSPF::clamp(audioSettings.device(), 0u,
|
||||
uInt32(instance().sound().supportedDevices().size() - 1));
|
||||
myDevicePopup->setSelected(deviceId);
|
||||
|
||||
// Stereo
|
||||
myStereoSoundCheckbox->setState(audioSettings.stereo());
|
||||
|
||||
|
@ -666,6 +679,9 @@ void VideoAudioDialog::saveConfig()
|
|||
audioSettings.setVolume(myVolumeSlider->getValue());
|
||||
instance().sound().setVolume(myVolumeSlider->getValue());
|
||||
|
||||
// Device
|
||||
audioSettings.setDevice(myDevicePopup->getSelected());
|
||||
|
||||
// Stereo
|
||||
audioSettings.setStereo(myStereoSoundCheckbox->getState());
|
||||
|
||||
|
@ -754,6 +770,7 @@ void VideoAudioDialog::setDefaults()
|
|||
case 3: // Audio
|
||||
mySoundEnableCheckbox->setState(AudioSettings::DEFAULT_ENABLED);
|
||||
myVolumeSlider->setValue(AudioSettings::DEFAULT_VOLUME);
|
||||
myDevicePopup->setSelected(AudioSettings::DEFAULT_DEVICE);
|
||||
myStereoSoundCheckbox->setState(AudioSettings::DEFAULT_STEREO);
|
||||
myDpcPitch->setValue(AudioSettings::DEFAULT_DPC_PITCH);
|
||||
myModePopup->setSelected(static_cast<int>(AudioSettings::DEFAULT_PRESET));
|
||||
|
@ -1061,6 +1078,7 @@ void VideoAudioDialog::updateEnabledState()
|
|||
bool userMode = preset == AudioSettings::Preset::custom;
|
||||
|
||||
myVolumeSlider->setEnabled(active);
|
||||
myDevicePopup->setEnabled(active);
|
||||
myStereoSoundCheckbox->setEnabled(active);
|
||||
myModePopup->setEnabled(active);
|
||||
// enable only for Pitfall II cart
|
||||
|
|
|
@ -115,6 +115,7 @@ class VideoAudioDialog : public Dialog
|
|||
// Audio
|
||||
CheckboxWidget* mySoundEnableCheckbox{nullptr};
|
||||
SliderWidget* myVolumeSlider{nullptr};
|
||||
PopUpWidget* myDevicePopup{nullptr};
|
||||
CheckboxWidget* myStereoSoundCheckbox{nullptr};
|
||||
PopUpWidget* myModePopup{nullptr};
|
||||
PopUpWidget* myFragsizePopup{nullptr};
|
||||
|
@ -149,6 +150,7 @@ class VideoAudioDialog : public Dialog
|
|||
kScanlinesChanged = 'VDsc',
|
||||
|
||||
kSoundEnableChanged = 'ADse',
|
||||
kDeviceChanged = 'ADdc',
|
||||
kModeChanged = 'ADmc',
|
||||
kHeadroomChanged = 'ADhc',
|
||||
kBufferSizeChanged = 'ADbc'
|
||||
|
|
Loading…
Reference in New Issue