Audacity  2.2.2
Classes | Typedefs | Functions
Mix.h File Reference
#include "MemoryX.h"
#include <wx/string.h>
#include "SampleFormat.h"
#include <vector>

Go to the source code of this file.

Classes

class  MixerSpec
 Class used with Mixer. More...
 
class  Mixer
 Functions for doing the mixdown of the tracks. More...
 
class  Mixer::WarpOptions
 

Typedefs

using WaveTrackConstArray = std::vector< std::shared_ptr< const WaveTrack > >
 

Functions

void MixAndRender (TrackList *tracks, TrackFactory *factory, double rate, sampleFormat format, double startTime, double endTime, std::unique_ptr< WaveTrack > &uLeft, std::unique_ptr< WaveTrack > &uRight)
 Mixes together all input tracks, applying any envelopes, amplitude gain, panning, and real-time effects in the process. More...
 
void MixBuffers (unsigned numChannels, int *channelFlags, float *gains, samplePtr src, samplePtr *dests, int len, bool interleaved)
 

Typedef Documentation

using WaveTrackConstArray = std::vector < std::shared_ptr < const WaveTrack > >

Definition at line 34 of file Mix.h.

Function Documentation

void MixAndRender ( TrackList tracks,
TrackFactory factory,
double  rate,
sampleFormat  format,
double  startTime,
double  endTime,
std::unique_ptr< WaveTrack > &  uLeft,
std::unique_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.

: could we not use a SelectedTrackListOfKindIterator here?

Definition at line 44 of file Mix.cpp.

References _(), Cancelled, Failed, TrackListIterator::First(), TrackListCondIterator::First(), Mixer::GetBuffer(), Track::GetChannel(), Track::GetEndTime(), Track::GetKind(), Track::GetLink(), Track::GetName(), Track::GetSelected(), Track::GetStartTime(), TrackList::GetTimeTrack(), Track::LeftChannel, Mixer::MixGetCurrentTime(), Track::MonoChannel, TrackFactory::NewWaveTrack(), TrackListIterator::Next(), Mixer::Process(), Track::RightChannel, Success, ProgressDialog::Update(), and Track::Wave.

Referenced by AudacityProject::HandleMixAndRender(), and Effect::Preview().

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 }
ProgressDialog Class.
bool GetSelected() const
Definition: Track.h:275
virtual double GetEndTime() const =0
virtual int GetChannel() const
Definition: Track.h:285
virtual double GetStartTime() const =0
TimeTrack * GetTimeTrack()
Definition: Track.cpp:1244
virtual int GetKind() const
Definition: Track.h:329
int format
Definition: ExportPCM.cpp:56
std::vector< std::shared_ptr< const WaveTrack > > WaveTrackConstArray
Definition: AudioIO.h:66
char * samplePtr
Definition: Types.h:203
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
Fundamental data object of Audacity, placed in the TrackPanel. Classes derived form it include the Wa...
Definition: Track.h:101
An iterator for a TrackList.
Definition: Track.h:401
_("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
void SetName(const wxString &n)
Definition: Track.h:271
Functions for doing the mixdown of the tracks.
Definition: Mix.h:80
void MixBuffers ( unsigned  numChannels,
int *  channelFlags,
float *  gains,
samplePtr  src,
samplePtr dests,
int  len,
bool  interleaved 
)