mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-08-19 08:41:23 +02:00
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:
@@ -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;
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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(
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user