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 const ArrayOf<bool> *pMap
294) : mpSeq{ seq }
295 , mnChannels{ mpSeq->NChannels() }
296 , mRate{ rate }
297 , mEnvelope{ options.envelope }
298 , mMayThrow{ mayThrow }
299 , mTimesAndSpeed{ move(pTimesAndSpeed) }
300 , mSampleQueue{ initVector<float>(mnChannels, sQueueMaxLen) }
301 , mQueueStart{ 0 }
302 , mQueueLen{ 0 }
303 , mResampleParameters{ highQuality, mpSeq->GetRate(), rate, options }
304 , mResample( mnChannels )
305 , mEnvValues( std::max(sQueueMaxLen, bufferSize) )
306 , mpMap{ pMap }
307{
308 assert(mTimesAndSpeed);
309 auto t0 = mTimesAndSpeed->mT0;
312}
313
314MixerSource::~MixerSource() = default;
315
317{
318 return *mpSeq;
319}
320
321const bool *MixerSource::MixerSpec(unsigned iChannel) const
322{
323 return mpMap ? mpMap[iChannel].get() : nullptr;
324}
325
326bool MixerSource::AcceptsBuffers(const Buffers &buffers) const
327{
328 return AcceptsBlockSize(buffers.BufferSize());
329}
330
331bool MixerSource::AcceptsBlockSize(size_t blockSize) const
332{
333 return blockSize <= mEnvValues.size();
334}
335
336#define stackAllocate(T, count) static_cast<T*>(alloca(count * sizeof(T)))
337
338std::optional<size_t> MixerSource::Acquire(Buffers &data, size_t bound)
339{
340 assert(AcceptsBuffers(data));
341 assert(AcceptsBlockSize(data.BlockSize()));
342 assert(bound <= data.BlockSize());
343 assert(data.BlockSize() <= data.Remaining());
344
345 auto &[mT0, mT1, _, mTime] = *mTimesAndSpeed;
346 const bool backwards = (mT1 < mT0);
347 // TODO: more-than-two-channels
348 const auto maxChannels = mMaxChannels = data.Channels();
349 const auto limit = std::min<size_t>(mnChannels, maxChannels);
350 size_t maxTrack = 0;
351 const auto mixed = stackAllocate(size_t, maxChannels);
352 const auto pFloats = stackAllocate(float *, limit);
353 for (size_t j = 0; j < limit; ++j)
354 pFloats[j] = &data.GetWritePosition(j);
355 const auto rate = GetSequence().GetRate();
356 auto result = (mResampleParameters.mVariableRates || rate != mRate)
357 ? MixVariableRates(limit, bound, pFloats)
358 : MixSameRate(limit, bound, pFloats);
359 maxTrack = std::max(maxTrack, result);
360 auto newT = mSamplePos.as_double() / rate;
361 if (backwards)
362 mTime = std::min(mTime, newT);
363 else
364 mTime = std::max(mTime, newT);
365 for (size_t j = 0; j < limit; ++j) {
366 mixed[j] = result;
367 }
368 // Another pass in case channels of a track did not produce equal numbers
369 for (size_t j = 0; j < limit; ++j) {
370 const auto pFloat = &data.GetWritePosition(j);
371 const auto result = mixed[j];
372 ZeroFill(result, maxTrack, *pFloat);
373 }
374
375 mLastProduced = maxTrack;
376 assert(maxTrack <= bound);
377 assert(maxTrack <= data.Remaining());
378 assert(maxTrack <= Remaining());
379 assert(data.Remaining() > 0);
380 assert(bound == 0 || Remaining() == 0 || maxTrack > 0);
381 return { mLastProduced };
382}
383
384// Does not return a strictly decreasing sequence of values such as to
385// provide proof of termination. Just an indication of whether done or not.
387{
388 // TODO: make a more exact calculation of total remaining; see Terminates()
389 return mLastProduced;
390}
391
393{
394 mLastProduced = 0;
395 return true;
396}
397
399{
400 // Not always terminating
401 // TODO: return true sometimes, for mixers that never reposition
402 // because they are not used in playback. But then an exact calculation of
403 // Remaining() is needed to satisfy the contract, and that is complicated
404 // when there is resampling or a time warp.
405 return false;
406}
407
408void MixerSource::Reposition(double time, bool skipping)
409{
411 mQueueStart = 0;
412 mQueueLen = 0;
413
414 // Bug 2025: libsoxr 0.1.3, first used in Audacity 2.3.0, crashes with
415 // constant rate resampling if you try to reuse the resampler after it has
416 // flushed. Should that be considered a bug in sox? This works around it.
417 // (See also bug 1887, and the same work around in Mixer::Restart().)
418 if (skipping)
420}
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:131
int mQueueStart
Position of the start of the next block to resample.
Definition: MixerSource.h:122
int mQueueLen
The number of available samples after the queue start.
Definition: MixerSource.h:125
const ResampleParameters mResampleParameters
Definition: MixerSource.h:127
const BoundedEnvelope *const mEnvelope
Resampling, as needed, after gain envelope.
Definition: MixerSource.h:107
const std::shared_ptr< TimesAndSpeed > mTimesAndSpeed
Definition: MixerSource.h:110
std::vector< std::vector< float > > mSampleQueue
First intermediate buffer when resampling is needed.
Definition: MixerSource.h:119
const std::shared_ptr< const WideSampleSequence > mpSeq
Definition: MixerSource.h:100
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:80
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:73
bool Terminates() const override
const ArrayOf< bool > *const mpMap
Definition: MixerSource.h:135
const bool mMayThrow
Definition: MixerSource.h:108
bool Release() override
Caller is done examining last Acquire()d positions.
size_t mLastProduced
Definition: MixerSource.h:139
std::vector< std::unique_ptr< Resample > > mResample
Definition: MixerSource.h:128
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, const ArrayOf< bool > *pMap)
void Reposition(double time, bool skipping)
const double mRate
Definition: MixerSource.h:104
unsigned mMaxChannels
Remember how many channels were passed to Acquire()
Definition: MixerSource.h:138
const size_t mnChannels
Definition: MixerSource.h:103
void ZeroFill(size_t produced, size_t max, float &floatBuffer)
const bool * MixerSpec(unsigned iChannel) const
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:116
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