mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-16 01:02:03 +00:00
- Sounds that define a loop no longer play looped by default. They must be started with
CHAN_LOOP so that the higher level sound code knows they loop and can handle them accordingly. - Added support for a LOOP_BIDI tag. Set it to "1", "On", "True", or "Yes" to use a bidirectional loop. This only works with sounds and not music, because music is streamed so does not support them. - Extended custom loop support to work with samples as well as music. SVN r2434 (trunk)
This commit is contained in:
parent
99a2014ead
commit
c29639426f
1 changed files with 105 additions and 58 deletions
|
@ -1456,6 +1456,88 @@ const char *GetTagData(FMOD::Sound *sound, const char *tag_name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// SetCustomLoopPts
|
||||
//
|
||||
// Sets up custom sound loops by checking for these tags:
|
||||
// LOOP_START
|
||||
// LOOP_END
|
||||
// LOOP_BIDI
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void SetCustomLoopPts(FMOD::Sound *sound)
|
||||
{
|
||||
#if 0
|
||||
FMOD_TAG tag;
|
||||
int numtags;
|
||||
if (FMOD_OK == stream->getNumTags(&numtags, NULL))
|
||||
{
|
||||
for (int i = 0; i < numtags; ++i)
|
||||
{
|
||||
if (FMOD_OK == sound->getTag(NULL, i, &tag))
|
||||
{
|
||||
Printf("Tag %2d. %d %s = %s\n", i, tag.datatype, tag.name, tag.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
const char *tag_data;
|
||||
unsigned int looppt[2];
|
||||
bool looppt_as_samples[2], have_looppt[2] = { false };
|
||||
static const char *const loop_tags[2] = { "LOOP_START", "LOOP_END" };
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
if (NULL != (tag_data = GetTagData(sound, loop_tags[i])))
|
||||
{
|
||||
if (S_ParseTimeTag(tag_data, &looppt_as_samples[i], &looppt[i]))
|
||||
{
|
||||
have_looppt[i] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Invalid %s tag: '%s'\n", loop_tags[i], tag_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (have_looppt[0] && !have_looppt[1])
|
||||
{ // Have a start tag, but not an end tag: End at the end of the song.
|
||||
have_looppt[1] = (FMOD_OK == sound->getLength(&looppt[1], FMOD_TIMEUNIT_PCM));
|
||||
looppt_as_samples[1] = true;
|
||||
}
|
||||
else if (!have_looppt[0] && have_looppt[1])
|
||||
{ // Have an end tag, but no start tag: Start at beginning of the song.
|
||||
looppt[0] = 0;
|
||||
looppt_as_samples[0] = true;
|
||||
have_looppt[0] = true;
|
||||
}
|
||||
if (have_looppt[0] && have_looppt[1])
|
||||
{ // Have both loop points: Try to set the loop.
|
||||
FMOD_RESULT res = sound->setLoopPoints(
|
||||
looppt[0], looppt_as_samples[0] ? FMOD_TIMEUNIT_PCM : FMOD_TIMEUNIT_MS,
|
||||
looppt[1] - 1, looppt_as_samples[1] ? FMOD_TIMEUNIT_PCM : FMOD_TIMEUNIT_MS);
|
||||
if (res != FMOD_OK)
|
||||
{
|
||||
Printf("Setting custom loop points failed. Error %d\n", res);
|
||||
}
|
||||
}
|
||||
// Check for a bi-directional loop.
|
||||
if (NULL != (tag_data = GetTagData(sound, "LOOP_BIDI")) &&
|
||||
(stricmp(tag_data, "on") == 0 ||
|
||||
stricmp(tag_data, "true") == 0 ||
|
||||
stricmp(tag_data, "yes") == 0 ||
|
||||
stricmp(tag_data, "1") == 0))
|
||||
{
|
||||
FMOD_MODE mode;
|
||||
if (FMOD_OK == (sound->getMode(&mode)))
|
||||
{
|
||||
sound->setMode(mode & ~(FMOD_LOOP_OFF | FMOD_LOOP_NORMAL) | FMOD_LOOP_BIDI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMODSoundRenderer :: OpenStream
|
||||
|
@ -1517,61 +1599,7 @@ SoundStream *FMODSoundRenderer::OpenStream(const char *filename_or_data, int fla
|
|||
}
|
||||
if (result == FMOD_OK)
|
||||
{
|
||||
// Handle custom loop starts by checking for a "loop_start" tag.
|
||||
#if 0
|
||||
FMOD_TAG tag;
|
||||
int numtags;
|
||||
if (FMOD_OK == stream->getNumTags(&numtags, NULL))
|
||||
{
|
||||
for (int i = 0; i < numtags; ++i)
|
||||
{
|
||||
if (FMOD_OK == stream->getTag(NULL, i, &tag))
|
||||
{
|
||||
Printf("Tag %2d. %d %s = %s\n", i, tag.datatype, tag.name, tag.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
const char *tag_data;
|
||||
unsigned int looppt[2];
|
||||
bool looppt_as_samples[2], have_looppt[2] = { false };
|
||||
static const char *const loop_tags[2] = { "LOOP_START", "LOOP_END" };
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
if (NULL != (tag_data = GetTagData(stream, loop_tags[i])))
|
||||
{
|
||||
if (S_ParseTimeTag(tag_data, &looppt_as_samples[i], &looppt[i]))
|
||||
{
|
||||
have_looppt[i] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Invalid %s tag: '%s'\n", loop_tags[i], tag_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (have_looppt[0] && !have_looppt[1])
|
||||
{ // Have a start tag, but not an end tag: End at the end of the song.
|
||||
have_looppt[1] = (FMOD_OK == stream->getLength(&looppt[1], FMOD_TIMEUNIT_PCM));
|
||||
looppt_as_samples[1] = true;
|
||||
}
|
||||
else if (!have_looppt[0] && have_looppt[1])
|
||||
{ // Have an end tag, but no start tag: Start at beginning of the song.
|
||||
looppt[0] = 0;
|
||||
looppt_as_samples[0] = true;
|
||||
have_looppt[0] = true;
|
||||
}
|
||||
if (have_looppt[0] && have_looppt[1])
|
||||
{ // Have both loop points: Try to set the loop.
|
||||
FMOD_RESULT res = stream->setLoopPoints(
|
||||
looppt[0], looppt_as_samples[0] ? FMOD_TIMEUNIT_PCM : FMOD_TIMEUNIT_MS,
|
||||
looppt[1] - 1, looppt_as_samples[1] ? FMOD_TIMEUNIT_PCM : FMOD_TIMEUNIT_MS);
|
||||
if (res != FMOD_OK)
|
||||
{
|
||||
Printf("Setting custom song loop points for song failed. Error %d\n", res);
|
||||
}
|
||||
}
|
||||
SetCustomLoopPts(stream);
|
||||
return new FMODStreamCapsule(stream, this, url ? filename_or_data : NULL);
|
||||
}
|
||||
return NULL;
|
||||
|
@ -1613,7 +1641,15 @@ FISoundChannel *FMODSoundRenderer::StartSound(SoundHandle sfx, float vol, int pi
|
|||
mode = (mode & ~FMOD_3D) | FMOD_2D;
|
||||
if (flags & SNDF_LOOP)
|
||||
{
|
||||
mode = (mode & ~FMOD_LOOP_OFF) | FMOD_LOOP_NORMAL;
|
||||
mode &= ~FMOD_LOOP_OFF;
|
||||
if (!(mode & (FMOD_LOOP_NORMAL | FMOD_LOOP_BIDI)))
|
||||
{
|
||||
mode |= FMOD_LOOP_NORMAL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mode |= FMOD_LOOP_OFF;
|
||||
}
|
||||
chan->setMode(mode);
|
||||
chan->setChannelGroup((flags & SNDF_NOPAUSE) ? SfxGroup : PausableSfx);
|
||||
|
@ -1713,7 +1749,16 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener *
|
|||
}
|
||||
if (flags & SNDF_LOOP)
|
||||
{
|
||||
mode = (mode & ~FMOD_LOOP_OFF) | FMOD_LOOP_NORMAL;
|
||||
mode &= ~FMOD_LOOP_OFF;
|
||||
if (!(mode & (FMOD_LOOP_NORMAL | FMOD_LOOP_BIDI)))
|
||||
{
|
||||
mode |= FMOD_LOOP_NORMAL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// FMOD_LOOP_OFF overrides FMOD_LOOP_NORMAL and FMOD_LOOP_BIDI
|
||||
mode |= FMOD_LOOP_OFF;
|
||||
}
|
||||
mode = SetChanHeadSettings(listener, chan, pos, !!(flags & SNDF_AREA), mode);
|
||||
chan->setMode(mode);
|
||||
|
@ -1810,13 +1855,14 @@ bool FMODSoundRenderer::HandleChannelDelay(FMOD::Channel *chan, FISoundChannel *
|
|||
// Clamp the position of looping sounds to be within the sound.
|
||||
// If we try to start it several minutes past its normal end,
|
||||
// FMOD doesn't like that.
|
||||
// FIXME: Clamp this right for loops that don't cover the whole sound.
|
||||
if (flags & SNDF_LOOP)
|
||||
{
|
||||
FMOD::Sound *sound;
|
||||
if (FMOD_OK == chan->getCurrentSound(&sound))
|
||||
{
|
||||
unsigned int len;
|
||||
if (FMOD_OK == sound->getLength(&len, FMOD_TIMEUNIT_MS) && len)
|
||||
if (FMOD_OK == sound->getLength(&len, FMOD_TIMEUNIT_MS) && len != 0)
|
||||
{
|
||||
difftime %= len;
|
||||
}
|
||||
|
@ -2358,6 +2404,7 @@ SoundHandle FMODSoundRenderer::LoadSound(BYTE *sfxdata, int length)
|
|||
DPrintf("Failed to allocate sample: Error %d\n", result);
|
||||
return retval;
|
||||
}
|
||||
SetCustomLoopPts(sample);
|
||||
retval.data = sample;
|
||||
return retval;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue