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  samplePtr buffer = mixer.GetBuffer();
169  mixLeft->Append(buffer, format, blockLen);
170  }
171  else {
172  samplePtr buffer;
173  buffer = mixer.GetBuffer(0);
174  mixLeft->Append(buffer, format, blockLen);
175  buffer = mixer.GetBuffer(1);
176  mixRight->Append(buffer, format, blockLen);
177  }
178 
179  updateResult = progress.Update(mixer.MixGetCurrentTime() - startTime, endTime - startTime);
180  }
181  }
182 
183  mixLeft->Flush();
184  if (!mono)
185  mixRight->Flush();
186  if (updateResult == ProgressResult::Cancelled || updateResult == ProgressResult::Failed)
187  {
188  return;
189  }
190  else {
191  uLeft = mixLeft, uRight = mixRight;
192 #if 0
193  int elapsedMS = wxGetElapsedTime();
194  double elapsedTime = elapsedMS * 0.001;
195  double maxTracks = totalTime / (elapsedTime / numWaves);
196 
197  // Note: these shouldn't be translated - they're for debugging
198  // and profiling only.
199  wxPrintf(" Tracks: %d\n", numWaves);
200  wxPrintf(" Mix length: %f sec\n", totalTime);
201  wxPrintf("Elapsed time: %f sec\n", elapsedTime);
202  wxPrintf("Max number of tracks to mix in real time: %f\n", maxTracks);
203 #endif
204  }
205 }
206 
208 : minSpeed(0.0), maxSpeed(0.0)
209 {
210  auto timeTrack = *(list.Any<const TimeTrack>().begin());
211  envelope = timeTrack ? timeTrack->GetEnvelope() : nullptr;
212 }
213 
215  : envelope(e), minSpeed(0.0), maxSpeed(0.0)
216  {}
217 
219  : minSpeed(min), maxSpeed(max)
220 {
221  if (minSpeed < 0)
222  {
223  wxASSERT(false);
224  minSpeed = 0;
225  }
226  if (maxSpeed < 0)
227  {
228  wxASSERT(false);
229  maxSpeed = 0;
230  }
231  if (minSpeed > maxSpeed)
232  {
233  wxASSERT(false);
235  }
236 }
237 
239  bool mayThrow,
240  const WarpOptions &warpOptions,
241  double startTime, double stopTime,
242  unsigned numOutChannels, size_t outBufferSize, bool outInterleaved,
243  double outRate, sampleFormat outFormat,
244  bool highQuality, MixerSpec *mixerSpec, bool applyTrackGains)
245  : mNumInputTracks { inputTracks.size() }
246 
247  , mApplyTrackGains{ applyTrackGains }
248 
249  // This is the number of samples grabbed in one go from a track
250  // and placed in a queue, when mixing with resampling.
251  // (Should we use WaveTrack::GetBestBlockSize instead?)
252  , mQueueMaxLen{ 65536 }
253  , mSampleQueue{ mNumInputTracks, mQueueMaxLen }
254 
255  , mNumChannels{ numOutChannels }
256  , mGains{ mNumChannels }
257 
258  , mFormat{ outFormat }
259  , mRate{ outRate }
260 
261  , mMayThrow{ mayThrow }
262 {
263  mHighQuality = highQuality;
264  mInputTrack.reinit(mNumInputTracks);
265 
266  // mSamplePos holds for each track the next sample position not
267  // yet processed.
268  mSamplePos.reinit(mNumInputTracks);
269  for(size_t i=0; i<mNumInputTracks; i++) {
270  mInputTrack[i].SetTrack(inputTracks[i]);
271  mSamplePos[i] = inputTracks[i]->TimeToLongSamples(startTime);
272  }
273  mEnvelope = warpOptions.envelope;
274  mT0 = startTime;
275  mT1 = stopTime;
276  mTime = startTime;
277  mBufferSize = outBufferSize;
278  mInterleaved = outInterleaved;
279  mSpeed = 1.0;
280  if( mixerSpec && mixerSpec->GetNumChannels() == mNumChannels &&
281  mixerSpec->GetNumTracks() == mNumInputTracks )
282  mMixerSpec = mixerSpec;
283  else
284  mMixerSpec = NULL;
285 
286  if (mInterleaved) {
287  mNumBuffers = 1;
288  mInterleavedBufferSize = mBufferSize * mNumChannels;
289  }
290  else {
291  mNumBuffers = mNumChannels;
292  mInterleavedBufferSize = mBufferSize;
293  }
294 
295  mBuffer.reinit(mNumBuffers);
296  mTemp.reinit(mNumBuffers);
297  for (unsigned int c = 0; c < mNumBuffers; c++) {
298  mBuffer[c].Allocate(mInterleavedBufferSize, mFormat);
299  mTemp[c].Allocate(mInterleavedBufferSize, floatSample);
300  }
301  // PRL: Bug2536: see other comments below
302  mFloatBuffer = Floats{ mInterleavedBufferSize + 1 };
303 
304  // But cut the queue into blocks of this finer size
305  // for variable rate resampling. Each block is resampled at some
306  // constant rate.
307  mProcessLen = 1024;
308 
309  // Position in each queue of the start of the next block to resample.
310  mQueueStart.reinit(mNumInputTracks);
311 
312  // For each queue, the number of available samples after the queue start.
313  mQueueLen.reinit(mNumInputTracks);
314  mResample.reinit(mNumInputTracks);
315  mMinFactor.resize(mNumInputTracks);
316  mMaxFactor.resize(mNumInputTracks);
317  for (size_t i = 0; i<mNumInputTracks; i++) {
318  double factor = (mRate / mInputTrack[i].GetTrack()->GetRate());
319  if (mEnvelope) {
320  // variable rate resampling
321  mbVariableRates = true;
322  mMinFactor[i] = factor / mEnvelope->GetRangeUpper();
323  mMaxFactor[i] = factor / mEnvelope->GetRangeLower();
324  }
325  else if (warpOptions.minSpeed > 0.0 && warpOptions.maxSpeed > 0.0) {
326  // variable rate resampling
327  mbVariableRates = true;
328  mMinFactor[i] = factor / warpOptions.maxSpeed;
329  mMaxFactor[i] = factor / warpOptions.minSpeed;
330  }
331  else {
332  // constant rate resampling
333  mbVariableRates = false;
334  mMinFactor[i] = mMaxFactor[i] = factor;
335  }
336 
337  mQueueStart[i] = 0;
338  mQueueLen[i] = 0;
339  }
340 
341  MakeResamplers();
342 
343  const auto envLen = std::max(mQueueMaxLen, mInterleavedBufferSize);
344  mEnvValues.reinit(envLen);
345 }
346 
347 Mixer::~Mixer()
348 {
349 }
350 
352 {
353  for (size_t i = 0; i < mNumInputTracks; i++)
354  mResample[i] = std::make_unique<Resample>(mHighQuality, mMinFactor[i], mMaxFactor[i]);
355 }
356 
358 {
359  for (unsigned int c = 0; c < mNumBuffers; c++) {
360  memset(mTemp[c].ptr(), 0, mInterleavedBufferSize * SAMPLE_SIZE(floatSample));
361  }
362 }
363 
364 void MixBuffers(unsigned numChannels, int *channelFlags, float *gains,
365  samplePtr src, SampleBuffer *dests,
366  int len, bool interleaved)
367 {
368  for (unsigned int c = 0; c < numChannels; c++) {
369  if (!channelFlags[c])
370  continue;
371 
372  samplePtr destPtr;
373  unsigned skip;
374 
375  if (interleaved) {
376  destPtr = dests[0].ptr() + c*SAMPLE_SIZE(floatSample);
377  skip = numChannels;
378  } else {
379  destPtr = dests[c].ptr();
380  skip = 1;
381  }
382 
383  float gain = gains[c];
384  float *dest = (float *)destPtr;
385  float *temp = (float *)src;
386  for (int j = 0; j < len; j++) {
387  *dest += temp[j] * gain; // the actual mixing process
388  dest += skip;
389  }
390  }
391 }
392 
393 namespace {
394  //Note: The meaning of this function has changed (December 2012)
395  //Previously this function did something that was close to the opposite (but not entirely accurate).
406 double ComputeWarpFactor(const Envelope &env, double t0, double t1)
407 {
408  return env.AverageOfInverse(t0, t1);
409 }
410 
411 }
412 
413 size_t Mixer::MixVariableRates(int *channelFlags, WaveTrackCache &cache,
414  sampleCount *pos, float *queue,
415  int *queueStart, int *queueLen,
416  Resample * pResample)
417 {
418  const WaveTrack *const track = cache.GetTrack().get();
419  const double trackRate = track->GetRate();
420  const double initialWarp = mRate / mSpeed / trackRate;
421  const double tstep = 1.0 / trackRate;
422  auto sampleSize = SAMPLE_SIZE(floatSample);
423 
424  decltype(mMaxOut) out = 0;
425 
426  /* time is floating point. Sample rate is integer. The number of samples
427  * has to be integer, but the multiplication gives a float result, which we
428  * round to get an integer result. TODO: is this always right or can it be
429  * off by one sometimes? Can we not get this information directly from the
430  * clip (which must know) rather than convert the time?
431  *
432  * LLL: Not at this time. While WaveClips provide methods to retrieve the
433  * start and end sample, they do the same float->sampleCount conversion
434  * to calculate the position.
435  */
436 
437  // Find the last sample
438  double endTime = track->GetEndTime();
439  double startTime = track->GetStartTime();
440  const bool backwards = (mT1 < mT0);
441  const double tEnd = backwards
442  ? std::max(startTime, mT1)
443  : std::min(endTime, mT1);
444  const auto endPos = track->TimeToLongSamples(tEnd);
445  // Find the time corresponding to the start of the queue, for use with time track
446  double t = ((*pos).as_long_long() +
447  (backwards ? *queueLen : - *queueLen)) / trackRate;
448 
449  while (out < mMaxOut) {
450  if (*queueLen < (int)mProcessLen) {
451  // Shift pending portion to start of the buffer
452  memmove(queue, &queue[*queueStart], (*queueLen) * sampleSize);
453  *queueStart = 0;
454 
455  auto getLen = limitSampleBufferSize(
456  mQueueMaxLen - *queueLen,
457  backwards ? *pos - endPos : endPos - *pos
458  );
459 
460  // Nothing to do if past end of play interval
461  if (getLen > 0) {
462  if (backwards) {
463  auto results = cache.Get(floatSample, *pos - (getLen - 1), getLen, mMayThrow);
464  if (results)
465  memcpy(&queue[*queueLen], results, sizeof(float) * getLen);
466  else
467  memset(&queue[*queueLen], 0, sizeof(float) * getLen);
468 
469  track->GetEnvelopeValues(mEnvValues.get(),
470  getLen,
471  (*pos - (getLen- 1)).as_double() / trackRate);
472  *pos -= getLen;
473  }
474  else {
475  auto results = cache.Get(floatSample, *pos, getLen, mMayThrow);
476  if (results)
477  memcpy(&queue[*queueLen], results, sizeof(float) * getLen);
478  else
479  memset(&queue[*queueLen], 0, sizeof(float) * getLen);
480 
481  track->GetEnvelopeValues(mEnvValues.get(),
482  getLen,
483  (*pos).as_double() / trackRate);
484 
485  *pos += getLen;
486  }
487 
488  for (decltype(getLen) i = 0; i < getLen; i++) {
489  queue[(*queueLen) + i] *= mEnvValues[i];
490  }
491 
492  if (backwards)
494  *queueLen, getLen);
495 
496  *queueLen += getLen;
497  }
498  }
499 
500  auto thisProcessLen = mProcessLen;
501  bool last = (*queueLen < (int)mProcessLen);
502  if (last) {
503  thisProcessLen = *queueLen;
504  }
505 
506  double factor = initialWarp;
507  if (mEnvelope)
508  {
509  //TODO-MB: The end time is wrong when the resampler doesn't use all input samples,
510  // as a result of this the warp factor may be slightly wrong, so AudioIO will stop too soon
511  // or too late (resulting in missing sound or inserted silence). This can't be fixed
512  // without changing the way the resampler works, because the number of input samples that will be used
513  // is unpredictable. Maybe it can be compensated later though.
514  if (backwards)
515  factor *= ComputeWarpFactor( *mEnvelope,
516  t - (double)thisProcessLen / trackRate + tstep, t + tstep);
517  else
518  factor *= ComputeWarpFactor( *mEnvelope,
519  t, t + (double)thisProcessLen / trackRate);
520  }
521 
522  auto results = pResample->Process(factor,
523  &queue[*queueStart],
524  thisProcessLen,
525  last,
526  // PRL: Bug2536: crash in soxr happened on Mac, sometimes, when
527  // mMaxOut - out == 1 and &mFloatBuffer[out + 1] was an unmapped
528  // address, because soxr, strangely, fetched an 8-byte (misaligned!)
529  // value from &mFloatBuffer[out], but did nothing with it anyway,
530  // in soxr_output_no_callback.
531  // Now we make the bug go away by allocating a little more space in
532  // the buffer than we need.
533  &mFloatBuffer[out],
534  mMaxOut - out);
535 
536  const auto input_used = results.first;
537  *queueStart += input_used;
538  *queueLen -= input_used;
539  out += results.second;
540  t += (input_used / trackRate) * (backwards ? -1 : 1);
541 
542  if (last) {
543  break;
544  }
545  }
546 
547  for (size_t c = 0; c < mNumChannels; c++) {
548  if (mApplyTrackGains) {
549  mGains[c] = track->GetChannelGain(c);
550  }
551  else {
552  mGains[c] = 1.0;
553  }
554  }
555 
557  channelFlags,
558  mGains.get(),
559  (samplePtr)mFloatBuffer.get(),
560  mTemp.get(),
561  out,
562  mInterleaved);
563 
564  return out;
565 }
566 
567 size_t Mixer::MixSameRate(int *channelFlags, WaveTrackCache &cache,
568  sampleCount *pos)
569 {
570  const WaveTrack *const track = cache.GetTrack().get();
571  const double t = ( *pos ).as_double() / track->GetRate();
572  const double trackEndTime = track->GetEndTime();
573  const double trackStartTime = track->GetStartTime();
574  const bool backwards = (mT1 < mT0);
575  const double tEnd = backwards
576  ? std::max(trackStartTime, mT1)
577  : std::min(trackEndTime, mT1);
578 
579  //don't process if we're at the end of the selection or track.
580  if ((backwards ? t <= tEnd : t >= tEnd))
581  return 0;
582  //if we're about to approach the end of the track or selection, figure out how much we need to grab
583  auto slen = limitSampleBufferSize(
584  mMaxOut,
585  // PRL: maybe t and tEnd should be given as sampleCount instead to
586  // avoid trouble subtracting one large value from another for a small
587  // difference
588  sampleCount{ (backwards ? t - tEnd : tEnd - t) * track->GetRate() + 0.5 }
589  );
590 
591  if (backwards) {
592  auto results = cache.Get(floatSample, *pos - (slen - 1), slen, mMayThrow);
593  if (results)
594  memcpy(mFloatBuffer.get(), results, sizeof(float) * slen);
595  else
596  memset(mFloatBuffer.get(), 0, sizeof(float) * slen);
597  track->GetEnvelopeValues(mEnvValues.get(), slen, t - (slen - 1) / mRate);
598  for(decltype(slen) i = 0; i < slen; i++)
599  mFloatBuffer[i] *= mEnvValues[i]; // Track gain control will go here?
601 
602  *pos -= slen;
603  }
604  else {
605  auto results = cache.Get(floatSample, *pos, slen, mMayThrow);
606  if (results)
607  memcpy(mFloatBuffer.get(), results, sizeof(float) * slen);
608  else
609  memset(mFloatBuffer.get(), 0, sizeof(float) * slen);
610  track->GetEnvelopeValues(mEnvValues.get(), slen, t);
611  for(decltype(slen) i = 0; i < slen; i++)
612  mFloatBuffer[i] *= mEnvValues[i]; // Track gain control will go here?
613 
614  *pos += slen;
615  }
616 
617  for(size_t c=0; c<mNumChannels; c++)
618  if (mApplyTrackGains)
619  mGains[c] = track->GetChannelGain(c);
620  else
621  mGains[c] = 1.0;
622 
623  MixBuffers(mNumChannels, channelFlags, mGains.get(),
624  (samplePtr)mFloatBuffer.get(), mTemp.get(), slen, mInterleaved);
625 
626  return slen;
627 }
628 
629 size_t Mixer::Process(size_t maxToProcess)
630 {
631  // MB: this is wrong! mT represented warped time, and mTime is too inaccurate to use
632  // it here. It's also unnecessary I think.
633  //if (mT >= mT1)
634  // return 0;
635 
636  decltype(Process(0)) maxOut = 0;
637  ArrayOf<int> channelFlags{ mNumChannels };
638 
639  mMaxOut = maxToProcess;
640 
641  Clear();
642  for(size_t i=0; i<mNumInputTracks; i++) {
643  const WaveTrack *const track = mInputTrack[i].GetTrack().get();
644  for(size_t j=0; j<mNumChannels; j++)
645  channelFlags[j] = 0;
646 
647  if( mMixerSpec ) {
648  //ignore left and right when downmixing is not required
649  for(size_t j = 0; j < mNumChannels; j++ )
650  channelFlags[ j ] = mMixerSpec->mMap[ i ][ j ] ? 1 : 0;
651  }
652  else {
653  switch(track->GetChannel()) {
654  case Track::MonoChannel:
655  default:
656  for(size_t j=0; j<mNumChannels; j++)
657  channelFlags[j] = 1;
658  break;
659  case Track::LeftChannel:
660  channelFlags[0] = 1;
661  break;
662  case Track::RightChannel:
663  if (mNumChannels >= 2)
664  channelFlags[1] = 1;
665  else
666  channelFlags[0] = 1;
667  break;
668  }
669  }
670  if (mbVariableRates || track->GetRate() != mRate)
671  maxOut = std::max(maxOut,
672  MixVariableRates(channelFlags.get(), mInputTrack[i],
673  &mSamplePos[i], mSampleQueue[i].get(),
674  &mQueueStart[i], &mQueueLen[i], mResample[i].get()));
675  else
676  maxOut = std::max(maxOut,
677  MixSameRate(channelFlags.get(), mInputTrack[i], &mSamplePos[i]));
678 
679  double t = mSamplePos[i].as_double() / (double)track->GetRate();
680  if (mT0 > mT1)
681  // backwards (as possibly in scrubbing)
682  mTime = std::max(std::min(t, mTime), mT1);
683  else
684  // forwards (the usual)
685  mTime = std::min(std::max(t, mTime), mT1);
686  }
687  if(mInterleaved) {
688  for(size_t c=0; c<mNumChannels; c++) {
689  CopySamples(mTemp[0].ptr() + (c * SAMPLE_SIZE(floatSample)),
690  floatSample,
691  mBuffer[0].ptr() + (c * SAMPLE_SIZE(mFormat)),
692  mFormat,
693  maxOut,
694  mHighQuality,
695  mNumChannels,
696  mNumChannels);
697  }
698  }
699  else {
700  for(size_t c=0; c<mNumBuffers; c++) {
701  CopySamples(mTemp[c].ptr(),
702  floatSample,
703  mBuffer[c].ptr(),
704  mFormat,
705  maxOut,
706  mHighQuality);
707  }
708  }
709  // MB: this doesn't take warping into account, replaced with code based on mSamplePos
710  //mT += (maxOut / mRate);
711 
712  return maxOut;
713 }
714 
716 {
717  return mBuffer[0].ptr();
718 }
719 
721 {
722  return mBuffer[channel].ptr();
723 }
724 
726 {
727  return mTime;
728 }
729 
731 {
732  mTime = mT0;
733 
734  for(size_t i=0; i<mNumInputTracks; i++)
735  mSamplePos[i] = mInputTrack[i].GetTrack()->TimeToLongSamples(mT0);
736 
737  for(size_t i=0; i<mNumInputTracks; i++) {
738  mQueueStart[i] = 0;
739  mQueueLen[i] = 0;
740  }
741 
742  // Bug 1887: libsoxr 0.1.3, first used in Audacity 2.3.0, crashes with
743  // constant rate resampling if you try to reuse the resampler after it has
744  // flushed. Should that be considered a bug in sox? This works around it:
745  MakeResamplers();
746 }
747 
748 void Mixer::Reposition(double t, bool bSkipping)
749 {
750  mTime = t;
751  const bool backwards = (mT1 < mT0);
752  if (backwards)
753  mTime = std::max(mT1, (std::min(mT0, mTime)));
754  else
755  mTime = std::max(mT0, (std::min(mT1, mTime)));
756 
757  for(size_t i=0; i<mNumInputTracks; i++) {
758  mSamplePos[i] = mInputTrack[i].GetTrack()->TimeToLongSamples(mTime);
759  mQueueStart[i] = 0;
760  mQueueLen[i] = 0;
761  }
762 
763  // Bug 2025: libsoxr 0.1.3, first used in Audacity 2.3.0, crashes with
764  // constant rate resampling if you try to reuse the resampler after it has
765  // flushed. Should that be considered a bug in sox? This works around it.
766  // (See also bug 1887, and the same work around in Mixer::Restart().)
767  if( bSkipping )
768  MakeResamplers();
769 }
770 
771 void Mixer::SetTimesAndSpeed(double t0, double t1, double speed)
772 {
773  wxASSERT(std::isfinite(speed));
774  mT0 = t0;
775  mT1 = t1;
776  mSpeed = fabs(speed);
777  Reposition(t0);
778 }
779 
781 {
782  wxASSERT(std::isfinite(speed));
783  mSpeed = fabs(speed);
784 }
785 
786 void Mixer::SetSpeedForKeyboardScrubbing(double speed, double startTime)
787 {
788  wxASSERT(std::isfinite(speed));
789 
790  // Check if the direction has changed
791  if ((speed > 0.0 && mT1 < mT0) || (speed < 0.0 && mT1 > mT0)) {
792  // It's safe to use 0 and std::numeric_limits<double>::max(),
793  // because Mixer::MixVariableRates() doesn't sample past the start
794  // or end of the audio in a track.
795  if (speed > 0.0 && mT1 < mT0) {
796  mT0 = 0;
797  mT1 = std::numeric_limits<double>::max();
798  }
799  else {
800  mT0 = std::numeric_limits<double>::max();
801  mT1 = 0;
802  }
803 
804  Reposition(startTime, true);
805  }
806 
807  mSpeed = fabs(speed);
808 }
809 
810 MixerSpec::MixerSpec( unsigned numTracks, unsigned maxNumChannels )
811 {
812  mNumTracks = mNumChannels = numTracks;
813  mMaxNumChannels = maxNumChannels;
814 
817 
818  Alloc();
819 
820  for( unsigned int i = 0; i < mNumTracks; i++ )
821  for( unsigned int j = 0; j < mNumChannels; j++ )
822  mMap[ i ][ j ] = ( i == j );
823 }
824 
825 MixerSpec::MixerSpec( const MixerSpec &mixerSpec )
826 {
827  mNumTracks = mixerSpec.mNumTracks;
828  mMaxNumChannels = mixerSpec.mMaxNumChannels;
829  mNumChannels = mixerSpec.mNumChannels;
830 
831  Alloc();
832 
833  for( unsigned int i = 0; i < mNumTracks; i++ )
834  for( unsigned int j = 0; j < mNumChannels; j++ )
835  mMap[ i ][ j ] = mixerSpec.mMap[ i ][ j ];
836 }
837 
839 {
841 }
842 
844 {
845 }
846 
847 bool MixerSpec::SetNumChannels( unsigned newNumChannels )
848 {
849  if( mNumChannels == newNumChannels )
850  return true;
851 
852  if( newNumChannels > mMaxNumChannels )
853  return false;
854 
855  for( unsigned int i = 0; i < mNumTracks; i++ )
856  {
857  for( unsigned int j = newNumChannels; j < mNumChannels; j++ )
858  mMap[ i ][ j ] = false;
859 
860  for( unsigned int j = mNumChannels; j < newNumChannels; j++ )
861  mMap[ i ][ j ] = false;
862  }
863 
864  mNumChannels = newNumChannels;
865  return true;
866 }
867 
869 {
870  mNumTracks = mixerSpec.mNumTracks;
871  mNumChannels = mixerSpec.mNumChannels;
872  mMaxNumChannels = mixerSpec.mMaxNumChannels;
873 
874  Alloc();
875 
876  for( unsigned int i = 0; i < mNumTracks; i++ )
877  for( unsigned int j = 0; j < mNumChannels; j++ )
878  mMap[ i ][ j ] = mixerSpec.mMap[ i ][ j ];
879 
880  return *this;
881 }
882 
WaveTrackCache
Definition: WaveTrack.h:599
WaveTrack.h
Mixer::MixSameRate
size_t MixSameRate(int *channelFlags, WaveTrackCache &cache, sampleCount *pos)
Definition: Mix.cpp:567
Mixer::mSampleQueue
FloatBuffers mSampleQueue
Definition: Mix.h:175
Mixer::WarpOptions::maxSpeed
double maxSpeed
Definition: Mix.h:97
MixBuffers
void MixBuffers(unsigned numChannels, int *channelFlags, float *gains, samplePtr src, SampleBuffer *dests, int len, bool interleaved)
Definition: Mix.cpp:364
WaveTrackConstArray
std::vector< std::shared_ptr< const WaveTrack > > WaveTrackConstArray
Definition: AudioIO.h:63
Mixer::GetBuffer
samplePtr GetBuffer()
Retrieve the main buffer or the interleaved buffer.
Definition: Mix.cpp:715
WaveTrack
A Track that contains audio waveform data.
Definition: WaveTrack.h:68
Mixer::mInterleaved
bool mInterleaved
Definition: Mix.h:189
Track::RightChannel
static const auto RightChannel
Definition: Track.h:266
Mixer::mInputTrack
ArrayOf< WaveTrackCache > mInputTrack
Definition: Mix.h:164
Mixer::mMixerSpec
MixerSpec * mMixerSpec
Definition: Mix.h:179
Mixer::mFormat
const sampleFormat mFormat
Definition: Mix.h:188
MixerSpec::operator=
MixerSpec & operator=(const MixerSpec &mixerSpec)
Definition: Mix.cpp:868
Mixer::mBuffer
ArrayOf< SampleBuffer > mBuffer
Definition: Mix.h:190
Mixer::mTemp
ArrayOf< SampleBuffer > mTemp
Definition: Mix.h:190
Mixer::mMaxOut
size_t mMaxOut
Definition: Mix.h:182
WaveTrack::GetEnvelopeValues
void GetEnvelopeValues(double *buffer, size_t bufferLen, double t0) const
Definition: WaveTrack.cpp:2020
WaveTrack::GetEndTime
double GetEndTime() const override
Get the time at which the last clip in the track ends, plus recorded stuff.
Definition: WaveTrack.cpp:1797
Track::GetName
wxString GetName() const
Definition: Track.h:409
Mixer::mEnvelope
const BoundedEnvelope * mEnvelope
Definition: Mix.h:166
Mixer::mRate
const double mRate
Definition: Mix.h:192
Mixer::WarpOptions
Definition: Mix.h:83
Mixer::mGains
Floats mGains
Definition: Mix.h:184
TrackList::Channels
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1467
Mix.h
TrackList
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
Definition: Track.h:1263
Mixer::Reposition
void Reposition(double t, bool bSkipping=false)
Definition: Mix.cpp:748
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:810
ArrayOf::reinit
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:112
Mixer::MakeResamplers
void MakeResamplers()
Definition: Mix.cpp:351
Mixer::SetSpeedForKeyboardScrubbing
void SetSpeedForKeyboardScrubbing(double speed, double startTime)
Definition: Mix.cpp:786
Mixer::mEnvValues
Doubles mEnvValues
Definition: Mix.h:169
XO
#define XO(s)
Definition: Internat.h:32
ProgressResult::Cancelled
@ Cancelled
ReverseSamples
void ReverseSamples(samplePtr dst, sampleFormat format, int start, int len)
Definition: SampleFormat.cpp:84
ProgressDialog.h
floatSample
@ floatSample
Definition: Types.h:714
TimeTrack.h
Mixer::SetTimesAndSpeed
void SetTimesAndSpeed(double t0, double t1, double speed)
Definition: Mix.cpp:771
Mixer::WarpOptions::minSpeed
double minSpeed
Definition: Mix.h:97
MixerSpec::~MixerSpec
virtual ~MixerSpec()
Definition: Mix.cpp:843
limitSampleBufferSize
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
Definition: Types.h:698
ArraysOf::reinit
void reinit(Integral count)
Definition: MemoryX.h:164
WaveTrack::Holder
std::shared_ptr< WaveTrack > Holder
Definition: WaveTrack.h:93
BoundedEnvelope
Definition: Envelope.h:284
samplePtr
char * samplePtr
Definition: Types.h:729
sampleFormat
sampleFormat
Definition: Types.h:709
ProgressResult::Failed
@ Failed
ProgressDialog
ProgressDialog Class.
Definition: ProgressDialog.h:56
MixerSpec::mMap
ArraysOf< bool > mMap
Definition: Mix.h:63
ProgressResult::Success
@ Success
WaveTrackCache::Get
constSamplePtr Get(sampleFormat format, sampleCount start, size_t len, bool mayThrow)
Definition: WaveTrack.cpp:2542
Mixer::mFloatBuffer
Floats mFloatBuffer
Definition: Mix.h:191
Track::MonoChannel
static const auto MonoChannel
Definition: Track.h:267
Mixer::MixVariableRates
size_t MixVariableRates(int *channelFlags, WaveTrackCache &cache, sampleCount *pos, float *queue, int *queueStart, int *queueLen, Resample *pResample)
Definition: Mix.cpp:413
Mixer::mTime
double mTime
Definition: Mix.h:172
Mixer::mNumInputTracks
const size_t mNumInputTracks
Definition: Mix.h:163
format
int format
Definition: ExportPCM.cpp:54
ProgressDialog::Update
ProgressResult Update(int value, const TranslatableString &message={})
Definition: ProgressDialog.cpp:1327
MixerSpec::mMaxNumChannels
unsigned mMaxNumChannels
Definition: Mix.h:58
Track::LeftChannel
static const auto LeftChannel
Definition: Track.h:265
Mixer::mSamplePos
ArrayOf< sampleCount > mSamplePos
Definition: Mix.h:167
anonymous_namespace{NoteTrack.cpp}::swap
void swap(std::unique_ptr< Alg_seq > &a, std::unique_ptr< Alg_seq > &b)
Definition: NoteTrack.cpp:733
MixerSpec::SetNumChannels
bool SetNumChannels(unsigned numChannels)
Definition: Mix.cpp:847
Mixer::mT0
double mT0
Definition: Mix.h:170
WaveTrack::GetStartTime
double GetStartTime() const override
Get the time at which the first clip in the track starts.
Definition: WaveTrack.cpp:1777
Mixer::mMaxFactor
std::vector< double > mMaxFactor
Definition: Mix.h:195
Resample
Interface to libsoxr.
Definition: Resample.h:29
Mixer::mT1
double mT1
Definition: Mix.h:171
WaveTrackFactory
Used to create or clone a WaveTrack, with appropriate context from the project that will own the trac...
Definition: WaveTrack.h:675
Mixer::Clear
void Clear()
Definition: Mix.cpp:357
CopySamples
void CopySamples(constSamplePtr src, sampleFormat srcFormat, samplePtr dst, sampleFormat dstFormat, unsigned int len, bool highQuality, unsigned int srcStride, unsigned int dstStride)
Definition: SampleFormat.cpp:102
SampleBuffer
Definition: SampleFormat.h:53
Envelope.h
Envelope::AverageOfInverse
double AverageOfInverse(double t0, double t1) const
Definition: Envelope.cpp:1078
MixerSpec::mNumChannels
unsigned mNumChannels
Definition: Mix.h:58
min
int min(int a, int b)
Definition: CompareAudioCommand.cpp:106
Mixer::mQueueLen
ArrayOf< int > mQueueLen
Definition: Mix.h:177
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:617
Mixer::MixGetCurrentTime
double MixGetCurrentTime()
Definition: Mix.cpp:725
Mixer::mHighQuality
bool mHighQuality
Definition: Mix.h:194
Mixer::SetSpeedForPlayAtSpeed
void SetSpeedForPlayAtSpeed(double speed)
Definition: Mix.cpp:780
WaveTrack::TimeToLongSamples
sampleCount TimeToLongSamples(double t0) const
Convert correctly between an (absolute) time in seconds and a number of samples.
Definition: WaveTrack.cpp:1767
Mixer::Restart
void Restart()
Definition: Mix.cpp:730
_
#define _(s)
Definition: Internat.h:76
Mixer::WarpOptions::WarpOptions
WarpOptions(const TrackList &list)
Construct with warp from the TimeTrack if there is one.
Definition: Mix.cpp:207
sampleCount
Definition: Types.h:581
Mixer::mQueueMaxLen
const size_t mQueueMaxLen
Definition: Mix.h:174
Mixer::mResample
ArrayOf< std::unique_ptr< Resample > > mResample
Definition: Mix.h:173
Mixer::mSpeed
double mSpeed
Definition: Mix.h:193
Mixer::mNumBuffers
unsigned mNumBuffers
Definition: Mix.h:185
Mixer::mNumChannels
const unsigned mNumChannels
Definition: Mix.h:183
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
Mixer::WarpOptions::envelope
const BoundedEnvelope * envelope
Definition: Mix.h:96
Mixer::mMinFactor
std::vector< double > mMinFactor
Definition: Mix.h:195
Mixer::mMayThrow
const bool mMayThrow
Definition: Mix.h:197
Prefs.h
MixerSpec::Alloc
void Alloc()
Definition: Mix.cpp:838
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:406
WaveTrack::GetChannelGain
float GetChannelGain(int channel) const
Definition: WaveTrack.cpp:408
Mixer::mApplyTrackGains
const bool mApplyTrackGains
Definition: Mix.h:168
TrackList::Any
auto Any() -> TrackIterRange< TrackType >
Definition: Track.h:1354
WaveTrack::GetPan
float GetPan() const
Definition: WaveTrack.cpp:390
MixerSpec
Class used with Mixer.
Definition: Mix.h:57
MixerSpec::mNumTracks
unsigned mNumTracks
Definition: Mix.h:58
float_cast.h
Mixer::mInterleavedBufferSize
size_t mInterleavedBufferSize
Definition: Mix.h:187
WaveTrack::GetChannel
ChannelType GetChannel() const override
Definition: WaveTrack.cpp:227
TrackList::Selected
auto Selected() -> TrackIterRange< TrackType >
Definition: Track.h:1371
Mixer
Functions for doing the mixdown of the tracks.
Definition: Mix.h:78
Mixer::mQueueStart
ArrayOf< int > mQueueStart
Definition: Mix.h:176
WaveTrackFactory::NewWaveTrack
std::shared_ptr< WaveTrack > NewWaveTrack(sampleFormat format=(sampleFormat) 0, double rate=0)
Definition: WaveTrack.cpp:85
ArrayOf< float >
Mixer::mProcessLen
size_t mProcessLen
Definition: Mix.h:178
TimeTrack
A kind of Track used to 'warp time'.
Definition: TimeTrack.h:24
SAMPLE_SIZE
#define SAMPLE_SIZE(SampleFormat)
Definition: Types.h:724
Resample.h
Mixer::Process
size_t Process(size_t maxSamples)
Definition: Mix.cpp:629
Mixer::mbVariableRates
bool mbVariableRates
Definition: Mix.h:165
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:238
SampleBuffer::ptr
samplePtr ptr() const
Definition: SampleFormat.h:82
WaveTrack::GetRate
double GetRate() const
Definition: WaveTrack.cpp:360