From 248e1e4d6befc574df2c1081dab347913e41e840 Mon Sep 17 00:00:00 2001 From: gewlitys Date: Sun, 4 Jan 2004 03:38:04 +0000 Subject: [PATCH] Sound code refactoring: core api is now virtualized, MixSDL is divided to generic mixer and driver entities git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1310 8092fc87-c524-0410-9efc-e669fe64eaf9 --- sc2/ChangeLog | 2 + sc2/src/msvc++/UrQuanMasters.dsp | 78 +- sc2/src/sc2code/credits.c | 2 +- sc2/src/sc2code/libs/sound/Makeinfo | 9 +- sc2/src/sc2code/libs/sound/audiocore.c | 226 ++ sc2/src/sc2code/libs/sound/audiocore.h | 166 ++ sc2/src/sc2code/libs/sound/decoders/modaud.c | 6 +- sc2/src/sc2code/libs/sound/mixer/Makeinfo | 2 + sc2/src/sc2code/libs/sound/mixer/mixer.c | 1848 +++++++++++++++++ sc2/src/sc2code/libs/sound/mixer/mixer.h | 274 +++ sc2/src/sc2code/libs/sound/mixer/mixerint.h | 108 + .../sc2code/libs/sound/mixer/nosound/Makeinfo | 1 + .../sound/mixer/nosound/audiodrv_nosound.c | 417 ++++ .../sound/mixer/nosound/audiodrv_nosound.h | 68 + sc2/src/sc2code/libs/sound/mixer/sdl/Makeinfo | 1 + .../libs/sound/mixer/sdl/audiodrv_sdl.c | 434 ++++ .../libs/sound/mixer/sdl/audiodrv_sdl.h | 66 + sc2/src/sc2code/libs/sound/music.c | 8 +- sc2/src/sc2code/libs/sound/openal/Makeinfo | 2 +- .../libs/sound/openal/audiodrv_openal.c | 411 ++++ .../libs/sound/openal/audiodrv_openal.h | 89 + sc2/src/sc2code/libs/sound/sfx.c | 36 +- sc2/src/sc2code/libs/sound/sound.c | 96 +- sc2/src/sc2code/libs/sound/sound.h | 24 +- sc2/src/sc2code/libs/sound/stream.c | 75 +- sc2/src/sc2code/libs/sound/stream.h | 9 +- sc2/src/sc2code/libs/sound/trackplayer.c | 20 +- sc2/src/sc2code/libs/video/vidplayer.c | 4 +- sc2/src/starcon2.c | 28 +- 29 files changed, 4331 insertions(+), 179 deletions(-) create mode 100644 sc2/src/sc2code/libs/sound/audiocore.c create mode 100644 sc2/src/sc2code/libs/sound/audiocore.h create mode 100644 sc2/src/sc2code/libs/sound/mixer/Makeinfo create mode 100644 sc2/src/sc2code/libs/sound/mixer/mixer.c create mode 100644 sc2/src/sc2code/libs/sound/mixer/mixer.h create mode 100644 sc2/src/sc2code/libs/sound/mixer/mixerint.h create mode 100644 sc2/src/sc2code/libs/sound/mixer/nosound/Makeinfo create mode 100644 sc2/src/sc2code/libs/sound/mixer/nosound/audiodrv_nosound.c create mode 100644 sc2/src/sc2code/libs/sound/mixer/nosound/audiodrv_nosound.h create mode 100644 sc2/src/sc2code/libs/sound/mixer/sdl/Makeinfo create mode 100644 sc2/src/sc2code/libs/sound/mixer/sdl/audiodrv_sdl.c create mode 100644 sc2/src/sc2code/libs/sound/mixer/sdl/audiodrv_sdl.h create mode 100644 sc2/src/sc2code/libs/sound/openal/audiodrv_openal.c create mode 100644 sc2/src/sc2code/libs/sound/openal/audiodrv_openal.h diff --git a/sc2/ChangeLog b/sc2/ChangeLog index 9a7541b2c..2df14b5c9 100644 --- a/sc2/ChangeLog +++ b/sc2/ChangeLog @@ -1,4 +1,6 @@ Changes towards version 0.4: +- Sound code refactoring: core api is now virtualized, + MixSDL is divided to generic mixer and driver entities - Mika - Optimized MixSDL mixing and resampling routines (hopefully fixes bug #435) - Mika - MOD music should now play properly on big endian machines if using diff --git a/sc2/src/msvc++/UrQuanMasters.dsp b/sc2/src/msvc++/UrQuanMasters.dsp index 7bd0aa202..6f623133a 100644 --- a/sc2/src/msvc++/UrQuanMasters.dsp +++ b/sc2/src/msvc++/UrQuanMasters.dsp @@ -42,7 +42,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I ".." /I "..\sc2code" /I "..\sc2code\libs" /I "..\sc2code\ships" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D _VW=320 /D _VH=240 /D "HAVE_OPENGL" /D "GFXMODULE_SDL" /D "HAVE_OPENAL" /D "SOUNDMODULE_SDL" /D "HAVE_ZIP" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I ".." /I "..\sc2code" /I "..\sc2code\libs" /I "..\sc2code\ships" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D _VW=320 /D _VH=240 /D "HAVE_OPENGL" /D "GFXMODULE_SDL" /D "HAVE_OPENAL" /D "HAVE_ZIP" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe @@ -66,7 +66,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "." /I ".." /I "..\sc2code" /I "..\sc2code\libs" /I "..\sc2code\ships" /D "_DEBUG" /D "DEBUG_TRACK_SEM" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D _VW=320 /D _VH=240 /D "HAVE_OPENGL" /D "GFXMODULE_SDL" /D "HAVE_OPENAL" /D "SOUNDMODULE_SDL" /D "HAVE_ZIP" /FR /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "." /I ".." /I "..\sc2code" /I "..\sc2code\libs" /I "..\sc2code\ships" /D "_DEBUG" /D "DEBUG_TRACK_SEM" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D _VW=320 /D _VH=240 /D "HAVE_OPENGL" /D "GFXMODULE_SDL" /D "HAVE_OPENAL" /D "HAVE_ZIP" /FR /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe @@ -460,11 +460,11 @@ SOURCE=..\sc2code\libs\resource\resintrn.h # PROP Default_Filter "" # Begin Source File -SOURCE=..\sc2code\libs\sound\openal\mixer.h +SOURCE=..\sc2code\libs\sound\openal\audiodrv_openal.c # End Source File # Begin Source File -SOURCE=..\sc2code\libs\sound\openal\sound_openal.c +SOURCE=..\sc2code\libs\sound\openal\audiodrv_openal.h # End Source File # End Group # Begin Group "decoders" @@ -603,44 +603,60 @@ SOURCE=..\sc2code\libs\sound\decoders\mikmod\virtch_common.c # End Source File # End Group # End Group +# Begin Group "mixer" + +# PROP Default_Filter "" # Begin Group "mixsdl" # PROP Default_Filter "" # Begin Source File -SOURCE=..\sc2code\libs\sound\mixsdl\mixer.c +SOURCE=..\sc2code\libs\sound\mixer\sdl\audiodrv_sdl.c # End Source File # Begin Source File -SOURCE=..\sc2code\libs\sound\mixsdl\mixer.h +SOURCE=..\sc2code\libs\sound\mixer\sdl\audiodrv_sdl.h +# End Source File +# End Group +# Begin Group "nosound" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\sc2code\libs\sound\mixer\nosound\audiodrv_nosound.c # End Source File # Begin Source File -SOURCE=..\sc2code\libs\sound\mixsdl\mixerint.h -# End Source File -# Begin Source File - -SOURCE=..\sc2code\libs\sound\mixsdl\sound_mixsdl.c -# End Source File -# Begin Source File - -SOURCE=..\sc2code\libs\sound\mixsdl\sound_mixsdl.h +SOURCE=..\sc2code\libs\sound\mixer\nosound\audiodrv_nosound.h # End Source File # End Group # Begin Source File +SOURCE=..\sc2code\libs\sound\mixer\mixer.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\sound\mixer\mixer.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\sound\mixer\mixerint.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\sc2code\libs\sound\audiocore.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\sound\audiocore.h +# End Source File +# Begin Source File + SOURCE=..\sc2code\libs\sound\fileinst.c # End Source File # Begin Source File -SOURCE=..\sc2code\libs\sound\play.h -# End Source File -# Begin Source File - -SOURCE=..\sc2code\libs\sound\redbook.h -# End Source File -# Begin Source File - SOURCE=..\sc2code\libs\sound\resinst.c # End Source File # Begin Source File @@ -649,22 +665,6 @@ SOURCE=..\sc2code\libs\sound\sndintrn.h # End Source File # Begin Source File -SOURCE=..\sc2code\libs\sound\sound_common.c -# End Source File -# Begin Source File - -SOURCE=..\sc2code\libs\sound\sound_common.h -# End Source File -# Begin Source File - -SOURCE=..\sc2code\libs\sound\sound_chooser.c -# End Source File -# Begin Source File - -SOURCE=..\sc2code\libs\sound\sound_chooser.h -# End Source File -# Begin Source File - SOURCE=..\sc2code\libs\sound\trackplayer.h # End Source File # Begin Source File diff --git a/sc2/src/sc2code/credits.c b/sc2/src/sc2code/credits.c index 2104afbe4..9400e0cc6 100644 --- a/sc2/src/sc2code/credits.c +++ b/sc2/src/sc2code/credits.c @@ -18,7 +18,7 @@ #include "starcon.h" #include "libs/graphics/gfx_common.h" -#include "libs/sound/sound_common.h" +#include "libs/sound/sound.h" #include "oscill.h" #include "options.h" diff --git a/sc2/src/sc2code/libs/sound/Makeinfo b/sc2/src/sc2code/libs/sound/Makeinfo index c48404281..6d476cc14 100644 --- a/sc2/src/sc2code/libs/sound/Makeinfo +++ b/sc2/src/sc2code/libs/sound/Makeinfo @@ -1,10 +1,9 @@ if [ "$uqm_SOUNDMODULE" = openal ]; then - uqm_SUBDIRS="openal mixsdl decoders" + uqm_SUBDIRS="openal mixer decoders" uqm_CFLAGS="$uqm_CFLAGS -DHAVE_OPENAL" -else # mixsdl - uqm_SUBDIRS="mixsdl decoders" - uqm_CFLAGS="$uqm_CFLAGS -DSOUNDMODULE_MIXSDL" +else + uqm_SUBDIRS="mixer decoders" fi -uqm_CFILES="fileinst.c resinst.c sound_common.c sound.c sfx.c music.c stream.c trackplayer.c sound_chooser.c" +uqm_CFILES="audiocore.c fileinst.c resinst.c sound.c sfx.c music.c stream.c trackplayer.c" diff --git a/sc2/src/sc2code/libs/sound/audiocore.c b/sc2/src/sc2code/libs/sound/audiocore.c new file mode 100644 index 000000000..b9fbe0411 --- /dev/null +++ b/sc2/src/sc2code/libs/sound/audiocore.c @@ -0,0 +1,226 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Audio Core API (derived from OpenAL) + */ + +#include +#include +#include "audiocore.h" + +static audio_Driver audiodrv; + +/* + * Declarations for driver init funcs + */ + +#ifdef HAVE_OPENAL +sint32 openAL_Init (audio_Driver *driver, sint32 flags); +#endif +sint32 mixSDL_Init (audio_Driver *driver, sint32 flags); +sint32 noSound_Init (audio_Driver *driver, sint32 flags); + + +/* + * Initialization + */ + +sint32 +initAudio (sint32 driver, sint32 flags) +{ + sint32 ret; + +#ifdef HAVE_OPENAL + if (driver == audio_DRIVER_MIXSDL) + ret = mixSDL_Init (&audiodrv, flags); + else if (driver == audio_DRIVER_OPENAL) + ret = openAL_Init (&audiodrv, flags); + else + ret = noSound_Init (&audiodrv, flags); +#else + if (driver == audio_DRIVER_OPENAL) + { + fprintf (stderr, "OpenAL driver not compiled in, so using MixSDL\n"); + driver = audio_DRIVER_MIXSDL; + } + if (driver == audio_DRIVER_MIXSDL) + ret = mixSDL_Init (&audiodrv, flags); + else + ret = noSound_Init (&audiodrv, flags); +#endif + + if (ret != 0) + { + fprintf (stderr, "Sound driver initialization failed.\n" + "This may happen when a soundcard is " + "not present or not available.\n" + "NOTICE: Try running UQM with '--sound=none' option\n"); + exit (EXIT_FAILURE); + } + return ret; +} + +void +unInitAudio (void) +{ + audiodrv.Uninitialize (); +} + + +/* + * General + */ + +sint32 +audio_GetError (void) +{ + return audiodrv.GetError (); +} + + +/* + * Sources + */ + +void +audio_GenSources (uint32 n, audio_Object *psrcobj) +{ + audiodrv.GenSources (n, psrcobj); +} + +void +audio_DeleteSources (uint32 n, audio_Object *psrcobj) +{ + audiodrv.DeleteSources (n, psrcobj); +} + +bool +audio_IsSource (audio_Object srcobj) +{ + return audiodrv.IsSource (srcobj); +} + +void +audio_Sourcei (audio_Object srcobj, audio_SourceProp pname, + audio_IntVal value) + +{ + audiodrv.Sourcei (srcobj, audiodrv.EnumLookup[pname], value); +} + +void +audio_Sourcef (audio_Object srcobj, audio_SourceProp pname, + float value) +{ + audiodrv.Sourcef (srcobj, audiodrv.EnumLookup[pname], value); +} + +void +audio_Sourcefv (audio_Object srcobj, audio_SourceProp pname, + float *value) +{ + audiodrv.Sourcefv (srcobj, audiodrv.EnumLookup[pname], value); +} + +void +audio_GetSourcei (audio_Object srcobj, audio_SourceProp pname, + audio_IntVal *value) +{ + audiodrv.GetSourcei (srcobj, audiodrv.EnumLookup[pname], value); +} + +void +audio_GetSourcef (audio_Object srcobj, audio_SourceProp pname, + float *value) +{ + audiodrv.GetSourcef (srcobj, audiodrv.EnumLookup[pname], value); +} + +void +audio_SourceRewind (audio_Object srcobj) +{ + audiodrv.SourceRewind (srcobj); +} + +void +audio_SourcePlay (audio_Object srcobj) +{ + audiodrv.SourcePlay (srcobj); +} + +void +audio_SourcePause (audio_Object srcobj) +{ + audiodrv.SourcePause (srcobj); +} + +void +audio_SourceStop (audio_Object srcobj) +{ + audiodrv.SourceStop (srcobj); +} + +void +audio_SourceQueueBuffers (audio_Object srcobj, uint32 n, + audio_Object* pbufobj) +{ + audiodrv.SourceQueueBuffers (srcobj, n, pbufobj); +} + +void +audio_SourceUnqueueBuffers (audio_Object srcobj, uint32 n, + audio_Object* pbufobj) +{ + audiodrv.SourceUnqueueBuffers (srcobj, n, pbufobj); +} + + +/* + * Buffers + */ + +void +audio_GenBuffers (uint32 n, audio_Object *pbufobj) +{ + audiodrv.GenBuffers (n, pbufobj); +} + +void +audio_DeleteBuffers (uint32 n, audio_Object *pbufobj) +{ + audiodrv.DeleteBuffers (n, pbufobj); +} + +bool +audio_IsBuffer (audio_Object bufobj) +{ + return audiodrv.IsBuffer (bufobj); +} + +void +audio_GetBufferi (audio_Object bufobj, audio_BufferProp pname, + audio_IntVal *value) +{ + audiodrv.GetBufferi (bufobj, audiodrv.EnumLookup[pname], value); +} + +void +audio_BufferData (audio_Object bufobj, uint32 format, void* data, + uint32 size, uint32 freq) +{ + audiodrv.BufferData (bufobj, audiodrv.EnumLookup[format], data, size, + freq); +} diff --git a/sc2/src/sc2code/libs/sound/audiocore.h b/sc2/src/sc2code/libs/sound/audiocore.h new file mode 100644 index 000000000..82e826d8b --- /dev/null +++ b/sc2/src/sc2code/libs/sound/audiocore.h @@ -0,0 +1,166 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Audio Core API (derived from OpenAL) + */ + +#ifndef _AUDIOCORE_H +#define _AUDIOCORE_H + +#include "config.h" +#include "types.h" + + +/* Available drivers */ +enum +{ + audio_DRIVER_MIXSDL, + audio_DRIVER_NOSOUND, + audio_DRIVER_OPENAL +}; + +/* Initialization flags */ +#define audio_QUALITY_HIGH (1 << 0) +#define audio_QUALITY_MEDIUM (1 << 1) +#define audio_QUALITY_LOW (1 << 2) + + +/* Interface Types */ +typedef intptr_t audio_Object; +typedef intptr_t audio_IntVal; +typedef const sint32 audio_SourceProp; +typedef const sint32 audio_BufferProp; + +enum +{ + /* Errors */ + audio_NO_ERROR = 0, + audio_INVALID_NAME, + audio_INVALID_ENUM, + audio_INVALID_VALUE, + audio_INVALID_OPERATION, + audio_OUT_OF_MEMORY, + audio_DRIVER_FAILURE, + + /* Source properties */ + audio_POSITION, + audio_LOOPING, + audio_BUFFER, + audio_GAIN, + audio_SOURCE_STATE, + audio_BUFFERS_QUEUED, + audio_BUFFERS_PROCESSED, + + /* Source state information */ + audio_INITIAL, + audio_STOPPED, + audio_PLAYING, + audio_PAUSED, + + /* Sound buffer properties */ + audio_FREQUENCY, + audio_BITS, + audio_CHANNELS, + audio_SIZE, + audio_DATA, + audio_FORMAT_MONO16, + audio_FORMAT_STEREO16, + audio_FORMAT_MONO8, + audio_FORMAT_STEREO8, + audio_ENUM_SIZE +}; + +typedef struct { + /* General */ + void (* Uninitialize) (void); + sint32 (* GetError) (void); + sint32 driverID; + sint32 EnumLookup[audio_ENUM_SIZE]; + + /* Sources */ + void (* GenSources) (uint32 n, audio_Object *psrcobj); + void (* DeleteSources) (uint32 n, audio_Object *psrcobj); + bool (* IsSource) (audio_Object srcobj); + void (* Sourcei) (audio_Object srcobj, audio_SourceProp pname, + audio_IntVal value); + void (* Sourcef) (audio_Object srcobj, audio_SourceProp pname, + float value); + void (* Sourcefv) (audio_Object srcobj, audio_SourceProp pname, + float *value); + void (* GetSourcei) (audio_Object srcobj, audio_SourceProp pname, + audio_IntVal *value); + void (* GetSourcef) (audio_Object srcobj, audio_SourceProp pname, + float *value); + void (* SourceRewind) (audio_Object srcobj); + void (* SourcePlay) (audio_Object srcobj); + void (* SourcePause) (audio_Object srcobj); + void (* SourceStop) (audio_Object srcobj); + void (* SourceQueueBuffers) (audio_Object srcobj, uint32 n, + audio_Object* pbufobj); + void (* SourceUnqueueBuffers) (audio_Object srcobj, uint32 n, + audio_Object* pbufobj); + + /* Buffers */ + void (* GenBuffers) (uint32 n, audio_Object *pbufobj); + void (* DeleteBuffers) (uint32 n, audio_Object *pbufobj); + bool (* IsBuffer) (audio_Object bufobj); + void (* GetBufferi) (audio_Object bufobj, audio_BufferProp pname, + audio_IntVal *value); + void (* BufferData) (audio_Object bufobj, uint32 format, void* data, + uint32 size, uint32 freq); +} audio_Driver; + + +/* Initialization */ +sint32 initAudio (sint32 driver, sint32 flags); +void unInitAudio (void); + +/* General */ +sint32 audio_GetError (void); + +/* Sources */ +void audio_GenSources (uint32 n, audio_Object *psrcobj); +void audio_DeleteSources (uint32 n, audio_Object *psrcobj); +bool audio_IsSource (audio_Object srcobj); +void audio_Sourcei (audio_Object srcobj, audio_SourceProp pname, + audio_IntVal value); +void audio_Sourcef (audio_Object srcobj, audio_SourceProp pname, + float value); +void audio_Sourcefv (audio_Object srcobj, audio_SourceProp pname, + float *value); +void audio_GetSourcei (audio_Object srcobj, audio_SourceProp pname, + audio_IntVal *value); +void audio_GetSourcef (audio_Object srcobj, audio_SourceProp pname, + float *value); +void audio_SourceRewind (audio_Object srcobj); +void audio_SourcePlay (audio_Object srcobj); +void audio_SourcePause (audio_Object srcobj); +void audio_SourceStop (audio_Object srcobj); +void audio_SourceQueueBuffers (audio_Object srcobj, uint32 n, + audio_Object* pbufobj); +void audio_SourceUnqueueBuffers (audio_Object srcobj, uint32 n, + audio_Object* pbufobj); + +/* Buffers */ +void audio_GenBuffers (uint32 n, audio_Object *pbufobj); +void audio_DeleteBuffers (uint32 n, audio_Object *pbufobj); +bool audio_IsBuffer (audio_Object bufobj); +void audio_GetBufferi (audio_Object bufobj, audio_BufferProp pname, + audio_IntVal *value); +void audio_BufferData (audio_Object bufobj, uint32 format, void* data, + uint32 size, uint32 freq); + +#endif /* _AUDIOCORE_H */ diff --git a/sc2/src/sc2code/libs/sound/decoders/modaud.c b/sc2/src/sc2code/libs/sound/decoders/modaud.c index 1ef7a3a4b..a4f9f6651 100644 --- a/sc2/src/sc2code/libs/sound/decoders/modaud.c +++ b/sc2/src/sc2code/libs/sound/decoders/modaud.c @@ -27,7 +27,7 @@ #include "uio.h" #include "decoder.h" #include "mikmod/mikmod.h" -#include "libs/sound/sound_common.h" +#include "libs/sound/audiocore.h" #include "modaud.h" #define THIS_PTR TFB_SoundDecoder* This @@ -87,7 +87,7 @@ moda_InitModule (int flags, const TFB_DecoderFormats* fmts) MikMod_RegisterDriver (&drv_openal); MikMod_RegisterAllLoaders (); - if (flags & TFB_SOUNDFLAGS_HQAUDIO) + if (flags & audio_QUALITY_HIGH) { #ifndef WORDS_BIGENDIAN md_mode = DMODE_HQMIXER|DMODE_STEREO|DMODE_16BITS|DMODE_INTERP|DMODE_SURROUND; @@ -98,7 +98,7 @@ moda_InitModule (int flags, const TFB_DecoderFormats* fmts) md_mixfreq = 44100; md_reverb = 1; } - else if (flags & TFB_SOUNDFLAGS_LQAUDIO) + else if (flags & audio_QUALITY_LOW) { md_mode = DMODE_SOFT_MUSIC|DMODE_STEREO|DMODE_16BITS; md_mixfreq = 22050; diff --git a/sc2/src/sc2code/libs/sound/mixer/Makeinfo b/sc2/src/sc2code/libs/sound/mixer/Makeinfo new file mode 100644 index 000000000..8f06188f7 --- /dev/null +++ b/sc2/src/sc2code/libs/sound/mixer/Makeinfo @@ -0,0 +1,2 @@ +uqm_SUBDIRS="sdl nosound" +uqm_CFILES="mixer.c" diff --git a/sc2/src/sc2code/libs/sound/mixer/mixer.c b/sc2/src/sc2code/libs/sound/mixer/mixer.c new file mode 100644 index 000000000..4faa7bcb0 --- /dev/null +++ b/sc2/src/sc2code/libs/sound/mixer/mixer.c @@ -0,0 +1,1848 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Mixer for low-level sound output drivers + */ + +#include +#include +#include +#include "mixer.h" +#include "mixerint.h" +#include "libs/misc.h" +#include "libs/threadlib.h" + +#define DEBUG + +static uint32 mixer_initialized = 0; +static uint32 mixer_format; +static uint32 mixer_chansize; +static uint32 mixer_sampsize; +static uint32 mixer_freq; +static uint32 mixer_channels; +static uint32 last_error = MIX_NO_ERROR; +static mixer_Quality mixer_quality; +static mixer_Resampling mixer_resampling; +static mixer_Flags mixer_flags; + +/* when locking more than one mutex + * you must lock them in this order + */ +static RecursiveMutex src_mutex; +static RecursiveMutex buf_mutex; +static RecursiveMutex act_mutex; + +#define MAX_SOURCES 8 +mixer_Source *active_sources[MAX_SOURCES]; + + +/************************************************* + * Internals + */ + +static void +mixer_SetError (uint32 error) +{ + last_error = error; +} + + +/************************************************* + * General interface + */ + +uint32 +mixer_GetError (void) +{ + uint32 error = last_error; + last_error = MIX_NO_ERROR; + return error; +} + +/* Initialize the mixer with a certain audio format */ +bool +mixer_Init (uint32 frequency, uint32 format, mixer_Quality quality, + mixer_Flags flags) +{ + if (mixer_initialized) + mixer_Uninit (); + + last_error = MIX_NO_ERROR; + memset (active_sources, 0, sizeof(mixer_Source*) * MAX_SOURCES); + + mixer_chansize = MIX_FORMAT_BPC (format); + mixer_channels = MIX_FORMAT_CHANS (format); + mixer_sampsize = MIX_FORMAT_SAMPSIZE (format); + mixer_freq = frequency; + mixer_quality = quality; + mixer_format = format; + mixer_flags = flags; + + mixer_resampling.None = mixer_ResampleNone; + mixer_resampling.Downsample = mixer_ResampleNearest; + if (mixer_quality == MIX_QUALITY_DEFAULT) + mixer_resampling.Upsample = mixer_UpsampleLinear; + else if (mixer_quality == MIX_QUALITY_HIGH) + mixer_resampling.Upsample = mixer_UpsampleCubic; + else + mixer_resampling.Upsample = mixer_ResampleNearest; + + src_mutex = CreateRecursiveMutex("mixer_SourceMutex", SYNC_CLASS_AUDIO); + buf_mutex = CreateRecursiveMutex("mixer_BufferMutex", SYNC_CLASS_AUDIO); + act_mutex = CreateRecursiveMutex("mixer_ActiveMutex", SYNC_CLASS_AUDIO); + + mixer_initialized = 1; + + return true; +} + +/* Uninitialize the mixer */ +void +mixer_Uninit (void) +{ + if (mixer_initialized) + { + DestroyRecursiveMutex (src_mutex); + DestroyRecursiveMutex (buf_mutex); + DestroyRecursiveMutex (act_mutex); + mixer_initialized = 0; + } +} + + +/********************************************************** + * THE mixer + * + */ + +void +mixer_MixChannels (void *userdata, uint8 *stream, sint32 len) +{ + uint8 *end_stream = stream + len; + bool left = true; + + /* keep this order or die */ + LockRecursiveMutex (src_mutex); + LockRecursiveMutex (buf_mutex); + LockRecursiveMutex (act_mutex); + + for (; stream < end_stream; stream += mixer_chansize) + { + uint32 i; + float fullsamp = 0; + + for (i = 0; i < MAX_SOURCES; i++) + { + mixer_Source *src; + float samp; + + /* find next source */ + for (; i < MAX_SOURCES && ( + (src = active_sources[i]) == 0 + || src->state != MIX_PLAYING + || !mixer_SourceGetNextSample (src, &samp, left)); + i++) + ; + + if (i < MAX_SOURCES) + { + /* sample acquired */ + fullsamp += samp; + } + } + + /* clip the sample */ + if (mixer_chansize == 2) + { + /* check S16 clipping */ + if (fullsamp > SINT16_MAX) + fullsamp = SINT16_MAX; + else if (fullsamp < SINT16_MIN) + fullsamp = SINT16_MIN; + } + else + { + /* check S8 clipping */ + if (fullsamp > SINT8_MAX) + fullsamp = SINT8_MAX; + else if (fullsamp < SINT8_MIN) + fullsamp = SINT8_MIN; + } + + mixer_PutSampleExt (stream, mixer_chansize, (sint32)fullsamp); + if (mixer_channels == 2) + left = !left; + } + + /* keep this order or die */ + UnlockRecursiveMutex (act_mutex); + UnlockRecursiveMutex (buf_mutex); + UnlockRecursiveMutex (src_mutex); + + (void) userdata; // satisfying compiler - unused arg +} + +/* fake mixer -- only process buffer and source states */ +void +mixer_MixFake (void *userdata, uint8 *stream, sint32 len) +{ + uint8 *end_stream = stream + len; + bool left = true; + + /* keep this order or die */ + LockRecursiveMutex (src_mutex); + LockRecursiveMutex (buf_mutex); + LockRecursiveMutex (act_mutex); + + for (; stream < end_stream; stream += mixer_chansize) + { + uint32 i; + + for (i = 0; i < MAX_SOURCES; i++) + { + mixer_Source *src; + float samp; + + /* find next source */ + for (; i < MAX_SOURCES && ( + (src = active_sources[i]) == 0 + || src->state != MIX_PLAYING + || !mixer_SourceGetFakeSample (src, &samp, left)); + i++) + ; + } + if (mixer_channels == 2) + left = !left; + } + + /* keep this order or die */ + UnlockRecursiveMutex (act_mutex); + UnlockRecursiveMutex (buf_mutex); + UnlockRecursiveMutex (src_mutex); + + (void) userdata; // satisfying compiler - unused arg +} + + +/************************************************* + * Sources interface + */ + +/* generate n sources */ +void +mixer_GenSources (uint32 n, mixer_Object *psrcobj) +{ + if (n == 0) + return; /* do nothing per OpenAL */ + + if (!psrcobj) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_GenSources() called with null ptr\n"); +#endif + return; + } + for (; n; n--, psrcobj++) + { + mixer_Source *src; + + src = (mixer_Source *) HMalloc (sizeof (mixer_Source)); + src->magic = mixer_srcMagic; + src->locked = false; + src->state = MIX_INITIAL; + src->looping = false; + src->gain = MIX_GAIN_ADJ; + src->cqueued = 0; + src->cprocessed = 0; + src->firstqueued = 0; + src->nextqueued = 0; + src->prevqueued = 0; + src->lastqueued = 0; + src->pos = 0; + src->count = 0; + + *psrcobj = (mixer_Object) src; + } +} + +/* delete n sources */ +void +mixer_DeleteSources (uint32 n, mixer_Object *psrcobj) +{ + uint32 i; + mixer_Object *pcurobj; + + if (n == 0) + return; /* do nothing per OpenAL */ + + if (!psrcobj) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_DeleteSources() called with null ptr\n"); +#endif + return; + } + + LockRecursiveMutex (src_mutex); + + /* check to make sure we can delete all sources */ + for (i = n, pcurobj = psrcobj; i && pcurobj; i--, pcurobj++) + { + mixer_Source *src = (mixer_Source *) *pcurobj; + + if (!src) + continue; + + if (src->magic != mixer_srcMagic) + break; + } + + if (i) + { /* some source failed */ + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_DeleteSources(): not a source\n"); +#endif + } + else + { /* all sources checked out */ + for (; n; n--, psrcobj++) + { + mixer_Source *src = (mixer_Source *) *psrcobj; + + if (!src) + continue; + + /* stopping should not be necessary + * under ideal circumstances + */ + if (src->state != MIX_INITIAL) + mixer_SourceStop_internal (src); + + /* unqueueing should not be necessary + * under ideal circumstances + */ + mixer_SourceUnqueueAll (src); + HFree (src); + *psrcobj = 0; + } + } + + UnlockRecursiveMutex (src_mutex); +} + +/* check if really is a source */ +bool +mixer_IsSource (mixer_Object srcobj) +{ + mixer_Source *src = (mixer_Source *) srcobj; + bool ret; + + if (!src) + return false; + + LockRecursiveMutex (src_mutex); + ret = src->magic == mixer_srcMagic; + UnlockRecursiveMutex (src_mutex); + + return ret; +} + +/* set source integer property */ +void +mixer_Sourcei (mixer_Object srcobj, mixer_SourceProp pname, + mixer_IntVal value) +{ + mixer_Source *src = (mixer_Source *) srcobj; + + if (!src) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_Sourcei() called with null source\n"); +#endif + return; + } + + LockRecursiveMutex (src_mutex); + + if (src->magic != mixer_srcMagic) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_Sourcei(): not a source\n"); +#endif + } + else + { + switch (pname) + { + case MIX_LOOPING: + src->looping = value; + break; + case MIX_BUFFER: + { + mixer_Buffer *buf = (mixer_Buffer *) value; + + if (src->cqueued > 0) + mixer_SourceUnqueueAll (src); + + if (buf && !mixer_CheckBufferState (buf, "mixer_Sourcei")) + break; + + src->firstqueued = buf; + src->nextqueued = src->firstqueued; + src->prevqueued = 0; + src->lastqueued = src->nextqueued; + if (src->lastqueued) + src->lastqueued->next = 0; + src->cqueued = 1; + } + break; + case MIX_SOURCE_STATE: + if (value == MIX_INITIAL) + { + mixer_SourceRewind_internal (src); + } + else + { + fprintf (stderr, "mixer_Sourcei(MIX_SOURCE_STATE): " + "unsupported state, call ignored\n"); + } + break; + default: + mixer_SetError (MIX_INVALID_ENUM); + fprintf (stderr, "mixer_Sourcei() called " + "with unsupported property %u\n", pname); + } + } + + UnlockRecursiveMutex (src_mutex); +} + +/* set source float property */ +void +mixer_Sourcef (mixer_Object srcobj, mixer_SourceProp pname, float value) +{ + mixer_Source *src = (mixer_Source *) srcobj; + + if (!src) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_Sourcef() called with null source\n"); +#endif + return; + } + + LockRecursiveMutex (src_mutex); + + if (src->magic != mixer_srcMagic) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_Sourcef(): not a source\n"); +#endif + } + else + { + switch (pname) + { + case MIX_GAIN: + src->gain = value * MIX_GAIN_ADJ; + break; + default: + fprintf (stderr, "mixer_Sourcei() called " + "with unsupported property %u\n", pname); + } + } + + UnlockRecursiveMutex (src_mutex); +} + +/* set source float array property (CURRENTLY NOT IMPLEMENTED) */ +void mixer_Sourcefv (mixer_Object srcobj, mixer_SourceProp pname, float *value) +{ + (void)srcobj; + (void)pname; + (void)value; +} + + +/* get source integer property */ +void +mixer_GetSourcei (mixer_Object srcobj, mixer_SourceProp pname, + mixer_IntVal *value) +{ + mixer_Source *src = (mixer_Source *) srcobj; + + if (!src || !value) + { + mixer_SetError (src ? MIX_INVALID_VALUE : MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_GetSourcei() called with null param\n"); +#endif + return; + } + + LockRecursiveMutex (src_mutex); + + if (src->magic != mixer_srcMagic) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_GetSourcei(): not a source\n"); +#endif + } + else + { + switch (pname) + { + case MIX_LOOPING: + *value = src->looping; + break; + case MIX_BUFFER: + *value = (mixer_IntVal) src->firstqueued; + break; + case MIX_SOURCE_STATE: + *value = src->state; + break; + case MIX_BUFFERS_QUEUED: + *value = src->cqueued; + break; + case MIX_BUFFERS_PROCESSED: + *value = src->cprocessed; + break; + default: + mixer_SetError (MIX_INVALID_ENUM); + fprintf (stderr, "mixer_GetSourcei() called " + "with unsupported property %u\n", pname); + } + } + + UnlockRecursiveMutex (src_mutex); +} + +/* get source float property */ +void +mixer_GetSourcef (mixer_Object srcobj, mixer_SourceProp pname, + float *value) +{ + mixer_Source *src = (mixer_Source *) srcobj; + + if (!src || !value) + { + mixer_SetError (src ? MIX_INVALID_VALUE : MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_GetSourcef() called with null param\n"); +#endif + return; + } + + LockRecursiveMutex (src_mutex); + + if (src->magic != mixer_srcMagic) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_GetSourcef(): not a source\n"); +#endif + } + else + { + switch (pname) + { + case MIX_GAIN: + *value = src->gain / MIX_GAIN_ADJ; + break; + default: + fprintf (stderr, "mixer_GetSourcef() called " + "with unsupported property %u\n", pname); + } + } + + UnlockRecursiveMutex (src_mutex); +} + +/* start the source; add it to active array */ +void +mixer_SourcePlay (mixer_Object srcobj) +{ + mixer_Source *src = (mixer_Source *) srcobj; + + if (!src) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_SourcePlay() called with null source\n"); +#endif + return; + } + + LockRecursiveMutex (src_mutex); + + if (src->magic != mixer_srcMagic) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_SourcePlay(): not a source\n"); +#endif + } + else /* should make the source active */ + { + if (src->state < MIX_PLAYING) + { + if (src->firstqueued && !src->nextqueued) + mixer_SourceRewind_internal (src); + mixer_SourceActivate (src); + } + src->state = MIX_PLAYING; + } + + UnlockRecursiveMutex (src_mutex); +} + +/* stop the source; remove it from active array and requeue buffers */ +void +mixer_SourceRewind (mixer_Object srcobj) +{ + mixer_Source *src = (mixer_Source *) srcobj; + + if (!src) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_SourceRewind() called with null source\n"); +#endif + return; + } + + LockRecursiveMutex (src_mutex); + + if (src->magic != mixer_srcMagic) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_SourcePlay(): not a source\n"); +#endif + } + else + { + mixer_SourceRewind_internal (src); + } + + UnlockRecursiveMutex (src_mutex); +} + +/* pause the source; keep in active array */ +void +mixer_SourcePause (mixer_Object srcobj) +{ + mixer_Source *src = (mixer_Source *) srcobj; + + if (!src) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_SourcePause() called with null source\n"); +#endif + return; + } + + LockRecursiveMutex (src_mutex); + + if (src->magic != mixer_srcMagic) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_SourcePause(): not a source\n"); +#endif + } + else /* should keep all buffers and offsets */ + { + if (src->state < MIX_PLAYING) + mixer_SourceActivate (src); + src->state = MIX_PAUSED; + } + + UnlockRecursiveMutex (src_mutex); +} + +/* stop the source; remove it from active array + * and unqueue 'queued' buffers + */ +void +mixer_SourceStop (mixer_Object srcobj) +{ + mixer_Source *src = (mixer_Source *) srcobj; + + if (!src) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_SourceStop() called with null source\n"); +#endif + return; + } + + LockRecursiveMutex (src_mutex); + + if (src->magic != mixer_srcMagic) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_SourceStop(): not a source\n"); +#endif + } + else /* should remove queued buffers */ + { + if (src->state >= MIX_PLAYING) + mixer_SourceDeactivate (src); + mixer_SourceStop_internal (src); + src->state = MIX_STOPPED; + } + + UnlockRecursiveMutex (src_mutex); +} + +/* queue buffers on the source */ +void +mixer_SourceQueueBuffers (mixer_Object srcobj, uint32 n, + mixer_Object* pbufobj) +{ + uint32 i; + mixer_Object* pobj; + mixer_Source *src = (mixer_Source *) srcobj; + + if (!src || !pbufobj) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_SourceQueueBuffers() called " + "with null param\n"); +#endif + return; + } + + LockRecursiveMutex (buf_mutex); + /* check to make sure we can safely queue all buffers */ + for (i = n, pobj = pbufobj; i; i--, pobj++) + { + mixer_Buffer *buf = (mixer_Buffer *) *pobj; + if (!buf || !mixer_CheckBufferState (buf, + "mixer_SourceQueueBuffers")) + { + break; + } + } + UnlockRecursiveMutex (buf_mutex); + + if (i == 0) + { /* all buffers checked out */ + LockRecursiveMutex (src_mutex); + LockRecursiveMutex (buf_mutex); + + if (src->magic != mixer_srcMagic) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_SourceQueueBuffers(): not a source\n"); +#endif + } + else + { + for (i = n, pobj = pbufobj; i; i--, pobj++) + { + mixer_Buffer *buf = (mixer_Buffer *) *pobj; + + /* add buffer to the chain */ + if (src->lastqueued) + src->lastqueued->next = buf; + src->lastqueued = buf; + + if (!src->firstqueued) + { + src->firstqueued = buf; + src->nextqueued = buf; + src->prevqueued = 0; + } + src->cqueued++; + buf->state = MIX_BUF_QUEUED; + } + } + + UnlockRecursiveMutex (buf_mutex); + UnlockRecursiveMutex (src_mutex); + } +} + +/* unqueue buffers from the source */ +void +mixer_SourceUnqueueBuffers (mixer_Object srcobj, uint32 n, + mixer_Object* pbufobj) +{ + uint32 i; + mixer_Source *src = (mixer_Source *) srcobj; + mixer_Buffer *curbuf = 0; + + if (!src || !pbufobj) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_SourceUnqueueBuffers() called " + "with null source\n"); +#endif + return; + } + + LockRecursiveMutex (src_mutex); + + if (src->magic != mixer_srcMagic) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_SourceUnqueueBuffers(): not a source\n"); +#endif + } + else if (n > src->cqueued) + { + mixer_SetError (MIX_INVALID_OPERATION); + } + else + { + LockRecursiveMutex (buf_mutex); + + /* check to make sure we can unqueue all buffers */ + for (i = n, curbuf = src->firstqueued; + i && curbuf && curbuf->state != MIX_BUF_PLAYING; + i--, curbuf = curbuf->next) + ; + + if (i) + { + mixer_SetError (MIX_INVALID_OPERATION); +#ifdef DEBUG + fprintf (stderr, "mixer_SourceUnqueueBuffers(): " + "active buffer attempted\n"); +#endif + } + else + { /* all buffers checked out */ + for (i = n; i; i--, pbufobj++) + { + mixer_Buffer *buf = src->firstqueued; + + /* remove buffer from the chain */ + if (src->nextqueued == buf) + src->nextqueued = buf->next; + if (src->prevqueued == buf) + src->prevqueued = 0; + if (src->lastqueued == buf) + src->lastqueued = 0; + src->firstqueued = buf->next; + src->cqueued--; + + if (buf->state == MIX_BUF_PROCESSED) + src->cprocessed--; + + buf->state = MIX_BUF_FILLED; + buf->next = 0; + *pbufobj = (mixer_Object) buf; + } + } + + UnlockRecursiveMutex (buf_mutex); + } + + UnlockRecursiveMutex (src_mutex); +} + +/************************************************* + * Sources internals + */ + +static void +mixer_SourceUnqueueAll (mixer_Source *src) +{ + mixer_Buffer *buf; + mixer_Buffer *nextbuf; + + if (!src) + { +#ifdef DEBUG + fprintf (stderr, "mixer_SourceUnqueueAll() called " + "with null source\n"); +#endif + return; + } + + LockRecursiveMutex (buf_mutex); + + for (buf = src->firstqueued; buf; buf = nextbuf) + { +#ifdef DEBUG + if (buf->state == MIX_BUF_PLAYING) + { + fprintf (stderr, "mixer_SourceUnqueueAll(): " + "attempted on active buffer\n"); + } +#endif + nextbuf = buf->next; + buf->state = MIX_BUF_FILLED; + buf->next = 0; + } + + UnlockRecursiveMutex (buf_mutex); + + src->firstqueued = 0; + src->nextqueued = 0; + src->prevqueued = 0; + src->lastqueued = 0; + src->cqueued = 0; + src->cprocessed = 0; + src->pos = 0; + src->count = 0; +} + +/* add the source to the active array */ +static void +mixer_SourceActivate (mixer_Source* src) +{ + uint32 i; + + LockRecursiveMutex (act_mutex); + +#ifdef DEBUG + /* check active sources, see if this source is there already */ + for (i = 0; i < MAX_SOURCES && active_sources[i] != src; i++) + ; + if (i < MAX_SOURCES) + { /* source found */ + fprintf (stderr, "mixer_SourceActivate(): " + "source already active in slot %u\n", i); + UnlockRecursiveMutex (act_mutex); + return; + } +#endif + + /* find an empty slot */ + for (i = 0; i < MAX_SOURCES && active_sources[i] != 0; i++) + ; + if (i < MAX_SOURCES) + { /* slot found */ + active_sources[i] = src; + } +#ifdef DEBUG + else + { + fprintf (stderr, "mixer_SourceActivate(): " + "no more slots available (max=%d)\n", MAX_SOURCES); + } +#endif + + UnlockRecursiveMutex (act_mutex); +} + +/* remove the source from the active array */ +static void +mixer_SourceDeactivate (mixer_Source* src) +{ + uint32 i; + + LockRecursiveMutex (act_mutex); + + /* check active sources, see if this source is there */ + for (i = 0; i < MAX_SOURCES && active_sources[i] != src; i++) + ; + if (i < MAX_SOURCES) + { /* source found */ + active_sources[i] = 0; + } +#ifdef DEBUG + else + { /* source not found */ + fprintf (stderr, "mixer_SourceDeactivate(): source not active\n"); + } +#endif + + UnlockRecursiveMutex (act_mutex); +} + +static void +mixer_SourceStop_internal (mixer_Source *src) +{ + mixer_Buffer *buf; + mixer_Buffer *nextbuf; + + if (!src->firstqueued) + return; + +#ifdef DEBUG + /* assert the source buffers state */ + if (!src->lastqueued) + { + fprintf (stderr, "mixer_SourceStop_internal(): " + "desynced source state\n"); + return; + } +#endif + + LockRecursiveMutex (buf_mutex); + + /* find last 'processed' buffer */ + for (buf = src->firstqueued; + buf && buf->next && buf->next != src->nextqueued; + buf = buf->next) + ; + src->lastqueued = buf; + if (buf) + buf->next = 0; /* break the chain */ + + /* unqueue all 'queued' buffers */ + for (buf = src->nextqueued; buf; buf = nextbuf) + { + nextbuf = buf->next; + buf->state = MIX_BUF_FILLED; + buf->next = 0; + src->cqueued--; + } + + if (src->cqueued == 0) + { /* all buffers were removed */ + src->firstqueued = 0; + src->lastqueued = 0; + } + src->nextqueued = 0; + src->prevqueued = 0; + src->pos = 0; + src->count = 0; + + UnlockRecursiveMutex (buf_mutex); +} + +static void +mixer_SourceRewind_internal (mixer_Source *src) +{ + /* should change the processed buffers to queued */ + mixer_Buffer *buf; + + if (src->state >= MIX_PLAYING) + mixer_SourceDeactivate (src); + + LockRecursiveMutex (buf_mutex); + + for (buf = src->firstqueued; + buf && buf->state != MIX_BUF_QUEUED; + buf = buf->next) + { + buf->state = MIX_BUF_QUEUED; + } + + UnlockRecursiveMutex (buf_mutex); + + src->pos = 0; + src->count = 0; + src->cprocessed = 0; + src->nextqueued = src->firstqueued; + src->prevqueued = 0; + src->state = MIX_INITIAL; +} + +/* get the sample next in queue in internal format */ +static __inline__ bool +mixer_SourceGetNextSample (mixer_Source *src, float *psamp, bool left) +{ + /* fake the data if requested */ + if (mixer_flags & MIX_FAKE_DATA) + return mixer_SourceGetFakeSample (src, psamp, left); + + while (src->nextqueued) + { + mixer_Buffer *buf = src->nextqueued; + + if (!buf->data || buf->size < mixer_sampsize) + { + /* buffer invalid, go next */ + buf->state = MIX_BUF_PROCESSED; + src->pos = 0; + src->nextqueued = src->nextqueued->next; + src->cprocessed++; + continue; + } + + if (!left && buf->orgchannels == 1) + { + /* mono source so we can copy left channel to right */ + *psamp = src->samplecache; + } + else + { + *psamp = src->samplecache = buf->Resample(src, left) * src->gain; + } + + if (src->pos < buf->size || + (left && buf->sampsize != mixer_sampsize)) + { + buf->state = MIX_BUF_PLAYING; + } + else + { + /* buffer exhausted, go next */ + buf->state = MIX_BUF_PROCESSED; + src->pos = 0; + src->prevqueued = src->nextqueued; + src->nextqueued = src->nextqueued->next; + src->cprocessed++; + } + + return true; + } + + /* no more playable buffers */ + if (src->state >= MIX_PLAYING) + mixer_SourceDeactivate (src); + + src->state = MIX_STOPPED; + + return false; +} + +/* fake the next sample, but process buffers and states */ +static __inline__ bool +mixer_SourceGetFakeSample (mixer_Source *src, float *psamp, bool left) +{ + while (src->nextqueued) + { + mixer_Buffer *buf = src->nextqueued; + + if (left || buf->orgchannels != 1) + { + if (mixer_freq == buf->orgfreq) + src->pos += mixer_chansize; + else + mixer_SourceAdvance(src, left); + } + *psamp = 0; + + if (src->pos < buf->size || + (left && buf->sampsize != mixer_sampsize)) + { + buf->state = MIX_BUF_PLAYING; + } + else + { + /* buffer exhausted, go next */ + buf->state = MIX_BUF_PROCESSED; + src->pos = 0; + src->prevqueued = src->nextqueued; + src->nextqueued = src->nextqueued->next; + src->cprocessed++; + } + + return true; + } + + /* no more playable buffers */ + if (src->state >= MIX_PLAYING) + mixer_SourceDeactivate (src); + + src->state = MIX_STOPPED; + + return false; +} + +/* advance position in currently queued buffer */ +static __inline__ bool +mixer_SourceAdvance (mixer_Source *src, bool left) +{ + mixer_Buffer *curr = src->nextqueued; + if (curr->orgchannels == 2 && mixer_channels == 2) + { + if (!left) + { + src->pos += curr->high; + src->count += curr->low; + if (src->count > UINT16_MAX) + { + src->count -= UINT16_MAX; + src->pos += curr->sampsize; + } + return mixer_chansize; + } + } + else + { + src->pos += curr->high; + src->count += curr->low; + if (src->count > UINT16_MAX) + { + src->count -= UINT16_MAX; + src->pos += curr->sampsize; + } + } + return 0; +} + + +/************************************************* + * Buffers interface + */ + +/* generate n buffer objects */ +void +mixer_GenBuffers (uint32 n, mixer_Object *pbufobj) +{ + if (n == 0) + return; /* do nothing per OpenAL */ + + if (!pbufobj) + { + mixer_SetError (MIX_INVALID_VALUE); +#ifdef DEBUG + fprintf (stderr, "mixer_GenBuffers() called with null ptr\n"); +#endif + return; + } + for (; n; n--, pbufobj++) + { + mixer_Buffer *buf; + + buf = (mixer_Buffer *) HMalloc (sizeof (mixer_Buffer)); + buf->magic = mixer_bufMagic; + buf->locked = false; + buf->state = MIX_BUF_INITIAL; + buf->data = 0; + buf->size = 0; + buf->next = 0; + buf->orgdata = 0; + buf->orgfreq = 0; + buf->orgsize = 0; + buf->orgchannels = 0; + buf->orgchansize = 0; + + *pbufobj = (mixer_Object) buf; + } +} + +/* delete n buffer objects */ +void +mixer_DeleteBuffers (uint32 n, mixer_Object *pbufobj) +{ + uint32 i; + mixer_Object *pcurobj; + + if (n == 0) + return; /* do nothing per OpenAL */ + + if (!pbufobj) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_DeleteBuffers() called with null ptr\n"); +#endif + return; + } + + LockRecursiveMutex (buf_mutex); + + /* check to make sure we can delete all buffers */ + for (i = n, pcurobj = pbufobj; i && pcurobj; i--, pcurobj++) + { + mixer_Buffer *buf = (mixer_Buffer *) *pcurobj; + + if (!buf) + continue; + + if (buf->magic != mixer_bufMagic) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_DeleteBuffers(): not a buffer\n"); +#endif + break; + } + else if (buf->locked) + { + mixer_SetError (MIX_INVALID_OPERATION); +#ifdef DEBUG + fprintf (stderr, "mixer_DeleteBuffers(): locked buffer\n"); +#endif + break; + } + else if (buf->state >= MIX_BUF_QUEUED) + { + mixer_SetError (MIX_INVALID_OPERATION); +#ifdef DEBUG + fprintf (stderr, "mixer_DeleteBuffers(): " + "attempted on queued/active buffer\n"); +#endif + break; + } + } + + if (i == 0) + { + /* all buffers check out */ + for (; n; n--, pbufobj++) + { + mixer_Buffer *buf = (mixer_Buffer *) *pbufobj; + + if (!buf) + continue; + + if (buf->data) + HFree (buf->data); + HFree (buf); + + *pbufobj = 0; + } + } + UnlockRecursiveMutex (buf_mutex); +} + +/* check if really a buffer object */ +bool +mixer_IsBuffer (mixer_Object bufobj) +{ + mixer_Buffer *buf = (mixer_Buffer *) bufobj; + bool ret; + + if (!buf) + return false; + + LockRecursiveMutex (buf_mutex); + ret = buf->magic == mixer_bufMagic; + UnlockRecursiveMutex (buf_mutex); + + return ret; +} + +/* get buffer property */ +void +mixer_GetBufferi (mixer_Object bufobj, mixer_BufferProp pname, + mixer_IntVal *value) +{ + mixer_Buffer *buf = (mixer_Buffer *) bufobj; + + if (!buf || !value) + { + mixer_SetError (buf ? MIX_INVALID_VALUE : MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_GetBufferi() called with null param\n"); +#endif + return; + } + + LockRecursiveMutex (buf_mutex); + + if (buf->locked) + { + UnlockRecursiveMutex (buf_mutex); + mixer_SetError (MIX_INVALID_OPERATION); +#ifdef DEBUG + fprintf (stderr, "mixer_GetBufferi() called with locked buffer\n"); +#endif + return; + } + + if (buf->magic != mixer_bufMagic) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_GetBufferi(): not a buffer\n"); +#endif + } + else + { + /* Return original buffer values + */ + switch (pname) + { + case MIX_FREQUENCY: + *value = buf->orgfreq; + break; + case MIX_BITS: + *value = buf->orgchansize << 3; + break; + case MIX_CHANNELS: + *value = buf->orgchannels; + break; + case MIX_SIZE: + *value = buf->orgsize; + break; + case MIX_DATA: + *value = (mixer_IntVal) buf->orgdata; + break; + default: + mixer_SetError (MIX_INVALID_ENUM); + fprintf (stderr, "mixer_GetBufferi() called " + "with invalid property %u\n", pname); + } + } + + UnlockRecursiveMutex (buf_mutex); +} + +/* fill buffer with external data */ +void +mixer_BufferData (mixer_Object bufobj, uint32 format, void* data, + uint32 size, uint32 freq) +{ + mixer_Buffer *buf = (mixer_Buffer *) bufobj; + mixer_Convertion conv; + uint32 dstsize; + + if (!buf || !data || !size) + { + mixer_SetError (buf ? MIX_INVALID_VALUE : MIX_INVALID_NAME); +#ifdef DEBUG +// fprintf (stderr, "mixer_BufferData() called with bad param\n"); +#endif + return; + } + + LockRecursiveMutex (buf_mutex); + + if (buf->locked) + { + UnlockRecursiveMutex (buf_mutex); + mixer_SetError (MIX_INVALID_OPERATION); +#ifdef DEBUG + fprintf (stderr, "mixer_BufferData() called " + "with locked buffer\n"); +#endif + return; + } + + if (buf->magic != mixer_bufMagic) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "mixer_BufferData(): not a buffer\n"); +#endif + } + else if (buf->state > MIX_BUF_FILLED) + { + mixer_SetError (MIX_INVALID_OPERATION); +#ifdef DEBUG + fprintf (stderr, "mixer_BufferData() attempted " + "on in-use buffer\n"); +#endif + } + else + { + if (buf->data) + HFree (buf->data); + buf->data = 0; + buf->size = 0; + + /* Store original buffer values for OpenAL compatibility */ + buf->orgdata = data; + buf->orgfreq = freq; + buf->orgsize = size; + buf->orgchannels = MIX_FORMAT_CHANS (format); + buf->orgchansize = MIX_FORMAT_BPC (format); + + conv.srcsamples = conv.dstsamples = + size / MIX_FORMAT_SAMPSIZE (format); + + if (conv.dstsamples > + UINT32_MAX / MIX_FORMAT_SAMPSIZE (format)) + { + mixer_SetError (MIX_INVALID_VALUE); + } + else + { + if (MIX_FORMAT_CHANS (format) < MIX_FORMAT_CHANS (mixer_format)) + buf->sampsize = MIX_FORMAT_BPC (mixer_format) * + MIX_FORMAT_CHANS (format); + else + buf->sampsize = MIX_FORMAT_SAMPSIZE (mixer_format); + buf->size = dstsize = conv.dstsamples * buf->sampsize; + + /* only copy/convert the data if not faking */ + if (! (mixer_flags & MIX_FAKE_DATA)) + { + buf->data = HMalloc (dstsize); + + if (MIX_FORMAT_BPC (format) == MIX_FORMAT_BPC (mixer_format) && + MIX_FORMAT_CHANS (format) <= MIX_FORMAT_CHANS (mixer_format)) + { + /* format is compatible with internal */ + buf->locked = true; + UnlockRecursiveMutex (buf_mutex); + + memcpy (buf->data, data, size); + if (MIX_FORMAT_BPC (format) == 1) + { + /* convert buffer to S8 format internally */ + uint8* dst; + for (dst = buf->data; dstsize; dstsize--, dst++) + *dst ^= 0x80; + } + + LockRecursiveMutex (buf_mutex); + buf->locked = false; + } + else + { + /* needs convertion */ + conv.srcfmt = format; + conv.srcdata = data; + conv.srcsize = size; + + if (MIX_FORMAT_CHANS (format) < MIX_FORMAT_CHANS (mixer_format)) + conv.dstfmt = MIX_FORMAT_MAKE (mixer_chansize, + MIX_FORMAT_CHANS (format)); + else + conv.dstfmt = mixer_format; + conv.dstdata = buf->data; + conv.dstsize = dstsize; + + buf->locked = true; + UnlockRecursiveMutex (buf_mutex); + + mixer_ConvertBuffer_internal (&conv); + + LockRecursiveMutex (buf_mutex); + buf->locked = false; + } + } + + buf->state = MIX_BUF_FILLED; + buf->high = (buf->orgfreq / mixer_freq) * buf->sampsize; + buf->low = (((buf->orgfreq % mixer_freq) << 16) / mixer_freq); + if (mixer_freq == buf->orgfreq) + buf->Resample = mixer_resampling.None; + else if (mixer_freq > buf->orgfreq) + buf->Resample = mixer_resampling.Upsample; + else + buf->Resample = mixer_resampling.Downsample; + } + } + + UnlockRecursiveMutex (buf_mutex); +} + + +/************************************************* + * Buffer internals + */ + +static __inline__ bool +mixer_CheckBufferState (mixer_Buffer *buf, const char* FuncName) +{ + if (!buf) + return false; + + if (buf->magic != mixer_bufMagic) + { + mixer_SetError (MIX_INVALID_NAME); +#ifdef DEBUG + fprintf (stderr, "%s(): not a buffer\n", FuncName); +#endif + return false; + } + + if (buf->locked) + { + mixer_SetError (MIX_INVALID_OPERATION); +#ifdef DEBUG + fprintf (stderr, "%s(): locked buffer attempted\n", FuncName); +#endif + return false; + } + + if (buf->state != MIX_BUF_FILLED) + { + mixer_SetError (MIX_INVALID_OPERATION); +#ifdef DEBUG + fprintf (stderr, "%s: invalid buffer attempted\n", FuncName); +#endif + return false; + } + return true; +} + +static void +mixer_ConvertBuffer_internal (mixer_Convertion *conv) +{ + conv->srcbpc = MIX_FORMAT_BPC (conv->srcfmt); + conv->srcchans = MIX_FORMAT_CHANS (conv->srcfmt); + conv->dstbpc = MIX_FORMAT_BPC (conv->dstfmt); + conv->dstchans = MIX_FORMAT_CHANS (conv->dstfmt); + + conv->flags = 0; + if (conv->srcbpc > conv->dstbpc) + conv->flags |= mixConvSizeDown; + else if (conv->srcbpc < conv->dstbpc) + conv->flags |= mixConvSizeUp; + if (conv->srcchans > conv->dstchans) + conv->flags |= mixConvStereoDown; + else if (conv->srcchans < conv->dstchans) + conv->flags |= mixConvStereoUp; + + mixer_ResampleFlat (conv); +} + +/************************************************* + * Resampling routines + */ + +/* get a sample from external buffer + * in internal format + */ +static __inline__ sint32 +mixer_GetSampleExt (void *src, uint32 bpc) +{ + if (bpc == 2) + return *(sint16 *)src; + else + return (*(uint8 *)src) - 128; +} + +/* get a sample from internal buffer */ +static __inline__ sint32 +mixer_GetSampleInt (void *src, uint32 bpc) +{ + if (bpc == 2) + return *(sint16 *)src; + else + return *(sint8 *)src; +} + +/* put a sample into an external buffer + * from internal format + */ +static __inline__ void +mixer_PutSampleExt (void *dst, uint32 bpc, sint32 samp) +{ + if (bpc == 2) + *(sint16 *)dst = samp; + else + *(uint8 *)dst = samp ^ 0x80; +} + +/* put a sample into an internal buffer + * in internal format + */ +static __inline__ void +mixer_PutSampleInt (void *dst, uint32 bpc, sint32 samp) +{ + if (bpc == 2) + *(sint16 *)dst = samp; + else + *(sint8 *)dst = samp; +} + +/* get a sample from source */ +static float +mixer_ResampleNone (mixer_Source *src, bool left) +{ + uint8 *d0 = src->nextqueued->data + src->pos; + src->pos += mixer_chansize; + (void) left; // satisfying compiler - unused arg + return (float)mixer_GetSampleInt (d0, mixer_chansize); +} + +/* get a resampled (up/down) sample from source (nearest neighbor) */ +static float +mixer_ResampleNearest (mixer_Source *src, bool left) +{ + uint8 *d0 = src->nextqueued->data + src->pos; + d0 += mixer_SourceAdvance (src, left); + return (float)mixer_GetSampleInt (d0, mixer_chansize); +} + +/* get an upsampled sample from source (linear interpolation) */ +static float +mixer_UpsampleLinear (mixer_Source *src, bool left) +{ + mixer_Buffer *curr = src->nextqueued; + mixer_Buffer *next = src->nextqueued->next; + uint8 *d0, *d1; + float s0, s1, t; + + t = src->count / 65536.0f; + d0 = curr->data + src->pos; + d0 += mixer_SourceAdvance (src, left); + + if (d0 + curr->sampsize >= curr->data + curr->size) + { + if (next && next->data && next->size >= curr->sampsize) + { + d1 = next->data; + if (!left) + d1 += mixer_chansize; + } + else + d1 = d0; + } + else + d1 = d0 + curr->sampsize; + + s0 = (float)mixer_GetSampleInt (d0, mixer_chansize); + s1 = (float)mixer_GetSampleInt (d1, mixer_chansize); + return s0 + t * (s1 - s0); +} + +/* get an upsampled sample from source (cubic interpolation) */ +static float +mixer_UpsampleCubic (mixer_Source *src, bool left) +{ + mixer_Buffer *prev = src->prevqueued; + mixer_Buffer *curr = src->nextqueued; + mixer_Buffer *next = src->nextqueued->next; + uint8 *d0, *d1, *d2, *d3; /* prev, curr, next, next + 1 */ + float t, t2, a, b, c, s0, s1, s2, s3; + + t = src->count / 65536.0f; + t2 = t * t; + d1 = curr->data + src->pos; + d1 += mixer_SourceAdvance (src, left); + + if (d1 - curr->sampsize < curr->data) + { + if (prev && prev->data && prev->size >= curr->sampsize) + { + d0 = prev->data + prev->size - curr->sampsize; + if (!left) + d0 += mixer_chansize; + } + else + d0 = d1; + } + else + d0 = d1 - curr->sampsize; + + if (d1 + curr->sampsize >= curr->data + curr->size) + { + if (next && next->data && next->size >= curr->sampsize * 2) + { + d2 = next->data; + if (!left) + d2 += mixer_chansize; + d3 = d2 + curr->sampsize; + } + else + d2 = d3 = d1; + } + else + { + d2 = d1 + curr->sampsize; + if (d2 + curr->sampsize >= curr->data + curr->size) + { + if (next && next->data && next->size >= curr->sampsize) + { + d3 = next->data; + if (!left) + d3 += mixer_chansize; + } + else + d3 = d2; + } + else + d3 = d2 + curr->sampsize; + } + + s0 = (float)mixer_GetSampleInt (d0, mixer_chansize); + s1 = (float)mixer_GetSampleInt (d1, mixer_chansize); + s2 = (float)mixer_GetSampleInt (d2, mixer_chansize); + s3 = (float)mixer_GetSampleInt (d3, mixer_chansize); + + a = (3.0f * (s1 - s2) - s0 + s3) * 0.5f; + b = 2.0f * s2 + s0 - ((5.0f * s1 + s3) * 0.5f); + c = (s2 - s0) * 0.5f; + + return a * t2 * t + b * t2 + c * t + s1; +} + +/* get next sample from external buffer + * in internal format, while performing + * convertion if necessary + */ +static __inline__ sint32 +mixer_GetConvSample (uint8 **psrc, uint32 bpc, uint32 flags) +{ + sint32 samp; + + samp = mixer_GetSampleExt (*psrc, bpc); + *psrc += bpc; + if (flags & mixConvStereoDown) + { + /* downmix to mono - average up channels */ + samp = (samp + mixer_GetSampleExt (*psrc, bpc)) / 2; + *psrc += bpc; + } + + if (flags & mixConvSizeUp) + { + /* convert S8 to S16 */ + samp <<= 8; + } + else if (flags & mixConvSizeDown) + { + /* convert S16 to S8 + * if arithmetic shift is available to the compiler + * it will use it to optimize this + */ + samp /= 0x100; + } + + return samp; +} + +/* put next sample into an internal buffer + * in internal format, while performing + * convertion if necessary + */ +static __inline__ void +mixer_PutConvSample (uint8 **pdst, uint32 bpc, uint32 flags, sint32 samp) +{ + mixer_PutSampleInt (*pdst, bpc, samp); + *pdst += bpc; + if (flags & mixConvStereoUp) + { + mixer_PutSampleInt (*pdst, bpc, samp); + *pdst += bpc; + } +} + +/* resampling with respect to sample size only */ +static void +mixer_ResampleFlat (mixer_Convertion *conv) +{ + mixer_ConvFlags flags = conv->flags; + uint8 *src = conv->srcdata; + uint8 *dst = conv->dstdata; + uint32 srcbpc = conv->srcbpc; + uint32 dstbpc = conv->dstbpc; + uint32 samples; + + samples = conv->srcsamples; + if ( !(conv->flags & (mixConvStereoUp | mixConvStereoDown))) + samples *= conv->srcchans; + + for (; samples; samples--) + { + sint32 samp; + + samp = mixer_GetConvSample (&src, srcbpc, flags); + mixer_PutConvSample (&dst, dstbpc, flags, samp); + } +} diff --git a/sc2/src/sc2code/libs/sound/mixer/mixer.h b/sc2/src/sc2code/libs/sound/mixer/mixer.h new file mode 100644 index 000000000..087299f16 --- /dev/null +++ b/sc2/src/sc2code/libs/sound/mixer/mixer.h @@ -0,0 +1,274 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Mixer for low-level sound output drivers + */ + +#ifndef _MIXER_H +#define _MIXER_H + +#include "config.h" +#include "types.h" +#include "endian_uqm.h" + +/** + * The interface heavily influenced by OpenAL + * to the point where you should use OpenAL's + * documentation when programming the mixer. + * (some source properties are not supported) + * + * EXCEPTION: You may not queue the same buffer + * on more than one source + */ + +#ifdef WORDS_BIGENDIAN +# define MIX_IS_BIG_ENDIAN true +# define MIX_WANT_BIG_ENDIAN true +#else +# define MIX_IS_BIG_ENDIAN false +# define MIX_WANT_BIG_ENDIAN false +#endif + +/** + * Mixer errors (see OpenAL errors) + */ +enum +{ + MIX_NO_ERROR = 0, + MIX_INVALID_NAME = 0xA001U, + MIX_INVALID_ENUM = 0xA002U, + MIX_INVALID_VALUE = 0xA003U, + MIX_INVALID_OPERATION = 0xA004U, + MIX_OUT_OF_MEMORY = 0xA005U, + + MIX_DRIVER_FAILURE = 0xA101U +}; + +/** + * Source properties (see OpenAL) + */ +typedef enum +{ + MIX_POSITION = 0x1004, + MIX_LOOPING = 0x1007, + MIX_BUFFER = 0x1009, + MIX_GAIN = 0x100A, + MIX_SOURCE_STATE = 0x1010, + + MIX_BUFFERS_QUEUED = 0x1015, + MIX_BUFFERS_PROCESSED = 0x1016 + +} mixer_SourceProp; + +/** + * Source state information + */ +typedef enum +{ + MIX_INITIAL = 0, + MIX_STOPPED, + MIX_PLAYING, + MIX_PAUSED, + +} mixer_SourceState; + +/** + * Sound buffer properties + */ +typedef enum +{ + MIX_FREQUENCY = 0x2001, + MIX_BITS = 0x2002, + MIX_CHANNELS = 0x2003, + MIX_SIZE = 0x2004, + MIX_DATA = 0x2005 + +} mixer_BufferProp; + +/** + * Buffer states: semi-private + */ +typedef enum +{ + MIX_BUF_INITIAL = 0, + MIX_BUF_FILLED, + MIX_BUF_QUEUED, + MIX_BUF_PLAYING, + MIX_BUF_PROCESSED + +} mixer_BufferState; + +/** Sound buffers: format specifier. + * bits 00..07: bytes per sample + * bits 08..15: channels + * bits 15..31: meaningless + */ +#define MIX_FORMAT_DUMMYID 0x00170000 +#define MIX_FORMAT_BPC(f) ((f) & 0xff) +#define MIX_FORMAT_CHANS(f) (((f) >> 8) & 0xff) +#define MIX_FORMAT_BPC_MAX 2 +#define MIX_FORMAT_CHANS_MAX 2 +#define MIX_FORMAT_MAKE(b, c) \ + ( MIX_FORMAT_DUMMYID | ((b) & 0xff) | (((c) & 0xff) << 8) ) + +#define MIX_FORMAT_SAMPSIZE(f) \ + ( MIX_FORMAT_BPC(f) * MIX_FORMAT_CHANS(f) ) + +typedef enum +{ + MIX_FORMAT_MONO8 = MIX_FORMAT_MAKE (1, 1), + MIX_FORMAT_STEREO8 = MIX_FORMAT_MAKE (1, 2), + MIX_FORMAT_MONO16 = MIX_FORMAT_MAKE (2, 1), + MIX_FORMAT_STEREO16 = MIX_FORMAT_MAKE (2, 2) + +} mixer_Format; + +typedef enum +{ + MIX_QUALITY_LOW = 0, + MIX_QUALITY_MEDIUM, + MIX_QUALITY_HIGH, + MIX_QUALITY_DEFAULT = MIX_QUALITY_MEDIUM, + MIX_QUALITY_COUNT + +} mixer_Quality; + +typedef enum +{ + MIX_NOFLAGS = 0, + MIX_FAKE_DATA = 1 +} mixer_Flags; + +/************************************************* + * Interface Types + */ + +typedef intptr_t mixer_Object; +typedef intptr_t mixer_IntVal; + +typedef struct _mixer_Source mixer_Source; + +typedef struct _mixer_Buffer +{ + uint32 magic; + bool locked; + mixer_BufferState state; + uint8 *data; + uint32 size; + uint32 sampsize; + uint32 high; + uint32 low; + float (* Resample) (mixer_Source *src, bool left); + /* original buffer values for OpenAL compat */ + void* orgdata; + uint32 orgfreq; + uint32 orgsize; + uint32 orgchannels; + uint32 orgchansize; + /* next buffer in chain */ + struct _mixer_Buffer *next; + +} mixer_Buffer; + +#define mixer_bufMagic 0x4258494DU /* MIXB in LSB */ + +struct _mixer_Source +{ + uint32 magic; + bool locked; + mixer_SourceState state; + bool looping; + float gain; + uint32 cqueued; + uint32 cprocessed; + mixer_Buffer *firstqueued; /* first buf in the queue */ + mixer_Buffer *nextqueued; /* next to play, or 0 */ + mixer_Buffer *prevqueued; /* previously played */ + mixer_Buffer *lastqueued; /* last in queue */ + uint32 pos; /* position in current buffer */ + uint32 count; /* fractional part of pos */ + + float samplecache; + +}; + +#define mixer_srcMagic 0x5358494DU /* MIXS in LSB */ + +/************************************************* + * General interface + */ +uint32 mixer_GetError (void); + +bool mixer_Init (uint32 frequency, uint32 format, mixer_Quality quality, + mixer_Flags flags); +void mixer_Uninit (void); +void mixer_MixChannels (void *userdata, uint8 *stream, sint32 len); +void mixer_MixFake (void *userdata, uint8 *stream, sint32 len); + +/************************************************* + * Sources + */ +void mixer_GenSources (uint32 n, mixer_Object *psrcobj); +void mixer_DeleteSources (uint32 n, mixer_Object *psrcobj); +bool mixer_IsSource (mixer_Object srcobj); +void mixer_Sourcei (mixer_Object srcobj, mixer_SourceProp pname, + mixer_IntVal value); +void mixer_Sourcef (mixer_Object srcobj, mixer_SourceProp pname, + float value); +void mixer_Sourcefv (mixer_Object srcobj, mixer_SourceProp pname, + float *value); +void mixer_GetSourcei (mixer_Object srcobj, mixer_SourceProp pname, + mixer_IntVal *value); +void mixer_GetSourcef (mixer_Object srcobj, mixer_SourceProp pname, + float *value); +void mixer_SourceRewind (mixer_Object srcobj); +void mixer_SourcePlay (mixer_Object srcobj); +void mixer_SourcePause (mixer_Object srcobj); +void mixer_SourceStop (mixer_Object srcobj); +void mixer_SourceQueueBuffers (mixer_Object srcobj, uint32 n, + mixer_Object* pbufobj); +void mixer_SourceUnqueueBuffers (mixer_Object srcobj, uint32 n, + mixer_Object* pbufobj); + +/************************************************* + * Buffers + */ +void mixer_GenBuffers (uint32 n, mixer_Object *pbufobj); +void mixer_DeleteBuffers (uint32 n, mixer_Object *pbufobj); +bool mixer_IsBuffer (mixer_Object bufobj); +void mixer_GetBufferi (mixer_Object bufobj, mixer_BufferProp pname, + mixer_IntVal *value); +void mixer_BufferData (mixer_Object bufobj, uint32 format, void* data, + uint32 size, uint32 freq); + + +/* Make sure the prop-value type is of suitable size + * it must be able to store both int and void* + * Adapted from SDL + * This will generate "negative subscript or subscript is too large" + * error during compile, if the actual size of a type is wrong + */ +#define MIX_COMPILE_TIME_ASSERT(name, x) \ + typedef int mixer_dummy_##name [(x) * 2 - 1] + +MIX_COMPILE_TIME_ASSERT (mixer_Object, + sizeof(mixer_Object) >= sizeof(void*)); +MIX_COMPILE_TIME_ASSERT (mixer_IntVal, + sizeof(mixer_IntVal) >= sizeof(mixer_Object)); + +#undef MIX_COMPILE_TIME_ASSERT + +#endif /* _MIXER_H */ diff --git a/sc2/src/sc2code/libs/sound/mixer/mixerint.h b/sc2/src/sc2code/libs/sound/mixer/mixerint.h new file mode 100644 index 000000000..1fd740f91 --- /dev/null +++ b/sc2/src/sc2code/libs/sound/mixer/mixerint.h @@ -0,0 +1,108 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Mixer for low-level sound output drivers + * Internals + */ + +#ifndef _MIXERINT_H +#define _MIXERINT_H + + +/************************************************* + * Internals + */ + +/* Conversion info types and funcs */ +typedef enum +{ + mixConvNone = 0, + mixConvStereoUp = 1, + mixConvStereoDown = 2, + mixConvSizeUp = 4, + mixConvSizeDown = 8 + +} mixer_ConvFlags; + +typedef struct +{ + uint32 srcfmt; + void *srcdata; + uint32 srcsize; + uint32 srcbpc; /* bytes/sample for 1 chan */ + uint32 srcchans; + uint32 srcsamples; + + uint32 dstfmt; + void *dstdata; + uint32 dstsize; + uint32 dstbpc; /* bytes/sample for 1 chan */ + uint32 dstchans; + uint32 dstsamples; + + mixer_ConvFlags flags; + +} mixer_Convertion; + +typedef struct +{ + float (* Upsample) (mixer_Source *src, bool left); + float (* Downsample) (mixer_Source *src, bool left); + float (* None) (mixer_Source *src, bool left); +} mixer_Resampling; + +static void mixer_ConvertBuffer_internal (mixer_Convertion *conv); +static void mixer_ResampleFlat (mixer_Convertion *conv); + +static __inline__ sint32 mixer_GetSampleExt (void *src, uint32 bpc); +static __inline__ sint32 mixer_GetSampleInt (void *src, uint32 bpc); +static __inline__ void mixer_PutSampleInt (void *dst, uint32 bpc, + sint32 samp); +static __inline__ void mixer_PutSampleExt (void *dst, uint32 bpc, + sint32 samp); + +static float mixer_ResampleNone (mixer_Source *src, bool left); +static float mixer_ResampleNearest (mixer_Source *src, bool left); +static float mixer_UpsampleLinear (mixer_Source *src, bool left); +static float mixer_UpsampleCubic (mixer_Source *src, bool left); + +/* Source manipulation */ +static void mixer_SourceUnqueueAll (mixer_Source *src); +static void mixer_SourceStop_internal (mixer_Source *src); +static void mixer_SourceRewind_internal (mixer_Source *src); +static void mixer_SourceActivate (mixer_Source* src); +static void mixer_SourceDeactivate (mixer_Source* src); + +static __inline__ bool mixer_CheckBufferState (mixer_Buffer *buf, + const char* FuncName); + +/* Clipping boundaries */ +#define MIX_S16_MAX ((float) SINT16_MAX) +#define MIX_S16_MIN ((float) SINT16_MIN) +#define MIX_S8_MAX ((float) SINT8_MAX) +#define MIX_S8_MIN ((float) SINT8_MIN) + +/* Channel gain adjustment for clipping reduction */ +#define MIX_GAIN_ADJ (0.75f) + +/* The Mixer */ +static __inline__ bool mixer_SourceGetNextSample (mixer_Source *src, + float *psamp, bool left); +static __inline__ bool mixer_SourceGetFakeSample (mixer_Source *src, + float *psamp, bool left); +static __inline__ uint32 mixer_SourceAdvance (mixer_Source *src, bool left); + +#endif /* _MIXERINT_H */ diff --git a/sc2/src/sc2code/libs/sound/mixer/nosound/Makeinfo b/sc2/src/sc2code/libs/sound/mixer/nosound/Makeinfo new file mode 100644 index 000000000..62d795c0a --- /dev/null +++ b/sc2/src/sc2code/libs/sound/mixer/nosound/Makeinfo @@ -0,0 +1 @@ +uqm_CFILES="audiodrv_nosound.c" diff --git a/sc2/src/sc2code/libs/sound/mixer/nosound/audiodrv_nosound.c b/sc2/src/sc2code/libs/sound/mixer/nosound/audiodrv_nosound.c new file mode 100644 index 000000000..092d418aa --- /dev/null +++ b/sc2/src/sc2code/libs/sound/mixer/nosound/audiodrv_nosound.c @@ -0,0 +1,417 @@ +//Copyright Paul Reiche, Fred Ford. 1992-2002 + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Nosound audio driver + */ + +#include "audiodrv_nosound.h" + +static Task StreamDecoderTask; +static Task PlaybackTask; +static uint32 nosound_freq = 22050; + +static const audio_Driver noSound_Driver = +{ + noSound_Uninit, + noSound_GetError, + audio_DRIVER_NOSOUND, + { + /* Errors */ + MIX_NO_ERROR, + MIX_INVALID_NAME, + MIX_INVALID_ENUM, + MIX_INVALID_VALUE, + MIX_INVALID_OPERATION, + MIX_OUT_OF_MEMORY, + MIX_DRIVER_FAILURE, + + /* Source properties */ + MIX_POSITION, + MIX_LOOPING, + MIX_BUFFER, + MIX_GAIN, + MIX_SOURCE_STATE, + MIX_BUFFERS_QUEUED, + MIX_BUFFERS_PROCESSED, + + /* Source state information */ + MIX_INITIAL, + MIX_STOPPED, + MIX_PLAYING, + MIX_PAUSED, + + /* Sound buffer properties */ + MIX_FREQUENCY, + MIX_BITS, + MIX_CHANNELS, + MIX_SIZE, + MIX_DATA, + MIX_FORMAT_MONO16, + MIX_FORMAT_STEREO16, + MIX_FORMAT_MONO8, + MIX_FORMAT_STEREO8 + }, + + /* Sources */ + noSound_GenSources, + noSound_DeleteSources, + noSound_IsSource, + noSound_Sourcei, + noSound_Sourcef, + noSound_Sourcefv, + noSound_GetSourcei, + noSound_GetSourcef, + noSound_SourceRewind, + noSound_SourcePlay, + noSound_SourcePause, + noSound_SourceStop, + noSound_SourceQueueBuffers, + noSound_SourceUnqueueBuffers, + + /* Buffers */ + noSound_GenBuffers, + noSound_DeleteBuffers, + noSound_IsBuffer, + noSound_GetBufferi, + noSound_BufferData +}; + + +/* + * Initialization + */ + +sint32 +noSound_Init (audio_Driver *driver, sint32 flags) +{ + int i; + TFB_DecoderFormats formats = + { + 0, 0, + audio_FORMAT_MONO8, audio_FORMAT_STEREO8, + audio_FORMAT_MONO16, audio_FORMAT_STEREO16 + }; + + fprintf (stderr, "Using nosound audio driver.\n"); + fprintf (stderr, "Initializing mixer.\n"); + + if (!mixer_Init (nosound_freq, MIX_FORMAT_MAKE (1, 1), + MIX_QUALITY_LOW, MIX_FAKE_DATA)) + { + fprintf (stderr, "Mixer initialization failed: %x\n", + mixer_GetError ()); + return -1; + } + fprintf (stderr, "Mixer initialized.\n"); + + fprintf (stderr, "Initializing sound decoders.\n"); + if (SoundDecoder_Init (flags, &formats)) + { + fprintf (stderr, "Sound decoders initialization failed.\n"); + mixer_Uninit (); + return -1; + } + fprintf (stderr, "Sound decoders initialized.\n"); + + *driver = noSound_Driver; + for (i = 0; i < NUM_SOUNDSOURCES; ++i) + { + audio_GenSources (1, &soundSource[i].handle); + soundSource[i].sample = NULL; + soundSource[i].stream_should_be_playing = FALSE; + soundSource[i].stream_mutex = CreateMutex ("Nosound stream mutex", SYNC_CLASS_AUDIO); + soundSource[i].sbuffer = NULL; + soundSource[i].sbuf_start = 0; + soundSource[i].sbuf_size = 0; + soundSource[i].sbuf_offset = 0; + } + + atexit (unInitAudio); + + SetSFXVolume (sfxVolumeScale); + SetSpeechVolume (speechVolumeScale); + SetMusicVolume ((COUNT)musicVolume); + + StreamDecoderTask = AssignTask (StreamDecoderTaskFunc, 1024, + "audio stream decoder"); + PlaybackTask = AssignTask (PlaybackTaskFunc, 1024, + "nosound audio playback"); + + return 0; +} + +void +noSound_Uninit (void) +{ + int i; + + if (StreamDecoderTask) + { + ConcludeTask (StreamDecoderTask); + StreamDecoderTask = NULL; + } + + for (i = 0; i < NUM_SOUNDSOURCES; ++i) + { + if (soundSource[i].sample && soundSource[i].sample->decoder) + { + StopStream (i); + } + if (soundSource[i].sbuffer) + { + void *sbuffer = soundSource[i].sbuffer; + soundSource[i].sbuffer = NULL; + HFree (sbuffer); + } + DestroyMutex (soundSource[i].stream_mutex); + + noSound_DeleteSources (1, &soundSource[i].handle); + } + + if (PlaybackTask) + { + ConcludeTask (PlaybackTask); + PlaybackTask = 0; + } + + mixer_Uninit (); + SoundDecoder_Uninit (); +} + + +/* + * Playback task + */ + +int +PlaybackTaskFunc (void *data) +{ + Task task = (Task)data; + uint8 *stream; + uint32 entryTime; + sint32 period, delay; + uint32 len = 2048; + + stream = (uint8 *) HMalloc (len); + period = (sint32)((len / (double)nosound_freq) * ONE_SECOND); + + while (!Task_ReadState (task, TASK_EXIT)) + { + entryTime = GetTimeCounter (); + mixer_MixFake (NULL, stream, len); + delay = period - (GetTimeCounter () - entryTime); + if (delay > 0) + SleepThread (delay); + } + + HFree (stream); + FinishTask (task); + return 0; +} + + +/* + * General + */ + +sint32 +noSound_GetError (void) +{ + sint32 value = mixer_GetError (); + switch (value) + { + case MIX_NO_ERROR: + return audio_NO_ERROR; + case MIX_INVALID_NAME: + return audio_INVALID_NAME; + case MIX_INVALID_ENUM: + return audio_INVALID_ENUM; + case MIX_INVALID_VALUE: + return audio_INVALID_VALUE; + case MIX_INVALID_OPERATION: + return audio_INVALID_OPERATION; + case MIX_OUT_OF_MEMORY: + return audio_OUT_OF_MEMORY; + default: + fprintf (stderr, "noSound_GetError: unknown value %x\n", + value); + return audio_DRIVER_FAILURE; + break; + } +} + + +/* + * Sources + */ + +void +noSound_GenSources (uint32 n, audio_Object *psrcobj) +{ + mixer_GenSources (n, (mixer_Object *) psrcobj); +} + +void +noSound_DeleteSources (uint32 n, audio_Object *psrcobj) +{ + mixer_DeleteSources (n, (mixer_Object *) psrcobj); +} + +bool +noSound_IsSource (audio_Object srcobj) +{ + return mixer_IsSource ((mixer_Object) srcobj); +} + +void +noSound_Sourcei (audio_Object srcobj, audio_SourceProp pname, + audio_IntVal value) + +{ + mixer_Sourcei ((mixer_Object) srcobj, (mixer_SourceProp) pname, + (mixer_IntVal) value); +} + +void +noSound_Sourcef (audio_Object srcobj, audio_SourceProp pname, + float value) +{ + mixer_Sourcef ((mixer_Object) srcobj, (mixer_SourceProp) pname, value); +} + +void +noSound_Sourcefv (audio_Object srcobj, audio_SourceProp pname, + float *value) +{ + mixer_Sourcefv ((mixer_Object) srcobj, (mixer_SourceProp) pname, value); +} + +void +noSound_GetSourcei (audio_Object srcobj, audio_SourceProp pname, + audio_IntVal *value) +{ + mixer_GetSourcei ((mixer_Object) srcobj, (mixer_SourceProp) pname, + (mixer_IntVal *) value); + if (pname == MIX_SOURCE_STATE) + { + switch (*value) + { + case MIX_INITIAL: + *value = audio_INITIAL; + break; + case MIX_STOPPED: + *value = audio_STOPPED; + break; + case MIX_PLAYING: + *value = audio_PLAYING; + break; + case MIX_PAUSED: + *value = audio_PAUSED; + break; + default: + fprintf (stderr, "noSound_GetSourcei(): unknown value %x\n", + *value); + *value = audio_DRIVER_FAILURE; + } + } +} + +void +noSound_GetSourcef (audio_Object srcobj, audio_SourceProp pname, + float *value) +{ + mixer_GetSourcef ((mixer_Object) srcobj, (mixer_SourceProp) pname, value); +} + +void +noSound_SourceRewind (audio_Object srcobj) +{ + mixer_SourceRewind ((mixer_Object) srcobj); +} + +void +noSound_SourcePlay (audio_Object srcobj) +{ + mixer_SourcePlay ((mixer_Object) srcobj); +} + +void +noSound_SourcePause (audio_Object srcobj) +{ + mixer_SourcePause ((mixer_Object) srcobj); +} + +void +noSound_SourceStop (audio_Object srcobj) +{ + mixer_SourceStop ((mixer_Object) srcobj); +} + +void +noSound_SourceQueueBuffers (audio_Object srcobj, uint32 n, + audio_Object* pbufobj) +{ + mixer_SourceQueueBuffers ((mixer_Object) srcobj, n, + (mixer_Object *) pbufobj); +} + +void +noSound_SourceUnqueueBuffers (audio_Object srcobj, uint32 n, + audio_Object* pbufobj) +{ + mixer_SourceUnqueueBuffers ((mixer_Object) srcobj, n, + (mixer_Object *) pbufobj); +} + + +/* + * Buffers + */ + +void +noSound_GenBuffers (uint32 n, audio_Object *pbufobj) +{ + mixer_GenBuffers (n, (mixer_Object *) pbufobj); +} + +void +noSound_DeleteBuffers (uint32 n, audio_Object *pbufobj) +{ + mixer_DeleteBuffers (n, (mixer_Object *) pbufobj); +} + +bool +noSound_IsBuffer (audio_Object bufobj) +{ + return mixer_IsBuffer ((mixer_Object) bufobj); +} + +void +noSound_GetBufferi (audio_Object bufobj, audio_BufferProp pname, + audio_IntVal *value) +{ + mixer_GetBufferi ((mixer_Object) bufobj, (mixer_BufferProp) pname, + (mixer_IntVal *) value); +} + +void +noSound_BufferData (audio_Object bufobj, uint32 format, void* data, + uint32 size, uint32 freq) +{ + mixer_BufferData ((mixer_Object) bufobj, format, data, size, freq); +} diff --git a/sc2/src/sc2code/libs/sound/mixer/nosound/audiodrv_nosound.h b/sc2/src/sc2code/libs/sound/mixer/nosound/audiodrv_nosound.h new file mode 100644 index 000000000..9e0f9f6fd --- /dev/null +++ b/sc2/src/sc2code/libs/sound/mixer/nosound/audiodrv_nosound.h @@ -0,0 +1,68 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Nosound audio driver + */ + +#ifndef _AUDIODRV_NOSOUND_H +#define _AUDIODRV_NOSOUND_H + +#include "config.h" +#include "libs/sound/sound.h" +#include "libs/sound/mixer/mixer.h" + +/* Playback task */ +int PlaybackTaskFunc (void *data); + +/* General */ +sint32 noSound_Init (audio_Driver *driver, sint32 flags); +void noSound_Uninit (void); +sint32 noSound_GetError (void); + +/* Sources */ +void noSound_GenSources (uint32 n, audio_Object *psrcobj); +void noSound_DeleteSources (uint32 n, audio_Object *psrcobj); +bool noSound_IsSource (audio_Object srcobj); +void noSound_Sourcei (audio_Object srcobj, audio_SourceProp pname, + audio_IntVal value); +void noSound_Sourcef (audio_Object srcobj, audio_SourceProp pname, + float value); +void noSound_Sourcefv (audio_Object srcobj, audio_SourceProp pname, + float *value); +void noSound_GetSourcei (audio_Object srcobj, audio_SourceProp pname, + audio_IntVal *value); +void noSound_GetSourcef (audio_Object srcobj, audio_SourceProp pname, + float *value); +void noSound_SourceRewind (audio_Object srcobj); +void noSound_SourcePlay (audio_Object srcobj); +void noSound_SourcePause (audio_Object srcobj); +void noSound_SourceStop (audio_Object srcobj); +void noSound_SourceQueueBuffers (audio_Object srcobj, uint32 n, + audio_Object* pbufobj); +void noSound_SourceUnqueueBuffers (audio_Object srcobj, uint32 n, + audio_Object* pbufobj); + +/* Buffers */ +void noSound_GenBuffers (uint32 n, audio_Object *pbufobj); +void noSound_DeleteBuffers (uint32 n, audio_Object *pbufobj); +bool noSound_IsBuffer (audio_Object bufobj); +void noSound_GetBufferi (audio_Object bufobj, audio_BufferProp pname, + audio_IntVal *value); +void noSound_BufferData (audio_Object bufobj, uint32 format, void* data, + uint32 size, uint32 freq); + + +#endif /* _AUDIODRV_NOSOUND_H */ diff --git a/sc2/src/sc2code/libs/sound/mixer/sdl/Makeinfo b/sc2/src/sc2code/libs/sound/mixer/sdl/Makeinfo new file mode 100644 index 000000000..5ff5a5cc2 --- /dev/null +++ b/sc2/src/sc2code/libs/sound/mixer/sdl/Makeinfo @@ -0,0 +1 @@ +uqm_CFILES="audiodrv_sdl.c" diff --git a/sc2/src/sc2code/libs/sound/mixer/sdl/audiodrv_sdl.c b/sc2/src/sc2code/libs/sound/mixer/sdl/audiodrv_sdl.c new file mode 100644 index 000000000..6e4ae6433 --- /dev/null +++ b/sc2/src/sc2code/libs/sound/mixer/sdl/audiodrv_sdl.c @@ -0,0 +1,434 @@ +//Copyright Paul Reiche, Fred Ford. 1992-2002 + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* SDL audio driver + */ + +#include "audiodrv_sdl.h" + +static Task StreamDecoderTask; + +static const audio_Driver mixSDL_Driver = +{ + mixSDL_Uninit, + mixSDL_GetError, + audio_DRIVER_MIXSDL, + { + /* Errors */ + MIX_NO_ERROR, + MIX_INVALID_NAME, + MIX_INVALID_ENUM, + MIX_INVALID_VALUE, + MIX_INVALID_OPERATION, + MIX_OUT_OF_MEMORY, + MIX_DRIVER_FAILURE, + + /* Source properties */ + MIX_POSITION, + MIX_LOOPING, + MIX_BUFFER, + MIX_GAIN, + MIX_SOURCE_STATE, + MIX_BUFFERS_QUEUED, + MIX_BUFFERS_PROCESSED, + + /* Source state information */ + MIX_INITIAL, + MIX_STOPPED, + MIX_PLAYING, + MIX_PAUSED, + + /* Sound buffer properties */ + MIX_FREQUENCY, + MIX_BITS, + MIX_CHANNELS, + MIX_SIZE, + MIX_DATA, + MIX_FORMAT_MONO16, + MIX_FORMAT_STEREO16, + MIX_FORMAT_MONO8, + MIX_FORMAT_STEREO8 + }, + + /* Sources */ + mixSDL_GenSources, + mixSDL_DeleteSources, + mixSDL_IsSource, + mixSDL_Sourcei, + mixSDL_Sourcef, + mixSDL_Sourcefv, + mixSDL_GetSourcei, + mixSDL_GetSourcef, + mixSDL_SourceRewind, + mixSDL_SourcePlay, + mixSDL_SourcePause, + mixSDL_SourceStop, + mixSDL_SourceQueueBuffers, + mixSDL_SourceUnqueueBuffers, + + /* Buffers */ + mixSDL_GenBuffers, + mixSDL_DeleteBuffers, + mixSDL_IsBuffer, + mixSDL_GetBufferi, + mixSDL_BufferData +}; + + +/* + * Initialization + */ + +sint32 +mixSDL_Init (audio_Driver *driver, sint32 flags) +{ + int i; + char devicename[256]; + SDL_AudioSpec desired, obtained; + mixer_Quality quality; + TFB_DecoderFormats formats = + { + MIX_IS_BIG_ENDIAN, MIX_WANT_BIG_ENDIAN, + audio_FORMAT_MONO8, audio_FORMAT_STEREO8, + audio_FORMAT_MONO16, audio_FORMAT_STEREO16 + }; + + fprintf (stderr, "Initializing SDL audio subsystem.\n"); + if ((SDL_InitSubSystem(SDL_INIT_AUDIO)) == -1) + { + fprintf (stderr, "Couldn't initialize audio subsystem: %s\n", SDL_GetError()); + return -1; + } + fprintf (stderr, "SDL audio subsystem initialized.\n"); + + if (flags & audio_QUALITY_HIGH) + { + quality = MIX_QUALITY_HIGH; + desired.freq = 44100; + desired.samples = 4096; + } + else if (flags & audio_QUALITY_LOW) + { + quality = MIX_QUALITY_LOW; + desired.freq = 22050; + desired.samples = 2048; + } + else + { + quality = MIX_QUALITY_DEFAULT; + desired.freq = 44100; + desired.samples = 4096; + } + + desired.format = AUDIO_S16SYS; + desired.channels = 2; + desired.callback = mixer_MixChannels; + + fprintf (stderr, "Opening SDL audio device.\n"); + if (SDL_OpenAudio (&desired, &obtained) < 0) + { + fprintf (stderr, "Unable to open audio device: %s\n", SDL_GetError ()); + SDL_QuitSubSystem (SDL_INIT_AUDIO); + return -1; + } + if (obtained.format != desired.format || + (obtained.channels != 1 && obtained.channels != 2)) + { + fprintf (stderr, "Unable to obtain desired audio format.\n"); + SDL_CloseAudio (); + SDL_QuitSubSystem (SDL_INIT_AUDIO); + return -1; + } + + SDL_AudioDriverName (devicename, sizeof (devicename)); + fprintf (stderr, " using %s at %d Hz 16 bit %s, %d samples audio buffer\n", + devicename, obtained.freq, obtained.channels > 1 ? "stereo" : "mono", + obtained.samples); + + fprintf (stderr, "Initializing mixer.\n"); + if (!mixer_Init (obtained.freq, MIX_FORMAT_MAKE (2, obtained.channels), + quality, 0)) + { + fprintf (stderr, "Mixer initialization failed: %x\n", + mixer_GetError ()); + SDL_CloseAudio (); + SDL_QuitSubSystem (SDL_INIT_AUDIO); + return -1; + } + fprintf (stderr, "Mixer initialized.\n"); + + fprintf (stderr, "Initializing sound decoders.\n"); + if (SoundDecoder_Init (flags, &formats)) + { + fprintf (stderr, "Sound decoders initialization failed.\n"); + SDL_CloseAudio (); + mixer_Uninit (); + SDL_QuitSubSystem (SDL_INIT_AUDIO); + return -1; + } + fprintf (stderr, "Sound decoders initialized.\n"); + + *driver = mixSDL_Driver; + for (i = 0; i < NUM_SOUNDSOURCES; ++i) + { + audio_GenSources (1, &soundSource[i].handle); + soundSource[i].sample = NULL; + soundSource[i].stream_should_be_playing = FALSE; + soundSource[i].stream_mutex = CreateMutex ("MixSDL stream mutex", SYNC_CLASS_AUDIO); + soundSource[i].sbuffer = NULL; + soundSource[i].sbuf_start = 0; + soundSource[i].sbuf_size = 0; + soundSource[i].sbuf_offset = 0; + } + + atexit (unInitAudio); + + SetSFXVolume (sfxVolumeScale); + SetSpeechVolume (speechVolumeScale); + SetMusicVolume ((COUNT)musicVolume); + + StreamDecoderTask = AssignTask (StreamDecoderTaskFunc, 1024, + "audio stream decoder"); + + SDL_PauseAudio (0); + + return 0; +} + +void +mixSDL_Uninit (void) +{ + int i; + + if (StreamDecoderTask) + { + ConcludeTask (StreamDecoderTask); + StreamDecoderTask = NULL; + } + + for (i = 0; i < NUM_SOUNDSOURCES; ++i) + { + if (soundSource[i].sample && soundSource[i].sample->decoder) + { + StopStream (i); + } + if (soundSource[i].sbuffer) + { + void *sbuffer = soundSource[i].sbuffer; + soundSource[i].sbuffer = NULL; + HFree (sbuffer); + } + DestroyMutex (soundSource[i].stream_mutex); + + mixSDL_DeleteSources (1, &soundSource[i].handle); + } + + SDL_CloseAudio (); + mixer_Uninit (); + SoundDecoder_Uninit (); + SDL_QuitSubSystem (SDL_INIT_AUDIO); +} + + +/* + * General + */ + +sint32 +mixSDL_GetError (void) +{ + sint32 value = mixer_GetError (); + switch (value) + { + case MIX_NO_ERROR: + return audio_NO_ERROR; + case MIX_INVALID_NAME: + return audio_INVALID_NAME; + case MIX_INVALID_ENUM: + return audio_INVALID_ENUM; + case MIX_INVALID_VALUE: + return audio_INVALID_VALUE; + case MIX_INVALID_OPERATION: + return audio_INVALID_OPERATION; + case MIX_OUT_OF_MEMORY: + return audio_OUT_OF_MEMORY; + default: + fprintf (stderr, "mixSDL_GetError: unknown value %x\n", value); + return audio_DRIVER_FAILURE; + break; + } +} + + +/* + * Sources + */ + +void +mixSDL_GenSources (uint32 n, audio_Object *psrcobj) +{ + mixer_GenSources (n, (mixer_Object *) psrcobj); +} + +void +mixSDL_DeleteSources (uint32 n, audio_Object *psrcobj) +{ + mixer_DeleteSources (n, (mixer_Object *) psrcobj); +} + +bool +mixSDL_IsSource (audio_Object srcobj) +{ + return mixer_IsSource ((mixer_Object) srcobj); +} + +void +mixSDL_Sourcei (audio_Object srcobj, audio_SourceProp pname, + audio_IntVal value) + +{ + mixer_Sourcei ((mixer_Object) srcobj, (mixer_SourceProp) pname, + (mixer_IntVal) value); +} + +void +mixSDL_Sourcef (audio_Object srcobj, audio_SourceProp pname, + float value) +{ + mixer_Sourcef ((mixer_Object) srcobj, (mixer_SourceProp) pname, value); +} + +void +mixSDL_Sourcefv (audio_Object srcobj, audio_SourceProp pname, + float *value) +{ + mixer_Sourcefv ((mixer_Object) srcobj, (mixer_SourceProp) pname, value); +} + +void +mixSDL_GetSourcei (audio_Object srcobj, audio_SourceProp pname, + audio_IntVal *value) +{ + mixer_GetSourcei ((mixer_Object) srcobj, (mixer_SourceProp) pname, + (mixer_IntVal *) value); + if (pname == MIX_SOURCE_STATE) + { + switch (*value) + { + case MIX_INITIAL: + *value = audio_INITIAL; + break; + case MIX_STOPPED: + *value = audio_STOPPED; + break; + case MIX_PLAYING: + *value = audio_PLAYING; + break; + case MIX_PAUSED: + *value = audio_PAUSED; + break; + default: + *value = audio_DRIVER_FAILURE; + } + } +} + +void +mixSDL_GetSourcef (audio_Object srcobj, audio_SourceProp pname, + float *value) +{ + mixer_GetSourcef ((mixer_Object) srcobj, (mixer_SourceProp) pname, value); +} + +void +mixSDL_SourceRewind (audio_Object srcobj) +{ + mixer_SourceRewind ((mixer_Object) srcobj); +} + +void +mixSDL_SourcePlay (audio_Object srcobj) +{ + mixer_SourcePlay ((mixer_Object) srcobj); +} + +void +mixSDL_SourcePause (audio_Object srcobj) +{ + mixer_SourcePause ((mixer_Object) srcobj); +} + +void +mixSDL_SourceStop (audio_Object srcobj) +{ + mixer_SourceStop ((mixer_Object) srcobj); +} + +void +mixSDL_SourceQueueBuffers (audio_Object srcobj, uint32 n, + audio_Object* pbufobj) +{ + mixer_SourceQueueBuffers ((mixer_Object) srcobj, n, + (mixer_Object *) pbufobj); +} + +void +mixSDL_SourceUnqueueBuffers (audio_Object srcobj, uint32 n, + audio_Object* pbufobj) +{ + mixer_SourceUnqueueBuffers ((mixer_Object) srcobj, n, + (mixer_Object *) pbufobj); +} + + +/* + * Buffers + */ + +void +mixSDL_GenBuffers (uint32 n, audio_Object *pbufobj) +{ + mixer_GenBuffers (n, (mixer_Object *) pbufobj); +} + +void +mixSDL_DeleteBuffers (uint32 n, audio_Object *pbufobj) +{ + mixer_DeleteBuffers (n, (mixer_Object *) pbufobj); +} + +bool +mixSDL_IsBuffer (audio_Object bufobj) +{ + return mixer_IsBuffer ((mixer_Object) bufobj); +} + +void +mixSDL_GetBufferi (audio_Object bufobj, audio_BufferProp pname, + audio_IntVal *value) +{ + mixer_GetBufferi ((mixer_Object) bufobj, (mixer_BufferProp) pname, + (mixer_IntVal *) value); +} + +void +mixSDL_BufferData (audio_Object bufobj, uint32 format, void* data, + uint32 size, uint32 freq) +{ + mixer_BufferData ((mixer_Object) bufobj, format, data, size, freq); +} diff --git a/sc2/src/sc2code/libs/sound/mixer/sdl/audiodrv_sdl.h b/sc2/src/sc2code/libs/sound/mixer/sdl/audiodrv_sdl.h new file mode 100644 index 000000000..2a7e3c341 --- /dev/null +++ b/sc2/src/sc2code/libs/sound/mixer/sdl/audiodrv_sdl.h @@ -0,0 +1,66 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* SDL audio driver + */ + +#ifndef _AUDIODRV_SDL_H +#define _AUDIODRV_SDL_H + +#include "config.h" +#include "libs/sound/sound.h" +#include "libs/sound/mixer/mixer.h" +#include + +/* General */ +sint32 mixSDL_Init (audio_Driver *driver, sint32 flags); +void mixSDL_Uninit (void); +sint32 mixSDL_GetError (void); + +/* Sources */ +void mixSDL_GenSources (uint32 n, audio_Object *psrcobj); +void mixSDL_DeleteSources (uint32 n, audio_Object *psrcobj); +bool mixSDL_IsSource (audio_Object srcobj); +void mixSDL_Sourcei (audio_Object srcobj, audio_SourceProp pname, + audio_IntVal value); +void mixSDL_Sourcef (audio_Object srcobj, audio_SourceProp pname, + float value); +void mixSDL_Sourcefv (audio_Object srcobj, audio_SourceProp pname, + float *value); +void mixSDL_GetSourcei (audio_Object srcobj, audio_SourceProp pname, + audio_IntVal *value); +void mixSDL_GetSourcef (audio_Object srcobj, audio_SourceProp pname, + float *value); +void mixSDL_SourceRewind (audio_Object srcobj); +void mixSDL_SourcePlay (audio_Object srcobj); +void mixSDL_SourcePause (audio_Object srcobj); +void mixSDL_SourceStop (audio_Object srcobj); +void mixSDL_SourceQueueBuffers (audio_Object srcobj, uint32 n, + audio_Object* pbufobj); +void mixSDL_SourceUnqueueBuffers (audio_Object srcobj, uint32 n, + audio_Object* pbufobj); + +/* Buffers */ +void mixSDL_GenBuffers (uint32 n, audio_Object *pbufobj); +void mixSDL_DeleteBuffers (uint32 n, audio_Object *pbufobj); +bool mixSDL_IsBuffer (audio_Object bufobj); +void mixSDL_GetBufferi (audio_Object bufobj, audio_BufferProp pname, + audio_IntVal *value); +void mixSDL_BufferData (audio_Object bufobj, uint32 format, void* data, + uint32 size, uint32 freq); + + +#endif /* _AUDIODRV_SDL_H */ diff --git a/sc2/src/sc2code/libs/sound/music.c b/sc2/src/sc2code/libs/sound/music.c index d9c05b251..634d929f9 100644 --- a/sc2/src/sc2code/libs/sound/music.c +++ b/sc2/src/sc2code/libs/sound/music.c @@ -103,7 +103,7 @@ SetMusicVolume (COUNT Volume) { float f = (Volume / (float)MAX_VOLUME) * musicVolumeScale; musicVolume = Volume; - TFBSound_Sourcef (soundSource[MUSIC_SOURCE].handle, TFBSOUND_GAIN, f); + audio_Sourcef (soundSource[MUSIC_SOURCE].handle, audio_GAIN, f); } MEM_HANDLE @@ -169,8 +169,8 @@ _GetMusicData (uio_Stream *fp, DWORD length) (*pmus)->decoder->frequency, (*pmus)->decoder->format); (*pmus)->num_buffers = 64; - (*pmus)->buffer = (TFBSound_Object *) HMalloc (sizeof (TFBSound_Object) * (*pmus)->num_buffers); - TFBSound_GenBuffers ((*pmus)->num_buffers, (*pmus)->buffer); + (*pmus)->buffer = (audio_Object *) HMalloc (sizeof (audio_Object) * (*pmus)->num_buffers); + audio_GenBuffers ((*pmus)->num_buffers, (*pmus)->buffer); } } @@ -203,7 +203,7 @@ _ReleaseMusicData (MEM_HANDLE handle) (*pmus)->decoder = NULL; SoundDecoder_Free (decoder); - TFBSound_DeleteBuffers ((*pmus)->num_buffers, (*pmus)->buffer); + audio_DeleteBuffers ((*pmus)->num_buffers, (*pmus)->buffer); HFree ((*pmus)->buffer); if ((*pmus)->buffer_tag) HFree ((*pmus)->buffer_tag); diff --git a/sc2/src/sc2code/libs/sound/openal/Makeinfo b/sc2/src/sc2code/libs/sound/openal/Makeinfo index 5c2f7cbdc..a099c70aa 100644 --- a/sc2/src/sc2code/libs/sound/openal/Makeinfo +++ b/sc2/src/sc2code/libs/sound/openal/Makeinfo @@ -1 +1 @@ -uqm_CFILES="sound_openal.c" +uqm_CFILES="audiodrv_openal.c" diff --git a/sc2/src/sc2code/libs/sound/openal/audiodrv_openal.c b/sc2/src/sc2code/libs/sound/openal/audiodrv_openal.c new file mode 100644 index 000000000..08f9ea075 --- /dev/null +++ b/sc2/src/sc2code/libs/sound/openal/audiodrv_openal.c @@ -0,0 +1,411 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* OpenAL audio driver + */ + +#ifdef HAVE_OPENAL + +#include "audiodrv_openal.h" + +ALCcontext *alcContext = NULL; +ALCdevice *alcDevice = NULL; +ALfloat listenerPos[] = {0.0f, 0.0f, 0.0f}; +ALfloat listenerVel[] = {0.0f, 0.0f, 0.0f}; +ALfloat listenerOri[] = {0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f}; +static Task StreamDecoderTask; + +static const audio_Driver openAL_Driver = +{ + openAL_Uninit, + openAL_GetError, + audio_DRIVER_OPENAL, + { + /* Errors */ + AL_FALSE, + AL_INVALID_NAME, + AL_INVALID_ENUM, + AL_INVALID_VALUE, + AL_INVALID_OPERATION, + AL_OUT_OF_MEMORY, + audio_DRIVER_FAILURE, + + /* Source properties */ + AL_POSITION, + AL_LOOPING, + AL_BUFFER, + AL_GAIN, + AL_SOURCE_STATE, + AL_BUFFERS_QUEUED, + AL_BUFFERS_PROCESSED, + + /* Source state information */ + AL_INITIAL, + AL_STOPPED, + AL_PLAYING, + AL_PAUSED, + + /* Sound buffer properties */ + AL_FREQUENCY, + AL_BITS, + AL_CHANNELS, + AL_SIZE, + AL_DATA, + AL_FORMAT_MONO16, + AL_FORMAT_STEREO16, + AL_FORMAT_MONO8, + AL_FORMAT_STEREO8 + }, + + /* Sources */ + openAL_GenSources, + openAL_DeleteSources, + openAL_IsSource, + openAL_Sourcei, + openAL_Sourcef, + openAL_Sourcefv, + openAL_GetSourcei, + openAL_GetSourcef, + openAL_SourceRewind, + openAL_SourcePlay, + openAL_SourcePause, + openAL_SourceStop, + openAL_SourceQueueBuffers, + openAL_SourceUnqueueBuffers, + + /* Buffers */ + openAL_GenBuffers, + openAL_DeleteBuffers, + openAL_IsBuffer, + openAL_GetBufferi, + openAL_BufferData +}; + + +/* + * Initialization + */ + +sint32 +openAL_Init (audio_Driver *driver, sint32 flags) +{ + int i; + TFB_DecoderFormats formats = + { + MIX_IS_BIG_ENDIAN, MIX_WANT_BIG_ENDIAN, + audio_FORMAT_MONO8, audio_FORMAT_STEREO8, + audio_FORMAT_MONO16, audio_FORMAT_STEREO16 + }; + + fprintf (stderr, "Initializing OpenAL.\n"); +#ifdef WIN32 + alcDevice = alcOpenDevice ((ALubyte*)"DirectSound3D"); +#else + alcDevice = alcOpenDevice (NULL); +#endif + + if (!alcDevice) + { + fprintf (stderr,"Couldn't initialize OpenAL: %d\n", alcGetError (NULL)); + return -1; + } + + *driver = openAL_Driver; + atexit (unInitAudio); + + alcContext = alcCreateContext (alcDevice, NULL); + if (!alcContext) + { + fprintf (stderr, "Couldn't create OpenAL context: %d\n", alcGetError (alcDevice)); + } + + alcMakeContextCurrent (alcContext); + + fprintf (stderr, "OpenAL initialized.\n"); + fprintf (stderr, " version: %s\n", alGetString (AL_VERSION)); + fprintf (stderr, " vendor: %s\n", alGetString (AL_VENDOR)); + fprintf (stderr, " renderer: %s\n", alGetString (AL_RENDERER)); + fprintf (stderr, " device: %s\n", + alcGetString (alcDevice, ALC_DEFAULT_DEVICE_SPECIFIER)); + //fprintf (stderr, " extensions: %s\n", alGetString (AL_EXTENSIONS)); + + fprintf (stderr, "Initializing sound decoders.\n"); + SoundDecoder_Init (flags, &formats); + fprintf (stderr, "Sound decoders initialized.\n"); + + alListenerfv (AL_POSITION, listenerPos); + alListenerfv (AL_VELOCITY, listenerVel); + alListenerfv (AL_ORIENTATION, listenerOri); + + for (i = 0; i < NUM_SOUNDSOURCES; ++i) + { + float zero[3] = {0.0f, 0.0f, 0.0f}; + + alGenSources (1, &soundSource[i].handle); + alSourcei (soundSource[i].handle, AL_LOOPING, AL_FALSE); + alSourcefv (soundSource[i].handle, AL_POSITION, zero); + alSourcefv (soundSource[i].handle, AL_VELOCITY, zero); + alSourcefv (soundSource[i].handle, AL_DIRECTION, zero); + + soundSource[i].sample = NULL; + soundSource[i].stream_should_be_playing = FALSE; + soundSource[i].stream_mutex = CreateMutex ("OpenAL stream mutex", SYNC_CLASS_AUDIO); + soundSource[i].sbuffer = NULL; + soundSource[i].sbuf_start = 0; + soundSource[i].sbuf_size = 0; + soundSource[i].sbuf_offset = 0; + } + + SetSFXVolume (sfxVolumeScale); + SetSpeechVolume (speechVolumeScale); + SetMusicVolume ((COUNT) musicVolume); + + if (optStereoSFX) + alDistanceModel (AL_INVERSE_DISTANCE); + else + alDistanceModel (AL_NONE); + + StreamDecoderTask = AssignTask (StreamDecoderTaskFunc, 1024, + "audio stream decoder"); + + (void) driver; // eat compiler warning + + return 0; +} + +void +openAL_Uninit (void) +{ + int i; + + if (StreamDecoderTask) + { + ConcludeTask (StreamDecoderTask); + StreamDecoderTask = NULL; + } + + for (i = 0; i < NUM_SOUNDSOURCES; ++i) + { + if (soundSource[i].sample && soundSource[i].sample->decoder) + { + StopStream (i); + } + if (soundSource[i].sbuffer) + { + void *sbuffer = soundSource[i].sbuffer; + soundSource[i].sbuffer = NULL; + HFree (sbuffer); + } + DestroyMutex (soundSource[i].stream_mutex); + } + + alcMakeContextCurrent (NULL); + alcDestroyContext (alcContext); + alcContext = NULL; + alcCloseDevice (alcDevice); + alcDevice = NULL; + + SoundDecoder_Uninit (); +} + + +/* + * General + */ + +sint32 +openAL_GetError (void) +{ + ALint value = alGetError (); + switch (value) + { + case AL_FALSE: + return audio_NO_ERROR; + case AL_INVALID_NAME: + return audio_INVALID_NAME; + case AL_INVALID_ENUM: + return audio_INVALID_ENUM; + case AL_INVALID_VALUE: + return audio_INVALID_VALUE; + case AL_INVALID_OPERATION: + return audio_INVALID_OPERATION; + case AL_OUT_OF_MEMORY: + return audio_OUT_OF_MEMORY; + default: + fprintf (stderr, "openAL_GetError: unknown value %x\n", value); + return audio_DRIVER_FAILURE; + break; + } +} + + +/* + * Sources + */ + +void +openAL_GenSources (uint32 n, audio_Object *psrcobj) +{ + alGenSources ((ALsizei) n, (ALuint *) psrcobj); +} + +void +openAL_DeleteSources (uint32 n, audio_Object *psrcobj) +{ + alDeleteSources ((ALsizei) n, (ALuint *) psrcobj); +} + +bool +openAL_IsSource (audio_Object srcobj) +{ + return alIsSource ((ALuint) srcobj); +} + +void +openAL_Sourcei (audio_Object srcobj, audio_SourceProp pname, + audio_IntVal value) + +{ + alSourcei ((ALuint) srcobj, (ALenum) pname, (ALint) value); +} + +void +openAL_Sourcef (audio_Object srcobj, audio_SourceProp pname, + float value) +{ + alSourcef ((ALuint) srcobj, (ALenum) pname, (ALfloat) value); +} + +void +openAL_Sourcefv (audio_Object srcobj, audio_SourceProp pname, + float *value) +{ + alSourcefv ((ALuint) srcobj, (ALenum) pname, (ALfloat *) value); +} + +void +openAL_GetSourcei (audio_Object srcobj, audio_SourceProp pname, + audio_IntVal *value) +{ + alGetSourcei ((ALuint) srcobj, (ALenum) pname, (ALint *) value); + if (pname == AL_SOURCE_STATE) + { + switch (*value) + { + case AL_INITIAL: + *value = audio_INITIAL; + break; + case AL_STOPPED: + *value = audio_STOPPED; + break; + case AL_PLAYING: + *value = audio_PLAYING; + break; + case AL_PAUSED: + *value = audio_PAUSED; + break; + default: + fprintf (stderr, "openAL_GetSourcei(): unknown value %x\n", + *value); + *value = audio_DRIVER_FAILURE; + } + } +} + +void +openAL_GetSourcef (audio_Object srcobj, audio_SourceProp pname, + float *value) +{ + alGetSourcef ((ALuint) srcobj, (ALenum) pname, (ALfloat *) value); +} + +void +openAL_SourceRewind (audio_Object srcobj) +{ + alSourceRewind ((ALuint) srcobj); +} + +void +openAL_SourcePlay (audio_Object srcobj) +{ + alSourcePlay ((ALuint) srcobj); +} + +void +openAL_SourcePause (audio_Object srcobj) +{ + alSourcePause ((ALuint) srcobj); +} + +void +openAL_SourceStop (audio_Object srcobj) +{ + alSourceStop ((ALuint) srcobj); +} + +void +openAL_SourceQueueBuffers (audio_Object srcobj, uint32 n, + audio_Object* pbufobj) +{ + alSourceQueueBuffers ((ALuint) srcobj, (ALsizei) n, (ALuint *) pbufobj); +} + +void +openAL_SourceUnqueueBuffers (audio_Object srcobj, uint32 n, + audio_Object* pbufobj) +{ + alSourceUnqueueBuffers ((ALuint) srcobj, (ALsizei) n, (ALuint *) pbufobj); +} + + +/* + * Buffers + */ + +void +openAL_GenBuffers (uint32 n, audio_Object *pbufobj) +{ + alGenBuffers ((ALsizei) n, (ALuint *) pbufobj); +} + +void +openAL_DeleteBuffers (uint32 n, audio_Object *pbufobj) +{ + alDeleteBuffers ((ALsizei) n, (ALuint *) pbufobj); +} + +bool +openAL_IsBuffer (audio_Object bufobj) +{ + return alIsBuffer ((ALuint) bufobj); +} + +void +openAL_GetBufferi (audio_Object bufobj, audio_BufferProp pname, + audio_IntVal *value) +{ + alGetBufferi ((ALuint) bufobj, (ALenum) pname, (ALint *) value); +} + +void +openAL_BufferData (audio_Object bufobj, uint32 format, void* data, + uint32 size, uint32 freq) +{ + alBufferData ((ALuint) bufobj, (ALenum) format, (ALvoid *) data, + (ALsizei) size, (ALsizei) freq); +} + +#endif diff --git a/sc2/src/sc2code/libs/sound/openal/audiodrv_openal.h b/sc2/src/sc2code/libs/sound/openal/audiodrv_openal.h new file mode 100644 index 000000000..4e0aa9e21 --- /dev/null +++ b/sc2/src/sc2code/libs/sound/openal/audiodrv_openal.h @@ -0,0 +1,89 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* OpenAL audio driver + */ + +#ifndef _AUDIODRV_OPENAL_H +#define _AUDIODRV_OPENAL_H + +#include "config.h" +#include "libs/sound/sound.h" +#include "options.h" + +#ifdef WIN32 +# include +# include +# ifdef _MSC_VER +# pragma comment (lib, "OpenAL32.lib") +# endif +#else +# include +# include +# define AL_INVALID_ENUM AL_ILLEGAL_ENUM +# define AL_INVALID_OPERATION AL_ILLEGAL_COMMAND +# define AL_DATA 0x2005 +#endif + +/* This is just a simple endianness setup for decoders */ +#ifdef WORDS_BIGENDIAN +# define MIX_IS_BIG_ENDIAN true +# define MIX_WANT_BIG_ENDIAN false +#else +# define MIX_IS_BIG_ENDIAN false +# define MIX_WANT_BIG_ENDIAN false +#endif + + +/* General */ +sint32 openAL_Init (audio_Driver *driver, sint32 flags); +void openAL_Uninit (void); +sint32 openAL_GetError (void); + +/* Sources */ +void openAL_GenSources (uint32 n, audio_Object *psrcobj); +void openAL_DeleteSources (uint32 n, audio_Object *psrcobj); +bool openAL_IsSource (audio_Object srcobj); +void openAL_Sourcei (audio_Object srcobj, audio_SourceProp pname, + audio_IntVal value); +void openAL_Sourcef (audio_Object srcobj, audio_SourceProp pname, + float value); +void openAL_Sourcefv (audio_Object srcobj, audio_SourceProp pname, + float *value); +void openAL_GetSourcei (audio_Object srcobj, audio_SourceProp pname, + audio_IntVal *value); +void openAL_GetSourcef (audio_Object srcobj, audio_SourceProp pname, + float *value); +void openAL_SourceRewind (audio_Object srcobj); +void openAL_SourcePlay (audio_Object srcobj); +void openAL_SourcePause (audio_Object srcobj); +void openAL_SourceStop (audio_Object srcobj); +void openAL_SourceQueueBuffers (audio_Object srcobj, uint32 n, + audio_Object* pbufobj); +void openAL_SourceUnqueueBuffers (audio_Object srcobj, uint32 n, + audio_Object* pbufobj); + +/* Buffers */ +void openAL_GenBuffers (uint32 n, audio_Object *pbufobj); +void openAL_DeleteBuffers (uint32 n, audio_Object *pbufobj); +bool openAL_IsBuffer (audio_Object bufobj); +void openAL_GetBufferi (audio_Object bufobj, audio_BufferProp pname, + audio_IntVal *value); +void openAL_BufferData (audio_Object bufobj, uint32 format, void* data, + uint32 size, uint32 freq); + + +#endif /* _AUDIODRV_OPENAL_H */ diff --git a/sc2/src/sc2code/libs/sound/sfx.c b/sc2/src/sc2code/libs/sound/sfx.c index c630e2f67..8d54868fa 100644 --- a/sc2/src/sc2code/libs/sound/sfx.c +++ b/sc2/src/sc2code/libs/sound/sfx.c @@ -42,9 +42,9 @@ PlayChannel (COUNT channel, PVOID sample, SoundPosition pos, if (optStereoSFX) UpdateSoundPosition (channel, pos); - TFBSound_Sourcei (soundSource[channel].handle, TFBSOUND_BUFFER, + audio_Sourcei (soundSource[channel].handle, audio_BUFFER, tfb_sample->buffer[0]); - TFBSound_SourcePlay (soundSource[channel].handle); + audio_SourcePlay (soundSource[channel].handle); (void) priority; } @@ -62,15 +62,15 @@ CheckFinishedChannels (void) for (i = FIRST_SFX_SOURCE; i <= LAST_SFX_SOURCE; ++i) { - TFBSound_IntVal state; + audio_IntVal state; - TFBSound_GetSourcei (soundSource[i].handle, TFBSOUND_SOURCE_STATE, + audio_GetSourcei (soundSource[i].handle, audio_SOURCE_STATE, &state); - if (state == TFBSOUND_STOPPED) + if (state == audio_STOPPED) { CleanSource (i); // and if it failed... we still dont care - TFBSound_GetError(); + audio_GetError(); } } } @@ -78,11 +78,11 @@ CheckFinishedChannels (void) BOOLEAN ChannelPlaying (COUNT WhichChannel) { - TFBSound_IntVal state; + audio_IntVal state; - TFBSound_GetSourcei (soundSource[WhichChannel].handle, - TFBSOUND_SOURCE_STATE, &state); - if (state == TFBSOUND_PLAYING) + audio_GetSourcei (soundSource[WhichChannel].handle, + audio_SOURCE_STATE, &state); + if (state == audio_PLAYING) return TRUE; return FALSE; } @@ -110,14 +110,14 @@ UpdateSoundPosition (COUNT channel, SoundPosition pos) fpos[0] = pos.x / ATTENUATION; fpos[1] = 0.0f; fpos[2] = pos.y / ATTENUATION; - TFBSound_Sourcefv (soundSource[channel].handle, TFBSOUND_POSITION, fpos); + audio_Sourcefv (soundSource[channel].handle, audio_POSITION, fpos); //fprintf (stderr, "UpdateSoundPosition(): channel %d, pos %d %d, posobj %x\n", // channel, pos.x, pos.y, (unsigned int)soundSource[channel].positional_object); } else { fpos[0] = fpos[1] = fpos[2] = 0.0f; - TFBSound_Sourcefv (soundSource[channel].handle, TFBSOUND_POSITION, fpos); + audio_Sourcefv (soundSource[channel].handle, audio_POSITION, fpos); } } @@ -126,7 +126,7 @@ SetChannelVolume (COUNT channel, COUNT volume, BYTE priority) // I wonder what this whole priority business is... // I can probably ignore it. { - TFBSound_Sourcef (soundSource[channel].handle, TFBSOUND_GAIN, + audio_Sourcef (soundSource[channel].handle, audio_GAIN, (volume / (float)MAX_VOLUME) * sfxVolumeScale); (void)priority; // ignored } @@ -219,10 +219,10 @@ _GetSoundBankData (uio_Stream *fp, DWORD length) //fprintf (stderr, "_GetSoundBankData(): decoded_bytes %d\n", decoded_bytes); sndfx[snd_ct]->num_buffers = 1; - sndfx[snd_ct]->buffer = (TFBSound_Object *) HMalloc ( - sizeof (TFBSound_Object) * sndfx[snd_ct]->num_buffers); - TFBSound_GenBuffers (sndfx[snd_ct]->num_buffers, sndfx[snd_ct]->buffer); - TFBSound_BufferData (sndfx[snd_ct]->buffer[0], sndfx[snd_ct]->decoder->format, + sndfx[snd_ct]->buffer = (audio_Object *) HMalloc ( + sizeof (audio_Object) * sndfx[snd_ct]->num_buffers); + audio_GenBuffers (sndfx[snd_ct]->num_buffers, sndfx[snd_ct]->buffer); + audio_BufferData (sndfx[snd_ct]->buffer[0], sndfx[snd_ct]->decoder->format, sndfx[snd_ct]->decoder->buffer, decoded_bytes, sndfx[snd_ct]->decoder->frequency); @@ -313,7 +313,7 @@ _ReleaseSoundBankData (MEM_HANDLE Snd) if ((*sptr)->decoder) SoundDecoder_Free ((*sptr)->decoder); - TFBSound_DeleteBuffers ((*sptr)->num_buffers, (*sptr)->buffer); + audio_DeleteBuffers ((*sptr)->num_buffers, (*sptr)->buffer); HFree ((*sptr)->buffer); if ((*sptr)->buffer_tag) HFree ((*sptr)->buffer_tag); diff --git a/sc2/src/sc2code/libs/sound/sound.c b/sc2/src/sc2code/libs/sound/sound.c index d615c7f18..bdb25c4f1 100644 --- a/sc2/src/sc2code/libs/sound/sound.c +++ b/sc2/src/sc2code/libs/sound/sound.c @@ -16,9 +16,16 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "libs/sound/sound_common.h" #include "sound.h" +static Task FadeTask; +static SIZE TTotal; +static SIZE volume_end; + +int musicVolume = (MAX_VOLUME >> 1); +float musicVolumeScale = 1.0f; +float sfxVolumeScale = 1.0f; +float speechVolumeScale = 1.0f; TFB_SoundSource soundSource[NUM_SOUNDSOURCES]; @@ -37,36 +44,36 @@ void CleanSource (int iSource) { #define MAX_STACK_BUFFERS 64 - TFBSound_IntVal processed; + audio_IntVal processed; soundSource[iSource].positional_object = NULL; - TFBSound_GetSourcei (soundSource[iSource].handle, - TFBSOUND_BUFFERS_PROCESSED, &processed); + audio_GetSourcei (soundSource[iSource].handle, + audio_BUFFERS_PROCESSED, &processed); if (processed != 0) { - TFBSound_Object stack_bufs[MAX_STACK_BUFFERS]; - TFBSound_Object *bufs; + audio_Object stack_bufs[MAX_STACK_BUFFERS]; + audio_Object *bufs; if (processed > MAX_STACK_BUFFERS) - bufs = (TFBSound_Object *) HMalloc ( - sizeof (TFBSound_Object) * processed); + bufs = (audio_Object *) HMalloc ( + sizeof (audio_Object) * processed); else bufs = stack_bufs; - TFBSound_SourceUnqueueBuffers (soundSource[iSource].handle, + audio_SourceUnqueueBuffers (soundSource[iSource].handle, processed, bufs); if (processed > MAX_STACK_BUFFERS) HFree (bufs); } // set the source state to 'initial' - TFBSound_SourceRewind (soundSource[iSource].handle); + audio_SourceRewind (soundSource[iSource].handle); } void StopSource (int iSource) { - TFBSound_SourceStop (soundSource[iSource].handle); + audio_SourceStop (soundSource[iSource].handle); CleanSource (iSource); } @@ -90,9 +97,9 @@ SoundPlaying (void) } else { - TFBSound_IntVal state; - TFBSound_GetSourcei (soundSource[i].handle, TFBSOUND_SOURCE_STATE, &state); - if (state == TFBSOUND_PLAYING) + audio_IntVal state; + audio_GetSourcei (soundSource[i].handle, audio_SOURCE_STATE, &state); + if (state == audio_PLAYING) return TRUE; } } @@ -134,12 +141,69 @@ void SetSFXVolume (float volume) int i; for (i = FIRST_SFX_SOURCE; i <= LAST_SFX_SOURCE; ++i) { - TFBSound_Sourcef (soundSource[i].handle, TFBSOUND_GAIN, volume); + audio_Sourcef (soundSource[i].handle, audio_GAIN, volume); } } void SetSpeechVolume (float volume) { - TFBSound_Sourcef (soundSource[SPEECH_SOURCE].handle, TFBSOUND_GAIN, volume); + audio_Sourcef (soundSource[SPEECH_SOURCE].handle, audio_GAIN, volume); } +static int +fade_task (void *data) +{ + SIZE TDelta, volume_beg; + DWORD StartTime, CurTime; + Task task = (Task) data; + + volume_beg = musicVolume; + StartTime = CurTime = GetTimeCounter (); + do + { + SleepThreadUntil (CurTime + ONE_SECOND / 120); + CurTime = GetTimeCounter (); + if ((TDelta = (SIZE) (CurTime - StartTime)) > TTotal) + TDelta = TTotal; + + SetMusicVolume ((COUNT) (volume_beg + (SIZE) + ((long) (volume_end - volume_beg) * TDelta / TTotal))); + } while (TDelta < TTotal); + + FadeTask = 0; + FinishTask (task); + return (1); +} + +DWORD +FadeMusic (BYTE end_vol, SIZE TimeInterval) +{ + DWORD TimeOut; + + if (FadeTask) + { + volume_end = musicVolume; + TTotal = 1; + do + TaskSwitch (); + while (FadeTask); + TaskSwitch (); + } + + if ((TTotal = TimeInterval) <= 0) + TTotal = 1; /* prevent divide by zero and negative fade */ + volume_end = end_vol; + + if (TTotal > 1 && (FadeTask = AssignTask (fade_task, 0, + "fade music"))) + { + TimeOut = GetTimeCounter () + TTotal + 1; + } + else + { + SetMusicVolume (end_vol); + TimeOut = GetTimeCounter (); + } + + return (TimeOut); +} diff --git a/sc2/src/sc2code/libs/sound/sound.h b/sc2/src/sc2code/libs/sound/sound.h index 52c00ab62..ec4f053bb 100644 --- a/sc2/src/sc2code/libs/sound/sound.h +++ b/sc2/src/sc2code/libs/sound/sound.h @@ -20,13 +20,8 @@ #include "starcon.h" #include "misc.h" #include "libs/strings/strintrn.h" -#include "libs/sound/sndintrn.h" -#include "libs/sound/sound_common.h" -#ifdef HAVE_OPENAL -#include "libs/sound/sound_chooser.h" -#else -#include "mixsdl/sound_mixsdl.h" -#endif +#include "sndintrn.h" +#include "audiocore.h" #include "decoders/decoder.h" #define FIRST_SFX_SOURCE 0 @@ -39,7 +34,7 @@ typedef struct { int in_use; - TFBSound_Object buf_name; + audio_Object buf_name; void *data; // user-defined data } TFB_SoundTag; @@ -51,13 +46,13 @@ typedef struct tfb_soundcallbacks // return TRUE to continue, FALSE to abort bool (* OnStartStream) (TFB_SoundSample*); // return TRUE to continue, FALSE to abort - bool (* OnEndChunk) (TFB_SoundSample*, TFBSound_Object); + bool (* OnEndChunk) (TFB_SoundSample*, audio_Object); // return TRUE to continue, FALSE to abort void (* OnEndStream) (TFB_SoundSample*); // tagged buffer callback void (* OnTaggedBuffer) (TFB_SoundSample*, TFB_SoundTag*); // buffer just queued - void (* OnQueueBuffer) (TFB_SoundSample*, TFBSound_Object); + void (* OnQueueBuffer) (TFB_SoundSample*, audio_Object); } TFB_SoundCallbacks; // audio data @@ -65,7 +60,7 @@ struct tfb_soundsample { TFB_SoundDecoder *decoder; // decoder to read from float length; // total length of decoder chain in seconds - TFBSound_Object *buffer; + audio_Object *buffer; uint32 num_buffers; TFB_SoundTag *buffer_tag; sint32 offset; // initial offset @@ -77,7 +72,7 @@ struct tfb_soundsample typedef struct tfb_soundsource { TFB_SoundSample *sample; - TFBSound_Object handle; + audio_Object handle; bool stream_should_be_playing; Mutex stream_mutex; sint32 start_time; @@ -96,6 +91,11 @@ typedef struct tfb_soundsource extern TFB_SoundSource soundSource[]; +extern int musicVolume; +extern float musicVolumeScale; +extern float sfxVolumeScale; +extern float speechVolumeScale; + void StopSource (int iSource); void CleanSource (int iSource); diff --git a/sc2/src/sc2code/libs/sound/stream.c b/sc2/src/sc2code/libs/sound/stream.c index db81dec71..538de6fdc 100644 --- a/sc2/src/sc2code/libs/sound/stream.c +++ b/sc2/src/sc2code/libs/sound/stream.c @@ -42,7 +42,7 @@ PlayStream (TFB_SoundSample *sample, uint32 source, bool looping, bool scope, bo offset += (sint32)(SoundDecoder_GetTime (sample->decoder) * (float)ONE_SECOND); soundSource[source].sample = sample; soundSource[source].sample->decoder->looping = looping; - TFBSound_Sourcei (soundSource[source].handle, TFBSOUND_LOOPING, false); + audio_Sourcei (soundSource[source].handle, audio_LOOPING, false); if (scope) { @@ -60,9 +60,9 @@ PlayStream (TFB_SoundSample *sample, uint32 source, bool looping, bool scope, bo if (decoded_bytes == 0) break; - TFBSound_BufferData (sample->buffer[i], sample->decoder->format, sample->decoder->buffer, + audio_BufferData (sample->buffer[i], sample->decoder->format, sample->decoder->buffer, decoded_bytes, sample->decoder->frequency); - TFBSound_SourceQueueBuffers (soundSource[source].handle, 1, &sample->buffer[i]); + audio_SourceQueueBuffers (soundSource[source].handle, 1, &sample->buffer[i]); if (sample->callbacks.OnQueueBuffer) sample->callbacks.OnQueueBuffer (sample, sample->buffer[i]); @@ -90,7 +90,7 @@ PlayStream (TFB_SoundSample *sample, uint32 source, bool looping, bool scope, bo soundSource[source].sbuf_lasttime = GetTimeCounter (); soundSource[source].start_time = (sint32)GetTimeCounter () - offset; soundSource[source].stream_should_be_playing = TRUE; - TFBSound_SourcePlay (soundSource[source].handle); + audio_SourcePlay (soundSource[source].handle); } void @@ -116,14 +116,14 @@ void PauseStream (uint32 source) { soundSource[source].stream_should_be_playing = FALSE; - TFBSound_SourcePause (soundSource[source].handle); + audio_SourcePause (soundSource[source].handle); } void ResumeStream (uint32 source) { soundSource[source].stream_should_be_playing = TRUE; - TFBSound_SourcePlay (soundSource[source].handle); + audio_SourcePlay (soundSource[source].handle); } void @@ -150,7 +150,7 @@ PlayingStream (uint32 source) } TFB_SoundTag* -TFB_FindTaggedBuffer (TFB_SoundSample* sample, TFBSound_Object buffer) +TFB_FindTaggedBuffer (TFB_SoundSample* sample, audio_Object buffer) { uint32 buf_num; @@ -167,7 +167,7 @@ TFB_FindTaggedBuffer (TFB_SoundSample* sample, TFBSound_Object buffer) } void -TFB_TagBuffer (TFB_SoundSample* sample, TFBSound_Object buffer, void* data) +TFB_TagBuffer (TFB_SoundSample* sample, audio_Object buffer, void* data) { uint32 buf_num; @@ -198,7 +198,7 @@ StreamDecoderTaskFunc (void *data) { Task task = (Task)data; int i; - TFBSound_Object last_buffer[NUM_SOUNDSOURCES]; + audio_Object last_buffer[NUM_SOUNDSOURCES]; for (i = 0; i < NUM_SOUNDSOURCES; i++) last_buffer[i] = 0; @@ -210,8 +210,8 @@ StreamDecoderTaskFunc (void *data) for (i = MUSIC_SOURCE; i < NUM_SOUNDSOURCES; ++i) { - TFBSound_IntVal processed, queued; - TFBSound_IntVal state; + audio_IntVal processed, queued; + audio_IntVal state; LockMutex (soundSource[i].stream_mutex); @@ -224,13 +224,13 @@ StreamDecoderTaskFunc (void *data) continue; } - TFBSound_GetSourcei (soundSource[i].handle, TFBSOUND_BUFFERS_PROCESSED, &processed); - TFBSound_GetSourcei (soundSource[i].handle, TFBSOUND_BUFFERS_QUEUED, &queued); + audio_GetSourcei (soundSource[i].handle, audio_BUFFERS_PROCESSED, &processed); + audio_GetSourcei (soundSource[i].handle, audio_BUFFERS_QUEUED, &queued); if (processed == 0) { - TFBSound_GetSourcei (soundSource[i].handle, TFBSOUND_SOURCE_STATE, &state); - if (state != TFBSOUND_PLAYING) + audio_GetSourcei (soundSource[i].handle, audio_SOURCE_STATE, &state); + if (state != audio_PLAYING) { if (queued == 0 && soundSource[i].sample->decoder->error == SOUNDDECODER_EOF) { @@ -243,7 +243,7 @@ StreamDecoderTaskFunc (void *data) { fprintf (stderr, "StreamDecoderTaskFunc(): buffer underrun when playing %s, source %d\n", soundSource[i].sample->decoder->filename, i); - TFBSound_SourcePlay (soundSource[i].handle); + audio_SourcePlay (soundSource[i].handle); } } } @@ -253,14 +253,14 @@ StreamDecoderTaskFunc (void *data) while (processed) { uint32 error; - TFBSound_Object buffer; + audio_Object buffer; uint32 decoded_bytes; - TFBSound_GetError (); // clear error state + audio_GetError (); // clear error state - TFBSound_SourceUnqueueBuffers (soundSource[i].handle, 1, &buffer); + audio_SourceUnqueueBuffers (soundSource[i].handle, 1, &buffer); - if ((error = TFBSound_GetError()) != TFBSOUND_NO_ERROR) + if ((error = audio_GetError()) != audio_NO_ERROR) { fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alSourceUnqueueBuffers: %x, file %s, source %d\n", error, soundSource[i].sample->decoder->filename, i); break; @@ -276,9 +276,9 @@ StreamDecoderTaskFunc (void *data) } } { - TFBSound_IntVal buf_size; + audio_IntVal buf_size; soundSource[i].sbuf_lasttime = GetTimeCounter (); - TFBSound_GetBufferi(buffer, TFBSOUND_SIZE, &buf_size); + audio_GetBufferi(buffer, audio_SIZE, &buf_size); soundSource[i].sbuf_offset += buf_size; if (soundSource[i].sbuf_offset > soundSource[i].sbuf_size) soundSource[i].sbuf_offset -= soundSource[i].sbuf_size; @@ -317,38 +317,19 @@ StreamDecoderTaskFunc (void *data) if (decoded_bytes > 0) { -#if defined HAVE_OPENAL && !defined (WIN32) // && !defined (MacOS and BeOS too) - // *nix OpenAL implementation has to handle stereo data differently to avoid mixing it to mono - if (SoundDriver == TFB_SOUNDDRIVER_OPENAL && - (soundSource[i].sample->decoder->format == TFBSOUND_FORMAT_STEREO8 || - soundSource[i].sample->decoder->format == TFBSOUND_FORMAT_STEREO16)) - { - TFBSound_BufferData_Linux (buffer, soundSource[i].sample->decoder->format, - soundSource[i].sample->decoder->buffer, decoded_bytes, - soundSource[i].sample->decoder->frequency, - soundSource[i].sample->decoder->format); - } - else - { - TFBSound_BufferData (buffer, soundSource[i].sample->decoder->format, - soundSource[i].sample->decoder->buffer, decoded_bytes, - soundSource[i].sample->decoder->frequency); - } -#else - TFBSound_BufferData (buffer, soundSource[i].sample->decoder->format, + audio_BufferData (buffer, soundSource[i].sample->decoder->format, soundSource[i].sample->decoder->buffer, decoded_bytes, soundSource[i].sample->decoder->frequency); -#endif - if ((error = TFBSound_GetError()) != TFBSOUND_NO_ERROR) + if ((error = audio_GetError()) != audio_NO_ERROR) { - fprintf (stderr, "StreamDecoderTaskFunc(): TFBSound error after TFBSound_BufferData: %x, file %s, source %d, decoded_bytes %d\n", + fprintf (stderr, "StreamDecoderTaskFunc(): TFBSound error after audio_BufferData: %x, file %s, source %d, decoded_bytes %d\n", error, soundSource[i].sample->decoder->filename, i, decoded_bytes); } else { last_buffer[i] = buffer; - TFBSound_SourceQueueBuffers (soundSource[i].handle, 1, &buffer); + audio_SourceQueueBuffers (soundSource[i].handle, 1, &buffer); // do OnQueue callback if (soundSource[i].sample->callbacks.OnQueueBuffer) soundSource[i].sample->callbacks.OnQueueBuffer ( @@ -390,9 +371,9 @@ StreamDecoderTaskFunc (void *data) } } - if ((error = TFBSound_GetError()) != TFBSOUND_NO_ERROR) + if ((error = audio_GetError()) != audio_NO_ERROR) { - fprintf (stderr, "StreamDecoderTaskFunc(): TFBSound error after TFBSound_SourceQueueBuffers: %x, file %s, source %d, decoded_bytes %d\n", + fprintf (stderr, "StreamDecoderTaskFunc(): TFBSound error after audio_SourceQueueBuffers: %x, file %s, source %d, decoded_bytes %d\n", error, soundSource[i].sample->decoder->filename, i, decoded_bytes); } } diff --git a/sc2/src/sc2code/libs/sound/stream.h b/sc2/src/sc2code/libs/sound/stream.h index a60e8d549..1bac490ae 100644 --- a/sc2/src/sc2code/libs/sound/stream.h +++ b/sc2/src/sc2code/libs/sound/stream.h @@ -25,14 +25,9 @@ void ResumeStream (uint32 source); void SeekStream (uint32 source, uint32 pos); BOOLEAN PlayingStream (uint32 source); int StreamDecoderTaskFunc (void *data); -int PreDecodeClips (TFB_SoundSample *sample, TFB_SoundDecoder *decoders[], bool autofree); -void PlayDecodedClip (TFB_SoundSample *sample, uint32 source, bool scope); -TFB_SoundTag* FindTaggedBuffer (TFB_SoundSample* sample, TFBSound_Object buffer); +TFB_SoundTag* FindTaggedBuffer (TFB_SoundSample* sample, audio_Object buffer); void TFB_ClearBufferTag (TFB_SoundTag* ptag); -void TFB_TagBuffer (TFB_SoundSample* sample, TFBSound_Object buffer, void* data); - -extern bool speech_advancetrack; -void advance_track (int channel_finished); +void TFB_TagBuffer (TFB_SoundSample* sample, audio_Object buffer, void* data); #endif diff --git a/sc2/src/sc2code/libs/sound/trackplayer.c b/sc2/src/sc2code/libs/sound/trackplayer.c index a0335e6ee..b1a6f741c 100644 --- a/sc2/src/sc2code/libs/sound/trackplayer.c +++ b/sc2/src/sc2code/libs/sound/trackplayer.c @@ -42,7 +42,7 @@ bool is_sample_playing(TFB_SoundSample* samp); // stream callbacks static bool OnTrackStart (TFB_SoundSample* sample); -static bool OnChunkEnd (TFB_SoundSample* sample, TFBSound_Object buffer); +static bool OnChunkEnd (TFB_SoundSample* sample, audio_Object buffer); static void OnTrackEnd (TFB_SoundSample* sample); static void OnTrackTag (TFB_SoundSample* sample, TFB_SoundTag* tag); @@ -123,13 +123,13 @@ ResumeTrack () if (scd->read_chain_ptr || sound_sample->decoder) { // Only try to start the track if there is something to play - TFBSound_IntVal state; + audio_IntVal state; BOOLEAN playing; LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); - TFBSound_GetSourcei (soundSource[SPEECH_SOURCE].handle, TFBSOUND_SOURCE_STATE, &state); + audio_GetSourcei (soundSource[SPEECH_SOURCE].handle, audio_SOURCE_STATE, &state); playing = PlayingStream (SPEECH_SOURCE); - if (!track_pos_changed && !playing && state == TFBSOUND_PAUSED) + if (!track_pos_changed && !playing && state == audio_PAUSED) { /*adjust start time so the slider doesn't go crazy*/ soundSource[SPEECH_SOURCE].start_time += GetTimeCounter () - soundSource[SPEECH_SOURCE].pause_time; @@ -198,7 +198,7 @@ StopTrack () if (sound_sample) { DestroyMutex (track_mutex); - TFBSound_DeleteBuffers (sound_sample->num_buffers, sound_sample->buffer); + audio_DeleteBuffers (sound_sample->num_buffers, sound_sample->buffer); HFree (sound_sample->buffer); HFree (sound_sample->buffer_tag); HFree (sound_sample->data); @@ -254,7 +254,7 @@ OnTrackStart (TFB_SoundSample* sample) } static bool -OnChunkEnd (TFB_SoundSample* sample, TFBSound_Object buffer) +OnChunkEnd (TFB_SoundSample* sample, audio_Object buffer) { TFB_SoundChainData* scd = (TFB_SoundChainData*) sample->data; @@ -591,7 +591,7 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, TFB_Tra sound_sample->num_buffers = 8; sound_sample->buffer_tag = HCalloc (sizeof (TFB_SoundTag) * sound_sample->num_buffers); sound_sample->buffer = HMalloc (sizeof (uint32) * sound_sample->num_buffers); - TFBSound_GenBuffers (sound_sample->num_buffers, sound_sample->buffer); + audio_GenBuffers (sound_sample->num_buffers, sound_sample->buffer); decoder = SoundDecoder_Load (contentDir, TrackName, 4096, startTime, time_stamps[page_counter]); scd->read_chain_ptr = create_soundchain (decoder, 0.0); @@ -652,7 +652,7 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, TFB_Tra else { fprintf (stderr, "SpliceTrack(): couldn't load %s\n", TrackName); - TFBSound_DeleteBuffers (sound_sample->num_buffers, sound_sample->buffer); + audio_DeleteBuffers (sound_sample->num_buffers, sound_sample->buffer); destroy_soundchain (first_chain); first_chain = NULL; HFree (sound_sample->buffer); @@ -839,7 +839,7 @@ GetSoundData (void *data) UBYTE *sbuffer = soundSource[SPEECH_SOURCE].sbuffer; assert (soundSource[SPEECH_SOURCE].sample->decoder->frequency == 11025); - assert (soundSource[SPEECH_SOURCE].sample->decoder->format == TFBSOUND_FORMAT_MONO16); + assert (soundSource[SPEECH_SOURCE].sample->decoder->format == audio_FORMAT_MONO16); if (delta < 0) { @@ -908,7 +908,7 @@ GetSoundData (void *data) UBYTE *sbuffer = soundSource[MUSIC_SOURCE].sbuffer; assert (soundSource[MUSIC_SOURCE].sample->decoder->frequency >= 11025); - assert (soundSource[MUSIC_SOURCE].sample->decoder->format == TFBSOUND_FORMAT_STEREO16); + assert (soundSource[MUSIC_SOURCE].sample->decoder->format == audio_FORMAT_STEREO16); step = soundSource[MUSIC_SOURCE].sample->decoder->frequency / 11025 * 16; if (step % 2 == 1) diff --git a/sc2/src/sc2code/libs/video/vidplayer.c b/sc2/src/sc2code/libs/video/vidplayer.c index ff97ffcb7..ba1a6f398 100644 --- a/sc2/src/sc2code/libs/video/vidplayer.c +++ b/sc2/src/sc2code/libs/video/vidplayer.c @@ -34,7 +34,7 @@ TFB_VideoCallbacks vp_DecoderCBs = static bool vp_AudioStart (TFB_SoundSample* sample); static void vp_AudioEnd (TFB_SoundSample* sample); static void vp_BufferTag (TFB_SoundSample* sample, TFB_SoundTag* tag); -static void vp_QueueBuffer (TFB_SoundSample* sample, TFBSound_Object buffer); +static void vp_QueueBuffer (TFB_SoundSample* sample, audio_Object buffer); static TFB_SoundCallbacks vp_AudioCBs = { @@ -515,7 +515,7 @@ vp_BufferTag (TFB_SoundSample* sample, TFB_SoundTag* tag) } static void -vp_QueueBuffer (TFB_SoundSample* sample, TFBSound_Object buffer) +vp_QueueBuffer (TFB_SoundSample* sample, audio_Object buffer) { //TFB_VideoClip* vid = sample->data; diff --git a/sc2/src/starcon2.c b/sc2/src/starcon2.c index 02b807093..74c46123b 100644 --- a/sc2/src/starcon2.c +++ b/sc2/src/starcon2.c @@ -30,7 +30,7 @@ #endif #include "libs/graphics/gfx_common.h" -#include "libs/sound/sound_common.h" +#include "libs/sound/sound.h" #include "libs/input/input_common.h" #include "libs/tasklib.h" #include "file.h" @@ -39,7 +39,7 @@ #include "uqmversion.h" #include "comm.h" -#if defined(GFXMODULE_SDL) || defined(SOUNDMODULE_SDL) +#if defined(GFXMODULE_SDL) # include // Including this is actually necessary on OSX. #endif @@ -66,9 +66,9 @@ int main (int argc, char *argv[]) { int gfxdriver = TFB_GFXDRIVER_SDL_PURE; - int snddriver = TFB_SOUNDDRIVER_MIXSDL; + int snddriver = audio_DRIVER_MIXSDL; int gfxflags = 0; - int soundflags = TFB_SOUNDFLAGS_MQAUDIO; + int soundflags = audio_QUALITY_MEDIUM; int width = 640, height = 480, bpp = 16; int vol; int val; @@ -218,18 +218,18 @@ main (int argc, char *argv[]) case 'q': if (!strcmp (optarg, "high")) { - soundflags &= ~(TFB_SOUNDFLAGS_MQAUDIO|TFB_SOUNDFLAGS_LQAUDIO); - soundflags |= TFB_SOUNDFLAGS_HQAUDIO; + soundflags &= ~(audio_QUALITY_MEDIUM|audio_QUALITY_LOW); + soundflags |= audio_QUALITY_HIGH; } else if (!strcmp (optarg, "medium")) { - soundflags &= ~(TFB_SOUNDFLAGS_HQAUDIO|TFB_SOUNDFLAGS_LQAUDIO); - soundflags |= TFB_SOUNDFLAGS_MQAUDIO; + soundflags &= ~(audio_QUALITY_HIGH|audio_QUALITY_LOW); + soundflags |= audio_QUALITY_MEDIUM; } else if (!strcmp (optarg, "low")) { - soundflags &= ~(TFB_SOUNDFLAGS_HQAUDIO|TFB_SOUNDFLAGS_MQAUDIO); - soundflags |= TFB_SOUNDFLAGS_LQAUDIO; + soundflags &= ~(audio_QUALITY_HIGH|audio_QUALITY_MEDIUM); + soundflags |= audio_QUALITY_LOW; } break; case 'u': @@ -272,15 +272,15 @@ main (int argc, char *argv[]) case SOUND_OPT: if (!strcmp (optarg, "openal")) { - snddriver = TFB_SOUNDDRIVER_OPENAL; + snddriver = audio_DRIVER_OPENAL; } else if (!strcmp (optarg, "none")) { - snddriver = TFB_SOUNDDRIVER_NOSOUND; + snddriver = audio_DRIVER_NOSOUND; } else if (!strcmp (optarg, "mixsdl")) { - snddriver = TFB_SOUNDDRIVER_MIXSDL; + snddriver = audio_DRIVER_MIXSDL; } break; case STEREOSFX_OPT: @@ -357,7 +357,7 @@ main (int argc, char *argv[]) init_communication (); if (gammaset) TFB_SetGamma (gamma); - TFB_InitSound (snddriver, soundflags); + initAudio (snddriver, soundflags); TFB_InitInput (TFB_INPUTDRIVER_SDL, 0); AssignTask (Starcon2Main, 1024, "Starcon2Main");