Update to v093 release.

byuu says:

Changelog:
- added Cocoa target: higan can now be compiled for OS X Lion
  [Cydrak, byuu]
- SNES/accuracy profile hires color blending improvements - fixes
  Marvelous text [AWJ]
- fixed a slight bug in SNES/SA-1 VBR support caused by a typo
- added support for multi-pass shaders that can load external textures
  (requires OpenGL 3.2+)
- added game library path (used by ananke->Import Game) to
  Settings->Advanced
- system profiles, shaders and cheats database can be stored in "all
  users" shared folders now (eg /usr/share on Linux)
- all configuration files are in BML format now, instead of XML (much
  easier to read and edit this way)
- main window supports drag-and-drop of game folders (but not game files
  / ZIP archives)
- audio buffer clears when entering a modal loop on Windows (prevents
  audio repetition with DirectSound driver)
- a substantial amount of code clean-up (probably the biggest
  refactoring to date)

One highly desired target for this release was to default to the optimal
drivers instead of the safest drivers, but because AMD drivers don't
seem to like my OpenGL 3.2 driver, I've decided to postpone that. AMD
has too big a market share. Hopefully with v093 officially released, we
can get some public input on what AMD doesn't like.
This commit is contained in:
Tim Allen
2013-08-18 13:21:14 +10:00
parent c74865e171
commit 4e2eb23835
1928 changed files with 4834 additions and 84223 deletions

240
ruby/audio/alsa.cpp Normal file
View File

