Audacity  2.2.2
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 #include "Audacity.h"
25 #include "Mix.h"
26 
27 #include <math.h>
28 
29 #include <wx/textctrl.h>
30 #include <wx/progdlg.h>
31 #include <wx/timer.h>
32 #include <wx/intl.h>
33 
34 #include "WaveTrack.h"
35 #include "DirManager.h"
36 #include "Internat.h"
37 #include "Prefs.h"
38 #include "Project.h"
39 #include "Resample.h"
40 #include "TimeTrack.h"
41 #include "float_cast.h"
42 
43 //TODO-MB: wouldn't it make more sense to DELETE the time track after 'mix and render'?
44 void MixAndRender(TrackList *tracks, TrackFactory *trackFactory,
45  double rate, sampleFormat format,
46  double startTime, double endTime,
47  WaveTrack::Holder &uLeft, WaveTrack::Holder &uRight)
48 {
49  uLeft.reset(), uRight.reset();
50 
51  // This function was formerly known as "Quick Mix".
52  const Track *t;
53  bool mono = false; /* flag if output can be mono without loosing anything*/
54  bool oneinput = false; /* flag set to true if there is only one input track
55  (mono or stereo) */
56 
57  TrackListIterator iter(tracks);
58  SelectedTrackListOfKindIterator usefulIter(Track::Wave, tracks);
59  // this only iterates tracks which are relevant to this function, i.e.
60  // selected WaveTracks. The tracklist is (confusingly) the list of all
61  // tracks in the project
62 
63  int numWaves = 0; /* number of wave tracks in the selection */
64  int numMono = 0; /* number of mono, centre-panned wave tracks in selection*/
65  t = iter.First();
66  while (t) {
67  if (t->GetSelected() && t->GetKind() == Track::Wave) {
68  numWaves++;
69  float pan = ((WaveTrack*)t)->GetPan();
70  if (t->GetChannel() == Track::MonoChannel && pan == 0)
71  numMono++;
72  }
73  t = iter.Next();
74  }
75 
76  if (numMono == numWaves)
77  mono = true;
78 
79  /* the next loop will do two things at once:
80  * 1. build an array of all the wave tracks were are trying to process
81  * 2. determine when the set of WaveTracks starts and ends, in case we
82  * need to work out for ourselves when to start and stop rendering.
83  */
84 
85  double mixStartTime = 0.0; /* start time of first track to start */
86  bool gotstart = false; // flag indicates we have found a start time
87  double mixEndTime = 0.0; /* end time of last track to end */
88  double tstart, tend; // start and end times for one track.
89 
90  WaveTrackConstArray waveArray;
91  t = iter.First();
92 
93  while (t) {
94  if (t->GetSelected() && t->GetKind() == Track::Wave) {
95  waveArray.push_back(Track::Pointer<const WaveTrack>(t));
96  tstart = t->GetStartTime();
97  tend = t->GetEndTime();
98  if (tend > mixEndTime)
99  mixEndTime = tend;
100  // try and get the start time. If the track is empty we will get 0,
101  // which is ambiguous because it could just mean the track starts at
102  // the beginning of the project, as well as empty track. The give-away
103  // is that an empty track also ends at zero.
104 
105  if (tstart != tend) {
106  // we don't get empty tracks here
107  if (!gotstart) {
108  // no previous start, use this one unconditionally
109  mixStartTime = tstart;
110  gotstart = true;
111  } else if (tstart < mixStartTime)
112  mixStartTime = tstart; // have a start, only make it smaller
113  } // end if start and end are different
114  } // end if track is a selected WaveTrack.
116  t = iter.Next();
117  }
118 
119  /* create the destination track (NEW track) */
120  if ((numWaves == 1) || ((numWaves == 2) && (usefulIter.First()->GetLink() != NULL)))
121  oneinput = true;
122  // only one input track (either 1 mono or one linked stereo pair)
123 
124  auto mixLeft = trackFactory->NewWaveTrack(format, rate);
125  if (oneinput)
126  mixLeft->SetName(usefulIter.First()->GetName()); /* set name of output track to be the same as the sole input track */
127  else
128  mixLeft->SetName(_("Mix"));
129  mixLeft->SetOffset(mixStartTime);
130  decltype(mixLeft) mixRight{};
131  if (mono) {
132  mixLeft->SetChannel(Track::MonoChannel);
133  }
134  else {
135  mixRight = trackFactory->NewWaveTrack(format, rate);
136  if (oneinput) {
137  if (usefulIter.First()->GetLink() != NULL) // we have linked track
138  mixRight->SetName(usefulIter.First()->GetLink()->GetName()); /* set name to match input track's right channel!*/
139  else
140  mixRight->SetName(usefulIter.First()->GetName()); /* set name to that of sole input channel */
141  }
142  else
143  mixRight->SetName(_("Mix"));
144  mixLeft->SetChannel(Track::LeftChannel);
145  mixRight->SetChannel(Track::RightChannel);
146  mixRight->SetOffset(mixStartTime);
147  mixLeft->SetLinked(true);
148  }
149 
150 
151 
152  auto maxBlockLen = mixLeft->GetIdealBlockSize();
153 
154  // If the caller didn't specify a time range, use the whole range in which
155  // any input track had clips in it.
156  if (startTime == endTime) {
157  startTime = mixStartTime;
158  endTime = mixEndTime;
159  }
160 
161  Mixer mixer(waveArray,
162  // Throw to abort mix-and-render if read fails:
163  true,
164  Mixer::WarpOptions(tracks->GetTimeTrack()),
165  startTime, endTime, mono ? 1 : 2, maxBlockLen, false,
166  rate, format);
167 
168  ::wxSafeYield();
169 
170  auto updateResult = ProgressResult::Success;
171  {
172  ProgressDialog progress(_("Mix and Render"),
173  _("Mixing and rendering tracks"));
174 
175  while (updateResult == ProgressResult::Success) {
176  auto blockLen = mixer.Process(maxBlockLen);
177 
178  if (blockLen == 0)
179  break;
180 
181  if (mono) {
182  samplePtr buffer = mixer.GetBuffer();
183  mixLeft->Append(buffer, format, blockLen);
184  }
185  else {
186  samplePtr buffer;
187  buffer = mixer.GetBuffer(0);
188  mixLeft->Append(buffer, format, blockLen);
189  buffer = mixer.GetBuffer(1);
190  mixRight->Append(buffer, format, blockLen);
191  }
192 
193  updateResult = progress.Update(mixer.MixGetCurrentTime() - startTime, endTime - startTime);
194  }
195  }
196 
197  mixLeft->Flush();
198  if (!mono)
199  mixRight->Flush();
200  if (updateResult == ProgressResult::Cancelled || updateResult == ProgressResult::Failed)
201  {
202  return;
203  }
204  else {
205  uLeft = std::move(mixLeft),
206  uRight = std::move(mixRight);
207 #if 0
208  int elapsedMS = wxGetElapsedTime();
209  double elapsedTime = elapsedMS * 0.001;
210  double maxTracks = totalTime / (elapsedTime / numWaves);
211 
212  // Note: these shouldn't be translated - they're for debugging
213  // and profiling only.
214  wxPrintf(" Tracks: %d\n", numWaves);
215  wxPrintf(" Mix length: %f sec\n", totalTime);
216  wxPrintf("Elapsed time: %f sec\n", elapsedTime);
217  wxPrintf("Max number of tracks to mix in real time: %f\n", maxTracks);
218 #endif
219  }
220 }
221 
223  : timeTrack(0), minSpeed(min), maxSpeed(max)
224 {
225  if (minSpeed < 0)
226  {
227  wxASSERT(false);
228  minSpeed = 0;
229  }
230  if (maxSpeed < 0)
231  {
232  wxASSERT(false);
233  maxSpeed = 0;
234  }
235  if (minSpeed > maxSpeed)
236  {
237  wxASSERT(false);
238  std::swap(minSpeed, maxSpeed);
239  }
240 }
241 
243  bool mayThrow,
244  const WarpOptions &warpOptions,
245  double startTime, double stopTime,
246  unsigned numOutChannels, size_t outBufferSize, bool outInterleaved,
247  double outRate, sampleFormat outFormat,
248  bool highQuality, MixerSpec *mixerSpec)
249  : mNumInputTracks { inputTracks.size() }
250 
251  // This is the number of samples grabbed in one go from a track
252  // and placed in a queue, when mixing with resampling.
253  // (Should we use WaveTrack::GetBestBlockSize instead?)
254  , mQueueMaxLen{ 65536 }
255  , mSampleQueue{ mNumInputTracks, mQueueMaxLen }
256 
257  , mNumChannels{ numOutChannels }
258  , mGains{ mNumChannels }
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  mTimeTrack = warpOptions.timeTrack;
273  mT0 = startTime;
274  mT1 = stopTime;
275  mTime = startTime;
276  mBufferSize = outBufferSize;
277  mInterleaved = outInterleaved;
278  mRate = outRate;
279  mSpeed = 1.0;
280  mFormat = outFormat;
281  mApplyTrackGains = true;
282  if( mixerSpec && mixerSpec->GetNumChannels() == mNumChannels &&
283  mixerSpec->GetNumTracks() == mNumInputTracks )
284  mMixerSpec = mixerSpec;
285  else
286  mMixerSpec = NULL;
287 
288  if (mInterleaved) {
289  mNumBuffers = 1;
290  mInterleavedBufferSize = mBufferSize * mNumChannels;
291  }
292  else {
293  mNumBuffers = mNumChannels;
294  mInterleavedBufferSize = mBufferSize;
295  }
296 
297  mBuffer.reinit(mNumBuffers);
298  mTemp.reinit(mNumBuffers);
299  for (unsigned int c = 0; c < mNumBuffers; c++) {
300  mBuffer[c].Allocate(mInterleavedBufferSize, mFormat);
301  mTemp[c].Allocate(mInterleavedBufferSize, floatSample);
302  }
303  mFloatBuffer = Floats{ mInterleavedBufferSize };
304 
305  // But cut the queue into blocks of this finer size
306  // for variable rate resampling. Each block is resampled at some
307  // constant rate.
308  mProcessLen = 1024;
309 
310  // Position in each queue of the start of the next block to resample.
311  mQueueStart.reinit(mNumInputTracks);
312 
313  // For each queue, the number of available samples after the queue start.
314  mQueueLen.reinit(mNumInputTracks);
315  mResample.reinit(mNumInputTracks);
316  for(size_t i=0; i<mNumInputTracks; i++) {
317  double factor = (mRate / mInputTrack[i].GetTrack()->GetRate());
318  double minFactor, maxFactor;
319  if (mTimeTrack) {
320  // variable rate resampling
321  mbVariableRates = true;
322  minFactor = factor / mTimeTrack->GetRangeUpper();
323  maxFactor = factor / mTimeTrack->GetRangeLower();
324  }
325  else if (warpOptions.minSpeed > 0.0 && warpOptions.maxSpeed > 0.0) {
326  // variable rate resampling
327  mbVariableRates = true;
328  minFactor = factor / warpOptions.maxSpeed;
329  maxFactor = factor / warpOptions.minSpeed;
330  }
331  else {
332  // constant rate resampling
333  mbVariableRates = false;
334  minFactor = maxFactor = factor;
335  }
336 
337  mResample[i] = std::make_unique<Resample>(mHighQuality, minFactor, maxFactor);
338  mQueueStart[i] = 0;
339  mQueueLen[i] = 0;
340  }
341 
342  const auto envLen = std::max(mQueueMaxLen, mInterleavedBufferSize);
343  mEnvValues.reinit(envLen);
344 }
345 
347 {
348 }
349 
350 void Mixer::ApplyTrackGains(bool apply)
351 {
352  mApplyTrackGains = apply;
353 }
354 
356 {
357  for (unsigned int c = 0; c < mNumBuffers; c++) {
358  memset(mTemp[c].ptr(), 0, mInterleavedBufferSize * SAMPLE_SIZE(floatSample));
359  }
360 }
361 
362 void MixBuffers(unsigned numChannels, int *channelFlags, float *gains,
363  samplePtr src, SampleBuffer *dests,
364  int len, bool interleaved)
365 {
366  for (unsigned int c = 0; c < numChannels; c++) {
367  if (!channelFlags[c])
368  continue;
369 
370  samplePtr destPtr;
371  unsigned skip;
372 
373  if (interleaved) {
374  destPtr = dests[0].ptr() + c*SAMPLE_SIZE(floatSample);
375  skip = numChannels;
376  } else {
377  destPtr = dests[c].ptr();
378  skip = 1;
379  }
380 
381  float gain = gains[c];
382  float *dest = (float *)destPtr;
383  float *temp = (float *)src;
384  for (int j = 0; j < len; j++) {
385  *dest += temp[j] * gain; // the actual mixing process
386  dest += skip;
387  }
388  }
389 }
390 
391 size_t Mixer::MixVariableRates(int *channelFlags, WaveTrackCache &cache,
392  sampleCount *pos, float *queue,
393  int *queueStart, int *queueLen,
394  Resample * pResample)
395 {
396  const WaveTrack *const track = cache.GetTrack();
397  const double trackRate = track->GetRate();
398  const double initialWarp = mRate / mSpeed / trackRate;
399  const double tstep = 1.0 / trackRate;
400  auto sampleSize = SAMPLE_SIZE(floatSample);
401 
402  decltype(mMaxOut) out = 0;
403 
404  /* time is floating point. Sample rate is integer. The number of samples
405  * has to be integer, but the multiplication gives a float result, which we
406  * round to get an integer result. TODO: is this always right or can it be
407  * off by one sometimes? Can we not get this information directly from the
408  * clip (which must know) rather than convert the time?
409  *
410  * LLL: Not at this time. While WaveClips provide methods to retrieve the
411  * start and end sample, they do the same float->sampleCount conversion
412  * to calculate the position.
413  */
414 
415  // Find the last sample
416  double endTime = track->GetEndTime();
417  double startTime = track->GetStartTime();
418  const bool backwards = (mT1 < mT0);
419  const double tEnd = backwards
420  ? std::max(startTime, mT1)
421  : std::min(endTime, mT1);
422  const auto endPos = track->TimeToLongSamples(tEnd);
423  // Find the time corresponding to the start of the queue, for use with time track
424  double t = ((*pos).as_long_long() +
425  (backwards ? *queueLen : - *queueLen)) / trackRate;
426 
427  while (out < mMaxOut) {
428  if (*queueLen < (int)mProcessLen) {
429  // Shift pending portion to start of the buffer
430  memmove(queue, &queue[*queueStart], (*queueLen) * sampleSize);
431  *queueStart = 0;
432 
433  auto getLen = limitSampleBufferSize(
434  mQueueMaxLen - *queueLen,
435  backwards ? *pos - endPos : endPos - *pos
436  );
437 
438  // Nothing to do if past end of play interval
439  if (getLen > 0) {
440  if (backwards) {
441  auto results = cache.Get(floatSample, *pos - (getLen - 1), getLen, mMayThrow);
442  if (results)
443  memcpy(&queue[*queueLen], results, sizeof(float) * getLen);
444  else
445  memset(&queue[*queueLen], 0, sizeof(float) * getLen);
446 
447  track->GetEnvelopeValues(mEnvValues.get(),
448  getLen,
449  (*pos - (getLen- 1)).as_double() / trackRate);
450  *pos -= getLen;
451  }
452  else {
453  auto results = cache.Get(floatSample, *pos, getLen, mMayThrow);
454  if (results)
455  memcpy(&queue[*queueLen], results, sizeof(float) * getLen);
456  else
457  memset(&queue[*queueLen], 0, sizeof(float) * getLen);
458 
459  track->GetEnvelopeValues(mEnvValues.get(),
460  getLen,
461  (*pos).as_double() / trackRate);
462 
463  *pos += getLen;
464  }
465 
466  for (decltype(getLen) i = 0; i < getLen; i++) {
467  queue[(*queueLen) + i] *= mEnvValues[i];
468  }
469 
470  if (backwards)
472  *queueLen, getLen);
473 
474  *queueLen += getLen;
475  }
476  }
477 
478  auto thisProcessLen = mProcessLen;
479  bool last = (*queueLen < (int)mProcessLen);
480  if (last) {
481  thisProcessLen = *queueLen;
482  }
483 
484  double factor = initialWarp;
485  if (mTimeTrack)
486  {
487  //TODO-MB: The end time is wrong when the resampler doesn't use all input samples,
488  // as a result of this the warp factor may be slightly wrong, so AudioIO will stop too soon
489  // or too late (resulting in missing sound or inserted silence). This can't be fixed
490  // without changing the way the resampler works, because the number of input samples that will be used
491  // is unpredictable. Maybe it can be compensated later though.
492  if (backwards)
493  factor *= mTimeTrack->ComputeWarpFactor
494  (t - (double)thisProcessLen / trackRate + tstep, t + tstep);
495  else
496  factor *= mTimeTrack->ComputeWarpFactor
497  (t, t + (double)thisProcessLen / trackRate);
498  }
499 
500  auto results = pResample->Process(factor,
501  &queue[*queueStart],
502  thisProcessLen,
503  last,
504  &mFloatBuffer[out],
505  mMaxOut - out);
506 
507  const auto input_used = results.first;
508  *queueStart += input_used;
509  *queueLen -= input_used;
510  out += results.second;
511  t += (input_used / trackRate) * (backwards ? -1 : 1);
512 
513  if (last) {
514  break;
515  }
516  }
517 
518  for (size_t c = 0; c < mNumChannels; c++) {
519  if (mApplyTrackGains) {
520  mGains[c] = track->GetChannelGain(c);
521  }
522  else {
523  mGains[c] = 1.0;
524  }
525  }
526 
527  MixBuffers(mNumChannels,
528  channelFlags,
529  mGains.get(),
530  (samplePtr)mFloatBuffer.get(),
531  mTemp.get(),
532  out,
533  mInterleaved);
534 
535  return out;
536 }
537 
538 size_t Mixer::MixSameRate(int *channelFlags, WaveTrackCache &cache,
539  sampleCount *pos)
540 {
541  const WaveTrack *const track = cache.GetTrack();
542  const double t = ( *pos ).as_double() / track->GetRate();
543  const double trackEndTime = track->GetEndTime();
544  const double trackStartTime = track->GetStartTime();
545  const bool backwards = (mT1 < mT0);
546  const double tEnd = backwards
547  ? std::max(trackStartTime, mT1)
548  : std::min(trackEndTime, mT1);
549 
550  //don't process if we're at the end of the selection or track.
551  if ((backwards ? t <= tEnd : t >= tEnd))
552  return 0;
553  //if we're about to approach the end of the track or selection, figure out how much we need to grab
554  auto slen = limitSampleBufferSize(
555  mMaxOut,
556  // PRL: maybe t and tEnd should be given as sampleCount instead to
557  // avoid trouble subtracting one large value from another for a small
558  // difference
559  sampleCount{ (backwards ? t - tEnd : tEnd - t) * track->GetRate() + 0.5 }
560  );
561 
562  if (backwards) {
563  auto results = cache.Get(floatSample, *pos - (slen - 1), slen, mMayThrow);
564  if (results)
565  memcpy(mFloatBuffer.get(), results, sizeof(float) * slen);
566  else
567  memset(mFloatBuffer.get(), 0, sizeof(float) * slen);
568  track->GetEnvelopeValues(mEnvValues.get(), slen, t - (slen - 1) / mRate);
569  for(decltype(slen) i = 0; i < slen; i++)
570  mFloatBuffer[i] *= mEnvValues[i]; // Track gain control will go here?
572 
573  *pos -= slen;
574  }
575  else {
576  auto results = cache.Get(floatSample, *pos, slen, mMayThrow);
577  if (results)
578  memcpy(mFloatBuffer.get(), results, sizeof(float) * slen);
579  else
580  memset(mFloatBuffer.get(), 0, sizeof(float) * slen);
581  track->GetEnvelopeValues(mEnvValues.get(), slen, t);
582  for(decltype(slen) i = 0; i < slen; i++)
583  mFloatBuffer[i] *= mEnvValues[i]; // Track gain control will go here?
584 
585  *pos += slen;
586  }
587 
588  for(size_t c=0; c<mNumChannels; c++)
589  if (mApplyTrackGains)
590  mGains[c] = track->GetChannelGain(c);
591  else
592  mGains[c] = 1.0;
593 
594  MixBuffers(mNumChannels, channelFlags, mGains.get(),
595  (samplePtr)mFloatBuffer.get(), mTemp.get(), slen, mInterleaved);
596 
597  return slen;
598 }
599 
600 size_t Mixer::Process(size_t maxToProcess)
601 {
602  // MB: this is wrong! mT represented warped time, and mTime is too inaccurate to use
603  // it here. It's also unnecessary I think.
604  //if (mT >= mT1)
605  // return 0;
606 
607  decltype(Process(0)) maxOut = 0;
608  ArrayOf<int> channelFlags{ mNumChannels };
609 
610  mMaxOut = maxToProcess;
611 
612  Clear();
613  for(size_t i=0; i<mNumInputTracks; i++) {
614  const WaveTrack *const track = mInputTrack[i].GetTrack();
615  for(size_t j=0; j<mNumChannels; j++)
616  channelFlags[j] = 0;
617 
618  if( mMixerSpec ) {
619  //ignore left and right when downmixing is not required
620  for(size_t j = 0; j < mNumChannels; j++ )
621  channelFlags[ j ] = mMixerSpec->mMap[ i ][ j ] ? 1 : 0;
622  }
623  else {
624  switch(track->GetChannel()) {
625  case Track::MonoChannel:
626  default:
627  for(size_t j=0; j<mNumChannels; j++)
628  channelFlags[j] = 1;
629  break;
630  case Track::LeftChannel:
631  channelFlags[0] = 1;
632  break;
633  case Track::RightChannel:
634  if (mNumChannels >= 2)
635  channelFlags[1] = 1;
636  else
637  channelFlags[0] = 1;
638  break;
639  }
640  }
641  if (mbVariableRates || track->GetRate() != mRate)
642  maxOut = std::max(maxOut,
643  MixVariableRates(channelFlags.get(), mInputTrack[i],
644  &mSamplePos[i], mSampleQueue[i].get(),
645  &mQueueStart[i], &mQueueLen[i], mResample[i].get()));
646  else
647  maxOut = std::max(maxOut,
648  MixSameRate(channelFlags.get(), mInputTrack[i], &mSamplePos[i]));
649 
650  double t = mSamplePos[i].as_double() / (double)track->GetRate();
651  if (mT0 > mT1)
652  // backwards (as possibly in scrubbing)
653  mTime = std::max(std::min(t, mTime), mT1);
654  else
655  // forwards (the usual)
656  mTime = std::min(std::max(t, mTime), mT1);
657  }
658  if(mInterleaved) {
659  for(size_t c=0; c<mNumChannels; c++) {
660  CopySamples(mTemp[0].ptr() + (c * SAMPLE_SIZE(floatSample)),
661  floatSample,
662  mBuffer[0].ptr() + (c * SAMPLE_SIZE(mFormat)),
663  mFormat,
664  maxOut,
665  mHighQuality,
666  mNumChannels,
667  mNumChannels);
668  }
669  }
670  else {
671  for(size_t c=0; c<mNumBuffers; c++) {
672  CopySamples(mTemp[c].ptr(),
673  floatSample,
674  mBuffer[c].ptr(),
675  mFormat,
676  maxOut,
677  mHighQuality);
678  }
679  }
680  // MB: this doesn't take warping into account, replaced with code based on mSamplePos
681  //mT += (maxOut / mRate);
682 
683  return maxOut;
684 }
685 
687 {
688  return mBuffer[0].ptr();
689 }
690 
692 {
693  return mBuffer[channel].ptr();
694 }
695 
697 {
698  return mTime;
699 }
700 
702 {
703  mTime = mT0;
704 
705  for(size_t i=0; i<mNumInputTracks; i++)
706  mSamplePos[i] = mInputTrack[i].GetTrack()->TimeToLongSamples(mT0);
707 
708  for(size_t i=0; i<mNumInputTracks; i++) {
709  mQueueStart[i] = 0;
710  mQueueLen[i] = 0;
711  }
712 }
713 
714 void Mixer::Reposition(double t)
715 {
716  mTime = t;
717  const bool backwards = (mT1 < mT0);
718  if (backwards)
719  mTime = std::max(mT1, (std::min(mT0, mTime)));
720  else
721  mTime = std::max(mT0, (std::min(mT1, mTime)));
722 
723  for(size_t i=0; i<mNumInputTracks; i++) {
724  mSamplePos[i] = mInputTrack[i].GetTrack()->TimeToLongSamples(mTime);
725  mQueueStart[i] = 0;
726  mQueueLen[i] = 0;
727  }
728 }
729 
730 void Mixer::SetTimesAndSpeed(double t0, double t1, double speed)
731 {
732  wxASSERT(std::isfinite(speed));
733  mT0 = t0;
734  mT1 = t1;
735  mSpeed = fabs(speed);
736  Reposition(t0);
737 }
738 
739 MixerSpec::MixerSpec( unsigned numTracks, unsigned maxNumChannels )
740 {
741  mNumTracks = mNumChannels = numTracks;
742  mMaxNumChannels = maxNumChannels;
743 
746 
747  Alloc();
748 
749  for( unsigned int i = 0; i < mNumTracks; i++ )
750  for( unsigned int j = 0; j < mNumChannels; j++ )
751  mMap[ i ][ j ] = ( i == j );
752 }
753 
754 MixerSpec::MixerSpec( const MixerSpec &mixerSpec )
755 {
756  mNumTracks = mixerSpec.mNumTracks;
757  mMaxNumChannels = mixerSpec.mMaxNumChannels;
758  mNumChannels = mixerSpec.mNumChannels;
759 
760  Alloc();
761 
762  for( unsigned int i = 0; i < mNumTracks; i++ )
763  for( unsigned int j = 0; j < mNumChannels; j++ )
764  mMap[ i ][ j ] = mixerSpec.mMap[ i ][ j ];
765 }
766 
768 {
770 }
771 
773 {
774 }
775 
776 bool MixerSpec::SetNumChannels( unsigned newNumChannels )
777 {
778  if( mNumChannels == newNumChannels )
779  return true;
780 
781  if( newNumChannels > mMaxNumChannels )
782  return false;
783 
784  for( unsigned int i = 0; i < mNumTracks; i++ )
785  {
786  for( unsigned int j = newNumChannels; j < mNumChannels; j++ )
787  mMap[ i ][ j ] = false;
788 
789  for( unsigned int j = mNumChannels; j < newNumChannels; j++ )
790  mMap[ i ][ j ] = false;
791  }
792 
793  mNumChannels = newNumChannels;
794  return true;
795 }
796 
798 {
799  mNumTracks = mixerSpec.mNumTracks;
800  mNumChannels = mixerSpec.mNumChannels;
801  mMaxNumChannels = mixerSpec.mMaxNumChannels;
802 
803  Alloc();
804 
805  for( unsigned int i = 0; i < mNumTracks; i++ )
806  for( unsigned int j = 0; j < mNumChannels; j++ )
807  mMap[ i ][ j ] = mixerSpec.mMap[ i ][ j ];
808 
809  return *this;
810 }
811 
size_t Process(size_t maxSamples)
Definition: Mix.cpp:600
ArrayOf< WaveTrackCache > mInputTrack
Definition: Mix.h:164
size_t MixVariableRates(int *channelFlags, WaveTrackCache &cache, sampleCount *pos, float *queue, int *queueStart, int *queueLen, Resample *pResample)
Definition: Mix.cpp:391
A list of TrackListNode items.
Definition: Track.h:618
void ReverseSamples(samplePtr dst, sampleFormat format, int start, int len)
void Restart()
Definition: Mix.cpp:701
ProgressDialog Class.
double mT0
Definition: Mix.h:170
bool GetSelected() const
Definition: Track.h:275
MixerSpec(unsigned numTracks, unsigned maxNumChannels)
Definition: Mix.cpp:739
double mSpeed
Definition: Mix.h:193
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:117
double MixGetCurrentTime()
Definition: Mix.cpp:696
unsigned mNumBuffers
Definition: Mix.h:185
ArrayOf< std::unique_ptr< Resample > > mResample
Definition: Mix.h:173
void CopySamples(samplePtr src, sampleFormat srcFormat, samplePtr dst, sampleFormat dstFormat, unsigned int len, bool highQuality, unsigned int srcStride, unsigned int dstStride)
virtual double GetEndTime() const =0
ArrayOf< sampleCount > mSamplePos
Definition: Mix.h:167
#define SAMPLE_SIZE(SampleFormat)
Definition: Types.h:198
Floats mGains
Definition: Mix.h:184
virtual int GetChannel() const
Definition: Track.h:285
double GetEndTime() const override
Get the time at which the last clip in the track ends, plus recorded stuff.
Definition: WaveTrack.cpp:1873
float GetChannelGain(int channel) const
Definition: WaveTrack.cpp:440
double mTime
Definition: Mix.h:172
virtual double GetStartTime() const =0
constSamplePtr Get(sampleFormat format, sampleCount start, size_t len, bool mayThrow)
Definition: WaveTrack.cpp:2633
bool mApplyTrackGains
Definition: Mix.h:168
double minSpeed
Definition: Mix.h:96
TimeTrack * GetTimeTrack()
Definition: Track.cpp:1244
virtual int GetKind() const
Definition: Track.h:329
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
Definition: Types.h:178
Used to create a WaveTrack, or a LabelTrack.. Implementation of the functions of this class are dispe...
Definition: Track.h:862
virtual ~MixerSpec()
Definition: Mix.cpp:772
size_t mInterleavedBufferSize
Definition: Mix.h:187
double GetStartTime() const override
Get the time at which the first clip in the track starts.
Definition: WaveTrack.cpp:1853
size_t MixSameRate(int *channelFlags, WaveTrackCache &cache, sampleCount *pos)
Definition: Mix.cpp:538
int format
Definition: ExportPCM.cpp:56
sampleFormat mFormat
Definition: Mix.h:188
std::unique_ptr< WaveTrack > Holder
Definition: WaveTrack.h:90
const TimeTrack * mTimeTrack
Definition: Mix.h:166
void Reposition(double t)
Definition: Mix.cpp:714
size_t mNumInputTracks
Definition: Mix.h:163
size_t mMaxOut
Definition: Mix.h:182
void ApplyTrackGains(bool apply=true)
Definition: Mix.cpp:350
size_t mProcessLen
Definition: Mix.h:178
ArraysOf< bool > mMap
Definition: Mix.h:65
std::vector< std::shared_ptr< const WaveTrack > > WaveTrackConstArray
Definition: AudioIO.h:66
sampleFormat
Definition: Types.h:188
char * samplePtr
Definition: Types.h:203
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
ArrayOf< int > mQueueStart
Definition: Mix.h:176
unsigned mNumChannels
Definition: Mix.h:183
Fundamental data object of Audacity, placed in the TrackPanel. Classes derived form it include the Wa...
Definition: Track.h:101
size_t mQueueMaxLen
Definition: Mix.h:174
ProgressResult Update(int value, const wxString &message=wxEmptyString)
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=NULL)
Definition: Mix.cpp:242
void MixBuffers(unsigned numChannels, int *channelFlags, float *gains, samplePtr src, SampleBuffer *dests, int len, bool interleaved)
Definition: Mix.cpp:362
double mT1
Definition: Mix.h:171
int min(int a, int b)
wxString GetName() const
Definition: Track.h:270
samplePtr ptr() const
Definition: SampleFormat.h:81
virtual Track * First(TrackList *val=nullptr)
Definition: Track.cpp:418
samplePtr GetBuffer()
Retrieve the main buffer or the interleaved buffer.
Definition: Mix.cpp:686
ArrayOf< int > mQueueLen
Definition: Mix.h:177
std::unique_ptr< WaveTrack > NewWaveTrack(sampleFormat format=(sampleFormat) 0, double rate=0)
Definition: WaveTrack.cpp:78
double mRate
Definition: Mix.h:192
An iterator for a TrackList.
Definition: Track.h:401
void Alloc()
Definition: Mix.cpp:767
unsigned mMaxNumChannels
Definition: Mix.h:60
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
unsigned mNumChannels
Definition: Mix.h:60
Interface to libsoxr.
Definition: Resample.h:32
void MixAndRender(TrackList *tracks, TrackFactory *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:44
void SetTimesAndSpeed(double t0, double t1, double speed)
Definition: Mix.cpp:730
void reinit(Integral count)
Definition: MemoryX.h:166
bool SetNumChannels(unsigned numChannels)
Definition: Mix.cpp:776
Track * GetLink() const
Definition: Track.cpp:269
sampleCount TimeToLongSamples(double t0) const
Convert correctly between an (absolute) time in seconds and a number of samples.
Definition: WaveTrack.cpp:1843
virtual Track * Next(bool skiplinked=false)
Definition: Track.cpp:460
bool mMayThrow
Definition: Mix.h:196
WarpOptions(const TimeTrack *t)
Definition: Mix.h:87
Track * First(TrackList *val=NULL) override
Definition: Track.cpp:558
Doubles mEnvValues
Definition: Mix.h:169
FloatBuffers mSampleQueue
Definition: Mix.h:175
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:106
unsigned mNumTracks
Definition: Mix.h:60
const WaveTrack * GetTrack() const
Definition: WaveTrack.h:683
void GetEnvelopeValues(double *buffer, size_t bufferLen, double t0) const
Definition: WaveTrack.cpp:2095
double maxSpeed
Definition: Mix.h:96
double GetRate() const
Definition: WaveTrack.cpp:398
ArrayOf< SampleBuffer > mBuffer
Definition: Mix.h:190
virtual ~Mixer()
Definition: Mix.cpp:346
Functions for doing the mixdown of the tracks.
Definition: Mix.h:80
double ComputeWarpFactor(double t0, double t1) const
Compute the integral warp factor between two non-warped time points.
Definition: TimeTrack.cpp:155
ArrayOf< SampleBuffer > mTemp
Definition: Mix.h:190
bool mbVariableRates
Definition: Mix.h:165
MixerSpec * mMixerSpec
Definition: Mix.h:179
MixerSpec & operator=(const MixerSpec &mixerSpec)
Definition: Mix.cpp:797
void Clear()
Definition: Mix.cpp:355
bool mInterleaved
Definition: Mix.h:189
bool mHighQuality
Definition: Mix.h:194
virtual int GetChannel() const override
Definition: WaveTrack.cpp:236
Floats mFloatBuffer
Definition: Mix.h:191
Class used with Mixer.
Definition: Mix.h:58