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