Audacity 3.2.0
SpectralDataManager.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 SpectralDataManager.cpp
6
7 Edward Hui
8
9*******************************************************************//*******************************************************************/
15
16#include <iostream>
17#include "FFT.h"
18#include "ProjectHistory.h"
19#include "SpectralDataManager.h"
20#include "WaveTrack.h"
21
23
25
29 size_t mWindowSize = 2048;
30 unsigned mStepsPerWindow = 4;
31 bool mLeadingPadding = true;
32 bool mTrailingPadding = true;
33 bool mNeedOutput = true;
34};
35
37 auto &tracks = TrackList::Get(project);
38 int applyCount = 0;
39 Setting setting;
40 Worker worker(setting);
41
42 for ( auto wt : tracks.Any< WaveTrack >() ) {
43 auto &trackView = TrackView::Get(*wt);
44
45 if(auto waveTrackViewPtr = dynamic_cast<WaveTrackView*>(&trackView)){
46 for(const auto &subViewPtr : waveTrackViewPtr->GetAllSubViews()){
47 if(!subViewPtr->IsSpectral())
48 continue;
49 auto sView = std::static_pointer_cast<SpectrumView>(subViewPtr).get();
50 auto pSpectralData = sView->GetSpectralData();
51
52 if(!pSpectralData->dataHistory.empty()){
53 worker.Process(wt, pSpectralData);
54 applyCount += static_cast<int>(pSpectralData->dataHistory.size());
55 pSpectralData->clearAllData();
56 }
57 }
58 }
59 }
60
61 if (applyCount) {
63 XO("Applied effect to selection"),
64 XO("Applied effect to selection"));
65 ProjectHistory::Get(project).ModifyState(true);
66 }
67
68 return applyCount > 0;
69}
70
72 long long int startSC,
73 int hopSize,
74 double threshold,
75 int targetFreqBin)
76{
77 Setting setting;
78 setting.mNeedOutput = false;
79 Worker worker(setting);
80
81 return worker.ProcessSnapping(wt, startSC, hopSize, setting.mWindowSize, threshold, targetFreqBin);
82}
83
85 long long int startSC,
86 int hopSize,
87 double threshold,
88 int targetFreqBin)
89 {
90 Setting setting;
91 setting.mNeedOutput = false;
92 Worker worker(setting);
93
94 return worker.ProcessOvertones(wt, startSC, hopSize, setting.mWindowSize, threshold, targetFreqBin);
95 }
96
98:TrackSpectrumTransformer{ setting.mNeedOutput, setting.mInWindowType, setting.mOutWindowType,
99 setting.mWindowSize, setting.mStepsPerWindow,
100 setting.mLeadingPadding, setting.mTrailingPadding}
101// Work members
102{
103}
104
106
109}
112}
113
115 const std::shared_ptr<SpectralData>& pSpectralData)
116{
117 mpSpectralData = pSpectralData;
118 const auto &hopSize = mpSpectralData->GetHopSize();
119 auto startSample = mpSpectralData->GetStartSample();
120 const auto &endSample = mpSpectralData->GetEndSample();
121 // Correct the first hop num, because SpectrumTransformer will send
122 // a few initial windows that overlay the range only partially
123 mStartHopNum = startSample / hopSize - (mStepsPerWindow - 1);
124 mWindowCount = 0;
125
126 // Correct the start of range so that the first full window is
127 // centered at that position
128 startSample = std::max(static_cast<long long>(0), startSample - 2 * hopSize);
129 if (!TrackSpectrumTransformer::Process( Processor, wt, 1, startSample, endSample - startSample))
130 return false;
131
132 return true;
133}
134
136 long long startSC,
137 int hopSize,
138 size_t winSize,
139 double threshold,
140 int targetFreqBin)
141{
142 mSnapThreshold = threshold;
143 mSnapTargetFreqBin = targetFreqBin;
144 mSnapSamplingRate = wt->GetRate();
145
146 startSC = std::max(static_cast<long long>(0), startSC - 2 * hopSize);
147 // The calculated frequency peak will be stored in mReturnFreq
148 if (!TrackSpectrumTransformer::Process( SnappingProcessor, wt,
149 1, startSC, winSize))
150 return 0;
151
152 return mSnapReturnFreqBin;
153}
154
156 long long startSC,
157 int hopSize,
158 size_t winSize,
159 double threshold,
160 int targetFreqBin)
161 {
162 mOvertonesThreshold = threshold;
163 mSnapTargetFreqBin = targetFreqBin;
164 mSnapSamplingRate = wt->GetRate();
165
166 startSC = std::max(static_cast<long long>(0), startSC - 2 * hopSize);
167 // The calculated multiple frequency peaks will be stored in mOvertonesTargetFreqBin
168 TrackSpectrumTransformer::Process( OvertonesProcessor, wt, 1, startSC, winSize);
169 return move( mOvertonesTargetFreqBin );
170 }
171
173 auto &worker = static_cast<Worker &>(transformer);
174 // Compute power spectrum in the newest window
175 {
176 MyWindow &record = worker.NthWindow(0);
177 float *pSpectrum = &record.mSpectrums[0];
178 const double dc = record.mRealFFTs[0];
179 *pSpectrum++ = dc * dc;
180 float *pReal = &record.mRealFFTs[1], *pImag = &record.mImagFFTs[1];
181 for (size_t nn = worker.mSpectrumSize - 2; nn--;) {
182 const double re = *pReal++, im = *pImag++;
183 *pSpectrum++ = re * re + im * im;
184 }
185 const double nyquist = record.mImagFFTs[0];
186 *pSpectrum = nyquist * nyquist;
187
188 const double &sr = worker.mSnapSamplingRate;
189 const double nyquistRate = sr / 2;
190 const double &threshold = worker.mSnapThreshold;
191 const double &spectrumSize = worker.mSpectrumSize;
192 const int &targetBin = worker.mSnapTargetFreqBin;
193
194 int binBound = spectrumSize * threshold;
195 float maxValue = std::numeric_limits<float>::min();
196
197 // Skip the first and last bin
198 for(int i = -binBound; i < binBound; i++){
199 int idx = std::clamp(targetBin + i, 0, static_cast<int>(spectrumSize - 1));
200 if(record.mSpectrums[idx] > maxValue){
201 maxValue = record.mSpectrums[idx];
202 // Update the return frequency
203 worker.mSnapReturnFreqBin = idx;
204 }
205 }
206 }
207
208 return true;
209}
210
212 auto &worker = static_cast<Worker &>(transformer);
213 // Compute power spectrum in the newest window
214 {
215 MyWindow &record = worker.NthWindow(0);
216 float *pSpectrum = &record.mSpectrums[0];
217 const double dc = record.mRealFFTs[0];
218 *pSpectrum++ = dc * dc;
219 float *pReal = &record.mRealFFTs[1], *pImag = &record.mImagFFTs[1];
220 for (size_t nn = worker.mSpectrumSize - 2; nn--;) {
221 const double re = *pReal++, im = *pImag++;
222 *pSpectrum++ = re * re + im * im;
223 }
224 const double nyquist = record.mImagFFTs[0];
225 *pSpectrum = nyquist * nyquist;
226
227 const double &spectrumSize = worker.mSpectrumSize;
228 const int &targetBin = worker.mSnapTargetFreqBin;
229
230 float targetValue = record.mSpectrums[targetBin];
231
232 double fundamental = targetBin;
233 int overtone = 2, binNum = 0;
234 pSpectrum = &record.mSpectrums[0];
235 while ( fundamental >= 1 &&
236 ( binNum = lrint( fundamental * overtone ) ) < spectrumSize) {
237 // Examine a few bins each way up and down
238 constexpr int tolerance = 3;
239 auto begin = pSpectrum + std::max( 0, binNum - (tolerance + 1) );
240 auto end = pSpectrum +
241 std::min<size_t>( spectrumSize, binNum + (tolerance + 1) + 1 );
242 auto peak = std::max_element( begin, end );
243
244 // Abandon if the peak is too far up or down
245 if ( peak == begin || peak == end - 1 )
246 break;
247
248 int newBin = peak - pSpectrum;
249 worker.mOvertonesTargetFreqBin.push_back(newBin);
250 // Correct the estimate of the fundamental
251 fundamental = double(newBin) / overtone++;
252 }
253 }
254 return true;
255}
256
258{
259 auto &worker = static_cast<Worker &>(transformer);
260 // Compute power spectrum in the newest window
261 {
262 MyWindow &record = worker.NthWindow(0);
263 float *pSpectrum = &record.mSpectrums[0];
264 const double dc = record.mRealFFTs[0];
265 *pSpectrum++ = dc * dc;
266 float *pReal = &record.mRealFFTs[1], *pImag = &record.mImagFFTs[1];
267 for (size_t nn = worker.mSpectrumSize - 2; nn--;) {
268 const double re = *pReal++, im = *pImag++;
269 *pSpectrum++ = re * re + im * im;
270 }
271 const double nyquist = record.mImagFFTs[0];
272 *pSpectrum = nyquist * nyquist;
273 }
274
275 worker.ApplyEffectToSelection();
276 return true;
277}
278
280 auto &record = NthWindow(0);
281
282 for(auto &spectralDataMap: mpSpectralData->dataHistory){
283 // For all added frequency
284 for(const int &freqBin: spectralDataMap[mStartHopNum]){
285 record.mRealFFTs[freqBin] = 0;
286 record.mImagFFTs[freqBin] = 0;
287 }
288 }
289
290 mWindowCount++;
291 mStartHopNum ++;
292 return true;
293}
294
296-> std::unique_ptr<Window>
297{
298 return std::make_unique<MyWindow>(windowSize);
299}
300
302
303}
int min(int a, int b)
eWindowFunctions
Definition: FFT.h:110
@ eWinFuncHann
Definition: FFT.h:114
XO("Cut/Copy/Paste")
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
void PushState(const TranslatableString &desc, const TranslatableString &shortDesc)
void ModifyState(bool bWantsAutoSave)
static ProjectHistory & Get(AudacityProject &project)
bool DoFinish() override
Called after the last call to ProcessWindow().
int ProcessSnapping(WaveTrack *wt, long long int startSC, int hopSize, size_t winSize, double threshold, int targetFreqBin)
bool DoStart() override
Called before any calls to ProcessWindow.
std::unique_ptr< Window > NewWindow(size_t windowSize) override
Allocates a window to place in the queue.
std::vector< int > ProcessOvertones(WaveTrack *wt, long long int startSC, int hopSize, size_t winSize, double threshold, int targetFreqBin)
Worker(const Setting &setting)
bool Process(WaveTrack *wt, const std::shared_ptr< SpectralData > &sDataPtr)
static bool OvertonesProcessor(SpectrumTransformer &transformer)
static bool Processor(SpectrumTransformer &transformer)
static bool SnappingProcessor(SpectrumTransformer &transformer)
static int FindFrequencySnappingBin(WaveTrack *wt, long long startSC, int hopSize, double threshold, int targetFreqBin)
static std::vector< int > FindHighestFrequencyBins(WaveTrack *wt, long long int startSC, int hopSize, double threshold, int targetFreqBin)
static bool ProcessTracks(AudacityProject &project)
A class that transforms a portion of a wave track (preserving duration) by applying Fourier transform...
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:385
Subclass of SpectrumTransformer that rewrites a track.
bool Process(const WindowProcessor &processor, WaveTrack *track, size_t queueLength, sampleCount start, sampleCount len)
Invokes Start(), ProcessSamples(), and Finish()
bool DoFinish() override
Called after the last call to ProcessWindow().
bool DoStart() override
Called before any calls to ProcessWindow.
static TrackView & Get(Track &)
Definition: TrackView.cpp:69
A Track that contains audio waveform data.
Definition: WaveTrack.h:51
double GetRate() const override
Definition: WaveTrack.cpp:421
#define lrint(dbl)
Definition: float_cast.h:169
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:150