mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-08-11 16:44:49 +02:00
v114.5
* improved appended firmware detection [devinacker] * added dynamic rate control support to ALSA and PulseAudio drivers [RedDwarf] * added option to use native file dialogs
This commit is contained in:
@@ -17,6 +17,7 @@ struct AudioALSA : AudioDriver {
|
||||
auto ready() -> bool override { return _ready; }
|
||||
|
||||
auto hasBlocking() -> bool override { return true; }
|
||||
auto hasDynamic() -> bool override { return true; }
|
||||
|
||||
auto hasDevices() -> vector<string> override {
|
||||
vector<string> devices;
|
||||
@@ -55,20 +56,27 @@ struct AudioALSA : AudioDriver {
|
||||
auto setLatency(uint latency) -> bool override { return initialize(); }
|
||||
|
||||
auto level() -> double override {
|
||||
snd_pcm_sframes_t available = snd_pcm_avail_update(_interface);
|
||||
if(available < 0) return 0.5;
|
||||
snd_pcm_sframes_t available;
|
||||
for(uint timeout : range(256)) {
|
||||
available = snd_pcm_avail_update(_interface);
|
||||
if(available >= 0) break;
|
||||
snd_pcm_recover(_interface, available, 1);
|
||||
}
|
||||
return (double)(_bufferSize - available) / _bufferSize;
|
||||
}
|
||||
|
||||
auto output(const double samples[]) -> void override {
|
||||
_buffer[_offset] = (uint16_t)sclamp<16>(samples[0] * 32767.0) << 0;
|
||||
_buffer[_offset] |= (uint16_t)sclamp<16>(samples[1] * 32767.0) << 16;
|
||||
_offset++;
|
||||
if(++_offset < _periodSize) return;
|
||||
|
||||
snd_pcm_sframes_t available;
|
||||
do {
|
||||
available = snd_pcm_avail_update(_interface);
|
||||
if(available < 0) snd_pcm_recover(_interface, available, 1);
|
||||
if(available < 0) {
|
||||
snd_pcm_recover(_interface, available, 1);
|
||||
continue;
|
||||
}
|
||||
if(available < _offset) {
|
||||
if(!self.blocking) {
|
||||
_offset = 0;
|
||||
|
@@ -52,6 +52,11 @@ struct AudioASIO : AudioDriver {
|
||||
}
|
||||
latencies.append(latency);
|
||||
}
|
||||
//it is possible that no latencies in the hard-coded list above will match; so ensure driver-declared latencies are available
|
||||
if(!latencies.find(self.activeDevice.minimumBufferSize)) latencies.append(self.activeDevice.minimumBufferSize);
|
||||
if(!latencies.find(self.activeDevice.maximumBufferSize)) latencies.append(self.activeDevice.maximumBufferSize);
|
||||
if(!latencies.find(self.activeDevice.preferredBufferSize)) latencies.append(self.activeDevice.preferredBufferSize);
|
||||
latencies.sort();
|
||||
return latencies;
|
||||
}
|
||||
|
||||
@@ -75,6 +80,15 @@ struct AudioASIO : AudioDriver {
|
||||
|
||||
auto output(const double samples[]) -> void override {
|
||||
if(!ready()) return;
|
||||
//defer call to IASIO::start(), because the drivers themselves will sometimes crash internally.
|
||||
//if software initializes AudioASIO but does not play music at startup, this can prevent a crash loop.
|
||||
if(!_started) {
|
||||
_started = true;
|
||||
if(_asio->start() != ASE_OK) {
|
||||
_ready = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(self.blocking) {
|
||||
while(_queue.count >= self.latency);
|
||||
}
|
||||
@@ -151,13 +165,14 @@ private:
|
||||
}
|
||||
|
||||
_ready = true;
|
||||
_started = false;
|
||||
clear();
|
||||
if(_asio->start() != ASE_OK) return _ready = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
auto terminate() -> void {
|
||||
_ready = false;
|
||||
_started = false;
|
||||
self.activeDevice = {};
|
||||
if(_asio) {
|
||||
_asio->stop();
|
||||
@@ -244,6 +259,7 @@ private:
|
||||
}
|
||||
|
||||
bool _ready = false;
|
||||
bool _started = false;
|
||||
|
||||
struct Queue {
|
||||
double samples[65536][8];
|
||||
|
@@ -242,10 +242,10 @@ auto Audio::hasDrivers() -> vector<string> {
|
||||
}
|
||||
|
||||
auto Audio::optimalDriver() -> string {
|
||||
#if defined(AUDIO_ASIO)
|
||||
return "ASIO";
|
||||
#elif defined(AUDIO_WASAPI)
|
||||
#if defined(AUDIO_WASAPI)
|
||||
return "WASAPI";
|
||||
#elif defined(AUDIO_ASIO)
|
||||
return "ASIO";
|
||||
#elif defined(AUDIO_XAUDIO2)
|
||||
return "XAudio 2.1";
|
||||
#elif defined(AUDIO_DIRECTSOUND)
|
||||
|
@@ -15,6 +15,7 @@ struct AudioPulseAudio : AudioDriver {
|
||||
auto ready() -> bool override { return _ready; }
|
||||
|
||||
auto hasBlocking() -> bool override { return true; }
|
||||
auto hasDynamic() -> bool override { return true; }
|
||||
|
||||
auto hasFrequencies() -> vector<uint> override {
|
||||
return {44100, 48000, 96000};
|
||||
@@ -28,6 +29,12 @@ struct AudioPulseAudio : AudioDriver {
|
||||
auto setFrequency(uint frequency) -> bool override { return initialize(); }
|
||||
auto setLatency(uint latency) -> bool override { return initialize(); }
|
||||
|
||||
auto level() -> double override {
|
||||
pa_mainloop_iterate(_mainLoop, 0, nullptr);
|
||||
auto length = pa_stream_writable_size(_stream);
|
||||
return (double)(_bufferSize - length) / _bufferSize;
|
||||
}
|
||||
|
||||
auto output(const double samples[]) -> void override {
|
||||
pa_stream_begin_write(_stream, (void**)&_buffer, &_period);
|
||||
_buffer[_offset] = (uint16_t)sclamp<16>(samples[0] * 32767.0) << 0;
|
||||
@@ -35,13 +42,8 @@ struct AudioPulseAudio : AudioDriver {
|
||||
if((++_offset + 1) * pa_frame_size(&_specification) <= _period) return;
|
||||
|
||||
while(true) {
|
||||
if(_first) {
|
||||
_first = false;
|
||||
pa_mainloop_iterate(_mainLoop, 0, nullptr);
|
||||
} else {
|
||||
pa_mainloop_iterate(_mainLoop, 1, nullptr);
|
||||
}
|
||||
uint length = pa_stream_writable_size(_stream);
|
||||
pa_mainloop_iterate(_mainLoop, 0, nullptr);
|
||||
auto length = pa_stream_writable_size(_stream);
|
||||
if(length >= _offset * pa_frame_size(&_specification)) break;
|
||||
if(!self.blocking) {
|
||||
_offset = 0;
|
||||
@@ -91,9 +93,10 @@ private:
|
||||
if(!PA_STREAM_IS_GOOD(streamState)) return false;
|
||||
} while(streamState != PA_STREAM_READY);
|
||||
|
||||
_period = 960;
|
||||
pa_buffer_attr* attributes = pa_stream_get_buffer_attr(_stream);
|
||||
_period = attributes->minreq;
|
||||
_bufferSize = attributes->tlength;
|
||||
_offset = 0;
|
||||
_first = true;
|
||||
return _ready = true;
|
||||
}
|
||||
|
||||
@@ -127,11 +130,11 @@ private:
|
||||
|
||||
uint32_t* _buffer = nullptr;
|
||||
size_t _period = 0;
|
||||
size_t _bufferSize = 0;
|
||||
uint _offset = 0;
|
||||
|
||||
pa_mainloop* _mainLoop = nullptr;
|
||||
pa_context* _context = nullptr;
|
||||
pa_stream* _stream = nullptr;
|
||||
pa_sample_spec _specification;
|
||||
bool _first = true;
|
||||
};
|
||||
|
Reference in New Issue
Block a user