Audacity 3.2.0
MixAndRender.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5MixAndRender.cpp
6
7Paul Licameli split from Mix.cpp
8
9**********************************************************************/
10
11#include "MixAndRender.h"
12
13#include "BasicUI.h"
14#include "Mix.h"
16#include "WaveTrack.h"
17
18using WaveTrackConstArray = std::vector < std::shared_ptr < const WaveTrack > >;
19
20//TODO-MB: wouldn't it make more sense to DELETE the time track after 'mix and render'?
22 const Mixer::WarpOptions &warpOptions,
23 const wxString &newTrackName,
24 WaveTrackFactory *trackFactory,
25 double rate, sampleFormat format,
26 double startTime, double endTime,
28{
29 uLeft.reset(), uRight.reset();
30 if (trackRange.empty())
31 return;
32
33 // This function was formerly known as "Quick Mix".
34 bool mono = false; /* flag if output can be mono without losing anything*/
35 bool oneinput = false; /* flag set to true if there is only one input track
36 (mono or stereo) */
37
38 auto first = *trackRange.begin();
39 assert(first); // because the range is known to be nonempty
40
41 // this only iterates tracks which are relevant to this function, i.e.
42 // selected WaveTracks. The tracklist is (confusingly) the list of all
43 // tracks in the project
44
45 int numWaves = 0; /* number of wave tracks in the selection */
46 int numMono = 0; /* number of mono, centre-panned wave tracks in selection*/
47 for(auto wt : trackRange) {
48 numWaves++;
49 float pan = wt->GetPan();
50 if (wt->GetChannel() == Track::MonoChannel && pan == 0)
51 numMono++;
52 }
53
54 if (numMono == numWaves)
55 mono = true;
56
57 /* the next loop will do two things at once:
58 * 1. build an array of all the wave tracks were are trying to process
59 * 2. determine when the set of WaveTracks starts and ends, in case we
60 * need to work out for ourselves when to start and stop rendering.
61 */
62
63 double mixStartTime = 0.0; /* start time of first track to start */
64 bool gotstart = false; // flag indicates we have found a start time
65 double mixEndTime = 0.0; /* end time of last track to end */
66 double tstart, tend; // start and end times for one track.
67
68 Mixer::Inputs waveArray;
69
70 for(auto wt : trackRange) {
71 waveArray.emplace_back(
72 wt->SharedPointer<const SampleTrack>(), GetEffectStages(*wt));
73 tstart = wt->GetStartTime();
74 tend = wt->GetEndTime();
75 if (tend > mixEndTime)
76 mixEndTime = tend;
77 // try and get the start time. If the track is empty we will get 0,
78 // which is ambiguous because it could just mean the track starts at
79 // the beginning of the project, as well as empty track. The give-away
80 // is that an empty track also ends at zero.
81
82 if (tstart != tend) {
83 // we don't get empty tracks here
84 if (!gotstart) {
85 // no previous start, use this one unconditionally
86 mixStartTime = tstart;
87 gotstart = true;
88 } else if (tstart < mixStartTime)
89 mixStartTime = tstart; // have a start, only make it smaller
90 } // end if start and end are different
91 }
92
93 /* create the destination track (NEW track) */
94 if (numWaves == (int)TrackList::Channels(first).size())
95 oneinput = true;
96 // only one input track (either 1 mono or one linked stereo pair)
97
98 // EmptyCopy carries over any interesting channel group information
99 // But make sure the left is unlinked before we re-link
100 // And reset pan and gain
101 auto mixLeft =
102 first->EmptyCopy(trackFactory->GetSampleBlockFactory(), false);
103 mixLeft->SetPan(0);
104 mixLeft->SetGain(1);
105 mixLeft->SetRate(rate);
106 mixLeft->ConvertToSampleFormat(format);
107 if (oneinput)
108 mixLeft->SetName(first->GetName()); /* set name of output track to be the same as the sole input track */
109 else
110 /* i18n-hint: noun, means a track, made by mixing other tracks */
111 mixLeft->SetName(newTrackName);
112 mixLeft->SetOffset(mixStartTime);
113
114 // TODO: more-than-two-channels
115 decltype(mixLeft) mixRight{};
116 if ( !mono ) {
117 mixRight = trackFactory->Create(format, rate);
118 if (oneinput) {
119 auto channels = TrackList::Channels(first);
120 if (channels.size() > 1)
121 mixRight->SetName((*channels.begin().advance(1))->GetName()); /* set name to match input track's right channel!*/
122 else
123 mixRight->SetName(first->GetName()); /* set name to that of sole input channel */
124 }
125 else
126 mixRight->SetName(newTrackName);
127 mixRight->SetOffset(mixStartTime);
128 }
129
130
131 auto maxBlockLen = mixLeft->GetIdealBlockSize();
132
133 // If the caller didn't specify a time range, use the whole range in which
134 // any input track had clips in it.
135 if (startTime == endTime) {
136 startTime = mixStartTime;
137 endTime = mixEndTime;
138 }
139
140 Mixer mixer(move(waveArray),
141 // Throw to abort mix-and-render if read fails:
142 true, warpOptions,
143 startTime, endTime, mono ? 1 : 2, maxBlockLen, false,
144 rate, format);
145
146 using namespace BasicUI;
147 auto updateResult = ProgressResult::Success;
148 {
149 auto pProgress = MakeProgress(XO("Mix and Render"),
150 XO("Mixing and rendering tracks"));
151
152 while (updateResult == ProgressResult::Success) {
153 auto blockLen = mixer.Process();
154
155 if (blockLen == 0)
156 break;
157
158 if (mono) {
159 auto buffer = mixer.GetBuffer();
160 mixLeft->Append(buffer, format, blockLen);
161 }
162 else {
163 auto buffer = mixer.GetBuffer(0);
164 mixLeft->Append(buffer, format, blockLen);
165 buffer = mixer.GetBuffer(1);
166 mixRight->Append(buffer, format, blockLen);
167 }
168
169 updateResult = pProgress->Poll(
170 mixer.MixGetCurrentTime() - startTime, endTime - startTime);
171 }
172 }
173
174 mixLeft->Flush();
175 if (!mono)
176 mixRight->Flush();
177 if (updateResult == ProgressResult::Cancelled || updateResult == ProgressResult::Failed)
178 {
179 return;
180 }
181 else {
182 uLeft = mixLeft, uRight = mixRight;
183#if 0
184 int elapsedMS = wxGetElapsedTime();
185 double elapsedTime = elapsedMS * 0.001;
186 double maxTracks = totalTime / (elapsedTime / numWaves);
187
188 // Note: these shouldn't be translated - they're for debugging
189 // and profiling only.
190 wxPrintf(" Tracks: %d\n", numWaves);
191 wxPrintf(" Mix length: %f sec\n", totalTime);
192 wxPrintf("Elapsed time: %f sec\n", elapsedTime);
193 wxPrintf("Max number of tracks to mix in real time: %f\n", maxTracks);
194#endif
195
196 for (auto pTrack : { uLeft.get(), uRight.get() })
197 if (pTrack)
199 }
200}
201
204
205std::vector<MixerOptions::StageSpecification>
207{
208 auto &effects = RealtimeEffectList::Get(track);
209 if (!effects.IsActive())
210 return {};
211 std::vector<MixerOptions::StageSpecification> result;
212 for (size_t i = 0, count = effects.GetStatesCount(); i < count; ++i) {
213 const auto pState = effects.GetStateAt(i);
214 if (!pState->IsEnabled())
215 continue;
216 const auto pEffect = pState->GetEffect();
217 if (!pEffect)
218 continue;
219 const auto &settings = pState->GetSettings();
220 if (!settings.has_value())
221 continue;
222 auto &stage = result.emplace_back(MixerOptions::StageSpecification{
223 [pEffect]{ return std::dynamic_pointer_cast<EffectInstanceEx>(
224 pEffect->MakeInstance()); },
225 settings });
226 }
227 return result;
228}
std::vector< std::shared_ptr< const WaveTrack > > WaveTrackConstArray
Definition: AudioIO.h:50
Toolkit-neutral facade for basic user interface services.
int format
Definition: ExportPCM.cpp:56
#define XO(s)
Definition: Internat.h:31
void MixAndRender(const TrackIterRange< const WaveTrack > &trackRange, const Mixer::WarpOptions &warpOptions, const wxString &newTrackName, 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...
std::vector< MixerOptions::StageSpecification > GetEffectStages(const WaveTrack &track)
sampleFormat
Definition: SampleFormat.h:29
static Settings & settings()
Definition: TrackInfo.cpp:87
Functions for doing the mixdown of the tracks.
Definition: Mix.h:26
size_t Process(size_t maxSamples)
Definition: Mix.cpp:199
std::vector< Input > Inputs
Definition: Mix.h:43
constSamplePtr GetBuffer()
Retrieve the main buffer or the interleaved buffer.
Definition: Mix.cpp:298
double MixGetCurrentTime()
Definition: Mix.cpp:308
static RealtimeEffectList & Get(AudacityProject &project)
void Clear()
Use only in the main thread. Sends Remove messages.
@ MonoChannel
Definition: Track.h:284
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1541
Used to create or clone a WaveTrack, with appropriate context from the project that will own the trac...
Definition: WaveTrack.h:613
std::shared_ptr< WaveTrack > Create()
Creates an unnamed empty WaveTrack with default sample format and default rate.
Definition: WaveTrack.cpp:118
const SampleBlockFactoryPtr & GetSampleBlockFactory() const
Definition: WaveTrack.h:630
A Track that contains audio waveform data.
Definition: WaveTrack.h:57
std::shared_ptr< WaveTrack > Holder
Definition: WaveTrack.h:106
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:284
bool empty() const
Definition: MemoryX.h:279
Iterator begin() const
Definition: MemoryX.h:273
Immutable structure is an argument to Mixer's constructor.
Definition: MixerOptions.h:54
Range between two TrackIters, usable in range-for statements, and with Visit member functions.
Definition: Track.h:1167