Buffer tagging and trackplayer chaining abstraction;

Trackplayer-specific code is separated from the streamer and
is done in callbacks; buffer-tagging is also callback-driven;
(movie playback support phase 1)


git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1238 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
avolkov
2003-09-18 10:02:10 +00:00
parent b33f1a5982
commit f1e355898a
12 changed files with 395 additions and 227 deletions
+2 -2
View File
@@ -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);
+1 -2
View File
@@ -18,14 +18,13 @@
#include "starcon.h"
#include "commglue.h"
#include "libs/sound/trackplayer.h"
#include <stdarg.h>
#include <assert.h>
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;
+3 -1
View File
@@ -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);
+3 -3
View File
@@ -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);
+3 -3
View File
@@ -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;
}
-48
View File
@@ -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
+20 -24
View File
@@ -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"
+75 -74
View File
@@ -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,15 +49,10 @@ 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,
@@ -67,6 +63,8 @@ PlayStream (TFB_SoundSample *sample, uint32 source, bool looping, bool scope, bo
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 <sample->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)
{
+4
View File
@@ -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);
+44
View File
@@ -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
+224 -56
View File
@@ -18,6 +18,7 @@
#include <ctype.h>
#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)
{
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;
sound_sample->play_chain_ptr = last_chain;
scd->play_chain_ptr = last_chain;
recompute_track_pos(sound_sample, first_chain, total_length);
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
PlayingTrack();
return;
}
}
//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)
{
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)
{
if (tag->type == MIX_BUFFER_TAG_TEXT)
{
LockMutex (track_mutex);
if (tag->callback)
tag->callback ();
tcur = tag->value;
cur_page = (UNICODE *)tag->data;
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)
{
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);
}
+3 -1
View File
@@ -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);