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