@@ -0,0 +1,240 @@
//audio.alsa (2009-11-30)
//authors: BearOso, byuu, Nach, RedDwarf
#include <alsa/asoundlib.h>
namespace ruby {
class pAudioALSA {
public:
struct {
snd_pcm_t* handle;
snd_pcm_format_t format;
snd_pcm_uframes_t buffer_size;
snd_pcm_uframes_t period_size;
int channels;
const char* name;
} device;
struct {
uint32_t* data;
unsigned length;
} buffer;
struct {
bool synchronize;
unsigned frequency;
unsigned latency;
} settings;
bool cap(const string& name) {
if(name == Audio::Synchronize) return true;
if(name == Audio::Frequency) return true;
if(name == Audio::Latency) return true;
return false;
}
any get(const string& name) {
if(name == Audio::Synchronize) return settings.synchronize;
if(name == Audio::Frequency) return settings.frequency;
if(name == Audio::Latency) return settings.latency;
return false;
}
bool set(const string& name, const any& value) {
if(name == Audio::Synchronize) {
if(settings.synchronize != any_cast<bool>(value)) {
settings.synchronize = any_cast<bool>(value);
if(device.handle) init();
}
return true;
}
if(name == Audio::Frequency) {
if(settings.frequency != any_cast<unsigned>(value)) {
settings.frequency = any_cast<unsigned>(value);
if(device.handle) init();
}
return true;
}
if(name == Audio::Latency) {
if(settings.latency != any_cast<unsigned>(value)) {
settings.latency = any_cast<unsigned>(value);
if(device.handle) init();
}
return true;
}
return false;
}
void sample(uint16_t left, uint16_t right) {
if(!device.handle) return;
buffer.data[buffer.length++] = left + (right << 16);
if(buffer.length < device.period_size) return;
snd_pcm_sframes_t avail;
do {
avail = snd_pcm_avail_update(device.handle);
if(avail < 0) snd_pcm_recover(device.handle, avail, 1);
if(avail < buffer.length) {
if(settings.synchronize == false) {
buffer.length = 0;
return;
}
int error = snd_pcm_wait(device.handle, -1);
if(error < 0) snd_pcm_recover(device.handle, error, 1);
}
} while(avail < buffer.length);
//below code has issues with PulseAudio sound server
#if 0
if(settings.synchronize == false) {
snd_pcm_sframes_t avail = snd_pcm_avail_update(device.handle);
if(avail < device.period_size) {
buffer.length = 0;
return;
}
}
#endif
uint32_t* buffer_ptr = buffer.data;
int i = 4;
while((buffer.length > 0) && i--) {
snd_pcm_sframes_t written = snd_pcm_writei(device.handle, buffer_ptr, buffer.length);
if(written < 0) {
//no samples written
snd_pcm_recover(device.handle, written, 1);
} else if(written <= buffer.length) {
buffer.length -= written;
buffer_ptr += written;
}
}
if(i < 0) {
if(buffer.data == buffer_ptr) {
buffer.length--;
buffer_ptr++;
}
memmove(buffer.data, buffer_ptr, buffer.length * sizeof(uint32_t));
}
}
void clear() {
}
bool init() {
term();
if(snd_pcm_open(&device.handle, device.name, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) {
term();
return false;
}
//below code will not work with 24khz frequency rate (ALSA library bug)
#if 0
if(snd_pcm_set_params(device.handle, device.format, SND_PCM_ACCESS_RW_INTERLEAVED,
device.channels, settings.frequency, 1, settings.latency * 1000) < 0) {
//failed to set device parameters
term();
return false;
}
if(snd_pcm_get_params(device.handle, &device.buffer_size, &device.period_size) < 0) {
device.period_size = settings.latency * 1000 * 1e-6 * settings.frequency / 4;
}
#endif
snd_pcm_hw_params_t* hwparams;
snd_pcm_sw_params_t* swparams;
unsigned rate = settings.frequency;
unsigned buffer_time = settings.latency * 1000;
unsigned period_time = settings.latency * 1000 / 4;
snd_pcm_hw_params_alloca(&hwparams);
if(snd_pcm_hw_params_any(device.handle, hwparams) < 0) {
term();
return false;
}
if(snd_pcm_hw_params_set_access(device.handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0
|| snd_pcm_hw_params_set_format(device.handle, hwparams, device.format) < 0
|| snd_pcm_hw_params_set_channels(device.handle, hwparams, device.channels) < 0
|| snd_pcm_hw_params_set_rate_near(device.handle, hwparams, &rate, 0) < 0
|| snd_pcm_hw_params_set_period_time_near(device.handle, hwparams, &period_time, 0) < 0
|| snd_pcm_hw_params_set_buffer_time_near(device.handle, hwparams, &buffer_time, 0) < 0
) {
term();
return false;
}
if(snd_pcm_hw_params(device.handle, hwparams) < 0) {
term();
return false;
}
if(snd_pcm_get_params(device.handle, &device.buffer_size, &device.period_size) < 0) {
term();
return false;
}
snd_pcm_sw_params_alloca(&swparams);
if(snd_pcm_sw_params_current(device.handle, swparams) < 0) {
term();
return false;
}
if(snd_pcm_sw_params_set_start_threshold(device.handle, swparams,
(device.buffer_size / device.period_size) * device.period_size) < 0
) {
term();
return false;
}
if(snd_pcm_sw_params(device.handle, swparams) < 0) {
term();
return false;
}
buffer.data = new uint32_t[device.period_size];
return true;
}
void term() {
if(device.handle) {
//snd_pcm_drain(device.handle); //prevents popping noise; but causes multi-second lag
snd_pcm_close(device.handle);
device.handle = 0;
}
if(buffer.data) {
delete[] buffer.data;
buffer.data = 0;
}
}
pAudioALSA() {
device.handle = 0;
device.format = SND_PCM_FORMAT_S16_LE;
device.channels = 2;
device.name = "default";
buffer.data = 0;
buffer.length = 0;
settings.synchronize = false;
settings.frequency = 22050;
settings.latency = 60;
}
~pAudioALSA() {
term();
}
};
DeclareAudio(ALSA)
};

94
ruby/audio/ao.cpp Normal file
View File

@@ -0,0 +1,94 @@
/*
audio.ao (2008-06-01)
authors: Nach, RedDwarf
*/
#include <ao/ao.h>
namespace ruby {
class pAudioAO {
public:
int driver_id;
ao_sample_format driver_format;
ao_device* audio_device;
struct {
unsigned frequency;
} settings;
bool cap(const string& name) {
if(name == Audio::Frequency) return true;
return false;
}
any get(const string& name) {
if(name == Audio::Frequency) return settings.frequency;
return false;
}
bool set(const string& name, const any& value) {
if(name == Audio::Frequency) {
settings.frequency = any_cast<unsigned>(value);
if(audio_device) init();
return true;
}
return false;
}
void sample(uint16_t l_sample, uint16_t r_sample) {
uint32_t samp = (l_sample << 0) + (r_sample << 16);
ao_play(audio_device, (char*)&samp, 4); //This may need to be byte swapped for Big Endian
}
void clear() {
}
bool init() {
term();
driver_id = ao_default_driver_id(); //ao_driver_id((const char*)driver)
if(driver_id < 0) return false;
driver_format.bits = 16;
driver_format.channels = 2;
driver_format.rate = settings.frequency;
driver_format.byte_format = AO_FMT_LITTLE;
ao_option* options = nullptr;
ao_info *di = ao_driver_info(driver_id);
if(!di) return false;
if(!strcmp(di->short_name, "alsa")) {
ao_append_option(&options, "buffer_time", "100000"); //100ms latency (default was 500ms)
}
audio_device = ao_open_live(driver_id, &driver_format, options);
if(!audio_device) return false;
return true;
}
void term() {
if(audio_device) {
ao_close(audio_device);
audio_device = 0;
}
}
pAudioAO() {
audio_device = 0;
ao_initialize();
settings.frequency = 22050;
}
~pAudioAO() {
term();
//ao_shutdown(); //FIXME: this is causing a segfault for some reason when called ...
}
};
DeclareAudio(AO)
};

212
ruby/audio/directsound.cpp Normal file
View File

@@ -0,0 +1,212 @@
/*
audio.directsound (2007-12-26)
author: byuu
*/
#include <dsound.h>
namespace ruby {
class pAudioDS {
public:
LPDIRECTSOUND ds;
LPDIRECTSOUNDBUFFER dsb_p, dsb_b;
DSBUFFERDESC dsbd;
WAVEFORMATEX wfx;
struct {
unsigned rings;
unsigned latency;
uint32_t* buffer;
unsigned bufferoffset;
unsigned readring;
unsigned writering;
int distance;
} device;
struct {
HWND handle;
bool synchronize;
unsigned frequency;
unsigned latency;
} settings;
bool cap(const string& name) {
if(name == Audio::Handle) return true;
if(name == Audio::Synchronize) return true;
if(name == Audio::Frequency) return true;
if(name == Audio::Latency) return true;
return false;
}
any get(const string& name) {
if(name == Audio::Handle) return (uintptr_t)settings.handle;
if(name == Audio::Synchronize) return settings.synchronize;
if(name == Audio::Frequency) return settings.frequency;
if(name == Audio::Latency) return settings.latency;
return false;
}
bool set(const string& name, const any& value) {
if(name == Audio::Handle) {
settings.handle = (HWND)any_cast<uintptr_t>(value);
return true;
}
if(name == Audio::Synchronize) {
settings.synchronize = any_cast<bool>(value);
if(ds) clear();
return true;
}
if(name == Audio::Frequency) {
settings.frequency = any_cast<unsigned>(value);
if(ds) init();
return true;
}
if(name == Audio::Latency) {
settings.latency = any_cast<unsigned>(value);
if(ds) init();
return true;
}
return false;
}
void sample(uint16_t left, uint16_t right) {
device.buffer[device.bufferoffset++] = left + (right << 16);
if(device.bufferoffset < device.latency) return;
device.bufferoffset = 0;
DWORD pos, size;
void* output;
if(settings.synchronize == true) {
//wait until playback buffer has an empty ring to write new audio data to
while(device.distance >= device.rings - 1) {
dsb_b->GetCurrentPosition(&pos, 0);
unsigned activering = pos / (device.latency * 4);
if(activering == device.readring) {
if(settings.synchronize == false) Sleep(1);
continue;
}
//subtract number of played rings from ring distance counter
device.distance -= (device.rings + activering - device.readring) % device.rings;
device.readring = activering;
if(device.distance < 2) {
//buffer underflow; set max distance to recover quickly
device.distance = device.rings - 1;
device.writering = (device.rings + device.readring - 1) % device.rings;
break;
}
}
}
device.writering = (device.writering + 1) % device.rings;
device.distance = (device.distance + 1) % device.rings;
if(dsb_b->Lock(device.writering * device.latency * 4, device.latency * 4, &output, &size, 0, 0, 0) == DS_OK) {
memcpy(output, device.buffer, device.latency * 4);
dsb_b->Unlock(output, size, 0, 0);
}
}
void clear() {
device.readring = 0;
device.writering = device.rings - 1;
device.distance = device.rings - 1;
device.bufferoffset = 0;
if(device.buffer) memset(device.buffer, 0, device.latency * device.rings * 4);
if(!dsb_b) return;
dsb_b->Stop();
dsb_b->SetCurrentPosition(0);
DWORD size;
void* output;
dsb_b->Lock(0, device.latency * device.rings * 4, &output, &size, 0, 0, 0);
memset(output, 0, size);
dsb_b->Unlock(output, size, 0, 0);
dsb_b->Play(0, 0, DSBPLAY_LOOPING);
}
bool init() {
term();
device.rings = 8;
device.latency = settings.frequency * settings.latency / device.rings / 1000.0 + 0.5;
device.buffer = new uint32_t[device.latency * device.rings];
device.bufferoffset = 0;
DirectSoundCreate(0, &ds, 0);
ds->SetCooperativeLevel((HWND)settings.handle, DSSCL_PRIORITY);
memset(&dsbd, 0, sizeof(dsbd));
dsbd.dwSize = sizeof(dsbd);
dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
dsbd.dwBufferBytes = 0;
dsbd.lpwfxFormat = 0;
ds->CreateSoundBuffer(&dsbd, &dsb_p, 0);
memset(&wfx, 0, sizeof(wfx));
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2;
wfx.nSamplesPerSec = settings.frequency;
wfx.wBitsPerSample = 16;
wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
dsb_p->SetFormat(&wfx);
memset(&dsbd, 0, sizeof(dsbd));
dsbd.dwSize = sizeof(dsbd);
dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLFREQUENCY | DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCSOFTWARE;
dsbd.dwBufferBytes = device.latency * device.rings * sizeof(uint32_t);
dsbd.guid3DAlgorithm = GUID_NULL;
dsbd.lpwfxFormat = &wfx;
ds->CreateSoundBuffer(&dsbd, &dsb_b, 0);
dsb_b->SetFrequency(settings.frequency);
dsb_b->SetCurrentPosition(0);
clear();
return true;
}
void term() {
if(device.buffer) {
delete[] device.buffer;
device.buffer = 0;
}
if(dsb_b) { dsb_b->Stop(); dsb_b->Release(); dsb_b = 0; }
if(dsb_p) { dsb_p->Stop(); dsb_p->Release(); dsb_p = 0; }
if(ds) { ds->Release(); ds = 0; }
}
pAudioDS() {
ds = 0;
dsb_p = 0;
dsb_b = 0;
device.buffer = 0;
device.bufferoffset = 0;
device.readring = 0;
device.writering = 0;
device.distance = 0;
settings.handle = GetDesktopWindow();
settings.synchronize = false;
settings.frequency = 22050;
settings.latency = 120;
}
};
DeclareAudio(DS)
};

210
ruby/audio/openal.cpp Normal file
View File

@@ -0,0 +1,210 @@
/*
audio.openal (2007-12-26)
author: Nach
contributors: byuu, wertigon, _willow_
*/
#if defined(PLATFORM_OSX)
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#else
#include <AL/al.h>
#include <AL/alc.h>
#endif
namespace ruby {
class pAudioOpenAL {
public:
struct {
ALCdevice* handle;
ALCcontext* context;
ALuint source;
ALenum format;
unsigned latency;
unsigned queue_length;
} device;
struct {
uint32_t* data;
unsigned length;
unsigned size;
} buffer;
struct {
bool synchronize;
unsigned frequency;
unsigned latency;
} settings;
bool cap(const string& name) {
if(name == Audio::Synchronize) return true;
if(name == Audio::Frequency) return true;
if(name == Audio::Latency) return true;
return false;
}
any get(const string& name) {
if(name == Audio::Synchronize) return settings.synchronize;
if(name == Audio::Frequency) return settings.frequency;
if(name == Audio::Latency) return settings.latency;
return false;
}
bool set(const string& name, const any& value) {
if(name == Audio::Synchronize) {
settings.synchronize = any_cast<bool>(value);
return true;
}
if(name == Audio::Frequency) {
settings.frequency = any_cast<unsigned>(value);
return true;
}
if(name == Audio::Latency) {
if(settings.latency != any_cast<unsigned>(value)) {
settings.latency = any_cast<unsigned>(value);
update_latency();
}
return true;
}
return false;
}
void sample(uint16_t sl, uint16_t sr) {
buffer.data[buffer.length++] = sl + (sr << 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.queue_length--;
}
//wait for buffer playback to catch up to sample generation if not synchronizing
if(settings.synchronize == false || device.queue_length < 3) break;
}
if(device.queue_length < 3) {
alGenBuffers(1, &albuffer);
alBufferData(albuffer, device.format, buffer.data, buffer.size * 4, settings.frequency);
alSourceQueueBuffers(device.source, 1, &albuffer);
device.queue_length++;
}
ALint playing;
alGetSourcei(device.source, AL_SOURCE_STATE, &playing);
if(playing != AL_PLAYING) alSourcePlay(device.source);
buffer.length = 0;
}
void clear() {
}
void update_latency() {
if(buffer.data) delete[] buffer.data;
buffer.size = settings.frequency * settings.latency / 1000.0 + 0.5;
buffer.data = new uint32_t[buffer.size];
}
bool init() {
update_latency();
device.queue_length = 0;
bool success = false;
if(device.handle = alcOpenDevice(NULL)) {
if(device.context = alcCreateContext(device.handle, NULL)) {
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;
}
void term() {
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.queue_length--;
}
}
alDeleteSources(1, &device.source);
device.source = 0;
}
if(device.context) {
alcMakeContextCurrent(NULL);
alcDestroyContext(device.context);
device.context = 0;
}
if(device.handle) {
alcCloseDevice(device.handle);
device.handle = 0;
}
if(buffer.data) {
delete[] buffer.data;
buffer.data = 0;
}
}
pAudioOpenAL() {
device.source = 0;
device.handle = 0;
device.context = 0;
device.format = AL_FORMAT_STEREO16;
device.queue_length = 0;
buffer.data = 0;
buffer.length = 0;
buffer.size = 0;
settings.synchronize = true;
settings.frequency = 22050;
settings.latency = 40;
}
~pAudioOpenAL() {
term();
}
};
DeclareAudio(OpenAL)
};

