Audacity  3.0.3
Namespaces | Functions
Mix.cpp File Reference
#include "Mix.h"
#include <math.h>
#include <wx/textctrl.h>
#include <wx/timer.h>
#include <wx/intl.h>
#include "Envelope.h"
#include "WaveTrack.h"
#include "Prefs.h"
#include "Resample.h"
#include "TimeTrack.h"
#include "float_cast.h"
#include "widgets/ProgressDialog.h"
Include dependency graph for Mix.cpp:

Go to the source code of this file.

Namespaces

 anonymous_namespace{Mix.cpp}
 

Functions

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 effects in the process. More...
 
static void MixBuffers (unsigned numChannels, int *channelFlags, float *gains, const float *src, Floats *dests, int len, bool interleaved)
 
double anonymous_namespace{Mix.cpp}::ComputeWarpFactor (const Envelope &env, double t0, double t1)
 Compute the integral warp factor between two non-warped time points. More...
 

Function Documentation

◆ MixAndRender()

void MixAndRender ( TrackList tracks,
WaveTrackFactory factory,
double  rate,
sampleFormat  format,
double  startTime,
double  endTime,
std::shared_ptr< WaveTrack > &  uLeft,
std::shared_ptr< WaveTrack > &  uRight 
)

Mixes together all input tracks, applying any envelopes, amplitude gain, panning, and real-time effects in the process.

Takes one or more tracks as input; of all the WaveTrack s that are selected, it mixes them together, applying any envelopes, amplitude gain, panning, and real-time effects in the process. The resulting pair of tracks (stereo) are "rendered" and have no effects, gain, panning, or envelopes. Other sorts of tracks are ignored. If the start and end times passed are the same this is taken as meaning no explicit time range to process, and the whole occupied length of the input tracks is processed.

Definition at line 43 of file Mix.cpp.

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 }

References _, RefreshCode::Cancelled, TrackList::Channels(), format, Track::GetName(), WaveTrack::GetPan(), Track::MonoChannel, WaveTrackFactory::NewWaveTrack(), TrackList::Selected(), BasicUI::Success, ProgressDialog::Update(), and XO.

Referenced by anonymous_namespace{TrackMenus.cpp}::DoMixAndRender(), and Effect::Preview().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ MixBuffers()

static void MixBuffers ( unsigned  numChannels,
int *  channelFlags,
float *  gains,
const float *  src,
Floats dests,
int  len,
bool  interleaved 
)
static

Definition at line 363 of file Mix.cpp.

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 }

Referenced by Mixer::MixSameRate(), and Mixer::MixVariableRates().

Here is the caller graph for this function:
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
BasicUI::ProgressResult::Success
@ Success
Track::GetName
wxString GetName() const
Definition: Track.h:426
Mixer::WarpOptions
Definition: Mix.h:81
TrackList::Channels
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1484
RefreshCode::Cancelled
@ Cancelled
Definition: RefreshCode.h:23
XO
#define XO(s)
Definition: Internat.h:31
ProgressDialog
ProgressDialog Class.
Definition: ProgressDialog.h:51
format
int format
Definition: ExportPCM.cpp:56
_
#define _(s)
Definition: Internat.h:75
Track::MonoChannel
@ MonoChannel
Definition: Track.h:278
WaveTrack::GetPan
float GetPan() const
Definition: WaveTrack.cpp:482
TrackList::Selected
auto Selected() -> TrackIterRange< TrackType >
Definition: Track.h:1388
Mixer
Functions for doing the mixdown of the tracks.
Definition: Mix.h:76
WaveTrackFactory::NewWaveTrack
std::shared_ptr< WaveTrack > NewWaveTrack(sampleFormat format=(sampleFormat) 0, double rate=0)
Definition: WaveTrack.cpp:113