mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-24 09:14:04 +02:00
Add support for start delays for engine sounds.
This commit is contained in:
@@ -40,6 +40,7 @@ int main(int argc, char** argv)
|
|||||||
ma_engine_sound_set_pan(&engine, &sound, 0.0f);
|
ma_engine_sound_set_pan(&engine, &sound, 0.0f);
|
||||||
ma_engine_sound_set_looping(&engine, &sound, MA_TRUE);
|
ma_engine_sound_set_looping(&engine, &sound, MA_TRUE);
|
||||||
//ma_engine_sound_seek_to_pcm_frame(&engine, &sound, 6000000);
|
//ma_engine_sound_seek_to_pcm_frame(&engine, &sound, 6000000);
|
||||||
|
ma_engine_sound_set_start_delay(&engine, &sound, 1110);
|
||||||
ma_engine_sound_set_fade_in(&engine, &sound, 2000);
|
ma_engine_sound_set_fade_in(&engine, &sound, 2000);
|
||||||
ma_engine_sound_set_fade_out(&engine, &sound, 2000);
|
ma_engine_sound_set_fade_out(&engine, &sound, 2000);
|
||||||
ma_engine_sound_start(&engine, &sound);
|
ma_engine_sound_start(&engine, &sound);
|
||||||
|
|||||||
+38
-4
@@ -888,8 +888,10 @@ struct ma_sound
|
|||||||
ma_sound* pNextSoundInGroup;
|
ma_sound* pNextSoundInGroup;
|
||||||
ma_engine_effect effect; /* The effect containing all of the information for spatialization, pitching, etc. */
|
ma_engine_effect effect; /* The effect containing all of the information for spatialization, pitching, etc. */
|
||||||
float volume;
|
float volume;
|
||||||
|
ma_uint64 runningTimeInEngineFrames; /* The amount of time the sound has been running in engine frames, including start delays. */
|
||||||
ma_uint64 seekTarget; /* The PCM frame index to seek to in the mixing thread. Set to (~(ma_uint64)0) to not perform any seeking. */
|
ma_uint64 seekTarget; /* The PCM frame index to seek to in the mixing thread. Set to (~(ma_uint64)0) to not perform any seeking. */
|
||||||
ma_uint64 fadeOutTimeInFrames;
|
ma_uint64 fadeOutTimeInFrames; /* In the sound's sample rate. */
|
||||||
|
ma_uint64 startDelayInEngineFrames; /* In the engine's sample rate. */
|
||||||
ma_bool32 isPlaying; /* False by default. Sounds need to be explicitly started with ma_engine_sound_start() and stopped with ma_engine_sound_stop(). */
|
ma_bool32 isPlaying; /* False by default. Sounds need to be explicitly started with ma_engine_sound_start() and stopped with ma_engine_sound_stop(). */
|
||||||
ma_bool32 isFadingOut; /* Set to true to indicate that a fade out before stopping is in effect. */
|
ma_bool32 isFadingOut; /* Set to true to indicate that a fade out before stopping is in effect. */
|
||||||
ma_bool32 isSettingFadeOut; /* Whether or not a new fade out needs to be set. Fade outs are set on the mixer thread because it depends on the length of the sound which may not be known immediately. */
|
ma_bool32 isSettingFadeOut; /* Whether or not a new fade out needs to be set. Fade outs are set on the mixer thread because it depends on the length of the sound which may not be known immediately. */
|
||||||
@@ -907,7 +909,7 @@ struct ma_sound_group
|
|||||||
ma_sound_group* pFirstChild;
|
ma_sound_group* pFirstChild;
|
||||||
ma_sound_group* pPrevSibling;
|
ma_sound_group* pPrevSibling;
|
||||||
ma_sound_group* pNextSibling;
|
ma_sound_group* pNextSibling;
|
||||||
ma_sound* pFirstSoundInGroup; /* Marked as volatile because we need to be very explicit with when we make copies of this and we can't have the compiler optimize it out. */
|
ma_sound* pFirstSoundInGroup;
|
||||||
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_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. */
|
||||||
@@ -977,6 +979,7 @@ MA_API ma_result ma_engine_sound_set_effect(ma_engine* pEngine, ma_sound* pSound
|
|||||||
MA_API ma_result ma_engine_sound_set_looping(ma_engine* pEngine, ma_sound* pSound, ma_bool32 isLooping);
|
MA_API ma_result ma_engine_sound_set_looping(ma_engine* pEngine, ma_sound* pSound, ma_bool32 isLooping);
|
||||||
MA_API ma_result ma_engine_sound_set_fade_in(ma_engine* pEngine, ma_sound* pSound, ma_uint64 fadeTimeInMilliseconds);
|
MA_API ma_result ma_engine_sound_set_fade_in(ma_engine* pEngine, ma_sound* pSound, ma_uint64 fadeTimeInMilliseconds);
|
||||||
MA_API ma_result ma_engine_sound_set_fade_out(ma_engine* pEngine, ma_sound* pSound, ma_uint64 fadeTimeInMilliseconds);
|
MA_API ma_result ma_engine_sound_set_fade_out(ma_engine* pEngine, ma_sound* pSound, ma_uint64 fadeTimeInMilliseconds);
|
||||||
|
MA_API ma_result ma_engine_sound_set_start_delay(ma_engine* pEngine, ma_sound* pSound, ma_uint64 delayInMilliseconds);
|
||||||
MA_API ma_bool32 ma_engine_sound_at_end(ma_engine* pEngine, const ma_sound* pSound);
|
MA_API ma_bool32 ma_engine_sound_at_end(ma_engine* pEngine, const ma_sound* pSound);
|
||||||
MA_API ma_result ma_engine_sound_seek_to_pcm_frame(ma_engine* pEngine, ma_sound* pSound, ma_uint64 frameIndex); /* Just a wrapper around ma_data_source_seek_to_pcm_frame(). */
|
MA_API ma_result ma_engine_sound_seek_to_pcm_frame(ma_engine* pEngine, ma_sound* pSound, ma_uint64 frameIndex); /* Just a wrapper around ma_data_source_seek_to_pcm_frame(). */
|
||||||
MA_API ma_result ma_engine_sound_get_data_format(ma_engine* pEngine, ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate);
|
MA_API ma_result ma_engine_sound_get_data_format(ma_engine* pEngine, ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate);
|
||||||
@@ -5252,15 +5255,25 @@ static void ma_engine_mix_sound(ma_engine* pEngine, ma_sound_group* pGroup, ma_s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If the sound is being delayed we don't want to mix anything, nor do we want to advance time forward from the perspective of the data source. */
|
||||||
|
if ((pSound->runningTimeInEngineFrames + frameCount) > pSound->startDelayInEngineFrames) {
|
||||||
|
/* 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. */
|
||||||
|
ma_uint64 offsetInFrames = 0;
|
||||||
|
if (pSound->startDelayInEngineFrames > pSound->runningTimeInEngineFrames) {
|
||||||
|
offsetInFrames = pSound->startDelayInEngineFrames - pSound->runningTimeInEngineFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
MA_ASSERT(offsetInFrames < frameCount);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If the sound is muted we still need to move time forward, but we can save time by not mixing as it won't actually affect anything. If there's an
|
If the sound is muted we still need to move time forward, but we can save time by not mixing as it won't actually affect anything. If there's an
|
||||||
effect we need to make sure we run it through the mixer because it may require us to update internal state for things like echo effects.
|
effect we need to make sure we run it through the mixer because it may require us to update internal state for things like echo effects.
|
||||||
*/
|
*/
|
||||||
if (pSound->volume > 0 || ma_engine_effect_is_passthrough(&pSound->effect) == MA_FALSE) {
|
if (pSound->volume > 0 || ma_engine_effect_is_passthrough(&pSound->effect) == MA_FALSE) {
|
||||||
result = ma_mixer_mix_data_source(&pGroup->mixer, pSound->pDataSource, frameCount, &framesProcessed, pSound->volume, &pSound->effect, pSound->isLooping);
|
result = ma_mixer_mix_data_source(&pGroup->mixer, pSound->pDataSource, offsetInFrames, (frameCount - offsetInFrames), &framesProcessed, pSound->volume, &pSound->effect, pSound->isLooping);
|
||||||
} else {
|
} else {
|
||||||
/* The sound is muted. We want to move time forward, but it be made faster by simply seeking instead of reading. We also want to bypass mixing completely. */
|
/* The sound is muted. We want to move time forward, but it be made faster by simply seeking instead of reading. We also want to bypass mixing completely. */
|
||||||
result = ma_data_source_seek_pcm_frames(pSound->pDataSource, frameCount, &framesProcessed, pSound->isLooping);
|
result = ma_data_source_seek_pcm_frames(pSound->pDataSource, (frameCount - offsetInFrames), &framesProcessed, pSound->isLooping);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If fading out we need to stop the sound if it's done fading. */
|
/* If fading out we need to stop the sound if it's done fading. */
|
||||||
@@ -5287,6 +5300,12 @@ static void ma_engine_mix_sound(ma_engine* pEngine, ma_sound_group* pGroup, ma_s
|
|||||||
ma_engine_sound_stop_internal(pEngine, pSound);
|
ma_engine_sound_stop_internal(pEngine, pSound);
|
||||||
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;
|
||||||
|
} else {
|
||||||
|
/* The sound hasn't started yet. Just keep advancing time forward, but leave the data source alone. */
|
||||||
|
pSound->runningTimeInEngineFrames += frameCount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c89atomic_exchange_32(&pSound->isMixing, MA_FALSE);
|
c89atomic_exchange_32(&pSound->isMixing, MA_FALSE);
|
||||||
@@ -6035,6 +6054,21 @@ MA_API ma_result ma_engine_sound_set_fade_out(ma_engine* pEngine, ma_sound* pSou
|
|||||||
return MA_SUCCESS;
|
return MA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MA_API ma_result ma_engine_sound_set_start_delay(ma_engine* pEngine, ma_sound* pSound, ma_uint64 delayInMilliseconds)
|
||||||
|
{
|
||||||
|
if (pEngine == NULL || pSound == NULL) {
|
||||||
|
return MA_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
It's important that the delay be timed based on the engine's sample rate and not the rate of the sound. The reason is that no processing will be happening
|
||||||
|
by the sound before playback has actually begun and we won't have accurate frame counters due to resampling.
|
||||||
|
*/
|
||||||
|
pSound->startDelayInEngineFrames = (pEngine->sampleRate * delayInMilliseconds) / 1000;
|
||||||
|
|
||||||
|
return MA_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
MA_API ma_bool32 ma_engine_sound_at_end(ma_engine* pEngine, const ma_sound* pSound)
|
MA_API ma_bool32 ma_engine_sound_at_end(ma_engine* pEngine, const ma_sound* pSound)
|
||||||
{
|
{
|
||||||
if (pEngine == NULL || pSound == NULL) {
|
if (pEngine == NULL || pSound == NULL) {
|
||||||
|
|||||||
Reference in New Issue
Block a user