aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2022-11-03 02:17:54 -0700
committerChris Robinson <[email protected]>2022-11-03 02:17:54 -0700
commitd8361bdd6fa807a4200e18e8ef7ffd13ab849b74 (patch)
tree1df40b4006ade3e715c84701916fab23af65d612 /core
parentb73e0ecbc55cb09788d056131aaec0ed27f6046a (diff)
Add the ability to start a voice at a particular time
Diffstat (limited to 'core')
-rw-r--r--core/voice.cpp44
-rw-r--r--core/voice.h6
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);