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"
2015-04-14 20:32:15 +00:00
# include "oslib/audiobackend_directsound.h"
2015-04-14 21:08:32 +00:00
# include "oslib/audiobackend_android.h"
2015-04-14 14:58:41 +00:00
# include "oslib/audiobackend_alsa.h"
# include "oslib/audiobackend_oss.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 ;
2013-12-19 17:10:14 +00:00
# ifdef LOG_SOUND
WaveWriter rawout ( " d: \\ aica_out.wav " ) ;
# endif
2015-04-14 14:58:41 +00:00
static bool audiobackends_registered = false ;
static unsigned int audiobackends_num_max = 1 ;
static unsigned int audiobackends_num_registered = 0 ;
static audiobackend_t * * audiobackends = static_cast < audiobackend_t * * > ( calloc ( audiobackends_num_max , sizeof ( audiobackend_t * ) ) ) ;
static audiobackend_t * audiobackend_current = NULL ;
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 ;
}
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 ;
}
// 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 ;
}
audiobackends [ audiobackends_num_registered ] = backend ;
audiobackends_num_registered + + ;
return true ;
}
void RegisterAllAudioBackends ( ) {
2015-04-14 20:32:15 +00:00
# if HOST_OS==OS_WINDOWS
RegisterAudioBackend ( & audiobackend_directsound ) ;
# endif
2015-04-14 21:08:32 +00:00
# if ANDROID
RegisterAudioBackend ( & audiobackend_android ) ;
# endif
2015-04-14 19:31:40 +00:00
# if USE_OSS
RegisterAudioBackend ( & audiobackend_oss ) ;
# endif
2015-04-14 19:54:26 +00:00
// FIXME: We should definitely change this to "#if SUPPORT_ALSA" and set SUPPORT_ALSA to 0 or 1 in the Makefile
# if HOST_OS==OS_LINUX && !defined(TARGET_NACL32) && !defined(ANDROID)
RegisterAudioBackend ( & audiobackend_alsa ) ;
# endif
2015-04-14 14:58:41 +00:00
audiobackends_registered = true ;
}
2013-12-19 17:10:14 +00:00
2015-04-14 14:58:41 +00:00
static audiobackend_t * GetAudioBackend ( std : : string slug )
{
if ( slug = = " none " )
{
printf ( " WARNING: Audio backend set to \" none \" ! \n " ) ;
}
else if ( audiobackends_num_registered > 0 )
{
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 ;
}
u32 PushAudio ( void * frame , u32 amt , bool wait ) {
if ( audiobackend_current ! = NULL ) {
return audiobackend_current - > push ( frame , amt , wait ) ;
} else {
printf ( " AUDIO: Backend is NULL! \n " ) ;
}
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;
}
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
}
}
void InitAudio ( )
{
2015-04-14 14:58:41 +00:00
if ( cfgLoadInt ( " audio " , " disable " , 0 ) ) {
printf ( " WARNING: Audio disabled in config! \n " ) ;
return ;
}
cfgSaveInt ( " audio " , " disable " , 0 ) ;
if ( ! audiobackends_registered ) {
//FIXME: There might some nicer way to do this.
RegisterAllAudioBackends ( ) ;
}
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 ;
}
string audiobackend_slug = cfgLoadStr ( " audio " , " backend " , " auto " ) ; // FIXME: This could be made a parameter
audiobackend_current = GetAudioBackend ( audiobackend_slug ) ;
if ( audiobackend_current = = NULL ) {
printf ( " WARNING: Running without audio! \n " ) ;
return ;
}
printf ( " Initializing audio backend \" %s \" (%s)... \n " , audiobackend_current - > slug . c_str ( ) , audiobackend_current - > name . c_str ( ) ) ;
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 ;
}
2015-04-15 09:39:12 +00:00
}