Audacity  2.2.2
SpectrumPrefs.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  SpectrumPrefs.cpp
6 
7  Dominic Mazzoni
8  James Crook
9 
10 *******************************************************************//*******************************************************************/
16 
17 #include "../Audacity.h"
18 #include "SpectrumPrefs.h"
19 
20 #include <wx/defs.h>
21 #include <wx/intl.h>
22 #include <wx/checkbox.h>
23 
24 #include "../FFT.h"
25 #include "../Project.h"
26 #include "../ShuttleGui.h"
27 #include "../WaveTrack.h"
28 
29 #include "../TrackPanel.h"
30 
31 #include <algorithm>
32 
33 #include "../Experimental.h"
34 #include "../widgets/ErrorDialog.h"
35 
36 SpectrumPrefs::SpectrumPrefs(wxWindow * parent, wxWindowID winid, WaveTrack *wt)
37 : PrefsPanel(parent, winid, wt ? _("Spectrogram Settings") : _("Spectrograms"))
38 , mWt(wt)
39 , mPopulating(false)
40 {
41  if (mWt) {
44  mTempSettings = mOrigSettings = settings;
49  }
50  else {
52  mOrigDefaulted = mDefaulted = false;
53  }
54 
55  const auto windowSize = mTempSettings.WindowSize();
57  Populate(windowSize);
58 }
59 
61 {
62  if (!mCommitted)
63  Rollback();
64 }
65 
66 enum {
67  ID_WINDOW_SIZE = 10001,
68 #ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
80 #endif
82 };
83 
84 void SpectrumPrefs::Populate(size_t windowSize)
85 {
86  mSizeChoices.Add(_("8 - most wideband"));
87  mSizeChoices.Add(wxT("16"));
88  mSizeChoices.Add(wxT("32"));
89  mSizeChoices.Add(wxT("64"));
90  mSizeChoices.Add(wxT("128"));
91  mSizeChoices.Add(wxT("256"));
92  mSizeChoices.Add(wxT("512"));
93  mSizeChoices.Add(_("1024 - default"));
94  mSizeChoices.Add(wxT("2048"));
95  mSizeChoices.Add(wxT("4096"));
96  mSizeChoices.Add(wxT("8192"));
97  mSizeChoices.Add(wxT("16384"));
98  mSizeChoices.Add(_("32768 - most narrowband"));
100 
101  PopulatePaddingChoices(windowSize);
102 
103  for (int i = 0; i < NumWindowFuncs(); i++) {
105  }
106 
108 
110 
111  //------------------------- Main section --------------------
112  // Now construct the GUI itself.
115  // ----------------------- End of main section --------------
116 }
117 
119 {
120 #ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
121  mZeroPaddingChoice = 1;
122 
123  // The choice of window size restricts the choice of padding.
124  // So the padding menu might grow or shrink.
125 
126  // If pPaddingSizeControl is NULL, we have not yet tied the choice control.
127  // If it is not NULL, we rebuild the control by hand.
128  // I don't yet know an easier way to do this with ShuttleGUI functions.
129  // PRL
130  wxChoice *const pPaddingSizeControl =
131  static_cast<wxChoice*>(wxWindow::FindWindowById(ID_PADDING_SIZE, this));
132 
133  if (pPaddingSizeControl) {
134  mZeroPaddingChoice = pPaddingSizeControl->GetSelection();
135  pPaddingSizeControl->Clear();
136  }
137 
138  unsigned padding = 1;
139  int numChoices = 0;
140  const size_t maxWindowSize = 1 << (SpectrogramSettings::LogMaxWindowSize);
141  while (windowSize <= maxWindowSize) {
142  const wxString numeral = wxString::Format(wxT("%d"), padding);
143  mZeroPaddingChoices.Add(numeral);
144  if (pPaddingSizeControl)
145  pPaddingSizeControl->Append(numeral);
146  windowSize <<= 1;
147  padding <<= 1;
148  ++numChoices;
149  }
150 
152 
153  if (pPaddingSizeControl)
154  pPaddingSizeControl->SetSelection(mZeroPaddingChoice);
155 #endif
156 }
157 
159 {
160  mPopulating = true;
161  S.SetBorder(2);
162  S.StartScroller(); {
163 
164  // S.StartStatic(_("Track Settings"));
165  // {
166 
167 
168  mDefaultsCheckbox = 0;
169  if (mWt) {
170  /* i18n-hint: use is a verb */
171  mDefaultsCheckbox = S.Id(ID_DEFAULTS).TieCheckBox(_("&Use Preferences"), mDefaulted);
172  }
173 
174  S.StartStatic(_("Scale"));
175  {
176  S.StartTwoColumn();
177  {
178  S.Id(ID_SCALE).TieChoice(_("S&cale") + wxString(wxT(":")),
179  *(int*)&mTempSettings.scaleType,
180  &mScaleChoices);
181 
182  mMinFreq =
183  S.Id(ID_MINIMUM).TieNumericTextBox(_("Mi&nimum Frequency (Hz):"),
185  12);
186 
187  mMaxFreq =
188  S.Id(ID_MAXIMUM).TieNumericTextBox(_("Ma&ximum Frequency (Hz):"),
190  12);
191  }
192  S.EndTwoColumn();
193  }
194  S.EndStatic();
195 
196  S.StartStatic(_("Colors"));
197  {
198  S.StartTwoColumn();
199  {
200  mGain =
201  S.Id(ID_GAIN).TieNumericTextBox(_("&Gain (dB):"),
203  8);
204 
205  mRange =
206  S.Id(ID_RANGE).TieNumericTextBox(_("&Range (dB):"),
208  8);
209 
211  S.Id(ID_FREQUENCY_GAIN).TieNumericTextBox(_("Frequency g&ain (dB/dec):"),
213  4);
214  }
215 
216  S.Id(ID_GRAYSCALE).TieCheckBox(_("Gra&yscale"),
218 
219  S.EndTwoColumn();
220  }
221  S.EndStatic();
222 
223  S.StartStatic(_("Algorithm"));
224  {
225  S.StartMultiColumn(2);
226  {
228  S.Id(ID_ALGORITHM).TieChoice(_("A&lgorithm") + wxString(wxT(":")),
229  *(int*)&mTempSettings.algorithm,
231 
232  S.Id(ID_WINDOW_SIZE).TieChoice(_("Window &size:"),
234  &mSizeChoices);
236 
237  S.Id(ID_WINDOW_TYPE).TieChoice(_("Window &type:"),
239  &mTypeChoices);
241 
242 #ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
244  S.Id(ID_PADDING_SIZE).TieChoice(_("&Zero padding factor") + wxString(wxT(":")),
248 #endif
249  }
250  S.EndMultiColumn();
251  }
252  S.EndStatic();
253 
254 #ifndef SPECTRAL_SELECTION_GLOBAL_SWITCH
255  S.Id(ID_SPECTRAL_SELECTION).TieCheckBox(_("Ena&ble Spectral Selection"),
257 #endif
258 
259 #ifdef EXPERIMENTAL_FFT_Y_GRID
260  S.TieCheckBox(_("Show a grid along the &Y-axis"),
261  mTempSettings.fftYGrid);
262 #endif //EXPERIMENTAL_FFT_Y_GRID
263 
264 #ifdef EXPERIMENTAL_FIND_NOTES
265  /* i18n-hint: FFT stands for Fast Fourier Transform and probably shouldn't be translated*/
266  S.StartStatic(_("FFT Find Notes"));
267  {
268  S.StartTwoColumn();
269  {
270  mFindNotesMinA =
271  S.TieNumericTextBox(_("Minimum Amplitude (dB):"),
272  mTempSettings.findNotesMinA,
273  8);
274 
275  mFindNotesN =
276  S.TieNumericTextBox(_("Max. Number of Notes (1..128):"),
277  mTempSettings.numberOfMaxima,
278  8);
279  }
280  S.EndTwoColumn();
281 
282  S.TieCheckBox(_("&Find Notes"),
283  mTempSettings.fftFindNotes);
284 
285  S.TieCheckBox(_("&Quantize Notes"),
286  mTempSettings.findNotesQuantize);
287  }
288  S.EndStatic();
289 #endif //EXPERIMENTAL_FIND_NOTES
290  // S.EndStatic();
291 
292 #ifdef SPECTRAL_SELECTION_GLOBAL_SWITCH
293  S.StartStatic(_("Global settings"));
294  {
295  S.TieCheckBox(_("Ena&ble spectral selection"),
296  SpectrogramSettings::Globals::Get().spectralSelection);
297  }
298  S.EndStatic();
299 #endif
300 
301  } S.EndScroller();
302 
304 
305  mPopulating = false;
306 }
307 
309 {
310  // Do checking for whole numbers
311 
312  // ToDo: use wxIntegerValidator<unsigned> when available
313 
314  long maxFreq;
315  if (!mMaxFreq->GetValue().ToLong(&maxFreq)) {
316  AudacityMessageBox(_("The maximum frequency must be an integer"));
317  return false;
318  }
319 
320  long minFreq;
321  if (!mMinFreq->GetValue().ToLong(&minFreq)) {
322  AudacityMessageBox(_("The minimum frequency must be an integer"));
323  return false;
324  }
325 
326  long gain;
327  if (!mGain->GetValue().ToLong(&gain)) {
328  AudacityMessageBox(_("The gain must be an integer"));
329  return false;
330  }
331 
332  long range;
333  if (!mRange->GetValue().ToLong(&range)) {
334  AudacityMessageBox(_("The range must be a positive integer"));
335  return false;
336  }
337 
338  long frequencygain;
339  if (!mFrequencyGain->GetValue().ToLong(&frequencygain)) {
340  AudacityMessageBox(_("The frequency gain must be an integer"));
341  return false;
342  }
343 
344 #ifdef EXPERIMENTAL_FIND_NOTES
345  long findNotesMinA;
346  if (!mFindNotesMinA->GetValue().ToLong(&findNotesMinA)) {
347  AudacityMessageBox(_("The minimum amplitude (dB) must be an integer"));
348  return false;
349  }
350 
351  long findNotesN;
352  if (!mFindNotesN->GetValue().ToLong(&findNotesN)) {
353  AudacityMessageBox(_("The maximum number of notes must be an integer"));
354  return false;
355  }
356  if (findNotesN < 1 || findNotesN > 128) {
357  AudacityMessageBox(_("The maximum number of notes must be in the range 1..128"));
358  return false;
359  }
360 #endif //EXPERIMENTAL_FIND_NOTES
361 
362  ShuttleGui S(this, eIsSavingToPrefs);
364 
365  // Delegate range checking to SpectrogramSettings class
367  const bool result = mTempSettings.Validate(false);
369  return result;
370 }
371 
373 {
374  const auto partner =
375  mWt ?
376  // Assume linked track is wave or null
377  static_cast<WaveTrack*>(mWt->GetLink())
378  : nullptr;
379 
380  if (mWt) {
381  if (mOrigDefaulted) {
383  mWt->SetSpectrumBounds(-1, -1);
384  if (partner) {
385  partner->SetSpectrogramSettings({});
386  partner->SetSpectrumBounds(-1, -1);
387  }
388  }
389  else {
390  SpectrogramSettings *pSettings =
393  *pSettings = mOrigSettings;
394  if (partner) {
395  pSettings = &partner->GetIndependentSpectrogramSettings();
396  partner->SetSpectrumBounds(mOrigMin, mOrigMax);
397  *pSettings = mOrigSettings;
398  }
399  }
400  }
401 
402  if (!mWt || mOrigDefaulted) {
404  *pSettings = mOrigSettings;
405  }
406 
407  const bool isOpenPage = this->IsShown();
408  if (mWt && isOpenPage) {
410  if (partner)
411  partner->SetDisplay(mOrigDisplay);
412  }
413 
414  if (isOpenPage) {
416  tp->UpdateVRulers();
417  tp->Refresh(false);
418  }
419 }
420 
422 {
423  if (!Validate())
424  return;
425 
426  const bool isOpenPage = this->IsShown();
427 
428  const auto partner =
429  mWt ?
430  // Assume linked track is wave or null
431  static_cast<WaveTrack*>(mWt->GetLink())
432  : nullptr;
433 
434  ShuttleGui S(this, eIsSavingToPrefs);
436 
437 
439 
440  if (mWt) {
441  if (mDefaulted) {
443  // ... and so that the vertical scale also defaults:
444  mWt->SetSpectrumBounds(-1, -1);
445  if (partner) {
446  partner->SetSpectrogramSettings({});
447  partner->SetSpectrumBounds(-1, -1);
448  }
449  }
450  else {
451  SpectrogramSettings *pSettings =
454  *pSettings = mTempSettings;
455  if (partner) {
456  pSettings = &partner->GetIndependentSpectrogramSettings();
457  partner->SetSpectrumBounds(mTempSettings.minFreq, mTempSettings.maxFreq);
458  *pSettings = mTempSettings;
459  }
460  }
461  }
462 
463  if (!mWt || mDefaulted) {
465  *pSettings = mTempSettings;
466  }
468 
469  if (mWt && isOpenPage) {
471  if (partner)
472  partner->SetDisplay(WaveTrack::Spectrum);
473  }
474 
475  if (isOpenPage) {
477  tp->UpdateVRulers();
478  tp->Refresh(false);
479  }
480 }
481 
483 {
484  if (!Validate())
485  return false;
486 
487  mCommitted = true;
489  if (!mWt || mDefaulted) {
491  pSettings->SavePrefs();
492  }
493 
494  return true;
495 }
496 
498 {
499  return true;
500 }
501 
502 void SpectrumPrefs::OnControl(wxCommandEvent&)
503 {
504  // Common routine for most controls
505  // If any per-track setting is changed, break the association with defaults
506  // Skip this, and View Settings... will be able to change defaults instead
507  // when the checkbox is on, as in the original design.
508 
509  if (mDefaultsCheckbox && !mPopulating) {
510  mDefaulted = false;
511  mDefaultsCheckbox->SetValue(false);
512  }
513 }
514 
515 void SpectrumPrefs::OnWindowSize(wxCommandEvent &evt)
516 {
517  // Restrict choice of zero padding, so that product of window
518  // size and padding may not exceed the largest window size.
519  wxChoice *const pWindowSizeControl =
520  static_cast<wxChoice*>(wxWindow::FindWindowById(ID_WINDOW_SIZE, this));
521  size_t windowSize = 1 <<
522  (pWindowSizeControl->GetSelection() + SpectrogramSettings::LogMinWindowSize);
523  PopulatePaddingChoices(windowSize);
524 
525  // Do the common part
526  OnControl(evt);
527 }
528 
529 void SpectrumPrefs::OnDefaults(wxCommandEvent &)
530 {
531  if (mDefaultsCheckbox->IsChecked()) {
534  mDefaulted = true;
537  }
538 }
539 
540 void SpectrumPrefs::OnAlgorithm(wxCommandEvent &evt)
541 {
543  OnControl(evt);
544 }
545 
547 {
548  // Enable or disable other controls that are applicable only to STFT.
549  const bool STFT =
551  mGain->Enable(STFT);
552  mRange->Enable(STFT);
553  mFrequencyGain->Enable(STFT);
554 #ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
555  mZeroPaddingChoiceCtrl->Enable(STFT);
556 #endif
557 }
558 
560 {
561  return "Spectrograms_Preferences";
562 }
563 
564 BEGIN_EVENT_TABLE(SpectrumPrefs, PrefsPanel)
565  EVT_CHOICE(ID_WINDOW_SIZE, SpectrumPrefs::OnWindowSize)
566  EVT_CHECKBOX(ID_DEFAULTS, SpectrumPrefs::OnDefaults)
567  EVT_CHOICE(ID_ALGORITHM, SpectrumPrefs::OnAlgorithm)
568 
569  // Several controls with common routine that unchecks the default box
570  EVT_CHOICE(ID_WINDOW_TYPE, SpectrumPrefs::OnControl)
571  EVT_CHOICE(ID_PADDING_SIZE, SpectrumPrefs::OnControl)
572  EVT_CHOICE(ID_SCALE, SpectrumPrefs::OnControl)
573  EVT_TEXT(ID_MINIMUM, SpectrumPrefs::OnControl)
574  EVT_TEXT(ID_MAXIMUM, SpectrumPrefs::OnControl)
575  EVT_TEXT(ID_GAIN, SpectrumPrefs::OnControl)
576  EVT_TEXT(ID_RANGE, SpectrumPrefs::OnControl)
577  EVT_TEXT(ID_FREQUENCY_GAIN, SpectrumPrefs::OnControl)
578  EVT_CHECKBOX(ID_GRAYSCALE, SpectrumPrefs::OnControl)
579  EVT_CHECKBOX(ID_SPECTRAL_SELECTION, SpectrumPrefs::OnControl)
580 
582 
584 : mWt(wt)
585 {
586 }
587 
588 PrefsPanel *SpectrumPrefsFactory::operator () (wxWindow *parent, wxWindowID winid)
589 {
590  wxASSERT(parent); // to justify safenew
591  return safenew SpectrumPrefs(parent, winid, mWt);
592 }
wxChoice * TieChoice(const wxString &Prompt, WrappedType &WrappedRef, const wxArrayString *pChoices)
wxArrayString mTypeChoices
Definition: SpectrumPrefs.h:84
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI...
Definition: ShuttleGui.h:366
Spectrogram settings, either for one track or as defaults.
bool Commit() override
WaveTrack::WaveTrackDisplay mOrigDisplay
wxChoice * mAlgorithmChoice
Definition: SpectrumPrefs.h:87
void GetSpectrumBounds(float *min, float *max) const
Definition: WaveTrack.cpp:363
wxArrayString mScaleChoices
Definition: SpectrumPrefs.h:85
void EndMultiColumn()
static const wxArrayString & GetScaleNames()
wxChoice * mZeroPaddingChoiceCtrl
Definition: SpectrumPrefs.h:80
int AudacityMessageBox(const wxString &message, const wxString &caption=AudacityMessageBoxCaptionStr(), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: ErrorDialog.h:92
void PopulatePaddingChoices(size_t windowSize)
WaveTrack *const mWt
const SpectrogramSettings & GetSpectrogramSettings() const
Definition: WaveTrack.cpp:711
void EndScroller()
Definition: ShuttleGui.cpp:770
SpectrogramSettings & GetIndependentSpectrogramSettings()
Definition: WaveTrack.cpp:727
void Populate(size_t windowSize)
wxCheckBox * mDefaultsCheckbox
Definition: SpectrumPrefs.h:96
void SetSpectrogramSettings(std::unique_ptr< SpectrogramSettings > &&pSettings)
Definition: WaveTrack.cpp:735
wxArrayString mZeroPaddingChoices
Definition: SpectrumPrefs.h:81
#define safenew
Definition: Audacity.h:223
SpectrogramSettings mOrigSettings
Definition: SpectrumPrefs.h:98
const wxChar * WindowFuncName(int whichFunction)
Definition: FFT.cpp:335
A PrefsPanel for spectrum settings.
Definition: SpectrumPrefs.h:42
WaveTrack *const mWt
Definition: SpectrumPrefs.h:67
void SetSizeHints(int minX=-1, int minY=-1)
void SetDisplay(WaveTrackDisplay display)
Definition: WaveTrack.h:589
wxArrayString mSizeChoices
Definition: SpectrumPrefs.h:76
bool Validate() override
static const wxArrayString & GetAlgorithmNames()
wxScrolledWindow * StartScroller(int iStyle=0)
Definition: ShuttleGui.cpp:733
void StartTwoColumn()
Definition: ShuttleGui.h:125
The TrackPanel class coordinates updates and operations on the main part of the screen which contains...
Definition: TrackPanel.h:245
wxArrayString mAlgorithmChoices
Definition: SpectrumPrefs.h:88
bool ShowsPreviewButton() override
size_t WindowSize() const
void StartMultiColumn(int nCols, int PositionFlags=wxALIGN_LEFT)
Definition: ShuttleGui.cpp:998
SpectrumPrefs(wxWindow *parent, wxWindowID winid, WaveTrack *wt)
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
ShuttleGui & Id(int id)
virtual ~SpectrumPrefs()
void OnAlgorithm(wxCommandEvent &)
void OnWindowSize(wxCommandEvent &event)
wxTextCtrl * TieNumericTextBox(const wxString &Prompt, WrappedType &WrappedRef, const int nChars)
void Refresh(bool eraseBackground=true, const wxRect *rect=(const wxRect *) NULL) override
int min(int a, int b)
void OnControl(wxCommandEvent &event)
void PopulateOrExchange(ShuttleGui &S)
SpectrogramSettings mTempSettings
Definition: SpectrumPrefs.h:98
int NumWindowFuncs()
Definition: FFT.cpp:330
wxTextCtrl * mFrequencyGain
Definition: SpectrumPrefs.h:74
Used within the PrefsDialog, classes derived from this class include AudioIOPrefs, BatchPrefs, DirectoriesPrefs, FileFormatPrefs, GUIPrefs, KeyConfigPrefs, MousePrefs, QualityPrefs, SpectrumPrefs and ThemePrefs.
Definition: PrefsPanel.h:43
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom"))), OnMoveTrack) void TrackMenuTable::OnSetName(wxCommandEvent &)
wxTextCtrl * mGain
Definition: SpectrumPrefs.h:72
wxCheckBox * TieCheckBox(const wxString &Prompt, WrappedType &WrappedRef)
Track * GetLink() const
Definition: Track.cpp:267
void Preview() override
AUDACITY_DLL_API AudacityProject * GetActiveProject()
Definition: Project.cpp:300
void SetSpectrumBounds(float min, float max) const
Definition: WaveTrack.cpp:407
wxStaticBox * StartStatic(const wxString &Str, int iProp=0)
Definition: ShuttleGui.cpp:701
wxTextCtrl * mRange
Definition: SpectrumPrefs.h:73
int mZeroPaddingChoice
Definition: SpectrumPrefs.h:79
TrackPanel * GetTrackPanel()
Definition: Project.h:289
wxTextCtrl * mMinFreq
Definition: SpectrumPrefs.h:70
END_EVENT_TABLE()
void UpdateVRulers()
WaveTrackDisplay GetDisplay() const
Definition: WaveTrack.h:588
void SetBorder(int Border)
Definition: ShuttleGui.h:251
void EndTwoColumn()
Definition: ShuttleGui.h:126
wxString HelpPageName() override
static SpectrogramSettings & defaults()
void EnableDisableSTFTOnlyControls()
wxTextCtrl * mMaxFreq
Definition: SpectrumPrefs.h:71
PrefsPanel * operator()(wxWindow *parent, wxWindowID winid) override
void OnDefaults(wxCommandEvent &)