Audacity 3.2.0
MixerSource.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 @file MixerSource.cpp
6
7 Dominic Mazzoni
8 Markus Meyer
9 Vaughan Johnson
10
11 Paul Licameli split from Mix.cpp
12
13**********************************************************************/
14#include "MixerSource.h"
15
16#include "AudioGraphBuffers.h"
17#include "Envelope.h"
18#include "Resample.h"
19#include "WideSampleSequence.h"
20#include "float_cast.h"
21
22namespace {
23template<typename T, typename F> std::vector<T>
24initVector(size_t dim1, const F &f)
25{
26 std::vector<T> result( dim1 );
27 for (auto &row : result)
28 f(row);
29 return result;
30}
31
32template<typename T> std::vector<std::vector<T>>
33initVector(size_t dim1, size_t dim2)
34{
35 return initVector<std::vector<T>>(dim1,
36 [dim2](auto &row){ row.resize(dim2); });
37}
38}
39
41{
42 for (size_t j = 0; j < mnChannels; ++j)
43 mResample[j] = std::make_unique<Resample>(
46}
47
48namespace {
49 //Note: The meaning of this function has changed (December 2012)
50 //Previously this function did something that was close to the opposite (but not entirely accurate).
61double ComputeWarpFactor(const Envelope &env, double t0, double t1)
62{
63 return env.AverageOfInverse(t0, t1);
64}
65
66}
67
69 unsigned nChannels, const size_t maxOut, float *floatBuffers[])
70{
71 const auto &[mT0, mT1, mSpeed, _] = *mTimesAndSpeed;
72 const bool backwards = (mT1 < mT0);
73
74 const double sequenceRate = mpSeq->GetRate();
75 const double initialWarp = mRate / mSpeed / sequenceRate;
76 const double tstep = 1.0 / sequenceRate;
77 const auto sampleSize = SAMPLE_SIZE(floatSample);
78 // Find the last sample
79 const auto endPos = [mpSeq = mpSeq, mT1 = mT1, backwards]{
80 double endTime = mpSeq->GetEndTime();
81 double startTime = mpSeq->GetStartTime();
82 const double tEnd = backwards
83 ? std::max(startTime, mT1)
84 : std::min(endTime, mT1);
85 return mpSeq->TimeToLongSamples(tEnd);
86 }();
87
88 auto pos = mSamplePos;
89 auto queueStart = mQueueStart;
90 auto queueLen = mQueueLen;
91
92 size_t out = 0;
93
94 /* time is floating point. Sample rate is integer. The number of samples
95 * has to be integer, but the multiplication gives a float result, which we
96 * round to get an integer result. TODO: is this always right or can it be
97 * off by one sometimes? Can we not get this information directly from the
98 * clip (which must know) rather than convert the time?
99 *
100 * LLL: Not at this time. While WaveClips provide methods to retrieve the
101 * start and end sample, they do the same float->sampleCount conversion
102 * to calculate the position.
103 */
104
105 // Find the time corresponding to the start of the queue, for use with time track
106 double t = ((pos).as_long_long() +
107 (backwards ? queueLen : - queueLen)) / sequenceRate;
108
109 while (out < maxOut) {
110 if (queueLen < (int)sProcessLen) {
111 // Shift pending portion to start of the buffer
112 for (size_t iChannel = 0; iChannel < nChannels; ++iChannel) {
113 const auto queue = mSampleQueue[iChannel].data();
114 memmove(queue, &queue[queueStart], (queueLen) * sampleSize);
115 }
116 queueStart = 0;
117
118 // How far to advance depends on endPos,
119 // which is independent of channel
120 auto getLen = limitSampleBufferSize(
121 sQueueMaxLen - queueLen,
122 backwards ? pos - endPos : endPos - pos
123 );
124
125 // Nothing to do if past end of play interval
126 if (getLen > 0) {
127 std::vector<float*> dst;
128 for (auto& queue : mSampleQueue)
129 dst.push_back(queue.data() + queueLen);
130 constexpr auto iChannel = 0u;
131 if (!mpSeq->GetFloats(
132 iChannel, nChannels, dst.data(), pos, getLen, backwards,
134 // Now redundant in case of failure
135 // for (size_t iChannel = 0; iChannel < nChannels; ++iChannel)
136 // memset(dst[i], 0, sizeof(float) * getLen);
137 }
138 mpSeq->GetEnvelopeValues(
139 mEnvValues.data(), getLen, (pos).as_double() / sequenceRate,
140 backwards);
141 for (size_t iChannel = 0; iChannel < nChannels; ++iChannel) {
142 const auto queue = mSampleQueue[iChannel].data();
143 for (decltype(getLen) i = 0; i < getLen; i++)
144 queue[(queueLen) + i] *= mEnvValues[i];
145 }
146
147 if (backwards)
148 pos -= getLen;
149 else
150 pos += getLen;
151 queueLen += getLen;
152 }
153 }
154
155 auto thisProcessLen = sProcessLen;
156 bool last = (queueLen < (int)sProcessLen);
157 if (last) {
158 thisProcessLen = queueLen;
159 }
160
161 double factor = initialWarp;
162 if (mEnvelope)
163 {
164 //TODO-MB: The end time is wrong when the resampler doesn't use all input samples,
165 // as a result of this the warp factor may be slightly wrong, so AudioIO will stop too soon
166 // or too late (resulting in missing sound or inserted silence). This can't be fixed
167 // without changing the way the resampler works, because the number of input samples that will be used
168 // is unpredictable. Maybe it can be compensated later though.
169 if (backwards)
170 factor *= ComputeWarpFactor( *mEnvelope,
171 t - (double)thisProcessLen / sequenceRate + tstep, t + tstep);
172 else
173 factor *= ComputeWarpFactor( *mEnvelope,
174 t, t + (double)thisProcessLen / sequenceRate);
175 }
176
177 std::pair<size_t, size_t> results;
178 for (size_t iChannel = 0; iChannel < nChannels; ++iChannel) {
179 const auto queue = mSampleQueue[iChannel].data();
180 const auto pResample = mResample[iChannel].get();
181 const auto pFloat = floatBuffers[iChannel];
182 // Assuming that progress of the Resampler depends only
183 // on the size of its inputs, this assignment has the same effect on
184 // each pass.
185 results = pResample->Process(factor,
186 &queue[queueStart],
187 thisProcessLen,
188 last,
189 // PRL: Bug2536: crash in soxr happened on Mac, sometimes, when
190 // maxOut - out == 1 and &pFloat[out + 1] was an unmapped
191 // address, because soxr, strangely, fetched an 8-byte (misaligned!)
192 // value from &pFloat[out], but did nothing with it anyway,
193 // in soxr_output_no_callback.
194 // Now we make the bug go away by allocating a little more space in
195 // the buffer than we need.
196 &pFloat[out],
197 maxOut - out);
198 }
199
200 const auto input_used = results.first;
201 queueStart += input_used;
202 queueLen -= input_used;
203 out += results.second;
204 t += (input_used / sequenceRate) * (backwards ? -1 : 1);
205
206 if (last) {
207 break;
208 }
209 }
210
211 assert(out <= maxOut);
212
213 mSamplePos = pos;
214 mQueueStart = queueStart;
215 mQueueLen = queueLen;
216 return out;
217}
218
219size_t MixerSource::MixSameRate(unsigned nChannels, const size_t maxOut,
220 float *floatBuffers[])
221{
222 const auto &[mT0, mT1, _, __] = *mTimesAndSpeed;
223 const bool backwards = (mT1 < mT0);
224 const auto sequenceRate = mpSeq->GetRate();
225 const double tEnd = [mpSeq = mpSeq, mT1 = mT1, backwards]{
226 const double sequenceEndTime = mpSeq->GetEndTime();
227 const double sequenceStartTime = mpSeq->GetStartTime();
228 return backwards
229 ? std::max(sequenceStartTime, mT1)
230 : std::min(sequenceEndTime, mT1);
231 }();
232
233 // This function fetches samples from the input sequences, whatever their
234 // formats, as floats; it may also apply envelope values.
235
236 auto pos = mSamplePos;
237
238 const double t = (pos).as_double() / sequenceRate;
239
240 //don't process if we're at the end of the selection or sequence.
241 if ((backwards ? t <= tEnd : t >= tEnd))
242 return 0;
243 //if we're about to approach the end of the sequence or selection, figure out how much we need to grab
244 const auto slen = limitSampleBufferSize(
245 maxOut,
246 // PRL: maybe t and tEnd should be given as sampleCount instead to
247 // avoid trouble subtracting one large value from another for a small
248 // difference
249 sampleCount{ (backwards ? t - tEnd : tEnd - t) * sequenceRate + 0.5 }
250 );
251
252 constexpr auto iChannel = 0u;
253 if (!mpSeq->GetFloats(
254 iChannel, nChannels, floatBuffers, pos, slen, backwards,
256 ) {
257 // Now redundant in case of failure
258 // for (size_t iChannel = 0; iChannel < nChannels; ++iChannel)
259 // memset(floatBuffers[iChannel], 0, sizeof(float) * slen);
260
261 }
262
263 mpSeq->GetEnvelopeValues(mEnvValues.data(), slen, t, backwards);
264
265 for (size_t iChannel = 0; iChannel < nChannels; ++iChannel) {
266 const auto pFloat = floatBuffers[iChannel];
267 for (size_t i = 0; i < slen; i++)
268 pFloat[i] *= mEnvValues[i]; // Track gain control will go here?
269 }
270
271 if (backwards)
272 pos -= slen;
273 else
274 pos += slen;
275
276 assert(slen <= maxOut);
277 mSamplePos = pos;
278 return slen;
279}
280
282 size_t produced, size_t max, float &floatBuffer)
283{
284 assert(produced <= max);
285 const auto pFloat = &floatBuffer;
286 std::fill(pFloat + produced, pFloat + max, 0);
287}
288
290 const std::shared_ptr<const WideSampleSequence> &seq, size_t bufferSize,
291 double rate, const MixerOptions::Warp &options, bool highQuality,
292 bool mayThrow, std::shared_ptr<TimesAndSpeed> pTimesAndSpeed
293) : mpSeq{ seq }
294 , mnChannels{ mpSeq->NChannels() }
295 , mRate{ rate }
296 , mEnvelope{ options.envelope }
297 , mMayThrow{ mayThrow }
298 , mTimesAndSpeed{ move(pTimesAndSpeed) }
299 , mSampleQueue{ initVector<float>(mnChannels, sQueueMaxLen) }
300 , mQueueStart{ 0 }
301 , mQueueLen{ 0 }
302 , mResampleParameters{ highQuality, mpSeq->GetRate(), rate, options }
303 , mResample( mnChannels )
304 , mEnvValues( std::max(sQueueMaxLen, bufferSize) )
305{
306 assert(mTimesAndSpeed);
307 auto t0 = mTimesAndSpeed->mT0;
310}
311
312MixerSource::~MixerSource() = default;
313
315{
316 return *mpSeq;
317}
318
319bool MixerSource::AcceptsBuffers(const Buffers &buffers) const
320{
321 return AcceptsBlockSize(buffers.BufferSize());
322}
323
324bool MixerSource::AcceptsBlockSize(size_t blockSize) const
325{
326 return blockSize <= mEnvValues.size();
327}
328
329#define stackAllocate(T, count) static_cast<T*>(alloca(count * sizeof(T)))
330
331std::optional<size_t> MixerSource::Acquire(Buffers &data, size_t bound)
332{
333 assert(AcceptsBuffers(data));
334 assert(AcceptsBlockSize(data.BlockSize()));
335 assert(bound <= data.BlockSize());
336 assert(data.BlockSize() <= data.Remaining());
337
338 auto &[mT0, mT1, _, mTime] = *mTimesAndSpeed;
339 const bool backwards = (mT1 < mT0);
340 // TODO: more-than-two-channels
341 const auto maxChannels = mMaxChannels = data.Channels();
342 const auto limit = std::min<size_t>(mnChannels, maxChannels);
343 size_t maxTrack = 0;
344 const auto mixed = stackAllocate(size_t, maxChannels);
345 const auto pFloats = stackAllocate(float *, limit);
346 for (size_t j = 0; j < limit; ++j)
347 pFloats[j] = &data.GetWritePosition(j);
348 const auto rate = GetSequence().GetRate();
349 auto result = (mResampleParameters.mVariableRates || rate != mRate)
350 ? MixVariableRates(limit, bound, pFloats)
351 : MixSameRate(limit, bound, pFloats);
352 maxTrack = std::max(maxTrack, result);
353 auto newT = mSamplePos.as_double() / rate;
354 if (backwards)
355 mTime = std::min(mTime, newT);
356 else
357 mTime = std::max(mTime, newT);
358 for (size_t j = 0; j < limit; ++j) {
359 mixed[j] = result;
360 }
361 // Another pass in case channels of a track did not produce equal numbers
362 for (size_t j = 0; j < limit; ++j) {
363 const auto pFloat = &data.GetWritePosition(j);
364 const auto result = mixed[j];
365 ZeroFill(result, maxTrack, *pFloat);
366 }
367
368 mLastProduced = maxTrack;
369 assert(maxTrack <= bound);
370 assert(maxTrack <= data.Remaining());
371 assert(maxTrack <= Remaining());
372 assert(data.Remaining() > 0);
373 assert(bound == 0 || Remaining() == 0 || maxTrack > 0);
374 return { mLastProduced };
375}
376
377// Does not return a strictly decreasing sequence of values such as to
378// provide proof of termination. Just an indication of whether done or not.
380{
381 // TODO: make a more exact calculation of total remaining; see Terminates()
382 return mLastProduced;
383}
384
386{
387 mLastProduced = 0;
388 return true;
389}
390
392{
393 // Not always terminating
394 // TODO: return true sometimes, for mixers that never reposition
395 // because they are not used in playback. But then an exact calculation of
396 // Remaining() is needed to satisfy the contract, and that is complicated
397 // when there is resampling or a time warp.
398 return false;
399}
400
401void MixerSource::Reposition(double time, bool skipping)
402{
404 mQueueStart = 0;
405 mQueueLen = 0;
406
407 // Bug 2025: libsoxr 0.1.3, first used in Audacity 2.3.0, crashes with
408 // constant rate resampling if you try to reuse the resampler after it has
409 // flushed. Should that be considered a bug in sox? This works around it.
410 // (See also bug 1887, and the same work around in Mixer::Restart().)
411 if (skipping)
413}
int min(int a, int b)
#define _(s)
Definition: Internat.h:73
#define stackAllocate(T, count)
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
Definition: SampleCount.cpp:22
#define SAMPLE_SIZE(SampleFormat)
Definition: SampleFormat.h:52
Accumulates (non-interleaved) data during effect processing.
size_t BlockSize() const
float & GetWritePosition(unsigned iChannel)
Get writable position for one channel.
size_t Remaining() const
size_t BufferSize() const
unsigned Channels() const
Piecewise linear or piecewise exponential function from double to double.
Definition: Envelope.h:72
double AverageOfInverse(double t0, double t1) const
Definition: Envelope.cpp:1133
std::vector< double > mEnvValues
Gain envelopes are applied to input before other transformations.
Definition: MixerSource.h:127
int mQueueStart
Position of the start of the next block to resample.
Definition: MixerSource.h:118
int mQueueLen
The number of available samples after the queue start.
Definition: MixerSource.h:121
const ResampleParameters mResampleParameters
Definition: MixerSource.h:123
const BoundedEnvelope *const mEnvelope
Resampling, as needed, after gain envelope.
Definition: MixerSource.h:103
const std::shared_ptr< TimesAndSpeed > mTimesAndSpeed
Definition: MixerSource.h:106
std::vector< std::vector< float > > mSampleQueue
First intermediate buffer when resampling is needed.
Definition: MixerSource.h:115
MixerSource(const std::shared_ptr< const WideSampleSequence > &seq, size_t bufferSize, double rate, const MixerOptions::Warp &options, bool highQuality, bool mayThrow, std::shared_ptr< TimesAndSpeed > pTimesAndSpeed)
size_t i
Definition: MixerSource.h:97
const std::shared_ptr< const WideSampleSequence > mpSeq
Definition: MixerSource.h:96
sampleCount Remaining() const override
Result includes any amount Acquired and not yet Released.
size_t MixSameRate(unsigned nChannels, size_t maxOut, float *floatBuffers[])
static constexpr size_t sQueueMaxLen
Definition: MixerSource.h:76
bool AcceptsBlockSize(size_t blockSize) const override
bool AcceptsBuffers(const Buffers &buffers) const override
size_t MixVariableRates(unsigned nChannels, size_t maxOut, float *floatBuffers[])
Definition: MixerSource.cpp:68
static constexpr size_t sProcessLen
Definition: MixerSource.h:69
bool Terminates() const override
const bool mMayThrow
Definition: MixerSource.h:104
bool Release() override
Caller is done examining last Acquire()d positions.
size_t mLastProduced
Definition: MixerSource.h:131
std::vector< std::unique_ptr< Resample > > mResample
Definition: MixerSource.h:124
void Reposition(double time, bool skipping)
const double mRate
Definition: MixerSource.h:100
unsigned mMaxChannels
Remember how many channels were passed to Acquire()
Definition: MixerSource.h:130
~MixerSource() override
const size_t mnChannels
Definition: MixerSource.h:99
void ZeroFill(size_t produced, size_t max, float &floatBuffer)
std::optional< size_t > Acquire(Buffers &data, size_t bound) override
Occupy vacant space in Buffers with some data.
void MakeResamplers()
Definition: MixerSource.cpp:40
sampleCount mSamplePos
Fetch position for source.
Definition: MixerSource.h:112
const WideSampleSequence & GetSequence() const
sampleCount TimeToLongSamples(double t0) const
virtual double GetRate() const =0
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:19
double as_double() const
Definition: SampleCount.h:46
std::vector< std::vector< T > > initVector(size_t dim1, size_t dim2)
Definition: MixerSource.cpp:33
double ComputeWarpFactor(const Envelope &env, double t0, double t1)
Compute the integral warp factor between two non-warped time points.
Definition: MixerSource.cpp:61
double GetRate(const Track &track)
Definition: TimeTrack.cpp:182
STL namespace.
Immutable structure is an argument to Mixer's constructor.
Definition: MixerOptions.h:56