Audacity  3.0.3
Mix.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  Mix.cpp
6 
7  Dominic Mazzoni
8  Markus Meyer
9  Vaughan Johnson
10 
11 *******************************************************************//****************************************************************//*******************************************************************/
22 
23 
24 
25 #include "Mix.h"
26 
27 #include <math.h>
28 
29 #include <wx/textctrl.h>
30 #include <wx/timer.h>
31 #include <wx/intl.h>
32 
33 #include "Envelope.h"
34 #include "WaveTrack.h"
35 #include "Prefs.h"
36 #include "Resample.h"
37 #include "TimeTrack.h"
38 #include "float_cast.h"
39 
40 #include "widgets/ProgressDialog.h"
41 
42 //TODO-MB: wouldn't it make more sense to DELETE the time track after 'mix and render'?
43 void MixAndRender(TrackList *tracks, WaveTrackFactory *trackFactory,
44  double rate, sampleFormat format,
45  double startTime, double endTime,
46  WaveTrack::Holder &uLeft, WaveTrack::Holder &uRight)
47 {
48  uLeft.reset(), uRight.reset();
49 
50  // This function was formerly known as "Quick Mix".
51  bool mono = false; /* flag if output can be mono without losing anything*/
52  bool oneinput = false; /* flag set to true if there is only one input track
53  (mono or stereo) */
54 
55  const auto trackRange = tracks->Selected< const WaveTrack >();
56  auto first = *trackRange.begin();
57  // this only iterates tracks which are relevant to this function, i.e.
58  // selected WaveTracks. The tracklist is (confusingly) the list of all
59  // tracks in the project
60 
61  int numWaves = 0; /* number of wave tracks in the selection */
62  int numMono = 0; /* number of mono, centre-panned wave tracks in selection*/
63  for(auto wt : trackRange) {
64  numWaves++;
65  float pan = wt->GetPan();
66  if (wt->GetChannel() == Track::MonoChannel && pan == 0)
67  numMono++;
68  }
69 
70  if (numMono == numWaves)
71  mono = true;
72 
73  /* the next loop will do two things at once:
74  * 1. build an array of all the wave tracks were are trying to process
75  * 2. determine when the set of WaveTracks starts and ends, in case we
76  * need to work out for ourselves when to start and stop rendering.
77  */
78 
79  double mixStartTime = 0.0; /* start time of first track to start */
80  bool gotstart = false; // flag indicates we have found a start time
81  double mixEndTime = 0.0; /* end time of last track to end */
82  double tstart, tend; // start and end times for one track.
83 
84  WaveTrackConstArray waveArray;
85 
86  for(auto wt : trackRange) {
87  waveArray.push_back( wt->SharedPointer< const WaveTrack >() );
88  tstart = wt->GetStartTime();
89  tend = wt->GetEndTime();
90  if (tend > mixEndTime)
91  mixEndTime = tend;
92  // try and get the start time. If the track is empty we will get 0,
93  // which is ambiguous because it could just mean the track starts at
94  // the beginning of the project, as well as empty track. The give-away
95  // is that an empty track also ends at zero.
96 
97  if (tstart != tend) {
98  // we don't get empty tracks here
99  if (!gotstart) {
100  // no previous start, use this one unconditionally
101  mixStartTime = tstart;
102  gotstart = true;
103  } else if (tstart < mixStartTime)
104  mixStartTime = tstart; // have a start, only make it smaller
105  } // end if start and end are different
106  }
107 
108  /* create the destination track (NEW track) */
109  if (numWaves == (int)TrackList::Channels(first).size())
110  oneinput = true;
111  // only one input track (either 1 mono or one linked stereo pair)
112 
113  auto mixLeft = trackFactory->NewWaveTrack(format, rate);
114  if (oneinput)
115  mixLeft->SetName(first->GetName()); /* set name of output track to be the same as the sole input track */
116  else
117  /* i18n-hint: noun, means a track, made by mixing other tracks */
118  mixLeft->SetName(_("Mix"));
119  mixLeft->SetOffset(mixStartTime);
120 
121  // TODO: more-than-two-channels
122  decltype(mixLeft) mixRight{};
123  if ( !mono ) {
124  mixRight = trackFactory->NewWaveTrack(format, rate);
125  if (oneinput) {
126  auto channels = TrackList::Channels(first);
127  if (channels.size() > 1)
128  mixRight->SetName((*channels.begin().advance(1))->GetName()); /* set name to match input track's right channel!*/
129  else
130  mixRight->SetName(first->GetName()); /* set name to that of sole input channel */
131  }
132  else
133  mixRight->SetName(_("Mix"));
134  mixRight->SetOffset(mixStartTime);
135  }
136 
137 
138  auto maxBlockLen = mixLeft->GetIdealBlockSize();
139 
140  // If the caller didn't specify a time range, use the whole range in which
141  // any input track had clips in it.
142  if (startTime == endTime) {
143  startTime = mixStartTime;
144  endTime = mixEndTime;
145  }
146 
147  Mixer mixer(waveArray,
148  // Throw to abort mix-and-render if read fails:
149  true,
150  Mixer::WarpOptions{*tracks},
151  startTime, endTime, mono ? 1 : 2, maxBlockLen, false,
152  rate, format);
153 
154  ::wxSafeYield();
155 
156  auto updateResult = ProgressResult::Success;
157  {
158  ProgressDialog progress(XO("Mix and Render"),
159  XO("Mixing and rendering tracks"));
160 
161  while (updateResult == ProgressResult::Success) {
162  auto blockLen = mixer.Process(maxBlockLen);
163 
164  if (blockLen == 0)
165  break;
166 
167  if (mono) {
168  auto buffer = mixer.GetBuffer();
169  mixLeft->Append(buffer, format, blockLen);
170  }
171  else {
172  auto buffer = mixer.GetBuffer(0);
173  mixLeft->Append(buffer, format, blockLen);
174  buffer = mixer.GetBuffer(1);
175  mixRight->Append(buffer, format, blockLen);
176  }
177 
178  updateResult = progress.Update(mixer.MixGetCurrentTime() - startTime, endTime - startTime);
179  }
180  }
181 
182  mixLeft->Flush();
183  if (!mono)
184  mixRight->Flush();
185  if (updateResult == ProgressResult::Cancelled || updateResult == ProgressResult::Failed)
186  {
187  return;
188  }
189  else {
190  uLeft = mixLeft, uRight = mixRight;
191 #if 0
192  int elapsedMS = wxGetElapsedTime();
193  double elapsedTime = elapsedMS * 0.001;
194  double maxTracks = totalTime / (elapsedTime / numWaves);
195 
196  // Note: these shouldn't be translated - they're for debugging
197  // and profiling only.
198  wxPrintf(" Tracks: %d\n", numWaves);
199  wxPrintf(" Mix length: %f sec\n", totalTime);
200  wxPrintf("Elapsed time: %f sec\n", elapsedTime);
201  wxPrintf("Max number of tracks to mix in real time: %f\n", maxTracks);
202 #endif
203  }
204 }
205 
207 : minSpeed(0.0), maxSpeed(0.0)
208 {
209  auto timeTrack = *(list.Any<const TimeTrack>().begin());
210  envelope = timeTrack ? timeTrack->GetEnvelope() : nullptr;
211 }
212 
214  : envelope(e), minSpeed(0.0), maxSpeed(0.0)
215  {}
216 
218  : minSpeed(min), maxSpeed(max)
219 {
220  if (minSpeed < 0)
221  {
222  wxASSERT(false);
223  minSpeed = 0;
224  }
225  if (maxSpeed < 0)
226  {
227  wxASSERT(false);
228  maxSpeed = 0;
229  }
230  if (minSpeed > maxSpeed)
231  {
232  wxASSERT(false);
234  }
235 }
236 
238  bool mayThrow,
239  const WarpOptions &warpOptions,
240  double startTime, double stopTime,
241  unsigned numOutChannels, size_t outBufferSize, bool outInterleaved,
242  double outRate, sampleFormat outFormat,
243  bool highQuality, MixerSpec *mixerSpec, bool applyTrackGains)
244  : mNumInputTracks { inputTracks.size() }
245 
246  , mApplyTrackGains{ applyTrackGains }
247 
248  // This is the number of samples grabbed in one go from a track
249  // and placed in a queue, when mixing with resampling.
250  // (Should we use WaveTrack::GetBestBlockSize instead?)
251  , mQueueMaxLen{ 65536 }
252  , mSampleQueue{ mNumInputTracks, mQueueMaxLen }
253 
254  , mNumChannels{ numOutChannels }
255  , mGains{ mNumChannels }
256 
257  , mFormat{ outFormat }
258  , mRate{ outRate }
259 
260  , mMayThrow{ mayThrow }
261 {
262  mHighQuality = highQuality;
263  mInputTrack.reinit(mNumInputTracks);
264 
265  // mSamplePos holds for each track the next sample position not
266  // yet processed.
267  mSamplePos.reinit(mNumInputTracks);
268  for(size_t i=0; i<mNumInputTracks; i++) {
269  mInputTrack[i].SetTrack(inputTracks[i]);
270  mSamplePos[i] = inputTracks[i]->TimeToLongSamples(startTime);
271  }
272  mEnvelope = warpOptions.envelope;
273  mT0 = startTime;
274  mT1 = stopTime;
275  mTime = startTime;
276  mBufferSize = outBufferSize;
277  mInterleaved = outInterleaved;
278  mSpeed = 1.0;
279  if( mixerSpec && mixerSpec->GetNumChannels() == mNumChannels &&
280  mixerSpec->GetNumTracks() == mNumInputTracks )
281  mMixerSpec = mixerSpec;
282  else
283  mMixerSpec = NULL;
284 
285  if (mInterleaved) {
286  mNumBuffers = 1;
287  mInterleavedBufferSize = mBufferSize * mNumChannels;
288  }
289  else {
290  mNumBuffers = mNumChannels;
291  mInterleavedBufferSize = mBufferSize;
292  }
293 
294  mBuffer.reinit(mNumBuffers);
295  mTemp.reinit(mNumBuffers);
296  for (unsigned int c = 0; c < mNumBuffers; c++) {
297  mBuffer[c].Allocate(mInterleavedBufferSize, mFormat);
298  mTemp[c].reinit(mInterleavedBufferSize);
299  }
300  // PRL: Bug2536: see other comments below
301  mFloatBuffer = Floats{ mInterleavedBufferSize + 1 };
302 
303  // But cut the queue into blocks of this finer size
304  // for variable rate resampling. Each block is resampled at some
305  // constant rate.
306  mProcessLen = 1024;
307 
308  // Position in each queue of the start of the next block to resample.
309  mQueueStart.reinit(mNumInputTracks);
310 
311  // For each queue, the number of available samples after the queue start.
312  mQueueLen.reinit(mNumInputTracks);
313  mResample.reinit(mNumInputTracks);
314  mMinFactor.resize(mNumInputTracks);
315  mMaxFactor.resize(mNumInputTracks);
316  for (size_t i = 0; i<mNumInputTracks; i++) {
317  double factor = (mRate / mInputTrack[i].GetTrack()->GetRate());
318  if (mEnvelope) {
319  // variable rate resampling
320  mbVariableRates = true;
321  mMinFactor[i] = factor / mEnvelope->GetRangeUpper();
322  mMaxFactor[i] = factor / mEnvelope->GetRangeLower();
323  }
324  else if (warpOptions.minSpeed > 0.0 && warpOptions.maxSpeed > 0.0) {
325  // variable rate resampling
326  mbVariableRates = true;
327  mMinFactor[i] = factor / warpOptions.maxSpeed;
328  mMaxFactor[i] = factor / warpOptions.minSpeed;
329  }
330  else {
331  // constant rate resampling
332  mbVariableRates = false;
333  mMinFactor[i] = mMaxFactor[i] = factor;
334  }
335 
336  mQueueStart[i] = 0;
337  mQueueLen[i] = 0;
338  }
339 
340  MakeResamplers();
341 
342  const auto envLen = std::max(mQueueMaxLen, mInterleavedBufferSize);
343  mEnvValues.reinit(envLen);
344 }
345 
346 Mixer::~Mixer()
347 {
348 }
349 
351 {
352  for (size_t i = 0; i < mNumInputTracks; i++)
353  mResample[i] = std::make_unique<Resample>(mHighQuality, mMinFactor[i], mMaxFactor[i]);
354 }
355 
357 {
358  for (unsigned int c = 0; c < mNumBuffers; c++) {
359  memset(mTemp[c].get(), 0, mInterleavedBufferSize * sizeof(float));
360  }
361 }
362 
363 static void MixBuffers(unsigned numChannels, int *channelFlags, float *gains,
364  const float *src, Floats *dests,
365  int len, bool interleaved)
366 {
367  for (unsigned int c = 0; c < numChannels; c++) {
368  if (!channelFlags[c])
369  continue;
370 
371  float *dest;
372  unsigned skip;
373 
374  if (interleaved) {
375  dest = dests[0].get() + c;
376  skip = numChannels;
377  } else {
378  dest = dests[c].get();
379  skip = 1;
380  }
381 
382  float gain = gains[c];
383  for (int j = 0; j < len; j++) {
384  *dest += src[j] * gain; // the actual mixing process
385  dest += skip;
386  }
387  }
388 }
389 
390 namespace {
391  //Note: The meaning of this function has changed (December 2012)
392  //Previously this function did something that was close to the opposite (but not entirely accurate).
403 double ComputeWarpFactor(const Envelope &env, double t0, double t1)
404 {
405  return env.AverageOfInverse(t0, t1);
406 }
407 
408 }
409 
410 size_t Mixer::MixVariableRates(int *channelFlags, WaveTrackCache &cache,
411  sampleCount *pos, float *queue,
412  int *queueStart, int *queueLen,
413  Resample * pResample)
414 {
415  const WaveTrack *const track = cache.GetTrack().get();
416  const double trackRate = track->GetRate();
417  const double initialWarp = mRate / mSpeed / trackRate;
418  const double tstep = 1.0 / trackRate;
419  auto sampleSize = SAMPLE_SIZE(floatSample);
420 
421  decltype(mMaxOut) out = 0;
422 
423  /* time is floating point. Sample rate is integer. The number of samples
424  * has to be integer, but the multiplication gives a float result, which we
425  * round to get an integer result. TODO: is this always right or can it be
426  * off by one sometimes? Can we not get this information directly from the
427  * clip (which must know) rather than convert the time?
428  *
429  * LLL: Not at this time. While WaveClips provide methods to retrieve the
430  * start and end sample, they do the same float->sampleCount conversion
431  * to calculate the position.
432  */
433 
434  // Find the last sample
435  double endTime = track->GetEndTime();
436  double startTime = track->GetStartTime();
437  const bool backwards = (mT1 < mT0);
438  const double tEnd = backwards
439  ? std::max(startTime, mT1)
440  : std::min(endTime, mT1);
441  const auto endPos = track->TimeToLongSamples(tEnd);
442  // Find the time corresponding to the start of the queue, for use with time track
443  double t = ((*pos).as_long_long() +
444  (backwards ? *queueLen : - *queueLen)) / trackRate;
445 
446  while (out < mMaxOut) {
447  if (*queueLen < (int)mProcessLen) {
448  // Shift pending portion to start of the buffer
449  memmove(queue, &queue[*queueStart], (*queueLen) * sampleSize);
450  *queueStart = 0;
451 
452  auto getLen = limitSampleBufferSize(
453  mQueueMaxLen - *queueLen,
454  backwards ? *pos - endPos : endPos - *pos
455  );
456 
457  // Nothing to do if past end of play interval
458  if (getLen > 0) {
459  if (backwards) {
460  auto results =
461  cache.GetFloats(*pos - (getLen - 1), getLen, mMayThrow);
462  if (results)
463  memcpy(&queue[*queueLen], results, sizeof(float) * getLen);
464  else
465  memset(&queue[*queueLen], 0, sizeof(float) * getLen);
466 
467  track->GetEnvelopeValues(mEnvValues.get(),
468  getLen,
469  (*pos - (getLen- 1)).as_double() / trackRate);
470  *pos -= getLen;
471  }
472  else {
473  auto results = cache.GetFloats(*pos, getLen, mMayThrow);
474  if (results)
475  memcpy(&queue[*queueLen], results, sizeof(float) * getLen);
476  else
477  memset(&queue[*queueLen], 0, sizeof(float) * getLen);
478 
479  track->GetEnvelopeValues(mEnvValues.get(),
480  getLen,
481  (*pos).as_double() / trackRate);
482 
483  *pos += getLen;
484  }
485 
486  for (decltype(getLen) i = 0; i < getLen; i++) {
487  queue[(*queueLen) + i] *= mEnvValues[i];
488  }
489 
490  if (backwards)
492  *queueLen, getLen);
493 
494  *queueLen += getLen;
495  }
496  }
497 
498  auto thisProcessLen = mProcessLen;
499  bool last = (*queueLen < (int)mProcessLen);
500  if (last) {
501  thisProcessLen = *queueLen;
502  }
503 
504  double factor = initialWarp;
505  if (mEnvelope)
506  {
507  //TODO-MB: The end time is wrong when the resampler doesn't use all input samples,
508  // as a result of this the warp factor may be slightly wrong, so AudioIO will stop too soon
509  // or too late (resulting in missing sound or inserted silence). This can't be fixed
510  // without changing the way the resampler works, because the number of input samples that will be used
511  // is unpredictable. Maybe it can be compensated later though.
512  if (backwards)
513  factor *= ComputeWarpFactor( *mEnvelope,
514  t - (double)thisProcessLen / trackRate + tstep, t + tstep);
515  else
516  factor *= ComputeWarpFactor( *mEnvelope,
517  t, t + (double)thisProcessLen / trackRate);
518  }
519 
520  auto results = pResample->Process(factor,
521  &queue[*queueStart],
522  thisProcessLen,
523  last,
524  // PRL: Bug2536: crash in soxr happened on Mac, sometimes, when
525  // mMaxOut - out == 1 and &mFloatBuffer[out + 1] was an unmapped
526  // address, because soxr, strangely, fetched an 8-byte (misaligned!)
527  // value from &mFloatBuffer[out], but did nothing with it anyway,
528  // in soxr_output_no_callback.
529  // Now we make the bug go away by allocating a little more space in
530  // the buffer than we need.
531  &mFloatBuffer[out],
532  mMaxOut - out);
533 
534  const auto input_used = results.first;
535  *queueStart += input_used;
536  *queueLen -= input_used;
537  out += results.second;
538  t += (input_used / trackRate) * (backwards ? -1 : 1);
539 
540  if (last) {
541  break;
542  }
543  }
544 
545  for (size_t c = 0; c < mNumChannels; c++) {
546  if (mApplyTrackGains) {
547  mGains[c] = track->GetChannelGain(c);
548  }
549  else {
550  mGains[c] = 1.0;
551  }
552  }
553 
555  channelFlags,
556  mGains.get(),
557  mFloatBuffer.get(),
558  mTemp.get(),
559  out,
560  mInterleaved);
561 
562  return out;
563 }
564 
565 size_t Mixer::MixSameRate(int *channelFlags, WaveTrackCache &cache,
566  sampleCount *pos)
567 {
568  const WaveTrack *const track = cache.GetTrack().get();
569  const double t = ( *pos ).as_double() / track->GetRate();
570  const double trackEndTime = track->GetEndTime();
571  const double trackStartTime = track->GetStartTime();
572  const bool backwards = (mT1 < mT0);
573  const double tEnd = backwards
574  ? std::max(trackStartTime, mT1)
575  : std::min(trackEndTime, mT1);
576 
577  //don't process if we're at the end of the selection or track.
578  if ((backwards ? t <= tEnd : t >= tEnd))
579  return 0;
580  //if we're about to approach the end of the track or selection, figure out how much we need to grab
581  auto slen = limitSampleBufferSize(
582  mMaxOut,
583  // PRL: maybe t and tEnd should be given as sampleCount instead to
584  // avoid trouble subtracting one large value from another for a small
585  // difference
586  sampleCount{ (backwards ? t - tEnd : tEnd - t) * track->GetRate() + 0.5 }
587  );
588 
589  if (backwards) {
590  auto results = cache.GetFloats(*pos - (slen - 1), slen, mMayThrow);
591  if (results)
592  memcpy(mFloatBuffer.get(), results, sizeof(float) * slen);
593  else
594  memset(mFloatBuffer.get(), 0, sizeof(float) * slen);
595  track->GetEnvelopeValues(mEnvValues.get(), slen, t - (slen - 1) / mRate);
596  for(decltype(slen) i = 0; i < slen; i++)
597  mFloatBuffer[i] *= mEnvValues[i]; // Track gain control will go here?
599 
600  *pos -= slen;
601  }
602  else {
603  auto results = cache.GetFloats(*pos, slen, mMayThrow);
604  if (results)
605  memcpy(mFloatBuffer.get(), results, sizeof(float) * slen);
606  else
607  memset(mFloatBuffer.get(), 0, sizeof(float) * slen);
608  track->GetEnvelopeValues(mEnvValues.get(), slen, t);
609  for(decltype(slen) i = 0; i < slen; i++)
610  mFloatBuffer[i] *= mEnvValues[i]; // Track gain control will go here?
611 
612  *pos += slen;
613  }
614 
615  for(size_t c=0; c<mNumChannels; c++)
616  if (mApplyTrackGains)
617  mGains[c] = track->GetChannelGain(c);
618  else
619  mGains[c] = 1.0;
620 
621  MixBuffers(mNumChannels, channelFlags, mGains.get(),
622  mFloatBuffer.get(), mTemp.get(), slen, mInterleaved);
623 
624  return slen;
625 }
626 
627 size_t Mixer::Process(size_t maxToProcess)
628 {
629  // MB: this is wrong! mT represented warped time, and mTime is too inaccurate to use
630  // it here. It's also unnecessary I think.
631  //if (mT >= mT1)
632  // return 0;
633 
634  decltype(Process(0)) maxOut = 0;
635  ArrayOf<int> channelFlags{ mNumChannels };
636 
637  mMaxOut = maxToProcess;
638 
639  Clear();
640  for(size_t i=0; i<mNumInputTracks; i++) {
641  const WaveTrack *const track = mInputTrack[i].GetTrack().get();
642  for(size_t j=0; j<mNumChannels; j++)
643  channelFlags[j] = 0;
644 
645  if( mMixerSpec ) {
646  //ignore left and right when downmixing is not required
647  for(size_t j = 0; j < mNumChannels; j++ )
648  channelFlags[ j ] = mMixerSpec->mMap[ i ][ j ] ? 1 : 0;
649  }
650  else {
651  switch(track->GetChannel()) {
652  case Track::MonoChannel:
653  default:
654  for(size_t j=0; j<mNumChannels; j++)
655  channelFlags[j] = 1;
656  break;
657  case Track::LeftChannel:
658  channelFlags[0] = 1;
659  break;
660  case Track::RightChannel:
661  if (mNumChannels >= 2)
662  channelFlags[1] = 1;
663  else
664  channelFlags[0] = 1;
665  break;
666  }
667  }
668  if (mbVariableRates || track->GetRate() != mRate)
669  maxOut = std::max(maxOut,
670  MixVariableRates(channelFlags.get(), mInputTrack[i],
671  &mSamplePos[i], mSampleQueue[i].get(),
672  &mQueueStart[i], &mQueueLen[i], mResample[i].get()));
673  else
674  maxOut = std::max(maxOut,
675  MixSameRate(channelFlags.get(), mInputTrack[i], &mSamplePos[i]));
676 
677  double t = mSamplePos[i].as_double() / (double)track->GetRate();
678  if (mT0 > mT1)
679  // backwards (as possibly in scrubbing)
680  mTime = std::max(std::min(t, mTime), mT1);
681  else
682  // forwards (the usual)
683  mTime = std::min(std::max(t, mTime), mT1);
684  }
685  if(mInterleaved) {
686  for(size_t c=0; c<mNumChannels; c++) {
687  CopySamples((constSamplePtr)(mTemp[0].get() + c),
688  floatSample,
689  mBuffer[0].ptr() + (c * SAMPLE_SIZE(mFormat)),
690  mFormat,
691  maxOut,
693  mNumChannels,
694  mNumChannels);
695  }
696  }
697  else {
698  for(size_t c=0; c<mNumBuffers; c++) {
699  CopySamples((constSamplePtr)mTemp[c].get(),
700  floatSample,
701  mBuffer[c].ptr(),
702  mFormat,
703  maxOut,
705  }
706  }
707  // MB: this doesn't take warping into account, replaced with code based on mSamplePos
708  //mT += (maxOut / mRate);
709 
710  return maxOut;
711 }
712 
714 {
715  return mBuffer[0].ptr();
716 }
717 
719 {
720  return mBuffer[channel].ptr();
721 }
722 
724 {
725  return mTime;
726 }
727 
729 {
730  mTime = mT0;
731 
732  for(size_t i=0; i<mNumInputTracks; i++)
733  mSamplePos[i] = mInputTrack[i].GetTrack()->TimeToLongSamples(mT0);
734 
735  for(size_t i=0; i<mNumInputTracks; i++) {
736  mQueueStart[i] = 0;
737  mQueueLen[i] = 0;
738  }
739 
740  // Bug 1887: libsoxr 0.1.3, first used in Audacity 2.3.0, crashes with
741  // constant rate resampling if you try to reuse the resampler after it has
742  // flushed. Should that be considered a bug in sox? This works around it:
743  MakeResamplers();
744 }
745 
746 void Mixer::Reposition(double t, bool bSkipping)
747 {
748  mTime = t;
749  const bool backwards = (mT1 < mT0);
750  if (backwards)
751  mTime = std::max(mT1, (std::min(mT0, mTime)));
752  else
753  mTime = std::max(mT0, (std::min(mT1, mTime)));
754 
755  for(size_t i=0; i<mNumInputTracks; i++) {
756  mSamplePos[i] = mInputTrack[i].GetTrack()->TimeToLongSamples(mTime);
757  mQueueStart[i] = 0;
758  mQueueLen[i] = 0;
759  }
760 
761  // Bug 2025: libsoxr 0.1.3, first used in Audacity 2.3.0, crashes with
762  // constant rate resampling if you try to reuse the resampler after it has
763  // flushed. Should that be considered a bug in sox? This works around it.
764  // (See also bug 1887, and the same work around in Mixer::Restart().)
765  if( bSkipping )
766  MakeResamplers();
767 }
768 
769 void Mixer::SetTimesAndSpeed(double t0, double t1, double speed)
770 {
771  wxASSERT(std::isfinite(speed));
772  mT0 = t0;
773  mT1 = t1;
774  mSpeed = fabs(speed);
775  Reposition(t0);
776 }
777 
779 {
780  wxASSERT(std::isfinite(speed));
781  mSpeed = fabs(speed);
782 }
783 
784 void Mixer::SetSpeedForKeyboardScrubbing(double speed, double startTime)
785 {
786  wxASSERT(std::isfinite(speed));
787 
788  // Check if the direction has changed
789  if ((speed > 0.0 && mT1 < mT0) || (speed < 0.0 && mT1 > mT0)) {
790  // It's safe to use 0 and std::numeric_limits<double>::max(),
791  // because Mixer::MixVariableRates() doesn't sample past the start
792  // or end of the audio in a track.
793  if (speed > 0.0 && mT1 < mT0) {
794  mT0 = 0;
795  mT1 = std::numeric_limits<double>::max();
796  }
797  else {
798  mT0 = std::numeric_limits<double>::max();
799  mT1 = 0;
800  }
801 
802  Reposition(startTime, true);
803  }
804 
805  mSpeed = fabs(speed);
806 }
807 
808 MixerSpec::MixerSpec( unsigned numTracks, unsigned maxNumChannels )
809 {
810  mNumTracks = mNumChannels = numTracks;
811  mMaxNumChannels = maxNumChannels;
812 
815 
816  Alloc();
817 
818  for( unsigned int i = 0; i < mNumTracks; i++ )
819  for( unsigned int j = 0; j < mNumChannels; j++ )
820  mMap[ i ][ j ] = ( i == j );
821 }
822 
823 MixerSpec::MixerSpec( const MixerSpec &mixerSpec )
824 {
825  mNumTracks = mixerSpec.mNumTracks;
826  mMaxNumChannels = mixerSpec.mMaxNumChannels;
827  mNumChannels = mixerSpec.mNumChannels;
828 
829  Alloc();
830 
831  for( unsigned int i = 0; i < mNumTracks; i++ )
832  for( unsigned int j = 0; j < mNumChannels; j++ )
833  mMap[ i ][ j ] = mixerSpec.mMap[ i ][ j ];
834 }
835 
837 {
839 }
840 
842 {
843 }
844 
845 bool MixerSpec::SetNumChannels( unsigned newNumChannels )
846 {
847  if( mNumChannels == newNumChannels )
848  return true;
849 
850  if( newNumChannels > mMaxNumChannels )
851  return false;
852 
853  for( unsigned int i = 0; i < mNumTracks; i++ )
854  {
855  for( unsigned int j = newNumChannels; j < mNumChannels; j++ )
856  mMap[ i ][ j ] = false;
857 
858  for( unsigned int j = mNumChannels; j < newNumChannels; j++ )
859  mMap[ i ][ j ] = false;
860  }
861 
862  mNumChannels = newNumChannels;
863  return true;
864 }
865 
867 {
868  mNumTracks = mixerSpec.mNumTracks;
869  mNumChannels = mixerSpec.mNumChannels;
870  mMaxNumChannels = mixerSpec.mMaxNumChannels;
871 
872  Alloc();
873 
874  for( unsigned int i = 0; i < mNumTracks; i++ )
875  for( unsigned int j = 0; j < mNumChannels; j++ )
876  mMap[ i ][ j ] = mixerSpec.mMap[ i ][ j ];
877 
878  return *this;
879 }
880 
WaveTrackCache
A short-lived object, during whose lifetime, the contents of the WaveTrack are assumed not to change.
Definition: WaveTrack.h:633
WaveTrack.h
Mixer::MixSameRate
size_t MixSameRate(int *channelFlags, WaveTrackCache &cache, sampleCount *pos)
Definition: Mix.cpp:565
Mixer::mSampleQueue
FloatBuffers mSampleQueue
Definition: Mix.h:173
Mixer::WarpOptions::maxSpeed
double maxSpeed
Definition: Mix.h:95
WaveTrackConstArray
std::vector< std::shared_ptr< const WaveTrack > > WaveTrackConstArray
Definition: AudioIO.h:49
WaveTrack
A Track that contains audio waveform data.
Definition: WaveTrack.h:69
Mixer::mInterleaved
bool mInterleaved
Definition: Mix.h:187
BasicUI::ProgressResult::Success
@ Success
Mixer::mInputTrack
ArrayOf< WaveTrackCache > mInputTrack
Definition: Mix.h:162
Mixer::mMixerSpec
MixerSpec * mMixerSpec
Definition: Mix.h:177
Mixer::mFormat
const sampleFormat mFormat
Definition: Mix.h:186
MixerSpec::operator=
MixerSpec & operator=(const MixerSpec &mixerSpec)
Definition: Mix.cpp:866
Mixer::mBuffer
ArrayOf< SampleBuffer > mBuffer
Definition: Mix.h:188
Mixer::mMaxOut
size_t mMaxOut
Definition: Mix.h:180
WaveTrack::GetEnvelopeValues
void GetEnvelopeValues(double *buffer, size_t bufferLen, double t0) const
Definition: WaveTrack.cpp:2118
WaveTrack::GetEndTime
double GetEndTime() const override
Get the time at which the last clip in the track ends, plus recorded stuff.
Definition: WaveTrack.cpp:1895
Track::GetName
wxString GetName() const
Definition: Track.h:426
Mixer::mEnvelope
const BoundedEnvelope * mEnvelope
Definition: Mix.h:164
Mixer::mRate
const double mRate
Definition: Mix.h:191
Mixer::WarpOptions
Definition: Mix.h:81
Mixer::mGains
Floats mGains
Definition: Mix.h:182
TrackList::Channels
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1484
Mix.h
TrackList
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
Definition: Track.h:1280
Mixer::Reposition
void Reposition(double t, bool bSkipping=false)
Definition: Mix.cpp:746
Envelope
Piecewise linear or piecewise exponential function from double to double.
Definition: Envelope.h:71
MixerSpec::MixerSpec
MixerSpec(unsigned numTracks, unsigned maxNumChannels)
Definition: Mix.cpp:808
ArrayOf::reinit
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:57
Mixer::MakeResamplers
void MakeResamplers()
Definition: Mix.cpp:350
Mixer::SetSpeedForKeyboardScrubbing
void SetSpeedForKeyboardScrubbing(double speed, double startTime)
Definition: Mix.cpp:784
Mixer::mEnvValues
Doubles mEnvValues
Definition: Mix.h:167
SAMPLE_SIZE
#define SAMPLE_SIZE(SampleFormat)
Definition: SampleFormat.h:44
RefreshCode::Cancelled
@ Cancelled
Definition: RefreshCode.h:23
XO
#define XO(s)
Definition: Internat.h:31
ReverseSamples
void ReverseSamples(samplePtr dst, sampleFormat format, int start, int len)
Definition: SampleFormat.cpp:84
ProgressDialog.h
TimeTrack.h
Mixer::SetTimesAndSpeed
void SetTimesAndSpeed(double t0, double t1, double speed)
Definition: Mix.cpp:769
Mixer::WarpOptions::minSpeed
double minSpeed
Definition: Mix.h:95
WaveTrackCache::GetFloats
const float * GetFloats(sampleCount start, size_t len, bool mayThrow)
Retrieve samples as floats from the track or from the memory cache.
Definition: WaveTrack.cpp:2646
MixerSpec::~MixerSpec
virtual ~MixerSpec()
Definition: Mix.cpp:841
floatSample
@ floatSample
Definition: SampleFormat.h:34
ArraysOf::reinit
void reinit(Integral count)
Definition: MemoryX.h:109
WaveTrack::Holder
std::shared_ptr< WaveTrack > Holder
Definition: WaveTrack.h:96
BoundedEnvelope
Definition: Envelope.h:284
ProgressDialog
ProgressDialog Class.
Definition: ProgressDialog.h:51
MixerSpec::mMap
ArraysOf< bool > mMap
Definition: Mix.h:61
CopySamples
void CopySamples(constSamplePtr src, sampleFormat srcFormat, samplePtr dst, sampleFormat dstFormat, size_t len, DitherType ditherType, unsigned int srcStride, unsigned int dstStride)
Copy samples from any format to any other format; apply dithering only if narrowing the format.
Definition: SampleFormat.cpp:111
Mixer::mFloatBuffer
Floats mFloatBuffer
Definition: Mix.h:190
constSamplePtr
const char * constSamplePtr
Definition: SampleFormat.h:50
Mixer::MixVariableRates
size_t MixVariableRates(int *channelFlags, WaveTrackCache &cache, sampleCount *pos, float *queue, int *queueStart, int *queueLen, Resample *pResample)
Definition: Mix.cpp:410
Mixer::mTime
double mTime
Definition: Mix.h:170
Mixer::mTemp
ArrayOf< Floats > mTemp
Definition: Mix.h:189
Mixer::mNumInputTracks
const size_t mNumInputTracks
Definition: Mix.h:161
Track::RightChannel
@ RightChannel
Definition: Track.h:277
format
int format
Definition: ExportPCM.cpp:56
ProgressDialog::Update
ProgressResult Update(int value, const TranslatableString &message={})
Definition: ProgressDialog.cpp:1327
MixerSpec::mMaxNumChannels
unsigned mMaxNumChannels
Definition: Mix.h:56
Mixer::mSamplePos
ArrayOf< sampleCount > mSamplePos
Definition: Mix.h:165
anonymous_namespace{NoteTrack.cpp}::swap
void swap(std::unique_ptr< Alg_seq > &a, std::unique_ptr< Alg_seq > &b)
Definition: NoteTrack.cpp:735
MixerSpec::SetNumChannels
bool SetNumChannels(unsigned numChannels)
Definition: Mix.cpp:845
Mixer::mT0
double mT0
Definition: Mix.h:168
WaveTrack::GetStartTime
double GetStartTime() const override
Get the time at which the first clip in the track starts.
Definition: WaveTrack.cpp:1875
Mixer::mMaxFactor
std::vector< double > mMaxFactor
Definition: Mix.h:194
Resample
Interface to libsoxr.
Definition: Resample.h:27
Mixer::mT1
double mT1
Definition: Mix.h:169
WaveTrackFactory
Used to create or clone a WaveTrack, with appropriate context from the project that will own the trac...
Definition: WaveTrack.h:710
Mixer::Clear
void Clear()
Definition: Mix.cpp:356
Envelope.h
Envelope::AverageOfInverse
double AverageOfInverse(double t0, double t1) const
Definition: Envelope.cpp:1079
sampleFormat
sampleFormat
Definition: SampleFormat.h:29
samplePtr
char * samplePtr
Definition: SampleFormat.h:49
MixerSpec::mNumChannels
unsigned mNumChannels
Definition: Mix.h:56
min
int min(int a, int b)
Definition: CompareAudioCommand.cpp:106
Mixer::mQueueLen
ArrayOf< int > mQueueLen
Definition: Mix.h:175
MixAndRender
void MixAndRender(TrackList *tracks, WaveTrackFactory *trackFactory, double rate, sampleFormat format, double startTime, double endTime, WaveTrack::Holder &uLeft, WaveTrack::Holder &uRight)
Mixes together all input tracks, applying any envelopes, amplitude gain, panning, and real-time effec...
Definition: Mix.cpp:43
WaveTrackCache::GetTrack
const std::shared_ptr< const WaveTrack > & GetTrack() const
Definition: WaveTrack.h:651
Mixer::MixGetCurrentTime
double MixGetCurrentTime()
Definition: Mix.cpp:723
Mixer::mHighQuality
bool mHighQuality
Definition: Mix.h:193
Mixer::SetSpeedForPlayAtSpeed
void SetSpeedForPlayAtSpeed(double speed)
Definition: Mix.cpp:778
MixBuffers
static void MixBuffers(unsigned numChannels, int *channelFlags, float *gains, const float *src, Floats *dests, int len, bool interleaved)
Definition: Mix.cpp:363
WaveTrack::TimeToLongSamples
sampleCount TimeToLongSamples(double t0) const
Convert correctly between an (absolute) time in seconds and a number of samples.
Definition: WaveTrack.cpp:1865
Mixer::Restart
void Restart()
Definition: Mix.cpp:728
_
#define _(s)
Definition: Internat.h:75
Mixer::WarpOptions::WarpOptions
WarpOptions(const TrackList &list)
Construct with warp from the TimeTrack if there is one.
Definition: Mix.cpp:206
sampleCount
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:18
Mixer::mQueueMaxLen
const size_t mQueueMaxLen
Definition: Mix.h:172
Mixer::mResample
ArrayOf< std::unique_ptr< Resample > > mResample
Definition: Mix.h:171
Track::MonoChannel
@ MonoChannel
Definition: Track.h:278
Mixer::mSpeed
double mSpeed
Definition: Mix.h:192
gLowQualityDither
DitherType gLowQualityDither
Definition: SampleFormat.cpp:49
Mixer::mNumBuffers
unsigned mNumBuffers
Definition: Mix.h:183
Mixer::mNumChannels
const unsigned mNumChannels
Definition: Mix.h:181
Resample::Process
std::pair< size_t, size_t > Process(double factor, float *inBuffer, size_t inBufferLen, bool lastFlag, float *outBuffer, size_t outBufferLen)
Main processing function. Resamples from the input buffer to the output buffer.
Definition: Resample.cpp:88
gHighQualityDither
DitherType gHighQualityDither
Definition: SampleFormat.cpp:50
Mixer::WarpOptions::envelope
const BoundedEnvelope * envelope
Definition: Mix.h:94
Mixer::GetBuffer
constSamplePtr GetBuffer()
Retrieve the main buffer or the interleaved buffer.
Definition: Mix.cpp:713
Mixer::mMinFactor
std::vector< double > mMinFactor
Definition: Mix.h:194
Mixer::mMayThrow
const bool mMayThrow
Definition: Mix.h:196
Prefs.h
MixerSpec::Alloc
void Alloc()
Definition: Mix.cpp:836
anonymous_namespace{Mix.cpp}::ComputeWarpFactor
double ComputeWarpFactor(const Envelope &env, double t0, double t1)
Compute the integral warp factor between two non-warped time points.
Definition: Mix.cpp:403
WaveTrack::GetChannelGain
float GetChannelGain(int channel) const
Definition: WaveTrack.cpp:500
Mixer::mApplyTrackGains
const bool mApplyTrackGains
Definition: Mix.h:166
TrackList::Any
auto Any() -> TrackIterRange< TrackType >
Definition: Track.h:1371
WaveTrack::GetPan
float GetPan() const
Definition: WaveTrack.cpp:482
MixerSpec
Class used with Mixer.
Definition: Mix.h:55
MixerSpec::mNumTracks
unsigned mNumTracks
Definition: Mix.h:56
float_cast.h
limitSampleBufferSize
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
Definition: SampleCount.cpp:23
Track::LeftChannel
@ LeftChannel
Definition: Track.h:276
Mixer::mInterleavedBufferSize
size_t mInterleavedBufferSize
Definition: Mix.h:185
WaveTrack::GetChannel
ChannelType GetChannel() const override
Definition: WaveTrack.cpp:253
TrackList::Selected
auto Selected() -> TrackIterRange< TrackType >
Definition: Track.h:1388
Mixer
Functions for doing the mixdown of the tracks.
Definition: Mix.h:76
Mixer::mQueueStart
ArrayOf< int > mQueueStart
Definition: Mix.h:174
WaveTrackFactory::NewWaveTrack
std::shared_ptr< WaveTrack > NewWaveTrack(sampleFormat format=(sampleFormat) 0, double rate=0)
Definition: WaveTrack.cpp:113
ArrayOf< float >
Mixer::mProcessLen
size_t mProcessLen
Definition: Mix.h:176
TimeTrack
A kind of Track used to 'warp time'.
Definition: TimeTrack.h:24
Resample.h
Mixer::Process
size_t Process(size_t maxSamples)
Definition: Mix.cpp:627
Mixer::mbVariableRates
bool mbVariableRates
Definition: Mix.h:163
Mixer::Mixer
Mixer(const WaveTrackConstArray &inputTracks, bool mayThrow, const WarpOptions &warpOptions, double startTime, double stopTime, unsigned numOutChannels, size_t outBufferSize, bool outInterleaved, double outRate, sampleFormat outFormat, bool highQuality=true, MixerSpec *mixerSpec=nullptr, bool applytTrackGains=true)
Definition: Mix.cpp:237
WaveTrack::GetRate
double GetRate() const
Definition: WaveTrack.cpp:452