113
ruby/audio/oss.cpp Normal file
View File

@@ -0,0 +1,113 @@
/*
audio.oss (2007-12-26)
author: Nach
*/
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>
//OSS4 soundcard.h includes below SNDCTL defines, but OSS3 does not
//However, OSS4 soundcard.h does not reside in <sys/>
//Therefore, attempt to manually define SNDCTL values if using OSS3 header
//Note that if the defines below fail to work on any specific platform, one can point soundcard.h
//above to the correct location for OSS4 (usually /usr/lib/oss/include/sys/soundcard.h)
//Failing that, one can disable OSS4 ioctl calls inside init() and remove the below defines
#ifndef SNDCTL_DSP_COOKEDMODE
#define SNDCTL_DSP_COOKEDMODE _IOW('P', 30, int)
#endif
#ifndef SNDCTL_DSP_POLICY
#define SNDCTL_DSP_POLICY _IOW('P', 45, int)
#endif
namespace ruby {
class pAudioOSS {
public:
struct {
int fd;
int format;
int channels;
const char* name;
} device;
struct {
unsigned frequency;
} settings;
bool cap(const string& name) {
if(name == Audio::Frequency) return true;
return false;
}
any get(const string& name) {
if(name == Audio::Frequency) return settings.frequency;
return false;
}
bool set(const string& name, const any& value) {
if(name == Audio::Frequency) {
settings.frequency = any_cast<unsigned>(value);
if(device.fd > 0) init();
return true;
}
return false;
}
void sample(uint16_t sl, uint16_t sr) {
uint32_t sample = sl + (sr << 16);
unsigned unused = write(device.fd, &sample, 4);
}
void clear() {
}
bool init() {
term();
device.fd = open(device.name, O_WRONLY, O_NONBLOCK);
if(device.fd < 0) return false;
#if 1 //SOUND_VERSION >= 0x040000
//attempt to enable OSS4-specific features regardless of version
//OSS3 ioctl calls will silently fail, but sound will still work
int cooked = 1, policy = 4; //policy should be 0 - 10, lower = less latency, more CPU usage
ioctl(device.fd, SNDCTL_DSP_COOKEDMODE, &cooked);
ioctl(device.fd, SNDCTL_DSP_POLICY, &policy);
#endif
int freq = settings.frequency;
ioctl(device.fd, SNDCTL_DSP_CHANNELS, &device.channels);
ioctl(device.fd, SNDCTL_DSP_SETFMT, &device.format);
ioctl(device.fd, SNDCTL_DSP_SPEED, &freq);
return true;
}
void term() {
if(device.fd > 0) {
close(device.fd);
device.fd = -1;
}
}
pAudioOSS() {
device.fd = -1;
device.format = AFMT_S16_LE;
device.channels = 2;
device.name = "/dev/dsp";
settings.frequency = 22050;
}
~pAudioOSS() {
term();
}
};
DeclareAudio(OSS)
};

