diff --git a/sc2/src/sc2code/comm.c b/sc2/src/sc2code/comm.c index 30d52e80d..7fe90664b 100644 --- a/sc2/src/sc2code/comm.c +++ b/sc2/src/sc2code/comm.c @@ -25,6 +25,7 @@ #include "options.h" #include "comm.h" #include "libs/sound/sound.h" +#include "libs/sound/trackint.h" #include "controls.h" #include "endian_uqm.h" @@ -1661,7 +1662,6 @@ DoCommunication (PENCOUNTER_STATE pES) else if (CurrentMenuState.cancel && LOBYTE (GLOBAL (CurrentActivity)) != WON_LAST_BATTLE) { - extern TFB_SoundChain *first_chain; TFB_SoundChain *curr; RECT r; TEXT t; @@ -1703,7 +1703,7 @@ DoCommunication (PENCOUNTER_STATE pES) for (curr = first_chain; curr != NULL; curr = curr->next) { - temp = curr->tag.data; + temp = curr->text; if (temp == NULL) continue; // fprintf (stderr, "%s\n", temp); diff --git a/sc2/src/sc2code/commglue.c b/sc2/src/sc2code/commglue.c index 5000c4c84..b416e51cd 100644 --- a/sc2/src/sc2code/commglue.c +++ b/sc2/src/sc2code/commglue.c @@ -18,14 +18,13 @@ #include "starcon.h" #include "commglue.h" -#include "libs/sound/trackplayer.h" #include #include int NPCNumberPhrase (int number, UNICODE **ptrack); void -NPCPhrase_cb (int index, void (*cb) (void)) +NPCPhrase_cb (int index, TFB_TrackCB cb) { UNICODE *pStr, numbuf[100]; void *pClip, *pTimeStamp; diff --git a/sc2/src/sc2code/commglue.h b/sc2/src/sc2code/commglue.h index 1f42ea048..d14130f56 100644 --- a/sc2/src/sc2code/commglue.h +++ b/sc2/src/sc2code/commglue.h @@ -19,6 +19,8 @@ #ifndef _COMMGLUE_H #define _COMMGLUE_H +#include "libs/sound/trackplayer.h" + extern LOCDATA CommData; extern int cur_comm; extern UNICODE shared_phrase_buf[256]; @@ -55,7 +57,7 @@ extern void DoResponsePhrase (RESPONSE_REF R, RESPONSE_FUNC response_func, UNICODE *ContstructStr); extern void DoNPCPhrase (UNICODE *pStr); -extern void NPCPhrase_cb (int index, void (*cb) (void)); +extern void NPCPhrase_cb (int index, TFB_TrackCB cb); #define NPCPhrase(index) NPCPhrase_cb ((index), NULL) extern void GetAllianceName (UNICODE *buf, RESPONSE_REF name_1); diff --git a/sc2/src/sc2code/libs/sound/music.c b/sc2/src/sc2code/libs/sound/music.c index 32a0f93f7..4f0ce1664 100644 --- a/sc2/src/sc2code/libs/sound/music.c +++ b/sc2/src/sc2code/libs/sound/music.c @@ -128,9 +128,7 @@ _GetMusicData (uio_Stream *fp, DWORD length) { char filename[1000]; - *pmus = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample)); - (*pmus)->buffer_tag = 0; - (*pmus)->read_chain_ptr = NULL; + *pmus = (TFB_SoundSample *) HCalloc (sizeof (TFB_SoundSample)); strcpy (filename, _cur_resfile_name); switch (optWhichMusic) @@ -206,6 +204,8 @@ _ReleaseMusicData (MEM_HANDLE handle) SoundDecoder_Free (decoder); TFBSound_DeleteBuffers ((*pmus)->num_buffers, (*pmus)->buffer); HFree ((*pmus)->buffer); + if ((*pmus)->buffer_tag) + HFree ((*pmus)->buffer_tag); } HFree (*pmus); diff --git a/sc2/src/sc2code/libs/sound/sfx.c b/sc2/src/sc2code/libs/sound/sfx.c index d30adcb38..c630e2f67 100644 --- a/sc2/src/sc2code/libs/sound/sfx.c +++ b/sc2/src/sc2code/libs/sound/sfx.c @@ -202,9 +202,7 @@ _GetSoundBankData (uio_Stream *fp, DWORD length) { fprintf (stderr, "_GetSoundBankData(): loading %s\n", filename); - sndfx[snd_ct] = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample)); - sndfx[snd_ct]->buffer_tag = 0; - sndfx[snd_ct]->read_chain_ptr = NULL; + sndfx[snd_ct] = (TFB_SoundSample *) HCalloc (sizeof (TFB_SoundSample)); sndfx[snd_ct]->decoder = SoundDecoder_Load (contentDir, filename, 4096, 0, 0); @@ -317,6 +315,8 @@ _ReleaseSoundBankData (MEM_HANDLE Snd) SoundDecoder_Free ((*sptr)->decoder); TFBSound_DeleteBuffers ((*sptr)->num_buffers, (*sptr)->buffer); HFree ((*sptr)->buffer); + if ((*sptr)->buffer_tag) + HFree ((*sptr)->buffer_tag); HFree (*sptr); *sptr++ = 0; } diff --git a/sc2/src/sc2code/libs/sound/sound.c b/sc2/src/sc2code/libs/sound/sound.c index 21ba1b540..d615c7f18 100644 --- a/sc2/src/sc2code/libs/sound/sound.c +++ b/sc2/src/sc2code/libs/sound/sound.c @@ -112,54 +112,6 @@ WaitForSoundEnd (COUNT Channel) } } -TFB_SoundChain * -create_soundchain (TFB_SoundDecoder *decoder, float startTime) -{ - TFB_SoundChain *chain; - chain = (TFB_SoundChain *)HMalloc (sizeof (TFB_SoundChain)); - chain->decoder = decoder; - chain->next =NULL; - chain->start_time = startTime; - chain->tag.buf_name = 0; - chain->tag.type = 0; - chain->tag.data = 0; - return (chain); -} - -void -destroy_soundchain (TFB_SoundChain *chain) -{ - while (chain->next) - { - TFB_SoundChain *tmp_chain = chain->next; - chain->next = chain->next->next; - if (tmp_chain->decoder) - SoundDecoder_Free (tmp_chain->decoder); - if (tmp_chain->tag.data) - HFree (tmp_chain->tag.data); - HFree (tmp_chain); - } - SoundDecoder_Free (chain->decoder); - HFree (chain); -} - -TFB_SoundChain * -get_previous_chain (TFB_SoundChain *first_chain, TFB_SoundChain *current_chain) -{ - TFB_SoundChain *prev_chain, *last_valid = NULL; - prev_chain = first_chain; - if (prev_chain == current_chain) - return (prev_chain); - while (prev_chain->next) - { - if (prev_chain->tag.type) - last_valid = prev_chain; - if (prev_chain->next == current_chain) - return (last_valid); - prev_chain = prev_chain->next; - } - return (first_chain); -} // Status: Ignored BOOLEAN diff --git a/sc2/src/sc2code/libs/sound/sound.h b/sc2/src/sc2code/libs/sound/sound.h index e63cfe264..bfb14e907 100644 --- a/sc2/src/sc2code/libs/sound/sound.h +++ b/sc2/src/sc2code/libs/sound/sound.h @@ -26,7 +26,6 @@ #endif #include "decoders/decoder.h" - #define FIRST_SFX_SOURCE 0 #define LAST_SFX_SOURCE 4 #define MUSIC_SOURCE (LAST_SFX_SOURCE + 1) @@ -36,37 +35,39 @@ typedef struct { + int in_use; TFBSound_Object buf_name; - int type; - uint32 value; - void *data; - void (*callback) (void); + void *data; // user-defined data } TFB_SoundTag; -enum -{ - MIX_BUFFER_TAG_TEXT = 1, - MIX_BUFFER_TAG_TEXTPAGE -}; +// forward-declare +typedef struct tfb_soundsample; -typedef struct tfb_soundchain +typedef struct tfb_soundcallbacks { - TFB_SoundDecoder *decoder; // points at the decoder to read from - float start_time; - TFB_SoundTag tag; - struct tfb_soundchain *next; -} TFB_SoundChain; + // return TRUE to continue, FALSE to abort + bool (* OnStartStream) (struct tfb_soundsample*); + // return TRUE to continue, FALSE to abort + bool (* OnEndChunk) (struct tfb_soundsample*, TFBSound_Object); + // return TRUE to continue, FALSE to abort + void (* OnEndStream) (struct tfb_soundsample*); + // tagged buffer callback + void (* OnTaggedBuffer) (struct tfb_soundsample*, TFB_SoundTag*); + // buffer just queued + void (* OnQueueBuffer) (struct tfb_soundsample*, TFBSound_Object); +} TFB_SoundCallbacks; // audio data typedef struct tfb_soundsample { TFB_SoundDecoder *decoder; // decoder to read from - TFB_SoundChain *read_chain_ptr; // points to chain read poistion - TFB_SoundChain *play_chain_ptr; // points to chain playing position float length; // total length of decoder chain in seconds TFBSound_Object *buffer; uint32 num_buffers; - TFB_SoundTag **buffer_tag; + TFB_SoundTag *buffer_tag; + sint32 offset; // initial offset + void* data; // user-defined data + TFB_SoundCallbacks callbacks; // user-defined callbacks } TFB_SoundSample; // equivalent to channel in legacy sound code @@ -97,10 +98,5 @@ void CleanSource (int iSource); void SetSFXVolume (float volume); void SetSpeechVolume (float volume); -void DoTrackTag (TFB_SoundTag *tag); - -TFB_SoundChain *create_soundchain (TFB_SoundDecoder *decoder, float startTime); -void destroy_soundchain (TFB_SoundChain *chain); -TFB_SoundChain *get_previous_chain (TFB_SoundChain *first_chain, TFB_SoundChain *current_chain); #include "stream.h" diff --git a/sc2/src/sc2code/libs/sound/stream.c b/sc2/src/sc2code/libs/sound/stream.c index 1c8bf281a..6cb32e89e 100644 --- a/sc2/src/sc2code/libs/sound/stream.c +++ b/sc2/src/sc2code/libs/sound/stream.c @@ -23,23 +23,24 @@ PlayStream (TFB_SoundSample *sample, uint32 source, bool looping, bool scope, bo uint32 i, pos = 0; sint32 offset = 0; - if (!sample || (!sample->read_chain_ptr && !sample->decoder)) + if (!sample) return; StopStream (source); - if (sample->read_chain_ptr) - { - sample->decoder = sample->read_chain_ptr->decoder; - offset = (sint32) (sample->read_chain_ptr->start_time * (float)ONE_SECOND); - } - else - offset= 0; + if (sample->callbacks.OnStartStream && + !sample->callbacks.OnStartStream (sample)) + return; // callback failed + + if (sample->buffer_tag) + memset (sample->buffer_tag, 0, + sample->num_buffers * sizeof (sample->buffer_tag[0])); + + offset = sample->offset; if (rewind) SoundDecoder_Rewind (sample->decoder); else offset += (sint32)(SoundDecoder_GetTime (sample->decoder) * (float)ONE_SECOND); soundSource[source].sample = sample; - soundSource[source].sample->play_chain_ptr = sample->read_chain_ptr; soundSource[source].sample->decoder->looping = looping; TFBSound_Sourcei (soundSource[source].handle, TFBSOUND_LOOPING, false); @@ -48,25 +49,22 @@ PlayStream (TFB_SoundSample *sample, uint32 source, bool looping, bool scope, bo soundSource[source].sbuffer = HMalloc (PAD_SCOPE_BYTES); } - if (sample->read_chain_ptr && sample->read_chain_ptr->tag.type) - { - DoTrackTag(&sample->read_chain_ptr->tag); - } for (i = 0; i < sample->num_buffers; ++i) { uint32 decoded_bytes; - if (sample->buffer_tag) - sample->buffer_tag[i] = 0; + decoded_bytes = SoundDecoder_Decode (sample->decoder); //fprintf (stderr, "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); if (decoded_bytes == 0) break; - + TFBSound_BufferData (sample->buffer[i], sample->decoder->format, sample->decoder->buffer, decoded_bytes, sample->decoder->frequency); TFBSound_SourceQueueBuffers (soundSource[source].handle, 1, &sample->buffer[i]); + if (sample->callbacks.OnQueueBuffer) + sample->callbacks.OnQueueBuffer (sample, sample->buffer[i]); if (scope) { @@ -80,27 +78,13 @@ PlayStream (TFB_SoundSample *sample, uint32 source, bool looping, bool scope, bo if (sample->decoder->error) { - if (sample->decoder->error == SOUNDDECODER_EOF && - sample->read_chain_ptr && sample->read_chain_ptr->next) - { - sample->read_chain_ptr = sample->read_chain_ptr->next; - sample->decoder = sample->read_chain_ptr->decoder; - SoundDecoder_Rewind (sample->decoder); - fprintf (stderr, "Switching to stream %s at pos %d\n", - sample->decoder->filename, sample->decoder->start_sample); - if (sample->buffer_tag && sample->read_chain_ptr->tag.type) - { - sample->buffer_tag[i] = &sample->read_chain_ptr->tag; - sample->read_chain_ptr->tag.buf_name = sample->buffer[i]; - } - } - else + if (sample->decoder->error != SOUNDDECODER_EOF || + !sample->callbacks.OnEndChunk || + !sample->callbacks.OnEndChunk (sample, sample->buffer[i])) break; } } - if (sample->buffer_tag) - for ( ; i num_buffers; ++i) - sample->buffer_tag[i] = 0; + soundSource[source].sbuf_size = pos + PAD_SCOPE_BYTES; soundSource[source].sbuf_start = pos; soundSource[source].sbuf_lasttime = GetTimeCounter (); @@ -148,6 +132,50 @@ PlayingStream (uint32 source) return soundSource[source].stream_should_be_playing; } +TFB_SoundTag* +TFB_FindTaggedBuffer (TFB_SoundSample* sample, TFBSound_Object buffer) +{ + uint32 buf_num; + + for (buf_num = 0; + buf_num < sample->num_buffers && + (!sample->buffer_tag[buf_num].in_use || + sample->buffer_tag[buf_num].buf_name != buffer + ); + buf_num++) + ; + + return buf_num < sample->num_buffers ? + &sample->buffer_tag[buf_num] : NULL; +} + +void +TFB_TagBuffer (TFB_SoundSample* sample, TFBSound_Object buffer, void* data) +{ + uint32 buf_num; + + for (buf_num = 0; + buf_num < sample->num_buffers && + sample->buffer_tag[buf_num].in_use && + sample->buffer_tag[buf_num].buf_name != buffer; + buf_num++) + ; + + if (buf_num >= sample->num_buffers) + return; // 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; +} + +void +TFB_ClearBufferTag (TFB_SoundTag* ptag) +{ + ptag->in_use = 0; + ptag->buf_name = 0; +} + int StreamDecoderTaskFunc (void *data) { @@ -191,11 +219,8 @@ StreamDecoderTaskFunc (void *data) { fprintf (stderr, "StreamDecoderTaskFunc(): finished playing %s, source %d\n", soundSource[i].sample->decoder->filename, i); soundSource[i].stream_should_be_playing = FALSE; - if (i == SPEECH_SOURCE) - { - soundSource[i].sample->decoder = NULL; - soundSource[i].sample->read_chain_ptr = NULL; - } + if (soundSource[i].sample->callbacks.OnEndStream) + soundSource[i].sample->callbacks.OnEndStream (soundSource[i].sample); } else { @@ -213,7 +238,6 @@ StreamDecoderTaskFunc (void *data) uint32 error; TFBSound_Object buffer; uint32 decoded_bytes; - uint32 buf_num; TFBSound_GetError (); // clear error state @@ -225,20 +249,13 @@ StreamDecoderTaskFunc (void *data) break; } - if (i == SPEECH_SOURCE) + if (soundSource[i].sample->callbacks.OnTaggedBuffer) { - for (buf_num = 0; buf_num < soundSource[i].sample->num_buffers; buf_num++) + TFB_SoundTag* tag = TFB_FindTaggedBuffer (soundSource[i].sample, buffer); + if (tag) { - TFB_SoundTag *cur_tag = soundSource[i].sample->buffer_tag[buf_num]; - if (cur_tag && cur_tag->buf_name == buffer) - { - // ...do tag stuff ... - DoTrackTag (cur_tag); - soundSource[i].sample->buffer_tag[buf_num] = NULL; - soundSource[i].sample->play_chain_ptr = soundSource[i].sample->read_chain_ptr; - cur_tag->buf_name = 0; - break; - } + soundSource[i].sample->callbacks.OnTaggedBuffer ( + soundSource[i].sample, tag); } } { @@ -255,29 +272,9 @@ StreamDecoderTaskFunc (void *data) { if (soundSource[i].sample->decoder->error == SOUNDDECODER_EOF) { - if (soundSource[i].sample->read_chain_ptr && - soundSource[i].sample->read_chain_ptr->next) - { - soundSource[i].sample->read_chain_ptr = soundSource[i].sample->read_chain_ptr->next; - soundSource[i].sample->decoder = soundSource[i].sample->read_chain_ptr->decoder; - SoundDecoder_Rewind (soundSource[i].sample->decoder); - fprintf (stderr, "Switching to stream %s at pos %d\n", - soundSource[i].sample->decoder->filename, - soundSource[i].sample->decoder->start_sample); - if (i == SPEECH_SOURCE) - { - for (buf_num = 0; buf_num < soundSource[i].sample->num_buffers; buf_num++) - { - if (soundSource[i].sample->buffer_tag[buf_num] == 0) - { - soundSource[i].sample->buffer_tag[buf_num] = &soundSource[i].sample->read_chain_ptr->tag; - soundSource[i].sample->read_chain_ptr->tag.buf_name = last_buffer[i]; - break; - } - } - } - } - else + if (!soundSource[i].sample->callbacks.OnEndChunk || + !soundSource[i].sample->callbacks.OnEndChunk ( + soundSource[i].sample, last_buffer[i])) { //fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is eof for %s\n", soundSource[i].sample->decoder->filename); processed--; @@ -335,6 +332,10 @@ StreamDecoderTaskFunc (void *data) { last_buffer[i] = buffer; TFBSound_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) { diff --git a/sc2/src/sc2code/libs/sound/stream.h b/sc2/src/sc2code/libs/sound/stream.h index 1fa2630ab..21f0e4530 100644 --- a/sc2/src/sc2code/libs/sound/stream.h +++ b/sc2/src/sc2code/libs/sound/stream.h @@ -27,6 +27,10 @@ int StreamDecoderTaskFunc (void *data); int PreDecodeClips (TFB_SoundSample *sample, TFB_SoundDecoder *decoders[], bool autofree); void PlayDecodedClip (TFB_SoundSample *sample, uint32 source, bool scope); +TFB_SoundTag* FindTaggedBuffer (TFB_SoundSample* sample, TFBSound_Object buffer); +void TFB_ClearBufferTag (TFB_SoundTag* ptag); +void TFB_TagBuffer (TFB_SoundSample* sample, TFBSound_Object buffer, void* data); + extern bool speech_advancetrack; void advance_track (int channel_finished); diff --git a/sc2/src/sc2code/libs/sound/trackint.h b/sc2/src/sc2code/libs/sound/trackint.h new file mode 100644 index 000000000..ea998f2e2 --- /dev/null +++ b/sc2/src/sc2code/libs/sound/trackint.h @@ -0,0 +1,44 @@ +/* + * 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. + */ + +#ifndef TRACKINT_H +#define TRACKINT_H + +typedef struct tfb_soundchain +{ + TFB_SoundDecoder *decoder; // points at the decoder to read from + float start_time; + int tag_me; + uint32 track_num; + void *text; + TFB_TrackCB callback; + struct tfb_soundchain *next; +} TFB_SoundChain; + +typedef struct tfb_soundchaindata +{ + TFB_SoundChain *read_chain_ptr; // points to chain read poistion + TFB_SoundChain *play_chain_ptr; // points to chain playing position + +} TFB_SoundChainData; + +extern TFB_SoundChain *first_chain; + +TFB_SoundChain *create_soundchain (TFB_SoundDecoder *decoder, float startTime); +void destroy_soundchain (TFB_SoundChain *chain); +TFB_SoundChain *get_previous_chain (TFB_SoundChain *first_chain, TFB_SoundChain *current_chain); + +#endif // TRACKINT_H diff --git a/sc2/src/sc2code/libs/sound/trackplayer.c b/sc2/src/sc2code/libs/sound/trackplayer.c index 5ed6e7f5d..2c7692116 100644 --- a/sc2/src/sc2code/libs/sound/trackplayer.c +++ b/sc2/src/sc2code/libs/sound/trackplayer.c @@ -18,6 +18,7 @@ #include #include "sound.h" #include "libs/sound/trackplayer.h" +#include "libs/sound/trackint.h" #include "comm.h" #include "options.h" @@ -26,11 +27,9 @@ static int tcur; //currently playing subtitle track static UNICODE *cur_page = 0; //current page of subtitle track static int no_page_break = 0; static int track_pos_changed = 0; // set whenever ff, frev is enabled -static TFB_SoundTag *last_tag = NULL; +static TFB_SoundChain *cur_text_chain = NULL; //current link w/ subbies #define MAX_CLIPS 50 -#define is_sample_playing(samp) (((samp)->read_chain_ptr && (samp)->play_chain_ptr) ||\ - (!(samp)->read_chain_ptr && (samp)->decoder)) static TFB_SoundSample *sound_sample = NULL; TFB_SoundChain *first_chain = NULL; //first decoder in linked list static TFB_SoundChain *last_chain = NULL; //last decoder in linked list @@ -39,6 +38,22 @@ static TFB_SoundChain *last_ts_chain = NULL; //last element in the chain with a static Mutex track_mutex; //protects tcur and tct void recompute_track_pos (TFB_SoundSample *sample, TFB_SoundChain *first_chain, sint32 offset); +bool is_sample_playing(TFB_SoundSample* samp); + +// stream callbacks +static bool OnTrackStart (TFB_SoundSample* sample); +static bool OnChunkEnd (TFB_SoundSample* sample, TFBSound_Object buffer); +static void OnTrackEnd (TFB_SoundSample* sample); +static void OnTrackTag (TFB_SoundSample* sample, TFB_SoundTag* tag); + +static TFB_SoundCallbacks trackCBs = +{ + OnTrackStart, + OnChunkEnd, + OnTrackEnd, + OnTrackTag, + NULL +}; //JumpTrack currently aborts the current track. However, it doesn't clear the //data-structures as StopTrack does. this allows for rewind even after the @@ -47,23 +62,26 @@ void recompute_track_pos (TFB_SoundSample *sample, void JumpTrack (void) { - if (sound_sample) - { - uint32 cur_time; - sint32 total_length = (sint32)((last_chain->start_time + - last_chain->decoder->length) * (float)ONE_SECOND); - LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); - PauseStream (SPEECH_SOURCE); - cur_time = GetTimeCounter(); - soundSource[SPEECH_SOURCE].start_time = - (sint32)cur_time - total_length; - track_pos_changed = 1; - sound_sample->play_chain_ptr = last_chain; - recompute_track_pos(sound_sample, first_chain, total_length); - UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); - PlayingTrack(); + TFB_SoundChainData* scd; + uint32 cur_time; + sint32 total_length = (sint32)((last_chain->start_time + + last_chain->decoder->length) * (float)ONE_SECOND); + + if (!sound_sample) return; - } + + scd = (TFB_SoundChainData*) sound_sample->data; + + LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + PauseStream (SPEECH_SOURCE); + cur_time = GetTimeCounter(); + soundSource[SPEECH_SOURCE].start_time = + (sint32)cur_time - total_length; + track_pos_changed = 1; + scd->play_chain_ptr = last_chain; + recompute_track_pos(sound_sample, first_chain, total_length); + UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + PlayingTrack(); } //advance to the next track and start playing @@ -72,7 +90,14 @@ JumpTrack (void) void PlayTrack (void) { - if (sound_sample && (sound_sample->read_chain_ptr || sound_sample->decoder)) + TFB_SoundChainData* scd; + + if (!sound_sample) + return; + + scd = (TFB_SoundChainData*) sound_sample->data; + + if (scd->read_chain_ptr || sound_sample->decoder) { LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); PlayStream (sound_sample, @@ -88,7 +113,14 @@ PlayTrack (void) void ResumeTrack () { - if (sound_sample && (sound_sample->read_chain_ptr || sound_sample->decoder)) + TFB_SoundChainData* scd; + + if (!sound_sample) + return; + + scd = (TFB_SoundChainData*) sound_sample->data; + + if (scd->read_chain_ptr || sound_sample->decoder) { // Only try to start the track if there is something to play TFBSound_IntVal state; @@ -169,6 +201,7 @@ StopTrack () TFBSound_DeleteBuffers (sound_sample->num_buffers, sound_sample->buffer); HFree (sound_sample->buffer); HFree (sound_sample->buffer_tag); + HFree (sound_sample->data); HFree (sound_sample); sound_sample = NULL; } @@ -177,18 +210,90 @@ StopTrack () do_subtitles ((void *)~0); } -void -DoTrackTag (TFB_SoundTag *tag) +bool is_sample_playing(TFB_SoundSample* sample) { - if (tag->type == MIX_BUFFER_TAG_TEXT) + TFB_SoundChainData* scd = (TFB_SoundChainData*) sample->data; + + return (scd->read_chain_ptr && scd->play_chain_ptr) + || (!scd->read_chain_ptr && sample->decoder); +} + +static void +DoTrackTag (TFB_SoundChain *chain) +{ + LockMutex (track_mutex); + if (chain->callback) + chain->callback (); + tcur = chain->track_num; + cur_page = (UNICODE *) chain->text; + UnlockMutex (track_mutex); +} + +static bool +OnTrackStart (TFB_SoundSample* sample) +{ + TFB_SoundChainData* scd = (TFB_SoundChainData*) sample->data; + + if (!scd->read_chain_ptr && !sample->decoder) + return false; + + if (scd->read_chain_ptr) { - LockMutex (track_mutex); - if (tag->callback) - tag->callback (); - tcur = tag->value; - cur_page = (UNICODE *)tag->data; - UnlockMutex (track_mutex); + sample->decoder = scd->read_chain_ptr->decoder; + sample->offset = (sint32) (scd->read_chain_ptr->start_time * (float)ONE_SECOND); } + else + sample->offset = 0; + + scd->play_chain_ptr = scd->read_chain_ptr; + + if (scd->read_chain_ptr && scd->read_chain_ptr->tag_me) + DoTrackTag(scd->read_chain_ptr); + + return true; +} + +static bool +OnChunkEnd (TFB_SoundSample* sample, TFBSound_Object buffer) +{ + TFB_SoundChainData* scd = (TFB_SoundChainData*) sample->data; + + if (!scd->read_chain_ptr || !scd->read_chain_ptr->next) + return false; + + scd->read_chain_ptr = scd->read_chain_ptr->next; + sample->decoder = scd->read_chain_ptr->decoder; + SoundDecoder_Rewind (sample->decoder); + fprintf (stderr, "Switching to stream %s at pos %d\n", + sample->decoder->filename, sample->decoder->start_sample); + + if (sample->buffer_tag && scd->read_chain_ptr->tag_me) + { + TFB_TagBuffer (sample, buffer, scd->read_chain_ptr); + } + + return true; +} + +static void +OnTrackEnd (TFB_SoundSample* sample) +{ + TFB_SoundChainData* scd = (TFB_SoundChainData*) sample->data; + + sample->decoder = NULL; + scd->read_chain_ptr = NULL; +} + +static void +OnTrackTag (TFB_SoundSample* sample, TFB_SoundTag* tag) +{ + TFB_SoundChainData* scd = (TFB_SoundChainData*) sample->data; + TFB_SoundChain* chain = (TFB_SoundChain*) tag->data; + + TFB_ClearBufferTag (tag); + DoTrackTag (chain); + + scd->play_chain_ptr = scd->read_chain_ptr; } int @@ -360,18 +465,19 @@ SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText) if (tct) { int slen1; - slen1 = wstrlen ((UNICODE *)last_tag->data); - last_tag->data = HRealloc ((UNICODE *)last_tag->data, slen1 + slen + 1); - wstrcpy (&((UNICODE *)last_tag->data)[slen1], TrackText); + slen1 = wstrlen ((UNICODE *)cur_text_chain->text); + cur_text_chain->text = HRealloc ( + (UNICODE *)cur_text_chain->text, slen1 + slen + 1); + wstrcpy (&((UNICODE *)cur_text_chain->text)[slen1], TrackText); } else { - begin_chain->tag.data = HMalloc (slen + 1); - wstrcpy ((UNICODE *)begin_chain->tag.data, TrackText); - last_tag = &begin_chain->tag; + begin_chain->text = HMalloc (slen + 1); + wstrcpy ((UNICODE *)begin_chain->text, TrackText); + cur_text_chain = begin_chain; + begin_chain->tag_me = 1; + begin_chain->track_num = tct; tct++; - begin_chain->tag.type = MIX_BUFFER_TAG_TEXT; - begin_chain->tag.value = tct - 1; } no_page_break = 1; @@ -384,7 +490,7 @@ SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText) } void -SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (*cb) (void)) +SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, TFB_TrackCB cb) { unsigned long startTime; UNICODE **split_text = NULL; @@ -399,7 +505,7 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (* int num_pages = 0, page_counter; sint32 time_stamps[50]; - if (! last_ts_chain || !last_ts_chain->tag.data) + if (!last_ts_chain || !last_ts_chain->text) { fprintf (stderr, "SpliceTrack(): Tried to append a subtitle to a NULL string\n"); @@ -411,11 +517,11 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (* fprintf (stderr, "SpliceTrack(): Failed to parse sutitles\n"); return; } - oTT = (UNICODE *)last_ts_chain->tag.data; + oTT = (UNICODE *)last_ts_chain->text; slen1 = wstrlen (oTT); slen2 = wstrlen (split_text[0]); - last_ts_chain->tag.data = HRealloc (oTT, slen1 + slen2 + 1); - wstrcpy (&((UNICODE *)last_ts_chain->tag.data)[slen1], split_text[0]); + last_ts_chain->text = HRealloc (oTT, slen1 + slen2 + 1); + wstrcpy (&((UNICODE *)last_ts_chain->text)[slen1], split_text[0]); HFree (split_text[0]); for (page_counter = 1; page_counter < num_pages; page_counter++) { @@ -425,7 +531,7 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (* break; } last_ts_chain = last_ts_chain->next; - last_ts_chain->tag.data = split_text[page_counter]; + last_ts_chain->text = split_text[page_counter]; } } } @@ -449,11 +555,11 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (* int slen1, slen2; UNICODE *oTT; - oTT = (UNICODE *)last_tag->data; + oTT = (UNICODE *)cur_text_chain->text; slen1 = wstrlen (oTT); slen2 = wstrlen (split_text[0]); - last_tag->data = HRealloc (oTT, slen1 + slen2 + 1); - wstrcpy (&((UNICODE *)last_tag->data)[slen1], split_text[0]); + cur_text_chain->text = HRealloc (oTT, slen1 + slen2 + 1); + wstrcpy (&((UNICODE *)cur_text_chain->text)[slen1], split_text[0]); HFree (split_text[0]); } else @@ -475,19 +581,24 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (* if (! sound_sample) { TFB_SoundDecoder *decoder; + TFB_SoundChainData* scd; + track_mutex = CreateMutex(); sound_sample = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample)); + scd = (TFB_SoundChainData *) HCalloc (sizeof (TFB_SoundChainData)); + sound_sample->data = scd; + sound_sample->callbacks = trackCBs; sound_sample->num_buffers = 8; - sound_sample->buffer_tag = HMalloc (sizeof (TFB_SoundTag *) * sound_sample->num_buffers); + sound_sample->buffer_tag = HCalloc (sizeof (TFB_SoundTag) * sound_sample->num_buffers); sound_sample->buffer = HMalloc (sizeof (uint32) * sound_sample->num_buffers); TFBSound_GenBuffers (sound_sample->num_buffers, sound_sample->buffer); decoder = SoundDecoder_Load (contentDir, TrackName, 4096, startTime, time_stamps[page_counter]); - sound_sample->read_chain_ptr = create_soundchain (decoder, 0.0); + scd->read_chain_ptr = create_soundchain (decoder, 0.0); sound_sample->decoder = decoder; - first_chain = last_chain = sound_sample->read_chain_ptr; + first_chain = last_chain = scd->read_chain_ptr; sound_sample->length = 0; - sound_sample->play_chain_ptr = 0; + scd->play_chain_ptr = 0; } else { @@ -525,16 +636,16 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (* sound_sample->length += last_chain->decoder->length; if (! no_page_break) { - last_chain->tag.type = MIX_BUFFER_TAG_TEXT; + last_chain->tag_me = 1; // last_chain->tag.value = (void *)(((tct - 1) << 8) | page_counter); - last_chain->tag.value = tct - 1; + last_chain->track_num = tct - 1; if (page_counter < num_pages) { - last_chain->tag.data = (void *)split_text[page_counter]; + last_chain->text = (void *)split_text[page_counter]; last_ts_chain = last_chain; } - last_chain->tag.callback = cb; - last_tag = &last_chain->tag; + last_chain->callback = cb; + cur_text_chain = last_chain; } no_page_break = 0; } @@ -568,27 +679,32 @@ PauseTrack () void recompute_track_pos (TFB_SoundSample *sample, TFB_SoundChain *first_chain, sint32 offset) { + TFB_SoundChainData* scd; TFB_SoundChain *cur_chain = first_chain; + if (! sample) return; + + scd = (TFB_SoundChainData*) sample->data; + while (cur_chain->next && (sint32)(cur_chain->next->start_time * (float)ONE_SECOND) < offset) { - if (cur_chain->tag.type) - DoTrackTag (&cur_chain->tag); + if (cur_chain->tag_me) + DoTrackTag (cur_chain); cur_chain = cur_chain->next; } - if (cur_chain->tag.type) - DoTrackTag (&cur_chain->tag); + if (cur_chain->tag_me) + DoTrackTag (cur_chain); if ((sint32)((cur_chain->start_time + cur_chain->decoder->length) * (float)ONE_SECOND) < offset) { - sample->read_chain_ptr = NULL; + scd->read_chain_ptr = NULL; sample->decoder = NULL; } else { - sample->read_chain_ptr = cur_chain; - SoundDecoder_Seek(sample->read_chain_ptr->decoder, + scd->read_chain_ptr = cur_chain; + SoundDecoder_Seek(scd->read_chain_ptr->decoder, (uint32)(1000 * (offset / (float)ONE_SECOND - cur_chain->start_time))); } } @@ -630,12 +746,14 @@ FastReverse_Page () { if (sound_sample) { + TFB_SoundChainData* scd = (TFB_SoundChainData*) sound_sample->data; TFB_SoundChain *prev_chain; + LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); - prev_chain = get_previous_chain(first_chain, sound_sample->play_chain_ptr); + prev_chain = get_previous_chain (first_chain, scd->play_chain_ptr); if (prev_chain) { - sound_sample->read_chain_ptr = prev_chain; + scd->read_chain_ptr = prev_chain; PlayStream (sound_sample, SPEECH_SOURCE, false, speechVolumeScale != 0.0f, true); @@ -674,13 +792,15 @@ FastForward_Page () { if (sound_sample) { - TFB_SoundChain *cur_ptr = sound_sample->play_chain_ptr; + TFB_SoundChainData* scd = (TFB_SoundChainData*) sound_sample->data; + TFB_SoundChain *cur_ptr = scd->play_chain_ptr; + LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); - while (cur_ptr->next && ! cur_ptr->next->tag.type) + while (cur_ptr->next && !cur_ptr->next->tag_me) cur_ptr = cur_ptr->next; if (cur_ptr->next) { - sound_sample->read_chain_ptr = cur_ptr->next; + scd->read_chain_ptr = cur_ptr->next; PlayStream (sound_sample, SPEECH_SOURCE, false, speechVolumeScale != 0.0f, true); @@ -868,3 +988,51 @@ GetSoundInfo (int max_len) return max_len; return (int)(max_len * offset / length); } + +TFB_SoundChain * +create_soundchain (TFB_SoundDecoder *decoder, float startTime) +{ + TFB_SoundChain *chain; + chain = (TFB_SoundChain *)HMalloc (sizeof (TFB_SoundChain)); + chain->decoder = decoder; + chain->next = NULL; + chain->start_time = startTime; + chain->tag_me = 0; + chain->text = 0; + return (chain); +} + +void +destroy_soundchain (TFB_SoundChain *chain) +{ + while (chain->next) + { + TFB_SoundChain *tmp_chain = chain->next; + chain->next = chain->next->next; + if (tmp_chain->decoder) + SoundDecoder_Free (tmp_chain->decoder); + if (tmp_chain->text) + HFree (tmp_chain->text); + HFree (tmp_chain); + } + SoundDecoder_Free (chain->decoder); + HFree (chain); +} + +TFB_SoundChain * +get_previous_chain (TFB_SoundChain *first_chain, TFB_SoundChain *current_chain) +{ + TFB_SoundChain *prev_chain, *last_valid = NULL; + prev_chain = first_chain; + if (prev_chain == current_chain) + return (prev_chain); + while (prev_chain->next) + { + if (prev_chain->tag_me) + last_valid = prev_chain; + if (prev_chain->next == current_chain) + return (last_valid); + prev_chain = prev_chain->next; + } + return (first_chain); +} diff --git a/sc2/src/sc2code/libs/sound/trackplayer.h b/sc2/src/sc2code/libs/sound/trackplayer.h index 90201f686..6867e5297 100644 --- a/sc2/src/sc2code/libs/sound/trackplayer.h +++ b/sc2/src/sc2code/libs/sound/trackplayer.h @@ -19,6 +19,8 @@ #ifndef TRACKPLAYER_H #define TRACKPLAYER_H +typedef void (*TFB_TrackCB) (void); + #define ACCEL_SCROLL_SPEED 300 void ResumeTrack(void); @@ -30,7 +32,7 @@ int FastForward_Page(void); void FastReverse_Smooth(void); void FastReverse_Page(void); void StopTrack(void); -void SpliceTrack(UNICODE *filespec, UNICODE *textspec, UNICODE *TimeStamp, void (*cb) (void)); +void SpliceTrack(UNICODE *filespec, UNICODE *textspec, UNICODE *TimeStamp, TFB_TrackCB cb); void SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText); int GetSoundData (void *data); int GetSoundInfo (int max_len);