diff --git a/sc2/INSTALL b/sc2/INSTALL index 15db6e8a8..c23a3ab63 100644 --- a/sc2/INSTALL +++ b/sc2/INSTALL @@ -33,15 +33,19 @@ SDL-image Homepage: http://www.libsdl.org/projects/SDL_image/ Download: http://www.libsdl.org/projects/SDL_image/release/ -SDL-mixer - A sound mixing library used with SDL. - Homepage: http://www.libsdl.org/projects/SDL_mixer/ - Download: http://www.libsdl.org/projects/SDL_mixer/release/ - SDL-sound - A sound loader library used with SDL. + An audio format decoder library. Homepage: http://www.icculus.org/SDL_sound/ Download: http://www.icculus.org/SDL_sound/downloads/ + Win32 users maybe need to get few updated dll's from: http://www.cc.jyu.fi/~mimakole/sc2/sdl_sound_dlls.zip + If compiling this yourself, be sure ogg vorbis and libmikmod (or libmodplug) support is compiled in. + +OpenAL + A cross-platform spatialized audio library. + Homepage: http://www.openal.org + Linux download via CVS: http://opensource.creative.com + Win32 SDK download: http://ftp://opensource.creative.com/pub/sdk/OpenALSDK.exe + If you find these aren't enough, or if you know the names of the corresponding RPM etc. packages, please report to diff --git a/sc2/TODO b/sc2/TODO index 6f3f8d671..0bcc2b0b5 100644 --- a/sc2/TODO +++ b/sc2/TODO @@ -67,6 +67,25 @@ Glitches (don't crash the game, medium priority): crash anymore. This means the memory will not be freed until after the complete battle (not just one fight). There's no permanent memory leak though. +- OpenAL sound code problems: + - On Linux, volume control (AL_GAIN) doesn't work for streams. + This prevents also music fade in/out from working. + Most probably this is a Linux OpenAL implementation bug itself, and + authors have been informed. + - Occasional clipping/popping/etc artifacts + - Maybe caused by buggy soundcard drivers also + - Some unimplemented functions (for oscilloscope and dialogue seeking) + - Occasionally some speech oggs don't play + - When mod music is looping, there's some volume fade at the end of tune, + then it starts playing again. Should this happen? (modplug only?) + - Stock SDL_sound package for VC is outdated and win32 users have to get + few new .dll's to ensure proper operation + - Perhaps we should integrate mikmod to our code and use vorbis libs + directly to avoid depending on SDL_sound at all? + - If OpenAL causes too many problems, reverting to SDL_mixer is easy as + all code is preserved related to that, etc.. but SDL_mixer is pretty + sucky for various reasons so I'd like to avoid that. + Implementation bugs (low priority): - The main thread is still created by a direct all to the SDL function, @@ -137,7 +156,3 @@ Questions: which we can free when no more memory is available, to allow an emergency save. - How about an ISO image for a self-contained linux CD which boots into SC2? -- SDL_mixer really doesn't seem to meet our needs.. should we - a) write our own mixing routines - b) look for alternatives (OpenAL perhaps?) - c) what? diff --git a/sc2/configure.ac b/sc2/configure.ac index 8053f0dea..e1f2f2c5e 100644 --- a/sc2/configure.ac +++ b/sc2/configure.ac @@ -27,8 +27,8 @@ AM_MAINTAINER_MODE # Configurables -CFLAGS="$CFLAGS -g -W -Wall -DHAVE_OPENGL -DSDL_PTHREADS -DGFXMODULE_SDL -DSOUNDMODULE_SDL" -CPPFLAGS="$CPPFLAGS -g -W -Wall -DHAVE_OPENGL -DSDL_PTHREADS -DGFXMODULE_SDL -DSOUNDMODULE_SDL" +CFLAGS="$CFLAGS -g -W -Wall -DHAVE_OPENGL -DSDL_PTHREADS -DGFXMODULE_SDL -DSOUNDMODULE_OPENAL" +CPPFLAGS="$CPPFLAGS -g -W -Wall -DHAVE_OPENGL -DSDL_PTHREADS -DGFXMODULE_SDL -DSOUNDMODULE_OPENAL" # -------------------------------------------------------------------------- @@ -68,11 +68,11 @@ AC_CHECK_FUNCS([strupr]) # Check for SDL SDL_VERSION=1.2.2 AM_PATH_SDL($SDL_VERSION, , AC_MSG_ERROR([*** SDL version $SDL_VERSION not found!])) -AC_CHECK_LIB(SDL_mixer, main, , AC_MSG_ERROR([Your system is missing libSDL_mixer!]),`sdl-config --libs`) AC_CHECK_LIB(SDL_image, main, , AC_MSG_ERROR([Your system is missing libSDL_image!]),`sdl-config --libs`) AC_CHECK_LIB(SDL_sound, main, , AC_MSG_ERROR([Your system is missing libSDL_sound!]),`sdl-config --libs`) +AC_CHECK_LIB(openal, main, , AC_MSG_ERROR([Your system is missing libopenal!]),"-lm") +#AC_CHECK_LIB(SDL_mixer, main, , AC_MSG_ERROR([Your system is missing libSDL_mixer!]),`sdl-config --libs`) #AC_CHECK_HEADERS(SDL/SDL_image.h, , AC_MSG_ERROR([Your system is missing SDL_image.h!])) -#AC_CHECK_HEADERS(SDL/SDL_mixer.h, , AC_MSG_ERROR([Your system is missing SDL_mixer.h!])) # Select platform dependent OpenGL libs.. (tweak your platform here) case "$target" in @@ -211,7 +211,7 @@ AC_CONFIG_FILES([ src/sc2code/libs/input/Makefile src/sc2code/libs/input/sdl/Makefile src/sc2code/libs/sound/Makefile - src/sc2code/libs/sound/sdl/Makefile + src/sc2code/libs/sound/openal/Makefile src/sc2code/libs/graphics/Makefile src/sc2code/libs/graphics/sdl/Makefile src/sc2code/libs/task/Makefile diff --git a/sc2/src/msvc++/Starcon2.dsp b/sc2/src/msvc++/Starcon2.dsp index 23e57d2ed..f556fee65 100644 --- a/sc2/src/msvc++/Starcon2.dsp +++ b/sc2/src/msvc++/Starcon2.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 "..\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 "SOUNDMODULE_SDL" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /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 "SOUNDMODULE_OPENAL" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe @@ -50,7 +50,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib SDL.lib SDLmain.lib SDL_image.lib SDL_mixer.lib SDL_sound.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"msvcrtd.lib" /out:"../../Content/Starcon2.exe" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib SDL.lib SDLmain.lib SDL_image.lib SDL_sound.lib OpenAL32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"msvcrtd.lib" /out:"../../Content/Starcon2.exe" !ELSEIF "$(CFG)" == "Starcon2 - Win32 Debug" @@ -66,7 +66,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I ".." /I "..\sc2code" /I "..\sc2code\libs" /I "..\sc2code\ships" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D _VW=320 /D _VH=240 /D "HAVE_OPENGL" /D "GFXMODULE_SDL" /D "SOUNDMODULE_SDL" /FR /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I ".." /I "..\sc2code" /I "..\sc2code\libs" /I "..\sc2code\ships" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D _VW=320 /D _VH=240 /D "HAVE_OPENGL" /D "GFXMODULE_SDL" /D "SOUNDMODULE_OPENAL" /FR /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe @@ -74,7 +74,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo /o"Starcon2.bsc" LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib SDL.lib SDLmain.lib SDL_image.lib SDL_mixer.lib SDL_sound.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"../../Content/Starcon2Debug.exe" /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib SDL.lib SDLmain.lib SDL_image.lib SDL_sound.lib OpenAL32.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"../../Content/Starcon2Debug.exe" /pdbtype:sept # SUBTRACT LINK32 /nodefaultlib !ENDIF @@ -395,24 +395,36 @@ SOURCE=..\sc2code\libs\resource\resintrn.h # Begin Group "sound" # PROP Default_Filter "" -# Begin Group "sdl No. 2" +# Begin Group "openal" # PROP Default_Filter "" # Begin Source File -SOURCE=..\sc2code\libs\sound\sdl\modfuncs.c +SOURCE=..\sc2code\libs\sound\openal\music.c # End Source File # Begin Source File -SOURCE=..\sc2code\libs\sound\sdl\play.c +SOURCE=..\sc2code\libs\sound\openal\sfx.c # End Source File # Begin Source File -SOURCE=..\sc2code\libs\sound\sdl\sound.c +SOURCE=..\sc2code\libs\sound\openal\sound.c # End Source File # Begin Source File -SOURCE=..\sc2code\libs\sound\sdl\trackplayer.c +SOURCE=..\sc2code\libs\sound\openal\sound.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\sound\openal\stream.c +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\sound\openal\stream.h +# End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\sound\openal\trackplayer.c # End Source File # End Group # Begin Source File diff --git a/sc2/src/sc2code/libs/graphics/gfx_common.c b/sc2/src/sc2code/libs/graphics/gfx_common.c index 2d58cf741..f531d5e9c 100644 --- a/sc2/src/sc2code/libs/graphics/gfx_common.c +++ b/sc2/src/sc2code/libs/graphics/gfx_common.c @@ -31,7 +31,7 @@ int ScreenHeight; int ScreenWidthActual; int ScreenHeightActual; int GraphicsDriver; -int TFB_DEBUG_HALT; +int TFB_DEBUG_HALT = 0; int BlendNumerator = 4; int BlendDenominator = 4; diff --git a/sc2/src/sc2code/libs/graphics/gfx_common.h b/sc2/src/sc2code/libs/graphics/gfx_common.h index 4b5a33d08..39c79d8a2 100644 --- a/sc2/src/sc2code/libs/graphics/gfx_common.h +++ b/sc2/src/sc2code/libs/graphics/gfx_common.h @@ -45,7 +45,7 @@ enum int TFB_InitGraphics (int driver, int flags, int width, int height, int bpp); -int TFB_CreateGamePlayThread (void); +void TFB_UninitGraphics (); void TFB_ProcessEvents (void); // 3DO Graphics Stuff diff --git a/sc2/src/sc2code/libs/graphics/sdl/3do_funcs.c b/sc2/src/sc2code/libs/graphics/sdl/3do_funcs.c index 993b23be2..2c3c9562f 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/3do_funcs.c +++ b/sc2/src/sc2code/libs/graphics/sdl/3do_funcs.c @@ -35,7 +35,6 @@ InitGraphics (int argc, char* argv[], COUNT KbytesRequired) BOOLEAN ret; LoadDisplay (&_pCurDisplay); - mem_init (); ActivateDisplay (); DrawCommandQueue = TFB_DrawCommandQueue_Create (); @@ -50,7 +49,7 @@ UninitGraphics () // Also probably empty { // HFree (DrawCommandQueue); This is static now! - mem_uninit (); + //mem_uninit (); } diff --git a/sc2/src/sc2code/libs/graphics/sdl/opengl.c b/sc2/src/sc2code/libs/graphics/sdl/opengl.c index 5f310c250..310046fcc 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/opengl.c +++ b/sc2/src/sc2code/libs/graphics/sdl/opengl.c @@ -47,7 +47,6 @@ TFB_GL_InitGraphics (int driver, int flags, int width, int height, int bpp) SDL_VideoDriverName (VideoName, sizeof (VideoName)); fprintf (stderr, "SDL driver used: %s\n", VideoName); - atexit (SDL_Quit); fprintf (stderr, "SDL initialized.\n"); fprintf (stderr, "Initializing Screen.\n"); diff --git a/sc2/src/sc2code/libs/graphics/sdl/pure.c b/sc2/src/sc2code/libs/graphics/sdl/pure.c index ee869b9af..86ab2d2a0 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/pure.c +++ b/sc2/src/sc2code/libs/graphics/sdl/pure.c @@ -48,7 +48,6 @@ TFB_Pure_InitGraphics (int driver, int flags, int width, int height, int bpp) // For Linux: x11 (default), dga, fbcon, directfb, svgalib, // ggi, aalib // For Windows: directx (default), windib - atexit (SDL_Quit); fprintf (stderr, "SDL initialized.\n"); diff --git a/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c b/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c index 1c6f89e89..24b004cc4 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c +++ b/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c @@ -50,6 +50,8 @@ TFB_InitGraphics (int driver, int flags, int width, int height, int bpp) exit(-1); } + atexit (TFB_UninitGraphics); + if (driver == TFB_GFXDRIVER_SDL_OPENGL) { #ifdef HAVE_OPENGL @@ -77,17 +79,10 @@ TFB_InitGraphics (int driver, int flags, int width, int height, int bpp) return 0; } -int -TFB_CreateGamePlayThread () +void +TFB_UninitGraphics (void) { - TFB_DEBUG_HALT = 0; - - GraphicsSem = SDL_CreateSemaphore (1); - _MemorySem = SDL_CreateSemaphore (1); - - SDL_CreateThread (Starcon2Main, NULL); - - return 0; + SDL_Quit (); } void diff --git a/sc2/src/sc2code/libs/input/input_common.h b/sc2/src/sc2code/libs/input/input_common.h index 134e177ad..6ec6a0ca8 100644 --- a/sc2/src/sc2code/libs/input/input_common.h +++ b/sc2/src/sc2code/libs/input/input_common.h @@ -29,5 +29,6 @@ enum //#define TFB_INPUTFLAGS_ETC (1<<0) int TFB_InitInput (int driver, int flags); +void TFB_UninitInput (void); #endif diff --git a/sc2/src/sc2code/libs/input/sdl/input.c b/sc2/src/sc2code/libs/input/sdl/input.c index c63fa3f54..17569e6d4 100644 --- a/sc2/src/sc2code/libs/input/sdl/input.c +++ b/sc2/src/sc2code/libs/input/sdl/input.c @@ -19,6 +19,7 @@ #ifdef GFXMODULE_SDL #include "libs/graphics/sdl/sdl_common.h" +#include "libs/input/input_common.h" Uint8 KeyboardDown[512]; @@ -48,6 +49,8 @@ TFB_InitInput (int driver, int flags) int i; SDL_Joystick *Joystick1; + atexit (TFB_UninitInput); + if ((SDL_InitSubSystem(SDL_INIT_JOYSTICK)) == -1) { fprintf (stderr, "Couldn't initialize joystick subsystem: %s\n", SDL_GetError()); @@ -86,6 +89,11 @@ TFB_InitInput (int driver, int flags) return 0; } +void +TFB_UninitInput (void) +{ +} + void ProcessKeyboardEvent(const SDL_Event *Event) { diff --git a/sc2/src/sc2code/libs/sound/Makefile.am b/sc2/src/sc2code/libs/sound/Makefile.am index 8e6b22bcf..7d4869962 100644 --- a/sc2/src/sc2code/libs/sound/Makefile.am +++ b/sc2/src/sc2code/libs/sound/Makefile.am @@ -3,7 +3,7 @@ # Written by Mudry , protected by GNU GPL. # CVS $ Id: $ -SUBDIRS = sdl +SUBDIRS = openal INCLUDES = @SDL_CFLAGS@ \ -I$(top_srcdir)/src \ @@ -12,6 +12,6 @@ INCLUDES = @SDL_CFLAGS@ \ noinst_LTLIBRARIES = libsound.la libsound_la_SOURCES = fileinst.c resinst.c sound_common.c -libsound_la_LIBADD = sdl/libsdlsound.la +libsound_la_LIBADD = openal/libopenalsound.la noinst_HEADERS = play.h redbook.h sndintrn.h trackplayer.h sound_common.h diff --git a/sc2/src/sc2code/libs/sound/openal/Makefile.am b/sc2/src/sc2code/libs/sound/openal/Makefile.am new file mode 100644 index 000000000..8c703a1c3 --- /dev/null +++ b/sc2/src/sc2code/libs/sound/openal/Makefile.am @@ -0,0 +1,15 @@ + +# Automake template file. +# Written by Mudry , protected by GNU GPL. +# CVS $ Id: $ + +INCLUDES = @SDL_CFLAGS@ \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/sc2code \ + -I$(top_srcdir)/src/sc2code/libs + +noinst_LTLIBRARIES = libopenalsound.la +libopenalsound_la_SOURCES = music.c sfx.c sound.c stream.c trackplayer.c + +noinst_HEADERS = sound.h stream.h + diff --git a/sc2/src/sc2code/libs/sound/openal/music.c b/sc2/src/sc2code/libs/sound/openal/music.c new file mode 100644 index 000000000..aee085ce8 --- /dev/null +++ b/sc2/src/sc2code/libs/sound/openal/music.c @@ -0,0 +1,187 @@ +/* + * 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 specific code by Mika Kolehmainen, 2002-10-23 + */ + +#ifdef SOUNDMODULE_OPENAL + +#include "sound.h" + +static MUSIC_REF curMusicRef; + +void +PLRPlaySong (MUSIC_REF MusicRef, BOOLEAN Continuous, BYTE Priority) +{ + TFB_SoundSample **pmus; + + LockMusicData (MusicRef, &pmus); + if (pmus) + { + LockMutex (soundSource[MUSIC_SOURCE].stream_mutex); + PlayStream ((*pmus), MUSIC_SOURCE, Continuous); + UnlockMutex (soundSource[MUSIC_SOURCE].stream_mutex); + + curMusicRef = MusicRef; + } + + (void) Priority; /* Satisfy compiler because of unused variable */ +} + +void +PLRStop (MUSIC_REF MusicRef) +{ + if (MusicRef == curMusicRef || MusicRef == (MUSIC_REF)~0) + { + LockMutex (soundSource[MUSIC_SOURCE].stream_mutex); + StopStream (MUSIC_SOURCE); + UnlockMutex (soundSource[MUSIC_SOURCE].stream_mutex); + UnlockMusicData (curMusicRef); + + curMusicRef = 0; + } +} + +BOOLEAN +PLRPlaying (MUSIC_REF MusicRef) +{ + if (curMusicRef && (MusicRef == curMusicRef || MusicRef == (MUSIC_REF)~0)) + { + BOOLEAN playing; + + LockMutex (soundSource[MUSIC_SOURCE].stream_mutex); + playing = PlayingStream (MUSIC_SOURCE); + UnlockMutex (soundSource[MUSIC_SOURCE].stream_mutex); + + return playing; + } + + return FALSE; +} + +void +PLRPause (MUSIC_REF MusicRef) +{ + if (MusicRef == curMusicRef || MusicRef == (MUSIC_REF)~0) + { + LockMutex (soundSource[MUSIC_SOURCE].stream_mutex); + PauseStream (MUSIC_SOURCE); + UnlockMutex (soundSource[MUSIC_SOURCE].stream_mutex); + } +} + +void +PLRResume (MUSIC_REF MusicRef) +{ + if (MusicRef == curMusicRef || MusicRef == (MUSIC_REF)~0) + { + LockMutex (soundSource[MUSIC_SOURCE].stream_mutex); + ResumeStream (MUSIC_SOURCE); + UnlockMutex (soundSource[MUSIC_SOURCE].stream_mutex); + } +} + +BOOLEAN +DestroyMusic (MUSIC_REF MusicRef) +{ + return (FreeMusicData (MusicRef)); +} + +void +SetMusicVolume (COUNT Volume) +{ + float f = (Volume / (ALfloat)MAX_VOLUME) * musicVolumeScale; + musicVolume = Volume; + alSourcef (soundSource[MUSIC_SOURCE].handle, AL_GAIN, f); +} + +MEM_HANDLE +_GetMusicData (FILE *fp, DWORD length) +{ + MEM_HANDLE h; + extern char *_cur_resfile_name; + + h = 0; + if (_cur_resfile_name && (h = AllocMusicData (sizeof (void *)))) + { + TFB_SoundSample **pmus; + + LockMusicData (h, &pmus); + if (!pmus) + { + UnlockMusicData (h); + mem_release (h); + h = 0; + } + else + { + *pmus = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample)); + + if (((*pmus)->decoder = Sound_NewSampleFromFile (_cur_resfile_name, NULL, 4096)) == 0) + { + fprintf (stderr, "_GetMusicData(): couldn't load %s\n", _cur_resfile_name); + + UnlockMusicData (h); + mem_release (h); + h = 0; + HFree (*pmus); + } + else + { + fprintf (stderr, "decoder %s rate %d channels %d\n", (*pmus)->decoder->decoder->description, + (*pmus)->decoder->actual.rate, (*pmus)->decoder->actual.channels); + alGenBuffers (NUM_SOUNDBUFFERS, (*pmus)->buffer); + } + } + + UnlockMusicData (h); + } + + (void) fp; /* satisfy compiler (unused parameter) */ + (void) length; /* satisfy compiler (unused parameter) */ + return (h); +} + +BOOLEAN +_ReleaseMusicData (MEM_HANDLE handle) +{ + TFB_SoundSample **pmus; + + LockMusicData (handle, &pmus); + if (pmus == 0) + return (FALSE); + + if ((*pmus)->decoder) + { + LockMutex (soundSource[MUSIC_SOURCE].stream_mutex); + if (soundSource[MUSIC_SOURCE].sample == (*pmus)) + { + StopStream (MUSIC_SOURCE); + } + UnlockMutex (soundSource[MUSIC_SOURCE].stream_mutex); + + Sound_FreeSample ((*pmus)->decoder); + alDeleteBuffers (NUM_SOUNDBUFFERS, (*pmus)->buffer); + } + HFree (*pmus); + + UnlockMusicData (handle); + mem_release (handle); + + return (TRUE); +} + +#endif diff --git a/sc2/src/sc2code/libs/sound/openal/sfx.c b/sc2/src/sc2code/libs/sound/openal/sfx.c new file mode 100644 index 000000000..adad7caab --- /dev/null +++ b/sc2/src/sc2code/libs/sound/openal/sfx.c @@ -0,0 +1,258 @@ +/* + * 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 specific code by Mika Kolehmainen, 2002-10-23 + */ + +#ifdef SOUNDMODULE_OPENAL + +#ifdef WIN32 +#include +#endif +#include + +#include "sound.h" + + +void +PlayChannel (COUNT channel, PVOID sample, COUNT sample_length, COUNT loop_begin, + COUNT loop_length, unsigned char priority) +{ + TFB_SoundSample *tfb_sample = *(TFB_SoundSample**) sample; + + //fprintf (stderr, "PlayChannel %d tfb_sample %x\n", channel, tfb_sample); + + soundSource[channel].sample = tfb_sample; + alSourceRewind (soundSource[channel].handle); + alSourcei (soundSource[channel].handle, AL_BUFFER, tfb_sample->buffer[0]); + alSourcePlay (soundSource[channel].handle); +} + +void +StopChannel(COUNT channel, unsigned char Priority) +{ + alSourceRewind (soundSource[channel].handle); +} + +BOOLEAN +ChannelPlaying (COUNT WhichChannel) +{ + ALint state; + + alGetSourcei (soundSource[WhichChannel].handle, AL_SOURCE_STATE, &state); + if (state == AL_PLAYING) + return TRUE; + return FALSE; +} + +void +SetChannelVolume (COUNT channel, COUNT volume, BYTE priority) + // I wonder what this whole priority business is... + // I can probably ignore it. +{ + alSourcef (soundSource[channel].handle, AL_GAIN, + (volume / (ALfloat)MAX_VOLUME) * sfxVolumeScale); +} + +// Status: Ignored +PBYTE +GetSampleAddress (SOUND sound) + // I might be prototyping this wrong, type-wise. +{ + return ((PBYTE)GetSoundAddress (sound)); +} + +// Status: Ignored +COUNT +GetSampleLength (SOUND sound) +{ + return 0; +} + +// Status: Ignored +void +SetChannelRate (COUNT channel, DWORD rate_hz, unsigned char priority) +{ +} + +// Status: Ignored +COUNT +GetSampleRate (SOUND sound) +{ + return 0; +} + +MEM_HANDLE +_GetSoundBankData (FILE *fp, DWORD length) +{ +#ifdef WIN32 + int omode; +#endif + int snd_ct, n; + DWORD opos; + char CurrentLine[1024], filename[1024]; +#define MAX_FX 256 + TFB_SoundSample *sndfx[MAX_FX]; + STRING_TABLE Snd; + + opos = ftell (fp); + + { + char *s1, *s2; + extern char *_cur_resfile_name; + + if (_cur_resfile_name == 0 + || (((s2 = 0), (s1 = strrchr (_cur_resfile_name, '/')) == 0) + && (s2 = strrchr (_cur_resfile_name, '\\')) == 0)) + n = 0; + else + { + if (s2 > s1) + s1 = s2; + n = s1 - _cur_resfile_name + 1; + strncpy (filename, _cur_resfile_name, n); + } + } + +#ifdef WIN32 + omode = _setmode (fileno (fp), O_TEXT); +#endif + snd_ct = 0; + while (fgets (CurrentLine, sizeof (CurrentLine), fp) && snd_ct < MAX_FX) + { + if (sscanf(CurrentLine, "%s", &filename[n]) == 1) + { + fprintf (stderr, "_GetSoundBankData(): loading %s\n", filename); + + sndfx[snd_ct] = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample)); + sndfx[snd_ct]->decoder = Sound_NewSampleFromFile (filename, NULL, 4096); + if (!sndfx[snd_ct]->decoder) + { + fprintf (stderr, "_GetSoundBankData(): couldn't load %s\n", filename); + HFree (sndfx[snd_ct]); + } + else + { + Uint32 decoded_bytes; + ALenum format; + + decoded_bytes = Sound_DecodeAll (sndfx[snd_ct]->decoder); + //fprintf (stderr, "decoded_bytes %d\n", decoded_bytes); + + format = DetermineALFormat (sndfx[snd_ct]->decoder); + + alGenBuffers (NUM_SOUNDBUFFERS, sndfx[snd_ct]->buffer); + alBufferData (sndfx[snd_ct]->buffer[0], format, + sndfx[snd_ct]->decoder->buffer, decoded_bytes, + sndfx[snd_ct]->decoder->actual.rate); + + Sound_FreeSample (sndfx[snd_ct]->decoder); + sndfx[snd_ct]->decoder = NULL; + + ++snd_ct; + } + } + else + { + fprintf (stderr, "_GetSoundBankData: Bad file!\n"); + } + + if (ftell (fp) - opos >= length) + break; + } +#ifdef WIN32 + _setmode (fileno (fp), omode); +#endif + + Snd = 0; + if (snd_ct && (Snd = AllocStringTable ( + sizeof (STRING_TABLE_DESC) + + (sizeof (DWORD) * snd_ct) + + (sizeof (sndfx[0]) * snd_ct) + ))) + { + STRING_TABLEPTR fxTab; + + LockStringTable (Snd, &fxTab); + if (fxTab == 0) + { + while (snd_ct--) + { + if (sndfx[snd_ct]->decoder) + Sound_FreeSample (sndfx[snd_ct]->decoder); + HFree (sndfx[snd_ct]); + } + + FreeStringTable (Snd); + Snd = 0; + } + else + { + DWORD *offs, StringOffs; + + fxTab->StringCount = snd_ct; + fxTab->flags = 0; + offs = fxTab->StringOffsets; + StringOffs = sizeof (STRING_TABLE_DESC) + (sizeof (DWORD) * snd_ct); + memcpy ((BYTE *)fxTab + StringOffs, sndfx, sizeof (sndfx[0]) * snd_ct); + do + { + *offs++ = StringOffs; + StringOffs += sizeof (sndfx[0]); + } while (snd_ct--); + UnlockStringTable (Snd); + } + } + + return ((MEM_HANDLE)Snd); +} + +BOOLEAN +_ReleaseSoundBankData (MEM_HANDLE Snd) +{ + STRING_TABLEPTR fxTab; + + LockStringTable (Snd, &fxTab); + if (fxTab) + { + int snd_ct; + TFB_SoundSample **sptr; + + snd_ct = fxTab->StringCount; + sptr = (TFB_SoundSample **)((BYTE *)fxTab + fxTab->StringOffsets[0]); + while (snd_ct--) + { + Sound_FreeSample ((*sptr)->decoder); + alDeleteBuffers (NUM_SOUNDBUFFERS, (*sptr)->buffer); + HFree (*sptr); + *sptr++ = 0; + } + UnlockStringTable (Snd); + FreeStringTable (Snd); + + return (TRUE); + } + + return (FALSE); +} + +BOOLEAN +DestroySound(SOUND_REF target) +{ + return (_ReleaseSoundBankData (target)); +} + +#endif diff --git a/sc2/src/sc2code/libs/sound/openal/sound.c b/sc2/src/sc2code/libs/sound/openal/sound.c new file mode 100644 index 000000000..01f88045c --- /dev/null +++ b/sc2/src/sc2code/libs/sound/openal/sound.c @@ -0,0 +1,238 @@ +/* + * 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 specific code by Mika Kolehmainen, 2002-10-23 + */ + +#ifdef SOUNDMODULE_OPENAL + +#include "sound.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}; +TFB_SoundSource soundSource[NUM_SOUNDSOURCES]; +static Task StreamDecoderTask; + + +int +TFB_InitSound (int driver, int flags, int frequency) +{ + int i; + + fprintf (stderr, "Initializing OpenAL.\n"); + atexit (TFB_UninitSound); + +#ifdef WIN32 + alcDevice = alcOpenDevice ((ALubyte*)"DirectSound3D"); +#else + alcDevice = alcOpenDevice (NULL); +#endif + + if (!alcDevice) + { + fprintf (stderr,"Couldn't initialize OpenAL: %d\n", alcGetError (NULL)); + exit (-1); + } + + 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, "Initializing SDL_sound.\n"); + if (!Sound_Init()) + { + fprintf(stderr, "SDL_sound initialization failed: %s\n", Sound_GetError()); + exit (-1); + } + else + { + const Sound_DecoderInfo **sdi; + Sound_Version compiled, linked; + + SOUND_VERSION (&compiled); + Sound_GetLinkedVersion (&linked); + + fprintf (stderr, "SDL_sound initialized.\n"); + fprintf (stderr, " compiled version: %d.%d.%d linked version: %d.%d.%d\n", + compiled.major, compiled.minor, compiled.patch, + linked.major, linked.minor, linked.patch); + + for (sdi = Sound_AvailableDecoders(); *sdi != NULL; ++sdi) + { + fprintf (stderr, " supported format: %s\n", + (*sdi)->description); + } + } + + 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_looping = FALSE; + soundSource[i].stream_should_be_playing = FALSE; + soundSource[i].stream_mutex = CreateMutex (); + } + + SetSFXVolume (sfxVolumeScale); + SetSpeechVolume (speechVolumeScale); + SetMusicVolume (musicVolume); + + // NOTE: change this if implementing 3D sound stuff + alDistanceModel (AL_NONE); + + StreamDecoderTask = AssignTask (StreamDecoderTaskFunc, 1024, + "audio stream decoder"); + + return 0; +} + +void +TFB_UninitSound (void) +{ + ConcludeTask (StreamDecoderTask); + alcMakeContextCurrent (NULL); + alcDestroyContext (alcContext); + alcContext = NULL; + alcCloseDevice (alcDevice); + alcDevice = NULL; +} + +void +StopSound (void) +{ + int i; + + for (i = FIRST_SFX_SOURCE; i <= LAST_SFX_SOURCE; ++i) + { + alSourceRewind (soundSource[i].handle); + } +} + +BOOLEAN +SoundPlaying (void) +{ + int i; + + for (i = 0; i < NUM_SOUNDSOURCES; ++i) + { + if (soundSource[i].sample && soundSource[i].sample->decoder) + { + BOOLEAN result; + LockMutex (soundSource[i].stream_mutex); + result = PlayingStream (i); + UnlockMutex (soundSource[i].stream_mutex); + if (result) + return TRUE; + } + else + { + ALint state; + alGetSourcei (soundSource[i].handle, AL_SOURCE_STATE, &state); + if (state == AL_PLAYING) + return TRUE; + } + } + + return FALSE; +} + +// Status: Ignored +BOOLEAN +InitSound (int argc, char* argv[]) +{ + return TRUE; +} + +// Status: Ignored +void +UninitSound (void) +{ +} + +ALenum +DetermineALFormat (Sound_Sample *sample) +{ + ALenum format; + + if (sample->actual.channels == 1) + { + if (sample->actual.format == AUDIO_U8 || + sample->actual.format == AUDIO_S8) + { + format = AL_FORMAT_MONO8; + } + else + { + format = AL_FORMAT_MONO16; + } + } + else + { + if (sample->actual.format == AUDIO_U8 || + sample->actual.format == AUDIO_S8) + { + format = AL_FORMAT_STEREO8; + } + else + { + format = AL_FORMAT_STEREO16; + } + } + + return format; +} + +void SetSFXVolume (float volume) +{ + int i; + for (i = FIRST_SFX_SOURCE; i <= LAST_SFX_SOURCE; ++i) + { + alSourcef (soundSource[i].handle, AL_GAIN, sfxVolumeScale); + } +} + +void SetSpeechVolume (float volume) +{ + alSourcef (soundSource[SPEECH_SOURCE].handle, AL_GAIN, speechVolumeScale); +} + + +#endif diff --git a/sc2/src/sc2code/libs/sound/openal/sound.h b/sc2/src/sc2code/libs/sound/openal/sound.h new file mode 100644 index 000000000..48ec240b1 --- /dev/null +++ b/sc2/src/sc2code/libs/sound/openal/sound.h @@ -0,0 +1,72 @@ +/* + * 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 specific code by Mika Kolehmainen, 2002-10-23 + */ + +#include "libs/strings/strintrn.h" +#include "libs/sound/sndintrn.h" +#include "libs/graphics/sdl/sdl_common.h" +#include "libs/sound/sound_common.h" + +#ifdef WIN32 +#include +#include +#include +#else +#include +#include +#include +#endif + + +#define NUM_SOUNDBUFFERS 8 +#define FIRST_SFX_SOURCE 0 +#define LAST_SFX_SOURCE 4 +#define MUSIC_SOURCE (LAST_SFX_SOURCE + 1) +#define SPEECH_SOURCE (MUSIC_SOURCE + 1) +#define NUM_SOUNDSOURCES (SPEECH_SOURCE + 1) + +// audio data +typedef struct tfb_soundsample +{ + Sound_Sample *decoder; // if != NULL, sound is streamed + ALuint buffer[NUM_SOUNDBUFFERS]; // if not streamed, only buffer[0] is used +} TFB_SoundSample; + +// equivalent to channel in legacy sound code +typedef struct tfb_soundsource +{ + TFB_SoundSample *sample; + ALuint handle; + BOOLEAN stream_looping; + BOOLEAN stream_should_be_playing; + Mutex stream_mutex; +} TFB_SoundSource; + + +extern ALCcontext *alcContext; // OpenAL context +extern ALCdevice *alcDevice; // OpenAL device +extern ALfloat listenerPos[]; // listener position (3 floats) +extern ALfloat listenerVel[]; // listener velocity (3 floats) +extern ALfloat listenerOri[]; // listener orientation (two 3 float vectors, "look at" and "up") +extern TFB_SoundSource soundSource[]; + +ALenum DetermineALFormat (Sound_Sample *sample); +void SetSFXVolume (float volume); +void SetSpeechVolume (float volume); + +#include "stream.h" diff --git a/sc2/src/sc2code/libs/sound/openal/stream.c b/sc2/src/sc2code/libs/sound/openal/stream.c new file mode 100644 index 000000000..35e88374f --- /dev/null +++ b/sc2/src/sc2code/libs/sound/openal/stream.c @@ -0,0 +1,238 @@ +/* +* 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. +*/ + +/* By Mika Kolehmainen, 2002-10-23 +*/ + +#ifdef SOUNDMODULE_OPENAL + +#include "sound.h" + +BOOLEAN speech_callback = FALSE; + + +void +PlayStream (TFB_SoundSample *sample, ALuint source, BOOLEAN looping) +{ + int i; + ALenum format = DetermineALFormat (sample->decoder); + + StopStream (source); + + Sound_Rewind (sample->decoder); + soundSource[source].sample = sample; + + alSourcei (soundSource[source].handle, AL_LOOPING, AL_FALSE); + + for (i = 0; i < NUM_SOUNDBUFFERS; ++i) + { + Uint32 decoded_bytes; + + if (sample->decoder->flags & SOUND_SAMPLEFLAG_EOF || + sample->decoder->flags & SOUND_SAMPLEFLAG_ERROR) + break; + + decoded_bytes = Sound_Decode (sample->decoder); + //fprintf (stderr, "PlayStream(): source %d sample %x decoded_bytes %d\n", source, sample, decoded_bytes); + if (decoded_bytes == 0) + break; + + alBufferData (sample->buffer[i], format, sample->decoder->buffer, + decoded_bytes, sample->decoder->actual.rate); + + alSourceQueueBuffers (soundSource[source].handle, 1, &sample->buffer[i]); + } + + soundSource[source].stream_looping = looping; + soundSource[source].stream_should_be_playing = TRUE; + alSourcePlay (soundSource[source].handle); +} + +void +StopStream (ALuint source) +{ + ALuint queued, processed; + ALuint *buffer; + + soundSource[source].stream_should_be_playing = FALSE; + soundSource[source].sample = NULL; + alSourceStop (soundSource[source].handle); + alGetSourcei (soundSource[source].handle, AL_BUFFERS_PROCESSED, &processed); + alGetSourcei (soundSource[source].handle, AL_BUFFERS_QUEUED, &queued); + + //fprintf (stderr, "StopStream(): source %d processed %d queued %d NUM_SOUNDBUFFERS %d\n", + // source, processed, queued, NUM_SOUNDBUFFERS); + + buffer = (ALuint *) HMalloc (sizeof (ALuint) * processed); + alSourceUnqueueBuffers (soundSource[source].handle, processed, buffer); + HFree (buffer); +} + +void +PauseStream (ALuint source) +{ + soundSource[source].stream_should_be_playing = FALSE; + alSourcePause (soundSource[source].handle); +} + +void +ResumeStream (ALuint source) +{ + soundSource[source].stream_should_be_playing = TRUE; + alSourcePlay (soundSource[source].handle); +} + +BOOLEAN +PlayingStream (ALuint source) +{ + return soundSource[source].stream_should_be_playing; +} + +int +StreamDecoderTaskFunc (void *data) +{ + Task task = (Task)data; + + while (!Task_ReadState (task, TASK_EXIT)) + { + int i; + + SleepThread (1); + + for (i = MUSIC_SOURCE; i < NUM_SOUNDSOURCES; ++i) + { + ALuint processed; + //ALuint queued; + ALint state; + ALboolean finished = AL_FALSE; + + LockMutex (soundSource[i].stream_mutex); + + if (!soundSource[i].sample || + !soundSource[i].sample->decoder || + !soundSource[i].stream_should_be_playing || + soundSource[i].sample->decoder->flags & SOUND_SAMPLEFLAG_EOF || + soundSource[i].sample->decoder->flags & SOUND_SAMPLEFLAG_ERROR) + { + UnlockMutex (soundSource[i].stream_mutex); + continue; + } + + alGetSourcei (soundSource[i].handle, AL_BUFFERS_PROCESSED, &processed); + if (processed == 0) + { + alGetSourcei (soundSource[i].handle, AL_SOURCE_STATE, &state); + if (state != AL_PLAYING) + { + //fprintf (stderr, "StreamDecoderTaskFunc(): forcing alSourcePlay on %d\n", i); + alSourcePlay (soundSource[i].handle); + } + } + + //alGetSourcei (soundSource[i].handle, AL_BUFFERS_QUEUED, &queued); + //fprintf (stderr, "StreamDecoderTaskFunc(): source %d, processed %d queued %d\n", i, processed, queued); + + while (processed && !finished) + { + ALenum format, error; + ALuint buffer; + Uint32 decoded_bytes; + + alGetError (); // clear error state + + alSourceUnqueueBuffers (soundSource[i].handle, 1, &buffer); + if ((error = alGetError()) != AL_NO_ERROR) + { + fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alSourceUnqueueBuffers: %x, source %d\n", error, i); + break; + } + + decoded_bytes = Sound_Decode (soundSource[i].sample->decoder); + + if (soundSource[i].sample->decoder->flags & SOUND_SAMPLEFLAG_EOF) + { + if (i == SPEECH_SOURCE && speech_callback) + { + advance_track (0); + finished = AL_TRUE; + soundSource[i].stream_should_be_playing = FALSE; + } + else + { + if (soundSource[i].stream_looping) + { + if ((Sound_Rewind (soundSource[i].sample->decoder)) == 0) + { + fprintf (stderr, "StreamDecoderTaskFunc(): Sound_Rewind error %s, source %d\n", + Sound_GetError(), i); + finished = AL_TRUE; + soundSource[i].stream_should_be_playing = FALSE; + } + else if (decoded_bytes == 0) + { + decoded_bytes = Sound_Decode (soundSource[i].sample->decoder); + } + } + else + { + finished = AL_TRUE; + soundSource[i].stream_should_be_playing = FALSE; + } + } + } + else if (soundSource[i].sample->decoder->flags & SOUND_SAMPLEFLAG_ERROR) + { + fprintf (stderr, "StreamDecoderTaskFunc(): Sound_Decode error %s, source %d\n", + Sound_GetError(), i); + soundSource[i].stream_should_be_playing = FALSE; + break; + } + + if (decoded_bytes > 0) + { + format = DetermineALFormat (soundSource[i].sample->decoder); + alBufferData (buffer, format, soundSource[i].sample->decoder->buffer, + decoded_bytes, soundSource[i].sample->decoder->actual.rate); + + if ((error = alGetError()) != AL_NO_ERROR) + { + fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alBufferData: %x, source %d, decoded_bytes %d\n", error, i, decoded_bytes); + finished = AL_TRUE; + } + else + { + alSourceQueueBuffers (soundSource[i].handle, 1, &buffer); + + if ((error = alGetError()) != AL_NO_ERROR) + { + fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alSourceQueueBuffers: %x, source %d, decoded_bytes %d\n", error, i, decoded_bytes); + finished = AL_TRUE; + } + } + } + + processed--; + } + + UnlockMutex (soundSource[i].stream_mutex); + } + } + + FinishTask (task); + return 0; +} + +#endif diff --git a/sc2/src/sc2code/libs/sound/openal/stream.h b/sc2/src/sc2code/libs/sound/openal/stream.h new file mode 100644 index 000000000..6260a39d6 --- /dev/null +++ b/sc2/src/sc2code/libs/sound/openal/stream.h @@ -0,0 +1,33 @@ +/* + * 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 specific code by Mika Kolehmainen, 2002-10-23 + */ + +#ifndef STREAM_H +#define STREAM_H + +void PlayStream (TFB_SoundSample *sample, ALuint source, BOOLEAN looping); +void StopStream (ALuint source); +void PauseStream (ALuint source); +void ResumeStream (ALuint source); +BOOLEAN PlayingStream (ALuint source); +int StreamDecoderTaskFunc (void *data); + +extern BOOLEAN speech_callback; +void advance_track (int channel_finished); + +#endif diff --git a/sc2/src/sc2code/libs/sound/openal/trackplayer.c b/sc2/src/sc2code/libs/sound/openal/trackplayer.c new file mode 100644 index 000000000..a72367a27 --- /dev/null +++ b/sc2/src/sc2code/libs/sound/openal/trackplayer.c @@ -0,0 +1,266 @@ +/* + * 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 specific code by Mika Kolehmainen, 2002-10-23 + */ + +#ifdef SOUNDMODULE_OPENAL + +#include "sound.h" +#include "libs/sound/trackplayer.h" + +extern int do_subtitles (UNICODE *pStr); + +static int tct, tcur, no_voice; + +#define MAX_CLIPS 50 +static struct +{ + int text_spliced; + UNICODE *text; + TFB_SoundSample *sample; +} track_clip[MAX_CLIPS]; + + +void +JumpTrack (int abort) +{ + speech_callback = FALSE; + + if (track_clip[tcur].sample) + { + LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + StopStream (SPEECH_SOURCE); + UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + } + + no_voice = 1; + do_subtitles ((void *)~0); + + if (abort) + tcur = tct; +} + +void +advance_track (int channel_finished) +{ + if (channel_finished <= 0) + { + if (channel_finished == 0) + ++tcur; + if (tcur < tct) + { + LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + PlayStream (track_clip[tcur].sample, SPEECH_SOURCE, FALSE); + UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + do_subtitles (0); + } + else if (channel_finished == 0) + { + --tcur; + no_voice = 1; + } + } +} + +void +ResumeTrack () +{ + if (tcur < tct) + { + ALint state; + + LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + alGetSourcei (soundSource[SPEECH_SOURCE].handle, AL_SOURCE_STATE, &state); + UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + + if (!soundSource[SPEECH_SOURCE].stream_should_be_playing && + state == AL_PAUSED) + { + LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + ResumeStream (SPEECH_SOURCE); + UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + } + else if (!no_voice) + { + if (tcur == 0) + { + speech_callback = TRUE; + } + advance_track (-1); + } + } +} + +COUNT +PlayingTrack () +{ + if (tcur < tct) + { + if (do_subtitles (track_clip[tcur].text) || + (no_voice && ++tcur < tct && do_subtitles (0))) + { + return (tcur + 1); + } + else if (track_clip[tcur].sample) + { + COUNT result; + + LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + result = (PlayingStream (SPEECH_SOURCE) ? (COUNT)(tcur + 1) : 0); + UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + + return result; + } + } + + return (0); +} + +void +StopTrack () +{ + speech_callback = FALSE; + LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + StopStream (SPEECH_SOURCE); + UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + + while (tct--) + { + if (track_clip[tct].text_spliced) + { + track_clip[tct].text_spliced = 0; + HFree (track_clip[tct].text); + track_clip[tct].text = 0; + } + if (track_clip[tct].sample) + { + if (track_clip[tct].sample->decoder) + { + Sound_FreeSample (track_clip[tct].sample->decoder); + alDeleteBuffers (NUM_SOUNDBUFFERS, track_clip[tct].sample->buffer); + } + HFree (track_clip[tct].sample); + track_clip[tct].sample = 0; + } + } + tct = tcur = 0; + no_voice = 0; + do_subtitles (0); +} + +void +SpliceTrack (UNICODE *TrackName, UNICODE *TrackText) +{ + if (TrackText) + { + if (TrackName == 0) + { + if (tct) + { + int slen1, slen2; + UNICODE *oTT; + + oTT = track_clip[tct - 1].text; + slen1 = wstrlen (oTT); + slen2 = wstrlen (TrackText); + if (track_clip[tct - 1].text_spliced) + track_clip[tct - 1].text = HRealloc (oTT, slen1 + slen2 + 1); + else + { + track_clip[tct - 1].text = HMalloc (slen1 + slen2 + 1); + wstrcpy (track_clip[tct - 1].text, oTT); + track_clip[tct - 1].text_spliced = 1; + } + wstrcpy (&track_clip[tct - 1].text[slen1], TrackText); + } + } + else if (tct < MAX_CLIPS) + { + track_clip[tct].text = TrackText; + track_clip[tct].text_spliced = 0; + + fprintf (stderr, "SpliceTrack(): loading %s\n", TrackName); + + track_clip[tct].sample = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample)); + track_clip[tct].sample->decoder = Sound_NewSampleFromFile (TrackName, NULL, 4096); + + if (track_clip[tct].sample->decoder) + { + fprintf (stderr, "decoder %s rate %d channels %d\n", + track_clip[tct].sample->decoder->decoder->description, + track_clip[tct].sample->decoder->actual.rate, + track_clip[tct].sample->decoder->actual.channels); + + alGenBuffers (NUM_SOUNDBUFFERS, track_clip[tct].sample->buffer); + } + else + { + fprintf (stderr, "SpliceTrack(): couldn't load %s: %s\n", + TrackName, Sound_GetError()); + HFree (track_clip[tct].sample); + track_clip[tct].sample = NULL; + } + + ++tct; + } + } +} + +void +PauseTrack () +{ + /*if (tcur < tct && track_clip[tcur].chunk) + Mix_Pause (VOICE_CHANNEL);*/ +} + +void +FastReverse () +{ + JumpTrack (0); + no_voice = 0; + tcur = 0; + ResumeTrack (); +} + +void +FastForward () +{ + JumpTrack (0); + //no_voice = 0; +} + +int +GetSoundData (char* data) + // Returns the data size. Only used in oscill.c +{ + //fprintf (stderr, "Unimplemented function activated: GetSoundData()\n"); + return 0; +} + +// Status: Unimplemented +int +GetSoundInfo (int *length, int *offset) + // Umm... How does it know which sound? + // Answer: only used in oscill.c slider so sound must be current speech +{ + //fprintf (stderr, "Unimplemented function activated: GetSoundInfo()\n"); + *length = 1; + *offset = 0; + return 1; +} + +#endif diff --git a/sc2/src/sc2code/libs/sound/sdl/sound.c b/sc2/src/sc2code/libs/sound/sdl/sound.c index ba801b780..679b0a10b 100644 --- a/sc2/src/sc2code/libs/sound/sdl/sound.c +++ b/sc2/src/sc2code/libs/sound/sdl/sound.c @@ -26,48 +26,57 @@ int TFB_InitSound (int driver, int flags, int frequency) { + // NOTE: SDL_sound should be compiled without mikmod support + // or potential lockup occurs because both + // SDL_mixer and SDL_sound try to initialize it + char SoundcardName[256]; int audio_rate,audio_channels; Uint16 audio_format; SDL_version compile_version; + 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()); exit(-1); } - + fprintf (stderr, "SDL audio subsystem initialized.\n"); + + fprintf (stderr, "Initializing SDL_mixer.\n"); if (Mix_OpenAudio(frequency, AUDIO_S16, 2, 2048)) { fprintf (stderr, "Unable to open audio: %s\n", Mix_GetError()); exit (-1); } - + fprintf (stderr, "SDL_mixer initialized.\n"); atexit (Mix_CloseAudio); + + SDL_AudioDriverName (SoundcardName, sizeof (SoundcardName)); + Mix_QuerySpec (&audio_rate, &audio_format, &audio_channels); + fprintf (stderr, " opened %s at %d Hz %d bit %s, %d bytes audio buffer\n", + SoundcardName, audio_rate, audio_format & 0xFF, + audio_channels > 1 ? "stereo" : "mono", 2048); + MIX_VERSION (&compile_version); + fprintf (stderr, " compiled with SDL_mixer version: %d.%d.%d\n", + compile_version.major, + compile_version.minor, + compile_version.patch); + fprintf (stderr, " running with SDL_mixer version: %d.%d.%d\n", + Mix_Linked_Version()->major, + Mix_Linked_Version()->minor, + Mix_Linked_Version()->patch); + fprintf (stderr, "Initializing SDL_sound.\n"); + fprintf (stderr, "(NOTE: if this locks up, compile SDL_sound without libmikmod support)\n"); + fflush (stderr); if (!Sound_Init()) { fprintf(stderr, "Sound_Init() failed: %s\n", Sound_GetError()); exit (-1); } + fprintf (stderr, "SDL_sound initialized.\n"); - SDL_AudioDriverName (SoundcardName, sizeof (SoundcardName)); - - Mix_QuerySpec (&audio_rate, &audio_format, &audio_channels); - fprintf (stderr, "Opened %s at %d Hz %d bit %s, %d bytes audio buffer\n", - SoundcardName, audio_rate, audio_format & 0xFF, - audio_channels > 1 ? "stereo" : "mono", 2048); - - MIX_VERSION (&compile_version); - fprintf (stderr, "Compiled with SDL_mixer version: %d.%d.%d\n", - compile_version.major, - compile_version.minor, - compile_version.patch); - fprintf (stderr, "Running with SDL_mixer version: %d.%d.%d\n", - Mix_Linked_Version()->major, - Mix_Linked_Version()->minor, - Mix_Linked_Version()->patch); - return 0; } diff --git a/sc2/src/sc2code/libs/sound/sound_common.c b/sc2/src/sc2code/libs/sound/sound_common.c index dc41ec360..75fe35d12 100644 --- a/sc2/src/sc2code/libs/sound/sound_common.c +++ b/sc2/src/sc2code/libs/sound/sound_common.c @@ -20,7 +20,10 @@ #include "libs/sound/sound_common.h" #include "libs/tasklib.h" -extern int _music_volume; +int musicVolume = (MAX_VOLUME >> 1); +float musicVolumeScale = 1.0f; +float sfxVolumeScale = 1.0f; +float speechVolumeScale = 1.0f; static Task FadeTask; static SIZE TTotal; @@ -33,7 +36,7 @@ fade_task (void *data) DWORD StartTime, CurTime; Task task = (Task) data; - volume_beg = _music_volume; + volume_beg = musicVolume; StartTime = CurTime = GetTimeCounter (); do { @@ -58,7 +61,7 @@ FadeMusic (BYTE end_vol, SIZE TimeInterval) if (FadeTask) { - volume_end = _music_volume; + volume_end = musicVolume; TTotal = 1; do TaskSwitch (); diff --git a/sc2/src/sc2code/libs/sound/sound_common.h b/sc2/src/sc2code/libs/sound/sound_common.h index 16f24e4ed..c3249fc99 100644 --- a/sc2/src/sc2code/libs/sound/sound_common.h +++ b/sc2/src/sc2code/libs/sound/sound_common.h @@ -29,5 +29,11 @@ enum //#define TFB_SOUNDFLAGS_ETC (1<<0) int TFB_InitSound (int driver, int flags, int frequency); +void TFB_UninitSound (void); + +extern int musicVolume; +extern float musicVolumeScale; +extern float sfxVolumeScale; +extern float speechVolumeScale; #endif diff --git a/sc2/src/starcon2.c b/sc2/src/starcon2.c index c20f06578..8042f399f 100644 --- a/sc2/src/starcon2.c +++ b/sc2/src/starcon2.c @@ -61,6 +61,7 @@ main (int argc, char *argv[]) int gfxflags = 0; int width = 640, height = 480, bpp = 16; int frequency = 44100; + int vol; char contentdir[1000]; int option_index = 0, c; @@ -76,6 +77,9 @@ main (int argc, char *argv[]) {"tv", 0, NULL, 't'}, {"contentdir", 1, NULL, 'c'}, {"help", 0, NULL, 'h'}, + {"musicvol", 1, NULL, 'M'}, + {"sfxvol", 1, NULL, 'S'}, + {"speechvol", 1, NULL, 'T'}, {0, 0, 0, 0} }; @@ -85,7 +89,7 @@ main (int argc, char *argv[]) strcpy (contentdir, "../../content"); #endif - while ((c = getopt_long(argc, argv, "r:d:fobq:ptc:?h", long_options, &option_index)) != -1) + while ((c = getopt_long(argc, argv, "r:d:fobq:ptc:?hM:S:T:", long_options, &option_index)) != -1) { switch (c) { case 'r': @@ -115,6 +119,30 @@ main (int argc, char *argv[]) case 'c': sscanf(optarg, "%s", contentdir); break; + case 'M': + sscanf(optarg, "%d", &vol); + if (vol < 0) + vol = 0; + if (vol > 100) + vol = 100; + musicVolumeScale = vol / 100.0f; + break; + case 'S': + sscanf(optarg, "%d", &vol); + if (vol < 0) + vol = 0; + if (vol > 100) + vol = 100; + sfxVolumeScale = vol / 100.0f; + break; + case 'T': + sscanf(optarg, "%d", &vol); + if (vol < 0) + vol = 0; + if (vol > 100) + vol = 100; + speechVolumeScale = vol / 100.0f; + break; default: printf ("\nOption %s not found!\n", long_options[option_index].name); case '?': @@ -122,7 +150,7 @@ main (int argc, char *argv[]) printf("\nThe Ur-Quan Masters\n"); printf("Options:\n"); printf(" -r, --res=WIDTHxHEIGHT\n"); - printf(" -d, --bpp=BITSPERPLANE\n"); + printf(" -d, --bpp=BITSPERPIXEL\n"); printf(" -f, --fullscreen\n"); printf(" -o, --opengl\n"); printf(" -b, --bilinear\n"); @@ -130,6 +158,9 @@ main (int argc, char *argv[]) printf(" -p, --fps\n"); printf(" -t, --tv\n"); printf(" -c, --contentdir=CONTENTDIR\n"); + printf(" -M, --musicvol=VOLUME (0-100)\n"); + printf(" -S, --sfxvol=VOLUME (0-100)\n"); + printf(" -T, --speechvol=VOLUME (0-100)\n"); return 0; break; } @@ -140,11 +171,16 @@ main (int argc, char *argv[]) InitThreadSystem (); InitTimeSystem (); InitTaskSystem (); + + _MemorySem = CreateSemaphore (1); + GraphicsSem = CreateSemaphore (1); + mem_init (); + TFB_InitGraphics (gfxdriver, gfxflags, width, height, bpp); TFB_InitSound (TFB_SOUNDDRIVER_SDL, 0, frequency); TFB_InitInput (TFB_INPUTDRIVER_SDL, 0); - TFB_CreateGamePlayThread (); + AssignTask (Starcon2Main, 1024, "Starcon2Main"); for (;;) { @@ -152,5 +188,5 @@ main (int argc, char *argv[]) TFB_FlushGraphics (); } - return 0; + exit(0); }