177
ruby/audio/pulseaudio.cpp Normal file
View File

@@ -0,0 +1,177 @@
//audio.pulseaudio (2010-01-05)
//author: RedDwarf
#include <pulse/pulseaudio.h>
namespace ruby {
class pAudioPulseAudio {
public:
struct {
pa_mainloop* mainloop;
pa_context* context;
pa_stream* stream;
pa_sample_spec spec;
pa_buffer_attr buffer_attr;
bool first;
} device;
struct {
uint32_t* data;
size_t size;
unsigned offset;
} buffer;
struct {
bool synchronize;
unsigned frequency;
unsigned latency;
} settings;
bool cap(const string& name) {
if(name == Audio::Synchronize) return true;
if(name == Audio::Frequency) return true;
if(name == Audio::Latency) return true;
}
any get(const string& name) {
if(name == Audio::Synchronize) return settings.synchronize;
if(name == Audio::Frequency) return settings.frequency;
if(name == Audio::Latency) return settings.latency;
}
bool set(const string& name, const any& value) {
if(name == Audio::Synchronize) {
settings.synchronize = any_cast<bool>(value);
return true;
}
if(name == Audio::Frequency) {
settings.frequency = any_cast<unsigned>(value);
if(device.stream) {
pa_operation_unref(pa_stream_update_sample_rate(device.stream, settings.frequency, NULL, NULL));
}
return true;
}
if(name == Audio::Latency) {
settings.latency = any_cast<unsigned>(value);
if(device.stream) {
device.buffer_attr.tlength = pa_usec_to_bytes(settings.latency * PA_USEC_PER_MSEC, &device.spec);
pa_stream_set_buffer_attr(device.stream, &device.buffer_attr, NULL, NULL);
}
return true;
}
}
void sample(uint16_t left, uint16_t right) {
pa_stream_begin_write(device.stream, (void**)&buffer.data, &buffer.size);
buffer.data[buffer.offset++] = left + (right << 16);
if((buffer.offset + 1) * pa_frame_size(&device.spec) <= buffer.size) return;
while(true) {
if(device.first) {
device.first = false;
pa_mainloop_iterate(device.mainloop, 0, NULL);
} else {
pa_mainloop_iterate(device.mainloop, 1, NULL);
}
unsigned length = pa_stream_writable_size(device.stream);
if(length >= buffer.offset * pa_frame_size(&device.spec)) break;
if(settings.synchronize == false) {
buffer.offset = 0;
return;
}
}
pa_stream_write(device.stream, (const void*)buffer.data, buffer.offset * pa_frame_size(&device.spec), NULL, 0LL, PA_SEEK_RELATIVE);
buffer.data = 0;
buffer.offset = 0;
}
void clear() {
}
bool init() {
device.mainloop = pa_mainloop_new();
device.context = pa_context_new(pa_mainloop_get_api(device.mainloop), "ruby::pulseaudio");
pa_context_connect(device.context, NULL, PA_CONTEXT_NOFLAGS, NULL);
pa_context_state_t cstate;
do {
pa_mainloop_iterate(device.mainloop, 1, NULL);
cstate = pa_context_get_state(device.context);
if(!PA_CONTEXT_IS_GOOD(cstate)) return false;
} while(cstate != PA_CONTEXT_READY);
device.spec.format = PA_SAMPLE_S16LE;
device.spec.channels = 2;
device.spec.rate = settings.frequency;
device.stream = pa_stream_new(device.context, "audio", &device.spec, NULL);
device.buffer_attr.maxlength = -1;
device.buffer_attr.tlength = pa_usec_to_bytes(settings.latency * PA_USEC_PER_MSEC, &device.spec);
device.buffer_attr.prebuf = -1;
device.buffer_attr.minreq = -1;
device.buffer_attr.fragsize = -1;
pa_stream_flags_t flags = (pa_stream_flags_t)(PA_STREAM_ADJUST_LATENCY | PA_STREAM_VARIABLE_RATE);
pa_stream_connect_playback(device.stream, NULL, &device.buffer_attr, flags, NULL, NULL);
pa_stream_state_t sstate;
do {
pa_mainloop_iterate(device.mainloop, 1, NULL);
sstate = pa_stream_get_state(device.stream);
if(!PA_STREAM_IS_GOOD(sstate)) return false;
} while(sstate != PA_STREAM_READY);
buffer.size = 960;
buffer.offset = 0;
device.first = true;
return true;
}
void term() {
if(buffer.data) {
pa_stream_cancel_write(device.stream);
buffer.data = 0;
}
if(device.stream) {
pa_stream_disconnect(device.stream);
pa_stream_unref(device.stream);
device.stream = 0;
}
if(device.context) {
pa_context_disconnect(device.context);
pa_context_unref(device.context);
device.context = 0;
}
if(device.mainloop) {
pa_mainloop_free(device.mainloop);
device.mainloop = 0;
}
}
pAudioPulseAudio() {
device.mainloop = 0;
device.context = 0;
device.stream = 0;
buffer.data = 0;
settings.synchronize = false;
settings.frequency = 22050;
settings.latency = 60;
}
~pAudioPulseAudio() {
term();
}
};
DeclareAudio(PulseAudio)
}

