diff --git a/sc2/src/libs/sndlib.h b/sc2/src/libs/sndlib.h index 6fcb60c3f..dca4cfaf5 100644 --- a/sc2/src/libs/sndlib.h +++ b/sc2/src/libs/sndlib.h @@ -69,11 +69,12 @@ extern void PLRPlaySong (MUSIC_REF MusicRef, BOOLEAN Continuous, BYTE Priority); extern void PLRStop (MUSIC_REF MusicRef); extern BOOLEAN PLRPlaying (MUSIC_REF MusicRef); +extern void PLRSeek (MUSIC_REF MusicRef, DWORD pos); extern void PLRPause (MUSIC_REF MusicRef); extern void PLRResume (MUSIC_REF MusicRef); extern void snd_PlaySpeech (MUSIC_REF SpeechRef); extern void snd_StopSpeech (void); -extern void PlayChannel (COUNT channel, void *sample, SoundPosition pos, +extern void PlayChannel (COUNT channel, SOUND snd, SoundPosition pos, void *positional_object, unsigned char priority); extern BOOLEAN ChannelPlaying (COUNT Channel); extern void * GetPositionalObject (COUNT channel); @@ -83,7 +84,6 @@ extern void StopChannel (COUNT Channel, BYTE Priority); extern void SetMusicVolume (COUNT Volume); extern void SetChannelVolume (COUNT Channel, COUNT Volume, BYTE Priority); -extern void SetChannelRate (COUNT Channel, DWORD Rate, BYTE Priority); extern void StopSound (void); extern BOOLEAN SoundPlaying (void); @@ -91,13 +91,6 @@ extern BOOLEAN SoundPlaying (void); extern void WaitForSoundEnd (COUNT Channel); #define TFBSOUND_WAIT_ALL ((COUNT)~0) -extern BOOLEAN AllocHardwareSample (BYTE *lpSnd, DWORD SampleRate, COUNT - SampleLength, COUNT LoopBegin, COUNT LoopLen); -extern BOOLEAN FreeHardwareSample (BYTE *lpSnd, COUNT SampleLength); - -extern COUNT GetSampleRate (SOUND Sound); -extern COUNT GetSampleLength (SOUND Sound); -extern BYTE* GetSampleAddress (SOUND Sound); extern DWORD FadeMusic (BYTE end_vol, SIZE TimeInterval); #endif /* _SNDLIB_H */ diff --git a/sc2/src/libs/sound/decoders/decoder.c b/sc2/src/libs/sound/decoders/decoder.c index e375c9cab..8c208776a 100644 --- a/sc2/src/libs/sound/decoders/decoder.c +++ b/sc2/src/libs/sound/decoders/decoder.c @@ -575,6 +575,8 @@ SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder) } decoder->buffer_size = decoded_bytes; decoder->pos += decoded_bytes; + // Free up some unused memory + decoder->buffer = HRealloc (decoder->buffer, decoded_bytes); if (decoder->need_swap && decoded_bytes > 0 && (decoder->format == decoder_formats.stereo16 || diff --git a/sc2/src/libs/sound/fileinst.c b/sc2/src/libs/sound/fileinst.c index 0ab7644da..cafbb8fda 100644 --- a/sc2/src/libs/sound/fileinst.c +++ b/sc2/src/libs/sound/fileinst.c @@ -16,6 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "sound.h" #include "sndintrn.h" #include "options.h" #include "libs/reslib.h" diff --git a/sc2/src/libs/sound/mixer/nosound/audiodrv_nosound.c b/sc2/src/libs/sound/mixer/nosound/audiodrv_nosound.c index 04ccd0076..4b9f1301d 100644 --- a/sc2/src/libs/sound/mixer/nosound/audiodrv_nosound.c +++ b/sc2/src/libs/sound/mixer/nosound/audiodrv_nosound.c @@ -1,5 +1,3 @@ -//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 @@ -20,6 +18,7 @@ */ #include "audiodrv_nosound.h" +#include "../../sndintrn.h" #include "libs/tasklib.h" #include "libs/log.h" #include "libs/memlib.h" @@ -136,13 +135,7 @@ noSound_Init (audio_Driver *driver, sint32 flags) 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); diff --git a/sc2/src/libs/sound/mixer/nosound/audiodrv_nosound.h b/sc2/src/libs/sound/mixer/nosound/audiodrv_nosound.h index 9e0f9f6fd..2f06d6044 100644 --- a/sc2/src/libs/sound/mixer/nosound/audiodrv_nosound.h +++ b/sc2/src/libs/sound/mixer/nosound/audiodrv_nosound.h @@ -24,6 +24,7 @@ #include "libs/sound/sound.h" #include "libs/sound/mixer/mixer.h" + /* Playback task */ int PlaybackTaskFunc (void *data); diff --git a/sc2/src/libs/sound/mixer/sdl/audiodrv_sdl.c b/sc2/src/libs/sound/mixer/sdl/audiodrv_sdl.c index a153999b8..718501c65 100644 --- a/sc2/src/libs/sound/mixer/sdl/audiodrv_sdl.c +++ b/sc2/src/libs/sound/mixer/sdl/audiodrv_sdl.c @@ -1,5 +1,3 @@ -//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 @@ -20,6 +18,7 @@ */ #include "audiodrv_sdl.h" +#include "../../sndintrn.h" #include "libs/tasklib.h" #include "libs/log.h" #include "libs/memlib.h" @@ -200,13 +199,7 @@ mixSDL_Init (audio_Driver *driver, sint32 flags) 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); diff --git a/sc2/src/libs/sound/music.c b/sc2/src/libs/sound/music.c index e2bfceb33..e4445a63b 100644 --- a/sc2/src/libs/sound/music.c +++ b/sc2/src/libs/sound/music.c @@ -18,6 +18,7 @@ #include "libs/file.h" #include "options.h" #include "sound.h" +#include "sndintrn.h" #include "libs/reslib.h" #include "libs/log.h" #include "libs/memlib.h" @@ -74,6 +75,17 @@ PLRPlaying (MUSIC_REF MusicRef) return FALSE; } +void +PLRSeek (MUSIC_REF MusicRef, DWORD pos) +{ + if (MusicRef == curMusicRef || MusicRef == (MUSIC_REF)~0) + { + LockMutex (soundSource[MUSIC_SOURCE].stream_mutex); + SeekStream (MUSIC_SOURCE, pos); + UnlockMutex (soundSource[MUSIC_SOURCE].stream_mutex); + } +} + void PLRPause (MUSIC_REF MusicRef) { @@ -152,46 +164,39 @@ void * _GetMusicData (uio_Stream *fp, DWORD length) { MUSIC_REF h; + TFB_SoundSample *sample; + TFB_SoundDecoder *decoder; + char filename[256]; - if (_cur_resfile_name && (h = AllocMusicData (sizeof (void *)))) + if (!_cur_resfile_name) + return NULL; + + strncpy (filename, _cur_resfile_name, sizeof(filename) - 1); + filename[sizeof(filename) - 1] = '\0'; + CheckMusicResName (filename); + + log_add (log_Info, "_GetMusicData(): loading %s", filename); + decoder = SoundDecoder_Load (contentDir, filename, 4096, 0, 0); + if (!decoder) { - TFB_SoundSample **pmus = h; - - if (!pmus) - { - return NULL; - } - else - { - char filename[256]; - - *pmus = (TFB_SoundSample *) HCalloc (sizeof (TFB_SoundSample)); - strncpy (filename, _cur_resfile_name, sizeof(filename) - 1); - filename[sizeof(filename) - 1] = '\0'; - CheckMusicResName (filename); - - log_add (log_Info, "_GetMusicData(): loading %s", filename); - if (((*pmus)->decoder = SoundDecoder_Load (contentDir, filename, - 4096, 0, 0)) == 0) - { - log_add (log_Warning, "_GetMusicData(): couldn't load %s", filename); - - HFree (h); - return NULL; - } - else - { - log_add (log_Info, " decoder: %s, rate %d format %x", - SoundDecoder_GetName ((*pmus)->decoder), - (*pmus)->decoder->frequency, (*pmus)->decoder->format); - - (*pmus)->num_buffers = 64; - (*pmus)->buffer = (audio_Object *) HMalloc (sizeof (audio_Object) * (*pmus)->num_buffers); - audio_GenBuffers ((*pmus)->num_buffers, (*pmus)->buffer); - } - } + log_add (log_Warning, "_GetMusicData(): couldn't load %s", filename); + return NULL; } + h = AllocMusicData (sizeof (void *)); + if (!h) + { + SoundDecoder_Free (decoder); + return NULL; + } + + sample = TFB_CreateSoundSample (decoder, 64, NULL); + *h = sample; + + log_add (log_Info, " decoder: %s, rate %d format %x", + SoundDecoder_GetName (sample->decoder), + sample->decoder->frequency, sample->decoder->format); + (void) fp; /* satisfy compiler (unused parameter) */ (void) length; /* satisfy compiler (unused parameter) */ return (h); @@ -201,28 +206,27 @@ BOOLEAN _ReleaseMusicData (void *data) { TFB_SoundSample **pmus = data; + TFB_SoundSample *sample; if (pmus == NULL) return (FALSE); - if ((*pmus)->decoder) + sample = *pmus; + assert (sample != 0); + if (sample->decoder) { - TFB_SoundDecoder *decoder = (*pmus)->decoder; + TFB_SoundDecoder *decoder = sample->decoder; LockMutex (soundSource[MUSIC_SOURCE].stream_mutex); - if (soundSource[MUSIC_SOURCE].sample == (*pmus)) - { + if (soundSource[MUSIC_SOURCE].sample == sample) + { // Currently playing this sample! Not good. StopStream (MUSIC_SOURCE); } UnlockMutex (soundSource[MUSIC_SOURCE].stream_mutex); - (*pmus)->decoder = NULL; + sample->decoder = NULL; SoundDecoder_Free (decoder); - audio_DeleteBuffers ((*pmus)->num_buffers, (*pmus)->buffer); - HFree ((*pmus)->buffer); - if ((*pmus)->buffer_tag) - HFree ((*pmus)->buffer_tag); } - HFree (*pmus); + TFB_DestroySoundSample (sample); HFree (pmus); return (TRUE); diff --git a/sc2/src/libs/sound/openal/audiodrv_openal.c b/sc2/src/libs/sound/openal/audiodrv_openal.c index 96d09d9f1..dec3d154f 100644 --- a/sc2/src/libs/sound/openal/audiodrv_openal.c +++ b/sc2/src/libs/sound/openal/audiodrv_openal.c @@ -21,6 +21,7 @@ #include "audiodrv_openal.h" +#include "../sndintrn.h" #include "libs/tasklib.h" #include "libs/log.h" #include "libs/memlib.h" @@ -182,13 +183,7 @@ openAL_Init (audio_Driver *driver, sint32 flags) 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); diff --git a/sc2/src/libs/sound/resinst.c b/sc2/src/libs/sound/resinst.c index 9e4b179bd..dc44c497e 100644 --- a/sc2/src/libs/sound/resinst.c +++ b/sc2/src/libs/sound/resinst.c @@ -16,6 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "sound.h" #include "sndintrn.h" static void diff --git a/sc2/src/libs/sound/sfx.c b/sc2/src/libs/sound/sfx.c index 399cf76a4..409874e43 100644 --- a/sc2/src/libs/sound/sfx.c +++ b/sc2/src/libs/sound/sfx.c @@ -16,6 +16,7 @@ #include "options.h" #include "sound.h" +#include "sndintrn.h" #include "libs/reslib.h" #include "libs/log.h" #include "libs/strings/strintrn.h" @@ -27,24 +28,30 @@ static void CheckFinishedChannels (void); void -PlayChannel (COUNT channel, void *sample, SoundPosition pos, +PlayChannel (COUNT channel, SOUND snd, SoundPosition pos, void *positional_object, unsigned char priority) { - TFB_SoundSample *tfb_sample = *(TFB_SoundSample**) sample; + void *snd_ptr = GetSoundAddress (snd); + TFB_SoundSample *sample; StopSource (channel); // all finished (stopped) channels can be cleaned up at this point // since this is the only func that can initiate an sfx sound CheckFinishedChannels (); - soundSource[channel].sample = tfb_sample; + if (!snd_ptr) + return; // nothing to play + + sample = *(TFB_SoundSample**) snd_ptr; + + soundSource[channel].sample = sample; soundSource[channel].positional_object = positional_object; if (optStereoSFX) UpdateSoundPosition (channel, pos); audio_Sourcei (soundSource[channel].handle, audio_BUFFER, - tfb_sample->buffer[0]); + sample->buffer[0]); audio_SourcePlay (soundSource[channel].handle); (void) priority; } @@ -145,39 +152,6 @@ SetChannelVolume (COUNT channel, COUNT volume, BYTE priority) (void)priority; // ignored } -// Status: Ignored -BYTE* -GetSampleAddress (SOUND sound) - // I might be prototyping this wrong, type-wise. -{ - return ((BYTE*)GetSoundAddress (sound)); -} - -// Status: Ignored -COUNT -GetSampleLength (SOUND sound) -{ - (void)sound; - return 0; -} - -// Status: Ignored -void -SetChannelRate (COUNT channel, DWORD rate_hz, unsigned char priority) -{ - (void) channel; - (void) rate_hz; - (void) priority; -} - -// Status: Ignored -COUNT -GetSampleRate (SOUND sound) -{ - (void) sound; - return 0; -} - void * _GetSoundBankData (uio_Stream *fp, DWORD length) { @@ -187,6 +161,8 @@ _GetSoundBankData (uio_Stream *fp, DWORD length) #define MAX_FX 256 TFB_SoundSample *sndfx[MAX_FX]; STRING_TABLE Snd; + STRING str; + int i; (void) length; // ignored opos = uio_ftell (fp); @@ -211,82 +187,65 @@ _GetSoundBankData (uio_Stream *fp, DWORD length) while (uio_fgets (CurrentLine, sizeof (CurrentLine), fp) && snd_ct < MAX_FX) { - if (sscanf(CurrentLine, "%s", &filename[n]) == 1) + TFB_SoundSample* sample; + TFB_SoundDecoder* decoder; + uint32 decoded_bytes; + + if (sscanf (CurrentLine, "%s", &filename[n]) != 1) { - log_add (log_Info, "_GetSoundBankData(): loading %s", filename); - - sndfx[snd_ct] = (TFB_SoundSample *) HCalloc (sizeof (TFB_SoundSample)); - - sndfx[snd_ct]->decoder = SoundDecoder_Load (contentDir, - filename, 4096, 0, 0); - if (!sndfx[snd_ct]->decoder) - { - log_add (log_Warning, "_GetSoundBankData(): couldn't load %s", filename); - HFree (sndfx[snd_ct]); - } - else - { - uint32 decoded_bytes; - - decoded_bytes = SoundDecoder_DecodeAll (sndfx[snd_ct]->decoder); - log_add (log_Info, "_GetSoundBankData(): decoded_bytes %d", decoded_bytes); - - sndfx[snd_ct]->num_buffers = 1; - 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); - - SoundDecoder_Free (sndfx[snd_ct]->decoder); - sndfx[snd_ct]->decoder = NULL; - - ++snd_ct; - } - } - else - { - log_add (log_Warning, "_GetSoundBankData: Bad file!"); + log_add (log_Warning, "_GetSoundBankData: bad line: '%s'", + CurrentLine); + continue; } - // pkunk insult fix 2002/11/12 (ftell shouldn't be needed for loop to terminate) - /*if (uio_ftell (fp) - opos >= length) - break;*/ + log_add (log_Info, "_GetSoundBankData(): loading %s", filename); + + decoder = SoundDecoder_Load (contentDir, filename, 4096, 0, 0); + if (!decoder) + { + log_add (log_Warning, "_GetSoundBankData(): couldn't load %s", + filename); + continue; + } + + // SFX samples don't have decoders, everything is pre-decoded below + sample = TFB_CreateSoundSample (NULL, 1, NULL); + + // Decode everything and stash it in 1 buffer + decoded_bytes = SoundDecoder_DecodeAll (decoder); + log_add (log_Info, "_GetSoundBankData(): decoded bytes %d", + decoded_bytes); + + audio_BufferData (sample->buffer[0], decoder->format, + decoder->buffer, decoded_bytes, decoder->frequency); + // just for informational purposes + sample->length = decoder->length; + + SoundDecoder_Free (decoder); + + sndfx[snd_ct] = sample; + ++snd_ct; } - Snd = NULL; - if (snd_ct && (Snd = AllocStringTable (snd_ct, 0))) + if (!snd_ct) + return NULL; // no sounds decoded + + Snd = AllocStringTable (snd_ct, 0); + if (!Snd) + { // Oops, have to delete everything now + while (snd_ct--) + TFB_DestroySoundSample (sndfx[snd_ct]); + + return NULL; + } + + // Populate the STRING_TABLE with ptrs to sample + for (i = 0, str = Snd->strings; i < snd_ct; ++i, ++str) { - STRING_TABLE fxTab = Snd; - - if (fxTab == 0) - { - while (snd_ct--) - { - if (sndfx[snd_ct]->decoder) - SoundDecoder_Free (sndfx[snd_ct]->decoder); - HFree (sndfx[snd_ct]); - } - - FreeStringTable (Snd); - Snd = 0; - } - else - { - STRING str; - int i; - - str = fxTab->strings; - for (i = 0; i < snd_ct; i++) - { - TFB_SoundSample **target = HMalloc (sizeof (sndfx[0])); - *target = sndfx[i]; - str->data = (STRINGPTR)target; - str->length = sizeof (sndfx[0]); - str++; - } - } + TFB_SoundSample **target = HMalloc (sizeof (sndfx[0])); + *target = sndfx[i]; + str->data = (STRINGPTR)target; + str->length = sizeof (sndfx[0]); } return Snd; @@ -296,45 +255,37 @@ BOOLEAN _ReleaseSoundBankData (void *Snd) { STRING_TABLE fxTab = Snd; + int index; + + if (!fxTab) + return FALSE; - if (fxTab) + for (index = 0; index < fxTab->size; ++index) { - int snd_ct, index; - TFB_SoundSample **sptr; + int i; + void **sptr = (void**)fxTab->strings[index].data; + TFB_SoundSample *sample = (TFB_SoundSample*)*sptr; - snd_ct = fxTab->size; - index = 0; - while (snd_ct--) + // Check all sources and see if we are currently playing this sample + for (i = 0; i < NUM_SOUNDSOURCES; ++i) { - int i; - - sptr = (TFB_SoundSample **)(fxTab->strings[index].data); - - for (i = 0; i < NUM_SOUNDSOURCES; ++i) - { - if (soundSource[i].sample == (*sptr)) - { - StopSource (i); - soundSource[i].sample = NULL; - } + if (soundSource[i].sample == sample) + { // Playing this sample. Have to stop it. + StopSource (i); + soundSource[i].sample = NULL; } - - if ((*sptr)->decoder) - SoundDecoder_Free ((*sptr)->decoder); - audio_DeleteBuffers ((*sptr)->num_buffers, (*sptr)->buffer); - HFree ((*sptr)->buffer); - if ((*sptr)->buffer_tag) - HFree ((*sptr)->buffer_tag); - HFree (*sptr); - *sptr = 0; - index++; } - FreeStringTable (Snd); - return (TRUE); + if (sample->decoder) + SoundDecoder_Free (sample->decoder); + sample->decoder = NULL; + TFB_DestroySoundSample (sample); + // sptr will be deleted by FreeStringTable() below } + + FreeStringTable (fxTab); - return (FALSE); + return TRUE; } BOOLEAN diff --git a/sc2/src/libs/sound/sndintrn.h b/sc2/src/libs/sound/sndintrn.h index 1c35b550a..feb12318e 100644 --- a/sc2/src/libs/sound/sndintrn.h +++ b/sc2/src/libs/sound/sndintrn.h @@ -20,10 +20,12 @@ #define _SNDINTRN_H #include -#include "libs/sndlib.h" +#include "types.h" #include "libs/reslib.h" #include "libs/memlib.h" +#define PAD_SCOPE_BYTES 256 + extern void *_GetMusicData (uio_Stream *fp, DWORD length); extern BOOLEAN _ReleaseMusicData (void *handle); @@ -35,5 +37,40 @@ extern BOOLEAN _ReleaseSoundBankData (void *handle); extern char* CheckMusicResName (char* filename); -#endif /* _SNDINTRN_H */ +// audio data +struct tfb_soundsample +{ + TFB_SoundDecoder *decoder; // decoder to read from + float length; // total length of decoder chain in seconds + audio_Object *buffer; + uint32 num_buffers; + TFB_SoundTag *buffer_tag; + sint32 offset; // initial offset + intptr_t data; // user-defined data + TFB_SoundCallbacks callbacks; // user-defined callbacks +}; +// equivalent to channel in legacy sound code +typedef struct tfb_soundsource +{ + TFB_SoundSample *sample; + audio_Object handle; + bool stream_should_be_playing; + Mutex stream_mutex; + sint32 start_time; // for tracks played-time math + uint32 pause_time; // keep track for paused tracks + void *positional_object; + + audio_Object last_q_buf; // for callbacks processing + + // Cyclic waveform buffer for oscilloscope + void *sbuffer; + uint32 sbuf_size; + uint32 sbuf_tail; + uint32 sbuf_head; + uint32 sbuf_lasttime; // timestamp of the first queued buffer +} TFB_SoundSource; + +extern TFB_SoundSource soundSource[]; + +#endif /* _SNDINTRN_H */ diff --git a/sc2/src/libs/sound/sound.c b/sc2/src/libs/sound/sound.c index 147ff1eef..137f4fd6e 100644 --- a/sc2/src/libs/sound/sound.c +++ b/sc2/src/libs/sound/sound.c @@ -17,6 +17,7 @@ */ #include "sound.h" +#include "sndintrn.h" #include "libs/compiler.h" #include "libs/tasklib.h" #include "libs/inplib.h" diff --git a/sc2/src/libs/sound/sound.h b/sc2/src/libs/sound/sound.h index d77db235e..311f43037 100644 --- a/sc2/src/libs/sound/sound.h +++ b/sc2/src/libs/sound/sound.h @@ -17,10 +17,11 @@ #ifndef _UQM_SOUND_H // try avoiding collisions on id #define _UQM_SOUND_H -#include "sndintrn.h" +#include "types.h" #include "audiocore.h" #include "decoders/decoder.h" #include "libs/threadlib.h" +#include "libs/sndlib.h" #define FIRST_SFX_SOURCE 0 @@ -28,13 +29,12 @@ #define MUSIC_SOURCE (LAST_SFX_SOURCE + 1) #define SPEECH_SOURCE (MUSIC_SOURCE + 1) #define NUM_SOUNDSOURCES (SPEECH_SOURCE + 1) -#define PAD_SCOPE_BYTES 8096 typedef struct { int in_use; audio_Object buf_name; - void *data; // user-defined data + intptr_t data; // user-defined data } TFB_SoundTag; typedef struct tfb_soundcallbacks @@ -51,41 +51,6 @@ typedef struct tfb_soundcallbacks void (* OnQueueBuffer) (TFB_SoundSample*, audio_Object); } TFB_SoundCallbacks; -// audio data -struct tfb_soundsample -{ - TFB_SoundDecoder *decoder; // decoder to read from - float length; // total length of decoder chain in seconds - audio_Object *buffer; - uint32 num_buffers; - TFB_SoundTag *buffer_tag; - sint32 offset; // initial offset - void* data; // user-defined data - TFB_SoundCallbacks callbacks; // user-defined callbacks -}; - -// equivalent to channel in legacy sound code -typedef struct tfb_soundsource -{ - TFB_SoundSample *sample; - audio_Object handle; - bool stream_should_be_playing; - Mutex stream_mutex; - sint32 start_time; - void *positional_object; - - // Cyclic waveform buffer for oscilloscope - void *sbuffer; - uint32 sbuf_start; // cyclic buffer tail (confusing, eh?) - uint32 sbuf_size; - uint32 sbuf_offset; // cyclic buffer head - uint32 sbuf_lasttime; - // keep track for paused tracks - uint32 pause_time; -} TFB_SoundSource; - - -extern TFB_SoundSource soundSource[]; extern int musicVolume; extern float musicVolumeScale; @@ -98,6 +63,19 @@ void CleanSource (int iSource); void SetSFXVolume (float volume); void SetSpeechVolume (float volume); +TFB_SoundSample *TFB_CreateSoundSample (TFB_SoundDecoder*, uint32 num_buffers, + const TFB_SoundCallbacks* /* can be NULL */); +void TFB_DestroySoundSample (TFB_SoundSample*); +void TFB_SetSoundSampleData (TFB_SoundSample*, intptr_t data); +intptr_t TFB_GetSoundSampleData (TFB_SoundSample*); +void TFB_SetSoundSampleCallbacks (TFB_SoundSample*, + const TFB_SoundCallbacks* /* can be NULL */); +TFB_SoundDecoder* TFB_GetSoundSampleDecoder (TFB_SoundSample*); + +TFB_SoundTag* TFB_FindTaggedBuffer (TFB_SoundSample*, audio_Object buffer); +void TFB_ClearBufferTag (TFB_SoundTag*); +bool TFB_TagBuffer (TFB_SoundSample*, audio_Object buffer, intptr_t data); + #include "stream.h" #endif // _UQM_SOUND_H diff --git a/sc2/src/libs/sound/stream.c b/sc2/src/libs/sound/stream.c index 3dad64be4..98c2caee6 100644 --- a/sc2/src/libs/sound/stream.c +++ b/sc2/src/libs/sound/stream.c @@ -19,17 +19,22 @@ #include // for abs() #include "sound.h" +#include "sndintrn.h" #include "libs/tasklib.h" #include "libs/log.h" #include "libs/memlib.h" +static void add_scope_data (TFB_SoundSource *source, uint32 bytes); + + void PlayStream (TFB_SoundSample *sample, uint32 source, bool looping, bool scope, bool rewind) { - uint32 i, pos = 0; - sint32 offset = 0; + uint32 i; + sint32 offset; + TFB_SoundDecoder *decoder; if (!sample) return; @@ -43,64 +48,65 @@ PlayStream (TFB_SoundSample *sample, uint32 source, bool looping, bool scope, memset (sample->buffer_tag, 0, sample->num_buffers * sizeof (sample->buffer_tag[0])); + decoder = sample->decoder; offset = sample->offset; if (rewind) - SoundDecoder_Rewind (sample->decoder); + SoundDecoder_Rewind (decoder); else - offset += (sint32)(SoundDecoder_GetTime (sample->decoder) * - (float)ONE_SECOND); + offset += (sint32)(SoundDecoder_GetTime (decoder) * ONE_SECOND); + soundSource[source].sample = sample; - soundSource[source].sample->decoder->looping = looping; + decoder->looping = looping; audio_Sourcei (soundSource[source].handle, audio_LOOPING, false); if (scope) - { - soundSource[source].sbuffer = HMalloc (PAD_SCOPE_BYTES); + { // Prealloc the scope buffer in advance so that we do not + // realloc it a zillion times + soundSource[source].sbuf_size = sample->num_buffers * + decoder->buffer_size + PAD_SCOPE_BYTES; + soundSource[source].sbuffer = HMalloc (soundSource[source].sbuf_size); } for (i = 0; i < sample->num_buffers; ++i) { uint32 decoded_bytes; - decoded_bytes = SoundDecoder_Decode (sample->decoder); + decoded_bytes = SoundDecoder_Decode (decoder); #if 0 - log_add (log_Debug, "PlayStream(): source:%d filename:%s start:%d position:%d bytes:%d\n", - source, sample->decoder->filename, sample->decoder->start_sample, - sample->decoder->pos, decoded_bytes); + log_add (log_Debug, "PlayStream(): source:%d filename:%s start:%d " + "position:%d bytes:%d\n", + source, decoder->filename, decoder->start_sample, + decoder->pos, decoded_bytes); #endif if (decoded_bytes == 0) break; - audio_BufferData (sample->buffer[i], sample->decoder->format, - sample->decoder->buffer, decoded_bytes, - sample->decoder->frequency); + audio_BufferData (sample->buffer[i], decoder->format, + decoder->buffer, decoded_bytes, decoder->frequency); audio_SourceQueueBuffers (soundSource[source].handle, 1, &sample->buffer[i]); if (sample->callbacks.OnQueueBuffer) sample->callbacks.OnQueueBuffer (sample, sample->buffer[i]); if (scope) - { - UBYTE *p; - soundSource[source].sbuffer = HRealloc ( - soundSource[source].sbuffer, - pos + decoded_bytes + PAD_SCOPE_BYTES); - p = (UBYTE *)soundSource[source].sbuffer; - memcpy (&p[pos], sample->decoder->buffer, decoded_bytes); - pos += decoded_bytes; - } + add_scope_data (&soundSource[source], decoded_bytes); - if (sample->decoder->error) + if (decoder->error != SOUNDDECODER_OK) { - if (sample->decoder->error != SOUNDDECODER_EOF || + if (decoder->error != SOUNDDECODER_EOF || !sample->callbacks.OnEndChunk || !sample->callbacks.OnEndChunk (sample, sample->buffer[i])) + { // Decoder probably run out of data before we could fill + // all buffers, and OnEndChunk() did not set a new one break; + } + else + { // OnEndChunk() probably set a new decoder, get it + decoder = sample->decoder; + } } } - soundSource[source].sbuf_size = pos + PAD_SCOPE_BYTES; - soundSource[source].sbuf_start = pos; soundSource[source].sbuf_lasttime = GetTimeCounter (); // Adjust the start time so it looks like the stream has been playing // from the very beginning @@ -124,9 +130,9 @@ StopStream (uint32 source) soundSource[source].sbuffer = NULL; HFree (sbuffer); } - soundSource[source].sbuf_start = 0; soundSource[source].sbuf_size = 0; - soundSource[source].sbuf_offset = 0; + soundSource[source].sbuf_head = 0; + soundSource[source].sbuf_tail = 0; soundSource[source].pause_time = 0; } @@ -176,11 +182,73 @@ PlayingStream (uint32 source) return soundSource[source].stream_should_be_playing; } + +TFB_SoundSample * +TFB_CreateSoundSample (TFB_SoundDecoder *decoder, uint32 num_buffers, + const TFB_SoundCallbacks *pcbs /* can be NULL */) +{ + TFB_SoundSample *sample; + + sample = HCalloc (sizeof (*sample)); + sample->decoder = decoder; + sample->num_buffers = num_buffers; + sample->buffer = HCalloc (sizeof (audio_Object) * num_buffers); + audio_GenBuffers (num_buffers, sample->buffer); + if (pcbs) + sample->callbacks = *pcbs; + + return sample; +} + +// Deletes all TFB_SoundSample data structures, except decoder +void +TFB_DestroySoundSample (TFB_SoundSample *sample) +{ + if (sample->buffer) + { + audio_DeleteBuffers (sample->num_buffers, sample->buffer); + HFree (sample->buffer); + } + HFree (sample->buffer_tag); + HFree (sample); +} + +void +TFB_SetSoundSampleData (TFB_SoundSample *sample, intptr_t data) +{ + sample->data = data; +} + +intptr_t +TFB_GetSoundSampleData (TFB_SoundSample *sample) +{ + return sample->data; +} + +void +TFB_SetSoundSampleCallbacks (TFB_SoundSample *sample, + const TFB_SoundCallbacks *pcbs /* can be NULL */) +{ + if (pcbs) + sample->callbacks = *pcbs; + else + memset (&sample->callbacks, 0, sizeof (sample->callbacks)); +} + +TFB_SoundDecoder* +TFB_GetSoundSampleDecoder (TFB_SoundSample *sample) +{ + return sample->decoder; +} + TFB_SoundTag* -TFB_FindTaggedBuffer (TFB_SoundSample* sample, audio_Object buffer) +TFB_FindTaggedBuffer (TFB_SoundSample *sample, audio_Object buffer) { uint32 buf_num; + if (!sample->buffer_tag) + return NULL; // do not have any tags + for (buf_num = 0; buf_num < sample->num_buffers && (!sample->buffer_tag[buf_num].in_use || @@ -193,11 +261,15 @@ TFB_FindTaggedBuffer (TFB_SoundSample* sample, audio_Object buffer) &sample->buffer_tag[buf_num] : NULL; } -void -TFB_TagBuffer (TFB_SoundSample* sample, audio_Object buffer, void* data) +bool +TFB_TagBuffer (TFB_SoundSample *sample, audio_Object buffer, intptr_t data) { uint32 buf_num; + if (!sample->buffer_tag) + sample->buffer_tag = HCalloc (sizeof (TFB_SoundTag) * + sample->num_buffers); + for (buf_num = 0; buf_num < sample->num_buffers && sample->buffer_tag[buf_num].in_use && @@ -206,258 +278,247 @@ TFB_TagBuffer (TFB_SoundSample* sample, audio_Object buffer, void* data) ; if (buf_num >= sample->num_buffers) - return; // no empty slot + return false; // no empty slot sample->buffer_tag[buf_num].in_use = 1; sample->buffer_tag[buf_num].buf_name = buffer; sample->buffer_tag[buf_num].data = data; + + return true; } void -TFB_ClearBufferTag (TFB_SoundTag* ptag) +TFB_ClearBufferTag (TFB_SoundTag *ptag) { ptag->in_use = 0; ptag->buf_name = 0; } +static void +remove_scope_data (TFB_SoundSource *source, audio_Object buffer) +{ + audio_IntVal buf_size; + + audio_GetBufferi (buffer, audio_SIZE, &buf_size); + source->sbuf_head += buf_size; + // the buffer is cyclic + source->sbuf_head %= source->sbuf_size; + + source->sbuf_lasttime = GetTimeCounter (); +} + +static void +add_scope_data (TFB_SoundSource *source, uint32 bytes) +{ + uint8 *sbuffer = source->sbuffer; + uint8 *dec_buf = source->sample->decoder->buffer; + uint32 tail_bytes; + uint32 wrap_bytes; + + if (source->sbuf_tail + bytes > source->sbuf_size) + { // does not fit at the tail, have to split it up + tail_bytes = source->sbuf_size - source->sbuf_tail; + wrap_bytes = bytes - tail_bytes; + } + else + { // all fits at the tail + tail_bytes = bytes; + wrap_bytes = 0; + } + + if (tail_bytes) + { + memcpy (sbuffer + source->sbuf_tail, dec_buf, tail_bytes); + source->sbuf_tail += tail_bytes; + } + + if (wrap_bytes) + { + memcpy (sbuffer, dec_buf + tail_bytes, wrap_bytes); + source->sbuf_tail = wrap_bytes; + } +} + +static void +process_stream (TFB_SoundSource *source) +{ + TFB_SoundSample *sample = source->sample; + TFB_SoundDecoder *decoder = sample->decoder; + bool end_chunk_failed = false; + audio_IntVal processed; + audio_IntVal queued; + + audio_GetSourcei (source->handle, audio_BUFFERS_PROCESSED, &processed); + audio_GetSourcei (source->handle, audio_BUFFERS_QUEUED, &queued); + + if (processed == 0) + { // Nothing was played + audio_IntVal state; + + audio_GetSourcei (source->handle, audio_SOURCE_STATE, &state); + if (state != audio_PLAYING) + { + if (queued == 0 && decoder->error == SOUNDDECODER_EOF) + { // The stream has reached the end + log_add (log_Info, "StreamDecoderTaskFunc(): " + "finished playing %s", decoder->filename); + source->stream_should_be_playing = FALSE; + + if (sample->callbacks.OnEndStream) + sample->callbacks.OnEndStream (sample); + } + else + { + log_add (log_Warning, "StreamDecoderTaskFunc(): " + "buffer underrun playing %s", decoder->filename); + audio_SourcePlay (source->handle); + } + } + } + + // Unqueue processed buffers and replace them with new ones + for (processed; processed > 0; --processed) + { + uint32 error; + audio_Object buffer; + uint32 decoded_bytes; + + audio_GetError (); // clear error state + + // Get the buffer that finished playing + audio_SourceUnqueueBuffers (source->handle, 1, &buffer); + error = audio_GetError(); + if (error != audio_NO_ERROR) + { + log_add (log_Warning, "StreamDecoderTaskFunc(): " + "error after audio_SourceUnqueueBuffers: %x, file %s", + error, decoder->filename); + break; + } + + // Process a callback on a tagged buffer, if any + if (sample->callbacks.OnTaggedBuffer) + { + TFB_SoundTag* tag = TFB_FindTaggedBuffer (sample, buffer); + if (tag) + sample->callbacks.OnTaggedBuffer (sample, tag); + } + + if (source->sbuffer) + remove_scope_data (source, buffer); + + // See what state the decoder was left in last time around + if (decoder->error != SOUNDDECODER_OK) + { + if (decoder->error == SOUNDDECODER_EOF) + { + if (end_chunk_failed) + continue; // should not do it again + + if (!sample->callbacks.OnEndChunk || + !sample->callbacks.OnEndChunk (sample, source->last_q_buf)) + { // Reached the end of the current stream and we did not + // get another sample to play (relevant for Trackplayer) + end_chunk_failed = true; + continue; + } + else + { // OnEndChunk succeeded, so someone (read: Trackplayer) + // wants to keep going, probably with a new decoder. + // Get the new decoder + decoder = sample->decoder; + } + } + else + { // Decoder returned a real error, keep going +#if 0 + log_add (log_Debug, "StreamDecoderTaskFunc(): " + "decoder->error is %d for %s", decoder->error, + decoder->filename); +#endif + continue; + } + } + + // Now replace the unqueued buffer with a new one + decoded_bytes = SoundDecoder_Decode (decoder); + if (decoder->error == SOUNDDECODER_ERROR) + { + log_add (log_Warning, "StreamDecoderTaskFunc(): " + "SoundDecoder_Decode error %d, file %s", + decoder->error, decoder->filename); + source->stream_should_be_playing = FALSE; + continue; + } + + if (decoded_bytes == 0) + { // Nothing was decoded, keep going + continue; + // This loses a stream buffer, which we cannot get back + // w/o restarting the stream, but we should never get here. + } + + // And a new buffer is born + audio_BufferData (buffer, decoder->format, decoder->buffer, + decoded_bytes, decoder->frequency); + error = audio_GetError(); + if (error != audio_NO_ERROR) + { + log_add (log_Warning, "StreamDecoderTaskFunc(): " + "error after audio_BufferData: %x, file %s, decoded %d", + error, decoder->filename, decoded_bytes); + continue; + } + + // Now queue the buffer + audio_SourceQueueBuffers (source->handle, 1, &buffer); + error = audio_GetError(); + if (error != audio_NO_ERROR) + { + log_add (log_Warning, "StreamDecoderTaskFunc(): " + "error after audio_SourceQueueBuffers: %x, file %s, " + "decoded %d", error, decoder->filename, decoded_bytes); + continue; + } + + // Remember the last queued buffer so we can pass it to callbacks + source->last_q_buf = buffer; + if (sample->callbacks.OnQueueBuffer) + sample->callbacks.OnQueueBuffer (sample, buffer); + + if (source->sbuffer) + add_scope_data (source, decoded_bytes); + } +} + int StreamDecoderTaskFunc (void *data) { Task task = (Task)data; int i; - audio_Object last_buffer[NUM_SOUNDSOURCES]; - - for (i = 0; i < NUM_SOUNDSOURCES; i++) - last_buffer[i] = 0; - + while (!Task_ReadState (task, TASK_EXIT)) { - TaskSwitch (); for (i = MUSIC_SOURCE; i < NUM_SOUNDSOURCES; ++i) { - audio_IntVal processed, queued; - audio_IntVal state; + TFB_SoundSource *source = &soundSource[i]; - LockMutex (soundSource[i].stream_mutex); + LockMutex (source->stream_mutex); - if (!soundSource[i].sample || - !soundSource[i].sample->decoder || - !soundSource[i].stream_should_be_playing || - soundSource[i].sample->decoder->error == SOUNDDECODER_ERROR) + if (!source->sample || + !source->sample->decoder || + !source->stream_should_be_playing || + source->sample->decoder->error == SOUNDDECODER_ERROR) { - UnlockMutex (soundSource[i].stream_mutex); + UnlockMutex (source->stream_mutex); continue; } - audio_GetSourcei (soundSource[i].handle, audio_BUFFERS_PROCESSED, - &processed); - audio_GetSourcei (soundSource[i].handle, audio_BUFFERS_QUEUED, - &queued); + process_stream (source); - if (processed == 0) - { - audio_GetSourcei (soundSource[i].handle, audio_SOURCE_STATE, - &state); - if (state != audio_PLAYING) - { - if (queued == 0 && soundSource[i].sample->decoder->error - == SOUNDDECODER_EOF) - { - log_add (log_Info, "StreamDecoderTaskFunc(): " - "finished playing %s, source %d", - soundSource[i].sample->decoder->filename, i); - soundSource[i].stream_should_be_playing = FALSE; - if (soundSource[i].sample->callbacks.OnEndStream) - soundSource[i].sample->callbacks.OnEndStream ( - soundSource[i].sample); - } - else - { - log_add (log_Warning, "StreamDecoderTaskFunc(): buffer " - "underrun when playing %s, source %d", - soundSource[i].sample->decoder->filename, i); - audio_SourcePlay (soundSource[i].handle); - } - } - } - -#if 0 - log_add (log_Debug, "StreamDecoderTaskFunc(): source %d, processed %d queued %d", - i, processed, queued); -#endif - - while (processed) - { - uint32 error; - audio_Object buffer; - uint32 decoded_bytes; - - audio_GetError (); // clear error state - - audio_SourceUnqueueBuffers (soundSource[i].handle, 1, &buffer); - - error = audio_GetError(); - if (error != audio_NO_ERROR) - { - log_add (log_Warning, "StreamDecoderTaskFunc(): OpenAL " - "error after alSourceUnqueueBuffers: %x, " - "file %s, source %d", error, - soundSource[i].sample->decoder->filename, i); - break; - } - - if (soundSource[i].sample->callbacks.OnTaggedBuffer) - { - TFB_SoundTag* tag = TFB_FindTaggedBuffer ( - soundSource[i].sample, buffer); - if (tag) - { - soundSource[i].sample->callbacks.OnTaggedBuffer ( - soundSource[i].sample, tag); - } - } - { - audio_IntVal buf_size; - soundSource[i].sbuf_lasttime = GetTimeCounter (); - 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; - } - //soundSource[i].total_decoded += soundSource[i].sample->decoder->buffer_size; - - if (soundSource[i].sample->decoder->error) - { - if (soundSource[i].sample->decoder->error == - SOUNDDECODER_EOF) - { - if (!soundSource[i].sample->callbacks.OnEndChunk || - !soundSource[i].sample->callbacks.OnEndChunk ( - soundSource[i].sample, last_buffer[i])) - { -#if 0 - log_add (log_Debug, "StreamDecoderTaskFunc(): decoder->error is eof for %s", - soundSource[i].sample->decoder->filename); -#endif - processed--; - continue; - } - } - else - { -#if 0 - log_add (log_Debug, "StreamDecoderTaskFunc(): decoder->error is %d for %s", - soundSource[i].sample->decoder->error, - soundSource[i].sample->decoder->filename); -#endif - processed--; - continue; - } - } - - decoded_bytes = SoundDecoder_Decode ( - soundSource[i].sample->decoder); - if (soundSource[i].sample->decoder->error == - SOUNDDECODER_ERROR) - { - log_add (log_Warning, "StreamDecoderTaskFunc(): " - "SoundDecoder_Decode error %d, file %s, " - "source %d", - soundSource[i].sample->decoder->error, - soundSource[i].sample->decoder->filename, i); - soundSource[i].stream_should_be_playing = FALSE; - processed--; - continue; - } - - if (decoded_bytes > 0) - { - audio_BufferData (buffer, - soundSource[i].sample->decoder->format, - soundSource[i].sample->decoder->buffer, - decoded_bytes, - soundSource[i].sample->decoder->frequency); - - error = audio_GetError(); - if (error != audio_NO_ERROR) - { - log_add (log_Warning, "StreamDecoderTaskFunc(): " - "TFBSound error after audio_BufferData: " - "%x, file %s, source %d, decoded_bytes %d", - error, soundSource[i].sample->decoder->filename, - i, decoded_bytes); - } - else - { - last_buffer[i] = buffer; - audio_SourceQueueBuffers (soundSource[i].handle, 1, - &buffer); - // do OnQueue callback - if (soundSource[i].sample->callbacks.OnQueueBuffer) - soundSource[i].sample->callbacks.OnQueueBuffer ( - soundSource[i].sample, buffer); - - if (soundSource[i].sbuffer) - { - // copies decoded data to oscilloscope buffer - - uint32 j, remaining_bytes = 0; - UBYTE *sbuffer = (UBYTE *) soundSource[i].sbuffer; - UBYTE *decoder_buffer = (UBYTE *) soundSource[i]. - sample->decoder->buffer; - - if (soundSource[i].sbuf_start + decoded_bytes > - soundSource[i].sbuf_size) - { - j = soundSource[i].sbuf_size; - remaining_bytes = decoded_bytes - - (j - soundSource[i].sbuf_start); - } - else - { - j = soundSource[i].sbuf_start + decoded_bytes; - } - - if (j - soundSource[i].sbuf_start >= 1) - { - memcpy (&sbuffer[soundSource[i].sbuf_start], - decoder_buffer, - j - soundSource[i].sbuf_start); - } - - if (remaining_bytes) - { - memcpy (sbuffer, &decoder_buffer[ - j - soundSource[i].sbuf_start], - remaining_bytes); - soundSource[i].sbuf_start = remaining_bytes; - } - else - { - soundSource[i].sbuf_start += decoded_bytes; - } - } - - error = audio_GetError(); - if (error != audio_NO_ERROR) - { - log_add (log_Warning, "StreamDecoderTaskFunc(): " - "TFBSound error after " - "audio_SourceQueueBuffers: %x, file %s, " - "source %d, decoded_bytes %d", error, - soundSource[i].sample->decoder->filename, - i, decoded_bytes); - } - } - } - - processed--; - } - - UnlockMutex (soundSource[i].stream_mutex); + UnlockMutex (source->stream_mutex); } } @@ -582,7 +643,7 @@ GraphForegroundStream (uint8 *data, sint32 width, sint32 height) step *= full_sample; sbuffer = source->sbuffer; - pos = source->sbuf_offset + delta; + pos = source->sbuf_head + delta; // We are not basing the scaling factor on signal energy, because we // want it to *look* pretty instead of sounding nice and even diff --git a/sc2/src/libs/sound/stream.h b/sc2/src/libs/sound/stream.h index aac8f2841..65db328c5 100644 --- a/sc2/src/libs/sound/stream.h +++ b/sc2/src/libs/sound/stream.h @@ -26,10 +26,6 @@ void SeekStream (uint32 source, uint32 pos); BOOLEAN PlayingStream (uint32 source); int StreamDecoderTaskFunc (void *data); -TFB_SoundTag* FindTaggedBuffer (TFB_SoundSample* sample, audio_Object buffer); -void TFB_ClearBufferTag (TFB_SoundTag* ptag); -void TFB_TagBuffer (TFB_SoundSample* sample, audio_Object buffer, void* data); - int GraphForegroundStream (uint8 *data, sint32 width, sint32 height); #endif diff --git a/sc2/src/libs/sound/trackplayer.c b/sc2/src/libs/sound/trackplayer.c index 1d841fa24..01cf57131 100644 --- a/sc2/src/libs/sound/trackplayer.c +++ b/sc2/src/libs/sound/trackplayer.c @@ -15,6 +15,7 @@ */ #include "sound.h" +#include "sndintrn.h" #include "libs/sound/trackplayer.h" #include "trackint.h" #include "libs/log.h" @@ -54,7 +55,6 @@ static TFB_SoundChunk *cur_sub_chunk; // currently displayed subtitle chunk // structures the same way. static void seek_track (sint32 offset); -static void destroy_SoundSample (TFB_SoundSample *sample); // stream callbacks static bool OnStreamStart (TFB_SoundSample* sample); @@ -190,7 +190,9 @@ StopTrack (void) } if (sound_sample) { - destroy_SoundSample (sound_sample); + // We delete the decoders ourselves + sound_sample->decoder = NULL; + TFB_DestroySoundSample (sound_sample); sound_sample = NULL; } } @@ -250,7 +252,7 @@ OnChunkEnd (TFB_SoundSample* sample, audio_Object buffer) if (cur_chunk->tag_me) { // Tag the last buffer of the chunk with the next chunk - TFB_TagBuffer (sample, buffer, cur_chunk); + TFB_TagBuffer (sample, buffer, (intptr_t)cur_chunk); } return true; @@ -276,6 +278,8 @@ OnBufferTag (TFB_SoundSample* sample, TFB_SoundTag* tag) { TFB_SoundChunk* chunk = (TFB_SoundChunk*) tag->data; + assert (sizeof (tag->data) >= sizeof (chunk)); + if (sample != sound_sample) return; // Huh? Why did we get called on this? @@ -562,13 +566,7 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, TFB_Tra if (!sound_sample) { - sound_sample = HCalloc (sizeof (*sound_sample)); - sound_sample->callbacks = trackCBs; - sound_sample->num_buffers = 8; - sound_sample->buffer_tag = HCalloc (sizeof (TFB_SoundTag) * sound_sample->num_buffers); - sound_sample->buffer = HCalloc (sizeof (audio_Object) * sound_sample->num_buffers); - sound_sample->length = 0; - audio_GenBuffers (sound_sample->num_buffers, sound_sample->buffer); + sound_sample = TFB_CreateSoundSample (NULL, 8, &trackCBs); chunks_head = create_SoundChunk (decoder, 0.0); chunks_tail = chunks_head; } @@ -800,19 +798,6 @@ destroy_SoundChunk_list (TFB_SoundChunk *chunk) } } -static void -destroy_SoundSample (TFB_SoundSample *sample) -{ - if (sample->buffer) - { - audio_DeleteBuffers (sample->num_buffers, sample->buffer); - HFree (sample->buffer); - } - HFree (sample->buffer_tag); - HFree (sample->data); - HFree (sample); -} - // Returns the next chunk with a subtitle TFB_SoundChunk * find_next_page (TFB_SoundChunk *cur) diff --git a/sc2/src/libs/video/vidplayer.c b/sc2/src/libs/video/vidplayer.c index 1ddc6dc05..ade2820dc 100644 --- a/sc2/src/libs/video/vidplayer.c +++ b/sc2/src/libs/video/vidplayer.c @@ -31,7 +31,7 @@ static uint32 vp_GetTicks (TFB_VideoDecoder*); static bool vp_SetTimer (TFB_VideoDecoder*, uint32 msecs); -TFB_VideoCallbacks vp_DecoderCBs = +static const TFB_VideoCallbacks vp_DecoderCBs = { vp_BeginFrame, vp_EndFrame, @@ -46,7 +46,7 @@ static void vp_AudioEnd (TFB_SoundSample* sample); static void vp_BufferTag (TFB_SoundSample* sample, TFB_SoundTag* tag); static void vp_QueueBuffer (TFB_SoundSample* sample, audio_Object buffer); -static TFB_SoundCallbacks vp_AudioCBs = +static const TFB_SoundCallbacks vp_AudioCBs = { vp_AudioStart, NULL, @@ -307,8 +307,6 @@ TFB_PlayVideo (VIDEO_REF vid, uint32 x, uint32 y) if (vid->decoder->audio_synced) { - TFB_SoundSample **pmus; - if (!vid->hAudio) { log_add (log_Warning, "TFB_PlayVideo: " @@ -316,12 +314,8 @@ TFB_PlayVideo (VIDEO_REF vid, uint32 x, uint32 y) return false; } - // nasty hack for now - pmus = vid->hAudio; - (*pmus)->buffer_tag = HCalloc ( - sizeof (TFB_SoundTag) * (*pmus)->num_buffers); - (*pmus)->callbacks = vp_AudioCBs; - (*pmus)->data = vid; // hijack data ;) + TFB_SetSoundSampleCallbacks (*vid->hAudio, &vp_AudioCBs); + TFB_SetSoundSampleData (*vid->hAudio, (intptr_t)vid); } SetSemaphore (vp_interthread_lock); @@ -406,9 +400,7 @@ TFB_SeekVideo (VIDEO_REF vid, uint32 pos) if (vid->decoder->audio_synced) { - LockMutex (soundSource[MUSIC_SOURCE].stream_mutex); - SeekStream (MUSIC_SOURCE, pos); - UnlockMutex (soundSource[MUSIC_SOURCE].stream_mutex); + PLRSeek (vid->hAudio, pos); TaskSwitch (); return true; } @@ -475,10 +467,16 @@ vp_SetTimer (TFB_VideoDecoder* decoder, uint32 msecs) static bool vp_AudioStart (TFB_SoundSample* sample) { - TFB_VideoClip* vid = sample->data; + TFB_VideoClip* vid = (TFB_VideoClip*) TFB_GetSoundSampleData (sample); + TFB_SoundDecoder *decoder; + + assert (sizeof (intptr_t) >= sizeof (vid)); + assert (vid != NULL); + + decoder = TFB_GetSoundSampleDecoder (sample); LockMutex (vid->guard); - vid->want_frame = SoundDecoder_GetFrame (sample->decoder); + vid->want_frame = SoundDecoder_GetFrame (decoder); UnlockMutex (vid->guard); return true; @@ -487,7 +485,9 @@ vp_AudioStart (TFB_SoundSample* sample) static void vp_AudioEnd (TFB_SoundSample* sample) { - TFB_VideoClip* vid = sample->data; + TFB_VideoClip* vid = (TFB_VideoClip*) TFB_GetSoundSampleData (sample); + + assert (vid != NULL); LockMutex (vid->guard); vid->want_frame = vid->decoder->frame_count; // end it @@ -497,9 +497,12 @@ vp_AudioEnd (TFB_SoundSample* sample) static void vp_BufferTag (TFB_SoundSample* sample, TFB_SoundTag* tag) { - TFB_VideoClip* vid = sample->data; - uint32 frame = (uint32) (intptr_t) tag->data; - + TFB_VideoClip* vid = (TFB_VideoClip*) TFB_GetSoundSampleData (sample); + uint32 frame = (uint32) tag->data; + + assert (sizeof (tag->data) >= sizeof (frame)); + assert (vid != NULL); + LockMutex (vid->guard); vid->want_frame = frame; // let it go! UnlockMutex (vid->guard); @@ -508,9 +511,10 @@ vp_BufferTag (TFB_SoundSample* sample, TFB_SoundTag* tag) static void vp_QueueBuffer (TFB_SoundSample* sample, audio_Object buffer) { - //TFB_VideoClip* vid = sample->data; + //TFB_VideoClip* vid = (TFB_VideoClip*) TFB_GetSoundSampleData (sample); + TFB_SoundDecoder *decoder = TFB_GetSoundSampleDecoder (sample); TFB_TagBuffer (sample, buffer, - (void *) (intptr_t) SoundDecoder_GetFrame (sample->decoder)); + (intptr_t) SoundDecoder_GetFrame (decoder)); } diff --git a/sc2/src/uqm/settings.c b/sc2/src/uqm/settings.c index 8b9b7bd6c..3e959a1c0 100644 --- a/sc2/src/uqm/settings.c +++ b/sc2/src/uqm/settings.c @@ -90,8 +90,8 @@ PlaySoundEffect (SOUND S, COUNT Channel, SoundPosition Pos, if (!(GLOBAL (glob_flags) & SOUND_DISABLED)) { SetChannelVolume (Channel, MAX_VOLUME >> 1, Priority); - SetChannelRate (Channel, GetSampleRate (S), Priority); - PlayChannel (Channel, GetSampleAddress (S), Pos, PositionalObject, Priority); + //SetChannelRate (Channel, GetSampleRate (S), Priority); + PlayChannel (Channel, S, Pos, PositionalObject, Priority); } }