Audacity  3.2.0
MixAndRender.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 MixAndRender.cpp
6 
7 Paul Licameli split from Mix.cpp
8 
9 **********************************************************************/
10 
11 #include "MixAndRender.h"
12 
13 #include "BasicUI.h"
14 #include "Mix.h"
15 #include "WaveTrack.h"
16 
17 using WaveTrackConstArray = std::vector < std::shared_ptr < const WaveTrack > >;
18 
19 //TODO-MB: wouldn't it make more sense to DELETE the time track after 'mix and render'?
20 void MixAndRender(TrackList *tracks, WaveTrackFactory *trackFactory,
21  double rate, sampleFormat format,
22  double startTime, double endTime,
23  WaveTrack::Holder &uLeft, WaveTrack::Holder &uRight)
24 {
25  uLeft.reset(), uRight.reset();
26 
27  // This function was formerly known as "Quick Mix".
28  bool mono = false; /* flag if output can be mono without losing anything*/
29  bool oneinput = false; /* flag set to true if there is only one input track
30  (mono or stereo) */
31 
32  const auto trackRange = tracks->Selected< const WaveTrack >();
33  auto first = *trackRange.begin();
34  // this only iterates tracks which are relevant to this function, i.e.
35  // selected WaveTracks. The tracklist is (confusingly) the list of all
36  // tracks in the project
37 
38  int numWaves = 0; /* number of wave tracks in the selection */
39  int numMono = 0; /* number of mono, centre-panned wave tracks in selection*/
40  for(auto wt : trackRange) {
41  numWaves++;
42  float pan = wt->GetPan();
43  if (wt->GetChannel() == Track::MonoChannel && pan == 0)
44  numMono++;
45  }
46 
47  if (numMono == numWaves)
48  mono = true;
49 
50  /* the next loop will do two things at once:
51  * 1. build an array of all the wave tracks were are trying to process
52  * 2. determine when the set of WaveTracks starts and ends, in case we
53  * need to work out for ourselves when to start and stop rendering.
54  */
55 
56  double mixStartTime = 0.0; /* start time of first track to start */
57  bool gotstart = false; // flag indicates we have found a start time
58  double mixEndTime = 0.0; /* end time of last track to end */
59  double tstart, tend; // start and end times for one track.
60 
61  SampleTrackConstArray waveArray;
62 
63  for(auto wt : trackRange) {
64  waveArray.push_back( wt->SharedPointer< const SampleTrack >() );
65  tstart = wt->GetStartTime();
66  tend = wt->GetEndTime();
67  if (tend > mixEndTime)
68  mixEndTime = tend;
69  // try and get the start time. If the track is empty we will get 0,
70  // which is ambiguous because it could just mean the track starts at
71  // the beginning of the project, as well as empty track. The give-away
72  // is that an empty track also ends at zero.
73 
74  if (tstart != tend) {
75  // we don't get empty tracks here
76  if (!gotstart) {
77  // no previous start, use this one unconditionally
78  mixStartTime = tstart;
79  gotstart = true;
80  } else if (tstart < mixStartTime)
81  mixStartTime = tstart; // have a start, only make it smaller
82  } // end if start and end are different
83  }
84 
85  /* create the destination track (NEW track) */
86  if (numWaves == (int)TrackList::Channels(first).size())
87  oneinput = true;
88  // only one input track (either 1 mono or one linked stereo pair)
89 
90  auto mixLeft = trackFactory->NewWaveTrack(format, rate);
91  if (oneinput)
92  mixLeft->SetName(first->GetName()); /* set name of output track to be the same as the sole input track */
93  else
94  /* i18n-hint: noun, means a track, made by mixing other tracks */
95  mixLeft->SetName(_("Mix"));
96  mixLeft->SetOffset(mixStartTime);
97 
98  // TODO: more-than-two-channels
99  decltype(mixLeft) mixRight{};
100  if ( !mono ) {
101  mixRight = trackFactory->NewWaveTrack(format, rate);
102  if (oneinput) {
103  auto channels = TrackList::Channels(first);
104  if (channels.size() > 1)
105  mixRight->SetName((*channels.begin().advance(1))->GetName()); /* set name to match input track's right channel!*/
106  else
107  mixRight->SetName(first->GetName()); /* set name to that of sole input channel */
108  }
109  else
110  mixRight->SetName(_("Mix"));
111  mixRight->SetOffset(mixStartTime);
112  }
113 
114 
115  auto maxBlockLen = mixLeft->GetIdealBlockSize();
116 
117  // If the caller didn't specify a time range, use the whole range in which
118  // any input track had clips in it.
119  if (startTime == endTime) {
120  startTime = mixStartTime;
121  endTime = mixEndTime;
122  }
123 
124  Mixer mixer(waveArray,
125  // Throw to abort mix-and-render if read fails:
126  true,
127  Mixer::WarpOptions{*tracks},
128  startTime, endTime, mono ? 1 : 2, maxBlockLen, false,
129  rate, format);
130 
131  using namespace BasicUI;
132  auto updateResult = ProgressResult::Success;
133  {
134  auto pProgress = MakeProgress(XO("Mix and Render"),
135  XO("Mixing and rendering tracks"));
136 
137  while (updateResult == ProgressResult::Success) {
138  auto blockLen = mixer.Process(maxBlockLen);
139 
140  if (blockLen == 0)
141  break;
142 
143  if (mono) {
144  auto buffer = mixer.GetBuffer();
145  mixLeft->Append(buffer, format, blockLen);
146  }
147  else {
148  auto buffer = mixer.GetBuffer(0);
149  mixLeft->Append(buffer, format, blockLen);
150  buffer = mixer.GetBuffer(1);
151  mixRight->Append(buffer, format, blockLen);
152  }
153 
154  updateResult = pProgress->Poll(
155  mixer.MixGetCurrentTime() - startTime, endTime - startTime);
156  }
157  }
158 
159  mixLeft->Flush();
160  if (!mono)
161  mixRight->Flush();
162  if (updateResult == ProgressResult::Cancelled || updateResult == ProgressResult::Failed)
163  {
164  return;
165  }
166  else {
167  uLeft = mixLeft, uRight = mixRight;
168 #if 0
169  int elapsedMS = wxGetElapsedTime();
170  double elapsedTime = elapsedMS * 0.001;
171  double maxTracks = totalTime / (elapsedTime / numWaves);
172 
173  // Note: these shouldn't be translated - they're for debugging
174  // and profiling only.
175  wxPrintf(" Tracks: %d\n", numWaves);
176  wxPrintf(" Mix length: %f sec\n", totalTime);
177  wxPrintf("Elapsed time: %f sec\n", elapsedTime);
178  wxPrintf("Max number of tracks to mix in real time: %f\n", maxTracks);
179 #endif
180  }
181 }
WaveTrack.h
WaveTrackConstArray
std::vector< std::shared_ptr< const WaveTrack > > WaveTrackConstArray
Definition: AudioIO.h:47
BasicUI::MakeProgress
std::unique_ptr< ProgressDialog > MakeProgress(const TranslatableString &title, const TranslatableString &message, unsigned flags=(ProgressShowStop|ProgressShowCancel), const TranslatableString &remainingLabelText={})
Create and display a progress dialog.
Definition: BasicUI.h:271
WaveTrack
A Track that contains audio waveform data.
Definition: WaveTrack.h:75
BasicUI::ProgressResult::Success
@ Success
SampleTrackConstArray
std::vector< std::shared_ptr< const SampleTrack > > SampleTrackConstArray
Definition: Mix.h:33
Track::GetName
wxString GetName() const
Definition: Track.h:423
SampleTrack
Definition: SampleTrack.h:21
Mixer::WarpOptions
Definition: Mix.h:63
TrackList::Channels
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1483
Mix.h
TrackList
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
Definition: Track.h:1288
XO
#define XO(s)
Definition: Internat.h:31
BasicUI::ProgressResult::Failed
@ Failed
WaveTrack::Holder
std::shared_ptr< WaveTrack > Holder
Definition: WaveTrack.h:105
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: MixAndRender.cpp:20
format
int format
Definition: ExportPCM.cpp:56
MixAndRender.h
BasicUI::ProgressResult::Cancelled
@ Cancelled
WaveTrackFactory
Used to create or clone a WaveTrack, with appropriate context from the project that will own the trac...
Definition: WaveTrack.h:609
BasicUI.h
Toolkit-neutral facade for basic user interface services.
sampleFormat
sampleFormat
Definition: SampleFormat.h:29
BasicUI
Definition: Effect.h:47
Mixer::MixGetCurrentTime
double MixGetCurrentTime()
Definition: Mix.cpp:550
_
#define _(s)
Definition: Internat.h:75
Track::MonoChannel
@ MonoChannel
Definition: Track.h:263
Mixer::GetBuffer
constSamplePtr GetBuffer()
Retrieve the main buffer or the interleaved buffer.
Definition: Mix.cpp:540
WaveTrack::GetPan
float GetPan() const
Definition: WaveTrack.cpp:525
TrackList::Selected
auto Selected() -> TrackIterRange< TrackType >
Definition: Track.h:1396
Mixer
Functions for doing the mixdown of the tracks.
Definition: Mix.h:58
WaveTrackFactory::NewWaveTrack
std::shared_ptr< WaveTrack > NewWaveTrack(sampleFormat format=(sampleFormat) 0, double rate=0)
Definition: WaveTrack.cpp:126
Mixer::Process
size_t Process(size_t maxSamples)
Definition: Mix.cpp:454