View File

@@ -0,0 +1,115 @@
//audio.pulseaudiosimple (2010-01-05)
//author: byuu
#include <pulse/simple.h>
#include <pulse/error.h>
namespace ruby {
class pAudioPulseAudioSimple {
public:
struct {
pa_simple* handle;
pa_sample_spec spec;
} device;
struct {
uint32_t* data;
unsigned offset;
} buffer;
struct {
unsigned frequency;
} settings;
bool cap(const string& name) {
if(name == Audio::Frequency) return true;
return false;
}
any get(const string& name) {
if(name == Audio::Frequency) return settings.frequency;
return false;
}
bool set(const string& name, const any& value) {
if(name == Audio::Frequency) {
settings.frequency = any_cast<unsigned>(value);
if(device.handle) init();
return true;
}
return false;
}
void sample(uint16_t left, uint16_t right) {
if(!device.handle) return;
buffer.data[buffer.offset++] = left + (right << 16);
if(buffer.offset >= 64) {
int error;
pa_simple_write(device.handle, (const void*)buffer.data, buffer.offset * sizeof(uint32_t), &error);
buffer.offset = 0;
}
}
void clear() {
}
bool init() {
term();
device.spec.format = PA_SAMPLE_S16LE;
device.spec.channels = 2;
device.spec.rate = settings.frequency;
int error = 0;
device.handle = pa_simple_new(
0, //default server
"ruby::pulseaudiosimple", //application name
PA_STREAM_PLAYBACK, //direction
0, //default device
"audio", //stream description
&device.spec, //sample format
0, //default channel map
0, //default buffering attributes
&error //error code
);
if(!device.handle) {
fprintf(stderr, "ruby::pulseaudiosimple failed to initialize - %s\n", pa_strerror(error));
return false;
}
buffer.data = new uint32_t[64];
buffer.offset = 0;
return true;
}
void term() {
if(device.handle) {
int error;
pa_simple_flush(device.handle, &error);
pa_simple_free(device.handle);
device.handle = nullptr;
}
if(buffer.data) {
delete[] buffer.data;
buffer.data = nullptr;
}
}
pAudioPulseAudioSimple() {
device.handle = nullptr;
buffer.data = nullptr;
settings.frequency = 22050;
}
~pAudioPulseAudioSimple() {
term();
}
};
DeclareAudio(PulseAudioSimple)
};

198
ruby/audio/xaudio2.cpp Normal file
View File

@@ -0,0 +1,198 @@
/*
audio.xaudio2 (2010-08-14)
author: OV2
*/
#include "xaudio2.hpp"
#include <windows.h>
namespace ruby {
class pAudioXAudio2: public IXAudio2VoiceCallback {
public:
IXAudio2* pXAudio2;
IXAudio2MasteringVoice* pMasterVoice;
IXAudio2SourceVoice* pSourceVoice;
//inherited from IXAudio2VoiceCallback
STDMETHODIMP_(void) OnBufferStart(void* pBufferContext){}
STDMETHODIMP_(void) OnLoopEnd(void* pBufferContext){}
STDMETHODIMP_(void) OnStreamEnd() {}
STDMETHODIMP_(void) OnVoiceError(void* pBufferContext, HRESULT Error) {}
STDMETHODIMP_(void) OnVoiceProcessingPassEnd() {}
STDMETHODIMP_(void) OnVoiceProcessingPassStart(UINT32 BytesRequired) {}
struct {
unsigned buffers;
unsigned latency;
uint32_t* buffer;
unsigned bufferoffset;
volatile long submitbuffers;
unsigned writebuffer;
} device;
struct {
bool synchronize;
unsigned frequency;
unsigned latency;
} settings;
bool cap(const string& name) {
if(name == Audio::Synchronize) return true;
if(name == Audio::Frequency) return true;
if(name == Audio::Latency) return true;
return false;
}
any get(const string& name) {
if(name == Audio::Synchronize) return settings.synchronize;
if(name == Audio::Frequency) return settings.frequency;
if(name == Audio::Latency) return settings.latency;
return false;
}
bool set(const string& name, const any& value) {
if(name == Audio::Synchronize) {
settings.synchronize = any_cast<bool>(value);
if(pXAudio2) clear();
return true;
}
if(name == Audio::Frequency) {
settings.frequency = any_cast<unsigned>(value);
if(pXAudio2) init();
return true;
}
if(name == Audio::Latency) {
settings.latency = any_cast<unsigned>(value);
if(pXAudio2) init();
return true;
}
return false;
}
void pushbuffer(unsigned bytes, uint32_t* pAudioData) {
XAUDIO2_BUFFER xa2buffer = {0};
xa2buffer.AudioBytes = bytes;
xa2buffer.pAudioData = reinterpret_cast<BYTE*>(pAudioData);
xa2buffer.pContext = 0;
InterlockedIncrement(&device.submitbuffers);
pSourceVoice->SubmitSourceBuffer(&xa2buffer);
}
void sample(uint16_t left, uint16_t right) {
device.buffer[device.writebuffer * device.latency + device.bufferoffset++] = left + (right << 16);
if(device.bufferoffset < device.latency) return;
device.bufferoffset = 0;
if(device.submitbuffers == device.buffers - 1) {
if(settings.synchronize == true) {
//wait until there is at least one other free buffer for the next sample
while(device.submitbuffers == device.buffers - 1) {
//Sleep(0);
}
} else { //we need one free buffer for the next sample, so ignore the current contents
return;
}
}
pushbuffer(device.latency * 4,device.buffer + device.writebuffer * device.latency);
device.writebuffer = (device.writebuffer + 1) % device.buffers;
}
void clear() {
if(!pSourceVoice) return;
pSourceVoice->Stop(0);
pSourceVoice->FlushSourceBuffers(); //calls OnBufferEnd for all currently submitted buffers
device.writebuffer = 0;
device.bufferoffset = 0;
if(device.buffer) memset(device.buffer, 0, device.latency * device.buffers * 4);
pSourceVoice->Start(0);
}
bool init() {
term();
device.buffers = 8;
device.latency = settings.frequency * settings.latency / device.buffers / 1000.0 + 0.5;
device.buffer = new uint32_t[device.latency * device.buffers];
device.bufferoffset = 0;
device.submitbuffers = 0;
HRESULT hr;
if(FAILED(hr = XAudio2Create(&pXAudio2, 0 , XAUDIO2_DEFAULT_PROCESSOR))) {
return false;
}
if(FAILED(hr = pXAudio2->CreateMasteringVoice( &pMasterVoice, 2, settings.frequency, 0, 0 , NULL))) {
return false;
}
WAVEFORMATEX wfx;
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2;
wfx.nSamplesPerSec = settings.frequency;
wfx.nBlockAlign = 4;
wfx.wBitsPerSample = 16;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
wfx.cbSize = 0;
if(FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX*)&wfx, XAUDIO2_VOICE_NOSRC , XAUDIO2_DEFAULT_FREQ_RATIO, this, NULL, NULL))) {
return false;
}
clear();
return true;
}
void term() {
if(pSourceVoice) {
pSourceVoice->Stop(0);
pSourceVoice->DestroyVoice();
pSourceVoice = nullptr;
}
if(pMasterVoice) {
pMasterVoice->DestroyVoice();
pMasterVoice = nullptr;
}
if(pXAudio2) {
pXAudio2->Release();
pXAudio2 = nullptr;
}
if(device.buffer) {
delete[] device.buffer;
device.buffer = nullptr;
}
}
STDMETHODIMP_(void) OnBufferEnd(void* pBufferContext) {
InterlockedDecrement(&device.submitbuffers);
}
pAudioXAudio2() {
pXAudio2 = nullptr;
pMasterVoice = nullptr;
pSourceVoice = nullptr;
device.buffer = nullptr;
device.bufferoffset = 0;
device.submitbuffers = 0;
device.writebuffer = 0;
settings.synchronize = false;
settings.frequency = 22050;
settings.latency = 120;
}
};
DeclareAudio(XAudio2)
};

