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
+1
View File
@@ -1,4 +1,5 @@
Changes towards version 0.2: Changes towards version 0.2:
- New streaming code for openal/mixsdl. supports ff/frev in subtitles -PBlue
- New sound module "mixsdl" (experimental) -fOSSiL - New sound module "mixsdl" (experimental) -fOSSiL
- Fixed overlapping subtitle text while switch tracks -PhracturedBlue - Fixed overlapping subtitle text while switch tracks -PhracturedBlue
- New flash-thread cacheing scheme - PhracturedBlue - New flash-thread cacheing scheme - PhracturedBlue
+4 -3
View File
@@ -100,10 +100,11 @@ Implementation bugs (low priority):
yehat021.ogg yehat023.ogg supox002.ogg supox003.ogg supox028.ogg yehat021.ogg yehat023.ogg supox002.ogg supox003.ogg supox028.ogg
vux001.ogg utwig072.ogg umgah027.ogg talkp068.ogg spaho007.ogg vux001.ogg utwig072.ogg umgah027.ogg talkp068.ogg spaho007.ogg
syree012.ogg syree021.ogg syree028.ogg syree069.ogg orz000.ogg syree012.ogg syree021.ogg syree028.ogg syree069.ogg orz000.ogg
- Should be skip forward/back one frame (using arrows?), and keep text synced - Using arrow keys with SDL_mixer will not work.
may only be possible using openAL though - Arrow keys for mixsdl/openAL skip forward/back one page. We should also
have a 'smooth' scrolling mechanism like the 3do
- More work should be done to better sync the text we have. - More work should be done to better sync the text we have.
Match timing between subtitles and speech clips - Slider doesn't track the audio very well
Stuff still to do (large): Stuff still to do (large):
- add some way to configure your keys - add some way to configure your keys
(assigned to mstr) (assigned to mstr)
+72 -19
View File
@@ -1161,7 +1161,7 @@ SpewPhrases (COUNT wait_track)
BOOLEAN ContinuityBreak; BOOLEAN ContinuityBreak;
DWORD TimeIn; DWORD TimeIn;
COUNT which_track; COUNT which_track;
INPUT_STATE InputState; INPUT_STATE InputState, LastInputState;
FRAME F; FRAME F;
TimeIn = GetTimeCounter (); TimeIn = GetTimeCounter ();
@@ -1195,6 +1195,7 @@ SpewPhrases (COUNT wait_track)
else if (which_track <= wait_track) else if (which_track <= wait_track)
ResumeTrack (); ResumeTrack ();
LastInputState = 0;
do do
{ {
ClearSemaphore (GraphicsSem); ClearSemaphore (GraphicsSem);
@@ -1219,14 +1220,14 @@ SpewPhrases (COUNT wait_track)
if (which_track) if (which_track)
{ {
if (GetInputXComponent (InputState) > 0) if (InputState != LastInputState && GetInputXComponent (InputState) > 0)
{ {
SetSliderImage (SetAbsFrameIndex (ActivityFrame, 3)); SetSliderImage (SetAbsFrameIndex (ActivityFrame, 3));
FastForward (); FastForward ();
ContinuityBreak = TRUE; ContinuityBreak = TRUE;
CommData.AlienFrame = 0; CommData.AlienFrame = 0;
} }
else if (GetInputXComponent (InputState) < 0) else if (InputState != LastInputState && GetInputXComponent (InputState) < 0)
{ {
Rewind: Rewind:
SetSliderImage (SetAbsFrameIndex (ActivityFrame, 4)); SetSliderImage (SetAbsFrameIndex (ActivityFrame, 4));
@@ -1234,18 +1235,19 @@ Rewind:
ContinuityBreak = TRUE; ContinuityBreak = TRUE;
CommData.AlienFrame = 0; CommData.AlienFrame = 0;
} }
else if (ContinuityBreak) else if (InputState != LastInputState && ContinuityBreak)
{ {
SetSliderImage (SetAbsFrameIndex (ActivityFrame, 2)); SetSliderImage (SetAbsFrameIndex (ActivityFrame, 2));
if ((which_track = PlayingTrack ()) if ((which_track = PlayingTrack ())
&& which_track <= wait_track) && which_track <= wait_track) ;
ResumeTrack (); // ResumeTrack ();
ContinuityBreak = FALSE; ContinuityBreak = FALSE;
} }
else if (which_track == wait_track else if (which_track == wait_track
|| wait_track == (COUNT)~0) || wait_track == (COUNT)~0)
CommData.AlienFrame = F; CommData.AlienFrame = F;
} }
LastInputState = InputState;
} while (ContinuityBreak } while (ContinuityBreak
|| ((which_track = PlayingTrack ()) && which_track <= wait_track)); || ((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 int
do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp) do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp, int method)
{ {
static DWORD TimeOut; static DWORD TimeOut;
static unsigned long *cur_sub_ts; 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' // TODO: proper disabling of subtitles, this one prolly isn't 'safe'
if (optSubtitles == FALSE) if (optSubtitles == FALSE)
@@ -1961,8 +1970,31 @@ do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp)
if (subtitle_state <= NEXT_SUBTITLE) if (subtitle_state <= NEXT_SUBTITLE)
return (subtitle_state); return (subtitle_state);
TimeOut = 0; TimeOut = 0;
NextPage = 1;
subtitle_state = WAIT_SUBTITLE; 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) switch (subtitle_state)
{ {
@@ -1976,23 +2008,28 @@ do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp)
24, 24,
32, 32,
}; };
static UNICODE alien_phrase_buf[4096];
static int page_break_pos[50];
case NEXT_SUBTITLE: case NEXT_SUBTITLE:
{ {
UNICODE ch; UNICODE ch;
COUNT numchars; COUNT numchars;
static UNICODE alien_phrase_buf[4096]; int cur_pos = 0;
UNICODE *s; UNICODE *s;
static unsigned long subtitle_frames_ts[50]; 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; CommData.AlienTextTemplate.pStr = alien_phrase_buf;
numchars = 0; numchars = 0;
do do
{ {
++numchars; ++numchars;
if (((ch = *pStr++) == '\n' || ch == '\r') if ((ch = *pStr++) == '\n' || ch == '\r')
&& !ispunct (pStr[-2]) {
&& !isspace (pStr[-2])) if (!ispunct (pStr[-2]) && !isspace (pStr[-2]))
{ {
*CommData.AlienTextTemplate.pStr++ = '.'; *CommData.AlienTextTemplate.pStr++ = '.';
*CommData.AlienTextTemplate.pStr++ = '.'; *CommData.AlienTextTemplate.pStr++ = '.';
@@ -2001,9 +2038,16 @@ do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp)
*CommData.AlienTextTemplate.pStr++ = '.'; *CommData.AlienTextTemplate.pStr++ = '.';
*CommData.AlienTextTemplate.pStr++ = '.'; *CommData.AlienTextTemplate.pStr++ = '.';
ch = '.'; ch = '.';
page_break_pos[cur_pos++] = numchars + 3;
numchars += 6; numchars += 6;
} }
else
page_break_pos[cur_pos++] = numchars;
}
} while ((*CommData.AlienTextTemplate.pStr++ = ch)); } while ((*CommData.AlienTextTemplate.pStr++ = ch));
subtitle_frames_ts[0] = 0;
if (! method)
{
if (s = pTimeStamp) if (s = pTimeStamp)
{ {
int pos; int pos;
@@ -2021,8 +2065,7 @@ do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp)
*cur_sub_ts = 0; *cur_sub_ts = 0;
TimeOut = GetTimeCounter (); TimeOut = GetTimeCounter ();
} }
else }
subtitle_frames_ts[0] = 0;
cur_sub_ts = subtitle_frames_ts; cur_sub_ts = subtitle_frames_ts;
CommData.AlienTextTemplate.pStr = alien_phrase_buf; CommData.AlienTextTemplate.pStr = alien_phrase_buf;
@@ -2044,7 +2087,7 @@ do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp)
BYTE read_speed; BYTE read_speed;
CONTEXT OldContext; CONTEXT OldContext;
CommData.AlienTextTemplate.pStr += CommData.AlienTextTemplate.CharCount; CommData.AlienTextTemplate.pStr = alien_phrase_buf + page_break_pos[cur_page];
t = CommData.AlienTextTemplate; t = CommData.AlienTextTemplate;
OldContext = SetContext (TaskContext); OldContext = SetContext (TaskContext);
@@ -2060,12 +2103,12 @@ do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp)
talk_length = *cur_sub_ts++ * ONE_SECOND /1000; talk_length = *cur_sub_ts++ * ONE_SECOND /1000;
silence_length = 0; silence_length = 0;
TimeOut += talk_length; 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]; 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) if (read_speed)
{ {
silence_length = ONE_SECOND silence_length = ONE_SECOND
@@ -2076,18 +2119,28 @@ do_subtitles (UNICODE *pStr, UNICODE *pTimeStamp)
} }
TimeOut = GetTimeCounter () + talk_length; TimeOut = GetTimeCounter () + talk_length;
} }
else
{
TimeOut = 0;
silence_length = 0;
}
subtitle_state = SPACE_SUBTITLE; subtitle_state = SPACE_SUBTITLE;
break; break;
} }
case SPACE_SUBTITLE: case SPACE_SUBTITLE:
if (GetTimeCounter () < TimeOut) if (! NextPage && (disable_timer || GetTimeCounter () < TimeOut))
break; break;
TimeOut += silence_length; TimeOut += silence_length;
subtitle_state = WAIT_SUBTITLE; subtitle_state = WAIT_SUBTITLE;
/* fall through */ /* fall through */
case WAIT_SUBTITLE: 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') if (CommData.AlienTextTemplate.pStr[CommData.AlienTextTemplate.CharCount - 1] == '\n')
subtitle_state = READ_SUBTITLE; subtitle_state = READ_SUBTITLE;
else else
@@ -153,7 +153,8 @@ void SoundDecoder_Uninit (void)
MikMod_Exit (); 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; int i;
@@ -181,6 +182,9 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size)
decoder->decoder_info = decoder_info_wav; decoder->decoder_info = decoder_info_wav;
decoder->type = SOUNDDECODER_WAV; decoder->type = SOUNDDECODER_WAV;
decoder->filename = (char *) HMalloc (strlen (filename) + 1); decoder->filename = (char *) HMalloc (strlen (filename) + 1);
decoder->start_sample = 0;
decoder->end_sample = 0;
decoder->pos = 0;
strcpy (decoder->filename, filename); strcpy (decoder->filename, filename);
return decoder; return decoder;
@@ -215,6 +219,9 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size)
decoder->decoder_info = decoder_info_mod; decoder->decoder_info = decoder_info_mod;
decoder->type = SOUNDDECODER_MOD; decoder->type = SOUNDDECODER_MOD;
decoder->filename = (char *) HMalloc (strlen (filename) + 1); decoder->filename = (char *) HMalloc (strlen (filename) + 1);
decoder->start_sample = 0;
decoder->end_sample = 0;
decoder->pos = 0;
strcpy (decoder->filename, filename); strcpy (decoder->filename, filename);
decoder->data = mod; decoder->data = mod;
@@ -270,14 +277,30 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, uint32 buffer_size)
decoder = (TFB_SoundDecoder *) HMalloc (sizeof (TFB_SoundDecoder)); decoder = (TFB_SoundDecoder *) HMalloc (sizeof (TFB_SoundDecoder));
decoder->buffer = HMalloc (buffer_size); decoder->buffer = HMalloc (buffer_size);
decoder->buffer_size = 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->frequency = vinfo->rate;
decoder->looping = false; decoder->looping = false;
decoder->error = SOUNDDECODER_OK; decoder->error = SOUNDDECODER_OK;
decoder->length = (float) ov_time_total (vf, -1); 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->decoder_info = decoder_info_ogg;
decoder->type = SOUNDDECODER_OGG; decoder->type = SOUNDDECODER_OGG;
decoder->filename = (char *) HMalloc (strlen (filename) + 1); decoder->filename = (char *) HMalloc (strlen (filename) + 1);
@@ -346,13 +369,33 @@ uint32 SoundDecoder_Decode (TFB_SoundDecoder *decoder)
uint32 decoded_bytes = 0, count = 0; uint32 decoded_bytes = 0, count = 0;
long rc; long rc;
int bitstream; int bitstream;
uint32 max_bytes, buffer_size, close_on_done = 0;
char *buffer = (char *) decoder->buffer; 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 */ /* Produce output in requested byte-order */
rc = ov_read (vf, &buffer[decoded_bytes], rc = ov_read (vf, &buffer[decoded_bytes],
decoder->buffer_size - decoded_bytes, buffer_size - decoded_bytes,
decoder_formats.want_big_endian, 2, 1, &bitstream); decoder_formats.want_big_endian, 2, 1, &bitstream);
if (rc < 0) 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); fprintf (stderr, "SoundDecoder_Decode(): error decoding %s, code %d\n", decoder->filename, rc);
return decoded_bytes; 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) if (decoder->looping)
{ {
int err; SoundDecoder_Rewind (decoder);
if ((err = ov_pcm_seek (vf, 0)) != 0) 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 else
{ {
@@ -376,6 +423,8 @@ uint32 SoundDecoder_Decode (TFB_SoundDecoder *decoder)
continue; continue;
} }
} }
else
decoder->pos += decoded_bytes;
fprintf (stderr, "SoundDecoder_Decode(): eof for %s\n", decoder->filename); fprintf (stderr, "SoundDecoder_Decode(): eof for %s\n", decoder->filename);
decoder->error = SOUNDDECODER_EOF; 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); //fprintf (stderr, "iter %d rc %d decoded_bytes %d remaining %d\n", count, rc, decoded_bytes, decoder->buffer_size - decoded_bytes);
count++; count++;
} }
decoder->pos += decoded_bytes;
decoder->error = SOUNDDECODER_OK; decoder->error = SOUNDDECODER_OK;
//fprintf (stderr, "SoundDecoder_Decode(): decoded %d bytes from %s\n", decoded_bytes, decoder->filename); //fprintf (stderr, "SoundDecoder_Decode(): decoded %d bytes from %s\n", decoded_bytes, decoder->filename);
return decoded_bytes; return decoded_bytes;
} }
case SOUNDDECODER_BUF:
decoder->error = SOUNDDECODER_EOF;
return (decoder->buffer_size);
default: default:
{ {
fprintf (stderr, "SoundDecoder_Decode(): unknown type %d\n", decoder->type); 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) if (decoder->buffer_size != 0)
{ {
decoder->type = SOUNDDECODER_BUF;
decoder->error = SOUNDDECODER_OK; decoder->error = SOUNDDECODER_OK;
/* WAVs are loaded in little-endian order /* WAVs are loaded in little-endian order
@@ -488,6 +541,11 @@ uint32 SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder)
decoded_bytes += rc; decoded_bytes += rc;
} }
decoder->buffer_size = decoded_bytes;
ov_clear (vf);
HFree (vf);
decoder->type = SOUNDDECODER_BUF;
decoder->error = SOUNDDECODER_OK; decoder->error = SOUNDDECODER_OK;
return decoded_bytes; return decoded_bytes;
break; break;
@@ -525,15 +583,25 @@ void SoundDecoder_Rewind (TFB_SoundDecoder *decoder)
{ {
int err; int err;
OggVorbis_File *vf = (OggVorbis_File *) decoder->data; 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); fprintf (stderr, "SoundDecoder_Rewind(): couldn't rewind %s, error code %d\n", decoder->filename, err);
break; 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); //fprintf (stderr, "SoundDecoder_Rewind(): rewound %s\n", decoder->filename);
decoder->error = SOUNDDECODER_OK; decoder->error = SOUNDDECODER_OK;
return; return;
} }
case SOUNDDECODER_BUF:
{
decoder->error = SOUNDDECODER_OK;
return;
}
default: default:
{ {
fprintf (stderr, "SoundDecoder_Rewind(): unknown type %d\n", decoder->type); fprintf (stderr, "SoundDecoder_Rewind(): unknown type %d\n", decoder->type);
@@ -573,6 +641,8 @@ void SoundDecoder_Free (TFB_SoundDecoder *decoder)
HFree (vf); HFree (vf);
break; break;
} }
case SOUNDDECODER_BUF:
break;
default: default:
{ {
fprintf (stderr, "SoundDecoder_Free(): unknown type %d\n", decoder->type); fprintf (stderr, "SoundDecoder_Free(): unknown type %d\n", decoder->type);
@@ -54,6 +54,10 @@ typedef struct tfb_sounddecoder
sint32 type; sint32 type;
char *filename; char *filename;
void *data; void *data;
uint32 pos;
uint32 start_sample;
uint32 end_sample;
} TFB_SoundDecoder; } TFB_SoundDecoder;
// return values // return values
@@ -71,13 +75,15 @@ enum
SOUNDDECODER_WAV, SOUNDDECODER_WAV,
SOUNDDECODER_MOD, SOUNDDECODER_MOD,
SOUNDDECODER_OGG, SOUNDDECODER_OGG,
SOUNDDECODER_BUF,
}; };
extern TFB_DecoderFormats decoder_formats; extern TFB_DecoderFormats decoder_formats;
sint32 SoundDecoder_Init (int flags, TFB_DecoderFormats* formats); sint32 SoundDecoder_Init (int flags, TFB_DecoderFormats* formats);
void SoundDecoder_Uninit (void); 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_Decode (TFB_SoundDecoder *decoder);
uint32 SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder); uint32 SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder);
void SoundDecoder_Rewind (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]; char filename[1000];
*pmus = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample)); *pmus = (TFB_SoundSample *) HMalloc (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)
@@ -158,7 +160,7 @@ _GetMusicData (FILE *fp, DWORD length)
} }
fprintf (stderr, "_GetMusicData(): loading %s\n", filename); 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); 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); fprintf (stderr, "_GetSoundBankData(): loading %s\n", filename);
sndfx[snd_ct] = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample)); 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) if (!sndfx[snd_ct]->decoder)
{ {
fprintf (stderr, "_GetSoundBankData(): couldn't load %s\n", filename); fprintf (stderr, "_GetSoundBankData(): couldn't load %s\n", filename);
+44
View File
@@ -175,6 +175,50 @@ SoundPlaying (void)
return FALSE; 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 // Status: Ignored
BOOLEAN BOOLEAN
InitSound (int argc, char* argv[]) InitSound (int argc, char* argv[])
+31 -2
View File
@@ -32,13 +32,37 @@
#define SPEECH_SOURCE (MUSIC_SOURCE + 1) #define SPEECH_SOURCE (MUSIC_SOURCE + 1)
#define NUM_SOUNDSOURCES (SPEECH_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 // audio data
typedef struct tfb_soundsample typedef struct tfb_soundsample
{ {
TFB_SoundDecoder *decoder; // if != NULL, sound is streamed TFB_SoundDecoder *decoder; // decoder to read from
float length; // total length in seconds 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; mixSDL_Object *buffer;
uint32 num_buffers; uint32 num_buffers;
TFB_SoundTag **buffer_tag;
} TFB_SoundSample; } TFB_SoundSample;
// equivalent to channel in legacy sound code // equivalent to channel in legacy sound code
@@ -62,5 +86,10 @@ extern TFB_SoundSource soundSource[];
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"
+107 -112
View File
@@ -25,138 +25,90 @@
bool speech_advancetrack = FALSE; bool speech_advancetrack = FALSE;
void void
PlayStream (TFB_SoundSample *sample, uint32 source, bool looping, bool scope) 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; return;
StopStream (source); 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); SoundDecoder_Rewind (sample->decoder);
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;
mixSDL_Sourcei (soundSource[source].handle, MIX_LOOPING, false); mixSDL_Sourcei (soundSource[source].handle, MIX_LOOPING, false);
if (scope) 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) 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 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) if (decoded_bytes == 0)
break; break;
mixSDL_BufferData (sample->buffer[i], sample->decoder->format, sample->decoder->buffer, mixSDL_BufferData (sample->buffer[i], sample->decoder->format, sample->decoder->buffer,
decoded_bytes, sample->decoder->frequency); decoded_bytes, sample->decoder->frequency);
mixSDL_SourceQueueBuffers (soundSource[source].handle, 1, &sample->buffer[i]); mixSDL_SourceQueueBuffers (soundSource[source].handle, 1, &sample->buffer[i]);
if (scope) if (scope)
{ {
UBYTE *p = (UBYTE *)soundSource[source].sbuffer; UBYTE *p;
assert (pos + decoded_bytes <= sample->num_buffers * sample->decoder->buffer_size); 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); memcpy (&p[pos], sample->decoder->buffer, decoded_bytes);
pos += decoded_bytes; pos += decoded_bytes;
} }
if (sample->decoder->error) 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];
} }
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 else
{ break;
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 (sample->buffer_tag)
if (autofree && i < sample->num_buffers) for ( ; i <sample->num_buffers; ++i)
{ sample->buffer_tag[i] = 0;
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].sbuf_size = pos;
soundSource[source].start_time = GetTimeCounter (); soundSource[source].start_time = GetTimeCounter () - offset;
soundSource[source].stream_should_be_playing = TRUE; soundSource[source].stream_should_be_playing = TRUE;
mixSDL_SourcePlay (soundSource[source].handle); mixSDL_SourcePlay (soundSource[source].handle);
} }
@@ -220,10 +172,14 @@ int
StreamDecoderTaskFunc (void *data) StreamDecoderTaskFunc (void *data)
{ {
Task task = (Task)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)) while (!Task_ReadState (task, TASK_EXIT))
{ {
int i;
TaskSwitch (); TaskSwitch ();
@@ -232,21 +188,18 @@ StreamDecoderTaskFunc (void *data)
uint32 processed, queued; uint32 processed, queued;
mixSDL_Object state; mixSDL_Object state;
bool do_speech_advancetrack = false; bool do_speech_advancetrack = false;
int streaming;
LockMutex (soundSource[i].stream_mutex); LockMutex (soundSource[i].stream_mutex);
if (!soundSource[i].sample || if (!soundSource[i].sample ||
!soundSource[i].sample->decoder ||
!soundSource[i].stream_should_be_playing || !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); UnlockMutex (soundSource[i].stream_mutex);
continue; continue;
} }
streaming = soundSource[i].sample->decoder != 0;
mixSDL_GetSourcei (soundSource[i].handle, MIX_BUFFERS_PROCESSED, &processed); mixSDL_GetSourcei (soundSource[i].handle, MIX_BUFFERS_PROCESSED, &processed);
mixSDL_GetSourcei (soundSource[i].handle, MIX_BUFFERS_QUEUED, &queued); mixSDL_GetSourcei (soundSource[i].handle, MIX_BUFFERS_QUEUED, &queued);
@@ -255,18 +208,19 @@ StreamDecoderTaskFunc (void *data)
mixSDL_GetSourcei (soundSource[i].handle, MIX_SOURCE_STATE, &state); mixSDL_GetSourcei (soundSource[i].handle, MIX_SOURCE_STATE, &state);
if (state != MIX_PLAYING) if (state != MIX_PLAYING)
{ {
if (queued == 0 && (!streaming || if (queued == 0 && soundSource[i].sample->decoder->error == SOUNDDECODER_EOF)
soundSource[i].sample->decoder->error == SOUNDDECODER_EOF))
{ {
fprintf (stderr, "StreamDecoderTaskFunc(): finished playing %s, source %d\n", fprintf (stderr, "StreamDecoderTaskFunc(): finished playing %s, source %d\n", soundSource[i].sample->decoder->filename, i);
streaming ? soundSource[i].sample->decoder->filename : "(decoded)", i); soundSource[i].stream_should_be_playing = FALSE;
soundSource[i].stream_should_be_playing = false; if (i == SPEECH_SOURCE)
if (i == SPEECH_SOURCE && speech_advancetrack)
{ {
soundSource[i].sample->decoder = NULL;
soundSource[i].sample->read_chain_ptr = NULL;
if (speech_advancetrack)
do_speech_advancetrack = true; do_speech_advancetrack = true;
} }
} }
else if (streaming) else
{ {
fprintf (stderr, "StreamDecoderTaskFunc(): buffer underrun when playing %s, source %d\n", fprintf (stderr, "StreamDecoderTaskFunc(): buffer underrun when playing %s, source %d\n",
soundSource[i].sample->decoder->filename, i); soundSource[i].sample->decoder->filename, i);
@@ -282,20 +236,33 @@ StreamDecoderTaskFunc (void *data)
uint32 error; uint32 error;
mixSDL_Object buffer; mixSDL_Object buffer;
uint32 decoded_bytes; uint32 decoded_bytes;
uint32 buf_num;
mixSDL_GetError (); // clear error state mixSDL_GetError (); // clear error state
mixSDL_SourceUnqueueBuffers (soundSource[i].handle, 1, &buffer); mixSDL_SourceUnqueueBuffers (soundSource[i].handle, 1, &buffer);
if ((error = mixSDL_GetError()) != MIX_NO_ERROR) 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); fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alSourceUnqueueBuffers: %x, file %s, source %d\n", error, soundSource[i].sample->decoder->filename, i);
break; break;
} }
if (!streaming) if (i == SPEECH_SOURCE)
{ {
processed--; for (buf_num = 0; buf_num < soundSource[i].sample->num_buffers; buf_num++)
continue; {
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; soundSource[i].total_decoded += soundSource[i].sample->decoder->buffer_size;
@@ -303,16 +270,43 @@ StreamDecoderTaskFunc (void *data)
if (soundSource[i].sample->decoder->error) if (soundSource[i].sample->decoder->error)
{ {
if (soundSource[i].sample->decoder->error == SOUNDDECODER_EOF) if (soundSource[i].sample->decoder->error == SOUNDDECODER_EOF)
{
if (soundSource[i].sample->read_chain_ptr &&
soundSource[i].sample->read_chain_ptr->next)
{
soundSource[i].sample->read_chain_ptr = soundSource[i].sample->read_chain_ptr->next;
soundSource[i].sample->decoder = soundSource[i].sample->read_chain_ptr->decoder;
SoundDecoder_Rewind (soundSource[i].sample->decoder);
fprintf (stderr, "Switching to stream %s at pos %d\n",
soundSource[i].sample->decoder->filename,
soundSource[i].sample->decoder->start_sample);
if (i == SPEECH_SOURCE)
{
for (buf_num = 0; buf_num < soundSource[i].sample->num_buffers; buf_num++)
{
if (soundSource[i].sample->buffer_tag[buf_num] == 0)
{
soundSource[i].sample->buffer_tag[buf_num] = &soundSource[i].sample->read_chain_ptr->tag;
soundSource[i].sample->read_chain_ptr->tag.buf_name = last_buffer[i];
break;
}
}
}
}
else
{ {
//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--;
continue;
}
} }
else else
{ {
//fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is %d for %s\n", soundSource[i].sample->decoder->error, soundSource[i].sample->decoder->filename); //fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is %d for %s\n", soundSource[i].sample->decoder->error, soundSource[i].sample->decoder->filename);
}
processed--; processed--;
continue; continue;
} }
}
decoded_bytes = SoundDecoder_Decode (soundSource[i].sample->decoder); decoded_bytes = SoundDecoder_Decode (soundSource[i].sample->decoder);
if (soundSource[i].sample->decoder->error == SOUNDDECODER_ERROR) if (soundSource[i].sample->decoder->error == SOUNDDECODER_ERROR)
@@ -331,11 +325,12 @@ StreamDecoderTaskFunc (void *data)
if ((error = mixSDL_GetError()) != MIX_NO_ERROR) if ((error = mixSDL_GetError()) != MIX_NO_ERROR)
{ {
fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alBufferData: %x, file %s, source %d, decoded_bytes %d\n", 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); error, soundSource[i].sample->decoder->filename, i, decoded_bytes);
} }
else else
{ {
last_buffer[i] = buffer;
mixSDL_SourceQueueBuffers (soundSource[i].handle, 1, &buffer); mixSDL_SourceQueueBuffers (soundSource[i].handle, 1, &buffer);
if (soundSource[i].sbuffer) if (soundSource[i].sbuffer)
@@ -376,7 +371,7 @@ StreamDecoderTaskFunc (void *data)
if ((error = mixSDL_GetError()) != MIX_NO_ERROR) if ((error = mixSDL_GetError()) != MIX_NO_ERROR)
{ {
fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alSourceQueueBuffers: %x, file %s, source %d, decoded_bytes %d\n", 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); error, i, soundSource[i].sample->decoder->filename, decoded_bytes);
} }
} }
@@ -391,7 +386,7 @@ StreamDecoderTaskFunc (void *data)
{ {
if (do_speech_advancetrack) if (do_speech_advancetrack)
{ {
//fprintf (stderr, "StreamDecoderTaskFunc(): calling advance_track\n"); fprintf (stderr, "StreamDecoderTaskFunc(): calling advance_track\n");
do_speech_advancetrack = false; do_speech_advancetrack = false;
advance_track (0); advance_track (0);
} }
+225 -109
View File
@@ -24,37 +24,47 @@
#include "sound.h" #include "sound.h"
#include "libs/sound/trackplayer.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 #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 void
JumpTrack (int abort) JumpTrack (int abort)
{ {
speech_advancetrack = FALSE; speech_advancetrack = FALSE;
if (track_clip[tcur].sample) if (sound_sample)
{ {
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
StopStream (SPEECH_SOURCE); StopStream (SPEECH_SOURCE);
if (abort)
{
sound_sample->read_chain_ptr = NULL;
sound_sample->decoder = NULL;
}
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
} }
no_voice = 1; no_voice = 1;
do_subtitles ((void *)~0, 0); do_subtitles ((void *)~0, (void *)~0, 1);
if (abort) if (abort)
LockMutex (track_mutex);
tcur = tct; tcur = tct;
UnlockMutex(track_mutex);
} }
void void
@@ -62,25 +72,16 @@ advance_track (int channel_finished)
{ {
if (channel_finished <= 0) if (channel_finished <= 0)
{ {
if (channel_finished == 0) if (sound_sample->decoder)
++tcur;
if (tcur < tct)
{ {
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
if (track_clip[tcur].sample->decoder) PlayStream (sound_sample,
PlayStream (track_clip[tcur].sample,
SPEECH_SOURCE, false, SPEECH_SOURCE, false,
speechVolumeScale != 0.0f); speechVolumeScale != 0.0f);
else
PlayDecodedClip (track_clip[tcur].sample,
SPEECH_SOURCE, false);
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
do_subtitles ((UNICODE *) ~0, 0);
do_subtitles (0, 0);
} }
else if (channel_finished == 0) else if (channel_finished == 0)
{ {
--tcur;
no_voice = 1; no_voice = 1;
} }
} }
@@ -89,7 +90,7 @@ advance_track (int channel_finished)
void void
ResumeTrack () ResumeTrack ()
{ {
if (tcur < tct) if (sound_sample && sound_sample->decoder)
{ {
uint32 state; uint32 state;
@@ -121,21 +122,25 @@ ResumeTrack ()
COUNT COUNT
PlayingTrack () PlayingTrack ()
{ {
if (tcur < tct) if (sound_sample->decoder)
{ {
if (do_subtitles (track_clip[tcur].text, track_clip[tcur].timestamp) || int last_track, last_page;
(no_voice && ++tcur < tct && do_subtitles (0, 0))) 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); return (tcur + 1);
} }
else if (track_clip[tcur].sample) else if (sound_sample)
{ {
COUNT result; COUNT result;
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); 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); UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
return result; return result;
} }
} }
@@ -146,39 +151,70 @@ PlayingTrack ()
void void
StopTrack () StopTrack ()
{ {
int i;
speech_advancetrack = FALSE; speech_advancetrack = FALSE;
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
StopStream (SPEECH_SOURCE); StopStream (SPEECH_SOURCE);
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
while (tct--) for (i = 0; i < tct; i++)
{ {
if (track_clip[tct].text_spliced) HFree (TrackTextArray[i]);
{ TrackTextArray[i] = 0;
track_clip[tct].text_spliced = 0;
HFree (track_clip[tct].text);
track_clip[tct].text = 0;
} }
if (track_clip[tct].sample) if (first_chain)
{ {
TFB_SoundSample *sample = track_clip[tct].sample; destroy_soundchain (first_chain);
track_clip[tct].sample = NULL; first_chain = NULL;
if (sample->decoder) }
if (sound_sample)
{ {
TFB_SoundDecoder *decoder = sample->decoder; DestroyMutex (track_mutex);
mixSDL_Object *buffer = sample->buffer; mixSDL_DeleteBuffers (sound_sample->num_buffers, sound_sample->buffer);
sample->decoder = NULL; HFree (sound_sample->buffer);
sample->buffer = NULL; HFree (sound_sample->buffer_tag);
SoundDecoder_Free (decoder); HFree (sound_sample);
mixSDL_DeleteBuffers (sample->num_buffers, buffer); sound_sample = NULL;
HFree (buffer);
}
HFree (sample);
}
} }
tct = tcur = 0; tct = tcur = 0;
no_voice = 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 // 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_TRACKS 20
#define MAX_MULTI_BUFFERS 100 #define MAX_MULTI_BUFFERS 100
TFB_SoundDecoder* track_decs[MAX_MULTI_TRACKS + 1]; TFB_SoundDecoder* track_decs[MAX_MULTI_TRACKS + 1];
TFB_SoundChain *begin_chain;
int tracks; int tracks;
int slen; int slen;
@@ -202,17 +239,21 @@ SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText)
if (tct >= MAX_CLIPS) if (tct >= MAX_CLIPS)
{ {
#ifdef DEBUG
fprintf (stderr, "SpliceMultiTrack(): no more clip slots (%d)\n", fprintf (stderr, "SpliceMultiTrack(): no more clip slots (%d)\n",
MAX_CLIPS); MAX_CLIPS);
#endif return;
}
if (! sound_sample)
{
fprintf (stderr, "SpliceMultiTrack(): Cannot be called before SpliceTrack()\n");
return; return;
} }
fprintf (stderr, "SpliceMultiTrack(): loading...\n"); fprintf (stderr, "SpliceMultiTrack(): loading...\n");
for (tracks = 0; *TrackNames && tracks < MAX_MULTI_TRACKS; TrackNames++, tracks++) 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]) if (track_decs[tracks])
{ {
fprintf (stderr, " track: %s, decoder: %s, rate %d format %x\n", 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]->decoder_info,
track_decs[tracks]->frequency, track_decs[tracks]->frequency,
track_decs[tracks]->format); 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 else
{ {
@@ -237,34 +284,34 @@ SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText)
} }
slen = wstrlen (TrackText); slen = wstrlen (TrackText);
track_clip[tct].text = HMalloc (slen + 1); if (tct)
wstrcpy (track_clip[tct].text, TrackText); {
track_clip[tct].text_spliced = 1; int slen1;
track_clip[tct].timestamp = NULL; slen1 = wstrlen (TrackTextArray[tct - 1]);
TrackTextArray[tct - 1] = HRealloc (TrackTextArray[tct - 1], slen1 + slen + 1);
track_clip[tct].sample = (TFB_SoundSample *) HMalloc ( wstrcpy (&TrackTextArray[tct - 1][slen1], TrackText);
sizeof (TFB_SoundSample)); }
track_clip[tct].sample->decoder = NULL; else
track_clip[tct].sample->num_buffers = tracks; {
track_clip[tct].sample->buffer = HMalloc (sizeof (mixSDL_Object) TrackTextArray[tct] = HMalloc (slen + 1);
* track_clip[tct].sample->num_buffers); wstrcpy (TrackTextArray[tct++], TrackText);
mixSDL_GenBuffers (track_clip[tct].sample->num_buffers, track_clip[tct].sample->buffer); begin_chain->tag.type = MIX_BUFFER_TAG_TEXT;
begin_chain->tag.value = (void *)((tct - 1) << 8);
tracks = PreDecodeClips (track_clip[tct].sample, track_decs, true); }
no_page_break = 1;
if (tracks > 0) if (tracks > 0)
++tct; return;
else else
{ {
fprintf (stderr, " no tracks loaded\n"); fprintf (stderr, " no tracks loaded\n");
HFree (track_clip[tct].sample);
track_clip[tct].sample = NULL;
} }
} }
void void
SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp) SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp)
{ {
unsigned long startTime;
if (TrackText) if (TrackText)
{ {
if (TrackName == 0) if (TrackName == 0)
@@ -274,55 +321,95 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp)
int slen1, slen2; int slen1, slen2;
UNICODE *oTT; UNICODE *oTT;
oTT = track_clip[tct - 1].text; oTT = TrackTextArray[tct - 1];
slen1 = wstrlen (oTT); slen1 = wstrlen (oTT);
slen2 = wstrlen (TrackText); slen2 = wstrlen (TrackText);
if (track_clip[tct - 1].text_spliced) TrackTextArray[tct - 1] = HRealloc (oTT, slen1 + slen2 + 1);
track_clip[tct - 1].text = HRealloc (oTT, slen1 + slen2 + 1); wstrcpy (&TrackTextArray[tct - 1][slen1], TrackText);
}
}
else else
{ {
track_clip[tct - 1].text = HMalloc (slen1 + slen2 + 1); int num_pages, cur_page;
wstrcpy (track_clip[tct - 1].text, oTT); uint32 time_stamps[50];
track_clip[tct - 1].text_spliced = 1;
if (no_page_break && tct)
{
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);
} }
wstrcpy (&track_clip[tct - 1].text[slen1], TrackText); else
{
TrackTextArray[tct] = HMalloc (sizeof (UNICODE) * (wstrlen (TrackText) + 1));
wstrcpy (TrackTextArray[tct++], TrackText);
} }
} if (TimeStamp)
else if (tct < MAX_CLIPS) num_pages = GetTimeStamps (TimeStamp, time_stamps);
{ else
track_clip[tct].text = TrackText; num_pages = 0;
track_clip[tct].text_spliced = 0;
track_clip[tct].timestamp = TimeStamp;
fprintf (stderr, "SpliceTrack(): loading %s\n", TrackName); fprintf (stderr, "SpliceTrack(): loading %s\n", TrackName);
track_clip[tct].sample = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample)); startTime = 0;
track_clip[tct].sample->decoder = SoundDecoder_Load (TrackName, 4096); for (cur_page = 0; cur_page <= num_pages; cur_page++)
if (track_clip[tct].sample->decoder)
{ {
fprintf (stderr, " decoder: %s, rate %d format %x\n", if (! sound_sample)
track_clip[tct].sample->decoder->decoder_info, {
track_clip[tct].sample->decoder->frequency, TFB_SoundDecoder *decoder;
track_clip[tct].sample->decoder->format); 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];
track_clip[tct].sample->length = // fprintf (stderr, "page (%d of %d): %d\n",cur_page, num_pages, startTime);
track_clip[tct].sample->decoder->length; if (last_chain->decoder)
track_clip[tct].sample->num_buffers = 8; {
track_clip[tct].sample->buffer = HMalloc ( //fprintf (stderr, " decoder: %s, rate %d format %x\n",
sizeof (mixSDL_Object) * // last_chain->decoder->decoder_info,
track_clip[tct].sample->num_buffers); // last_chain->decoder->frequency,
mixSDL_GenBuffers (track_clip[tct].sample->num_buffers, // last_chain->decoder->format);
track_clip[tct].sample->buffer);
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 else
{ {
fprintf (stderr, "SpliceTrack(): couldn't load %s\n", TrackName); fprintf (stderr, "SpliceTrack(): couldn't load %s\n", TrackName);
HFree (track_clip[tct].sample); mixSDL_DeleteBuffers (sound_sample->num_buffers, sound_sample->buffer);
track_clip[tct].sample = NULL; destroy_soundchain (first_chain);
first_chain = NULL;
HFree (sound_sample->buffer);
HFree (sound_sample);
sound_sample = NULL;
}
} }
++tct;
} }
} }
} }
@@ -330,7 +417,7 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp)
void void
PauseTrack () PauseTrack ()
{ {
if (tcur < tct && track_clip[tcur].sample) if (sound_sample && sound_sample->decoder)
{ {
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
PauseStream (SPEECH_SOURCE); PauseStream (SPEECH_SOURCE);
@@ -341,16 +428,45 @@ PauseTrack ()
void void
FastReverse () FastReverse ()
{ {
JumpTrack (0); if (sound_sample)
no_voice = 0; {
tcur = 0; TFB_SoundChain *prev_chain;
ResumeTrack (); 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 void
FastForward () 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; //no_voice = 0;
} }
@@ -122,7 +122,7 @@ void SoundDecoder_Uninit (void)
MikMod_Exit (); 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; int i;
@@ -150,6 +150,9 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, ALuint buffer_size)
decoder->decoder_info = decoder_info_wav; decoder->decoder_info = decoder_info_wav;
decoder->type = SOUNDDECODER_WAV; decoder->type = SOUNDDECODER_WAV;
decoder->filename = (char *) HMalloc (strlen (filename) + 1); decoder->filename = (char *) HMalloc (strlen (filename) + 1);
decoder->start_sample = 0;
decoder->end_sample = 0;
decoder->pos = 0;
strcpy (decoder->filename, filename); strcpy (decoder->filename, filename);
return decoder; return decoder;
@@ -184,6 +187,9 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, ALuint buffer_size)
decoder->decoder_info = decoder_info_mod; decoder->decoder_info = decoder_info_mod;
decoder->type = SOUNDDECODER_MOD; decoder->type = SOUNDDECODER_MOD;
decoder->filename = (char *) HMalloc (strlen (filename) + 1); decoder->filename = (char *) HMalloc (strlen (filename) + 1);
decoder->start_sample = 0;
decoder->end_sample = 0;
decoder->pos = 0;
strcpy (decoder->filename, filename); strcpy (decoder->filename, filename);
decoder->data = mod; decoder->data = mod;
@@ -239,14 +245,30 @@ TFB_SoundDecoder* SoundDecoder_Load (char *filename, ALuint buffer_size)
decoder = (TFB_SoundDecoder *) HMalloc (sizeof (TFB_SoundDecoder)); decoder = (TFB_SoundDecoder *) HMalloc (sizeof (TFB_SoundDecoder));
decoder->buffer = HMalloc (buffer_size); decoder->buffer = HMalloc (buffer_size);
decoder->buffer_size = 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->frequency = vinfo->rate;
decoder->looping = AL_FALSE; decoder->looping = AL_FALSE;
decoder->error = SOUNDDECODER_OK; decoder->error = SOUNDDECODER_OK;
decoder->length = (float) ov_time_total (vf, -1); 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->decoder_info = decoder_info_ogg;
decoder->type = SOUNDDECODER_OGG; decoder->type = SOUNDDECODER_OGG;
decoder->filename = (char *) HMalloc (strlen (filename) + 1); decoder->filename = (char *) HMalloc (strlen (filename) + 1);
@@ -300,26 +322,50 @@ ALuint SoundDecoder_Decode (TFB_SoundDecoder *decoder)
ALuint decoded_bytes = 0, count = 0; ALuint decoded_bytes = 0, count = 0;
long rc; long rc;
int bitstream; int bitstream;
unsigned long max_bytes, buffer_size, close_on_done = 0;
char *buffer = (char *) decoder->buffer; 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;
rc = ov_read (vf, &buffer[decoded_bytes], decoder->buffer_size - decoded_bytes, 0, 2, 1, &bitstream); while (decoded_bytes < buffer_size)
{
rc = ov_read (vf, &buffer[decoded_bytes],
buffer_size - decoded_bytes, 0, 2, 1, &bitstream);
if (rc < 0) if (rc < 0)
{ {
decoder->error = SOUNDDECODER_ERROR; decoder->error = SOUNDDECODER_ERROR;
fprintf (stderr, "SoundDecoder_Decode(): error decoding %s, code %d\n", decoder->filename, rc); fprintf (stderr, "SoundDecoder_Decode(): error decoding %s, code %d\n", decoder->filename, rc);
return decoded_bytes; 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) if (decoder->looping)
{ {
int err; SoundDecoder_Rewind (decoder);
if ((err = ov_pcm_seek (vf, 0)) != 0) 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 else
{ {
@@ -328,6 +374,8 @@ ALuint SoundDecoder_Decode (TFB_SoundDecoder *decoder)
continue; continue;
} }
} }
else
decoder->pos += decoded_bytes;
fprintf (stderr, "SoundDecoder_Decode(): eof for %s\n", decoder->filename); fprintf (stderr, "SoundDecoder_Decode(): eof for %s\n", decoder->filename);
decoder->error = SOUNDDECODER_EOF; 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); //fprintf (stderr, "iter %d rc %d decoded_bytes %d remaining %d\n", count, rc, decoded_bytes, decoder->buffer_size - decoded_bytes);
count++; count++;
} }
decoder->pos += decoded_bytes;
decoder->error = SOUNDDECODER_OK; decoder->error = SOUNDDECODER_OK;
//fprintf (stderr, "SoundDecoder_Decode(): decoded %d bytes from %s\n", decoded_bytes, decoder->filename); //fprintf (stderr, "SoundDecoder_Decode(): decoded %d bytes from %s\n", decoded_bytes, decoder->filename);
return decoded_bytes; return decoded_bytes;
} }
case SOUNDDECODER_BUF:
decoder->error = SOUNDDECODER_EOF;
return (decoder->buffer_size);
default: default:
{ {
fprintf (stderr, "SoundDecoder_Decode(): unknown type %d\n", decoder->type); fprintf (stderr, "SoundDecoder_Decode(): unknown type %d\n", decoder->type);
@@ -366,7 +417,10 @@ ALuint SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder)
&decoder->buffer_size, &decoder->frequency, &loop); &decoder->buffer_size, &decoder->frequency, &loop);
if (decoder->buffer_size != 0) if (decoder->buffer_size != 0)
{
decoder->type = SOUNDDECODER_BUF;
decoder->error = SOUNDDECODER_OK; decoder->error = SOUNDDECODER_OK;
}
else else
decoder->error = SOUNDDECODER_ERROR; decoder->error = SOUNDDECODER_ERROR;
@@ -379,7 +433,59 @@ ALuint SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder)
} }
case SOUNDDECODER_OGG: 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; break;
} }
default: default:
@@ -415,15 +521,25 @@ void SoundDecoder_Rewind (TFB_SoundDecoder *decoder)
{ {
int err; int err;
OggVorbis_File *vf = (OggVorbis_File *) decoder->data; 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); fprintf (stderr, "SoundDecoder_Rewind(): couldn't rewind %s, error code %d\n", decoder->filename, err);
break; 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); //fprintf (stderr, "SoundDecoder_Rewind(): rewound %s\n", decoder->filename);
decoder->error = SOUNDDECODER_OK; decoder->error = SOUNDDECODER_OK;
return; return;
} }
case SOUNDDECODER_BUF:
{
decoder->error = SOUNDDECODER_OK;
return;
}
default: default:
{ {
fprintf (stderr, "SoundDecoder_Rewind(): unknown type %d\n", decoder->type); fprintf (stderr, "SoundDecoder_Rewind(): unknown type %d\n", decoder->type);
@@ -463,6 +579,8 @@ void SoundDecoder_Free (TFB_SoundDecoder *decoder)
HFree (vf); HFree (vf);
break; break;
} }
case SOUNDDECODER_BUF:
break;
default: default:
{ {
fprintf (stderr, "SoundDecoder_Free(): unknown type %d\n", decoder->type); fprintf (stderr, "SoundDecoder_Free(): unknown type %d\n", decoder->type);
@@ -45,6 +45,9 @@ typedef struct tfb_sounddecoder
ALint type; ALint type;
char *filename; char *filename;
void *data; void *data;
unsigned long pos;
unsigned long start_sample;
unsigned long end_sample;
} TFB_SoundDecoder; } TFB_SoundDecoder;
// return values // return values
@@ -62,11 +65,12 @@ enum
SOUNDDECODER_WAV, SOUNDDECODER_WAV,
SOUNDDECODER_MOD, SOUNDDECODER_MOD,
SOUNDDECODER_OGG, SOUNDDECODER_OGG,
SOUNDDECODER_BUF,
}; };
ALint SoundDecoder_Init (int flags); ALint SoundDecoder_Init (int flags);
void SoundDecoder_Uninit (void); 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_Decode (TFB_SoundDecoder *decoder);
ALuint SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder); ALuint SoundDecoder_DecodeAll (TFB_SoundDecoder *decoder);
void SoundDecoder_Rewind (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]; char filename[1000];
*pmus = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample)); *pmus = (TFB_SoundSample *) HMalloc (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)
@@ -158,7 +160,7 @@ _GetMusicData (FILE *fp, DWORD length)
} }
fprintf (stderr, "_GetMusicData(): loading %s\n", filename); 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); 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); fprintf (stderr, "_GetSoundBankData(): loading %s\n", filename);
sndfx[snd_ct] = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample)); 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) if (!sndfx[snd_ct]->decoder)
{ {
fprintf (stderr, "_GetSoundBankData(): couldn't load %s\n", filename); fprintf (stderr, "_GetSoundBankData(): couldn't load %s\n", filename);
+44
View File
@@ -178,6 +178,50 @@ SoundPlaying (void)
return FALSE; 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 // Status: Ignored
BOOLEAN BOOLEAN
InitSound (int argc, char* argv[]) InitSound (int argc, char* argv[])
+32 -1
View File
@@ -40,14 +40,40 @@
#define SPEECH_SOURCE (MUSIC_SOURCE + 1) #define SPEECH_SOURCE (MUSIC_SOURCE + 1)
#define NUM_SOUNDSOURCES (SPEECH_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 // audio data
typedef struct tfb_soundsample 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 *buffer;
ALuint num_buffers; ALuint num_buffers;
TFB_SoundTag **buffer_tag;
} TFB_SoundSample; } TFB_SoundSample;
// equivalent to channel in legacy sound code // equivalent to channel in legacy sound code
typedef struct tfb_soundsource typedef struct tfb_soundsource
{ {
@@ -74,5 +100,10 @@ extern TFB_SoundSource soundSource[];
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"
+108 -18
View File
@@ -28,32 +28,46 @@
BOOLEAN speech_advancetrack = FALSE; BOOLEAN speech_advancetrack = FALSE;
void void
PlayStream (TFB_SoundSample *sample, ALuint source, ALboolean looping, ALboolean scope) PlayStream (TFB_SoundSample *sample, ALuint source, ALboolean looping, ALboolean scope)
{ {
ALuint i, pos = 0; ALuint i, pos = 0;
ALuint offset = 0;
if (!sample) if (!sample || (!sample->read_chain_ptr && !sample->decoder))
return; return;
StopStream (source); 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); SoundDecoder_Rewind (sample->decoder);
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;
alSourcei (soundSource[source].handle, AL_LOOPING, AL_FALSE); alSourcei (soundSource[source].handle, AL_LOOPING, AL_FALSE);
if (scope) 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) for (i = 0; i < sample->num_buffers; ++i)
{ {
ALuint decoded_bytes; ALuint 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 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) if (decoded_bytes == 0)
break; break;
@@ -64,8 +78,7 @@ PlayStream (TFB_SoundSample *sample, ALuint source, ALboolean looping, ALboolean
sample->decoder->format == AL_FORMAT_STEREO16) sample->decoder->format == AL_FORMAT_STEREO16)
{ {
alBufferWriteData_LOKI (sample->buffer[i], sample->decoder->format, sample->decoder->buffer, alBufferWriteData_LOKI (sample->buffer[i], sample->decoder->format, sample->decoder->buffer,
decoded_bytes, sample->decoder->frequency, decoded_bytes, sample->decoder->frequency, sample->decoder->format);
sample->decoder->format);
} }
else else
{ {
@@ -76,23 +89,45 @@ PlayStream (TFB_SoundSample *sample, ALuint source, ALboolean looping, ALboolean
alBufferData (sample->buffer[i], sample->decoder->format, sample->decoder->buffer, alBufferData (sample->buffer[i], sample->decoder->format, sample->decoder->buffer,
decoded_bytes, sample->decoder->frequency); decoded_bytes, sample->decoder->frequency);
#endif #endif
alSourceQueueBuffers (soundSource[source].handle, 1, &sample->buffer[i]); alSourceQueueBuffers (soundSource[source].handle, 1, &sample->buffer[i]);
if (scope) if (scope)
{ {
UBYTE *p = (UBYTE *)soundSource[source].sbuffer; UBYTE *p;
assert (pos + decoded_bytes <= sample->num_buffers * sample->decoder->buffer_size); 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); memcpy (&p[pos], sample->decoder->buffer, decoded_bytes);
pos += decoded_bytes; pos += decoded_bytes;
} }
if (sample->decoder->error) if (sample->decoder->error)
{
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; break;
} }
}
if (sample->buffer_tag)
for ( ; i <sample->num_buffers; ++i)
sample->buffer_tag[i] = 0;
soundSource[source].sbuf_size = pos; soundSource[source].sbuf_size = pos;
soundSource[source].start_time = GetTimeCounter (); soundSource[source].start_time = GetTimeCounter () - offset;
soundSource[source].stream_should_be_playing = TRUE; soundSource[source].stream_should_be_playing = TRUE;
alSourcePlay (soundSource[source].handle); alSourcePlay (soundSource[source].handle);
} }
@@ -156,10 +191,14 @@ int
StreamDecoderTaskFunc (void *data) StreamDecoderTaskFunc (void *data)
{ {
Task task = (Task)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)) while (!Task_ReadState (task, TASK_EXIT))
{ {
int i;
TaskSwitch (); TaskSwitch ();
@@ -192,14 +231,18 @@ 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 && speech_advancetrack) if (i == SPEECH_SOURCE)
{ {
soundSource[i].sample->decoder = NULL;
soundSource[i].sample->read_chain_ptr = NULL;
if (speech_advancetrack)
do_speech_advancetrack = AL_TRUE; do_speech_advancetrack = AL_TRUE;
} }
} }
else 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); alSourcePlay (soundSource[i].handle);
} }
} }
@@ -212,31 +255,77 @@ StreamDecoderTaskFunc (void *data)
ALenum error; ALenum error;
ALuint buffer; ALuint buffer;
ALuint decoded_bytes; ALuint decoded_bytes;
ALuint buf_num;
alGetError (); // clear error state alGetError (); // clear error state
alSourceUnqueueBuffers (soundSource[i].handle, 1, &buffer); alSourceUnqueueBuffers (soundSource[i].handle, 1, &buffer);
if ((error = alGetError()) != AL_NO_ERROR) 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); fprintf (stderr, "StreamDecoderTaskFunc(): OpenAL error after alSourceUnqueueBuffers: %x, file %s, source %d\n", error, soundSource[i].sample->decoder->filename, i);
break; 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; soundSource[i].total_decoded += soundSource[i].sample->decoder->buffer_size;
if (soundSource[i].sample->decoder->error) if (soundSource[i].sample->decoder->error)
{ {
if (soundSource[i].sample->decoder->error == SOUNDDECODER_EOF) if (soundSource[i].sample->decoder->error == SOUNDDECODER_EOF)
{
if (soundSource[i].sample->read_chain_ptr &&
soundSource[i].sample->read_chain_ptr->next)
{
soundSource[i].sample->read_chain_ptr = soundSource[i].sample->read_chain_ptr->next;
soundSource[i].sample->decoder = soundSource[i].sample->read_chain_ptr->decoder;
SoundDecoder_Rewind (soundSource[i].sample->decoder);
fprintf (stderr, "Switching to stream %s at pos %d\n",
soundSource[i].sample->decoder->filename,
soundSource[i].sample->decoder->start_sample);
if (i == SPEECH_SOURCE)
{
for (buf_num = 0; buf_num < soundSource[i].sample->num_buffers; buf_num++)
{
if (soundSource[i].sample->buffer_tag[buf_num] == 0)
{
soundSource[i].sample->buffer_tag[buf_num] = &soundSource[i].sample->read_chain_ptr->tag;
soundSource[i].sample->read_chain_ptr->tag.buf_name = last_buffer[i];
break;
}
}
}
}
else
{ {
//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--;
continue;
}
} }
else else
{ {
//fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is %d for %s\n", soundSource[i].sample->decoder->error, soundSource[i].sample->decoder->filename); //fprintf (stderr, "StreamDecoderTaskFunc(): decoder->error is %d for %s\n", soundSource[i].sample->decoder->error, soundSource[i].sample->decoder->filename);
}
processed--; processed--;
continue; continue;
} }
}
decoded_bytes = SoundDecoder_Decode (soundSource[i].sample->decoder); decoded_bytes = SoundDecoder_Decode (soundSource[i].sample->decoder);
if (soundSource[i].sample->decoder->error == SOUNDDECODER_ERROR) if (soundSource[i].sample->decoder->error == SOUNDDECODER_ERROR)
@@ -279,6 +368,7 @@ StreamDecoderTaskFunc (void *data)
else else
{ {
alSourceQueueBuffers (soundSource[i].handle, 1, &buffer); alSourceQueueBuffers (soundSource[i].handle, 1, &buffer);
last_buffer[i] = buffer;
if (soundSource[i].sbuffer) if (soundSource[i].sbuffer)
{ {
@@ -333,7 +423,7 @@ StreamDecoderTaskFunc (void *data)
{ {
if (do_speech_advancetrack) if (do_speech_advancetrack)
{ {
//fprintf (stderr, "StreamDecoderTaskFunc(): calling advance_track\n"); fprintf (stderr, "StreamDecoderTaskFunc(): calling advance_track\n");
do_speech_advancetrack = AL_FALSE; do_speech_advancetrack = AL_FALSE;
advance_track (0); advance_track (0);
} }
+290 -83
View File
@@ -23,37 +23,47 @@
#include "sound.h" #include "sound.h"
#include "libs/sound/trackplayer.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 #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 void
JumpTrack (int abort) JumpTrack (int abort)
{ {
speech_advancetrack = FALSE; speech_advancetrack = FALSE;
if (track_clip[tcur].sample) if (sound_sample)
{ {
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
StopStream (SPEECH_SOURCE); StopStream (SPEECH_SOURCE);
if (abort)
{
sound_sample->read_chain_ptr = NULL;
sound_sample->decoder = NULL;
}
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
} }
no_voice = 1; no_voice = 1;
do_subtitles ((void *)~0, 0); do_subtitles ((void *)~0, (void *)~0, 1);
if (abort) if (abort)
LockMutex (track_mutex);
tcur = tct; tcur = tct;
UnlockMutex(track_mutex);
} }
void void
@@ -61,20 +71,16 @@ advance_track (int channel_finished)
{ {
if (channel_finished <= 0) if (channel_finished <= 0)
{ {
if (channel_finished == 0) if (sound_sample->decoder)
++tcur;
if (tcur < tct)
{ {
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
PlayStream (track_clip[tcur].sample, SPEECH_SOURCE, AL_FALSE, PlayStream (sound_sample,
speechVolumeScale == 0.0f ? AL_FALSE : AL_TRUE); SPEECH_SOURCE, AL_FALSE,
speechVolumeScale != 0.0f);
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
do_subtitles (~0, 0);
do_subtitles (0, 0);
} }
else if (channel_finished == 0) else if (channel_finished == 0)
{ {
--tcur;
no_voice = 1; no_voice = 1;
} }
} }
@@ -83,7 +89,7 @@ advance_track (int channel_finished)
void void
ResumeTrack () ResumeTrack ()
{ {
if (tcur < tct) if (sound_sample && sound_sample->decoder)
{ {
ALint state; ALint state;
@@ -115,21 +121,25 @@ ResumeTrack ()
COUNT COUNT
PlayingTrack () PlayingTrack ()
{ {
if (tcur < tct) if (sound_sample->decoder)
{ {
if (do_subtitles (track_clip[tcur].text, track_clip[tcur].timestamp) || int last_track, last_page;
(no_voice && ++tcur < tct && do_subtitles (0, 0))) 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); return (tcur + 1);
} }
else if (track_clip[tcur].sample) else if (sound_sample)
{ {
COUNT result; COUNT result;
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); 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); UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
return result; return result;
} }
} }
@@ -140,44 +150,167 @@ PlayingTrack ()
void void
StopTrack () StopTrack ()
{ {
int i;
speech_advancetrack = FALSE; speech_advancetrack = FALSE;
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
StopStream (SPEECH_SOURCE); StopStream (SPEECH_SOURCE);
UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex); UnlockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
while (tct--) for (i = 0; i < tct; i++)
{ {
if (track_clip[tct].text_spliced) HFree (TrackTextArray[i]);
{ TrackTextArray[i] = 0;
track_clip[tct].text_spliced = 0;
HFree (track_clip[tct].text);
track_clip[tct].text = 0;
} }
if (track_clip[tct].sample) if (first_chain)
{ {
TFB_SoundSample *sample = track_clip[tct].sample; destroy_soundchain (first_chain);
track_clip[tct].sample = NULL; first_chain = NULL;
if (sample->decoder) }
if (sound_sample)
{ {
TFB_SoundDecoder *decoder = sample->decoder; DestroyMutex (track_mutex);
ALuint *buffer = sample->buffer; alDeleteBuffers (sound_sample->num_buffers, sound_sample->buffer);
sample->decoder = NULL; HFree (sound_sample->buffer);
sample->buffer = NULL; HFree (sound_sample->buffer_tag);
SoundDecoder_Free (decoder); HFree (sound_sample);
alDeleteBuffers (sample->num_buffers, buffer); sound_sample = NULL;
HFree (buffer);
}
HFree (sample);
}
} }
tct = tcur = 0; tct = tcur = 0;
no_voice = 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 void
SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp) SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp)
{ {
unsigned long startTime;
if (TrackText) if (TrackText)
{ {
if (TrackName == 0) if (TrackName == 0)
@@ -187,50 +320,95 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp)
int slen1, slen2; int slen1, slen2;
UNICODE *oTT; UNICODE *oTT;
oTT = track_clip[tct - 1].text; oTT = TrackTextArray[tct - 1];
slen1 = wstrlen (oTT); slen1 = wstrlen (oTT);
slen2 = wstrlen (TrackText); slen2 = wstrlen (TrackText);
if (track_clip[tct - 1].text_spliced) TrackTextArray[tct - 1] = HRealloc (oTT, slen1 + slen2 + 1);
track_clip[tct - 1].text = HRealloc (oTT, slen1 + slen2 + 1); wstrcpy (&TrackTextArray[tct - 1][slen1], TrackText);
}
}
else else
{ {
track_clip[tct - 1].text = HMalloc (slen1 + slen2 + 1); int num_pages, cur_page;
wstrcpy (track_clip[tct - 1].text, oTT); unsigned long time_stamps[50];
track_clip[tct - 1].text_spliced = 1;
if (no_page_break && tct)
{
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);
} }
wstrcpy (&track_clip[tct - 1].text[slen1], TrackText); else
{
TrackTextArray[tct] = HMalloc (sizeof (UNICODE) * (wstrlen (TrackText) + 1));
wstrcpy (TrackTextArray[tct++], TrackText);
} }
} if (TimeStamp)
else if (tct < MAX_CLIPS) num_pages = GetTimeStamps (TimeStamp, time_stamps);
{ else
track_clip[tct].text = TrackText; num_pages = 0;
track_clip[tct].text_spliced = 0;
track_clip[tct].timestamp = TimeStamp;
fprintf (stderr, "SpliceTrack(): loading %s\n", TrackName); fprintf (stderr, "SpliceTrack(): loading %s\n", TrackName);
track_clip[tct].sample = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample)); startTime = 0;
track_clip[tct].sample->decoder = SoundDecoder_Load (TrackName, 4096); for (cur_page = 0; cur_page <= num_pages; cur_page++)
if (track_clip[tct].sample->decoder)
{ {
fprintf (stderr, " decoder: %s, rate %d format %x\n", if (! sound_sample)
track_clip[tct].sample->decoder->decoder_info, {
track_clip[tct].sample->decoder->frequency, TFB_SoundDecoder *decoder;
track_clip[tct].sample->decoder->format); 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];
track_clip[tct].sample->num_buffers = 8; // fprintf (stderr, "page (%d of %d): %d\n",cur_page, num_pages, startTime);
track_clip[tct].sample->buffer = HMalloc (sizeof (ALuint) * track_clip[tct].sample->num_buffers); if (last_chain->decoder)
alGenBuffers (track_clip[tct].sample->num_buffers, track_clip[tct].sample->buffer); {
//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 else
{ {
fprintf (stderr, "SpliceTrack(): couldn't load %s\n", TrackName); fprintf (stderr, "SpliceTrack(): couldn't load %s\n", TrackName);
HFree (track_clip[tct].sample); alDeleteBuffers (sound_sample->num_buffers, sound_sample->buffer);
track_clip[tct].sample = NULL; destroy_soundchain (first_chain);
first_chain = NULL;
HFree (sound_sample->buffer);
HFree (sound_sample);
sound_sample = NULL;
}
} }
++tct;
} }
} }
} }
@@ -238,7 +416,7 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp)
void void
PauseTrack () PauseTrack ()
{ {
if (tcur < tct && track_clip[tcur].sample) if (sound_sample && sound_sample->decoder)
{ {
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); LockMutex (soundSource[SPEECH_SOURCE].stream_mutex);
PauseStream (SPEECH_SOURCE); PauseStream (SPEECH_SOURCE);
@@ -249,16 +427,45 @@ PauseTrack ()
void void
FastReverse () FastReverse ()
{ {
JumpTrack (0); if (sound_sample)
no_voice = 0; {
tcur = 0; TFB_SoundChain *prev_chain;
ResumeTrack (); 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 void
FastForward () 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; //no_voice = 0;
} }
@@ -416,9 +623,9 @@ int
GetSoundInfo (int *length, int *offset) GetSoundInfo (int *length, int *offset)
{ {
LockMutex (soundSource[SPEECH_SOURCE].stream_mutex); 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); *offset = (int) (GetTimeCounter () - soundSource[SPEECH_SOURCE].start_time);
} }
else else
+7 -7
View File
@@ -27,7 +27,7 @@
#define VOICE_CHANNEL 0 #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; static int tct, tcur, no_voice;
#define MAX_CLIPS 50 #define MAX_CLIPS 50
@@ -48,7 +48,7 @@ JumpTrack (int abort)
Mix_HaltChannel (VOICE_CHANNEL); Mix_HaltChannel (VOICE_CHANNEL);
no_voice = 1; no_voice = 1;
do_subtitles ((void *)~0, 0); do_subtitles ((void *)~0, 0, 0);
if (abort) if (abort)
tcur = tct; tcur = tct;
@@ -64,8 +64,8 @@ advance_track (int channel_finished)
if (tcur < tct) if (tcur < tct)
{ {
Mix_PlayChannel (VOICE_CHANNEL, track_clip[tcur].chunk, 0); Mix_PlayChannel (VOICE_CHANNEL, track_clip[tcur].chunk, 0);
do_subtitles (~0, 0); do_subtitles ((void *)~0, 0, 0);
do_subtitles (0, 0); do_subtitles (0, 0, 0);
} }
else if (channel_finished == VOICE_CHANNEL) else if (channel_finished == VOICE_CHANNEL)
{ {
@@ -96,8 +96,8 @@ PlayingTrack ()
{ {
if (tcur < tct) if (tcur < tct)
{ {
if (do_subtitles (track_clip[tcur].text, track_clip[tcur].timestamp) if (do_subtitles (track_clip[tcur].text, track_clip[tcur].timestamp, 0)
|| (no_voice && ++tcur < tct && do_subtitles (0, 0))) || (no_voice && ++tcur < tct && do_subtitles (0, 0, 0)))
return (tcur + 1); return (tcur + 1);
else if (track_clip[tcur].chunk) else if (track_clip[tcur].chunk)
return (Mix_Playing (VOICE_CHANNEL) ? (COUNT)(tcur + 1) : 0); return (Mix_Playing (VOICE_CHANNEL) ? (COUNT)(tcur + 1) : 0);
@@ -128,7 +128,7 @@ StopTrack ()
} }
tct = tcur = 0; tct = tcur = 0;
no_voice = 0; no_voice = 0;
do_subtitles (0, 0); do_subtitles (0, 0, 0);
} }
void void
+1
View File
@@ -27,6 +27,7 @@ void FastForward();
void FastReverse(); void FastReverse();
void StopTrack(); void StopTrack();
void SpliceTrack(UNICODE *filespec, UNICODE *textspec, UNICODE *TimeStamp); void SpliceTrack(UNICODE *filespec, UNICODE *textspec, UNICODE *TimeStamp);
void SpliceMultiTrack (UNICODE *TrackNames[], UNICODE *TrackText);
int GetSoundData (void *data); int GetSoundData (void *data);
int GetSoundInfo (int *len, int *offs); int GetSoundInfo (int *len, int *offs);