diff options
author | Chris Robinson <[email protected]> | 2022-11-03 02:17:54 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2022-11-03 02:17:54 -0700 |
commit | d8361bdd6fa807a4200e18e8ef7ffd13ab849b74 (patch) | |
tree | 1df40b4006ade3e715c84701916fab23af65d612 /core | |
parent | b73e0ecbc55cb09788d056131aaec0ed27f6046a (diff) |
Add the ability to start a voice at a particular time
Diffstat (limited to 'core')
-rw-r--r-- | core/voice.cpp | 44 | ||||
-rw-r--r-- | core/voice.h | 6 |
2 files changed, 42 insertions, 8 deletions
diff --git a/core/voice.cpp b/core/voice.cpp index 349c3430..bf13d563 100644 --- a/core/voice.cpp +++ b/core/voice.cpp @@ -60,6 +60,7 @@ Resampler ResamplerDefault{Resampler::Linear}; namespace { using uint = unsigned int; +using namespace std::chrono; using HrtfMixerFunc = void(*)(const float *InSamples, float2 *AccumSamples, const uint IrSize, const MixHrtfFilter *hrtfparams, const size_t BufferSize); @@ -456,12 +457,16 @@ void DoNfcMix(const al::span<const float> samples, FloatBufferLine *OutBuffer, D } // namespace -void Voice::mix(const State vstate, ContextBase *Context, const uint SamplesToDo) +void Voice::mix(const State vstate, ContextBase *Context, const nanoseconds deviceTime, + const uint SamplesToDo) { static constexpr std::array<float,MAX_OUTPUT_CHANNELS> SilentTarget{}; ASSUME(SamplesToDo > 0); + DeviceBase *Device{Context->mDevice}; + const uint NumSends{Device->NumAuxSends}; + /* Get voice info */ int DataPosInt{mPosition.load(std::memory_order_relaxed)}; uint DataPosFrac{mPositionFrac.load(std::memory_order_relaxed)}; @@ -478,13 +483,37 @@ void Voice::mix(const State vstate, ContextBase *Context, const uint SamplesToDo return; } - DeviceBase *Device{Context->mDevice}; - const uint NumSends{Device->NumAuxSends}; + uint Counter{mFlags.test(VoiceIsFading) ? SamplesToDo : 0}; + uint OutPos{0u}; - ResamplerFunc Resample{(increment == MixerFracOne && DataPosFrac == 0) ? - Resample_<CopyTag,CTag> : mResampler}; + /* Check if we're doing a delayed start, and we start in this update. */ + if(mStartTime > deviceTime) + { + /* If the start time is too far ahead, don't bother. */ + auto diff = mStartTime - deviceTime; + if(diff >= seconds{1}) + return; + + /* Get the number of samples ahead of the current time that output + * should start at. Skip this update if it's beyond the output sample + * count. + */ + seconds::rep sampleOffset{duration_cast<seconds>(diff * Device->Frequency).count()}; + if(sampleOffset >= SamplesToDo) + return; + + /* Round the start position down to a multiple of 4, which some mixers + * want. This makes the start time accurate to 4 samples. This could be + * made sample-accurate by forcing non-SIMD functions on the first run. + * + * Also ensure any fading completes within this update (though don't go + * less than 64 samples, or the fade could be too fast). + */ + OutPos = static_cast<uint>(sampleOffset) & ~3u; + if(Counter > 0) + Counter = maxu(Counter-OutPos, 64); + } - uint Counter{mFlags.test(VoiceIsFading) ? SamplesToDo : 0}; if(!Counter) { /* No fading, just overwrite the old/current params. */ @@ -517,9 +546,10 @@ void Voice::mix(const State vstate, ContextBase *Context, const uint SamplesToDo std::transform(Device->mSampleData.end() - mChans.size(), Device->mSampleData.end(), MixingSamples.begin(), offset_bufferline); + const ResamplerFunc Resample{(increment == MixerFracOne && DataPosFrac == 0) ? + Resample_<CopyTag,CTag> : mResampler}; const uint PostPadding{MaxResamplerEdge + mDecoderPadding}; uint buffers_done{0u}; - uint OutPos{0u}; do { /* Figure out how many buffer samples will be needed */ uint DstBufferSize{SamplesToDo - OutPos}; diff --git a/core/voice.h b/core/voice.h index cf558341..df0c8c9e 100644 --- a/core/voice.h +++ b/core/voice.h @@ -4,6 +4,7 @@ #include <array> #include <atomic> #include <bitset> +#include <chrono> #include <memory> #include <stddef.h> #include <string> @@ -209,6 +210,8 @@ struct Voice { */ std::atomic<VoiceBufferItem*> mLoopBuffer; + std::chrono::nanoseconds mStartTime{}; + /* Properties for the attached buffer(s). */ FmtChannels mFmtChannels; FmtType mFmtType; @@ -262,7 +265,8 @@ struct Voice { Voice(const Voice&) = delete; Voice& operator=(const Voice&) = delete; - void mix(const State vstate, ContextBase *Context, const uint SamplesToDo); + void mix(const State vstate, ContextBase *Context, const std::chrono::nanoseconds deviceTime, + const uint SamplesToDo); void prepare(DeviceBase *device); |