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 = mpLeader->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 = [mpLeader = mpLeader, mT1 = mT1, backwards]{
80 double endTime = mpLeader->GetEndTime();
81 double startTime = mpLeader->GetStartTime();
82 const double tEnd = backwards
83 ? std::max(startTime, mT1)
84 : std::min(endTime, mT1);
85 return mpLeader->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 (!mpLeader->GetFloats(
132 iChannel, nChannels, dst.data(), pos, getLen, backwards,
134 for (size_t iChannel = 0; iChannel < nChannels; ++iChannel)
135 memset(dst[i], 0, sizeof(float) * getLen);
136 mpLeader->GetEnvelopeValues(
137 mEnvValues.data(), getLen, (pos).as_double() / sequenceRate,
138 backwards);
139 for (size_t iChannel = 0; iChannel < nChannels; ++iChannel) {
140 const auto queue = mSampleQueue[iChannel].data();
141 for (decltype(getLen) i = 0; i < getLen; i++)
142 queue[(queueLen) + i] *= mEnvValues[i];
143 }
144
145 if (backwards)
146 pos -= getLen;
147 else
148 pos += getLen;
149 queueLen += getLen;
150 }
151 }
152
153 auto thisProcessLen = sProcessLen;
154 bool last = (queueLen < (int)sProcessLen);
155 if (last) {
156 thisProcessLen = queueLen;
157 }
158
159 double factor = initialWarp;
160 if (mEnvelope)
161 {
162 //TODO-MB: The end time is wrong when the resampler doesn't use all input samples,
163 // as a result of this the warp factor may be slightly wrong, so AudioIO will stop too soon
164 // or too late (resulting in missing sound or inserted silence). This can't be fixed
165 // without changing the way the resampler works, because the number of input samples that will be used
166 // is unpredictable. Maybe it can be compensated later though.
167 if (backwards)
168 factor *= ComputeWarpFactor( *mEnvelope,
169 t - (double)thisProcessLen / sequenceRate + tstep, t + tstep);
170 else
171 factor *= ComputeWarpFactor( *mEnvelope,
172 t, t + (double)thisProcessLen / sequenceRate);
173 }
174
175 std::pair<size_t, size_t> results;
176 for (size_t iChannel = 0; iChannel < nChannels; ++iChannel) {
177 const auto queue = mSampleQueue[iChannel].data();
178 const auto pResample = mResample[iChannel].get();
179 const auto pFloat = floatBuffers[iChannel];
180 // Assuming that progress of the Resampler depends only
181 // on the size of its inputs, this assignment has the same effect on
182 // each pass.
183 results = pResample->Process(factor,
184 &queue[queueStart],
185 thisProcessLen,
186 last,
187 // PRL: Bug2536: crash in soxr happened on Mac, sometimes, when
188 // maxOut - out == 1 and &pFloat[out + 1] was an unmapped
189 // address, because soxr, strangely, fetched an 8-byte (misaligned!)
190 // value from &pFloat[out], but did nothing with it anyway,
191 // in soxr_output_no_callback.
192 // Now we make the bug go away by allocating a little more space in
193 // the buffer than we need.
194 &pFloat[out],
195 maxOut - out);
196 }
197
198 const auto input_used = results.first;
199 queueStart += input_used;
200 queueLen -= input_used;
201 out += results.second;
202 t += (input_used / sequenceRate) * (backwards ? -1 : 1);
203
204 if (last) {
205 break;
206 }
207 }
208
209 assert(out <= maxOut);
210
211 mSamplePos = pos;
212 mQueueStart = queueStart;
213 mQueueLen = queueLen;
214 return out;
215}
216
217size_t MixerSource::MixSameRate(unsigned nChannels, const size_t maxOut,
218 float *floatBuffers[])
219{
220 const auto &[mT0, mT1, _, __] = *mTimesAndSpeed;
221 const bool backwards = (mT1 < mT0);
222 const auto sequenceRate = mpLeader->GetRate();
223 const double tEnd = [mpLeader = mpLeader, mT1 = mT1, backwards]{
224 const double sequenceEndTime = mpLeader->GetEndTime();
225 const double sequenceStartTime = mpLeader->GetStartTime();
226 return backwards
227 ? std::max(sequenceStartTime, mT1)
228 : std::min(sequenceEndTime, mT1);
229 }();
230
231 // This function fetches samples from the input sequences, whatever their
232 // formats, as floats; it may also apply envelope values.
233
234 auto pos = mSamplePos;
235
236 const double t = (pos).as_double() / sequenceRate;
237
238 //don't process if we're at the end of the selection or sequence.
239 if ((backwards ? t <= tEnd : t >= tEnd))
240 return 0;
241 //if we're about to approach the end of the sequence or selection, figure out how much we need to grab
242 const auto slen = limitSampleBufferSize(
243 maxOut,
244 // PRL: maybe t and tEnd should be given as sampleCount instead to
245 // avoid trouble subtracting one large value from another for a small
246 // difference
247 sampleCount{ (backwards ? t - tEnd : tEnd - t) * sequenceRate + 0.5 }
248 );
249
250 constexpr auto iChannel = 0u;
251 if (!mpLeader->GetFloats(
252 iChannel, nChannels, floatBuffers, pos, slen, backwards,
254 )
255 for (size_t iChannel = 0; iChannel < nChannels; ++iChannel)
256 memset(floatBuffers[iChannel], 0, sizeof(float) * slen);
257
258 mpLeader->GetEnvelopeValues(mEnvValues.data(), slen, t, backwards);
259
260 for (size_t iChannel = 0; iChannel < nChannels; ++iChannel) {
261 const auto pFloat = floatBuffers[iChannel];
262 for (size_t i = 0; i < slen; i++)
263 pFloat[i] *= mEnvValues[i]; // Track gain control will go here?
264 }
265
266 if (backwards)
267 pos -= slen;
268 else
269 pos += slen;
270
271 assert(slen <= maxOut);
272 mSamplePos = pos;
273 return slen;
274}
275
277 size_t produced, size_t max, float &floatBuffer)
278{
279 assert(produced <= max);
280 const auto pFloat = &floatBuffer;
281 std::fill(pFloat + produced, pFloat + max, 0);
282}
283
285 const std::shared_ptr<const WideSampleSequence> &leader, size_t bufferSize,
286 double rate, const MixerOptions::Warp &options, bool highQuality,
287 bool mayThrow, std::shared_ptr<TimesAndSpeed> pTimesAndSpeed,
288 const ArrayOf<bool> *pMap
289) : mpLeader{ leader }
290 , mnChannels{ mpLeader->NChannels() }
291 , mRate{ rate }
292 , mEnvelope{ options.envelope }
293 , mMayThrow{ mayThrow }
294 , mTimesAndSpeed{ move(pTimesAndSpeed) }
295 , mSampleQueue{ initVector<float>(mnChannels, sQueueMaxLen) }
296 , mQueueStart{ 0 }
297 , mQueueLen{ 0 }
298 , mResampleParameters{ highQuality, mpLeader->GetRate(), rate, options }
299 , mResample( mnChannels )
300 , mEnvValues( std::max(sQueueMaxLen, bufferSize) )
301 , mpMap{ pMap }
302{
303 assert(mTimesAndSpeed);
304 auto t0 = mTimesAndSpeed->mT0;
307}
308
309MixerSource::~MixerSource() = default;
310
312{
313 return *mpLeader;
314}
315
316const bool *MixerSource::MixerSpec(unsigned iChannel) const
317{
318 return mpMap ? mpMap[iChannel].get() : nullptr;
319}
320
321bool MixerSource::AcceptsBuffers(const Buffers &buffers) const
322{
323 return AcceptsBlockSize(buffers.BufferSize());
324}
325
326bool MixerSource::AcceptsBlockSize(size_t blockSize) const
327{
328 return blockSize <= mEnvValues.size();
329}
330
331#define stackAllocate(T, count) static_cast<T*>(alloca(count * sizeof(T)))
332
333std::optional<size_t> MixerSource::Acquire(Buffers &data, size_t bound)
334{
335 assert(AcceptsBuffers(data));
336 assert(AcceptsBlockSize(data.BlockSize()));
337 assert(bound <= data.BlockSize());
338 assert(data.BlockSize() <= data.Remaining());
339
340 auto &[mT0, mT1, _, mTime] = *mTimesAndSpeed;
341 const bool backwards = (mT1 < mT0);
342 // TODO: more-than-two-channels
343 const auto maxChannels = mMaxChannels = data.Channels();
344 const auto limit = std::min<size_t>(mnChannels, maxChannels);
345 size_t maxTrack = 0;
346 const auto mixed = stackAllocate(size_t, maxChannels);
347 const auto pFloats = stackAllocate(float *, limit);
348 for (size_t j = 0; j < limit; ++j)
349 pFloats[j] = &data.GetWritePosition(j);
350 const auto rate = GetSequence().GetRate();
351 auto result = (mResampleParameters.mVariableRates || rate != mRate)
352 ? MixVariableRates(limit, bound, pFloats)
353 : MixSameRate(limit, bound, pFloats);
354 maxTrack = std::max(maxTrack, result);
355 auto newT = mSamplePos.as_double() / rate;
356 if (backwards)
357 mTime = std::min(mTime, newT);
358 else
359 mTime = std::max(mTime, newT);
360 for (size_t j = 0; j < limit; ++j) {
361 mixed[j] = result;
362 }
363 // Another pass in case channels of a track did not produce equal numbers
364 for (size_t j = 0; j < limit; ++j) {
365 const auto pFloat = &data.GetWritePosition(j);
366 const auto result = mixed[j];
367 ZeroFill(result, maxTrack, *pFloat);
368 }
369
370 mLastProduced = maxTrack;
371 assert(maxTrack <= bound);
372 assert(maxTrack <= data.Remaining());
373 assert(maxTrack <= Remaining());
374 assert(data.Remaining() > 0);
375 assert(bound == 0 || Remaining() == 0 || maxTrack > 0);
376 return { mLastProduced };
377}
378
379// Does not return a strictly decreasing sequence of values such as to
380// provide proof of termination. Just an indication of whether done or not.
382{
383 // TODO: make a more exact calculation of total remaining; see Terminates()
384 return mLastProduced;
385}
386
388{
389 mLastProduced = 0;
390 return true;
391}
392
394{
395 // Not always terminating
396 // TODO: return true sometimes, for mixers that never reposition
397 // because they are not used in playback. But then an exact calculation of
398 // Remaining() is needed to satisfy the contract, and that is complicated
399 // when there is resampling or a time warp.
400 return false;
401}
402
403void MixerSource::Reposition(double time, bool skipping)
404{
406 mQueueStart = 0;
407 mQueueLen = 0;
408
409 // Bug 2025: libsoxr 0.1.3, first used in Audacity 2.3.0, crashes with
410 // constant rate resampling if you try to reuse the resampler after it has
411 // flushed. Should that be considered a bug in sox? This works around it.
412 // (See also bug 1887, and the same work around in Mixer::Restart().)
413 if (skipping)
415}
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:50
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:1089
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
sampleCount Remaining() const override
Result includes any amount Acquired and not yet Released.
const std::shared_ptr< const WideSampleSequence > mpLeader
Definition: MixerSource.h:100
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
MixerSource(const std::shared_ptr< const WideSampleSequence > &leader, size_t bufferSize, double rate, const MixerOptions::Warp &options, bool highQuality, bool mayThrow, std::shared_ptr< TimesAndSpeed > pTimesAndSpeed, const ArrayOf< bool > *pMap)
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
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:196
STL namespace.
Immutable structure is an argument to Mixer's constructor.
Definition: MixerOptions.h:56