bsnes/ruby/audio/openal.cpp

195 lines
5.1 KiB
C++
Raw Normal View History

#if defined(PLATFORM_MACOSX)
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#else
#include <AL/al.h>
#include <AL/alc.h>
#endif
struct AudioOpenAL : Audio {
~AudioOpenAL() { term(); }
struct {
Update to v094r23 release. byuu says: The library window is gone, and replaced with hiro::BrowserWindow::openFolder(). This gives navigation capabilities to game loading, and it also completes our slotted cart selection code. As an added bonus, it's less code this way, too. I also set the window size to consistent sizes between all emulated systems, so that switching between SFC and GB don't cause the window size to keep changing, and so that the scaling size is consistent (eg at normal scale, GB @ 3x is closer to SNES @ 2x.) This means black borders in GB/GBA mode, but it doesn't look that bad, and it's not like many people ever use these modes anyway. Finally, added the placeholder tabs for video, audio and timing. I don't intend to add the timing calculator code to v095 (it might be better as a separate tool), but I'll add the ability to set video/audio rates, at least. Glitch 1: despite selecting the first item in the BrowserDialog list, if you press enter when the window appears, it doesn't activate the item until you press an arrow key first. Glitch 2: in Game Boy mode, if you set the 4x window size, it's not honoring the full requested height because the viewport is smaller than the window. 8+ years of trying to get GTK+ and Qt to simply set the god damned window size I ask for, and I still can't get them to do it reliably. Remaining issues: - finish configuration panels (video, audio, timing) - fix ruby driver compilation on Windows - add DIP switch selection window (NSS) [I may end up punting this one to v096]
2015-05-30 11:39:09 +00:00
ALCdevice* handle = nullptr;
ALCcontext* context = nullptr;
ALuint source = 0;
ALenum format = AL_FORMAT_STEREO16;
unsigned latency = 0;
unsigned queueLength = 0;
} device;
struct {
Update to v094r23 release. byuu says: The library window is gone, and replaced with hiro::BrowserWindow::openFolder(). This gives navigation capabilities to game loading, and it also completes our slotted cart selection code. As an added bonus, it's less code this way, too. I also set the window size to consistent sizes between all emulated systems, so that switching between SFC and GB don't cause the window size to keep changing, and so that the scaling size is consistent (eg at normal scale, GB @ 3x is closer to SNES @ 2x.) This means black borders in GB/GBA mode, but it doesn't look that bad, and it's not like many people ever use these modes anyway. Finally, added the placeholder tabs for video, audio and timing. I don't intend to add the timing calculator code to v095 (it might be better as a separate tool), but I'll add the ability to set video/audio rates, at least. Glitch 1: despite selecting the first item in the BrowserDialog list, if you press enter when the window appears, it doesn't activate the item until you press an arrow key first. Glitch 2: in Game Boy mode, if you set the 4x window size, it's not honoring the full requested height because the viewport is smaller than the window. 8+ years of trying to get GTK+ and Qt to simply set the god damned window size I ask for, and I still can't get them to do it reliably. Remaining issues: - finish configuration panels (video, audio, timing) - fix ruby driver compilation on Windows - add DIP switch selection window (NSS) [I may end up punting this one to v096]
2015-05-30 11:39:09 +00:00
uint32_t* data = nullptr;
unsigned length = 0;
unsigned size = 0;
} buffer;
struct {
Update to v094r23 release. byuu says: The library window is gone, and replaced with hiro::BrowserWindow::openFolder(). This gives navigation capabilities to game loading, and it also completes our slotted cart selection code. As an added bonus, it's less code this way, too. I also set the window size to consistent sizes between all emulated systems, so that switching between SFC and GB don't cause the window size to keep changing, and so that the scaling size is consistent (eg at normal scale, GB @ 3x is closer to SNES @ 2x.) This means black borders in GB/GBA mode, but it doesn't look that bad, and it's not like many people ever use these modes anyway. Finally, added the placeholder tabs for video, audio and timing. I don't intend to add the timing calculator code to v095 (it might be better as a separate tool), but I'll add the ability to set video/audio rates, at least. Glitch 1: despite selecting the first item in the BrowserDialog list, if you press enter when the window appears, it doesn't activate the item until you press an arrow key first. Glitch 2: in Game Boy mode, if you set the 4x window size, it's not honoring the full requested height because the viewport is smaller than the window. 8+ years of trying to get GTK+ and Qt to simply set the god damned window size I ask for, and I still can't get them to do it reliably. Remaining issues: - finish configuration panels (video, audio, timing) - fix ruby driver compilation on Windows - add DIP switch selection window (NSS) [I may end up punting this one to v096]
2015-05-30 11:39:09 +00:00
bool synchronize = true;
Update to v098r01 release. byuu says: Changelog: - SFC: balanced profile removed - SFC: performance profile removed - SFC: code for handling non-threaded CPU, SMP, DSP, PPU removed - SFC: Coprocessor, Controller (and expansion port) shared Thread code merged to SFC::Cothread - Cothread here just means "Thread with CPU affinity" (couldn't think of a better name, sorry) - SFC: CPU now has vector<Thread*> coprocessors, peripherals; - this is the beginning of work to allow expansion port devices to be dynamically changed at run-time - ruby: all audio drivers default to 48000hz instead of 22050hz now if no frequency is assigned - note: the WASAPI driver can default to whatever the native frequency is; doesn't have to be 48000hz - tomoko: removed the ability to change the frequency from the UI (but it will display the frequency used) - tomoko: removed the timing settings panel - the goal is to work toward smooth video via adaptive sync - the model is broken by not being in control of the audio frequency anyway - it's further broken by PAL running at 50hz and WSC running at 75hz - it was always broken anyway by SNES interlace timing varying from progressive timing - higan: audio/ stub created (for now, it's just nall/dsp/ moved here and included as a header) - higan: video/ stub created - higan/GNUmakefile: now includes build rules for essential components (libco, emulator, audio, video) The audio changes are in preparation to merge wareya's awesome WASAPI work without the need for the nall/dsp resampler.
2016-04-09 03:40:12 +00:00
unsigned frequency = 48000;
Update to v094r23 release. byuu says: The library window is gone, and replaced with hiro::BrowserWindow::openFolder(). This gives navigation capabilities to game loading, and it also completes our slotted cart selection code. As an added bonus, it's less code this way, too. I also set the window size to consistent sizes between all emulated systems, so that switching between SFC and GB don't cause the window size to keep changing, and so that the scaling size is consistent (eg at normal scale, GB @ 3x is closer to SNES @ 2x.) This means black borders in GB/GBA mode, but it doesn't look that bad, and it's not like many people ever use these modes anyway. Finally, added the placeholder tabs for video, audio and timing. I don't intend to add the timing calculator code to v095 (it might be better as a separate tool), but I'll add the ability to set video/audio rates, at least. Glitch 1: despite selecting the first item in the BrowserDialog list, if you press enter when the window appears, it doesn't activate the item until you press an arrow key first. Glitch 2: in Game Boy mode, if you set the 4x window size, it's not honoring the full requested height because the viewport is smaller than the window. 8+ years of trying to get GTK+ and Qt to simply set the god damned window size I ask for, and I still can't get them to do it reliably. Remaining issues: - finish configuration panels (video, audio, timing) - fix ruby driver compilation on Windows - add DIP switch selection window (NSS) [I may end up punting this one to v096]
2015-05-30 11:39:09 +00:00
unsigned latency = 40;
} settings;
auto cap(const string& name) -> bool {
if(name == Audio::Synchronize) return true;
if(name == Audio::Frequency) return true;
if(name == Audio::Latency) return true;
return false;
}
auto get(const string& name) -> any {
if(name == Audio::Synchronize) return settings.synchronize;
if(name == Audio::Frequency) return settings.frequency;
if(name == Audio::Latency) return settings.latency;
Update to v094r23 release. byuu says: The library window is gone, and replaced with hiro::BrowserWindow::openFolder(). This gives navigation capabilities to game loading, and it also completes our slotted cart selection code. As an added bonus, it's less code this way, too. I also set the window size to consistent sizes between all emulated systems, so that switching between SFC and GB don't cause the window size to keep changing, and so that the scaling size is consistent (eg at normal scale, GB @ 3x is closer to SNES @ 2x.) This means black borders in GB/GBA mode, but it doesn't look that bad, and it's not like many people ever use these modes anyway. Finally, added the placeholder tabs for video, audio and timing. I don't intend to add the timing calculator code to v095 (it might be better as a separate tool), but I'll add the ability to set video/audio rates, at least. Glitch 1: despite selecting the first item in the BrowserDialog list, if you press enter when the window appears, it doesn't activate the item until you press an arrow key first. Glitch 2: in Game Boy mode, if you set the 4x window size, it's not honoring the full requested height because the viewport is smaller than the window. 8+ years of trying to get GTK+ and Qt to simply set the god damned window size I ask for, and I still can't get them to do it reliably. Remaining issues: - finish configuration panels (video, audio, timing) - fix ruby driver compilation on Windows - add DIP switch selection window (NSS) [I may end up punting this one to v096]
2015-05-30 11:39:09 +00:00
return {};
}
auto set(const string& name, const any& value) -> bool {
Update to v094r23 release. byuu says: The library window is gone, and replaced with hiro::BrowserWindow::openFolder(). This gives navigation capabilities to game loading, and it also completes our slotted cart selection code. As an added bonus, it's less code this way, too. I also set the window size to consistent sizes between all emulated systems, so that switching between SFC and GB don't cause the window size to keep changing, and so that the scaling size is consistent (eg at normal scale, GB @ 3x is closer to SNES @ 2x.) This means black borders in GB/GBA mode, but it doesn't look that bad, and it's not like many people ever use these modes anyway. Finally, added the placeholder tabs for video, audio and timing. I don't intend to add the timing calculator code to v095 (it might be better as a separate tool), but I'll add the ability to set video/audio rates, at least. Glitch 1: despite selecting the first item in the BrowserDialog list, if you press enter when the window appears, it doesn't activate the item until you press an arrow key first. Glitch 2: in Game Boy mode, if you set the 4x window size, it's not honoring the full requested height because the viewport is smaller than the window. 8+ years of trying to get GTK+ and Qt to simply set the god damned window size I ask for, and I still can't get them to do it reliably. Remaining issues: - finish configuration panels (video, audio, timing) - fix ruby driver compilation on Windows - add DIP switch selection window (NSS) [I may end up punting this one to v096]
2015-05-30 11:39:09 +00:00
if(name == Audio::Synchronize && value.is<bool>()) {
settings.synchronize = value.get<bool>();
return true;
}
Update to v094r23 release. byuu says: The library window is gone, and replaced with hiro::BrowserWindow::openFolder(). This gives navigation capabilities to game loading, and it also completes our slotted cart selection code. As an added bonus, it's less code this way, too. I also set the window size to consistent sizes between all emulated systems, so that switching between SFC and GB don't cause the window size to keep changing, and so that the scaling size is consistent (eg at normal scale, GB @ 3x is closer to SNES @ 2x.) This means black borders in GB/GBA mode, but it doesn't look that bad, and it's not like many people ever use these modes anyway. Finally, added the placeholder tabs for video, audio and timing. I don't intend to add the timing calculator code to v095 (it might be better as a separate tool), but I'll add the ability to set video/audio rates, at least. Glitch 1: despite selecting the first item in the BrowserDialog list, if you press enter when the window appears, it doesn't activate the item until you press an arrow key first. Glitch 2: in Game Boy mode, if you set the 4x window size, it's not honoring the full requested height because the viewport is smaller than the window. 8+ years of trying to get GTK+ and Qt to simply set the god damned window size I ask for, and I still can't get them to do it reliably. Remaining issues: - finish configuration panels (video, audio, timing) - fix ruby driver compilation on Windows - add DIP switch selection window (NSS) [I may end up punting this one to v096]
2015-05-30 11:39:09 +00:00
if(name == Audio::Frequency && value.is<unsigned>()) {
settings.frequency = value.get<unsigned>();
return true;
}
Update to v094r23 release. byuu says: The library window is gone, and replaced with hiro::BrowserWindow::openFolder(). This gives navigation capabilities to game loading, and it also completes our slotted cart selection code. As an added bonus, it's less code this way, too. I also set the window size to consistent sizes between all emulated systems, so that switching between SFC and GB don't cause the window size to keep changing, and so that the scaling size is consistent (eg at normal scale, GB @ 3x is closer to SNES @ 2x.) This means black borders in GB/GBA mode, but it doesn't look that bad, and it's not like many people ever use these modes anyway. Finally, added the placeholder tabs for video, audio and timing. I don't intend to add the timing calculator code to v095 (it might be better as a separate tool), but I'll add the ability to set video/audio rates, at least. Glitch 1: despite selecting the first item in the BrowserDialog list, if you press enter when the window appears, it doesn't activate the item until you press an arrow key first. Glitch 2: in Game Boy mode, if you set the 4x window size, it's not honoring the full requested height because the viewport is smaller than the window. 8+ years of trying to get GTK+ and Qt to simply set the god damned window size I ask for, and I still can't get them to do it reliably. Remaining issues: - finish configuration panels (video, audio, timing) - fix ruby driver compilation on Windows - add DIP switch selection window (NSS) [I may end up punting this one to v096]
2015-05-30 11:39:09 +00:00
if(name == Audio::Latency && value.is<unsigned>()) {
if(settings.latency != value.get<unsigned>()) {
settings.latency = value.get<unsigned>();
updateLatency();
}
return true;
}
return false;
}
auto sample(int16_t left, int16_t right) -> void {
buffer.data[buffer.length++] = (uint16_t)left << 0 | (uint16_t)right << 16;
if(buffer.length < buffer.size) return;
ALuint albuffer = 0;
int processed = 0;
while(true) {
alGetSourcei(device.source, AL_BUFFERS_PROCESSED, &processed);
while(processed--) {
alSourceUnqueueBuffers(device.source, 1, &albuffer);
alDeleteBuffers(1, &albuffer);
device.queueLength--;
}
//wait for buffer playback to catch up to sample generation if not synchronizing
if(settings.synchronize == false || device.queueLength < 3) break;
}
if(device.queueLength < 3) {
alGenBuffers(1, &albuffer);
alBufferData(albuffer, device.format, buffer.data, buffer.size * 4, settings.frequency);
alSourceQueueBuffers(device.source, 1, &albuffer);
device.queueLength++;
}
ALint playing;
alGetSourcei(device.source, AL_SOURCE_STATE, &playing);
if(playing != AL_PLAYING) alSourcePlay(device.source);
buffer.length = 0;
}
auto clear() -> void {
}
auto init() -> bool {
updateLatency();
device.queueLength = 0;
bool success = false;
if(device.handle = alcOpenDevice(nullptr)) {
if(device.context = alcCreateContext(device.handle, nullptr)) {
alcMakeContextCurrent(device.context);
alGenSources(1, &device.source);
//alSourcef (device.source, AL_PITCH, 1.0);
//alSourcef (device.source, AL_GAIN, 1.0);
//alSource3f(device.source, AL_POSITION, 0.0, 0.0, 0.0);
//alSource3f(device.source, AL_VELOCITY, 0.0, 0.0, 0.0);
//alSource3f(device.source, AL_DIRECTION, 0.0, 0.0, 0.0);
//alSourcef (device.source, AL_ROLLOFF_FACTOR, 0.0);
//alSourcei (device.source, AL_SOURCE_RELATIVE, AL_TRUE);
alListener3f(AL_POSITION, 0.0, 0.0, 0.0);
alListener3f(AL_VELOCITY, 0.0, 0.0, 0.0);
ALfloat listener_orientation[] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
alListenerfv(AL_ORIENTATION, listener_orientation);
success = true;
}
}
if(success == false) {
term();
return false;
}
return true;
}
auto term() -> void {
if(alIsSource(device.source) == AL_TRUE) {
int playing = 0;
alGetSourcei(device.source, AL_SOURCE_STATE, &playing);
if(playing == AL_PLAYING) {
alSourceStop(device.source);
int queued = 0;
alGetSourcei(device.source, AL_BUFFERS_QUEUED, &queued);
while(queued--) {
ALuint albuffer = 0;
alSourceUnqueueBuffers(device.source, 1, &albuffer);
alDeleteBuffers(1, &albuffer);
device.queueLength--;
}
}
alDeleteSources(1, &device.source);
device.source = 0;
}
if(device.context) {
alcMakeContextCurrent(nullptr);
alcDestroyContext(device.context);
device.context = 0;
}
if(device.handle) {
alcCloseDevice(device.handle);
device.handle = 0;
}
if(buffer.data) {
delete[] buffer.data;
buffer.data = 0;
}
}
private:
auto queryDevices() -> string_vector {
string_vector result;
const char* buffer = alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
if(!buffer) return result;
while(buffer[0] || buffer[1]) {
result.append(buffer);
while(buffer[0]) buffer++;
}
return result;
}
auto updateLatency() -> void {
if(buffer.data) delete[] buffer.data;
buffer.size = settings.frequency * settings.latency / 1000.0 + 0.5;
buffer.data = new uint32_t[buffer.size]();
}
};