Audacity 3.2.0
StereoToMono.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 StereoToMono.cpp
6
7 Lynn Allan
8
9*******************************************************************//*******************************************************************/
15
16
17#include "StereoToMono.h"
18#include "LoadEffects.h"
19
20#include "Mix.h"
21#include "MixAndRender.h"
22#include "Project.h"
23#include "RealtimeEffectList.h"
24#include "WaveTrack.h"
25#include "ProgressDialog.h"
26
28{ XO("Stereo To Mono") };
29
31
33{
34}
35
37{
38}
39
40// ComponentInterface implementation
41
43{
44 return Symbol;
45}
46
48{
49 return XO("Converts stereo tracks to mono");
50}
51
52// EffectDefinitionInterface implementation
53
55{
56 // Really EffectTypeProcess, but this prevents it from showing in the Effect Menu
57 return EffectTypeHidden;
58}
59
61{
62 return false;
63}
64
66{
67 return 2;
68}
69
71{
72 return 1;
73}
74
75// Effect implementation
76
78{
79 // Do not use mWaveTracks here. We will possibly DELETE tracks,
80 // so we must use the "real" tracklist.
81 this->CopyInputTracks(); // Set up mOutputTracks.
82 bool bGoodResult = true;
83
84 // Determine the total time (in samples) used by all of the target tracks
85 sampleCount totalTime = 0;
86
87 auto trackRange = mOutputTracks->SelectedLeaders< WaveTrack >();
88 while (trackRange.first != trackRange.second)
89 {
90 auto left = *trackRange.first;
91 auto channels = TrackList::Channels(left);
92 if (channels.size() > 1)
93 {
94 auto right = *channels.rbegin();
95 auto leftRate = left->GetRate();
96 auto rightRate = right->GetRate();
97
98 if (leftRate != rightRate)
99 {
100 if (leftRate != mProjectRate)
101 {
102 mProgress->SetMessage(XO("Resampling left channel"));
103 left->Resample(mProjectRate, mProgress);
104 leftRate = mProjectRate;
105 }
106 if (rightRate != mProjectRate)
107 {
108 mProgress->SetMessage(XO("Resampling right channel"));
109 right->Resample(mProjectRate, mProgress);
110 rightRate = mProjectRate;
111 }
112 }
113 {
114 auto start = wxMin(left->TimeToLongSamples(left->GetStartTime()),
115 right->TimeToLongSamples(right->GetStartTime()));
116 auto end = wxMax(left->TimeToLongSamples(left->GetEndTime()),
117 right->TimeToLongSamples(right->GetEndTime()));
118
119 totalTime += (end - start);
120 }
121 }
122
123 ++trackRange.first;
124 }
125
126 // Process each stereo track
127 sampleCount curTime = 0;
128 bool refreshIter = false;
129
130 mProgress->SetMessage(XO("Mixing down to mono"));
131
132 trackRange = mOutputTracks->SelectedLeaders< WaveTrack >();
133 while (trackRange.first != trackRange.second)
134 {
135 auto left = *trackRange.first;
136 auto channels = TrackList::Channels(left);
137 if (channels.size() > 1)
138 {
139 auto right = *channels.rbegin();
140
141 bGoodResult = ProcessOne(curTime, totalTime, left, right);
142 if (!bGoodResult)
143 {
144 break;
145 }
146
147 // The right channel has been deleted, so we must restart from the beginning
148 refreshIter = true;
149 }
150
151 if (refreshIter)
152 {
153 trackRange = mOutputTracks->SelectedLeaders< WaveTrack >();
154 refreshIter = false;
155 }
156 else
157 {
158 ++trackRange.first;
159 }
160 }
161
162 this->ReplaceProcessedTracks(bGoodResult);
163 return bGoodResult;
164}
165
167{
168 auto idealBlockLen = left->GetMaxBlockSize() * 2;
169 bool bResult = true;
170 sampleCount processed = 0;
171
172 auto start = wxMin(left->GetStartTime(), right->GetStartTime());
173 auto end = wxMax(left->GetEndTime(), right->GetEndTime());
174
175 Mixer::Inputs tracks;
176 for (auto pTrack : { left, right })
177 tracks.emplace_back(
178 pTrack->SharedPointer<const SampleTrack>(), GetEffectStages(*pTrack));
179
180 Mixer mixer(move(tracks),
181 true, // Throw to abort mix-and-render if read fails:
183 start,
184 end,
185 1,
186 idealBlockLen,
187 false, // Not interleaved
188 left->GetRate(), // Process() checks that left and right
189 // rates are the same
191
192 auto outTrack = left->EmptyCopy();
193 outTrack->ConvertToSampleFormat(floatSample);
194
195 while (auto blockLen = mixer.Process()) {
196 auto buffer = mixer.GetBuffer();
197 for (auto i = 0; i < blockLen; i++)
198 {
199 ((float *)buffer)[i] /= 2.0;
200 }
201 // If mixing channels that both had only 16 bit effective format
202 // (for example), and no gains or envelopes, still there should be
203 // dithering because of the averaging above, which may introduce samples
204 // lying between the quantization levels. So default the effectiveFormat
205 // to widest.
206 outTrack->Append(buffer, floatSample, blockLen, 1);
207
208 curTime += blockLen;
209 if (TotalProgress(curTime.as_double() / totalTime.as_double()))
210 {
211 return false;
212 }
213 }
214 outTrack->Flush();
215
216 double minStart = wxMin(left->GetStartTime(), right->GetStartTime());
217 left->Clear(left->GetStartTime(), left->GetEndTime());
218 left->Paste(minStart, outTrack.get());
219 mOutputTracks->UnlinkChannels(*left);
220 mOutputTracks->Remove(right);
222
223 return bResult;
224}
225
227{
228 return true;
229}
EffectType
@ EffectTypeHidden
XO("Cut/Copy/Paste")
std::vector< MixerOptions::StageSpecification > GetEffectStages(const WaveTrack &track)
virtual void SetMessage(const TranslatableString &message)=0
Change an existing dialog's message.
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
std::shared_ptr< TrackList > mOutputTracks
Definition: EffectBase.h:111
const TrackList * inputTracks() const
Definition: EffectBase.h:108
double mProjectRate
Definition: EffectBase.h:105
BasicUI::ProgressDialog * mProgress
Definition: EffectBase.h:104
void ReplaceProcessedTracks(const bool bGoodResult)
Definition: EffectBase.cpp:232
void CopyInputTracks(bool allSyncLockSelected=false)
Definition: Effect.cpp:396
bool TotalProgress(double frac, const TranslatableString &={}) const
Definition: Effect.cpp:338
Performs effect computation.
unsigned GetAudioOutCount() const override
How many output buffers to allocate at once.
bool IsInteractive() const override
Whether the effect needs a dialog for entry of settings.
unsigned GetAudioInCount() const override
How many input buffers to allocate at once.
ComponentInterfaceSymbol GetSymbol() const override
static const ComponentInterfaceSymbol Symbol
Definition: StereoToMono.h:19
bool Process(EffectInstance &instance, EffectSettings &settings) override
TranslatableString GetDescription() const override
bool ProcessOne(sampleCount &curTime, sampleCount totalTime, WaveTrack *left, WaveTrack *right)
bool IsHiddenFromMenus() const override
Default is false.
EffectType GetType() const override
Type determines how it behaves.
virtual ~EffectStereoToMono()
Functions for doing the mixdown of the tracks.
Definition: Mix.h:26
std::vector< Input > Inputs
Definition: Mix.h:43
static RealtimeEffectList & Get(AudacityProject &project)
void Clear()
Use only in the main thread. Sends Remove messages.
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1544
Holds a msgid for the translation catalog; may also bind format arguments.
A Track that contains audio waveform data.
Definition: WaveTrack.h:51
void Paste(double t0, const Track *src) override
Definition: WaveTrack.cpp:1367
double GetStartTime() const override
Get the time at which the first clip in the track starts.
Definition: WaveTrack.cpp:1802
size_t GetMaxBlockSize() const override
This returns a nonnegative number of samples meant to size a memory buffer.
Definition: WaveTrack.cpp:1611
void Clear(double t0, double t1) override
Definition: WaveTrack.cpp:652
double GetEndTime() const override
Get the time at which the last clip in the track ends, plus recorded stuff.
Definition: WaveTrack.cpp:1822
double GetRate() const override
Definition: WaveTrack.cpp:360
Holder EmptyCopy(const SampleBlockFactoryPtr &pFactory={}, bool keepLink=true) const
Definition: WaveTrack.cpp:574
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:19
double as_double() const
Definition: SampleCount.h:46
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
BuiltinEffectsModule::Registration< EffectStereoToMono > reg
Externalized state of a plug-in.
Immutable structure is an argument to Mixer's constructor.
Definition: MixerOptions.h:54