340
ruby/audio/xaudio2.hpp Normal file
View File

@@ -0,0 +1,340 @@
/*
xaudio2.hpp (2010-08-14)
author: OV2
ruby-specific header to provide mingw-friendly xaudio2 interfaces
*/
#ifndef XAUDIO2_RUBY_H
#define XAUDIO2_RUBY_H
//64-bit GCC fix
#define GUID_EXT EXTERN_C
#define GUID_SECT
#include <BaseTyps.h>
#define DEFINE_GUID_X(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) GUID_EXT const GUID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
#define DEFINE_CLSID_X(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
DEFINE_GUID_X(CLSID_##className, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
#define DEFINE_IID_X(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
DEFINE_GUID_X(IID_##interfaceName, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
#define X2DEFAULT(x) =x
DEFINE_CLSID_X(XAudio2, e21a7345, eb21, 468e, be, 50, 80, 4d, b9, 7c, f7, 08);
DEFINE_CLSID_X(XAudio2_Debug, f7a76c21, 53d4, 46bb, ac, 53, 8b, 45, 9c, ae, 46, bd);
DEFINE_IID_X(IXAudio2, 8bcf1f58, 9fe7, 4583, 8a, c6, e2, ad, c4, 65, c8, bb);
DECLARE_INTERFACE(IXAudio2Voice);
#define XAUDIO2_COMMIT_NOW 0
#define XAUDIO2_DEFAULT_CHANNELS 0
#define XAUDIO2_DEFAULT_SAMPLERATE 0
#define XAUDIO2_DEFAULT_FREQ_RATIO 4.0f
#define XAUDIO2_DEBUG_ENGINE 0x0001
#define XAUDIO2_VOICE_NOSRC 0x0004
typedef struct
{
WAVEFORMATEX Format;
union
{
WORD wValidBitsPerSample;
WORD wSamplesPerBlock;
WORD wReserved;
} Samples;
DWORD dwChannelMask;
GUID SubFormat;
} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE, *LPPWAVEFORMATEXTENSIBLE;
typedef const WAVEFORMATEXTENSIBLE* LPCWAVEFORMATEXTENSIBLE;
typedef enum XAUDIO2_DEVICE_ROLE
{
NotDefaultDevice = 0x0,
DefaultConsoleDevice = 0x1,
DefaultMultimediaDevice = 0x2,
DefaultCommunicationsDevice = 0x4,
DefaultGameDevice = 0x8,
GlobalDefaultDevice = 0xf,
InvalidDeviceRole = ~GlobalDefaultDevice
} XAUDIO2_DEVICE_ROLE;
typedef struct XAUDIO2_DEVICE_DETAILS
{
WCHAR DeviceID[256];
WCHAR DisplayName[256];
XAUDIO2_DEVICE_ROLE Role;
WAVEFORMATEXTENSIBLE OutputFormat;
} XAUDIO2_DEVICE_DETAILS;
typedef struct XAUDIO2_VOICE_DETAILS
{
UINT32 CreationFlags;
UINT32 InputChannels;
UINT32 InputSampleRate;
} XAUDIO2_VOICE_DETAILS;
typedef enum XAUDIO2_WINDOWS_PROCESSOR_SPECIFIER
{
Processor1 = 0x00000001,
Processor2 = 0x00000002,
Processor3 = 0x00000004,
Processor4 = 0x00000008,
Processor5 = 0x00000010,
Processor6 = 0x00000020,
Processor7 = 0x00000040,
Processor8 = 0x00000080,
Processor9 = 0x00000100,
Processor10 = 0x00000200,
Processor11 = 0x00000400,
Processor12 = 0x00000800,
Processor13 = 0x00001000,
Processor14 = 0x00002000,
Processor15 = 0x00004000,
Processor16 = 0x00008000,
Processor17 = 0x00010000,
Processor18 = 0x00020000,
Processor19 = 0x00040000,
Processor20 = 0x00080000,
Processor21 = 0x00100000,
Processor22 = 0x00200000,
Processor23 = 0x00400000,
Processor24 = 0x00800000,
Processor25 = 0x01000000,
Processor26 = 0x02000000,
Processor27 = 0x04000000,
Processor28 = 0x08000000,
Processor29 = 0x10000000,
Processor30 = 0x20000000,
Processor31 = 0x40000000,
Processor32 = 0x80000000,
XAUDIO2_ANY_PROCESSOR = 0xffffffff,
XAUDIO2_DEFAULT_PROCESSOR = XAUDIO2_ANY_PROCESSOR
} XAUDIO2_WINDOWS_PROCESSOR_SPECIFIER, XAUDIO2_PROCESSOR;
typedef struct XAUDIO2_VOICE_SENDS
{
UINT32 OutputCount;
IXAudio2Voice** pOutputVoices;
} XAUDIO2_VOICE_SENDS;
typedef struct XAUDIO2_EFFECT_DESCRIPTOR
{
IUnknown* pEffect;
BOOL InitialState;
UINT32 OutputChannels;
} XAUDIO2_EFFECT_DESCRIPTOR;
typedef struct XAUDIO2_EFFECT_CHAIN
{
UINT32 EffectCount;
const XAUDIO2_EFFECT_DESCRIPTOR* pEffectDescriptors;
} XAUDIO2_EFFECT_CHAIN;
typedef enum XAUDIO2_FILTER_TYPE
{
LowPassFilter,
BandPassFilter,
HighPassFilter
} XAUDIO2_FILTER_TYPE;
typedef struct XAUDIO2_FILTER_PARAMETERS
{
XAUDIO2_FILTER_TYPE Type;
float Frequency;
float OneOverQ;
} XAUDIO2_FILTER_PARAMETERS;
typedef struct XAUDIO2_BUFFER
{
UINT32 Flags;
UINT32 AudioBytes;
const BYTE* pAudioData;
UINT32 PlayBegin;
UINT32 PlayLength;
UINT32 LoopBegin;
UINT32 LoopLength;
UINT32 LoopCount;
void* pContext;
} XAUDIO2_BUFFER;
typedef struct XAUDIO2_BUFFER_WMA
{
const UINT32* pDecodedPacketCumulativeBytes;
UINT32 PacketCount;
} XAUDIO2_BUFFER_WMA;
typedef struct XAUDIO2_VOICE_STATE
{
void* pCurrentBufferContext;
UINT32 BuffersQueued;
UINT64 SamplesPlayed;
} XAUDIO2_VOICE_STATE;
typedef struct XAUDIO2_PERFORMANCE_DATA
{
UINT64 AudioCyclesSinceLastQuery;
UINT64 TotalCyclesSinceLastQuery;
UINT32 MinimumCyclesPerQuantum;
UINT32 MaximumCyclesPerQuantum;
UINT32 MemoryUsageInBytes;
UINT32 CurrentLatencyInSamples;
UINT32 GlitchesSinceEngineStarted;
UINT32 ActiveSourceVoiceCount;
UINT32 TotalSourceVoiceCount;
UINT32 ActiveSubmixVoiceCount;
UINT32 TotalSubmixVoiceCount;
UINT32 ActiveXmaSourceVoices;
UINT32 ActiveXmaStreams;
} XAUDIO2_PERFORMANCE_DATA;
typedef struct XAUDIO2_DEBUG_CONFIGURATION
{
UINT32 TraceMask;
UINT32 BreakMask;
BOOL LogThreadID;
BOOL LogFileline;
BOOL LogFunctionName;
BOOL LogTiming;
} XAUDIO2_DEBUG_CONFIGURATION;
DECLARE_INTERFACE(IXAudio2EngineCallback)
{
STDMETHOD_(void, OnProcessingPassStart) (THIS) PURE;
STDMETHOD_(void, OnProcessingPassEnd) (THIS) PURE;
STDMETHOD_(void, OnCriticalError) (THIS_ HRESULT Error) PURE;
};
DECLARE_INTERFACE(IXAudio2VoiceCallback)
{
STDMETHOD_(void, OnVoiceProcessingPassStart) (THIS_ UINT32 BytesRequired) PURE;
STDMETHOD_(void, OnVoiceProcessingPassEnd) (THIS) PURE;
STDMETHOD_(void, OnStreamEnd) (THIS) PURE;
STDMETHOD_(void, OnBufferStart) (THIS_ void* pBufferContext) PURE;
STDMETHOD_(void, OnBufferEnd) (THIS_ void* pBufferContext) PURE;
STDMETHOD_(void, OnLoopEnd) (THIS_ void* pBufferContext) PURE;
STDMETHOD_(void, OnVoiceError) (THIS_ void* pBufferContext, HRESULT Error) PURE;
};
DECLARE_INTERFACE(IXAudio2Voice)
{
#define Declare_IXAudio2Voice_Methods() \
STDMETHOD_(void, GetVoiceDetails) (THIS_ XAUDIO2_VOICE_DETAILS* pVoiceDetails) PURE; \
STDMETHOD(SetOutputVoices) (THIS_ const XAUDIO2_VOICE_SENDS* pSendList) PURE; \
STDMETHOD(SetEffectChain) (THIS_ const XAUDIO2_EFFECT_CHAIN* pEffectChain) PURE; \
STDMETHOD(EnableEffect) (THIS_ UINT32 EffectIndex, \
UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \
STDMETHOD(DisableEffect) (THIS_ UINT32 EffectIndex, \
UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \
STDMETHOD_(void, GetEffectState) (THIS_ UINT32 EffectIndex, BOOL* pEnabled) PURE; \
STDMETHOD(SetEffectParameters) (THIS_ UINT32 EffectIndex, \
const void* pParameters, \
UINT32 ParametersByteSize, \
UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \
STDMETHOD(GetEffectParameters) (THIS_ UINT32 EffectIndex, void* pParameters, \
UINT32 ParametersByteSize) PURE; \
STDMETHOD(SetFilterParameters) (THIS_ const XAUDIO2_FILTER_PARAMETERS* pParameters, \
UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \
STDMETHOD_(void, GetFilterParameters) (THIS_ XAUDIO2_FILTER_PARAMETERS* pParameters) PURE; \
STDMETHOD(SetVolume) (THIS_ float Volume, \
UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \
STDMETHOD_(void, GetVolume) (THIS_ float* pVolume) PURE; \
STDMETHOD(SetChannelVolumes) (THIS_ UINT32 Channels, const float* pVolumes, \
UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \
STDMETHOD_(void, GetChannelVolumes) (THIS_ UINT32 Channels, float* pVolumes) PURE; \
STDMETHOD(SetOutputMatrix) (THIS_ IXAudio2Voice* pDestinationVoice, \
UINT32 SourceChannels, UINT32 DestinationChannels, \
const float* pLevelMatrix, \
UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \
STDMETHOD_(void, GetOutputMatrix) (THIS_ IXAudio2Voice* pDestinationVoice, \
UINT32 SourceChannels, UINT32 DestinationChannels, \
float* pLevelMatrix) PURE; \
STDMETHOD_(void, DestroyVoice) (THIS) PURE
Declare_IXAudio2Voice_Methods();
};
DECLARE_INTERFACE_(IXAudio2MasteringVoice, IXAudio2Voice)
{
Declare_IXAudio2Voice_Methods();
};
DECLARE_INTERFACE_(IXAudio2SubmixVoice, IXAudio2Voice)
{
Declare_IXAudio2Voice_Methods();
};
DECLARE_INTERFACE_(IXAudio2SourceVoice, IXAudio2Voice)
{
Declare_IXAudio2Voice_Methods();
STDMETHOD(Start) (THIS_ UINT32 Flags, UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE;
STDMETHOD(Stop) (THIS_ UINT32 Flags, UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE;
STDMETHOD(SubmitSourceBuffer) (THIS_ const XAUDIO2_BUFFER* pBuffer, const XAUDIO2_BUFFER_WMA* pBufferWMA X2DEFAULT(NULL)) PURE;
STDMETHOD(FlushSourceBuffers) (THIS) PURE;
STDMETHOD(Discontinuity) (THIS) PURE;
STDMETHOD(ExitLoop) (THIS_ UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE;
STDMETHOD_(void, GetState) (THIS_ XAUDIO2_VOICE_STATE* pVoiceState) PURE;
STDMETHOD(SetFrequencyRatio) (THIS_ float Ratio,
UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE;
STDMETHOD_(void, GetFrequencyRatio) (THIS_ float* pRatio) PURE;
};
DECLARE_INTERFACE_(IXAudio2, IUnknown)
{
STDMETHOD(QueryInterface) (THIS_ REFIID riid, void** ppvInterface) PURE;
STDMETHOD_(ULONG, AddRef) (THIS) PURE;
STDMETHOD_(ULONG, Release) (THIS) PURE;
STDMETHOD(GetDeviceCount) (THIS_ UINT32* pCount) PURE;
STDMETHOD(GetDeviceDetails) (THIS_ UINT32 Index, XAUDIO2_DEVICE_DETAILS* pDeviceDetails) PURE;
STDMETHOD(Initialize) (THIS_ UINT32 Flags X2DEFAULT(0),
XAUDIO2_PROCESSOR XAudio2Processor X2DEFAULT(XAUDIO2_DEFAULT_PROCESSOR)) PURE;
STDMETHOD(RegisterForCallbacks) (IXAudio2EngineCallback* pCallback) PURE;
STDMETHOD_(void, UnregisterForCallbacks) (IXAudio2EngineCallback* pCallback) PURE;
STDMETHOD(CreateSourceVoice) (THIS_ IXAudio2SourceVoice** ppSourceVoice,
const WAVEFORMATEX* pSourceFormat,
UINT32 Flags X2DEFAULT(0),
float MaxFrequencyRatio X2DEFAULT(XAUDIO2_DEFAULT_FREQ_RATIO),
IXAudio2VoiceCallback* pCallback X2DEFAULT(NULL),
const XAUDIO2_VOICE_SENDS* pSendList X2DEFAULT(NULL),
const XAUDIO2_EFFECT_CHAIN* pEffectChain X2DEFAULT(NULL)) PURE;
STDMETHOD(CreateSubmixVoice) (THIS_ IXAudio2SubmixVoice** ppSubmixVoice,
UINT32 InputChannels, UINT32 InputSampleRate,
UINT32 Flags X2DEFAULT(0), UINT32 ProcessingStage X2DEFAULT(0),
const XAUDIO2_VOICE_SENDS* pSendList X2DEFAULT(NULL),
const XAUDIO2_EFFECT_CHAIN* pEffectChain X2DEFAULT(NULL)) PURE;
STDMETHOD(CreateMasteringVoice) (THIS_ IXAudio2MasteringVoice** ppMasteringVoice,
UINT32 InputChannels X2DEFAULT(XAUDIO2_DEFAULT_CHANNELS),
UINT32 InputSampleRate X2DEFAULT(XAUDIO2_DEFAULT_SAMPLERATE),
UINT32 Flags X2DEFAULT(0), UINT32 DeviceIndex X2DEFAULT(0),
const XAUDIO2_EFFECT_CHAIN* pEffectChain X2DEFAULT(NULL)) PURE;
STDMETHOD(StartEngine) (THIS) PURE;
STDMETHOD_(void, StopEngine) (THIS) PURE;
STDMETHOD(CommitChanges) (THIS_ UINT32 OperationSet) PURE;
STDMETHOD_(void, GetPerformanceData) (THIS_ XAUDIO2_PERFORMANCE_DATA* pPerfData) PURE;
STDMETHOD_(void, SetDebugConfiguration) (THIS_ const XAUDIO2_DEBUG_CONFIGURATION* pDebugConfiguration,
void* pReserved X2DEFAULT(NULL)) PURE;
};
__inline HRESULT XAudio2Create(IXAudio2** ppXAudio2, UINT32 Flags X2DEFAULT(0),
XAUDIO2_PROCESSOR XAudio2Processor X2DEFAULT(XAUDIO2_DEFAULT_PROCESSOR))
{
IXAudio2* pXAudio2;
HRESULT hr = CoCreateInstance((Flags & XAUDIO2_DEBUG_ENGINE) ? CLSID_XAudio2_Debug : CLSID_XAudio2,
NULL, CLSCTX_INPROC_SERVER, IID_IXAudio2, (void**)&pXAudio2);
if (SUCCEEDED(hr))
{
hr = pXAudio2->Initialize(Flags, XAudio2Processor);
if (SUCCEEDED(hr))
{
*ppXAudio2 = pXAudio2;
}
else
{
pXAudio2->Release();
}
}
return hr;
}
#endif