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 auto mixLeft =
101 first->EmptyCopy(trackFactory->GetSampleBlockFactory(), false);
102 mixLeft->SetRate(rate);
103 mixLeft->ConvertToSampleFormat(format);
104 if (oneinput)
105 mixLeft->SetName(first->GetName()); /* set name of output track to be the same as the sole input track */
106 else
107 /* i18n-hint: noun, means a track, made by mixing other tracks */
108 mixLeft->SetName(newTrackName);
109 mixLeft->SetOffset(mixStartTime);
110
111 // TODO: more-than-two-channels
112 decltype(mixLeft) mixRight{};
113 if ( !mono ) {
114 mixRight = trackFactory->Create(format, rate);
115 if (oneinput) {
116 auto channels = TrackList::Channels(first);
117 if (channels.size() > 1)
118 mixRight->SetName((*channels.begin().advance(1))->GetName()); /* set name to match input track's right channel!*/
119 else
120 mixRight->SetName(first->GetName()); /* set name to that of sole input channel */
121 }
122 else
123 mixRight->SetName(newTrackName);
124 mixRight->SetOffset(mixStartTime);
125 }
126
127
128 auto maxBlockLen = mixLeft->GetIdealBlockSize();
129
130 // If the caller didn't specify a time range, use the whole range in which
131 // any input track had clips in it.
132 if (startTime == endTime) {
133 startTime = mixStartTime;
134 endTime = mixEndTime;
135 }
136
137 Mixer mixer(move(waveArray),
138 // Throw to abort mix-and-render if read fails:
139 true, warpOptions,
140 startTime, endTime, mono ? 1 : 2, maxBlockLen, false,
141 rate, format);
142
143 using namespace BasicUI;
144 auto updateResult = ProgressResult::Success;
145 {
146 auto pProgress = MakeProgress(XO("Mix and Render"),
147 XO("Mixing and rendering tracks"));
148
149 while (updateResult == ProgressResult::Success) {
150 auto blockLen = mixer.Process();
151
152 if (blockLen == 0)
153 break;
154
155 if (mono) {
156 auto buffer = mixer.GetBuffer();
157 mixLeft->Append(buffer, format, blockLen);
158 }
159 else {
160 auto buffer = mixer.GetBuffer(0);
161 mixLeft->Append(buffer, format, blockLen);
162 buffer = mixer.GetBuffer(1);
163 mixRight->Append(buffer, format, blockLen);
164 }
165
166 updateResult = pProgress->Poll(
167 mixer.MixGetCurrentTime() - startTime, endTime - startTime);
168 }
169 }
170
171 mixLeft->Flush();
172 if (!mono)
173 mixRight->Flush();
174 if (updateResult == ProgressResult::Cancelled || updateResult == ProgressResult::Failed)
175 {
176 return;
177 }
178 else {
179 uLeft = mixLeft, uRight = mixRight;
180#if 0
181 int elapsedMS = wxGetElapsedTime();
182 double elapsedTime = elapsedMS * 0.001;
183 double maxTracks = totalTime / (elapsedTime / numWaves);
184
185 // Note: these shouldn't be translated - they're for debugging
186 // and profiling only.
187 wxPrintf(" Tracks: %d\n", numWaves);
188 wxPrintf(" Mix length: %f sec\n", totalTime);
189 wxPrintf("Elapsed time: %f sec\n", elapsedTime);
190 wxPrintf("Max number of tracks to mix in real time: %f\n", maxTracks);
191#endif
192
193 for (auto pTrack : { uLeft.get(), uRight.get() })
194 if (pTrack)
196 }
197}
198
199#include "EffectInterface.h"
201 const Track &track, bool multichannel, ChannelName map[3])
202{
203 // Iterate either over one track which could be any channel,
204 // or if multichannel, then over all channels of track,
205 // which is a leader.
206 unsigned numChannels = 0;
207 for (auto channel : TrackList::Channels(&track).StartingWith(&track)) {
208 if (channel->GetChannel() == Track::LeftChannel)
209 map[numChannels] = ChannelNameFrontLeft;
210 else if (channel->GetChannel() == Track::RightChannel)
211 map[numChannels] = ChannelNameFrontRight;
212 else
213 map[numChannels] = ChannelNameMono;
214 ++ numChannels;
215 map[numChannels] = ChannelNameEOL;
216 if (! multichannel)
217 break;
218 if (numChannels == 2) {
219 // TODO: more-than-two-channels
220 // Ignore other channels
221 break;
222 }
223 }
224 return numChannels;
225}
226
229
230std::vector<MixerOptions::StageSpecification>
232{
233 auto &effects = RealtimeEffectList::Get(track);
234 if (!effects.IsActive())
235 return {};
236 std::vector<MixerOptions::StageSpecification> result;
237 for (size_t i = 0, count = effects.GetStatesCount(); i < count; ++i) {
238 const auto pState = effects.GetStateAt(i);
239 if (!pState->IsEnabled())
240 continue;
241 const auto pEffect = pState->GetEffect();
242 if (!pEffect)
243 continue;
244 const auto &settings = pState->GetSettings();
245 if (!settings.has_value())
246 continue;
247 const auto pInstance =
248 std::dynamic_pointer_cast<EffectInstanceEx>(pEffect->MakeInstance());
249 if (!pInstance)
250 continue;
251 auto &stage = result.emplace_back(MixerOptions::StageSpecification{
252 move(pInstance), settings });
253 MakeChannelMap(track, pEffect->GetAudioInCount() > 1, stage.map);
254 }
255 return result;
256}
std::vector< std::shared_ptr< const WaveTrack > > WaveTrackConstArray
Definition: AudioIO.h:50
Toolkit-neutral facade for basic user interface services.
ChannelName
@ ChannelNameFrontLeft
@ ChannelNameEOL
@ ChannelNameMono
@ ChannelNameFrontRight
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...
unsigned MakeChannelMap(const Track &track, bool multichannel, ChannelName map[3])
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:174
std::vector< Input > Inputs
Definition: Mix.h:43
constSamplePtr GetBuffer()
Retrieve the main buffer or the interleaved buffer.
Definition: Mix.cpp:273
double MixGetCurrentTime()
Definition: Mix.cpp:283
static RealtimeEffectList & Get(AudacityProject &project)
void Clear()
Use only in the main thread. Sends Remove messages.
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:225
@ LeftChannel
Definition: Track.h:282
@ RightChannel
Definition: Track.h:283
@ MonoChannel
Definition: Track.h:284
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1539
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:271
bool empty() const
Definition: MemoryX.h:271
Iterator begin() const
Definition: MemoryX.h:265
Immutable structure is an argument to Mixer's constructor.
Definition: MixerOptions.h:53
Range between two TrackIters, usable in range-for statements, and with Visit member functions.
Definition: Track.h:1167