Update to v106r55 release.

byuu says:

Everything *should* be working again, but of course that won't
actually be the case. Here's where things stand:

  - bsnes, higan, icarus, and genius compile and run fine on FreeBSD
    with GTK
  - ruby video and audio drivers are untested on Windows, macOS, and
    Linux
  - hiro is untested on macOS
  - bsnes' status bar is not showing up properly with hiro/qt
  - bsnes and higan's about screen is not showing up properly with
    hiro/qt (1x1 window size)
  - bsnes on Windows crashes often when saving states, and I'm not sure
    why ... it happens inside Encode::RLE
  - bsnes on Windows crashes with ruby.input.windows (unsure why)
  - bsnes on Windows fails to show the verified emblem on the status bar
    properly
  - hiro on Windows flickers when changing tabs

To build the Windows bsnes and higan ports, use

    ruby="video.gdi audio.directsound"

Compilation error logs for Linux will help me fix the inevitable list of
typos there. I can fix the typos on other platforms, I just haven't
gotten to it yet.
This commit is contained in:
Tim Allen
2018-08-05 19:00:15 +10:00
parent 552d385031
commit 5da4532771
117 changed files with 1316 additions and 2383 deletions

View File

@@ -1,63 +1,58 @@
#include <alsa/asoundlib.h>
struct AudioALSA : Audio {
AudioALSA() { initialize(); }
struct AudioALSA : AudioDriver {
AudioALSA& self = *this;
AudioALSA(Audio& super) : AudioDriver(super) {}
~AudioALSA() { terminate(); }
auto create() -> bool override {
super.setDevice(hasDevices().first());
super.setChannels(2);
super.setFrequency(48000);
super.setLatency(20);
return initialize();
}
auto driver() -> string override { return "ALSA"; }
auto ready() -> bool override { return _ready; }
auto hasDevice() -> bool override { return true; }
auto hasBlocking() -> bool override { return true; }
auto hasChannels() -> bool override { return true; }
auto hasFrequency() -> bool override { return true; }
auto hasLatency() -> bool override { return true; }
auto availableDevices() -> vector<string> override {
return queryDevices();
auto hasDevices() -> vector<string> override {
vector<string> devices;
char** list;
if(snd_device_name_hint(-1, "pcm", (void***)&list) == 0) {
uint index = 0;
while(list[index]) {
char* deviceName = snd_device_name_get_hint(list[index], "NAME");
if(deviceName) devices.append(deviceName);
free(deviceName);
index++;
}
}
snd_device_name_free_hint((void**)list);
return devices;
}
auto availableChannels() -> vector<uint> override {
auto hasChannels() -> vector<uint> override {
return {2};
}
auto availableFrequencies() -> vector<double> override {
return {44100.0, 48000.0, 96000.0};
auto hasFrequencies() -> vector<uint> override {
return {44100, 48000, 96000};
}
auto availableLatencies() -> vector<uint> override {
auto hasLatencies() -> vector<uint> override {
return {20, 40, 60, 80, 100};
}
auto setDevice(string device) -> bool override {
if(device == Audio::device()) return true;
if(!Audio::setDevice(device)) return false;
return initialize();
}
auto setBlocking(bool blocking) -> bool override {
if(blocking == Audio::blocking()) return true;
if(!Audio::setBlocking(blocking)) return false;
return true;
}
auto setChannels(uint channels) -> bool override {
if(channels == Audio::channels()) return true;
if(!Audio::setChannels(channels)) return false;
return true;
}
auto setFrequency(double frequency) -> bool override {
if(frequency == Audio::frequency()) return true;
if(!Audio::setFrequency(frequency)) return false;
return initialize();
}
auto setLatency(uint latency) -> bool override {
if(latency == Audio::latency()) return true;
if(!Audio::setLatency(latency)) return false;
return initialize();
}
auto setDevice(string device) -> bool override { return initialize(); }
auto setBlocking(bool blocking) -> bool override { return true; }
auto setChannels(uint channels) -> bool override { return true; }
auto setFrequency(uint frequency) -> bool override { return initialize(); }
auto setLatency(uint latency) -> bool override { return initialize(); }
auto level() -> double override {
snd_pcm_sframes_t available = snd_pcm_avail_update(_interface);
@@ -66,8 +61,6 @@ struct AudioALSA : Audio {
}
auto output(const double samples[]) -> void override {
if(!ready()) return;
_buffer[_offset] = (uint16_t)sclamp<16>(samples[0] * 32767.0) << 0;
_buffer[_offset] |= (uint16_t)sclamp<16>(samples[1] * 32767.0) << 16;
_offset++;
@@ -77,7 +70,7 @@ struct AudioALSA : Audio {
available = snd_pcm_avail_update(_interface);
if(available < 0) snd_pcm_recover(_interface, available, 1);
if(available < _offset) {
if(!_blocking) {
if(!self.blocking) {
_offset = 0;
return;
}
@@ -113,13 +106,12 @@ private:
auto initialize() -> bool {
terminate();
string device = "default";
if(queryDevices().find(_device)) device = _device;
if(snd_pcm_open(&_interface, device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return terminate(), false;
if(!hasDevices().find(self.device)) self.device = hasDevices().first();
if(snd_pcm_open(&_interface, self.device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return terminate(), false;
uint rate = (uint)_frequency;
uint bufferTime = _latency * 1000;
uint periodTime = _latency * 1000 / 8;
uint rate = self.frequency;
uint bufferTime = self.latency * 1000;
uint periodTime = self.latency * 1000 / 8;
snd_pcm_hw_params_t* hardwareParameters;
snd_pcm_hw_params_alloca(&hardwareParameters);
@@ -162,24 +154,6 @@ private:
}
}
auto queryDevices() -> vector<string> {
vector<string> devices;
char** list;
if(snd_device_name_hint(-1, "pcm", (void***)&list) == 0) {
uint index = 0;
while(list[index]) {
char* deviceName = snd_device_name_get_hint(list[index], "NAME");
if(deviceName) devices.append(deviceName);
free(deviceName);
index++;
}
}
snd_device_name_free_hint((void**)list);
return devices;
}
bool _ready = false;
snd_pcm_t* _interface = nullptr;

View File

@@ -1,24 +1,29 @@
#include <ao/ao.h>
struct AudioAO : Audio {
AudioAO() { initialize(); }
struct AudioAO : AudioDriver {
AudioAO& self = *this;
AudioAO(Audio& super) : AudioDriver(super) {}
~AudioAO() { terminate(); }
auto create() -> bool override {
super.setChannels(2);
super.setFrequency(48000);
return initialize();
}
auto driver() -> string override { return "libao"; }
auto ready() -> bool override { return _ready; }
auto hasFrequencies() -> bool override { return true; }
auto availableFrequencies() -> vector<double> override {
return {44100.0, 48000.0, 96000.0};
auto hasChannels() -> vector<uint> override {
return {2};
}
auto setFrequency(double frequency) -> bool override {
if(frequency == Audio::frequency()) return true;
if(!Audio::setFrequency(frequency)) return false;
return initialize();
auto hasFrequencies() -> vector<uint> override {
return {44100, 48000, 96000};
}
auto setFrequency(uint frequency) -> bool override { return initialize(); }
auto output(const double samples[]) -> void override {
uint32_t sample = 0;
sample |= (uint16_t)sclamp<16>(samples[0] * 32767.0) << 0;
@@ -38,7 +43,7 @@ private:
ao_sample_format format;
format.bits = 16;
format.channels = 2;
format.rate = (uint)_frequency;
format.rate = self.frequency;
format.byte_format = AO_FMT_LITTLE;
format.matrix = nullptr;

View File

@@ -2,80 +2,70 @@
#include "asio.hpp"
struct AudioASIO : Audio {
static AudioASIO* self;
AudioASIO() { self = this; initialize(); }
static AudioASIO* instance;
AudioASIO& self = *this;
AudioASIO(Audio& super) : AudioDriver(super) { instance = this; }
~AudioASIO() { terminate(); }
auto create() -> bool override {
super.setDevice(hasDevices().first());
super.setChannels(2);
super.setFrequency(48000);
super.setLatency(2048);
return initialize();
}
auto driver() -> string override { return "ASIO"; }
auto ready() -> bool override { return _ready; }
auto hasContext() -> bool override { return true; }
auto hasDevice() -> bool override { return true; }
auto hasBlocking() -> bool override { return true; }
auto hasChannels() -> bool override { return true; }
auto hasFrequency() -> bool override { return true; }
auto hasLatency() -> bool override { return true; }
auto availableDevices() -> vector<string> override {
auto hasDevices() -> vector<string> override {
self.devices.reset();
for(auto candidate : registry::contents("HKLM\\SOFTWARE\\ASIO\\")) {
if(auto classID = registry::read({"HKLM\\SOFTWARE\\ASIO\\", candidate, "CLSID"})) {
self.devices.append({candidate.trimRight("\\", 1L), classID});
}
}
vector<string> devices;
for(auto& device : _devices) devices.append(device.name);
for(auto& device : self.devices) devices.append(device.name);
return devices;
}
auto availableChannels() -> vector<uint> override {
auto hasChannels() -> vector<uint> override {
return {1, 2};
}
auto availableFrequencies() -> vector<double> override {
return {_frequency};
auto hasFrequencies() -> vector<uint> override {
return {self.frequency};
}
auto availableLatencies() -> vector<uint> override {
auto hasLatencies() -> vector<uint> override {
vector<uint> latencies;
uint latencyList[] = {64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 6144}; //factors of 6144
for(auto& latency : latencyList) {
if(latency < _active.minimumBufferSize) continue;
if(latency > _active.maximumBufferSize) continue;
if(self.activeDevice) {
if(latency < self.activeDevice.minimumBufferSize) continue;
if(latency > self.activeDevice.maximumBufferSize) continue;
}
latencies.append(latency);
}
return latencies;
}
auto setContext(uintptr context) -> bool override {
if(context == Audio::context()) return true;
if(!Audio::setContext(context)) return false;
return initialize();
}
auto setDevice(string device) -> bool override {
if(device == Audio::device()) return true;
if(!Audio::setDevice(device)) return false;
return initialize();
}
auto setBlocking(bool blocking) -> bool override {
if(blocking == Audio::blocking()) return true;
if(!Audio::setBlocking(blocking)) return false;
return initialize();
}
auto setChannels(uint channels) -> bool override {
if(channels == Audio::channels()) return true;
if(!Audio::setChannels(channels)) return false;
return initialize();
}
auto setLatency(uint latency) -> bool override {
if(latency == Audio::latency()) return true;
if(!Audio::setLatency(latency)) return false;
return initialize();
}
auto setContext(uintptr context) -> bool override { return initialize(); }
auto setDevice(string device) -> bool override { return initialize(); }
auto setBlocking(bool blocking) -> bool override { return initialize(); }
auto setChannels(uint channels) -> bool override { return initialize(); }
auto setLatency(uint latency) -> bool override { return initialize(); }
auto clear() -> void override {
if(!ready()) return;
for(uint n : range(_channels)) {
memory::fill<uint8_t>(_channel[n].buffers[0], _latency * _sampleSize);
memory::fill<uint8_t>(_channel[n].buffers[1], _latency * _sampleSize);
for(uint n : range(self.channels)) {
memory::fill<uint8_t>(_channel[n].buffers[0], self.latency * _sampleSize);
memory::fill<uint8_t>(_channel[n].buffers[1], self.latency * _sampleSize);
}
memory::fill<uint8_t>(_queue.samples, sizeof(_queue.samples));
_queue.read = 0;
@@ -85,10 +75,10 @@ struct AudioASIO : Audio {
auto output(const double samples[]) -> void override {
if(!ready()) return;
if(_blocking) {
while(_queue.count >= _latency);
if(self.blocking) {
while(_queue.count >= self.latency);
}
for(uint n : range(_channels)) {
for(uint n : range(self.channels)) {
_queue.samples[_queue.write][n] = samples[n];
}
_queue.write++;
@@ -99,39 +89,40 @@ private:
auto initialize() -> bool {
terminate();
//enumerate available ASIO drivers from the registry
for(auto candidate : registry::contents("HKLM\\SOFTWARE\\ASIO\\")) {
if(auto classID = registry::read({"HKLM\\SOFTWARE\\ASIO\\", candidate, "CLSID"})) {
_devices.append({candidate.trimRight("\\", 1L), classID});
if(candidate == _device) _active = _devices.right();
hasDevices(); //this call populates self.devices
if(!self.devices) return false;
self.activeDevice = {};
for(auto& device : self.devices) {
if(self.device == device.name) {
self.activeDevice = device;
break;
}
}
if(!_devices) return false;
if(!_active.name) {
_active = _devices.left();
_device = _active.name;
if(!self.activeDevice) {
self.activeDevice = self.devices.first();
self.device = self.activeDevice.name;
}
CLSID classID;
if(CLSIDFromString((LPOLESTR)utf16_t(_active.classID), (LPCLSID)&classID) != S_OK) return false;
if(CLSIDFromString((LPOLESTR)utf16_t(self.activeDevice.classID), (LPCLSID)&classID) != S_OK) return false;
if(CoCreateInstance(classID, 0, CLSCTX_INPROC_SERVER, classID, (void**)&_asio) != S_OK) return false;
if(!_asio->init((void*)_context)) return false;
if(_asio->getSampleRate(&_active.sampleRate) != ASE_OK) return false;
if(_asio->getChannels(&_active.inputChannels, &_active.outputChannels) != ASE_OK) return false;
if(!_asio->init((void*)self.context)) return false;
if(_asio->getSampleRate(&self.activeDevice.sampleRate) != ASE_OK) return false;
if(_asio->getChannels(&self.activeDevice.inputChannels, &self.activeDevice.outputChannels) != ASE_OK) return false;
if(_asio->getBufferSize(
&_active.minimumBufferSize,
&_active.maximumBufferSize,
&_active.preferredBufferSize,
&_active.granularity
&self.activeDevice.minimumBufferSize,
&self.activeDevice.maximumBufferSize,
&self.activeDevice.preferredBufferSize,
&self.activeDevice.granularity
) != ASE_OK) return false;
_frequency = _active.sampleRate;
_latency = _latency < _active.minimumBufferSize ? _active.minimumBufferSize : _latency;
_latency = _latency > _active.maximumBufferSize ? _active.maximumBufferSize : _latency;
self.frequency = self.activeDevice.sampleRate;
self.latency = self.latency < self.activeDevice.minimumBufferSize ? self.activeDevice.minimumBufferSize : self.latency;
self.latency = self.latency > self.activeDevice.maximumBufferSize ? self.activeDevice.maximumBufferSize : self.latency;
for(auto n : range(_channels)) {
for(uint n : range(self.channels)) {
_channel[n].isInput = false;
_channel[n].channelNum = n;
_channel[n].buffers[0] = nullptr;
@@ -142,8 +133,8 @@ private:
callbacks.sampleRateDidChange = &AudioASIO::_sampleRateDidChange;
callbacks.asioMessage = &AudioASIO::_asioMessage;
callbacks.bufferSwitchTimeInfo = &AudioASIO::_bufferSwitchTimeInfo;
if(_asio->createBuffers(_channel, _channels, _latency, &callbacks) != ASE_OK) return false;
if(_asio->getLatencies(&_active.inputLatency, &_active.outputLatency) != ASE_OK) return false;
if(_asio->createBuffers(_channel, self.channels, self.latency, &callbacks) != ASE_OK) return false;
if(_asio->getLatencies(&self.activeDevice.inputLatency, &self.activeDevice.outputLatency) != ASE_OK) return false;
//assume for the sake of sanity that all buffers use the same sample format ...
ASIOChannelInfo channelInformation = {};
@@ -167,8 +158,7 @@ private:
auto terminate() -> void {
_ready = false;
_devices.reset();
_active = {};
self.activeDevice = {};
if(_asio) {
_asio->stop();
_asio->disposeBuffers();
@@ -179,33 +169,33 @@ private:
private:
static auto _bufferSwitch(long doubleBufferInput, ASIOBool directProcess) -> void {
return self->bufferSwitch(doubleBufferInput, directProcess);
return instance->bufferSwitch(doubleBufferInput, directProcess);
}
static auto _sampleRateDidChange(ASIOSampleRate sampleRate) -> void {
return self->sampleRateDidChange(sampleRate);
return instance->sampleRateDidChange(sampleRate);
}
static auto _asioMessage(long selector, long value, void* message, double* optional) -> long {
return self->asioMessage(selector, value, message, optional);
return instance->asioMessage(selector, value, message, optional);
}
static auto _bufferSwitchTimeInfo(ASIOTime* parameters, long doubleBufferIndex, ASIOBool directProcess) -> ASIOTime* {
return self->bufferSwitchTimeInfo(parameters, doubleBufferIndex, directProcess);
return instance->bufferSwitchTimeInfo(parameters, doubleBufferIndex, directProcess);
}
auto bufferSwitch(long doubleBufferInput, ASIOBool directProcess) -> void {
for(uint sampleIndex : range(_latency)) {
for(uint sampleIndex : range(self.latency)) {
double samples[8] = {0};
if(_queue.count) {
for(uint n : range(_channels)) {
for(uint n : range(self.channels)) {
samples[n] = _queue.samples[_queue.read][n];
}
_queue.read++;
_queue.count--;
}
for(uint n : range(_channels)) {
for(uint n : range(self.channels)) {
auto buffer = (uint8_t*)_channel[n].buffers[doubleBufferInput];
buffer += sampleIndex * _sampleSize;
@@ -263,6 +253,8 @@ private:
};
struct Device {
explicit operator bool() const { return name; }
string name;
string classID;
@@ -278,12 +270,12 @@ private:
};
Queue _queue;
vector<Device> _devices;
Device _active;
vector<Device> devices;
Device activeDevice;
IASIO* _asio = nullptr;
ASIOBufferInfo _channel[8];
long _sampleFormat;
long _sampleSize;
};
AudioASIO* AudioASIO::self = nullptr;
AudioASIO* AudioASIO::instance = nullptr;

View File

@@ -1,51 +1,33 @@
#include <dsound.h>
struct AudioDirectSound : Audio {
AudioDirectSound() {
Audio::setFrequency(48000.0);
Audio::setLatency(40);
initialize();
}
struct AudioDirectSound : AudioDriver {
AudioDirectSound& self = *this;
AudioDirectSound(Audio& super) : AudioDriver(super) {}
~AudioDirectSound() { terminate(); }
~AudioDirectSound() {
terminate();
auto create() -> bool override {
super.setChannels(2);
super.setFrequency(48000);
super.setLatency(40);
return initialize();
}
auto driver() -> string override { return "DirectSound"; }
auto ready() -> bool override { return _ready; }
auto hasBlocking() -> bool override { return true; }
auto hasFrequency() -> bool override { return true; }
auto hasLatency() -> bool override { return true; }
auto availableFrequencies() -> vector<double> override {
return {44100.0, 48000.0, 96000.0};
auto hasFrequencies() -> vector<uint> override {
return {44100, 48000, 96000};
}
auto availableLatencies() -> vector<uint> override {
auto hasLatencies() -> vector<uint> override {
return {40, 60, 80, 100};
}
auto defaultFrequency() -> double override { return 48000.0; }
auto defaultLatency() -> uint override { return 40; }
auto setBlocking(bool blocking) -> bool override {
if(blocking == Audio::blocking()) return true;
if(!Audio::setBlocking(blocking)) return false;
return true;
}
auto setFrequency(double frequency) -> bool override {
if(frequency == Audio::frequency()) return true;
if(!Audio::setFrequency(frequency)) return false;
return initialize();
}
auto setLatency(uint latency) -> bool override {
if(latency == Audio::latency()) return true;
if(!Audio::setLatency(latency)) return false;
return initialize();
}
auto setBlocking(bool blocking) -> bool override { return true; }
auto setFrequency(uint frequency) -> bool override { return initialize(); }
auto setLatency(uint latency) -> bool override { return initialize(); }
auto clear() -> void override {
if(!ready()) return;
@@ -78,7 +60,7 @@ struct AudioDirectSound : Audio {
if(++_offset < _period) return;
_offset = 0;
if(_blocking) {
if(self.blocking) {
//wait until playback buffer has an empty ring to write new audio data to
while(_ringDistance >= _rings - 1) {
DWORD position;
@@ -115,7 +97,7 @@ private:
terminate();
_rings = 8;
_period = _frequency * _latency / _rings / 1000.0 + 0.5;
_period = self.frequency * self.latency / _rings / 1000.0 + 0.5;
_buffer = new uint32_t[_period * _rings];
_offset = 0;
@@ -131,8 +113,8 @@ private:
WAVEFORMATEX waveFormat = {};
waveFormat.wFormatTag = WAVE_FORMAT_PCM;
waveFormat.nChannels = _channels;
waveFormat.nSamplesPerSec = (uint)_frequency;
waveFormat.nChannels = self.channels;
waveFormat.nSamplesPerSec = self.frequency;
waveFormat.wBitsPerSample = 16;
waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
@@ -145,7 +127,7 @@ private:
secondaryDescription.guid3DAlgorithm = GUID_NULL;
secondaryDescription.lpwfxFormat = &waveFormat;
_interface->CreateSoundBuffer(&secondaryDescription, &_secondary, 0);
_secondary->SetFrequency((uint)_frequency);
_secondary->SetFrequency(self.frequency);
_secondary->SetCurrentPosition(0);
_ready = true;

View File

@@ -7,6 +7,7 @@
#endif
struct AudioOpenAL : AudioDriver {
AudioOpenAL& self = *this;
AudioOpenAL(Audio& driver) : AudioDriver(super) {}
~AudioOpenAL() { terminate(); }
@@ -161,8 +162,6 @@ private:
return true;
}
AudioOpenAL& self = *this;
bool _ready = false;
ALCdevice* _openAL = nullptr;

View File

@@ -14,6 +14,7 @@
#endif
struct AudioOSS : AudioDriver {
AudioOSS& self = *this;
AudioOSS(Audio& super) : AudioDriver(super) {}
~AudioOSS() { terminate(); }
@@ -118,8 +119,6 @@ private:
return true;
}
AudioOSS& self = *this;
int _fd = -1;
int _format = AFMT_S16_LE;
int _bufferSize = 1;

View File

@@ -1,41 +1,32 @@
#include <pulse/pulseaudio.h>
struct AudioPulseAudio : Audio {
AudioPulseAudio() { initialize(); }
AudioPulseAudio& self = *this;
AudioPulseAudio(Audio& super) : AudioDriver(super) {}
~AudioPulseAudio() { terminate(); }
auto create() -> bool override {
super.setFrequency(48000);
super.setLatency(40);
return initialize();
}
auto driver() -> string override { return "PulseAudio"; }
auto ready() -> bool override { return _ready; }
auto hasBlocking() -> bool override { return true; }
auto hasFrequency() -> bool override { return true; }
auto hasLatency() -> bool override { return true; }
auto availableFrequencies() -> vector<double> override {
return {44100.0, 48000.0, 96000.0};
auto hasFrequencies() -> vector<uint> override {
return {44100, 48000, 96000};
}
auto availableLatencies() -> vector<uint> override {
auto hasLatencies() -> vector<uint> override {
return {20, 40, 60, 80, 100};
}
auto setBlocking(bool blocking) -> bool override {
if(blocking == Audio::blocking()) return true;
if(!Audio::setBlocking(blocking)) return false;
return true;
}
auto setFrequency(double frequency) -> bool override {
if(frequency == Audio::frequency()) return true;
if(!Audio::setFrequency(frequency)) return false;
return initialize();
}
auto setLatency(uint latency) -> bool override {
if(latency == Audio::latency()) return true;
if(!Audio::setLatency(latency)) return false;
return initialize();
}
auto setBlocking(bool blocking) -> bool override { return true; }
auto setFrequency(double frequency) -> bool override { return initialize(); }
auto setLatency(uint latency) -> bool override { return initialize(); }
auto output(const double samples[]) -> void override {
pa_stream_begin_write(_stream, (void**)&_buffer, &_period);
@@ -80,12 +71,12 @@ private:
_specification.format = PA_SAMPLE_S16LE;
_specification.channels = 2;
_specification.rate = (uint)_frequency;
_specification.rate = self.frequency;
_stream = pa_stream_new(_context, "audio", &_specification, nullptr);
pa_buffer_attr bufferAttributes;
bufferAttributes.maxlength = -1;
bufferAttributes.tlength = pa_usec_to_bytes(_latency * PA_USEC_PER_MSEC, &_specification);
bufferAttributes.tlength = pa_usec_to_bytes(self.latency * PA_USEC_PER_MSEC, &_specification);
bufferAttributes.prebuf = -1;
bufferAttributes.minreq = -1;
bufferAttributes.fragsize = -1;

View File

@@ -1,24 +1,25 @@
#include <pulse/simple.h>
#include <pulse/error.h>
struct AudioPulseAudioSimple : Audio {
AudioPulseAudioSimple() { initialize(); }
struct AudioPulseAudioSimple : AudioDriver {
AudioPulseAudioSimple& self = *this;
AudioPulseAudioSimple(Audio& super) : AudioDriver(super) {}
~AudioPulseAudioSimple() { terminate(); }
auto create() -> bool override {
super.setBlocking(true);
super.setFrequency(48000);
return initialize();
}
auto driver() -> string override { return "PulseAudioSimple"; }
auto ready() -> bool override { return _ready; }
auto hasFrequency() -> bool override { return true; }
auto availableFrequencies() -> vector<double> override {
return {44100.0, 48000.0, 96000.0};
auto hasFrequencies() -> vector<uint> override {
return {44100, 48000, 96000};
}
auto setFrequency(double frequency) -> bool override {
if(frequency == Audio::frequency()) return true;
if(!Audio::setFrequency(frequency)) return false;
return initialize();
}
auto setFrequency(uint frequency) -> bool override { return initialize(); }
auto output(const double samples[]) -> void override {
if(!ready()) return;
@@ -39,7 +40,7 @@ private:
pa_sample_spec specification;
specification.format = PA_SAMPLE_S16LE;
specification.channels = 2;
specification.rate = (uint)_frequency;
specification.rate = self.frequency;
int error = 0;
_interface = pa_simple_new(

View File

@@ -6,63 +6,45 @@
#include <endpointvolume.h>
#include <functiondiscoverykeys_devpkey.h>
struct AudioWASAPI : Audio {
AudioWASAPI() { initialize(); }
struct AudioWASAPI : AudioDriver {
AudioWASAPI& self = *this;
AudioWASAPI(Audio& super) : AudioDriver(super) {}
~AudioWASAPI() { terminate(); }
auto create() -> bool override {
super.setLatency(40);
return initialize();
}
auto driver() -> string override { return "WASAPI"; }
auto ready() -> bool override { return _ready; }
auto hasExclusive() -> bool override { return true; }
auto hasDevice() -> bool override { return true; }
auto hasBlocking() -> bool override { return true; }
auto hasFrequency() -> bool override { return true; }
auto hasLatency() -> bool override { return true; }
auto availableDevices() -> vector<string> override {
auto hasDevices() -> vector<string> override {
return _devices;
}
auto availableFrequencies() -> vector<double> override {
return {_frequency};
auto hasChannels() -> vector<uint> override {
return {self.channels};
}
auto hasFrequencies() -> vector<uint> override {
return {self.frequency};
}
auto availableLatencies() -> vector<uint> override {
return {0, 20, 40, 60, 80, 100};
}
auto setExclusive(bool exclusive) -> bool override {
if(exclusive == Audio::exclusive()) return true;
if(!Audio::setExclusive(exclusive)) return false;
return initialize();
}
auto setDevice(string device) -> bool override {
if(device == Audio::device()) return true;
if(!Audio::setDevice(device)) return false;
return initialize();
}
auto setBlocking(bool blocking) -> bool override {
if(blocking == Audio::blocking()) return true;
if(!Audio::setBlocking(blocking)) return false;
return true;
}
auto setFrequency(double frequency) -> bool override {
if(frequency == Audio::frequency()) return true;
if(!Audio::setFrequency(frequency)) return false;
return initialize();
}
auto setLatency(uint latency) -> bool override {
if(latency == Audio::latency()) return true;
if(!Audio::setLatency(latency)) return false;
return initialize();
}
auto setExclusive(bool exclusive) -> bool override { return initialize(); }
auto setDevice(string device) -> bool override { return initialize(); }
auto setBlocking(bool blocking) -> bool override { return true; }
auto setFrequency(uint frequency) -> bool override { return initialize(); }
auto setLatency(uint latency) -> bool override { return initialize(); }
auto clear() -> void override {
if(!ready()) return;
_queue.read = 0;
_queue.write = 0;
_queue.count = 0;
@@ -72,8 +54,6 @@ struct AudioWASAPI : Audio {
}
auto output(const double samples[]) -> void override {
if(!ready()) return;
for(uint n : range(_channels)) {
_queue.samples[_queue.write][n] = samples[n];
}
@@ -81,7 +61,7 @@ struct AudioWASAPI : Audio {
_queue.count++;
if(_queue.count >= _bufferSize) {
if(WaitForSingleObject(_eventHandle, _blocking ? INFINITE : 0) == WAIT_OBJECT_0) {
if(WaitForSingleObject(_eventHandle, self.blocking ? INFINITE : 0) == WAIT_OBJECT_0) {
write();
}
}
@@ -131,7 +111,7 @@ private:
waveFormat = *(WAVEFORMATEXTENSIBLE*)propVariant.blob.pBlobData;
propertyStore->Release();
if(_audioClient->GetDevicePeriod(nullptr, &_devicePeriod) != S_OK) return false;
auto latency = max(_devicePeriod, (REFERENCE_TIME)_latency * 10'000); //1ms to 100ns units
auto latency = max(_devicePeriod, (REFERENCE_TIME)self.latency * 10'000); //1ms to 100ns units
auto result = _audioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, latency, latency, &waveFormat.Format, nullptr);
if(result == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) {
if(_audioClient->GetBufferSize(&_bufferSize) != S_OK) return false;
@@ -149,7 +129,7 @@ private:
waveFormat = *(WAVEFORMATEXTENSIBLE*)waveFormatEx;
CoTaskMemFree(waveFormatEx);
if(_audioClient->GetDevicePeriod(&_devicePeriod, nullptr)) return false;
auto latency = max(_devicePeriod, (REFERENCE_TIME)_latency * 10'000); //1ms to 100ns units
auto latency = max(_devicePeriod, (REFERENCE_TIME)self.latency * 10'000); //1ms to 100ns units
if(_audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, latency, 0, &waveFormat.Format, nullptr) != S_OK) return false;
}
@@ -158,8 +138,8 @@ private:
if(_audioClient->GetService(IID_IAudioRenderClient, (void**)&_renderClient) != S_OK) return false;
if(_audioClient->GetBufferSize(&_bufferSize) != S_OK) return false;
_channels = waveFormat.Format.nChannels;
_frequency = waveFormat.Format.nSamplesPerSec;
self.channels = waveFormat.Format.nChannels;
self.frequency = waveFormat.Format.nSamplesPerSec;
_mode = waveFormat.SubFormat.Data1;
_precision = waveFormat.Format.wBitsPerSample;

View File

@@ -1,42 +1,33 @@
#include "xaudio2.hpp"
#include <windows.h>
struct AudioXAudio2 : Audio, public IXAudio2VoiceCallback {
AudioXAudio2() { initialize(); }
struct AudioXAudio2 : AudioDriver, public IXAudio2VoiceCallback {
AudioXAudio2& self = *this;
AudioXAudio2(Audio& super) : AudioDriver(super) {}
~AudioXAudio2() { terminate(); }
auto create() -> bool override {
super.setFrequency(48000);
super.setLatency(40);
return initialize();
}
auto driver() -> string override { return "XAudio2"; }
auto ready() -> bool override { return _ready; }
auto hasBlocking() -> bool override { return true; }
auto hasFrequency() -> bool override { return true; }
auto hasLatency() -> bool override { return true; }
auto availableFrequencies() -> vector<double> override {
return {44100.0, 48000.0, 96000.0};
auto hasFrequencies() -> vector<uint> override {
return {44100, 48000, 96000};
}
auto availableLatencies() -> vector<uint> override {
auto hasLatencies() -> vector<uint> override {
return {20, 40, 60, 80, 100};
}
auto setBlocking(bool blocking) -> bool override {
if(blocking == Audio::blocking()) return true;
if(!Audio::setBlocking(blocking)) return false;
return true;
}
auto setFrequency(double frequency) -> bool override {
if(frequency == Audio::frequency()) return true;
if(!Audio::setFrequency(frequency)) return false;
return initialize();
}
auto setLatency(uint latency) -> bool override {
if(latency == Audio::latency()) return true;
if(!Audio::setLatency(latency)) return false;
return initialize();
}
auto setBlocking(bool blocking) -> bool override { return true; }
auto setFrequency(uint frequency) -> bool override { return initialize(); }
auto setLatency(uint latency) -> bool override { return initialize(); }
auto clear() -> void override {
if(!_sourceVoice) return;
@@ -58,7 +49,7 @@ struct AudioXAudio2 : Audio, public IXAudio2VoiceCallback {
_bufferOffset = 0;
if(_bufferQueue == _bufferCount - 1) {
if(_blocking) {
if(self.blocking) {
//wait until there is at least one other free buffer for the next sample
while(_bufferQueue == _bufferCount - 1);
} else { //we need one free buffer for the next sample, so ignore the current contents
@@ -75,7 +66,7 @@ private:
terminate();
_bufferCount = 8;
_period = _frequency * _latency / _bufferCount / 1000.0 + 0.5;
_period = self.frequency * self.latency / _bufferCount / 1000.0 + 0.5;
_buffer = new uint32_t[_period * _bufferCount];
_bufferOffset = 0;
_bufferIndex = 0;
@@ -94,12 +85,12 @@ private:
if(deviceDetails.Role & DefaultGameDevice) deviceID = deviceIndex;
}
if(FAILED(_interface->CreateMasteringVoice(&_masterVoice, _channels, (uint)_frequency, 0, deviceID, nullptr))) return terminate(), false;
if(FAILED(_interface->CreateMasteringVoice(&_masterVoice, _channels, self.frequency, 0, deviceID, nullptr))) return terminate(), false;
WAVEFORMATEX waveFormat;
waveFormat.wFormatTag = WAVE_FORMAT_PCM;
waveFormat.nChannels = _channels;
waveFormat.nSamplesPerSec = (uint)_frequency;
waveFormat.nSamplesPerSec = self.frequency;
waveFormat.nBlockAlign = 4;
waveFormat.wBitsPerSample = 16;
waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;