Audacity  3.0.3
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 
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 }
WaveTrack.h
ProjectHistory::ModifyState
void ModifyState(bool bWantsAutoSave)
Definition: ProjectHistory.cpp:124
TrackSpectrumTransformer::DoStart
bool DoStart() override
Called before any calls to ProcessWindow.
Definition: SpectrumTransformer.cpp:404
WaveTrack
A Track that contains audio waveform data.
Definition: WaveTrack.h:69
SpectralDataManager::Setting::mInWindowType
eWindowFunctions mInWindowType
Definition: SpectralDataManager.cpp:27
WaveTrackView
Definition: WaveTrackView.h:97
TrackView::Get
static TrackView & Get(Track &)
Definition: TrackView.cpp:63
SpectralDataManager::Setting
Definition: SpectralDataManager.cpp:26
SpectralDataManager::Worker::DoFinish
bool DoFinish() override
Called after the last call to ProcessWindow().
Definition: SpectralDataManager.cpp:110
eWindowFunctions
eWindowFunctions
Definition: FFT.h:110
SpectralData::GetHopSize
int GetHopSize() const
Definition: SpectrumView.h:59
XO
#define XO(s)
Definition: Internat.h:31
SpectralDataManager::Worker::Processor
static bool Processor(SpectrumTransformer &transformer)
Definition: SpectralDataManager.cpp:257
SpectralDataManager::Worker::OvertonesProcessor
static bool OvertonesProcessor(SpectrumTransformer &transformer)
Definition: SpectralDataManager.cpp:211
SpectralDataManager::Worker::SnappingProcessor
static bool SnappingProcessor(SpectrumTransformer &transformer)
Definition: SpectralDataManager.cpp:172
SpectralDataManager.h
SpectralDataManager::Worker
Definition: SpectralDataManager.h:42
FFT.h
SpectralDataManager::Setting::mNeedOutput
bool mNeedOutput
Definition: SpectralDataManager.cpp:33
SpectralDataManager::Setting::mTrailingPadding
bool mTrailingPadding
Definition: SpectralDataManager.cpp:32
eWinFuncHann
@ eWinFuncHann
Definition: FFT.h:114
SpectralDataManager::ProcessTracks
static bool ProcessTracks(AudacityProject &project)
Definition: SpectralDataManager.cpp:36
SpectralDataManager::Setting::mOutWindowType
eWindowFunctions mOutWindowType
Definition: SpectralDataManager.cpp:28
SpectralDataManager::Worker::ProcessSnapping
int ProcessSnapping(WaveTrack *wt, long long int startSC, int hopSize, size_t winSize, double threshold, int targetFreqBin)
Definition: SpectralDataManager.cpp:135
TrackSpectrumTransformer::DoFinish
bool DoFinish() override
Called after the last call to ProcessWindow().
Definition: SpectrumTransformer.cpp:378
min
int min(int a, int b)
Definition: CompareAudioCommand.cpp:106
ProjectHistory::PushState
void PushState(const TranslatableString &desc, const TranslatableString &shortDesc)
Definition: ProjectHistory.cpp:90
SpectralDataManager::Worker::Process
bool Process(WaveTrack *wt, const std::shared_ptr< SpectralData > &sDataPtr)
Definition: SpectralDataManager.cpp:114
SpectralDataManager::Setting::mWindowSize
size_t mWindowSize
Definition: SpectralDataManager.cpp:29
TrackList::Get
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:506
SpectralDataManager::Worker::MyWindow::mSpectrums
FloatVector mSpectrums
Definition: SpectralDataManager.h:58
SpectralDataManager::Setting::mLeadingPadding
bool mLeadingPadding
Definition: SpectralDataManager.cpp:31
SpectralDataManager::Worker::Worker
Worker(const Setting &setting)
Definition: SpectralDataManager.cpp:97
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:92
SpectralDataManager::Setting::mStepsPerWindow
unsigned mStepsPerWindow
Definition: SpectralDataManager.cpp:30
ProjectHistory.h
SpectralDataManager::Worker::MyWindow::~MyWindow
~MyWindow() override
Definition: SpectralDataManager.cpp:301
SpectralDataManager::Worker::MyWindow
Definition: SpectralDataManager.h:48
SpectralDataManager::Worker::ApplyEffectToSelection
bool ApplyEffectToSelection()
Definition: SpectralDataManager.cpp:279
SpectralDataManager::~SpectralDataManager
~SpectralDataManager()
SpectralDataManager::FindFrequencySnappingBin
static int FindFrequencySnappingBin(WaveTrack *wt, long long startSC, int hopSize, double threshold, int targetFreqBin)
Definition: SpectralDataManager.cpp:71
SpectralDataManager::FindHighestFrequencyBins
static std::vector< int > FindHighestFrequencyBins(WaveTrack *wt, long long int startSC, int hopSize, double threshold, int targetFreqBin)
Definition: SpectralDataManager.cpp:84
lrint
#define lrint(dbl)
Definition: float_cast.h:169
SpectralDataManager::Worker::DoStart
bool DoStart() override
Called before any calls to ProcessWindow.
Definition: SpectralDataManager.cpp:107
SpectralDataManager::Worker::NewWindow
std::unique_ptr< Window > NewWindow(size_t windowSize) override
Allocates a window to place in the queue.
Definition: SpectralDataManager.cpp:295
ProjectHistory::Get
static ProjectHistory & Get(AudacityProject &project)
Definition: ProjectHistory.cpp:26
TrackSpectrumTransformer
Subclass of SpectrumTransformer that rewrites a track.
Definition: SpectrumTransformer.h:183
TrackSpectrumTransformer::Process
bool Process(const WindowProcessor &processor, WaveTrack *track, size_t queueLength, sampleCount start, sampleCount len)
Invokes Start(), ProcessSamples(), and Finish()
Definition: SpectrumTransformer.cpp:341
SpectrumTransformer
Transformer of sample sequences by FFT, coefficient changes, inverse FFT, overlap-add.
Definition: SpectrumTransformer.h:34
SpectralDataManager::SpectralDataManager
SpectralDataManager()
SpectralDataManager::Worker::ProcessOvertones
std::vector< int > ProcessOvertones(WaveTrack *wt, long long int startSC, int hopSize, size_t winSize, double threshold, int targetFreqBin)
Definition: SpectralDataManager.cpp:155
SpectralDataManager::Worker::~Worker
~Worker()
WaveTrack::GetRate
double GetRate() const
Definition: WaveTrack.cpp:457