Audacity 3.2.0
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
18#include "SpectrumPrefs.h"
19
20#include <wx/choice.h>
21#include <wx/defs.h>
22#include <wx/checkbox.h>
23#include <wx/textctrl.h>
24
25#include "FFT.h"
26#include "Project.h"
27#include "ShuttleGui.h"
28
29#include "../TrackPanel.h"
30#include "WaveTrack.h"
31#include "../tracks/playabletrack/wavetrack/ui/WaveChannelView.h"
32
33#include <algorithm>
34
35#include "AudacityMessageBox.h"
36
37SpectrumPrefs::SpectrumPrefs(wxWindow * parent, wxWindowID winid,
38 AudacityProject *pProject, WaveChannel *wc)
39: PrefsPanel(parent, winid, wc ? XO("Spectrogram Settings") : XO("Spectrograms"))
40, mProject{ pProject }
41, mWc(wc)
42, mPopulating(false)
43{
44 if (mWc) {
52 }
53 else {
55 mOrigDefaulted = mDefaulted = false;
56 }
57
58 const auto windowSize = mTempSettings.WindowSize();
60 Populate(windowSize);
61}
62
64{
65 if (!mCommitted)
66 Rollback();
67}
68
70{
72}
73
75{
76 return XO("Preferences for Spectrum");
77}
78
80{
81 // Currently (May2017) Spectrum Settings is the only preferences
82 // we ever display in a dialog on its own without others.
83 // We do so when it is configuring spectrums for a track.
84 // Because this happens, we want to visit a different help page.
85 // So we change the page name in the case of a page on its own.
86 return mWc
87 ? "Spectrogram_Settings"
88 : "Spectrograms_Preferences";
89}
90
91enum {
105};
106
107void SpectrumPrefs::Populate(size_t windowSize)
108{
109 PopulatePaddingChoices(windowSize);
110
111 for (int i = 0; i < NumWindowFuncs(); i++) {
112 mTypeChoices.push_back( WindowFuncName(i) );
113 }
114
115 //------------------------- Main section --------------------
116 // Now construct the GUI itself.
119 // ----------------------- End of main section --------------
120}
121
123{
125
126 // The choice of window size restricts the choice of padding.
127 // So the padding menu might grow or shrink.
128
129 // If pPaddingSizeControl is NULL, we have not yet tied the choice control.
130 // If it is not NULL, we rebuild the control by hand.
131 // I don't yet know an easier way to do this with ShuttleGUI functions.
132 // PRL
133 wxChoice *const pPaddingSizeControl =
134 static_cast<wxChoice*>(wxWindow::FindWindowById(ID_PADDING_SIZE, this));
135
136 if (pPaddingSizeControl) {
137 mZeroPaddingChoice = pPaddingSizeControl->GetSelection();
138 pPaddingSizeControl->Clear();
139 }
140
141 unsigned padding = 1;
142 int numChoices = 0;
143 const size_t maxWindowSize = 1 << (SpectrogramSettings::LogMaxWindowSize);
144 while (windowSize <= maxWindowSize) {
145 const auto numeral = wxString::Format(wxT("%d"), padding);
146 mZeroPaddingChoices.push_back( Verbatim( numeral ) );
147 if (pPaddingSizeControl)
148 pPaddingSizeControl->Append(numeral);
149 windowSize <<= 1;
150 padding <<= 1;
151 ++numChoices;
152 }
153
155
156 if (pPaddingSizeControl)
157 pPaddingSizeControl->SetSelection(mZeroPaddingChoice);
158}
159
161{
162 mPopulating = true;
163 S.SetBorder(2);
164 S.StartScroller(); {
165
166 // S.StartStatic(XO("Track Settings"));
167 // {
168
169
171 if (mWc) {
172 /* i18n-hint: use is a verb */
173 mDefaultsCheckbox = S.Id(ID_DEFAULTS).TieCheckBox(XXO("&Use Preferences"), mDefaulted);
174 }
175
176 S.StartMultiColumn(2,wxEXPAND);
177 {
178 S.SetStretchyCol( 0 );
179 S.SetStretchyCol( 1 );
180 S.StartStatic(XO("Scale"),1);
181 {
182 S.StartMultiColumn(2,wxEXPAND);
183 {
184 S.SetStretchyCol( 0 );
185 S.SetStretchyCol( 1 );
186 S.Id(ID_SCALE).TieChoice(XXO("S&cale:"),
189 mMinFreq =
190 S.Id(ID_MINIMUM).TieNumericTextBox(XXO("Mi&n Frequency (Hz):"),
192 12);
193 mMaxFreq =
194 S.Id(ID_MAXIMUM).TieNumericTextBox(XXO("Ma&x Frequency (Hz):"),
196 12);
197 }
198 S.EndMultiColumn();
199 }
200 S.EndStatic();
201
202 S.StartStatic(XO("Colors"),1);
203 {
204 S.StartMultiColumn(2,wxEXPAND);
205 {
206 S.SetStretchyCol( 0 );
207 S.SetStretchyCol( 1 );
208 mGain =
209 S.Id(ID_GAIN).TieNumericTextBox(XXO("&Gain (dB):"),
211 8);
212 mRange =
213 S.Id(ID_RANGE).TieNumericTextBox(XXO("&Range (dB):"),
215 8);
216
218 S.Id(ID_FREQUENCY_GAIN).TieNumericTextBox(XXO("High &boost (dB/dec):"),
220 8);
221
222 // i18n-hint Scheme refers to a color scheme for spectrogram colors
223 S.Id(ID_COLOR_SCHEME).TieChoice(XC("Sche&me:", "spectrum prefs"),
226 }
227 S.EndMultiColumn();
228 }
229 S.EndStatic();
230 }
231 S.EndMultiColumn();
232
233 S.StartStatic(XO("Algorithm"));
234 {
235 S.StartMultiColumn(2);
236 {
238 S.Id(ID_ALGORITHM).TieChoice(XXO("A&lgorithm:"),
241
242 S.Id(ID_WINDOW_SIZE).TieChoice(XXO("Window &size:"),
244 {
245 XO("8 - most wideband"),
246 XO("16"),
247 XO("32"),
248 XO("64"),
249 XO("128"),
250 XO("256"),
251 XO("512"),
252 XO("1024"),
253 XO("2048"),
254 XO("4096"),
255 XO("8192"),
256 XO("16384"),
257 XO("32768 - most narrowband"),
258 }
259 );
260
261 S.Id(ID_WINDOW_TYPE).TieChoice(XXO("Window &type:"),
264
266 S.Id(ID_PADDING_SIZE).TieChoice(XXO("&Zero padding factor:"),
269 }
270 S.EndMultiColumn();
271 }
272 S.EndStatic();
273
274#ifndef SPECTRAL_SELECTION_GLOBAL_SWITCH
275 S.Id(ID_SPECTRAL_SELECTION).TieCheckBox(XXO("Ena&ble Spectral Selection"),
277#endif
278
279#ifdef EXPERIMENTAL_FFT_Y_GRID
280 S.TieCheckBox(XO("Show a grid along the &Y-axis"),
281 mTempSettings.fftYGrid);
282#endif //EXPERIMENTAL_FFT_Y_GRID
283
284#ifdef EXPERIMENTAL_FIND_NOTES
285 /* i18n-hint: FFT stands for Fast Fourier Transform and probably shouldn't be translated*/
286 S.StartStatic(XO("FFT Find Notes"));
287 {
288 S.StartTwoColumn();
289 {
290 mFindNotesMinA =
291 S.TieNumericTextBox(XXO("Minimum Amplitude (dB):"),
292 mTempSettings.findNotesMinA,
293 8);
294
295 mFindNotesN =
296 S.TieNumericTextBox(XXO("Max. Number of Notes (1..128):"),
297 mTempSettings.numberOfMaxima,
298 8);
299 }
300 S.EndTwoColumn();
301
302 S.TieCheckBox(XXO("&Find Notes"),
303 mTempSettings.fftFindNotes);
304
305 S.TieCheckBox(XXO("&Quantize Notes"),
306 mTempSettings.findNotesQuantize);
307 }
308 S.EndStatic();
309#endif //EXPERIMENTAL_FIND_NOTES
310 // S.EndStatic();
311
312#ifdef SPECTRAL_SELECTION_GLOBAL_SWITCH
313 S.StartStatic(XO("Global settings"));
314 {
315 S.TieCheckBox(XXO("Ena&ble spectral selection"),
316 SpectrogramSettings::Globals::Get().spectralSelection);
317 }
318 S.EndStatic();
319#endif
320
321 } S.EndScroller();
322
323 // Enabling and disabling belongs outside this function.
324 if( S.GetMode() != eIsGettingMetadata )
326
327 mPopulating = false;
328}
329
331{
332 // Do checking for whole numbers
333
334 // ToDo: use wxIntegerValidator<unsigned> when available
335
336 long maxFreq;
337 if (!mMaxFreq->GetValue().ToLong(&maxFreq)) {
338 AudacityMessageBox( XO("The maximum frequency must be an integer") );
339 return false;
340 }
341
342 long minFreq;
343 if (!mMinFreq->GetValue().ToLong(&minFreq)) {
344 AudacityMessageBox( XO("The minimum frequency must be an integer") );
345 return false;
346 }
347
348 long gain;
349 if (!mGain->GetValue().ToLong(&gain)) {
350 AudacityMessageBox( XO("The gain must be an integer") );
351 return false;
352 }
353
354 long range;
355 if (!mRange->GetValue().ToLong(&range)) {
356 AudacityMessageBox( XO("The range must be a positive integer") );
357 return false;
358 }
359
360 long frequencygain;
361 if (!mFrequencyGain->GetValue().ToLong(&frequencygain)) {
362 AudacityMessageBox( XO("The frequency gain must be an integer") );
363 return false;
364 }
365
366#ifdef EXPERIMENTAL_FIND_NOTES
367 long findNotesMinA;
368 if (!mFindNotesMinA->GetValue().ToLong(&findNotesMinA)) {
369 AudacityMessageBox( XO("The minimum amplitude (dB) must be an integer") );
370 return false;
371 }
372
373 long findNotesN;
374 if (!mFindNotesN->GetValue().ToLong(&findNotesN)) {
375 AudacityMessageBox( XO("The maximum number of notes must be an integer") );
376 return false;
377 }
378 if (findNotesN < 1 || findNotesN > 128) {
380"The maximum number of notes must be in the range 1..128") );
381 return false;
382 }
383#endif //EXPERIMENTAL_FIND_NOTES
384
387
388 // Delegate range checking to SpectrogramSettings class
390 const bool result = mTempSettings.Validate(false);
392 return result;
393}
394
396{
397 if (mWc) {
398 if (mOrigDefaulted) {
400 SpectrogramBounds::Get(*mWc).SetBounds(-1, -1);
401 }
402 else {
406 }
407 }
408
409 if (!mWc || mOrigDefaulted) {
411 *pSettings = mOrigSettings;
412 }
413
414 const bool isOpenPage = this->IsShown();
415 if (mWc && isOpenPage) {
417 }
418
419 if (isOpenPage) {
420 if ( mProject ) {
421 auto &tp = TrackPanel::Get ( *mProject );
422 tp.UpdateVRulers();
423 tp.Refresh(false);
424 }
425 }
426}
427
429{
430 if (!Validate())
431 return;
432
433 const bool isOpenPage = this->IsShown();
434
437
438
440
441 if (mWc) {
442 if (mDefaulted) {
444 // ... and so that the vertical scale also defaults:
445 SpectrogramBounds::Get(*mWc).SetBounds(-1, -1);
446 }
447 else {
452 }
453 }
454
455 if (!mWc || mDefaulted) {
457 *pSettings = mTempSettings;
458 }
460
461 // Bug 2278
462 // This code destroys any Multi-view we had.
463 // Commenting it out as it seems not to be needed.
464 /*
465 if (mWt && isOpenPage) {
466 for (auto &&channel : mWt->Channels())
467 WaveChannelView::Get(*channel)
468 .SetDisplay(WaveChannelViewConstants::Spectrum);
469 }
470 */
471
472 if (isOpenPage) {
473 if ( mProject ) {
474 auto &tp = TrackPanel::Get( *mProject );
475 tp.UpdateVRulers();
476 tp.Refresh(false);
477 }
478 }
479}
480
482{
483 if (!Validate())
484 return false;
485
486 mCommitted = true;
489 if (!mWc || mDefaulted) {
490 pSettings->SavePrefs();
491 }
492 pSettings->LoadPrefs(); // always; in case Globals changed
493
494 return true;
495}
496
498{
499 return mProject != nullptr;
500}
501
502void 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
510 mDefaulted = false;
511 mDefaultsCheckbox->SetValue(false);
512 }
513}
514
515void 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
529void SpectrumPrefs::OnDefaults(wxCommandEvent &)
530{
531 if (mDefaultsCheckbox->IsChecked()) {
534 mDefaulted = true;
537 }
538}
539
540void 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 mZeroPaddingChoiceCtrl->Enable(STFT);
555}
556
557BEGIN_EVENT_TABLE(SpectrumPrefs, PrefsPanel)
561
562 // Several controls with common routine that unchecks the default box
573
575
577{
578 return [=](wxWindow *parent, wxWindowID winid, AudacityProject *pProject)
579 {
580 wxASSERT(parent); // to justify safenew
581 return safenew SpectrumPrefs(parent, winid, pProject, wc);
582 };
583}
584
585namespace{
587 SpectrumPrefsFactory(nullptr),
588 false,
589 // Place it at a lower tree level
590 { "Tracks" }
591};
592}
wxT("CloseDown"))
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
END_EVENT_TABLE()
int min(int a, int b)
int NumWindowFuncs()
Definition: FFT.cpp:327
const TranslatableString WindowFuncName(int whichFunction)
Definition: FFT.cpp:332
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
#define XC(s, c)
Definition: Internat.h:37
#define safenew
Definition: MemoryX.h:10
TranslatableStrings Msgids(const EnumValueSymbol strings[], size_t nStrings)
Convenience function often useful when adding choice controls.
@ eIsSettingToDialog
Definition: ShuttleGui.h:39
@ eIsCreatingFromPrefs
Definition: ShuttleGui.h:46
@ eIsSavingToPrefs
Definition: ShuttleGui.h:47
@ eIsGettingMetadata
Definition: ShuttleGui.h:40
PrefsPanel::Factory SpectrumPrefsFactory(WaveChannel *wc)
@ ID_FREQUENCY_GAIN
@ ID_SCALE
@ ID_COLOR_SCHEME
@ ID_PADDING_SIZE
@ ID_WINDOW_TYPE
@ ID_DEFAULTS
@ ID_RANGE
@ ID_GAIN
@ ID_ALGORITHM
@ ID_MAXIMUM
@ ID_SPECTRAL_SELECTION
@ ID_MINIMUM
@ ID_WINDOW_SIZE
#define SPECTRUM_PREFS_PLUGIN_SYMBOL
Definition: SpectrumPrefs.h:39
#define S(N)
Definition: ToChars.cpp:64
static Settings & settings()
Definition: TrackInfo.cpp:51
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
Base class for a panel in the PrefsDialog. Classes derived from this class include BatchPrefs,...
Definition: PrefsPanel.h:51
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:640
void SetBounds(float min, float max)
void GetBounds(const WaveChannel &wc, float &min, float &max) const
static SpectrogramBounds & Get(WaveTrack &track)
Get either the global default settings, or the track's own if previously created.
Spectrogram settings, either for one track or as defaults.
static SpectrogramSettings & defaults()
static const TranslatableStrings & GetAlgorithmNames()
static const EnumValueSymbols & GetScaleNames()
static SpectrogramSettings & Get(const WaveTrack &track)
static const EnumValueSymbols & GetColorSchemeNames()
static SpectrogramSettings & Own(WaveChannel &wc)
static void Reset(WaveChannel &channel)
Make channel lose indpendent settings and use defaults.
A PrefsPanel for spectrum settings.
Definition: SpectrumPrefs.h:42
ComponentInterfaceSymbol GetSymbol() const override
AudacityProject * mProject
Definition: SpectrumPrefs.h:70
TranslatableStrings mZeroPaddingChoices
Definition: SpectrumPrefs.h:86
void Populate(size_t windowSize)
void Preview() override
WaveChannel *const mWc
Definition: SpectrumPrefs.h:72
void OnWindowSize(wxCommandEvent &event)
virtual ~SpectrumPrefs()
void OnDefaults(wxCommandEvent &)
bool Commit() override
void OnAlgorithm(wxCommandEvent &)
wxCheckBox * mDefaultsCheckbox
Definition: SpectrumPrefs.h:98
void PopulatePaddingChoices(size_t windowSize)
std::vector< WaveChannelSubViewPlacement > mOrigPlacements
void EnableDisableSTFTOnlyControls()
void PopulateOrExchange(ShuttleGui &S) override
void OnControl(wxCommandEvent &event)
TranslatableStrings mTypeChoices
Definition: SpectrumPrefs.h:88
ManualPageID HelpPageName() override
If not empty string, the Help button is added below the panel.
bool Validate() override
wxTextCtrl * mFrequencyGain
Definition: SpectrumPrefs.h:79
wxTextCtrl * mMaxFreq
Definition: SpectrumPrefs.h:76
wxTextCtrl * mRange
Definition: SpectrumPrefs.h:78
SpectrogramSettings mOrigSettings
wxTextCtrl * mGain
Definition: SpectrumPrefs.h:77
SpectrogramSettings mTempSettings
wxChoice * mZeroPaddingChoiceCtrl
Definition: SpectrumPrefs.h:85
SpectrumPrefs(wxWindow *parent, wxWindowID winid, AudacityProject *pProject, WaveChannel *wc)
bool ShowsPreviewButton() override
int mZeroPaddingChoice
Definition: SpectrumPrefs.h:84
TranslatableString GetDescription() const override
wxChoice * mAlgorithmChoice
Definition: SpectrumPrefs.h:90
wxTextCtrl * mMinFreq
Definition: SpectrumPrefs.h:75
static TrackPanel & Get(AudacityProject &project)
Definition: TrackPanel.cpp:234
Holds a msgid for the translation catalog; may also bind format arguments.
const WaveChannelSubViewPlacements & SavePlacements() const
static WaveChannelView & Get(WaveChannel &channel)
void RestorePlacements(const WaveChannelSubViewPlacements &placements)
PrefsPanel::Registration sAttachment