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