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 <wx/intl.h>
21
22#include "Mix.h"
23#include "Project.h"
24#include "../WaveTrack.h"
25#include "../widgets/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
176 tracks.push_back(left->SharedPointer< const SampleTrack >());
177 tracks.push_back(right->SharedPointer< const SampleTrack >());
178
179 Mixer mixer(tracks,
180 true, // Throw to abort mix-and-render if read fails:
182 start,
183 end,
184 1,
185 idealBlockLen,
186 false, // Not interleaved
187 left->GetRate(), // Process() checks that left and right
188 // rates are the same
190
191 auto outTrack = left->EmptyCopy();
192 outTrack->ConvertToSampleFormat(floatSample);
193
194 while (auto blockLen = mixer.Process(idealBlockLen))
195 {
196 auto buffer = mixer.GetBuffer();
197 for (auto i = 0; i < blockLen; i++)
198 {
199 ((float *)buffer)[i] /= 2.0;
200 }
201 outTrack->Append(buffer, floatSample, blockLen);
202
203 curTime += blockLen;
204 if (TotalProgress(curTime.as_double() / totalTime.as_double()))
205 {
206 return false;
207 }
208 }
209 outTrack->Flush();
210
211 double minStart = wxMin(left->GetStartTime(), right->GetStartTime());
212 left->Clear(left->GetStartTime(), left->GetEndTime());
213 left->Paste(minStart, outTrack.get());
214 mOutputTracks->UnlinkChannels(*left);
215 mOutputTracks->Remove(right);
216
217 return bResult;
218}
219
221{
222 return true;
223}
EffectType
@ EffectTypeHidden
#define XO(s)
Definition: Internat.h:31
std::vector< std::shared_ptr< const SampleTrack > > SampleTrackConstArray
Definition: Mix.h:33
@ floatSample
Definition: SampleFormat.h:34
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:105
const TrackList * inputTracks() const
Definition: EffectBase.h:102
double mProjectRate
Definition: EffectBase.h:99
BasicUI::ProgressDialog * mProgress
Definition: EffectBase.h:98
void ReplaceProcessedTracks(const bool bGoodResult)
Definition: EffectBase.cpp:236
void CopyInputTracks(bool allSyncLockSelected=false)
Definition: Effect.cpp:741
bool TotalProgress(double frac, const TranslatableString &={}) const
Definition: Effect.cpp:685
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
Actually do the effect here.
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:58
std::shared_ptr< Subclass > SharedPointer()
Definition: Track.h:297
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1539
Holds a msgid for the translation catalog; may also bind format arguments.
A Track that contains audio waveform data.
Definition: WaveTrack.h:57
void Paste(double t0, const Track *src) override
Definition: WaveTrack.cpp:1563
double GetStartTime() const override
Get the time at which the first clip in the track starts.
Definition: WaveTrack.cpp:1995
size_t GetMaxBlockSize() const override
This returns a nonnegative number of samples meant to size a memory buffer.
Definition: WaveTrack.cpp:1806
void Clear(double t0, double t1) override
Definition: WaveTrack.cpp:788
double GetEndTime() const override
Get the time at which the last clip in the track ends, plus recorded stuff.
Definition: WaveTrack.cpp:2015
double GetRate() const override
Definition: WaveTrack.cpp:479
Holder EmptyCopy(const SampleBlockFactoryPtr &pFactory={}, bool keepLink=true) const
Definition: WaveTrack.cpp:705
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:18
double as_double() const
Definition: SampleCount.h:45
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
BuiltinEffectsModule::Registration< EffectStereoToMono > reg
Externalized state of a plug-in.