Commit 3de7f5ca authored by David Reid's avatar David Reid

Add support for start delays to sound groups.

parent 56dbcb52
...@@ -38,6 +38,7 @@ int main(int argc, char** argv) ...@@ -38,6 +38,7 @@ int main(int argc, char** argv)
//ma_engine_sound_group_set_pan(&engine, NULL, -1); //ma_engine_sound_group_set_pan(&engine, NULL, -1);
ma_engine_sound_group_set_pitch(&engine, NULL, 1.0f); ma_engine_sound_group_set_pitch(&engine, NULL, 1.0f);
ma_engine_sound_group_set_fade_in(&engine, NULL, 4000); ma_engine_sound_group_set_fade_in(&engine, NULL, 4000);
ma_engine_sound_group_set_start_delay(&engine, NULL, 2000);
/*ma_engine_sound_set_volume(&engine, &sound, 0.25f);*/ /*ma_engine_sound_set_volume(&engine, &sound, 0.25f);*/
//ma_engine_sound_set_pitch(&engine, &sound, 2.0f); //ma_engine_sound_set_pitch(&engine, &sound, 2.0f);
......
...@@ -910,10 +910,12 @@ struct ma_sound_group ...@@ -910,10 +910,12 @@ struct ma_sound_group
ma_sound_group* pPrevSibling; ma_sound_group* pPrevSibling;
ma_sound_group* pNextSibling; ma_sound_group* pNextSibling;
ma_sound* pFirstSoundInGroup; ma_sound* pFirstSoundInGroup;
ma_engine_effect effect; /* The main effect for panning, etc. This is set on the mixer at initialisation time. */ ma_engine_effect effect; /* The main effect for panning, etc. This is set on the mixer at initialisation time. */
ma_mixer mixer; ma_mixer mixer;
ma_mutex lock; /* Only used by ma_engine_sound_init_*() and ma_engine_sound_uninit(). Not used in the mixing thread. */ ma_mutex lock; /* Only used by ma_engine_sound_init_*() and ma_engine_sound_uninit(). Not used in the mixing thread. */
ma_bool32 isPlaying; /* True by default. Sound groups can be stopped with ma_engine_sound_stop() and resumed with ma_engine_sound_start(). Also affects children. */ ma_uint64 runningTimeInEngineFrames; /* The amount of time the sound has been running in engine frames, including start delays. */
ma_uint64 startDelayInEngineFrames;
ma_bool32 isPlaying; /* True by default. Sound groups can be stopped with ma_engine_sound_stop() and resumed with ma_engine_sound_start(). Also affects children. */
}; };
struct ma_listener struct ma_listener
...@@ -998,6 +1000,7 @@ MA_API ma_result ma_engine_sound_group_set_effect(ma_engine* pEngine, ma_sound_g ...@@ -998,6 +1000,7 @@ MA_API ma_result ma_engine_sound_group_set_effect(ma_engine* pEngine, ma_sound_g
MA_API ma_result ma_engine_sound_group_set_pan(ma_engine* pEngine, ma_sound_group* pGroup, float pan); MA_API ma_result ma_engine_sound_group_set_pan(ma_engine* pEngine, ma_sound_group* pGroup, float pan);
MA_API ma_result ma_engine_sound_group_set_pitch(ma_engine* pEngine, ma_sound_group* pGroup, float pitch); MA_API ma_result ma_engine_sound_group_set_pitch(ma_engine* pEngine, ma_sound_group* pGroup, float pitch);
MA_API ma_result ma_engine_sound_group_set_fade_in(ma_engine* pEngine, ma_sound_group* pGroup, ma_uint64 fadeTimeInMilliseconds); MA_API ma_result ma_engine_sound_group_set_fade_in(ma_engine* pEngine, ma_sound_group* pGroup, ma_uint64 fadeTimeInMilliseconds);
MA_API ma_result ma_engine_sound_group_set_start_delay(ma_engine* pEngine, ma_sound_group* pGroup, ma_uint64 delayInMilliseconds);
MA_API ma_result ma_engine_listener_set_position(ma_engine* pEngine, ma_vec3 position); MA_API ma_result ma_engine_listener_set_position(ma_engine* pEngine, ma_vec3 position);
MA_API ma_result ma_engine_listener_set_rotation(ma_engine* pEngine, ma_quat rotation); MA_API ma_result ma_engine_listener_set_rotation(ma_engine* pEngine, ma_quat rotation);
...@@ -5336,7 +5339,7 @@ static void ma_engine_mix_sound(ma_engine* pEngine, ma_sound_group* pGroup, ma_s ...@@ -5336,7 +5339,7 @@ static void ma_engine_mix_sound(ma_engine* pEngine, ma_sound_group* pGroup, ma_s
c89atomic_exchange_32(&pSound->atEnd, MA_TRUE); /* This will be set to false in ma_engine_sound_start(). */ c89atomic_exchange_32(&pSound->atEnd, MA_TRUE); /* This will be set to false in ma_engine_sound_start(). */
} }
pSound->runningTimeInEngineFrames += framesProcessed; pSound->runningTimeInEngineFrames += offsetInFrames + framesProcessed;
} else { } else {
/* The sound hasn't started yet. Just keep advancing time forward, but leave the data source alone. */ /* The sound hasn't started yet. Just keep advancing time forward, but leave the data source alone. */
pSound->runningTimeInEngineFrames += frameCount; pSound->runningTimeInEngineFrames += frameCount;
...@@ -5372,37 +5375,53 @@ static void ma_engine_mix_sound_group(ma_engine* pEngine, ma_sound_group* pGroup ...@@ -5372,37 +5375,53 @@ static void ma_engine_mix_sound_group(ma_engine* pEngine, ma_sound_group* pGroup
frameCountOut = frameCount; frameCountOut = frameCount;
frameCountIn = frameCount; frameCountIn = frameCount;
/* We need to loop here to ensure we fill every frame. This won't necessarily be able to be done in one iteration due to resampling within the effect. */ /* If the group is being delayed we don't want to mix anything. */
totalFramesProcessed = 0; if ((pGroup->runningTimeInEngineFrames + frameCount) > pGroup->startDelayInEngineFrames) {
while (totalFramesProcessed < frameCount) { /* We're not delayed so we can mix or seek. In order to get frame-exact playback timing we need to start mixing from an offset. */
frameCountOut = frameCount - totalFramesProcessed; ma_uint64 offsetInFrames = 0;
frameCountIn = frameCount - totalFramesProcessed; if (pGroup->startDelayInEngineFrames > pGroup->runningTimeInEngineFrames) {
offsetInFrames = pGroup->startDelayInEngineFrames - pGroup->runningTimeInEngineFrames;
/* Before can mix the group we need to mix it's children. */
result = ma_mixer_begin(&pGroup->mixer, pParentMixer, &frameCountOut, &frameCountIn);
if (result != MA_SUCCESS) {
return;
} }
MA_ASSERT(frameCountIn < 0xFFFFFFFF); MA_ASSERT(offsetInFrames < frameCount);
/* Child groups need to be mixed based on the parent's input frame count. */ /* We need to loop here to ensure we fill every frame. This won't necessarily be able to be done in one iteration due to resampling within the effect. */
for (pNextChildGroup = pGroup->pFirstChild; pNextChildGroup != NULL; pNextChildGroup = pNextChildGroup->pNextSibling) { totalFramesProcessed = 0;
ma_engine_mix_sound_group(pEngine, pNextChildGroup, NULL, (ma_uint32)frameCountIn); /* Safe cast. */ while (totalFramesProcessed < (frameCount - offsetInFrames)) {
} frameCountOut = frameCount - offsetInFrames - totalFramesProcessed;
frameCountIn = frameCount - offsetInFrames - totalFramesProcessed;
/* Sounds in the group can now be mixed. This is where the real mixing work is done. */ /* Before can mix the group we need to mix it's children. */
for (pNextSound = pGroup->pFirstSoundInGroup; pNextSound != NULL; pNextSound = pNextSound->pNextSoundInGroup) { result = ma_mixer_begin(&pGroup->mixer, pParentMixer, &frameCountOut, &frameCountIn);
ma_engine_mix_sound(pEngine, pGroup, pNextSound, (ma_uint32)frameCountIn); /* Safe cast. */ if (result != MA_SUCCESS) {
} break;
}
/* Now mix into the parent. */ MA_ASSERT(frameCountIn < 0xFFFFFFFF);
result = ma_mixer_end(&pGroup->mixer, pParentMixer, pFramesOut, totalFramesProcessed);
if (result != MA_SUCCESS) { /* Child groups need to be mixed based on the parent's input frame count. */
return; for (pNextChildGroup = pGroup->pFirstChild; pNextChildGroup != NULL; pNextChildGroup = pNextChildGroup->pNextSibling) {
ma_engine_mix_sound_group(pEngine, pNextChildGroup, NULL, (ma_uint32)frameCountIn); /* Safe cast. */
}
/* Sounds in the group can now be mixed. This is where the real mixing work is done. */
for (pNextSound = pGroup->pFirstSoundInGroup; pNextSound != NULL; pNextSound = pNextSound->pNextSoundInGroup) {
ma_engine_mix_sound(pEngine, pGroup, pNextSound, (ma_uint32)frameCountIn); /* Safe cast. */
}
/* Now mix into the parent. */
result = ma_mixer_end(&pGroup->mixer, pParentMixer, pFramesOut, offsetInFrames + totalFramesProcessed);
if (result != MA_SUCCESS) {
break;
}
totalFramesProcessed += frameCountOut;
} }
totalFramesProcessed += frameCountOut; pGroup->runningTimeInEngineFrames += offsetInFrames + totalFramesProcessed;
} else {
/* The group hasn't started yet. Just keep advancing time forward, but leave the data source alone. */
pGroup->runningTimeInEngineFrames += frameCount;
} }
} }
...@@ -6568,6 +6587,21 @@ MA_API ma_result ma_engine_sound_group_set_fade_in(ma_engine* pEngine, ma_sound_ ...@@ -6568,6 +6587,21 @@ MA_API ma_result ma_engine_sound_group_set_fade_in(ma_engine* pEngine, ma_sound_
return ma_dual_fader_set_fade(&pGroup->effect.fader, 0, 0, 1, pGroup->effect.fader.timeInFramesCur, pGroup->effect.fader.timeInFramesCur + (fadeTimeInMilliseconds * pGroup->effect.fader.config.sampleRate) / 1000); return ma_dual_fader_set_fade(&pGroup->effect.fader, 0, 0, 1, pGroup->effect.fader.timeInFramesCur, pGroup->effect.fader.timeInFramesCur + (fadeTimeInMilliseconds * pGroup->effect.fader.config.sampleRate) / 1000);
} }
MA_API ma_result ma_engine_sound_group_set_start_delay(ma_engine* pEngine, ma_sound_group* pGroup, ma_uint64 delayInMilliseconds)
{
if (pEngine == NULL) {
return MA_INVALID_ARGS;
}
if (pGroup == NULL) {
pGroup = &pEngine->masterSoundGroup;
}
pGroup->startDelayInEngineFrames = (pEngine->sampleRate * delayInMilliseconds) / 1000;
return MA_SUCCESS;
}
MA_API ma_result ma_engine_listener_set_position(ma_engine* pEngine, ma_vec3 position) MA_API ma_result ma_engine_listener_set_position(ma_engine* pEngine, ma_vec3 position)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment