new streaming code for openal, mixsdl. Supports better subtitle alignemnt

and going forward-backwards one page at a time using the arrow keys


git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@588 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
ghaushe
2003-01-27 06:21:10 +00:00
parent 38d82d7713
commit 4ed4f72cf3
21 changed files with 1279 additions and 460 deletions
+93 -40
View File
@@ -1161,7 +1161,7 @@ SpewPhrases (COUNT wait_track)
BOOLEAN ContinuityBreak;
DWORD TimeIn;
COUNT which_track;
INPUT_STATE InputState;
INPUT_STATE InputState, LastInputState;
FRAME F;
TimeIn = GetTimeCounter ();
@@ -1195,6 +1195,7 @@ SpewPhrases (COUNT wait_track)
else if (which_track <= wait_track)
ResumeTrack ();
LastInputState = 0;
do
{
ClearSemaphore (GraphicsSem);
@@ -1219,14 +1220,14 @@ SpewPhrases (COUNT wait_track)
if (which_track)
{
if (GetInputXComponent (InputState) > 0)
if (InputState != LastInputState && GetInputXComponent (InputState) > 0)
{
SetSliderImage (SetAbsFrameIndex (ActivityFrame, 3));
FastForward ();
ContinuityBreak = TRUE;
CommData.AlienFrame = 0;
}
else if (GetInputXComponent (InputState) < 0)
else if (InputState != LastInputState && GetInputXComponent (InputState) < 0)
{
Rewind:
SetSliderImage (SetAbsFrameIndex (ActivityFrame, 4));
@@ -1234,18 +1235,19 @@ Rewind:
ContinuityBreak = TRUE;
CommData.AlienFrame = 0;
}
else if (ContinuityBreak)
else if (InputState != LastInputState && ContinuityBreak)
{
SetSliderImage (SetAbsFrameIndex (ActivityFrame, 2));
if ((which_track = PlayingTrack ())
&& which_track <= wait_track)
ResumeTrack ();
&& which_track <= wait_track) ;
// ResumeTrack ();
ContinuityBreak = FALSE;
}
else if (which_track == wait_track
|| wait_track == (COUNT)~0)
CommData.AlienFrame = F;
}
LastInputState = InputState;
} while (ContinuityBreak
|| ((which_track = PlayingTrack ()) && which_track <= wait_track));
@@ -1944,11 +1946,18 @@ RaceCommunication (void)
}
}
//method == 0 parses pTimeStamp, and self-times the subtitles
//method == 1 expects pTimeStamp to explicitly set the page to draw
int
do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp)
do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp, int method)
{
static DWORD TimeOut;
static unsigned long *cur_sub_ts;
int disable_timer = 0;
int cur_page = -1;
static int last_page = -1;
static UNICODE *lastPStr = 0;
int NextPage = 0;
// TODO: proper disabling of subtitles, this one prolly isn't 'safe'
if (optSubtitles == FALSE)
@@ -1961,8 +1970,31 @@ do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp)
if (subtitle_state <= NEXT_SUBTITLE)
return (subtitle_state);
TimeOut = 0;
NextPage = 1;
subtitle_state = WAIT_SUBTITLE;
}
if (method)
disable_timer = 1;
else if (! method)
{
if (last_page == -1)
last_page++;
cur_page = last_page;
}
if (method == 1 && pStr != (void *)~0 && pTimeStamp != (void *)~0)
{
cur_page = (int)pTimeStamp;
if (cur_page != last_page || lastPStr != pStr) {
if (lastPStr != pStr)
subtitle_state = NEXT_SUBTITLE;
else
subtitle_state = READ_SUBTITLE;
ColorChange = TRUE;
// fprintf (stderr, "changed page to: %d\n", cur_page);
}
}
lastPStr = pStr;
last_page = cur_page;
switch (subtitle_state)
{
@@ -1976,53 +2008,64 @@ do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp)
24,
32,
};
static UNICODE alien_phrase_buf[4096];
static int page_break_pos[50];
case NEXT_SUBTITLE:
{
UNICODE ch;
COUNT numchars;
static UNICODE alien_phrase_buf[4096];
int cur_pos = 0;
UNICODE *s;
static unsigned long subtitle_frames_ts[50];
if (! disable_timer)
cur_page = last_page = 0;
page_break_pos[cur_pos++] = 0;
CommData.AlienTextTemplate.pStr = alien_phrase_buf;
numchars = 0;
do
{
++numchars;
if (((ch = *pStr++) == '\n' || ch == '\r')
&& !ispunct (pStr[-2])
&& !isspace (pStr[-2]))
if ((ch = *pStr++) == '\n' || ch == '\r')
{
*CommData.AlienTextTemplate.pStr++ = '.';
*CommData.AlienTextTemplate.pStr++ = '.';
*CommData.AlienTextTemplate.pStr++ = '.';
*CommData.AlienTextTemplate.pStr++ = ch;
*CommData.AlienTextTemplate.pStr++ = '.';
*CommData.AlienTextTemplate.pStr++ = '.';
ch = '.';
numchars += 6;
if (!ispunct (pStr[-2]) && !isspace (pStr[-2]))
{
*CommData.AlienTextTemplate.pStr++ = '.';
*CommData.AlienTextTemplate.pStr++ = '.';
*CommData.AlienTextTemplate.pStr++ = '.';
*CommData.AlienTextTemplate.pStr++ = ch;
*CommData.AlienTextTemplate.pStr++ = '.';
*CommData.AlienTextTemplate.pStr++ = '.';
ch = '.';
page_break_pos[cur_pos++] = numchars + 3;
numchars += 6;
}
else
page_break_pos[cur_pos++] = numchars;
}
} while ((*CommData.AlienTextTemplate.pStr++ = ch));
if (s = pTimeStamp)
subtitle_frames_ts[0] = 0;
if (! method)
{
int pos;
cur_sub_ts = subtitle_frames_ts;
while (*s && (pos = wstrcspn (s, ",")))
if (s = pTimeStamp)
{
UNICODE valStr[10];
wstrncpy (valStr, s, pos);
valStr[pos] = '\0';
*cur_sub_ts++ = wstrtoul(valStr,NULL,10);
s += pos;
if (*s)
s++;
int pos;
cur_sub_ts = subtitle_frames_ts;
while (*s && (pos = wstrcspn (s, ",")))
{
UNICODE valStr[10];
wstrncpy (valStr, s, pos);
valStr[pos] = '\0';
*cur_sub_ts++ = wstrtoul(valStr,NULL,10);
s += pos;
if (*s)
s++;
}
*cur_sub_ts = 0;
TimeOut = GetTimeCounter ();
}
*cur_sub_ts = 0;
TimeOut = GetTimeCounter ();
}
else
subtitle_frames_ts[0] = 0;
cur_sub_ts = subtitle_frames_ts;
CommData.AlienTextTemplate.pStr = alien_phrase_buf;
@@ -2044,7 +2087,7 @@ do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp)
BYTE read_speed;
CONTEXT OldContext;
CommData.AlienTextTemplate.pStr += CommData.AlienTextTemplate.CharCount;
CommData.AlienTextTemplate.pStr = alien_phrase_buf + page_break_pos[cur_page];
t = CommData.AlienTextTemplate;
OldContext = SetContext (TaskContext);
@@ -2060,12 +2103,12 @@ do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp)
talk_length = *cur_sub_ts++ * ONE_SECOND /1000;
silence_length = 0;
TimeOut += talk_length;
//sprintf (stderr, "Sound length is %d\n", talk_length);
fprintf (stderr, "Sound length is %d\n", talk_length);
}
else
else if (! disable_timer)
{
read_speed = speed_array[GLOBAL (glob_flags) & READ_SPEED_MASK];
talk_length = ONE_SECOND * CommData.AlienTextTemplate.CharCount / MODERATE_SPEED;
talk_length = 3 * ONE_SECOND * CommData.AlienTextTemplate.CharCount / MODERATE_SPEED;
if (read_speed)
{
silence_length = ONE_SECOND
@@ -2076,18 +2119,28 @@ do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp)
}
TimeOut = GetTimeCounter () + talk_length;
}
else
{
TimeOut = 0;
silence_length = 0;
}
subtitle_state = SPACE_SUBTITLE;
break;
}
case SPACE_SUBTITLE:
if (GetTimeCounter () < TimeOut)
if (! NextPage && (disable_timer || GetTimeCounter () < TimeOut))
break;
TimeOut += silence_length;
subtitle_state = WAIT_SUBTITLE;
/* fall through */
case WAIT_SUBTITLE:
if (speed_array[GLOBAL (glob_flags) & READ_SPEED_MASK] == 0 || GetTimeCounter () >= TimeOut)
if (speed_array[GLOBAL (glob_flags) & READ_SPEED_MASK] == 0 || NextPage || (! disable_timer && GetTimeCounter () >= TimeOut))
{
// if (NextPage)
// fprintf (stderr, "Switching pages\n");
NextPage = 0;
if (! disable_timer)
last_page++;
if (CommData.AlienTextTemplate.pStr[CommData.AlienTextTemplate.CharCount - 1] == '\n')
subtitle_state = READ_SUBTITLE;
else
@@ -153,7 +153,8 @@ void SoundDecoder_Uninit (void)
MikMod_Exit ();
}
TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size)
TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size,
uint32 startTime, uint32 runTime)
{
int i;
@@ -181,6 +182,9 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size)
decoder->decoder_info = decoder_info_wav;
decoder->type = SOUNDDECODER_WAV;
decoder->filename = (char *) HMalloc (strlen (filename) + 1);
decoder->start_sample = 0;
decoder->end_sample = 0;
decoder->pos = 0;
strcpy (decoder->filename, filename);
return decoder;
@@ -215,6 +219,9 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size)
decoder->decoder_info = decoder_info_mod;
decoder->type = SOUNDDECODER_MOD;
decoder->filename = (char *) HMalloc (strlen (filename) + 1);
decoder->start_sample = 0;
decoder->end_sample = 0;
decoder->pos = 0;
strcpy (decoder->filename, filename);
decoder->data = mod;
@@ -270,14 +277,30 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size)
decoder = (TFB_SoundDecoder *) HMalloc (sizeof (TFB_SoundDecoder));
decoder->buffer = HMalloc (buffer_size);
decoder->buffer_size = buffer_size;
if (vinfo->channels == 1)
decoder->format = decoder_formats.mono16;
else
decoder->format = decoder_formats.stereo16;
decoder->frequency = vinfo->rate;
decoder->looping = false;
decoder->error = SOUNDDECODER_OK;
decoder->length = (float) ov_time_total (vf, -1);
if (runTime && runTime / 1000.0 < decoder->length)
decoder->length = (float)(runTime / 1000.0);
decoder->start_sample = decoder->frequency * startTime/1000;
decoder->end_sample = decoder->start_sample +
(unsigned long)(decoder->length * decoder->frequency);
if (decoder->start_sample)
ov_pcm_seek (vf, decoder->start_sample);
if (vinfo->channels == 1)
{
decoder->format = decoder_formats.mono16;
decoder->pos = decoder->start_sample * 2;
}
else
{
decoder->format = decoder_formats.stereo16;
decoder->pos = decoder->start_sample * 4;
}
decoder->decoder_info = decoder_info_ogg;
decoder->type = SOUNDDECODER_OGG;
decoder->filename = (char *) HMalloc (strlen (filename) + 1);
@@ -346,13 +369,33 @@ uint32 SoundDecoder_Decode (TFB_SoundDecoder *decoder)
uint32 decoded_bytes = 0, count = 0;
long rc;
int bitstream;
uint32 max_bytes, buffer_size, close_on_done = 0;
char *buffer = (char *) decoder->buffer;
while (decoded_bytes < decoder->buffer_size)
if (! decoder->looping)
{
if (decoder->format == decoder_formats.stereo16)
max_bytes = decoder->end_sample * 4;
else
max_bytes = decoder->end_sample * 2;
if (max_bytes - decoder->pos < decoder->buffer_size)
{
buffer_size = max_bytes - decoder->pos;
close_on_done = 1;
}
else
{
buffer_size = decoder->buffer_size;
}
}
else
buffer_size = decoder->buffer_size;
while (decoded_bytes < buffer_size)
{
/* Produce output in requested byte-order */
rc = ov_read (vf, &buffer[decoded_bytes],
decoder->buffer_size - decoded_bytes,
buffer_size - decoded_bytes,
decoder_formats.want_big_endian, 2, 1, &bitstream);
if (rc < 0)
{
@@ -360,14 +403,18 @@ uint32 SoundDecoder_Decode (TFB_SoundDecoder *decoder)
fprintf (stderr, "SoundDecoder_Decode(): error decoding %s, code %d\n", decoder->filename, rc);
return decoded_bytes;
}
if (rc == 0)
if (rc == 0 || close_on_done && buffer_size == decoded_bytes + rc)
{
if (close_on_done)
{
decoded_bytes += rc;
}
if (decoder->looping)
{
int err;
if ((err = ov_pcm_seek (vf, 0)) != 0)
SoundDecoder_Rewind (decoder);
if (decoder->error)
{
fprintf (stderr, "SoundDecoder_Decode(): tried to loop %s but couldn't rewind, error code %d\n", decoder->filename, err);
fprintf (stderr, "SoundDecoder_Decode(): tried to loop %s but couldn't rewind, error code %d\n", decoder->filename, decoder->error);
}
else
{
@@ -376,6 +423,8 @@ uint32 SoundDecoder_Decode (TFB_SoundDecoder *decoder)
continue;
}
}
else
decoder->pos += decoded_bytes;
fprintf (stderr, "SoundDecoder_Decode(): eof for %s\n", decoder->filename);
decoder->error = SOUNDDECODER_EOF;
@@ -386,11 +435,14 @@ uint32 SoundDecoder_Decode (TFB_SoundDecoder *decoder)
//fprintf (stderr, "iter %d rc %d decoded_bytes %d remaining %d\n", count, rc, decoded_bytes, decoder->buffer_size - decoded_bytes);
count++;
}
decoder->pos += decoded_bytes;
decoder->error = SOUNDDECODER_OK;
//fprintf (stderr, "SoundDecoder_Decode(): decoded %d bytes from %s\n", decoded_bytes, decoder->filename);
return decoded_bytes;
}
case SOUNDDECODER_BUF:
decoder->error = SOUNDDECODER_EOF;
return (decoder->buffer_size);
default:
{
fprintf (stderr, "SoundDecoder_Decode(): unknown type %d\n", decoder->type);
@@ -415,6 +467,7 @@ uint32 SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder)
if (decoder->buffer_size != 0)
{
decoder->type = SOUNDDECODER_BUF;
decoder->error = SOUNDDECODER_OK;
/* WAVs are loaded in little-endian order
@@ -488,6 +541,11 @@ uint32 SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder)
decoded_bytes += rc;
}
decoder->buffer_size = decoded_bytes;
ov_clear (vf);
HFree (vf);
decoder->type = SOUNDDECODER_BUF;
decoder->error = SOUNDDECODER_OK;
return decoded_bytes;
break;
@@ -525,15 +583,25 @@ void SoundDecoder_Rewind (TFB_SoundDecoder *decoder)
{
int err;
OggVorbis_File *vf = (OggVorbis_File *) decoder->data;
if ((err = ov_pcm_seek (vf, 0)) != 0)
if ((err = ov_pcm_seek (vf, decoder->start_sample)) != 0)
{
fprintf (stderr, "SoundDecoder_Rewind(): couldn't rewind %s, error code %d\n", decoder->filename, err);
break;
}
if (decoder->format == decoder_formats.mono16)
decoder->pos = decoder->start_sample * 2;
else
decoder->pos = decoder->start_sample * 4;
//fprintf (stderr, "SoundDecoder_Rewind(): rewound %s\n", decoder->filename);
decoder->error = SOUNDDECODER_OK;
return;
}
case SOUNDDECODER_BUF:
{
decoder->error = SOUNDDECODER_OK;
return;
}
default:
{
fprintf (stderr, "SoundDecoder_Rewind(): unknown type %d\n", decoder->type);
@@ -573,6 +641,8 @@ void SoundDecoder_Free (TFB_SoundDecoder *decoder)
HFree (vf);
break;
}
case SOUNDDECODER_BUF:
break;
default:
{
fprintf (stderr, "SoundDecoder_Free(): unknown type %d\n", decoder->type);
@@ -54,6 +54,10 @@ typedef struct tfb_sounddecoder
sint32 type;
char *filename;
void *data;
uint32 pos;
uint32 start_sample;
uint32 end_sample;
} TFB_SoundDecoder;
// return values
@@ -71,13 +75,15 @@ enum
SOUNDDECODER_WAV,
SOUNDDECODER_MOD,
SOUNDDECODER_OGG,
SOUNDDECODER_BUF,
};
extern TFB_DecoderFormats decoder_formats;
sint32 SoundDecoder_Init (int flags, TFB_DecoderFormats* formats);
void SoundDecoder_Uninit (void);
TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size);
TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size,
uint32 startTime, uint32 runTime);
uint32 SoundDecoder_Decode (TFB_SoundDecoder *decoder);
uint32 SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder);
void SoundDecoder_Rewind (TFB_SoundDecoder *decoder);
+3 -1
View File
@@ -134,6 +134,8 @@ _GetMusicData (FILE *fp, DWORD length)
char filename[1000];
*pmus = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample));
(*pmus)->buffer_tag = 0;
(*pmus)->read_chain_ptr = NULL;
strcpy (filename, _cur_resfile_name);
switch (optWhichMusic)
@@ -158,7 +160,7 @@ _GetMusicData (FILE *fp, DWORD length)
}
fprintf (stderr, "_GetMusicData(): loading %s\n", filename);
if (((*pmus)->decoder = SoundDecoder_Load (filename, 4096)) == 0)
if (((*pmus)->decoder = SoundDecoder_Load (filename, 4096, 0, 0)) == 0)
{
fprintf (stderr, "_GetMusicData(): couldn't load %s\n", filename);
+4 -1
View File
@@ -135,7 +135,10 @@ _GetSoundBankData (FILE *fp, DWORD length)
fprintf (stderr, "_GetSoundBankData(): loading %s\n", filename);
sndfx[snd_ct] = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample));
sndfx[snd_ct]->decoder = SoundDecoder_Load (filename, 4096);
sndfx[snd_ct]->buffer_tag = 0;
sndfx[snd_ct]->read_chain_ptr = NULL;
sndfx[snd_ct]->decoder = SoundDecoder_Load (filename, 4096, 0, 0);
if (!sndfx[snd_ct]->decoder)
{
fprintf (stderr, "_GetSoundBankData(): couldn't load %s\n", filename);
+44
View File
@@ -175,6 +175,50 @@ SoundPlaying (void)
return FALSE;
}
TFB_SoundChain *
create_soundchain (TFB_SoundDecoder *decoder, float startTime)
{
TFB_SoundChain *chain;
chain = (TFB_SoundChain *)HMalloc (sizeof (TFB_SoundChain));
chain->decoder = decoder;
chain->next =NULL;
chain->start_time = startTime;
chain->tag.buf_name = 0;
chain->tag.type = 0;
return (chain);
}
void
destroy_soundchain (TFB_SoundChain *chain)
{
while (chain->next)
{
TFB_SoundChain *tmp_chain = chain->next;
chain->next = chain->next->next;
if (tmp_chain->decoder)
SoundDecoder_Free (tmp_chain->decoder);
HFree (tmp_chain);
}
SoundDecoder_Free (chain->decoder);
HFree (chain);
}
TFB_SoundChain *
get_previous_chain (TFB_SoundChain *first_chain, TFB_SoundChain *current_chain)
{
TFB_SoundChain *prev_chain;
prev_chain = first_chain;
if (prev_chain == current_chain)
return (prev_chain);
while (prev_chain->next)
{
if (prev_chain->next == current_chain)
return (prev_chain);
prev_chain = prev_chain->next;
}
return (first_chain);
}
// Status: Ignored
BOOLEAN
InitSound (int argc, char* argv[])
+31 -2
View File
@@ -32,13 +32,37 @@
#define SPEECH_SOURCE (MUSIC_SOURCE + 1)
#define NUM_SOUNDSOURCES (SPEECH_SOURCE + 1)
typedef struct
{
mixSDL_Object buf_name;
int type;
void *value;
} TFB_SoundTag;
enum
{
MIX_BUFFER_TAG_TEXT = 1,
MIX_BUFFER_TAG_TEXTPAGE
};
typedef struct tfb_soundchain
{
TFB_SoundDecoder *decoder; // points at the decoder to read from
float start_time;
TFB_SoundTag tag;
struct tfb_soundchain *next;
} TFB_SoundChain;
// audio data
typedef struct tfb_soundsample
{
TFB_SoundDecoder *decoder; // if != NULL, sound is streamed
float length; // total length in seconds
TFB_SoundDecoder *decoder; // decoder to read from
TFB_SoundChain *read_chain_ptr; // points to chain read poistion
TFB_SoundChain *play_chain_ptr; // points to chain playing position
float length; // total length of decoder chain in seconds
mixSDL_Object *buffer;
uint32 num_buffers;
TFB_SoundTag **buffer_tag;
} TFB_SoundSample;
// equivalent to channel in legacy sound code
@@ -62,5 +86,10 @@ extern TFB_SoundSource soundSource[];
void SetSFXVolume (float volume);
void SetSpeechVolume (float volume);
void DoTrackTag (TFB_SoundTag *tag);
TFB_SoundChain *create_soundchain (TFB_SoundDecoder *decoder, float startTime);
void destroy_soundchain (TFB_SoundChain *chain);
TFB_SoundChain *get_previous_chain (TFB_SoundChain *first_chain, TFB_SoundChain *current_chain);
#include "stream.h"
+125 -130
View File
@@ -25,138 +25,90 @@
bool speech_advancetrack = FALSE;
void
PlayStream (TFB_SoundSample *sample, uint32 source, bool looping, bool scope)
{
uint32 i, pos = 0;
uint32 i, pos = 0, offset = 0;
if (!sample)
if (!sample || (!sample->read_chain_ptr && !sample->decoder))
return;
StopStream (source);
if (sample->read_chain_ptr)
{
sample->decoder = sample->read_chain_ptr->decoder;
offset = (int) (sample->read_chain_ptr->start_time * (float)ONE_SECOND);
}
else
offset= 0;
SoundDecoder_Rewind (sample->decoder);
soundSource[source].sample = sample;
soundSource[source].sample->play_chain_ptr = sample->read_chain_ptr;
soundSource[source].sample->decoder->looping = looping;
mixSDL_Sourcei (soundSource[source].handle, MIX_LOOPING, false);
if (scope)
{
soundSource[source].sbuffer = HMalloc (sample->num_buffers * sample->decoder->buffer_size);
soundSource[source].sbuffer = NULL;
}
if (sample->read_chain_ptr && sample->read_chain_ptr->tag.type)
{
DoTrackTag(&sample->read_chain_ptr->tag);
}
for (i = 0; i < sample->num_buffers; ++i)
{
uint32 decoded_bytes;
if (sample->buffer_tag)
sample->buffer_tag[i] = 0;
decoded_bytes = SoundDecoder_Decode (sample->decoder);
//fprintf (stderr, "PlayStream(): source %d sample %x decoded_bytes %d\n", source, sample, decoded_bytes);
//fprintf (stderr, "PlayStream(): source %d filename:%s start: %d position:%d bytes %d\n", source,
// sample->decoder->filename, sample->decoder->start_sample,
// sample->decoder->pos, decoded_bytes);
if (decoded_bytes == 0)
break;
mixSDL_BufferData (sample->buffer[i], sample->decoder->format, sample->decoder->buffer,
decoded_bytes, sample->decoder->frequency);
mixSDL_BufferData (sample->buffer[i], sample->decoder->format, sample->decoder->buffer,
decoded_bytes, sample->decoder->frequency);
mixSDL_SourceQueueBuffers (soundSource[source].handle, 1, &sample->buffer[i]);
if (scope)
{
UBYTE *p = (UBYTE *)soundSource[source].sbuffer;
assert (pos + decoded_bytes <= sample->num_buffers * sample->decoder->buffer_size);
UBYTE *p;
if (! soundSource[source].sbuffer)
soundSource[source].sbuffer = HMalloc (decoded_bytes);
else
soundSource[source].sbuffer = HRealloc (soundSource[source].sbuffer,
pos + decoded_bytes);
p = (UBYTE *)soundSource[source].sbuffer;
memcpy (&p[pos], sample->decoder->buffer, decoded_bytes);
pos += decoded_bytes;
}
if (sample->decoder->error)
break;
{
if (sample->decoder->error == SOUNDDECODER_EOF && sample->read_chain_ptr->next)
{
sample->read_chain_ptr = sample->read_chain_ptr->next;
sample->decoder = sample->read_chain_ptr->decoder;
SoundDecoder_Rewind (sample->decoder);
fprintf (stderr, "Switching to stream %s at pos %d\n",
sample->decoder->filename, sample->decoder->start_sample);
if (sample->buffer_tag && sample->read_chain_ptr->tag.type)
{
sample->buffer_tag[i] = &sample->read_chain_ptr->tag;
sample->read_chain_ptr->tag.buf_name = sample->buffer[i];
}
}
else
break;
}
}
if (sample->buffer_tag)
for ( ; i <sample->num_buffers; ++i)
sample->buffer_tag[i] = 0;
soundSource[source].sbuf_size = pos;
soundSource[source].start_time = GetTimeCounter ();
soundSource[source].stream_should_be_playing = TRUE;
mixSDL_SourcePlay (soundSource[source].handle);
}
// decoders array is NULL-terminated
int
PreDecodeClips (TFB_SoundSample *sample, TFB_SoundDecoder *decoders[], bool autofree)
{
uint32 i;
uint32 org_buffers;
TFB_SoundDecoder **pdecoder;
if (!sample)
return 0;
sample->length = 0.0;
org_buffers = sample->num_buffers;
for (i = 0, pdecoder = decoders;
i < sample->num_buffers && *pdecoder;
i++, pdecoder++)
{
TFB_SoundDecoder *decoder = *pdecoder;
uint32 decoded_bytes;
decoded_bytes = SoundDecoder_DecodeAll (decoder);
if (decoded_bytes == 0)
{
// decoder error, will reuse the buffer
i--;
}
else
{
mixSDL_BufferData (sample->buffer[i], decoder->format, decoder->buffer,
decoded_bytes, decoder->frequency);
sample->length += decoder->length;
}
if (autofree)
{
SoundDecoder_Free (*pdecoder);
*pdecoder = 0;
}
}
if (autofree && i < sample->num_buffers)
{
mixSDL_DeleteBuffers (sample->num_buffers - i, sample->buffer + i);
sample->num_buffers = i;
}
if (i == 0)
fprintf (stderr, "EnqueueClips(): no clips decoded\n");
return i;
}
void
PlayDecodedClip (TFB_SoundSample *sample, uint32 source, bool scope)
{
uint32 i, pos = 0;
if (!sample)
return;
StopStream (source);
soundSource[source].sample = sample;
mixSDL_Sourcei (soundSource[source].handle, MIX_LOOPING, false);
mixSDL_SourceQueueBuffers (soundSource[source].handle,
sample->num_buffers, sample->buffer);
for (i = 0; i < sample->num_buffers; i++)
{
mixSDL_Object size;
size = 0;
mixSDL_GetBufferi (sample->buffer[i], MIX_SIZE, &size);
//soundSource[source].total_decoded += size;
}
soundSource[source].sbuf_size = pos;
soundSource[source].start_time = GetTimeCounter ();
soundSource[source].start_time = GetTimeCounter () - offset;
soundSource[source].stream_should_be_playing = TRUE;
mixSDL_SourcePlay (soundSource[source].handle);
}
@@ -220,10 +172,14 @@ int
StreamDecoderTaskFunc (void *data)
{
Task task = (Task)data;
int i;
mixSDL_Object last_buffer[NUM_SOUNDSOURCES];
for (i = 0; i < NUM_SOUNDSOURCES; i++)
last_buffer[i] = 0;
while (!Task_ReadState (task, TASK_EXIT))
{
int i;
TaskSwitch ();
@@ -232,42 +188,40 @@ StreamDecoderTaskFunc (void *data)
uint32 processed, queued;
mixSDL_Object state;
bool do_speech_advancetrack = false;
int streaming;
LockMutex (soundSource[i].stream_mutex);
if (!soundSource[i].sample ||
!soundSource[i].sample->decoder ||
!soundSource[i].stream_should_be_playing ||
(soundSource[i].sample->decoder &&
soundSource[i].sample->decoder->error == SOUNDDECODER_ERROR))
soundSource[i].sample->decoder->error == SOUNDDECODER_ERROR)
{
UnlockMutex (soundSource[i].stream_mutex);
continue;
}
streaming = soundSource[i].sample->decoder != 0;
mixSDL_GetSourcei (soundSource[i].handle, MIX_BUFFERS_PROCESSED, &processed);
mixSDL_GetSourcei (soundSource[i].handle, MIX_BUFFERS_QUEUED, &queued);
if (processed == 0)
{
mixSDL_GetSourcei (soundSource[i].handle, MIX_SOURCE_STATE, &state);
mixSDL_GetSourcei (soundSource[i].handle, MIX_SOURCE_STATE, &state);
if (state != MIX_PLAYING)
{
if (queued == 0 && (!streaming ||
soundSource[i].sample->decoder->error == SOUNDDECODER_EOF))
if (queued == 0 && soundSource[i].sample->decoder->error == SOUNDDECODER_EOF)
{
fprintf (stderr, "StreamDecoderTaskFunc(): finished playing %s, source %d\n",
streaming ? soundSource[i].sample->decoder->filename : "(decoded)", i);
soundSource[i].stream_should_be_playing = false;
if (i == SPEECH_SOURCE && speech_advancetrack)
fprintf (stderr, "StreamDecoderTaskFunc(): finished playing %s, source %d\n", soundSource[i].sample->decoder->filename, i);
soundSource[i].stream_should_be_playing = FALSE;
if (i == SPEECH_SOURCE)
{
do_speech_advancetrack = true;
}
}
else if (streaming)
{
soundSource[i].sample->decoder = NULL;
soundSource[i].sample->read_chain_ptr = NULL;
if (speech_advancetrack)
do_speech_advancetrack = true;
}
}
else
{
fprintf (stderr, "StreamDecoderTaskFunc(): buffer underrun when playing %s, source %d\n",
soundSource[i].sample->decoder->filename, i);
mixSDL_SourcePlay (soundSource[i].handle);
@@ -282,20 +236,33 @@ StreamDecoderTaskFunc (void *data)
uint32 error;
mixSDL_Object buffer;
uint32 decoded_bytes;
uint32 buf_num;
mixSDL_GetError (); // clear error state
mixSDL_SourceUnqueueBuffers (soundSource[i].handle, 1, &buffer);
if ((error = mixSDL_GetError()) != MIX_NO_ERROR)
{
fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alSourceUnqueueBuffers: %x, file %s, source %d\n", error, soundSource[i].sample->decoder->filename, i);
break;
}
if (!streaming)
if (i == SPEECH_SOURCE)
{
processed--;
continue;
for (buf_num = 0; buf_num < soundSource[i].sample->num_buffers; buf_num++)
{
TFB_SoundTag *cur_tag = soundSource[i].sample->buffer_tag[buf_num];
if (cur_tag && cur_tag->buf_name == buffer)
{
// ...do tag stuff ...
DoTrackTag (cur_tag);
soundSource[i].sample->buffer_tag[buf_num] = NULL;
soundSource[i].sample->play_chain_ptr = soundSource[i].sample->read_chain_ptr;
cur_tag->buf_name = 0;
break;
}
}
}
soundSource[i].total_decoded += soundSource[i].sample->decoder->buffer_size;
@@ -304,14 +271,41 @@ StreamDecoderTaskFunc (void *data)
{
if (soundSource[i].sample->decoder->error == SOUNDDECODER_EOF)
{
//fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is eof for %s\n", soundSource[i].sample->decoder->filename);
if (soundSource[i].sample->read_chain_ptr &&
soundSource[i].sample->read_chain_ptr->next)
{
soundSource[i].sample->read_chain_ptr = soundSource[i].sample->read_chain_ptr->next;
soundSource[i].sample->decoder = soundSource[i].sample->read_chain_ptr->decoder;
SoundDecoder_Rewind (soundSource[i].sample->decoder);
fprintf (stderr, "Switching to stream %s at pos %d\n",
soundSource[i].sample->decoder->filename,
soundSource[i].sample->decoder->start_sample);
if (i == SPEECH_SOURCE)
{
for (buf_num = 0; buf_num < soundSource[i].sample->num_buffers; buf_num++)
{
if (soundSource[i].sample->buffer_tag[buf_num] == 0)
{
soundSource[i].sample->buffer_tag[buf_num] = &soundSource[i].sample->read_chain_ptr->tag;
soundSource[i].sample->read_chain_ptr->tag.buf_name = last_buffer[i];
break;
}
}
}
}
else
{
//fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is eof for %s\n", soundSource[i].sample->decoder->filename);
processed--;
continue;
}
}
else
{
//fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is %d for %s\n", soundSource[i].sample->decoder->error, soundSource[i].sample->decoder->filename);
processed--;
continue;
}
processed--;
continue;
}
decoded_bytes = SoundDecoder_Decode (soundSource[i].sample->decoder);
@@ -325,17 +319,18 @@ StreamDecoderTaskFunc (void *data)
if (decoded_bytes > 0)
{
mixSDL_BufferData (buffer, soundSource[i].sample->decoder->format,
soundSource[i].sample->decoder->buffer, decoded_bytes,
soundSource[i].sample->decoder->frequency);
mixSDL_BufferData (buffer, soundSource[i].sample->decoder->format,
soundSource[i].sample->decoder->buffer, decoded_bytes,
soundSource[i].sample->decoder->frequency);
if ((error = mixSDL_GetError()) != MIX_NO_ERROR)
{
fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alBufferData: %x, file %s, source %d, decoded_bytes %d\n",
error, soundSource[i].sample->decoder->filename, i, decoded_bytes);
fprintf (stderr, "StreamDecoderTaskFunc(): mixSDL error after mixSDL_BufferData: %x, file %s, source %d, decoded_bytes %d\n",
error, soundSource[i].sample->decoder->filename, i, decoded_bytes);
}
else
{
last_buffer[i] = buffer;
mixSDL_SourceQueueBuffers (soundSource[i].handle, 1, &buffer);
if (soundSource[i].sbuffer)
@@ -376,8 +371,8 @@ StreamDecoderTaskFunc (void *data)
if ((error = mixSDL_GetError()) != MIX_NO_ERROR)
{
fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alSourceQueueBuffers: %x, file %s, source %d, decoded_bytes %d\n",
error, i, soundSource[i].sample->decoder->filename, decoded_bytes);
fprintf (stderr, "StreamDecoderTaskFunc(): mixSDL error after mixSDL_SourceQueueBuffers: %x, file %s, source %d, decoded_bytes %d\n",
error, i, soundSource[i].sample->decoder->filename, decoded_bytes);
}
}
}
@@ -391,7 +386,7 @@ StreamDecoderTaskFunc (void *data)
{
if (do_speech_advancetrack)
{
//fprintf (stderr, "StreamDecoderTaskFunc(): calling advance_track\n");
fprintf (stderr, "StreamDecoderTaskFunc(): calling advance_track\n");
do_speech_advancetrack = false;
advance_track (0);
}
+242 -126
View File
@@ -24,37 +24,47 @@
#include "sound.h"
#include "libs/sound/trackplayer.h"
extern int do_subtitles (UNICODE *pStr, UNICODE *TimeStamp);
extern int do_subtitles (UNICODE *pStr, UNICODE *TimeStamp, int method);
static int tct; //total number of subtitle tracks
static int tcur; //currently playing subtitle track
static int cur_page = 0; //current page of subtitle track
static int no_page_break = 0;
static int no_voice;
static int tct, tcur, no_voice;
#define MAX_CLIPS 50
static struct
{
int text_spliced;
UNICODE *text;
UNICODE *timestamp;
TFB_SoundSample *sample;
} track_clip[MAX_CLIPS];
static TFB_SoundSample *sound_sample = NULL;
static TFB_SoundChain *first_chain = NULL; //first decoder in linked list
static TFB_SoundChain *last_chain = NULL; //last decoder in linked list
static UNICODE *TrackTextArray[MAX_CLIPS]; //storage for subtitlle text
static Mutex track_mutex; //protects tcur and tct
void
JumpTrack (int abort)
{
speech_advancetrack = FALSE;
if (track_clip[tcur].sample)
if (sound_sample)
{
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
StopStream (SPEECH_SOURCE);
if (abort)
{
sound_sample->read_chain_ptr = NULL;
sound_sample->decoder = NULL;
}
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
}
no_voice = 1;
do_subtitles ((void *)~0, 0);
do_subtitles ((void *)~0, (void *)~0, 1);
if (abort)
LockMutex (track_mutex);
tcur = tct;
UnlockMutex(track_mutex);
}
void
@@ -62,34 +72,25 @@ advance_track (int channel_finished)
{
if (channel_finished <= 0)
{
if (channel_finished == 0)
++tcur;
if (tcur < tct)
{
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
if (track_clip[tcur].sample->decoder)
PlayStream (track_clip[tcur].sample,
SPEECH_SOURCE, false,
speechVolumeScale != 0.0f);
else
PlayDecodedClip (track_clip[tcur].sample,
SPEECH_SOURCE, false);
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
do_subtitles ((UNICODE *) ~0, 0);
do_subtitles (0, 0);
}
else if (channel_finished == 0)
{
--tcur;
no_voice = 1;
}
if (sound_sample->decoder)
{
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
PlayStream (sound_sample,
SPEECH_SOURCE, false,
speechVolumeScale != 0.0f);
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
}
else if (channel_finished == 0)
{
no_voice = 1;
}
}
}
void
ResumeTrack ()
{
if (tcur < tct)
if (sound_sample && sound_sample->decoder)
{
uint32 state;
@@ -121,21 +122,25 @@ ResumeTrack ()
COUNT
PlayingTrack ()
{
if (tcur < tct)
if (sound_sample->decoder)
{
if (do_subtitles (track_clip[tcur].text, track_clip[tcur].timestamp) ||
(no_voice && ++tcur < tct && do_subtitles (0, 0)))
int last_track, last_page;
LockMutex (track_mutex);
last_track = tcur;
last_page = cur_page;
UnlockMutex (track_mutex);
if (do_subtitles (TrackTextArray[last_track], (void *)last_page, 1) ||
(no_voice && ++tcur < tct && do_subtitles (0, (void *)~0, 1)))
{
return (tcur + 1);
}
else if (track_clip[tcur].sample)
else if (sound_sample)
{
COUNT result;
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
result = (PlayingStream (SPEECH_SOURCE) ? (COUNT)(tcur + 1) : 0);
result = (PlayingStream (SPEECH_SOURCE) ? (COUNT)(last_track + 1) : 0);
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
return result;
}
}
@@ -146,39 +151,70 @@ PlayingTrack ()
void
StopTrack ()
{
int i;
speech_advancetrack = FALSE;
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
StopStream (SPEECH_SOURCE);
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
while (tct--)
for (i = 0; i < tct; i++)
{
if (track_clip[tct].text_spliced)
{
track_clip[tct].text_spliced = 0;
HFree (track_clip[tct].text);
track_clip[tct].text = 0;
}
if (track_clip[tct].sample)
{
TFB_SoundSample *sample = track_clip[tct].sample;
track_clip[tct].sample = NULL;
if (sample->decoder)
{
TFB_SoundDecoder *decoder = sample->decoder;
mixSDL_Object *buffer = sample->buffer;
sample->decoder = NULL;
sample->buffer = NULL;
SoundDecoder_Free (decoder);
mixSDL_DeleteBuffers (sample->num_buffers, buffer);
HFree (buffer);
}
HFree (sample);
}
HFree (TrackTextArray[i]);
TrackTextArray[i] = 0;
}
if (first_chain)
{
destroy_soundchain (first_chain);
first_chain = NULL;
}
if (sound_sample)
{
DestroyMutex (track_mutex);
mixSDL_DeleteBuffers (sound_sample->num_buffers, sound_sample->buffer);
HFree (sound_sample->buffer);
HFree (sound_sample->buffer_tag);
HFree (sound_sample);
sound_sample = NULL;
}
tct = tcur = 0;
no_voice = 0;
do_subtitles (0, 0);
do_subtitles (0, (void *)~0, 1);
}
void
DoTrackTag (TFB_SoundTag *tag)
{
if (tag->type == MIX_BUFFER_TAG_TEXT)
{
LockMutex (track_mutex);
tcur = ((int)tag->value) >> 8;
cur_page = ((int)tag->value) & 0xFF;
UnlockMutex (track_mutex);
}
}
int
GetTimeStamps(UNICODE *TimeStamps, uint32 *time_stamps)
{
int pos;
int num = 0;
while (*TimeStamps && (pos = wstrcspn (TimeStamps, ",\n")))
{
UNICODE valStr[10];
wstrncpy (valStr, TimeStamps, pos);
valStr[pos] = '\0';
*time_stamps = wstrtoul(valStr,NULL,10);
if (*time_stamps)
{
num++;
time_stamps++;
}
TimeStamps += pos;
if (*TimeStamps)
TimeStamps++;
}
*time_stamps = 0;
return (num);
}
// decodes several tracks into one and adds it to queue
@@ -189,6 +225,7 @@ SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText)
#define MAX_MULTI_TRACKS 20
#define MAX_MULTI_BUFFERS 100
TFB_SoundDecoder* track_decs[MAX_MULTI_TRACKS + 1];
TFB_SoundChain *begin_chain;
int tracks;
int slen;
@@ -202,17 +239,21 @@ SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText)
if (tct >= MAX_CLIPS)
{
#ifdef DEBUG
fprintf (stderr, "SpliceMultiTrack(): no more clip slots (%d)\n",
MAX_CLIPS);
#endif
return;
}
if (! sound_sample)
{
fprintf (stderr, "SpliceMultiTrack(): Cannot be called before SpliceTrack()\n");
return;
}
fprintf (stderr, "SpliceMultiTrack(): loading...\n");
for (tracks = 0; *TrackNames && tracks < MAX_MULTI_TRACKS; TrackNames++, tracks++)
{
track_decs[tracks] = SoundDecoder_Load (*TrackNames, 32768);
track_decs[tracks] = SoundDecoder_Load (*TrackNames, 32768, 0, 0);
if (track_decs[tracks])
{
fprintf (stderr, " track: %s, decoder: %s, rate %d format %x\n",
@@ -220,7 +261,13 @@ SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText)
track_decs[tracks]->decoder_info,
track_decs[tracks]->frequency,
track_decs[tracks]->format);
SoundDecoder_DecodeAll (track_decs[tracks]);
last_chain->next = create_soundchain (track_decs[tracks], sound_sample->length);
last_chain = last_chain->next;
if (tracks == 0)
begin_chain = last_chain;
sound_sample->length += track_decs[tracks]->length;
}
else
{
@@ -237,34 +284,34 @@ SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText)
}
slen = wstrlen (TrackText);
track_clip[tct].text = HMalloc (slen + 1);
wstrcpy (track_clip[tct].text, TrackText);
track_clip[tct].text_spliced = 1;
track_clip[tct].timestamp = NULL;
track_clip[tct].sample = (TFB_SoundSample *) HMalloc (
sizeof (TFB_SoundSample));
track_clip[tct].sample->decoder = NULL;
track_clip[tct].sample->num_buffers = tracks;
track_clip[tct].sample->buffer = HMalloc (sizeof (mixSDL_Object)
* track_clip[tct].sample->num_buffers);
mixSDL_GenBuffers (track_clip[tct].sample->num_buffers, track_clip[tct].sample->buffer);
tracks = PreDecodeClips (track_clip[tct].sample, track_decs, true);
if (tct)
{
int slen1;
slen1 = wstrlen (TrackTextArray[tct - 1]);
TrackTextArray[tct - 1] = HRealloc (TrackTextArray[tct - 1], slen1 + slen + 1);
wstrcpy (&TrackTextArray[tct - 1][slen1], TrackText);
}
else
{
TrackTextArray[tct] = HMalloc (slen + 1);
wstrcpy (TrackTextArray[tct++], TrackText);
begin_chain->tag.type = MIX_BUFFER_TAG_TEXT;
begin_chain->tag.value = (void *)((tct - 1) << 8);
}
no_page_break = 1;
if (tracks > 0)
++tct;
return;
else
{
fprintf (stderr, " no tracks loaded\n");
HFree (track_clip[tct].sample);
track_clip[tct].sample = NULL;
}
}
void
SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp)
{
unsigned long startTime;
if (TrackText)
{
if (TrackName == 0)
@@ -274,55 +321,95 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp)
int slen1, slen2;
UNICODE *oTT;
oTT = track_clip[tct - 1].text;
oTT = TrackTextArray[tct - 1];
slen1 = wstrlen (oTT);
slen2 = wstrlen (TrackText);
if (track_clip[tct - 1].text_spliced)
track_clip[tct - 1].text = HRealloc (oTT, slen1 + slen2 + 1);
else
{
track_clip[tct - 1].text = HMalloc (slen1 + slen2 + 1);
wstrcpy (track_clip[tct - 1].text, oTT);
track_clip[tct - 1].text_spliced = 1;
}
wstrcpy (&track_clip[tct - 1].text[slen1], TrackText);
TrackTextArray[tct - 1] = HRealloc (oTT, slen1 + slen2 + 1);
wstrcpy (&TrackTextArray[tct - 1][slen1], TrackText);
}
}
else if (tct < MAX_CLIPS)
else
{
track_clip[tct].text = TrackText;
track_clip[tct].text_spliced = 0;
int num_pages, cur_page;
uint32 time_stamps[50];
track_clip[tct].timestamp = TimeStamp;
fprintf (stderr, "SpliceTrack(): loading %s\n", TrackName);
track_clip[tct].sample = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample));
track_clip[tct].sample->decoder = SoundDecoder_Load (TrackName, 4096);
if (track_clip[tct].sample->decoder)
if (no_page_break && tct)
{
fprintf (stderr, " decoder: %s, rate %d format %x\n",
track_clip[tct].sample->decoder->decoder_info,
track_clip[tct].sample->decoder->frequency,
track_clip[tct].sample->decoder->format);
track_clip[tct].sample->length =
track_clip[tct].sample->decoder->length;
track_clip[tct].sample->num_buffers = 8;
track_clip[tct].sample->buffer = HMalloc (
sizeof (mixSDL_Object) *
track_clip[tct].sample->num_buffers);
mixSDL_GenBuffers (track_clip[tct].sample->num_buffers,
track_clip[tct].sample->buffer);
int slen1, slen2;
UNICODE *oTT;
oTT = TrackTextArray[tct - 1];
slen1 = wstrlen (oTT);
slen2 = wstrlen (TrackText);
TrackTextArray[tct - 1] = HRealloc (oTT, slen1 + slen2 + 1);
wstrcpy (&TrackTextArray[tct - 1][slen1], TrackText);
}
else
{
fprintf (stderr, "SpliceTrack(): couldn't load %s\n", TrackName);
HFree (track_clip[tct].sample);
track_clip[tct].sample = NULL;
TrackTextArray[tct] = HMalloc (sizeof (UNICODE) * (wstrlen (TrackText) + 1));
wstrcpy (TrackTextArray[tct++], TrackText);
}
if (TimeStamp)
num_pages = GetTimeStamps (TimeStamp, time_stamps);
else
num_pages = 0;
fprintf (stderr, "SpliceTrack(): loading %s\n", TrackName);
startTime = 0;
for (cur_page = 0; cur_page <= num_pages; cur_page++)
{
if (! sound_sample)
{
TFB_SoundDecoder *decoder;
track_mutex = CreateMutex();
sound_sample = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample));
sound_sample->num_buffers = 8;
sound_sample->buffer_tag = HMalloc (sizeof (TFB_SoundTag *) * sound_sample->num_buffers);
sound_sample->buffer = HMalloc (sizeof (uint32) * sound_sample->num_buffers);
mixSDL_GenBuffers (sound_sample->num_buffers, sound_sample->buffer);
decoder = SoundDecoder_Load (TrackName, 4096, startTime, time_stamps[cur_page]);
sound_sample->read_chain_ptr = create_soundchain (decoder, 0.0);
sound_sample->decoder = decoder;
first_chain = last_chain = sound_sample->read_chain_ptr;
sound_sample->length = 0;
}
else
{
TFB_SoundDecoder *decoder;
decoder = SoundDecoder_Load (TrackName, 4096, startTime, time_stamps[cur_page]);
last_chain->next = create_soundchain (decoder, sound_sample->length);
last_chain = last_chain->next;
}
startTime += time_stamps[cur_page];
++tct;
// fprintf (stderr, "page (%d of %d): %d\n",cur_page, num_pages, startTime);
if (last_chain->decoder)
{
//fprintf (stderr, " decoder: %s, rate %d format %x\n",
// last_chain->decoder->decoder_info,
// last_chain->decoder->frequency,
// last_chain->decoder->format);
sound_sample->length += last_chain->decoder->length;
if (! no_page_break)
{
last_chain->tag.type = MIX_BUFFER_TAG_TEXT;
last_chain->tag.value = (void *)(((tct - 1) << 8) | cur_page);
}
no_page_break = 0;
}
else
{
fprintf (stderr, "SpliceTrack(): couldn't load %s\n", TrackName);
mixSDL_DeleteBuffers (sound_sample->num_buffers, sound_sample->buffer);
destroy_soundchain (first_chain);
first_chain = NULL;
HFree (sound_sample->buffer);
HFree (sound_sample);
sound_sample = NULL;
}
}
}
}
}
@@ -330,7 +417,7 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp)
void
PauseTrack ()
{
if (tcur < tct && track_clip[tcur].sample)
if (sound_sample && sound_sample->decoder)
{
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
PauseStream (SPEECH_SOURCE);
@@ -341,16 +428,45 @@ PauseTrack ()
void
FastReverse ()
{
JumpTrack (0);
no_voice = 0;
tcur = 0;
ResumeTrack ();
if (sound_sample)
{
TFB_SoundChain *prev_chain;
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
// fprintf(stderr, "playing %s at %d\n",
// sound_sample->play_chain_ptr->decoder->filename,
// sound_sample->play_chain_ptr->decoder->start_sample);
prev_chain = get_previous_chain(first_chain, sound_sample->play_chain_ptr);
// fprintf(stderr, "now playing %s at %d\n",
// prev_chain->decoder->filename, prev_chain->decoder->start_sample);
if (prev_chain)
{
sound_sample->read_chain_ptr = prev_chain;
PlayStream (sound_sample,
SPEECH_SOURCE, false,
speechVolumeScale != 0.0f);
}
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
}
}
void
FastForward ()
{
JumpTrack (0);
if (sound_sample)
{
TFB_SoundChain *cur_ptr = sound_sample->play_chain_ptr;
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
while (cur_ptr->next && ! cur_ptr->tag.type)
cur_ptr = cur_ptr->next;
if (cur_ptr->next)
{
sound_sample->read_chain_ptr = cur_ptr->next;
PlayStream (sound_sample,
SPEECH_SOURCE, false,
speechVolumeScale != 0.0f);
}
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
}
//no_voice = 0;
}
@@ -122,7 +122,7 @@ void SoundDecoder_Uninit (void)
MikMod_Exit ();
}
TFB_SoundDecoder* SoundDecoder_Load (char *filename, ALuint buffer_size)
TFB_SoundDecoder* SoundDecoder_Load (char *filename, ALuint buffer_size, unsigned long startTime, unsigned long runTime)
{
int i;
@@ -150,6 +150,9 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, ALuint buffer_size)
decoder->decoder_info = decoder_info_wav;
decoder->type = SOUNDDECODER_WAV;
decoder->filename = (char *) HMalloc (strlen (filename) + 1);
decoder->start_sample = 0;
decoder->end_sample = 0;
decoder->pos = 0;
strcpy (decoder->filename, filename);
return decoder;
@@ -184,6 +187,9 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, ALuint buffer_size)
decoder->decoder_info = decoder_info_mod;
decoder->type = SOUNDDECODER_MOD;
decoder->filename = (char *) HMalloc (strlen (filename) + 1);
decoder->start_sample = 0;
decoder->end_sample = 0;
decoder->pos = 0;
strcpy (decoder->filename, filename);
decoder->data = mod;
@@ -239,20 +245,36 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, ALuint buffer_size)
decoder = (TFB_SoundDecoder *) HMalloc (sizeof (TFB_SoundDecoder));
decoder->buffer = HMalloc (buffer_size);
decoder->buffer_size = buffer_size;
if (vinfo->channels == 1)
decoder->format = AL_FORMAT_MONO16;
else
decoder->format = AL_FORMAT_STEREO16;
decoder->frequency = vinfo->rate;
decoder->looping = AL_FALSE;
decoder->error = SOUNDDECODER_OK;
decoder->length = (float) ov_time_total (vf, -1);
if (runTime && runTime / 1000.0 < decoder->length)
decoder->length = (float)(runTime / 1000.0);
decoder->start_sample = decoder->frequency * startTime/1000;
decoder->end_sample = decoder->start_sample +
(unsigned long)(decoder->length * decoder->frequency);
if (decoder->start_sample)
ov_pcm_seek (vf, decoder->start_sample);
if (vinfo->channels == 1)
{
decoder->format = AL_FORMAT_MONO16;
decoder->pos = decoder->start_sample * 2;
}
else
{
decoder->format = AL_FORMAT_STEREO16;
decoder->pos = decoder->start_sample * 4;
}
decoder->decoder_info = decoder_info_ogg;
decoder->type = SOUNDDECODER_OGG;
decoder->filename = (char *) HMalloc (strlen (filename) + 1);
strcpy (decoder->filename, filename);
decoder->data = vf;
return decoder;
}
else
@@ -300,26 +322,50 @@ ALuint SoundDecoder_Decode (TFB_SoundDecoder *decoder)
ALuint decoded_bytes = 0, count = 0;
long rc;
int bitstream;
unsigned long max_bytes, buffer_size, close_on_done = 0;
char *buffer = (char *) decoder->buffer;
while (decoded_bytes < decoder->buffer_size)
if (! decoder->looping)
{
if (decoder->format == AL_FORMAT_STEREO16)
max_bytes = decoder->end_sample * 4;
else
max_bytes = decoder->end_sample * 2;
if (max_bytes - decoder->pos < decoder->buffer_size)
{
buffer_size = max_bytes - decoder->pos;
close_on_done = 1;
}
else
{
buffer_size = decoder->buffer_size;
}
}
else
buffer_size = decoder->buffer_size;
while (decoded_bytes < buffer_size)
{
rc = ov_read (vf, &buffer[decoded_bytes], decoder->buffer_size - decoded_bytes, 0, 2, 1, &bitstream);
rc = ov_read (vf, &buffer[decoded_bytes],
buffer_size - decoded_bytes, 0, 2, 1, &bitstream);
if (rc < 0)
{
decoder->error = SOUNDDECODER_ERROR;
fprintf (stderr, "SoundDecoder_Decode(): error decoding %s, code %d\n", decoder->filename, rc);
return decoded_bytes;
}
if (rc == 0)
if (rc == 0 || close_on_done && buffer_size == decoded_bytes + rc)
{
if (close_on_done)
{
decoded_bytes += rc;
}
if (decoder->looping)
{
int err;
if ((err = ov_pcm_seek (vf, 0)) != 0)
SoundDecoder_Rewind (decoder);
if (decoder->error)
{
fprintf (stderr, "SoundDecoder_Decode(): tried to loop %s but couldn't rewind, error code %d\n", decoder->filename, err);
fprintf (stderr, "SoundDecoder_Decode(): tried to loop %s but couldn't rewind, error code %d\n", decoder->filename, decoder->error);
}
else
{
@@ -328,6 +374,8 @@ ALuint SoundDecoder_Decode (TFB_SoundDecoder *decoder)
continue;
}
}
else
decoder->pos += decoded_bytes;
fprintf (stderr, "SoundDecoder_Decode(): eof for %s\n", decoder->filename);
decoder->error = SOUNDDECODER_EOF;
@@ -338,11 +386,14 @@ ALuint SoundDecoder_Decode (TFB_SoundDecoder *decoder)
//fprintf (stderr, "iter %d rc %d decoded_bytes %d remaining %d\n", count, rc, decoded_bytes, decoder->buffer_size - decoded_bytes);
count++;
}
decoder->pos += decoded_bytes;
decoder->error = SOUNDDECODER_OK;
//fprintf (stderr, "SoundDecoder_Decode(): decoded %d bytes from %s\n", decoded_bytes, decoder->filename);
return decoded_bytes;
}
case SOUNDDECODER_BUF:
decoder->error = SOUNDDECODER_EOF;
return (decoder->buffer_size);
default:
{
fprintf (stderr, "SoundDecoder_Decode(): unknown type %d\n", decoder->type);
@@ -362,11 +413,14 @@ ALuint SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder)
{
ALboolean loop;
LoadWAVFile(decoder->filename ,&decoder->format, &decoder->buffer,
LoadWAVFile (decoder->filename ,&decoder->format, &decoder->buffer,
&decoder->buffer_size, &decoder->frequency, &loop);
if (decoder->buffer_size != 0)
{
decoder->type = SOUNDDECODER_BUF;
decoder->error = SOUNDDECODER_OK;
}
else
decoder->error = SOUNDDECODER_ERROR;
@@ -379,7 +433,59 @@ ALuint SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder)
}
case SOUNDDECODER_OGG:
{
fprintf (stderr, "SoundDecoder_DecodeAll(): unimplemented for ogg\n");
OggVorbis_File *vf = (OggVorbis_File *) decoder->data;
ALuint decoded_bytes = 0;
long rc;
int bitstream;
ALuint reqbufsize = decoder->buffer_size;
if (decoder->looping)
{
fprintf (stderr, "SoundDecoder_DecodeAll(): "
"called for %s with looping\n", decoder->filename);
return 0;
}
if (reqbufsize < 4096)
reqbufsize = 4096;
#ifdef DEBUG
if (reqbufsize < 16384)
fprintf (stderr, "SoundDecoder_DecodeAll(): WARNING, "
"called with a small buffer (%u)\n", reqbufsize);
#endif
for (rc = 1; rc > 0; )
{
if (decoded_bytes >= decoder->buffer_size)
{ // need to grow buffer
decoder->buffer_size += reqbufsize;
decoder->buffer = HRealloc (
decoder->buffer, decoder->buffer_size);
}
rc = ov_read (vf, (char*)decoder->buffer + decoded_bytes,
decoder->buffer_size - decoded_bytes,
0, 2, 1, &bitstream);
if (rc < 0)
{
decoder->error = SOUNDDECODER_ERROR;
fprintf (stderr, "SoundDecoder_DecodeAll(): "
"error decoding %s, code %d\n",
decoder->filename, rc);
return decoded_bytes;
}
decoded_bytes += rc;
}
decoder->buffer_size = decoded_bytes;
ov_clear (vf);
HFree (vf);
decoder->type = SOUNDDECODER_BUF;
decoder->error = SOUNDDECODER_OK;
return decoded_bytes;
break;
}
default:
@@ -415,15 +521,25 @@ void SoundDecoder_Rewind (TFB_SoundDecoder *decoder)
{
int err;
OggVorbis_File *vf = (OggVorbis_File *) decoder->data;
if ((err = ov_pcm_seek (vf, 0)) != 0)
if ((err = ov_pcm_seek (vf, decoder->start_sample)) != 0)
{
fprintf (stderr, "SoundDecoder_Rewind(): couldn't rewind %s, error code %d\n", decoder->filename, err);
break;
}
if (decoder->format == AL_FORMAT_MONO16)
decoder->pos = decoder->start_sample * 2;
else
decoder->pos = decoder->start_sample * 4;
//fprintf (stderr, "SoundDecoder_Rewind(): rewound %s\n", decoder->filename);
decoder->error = SOUNDDECODER_OK;
return;
}
case SOUNDDECODER_BUF:
{
decoder->error = SOUNDDECODER_OK;
return;
}
default:
{
fprintf (stderr, "SoundDecoder_Rewind(): unknown type %d\n", decoder->type);
@@ -463,6 +579,8 @@ void SoundDecoder_Free (TFB_SoundDecoder *decoder)
HFree (vf);
break;
}
case SOUNDDECODER_BUF:
break;
default:
{
fprintf (stderr, "SoundDecoder_Free(): unknown type %d\n", decoder->type);
@@ -45,6 +45,9 @@ typedef struct tfb_sounddecoder
ALint type;
char *filename;
void *data;
unsigned long pos;
unsigned long start_sample;
unsigned long end_sample;
} TFB_SoundDecoder;
// return values
@@ -62,11 +65,12 @@ enum
SOUNDDECODER_WAV,
SOUNDDECODER_MOD,
SOUNDDECODER_OGG,
SOUNDDECODER_BUF,
};
ALint SoundDecoder_Init (int flags);
void SoundDecoder_Uninit (void);
TFB_SoundDecoder* SoundDecoder_Load (char *filename, ALuint buffer_size);
TFB_SoundDecoder* SoundDecoder_Load (char *filename, ALuint buffer_size, unsigned long startTime, unsigned long runTime);
ALuint SoundDecoder_Decode (TFB_SoundDecoder *decoder);
ALuint SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder);
void SoundDecoder_Rewind (TFB_SoundDecoder *decoder);
+3 -1
View File
@@ -134,6 +134,8 @@ _GetMusicData (FILE *fp, DWORD length)
char filename[1000];
*pmus = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample));
(*pmus)->buffer_tag = 0;
(*pmus)->read_chain_ptr = NULL;
strcpy (filename, _cur_resfile_name);
switch (optWhichMusic)
@@ -158,7 +160,7 @@ _GetMusicData (FILE *fp, DWORD length)
}
fprintf (stderr, "_GetMusicData(): loading %s\n", filename);
if (((*pmus)->decoder = SoundDecoder_Load (filename, 4096)) == 0)
if (((*pmus)->decoder = SoundDecoder_Load (filename, 4096, 0, 0)) == 0)
{
fprintf (stderr, "_GetMusicData(): couldn't load %s\n", filename);
+3 -1
View File
@@ -135,7 +135,9 @@ _GetSoundBankData (FILE *fp, DWORD length)
fprintf (stderr, "_GetSoundBankData(): loading %s\n", filename);
sndfx[snd_ct] = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample));
sndfx[snd_ct]->decoder = SoundDecoder_Load (filename, 4096);
sndfx[snd_ct]->buffer_tag = 0;
sndfx[snd_ct]->read_chain_ptr = NULL;
sndfx[snd_ct]->decoder = SoundDecoder_Load (filename, 4096, 0, 0);
if (!sndfx[snd_ct]->decoder)
{
fprintf (stderr, "_GetSoundBankData(): couldn't load %s\n", filename);
+44
View File
@@ -178,6 +178,50 @@ SoundPlaying (void)
return FALSE;
}
TFB_SoundChain *
create_soundchain (TFB_SoundDecoder *decoder, float startTime)
{
TFB_SoundChain *chain;
chain = (TFB_SoundChain *)HMalloc (sizeof (TFB_SoundChain));
chain->decoder = decoder;
chain->next =NULL;
chain->start_time = startTime;
chain->tag.buf_name = 0;
chain->tag.type = 0;
return (chain);
}
void
destroy_soundchain (TFB_SoundChain *chain)
{
while (chain->next)
{
TFB_SoundChain *tmp_chain = chain->next;
chain->next = chain->next->next;
if (tmp_chain->decoder)
SoundDecoder_Free (tmp_chain->decoder);
HFree (tmp_chain);
}
SoundDecoder_Free (chain->decoder);
HFree (chain);
}
TFB_SoundChain *
get_previous_chain (TFB_SoundChain *first_chain, TFB_SoundChain *current_chain)
{
TFB_SoundChain *prev_chain;
prev_chain = first_chain;
if (prev_chain == current_chain)
return (prev_chain);
while (prev_chain->next)
{
if (prev_chain->next == current_chain)
return (prev_chain);
prev_chain = prev_chain->next;
}
return (first_chain);
}
// Status: Ignored
BOOLEAN
InitSound (int argc, char* argv[])
+32 -1
View File
@@ -40,14 +40,40 @@
#define SPEECH_SOURCE (MUSIC_SOURCE + 1)
#define NUM_SOUNDSOURCES (SPEECH_SOURCE + 1)
typedef struct
{
ALuint buf_name;
int type;
void *value;
} TFB_SoundTag;
enum
{
AL_BUFFER_TAG_TEXT = 1,
AL_BUFFER_TAG_TEXTPAGE
};
typedef struct tfb_soundchain
{
TFB_SoundDecoder *decoder; // points at the decoder to read from
float start_time;
TFB_SoundTag tag;
struct tfb_soundchain *next;
} TFB_SoundChain;
// audio data
typedef struct tfb_soundsample
{
TFB_SoundDecoder *decoder; // if != NULL, sound is streamed
TFB_SoundDecoder *decoder; // decoder to read from
TFB_SoundChain *read_chain_ptr; // points to chain read poistion
TFB_SoundChain *play_chain_ptr; // points to chain playing position
float length; // total length of decoder chain in seconds
ALuint *buffer;
ALuint num_buffers;
TFB_SoundTag **buffer_tag;
} TFB_SoundSample;
// equivalent to channel in legacy sound code
typedef struct tfb_soundsource
{
@@ -74,5 +100,10 @@ extern TFB_SoundSource soundSource[];
void SetSFXVolume (float volume);
void SetSpeechVolume (float volume);
void DoTrackTag (TFB_SoundTag *tag);
TFB_SoundChain *create_soundchain (TFB_SoundDecoder *decoder, float startTime);
void destroy_soundchain (TFB_SoundChain *chain);
TFB_SoundChain *get_previous_chain (TFB_SoundChain *first_chain, TFB_SoundChain *current_chain);
#include "stream.h"
+115 -25
View File
@@ -28,32 +28,46 @@
BOOLEAN speech_advancetrack = FALSE;
void
PlayStream (TFB_SoundSample *sample, ALuint source, ALboolean looping, ALboolean scope)
{
ALuint i, pos = 0;
if (!sample)
ALuint offset = 0;
if (!sample || (!sample->read_chain_ptr && !sample->decoder))
return;
StopStream (source);
if (sample->read_chain_ptr)
{
sample->decoder = sample->read_chain_ptr->decoder;
offset = (int) (sample->read_chain_ptr->start_time * (float)ONE_SECOND);
}
else
offset= 0;
SoundDecoder_Rewind (sample->decoder);
soundSource[source].sample = sample;
soundSource[source].sample->play_chain_ptr = sample->read_chain_ptr;
soundSource[source].sample->decoder->looping = looping;
alSourcei (soundSource[source].handle, AL_LOOPING, AL_FALSE);
if (scope)
{
soundSource[source].sbuffer = HMalloc (sample->num_buffers * sample->decoder->buffer_size);
soundSource[source].sbuffer = NULL;
}
if (sample->read_chain_ptr && sample->read_chain_ptr->tag.type)
{
DoTrackTag(&sample->read_chain_ptr->tag);
}
for (i = 0; i < sample->num_buffers; ++i)
{
ALuint decoded_bytes;
if (sample->buffer_tag)
sample->buffer_tag[i] = 0;
decoded_bytes = SoundDecoder_Decode (sample->decoder);
//fprintf (stderr, "PlayStream(): source %d sample %x decoded_bytes %d\n", source, sample, decoded_bytes);
//fprintf (stderr, "PlayStream(): source %d filename:%s start: %d position:%d bytes %d\n", source,
// sample->decoder->filename, sample->decoder->start_sample,
// sample->decoder->pos, decoded_bytes);
if (decoded_bytes == 0)
break;
@@ -64,8 +78,7 @@ PlayStream (TFB_SoundSample *sample, ALuint source, ALboolean looping, ALboolean
sample->decoder->format == AL_FORMAT_STEREO16)
{
alBufferWriteData_LOKI (sample->buffer[i], sample->decoder->format, sample->decoder->buffer,
decoded_bytes, sample->decoder->frequency,
sample->decoder->format);
decoded_bytes, sample->decoder->frequency, sample->decoder->format);
}
else
{
@@ -76,23 +89,45 @@ PlayStream (TFB_SoundSample *sample, ALuint source, ALboolean looping, ALboolean
alBufferData (sample->buffer[i], sample->decoder->format, sample->decoder->buffer,
decoded_bytes, sample->decoder->frequency);
#endif
alSourceQueueBuffers (soundSource[source].handle, 1, &sample->buffer[i]);
if (scope)
{
UBYTE *p = (UBYTE *)soundSource[source].sbuffer;
assert (pos + decoded_bytes <= sample->num_buffers * sample->decoder->buffer_size);
UBYTE *p;
if (! soundSource[source].sbuffer)
soundSource[source].sbuffer = HMalloc (decoded_bytes);
else
soundSource[source].sbuffer = HRealloc (soundSource[source].sbuffer,
pos + decoded_bytes);
p = (UBYTE *)soundSource[source].sbuffer;
memcpy (&p[pos], sample->decoder->buffer, decoded_bytes);
pos += decoded_bytes;
}
if (sample->decoder->error)
break;
{
if (sample->decoder->error == SOUNDDECODER_EOF && sample->read_chain_ptr->next)
{
sample->read_chain_ptr = sample->read_chain_ptr->next;
sample->decoder = sample->read_chain_ptr->decoder;
SoundDecoder_Rewind (sample->decoder);
fprintf (stderr, "Switching to stream %s at pos %d\n",
sample->decoder->filename, sample->decoder->start_sample);
if (sample->buffer_tag && sample->read_chain_ptr->tag.type)
{
sample->buffer_tag[i] = &sample->read_chain_ptr->tag;
sample->read_chain_ptr->tag.buf_name = sample->buffer[i];
}
}
else
break;
}
}
if (sample->buffer_tag)
for ( ; i <sample->num_buffers; ++i)
sample->buffer_tag[i] = 0;
soundSource[source].sbuf_size = pos;
soundSource[source].start_time = GetTimeCounter ();
soundSource[source].start_time = GetTimeCounter () - offset;
soundSource[source].stream_should_be_playing = TRUE;
alSourcePlay (soundSource[source].handle);
}
@@ -156,10 +191,14 @@ int
StreamDecoderTaskFunc (void *data)
{
Task task = (Task)data;
int i;
ALuint last_buffer[NUM_SOUNDSOURCES];
for (i = 0; i < NUM_SOUNDSOURCES; i++)
last_buffer[i] = 0;
while (!Task_ReadState (task, TASK_EXIT))
{
int i;
TaskSwitch ();
@@ -192,14 +231,18 @@ StreamDecoderTaskFunc (void *data)
{
fprintf (stderr, "StreamDecoderTaskFunc(): finished playing %s, source %d\n", soundSource[i].sample->decoder->filename, i);
soundSource[i].stream_should_be_playing = FALSE;
if (i == SPEECH_SOURCE && speech_advancetrack)
if (i == SPEECH_SOURCE)
{
do_speech_advancetrack = AL_TRUE;
}
}
soundSource[i].sample->decoder = NULL;
soundSource[i].sample->read_chain_ptr = NULL;
if (speech_advancetrack)
do_speech_advancetrack = AL_TRUE;
}
}
else
{
fprintf (stderr, "StreamDecoderTaskFunc(): buffer underrun when playing %s, source %d\n", soundSource[i].sample->decoder->filename, i);
{
fprintf (stderr, "StreamDecoderTaskFunc(): buffer underrun when playing %s, source %d\n",
soundSource[i].sample->decoder->filename, i);
alSourcePlay (soundSource[i].handle);
}
}
@@ -212,30 +255,76 @@ StreamDecoderTaskFunc (void *data)
ALenum error;
ALuint buffer;
ALuint decoded_bytes;
ALuint buf_num;
alGetError (); // clear error state
alSourceUnqueueBuffers (soundSource[i].handle, 1, &buffer);
if ((error = alGetError()) != AL_NO_ERROR)
{
fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alSourceUnqueueBuffers: %x, file %s, source %d\n", error, soundSource[i].sample->decoder->filename, i);
break;
}
if (i == SPEECH_SOURCE)
{
for (buf_num = 0; buf_num < soundSource[i].sample->num_buffers; buf_num++)
{
TFB_SoundTag *cur_tag = soundSource[i].sample->buffer_tag[buf_num];
if (cur_tag && cur_tag->buf_name == buffer)
{
// ...do tag stuff ...
DoTrackTag (cur_tag);
soundSource[i].sample->buffer_tag[buf_num] = NULL;
soundSource[i].sample->play_chain_ptr = soundSource[i].sample->read_chain_ptr;
cur_tag->buf_name = 0;
break;
}
}
}
soundSource[i].total_decoded += soundSource[i].sample->decoder->buffer_size;
if (soundSource[i].sample->decoder->error)
{
if (soundSource[i].sample->decoder->error == SOUNDDECODER_EOF)
{
//fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is eof for %s\n", soundSource[i].sample->decoder->filename);
if (soundSource[i].sample->read_chain_ptr &&
soundSource[i].sample->read_chain_ptr->next)
{
soundSource[i].sample->read_chain_ptr = soundSource[i].sample->read_chain_ptr->next;
soundSource[i].sample->decoder = soundSource[i].sample->read_chain_ptr->decoder;
SoundDecoder_Rewind (soundSource[i].sample->decoder);
fprintf (stderr, "Switching to stream %s at pos %d\n",
soundSource[i].sample->decoder->filename,
soundSource[i].sample->decoder->start_sample);
if (i == SPEECH_SOURCE)
{
for (buf_num = 0; buf_num < soundSource[i].sample->num_buffers; buf_num++)
{
if (soundSource[i].sample->buffer_tag[buf_num] == 0)
{
soundSource[i].sample->buffer_tag[buf_num] = &soundSource[i].sample->read_chain_ptr->tag;
soundSource[i].sample->read_chain_ptr->tag.buf_name = last_buffer[i];
break;
}
}
}
}
else
{
//fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is eof for %s\n", soundSource[i].sample->decoder->filename);
processed--;
continue;
}
}
else
{
//fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is %d for %s\n", soundSource[i].sample->decoder->error, soundSource[i].sample->decoder->filename);
processed--;
continue;
}
processed--;
continue;
}
decoded_bytes = SoundDecoder_Decode (soundSource[i].sample->decoder);
@@ -279,6 +368,7 @@ StreamDecoderTaskFunc (void *data)
else
{
alSourceQueueBuffers (soundSource[i].handle, 1, &buffer);
last_buffer[i] = buffer;
if (soundSource[i].sbuffer)
{
@@ -333,7 +423,7 @@ StreamDecoderTaskFunc (void *data)
{
if (do_speech_advancetrack)
{
//fprintf (stderr, "StreamDecoderTaskFunc(): calling advance_track\n");
fprintf (stderr, "StreamDecoderTaskFunc(): calling advance_track\n");
do_speech_advancetrack = AL_FALSE;
advance_track (0);
}
+297 -90
View File
@@ -23,37 +23,47 @@
#include "sound.h"
#include "libs/sound/trackplayer.h"
extern int do_subtitles (UNICODE *pStr, UNICODE *TimeStamp);
extern int do_subtitles (UNICODE *pStr, UNICODE *TimeStamp, int method);
static int tct; //total number of subtitle tracks
static int tcur; //currently playing subtitle track
static int cur_page = 0; //current page of subtitle track
static int no_page_break = 0;
static int no_voice;
static int tct, tcur, no_voice;
#define MAX_CLIPS 50
static struct
{
int text_spliced;
UNICODE *text;
UNICODE *timestamp;
TFB_SoundSample *sample;
} track_clip[MAX_CLIPS];
static TFB_SoundSample *sound_sample = NULL;
static TFB_SoundChain *first_chain = NULL; //first decoder in linked list
static TFB_SoundChain *last_chain = NULL; //last decoder in linked list
static UNICODE *TrackTextArray[MAX_CLIPS]; //storage for subtitlle text
static Mutex track_mutex; //protects tcur and tct
void
JumpTrack (int abort)
{
speech_advancetrack = FALSE;
if (track_clip[tcur].sample)
if (sound_sample)
{
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
StopStream (SPEECH_SOURCE);
if (abort)
{
sound_sample->read_chain_ptr = NULL;
sound_sample->decoder = NULL;
}
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
}
no_voice = 1;
do_subtitles ((void *)~0, 0);
do_subtitles ((void *)~0, (void *)~0, 1);
if (abort)
LockMutex (track_mutex);
tcur = tct;
UnlockMutex(track_mutex);
}
void
@@ -61,20 +71,16 @@ advance_track (int channel_finished)
{
if (channel_finished <= 0)
{
if (channel_finished == 0)
++tcur;
if (tcur < tct)
if (sound_sample->decoder)
{
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
PlayStream (track_clip[tcur].sample, SPEECH_SOURCE, AL_FALSE,
speechVolumeScale == 0.0f ? AL_FALSE : AL_TRUE);
PlayStream (sound_sample,
SPEECH_SOURCE, AL_FALSE,
speechVolumeScale != 0.0f);
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
do_subtitles (~0, 0);
do_subtitles (0, 0);
}
else if (channel_finished == 0)
{
--tcur;
no_voice = 1;
}
}
@@ -83,7 +89,7 @@ advance_track (int channel_finished)
void
ResumeTrack ()
{
if (tcur < tct)
if (sound_sample && sound_sample->decoder)
{
ALint state;
@@ -115,21 +121,25 @@ ResumeTrack ()
COUNT
PlayingTrack ()
{
if (tcur < tct)
if (sound_sample->decoder)
{
if (do_subtitles (track_clip[tcur].text, track_clip[tcur].timestamp) ||
(no_voice && ++tcur < tct && do_subtitles (0, 0)))
int last_track, last_page;
LockMutex (track_mutex);
last_track = tcur;
last_page = cur_page;
UnlockMutex (track_mutex);
if (do_subtitles (TrackTextArray[last_track], (void *)last_page, 1) ||
(no_voice && ++tcur < tct && do_subtitles (0, (void *)~0, 1)))
{
return (tcur + 1);
}
else if (track_clip[tcur].sample)
else if (sound_sample)
{
COUNT result;
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
result = (PlayingStream (SPEECH_SOURCE) ? (COUNT)(tcur + 1) : 0);
result = (PlayingStream (SPEECH_SOURCE) ? (COUNT)(last_track + 1) : 0);
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
return result;
}
}
@@ -140,44 +150,167 @@ PlayingTrack ()
void
StopTrack ()
{
int i;
speech_advancetrack = FALSE;
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
StopStream (SPEECH_SOURCE);
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
while (tct--)
for (i = 0; i < tct; i++)
{
if (track_clip[tct].text_spliced)
{
track_clip[tct].text_spliced = 0;
HFree (track_clip[tct].text);
track_clip[tct].text = 0;
}
if (track_clip[tct].sample)
{
TFB_SoundSample *sample = track_clip[tct].sample;
track_clip[tct].sample = NULL;
if (sample->decoder)
{
TFB_SoundDecoder *decoder = sample->decoder;
ALuint *buffer = sample->buffer;
sample->decoder = NULL;
sample->buffer = NULL;
SoundDecoder_Free (decoder);
alDeleteBuffers (sample->num_buffers, buffer);
HFree (buffer);
}
HFree (sample);
}
HFree (TrackTextArray[i]);
TrackTextArray[i] = 0;
}
if (first_chain)
{
destroy_soundchain (first_chain);
first_chain = NULL;
}
if (sound_sample)
{
DestroyMutex (track_mutex);
alDeleteBuffers (sound_sample->num_buffers, sound_sample->buffer);
HFree (sound_sample->buffer);
HFree (sound_sample->buffer_tag);
HFree (sound_sample);
sound_sample = NULL;
}
tct = tcur = 0;
no_voice = 0;
do_subtitles (0, 0);
do_subtitles (0, (void *)~0, 1);
}
void
DoTrackTag (TFB_SoundTag *tag)
{
if (tag->type == AL_BUFFER_TAG_TEXT)
{
LockMutex (track_mutex);
tcur = ((int)tag->value) >> 8;
cur_page = ((int)tag->value) & 0xFF;
UnlockMutex (track_mutex);
}
}
int
GetTimeStamps(UNICODE *TimeStamps, unsigned long *time_stamps)
{
int pos;
int num = 0;
while (*TimeStamps && (pos = wstrcspn (TimeStamps, ",\n")))
{
UNICODE valStr[10];
wstrncpy (valStr, TimeStamps, pos);
valStr[pos] = '\0';
*time_stamps = wstrtoul(valStr,NULL,10);
if (*time_stamps)
{
num++;
time_stamps++;
}
TimeStamps += pos;
if (*TimeStamps)
TimeStamps++;
}
*time_stamps = 0;
return (num);
}
// decodes several tracks into one and adds it to queue
// track list is NULL-terminated
void
SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText)
{
#define MAX_MULTI_TRACKS 20
#define MAX_MULTI_BUFFERS 100
TFB_SoundDecoder* track_decs[MAX_MULTI_TRACKS + 1];
TFB_SoundChain *begin_chain;
int tracks;
int slen;
if (!TrackText)
{
#ifdef DEBUG
fprintf (stderr, "SpliceMultiTrack(): no track text\n");
#endif
return;
}
if (tct >= MAX_CLIPS)
{
fprintf (stderr, "SpliceMultiTrack(): no more clip slots (%d)\n",
MAX_CLIPS);
return;
}
if (! sound_sample)
{
fprintf (stderr, "SpliceMultiTrack(): Cannot be called before SpliceTrack()\n");
return;
}
fprintf (stderr, "SpliceMultiTrack(): loading...\n");
for (tracks = 0; *TrackNames && tracks < MAX_MULTI_TRACKS; TrackNames++, tracks++)
{
track_decs[tracks] = SoundDecoder_Load (*TrackNames, 32768, 0, 0);
if (track_decs[tracks])
{
fprintf (stderr, " track: %s, decoder: %s, rate %d format %x\n",
*TrackNames,
track_decs[tracks]->decoder_info,
track_decs[tracks]->frequency,
track_decs[tracks]->format);
SoundDecoder_DecodeAll (track_decs[tracks]);
last_chain->next = create_soundchain (track_decs[tracks], sound_sample->length);
last_chain = last_chain->next;
if (tracks == 0)
begin_chain = last_chain;
sound_sample->length += track_decs[tracks]->length;
}
else
{
fprintf (stderr, " couldn't load %s\n", *TrackNames);
tracks--;
}
}
track_decs[tracks] = 0; // term
if (tracks == 0)
{
fprintf (stderr, " no tracks loaded\n");
return;
}
slen = wstrlen (TrackText);
if (tct)
{
int slen1;
slen1 = wstrlen (TrackTextArray[tct - 1]);
TrackTextArray[tct - 1] = HRealloc (TrackTextArray[tct - 1], slen1 + slen + 1);
wstrcpy (&TrackTextArray[tct - 1][slen1], TrackText);
}
else
{
TrackTextArray[tct] = HMalloc (slen + 1);
wstrcpy (TrackTextArray[tct++], TrackText);
begin_chain->tag.type = AL_BUFFER_TAG_TEXT;
begin_chain->tag.value = (void *)((tct - 1) << 8);
}
no_page_break = 1;
if (tracks > 0)
return;
else
{
fprintf (stderr, " no tracks loaded\n");
}
}
void
SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp)
{
unsigned long startTime;
if (TrackText)
{
if (TrackName == 0)
@@ -187,50 +320,95 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp)
int slen1, slen2;
UNICODE *oTT;
oTT = track_clip[tct - 1].text;
oTT = TrackTextArray[tct - 1];
slen1 = wstrlen (oTT);
slen2 = wstrlen (TrackText);
if (track_clip[tct - 1].text_spliced)
track_clip[tct - 1].text = HRealloc (oTT, slen1 + slen2 + 1);
else
{
track_clip[tct - 1].text = HMalloc (slen1 + slen2 + 1);
wstrcpy (track_clip[tct - 1].text, oTT);
track_clip[tct - 1].text_spliced = 1;
}
wstrcpy (&track_clip[tct - 1].text[slen1], TrackText);
TrackTextArray[tct - 1] = HRealloc (oTT, slen1 + slen2 + 1);
wstrcpy (&TrackTextArray[tct - 1][slen1], TrackText);
}
}
else if (tct < MAX_CLIPS)
else
{
track_clip[tct].text = TrackText;
track_clip[tct].text_spliced = 0;
int num_pages, cur_page;
unsigned long time_stamps[50];
track_clip[tct].timestamp = TimeStamp;
fprintf (stderr, "SpliceTrack(): loading %s\n", TrackName);
track_clip[tct].sample = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample));
track_clip[tct].sample->decoder = SoundDecoder_Load (TrackName, 4096);
if (track_clip[tct].sample->decoder)
if (no_page_break && tct)
{
fprintf (stderr, " decoder: %s, rate %d format %x\n",
track_clip[tct].sample->decoder->decoder_info,
track_clip[tct].sample->decoder->frequency,
track_clip[tct].sample->decoder->format);
track_clip[tct].sample->num_buffers = 8;
track_clip[tct].sample->buffer = HMalloc (sizeof (ALuint) * track_clip[tct].sample->num_buffers);
alGenBuffers (track_clip[tct].sample->num_buffers, track_clip[tct].sample->buffer);
int slen1, slen2;
UNICODE *oTT;
oTT = TrackTextArray[tct - 1];
slen1 = wstrlen (oTT);
slen2 = wstrlen (TrackText);
TrackTextArray[tct - 1] = HRealloc (oTT, slen1 + slen2 + 1);
wstrcpy (&TrackTextArray[tct - 1][slen1], TrackText);
}
else
{
fprintf (stderr, "SpliceTrack(): couldn't load %s\n", TrackName);
HFree (track_clip[tct].sample);
track_clip[tct].sample = NULL;
TrackTextArray[tct] = HMalloc (sizeof (UNICODE) * (wstrlen (TrackText) + 1));
wstrcpy (TrackTextArray[tct++], TrackText);
}
if (TimeStamp)
num_pages = GetTimeStamps (TimeStamp, time_stamps);
else
num_pages = 0;
fprintf (stderr, "SpliceTrack(): loading %s\n", TrackName);
startTime = 0;
for (cur_page = 0; cur_page <= num_pages; cur_page++)
{
if (! sound_sample)
{
TFB_SoundDecoder *decoder;
track_mutex = CreateMutex();
sound_sample = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample));
sound_sample->num_buffers = 8;
sound_sample->buffer_tag = HMalloc (sizeof (TFB_SoundTag *) * sound_sample->num_buffers);
sound_sample->buffer = HMalloc (sizeof (ALuint) * sound_sample->num_buffers);
alGenBuffers (sound_sample->num_buffers, sound_sample->buffer);
decoder = SoundDecoder_Load (TrackName, 4096, startTime, time_stamps[cur_page]);
sound_sample->read_chain_ptr = create_soundchain (decoder, 0.0);
sound_sample->decoder = decoder;
first_chain = last_chain = sound_sample->read_chain_ptr;
sound_sample->length = 0;
}
else
{
TFB_SoundDecoder *decoder;
decoder = SoundDecoder_Load (TrackName, 4096, startTime, time_stamps[cur_page]);
last_chain->next = create_soundchain (decoder, sound_sample->length);
last_chain = last_chain->next;
}
startTime += time_stamps[cur_page];
++tct;
// fprintf (stderr, "page (%d of %d): %d\n",cur_page, num_pages, startTime);
if (last_chain->decoder)
{
//fprintf (stderr, " decoder: %s, rate %d format %x\n",
// last_chain->decoder->decoder_info,
// last_chain->decoder->frequency,
// last_chain->decoder->format);
sound_sample->length += last_chain->decoder->length;
if (! no_page_break)
{
last_chain->tag.type = AL_BUFFER_TAG_TEXT;
last_chain->tag.value = (void *)(((tct - 1) << 8) | cur_page);
}
no_page_break = 0;
}
else
{
fprintf (stderr, "SpliceTrack(): couldn't load %s\n", TrackName);
alDeleteBuffers (sound_sample->num_buffers, sound_sample->buffer);
destroy_soundchain (first_chain);
first_chain = NULL;
HFree (sound_sample->buffer);
HFree (sound_sample);
sound_sample = NULL;
}
}
}
}
}
@@ -238,7 +416,7 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp)
void
PauseTrack ()
{
if (tcur < tct && track_clip[tcur].sample)
if (sound_sample && sound_sample->decoder)
{
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
PauseStream (SPEECH_SOURCE);
@@ -249,16 +427,45 @@ PauseTrack ()
void
FastReverse ()
{
JumpTrack (0);
no_voice = 0;
tcur = 0;
ResumeTrack ();
if (sound_sample)
{
TFB_SoundChain *prev_chain;
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
// fprintf(stderr, "playing %s at %d\n",
// sound_sample->play_chain_ptr->decoder->filename,
// sound_sample->play_chain_ptr->decoder->start_sample);
prev_chain = get_previous_chain(first_chain, sound_sample->play_chain_ptr);
// fprintf(stderr, "now playing %s at %d\n",
// prev_chain->decoder->filename, prev_chain->decoder->start_sample);
if (prev_chain)
{
sound_sample->read_chain_ptr = prev_chain;
PlayStream (sound_sample,
SPEECH_SOURCE, AL_FALSE,
speechVolumeScale != 0.0f);
}
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
}
}
void
FastForward ()
{
JumpTrack (0);
if (sound_sample)
{
TFB_SoundChain *cur_ptr = sound_sample->play_chain_ptr;
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
while (cur_ptr->next && ! cur_ptr->tag.type)
cur_ptr = cur_ptr->next;
if (cur_ptr->next)
{
sound_sample->read_chain_ptr = cur_ptr->next;
PlayStream (sound_sample,
SPEECH_SOURCE, AL_FALSE,
speechVolumeScale != 0.0f);
}
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
}
//no_voice = 0;
}
@@ -416,9 +623,9 @@ int
GetSoundInfo (int *length, int *offset)
{
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
if (soundSource[SPEECH_SOURCE].sample && soundSource[SPEECH_SOURCE].sample->decoder)
if (soundSource[SPEECH_SOURCE].sample)
{
*length = (int) (soundSource[SPEECH_SOURCE].sample->decoder->length * (float)ONE_SECOND);
*length = (int) (soundSource[SPEECH_SOURCE].sample->length * (float)ONE_SECOND);
*offset = (int) (GetTimeCounter () - soundSource[SPEECH_SOURCE].start_time);
}
else
+7 -7
View File
@@ -27,7 +27,7 @@
#define VOICE_CHANNEL 0
extern int do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp);
extern int do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp, int method);
static int tct, tcur, no_voice;
#define MAX_CLIPS 50
@@ -48,7 +48,7 @@ JumpTrack (int abort)
Mix_HaltChannel (VOICE_CHANNEL);
no_voice = 1;
do_subtitles ((void *)~0, 0);
do_subtitles ((void *)~0, 0, 0);
if (abort)
tcur = tct;
@@ -64,8 +64,8 @@ advance_track (int channel_finished)
if (tcur < tct)
{
Mix_PlayChannel (VOICE_CHANNEL, track_clip[tcur].chunk, 0);
do_subtitles (~0, 0);
do_subtitles (0, 0);
do_subtitles ((void *)~0, 0, 0);
do_subtitles (0, 0, 0);
}
else if (channel_finished == VOICE_CHANNEL)
{
@@ -96,8 +96,8 @@ PlayingTrack ()
{
if (tcur < tct)
{
if (do_subtitles (track_clip[tcur].text, track_clip[tcur].timestamp)
|| (no_voice && ++tcur < tct && do_subtitles (0, 0)))
if (do_subtitles (track_clip[tcur].text, track_clip[tcur].timestamp, 0)
|| (no_voice && ++tcur < tct && do_subtitles (0, 0, 0)))
return (tcur + 1);
else if (track_clip[tcur].chunk)
return (Mix_Playing (VOICE_CHANNEL) ? (COUNT)(tcur + 1) : 0);
@@ -128,7 +128,7 @@ StopTrack ()
}
tct = tcur = 0;
no_voice = 0;
do_subtitles (0, 0);
do_subtitles (0, 0, 0);
}
void
+1
View File
@@ -27,6 +27,7 @@ void FastForward();
void FastReverse();
void StopTrack();
void SpliceTrack(UNICODE *filespec, UNICODE *textspec, UNICODE *TimeStamp);
void SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText);
int GetSoundData (void *data);
int GetSoundInfo (int *len, int *offs);