* 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:
byuu
2020-02-23 20:23:25 +09:00
parent c13745d753
commit d2211d8818
63 changed files with 1091 additions and 1154 deletions

View File

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

View File

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

View File

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

View File

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