2015-04-14 14:58:41 +00:00
# include <limits.h>
# include "cfg/cfg.h"
2013-12-19 17:10:14 +00:00
# include "oslib/oslib.h"
2015-04-14 14:58:41 +00:00
# include "audiostream.h"
2013-12-19 17:10:14 +00:00
struct SoundFrame { s16 l ; s16 r ; } ;
# define SAMPLE_COUNT 512
SoundFrame RingBuffer [ SAMPLE_COUNT ] ;
const u32 RingBufferByteSize = sizeof ( RingBuffer ) ;
const u32 RingBufferSampleCount = SAMPLE_COUNT ;
2013-12-24 00:56:44 +00:00
volatile u32 WritePtr ; //last WRITEN sample
volatile u32 ReadPtr ; //next sample to read
2013-12-19 17:10:14 +00:00
u32 gen_samples = 0 ;
2015-04-14 13:31:32 +00:00
double time_diff = 128 / 44100.0 ;
double time_last ;
2019-04-05 19:05:18 +00:00
2013-12-19 17:10:14 +00:00
# ifdef LOG_SOUND
2019-04-05 19:05:18 +00:00
// TODO Only works on Windows!
2013-12-19 17:10:14 +00:00
WaveWriter rawout ( " d: \\ aica_out.wav " ) ;
# endif
2015-04-14 14:58:41 +00:00
static unsigned int audiobackends_num_max = 1 ;
static unsigned int audiobackends_num_registered = 0 ;
2019-04-05 19:05:18 +00:00
static audiobackend_t * * audiobackends = NULL ;
2015-04-14 14:58:41 +00:00
static audiobackend_t * audiobackend_current = NULL ;
2019-04-05 20:22:46 +00:00
u32 GetAudioBackendCount ( )
{
return audiobackends_num_registered ;
}
audiobackend_t * GetAudioBackend ( int num )
{
return audiobackends [ num ] ;
}
2015-04-14 14:58:41 +00:00
bool RegisterAudioBackend ( audiobackend_t * backend )
{
/* This function announces the availability of an audio backend to reicast. */
// Check if backend is valid
if ( backend = = NULL )
{
printf ( " ERROR: Tried to register invalid audio backend (NULL pointer). \n " ) ;
return false ;
}
2019-04-05 19:05:18 +00:00
2015-04-14 14:58:41 +00:00
if ( backend - > slug = = " auto " | | backend - > slug = = " none " ) {
printf ( " ERROR: Tried to register invalid audio backend (slug \" %s \" is a reserved keyword). \n " , backend - > slug . c_str ( ) ) ;
return false ;
}
2019-04-05 19:05:18 +00:00
// First call to RegisterAudioBackend(), create the backend structure;
if ( audiobackends = = NULL )
audiobackends = static_cast < audiobackend_t * * > ( calloc ( audiobackends_num_max , sizeof ( audiobackend_t * ) ) ) ;
2015-04-14 14:58:41 +00:00
// Check if we need to allocate addition memory for storing the pointers and allocate if neccessary
if ( audiobackends_num_registered = = audiobackends_num_max )
{
// Check for integer overflows
if ( audiobackends_num_max = = UINT_MAX )
{
printf ( " ERROR: Registering audio backend \" %s \" (%s) failed. Cannot register more than %u backends \n " , backend - > slug . c_str ( ) , backend - > name . c_str ( ) , audiobackends_num_max ) ;
return false ;
}
audiobackends_num_max + + ;
audiobackend_t * * new_ptr = static_cast < audiobackend_t * * > ( realloc ( audiobackends , audiobackends_num_max * sizeof ( audiobackend_t * ) ) ) ;
// Make sure that allocation worked
if ( new_ptr = = NULL )
{
printf ( " ERROR: Registering audio backend \" %s \" (%s) failed. Cannot allocate additional memory. \n " , backend - > slug . c_str ( ) , backend - > name . c_str ( ) ) ;
return false ;
}
audiobackends = new_ptr ;
}
2019-04-05 19:05:18 +00:00
2015-04-14 14:58:41 +00:00
audiobackends [ audiobackends_num_registered ] = backend ;
audiobackends_num_registered + + ;
return true ;
}
2019-04-05 20:22:46 +00:00
audiobackend_t * GetAudioBackend ( std : : string slug )
2015-04-14 14:58:41 +00:00
{
if ( slug = = " none " )
{
printf ( " WARNING: Audio backend set to \" none \" ! \n " ) ;
}
2019-04-05 19:05:18 +00:00
else if ( audiobackends_num_registered > 0 )
2015-04-14 14:58:41 +00:00
{
if ( slug = = " auto " )
{
/* FIXME: At some point, one might want to insert some intelligent
algorithm for autoselecting the approriate audio backend here .
I ' m too lazy right now . */
printf ( " Auto-selected audio backend \" %s \" (%s). \n " , audiobackends [ 0 ] - > slug . c_str ( ) , audiobackends [ 0 ] - > name . c_str ( ) ) ;
return audiobackends [ 0 ] ;
}
else
{
for ( unsigned int i = 0 ; i < audiobackends_num_registered ; i + + )
{
if ( audiobackends [ i ] - > slug = = slug )
{
return audiobackends [ i ] ;
}
}
printf ( " WARNING: Audio backend \" %s \" not found! \n " , slug . c_str ( ) ) ;
}
}
else
{
printf ( " WARNING: No audio backends available! \n " ) ;
}
return NULL ;
}
2019-05-01 16:01:45 +00:00
extern double full_rps ;
2019-04-05 19:05:18 +00:00
u32 PushAudio ( void * frame , u32 amt , bool wait )
{
2019-05-01 16:01:45 +00:00
bool do_wait = ( full_rps < 50.f ) ? false : wait ;
2015-04-14 14:58:41 +00:00
if ( audiobackend_current ! = NULL ) {
2019-05-01 16:01:45 +00:00
return audiobackend_current - > push ( frame , amt , do_wait ) ;
2015-04-14 14:58:41 +00:00
}
return 0 ;
}
2013-12-19 17:10:14 +00:00
u32 asRingUsedCount ( )
{
if ( WritePtr > ReadPtr )
return WritePtr - ReadPtr ;
else
return RingBufferSampleCount - ( ReadPtr - WritePtr ) ;
//s32 sz=(WritePtr+1)%RingBufferSampleCount-ReadPtr;
//return sz<0?sz+RingBufferSampleCount:sz;
}
2019-04-05 19:05:18 +00:00
2013-12-19 17:10:14 +00:00
u32 asRingFreeCount ( )
{
return RingBufferSampleCount - asRingUsedCount ( ) ;
}
void WriteSample ( s16 r , s16 l )
{
const u32 ptr = ( WritePtr + 1 ) % RingBufferSampleCount ;
RingBuffer [ ptr ] . r = r ;
RingBuffer [ ptr ] . l = l ;
WritePtr = ptr ;
if ( WritePtr = = ( SAMPLE_COUNT - 1 ) )
{
2015-04-14 13:50:08 +00:00
PushAudio ( RingBuffer , SAMPLE_COUNT , settings . aica . LimitFPS ) ;
2013-12-19 17:10:14 +00:00
}
}
2019-04-05 19:14:42 +00:00
static bool backends_sorted = false ;
2019-04-05 20:22:46 +00:00
void SortAudioBackends ( )
2019-04-05 19:14:42 +00:00
{
if ( backends_sorted )
return ;
// Sort backends by slug
for ( int n = audiobackends_num_registered ; n > 0 ; n - - )
{
for ( int i = 0 ; i < n - 1 ; i + + )
{
if ( audiobackends [ i ] - > slug > audiobackends [ i + 1 ] - > slug )
{
audiobackend_t * swap = audiobackends [ i ] ;
audiobackends [ i ] = audiobackends [ i + 1 ] ;
audiobackends [ i + 1 ] = swap ;
}
}
}
}
2013-12-19 17:10:14 +00:00
void InitAudio ( )
{
2015-04-14 14:58:41 +00:00
if ( cfgLoadInt ( " audio " , " disable " , 0 ) ) {
printf ( " WARNING: Audio disabled in config! \n " ) ;
return ;
}
2019-04-05 19:14:42 +00:00
cfgSaveInt ( " audio " , " disable " , 0 ) ;
2015-04-14 14:58:41 +00:00
if ( audiobackend_current ! = NULL ) {
printf ( " ERROR: The audio backend \" %s \" (%s) has already been initialized, you need to terminate it before you can call audio_init() again! \n " , audiobackend_current - > slug . c_str ( ) , audiobackend_current - > name . c_str ( ) ) ;
return ;
}
2019-04-05 20:22:46 +00:00
SortAudioBackends ( ) ;
2019-04-05 19:14:42 +00:00
2019-04-05 20:22:46 +00:00
string audiobackend_slug = settings . audio . backend ;
2015-04-14 14:58:41 +00:00
audiobackend_current = GetAudioBackend ( audiobackend_slug ) ;
if ( audiobackend_current = = NULL ) {
printf ( " WARNING: Running without audio! \n " ) ;
return ;
}
2019-04-05 19:05:18 +00:00
2015-04-14 14:58:41 +00:00
printf ( " Initializing audio backend \" %s \" (%s)... \n " , audiobackend_current - > slug . c_str ( ) , audiobackend_current - > name . c_str ( ) ) ;
2019-04-05 19:05:18 +00:00
audiobackend_current - > init ( ) ;
2013-12-19 17:10:14 +00:00
}
void TermAudio ( )
{
2015-04-14 14:58:41 +00:00
if ( audiobackend_current ! = NULL ) {
audiobackend_current - > term ( ) ;
printf ( " Terminating audio backend \" %s \" (%s)... \n " , audiobackend_current - > slug . c_str ( ) , audiobackend_current - > name . c_str ( ) ) ;
audiobackend_current = NULL ;
2019-04-05 19:05:18 +00:00
}
2015-04-15 09:39:12 +00:00
}