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.StartMultiColumn(2,wxEXPAND);
175  {
176  S.SetStretchyCol( 0 );
177  S.SetStretchyCol( 1 );
178  S.StartStatic(_("Scale"),1);
179  {
180  S.StartMultiColumn(2,wxEXPAND);
181  {
182  S.SetStretchyCol( 0 );
183  S.SetStretchyCol( 1 );
184  S.Id(ID_SCALE).TieChoice(_("S&cale") + wxString(wxT(":")),
186  &mScaleChoices);
187  mMinFreq =
188  S.Id(ID_MINIMUM).TieNumericTextBox(_("Mi&n Frequency (Hz):"),
190  12);
191  mMaxFreq =
192  S.Id(ID_MAXIMUM).TieNumericTextBox(_("Ma&x Frequency (Hz):"),
194  12);
195  }
196  S.EndMultiColumn();
197  }
198  S.EndStatic();
199 
200  S.StartStatic(_("Colors"),1);
201  {
202  S.StartMultiColumn(2,wxEXPAND);
203  {
204  S.SetStretchyCol( 0 );
205  S.SetStretchyCol( 1 );
206  mGain =
207  S.Id(ID_GAIN).TieNumericTextBox(_("&Gain (dB):"),
209  8);
210  mRange =
211  S.Id(ID_RANGE).TieNumericTextBox(_("&Range (dB):"),
213  8);
214 
216  S.Id(ID_FREQUENCY_GAIN).TieNumericTextBox(_("High &boost (dB/dec):"),
218  8);
219  }
220  S.EndMultiColumn();
221 
222  S.Id(ID_GRAYSCALE).TieCheckBox(_("Gra&yscale"),
224  }
225  S.EndStatic();
226  }
227  S.EndMultiColumn();
228 
229  S.StartStatic(_("Algorithm"));
230  {
231  S.StartMultiColumn(2);
232  {
234  S.Id(ID_ALGORITHM).TieChoice(_("A&lgorithm") + wxString(wxT(":")),
237 
238  S.Id(ID_WINDOW_SIZE).TieChoice(_("Window &size:"),
240  &mSizeChoices);
241 
242  S.Id(ID_WINDOW_TYPE).TieChoice(_("Window &type:"),
244  &mTypeChoices);
245 
246 #ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
248  S.Id(ID_PADDING_SIZE).TieChoice(_("&Zero padding factor") + wxString(wxT(":")),
251 #endif
252  }
253  S.EndMultiColumn();
254  }
255  S.EndStatic();
256 
257 #ifndef SPECTRAL_SELECTION_GLOBAL_SWITCH
258  S.Id(ID_SPECTRAL_SELECTION).TieCheckBox(_("Ena&ble Spectral Selection"),
260 #endif
261 
262 #ifdef EXPERIMENTAL_FFT_Y_GRID
263  S.TieCheckBox(_("Show a grid along the &Y-axis"),
264  mTempSettings.fftYGrid);
265 #endif //EXPERIMENTAL_FFT_Y_GRID
266 
267 #ifdef EXPERIMENTAL_FIND_NOTES
268  /* i18n-hint: FFT stands for Fast Fourier Transform and probably shouldn't be translated*/
269  S.StartStatic(_("FFT Find Notes"));
270  {
271  S.StartTwoColumn();
272  {
273  mFindNotesMinA =
274  S.TieNumericTextBox(_("Minimum Amplitude (dB):"),
275  mTempSettings.findNotesMinA,
276  8);
277 
278  mFindNotesN =
279  S.TieNumericTextBox(_("Max. Number of Notes (1..128):"),
280  mTempSettings.numberOfMaxima,
281  8);
282  }
283  S.EndTwoColumn();
284 
285  S.TieCheckBox(_("&Find Notes"),
286  mTempSettings.fftFindNotes);
287 
288  S.TieCheckBox(_("&Quantize Notes"),
289  mTempSettings.findNotesQuantize);
290  }
291  S.EndStatic();
292 #endif //EXPERIMENTAL_FIND_NOTES
293  // S.EndStatic();
294 
295 #ifdef SPECTRAL_SELECTION_GLOBAL_SWITCH
296  S.StartStatic(_("Global settings"));
297  {
298  S.TieCheckBox(_("Ena&ble spectral selection"),
299  SpectrogramSettings::Globals::Get().spectralSelection);
300  }
301  S.EndStatic();
302 #endif
303 
304  } S.EndScroller();
305 
306  // Enabling and disabling belongs outside this function.
307  if( S.GetMode() != eIsGettingMetadata )
309 
310  mPopulating = false;
311 }
312 
314 {
315  // Do checking for whole numbers
316 
317  // ToDo: use wxIntegerValidator<unsigned> when available
318 
319  long maxFreq;
320  if (!mMaxFreq->GetValue().ToLong(&maxFreq)) {
321  AudacityMessageBox(_("The maximum frequency must be an integer"));
322  return false;
323  }
324 
325  long minFreq;
326  if (!mMinFreq->GetValue().ToLong(&minFreq)) {
327  AudacityMessageBox(_("The minimum frequency must be an integer"));
328  return false;
329  }
330 
331  long gain;
332  if (!mGain->GetValue().ToLong(&gain)) {
333  AudacityMessageBox(_("The gain must be an integer"));
334  return false;
335  }
336 
337  long range;
338  if (!mRange->GetValue().ToLong(&range)) {
339  AudacityMessageBox(_("The range must be a positive integer"));
340  return false;
341  }
342 
343  long frequencygain;
344  if (!mFrequencyGain->GetValue().ToLong(&frequencygain)) {
345  AudacityMessageBox(_("The frequency gain must be an integer"));
346  return false;
347  }
348 
349 #ifdef EXPERIMENTAL_FIND_NOTES
350  long findNotesMinA;
351  if (!mFindNotesMinA->GetValue().ToLong(&findNotesMinA)) {
352  AudacityMessageBox(_("The minimum amplitude (dB) must be an integer"));
353  return false;
354  }
355 
356  long findNotesN;
357  if (!mFindNotesN->GetValue().ToLong(&findNotesN)) {
358  AudacityMessageBox(_("The maximum number of notes must be an integer"));
359  return false;
360  }
361  if (findNotesN < 1 || findNotesN > 128) {
362  AudacityMessageBox(_("The maximum number of notes must be in the range 1..128"));
363  return false;
364  }
365 #endif //EXPERIMENTAL_FIND_NOTES
366 
367  ShuttleGui S(this, eIsSavingToPrefs);
369 
370  // Delegate range checking to SpectrogramSettings class
372  const bool result = mTempSettings.Validate(false);
374  return result;
375 }
376 
378 {
379  const auto partner =
380  mWt ?
381  // Assume linked track is wave or null
382  static_cast<WaveTrack*>(mWt->GetLink())
383  : nullptr;
384 
385  if (mWt) {
386  if (mOrigDefaulted) {
388  mWt->SetSpectrumBounds(-1, -1);
389  if (partner) {
390  partner->SetSpectrogramSettings({});
391  partner->SetSpectrumBounds(-1, -1);
392  }
393  }
394  else {
395  SpectrogramSettings *pSettings =
398  *pSettings = mOrigSettings;
399  if (partner) {
400  pSettings = &partner->GetIndependentSpectrogramSettings();
401  partner->SetSpectrumBounds(mOrigMin, mOrigMax);
402  *pSettings = mOrigSettings;
403  }
404  }
405  }
406 
407  if (!mWt || mOrigDefaulted) {
409  *pSettings = mOrigSettings;
410  }
411 
412  const bool isOpenPage = this->IsShown();
413  if (mWt && isOpenPage) {
415  if (partner)
416  partner->SetDisplay(mOrigDisplay);
417  }
418 
419  if (isOpenPage) {
421  tp->UpdateVRulers();
422  tp->Refresh(false);
423  }
424 }
425 
427 {
428  if (!Validate())
429  return;
430 
431  const bool isOpenPage = this->IsShown();
432 
433  const auto partner =
434  mWt ?
435  // Assume linked track is wave or null
436  static_cast<WaveTrack*>(mWt->GetLink())
437  : nullptr;
438 
439  ShuttleGui S(this, eIsSavingToPrefs);
441 
442 
444 
445  if (mWt) {
446  if (mDefaulted) {
448  // ... and so that the vertical scale also defaults:
449  mWt->SetSpectrumBounds(-1, -1);
450  if (partner) {
451  partner->SetSpectrogramSettings({});
452  partner->SetSpectrumBounds(-1, -1);
453  }
454  }
455  else {
456  SpectrogramSettings *pSettings =
459  *pSettings = mTempSettings;
460  if (partner) {
461  pSettings = &partner->GetIndependentSpectrogramSettings();
462  partner->SetSpectrumBounds(mTempSettings.minFreq, mTempSettings.maxFreq);
463  *pSettings = mTempSettings;
464  }
465  }
466  }
467 
468  if (!mWt || mDefaulted) {
470  *pSettings = mTempSettings;
471  }
473 
474  if (mWt && isOpenPage) {
476  if (partner)
477  partner->SetDisplay(WaveTrack::Spectrum);
478  }
479 
480  if (isOpenPage) {
482  tp->UpdateVRulers();
483  tp->Refresh(false);
484  }
485 }
486 
488 {
489  if (!Validate())
490  return false;
491 
492  mCommitted = true;
494  if (!mWt || mDefaulted) {
496  pSettings->SavePrefs();
497  }
498 
499  return true;
500 }
501 
503 {
504  return true;
505 }
506 
507 void SpectrumPrefs::OnControl(wxCommandEvent&)
508 {
509  // Common routine for most controls
510  // If any per-track setting is changed, break the association with defaults
511  // Skip this, and View Settings... will be able to change defaults instead
512  // when the checkbox is on, as in the original design.
513 
514  if (mDefaultsCheckbox && !mPopulating) {
515  mDefaulted = false;
516  mDefaultsCheckbox->SetValue(false);
517  }
518 }
519 
520 void SpectrumPrefs::OnWindowSize(wxCommandEvent &evt)
521 {
522  // Restrict choice of zero padding, so that product of window
523  // size and padding may not exceed the largest window size.
524  wxChoice *const pWindowSizeControl =
525  static_cast<wxChoice*>(wxWindow::FindWindowById(ID_WINDOW_SIZE, this));
526  size_t windowSize = 1 <<
527  (pWindowSizeControl->GetSelection() + SpectrogramSettings::LogMinWindowSize);
528  PopulatePaddingChoices(windowSize);
529 
530  // Do the common part
531  OnControl(evt);
532 }
533 
534 void SpectrumPrefs::OnDefaults(wxCommandEvent &)
535 {
536  if (mDefaultsCheckbox->IsChecked()) {
539  mDefaulted = true;
542  }
543 }
544 
545 void SpectrumPrefs::OnAlgorithm(wxCommandEvent &evt)
546 {
548  OnControl(evt);
549 }
550 
552 {
553  // Enable or disable other controls that are applicable only to STFT.
554  const bool STFT =
556  mGain->Enable(STFT);
557  mRange->Enable(STFT);
558  mFrequencyGain->Enable(STFT);
559 #ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
560  mZeroPaddingChoiceCtrl->Enable(STFT);
561 #endif
562 }
563 
565 {
566  return "Spectrograms_Preferences";
567 }
568 
569 BEGIN_EVENT_TABLE(SpectrumPrefs, PrefsPanel)
570  EVT_CHOICE(ID_WINDOW_SIZE, SpectrumPrefs::OnWindowSize)
571  EVT_CHECKBOX(ID_DEFAULTS, SpectrumPrefs::OnDefaults)
572  EVT_CHOICE(ID_ALGORITHM, SpectrumPrefs::OnAlgorithm)
573 
574  // Several controls with common routine that unchecks the default box
575  EVT_CHOICE(ID_WINDOW_TYPE, SpectrumPrefs::OnControl)
576  EVT_CHOICE(ID_PADDING_SIZE, SpectrumPrefs::OnControl)
577  EVT_CHOICE(ID_SCALE, SpectrumPrefs::OnControl)
578  EVT_TEXT(ID_MINIMUM, SpectrumPrefs::OnControl)
579  EVT_TEXT(ID_MAXIMUM, SpectrumPrefs::OnControl)
580  EVT_TEXT(ID_GAIN, SpectrumPrefs::OnControl)
581  EVT_TEXT(ID_RANGE, SpectrumPrefs::OnControl)
582  EVT_TEXT(ID_FREQUENCY_GAIN, SpectrumPrefs::OnControl)
583  EVT_CHECKBOX(ID_GRAYSCALE, SpectrumPrefs::OnControl)
584  EVT_CHECKBOX(ID_SPECTRAL_SELECTION, SpectrumPrefs::OnControl)
585 
587 
589 : mWt(wt)
590 {
591 }
592 
593 PrefsPanel *SpectrumPrefsFactory::operator () (wxWindow *parent, wxWindowID winid)
594 {
595  wxASSERT(parent); // to justify safenew
596  return safenew SpectrumPrefs(parent, winid, mWt);
597 }
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:409
Spectrogram settings, either for one track or as defaults.
bool Commit() override
WaveTrack::WaveTrackDisplay mOrigDisplay
void PopulateOrExchange(ShuttleGui &S) override
wxChoice * mAlgorithmChoice
Definition: SpectrumPrefs.h:87
void GetSpectrumBounds(float *min, float *max) const
Definition: WaveTrack.cpp:337
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:690
void EndScroller()
Definition: ShuttleGui.cpp:828
SpectrogramSettings & GetIndependentSpectrogramSettings()
Definition: WaveTrack.cpp:706
void Populate(size_t windowSize)
wxCheckBox * mDefaultsCheckbox
Definition: SpectrumPrefs.h:96
void SetSpectrogramSettings(std::unique_ptr< SpectrogramSettings > &&pSettings)
Definition: WaveTrack.cpp:714
wxArrayString mZeroPaddingChoices
Definition: SpectrumPrefs.h:81
#define safenew
Definition: Audacity.h:230
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 SetDisplay(WaveTrackDisplay display)
Definition: WaveTrack.h:594
wxArrayString mSizeChoices
Definition: SpectrumPrefs.h:76
bool Validate() override
static const wxArrayString & GetAlgorithmNames()
wxScrolledWindow * StartScroller(int iStyle=0)
Definition: ShuttleGui.cpp:795
void StartTwoColumn()
Definition: ShuttleGui.h:136
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)
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)
SpectrogramSettings mTempSettings
Definition: SpectrumPrefs.h:98
int NumWindowFuncs()
Definition: FFT.cpp:330
wxTextCtrl * mFrequencyGain
Definition: SpectrumPrefs.h:74
teShuttleMode GetMode()
Definition: ShuttleGui.h:425
Used within the PrefsDialog, classes derived from this class include AudioIOPrefs, BatchPrefs, DirectoriesPrefs, FileFormatPrefs, GUIPrefs, KeyConfigPrefs, MousePrefs, QualityPrefs, SpectrumPrefs and ThemePrefs.
Definition: PrefsPanel.h:45
wxTextCtrl * mGain
Definition: SpectrumPrefs.h:72
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
wxCheckBox * TieCheckBox(const wxString &Prompt, WrappedType &WrappedRef)
Track * GetLink() const
Definition: Track.cpp:269
void Preview() override
AUDACITY_DLL_API AudacityProject * GetActiveProject()
Definition: Project.cpp:308
void SetSpectrumBounds(float min, float max) const
Definition: WaveTrack.cpp:381
wxStaticBox * StartStatic(const wxString &Str, int iProp=0)
Definition: ShuttleGui.cpp:763
wxTextCtrl * mRange
Definition: SpectrumPrefs.h:73
int mZeroPaddingChoice
Definition: SpectrumPrefs.h:79
TrackPanel * GetTrackPanel()
Definition: Project.h:307
wxTextCtrl * mMinFreq
Definition: SpectrumPrefs.h:70
END_EVENT_TABLE()
void UpdateVRulers()
WaveTrackDisplay GetDisplay() const
Definition: WaveTrack.h:593
void SetBorder(int Border)
Definition: ShuttleGui.h:286
void EndTwoColumn()
Definition: ShuttleGui.h:137
wxString HelpPageName() override
void SetStretchyCol(int i)
Used to modify an already placed FlexGridSizer to make a column stretchy.
Definition: ShuttleGui.cpp:203
static SpectrogramSettings & defaults()
void EnableDisableSTFTOnlyControls()
wxTextCtrl * mMaxFreq
Definition: SpectrumPrefs.h:71
PrefsPanel * operator()(wxWindow *parent, wxWindowID winid) override
void OnDefaults(wxCommandEvent &)