From 4ed4f72cf33d4b0399e4f38e581fad987f2f68f4 Mon Sep 17 00:00:00 2001 From: ghaushe Date: Mon, 27 Jan 2003 06:21:10 +0000 Subject: [PATCH] new streaming code for openal, mixsdl. Supports better subtitle alignemnt and going forward-backwards one page at a time using the arrow keys git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@588 8092fc87-c524-0410-9efc-e669fe64eaf9 --- sc2/ChangeLog | 1 + sc2/TODO | 7 +- sc2/src/sc2code/comm.c | 133 ++++-- .../libs/sound/mixsdl/decoders/decoder.c | 96 ++++- .../libs/sound/mixsdl/decoders/decoder.h | 8 +- sc2/src/sc2code/libs/sound/mixsdl/music.c | 4 +- sc2/src/sc2code/libs/sound/mixsdl/sfx.c | 5 +- sc2/src/sc2code/libs/sound/mixsdl/sound.c | 44 ++ sc2/src/sc2code/libs/sound/mixsdl/sound.h | 33 +- sc2/src/sc2code/libs/sound/mixsdl/stream.c | 255 ++++++------ .../sc2code/libs/sound/mixsdl/trackplayer.c | 368 +++++++++++------ .../libs/sound/openal/decoders/decoder.c | 152 ++++++- .../libs/sound/openal/decoders/decoder.h | 6 +- sc2/src/sc2code/libs/sound/openal/music.c | 4 +- sc2/src/sc2code/libs/sound/openal/sfx.c | 4 +- sc2/src/sc2code/libs/sound/openal/sound.c | 44 ++ sc2/src/sc2code/libs/sound/openal/sound.h | 33 +- sc2/src/sc2code/libs/sound/openal/stream.c | 140 +++++-- .../sc2code/libs/sound/openal/trackplayer.c | 387 ++++++++++++++---- sc2/src/sc2code/libs/sound/sdl/trackplayer.c | 14 +- sc2/src/sc2code/libs/sound/trackplayer.h | 1 + 21 files changed, 1279 insertions(+), 460 deletions(-) diff --git a/sc2/ChangeLog b/sc2/ChangeLog index d07cab676..0cec2dac3 100644 --- a/sc2/ChangeLog +++ b/sc2/ChangeLog @@ -1,4 +1,5 @@ Changes towards version 0.2: +- New streaming code for openal/mixsdl. supports ff/frev in subtitles -PBlue - New sound module "mixsdl" (experimental) -fOSSiL - Fixed overlapping subtitle text while switch tracks -PhracturedBlue - New flash-thread cacheing scheme - PhracturedBlue diff --git a/sc2/TODO b/sc2/TODO index 4d154612c..0a951dad4 100644 --- a/sc2/TODO +++ b/sc2/TODO @@ -100,10 +100,11 @@ Implementation bugs (low priority): yehat021.ogg yehat023.ogg supox002.ogg supox003.ogg supox028.ogg vux001.ogg utwig072.ogg umgah027.ogg talkp068.ogg spaho007.ogg syree012.ogg syree021.ogg syree028.ogg syree069.ogg orz000.ogg - - Should be skip forward/back one frame (using arrows?), and keep text synced - may only be possible using openAL though + - Using arrow keys with SDL_mixer will not work. + - Arrow keys for mixsdl/openAL skip forward/back one page. We should also + have a 'smooth' scrolling mechanism like the 3do - More work should be done to better sync the text we have. -Match timing between subtitles and speech clips +- Slider doesn't track the audio very well Stuff still to do (large): - add some way to configure your keys (assigned to mstr) diff --git a/sc2/src/sc2code/comm.c b/sc2/src/sc2code/comm.c index 394677e75..8a0584aa3 100644 --- a/sc2/src/sc2code/comm.c +++ b/sc2/src/sc2code/comm.c @@ -1161,7 +1161,7 @@ SpewPhrases (COUNT wait_track) BOOLEAN ContinuityBreak; DWORD TimeIn; COUNT which_track; - INPUT_STATE InputState; + INPUT_STATE InputState, LastInputState; FRAME F; TimeIn = GetTimeCounter (); @@ -1195,6 +1195,7 @@ SpewPhrases (COUNT wait_track) else if (which_track <= wait_track) ResumeTrack (); + LastInputState = 0; do { ClearSemaphore (GraphicsSem); @@ -1219,14 +1220,14 @@ SpewPhrases (COUNT wait_track) if (which_track) { - if (GetInputXComponent (InputState) > 0) + if (InputState != LastInputState && GetInputXComponent (InputState) > 0) { SetSliderImage (SetAbsFrameIndex (ActivityFrame, 3)); FastForward (); ContinuityBreak = TRUE; CommData.AlienFrame = 0; } - else if (GetInputXComponent (InputState) < 0) + else if (InputState != LastInputState && GetInputXComponent (InputState) < 0) { Rewind: SetSliderImage (SetAbsFrameIndex (ActivityFrame, 4)); @@ -1234,18 +1235,19 @@ Rewind: ContinuityBreak = TRUE; CommData.AlienFrame = 0; } - else if (ContinuityBreak) + else if (InputState != LastInputState && ContinuityBreak) { SetSliderImage (SetAbsFrameIndex (ActivityFrame, 2)); if ((which_track = PlayingTrack ()) - && which_track <= wait_track) - ResumeTrack (); + && which_track <= wait_track) ; +// ResumeTrack (); ContinuityBreak = FALSE; } else if (which_track == wait_track || wait_track == (COUNT)~0) CommData.AlienFrame = F; } + LastInputState = InputState; } while (ContinuityBreak || ((which_track = PlayingTrack ()) && which_track <= wait_track)); @@ -1944,11 +1946,18 @@ RaceCommunication (void) } } +//method == 0 parses pTimeStamp, and self-times the subtitles +//method == 1 expects pTimeStamp to explicitly set the page to draw int -do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp) +do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp, int method) { static DWORD TimeOut; static unsigned long *cur_sub_ts; + int disable_timer = 0; + int cur_page = -1; + static int last_page = -1; + static UNICODE *lastPStr = 0; + int NextPage = 0; // TODO: proper disabling of subtitles, this one prolly isn't 'safe' if (optSubtitles == FALSE) @@ -1961,8 +1970,31 @@ do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp) if (subtitle_state <= NEXT_SUBTITLE) return (subtitle_state); TimeOut = 0; + NextPage = 1; subtitle_state = WAIT_SUBTITLE; } + if (method) + disable_timer = 1; + else if (! method) + { + if (last_page == -1) + last_page++; + cur_page = last_page; + } + if (method == 1 && pStr != (void *)~0 && pTimeStamp != (void *)~0) + { + cur_page = (int)pTimeStamp; + if (cur_page != last_page || lastPStr != pStr) { + if (lastPStr != pStr) + subtitle_state = NEXT_SUBTITLE; + else + subtitle_state = READ_SUBTITLE; + ColorChange = TRUE; +// fprintf (stderr, "changed page to: %d\n", cur_page); + } + } + lastPStr = pStr; + last_page = cur_page; switch (subtitle_state) { @@ -1976,53 +2008,64 @@ do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp) 24, 32, }; + static UNICODE alien_phrase_buf[4096]; + static int page_break_pos[50]; case NEXT_SUBTITLE: { UNICODE ch; COUNT numchars; - static UNICODE alien_phrase_buf[4096]; + int cur_pos = 0; UNICODE *s; static unsigned long subtitle_frames_ts[50]; + if (! disable_timer) + cur_page = last_page = 0; + page_break_pos[cur_pos++] = 0; CommData.AlienTextTemplate.pStr = alien_phrase_buf; numchars = 0; do { ++numchars; - if (((ch = *pStr++) == '\n' || ch == '\r') - && !ispunct (pStr[-2]) - && !isspace (pStr[-2])) + if ((ch = *pStr++) == '\n' || ch == '\r') { - *CommData.AlienTextTemplate.pStr++ = '.'; - *CommData.AlienTextTemplate.pStr++ = '.'; - *CommData.AlienTextTemplate.pStr++ = '.'; - *CommData.AlienTextTemplate.pStr++ = ch; - *CommData.AlienTextTemplate.pStr++ = '.'; - *CommData.AlienTextTemplate.pStr++ = '.'; - ch = '.'; - numchars += 6; + if (!ispunct (pStr[-2]) && !isspace (pStr[-2])) + { + *CommData.AlienTextTemplate.pStr++ = '.'; + *CommData.AlienTextTemplate.pStr++ = '.'; + *CommData.AlienTextTemplate.pStr++ = '.'; + *CommData.AlienTextTemplate.pStr++ = ch; + *CommData.AlienTextTemplate.pStr++ = '.'; + *CommData.AlienTextTemplate.pStr++ = '.'; + ch = '.'; + page_break_pos[cur_pos++] = numchars + 3; + numchars += 6; + } + else + page_break_pos[cur_pos++] = numchars; } } while ((*CommData.AlienTextTemplate.pStr++ = ch)); - if (s = pTimeStamp) + subtitle_frames_ts[0] = 0; + if (! method) { - int pos; - cur_sub_ts = subtitle_frames_ts; - while (*s && (pos = wstrcspn (s, ","))) + if (s = pTimeStamp) { - UNICODE valStr[10]; - wstrncpy (valStr, s, pos); - valStr[pos] = '\0'; - *cur_sub_ts++ = wstrtoul(valStr,NULL,10); - s += pos; - if (*s) - s++; + int pos; + cur_sub_ts = subtitle_frames_ts; + while (*s && (pos = wstrcspn (s, ","))) + { + UNICODE valStr[10]; + wstrncpy (valStr, s, pos); + valStr[pos] = '\0'; + *cur_sub_ts++ = wstrtoul(valStr,NULL,10); + s += pos; + if (*s) + s++; + } + *cur_sub_ts = 0; + TimeOut = GetTimeCounter (); } - *cur_sub_ts = 0; - TimeOut = GetTimeCounter (); } - else - subtitle_frames_ts[0] = 0; cur_sub_ts = subtitle_frames_ts; CommData.AlienTextTemplate.pStr = alien_phrase_buf; @@ -2044,7 +2087,7 @@ do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp) BYTE read_speed; CONTEXT OldContext; - CommData.AlienTextTemplate.pStr += CommData.AlienTextTemplate.CharCount; + CommData.AlienTextTemplate.pStr = alien_phrase_buf + page_break_pos[cur_page]; t = CommData.AlienTextTemplate; OldContext = SetContext (TaskContext); @@ -2060,12 +2103,12 @@ do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp) talk_length = *cur_sub_ts++ * ONE_SECOND /1000; silence_length = 0; TimeOut += talk_length; - //sprintf (stderr, "Sound length is %d\n", talk_length); + fprintf (stderr, "Sound length is %d\n", talk_length); } - else + else if (! disable_timer) { read_speed = speed_array[GLOBAL (glob_flags) & READ_SPEED_MASK]; - talk_length = ONE_SECOND * CommData.AlienTextTemplate.CharCount / MODERATE_SPEED; + talk_length = 3 * ONE_SECOND * CommData.AlienTextTemplate.CharCount / MODERATE_SPEED; if (read_speed) { silence_length = ONE_SECOND @@ -2076,18 +2119,28 @@ do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp) } TimeOut = GetTimeCounter () + talk_length; } + else + { + TimeOut = 0; + silence_length = 0; + } subtitle_state = SPACE_SUBTITLE; break; } case SPACE_SUBTITLE: - if (GetTimeCounter () < TimeOut) + if (! NextPage && (disable_timer || GetTimeCounter () < TimeOut)) break; TimeOut += silence_length; subtitle_state = WAIT_SUBTITLE; /* fall through */ case WAIT_SUBTITLE: - if (speed_array[GLOBAL (glob_flags) & READ_SPEED_MASK] == 0 || GetTimeCounter () >= TimeOut) + if (speed_array[GLOBAL (glob_flags) & READ_SPEED_MASK] == 0 || NextPage || (! disable_timer && GetTimeCounter () >= TimeOut)) { +// if (NextPage) +// fprintf (stderr, "Switching pages\n"); + NextPage = 0; + if (! disable_timer) + last_page++; if (CommData.AlienTextTemplate.pStr[CommData.AlienTextTemplate.CharCount - 1] == '\n') subtitle_state = READ_SUBTITLE; else diff --git a/sc2/src/sc2code/libs/sound/mixsdl/decoders/decoder.c b/sc2/src/sc2code/libs/sound/mixsdl/decoders/decoder.c index 87651acb0..1dc21779c 100644 --- a/sc2/src/sc2code/libs/sound/mixsdl/decoders/decoder.c +++ b/sc2/src/sc2code/libs/sound/mixsdl/decoders/decoder.c @@ -153,7 +153,8 @@ void SoundDecoder_Uninit (void) MikMod_Exit (); } -TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size) +TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size, + uint32 startTime, uint32 runTime) { int i; @@ -181,6 +182,9 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size) decoder->decoder_info = decoder_info_wav; decoder->type = SOUNDDECODER_WAV; decoder->filename = (char *) HMalloc (strlen (filename) + 1); + decoder->start_sample = 0; + decoder->end_sample = 0; + decoder->pos = 0; strcpy (decoder->filename, filename); return decoder; @@ -215,6 +219,9 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size) decoder->decoder_info = decoder_info_mod; decoder->type = SOUNDDECODER_MOD; decoder->filename = (char *) HMalloc (strlen (filename) + 1); + decoder->start_sample = 0; + decoder->end_sample = 0; + decoder->pos = 0; strcpy (decoder->filename, filename); decoder->data = mod; @@ -270,14 +277,30 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size) decoder = (TFB_SoundDecoder *) HMalloc (sizeof (TFB_SoundDecoder)); decoder->buffer = HMalloc (buffer_size); decoder->buffer_size = buffer_size; - if (vinfo->channels == 1) - decoder->format = decoder_formats.mono16; - else - decoder->format = decoder_formats.stereo16; decoder->frequency = vinfo->rate; decoder->looping = false; decoder->error = SOUNDDECODER_OK; decoder->length = (float) ov_time_total (vf, -1); + if (runTime && runTime / 1000.0 < decoder->length) + decoder->length = (float)(runTime / 1000.0); + + decoder->start_sample = decoder->frequency * startTime/1000; + decoder->end_sample = decoder->start_sample + + (unsigned long)(decoder->length * decoder->frequency); + if (decoder->start_sample) + ov_pcm_seek (vf, decoder->start_sample); + + if (vinfo->channels == 1) + { + decoder->format = decoder_formats.mono16; + decoder->pos = decoder->start_sample * 2; + } + else + { + decoder->format = decoder_formats.stereo16; + decoder->pos = decoder->start_sample * 4; + } + decoder->decoder_info = decoder_info_ogg; decoder->type = SOUNDDECODER_OGG; decoder->filename = (char *) HMalloc (strlen (filename) + 1); @@ -346,13 +369,33 @@ uint32 SoundDecoder_Decode (TFB_SoundDecoder *decoder) uint32 decoded_bytes = 0, count = 0; long rc; int bitstream; + uint32 max_bytes, buffer_size, close_on_done = 0; char *buffer = (char *) decoder->buffer; - while (decoded_bytes < decoder->buffer_size) + if (! decoder->looping) + { + if (decoder->format == decoder_formats.stereo16) + max_bytes = decoder->end_sample * 4; + else + max_bytes = decoder->end_sample * 2; + if (max_bytes - decoder->pos < decoder->buffer_size) + { + buffer_size = max_bytes - decoder->pos; + close_on_done = 1; + } + else + { + buffer_size = decoder->buffer_size; + } + } + else + buffer_size = decoder->buffer_size; + + while (decoded_bytes < buffer_size) { /* Produce output in requested byte-order */ rc = ov_read (vf, &buffer[decoded_bytes], - decoder->buffer_size - decoded_bytes, + buffer_size - decoded_bytes, decoder_formats.want_big_endian, 2, 1, &bitstream); if (rc < 0) { @@ -360,14 +403,18 @@ uint32 SoundDecoder_Decode (TFB_SoundDecoder *decoder) fprintf (stderr, "SoundDecoder_Decode(): error decoding %s, code %d\n", decoder->filename, rc); return decoded_bytes; } - if (rc == 0) + if (rc == 0 || close_on_done && buffer_size == decoded_bytes + rc) { + if (close_on_done) + { + decoded_bytes += rc; + } if (decoder->looping) { - int err; - if ((err = ov_pcm_seek (vf, 0)) != 0) + SoundDecoder_Rewind (decoder); + if (decoder->error) { - fprintf (stderr, "SoundDecoder_Decode(): tried to loop %s but couldn't rewind, error code %d\n", decoder->filename, err); + fprintf (stderr, "SoundDecoder_Decode(): tried to loop %s but couldn't rewind, error code %d\n", decoder->filename, decoder->error); } else { @@ -376,6 +423,8 @@ uint32 SoundDecoder_Decode (TFB_SoundDecoder *decoder) continue; } } + else + decoder->pos += decoded_bytes; fprintf (stderr, "SoundDecoder_Decode(): eof for %s\n", decoder->filename); decoder->error = SOUNDDECODER_EOF; @@ -386,11 +435,14 @@ uint32 SoundDecoder_Decode (TFB_SoundDecoder *decoder) //fprintf (stderr, "iter %d rc %d decoded_bytes %d remaining %d\n", count, rc, decoded_bytes, decoder->buffer_size - decoded_bytes); count++; } - + decoder->pos += decoded_bytes; decoder->error = SOUNDDECODER_OK; //fprintf (stderr, "SoundDecoder_Decode(): decoded %d bytes from %s\n", decoded_bytes, decoder->filename); return decoded_bytes; } + case SOUNDDECODER_BUF: + decoder->error = SOUNDDECODER_EOF; + return (decoder->buffer_size); default: { fprintf (stderr, "SoundDecoder_Decode(): unknown type %d\n", decoder->type); @@ -415,6 +467,7 @@ uint32 SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder) if (decoder->buffer_size != 0) { + decoder->type = SOUNDDECODER_BUF; decoder->error = SOUNDDECODER_OK; /* WAVs are loaded in little-endian order @@ -488,6 +541,11 @@ uint32 SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder) decoded_bytes += rc; } + decoder->buffer_size = decoded_bytes; + ov_clear (vf); + HFree (vf); + decoder->type = SOUNDDECODER_BUF; + decoder->error = SOUNDDECODER_OK; return decoded_bytes; break; @@ -525,15 +583,25 @@ void SoundDecoder_Rewind (TFB_SoundDecoder *decoder) { int err; OggVorbis_File *vf = (OggVorbis_File *) decoder->data; - if ((err = ov_pcm_seek (vf, 0)) != 0) + if ((err = ov_pcm_seek (vf, decoder->start_sample)) != 0) { fprintf (stderr, "SoundDecoder_Rewind(): couldn't rewind %s, error code %d\n", decoder->filename, err); break; } + if (decoder->format == decoder_formats.mono16) + decoder->pos = decoder->start_sample * 2; + else + decoder->pos = decoder->start_sample * 4; + //fprintf (stderr, "SoundDecoder_Rewind(): rewound %s\n", decoder->filename); decoder->error = SOUNDDECODER_OK; return; } + case SOUNDDECODER_BUF: + { + decoder->error = SOUNDDECODER_OK; + return; + } default: { fprintf (stderr, "SoundDecoder_Rewind(): unknown type %d\n", decoder->type); @@ -573,6 +641,8 @@ void SoundDecoder_Free (TFB_SoundDecoder *decoder) HFree (vf); break; } + case SOUNDDECODER_BUF: + break; default: { fprintf (stderr, "SoundDecoder_Free(): unknown type %d\n", decoder->type); diff --git a/sc2/src/sc2code/libs/sound/mixsdl/decoders/decoder.h b/sc2/src/sc2code/libs/sound/mixsdl/decoders/decoder.h index 470d3e941..d714eea67 100644 --- a/sc2/src/sc2code/libs/sound/mixsdl/decoders/decoder.h +++ b/sc2/src/sc2code/libs/sound/mixsdl/decoders/decoder.h @@ -54,6 +54,10 @@ typedef struct tfb_sounddecoder sint32 type; char *filename; void *data; + uint32 pos; + uint32 start_sample; + uint32 end_sample; + } TFB_SoundDecoder; // return values @@ -71,13 +75,15 @@ enum SOUNDDECODER_WAV, SOUNDDECODER_MOD, SOUNDDECODER_OGG, + SOUNDDECODER_BUF, }; extern TFB_DecoderFormats decoder_formats; sint32 SoundDecoder_Init (int flags, TFB_DecoderFormats* formats); void SoundDecoder_Uninit (void); -TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size); +TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size, + uint32 startTime, uint32 runTime); uint32 SoundDecoder_Decode (TFB_SoundDecoder *decoder); uint32 SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder); void SoundDecoder_Rewind (TFB_SoundDecoder *decoder); diff --git a/sc2/src/sc2code/libs/sound/mixsdl/music.c b/sc2/src/sc2code/libs/sound/mixsdl/music.c index e88b78cc8..d5e053783 100644 --- a/sc2/src/sc2code/libs/sound/mixsdl/music.c +++ b/sc2/src/sc2code/libs/sound/mixsdl/music.c @@ -134,6 +134,8 @@ _GetMusicData (FILE *fp, DWORD length) char filename[1000]; *pmus = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample)); + (*pmus)->buffer_tag = 0; + (*pmus)->read_chain_ptr = NULL; strcpy (filename, _cur_resfile_name); switch (optWhichMusic) @@ -158,7 +160,7 @@ _GetMusicData (FILE *fp, DWORD length) } fprintf (stderr, "_GetMusicData(): loading %s\n", filename); - if (((*pmus)->decoder = SoundDecoder_Load (filename, 4096)) == 0) + if (((*pmus)->decoder = SoundDecoder_Load (filename, 4096, 0, 0)) == 0) { fprintf (stderr, "_GetMusicData(): couldn't load %s\n", filename); diff --git a/sc2/src/sc2code/libs/sound/mixsdl/sfx.c b/sc2/src/sc2code/libs/sound/mixsdl/sfx.c index 872492fec..9dbd3ec20 100644 --- a/sc2/src/sc2code/libs/sound/mixsdl/sfx.c +++ b/sc2/src/sc2code/libs/sound/mixsdl/sfx.c @@ -135,7 +135,10 @@ _GetSoundBankData (FILE *fp, DWORD length) fprintf (stderr, "_GetSoundBankData(): loading %s\n", filename); sndfx[snd_ct] = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample)); - sndfx[snd_ct]->decoder = SoundDecoder_Load (filename, 4096); + sndfx[snd_ct]->buffer_tag = 0; + sndfx[snd_ct]->read_chain_ptr = NULL; + + sndfx[snd_ct]->decoder = SoundDecoder_Load (filename, 4096, 0, 0); if (!sndfx[snd_ct]->decoder) { fprintf (stderr, "_GetSoundBankData(): couldn't load %s\n", filename); diff --git a/sc2/src/sc2code/libs/sound/mixsdl/sound.c b/sc2/src/sc2code/libs/sound/mixsdl/sound.c index b0b694d98..d09d6395f 100644 --- a/sc2/src/sc2code/libs/sound/mixsdl/sound.c +++ b/sc2/src/sc2code/libs/sound/mixsdl/sound.c @@ -175,6 +175,50 @@ SoundPlaying (void) return FALSE; } +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; + 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); + 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; + prev_chain = first_chain; + if (prev_chain == current_chain) + return (prev_chain); + while (prev_chain->next) + { + if (prev_chain->next == current_chain) + return (prev_chain); + prev_chain = prev_chain->next; + } + return (first_chain); +} + // Status: Ignored BOOLEAN InitSound (int argc, char* argv[]) diff --git a/sc2/src/sc2code/libs/sound/mixsdl/sound.h b/sc2/src/sc2code/libs/sound/mixsdl/sound.h index f69696911..db0e3432c 100644 --- a/sc2/src/sc2code/libs/sound/mixsdl/sound.h +++ b/sc2/src/sc2code/libs/sound/mixsdl/sound.h @@ -32,13 +32,37 @@ #define SPEECH_SOURCE (MUSIC_SOURCE + 1) #define NUM_SOUNDSOURCES (SPEECH_SOURCE + 1) +typedef struct +{ + mixSDL_Object buf_name; + int type; + void *value; +} TFB_SoundTag; + +enum +{ + MIX_BUFFER_TAG_TEXT = 1, + MIX_BUFFER_TAG_TEXTPAGE +}; + +typedef struct tfb_soundchain +{ + TFB_SoundDecoder *decoder; // points at the decoder to read from + float start_time; + TFB_SoundTag tag; + struct tfb_soundchain *next; +} TFB_SoundChain; + // audio data typedef struct tfb_soundsample { - TFB_SoundDecoder *decoder; // if != NULL, sound is streamed - float length; // total length in seconds + 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 mixSDL_Object *buffer; uint32 num_buffers; + TFB_SoundTag **buffer_tag; } TFB_SoundSample; // equivalent to channel in legacy sound code @@ -62,5 +86,10 @@ extern TFB_SoundSource soundSource[]; 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/mixsdl/stream.c b/sc2/src/sc2code/libs/sound/mixsdl/stream.c index 129c34803..340c9a5be 100644 --- a/sc2/src/sc2code/libs/sound/mixsdl/stream.c +++ b/sc2/src/sc2code/libs/sound/mixsdl/stream.c @@ -25,138 +25,90 @@ bool speech_advancetrack = FALSE; - void PlayStream (TFB_SoundSample *sample, uint32 source, bool looping, bool scope) { - uint32 i, pos = 0; + uint32 i, pos = 0, offset = 0; - if (!sample) + if (!sample || (!sample->read_chain_ptr && !sample->decoder)) return; StopStream (source); + if (sample->read_chain_ptr) + { + sample->decoder = sample->read_chain_ptr->decoder; + offset = (int) (sample->read_chain_ptr->start_time * (float)ONE_SECOND); + } + else + offset= 0; SoundDecoder_Rewind (sample->decoder); soundSource[source].sample = sample; + soundSource[source].sample->play_chain_ptr = sample->read_chain_ptr; soundSource[source].sample->decoder->looping = looping; mixSDL_Sourcei (soundSource[source].handle, MIX_LOOPING, false); if (scope) { - soundSource[source].sbuffer = HMalloc (sample->num_buffers * sample->decoder->buffer_size); + soundSource[source].sbuffer = NULL; } + 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 sample %x decoded_bytes %d\n", source, sample, decoded_bytes); + //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; - mixSDL_BufferData (sample->buffer[i], sample->decoder->format, sample->decoder->buffer, - decoded_bytes, sample->decoder->frequency); - + mixSDL_BufferData (sample->buffer[i], sample->decoder->format, sample->decoder->buffer, + decoded_bytes, sample->decoder->frequency); mixSDL_SourceQueueBuffers (soundSource[source].handle, 1, &sample->buffer[i]); if (scope) { - UBYTE *p = (UBYTE *)soundSource[source].sbuffer; - assert (pos + decoded_bytes <= sample->num_buffers * sample->decoder->buffer_size); + UBYTE *p; + if (! soundSource[source].sbuffer) + soundSource[source].sbuffer = HMalloc (decoded_bytes); + else + soundSource[source].sbuffer = HRealloc (soundSource[source].sbuffer, + pos + decoded_bytes); + p = (UBYTE *)soundSource[source].sbuffer; memcpy (&p[pos], sample->decoder->buffer, decoded_bytes); pos += decoded_bytes; } if (sample->decoder->error) - break; + { + if (sample->decoder->error == SOUNDDECODER_EOF && 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 + break; + } } - + if (sample->buffer_tag) + for ( ; i num_buffers; ++i) + sample->buffer_tag[i] = 0; soundSource[source].sbuf_size = pos; - soundSource[source].start_time = GetTimeCounter (); - soundSource[source].stream_should_be_playing = TRUE; - mixSDL_SourcePlay (soundSource[source].handle); -} - -// decoders array is NULL-terminated -int -PreDecodeClips (TFB_SoundSample *sample, TFB_SoundDecoder *decoders[], bool autofree) -{ - uint32 i; - uint32 org_buffers; - TFB_SoundDecoder **pdecoder; - - if (!sample) - return 0; - - sample->length = 0.0; - org_buffers = sample->num_buffers; - - for (i = 0, pdecoder = decoders; - i < sample->num_buffers && *pdecoder; - i++, pdecoder++) - { - TFB_SoundDecoder *decoder = *pdecoder; - uint32 decoded_bytes; - - decoded_bytes = SoundDecoder_DecodeAll (decoder); - if (decoded_bytes == 0) - { - // decoder error, will reuse the buffer - i--; - } - else - { - mixSDL_BufferData (sample->buffer[i], decoder->format, decoder->buffer, - decoded_bytes, decoder->frequency); - - sample->length += decoder->length; - } - - if (autofree) - { - SoundDecoder_Free (*pdecoder); - *pdecoder = 0; - } - } - - if (autofree && i < sample->num_buffers) - { - mixSDL_DeleteBuffers (sample->num_buffers - i, sample->buffer + i); - sample->num_buffers = i; - } - - if (i == 0) - fprintf (stderr, "EnqueueClips(): no clips decoded\n"); - - return i; -} - -void -PlayDecodedClip (TFB_SoundSample *sample, uint32 source, bool scope) -{ - uint32 i, pos = 0; - - if (!sample) - return; - - StopStream (source); - soundSource[source].sample = sample; - mixSDL_Sourcei (soundSource[source].handle, MIX_LOOPING, false); - - mixSDL_SourceQueueBuffers (soundSource[source].handle, - sample->num_buffers, sample->buffer); - - for (i = 0; i < sample->num_buffers; i++) - { - mixSDL_Object size; - - size = 0; - mixSDL_GetBufferi (sample->buffer[i], MIX_SIZE, &size); - //soundSource[source].total_decoded += size; - } - - soundSource[source].sbuf_size = pos; - soundSource[source].start_time = GetTimeCounter (); + soundSource[source].start_time = GetTimeCounter () - offset; soundSource[source].stream_should_be_playing = TRUE; mixSDL_SourcePlay (soundSource[source].handle); } @@ -220,10 +172,14 @@ int StreamDecoderTaskFunc (void *data) { Task task = (Task)data; + int i; + mixSDL_Object last_buffer[NUM_SOUNDSOURCES]; + + for (i = 0; i < NUM_SOUNDSOURCES; i++) + last_buffer[i] = 0; while (!Task_ReadState (task, TASK_EXIT)) { - int i; TaskSwitch (); @@ -232,42 +188,40 @@ StreamDecoderTaskFunc (void *data) uint32 processed, queued; mixSDL_Object state; bool do_speech_advancetrack = false; - int streaming; LockMutex (soundSource[i].stream_mutex); if (!soundSource[i].sample || + !soundSource[i].sample->decoder || !soundSource[i].stream_should_be_playing || - (soundSource[i].sample->decoder && - soundSource[i].sample->decoder->error == SOUNDDECODER_ERROR)) + soundSource[i].sample->decoder->error == SOUNDDECODER_ERROR) { UnlockMutex (soundSource[i].stream_mutex); continue; } - streaming = soundSource[i].sample->decoder != 0; - mixSDL_GetSourcei (soundSource[i].handle, MIX_BUFFERS_PROCESSED, &processed); mixSDL_GetSourcei (soundSource[i].handle, MIX_BUFFERS_QUEUED, &queued); if (processed == 0) { - mixSDL_GetSourcei (soundSource[i].handle, MIX_SOURCE_STATE, &state); + mixSDL_GetSourcei (soundSource[i].handle, MIX_SOURCE_STATE, &state); if (state != MIX_PLAYING) { - if (queued == 0 && (!streaming || - soundSource[i].sample->decoder->error == SOUNDDECODER_EOF)) + if (queued == 0 && soundSource[i].sample->decoder->error == SOUNDDECODER_EOF) { - fprintf (stderr, "StreamDecoderTaskFunc(): finished playing %s, source %d\n", - streaming ? soundSource[i].sample->decoder->filename : "(decoded)", i); - soundSource[i].stream_should_be_playing = false; - if (i == SPEECH_SOURCE && speech_advancetrack) + 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) { - do_speech_advancetrack = true; - } - } - else if (streaming) - { + soundSource[i].sample->decoder = NULL; + soundSource[i].sample->read_chain_ptr = NULL; + if (speech_advancetrack) + do_speech_advancetrack = true; + } + } + else + { fprintf (stderr, "StreamDecoderTaskFunc(): buffer underrun when playing %s, source %d\n", soundSource[i].sample->decoder->filename, i); mixSDL_SourcePlay (soundSource[i].handle); @@ -282,20 +236,33 @@ StreamDecoderTaskFunc (void *data) uint32 error; mixSDL_Object buffer; uint32 decoded_bytes; + uint32 buf_num; mixSDL_GetError (); // clear error state mixSDL_SourceUnqueueBuffers (soundSource[i].handle, 1, &buffer); + if ((error = mixSDL_GetError()) != MIX_NO_ERROR) { fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alSourceUnqueueBuffers: %x, file %s, source %d\n", error, soundSource[i].sample->decoder->filename, i); break; } - if (!streaming) + if (i == SPEECH_SOURCE) { - processed--; - continue; + for (buf_num = 0; buf_num < soundSource[i].sample->num_buffers; buf_num++) + { + 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].total_decoded += soundSource[i].sample->decoder->buffer_size; @@ -304,14 +271,41 @@ StreamDecoderTaskFunc (void *data) { if (soundSource[i].sample->decoder->error == SOUNDDECODER_EOF) { - //fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is eof for %s\n", soundSource[i].sample->decoder->filename); + 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 + { + //fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is eof for %s\n", soundSource[i].sample->decoder->filename); + processed--; + continue; + } } else { //fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is %d for %s\n", soundSource[i].sample->decoder->error, soundSource[i].sample->decoder->filename); + processed--; + continue; } - processed--; - continue; } decoded_bytes = SoundDecoder_Decode (soundSource[i].sample->decoder); @@ -325,17 +319,18 @@ StreamDecoderTaskFunc (void *data) if (decoded_bytes > 0) { - mixSDL_BufferData (buffer, soundSource[i].sample->decoder->format, - soundSource[i].sample->decoder->buffer, decoded_bytes, - soundSource[i].sample->decoder->frequency); + mixSDL_BufferData (buffer, soundSource[i].sample->decoder->format, + soundSource[i].sample->decoder->buffer, decoded_bytes, + soundSource[i].sample->decoder->frequency); if ((error = mixSDL_GetError()) != MIX_NO_ERROR) { - fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alBufferData: %x, file %s, source %d, decoded_bytes %d\n", - error, soundSource[i].sample->decoder->filename, i, decoded_bytes); + fprintf (stderr, "StreamDecoderTaskFunc(): mixSDL error after mixSDL_BufferData: %x, file %s, source %d, decoded_bytes %d\n", + error, soundSource[i].sample->decoder->filename, i, decoded_bytes); } else { + last_buffer[i] = buffer; mixSDL_SourceQueueBuffers (soundSource[i].handle, 1, &buffer); if (soundSource[i].sbuffer) @@ -376,8 +371,8 @@ StreamDecoderTaskFunc (void *data) if ((error = mixSDL_GetError()) != MIX_NO_ERROR) { - fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alSourceQueueBuffers: %x, file %s, source %d, decoded_bytes %d\n", - error, i, soundSource[i].sample->decoder->filename, decoded_bytes); + fprintf (stderr, "StreamDecoderTaskFunc(): mixSDL error after mixSDL_SourceQueueBuffers: %x, file %s, source %d, decoded_bytes %d\n", + error, i, soundSource[i].sample->decoder->filename, decoded_bytes); } } } @@ -391,7 +386,7 @@ StreamDecoderTaskFunc (void *data) { if (do_speech_advancetrack) { - //fprintf (stderr, "StreamDecoderTaskFunc(): calling advance_track\n"); + fprintf (stderr, "StreamDecoderTaskFunc(): calling advance_track\n"); do_speech_advancetrack = false; advance_track (0); } diff --git a/sc2/src/sc2code/libs/sound/mixsdl/trackplayer.c b/sc2/src/sc2code/libs/sound/mixsdl/trackplayer.c index acbf9fcb9..f82dab742 100644 --- a/sc2/src/sc2code/libs/sound/mixsdl/trackplayer.c +++ b/sc2/src/sc2code/libs/sound/mixsdl/trackplayer.c @@ -24,37 +24,47 @@ #include "sound.h" #include "libs/sound/trackplayer.h" -extern int do_subtitles (UNICODE *pStr, UNICODE *TimeStamp); +extern int do_subtitles (UNICODE *pStr, UNICODE *TimeStamp, int method); + +static int tct; //total number of subtitle tracks +static int tcur; //currently playing subtitle track +static int cur_page = 0; //current page of subtitle track +static int no_page_break = 0; +static int no_voice; -static int tct, tcur, no_voice; #define MAX_CLIPS 50 -static struct -{ - int text_spliced; - UNICODE *text; - UNICODE *timestamp; - TFB_SoundSample *sample; -} track_clip[MAX_CLIPS]; +static TFB_SoundSample *sound_sample = NULL; +static TFB_SoundChain *first_chain = NULL; //first decoder in linked list +static TFB_SoundChain *last_chain = NULL; //last decoder in linked list +static UNICODE *TrackTextArray[MAX_CLIPS]; //storage for subtitlle text +static Mutex track_mutex; //protects tcur and tct void JumpTrack (int abort) { speech_advancetrack = FALSE; - if (track_clip[tcur].sample) + if (sound_sample) { LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); StopStream (SPEECH_SOURCE); + if (abort) + { + sound_sample->read_chain_ptr = NULL; + sound_sample->decoder = NULL; + } UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); } no_voice = 1; - do_subtitles ((void *)~0, 0); + do_subtitles ((void *)~0, (void *)~0, 1); if (abort) + LockMutex (track_mutex); tcur = tct; + UnlockMutex(track_mutex); } void @@ -62,34 +72,25 @@ advance_track (int channel_finished) { if (channel_finished <= 0) { - if (channel_finished == 0) - ++tcur; - if (tcur < tct) - { - LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); - if (track_clip[tcur].sample->decoder) - PlayStream (track_clip[tcur].sample, - SPEECH_SOURCE, false, - speechVolumeScale != 0.0f); - else - PlayDecodedClip (track_clip[tcur].sample, - SPEECH_SOURCE, false); - UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); - do_subtitles ((UNICODE *) ~0, 0); - do_subtitles (0, 0); - } - else if (channel_finished == 0) - { - --tcur; - no_voice = 1; - } + if (sound_sample->decoder) + { + LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + PlayStream (sound_sample, + SPEECH_SOURCE, false, + speechVolumeScale != 0.0f); + UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + } + else if (channel_finished == 0) + { + no_voice = 1; + } } } void ResumeTrack () { - if (tcur < tct) + if (sound_sample && sound_sample->decoder) { uint32 state; @@ -121,21 +122,25 @@ ResumeTrack () COUNT PlayingTrack () { - if (tcur < tct) + if (sound_sample->decoder) { - if (do_subtitles (track_clip[tcur].text, track_clip[tcur].timestamp) || - (no_voice && ++tcur < tct && do_subtitles (0, 0))) + int last_track, last_page; + LockMutex (track_mutex); + last_track = tcur; + last_page = cur_page; + UnlockMutex (track_mutex); + if (do_subtitles (TrackTextArray[last_track], (void *)last_page, 1) || + (no_voice && ++tcur < tct && do_subtitles (0, (void *)~0, 1))) { return (tcur + 1); } - else if (track_clip[tcur].sample) + else if (sound_sample) { COUNT result; LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); - result = (PlayingStream (SPEECH_SOURCE) ? (COUNT)(tcur + 1) : 0); + result = (PlayingStream (SPEECH_SOURCE) ? (COUNT)(last_track + 1) : 0); UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); - return result; } } @@ -146,39 +151,70 @@ PlayingTrack () void StopTrack () { + int i; speech_advancetrack = FALSE; LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); StopStream (SPEECH_SOURCE); UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); - while (tct--) + for (i = 0; i < tct; i++) { - 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) - { - TFB_SoundSample *sample = track_clip[tct].sample; - track_clip[tct].sample = NULL; - if (sample->decoder) - { - TFB_SoundDecoder *decoder = sample->decoder; - mixSDL_Object *buffer = sample->buffer; - sample->decoder = NULL; - sample->buffer = NULL; - SoundDecoder_Free (decoder); - mixSDL_DeleteBuffers (sample->num_buffers, buffer); - HFree (buffer); - } - HFree (sample); - } + HFree (TrackTextArray[i]); + TrackTextArray[i] = 0; + } + if (first_chain) + { + destroy_soundchain (first_chain); + first_chain = NULL; + } + if (sound_sample) + { + DestroyMutex (track_mutex); + mixSDL_DeleteBuffers (sound_sample->num_buffers, sound_sample->buffer); + HFree (sound_sample->buffer); + HFree (sound_sample->buffer_tag); + HFree (sound_sample); + sound_sample = NULL; } tct = tcur = 0; no_voice = 0; - do_subtitles (0, 0); + do_subtitles (0, (void *)~0, 1); +} + +void +DoTrackTag (TFB_SoundTag *tag) +{ + if (tag->type == MIX_BUFFER_TAG_TEXT) + { + LockMutex (track_mutex); + tcur = ((int)tag->value) >> 8; + cur_page = ((int)tag->value) & 0xFF; + UnlockMutex (track_mutex); + } +} + +int +GetTimeStamps(UNICODE *TimeStamps, uint32 *time_stamps) +{ + int pos; + int num = 0; + while (*TimeStamps && (pos = wstrcspn (TimeStamps, ",\n"))) + { + UNICODE valStr[10]; + wstrncpy (valStr, TimeStamps, pos); + valStr[pos] = '\0'; + *time_stamps = wstrtoul(valStr,NULL,10); + if (*time_stamps) + { + num++; + time_stamps++; + } + TimeStamps += pos; + if (*TimeStamps) + TimeStamps++; + } + *time_stamps = 0; + return (num); } // decodes several tracks into one and adds it to queue @@ -189,6 +225,7 @@ SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText) #define MAX_MULTI_TRACKS 20 #define MAX_MULTI_BUFFERS 100 TFB_SoundDecoder* track_decs[MAX_MULTI_TRACKS + 1]; + TFB_SoundChain *begin_chain; int tracks; int slen; @@ -202,17 +239,21 @@ SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText) if (tct >= MAX_CLIPS) { -#ifdef DEBUG fprintf (stderr, "SpliceMultiTrack(): no more clip slots (%d)\n", MAX_CLIPS); -#endif + return; + } + + if (! sound_sample) + { + fprintf (stderr, "SpliceMultiTrack(): Cannot be called before SpliceTrack()\n"); return; } fprintf (stderr, "SpliceMultiTrack(): loading...\n"); for (tracks = 0; *TrackNames && tracks < MAX_MULTI_TRACKS; TrackNames++, tracks++) { - track_decs[tracks] = SoundDecoder_Load (*TrackNames, 32768); + track_decs[tracks] = SoundDecoder_Load (*TrackNames, 32768, 0, 0); if (track_decs[tracks]) { fprintf (stderr, " track: %s, decoder: %s, rate %d format %x\n", @@ -220,7 +261,13 @@ SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText) track_decs[tracks]->decoder_info, track_decs[tracks]->frequency, track_decs[tracks]->format); + SoundDecoder_DecodeAll (track_decs[tracks]); + last_chain->next = create_soundchain (track_decs[tracks], sound_sample->length); + last_chain = last_chain->next; + if (tracks == 0) + begin_chain = last_chain; + sound_sample->length += track_decs[tracks]->length; } else { @@ -237,34 +284,34 @@ SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText) } slen = wstrlen (TrackText); - track_clip[tct].text = HMalloc (slen + 1); - wstrcpy (track_clip[tct].text, TrackText); - track_clip[tct].text_spliced = 1; - track_clip[tct].timestamp = NULL; - - track_clip[tct].sample = (TFB_SoundSample *) HMalloc ( - sizeof (TFB_SoundSample)); - track_clip[tct].sample->decoder = NULL; - track_clip[tct].sample->num_buffers = tracks; - track_clip[tct].sample->buffer = HMalloc (sizeof (mixSDL_Object) - * track_clip[tct].sample->num_buffers); - mixSDL_GenBuffers (track_clip[tct].sample->num_buffers, track_clip[tct].sample->buffer); - - tracks = PreDecodeClips (track_clip[tct].sample, track_decs, true); + if (tct) + { + int slen1; + slen1 = wstrlen (TrackTextArray[tct - 1]); + TrackTextArray[tct - 1] = HRealloc (TrackTextArray[tct - 1], slen1 + slen + 1); + wstrcpy (&TrackTextArray[tct - 1][slen1], TrackText); + } + else + { + TrackTextArray[tct] = HMalloc (slen + 1); + wstrcpy (TrackTextArray[tct++], TrackText); + begin_chain->tag.type = MIX_BUFFER_TAG_TEXT; + begin_chain->tag.value = (void *)((tct - 1) << 8); + } + no_page_break = 1; if (tracks > 0) - ++tct; + return; else { fprintf (stderr, " no tracks loaded\n"); - HFree (track_clip[tct].sample); - track_clip[tct].sample = NULL; } } void SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp) { + unsigned long startTime; if (TrackText) { if (TrackName == 0) @@ -274,55 +321,95 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp) int slen1, slen2; UNICODE *oTT; - oTT = track_clip[tct - 1].text; + oTT = TrackTextArray[tct - 1]; 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); + TrackTextArray[tct - 1] = HRealloc (oTT, slen1 + slen2 + 1); + wstrcpy (&TrackTextArray[tct - 1][slen1], TrackText); } } - else if (tct < MAX_CLIPS) + else { - track_clip[tct].text = TrackText; - track_clip[tct].text_spliced = 0; + int num_pages, cur_page; + uint32 time_stamps[50]; - track_clip[tct].timestamp = TimeStamp; - fprintf (stderr, "SpliceTrack(): loading %s\n", TrackName); - - track_clip[tct].sample = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample)); - track_clip[tct].sample->decoder = SoundDecoder_Load (TrackName, 4096); - - if (track_clip[tct].sample->decoder) + if (no_page_break && tct) { - fprintf (stderr, " decoder: %s, rate %d format %x\n", - track_clip[tct].sample->decoder->decoder_info, - track_clip[tct].sample->decoder->frequency, - track_clip[tct].sample->decoder->format); - - track_clip[tct].sample->length = - track_clip[tct].sample->decoder->length; - track_clip[tct].sample->num_buffers = 8; - track_clip[tct].sample->buffer = HMalloc ( - sizeof (mixSDL_Object) * - track_clip[tct].sample->num_buffers); - mixSDL_GenBuffers (track_clip[tct].sample->num_buffers, - track_clip[tct].sample->buffer); + int slen1, slen2; + UNICODE *oTT; + + oTT = TrackTextArray[tct - 1]; + slen1 = wstrlen (oTT); + slen2 = wstrlen (TrackText); + TrackTextArray[tct - 1] = HRealloc (oTT, slen1 + slen2 + 1); + wstrcpy (&TrackTextArray[tct - 1][slen1], TrackText); } else { - fprintf (stderr, "SpliceTrack(): couldn't load %s\n", TrackName); - HFree (track_clip[tct].sample); - track_clip[tct].sample = NULL; + TrackTextArray[tct] = HMalloc (sizeof (UNICODE) * (wstrlen (TrackText) + 1)); + wstrcpy (TrackTextArray[tct++], TrackText); } + if (TimeStamp) + num_pages = GetTimeStamps (TimeStamp, time_stamps); + else + num_pages = 0; + + fprintf (stderr, "SpliceTrack(): loading %s\n", TrackName); + + startTime = 0; + for (cur_page = 0; cur_page <= num_pages; cur_page++) + { + if (! sound_sample) + { + TFB_SoundDecoder *decoder; + track_mutex = CreateMutex(); + sound_sample = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample)); + sound_sample->num_buffers = 8; + sound_sample->buffer_tag = HMalloc (sizeof (TFB_SoundTag *) * sound_sample->num_buffers); + sound_sample->buffer = HMalloc (sizeof (uint32) * sound_sample->num_buffers); + mixSDL_GenBuffers (sound_sample->num_buffers, sound_sample->buffer); + decoder = SoundDecoder_Load (TrackName, 4096, startTime, time_stamps[cur_page]); + sound_sample->read_chain_ptr = create_soundchain (decoder, 0.0); + sound_sample->decoder = decoder; + first_chain = last_chain = sound_sample->read_chain_ptr; + sound_sample->length = 0; + } + else + { + TFB_SoundDecoder *decoder; + decoder = SoundDecoder_Load (TrackName, 4096, startTime, time_stamps[cur_page]); + last_chain->next = create_soundchain (decoder, sound_sample->length); + last_chain = last_chain->next; + } + startTime += time_stamps[cur_page]; - ++tct; + // fprintf (stderr, "page (%d of %d): %d\n",cur_page, num_pages, startTime); + if (last_chain->decoder) + { + //fprintf (stderr, " decoder: %s, rate %d format %x\n", + // last_chain->decoder->decoder_info, + // last_chain->decoder->frequency, + // last_chain->decoder->format); + + sound_sample->length += last_chain->decoder->length; + if (! no_page_break) + { + last_chain->tag.type = MIX_BUFFER_TAG_TEXT; + last_chain->tag.value = (void *)(((tct - 1) << 8) | cur_page); + } + no_page_break = 0; + } + else + { + fprintf (stderr, "SpliceTrack(): couldn't load %s\n", TrackName); + mixSDL_DeleteBuffers (sound_sample->num_buffers, sound_sample->buffer); + destroy_soundchain (first_chain); + first_chain = NULL; + HFree (sound_sample->buffer); + HFree (sound_sample); + sound_sample = NULL; + } + } } } } @@ -330,7 +417,7 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp) void PauseTrack () { - if (tcur < tct && track_clip[tcur].sample) + if (sound_sample && sound_sample->decoder) { LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); PauseStream (SPEECH_SOURCE); @@ -341,16 +428,45 @@ PauseTrack () void FastReverse () { - JumpTrack (0); - no_voice = 0; - tcur = 0; - ResumeTrack (); + if (sound_sample) + { + TFB_SoundChain *prev_chain; + LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); +// fprintf(stderr, "playing %s at %d\n", +// sound_sample->play_chain_ptr->decoder->filename, +// sound_sample->play_chain_ptr->decoder->start_sample); + prev_chain = get_previous_chain(first_chain, sound_sample->play_chain_ptr); +// fprintf(stderr, "now playing %s at %d\n", +// prev_chain->decoder->filename, prev_chain->decoder->start_sample); + if (prev_chain) + { + sound_sample->read_chain_ptr = prev_chain; + PlayStream (sound_sample, + SPEECH_SOURCE, false, + speechVolumeScale != 0.0f); + } + UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + } } void FastForward () { - JumpTrack (0); + if (sound_sample) + { + TFB_SoundChain *cur_ptr = sound_sample->play_chain_ptr; + LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + while (cur_ptr->next && ! cur_ptr->tag.type) + cur_ptr = cur_ptr->next; + if (cur_ptr->next) + { + sound_sample->read_chain_ptr = cur_ptr->next; + PlayStream (sound_sample, + SPEECH_SOURCE, false, + speechVolumeScale != 0.0f); + } + UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + } //no_voice = 0; } diff --git a/sc2/src/sc2code/libs/sound/openal/decoders/decoder.c b/sc2/src/sc2code/libs/sound/openal/decoders/decoder.c index a1249ce70..cd4cf72db 100644 --- a/sc2/src/sc2code/libs/sound/openal/decoders/decoder.c +++ b/sc2/src/sc2code/libs/sound/openal/decoders/decoder.c @@ -122,7 +122,7 @@ void SoundDecoder_Uninit (void) MikMod_Exit (); } -TFB_SoundDecoder* SoundDecoder_Load (char *filename, ALuint buffer_size) +TFB_SoundDecoder* SoundDecoder_Load (char *filename, ALuint buffer_size, unsigned long startTime, unsigned long runTime) { int i; @@ -150,6 +150,9 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, ALuint buffer_size) decoder->decoder_info = decoder_info_wav; decoder->type = SOUNDDECODER_WAV; decoder->filename = (char *) HMalloc (strlen (filename) + 1); + decoder->start_sample = 0; + decoder->end_sample = 0; + decoder->pos = 0; strcpy (decoder->filename, filename); return decoder; @@ -184,6 +187,9 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, ALuint buffer_size) decoder->decoder_info = decoder_info_mod; decoder->type = SOUNDDECODER_MOD; decoder->filename = (char *) HMalloc (strlen (filename) + 1); + decoder->start_sample = 0; + decoder->end_sample = 0; + decoder->pos = 0; strcpy (decoder->filename, filename); decoder->data = mod; @@ -239,20 +245,36 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, ALuint buffer_size) decoder = (TFB_SoundDecoder *) HMalloc (sizeof (TFB_SoundDecoder)); decoder->buffer = HMalloc (buffer_size); decoder->buffer_size = buffer_size; - if (vinfo->channels == 1) - decoder->format = AL_FORMAT_MONO16; - else - decoder->format = AL_FORMAT_STEREO16; decoder->frequency = vinfo->rate; decoder->looping = AL_FALSE; decoder->error = SOUNDDECODER_OK; decoder->length = (float) ov_time_total (vf, -1); + if (runTime && runTime / 1000.0 < decoder->length) + decoder->length = (float)(runTime / 1000.0); + + decoder->start_sample = decoder->frequency * startTime/1000; + decoder->end_sample = decoder->start_sample + + (unsigned long)(decoder->length * decoder->frequency); + if (decoder->start_sample) + ov_pcm_seek (vf, decoder->start_sample); + + if (vinfo->channels == 1) + { + decoder->format = AL_FORMAT_MONO16; + decoder->pos = decoder->start_sample * 2; + } + else + { + decoder->format = AL_FORMAT_STEREO16; + decoder->pos = decoder->start_sample * 4; + } + decoder->decoder_info = decoder_info_ogg; decoder->type = SOUNDDECODER_OGG; decoder->filename = (char *) HMalloc (strlen (filename) + 1); strcpy (decoder->filename, filename); decoder->data = vf; - + return decoder; } else @@ -300,26 +322,50 @@ ALuint SoundDecoder_Decode (TFB_SoundDecoder *decoder) ALuint decoded_bytes = 0, count = 0; long rc; int bitstream; + unsigned long max_bytes, buffer_size, close_on_done = 0; char *buffer = (char *) decoder->buffer; - while (decoded_bytes < decoder->buffer_size) + if (! decoder->looping) + { + if (decoder->format == AL_FORMAT_STEREO16) + max_bytes = decoder->end_sample * 4; + else + max_bytes = decoder->end_sample * 2; + if (max_bytes - decoder->pos < decoder->buffer_size) + { + buffer_size = max_bytes - decoder->pos; + close_on_done = 1; + } + else + { + buffer_size = decoder->buffer_size; + } + } + else + buffer_size = decoder->buffer_size; + + while (decoded_bytes < buffer_size) { - - rc = ov_read (vf, &buffer[decoded_bytes], decoder->buffer_size - decoded_bytes, 0, 2, 1, &bitstream); + rc = ov_read (vf, &buffer[decoded_bytes], + buffer_size - decoded_bytes, 0, 2, 1, &bitstream); if (rc < 0) { decoder->error = SOUNDDECODER_ERROR; fprintf (stderr, "SoundDecoder_Decode(): error decoding %s, code %d\n", decoder->filename, rc); return decoded_bytes; } - if (rc == 0) + if (rc == 0 || close_on_done && buffer_size == decoded_bytes + rc) { + if (close_on_done) + { + decoded_bytes += rc; + } if (decoder->looping) { - int err; - if ((err = ov_pcm_seek (vf, 0)) != 0) + SoundDecoder_Rewind (decoder); + if (decoder->error) { - fprintf (stderr, "SoundDecoder_Decode(): tried to loop %s but couldn't rewind, error code %d\n", decoder->filename, err); + fprintf (stderr, "SoundDecoder_Decode(): tried to loop %s but couldn't rewind, error code %d\n", decoder->filename, decoder->error); } else { @@ -328,6 +374,8 @@ ALuint SoundDecoder_Decode (TFB_SoundDecoder *decoder) continue; } } + else + decoder->pos += decoded_bytes; fprintf (stderr, "SoundDecoder_Decode(): eof for %s\n", decoder->filename); decoder->error = SOUNDDECODER_EOF; @@ -338,11 +386,14 @@ ALuint SoundDecoder_Decode (TFB_SoundDecoder *decoder) //fprintf (stderr, "iter %d rc %d decoded_bytes %d remaining %d\n", count, rc, decoded_bytes, decoder->buffer_size - decoded_bytes); count++; } - + decoder->pos += decoded_bytes; decoder->error = SOUNDDECODER_OK; //fprintf (stderr, "SoundDecoder_Decode(): decoded %d bytes from %s\n", decoded_bytes, decoder->filename); return decoded_bytes; } + case SOUNDDECODER_BUF: + decoder->error = SOUNDDECODER_EOF; + return (decoder->buffer_size); default: { fprintf (stderr, "SoundDecoder_Decode(): unknown type %d\n", decoder->type); @@ -362,11 +413,14 @@ ALuint SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder) { ALboolean loop; - LoadWAVFile(decoder->filename ,&decoder->format, &decoder->buffer, + LoadWAVFile (decoder->filename ,&decoder->format, &decoder->buffer, &decoder->buffer_size, &decoder->frequency, &loop); if (decoder->buffer_size != 0) + { + decoder->type = SOUNDDECODER_BUF; decoder->error = SOUNDDECODER_OK; + } else decoder->error = SOUNDDECODER_ERROR; @@ -379,7 +433,59 @@ ALuint SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder) } case SOUNDDECODER_OGG: { - fprintf (stderr, "SoundDecoder_DecodeAll(): unimplemented for ogg\n"); + OggVorbis_File *vf = (OggVorbis_File *) decoder->data; + ALuint decoded_bytes = 0; + long rc; + int bitstream; + ALuint reqbufsize = decoder->buffer_size; + + if (decoder->looping) + { + fprintf (stderr, "SoundDecoder_DecodeAll(): " + "called for %s with looping\n", decoder->filename); + return 0; + } + + if (reqbufsize < 4096) + reqbufsize = 4096; + +#ifdef DEBUG + if (reqbufsize < 16384) + fprintf (stderr, "SoundDecoder_DecodeAll(): WARNING, " + "called with a small buffer (%u)\n", reqbufsize); +#endif + + for (rc = 1; rc > 0; ) + { + if (decoded_bytes >= decoder->buffer_size) + { // need to grow buffer + decoder->buffer_size += reqbufsize; + decoder->buffer = HRealloc ( + decoder->buffer, decoder->buffer_size); + } + + rc = ov_read (vf, (char*)decoder->buffer + decoded_bytes, + decoder->buffer_size - decoded_bytes, + 0, 2, 1, &bitstream); + if (rc < 0) + { + decoder->error = SOUNDDECODER_ERROR; + fprintf (stderr, "SoundDecoder_DecodeAll(): " + "error decoding %s, code %d\n", + decoder->filename, rc); + return decoded_bytes; + } + + decoded_bytes += rc; + } + + decoder->buffer_size = decoded_bytes; + ov_clear (vf); + HFree (vf); + decoder->type = SOUNDDECODER_BUF; + + decoder->error = SOUNDDECODER_OK; + return decoded_bytes; break; } default: @@ -415,15 +521,25 @@ void SoundDecoder_Rewind (TFB_SoundDecoder *decoder) { int err; OggVorbis_File *vf = (OggVorbis_File *) decoder->data; - if ((err = ov_pcm_seek (vf, 0)) != 0) + if ((err = ov_pcm_seek (vf, decoder->start_sample)) != 0) { fprintf (stderr, "SoundDecoder_Rewind(): couldn't rewind %s, error code %d\n", decoder->filename, err); break; } + if (decoder->format == AL_FORMAT_MONO16) + decoder->pos = decoder->start_sample * 2; + else + decoder->pos = decoder->start_sample * 4; + //fprintf (stderr, "SoundDecoder_Rewind(): rewound %s\n", decoder->filename); decoder->error = SOUNDDECODER_OK; return; } + case SOUNDDECODER_BUF: + { + decoder->error = SOUNDDECODER_OK; + return; + } default: { fprintf (stderr, "SoundDecoder_Rewind(): unknown type %d\n", decoder->type); @@ -463,6 +579,8 @@ void SoundDecoder_Free (TFB_SoundDecoder *decoder) HFree (vf); break; } + case SOUNDDECODER_BUF: + break; default: { fprintf (stderr, "SoundDecoder_Free(): unknown type %d\n", decoder->type); diff --git a/sc2/src/sc2code/libs/sound/openal/decoders/decoder.h b/sc2/src/sc2code/libs/sound/openal/decoders/decoder.h index a2cbc860a..2b21ea756 100644 --- a/sc2/src/sc2code/libs/sound/openal/decoders/decoder.h +++ b/sc2/src/sc2code/libs/sound/openal/decoders/decoder.h @@ -45,6 +45,9 @@ typedef struct tfb_sounddecoder ALint type; char *filename; void *data; + unsigned long pos; + unsigned long start_sample; + unsigned long end_sample; } TFB_SoundDecoder; // return values @@ -62,11 +65,12 @@ enum SOUNDDECODER_WAV, SOUNDDECODER_MOD, SOUNDDECODER_OGG, + SOUNDDECODER_BUF, }; ALint SoundDecoder_Init (int flags); void SoundDecoder_Uninit (void); -TFB_SoundDecoder* SoundDecoder_Load (char *filename, ALuint buffer_size); +TFB_SoundDecoder* SoundDecoder_Load (char *filename, ALuint buffer_size, unsigned long startTime, unsigned long runTime); ALuint SoundDecoder_Decode (TFB_SoundDecoder *decoder); ALuint SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder); void SoundDecoder_Rewind (TFB_SoundDecoder *decoder); diff --git a/sc2/src/sc2code/libs/sound/openal/music.c b/sc2/src/sc2code/libs/sound/openal/music.c index c4f788d9d..a2541f00c 100644 --- a/sc2/src/sc2code/libs/sound/openal/music.c +++ b/sc2/src/sc2code/libs/sound/openal/music.c @@ -134,6 +134,8 @@ _GetMusicData (FILE *fp, DWORD length) char filename[1000]; *pmus = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample)); + (*pmus)->buffer_tag = 0; + (*pmus)->read_chain_ptr = NULL; strcpy (filename, _cur_resfile_name); switch (optWhichMusic) @@ -158,7 +160,7 @@ _GetMusicData (FILE *fp, DWORD length) } fprintf (stderr, "_GetMusicData(): loading %s\n", filename); - if (((*pmus)->decoder = SoundDecoder_Load (filename, 4096)) == 0) + if (((*pmus)->decoder = SoundDecoder_Load (filename, 4096, 0, 0)) == 0) { fprintf (stderr, "_GetMusicData(): couldn't load %s\n", filename); diff --git a/sc2/src/sc2code/libs/sound/openal/sfx.c b/sc2/src/sc2code/libs/sound/openal/sfx.c index 12a4842b4..e92298b50 100644 --- a/sc2/src/sc2code/libs/sound/openal/sfx.c +++ b/sc2/src/sc2code/libs/sound/openal/sfx.c @@ -135,7 +135,9 @@ _GetSoundBankData (FILE *fp, DWORD length) fprintf (stderr, "_GetSoundBankData(): loading %s\n", filename); sndfx[snd_ct] = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample)); - sndfx[snd_ct]->decoder = SoundDecoder_Load (filename, 4096); + sndfx[snd_ct]->buffer_tag = 0; + sndfx[snd_ct]->read_chain_ptr = NULL; + sndfx[snd_ct]->decoder = SoundDecoder_Load (filename, 4096, 0, 0); if (!sndfx[snd_ct]->decoder) { fprintf (stderr, "_GetSoundBankData(): couldn't load %s\n", filename); diff --git a/sc2/src/sc2code/libs/sound/openal/sound.c b/sc2/src/sc2code/libs/sound/openal/sound.c index ab29087d7..d265e34a2 100644 --- a/sc2/src/sc2code/libs/sound/openal/sound.c +++ b/sc2/src/sc2code/libs/sound/openal/sound.c @@ -178,6 +178,50 @@ SoundPlaying (void) return FALSE; } +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; + 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); + 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; + prev_chain = first_chain; + if (prev_chain == current_chain) + return (prev_chain); + while (prev_chain->next) + { + if (prev_chain->next == current_chain) + return (prev_chain); + prev_chain = prev_chain->next; + } + return (first_chain); +} + // Status: Ignored BOOLEAN InitSound (int argc, char* argv[]) diff --git a/sc2/src/sc2code/libs/sound/openal/sound.h b/sc2/src/sc2code/libs/sound/openal/sound.h index 4b89176b4..bc1bf097e 100644 --- a/sc2/src/sc2code/libs/sound/openal/sound.h +++ b/sc2/src/sc2code/libs/sound/openal/sound.h @@ -40,14 +40,40 @@ #define SPEECH_SOURCE (MUSIC_SOURCE + 1) #define NUM_SOUNDSOURCES (SPEECH_SOURCE + 1) +typedef struct +{ + ALuint buf_name; + int type; + void *value; +} TFB_SoundTag; + +enum +{ + AL_BUFFER_TAG_TEXT = 1, + AL_BUFFER_TAG_TEXTPAGE +}; + +typedef struct tfb_soundchain +{ + TFB_SoundDecoder *decoder; // points at the decoder to read from + float start_time; + TFB_SoundTag tag; + struct tfb_soundchain *next; +} TFB_SoundChain; + // audio data typedef struct tfb_soundsample { - TFB_SoundDecoder *decoder; // if != NULL, sound is streamed + 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 ALuint *buffer; ALuint num_buffers; + TFB_SoundTag **buffer_tag; } TFB_SoundSample; + // equivalent to channel in legacy sound code typedef struct tfb_soundsource { @@ -74,5 +100,10 @@ extern TFB_SoundSource soundSource[]; 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/openal/stream.c b/sc2/src/sc2code/libs/sound/openal/stream.c index b9b510750..126c05daf 100644 --- a/sc2/src/sc2code/libs/sound/openal/stream.c +++ b/sc2/src/sc2code/libs/sound/openal/stream.c @@ -28,32 +28,46 @@ BOOLEAN speech_advancetrack = FALSE; - void PlayStream (TFB_SoundSample *sample, ALuint source, ALboolean looping, ALboolean scope) { ALuint i, pos = 0; - - if (!sample) + ALuint offset = 0; + if (!sample || (!sample->read_chain_ptr && !sample->decoder)) return; StopStream (source); + if (sample->read_chain_ptr) + { + sample->decoder = sample->read_chain_ptr->decoder; + offset = (int) (sample->read_chain_ptr->start_time * (float)ONE_SECOND); + } + else + offset= 0; SoundDecoder_Rewind (sample->decoder); soundSource[source].sample = sample; + soundSource[source].sample->play_chain_ptr = sample->read_chain_ptr; soundSource[source].sample->decoder->looping = looping; alSourcei (soundSource[source].handle, AL_LOOPING, AL_FALSE); if (scope) { - soundSource[source].sbuffer = HMalloc (sample->num_buffers * sample->decoder->buffer_size); + soundSource[source].sbuffer = NULL; } + 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) { ALuint decoded_bytes; - + if (sample->buffer_tag) + sample->buffer_tag[i] = 0; decoded_bytes = SoundDecoder_Decode (sample->decoder); - //fprintf (stderr, "PlayStream(): source %d sample %x decoded_bytes %d\n", source, sample, decoded_bytes); + //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; @@ -64,8 +78,7 @@ PlayStream (TFB_SoundSample *sample, ALuint source, ALboolean looping, ALboolean sample->decoder->format == AL_FORMAT_STEREO16) { alBufferWriteData_LOKI (sample->buffer[i], sample->decoder->format, sample->decoder->buffer, - decoded_bytes, sample->decoder->frequency, - sample->decoder->format); + decoded_bytes, sample->decoder->frequency, sample->decoder->format); } else { @@ -76,23 +89,45 @@ PlayStream (TFB_SoundSample *sample, ALuint source, ALboolean looping, ALboolean alBufferData (sample->buffer[i], sample->decoder->format, sample->decoder->buffer, decoded_bytes, sample->decoder->frequency); #endif - alSourceQueueBuffers (soundSource[source].handle, 1, &sample->buffer[i]); if (scope) { - UBYTE *p = (UBYTE *)soundSource[source].sbuffer; - assert (pos + decoded_bytes <= sample->num_buffers * sample->decoder->buffer_size); + UBYTE *p; + if (! soundSource[source].sbuffer) + soundSource[source].sbuffer = HMalloc (decoded_bytes); + else + soundSource[source].sbuffer = HRealloc (soundSource[source].sbuffer, + pos + decoded_bytes); + p = (UBYTE *)soundSource[source].sbuffer; memcpy (&p[pos], sample->decoder->buffer, decoded_bytes); pos += decoded_bytes; } if (sample->decoder->error) - break; + { + if (sample->decoder->error == SOUNDDECODER_EOF && 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 + break; + } } - + if (sample->buffer_tag) + for ( ; i num_buffers; ++i) + sample->buffer_tag[i] = 0; soundSource[source].sbuf_size = pos; - soundSource[source].start_time = GetTimeCounter (); + soundSource[source].start_time = GetTimeCounter () - offset; soundSource[source].stream_should_be_playing = TRUE; alSourcePlay (soundSource[source].handle); } @@ -156,10 +191,14 @@ int StreamDecoderTaskFunc (void *data) { Task task = (Task)data; + int i; + ALuint last_buffer[NUM_SOUNDSOURCES]; + + for (i = 0; i < NUM_SOUNDSOURCES; i++) + last_buffer[i] = 0; while (!Task_ReadState (task, TASK_EXIT)) { - int i; TaskSwitch (); @@ -192,14 +231,18 @@ 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 && speech_advancetrack) + if (i == SPEECH_SOURCE) { - do_speech_advancetrack = AL_TRUE; - } - } + soundSource[i].sample->decoder = NULL; + soundSource[i].sample->read_chain_ptr = NULL; + if (speech_advancetrack) + do_speech_advancetrack = AL_TRUE; + } + } else - { - fprintf (stderr, "StreamDecoderTaskFunc(): buffer underrun when playing %s, source %d\n", soundSource[i].sample->decoder->filename, i); + { + fprintf (stderr, "StreamDecoderTaskFunc(): buffer underrun when playing %s, source %d\n", + soundSource[i].sample->decoder->filename, i); alSourcePlay (soundSource[i].handle); } } @@ -212,30 +255,76 @@ StreamDecoderTaskFunc (void *data) ALenum error; ALuint buffer; ALuint decoded_bytes; + ALuint buf_num; alGetError (); // clear error state alSourceUnqueueBuffers (soundSource[i].handle, 1, &buffer); + if ((error = alGetError()) != AL_NO_ERROR) { fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alSourceUnqueueBuffers: %x, file %s, source %d\n", error, soundSource[i].sample->decoder->filename, i); break; } + if (i == SPEECH_SOURCE) + { + for (buf_num = 0; buf_num < soundSource[i].sample->num_buffers; buf_num++) + { + 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].total_decoded += soundSource[i].sample->decoder->buffer_size; if (soundSource[i].sample->decoder->error) { if (soundSource[i].sample->decoder->error == SOUNDDECODER_EOF) { - //fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is eof for %s\n", soundSource[i].sample->decoder->filename); + 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 + { + //fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is eof for %s\n", soundSource[i].sample->decoder->filename); + processed--; + continue; + } } else { //fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is %d for %s\n", soundSource[i].sample->decoder->error, soundSource[i].sample->decoder->filename); + processed--; + continue; } - processed--; - continue; } decoded_bytes = SoundDecoder_Decode (soundSource[i].sample->decoder); @@ -279,6 +368,7 @@ StreamDecoderTaskFunc (void *data) else { alSourceQueueBuffers (soundSource[i].handle, 1, &buffer); + last_buffer[i] = buffer; if (soundSource[i].sbuffer) { @@ -333,7 +423,7 @@ StreamDecoderTaskFunc (void *data) { if (do_speech_advancetrack) { - //fprintf (stderr, "StreamDecoderTaskFunc(): calling advance_track\n"); + fprintf (stderr, "StreamDecoderTaskFunc(): calling advance_track\n"); do_speech_advancetrack = AL_FALSE; advance_track (0); } diff --git a/sc2/src/sc2code/libs/sound/openal/trackplayer.c b/sc2/src/sc2code/libs/sound/openal/trackplayer.c index 7b0c3a3ed..6a860b61f 100644 --- a/sc2/src/sc2code/libs/sound/openal/trackplayer.c +++ b/sc2/src/sc2code/libs/sound/openal/trackplayer.c @@ -23,37 +23,47 @@ #include "sound.h" #include "libs/sound/trackplayer.h" -extern int do_subtitles (UNICODE *pStr, UNICODE *TimeStamp); +extern int do_subtitles (UNICODE *pStr, UNICODE *TimeStamp, int method); + +static int tct; //total number of subtitle tracks +static int tcur; //currently playing subtitle track +static int cur_page = 0; //current page of subtitle track +static int no_page_break = 0; +static int no_voice; -static int tct, tcur, no_voice; #define MAX_CLIPS 50 -static struct -{ - int text_spliced; - UNICODE *text; - UNICODE *timestamp; - TFB_SoundSample *sample; -} track_clip[MAX_CLIPS]; +static TFB_SoundSample *sound_sample = NULL; +static TFB_SoundChain *first_chain = NULL; //first decoder in linked list +static TFB_SoundChain *last_chain = NULL; //last decoder in linked list +static UNICODE *TrackTextArray[MAX_CLIPS]; //storage for subtitlle text +static Mutex track_mutex; //protects tcur and tct void JumpTrack (int abort) { speech_advancetrack = FALSE; - if (track_clip[tcur].sample) + if (sound_sample) { LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); StopStream (SPEECH_SOURCE); + if (abort) + { + sound_sample->read_chain_ptr = NULL; + sound_sample->decoder = NULL; + } UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); } no_voice = 1; - do_subtitles ((void *)~0, 0); + do_subtitles ((void *)~0, (void *)~0, 1); if (abort) + LockMutex (track_mutex); tcur = tct; + UnlockMutex(track_mutex); } void @@ -61,20 +71,16 @@ advance_track (int channel_finished) { if (channel_finished <= 0) { - if (channel_finished == 0) - ++tcur; - if (tcur < tct) + if (sound_sample->decoder) { LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); - PlayStream (track_clip[tcur].sample, SPEECH_SOURCE, AL_FALSE, - speechVolumeScale == 0.0f ? AL_FALSE : AL_TRUE); + PlayStream (sound_sample, + SPEECH_SOURCE, AL_FALSE, + speechVolumeScale != 0.0f); UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); - do_subtitles (~0, 0); - do_subtitles (0, 0); } else if (channel_finished == 0) { - --tcur; no_voice = 1; } } @@ -83,7 +89,7 @@ advance_track (int channel_finished) void ResumeTrack () { - if (tcur < tct) + if (sound_sample && sound_sample->decoder) { ALint state; @@ -115,21 +121,25 @@ ResumeTrack () COUNT PlayingTrack () { - if (tcur < tct) + if (sound_sample->decoder) { - if (do_subtitles (track_clip[tcur].text, track_clip[tcur].timestamp) || - (no_voice && ++tcur < tct && do_subtitles (0, 0))) + int last_track, last_page; + LockMutex (track_mutex); + last_track = tcur; + last_page = cur_page; + UnlockMutex (track_mutex); + if (do_subtitles (TrackTextArray[last_track], (void *)last_page, 1) || + (no_voice && ++tcur < tct && do_subtitles (0, (void *)~0, 1))) { return (tcur + 1); } - else if (track_clip[tcur].sample) + else if (sound_sample) { COUNT result; LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); - result = (PlayingStream (SPEECH_SOURCE) ? (COUNT)(tcur + 1) : 0); + result = (PlayingStream (SPEECH_SOURCE) ? (COUNT)(last_track + 1) : 0); UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); - return result; } } @@ -140,44 +150,167 @@ PlayingTrack () void StopTrack () { + int i; speech_advancetrack = FALSE; LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); StopStream (SPEECH_SOURCE); UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); - while (tct--) + for (i = 0; i < tct; i++) { - 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) - { - TFB_SoundSample *sample = track_clip[tct].sample; - track_clip[tct].sample = NULL; - if (sample->decoder) - { - TFB_SoundDecoder *decoder = sample->decoder; - ALuint *buffer = sample->buffer; - sample->decoder = NULL; - sample->buffer = NULL; - SoundDecoder_Free (decoder); - alDeleteBuffers (sample->num_buffers, buffer); - HFree (buffer); - } - HFree (sample); - } + HFree (TrackTextArray[i]); + TrackTextArray[i] = 0; + } + if (first_chain) + { + destroy_soundchain (first_chain); + first_chain = NULL; + } + if (sound_sample) + { + DestroyMutex (track_mutex); + alDeleteBuffers (sound_sample->num_buffers, sound_sample->buffer); + HFree (sound_sample->buffer); + HFree (sound_sample->buffer_tag); + HFree (sound_sample); + sound_sample = NULL; } tct = tcur = 0; no_voice = 0; - do_subtitles (0, 0); + do_subtitles (0, (void *)~0, 1); +} + +void +DoTrackTag (TFB_SoundTag *tag) +{ + if (tag->type == AL_BUFFER_TAG_TEXT) + { + LockMutex (track_mutex); + tcur = ((int)tag->value) >> 8; + cur_page = ((int)tag->value) & 0xFF; + UnlockMutex (track_mutex); + } +} + +int +GetTimeStamps(UNICODE *TimeStamps, unsigned long *time_stamps) +{ + int pos; + int num = 0; + while (*TimeStamps && (pos = wstrcspn (TimeStamps, ",\n"))) + { + UNICODE valStr[10]; + wstrncpy (valStr, TimeStamps, pos); + valStr[pos] = '\0'; + *time_stamps = wstrtoul(valStr,NULL,10); + if (*time_stamps) + { + num++; + time_stamps++; + } + TimeStamps += pos; + if (*TimeStamps) + TimeStamps++; + } + *time_stamps = 0; + return (num); +} + +// decodes several tracks into one and adds it to queue +// track list is NULL-terminated +void +SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText) +{ +#define MAX_MULTI_TRACKS 20 +#define MAX_MULTI_BUFFERS 100 + TFB_SoundDecoder* track_decs[MAX_MULTI_TRACKS + 1]; + TFB_SoundChain *begin_chain; + int tracks; + int slen; + + if (!TrackText) + { +#ifdef DEBUG + fprintf (stderr, "SpliceMultiTrack(): no track text\n"); +#endif + return; + } + + if (tct >= MAX_CLIPS) + { + fprintf (stderr, "SpliceMultiTrack(): no more clip slots (%d)\n", + MAX_CLIPS); + return; + } + + if (! sound_sample) + { + fprintf (stderr, "SpliceMultiTrack(): Cannot be called before SpliceTrack()\n"); + return; + } + + fprintf (stderr, "SpliceMultiTrack(): loading...\n"); + for (tracks = 0; *TrackNames && tracks < MAX_MULTI_TRACKS; TrackNames++, tracks++) + { + track_decs[tracks] = SoundDecoder_Load (*TrackNames, 32768, 0, 0); + if (track_decs[tracks]) + { + fprintf (stderr, " track: %s, decoder: %s, rate %d format %x\n", + *TrackNames, + track_decs[tracks]->decoder_info, + track_decs[tracks]->frequency, + track_decs[tracks]->format); + SoundDecoder_DecodeAll (track_decs[tracks]); + + last_chain->next = create_soundchain (track_decs[tracks], sound_sample->length); + last_chain = last_chain->next; + if (tracks == 0) + begin_chain = last_chain; + sound_sample->length += track_decs[tracks]->length; + } + else + { + fprintf (stderr, " couldn't load %s\n", *TrackNames); + tracks--; + } + } + track_decs[tracks] = 0; // term + + if (tracks == 0) + { + fprintf (stderr, " no tracks loaded\n"); + return; + } + + slen = wstrlen (TrackText); + if (tct) + { + int slen1; + slen1 = wstrlen (TrackTextArray[tct - 1]); + TrackTextArray[tct - 1] = HRealloc (TrackTextArray[tct - 1], slen1 + slen + 1); + wstrcpy (&TrackTextArray[tct - 1][slen1], TrackText); + } + else + { + TrackTextArray[tct] = HMalloc (slen + 1); + wstrcpy (TrackTextArray[tct++], TrackText); + begin_chain->tag.type = AL_BUFFER_TAG_TEXT; + begin_chain->tag.value = (void *)((tct - 1) << 8); + } + no_page_break = 1; + + if (tracks > 0) + return; + else + { + fprintf (stderr, " no tracks loaded\n"); + } } void SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp) { + unsigned long startTime; if (TrackText) { if (TrackName == 0) @@ -187,50 +320,95 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp) int slen1, slen2; UNICODE *oTT; - oTT = track_clip[tct - 1].text; + oTT = TrackTextArray[tct - 1]; 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); + TrackTextArray[tct - 1] = HRealloc (oTT, slen1 + slen2 + 1); + wstrcpy (&TrackTextArray[tct - 1][slen1], TrackText); } } - else if (tct < MAX_CLIPS) + else { - track_clip[tct].text = TrackText; - track_clip[tct].text_spliced = 0; + int num_pages, cur_page; + unsigned long time_stamps[50]; - track_clip[tct].timestamp = TimeStamp; - fprintf (stderr, "SpliceTrack(): loading %s\n", TrackName); - - track_clip[tct].sample = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample)); - track_clip[tct].sample->decoder = SoundDecoder_Load (TrackName, 4096); - - if (track_clip[tct].sample->decoder) + if (no_page_break && tct) { - fprintf (stderr, " decoder: %s, rate %d format %x\n", - track_clip[tct].sample->decoder->decoder_info, - track_clip[tct].sample->decoder->frequency, - track_clip[tct].sample->decoder->format); - - track_clip[tct].sample->num_buffers = 8; - track_clip[tct].sample->buffer = HMalloc (sizeof (ALuint) * track_clip[tct].sample->num_buffers); - alGenBuffers (track_clip[tct].sample->num_buffers, track_clip[tct].sample->buffer); + int slen1, slen2; + UNICODE *oTT; + + oTT = TrackTextArray[tct - 1]; + slen1 = wstrlen (oTT); + slen2 = wstrlen (TrackText); + TrackTextArray[tct - 1] = HRealloc (oTT, slen1 + slen2 + 1); + wstrcpy (&TrackTextArray[tct - 1][slen1], TrackText); } else { - fprintf (stderr, "SpliceTrack(): couldn't load %s\n", TrackName); - HFree (track_clip[tct].sample); - track_clip[tct].sample = NULL; + TrackTextArray[tct] = HMalloc (sizeof (UNICODE) * (wstrlen (TrackText) + 1)); + wstrcpy (TrackTextArray[tct++], TrackText); } + if (TimeStamp) + num_pages = GetTimeStamps (TimeStamp, time_stamps); + else + num_pages = 0; + + fprintf (stderr, "SpliceTrack(): loading %s\n", TrackName); + + startTime = 0; + for (cur_page = 0; cur_page <= num_pages; cur_page++) + { + if (! sound_sample) + { + TFB_SoundDecoder *decoder; + track_mutex = CreateMutex(); + sound_sample = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample)); + sound_sample->num_buffers = 8; + sound_sample->buffer_tag = HMalloc (sizeof (TFB_SoundTag *) * sound_sample->num_buffers); + sound_sample->buffer = HMalloc (sizeof (ALuint) * sound_sample->num_buffers); + alGenBuffers (sound_sample->num_buffers, sound_sample->buffer); + decoder = SoundDecoder_Load (TrackName, 4096, startTime, time_stamps[cur_page]); + sound_sample->read_chain_ptr = create_soundchain (decoder, 0.0); + sound_sample->decoder = decoder; + first_chain = last_chain = sound_sample->read_chain_ptr; + sound_sample->length = 0; + } + else + { + TFB_SoundDecoder *decoder; + decoder = SoundDecoder_Load (TrackName, 4096, startTime, time_stamps[cur_page]); + last_chain->next = create_soundchain (decoder, sound_sample->length); + last_chain = last_chain->next; + } + startTime += time_stamps[cur_page]; - ++tct; + // fprintf (stderr, "page (%d of %d): %d\n",cur_page, num_pages, startTime); + if (last_chain->decoder) + { + //fprintf (stderr, " decoder: %s, rate %d format %x\n", + // last_chain->decoder->decoder_info, + // last_chain->decoder->frequency, + // last_chain->decoder->format); + + sound_sample->length += last_chain->decoder->length; + if (! no_page_break) + { + last_chain->tag.type = AL_BUFFER_TAG_TEXT; + last_chain->tag.value = (void *)(((tct - 1) << 8) | cur_page); + } + no_page_break = 0; + } + else + { + fprintf (stderr, "SpliceTrack(): couldn't load %s\n", TrackName); + alDeleteBuffers (sound_sample->num_buffers, sound_sample->buffer); + destroy_soundchain (first_chain); + first_chain = NULL; + HFree (sound_sample->buffer); + HFree (sound_sample); + sound_sample = NULL; + } + } } } } @@ -238,7 +416,7 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp) void PauseTrack () { - if (tcur < tct && track_clip[tcur].sample) + if (sound_sample && sound_sample->decoder) { LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); PauseStream (SPEECH_SOURCE); @@ -249,16 +427,45 @@ PauseTrack () void FastReverse () { - JumpTrack (0); - no_voice = 0; - tcur = 0; - ResumeTrack (); + if (sound_sample) + { + TFB_SoundChain *prev_chain; + LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); +// fprintf(stderr, "playing %s at %d\n", +// sound_sample->play_chain_ptr->decoder->filename, +// sound_sample->play_chain_ptr->decoder->start_sample); + prev_chain = get_previous_chain(first_chain, sound_sample->play_chain_ptr); +// fprintf(stderr, "now playing %s at %d\n", +// prev_chain->decoder->filename, prev_chain->decoder->start_sample); + if (prev_chain) + { + sound_sample->read_chain_ptr = prev_chain; + PlayStream (sound_sample, + SPEECH_SOURCE, AL_FALSE, + speechVolumeScale != 0.0f); + } + UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + } } void FastForward () { - JumpTrack (0); + if (sound_sample) + { + TFB_SoundChain *cur_ptr = sound_sample->play_chain_ptr; + LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + while (cur_ptr->next && ! cur_ptr->tag.type) + cur_ptr = cur_ptr->next; + if (cur_ptr->next) + { + sound_sample->read_chain_ptr = cur_ptr->next; + PlayStream (sound_sample, + SPEECH_SOURCE, AL_FALSE, + speechVolumeScale != 0.0f); + } + UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); + } //no_voice = 0; } @@ -416,9 +623,9 @@ int GetSoundInfo (int *length, int *offset) { LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); - if (soundSource[SPEECH_SOURCE].sample && soundSource[SPEECH_SOURCE].sample->decoder) + if (soundSource[SPEECH_SOURCE].sample) { - *length = (int) (soundSource[SPEECH_SOURCE].sample->decoder->length * (float)ONE_SECOND); + *length = (int) (soundSource[SPEECH_SOURCE].sample->length * (float)ONE_SECOND); *offset = (int) (GetTimeCounter () - soundSource[SPEECH_SOURCE].start_time); } else diff --git a/sc2/src/sc2code/libs/sound/sdl/trackplayer.c b/sc2/src/sc2code/libs/sound/sdl/trackplayer.c index dfe7653a8..3cb28e92b 100644 --- a/sc2/src/sc2code/libs/sound/sdl/trackplayer.c +++ b/sc2/src/sc2code/libs/sound/sdl/trackplayer.c @@ -27,7 +27,7 @@ #define VOICE_CHANNEL 0 -extern int do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp); +extern int do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp, int method); static int tct, tcur, no_voice; #define MAX_CLIPS 50 @@ -48,7 +48,7 @@ JumpTrack (int abort) Mix_HaltChannel (VOICE_CHANNEL); no_voice = 1; - do_subtitles ((void *)~0, 0); + do_subtitles ((void *)~0, 0, 0); if (abort) tcur = tct; @@ -64,8 +64,8 @@ advance_track (int channel_finished) if (tcur < tct) { Mix_PlayChannel (VOICE_CHANNEL, track_clip[tcur].chunk, 0); - do_subtitles (~0, 0); - do_subtitles (0, 0); + do_subtitles ((void *)~0, 0, 0); + do_subtitles (0, 0, 0); } else if (channel_finished == VOICE_CHANNEL) { @@ -96,8 +96,8 @@ PlayingTrack () { if (tcur < tct) { - if (do_subtitles (track_clip[tcur].text, track_clip[tcur].timestamp) - || (no_voice && ++tcur < tct && do_subtitles (0, 0))) + if (do_subtitles (track_clip[tcur].text, track_clip[tcur].timestamp, 0) + || (no_voice && ++tcur < tct && do_subtitles (0, 0, 0))) return (tcur + 1); else if (track_clip[tcur].chunk) return (Mix_Playing (VOICE_CHANNEL) ? (COUNT)(tcur + 1) : 0); @@ -128,7 +128,7 @@ StopTrack () } tct = tcur = 0; no_voice = 0; - do_subtitles (0, 0); + do_subtitles (0, 0, 0); } void diff --git a/sc2/src/sc2code/libs/sound/trackplayer.h b/sc2/src/sc2code/libs/sound/trackplayer.h index 0bd8db189..0aebfbcc1 100644 --- a/sc2/src/sc2code/libs/sound/trackplayer.h +++ b/sc2/src/sc2code/libs/sound/trackplayer.h @@ -27,6 +27,7 @@ void FastForward(); void FastReverse(); void StopTrack(); void SpliceTrack(UNICODE *filespec, UNICODE *textspec, UNICODE *TimeStamp); +void SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText); int GetSoundData (void *data); int GetSoundInfo (int *len, int *offs);