Audacity 3.2.0
Typedefs | Functions
MixAndRender.cpp File Reference
#include "MixAndRender.h"
#include "BasicUI.h"
#include "Mix.h"
#include "effects/RealtimeEffectList.h"
#include "WaveTrack.h"
#include "effects/RealtimeEffectState.h"
Include dependency graph for MixAndRender.cpp:

Go to the source code of this file.

Typedefs

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

Functions

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 effects in the process. More...
 
std::vector< MixerOptions::StageSpecificationGetEffectStages (const WaveTrack &track)
 

Typedef Documentation

◆ WaveTrackConstArray

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

Definition at line 18 of file MixAndRender.cpp.

Function Documentation

◆ GetEffectStages()

std::vector< MixerOptions::StageSpecification > GetEffectStages ( const WaveTrack track)

Definition at line 206 of file MixAndRender.cpp.

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}
static Settings & settings()
Definition: TrackInfo.cpp:87
static RealtimeEffectList & Get(AudacityProject &project)

References RealtimeEffectList::Get(), and settings().

Referenced by ExportPlugin::CreateMixer(), MixAndRender(), and EffectStereoToMono::ProcessOne().

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

◆ MixAndRender()

void MixAndRender ( const TrackIterRange< const WaveTrack > &  trackRange,
const Mixer::WarpOptions warpOptions,
const wxString &  newTrackName,
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, 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. Channel group properties of the result are copied from the first input track.

Parameters
newTrackNameused only when there is more than one input track (one mono channel or a stereo pair); else the unique track's name is copied

Definition at line 21 of file MixAndRender.cpp.

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}
int format
Definition: ExportPCM.cpp:56
#define XO(s)
Definition: Internat.h:31
std::vector< MixerOptions::StageSpecification > GetEffectStages(const WaveTrack &track)
Functions for doing the mixdown of the tracks.
Definition: Mix.h:26
std::vector< Input > Inputs
Definition: Mix.h:43
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
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
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

References IteratorRange< Iterator >::begin(), RefreshCode::Cancelled, TrackList::Channels(), RealtimeEffectList::Clear(), WaveTrackFactory::Create(), IteratorRange< Iterator >::empty(), format, RealtimeEffectList::Get(), Mixer::GetBuffer(), GetEffectStages(), WaveTrackFactory::GetSampleBlockFactory(), BasicUI::MakeProgress(), Mixer::MixGetCurrentTime(), Track::MonoChannel, Mixer::Process(), size, BasicUI::Success, and XO.

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

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