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 "options.h"
|
||||||
#include "comm.h"
|
#include "comm.h"
|
||||||
#include "libs/sound/sound.h"
|
#include "libs/sound/sound.h"
|
||||||
|
#include "libs/sound/trackint.h"
|
||||||
#include "controls.h"
|
#include "controls.h"
|
||||||
#include "endian_uqm.h"
|
#include "endian_uqm.h"
|
||||||
|
|
||||||
@@ -1661,7 +1662,6 @@ DoCommunication (PENCOUNTER_STATE pES)
|
|||||||
else if (CurrentMenuState.cancel &&
|
else if (CurrentMenuState.cancel &&
|
||||||
LOBYTE (GLOBAL (CurrentActivity)) != WON_LAST_BATTLE)
|
LOBYTE (GLOBAL (CurrentActivity)) != WON_LAST_BATTLE)
|
||||||
{
|
{
|
||||||
extern TFB_SoundChain *first_chain;
|
|
||||||
TFB_SoundChain *curr;
|
TFB_SoundChain *curr;
|
||||||
RECT r;
|
RECT r;
|
||||||
TEXT t;
|
TEXT t;
|
||||||
@@ -1703,7 +1703,7 @@ DoCommunication (PENCOUNTER_STATE pES)
|
|||||||
|
|
||||||
for (curr = first_chain; curr != NULL; curr = curr->next)
|
for (curr = first_chain; curr != NULL; curr = curr->next)
|
||||||
{
|
{
|
||||||
temp = curr->tag.data;
|
temp = curr->text;
|
||||||
if (temp == NULL)
|
if (temp == NULL)
|
||||||
continue;
|
continue;
|
||||||
// fprintf (stderr, "%s\n", temp);
|
// fprintf (stderr, "%s\n", temp);
|
||||||
|
|||||||
@@ -18,14 +18,13 @@
|
|||||||
|
|
||||||
#include "starcon.h"
|
#include "starcon.h"
|
||||||
#include "commglue.h"
|
#include "commglue.h"
|
||||||
#include "libs/sound/trackplayer.h"
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
int NPCNumberPhrase (int number, UNICODE **ptrack);
|
int NPCNumberPhrase (int number, UNICODE **ptrack);
|
||||||
|
|
||||||
void
|
void
|
||||||
NPCPhrase_cb (int index, void (*cb) (void))
|
NPCPhrase_cb (int index, TFB_TrackCB cb)
|
||||||
{
|
{
|
||||||
UNICODE *pStr, numbuf[100];
|
UNICODE *pStr, numbuf[100];
|
||||||
void *pClip, *pTimeStamp;
|
void *pClip, *pTimeStamp;
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
#ifndef _COMMGLUE_H
|
#ifndef _COMMGLUE_H
|
||||||
#define _COMMGLUE_H
|
#define _COMMGLUE_H
|
||||||
|
|
||||||
|
#include "libs/sound/trackplayer.h"
|
||||||
|
|
||||||
extern LOCDATA CommData;
|
extern LOCDATA CommData;
|
||||||
extern int cur_comm;
|
extern int cur_comm;
|
||||||
extern UNICODE shared_phrase_buf[256];
|
extern UNICODE shared_phrase_buf[256];
|
||||||
@@ -55,7 +57,7 @@ extern void DoResponsePhrase (RESPONSE_REF R, RESPONSE_FUNC
|
|||||||
response_func, UNICODE *ContstructStr);
|
response_func, UNICODE *ContstructStr);
|
||||||
extern void DoNPCPhrase (UNICODE *pStr);
|
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)
|
#define NPCPhrase(index) NPCPhrase_cb ((index), NULL)
|
||||||
|
|
||||||
extern void GetAllianceName (UNICODE *buf, RESPONSE_REF name_1);
|
extern void GetAllianceName (UNICODE *buf, RESPONSE_REF name_1);
|
||||||
|
|||||||
@@ -128,9 +128,7 @@ _GetMusicData (uio_Stream *fp, DWORD length)
|
|||||||
{
|
{
|
||||||
char filename[1000];
|
char filename[1000];
|
||||||
|
|
||||||
*pmus = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample));
|
*pmus = (TFB_SoundSample *) HCalloc (sizeof (TFB_SoundSample));
|
||||||
(*pmus)->buffer_tag = 0;
|
|
||||||
(*pmus)->read_chain_ptr = NULL;
|
|
||||||
strcpy (filename, _cur_resfile_name);
|
strcpy (filename, _cur_resfile_name);
|
||||||
|
|
||||||
switch (optWhichMusic)
|
switch (optWhichMusic)
|
||||||
@@ -206,6 +204,8 @@ _ReleaseMusicData (MEM_HANDLE handle)
|
|||||||
SoundDecoder_Free (decoder);
|
SoundDecoder_Free (decoder);
|
||||||
TFBSound_DeleteBuffers ((*pmus)->num_buffers, (*pmus)->buffer);
|
TFBSound_DeleteBuffers ((*pmus)->num_buffers, (*pmus)->buffer);
|
||||||
HFree ((*pmus)->buffer);
|
HFree ((*pmus)->buffer);
|
||||||
|
if ((*pmus)->buffer_tag)
|
||||||
|
HFree ((*pmus)->buffer_tag);
|
||||||
}
|
}
|
||||||
HFree (*pmus);
|
HFree (*pmus);
|
||||||
|
|
||||||
|
|||||||
@@ -202,9 +202,7 @@ _GetSoundBankData (uio_Stream *fp, DWORD length)
|
|||||||
{
|
{
|
||||||
fprintf (stderr, "_GetSoundBankData(): loading %s\n", filename);
|
fprintf (stderr, "_GetSoundBankData(): loading %s\n", filename);
|
||||||
|
|
||||||
sndfx[snd_ct] = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample));
|
sndfx[snd_ct] = (TFB_SoundSample *) HCalloc (sizeof (TFB_SoundSample));
|
||||||
sndfx[snd_ct]->buffer_tag = 0;
|
|
||||||
sndfx[snd_ct]->read_chain_ptr = NULL;
|
|
||||||
|
|
||||||
sndfx[snd_ct]->decoder = SoundDecoder_Load (contentDir,
|
sndfx[snd_ct]->decoder = SoundDecoder_Load (contentDir,
|
||||||
filename, 4096, 0, 0);
|
filename, 4096, 0, 0);
|
||||||
@@ -317,6 +315,8 @@ _ReleaseSoundBankData (MEM_HANDLE Snd)
|
|||||||
SoundDecoder_Free ((*sptr)->decoder);
|
SoundDecoder_Free ((*sptr)->decoder);
|
||||||
TFBSound_DeleteBuffers ((*sptr)->num_buffers, (*sptr)->buffer);
|
TFBSound_DeleteBuffers ((*sptr)->num_buffers, (*sptr)->buffer);
|
||||||
HFree ((*sptr)->buffer);
|
HFree ((*sptr)->buffer);
|
||||||
|
if ((*sptr)->buffer_tag)
|
||||||
|
HFree ((*sptr)->buffer_tag);
|
||||||
HFree (*sptr);
|
HFree (*sptr);
|
||||||
*sptr++ = 0;
|
*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
|
// Status: Ignored
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
|
|||||||
@@ -26,7 +26,6 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "decoders/decoder.h"
|
#include "decoders/decoder.h"
|
||||||
|
|
||||||
|
|
||||||
#define FIRST_SFX_SOURCE 0
|
#define FIRST_SFX_SOURCE 0
|
||||||
#define LAST_SFX_SOURCE 4
|
#define LAST_SFX_SOURCE 4
|
||||||
#define MUSIC_SOURCE (LAST_SFX_SOURCE + 1)
|
#define MUSIC_SOURCE (LAST_SFX_SOURCE + 1)
|
||||||
@@ -36,37 +35,39 @@
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
int in_use;
|
||||||
TFBSound_Object buf_name;
|
TFBSound_Object buf_name;
|
||||||
int type;
|
void *data; // user-defined data
|
||||||
uint32 value;
|
|
||||||
void *data;
|
|
||||||
void (*callback) (void);
|
|
||||||
} TFB_SoundTag;
|
} TFB_SoundTag;
|
||||||
|
|
||||||
enum
|
// forward-declare
|
||||||
{
|
typedef struct tfb_soundsample;
|
||||||
MIX_BUFFER_TAG_TEXT = 1,
|
|
||||||
MIX_BUFFER_TAG_TEXTPAGE
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct tfb_soundchain
|
typedef struct tfb_soundcallbacks
|
||||||
{
|
{
|
||||||
TFB_SoundDecoder *decoder; // points at the decoder to read from
|
// return TRUE to continue, FALSE to abort
|
||||||
float start_time;
|
bool (* OnStartStream) (struct tfb_soundsample*);
|
||||||
TFB_SoundTag tag;
|
// return TRUE to continue, FALSE to abort
|
||||||
struct tfb_soundchain *next;
|
bool (* OnEndChunk) (struct tfb_soundsample*, TFBSound_Object);
|
||||||
} TFB_SoundChain;
|
// 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
|
// audio data
|
||||||
typedef struct tfb_soundsample
|
typedef struct tfb_soundsample
|
||||||
{
|
{
|
||||||
TFB_SoundDecoder *decoder; // decoder to read from
|
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
|
float length; // total length of decoder chain in seconds
|
||||||
TFBSound_Object *buffer;
|
TFBSound_Object *buffer;
|
||||||
uint32 num_buffers;
|
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;
|
} TFB_SoundSample;
|
||||||
|
|
||||||
// equivalent to channel in legacy sound code
|
// equivalent to channel in legacy sound code
|
||||||
@@ -97,10 +98,5 @@ void CleanSource (int iSource);
|
|||||||
|
|
||||||
void SetSFXVolume (float volume);
|
void SetSFXVolume (float volume);
|
||||||
void SetSpeechVolume (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"
|
#include "stream.h"
|
||||||
|
|||||||
@@ -23,23 +23,24 @@ PlayStream (TFB_SoundSample *sample, uint32 source, bool looping, bool scope, bo
|
|||||||
uint32 i, pos = 0;
|
uint32 i, pos = 0;
|
||||||
sint32 offset = 0;
|
sint32 offset = 0;
|
||||||
|
|
||||||
if (!sample || (!sample->read_chain_ptr && !sample->decoder))
|
if (!sample)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
StopStream (source);
|
StopStream (source);
|
||||||
if (sample->read_chain_ptr)
|
if (sample->callbacks.OnStartStream &&
|
||||||
{
|
!sample->callbacks.OnStartStream (sample))
|
||||||
sample->decoder = sample->read_chain_ptr->decoder;
|
return; // callback failed
|
||||||
offset = (sint32) (sample->read_chain_ptr->start_time * (float)ONE_SECOND);
|
|
||||||
}
|
if (sample->buffer_tag)
|
||||||
else
|
memset (sample->buffer_tag, 0,
|
||||||
offset= 0;
|
sample->num_buffers * sizeof (sample->buffer_tag[0]));
|
||||||
|
|
||||||
|
offset = sample->offset;
|
||||||
if (rewind)
|
if (rewind)
|
||||||
SoundDecoder_Rewind (sample->decoder);
|
SoundDecoder_Rewind (sample->decoder);
|
||||||
else
|
else
|
||||||
offset += (sint32)(SoundDecoder_GetTime (sample->decoder) * (float)ONE_SECOND);
|
offset += (sint32)(SoundDecoder_GetTime (sample->decoder) * (float)ONE_SECOND);
|
||||||
soundSource[source].sample = sample;
|
soundSource[source].sample = sample;
|
||||||
soundSource[source].sample->play_chain_ptr = sample->read_chain_ptr;
|
|
||||||
soundSource[source].sample->decoder->looping = looping;
|
soundSource[source].sample->decoder->looping = looping;
|
||||||
TFBSound_Sourcei (soundSource[source].handle, TFBSOUND_LOOPING, false);
|
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);
|
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)
|
for (i = 0; i < sample->num_buffers; ++i)
|
||||||
{
|
{
|
||||||
uint32 decoded_bytes;
|
uint32 decoded_bytes;
|
||||||
if (sample->buffer_tag)
|
|
||||||
sample->buffer_tag[i] = 0;
|
|
||||||
decoded_bytes = SoundDecoder_Decode (sample->decoder);
|
decoded_bytes = SoundDecoder_Decode (sample->decoder);
|
||||||
//fprintf (stderr, "PlayStream(): source %d filename:%s start: %d position:%d bytes %d\n", source,
|
//fprintf (stderr, "PlayStream(): source %d filename:%s start: %d position:%d bytes %d\n", source,
|
||||||
// sample->decoder->filename, sample->decoder->start_sample,
|
// 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,
|
TFBSound_BufferData (sample->buffer[i], sample->decoder->format, sample->decoder->buffer,
|
||||||
decoded_bytes, sample->decoder->frequency);
|
decoded_bytes, sample->decoder->frequency);
|
||||||
TFBSound_SourceQueueBuffers (soundSource[source].handle, 1, &sample->buffer[i]);
|
TFBSound_SourceQueueBuffers (soundSource[source].handle, 1, &sample->buffer[i]);
|
||||||
|
if (sample->callbacks.OnQueueBuffer)
|
||||||
|
sample->callbacks.OnQueueBuffer (sample, sample->buffer[i]);
|
||||||
|
|
||||||
if (scope)
|
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)
|
||||||
{
|
{
|
||||||
if (sample->decoder->error == SOUNDDECODER_EOF &&
|
if (sample->decoder->error != SOUNDDECODER_EOF ||
|
||||||
sample->read_chain_ptr && sample->read_chain_ptr->next)
|
!sample->callbacks.OnEndChunk ||
|
||||||
{
|
!sample->callbacks.OnEndChunk (sample, sample->buffer[i]))
|
||||||
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;
|
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_size = pos + PAD_SCOPE_BYTES;
|
||||||
soundSource[source].sbuf_start = pos;
|
soundSource[source].sbuf_start = pos;
|
||||||
soundSource[source].sbuf_lasttime = GetTimeCounter ();
|
soundSource[source].sbuf_lasttime = GetTimeCounter ();
|
||||||
@@ -148,6 +132,50 @@ PlayingStream (uint32 source)
|
|||||||
return soundSource[source].stream_should_be_playing;
|
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
|
int
|
||||||
StreamDecoderTaskFunc (void *data)
|
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);
|
fprintf (stderr, "StreamDecoderTaskFunc(): finished playing %s, source %d\n", soundSource[i].sample->decoder->filename, i);
|
||||||
soundSource[i].stream_should_be_playing = FALSE;
|
soundSource[i].stream_should_be_playing = FALSE;
|
||||||
if (i == SPEECH_SOURCE)
|
if (soundSource[i].sample->callbacks.OnEndStream)
|
||||||
{
|
soundSource[i].sample->callbacks.OnEndStream (soundSource[i].sample);
|
||||||
soundSource[i].sample->decoder = NULL;
|
|
||||||
soundSource[i].sample->read_chain_ptr = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -213,7 +238,6 @@ StreamDecoderTaskFunc (void *data)
|
|||||||
uint32 error;
|
uint32 error;
|
||||||
TFBSound_Object buffer;
|
TFBSound_Object buffer;
|
||||||
uint32 decoded_bytes;
|
uint32 decoded_bytes;
|
||||||
uint32 buf_num;
|
|
||||||
|
|
||||||
TFBSound_GetError (); // clear error state
|
TFBSound_GetError (); // clear error state
|
||||||
|
|
||||||
@@ -225,20 +249,13 @@ StreamDecoderTaskFunc (void *data)
|
|||||||
break;
|
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];
|
soundSource[i].sample->callbacks.OnTaggedBuffer (
|
||||||
if (cur_tag && cur_tag->buf_name == buffer)
|
soundSource[i].sample, tag);
|
||||||
{
|
|
||||||
// ...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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@@ -255,29 +272,9 @@ StreamDecoderTaskFunc (void *data)
|
|||||||
{
|
{
|
||||||
if (soundSource[i].sample->decoder->error == SOUNDDECODER_EOF)
|
if (soundSource[i].sample->decoder->error == SOUNDDECODER_EOF)
|
||||||
{
|
{
|
||||||
if (soundSource[i].sample->read_chain_ptr &&
|
if (!soundSource[i].sample->callbacks.OnEndChunk ||
|
||||||
soundSource[i].sample->read_chain_ptr->next)
|
!soundSource[i].sample->callbacks.OnEndChunk (
|
||||||
{
|
soundSource[i].sample, last_buffer[i]))
|
||||||
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);
|
//fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is eof for %s\n", soundSource[i].sample->decoder->filename);
|
||||||
processed--;
|
processed--;
|
||||||
@@ -335,6 +332,10 @@ StreamDecoderTaskFunc (void *data)
|
|||||||
{
|
{
|
||||||
last_buffer[i] = buffer;
|
last_buffer[i] = buffer;
|
||||||
TFBSound_SourceQueueBuffers (soundSource[i].handle, 1, &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)
|
if (soundSource[i].sbuffer)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ int StreamDecoderTaskFunc (void *data);
|
|||||||
int PreDecodeClips (TFB_SoundSample *sample, TFB_SoundDecoder *decoders[], bool autofree);
|
int PreDecodeClips (TFB_SoundSample *sample, TFB_SoundDecoder *decoders[], bool autofree);
|
||||||
void PlayDecodedClip (TFB_SoundSample *sample, uint32 source, bool scope);
|
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;
|
extern bool speech_advancetrack;
|
||||||
void advance_track (int channel_finished);
|
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 <ctype.h>
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "libs/sound/trackplayer.h"
|
#include "libs/sound/trackplayer.h"
|
||||||
|
#include "libs/sound/trackint.h"
|
||||||
#include "comm.h"
|
#include "comm.h"
|
||||||
#include "options.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 UNICODE *cur_page = 0; //current page of subtitle track
|
||||||
static int no_page_break = 0;
|
static int no_page_break = 0;
|
||||||
static int track_pos_changed = 0; // set whenever ff, frev is enabled
|
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 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;
|
static TFB_SoundSample *sound_sample = NULL;
|
||||||
TFB_SoundChain *first_chain = NULL; //first decoder in linked list
|
TFB_SoundChain *first_chain = NULL; //first decoder in linked list
|
||||||
static TFB_SoundChain *last_chain = NULL; //last 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
|
static Mutex track_mutex; //protects tcur and tct
|
||||||
void recompute_track_pos (TFB_SoundSample *sample,
|
void recompute_track_pos (TFB_SoundSample *sample,
|
||||||
TFB_SoundChain *first_chain, sint32 offset);
|
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
|
//JumpTrack currently aborts the current track. However, it doesn't clear the
|
||||||
//data-structures as StopTrack does. this allows for rewind even after 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
|
void
|
||||||
JumpTrack (void)
|
JumpTrack (void)
|
||||||
{
|
{
|
||||||
if (sound_sample)
|
TFB_SoundChainData* scd;
|
||||||
{
|
uint32 cur_time;
|
||||||
uint32 cur_time;
|
sint32 total_length = (sint32)((last_chain->start_time +
|
||||||
sint32 total_length = (sint32)((last_chain->start_time +
|
last_chain->decoder->length) * (float)ONE_SECOND);
|
||||||
last_chain->decoder->length) * (float)ONE_SECOND);
|
|
||||||
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
|
if (!sound_sample)
|
||||||
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();
|
|
||||||
return;
|
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
|
//advance to the next track and start playing
|
||||||
@@ -72,7 +90,14 @@ JumpTrack (void)
|
|||||||
void
|
void
|
||||||
PlayTrack (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);
|
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
|
||||||
PlayStream (sound_sample,
|
PlayStream (sound_sample,
|
||||||
@@ -88,7 +113,14 @@ PlayTrack (void)
|
|||||||
void
|
void
|
||||||
ResumeTrack ()
|
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
|
// Only try to start the track if there is something to play
|
||||||
TFBSound_IntVal state;
|
TFBSound_IntVal state;
|
||||||
@@ -169,6 +201,7 @@ StopTrack ()
|
|||||||
TFBSound_DeleteBuffers (sound_sample->num_buffers, sound_sample->buffer);
|
TFBSound_DeleteBuffers (sound_sample->num_buffers, sound_sample->buffer);
|
||||||
HFree (sound_sample->buffer);
|
HFree (sound_sample->buffer);
|
||||||
HFree (sound_sample->buffer_tag);
|
HFree (sound_sample->buffer_tag);
|
||||||
|
HFree (sound_sample->data);
|
||||||
HFree (sound_sample);
|
HFree (sound_sample);
|
||||||
sound_sample = NULL;
|
sound_sample = NULL;
|
||||||
}
|
}
|
||||||
@@ -177,18 +210,90 @@ StopTrack ()
|
|||||||
do_subtitles ((void *)~0);
|
do_subtitles ((void *)~0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool is_sample_playing(TFB_SoundSample* sample)
|
||||||
DoTrackTag (TFB_SoundTag *tag)
|
|
||||||
{
|
{
|
||||||
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);
|
sample->decoder = scd->read_chain_ptr->decoder;
|
||||||
if (tag->callback)
|
sample->offset = (sint32) (scd->read_chain_ptr->start_time * (float)ONE_SECOND);
|
||||||
tag->callback ();
|
|
||||||
tcur = tag->value;
|
|
||||||
cur_page = (UNICODE *)tag->data;
|
|
||||||
UnlockMutex (track_mutex);
|
|
||||||
}
|
}
|
||||||
|
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
|
int
|
||||||
@@ -360,18 +465,19 @@ SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText)
|
|||||||
if (tct)
|
if (tct)
|
||||||
{
|
{
|
||||||
int slen1;
|
int slen1;
|
||||||
slen1 = wstrlen ((UNICODE *)last_tag->data);
|
slen1 = wstrlen ((UNICODE *)cur_text_chain->text);
|
||||||
last_tag->data = HRealloc ((UNICODE *)last_tag->data, slen1 + slen + 1);
|
cur_text_chain->text = HRealloc (
|
||||||
wstrcpy (&((UNICODE *)last_tag->data)[slen1], TrackText);
|
(UNICODE *)cur_text_chain->text, slen1 + slen + 1);
|
||||||
|
wstrcpy (&((UNICODE *)cur_text_chain->text)[slen1], TrackText);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
begin_chain->tag.data = HMalloc (slen + 1);
|
begin_chain->text = HMalloc (slen + 1);
|
||||||
wstrcpy ((UNICODE *)begin_chain->tag.data, TrackText);
|
wstrcpy ((UNICODE *)begin_chain->text, TrackText);
|
||||||
last_tag = &begin_chain->tag;
|
cur_text_chain = begin_chain;
|
||||||
|
begin_chain->tag_me = 1;
|
||||||
|
begin_chain->track_num = tct;
|
||||||
tct++;
|
tct++;
|
||||||
begin_chain->tag.type = MIX_BUFFER_TAG_TEXT;
|
|
||||||
begin_chain->tag.value = tct - 1;
|
|
||||||
}
|
}
|
||||||
no_page_break = 1;
|
no_page_break = 1;
|
||||||
|
|
||||||
@@ -384,7 +490,7 @@ SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (*cb) (void))
|
SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, TFB_TrackCB cb)
|
||||||
{
|
{
|
||||||
unsigned long startTime;
|
unsigned long startTime;
|
||||||
UNICODE **split_text = NULL;
|
UNICODE **split_text = NULL;
|
||||||
@@ -399,7 +505,7 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (*
|
|||||||
int num_pages = 0, page_counter;
|
int num_pages = 0, page_counter;
|
||||||
sint32 time_stamps[50];
|
sint32 time_stamps[50];
|
||||||
|
|
||||||
if (! last_ts_chain || !last_ts_chain->tag.data)
|
if (!last_ts_chain || !last_ts_chain->text)
|
||||||
{
|
{
|
||||||
fprintf (stderr,
|
fprintf (stderr,
|
||||||
"SpliceTrack(): Tried to append a subtitle to a NULL string\n");
|
"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");
|
fprintf (stderr, "SpliceTrack(): Failed to parse sutitles\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
oTT = (UNICODE *)last_ts_chain->tag.data;
|
oTT = (UNICODE *)last_ts_chain->text;
|
||||||
slen1 = wstrlen (oTT);
|
slen1 = wstrlen (oTT);
|
||||||
slen2 = wstrlen (split_text[0]);
|
slen2 = wstrlen (split_text[0]);
|
||||||
last_ts_chain->tag.data = HRealloc (oTT, slen1 + slen2 + 1);
|
last_ts_chain->text = HRealloc (oTT, slen1 + slen2 + 1);
|
||||||
wstrcpy (&((UNICODE *)last_ts_chain->tag.data)[slen1], split_text[0]);
|
wstrcpy (&((UNICODE *)last_ts_chain->text)[slen1], split_text[0]);
|
||||||
HFree (split_text[0]);
|
HFree (split_text[0]);
|
||||||
for (page_counter = 1; page_counter < num_pages; page_counter++)
|
for (page_counter = 1; page_counter < num_pages; page_counter++)
|
||||||
{
|
{
|
||||||
@@ -425,7 +531,7 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (*
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
last_ts_chain = last_ts_chain->next;
|
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;
|
int slen1, slen2;
|
||||||
UNICODE *oTT;
|
UNICODE *oTT;
|
||||||
|
|
||||||
oTT = (UNICODE *)last_tag->data;
|
oTT = (UNICODE *)cur_text_chain->text;
|
||||||
slen1 = wstrlen (oTT);
|
slen1 = wstrlen (oTT);
|
||||||
slen2 = wstrlen (split_text[0]);
|
slen2 = wstrlen (split_text[0]);
|
||||||
last_tag->data = HRealloc (oTT, slen1 + slen2 + 1);
|
cur_text_chain->text = HRealloc (oTT, slen1 + slen2 + 1);
|
||||||
wstrcpy (&((UNICODE *)last_tag->data)[slen1], split_text[0]);
|
wstrcpy (&((UNICODE *)cur_text_chain->text)[slen1], split_text[0]);
|
||||||
HFree (split_text[0]);
|
HFree (split_text[0]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -475,19 +581,24 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (*
|
|||||||
if (! sound_sample)
|
if (! sound_sample)
|
||||||
{
|
{
|
||||||
TFB_SoundDecoder *decoder;
|
TFB_SoundDecoder *decoder;
|
||||||
|
TFB_SoundChainData* scd;
|
||||||
|
|
||||||
track_mutex = CreateMutex();
|
track_mutex = CreateMutex();
|
||||||
sound_sample = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample));
|
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->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);
|
sound_sample->buffer = HMalloc (sizeof (uint32) * sound_sample->num_buffers);
|
||||||
TFBSound_GenBuffers (sound_sample->num_buffers, sound_sample->buffer);
|
TFBSound_GenBuffers (sound_sample->num_buffers, sound_sample->buffer);
|
||||||
decoder = SoundDecoder_Load (contentDir, TrackName, 4096,
|
decoder = SoundDecoder_Load (contentDir, TrackName, 4096,
|
||||||
startTime, time_stamps[page_counter]);
|
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;
|
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->length = 0;
|
||||||
sound_sample->play_chain_ptr = 0;
|
scd->play_chain_ptr = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -525,16 +636,16 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, void (*
|
|||||||
sound_sample->length += last_chain->decoder->length;
|
sound_sample->length += last_chain->decoder->length;
|
||||||
if (! no_page_break)
|
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 = (void *)(((tct - 1) << 8) | page_counter);
|
||||||
last_chain->tag.value = tct - 1;
|
last_chain->track_num = tct - 1;
|
||||||
if (page_counter < num_pages)
|
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_ts_chain = last_chain;
|
||||||
}
|
}
|
||||||
last_chain->tag.callback = cb;
|
last_chain->callback = cb;
|
||||||
last_tag = &last_chain->tag;
|
cur_text_chain = last_chain;
|
||||||
}
|
}
|
||||||
no_page_break = 0;
|
no_page_break = 0;
|
||||||
}
|
}
|
||||||
@@ -568,27 +679,32 @@ PauseTrack ()
|
|||||||
void
|
void
|
||||||
recompute_track_pos (TFB_SoundSample *sample, TFB_SoundChain *first_chain, sint32 offset)
|
recompute_track_pos (TFB_SoundSample *sample, TFB_SoundChain *first_chain, sint32 offset)
|
||||||
{
|
{
|
||||||
|
TFB_SoundChainData* scd;
|
||||||
TFB_SoundChain *cur_chain = first_chain;
|
TFB_SoundChain *cur_chain = first_chain;
|
||||||
|
|
||||||
if (! sample)
|
if (! sample)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
scd = (TFB_SoundChainData*) sample->data;
|
||||||
|
|
||||||
while (cur_chain->next &&
|
while (cur_chain->next &&
|
||||||
(sint32)(cur_chain->next->start_time * (float)ONE_SECOND) < offset)
|
(sint32)(cur_chain->next->start_time * (float)ONE_SECOND) < offset)
|
||||||
{
|
{
|
||||||
if (cur_chain->tag.type)
|
if (cur_chain->tag_me)
|
||||||
DoTrackTag (&cur_chain->tag);
|
DoTrackTag (cur_chain);
|
||||||
cur_chain = cur_chain->next;
|
cur_chain = cur_chain->next;
|
||||||
}
|
}
|
||||||
if (cur_chain->tag.type)
|
if (cur_chain->tag_me)
|
||||||
DoTrackTag (&cur_chain->tag);
|
DoTrackTag (cur_chain);
|
||||||
if ((sint32)((cur_chain->start_time + cur_chain->decoder->length) * (float)ONE_SECOND) < offset)
|
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;
|
sample->decoder = NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sample->read_chain_ptr = cur_chain;
|
scd->read_chain_ptr = cur_chain;
|
||||||
SoundDecoder_Seek(sample->read_chain_ptr->decoder,
|
SoundDecoder_Seek(scd->read_chain_ptr->decoder,
|
||||||
(uint32)(1000 * (offset / (float)ONE_SECOND - cur_chain->start_time)));
|
(uint32)(1000 * (offset / (float)ONE_SECOND - cur_chain->start_time)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -630,12 +746,14 @@ FastReverse_Page ()
|
|||||||
{
|
{
|
||||||
if (sound_sample)
|
if (sound_sample)
|
||||||
{
|
{
|
||||||
|
TFB_SoundChainData* scd = (TFB_SoundChainData*) sound_sample->data;
|
||||||
TFB_SoundChain *prev_chain;
|
TFB_SoundChain *prev_chain;
|
||||||
|
|
||||||
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
|
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)
|
if (prev_chain)
|
||||||
{
|
{
|
||||||
sound_sample->read_chain_ptr = prev_chain;
|
scd->read_chain_ptr = prev_chain;
|
||||||
PlayStream (sound_sample,
|
PlayStream (sound_sample,
|
||||||
SPEECH_SOURCE, false,
|
SPEECH_SOURCE, false,
|
||||||
speechVolumeScale != 0.0f, true);
|
speechVolumeScale != 0.0f, true);
|
||||||
@@ -674,13 +792,15 @@ FastForward_Page ()
|
|||||||
{
|
{
|
||||||
if (sound_sample)
|
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);
|
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;
|
cur_ptr = cur_ptr->next;
|
||||||
if (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,
|
PlayStream (sound_sample,
|
||||||
SPEECH_SOURCE, false,
|
SPEECH_SOURCE, false,
|
||||||
speechVolumeScale != 0.0f, true);
|
speechVolumeScale != 0.0f, true);
|
||||||
@@ -868,3 +988,51 @@ GetSoundInfo (int max_len)
|
|||||||
return max_len;
|
return max_len;
|
||||||
return (int)(max_len * offset / length);
|
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
|
#ifndef TRACKPLAYER_H
|
||||||
#define TRACKPLAYER_H
|
#define TRACKPLAYER_H
|
||||||
|
|
||||||
|
typedef void (*TFB_TrackCB) (void);
|
||||||
|
|
||||||
#define ACCEL_SCROLL_SPEED 300
|
#define ACCEL_SCROLL_SPEED 300
|
||||||
|
|
||||||
void ResumeTrack(void);
|
void ResumeTrack(void);
|
||||||
@@ -30,7 +32,7 @@ int FastForward_Page(void);
|
|||||||
void FastReverse_Smooth(void);
|
void FastReverse_Smooth(void);
|
||||||
void FastReverse_Page(void);
|
void FastReverse_Page(void);
|
||||||
void StopTrack(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);
|
void SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText);
|
||||||
int GetSoundData (void *data);
|
int GetSoundData (void *data);
|
||||||
int GetSoundInfo (int max_len);
|
int GetSoundInfo (int max_len);
|
||||||
|
|||||||
Reference in New Issue
Block a user