Instancefy audioapi core (but not driver) stuff

This commit is contained in:
Ilari Liusvaara 2014-06-07 17:33:03 +03:00
parent a2fed56d69
commit 8f54db2902
16 changed files with 290 additions and 258 deletions

View file

@ -1,50 +1,55 @@
#ifndef _audioapi__hpp__included__
#define _audioapi__hpp__included__
#include "library/threads.hpp"
#include <map>
#include <cstdint>
#include <cstdlib>
#include <string>
#include <stdexcept>
class audioapi_instance
{
public:
/**
* Audio API music buffer.
*/
struct audioapi_buffer
{
struct buffer
{
/**
* The samples.
*
* Note: May be NULL if no samples are available..
*/
int16_t* samples;
int16_t* samples;
/**
* Playback pointer in samples structure.
*/
size_t pointer;
size_t pointer;
/**
* Total number of samples in this buffer.
*/
size_t total;
size_t total;
/**
* True if buffer is stereo, false if mono.
*/
bool stereo;
bool stereo;
/**
* The rate in samples per second the buffer is supposed to be played at.
*/
double rate;
};
double rate;
};
/**
* Audio API VU calculator.
*/
struct audioapi_vumeter
{
struct vumeter
{
/**
* Initialize.
*/
audioapi_vumeter();
vumeter();
/**
* Submit samples.
*
@ -54,38 +59,34 @@ struct audioapi_vumeter
* Parameter rate: Sound sampling rate.
* Parameter scale: Value to scale the samples by.
*/
void operator()(float* samples, size_t count, bool stereo, double rate, double scale);
void operator()(float* samples, size_t count, bool stereo, double rate, double scale);
/**
* Get VU value in dB.
*/
operator float() const throw() { return vu; }
private:
double accumulator;
size_t samples;
float vu;
void update_vu();
};
//VU values.
extern audioapi_vumeter audioapi_vu_mleft;
extern audioapi_vumeter audioapi_vu_mright;
extern audioapi_vumeter audioapi_vu_vout;
extern audioapi_vumeter audioapi_vu_vin;
//Resampler.
class audioapi_resampler
{
public:
audioapi_resampler();
//After call, either insize or outsize is zero.
void resample(float*& in, size_t& insize, float*& out, size_t& outsize, double ratio, bool stereo);
private:
double position;
double vAl, vBl, vCl, vDl, vAr, vBr, vCr, vDr;
};
operator float() const throw() { return vu; }
private:
double accumulator;
size_t samples;
float vu;
void update_vu();
};
//Resampler.
class resampler
{
public:
resampler();
//After call, either insize or outsize is zero.
void resample(float*& in, size_t& insize, float*& out, size_t& outsize, double ratio, bool stereo);
private:
double position;
double vAl, vBl, vCl, vDl, vAr, vBr, vCr, vDr;
};
/**
* Ctor.
*/
audioapi_instance();
~audioapi_instance();
//The following are intended to be used by the emulator core.
/**
* Submit a buffer for playback on music channel.
*
@ -94,114 +95,97 @@ private:
* Parameter stereo: If true, the signal is stereo. If false, mono.
* Parameter rate: Rate of buffer in samples per second.
*/
void audioapi_submit_buffer(int16_t* samples, size_t count, bool stereo, double rate);
void submit_buffer(int16_t* samples, size_t count, bool stereo, double rate);
/**
* Get the voice channel playback/record rate.
*
* Returns: The rate in samples per second (first for recording, then for playback).
*/
std::pair<unsigned,unsigned> audioapi_voice_rate();
std::pair<unsigned,unsigned> voice_rate();
/**
* Get the voice channel nominal playback/record rate.
*
* Returns: The rate in samples per second.
*/
unsigned audioapi_orig_voice_rate();
unsigned orig_voice_rate();
/**
* Get the voice channel playback status register.
*
* Returns: The number of samples free for playback.
*/
unsigned audioapi_voice_p_status();
unsigned voice_p_status();
/**
* Get the voice channel playback status register2.
*
* Returns: The number of samples in playback buffer.
*/
unsigned audioapi_voice_p_status2();
unsigned voice_p_status2();
/**
* Get the voice channel record status register.
*
* Returns: The number of samples in capture buffer.
*/
unsigned audioapi_voice_r_status();
unsigned voice_r_status();
/**
* Play sound on voice channel.
*
* Parameter samples: The samples to play.
* Parameter count: Number of samples to play. Must be less than number of samples free for playback.
*/
void audioapi_play_voice(float* samples, size_t count);
void play_voice(float* samples, size_t count);
/**
* Capture sound on voice channel.
*
* Parameter samples: The buffer to store captured samples to.
* Parameter count: Number of samples to capture. Must be less than number of samples used for capture.
*/
void audioapi_record_voice(float* samples, size_t count);
void record_voice(float* samples, size_t count);
/**
* Init the audio. Call on emulator startup.
*/
void audioapi_init();
void init();
/**
* Quit the audio. Call on emulator shutdown.
*/
void audioapi_quit();
void quit();
/**
* Set music volume.
*
* Parameter volume: The volume (0-1).
*/
void audioapi_music_volume(float volume);
void music_volume(float volume);
/**
* Get music volume.
*
* Returns: The music volume.
*/
float audioapi_music_volume();
float music_volume();
/**
* Set voice playback volume.
*
* Parameter volume: The volume (0-1).
*/
void audioapi_voicep_volume(float volume);
void voicep_volume(float volume);
/**
* Get voice playback volume.
*
* Returns: The voice playback volume.
*/
float audioapi_voicep_volume();
float voicep_volume();
/**
* Set voice capture volume.
*
* Parameter volume: The volume (0-1).
*/
void audioapi_voicer_volume(float volume);
void voicer_volume(float volume);
/**
* Get voice capture volume.
*
* Returns: The voice capture volume.
*/
float audioapi_voicer_volume();
float voicer_volume();
//The following are intended to be used by the driver from the callback
/**
* Get mixed music + voice buffer to play (at voice rate).
*
@ -209,8 +193,7 @@ float audioapi_voicer_volume();
* Parameter count: Number of samples to generate.
* Parameter stereo: If true, return stereo buffer, else mono.
*/
void audioapi_get_mixed(int16_t* samples, size_t count, bool stereo);
void get_mixed(int16_t* samples, size_t count, bool stereo);
/**
* Get music channel buffer to play.
*
@ -219,8 +202,7 @@ void audioapi_get_mixed(int16_t* samples, size_t count, bool stereo);
*
* Note: This should only be called from the sound driver.
*/
struct audioapi_buffer audioapi_get_music(size_t played);
struct buffer get_music(size_t played);
/**
* Get voice channel buffer to play.
*
@ -229,8 +211,7 @@ struct audioapi_buffer audioapi_get_music(size_t played);
*
* Note: This should only be called from the sound driver.
*/
void audioapi_get_voice(float* samples, size_t count);
void get_voice(float* samples, size_t count);
/**
* Put recorded voice channel buffer.
*
@ -240,8 +221,7 @@ void audioapi_get_voice(float* samples, size_t count);
* Note: Even if audio driver does not support capture, one should send in silence.
* Note: This should only be called from the sound driver.
*/
void audioapi_put_voice(float* samples, size_t count);
void put_voice(float* samples, size_t count);
/**
* Set the voice channel playback/record rate.
*
@ -251,7 +231,51 @@ void audioapi_put_voice(float* samples, size_t count);
* Note: This should only be called from the sound driver.
* Note: Setting rate to 0 enables dummy callbacks.
*/
void audioapi_voice_rate(unsigned rate_r, unsigned rate_p);
void voice_rate(unsigned rate_r, unsigned rate_p);
//Vu values.
vumeter vu_mleft;
vumeter vu_mright;
vumeter vu_vout;
vumeter vu_vin;
private:
struct dummy_cb_proc
{
dummy_cb_proc(audioapi_instance& _parent);
int operator()();
audioapi_instance& parent;
};
dummy_cb_proc dummyproc;
threads::thread* dummythread;
//3 music buffers is not enough due to huge blocksizes used by SDL.
const static unsigned MUSIC_BUFFERS = 8;
const static unsigned voicep_bufsize = 65536;
const static unsigned voicer_bufsize = 65536;
const static unsigned music_bufsize = 8192;
float voicep_buffer[voicep_bufsize];
float voicer_buffer[voicer_bufsize];
int16_t music_buffer[MUSIC_BUFFERS * music_bufsize];
volatile bool music_stereo[MUSIC_BUFFERS];
volatile double music_rate[MUSIC_BUFFERS];
volatile size_t music_size[MUSIC_BUFFERS];
unsigned music_ptr;
unsigned last_complete_music_seen;
volatile unsigned last_complete_music;
volatile unsigned voicep_get;
volatile unsigned voicep_put;
volatile unsigned voicer_get;
volatile unsigned voicer_put;
volatile unsigned voice_rate_play;
volatile unsigned orig_voice_rate_play;
volatile unsigned voice_rate_rec;
volatile bool dummy_cb_active_record;
volatile bool dummy_cb_active_play;
volatile bool dummy_cb_quit;
volatile float _music_volume;
volatile float _voicep_volume;
volatile float _voicer_volume;
};
//All the following need to be implemented by the sound driver itself
struct _audioapi_driver

