added option to select audio device (resolves #682)

This commit is contained in:
thrust26 2020-07-27 09:43:31 +02:00
parent 598e039001
commit 75a74e0be5
13 changed files with 125 additions and 9 deletions

View File

@ -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

View File

@ -2201,6 +2201,11 @@
<td>Set the volume.</td>
</tr>
<tr>
<td><pre>-audio.device &lt;number&gt;</pre></td>
<td>Set the audio device (0 = default).</td>
</tr>
<tr>
<td><pre>-audio.preset &lt;1 - 5&gt;</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>

View File

@ -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)
{

View File

@ -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);

View File

@ -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)

View File

@ -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.
*/

View File

@ -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: ";

View File

@ -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;

View File

@ -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"

View File

@ -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;

View File

@ -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

View File

@ -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'