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:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
{
|
||||
uint32 cur_time;
|
||||
sint32 total_length = (sint32)((last_chain->start_time +
|
||||
last_chain->decoder->length) * (float)ONE_SECOND);
|
||||
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
|
||||
PauseStream (SPEECH_SOURCE);
|
||||
cur_time = GetTimeCounter();
|
||||
soundSource[SPEECH_SOURCE].start_time =
|
||||
(sint32)cur_time - total_length;
|
||||
track_pos_changed = 1;
|
||||
sound_sample->play_chain_ptr = last_chain;
|
||||
recompute_track_pos(sound_sample, first_chain, total_length);
|
||||
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
|
||||
PlayingTrack();
|
||||
TFB_SoundChainData* scd;
|
||||
uint32 cur_time;
|
||||
sint32 total_length = (sint32)((last_chain->start_time +
|
||||
last_chain->decoder->length) * (float)ONE_SECOND);
|
||||
|
||||
if (!sound_sample)
|
||||
return;
|
||||
}
|
||||
|
||||
scd = (TFB_SoundChainData*) sound_sample->data;
|
||||
|
||||
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
|
||||
PauseStream (SPEECH_SOURCE);
|
||||
cur_time = GetTimeCounter();
|
||||
soundSource[SPEECH_SOURCE].start_time =
|
||||
(sint32)cur_time - total_length;
|
||||
track_pos_changed = 1;
|
||||
scd->play_chain_ptr = last_chain;
|
||||
recompute_track_pos(sound_sample, first_chain, total_length);
|
||||
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
|
||||
PlayingTrack();
|
||||
}
|
||||
|
||||
//advance to the next track and start playing
|
||||
@@ -72,7 +90,14 @@ JumpTrack (void)
|
||||
void
|
||||
PlayTrack (void)
|
||||
{
|
||||
if (sound_sample && (sound_sample->read_chain_ptr || sound_sample->decoder))
|
||||
TFB_SoundChainData* scd;
|
||||
|
||||
if (!sound_sample)
|
||||
return;
|
||||
|
||||
scd = (TFB_SoundChainData*) sound_sample->data;
|
||||
|
||||
if (scd->read_chain_ptr || sound_sample->decoder)
|
||||
{
|
||||
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
|
||||
PlayStream (sound_sample,
|
||||
@@ -88,7 +113,14 @@ PlayTrack (void)
|
||||
void
|
||||
ResumeTrack ()
|
||||
{
|
||||
if (sound_sample && (sound_sample->read_chain_ptr || sound_sample->decoder))
|
||||
TFB_SoundChainData* scd;
|
||||
|
||||
if (!sound_sample)
|
||||
return;
|
||||
|
||||
scd = (TFB_SoundChainData*) sound_sample->data;
|
||||
|
||||
if (scd->read_chain_ptr || sound_sample->decoder)
|
||||
{
|
||||
// Only try to start the track if there is something to play
|
||||
TFBSound_IntVal state;
|
||||
@@ -169,6 +201,7 @@ StopTrack ()
|
||||
TFBSound_DeleteBuffers (sound_sample->num_buffers, sound_sample->buffer);
|
||||
HFree (sound_sample->buffer);
|
||||
HFree (sound_sample->buffer_tag);
|
||||
HFree (sound_sample->data);
|
||||
HFree (sound_sample);
|
||||
sound_sample = NULL;
|
||||
}
|
||||
@@ -177,18 +210,90 @@ StopTrack ()
|
||||
do_subtitles ((void *)~0);
|
||||
}
|
||||
|
||||
void
|
||||
DoTrackTag (TFB_SoundTag *tag)
|
||||
bool is_sample_playing(TFB_SoundSample* sample)
|
||||
{
|
||||
if (tag->type == MIX_BUFFER_TAG_TEXT)
|
||||
TFB_SoundChainData* scd = (TFB_SoundChainData*) sample->data;
|
||||
|
||||
return (scd->read_chain_ptr && scd->play_chain_ptr)
|
||||
|| (!scd->read_chain_ptr && sample->decoder);
|
||||
}
|
||||
|
||||
static void
|
||||
DoTrackTag (TFB_SoundChain *chain)
|
||||
{
|
||||
LockMutex (track_mutex);
|
||||
if (chain->callback)
|
||||
chain->callback ();
|
||||
tcur = chain->track_num;
|
||||
cur_page = (UNICODE *) chain->text;
|
||||
UnlockMutex (track_mutex);
|
||||
}
|
||||
|
||||
static bool
|
||||
OnTrackStart (TFB_SoundSample* sample)
|
||||
{
|
||||
TFB_SoundChainData* scd = (TFB_SoundChainData*) sample->data;
|
||||
|
||||
if (!scd->read_chain_ptr && !sample->decoder)
|
||||
return false;
|
||||
|
||||
if (scd->read_chain_ptr)
|
||||
{
|
||||
LockMutex (track_mutex);
|
||||
if (tag->callback)
|
||||
tag->callback ();
|
||||
tcur = tag->value;
|
||||
cur_page = (UNICODE *)tag->data;
|
||||
UnlockMutex (track_mutex);
|
||||
sample->decoder = scd->read_chain_ptr->decoder;
|
||||
sample->offset = (sint32) (scd->read_chain_ptr->start_time * (float)ONE_SECOND);
|
||||
}
|
||||
else
|
||||
sample->offset = 0;
|
||||
|
||||
scd->play_chain_ptr = scd->read_chain_ptr;
|
||||
|
||||
if (scd->read_chain_ptr && scd->read_chain_ptr->tag_me)
|
||||
DoTrackTag(scd->read_chain_ptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
OnChunkEnd (TFB_SoundSample* sample, TFBSound_Object buffer)
|
||||
{
|
||||
TFB_SoundChainData* scd = (TFB_SoundChainData*) sample->data;
|
||||
|
||||
if (!scd->read_chain_ptr || !scd->read_chain_ptr->next)
|
||||
return false;
|
||||
|
||||
scd->read_chain_ptr = scd->read_chain_ptr->next;
|
||||
sample->decoder = scd->read_chain_ptr->decoder;
|
||||
SoundDecoder_Rewind (sample->decoder);
|
||||
fprintf (stderr, "Switching to stream %s at pos %d\n",
|
||||
sample->decoder->filename, sample->decoder->start_sample);
|
||||
|
||||
if (sample->buffer_tag && scd->read_chain_ptr->tag_me)
|
||||
{
|
||||
TFB_TagBuffer (sample, buffer, scd->read_chain_ptr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
OnTrackEnd (TFB_SoundSample* sample)
|
||||
{
|
||||
TFB_SoundChainData* scd = (TFB_SoundChainData*) sample->data;
|
||||
|
||||
sample->decoder = NULL;
|
||||
scd->read_chain_ptr = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
OnTrackTag (TFB_SoundSample* sample, TFB_SoundTag* tag)
|
||||
{
|
||||
TFB_SoundChainData* scd = (TFB_SoundChainData*) sample->data;
|
||||
TFB_SoundChain* chain = (TFB_SoundChain*) tag->data;
|
||||
|
||||
TFB_ClearBufferTag (tag);
|
||||
DoTrackTag (chain);
|
||||
|
||||
scd->play_chain_ptr = scd->read_chain_ptr;
|
||||
}
|
||||
|
||||
int
|
||||
@@ -360,18 +465,19 @@ SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText)
|
||||
if (tct)
|
||||
{
|
||||
int slen1;
|
||||
slen1 = wstrlen ((UNICODE *)last_tag->data);
|
||||
last_tag->data = HRealloc ((UNICODE *)last_tag->data, slen1 + slen + 1);
|
||||
wstrcpy (&((UNICODE *)last_tag->data)[slen1], TrackText);
|
||||
slen1 = wstrlen ((UNICODE *)cur_text_chain->text);
|
||||
cur_text_chain->text = HRealloc (
|
||||
(UNICODE *)cur_text_chain->text, slen1 + slen + 1);
|
||||
wstrcpy (&((UNICODE *)cur_text_chain->text)[slen1], TrackText);
|
||||
}
|
||||
else
|
||||
{
|
||||
begin_chain->tag.data = HMalloc (slen + 1);
|
||||
wstrcpy ((UNICODE *)begin_chain->tag.data, TrackText);
|
||||
last_tag = &begin_chain->tag;
|
||||
begin_chain->text = HMalloc (slen + 1);
|
||||
wstrcpy ((UNICODE *)begin_chain->text, TrackText);
|
||||
cur_text_chain = begin_chain;
|
||||
begin_chain->tag_me = 1;
|
||||
begin_chain->track_num = tct;
|
||||
tct++;
|
||||
begin_chain->tag.type = MIX_BUFFER_TAG_TEXT;
|
||||
begin_chain->tag.value = tct - 1;
|
||||
}
|
||||
no_page_break = 1;
|
||||
|
||||
@@ -384,7 +490,7 @@ SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText)
|
||||
}
|
||||
|
||||
void
|
||||
SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (*cb) (void))
|
||||
SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, TFB_TrackCB cb)
|
||||
{
|
||||
unsigned long startTime;
|
||||
UNICODE **split_text = NULL;
|
||||
@@ -399,7 +505,7 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (*
|
||||
int num_pages = 0, page_counter;
|
||||
sint32 time_stamps[50];
|
||||
|
||||
if (! last_ts_chain || !last_ts_chain->tag.data)
|
||||
if (!last_ts_chain || !last_ts_chain->text)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"SpliceTrack(): Tried to append a subtitle to a NULL string\n");
|
||||
@@ -411,11 +517,11 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (*
|
||||
fprintf (stderr, "SpliceTrack(): Failed to parse sutitles\n");
|
||||
return;
|
||||
}
|
||||
oTT = (UNICODE *)last_ts_chain->tag.data;
|
||||
oTT = (UNICODE *)last_ts_chain->text;
|
||||
slen1 = wstrlen (oTT);
|
||||
slen2 = wstrlen (split_text[0]);
|
||||
last_ts_chain->tag.data = HRealloc (oTT, slen1 + slen2 + 1);
|
||||
wstrcpy (&((UNICODE *)last_ts_chain->tag.data)[slen1], split_text[0]);
|
||||
last_ts_chain->text = HRealloc (oTT, slen1 + slen2 + 1);
|
||||
wstrcpy (&((UNICODE *)last_ts_chain->text)[slen1], split_text[0]);
|
||||
HFree (split_text[0]);
|
||||
for (page_counter = 1; page_counter < num_pages; page_counter++)
|
||||
{
|
||||
@@ -425,7 +531,7 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (*
|
||||
break;
|
||||
}
|
||||
last_ts_chain = last_ts_chain->next;
|
||||
last_ts_chain->tag.data = split_text[page_counter];
|
||||
last_ts_chain->text = split_text[page_counter];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -449,11 +555,11 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (*
|
||||
int slen1, slen2;
|
||||
UNICODE *oTT;
|
||||
|
||||
oTT = (UNICODE *)last_tag->data;
|
||||
oTT = (UNICODE *)cur_text_chain->text;
|
||||
slen1 = wstrlen (oTT);
|
||||
slen2 = wstrlen (split_text[0]);
|
||||
last_tag->data = HRealloc (oTT, slen1 + slen2 + 1);
|
||||
wstrcpy (&((UNICODE *)last_tag->data)[slen1], split_text[0]);
|
||||
cur_text_chain->text = HRealloc (oTT, slen1 + slen2 + 1);
|
||||
wstrcpy (&((UNICODE *)cur_text_chain->text)[slen1], split_text[0]);
|
||||
HFree (split_text[0]);
|
||||
}
|
||||
else
|
||||
@@ -475,19 +581,24 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (*
|
||||
if (! sound_sample)
|
||||
{
|
||||
TFB_SoundDecoder *decoder;
|
||||
TFB_SoundChainData* scd;
|
||||
|
||||
track_mutex = CreateMutex();
|
||||
sound_sample = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample));
|
||||
scd = (TFB_SoundChainData *) HCalloc (sizeof (TFB_SoundChainData));
|
||||
sound_sample->data = scd;
|
||||
sound_sample->callbacks = trackCBs;
|
||||
sound_sample->num_buffers = 8;
|
||||
sound_sample->buffer_tag = HMalloc (sizeof (TFB_SoundTag *) * sound_sample->num_buffers);
|
||||
sound_sample->buffer_tag = HCalloc (sizeof (TFB_SoundTag) * sound_sample->num_buffers);
|
||||
sound_sample->buffer = HMalloc (sizeof (uint32) * sound_sample->num_buffers);
|
||||
TFBSound_GenBuffers (sound_sample->num_buffers, sound_sample->buffer);
|
||||
decoder = SoundDecoder_Load (contentDir, TrackName, 4096,
|
||||
startTime, time_stamps[page_counter]);
|
||||
sound_sample->read_chain_ptr = create_soundchain (decoder, 0.0);
|
||||
scd->read_chain_ptr = create_soundchain (decoder, 0.0);
|
||||
sound_sample->decoder = decoder;
|
||||
first_chain = last_chain = sound_sample->read_chain_ptr;
|
||||
first_chain = last_chain = scd->read_chain_ptr;
|
||||
sound_sample->length = 0;
|
||||
sound_sample->play_chain_ptr = 0;
|
||||
scd->play_chain_ptr = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -525,16 +636,16 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (*
|
||||
sound_sample->length += last_chain->decoder->length;
|
||||
if (! no_page_break)
|
||||
{
|
||||
last_chain->tag.type = MIX_BUFFER_TAG_TEXT;
|
||||
last_chain->tag_me = 1;
|
||||
// last_chain->tag.value = (void *)(((tct - 1) << 8) | page_counter);
|
||||
last_chain->tag.value = tct - 1;
|
||||
last_chain->track_num = tct - 1;
|
||||
if (page_counter < num_pages)
|
||||
{
|
||||
last_chain->tag.data = (void *)split_text[page_counter];
|
||||
last_chain->text = (void *)split_text[page_counter];
|
||||
last_ts_chain = last_chain;
|
||||
}
|
||||
last_chain->tag.callback = cb;
|
||||
last_tag = &last_chain->tag;
|
||||
last_chain->callback = cb;
|
||||
cur_text_chain = last_chain;
|
||||
}
|
||||
no_page_break = 0;
|
||||
}
|
||||
@@ -568,27 +679,32 @@ PauseTrack ()
|
||||
void
|
||||
recompute_track_pos (TFB_SoundSample *sample, TFB_SoundChain *first_chain, sint32 offset)
|
||||
{
|
||||
TFB_SoundChainData* scd;
|
||||
TFB_SoundChain *cur_chain = first_chain;
|
||||
|
||||
if (! sample)
|
||||
return;
|
||||
|
||||
scd = (TFB_SoundChainData*) sample->data;
|
||||
|
||||
while (cur_chain->next &&
|
||||
(sint32)(cur_chain->next->start_time * (float)ONE_SECOND) < offset)
|
||||
{
|
||||
if (cur_chain->tag.type)
|
||||
DoTrackTag (&cur_chain->tag);
|
||||
if (cur_chain->tag_me)
|
||||
DoTrackTag (cur_chain);
|
||||
cur_chain = cur_chain->next;
|
||||
}
|
||||
if (cur_chain->tag.type)
|
||||
DoTrackTag (&cur_chain->tag);
|
||||
if (cur_chain->tag_me)
|
||||
DoTrackTag (cur_chain);
|
||||
if ((sint32)((cur_chain->start_time + cur_chain->decoder->length) * (float)ONE_SECOND) < offset)
|
||||
{
|
||||
sample->read_chain_ptr = NULL;
|
||||
scd->read_chain_ptr = NULL;
|
||||
sample->decoder = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
sample->read_chain_ptr = cur_chain;
|
||||
SoundDecoder_Seek(sample->read_chain_ptr->decoder,
|
||||
scd->read_chain_ptr = cur_chain;
|
||||
SoundDecoder_Seek(scd->read_chain_ptr->decoder,
|
||||
(uint32)(1000 * (offset / (float)ONE_SECOND - cur_chain->start_time)));
|
||||
}
|
||||
}
|
||||
@@ -630,12 +746,14 @@ FastReverse_Page ()
|
||||
{
|
||||
if (sound_sample)
|
||||
{
|
||||
TFB_SoundChainData* scd = (TFB_SoundChainData*) sound_sample->data;
|
||||
TFB_SoundChain *prev_chain;
|
||||
|
||||
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
|
||||
prev_chain = get_previous_chain(first_chain, sound_sample->play_chain_ptr);
|
||||
prev_chain = get_previous_chain (first_chain, scd->play_chain_ptr);
|
||||
if (prev_chain)
|
||||
{
|
||||
sound_sample->read_chain_ptr = prev_chain;
|
||||
scd->read_chain_ptr = prev_chain;
|
||||
PlayStream (sound_sample,
|
||||
SPEECH_SOURCE, false,
|
||||
speechVolumeScale != 0.0f, true);
|
||||
@@ -674,13 +792,15 @@ FastForward_Page ()
|
||||
{
|
||||
if (sound_sample)
|
||||
{
|
||||
TFB_SoundChain *cur_ptr = sound_sample->play_chain_ptr;
|
||||
TFB_SoundChainData* scd = (TFB_SoundChainData*) sound_sample->data;
|
||||
TFB_SoundChain *cur_ptr = scd->play_chain_ptr;
|
||||
|
||||
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
|
||||
while (cur_ptr->next && ! cur_ptr->next->tag.type)
|
||||
while (cur_ptr->next && !cur_ptr->next->tag_me)
|
||||
cur_ptr = cur_ptr->next;
|
||||
if (cur_ptr->next)
|
||||
{
|
||||
sound_sample->read_chain_ptr = cur_ptr->next;
|
||||
scd->read_chain_ptr = cur_ptr->next;
|
||||
PlayStream (sound_sample,
|
||||
SPEECH_SOURCE, false,
|
||||
speechVolumeScale != 0.0f, true);
|
||||
@@ -868,3 +988,51 @@ GetSoundInfo (int max_len)
|
||||
return max_len;
|
||||
return (int)(max_len * offset / length);
|
||||
}
|
||||
|
||||
TFB_SoundChain *
|
||||
create_soundchain (TFB_SoundDecoder *decoder, float startTime)
|
||||
{
|
||||
TFB_SoundChain *chain;
|
||||
chain = (TFB_SoundChain *)HMalloc (sizeof (TFB_SoundChain));
|
||||
chain->decoder = decoder;
|
||||
chain->next = NULL;
|
||||
chain->start_time = startTime;
|
||||
chain->tag_me = 0;
|
||||
chain->text = 0;
|
||||
return (chain);
|
||||
}
|
||||
|
||||
void
|
||||
destroy_soundchain (TFB_SoundChain *chain)
|
||||
{
|
||||
while (chain->next)
|
||||
{
|
||||
TFB_SoundChain *tmp_chain = chain->next;
|
||||
chain->next = chain->next->next;
|
||||
if (tmp_chain->decoder)
|
||||
SoundDecoder_Free (tmp_chain->decoder);
|
||||
if (tmp_chain->text)
|
||||
HFree (tmp_chain->text);
|
||||
HFree (tmp_chain);
|
||||
}
|
||||
SoundDecoder_Free (chain->decoder);
|
||||
HFree (chain);
|
||||
}
|
||||
|
||||
TFB_SoundChain *
|
||||
get_previous_chain (TFB_SoundChain *first_chain, TFB_SoundChain *current_chain)
|
||||
{
|
||||
TFB_SoundChain *prev_chain, *last_valid = NULL;
|
||||
prev_chain = first_chain;
|
||||
if (prev_chain == current_chain)
|
||||
return (prev_chain);
|
||||
while (prev_chain->next)
|
||||
{
|
||||
if (prev_chain->tag_me)
|
||||
last_valid = prev_chain;
|
||||
if (prev_chain->next == current_chain)
|
||||
return (last_valid);
|
||||
prev_chain = prev_chain->next;
|
||||
}
|
||||
return (first_chain);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user