View file

@ -25,6 +25,7 @@ class button_mapping;
class emulator_dispatch;
class slotinfo_cache;
class lua_state;
class audioapi_instance;
namespace command { class group; }
namespace lua { class state; }
namespace settingvar { class group; }
@ -117,6 +118,7 @@ struct emulator_instance
input_queue* iqueue;
master_dumper* mdumper;
slotinfo_cache* slotcache;
audioapi_instance* audio;
threads::id emu_thread;
time_t random_seed_value;
dtor_list D;

View file

@ -28,7 +28,7 @@ public:
uint64_t length;
};
voice_commentary(settingvar::group& _settings, emulator_dispatch& _dispatch);
voice_commentary(settingvar::group& _settings, emulator_dispatch& _dispatch, audioapi_instance& _audio);
~voice_commentary();
void init();
void kill();
@ -52,6 +52,7 @@ private:
void* internal;
settingvar::group& settings;
emulator_dispatch& edispatch;
audioapi_instance& audio;
};
#endif

View file

@ -12,65 +12,37 @@
#include <unistd.h>
#include <sys/time.h>
//3 music buffers is not enough due to huge blocksizes used by SDL.
#define MUSIC_BUFFERS 8
#define MAX_VOICE_ADJUST 200
audioapi_instance::dummy_cb_proc::dummy_cb_proc(audioapi_instance& _parent)
: parent(_parent)
{
}
int audioapi_instance::dummy_cb_proc::operator()()
{
int16_t buf[16384];
uint64_t last_ts = framerate_regulator::get_utime();
while(!parent.dummy_cb_quit) {
uint64_t cur_ts = framerate_regulator::get_utime();
uint64_t dt = cur_ts - last_ts;
last_ts = cur_ts;
unsigned samples = dt / 25;
if(samples > 16384)
samples = 16384; //Don't get crazy.
if(parent.dummy_cb_active_play)
parent.get_mixed(buf, samples, false);
if(parent.dummy_cb_active_record)
parent.put_voice(NULL, samples);
usleep(10000);
}
return 0;
}
namespace
{
bool paniced = false;
const unsigned voicep_bufsize = 65536;
const unsigned voicer_bufsize = 65536;
const unsigned music_bufsize = 8192;
float voicep_buffer[voicep_bufsize];
float voicer_buffer[voicer_bufsize];
int16_t music_buffer[MUSIC_BUFFERS * music_bufsize];
volatile bool music_stereo[MUSIC_BUFFERS];
volatile double music_rate[MUSIC_BUFFERS];
volatile size_t music_size[MUSIC_BUFFERS];
unsigned music_ptr;
unsigned last_complete_music_seen = MUSIC_BUFFERS + 1;
volatile unsigned last_complete_music = MUSIC_BUFFERS;
volatile unsigned voicep_get = 0;
volatile unsigned voicep_put = 0;
volatile unsigned voicer_get = 0;
volatile unsigned voicer_put = 0;
volatile unsigned voice_rate_play = 40000;
volatile unsigned orig_voice_rate_play = 40000;
volatile unsigned voice_rate_rec = 40000;
volatile bool dummy_cb_active_record = false;
volatile bool dummy_cb_active_play = false;
volatile bool dummy_cb_quit = false;
volatile float music_volume = 1;
volatile float voicep_volume = 32767.0;
volatile float voicer_volume = 1.0/32768;
struct dummy_cb_proc
{
int operator()()
{
int16_t buf[16384];
uint64_t last_ts = framerate_regulator::get_utime();
while(!dummy_cb_quit) {
uint64_t cur_ts = framerate_regulator::get_utime();
uint64_t dt = cur_ts - last_ts;
last_ts = cur_ts;
unsigned samples = dt / 25;
if(samples > 16384)
samples = 16384; //Don't get crazy.
if(dummy_cb_active_play)
audioapi_get_mixed(buf, samples, false);
if(dummy_cb_active_record)
audioapi_put_voice(NULL, samples);
usleep(10000);
}
return 0;
}
};
dummy_cb_proc* dummy_cb_proc_obj;
threads::thread* dummy_cb_thread;
// | -1 1 -1 1 | 1 0 0 0 |
// | 0 0 0 1 | 0 1 0 0 |
@ -100,14 +72,15 @@ namespace
}
}
audioapi_resampler::audioapi_resampler()
audioapi_instance::resampler::resampler()
{
position = 0;
vAl = vBl = vCl = vDl = 0;
vAr = vBr = vCr = vDr = 0;
}
void audioapi_resampler::resample(float*& in, size_t& insize, float*& out, size_t& outsize, double ratio, bool stereo)
void audioapi_instance::resampler::resample(float*& in, size_t& insize, float*& out, size_t& outsize, double ratio,
bool stereo)
{
double iratio = 1 / ratio;
while(outsize) {
@ -136,18 +109,43 @@ exit:
;
}
audioapi_instance::audioapi_instance()
: dummyproc(*this)
{
music_ptr = 0;
last_complete_music_seen = MUSIC_BUFFERS + 1;
last_complete_music = MUSIC_BUFFERS;
voicep_get = 0;
voicep_put = 0;
voicer_get = 0;
voicer_put = 0;
voice_rate_play = 40000;
orig_voice_rate_play = 40000;
voice_rate_rec = 40000;
dummy_cb_active_record = false;
dummy_cb_active_play = false;
dummy_cb_quit = false;
_music_volume = 1;
_voicep_volume = 32767.0;
_voicer_volume = 1.0/32768;
}
std::pair<unsigned, unsigned> audioapi_voice_rate()
audioapi_instance::~audioapi_instance()
{
quit();
}
std::pair<unsigned, unsigned> audioapi_instance::voice_rate()
{
return std::make_pair(voice_rate_rec, voice_rate_play);
}
unsigned audioapi_orig_voice_rate()
unsigned audioapi_instance::orig_voice_rate()
{
return orig_voice_rate_play;
}
void audioapi_voice_rate(unsigned rate_rec, unsigned rate_play)
void audioapi_instance::voice_rate(unsigned rate_rec, unsigned rate_play)
{
if(rate_rec)
voice_rate_rec = rate_rec;
@ -161,7 +159,7 @@ void audioapi_voice_rate(unsigned rate_rec, unsigned rate_play)
dummy_cb_active_play = !rate_play;
}
unsigned audioapi_voice_p_status()
unsigned audioapi_instance::voice_p_status()
{
unsigned p = voicep_put;
unsigned g = voicep_get;
@ -171,7 +169,7 @@ unsigned audioapi_voice_p_status()
return voicep_bufsize - (p - g) - 1;
}
unsigned audioapi_voice_p_status2()
unsigned audioapi_instance::voice_p_status2()
{
unsigned p = voicep_put;
unsigned g = voicep_get;
@ -181,7 +179,7 @@ unsigned audioapi_voice_p_status2()
return (p - g);
}
unsigned audioapi_voice_r_status()
unsigned audioapi_instance::voice_r_status()
{
unsigned p = voicer_put;
unsigned g = voicer_get;
@ -191,7 +189,7 @@ unsigned audioapi_voice_r_status()
return (p - g);
}
void audioapi_play_voice(float* samples, size_t count)
void audioapi_instance::play_voice(float* samples, size_t count)
{
unsigned ptr = voicep_put;
for(size_t i = 0; i < count; i++) {
@ -202,7 +200,7 @@ void audioapi_play_voice(float* samples, size_t count)
voicep_put = ptr;
}
void audioapi_record_voice(float* samples, size_t count)
void audioapi_instance::record_voice(float* samples, size_t count)
{
unsigned ptr = voicer_get;
for(size_t i = 0; i < count; i++) {
@ -213,7 +211,7 @@ void audioapi_record_voice(float* samples, size_t count)
voicer_get = ptr;
}
void audioapi_submit_buffer(int16_t* samples, size_t count, bool stereo, double rate)
void audioapi_instance::submit_buffer(int16_t* samples, size_t count, bool stereo, double rate)
{
if(stereo)
for(unsigned i = 0; i < count; i++)
@ -233,14 +231,14 @@ void audioapi_submit_buffer(int16_t* samples, size_t count, bool stereo, double
last_complete_music = bidx;
}
struct audioapi_buffer audioapi_get_music(size_t played)
struct audioapi_instance::buffer audioapi_instance::get_music(size_t played)
{
static bool last_adjust = false; //Adjusting consequtively is too hard.
unsigned midx = last_complete_music_seen;
unsigned midx2 = last_complete_music;
if(midx2 >= MUSIC_BUFFERS) {
//Special case: No buffer.
struct audioapi_buffer out;
struct buffer out;
out.samples = NULL;
out.pointer = 0;
//The rest are arbitrary.
@ -281,7 +279,7 @@ struct audioapi_buffer audioapi_get_music(size_t played)
}
}
//Fill the structure.
struct audioapi_buffer out;
struct buffer out;
if(music_ptr < music_size[midx]) {
out.samples = music_buffer + midx * music_bufsize;
out.pointer = music_ptr;
@ -301,14 +299,14 @@ struct audioapi_buffer audioapi_get_music(size_t played)
return out;
}
void audioapi_get_voice(float* samples, size_t count)
void audioapi_instance::get_voice(float* samples, size_t count)
{
unsigned g = voicep_get;
unsigned p = voicep_put;
if(samples) {
for(size_t i = 0; i < count; i++) {
if(g != p)
samples[i] = voicep_volume * voicep_buffer[g++];
samples[i] = _voicep_volume * voicep_buffer[g++];
else
samples[i] = 0.0;
if(g == voicep_bufsize)
@ -325,19 +323,19 @@ void audioapi_get_voice(float* samples, size_t count)
voicep_get = g;
}
void audioapi_put_voice(float* samples, size_t count)
void audioapi_instance::put_voice(float* samples, size_t count)
{
unsigned ptr = voicer_put;
audioapi_vu_vin(samples, count, false, voice_rate_rec, voicer_volume);
vu_vin(samples, count, false, voice_rate_rec, _voicer_volume);
for(size_t i = 0; i < count; i++) {
voicer_buffer[ptr++] = samples ? voicer_volume * samples[i] : 0.0;
voicer_buffer[ptr++] = samples ? _voicer_volume * samples[i] : 0.0;
if(ptr == voicer_bufsize)
ptr = 0;
}
voicer_put = ptr;
}
void audioapi_init()
void audioapi_instance::init()
{
voicep_get = 0;
voicep_put = 0;
@ -348,55 +346,56 @@ void audioapi_init()
dummy_cb_active_play = true;
dummy_cb_active_record = true;
dummy_cb_quit = false;
dummy_cb_proc_obj = new dummy_cb_proc;
dummy_cb_thread = new threads::thread(*dummy_cb_proc_obj);
dummythread = new threads::thread(dummyproc);
}
void audioapi_quit()
void audioapi_instance::quit()
{
dummy_cb_quit = true;
dummy_cb_thread->join();
delete dummy_cb_proc_obj;
if(dummythread) {
dummythread->join();
dummythread = NULL;
}
}
void audioapi_music_volume(float volume)
void audioapi_instance::music_volume(float volume)
{
music_volume = volume;
_music_volume = volume;
}
float audioapi_music_volume()
float audioapi_instance::music_volume()
{
return music_volume;
return _music_volume;
}
void audioapi_voicep_volume(float volume)
void audioapi_instance::voicep_volume(float volume)
{
voicep_volume = volume * 32767;
_voicep_volume = volume * 32767;
}
float audioapi_voicep_volume()
float audioapi_instance::voicep_volume()
{
return voicep_volume / 32767;
return _voicep_volume / 32767;
}
void audioapi_voicer_volume(float volume)
void audioapi_instance::voicer_volume(float volume)
{
voicer_volume = volume / 32768;
_voicer_volume = volume / 32768;
}
float audioapi_voicer_volume()
float audioapi_instance::voicer_volume()
{
return voicer_volume * 32768;
return _voicer_volume * 32768;
}
void audioapi_get_mixed(int16_t* samples, size_t count, bool stereo)
void audioapi_instance::get_mixed(int16_t* samples, size_t count, bool stereo)
{
static audioapi_resampler music_resampler;
static resampler music_resampler;
const size_t intbuf_size = 256;
float intbuf[intbuf_size];
float intbuf2[intbuf_size];
while(count > 0) {
audioapi_buffer b = audioapi_get_music(0);
buffer b = get_music(0);
float* in = intbuf;
float* out = intbuf2;
size_t outdata_used;
@ -407,19 +406,19 @@ void audioapi_get_mixed(int16_t* samples, size_t count, bool stereo)
outdata_used = outdata;
if(b.samples)
for(size_t i = 0; i < 2 * indata; i++)
intbuf[i] = music_volume * b.samples[i + 2 * b.pointer];
intbuf[i] = _music_volume * b.samples[i + 2 * b.pointer];
else
for(size_t i = 0; i < 2 * indata; i++)
intbuf[i] = 0;
music_resampler.resample(in, indata, out, outdata, (double)voice_rate_play / b.rate, true);
indata_used -= indata;
outdata_used -= outdata;
audioapi_get_music(indata_used);
audioapi_get_voice(intbuf, outdata_used);
get_music(indata_used);
get_voice(intbuf, outdata_used);
audioapi_vu_mleft(intbuf2, outdata_used, true, voice_rate_play, 1 / 32768.0);
audioapi_vu_mright(intbuf2 + 1, outdata_used, true, voice_rate_play, 1 / 32768.0);
audioapi_vu_vout(intbuf, outdata_used, false, voice_rate_play, 1 / 32768.0);
vu_mleft(intbuf2, outdata_used, true, voice_rate_play, 1 / 32768.0);
vu_mright(intbuf2 + 1, outdata_used, true, voice_rate_play, 1 / 32768.0);
vu_vout(intbuf, outdata_used, false, voice_rate_play, 1 / 32768.0);
for(size_t i = 0; i < outdata_used * (stereo ? 2 : 1); i++)
intbuf2[i] = max(min(intbuf2[i] + intbuf[i / 2], 32766.0f), -32767.0f);
@ -436,19 +435,19 @@ void audioapi_get_mixed(int16_t* samples, size_t count, bool stereo)
outdata_used = outdata;
if(b.samples)
for(size_t i = 0; i < indata; i++)
intbuf[i] = music_volume * b.samples[i + b.pointer];
intbuf[i] = _music_volume * b.samples[i + b.pointer];
else
for(size_t i = 0; i < indata; i++)
intbuf[i] = 0;
music_resampler.resample(in, indata, out, outdata, (double)voice_rate_play / b.rate, false);
indata_used -= indata;
outdata_used -= outdata;
audioapi_get_music(indata_used);
audioapi_get_voice(intbuf, outdata_used);
get_music(indata_used);
get_voice(intbuf, outdata_used);
audioapi_vu_mleft(intbuf2, outdata_used, false, voice_rate_play, 1 / 32768.0);
audioapi_vu_mright(intbuf2, outdata_used, false, voice_rate_play, 1 / 32768.0);
audioapi_vu_vout(intbuf, outdata_used, false, voice_rate_play, 1 / 32768.0);
vu_mleft(intbuf2, outdata_used, false, voice_rate_play, 1 / 32768.0);
vu_mright(intbuf2, outdata_used, false, voice_rate_play, 1 / 32768.0);
vu_vout(intbuf, outdata_used, false, voice_rate_play, 1 / 32768.0);
for(size_t i = 0; i < outdata_used; i++)
intbuf2[i] = max(min(intbuf2[i] + intbuf[i], 32766.0f), -32767.0f);
@ -466,14 +465,14 @@ void audioapi_get_mixed(int16_t* samples, size_t count, bool stereo)
}
}
audioapi_vumeter::audioapi_vumeter()
audioapi_instance::vumeter::vumeter()
{
accumulator = 0;
samples = 0;
vu = -999.0;
}
void audioapi_vumeter::operator()(float* asamples, size_t count, bool stereo, double rate, double scale)
void audioapi_instance::vumeter::operator()(float* asamples, size_t count, bool stereo, double rate, double scale)
{
size_t limit = rate / 25;
//If we already at or exceed limit, cut immediately.
@ -505,7 +504,7 @@ void audioapi_vumeter::operator()(float* asamples, size_t count, bool stereo, do
}
}
void audioapi_vumeter::update_vu()
void audioapi_instance::vumeter::update_vu()
{
if(paniced)
return;
@ -529,9 +528,3 @@ void audioapi_panicing() throw()
{
paniced = true;
}
//VU values.
audioapi_vumeter audioapi_vu_mleft;
audioapi_vumeter audioapi_vu_mright;
audioapi_vumeter audioapi_vu_vout;
audioapi_vumeter audioapi_vu_vin;

View file

@ -1,4 +1,5 @@
#include "core/audioapi.hpp"
#include "core/instance.hpp"
#include <cstdlib>
#include <iostream>
@ -7,7 +8,7 @@ namespace
{
void dummy_init() throw()
{
audioapi_voice_rate(0, 0);
lsnes_instance.audio->voice_rate(0, 0);
}
void dummy_quit() throw()

View file

@ -1,4 +1,5 @@
#include "core/advdumper.hpp"
#include "core/audioapi.hpp"
#include "core/command.hpp"
#include "core/controllerframe.hpp"
#include "core/controller.hpp"
@ -80,7 +81,8 @@ emulator_instance::emulator_instance()
D.init(mwatch, *memory, *project, *fbuf);
D.init(settings);
D.init(setcache, *settings);
D.init(commentary, *settings, *dispatch);
D.init(audio);
D.init(commentary, *settings, *dispatch, *audio);
D.init(subtitles, *mlogic, *fbuf, *dispatch);
D.init(mbranch, *mlogic, *dispatch);
D.init(controls, *project, *mlogic, *buttons, *dispatch);

View file

@ -74,8 +74,8 @@ namespace
struct voicesub_state
{
voicesub_state(settingvar::group& _settings, emulator_dispatch& _dispatch)
: settings(_settings), edispatch(_dispatch)
voicesub_state(settingvar::group& _settings, emulator_dispatch& _dispatch, audioapi_instance& _audio)
: settings(_settings), edispatch(_dispatch), audio(_audio)
{
current_time = 0;
time_jump = false;
@ -114,7 +114,7 @@ namespace
void start_management_stream(opus_stream& s);
void advance_time(uint64_t newtime);
void jump_time(uint64_t newtime);
void do_resample(audioapi_resampler& r, float* srcbuf, size_t& srcuse, float* dstbuf,
void do_resample(audioapi_instance::resampler& r, float* srcbuf, size_t& srcuse, float* dstbuf,
size_t& dstuse, size_t dstmax, double ratio);
void drain_input();
void read_input(float* buf, size_t& use, size_t maxuse);
@ -127,6 +127,7 @@ namespace
void handle_tangent_negative_edge(opus_stream*& active_stream, bitrate_tracker& brtrack);
settingvar::group& settings;
emulator_dispatch& edispatch;
audioapi_instance& audio;
};
voicesub_state* get_state(void* ptr)
@ -1397,8 +1398,8 @@ out:
}
//Resample.
void voicesub_state::do_resample(audioapi_resampler& r, float* srcbuf, size_t& srcuse, float* dstbuf,
size_t& dstuse, size_t dstmax, double ratio)
void voicesub_state::do_resample(audioapi_instance::resampler& r, float* srcbuf, size_t& srcuse,
float* dstbuf, size_t& dstuse, size_t dstmax, double ratio)
{
if(srcuse == 0 || dstuse >= dstmax)
return;
@ -1417,20 +1418,20 @@ out:
//Drain the input buffer.
void voicesub_state::drain_input()
{
while(audioapi_voice_r_status() > 0) {
while(audio.voice_r_status() > 0) {
float buf[256];
unsigned size = min(audioapi_voice_r_status(), 256u);
audioapi_record_voice(buf, size);
unsigned size = min(audio.voice_r_status(), 256u);
audio.record_voice(buf, size);
}
}
//Read the input buffer.
void voicesub_state::read_input(float* buf, size_t& use, size_t maxuse)
{
size_t rleft = audioapi_voice_r_status();
size_t rleft = audio.voice_r_status();
unsigned toread = min(rleft, max(maxuse, use) - use);
if(toread > 0) {
audioapi_record_voice(buf + use, toread);
audio.record_voice(buf + use, toread);
use += toread;
}
}
@ -1578,8 +1579,8 @@ out:
class inthread_th : public workthread::worker
{
public:
inthread_th(voicesub_state* _internal)
: internal(*_internal)
inthread_th(voicesub_state* _internal, audioapi_instance& _audio)
: internal(*_internal), audio(_audio)
{
quit = false;
quit_ack = false;
@ -1628,8 +1629,8 @@ out:
opus::encoder oenc(opus::samplerate::r48k, false, opus::application::voice);
oenc.ctl(opus::bitrate(SET_opus_bitrate(internal.settings)));
audioapi_resampler rin;
audioapi_resampler rout;
audioapi_instance::resampler rin;
audioapi_instance::resampler rout;
const unsigned buf_max = 6144; //These buffers better be large.
size_t buf_in_use = 0;
size_t buf_inr_use = 0;
@ -1663,8 +1664,8 @@ out:
break;
//Read input, up to 25ms.
unsigned rate_in = audioapi_voice_rate().first;
unsigned rate_out = audioapi_voice_rate().second;
unsigned rate_in = audio.voice_rate().first;
unsigned rate_out = audio.voice_rate().second;
size_t dbuf_max = min(buf_max, rate_in / REC_THRESHOLD_DIV);
internal.read_input(buf_in, buf_in_use, dbuf_max);
@ -1689,8 +1690,8 @@ out:
1.0 * rate_out / OPUS_SAMPLERATE);
//Output stuff.
if(buf_out_use > 0 && audioapi_voice_p_status2() < rate_out / PLAY_THRESHOLD_DIV) {
audioapi_play_voice(buf_out, buf_out_use);
if(buf_out_use > 0 && audio.voice_p_status2() < rate_out / PLAY_THRESHOLD_DIV) {
audio.play_voice(buf_out, buf_out_use);
buf_out_use = 0;
}
@ -1711,6 +1712,7 @@ out:
threads::lock lmut;
threads::cv lcond;
voicesub_state& internal;
audioapi_instance& audio;
};
//The tangent function.
@ -1727,8 +1729,9 @@ out:
keyboard::invbind_info IBIND_itangent(lsnes_invbinds, "+tangent", "Movie‣Voice tangent");
}
voice_commentary::voice_commentary(settingvar::group& _settings, emulator_dispatch& _dispatch)
: settings(_settings), edispatch(_dispatch)
voice_commentary::voice_commentary(settingvar::group& _settings, emulator_dispatch& _dispatch,
audioapi_instance& _audio)
: settings(_settings), edispatch(_dispatch), audio(_audio)
{
internal = NULL;
}
@ -1757,10 +1760,10 @@ void voice_commentary::frame_number(uint64_t newframe, double rate)
void voice_commentary::init()
{
internal = new voicesub_state(settings, edispatch);
internal = new voicesub_state(settings, edispatch, audio);
auto _internal = get_state(internal);
try {
_internal->int_task = new inthread_th(_internal);
_internal->int_task = new inthread_th(_internal, audio);
} catch(...) {
delete _internal;
throw;

View file

@ -173,7 +173,7 @@ void platform::init()
system_log << "-----------------------------------------------------------------------" << std::endl;
do_init_font();
graphics_driver_init();
audioapi_init();
lsnes_instance.audio->init();
audioapi_driver_init();
joystick_driver_init();
}
@ -182,7 +182,7 @@ void platform::quit()
{
joystick_driver_quit();
audioapi_driver_quit();
audioapi_quit();
lsnes_instance.audio->quit();
graphics_driver_quit();
msgbuf.unregister_handler(msg_callback_obj);
time_t curtime = time(NULL);

View file

@ -1754,7 +1754,7 @@ again2:
ecore_callbacks->output_frame(ls, fps_n, fps_d);
if(soundbuf_fill > 0) {
auto freq = SNES::system.apu_frequency();
audioapi_submit_buffer(soundbuf, soundbuf_fill / 2, true, freq / 768.0);
CORE().audio->submit_buffer(soundbuf, soundbuf_fill / 2, true, freq / 768.0);
soundbuf_fill = 0;
}
}

View file

@ -700,7 +700,7 @@ namespace
framebuffer::raw ls(inf);
ecore_callbacks->output_frame(ls, 262144, 4389);
audioapi_submit_buffer(soundbuf, emitted / 2, true, native_rate ? 2097152 : 32768);
CORE().audio->submit_buffer(soundbuf, emitted / 2, true, native_rate ? 2097152 : 32768);
}
void c_runtosave() {}
bool c_get_pflag() { return pflag; }

View file

@ -6,6 +6,7 @@
#include "demo.hpp"
#include "core/dispatch.hpp"
#include "core/audioapi.hpp"
#include "core/instance.hpp"
#include "core/messages.hpp"
#include "interface/romtype.hpp"
#include "interface/callbacks.hpp"
@ -326,7 +327,7 @@ namespace sky
samples += corei.extrasamples();
int16_t sbuf[2668];
fetch_sfx(corei, sbuf, samples);
audioapi_submit_buffer(sbuf, samples, true, 48000);
CORE().audio->submit_buffer(sbuf, samples, true, 48000);
}
void c_runtosave() {}
bool c_get_pflag() { return pflag; }

View file

@ -27,6 +27,7 @@
#include "core/controllerframe.hpp"
#include "core/dispatch.hpp"
#include "core/framebuffer.hpp"
#include "core/instance.hpp"
#include "core/messages.hpp"
#include "interface/callbacks.hpp"
#include "interface/cover.hpp"
@ -163,7 +164,7 @@ namespace
inf.offset_y = 0;
framebuffer::raw ls(inf);
ecore_callbacks->output_frame(ls, 60,1);
audioapi_submit_buffer(audio, 800, false, 48000);
CORE().audio->submit_buffer(audio, 800, false, 48000);
}
void c_runtosave() {}
bool c_get_pflag() { return pflag; }

View file

@ -12,6 +12,7 @@
#include "library/framebuffer-pixfmt-rgb32.hpp"
#include "library/framebuffer-pixfmt-lrgb.hpp"
#include "core/audioapi.hpp"
#include "core/instance.hpp"
#include "core/messages.hpp"
template<> int ccore_call_param_map<lsnes_core_enumerate_cores>::id = LSNES_CORE_ENUMERATE_CORES;
@ -855,7 +856,7 @@ failed:
void callback_submit_sound(const int16_t* samples, size_t count, int stereo, double rate)
{
audioapi_submit_buffer((int16_t*)samples, count, stereo, rate);
CORE().audio->submit_buffer((int16_t*)samples, count, stereo, rate);
}
void callback_notify_latch(const char** params)

View file

@ -21,6 +21,7 @@
#include <fstream>
#include <cassert>
#include "core/audioapi.hpp"
#include "core/instance.hpp"
#include "library/minmax.hpp"
#include "library/workthread.hpp"
#include <string>
@ -45,7 +46,7 @@ namespace
{
int16_t buffer[1024];
while(true) {
audioapi_get_mixed(buffer, 512, true);
lsnes_instance.audio->get_mixed(buffer, 512, true);
if(!was_enabled)
memset(buffer, 0, sizeof(buffer));
ao_device* d = cdev;
@ -67,7 +68,7 @@ namespace
usleep(50000);
ao_close(d);
current_device = "";
audioapi_voice_rate(0, 0);
lsnes_instance.audio->voice_rate(0, 0);
}
//Open new audio.
if(newdevice != -1) {
@ -101,7 +102,7 @@ namespace
(stringfmt() << "Error code " << err).throwex();
}
}
audioapi_voice_rate(0, 48000);
lsnes_instance.audio->voice_rate(0, 48000);
}
if(cdev) {
current_device = name;

View file

@ -3,6 +3,7 @@
#include "core/command.hpp"
#include "core/dispatch.hpp"
#include "core/framerate.hpp"
#include "core/instance.hpp"
#include "core/messages.hpp"
#include "core/framerate.hpp"
#include "core/keymapper.hpp"
@ -53,7 +54,7 @@ namespace
size_t ptr = 0;
while(pframe_count > 0) {
unsigned bsize = min(voice_blocksize / 2, static_cast<unsigned>(pframe_count));
audioapi_get_mixed(voicebuf, bsize, flag_pstereo);
lsnes_instance.audio->get_mixed(voicebuf, bsize, flag_pstereo);
unsigned limit = bsize * (flag_pstereo ? 2 : 1);
if(was_enabled)
for(size_t i = 0; i < limit; i++)
@ -80,7 +81,7 @@ namespace
else
for(size_t i = 0; i < bsize; i++)
voicebuf2[i] = _input[iptr++];
audioapi_put_voice(voicebuf2, bsize);
lsnes_instance.audio->put_voice(voicebuf2, bsize);
rframe_count -= bsize;
}
}
@ -175,7 +176,7 @@ namespace
stream_p = NULL;
current_pdev = paNoDevice;
current_pfreq = 0;
audioapi_voice_rate(current_rfreq, current_pfreq);
lsnes_instance.audio->voice_rate(current_rfreq, current_pfreq);
}
void close_input()
@ -184,7 +185,7 @@ namespace
stream_r = NULL;
current_rdev = paNoDevice;
current_rfreq = 0;
audioapi_voice_rate(current_rfreq, current_pfreq);
lsnes_instance.audio->voice_rate(current_rfreq, current_pfreq);
}
void close_all()
@ -228,20 +229,20 @@ namespace
PaError err = Pa_OpenStream(&stream_p, NULL, output, inf->defaultSampleRate, 0, 0, audiocb, NULL);
if(err != paNoError) {
messages << "Portaudio: error (open): " << Pa_GetErrorText(err) << std::endl;
audioapi_voice_rate(current_rfreq, current_pfreq);
lsnes_instance.audio->voice_rate(current_rfreq, current_pfreq);
return 1;
}
flag_pstereo = (output && output->channelCount == 2);
err = Pa_StartStream(stream_p);
if(err != paNoError) {
messages << "Portaudio error (start): " << Pa_GetErrorText(err) << std::endl;
audioapi_voice_rate(current_rfreq, current_pfreq);
lsnes_instance.audio->voice_rate(current_rfreq, current_pfreq);
return 1;
}
const PaStreamInfo* si = Pa_GetStreamInfo(stream_p);
current_pfreq = output ? si->sampleRate : 0;
current_pdev = dev;
audioapi_voice_rate(current_rfreq, current_pfreq);
lsnes_instance.audio->voice_rate(current_rfreq, current_pfreq);
print_status(2);
return 3;
}
@ -261,20 +262,20 @@ namespace
PaError err = Pa_OpenStream(&stream_r, input, NULL, inf->defaultSampleRate, 0, 0, audiocb, NULL);
if(err != paNoError) {
messages << "Portaudio: error (open): " << Pa_GetErrorText(err) << std::endl;
audioapi_voice_rate(current_rfreq, current_pfreq);
lsnes_instance.audio->voice_rate(current_rfreq, current_pfreq);
return 2;
}
flag_rstereo = (input && input->channelCount == 2);
err = Pa_StartStream(stream_r);
if(err != paNoError) {
messages << "Portaudio error (start): " << Pa_GetErrorText(err) << std::endl;
audioapi_voice_rate(current_rfreq, current_pfreq);
lsnes_instance.audio->voice_rate(current_rfreq, current_pfreq);
return 2;
}
const PaStreamInfo* si = Pa_GetStreamInfo(stream_r);
current_rfreq = input ? si->sampleRate : 0;
current_rdev = dev;
audioapi_voice_rate(current_rfreq, current_pfreq);
lsnes_instance.audio->voice_rate(current_rfreq, current_pfreq);
print_status(1);
return 3;
}

View file

@ -105,8 +105,8 @@ public:
private:
struct _vupanel : public wxPanel
{
_vupanel(wxwin_vumeter* v)
: wxPanel(v, wxID_ANY, wxDefaultPosition, wxSize(320, 64))
_vupanel(wxwin_vumeter* v, audioapi_instance& _audio)
: wxPanel(v, wxID_ANY, wxDefaultPosition, wxSize(320, 64)), audio(_audio)
{
obj = v;
buffer.resize(61440);
@ -127,10 +127,10 @@ private:
void signal_repaint()
{
mleft = vu_to_pixels(audioapi_vu_mleft);
mright = vu_to_pixels(audioapi_vu_mright);
vout = vu_to_pixels(audioapi_vu_vout);
vin = vu_to_pixels(audioapi_vu_vin);
mleft = vu_to_pixels(audio.vu_mleft);
mright = vu_to_pixels(audio.vu_mright);
vout = vu_to_pixels(audio.vu_vout);
vin = vu_to_pixels(audio.vu_vin);
Refresh();
obj->update_sent = false;
}
@ -162,6 +162,7 @@ private:
std::vector<unsigned char> buffer;
unsigned char colorstrip[960];
size_t bufferstride;
audioapi_instance& audio;
void draw_text(unsigned x, unsigned y, unsigned w, unsigned h, const uint32_t* buf)
{
unsigned spos = 0;
@ -229,20 +230,20 @@ wxwin_vumeter::wxwin_vumeter(wxWindow* parent, emulator_instance& _inst)
wxFlexGridSizer* top_s = new wxFlexGridSizer(5, 1, 0, 0);
SetSizer(top_s);
top_s->Add(vupanel = new _vupanel(this));
top_s->Add(vupanel = new _vupanel(this, *inst.audio));
top_s->Add(rate = new wxStaticText(this, wxID_ANY, wxT("")), 0, wxGROW);
wxFlexGridSizer* slier_s = new wxFlexGridSizer(3, 3, 0, 0);
slier_s->Add(new wxStaticText(this, wxID_ANY, wxT("Game:")), 0, wxGROW);
slier_s->Add(gamevol = new wxSlider(this, wxID_ANY, to_db(audioapi_music_volume()), -100, 50,
slier_s->Add(gamevol = new wxSlider(this, wxID_ANY, to_db(inst.audio->music_volume()), -100, 50,
wxDefaultPosition, wxSize(320, -1)), 1, wxGROW);
slier_s->Add(dgamevol = new wxButton(this, wxID_ANY, wxT("Reset")));
slier_s->Add(new wxStaticText(this, wxID_ANY, wxT("Voice out:")), 1, wxGROW);
slier_s->Add(voutvol = new wxSlider(this, wxID_ANY, to_db(audioapi_voicep_volume()), -100, 50,
slier_s->Add(voutvol = new wxSlider(this, wxID_ANY, to_db(inst.audio->voicep_volume()), -100, 50,
wxDefaultPosition, wxSize(320, -1)), 1, wxGROW);
slier_s->Add(dvoutvol = new wxButton(this, wxID_ANY, wxT("Reset")));
slier_s->Add(new wxStaticText(this, wxID_ANY, wxT("Voice in:")), 1, wxGROW);
slier_s->Add(vinvol = new wxSlider(this, wxID_ANY, to_db(audioapi_voicer_volume()), -100, 50,
slier_s->Add(vinvol = new wxSlider(this, wxID_ANY, to_db(inst.audio->voicer_volume()), -100, 50,
wxDefaultPosition, wxSize(320, -1)), 1, wxGROW);
slier_s->Add(dvinvol = new wxButton(this, wxID_ANY, wxT("Reset")));
top_s->Add(slier_s, 1, wxGROW);
@ -347,34 +348,34 @@ void wxwin_vumeter::on_devsel(wxCommandEvent& e)
void wxwin_vumeter::on_game_change(wxScrollEvent& e)
{
audioapi_music_volume(pow(10, gamevol->GetValue() / 20.0));
inst.audio->music_volume(pow(10, gamevol->GetValue() / 20.0));
}
void wxwin_vumeter::on_vout_change(wxScrollEvent& e)
{
audioapi_voicep_volume(pow(10, voutvol->GetValue() / 20.0));
inst.audio->voicep_volume(pow(10, voutvol->GetValue() / 20.0));
}
void wxwin_vumeter::on_vin_change(wxScrollEvent& e)
{
audioapi_voicer_volume(pow(10, vinvol->GetValue() / 20.0));
inst.audio->voicer_volume(pow(10, vinvol->GetValue() / 20.0));
}
void wxwin_vumeter::on_game_reset(wxCommandEvent& e)
{
audioapi_music_volume(1);
inst.audio->music_volume(1);
gamevol->SetValue(0);
}
void wxwin_vumeter::on_vout_reset(wxCommandEvent& e)
{
audioapi_voicep_volume(1);
inst.audio->voicep_volume(1);
voutvol->SetValue(0);
}
void wxwin_vumeter::on_vin_reset(wxCommandEvent& e)
{
audioapi_voicer_volume(1);
inst.audio->voicer_volume(1);
vinvol->SetValue(0);
}
@ -385,8 +386,8 @@ void wxwin_vumeter::on_mute(wxCommandEvent& e)
void wxwin_vumeter::refresh()
{
auto rate_cur = audioapi_voice_rate();
unsigned rate_nom = audioapi_orig_voice_rate();
auto rate_cur = inst.audio->voice_rate();
unsigned rate_nom = inst.audio->orig_voice_rate();
rate->SetLabel(towxstring((stringfmt() << "Current: " << rate_cur.second << "Hz (nominal " << rate_nom
<< "Hz), record: " << rate_cur.first << "Hz").str()));
vupanel->signal_repaint();