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/intl.h>
23#include <wx/checkbox.h>
24#include <wx/textctrl.h>
25
26#include "FFT.h"
27#include "Project.h"
28#include "../ShuttleGui.h"
29
30#include "../TrackPanel.h"
31#include "../WaveTrack.h"
32#include "../tracks/playabletrack/wavetrack/ui/WaveTrackView.h"
33
34#include <algorithm>
35
36#include "../widgets/AudacityMessageBox.h"
37
38SpectrumPrefs::SpectrumPrefs(wxWindow * parent, wxWindowID winid,
39 AudacityProject *pProject, WaveTrack *wt)
40: PrefsPanel(parent, winid, wt ? XO("Spectrogram Settings") : XO("Spectrograms"))
41, mProject{ pProject }
42, mWt(wt)
43, mPopulating(false)
44{
45 if (mWt) {
53 }
54 else {
56 mOrigDefaulted = mDefaulted = false;
57 }
58
59 const auto windowSize = mTempSettings.WindowSize();
61 Populate(windowSize);
62}
63
65{
66 if (!mCommitted)
67 Rollback();
68}
69
71{
73}
74
76{
77 return XO("Preferences for Spectrum");
78}
79
81{
82 // Currently (May2017) Spectrum Settings is the only preferences
83 // we ever display in a dialog on its own without others.
84 // We do so when it is configuring spectrums for a track.
85 // Because this happens, we want to visit a different help page.
86 // So we change the page name in the case of a page on its own.
87 return mWt
88 ? "Spectrogram_Settings"
89 : "Spectrograms_Preferences";
90}
91
92enum {
106};
107
108void SpectrumPrefs::Populate(size_t windowSize)
109{
110 PopulatePaddingChoices(windowSize);
111
112 for (int i = 0; i < NumWindowFuncs(); i++) {
113 mTypeChoices.push_back( WindowFuncName(i) );
114 }
115
116 //------------------------- Main section --------------------
117 // Now construct the GUI itself.
120 // ----------------------- End of main section --------------
121}
122
124{
126
127 // The choice of window size restricts the choice of padding.
128 // So the padding menu might grow or shrink.
129
130 // If pPaddingSizeControl is NULL, we have not yet tied the choice control.
131 // If it is not NULL, we rebuild the control by hand.
132 // I don't yet know an easier way to do this with ShuttleGUI functions.
133 // PRL
134 wxChoice *const pPaddingSizeControl =
135 static_cast<wxChoice*>(wxWindow::FindWindowById(ID_PADDING_SIZE, this));
136
137 if (pPaddingSizeControl) {
138 mZeroPaddingChoice = pPaddingSizeControl->GetSelection();
139 pPaddingSizeControl->Clear();
140 }
141
142 unsigned padding = 1;
143 int numChoices = 0;
144 const size_t maxWindowSize = 1 << (SpectrogramSettings::LogMaxWindowSize);
145 while (windowSize <= maxWindowSize) {
146 const auto numeral = wxString::Format(wxT("%d"), padding);
147 mZeroPaddingChoices.push_back( Verbatim( numeral ) );
148 if (pPaddingSizeControl)
149 pPaddingSizeControl->Append(numeral);
150 windowSize <<= 1;
151 padding <<= 1;
152 ++numChoices;
153 }
154
156
157 if (pPaddingSizeControl)
158 pPaddingSizeControl->SetSelection(mZeroPaddingChoice);
159}
160
162{
163 mPopulating = true;
164 S.SetBorder(2);
165 S.StartScroller(); {
166
167 // S.StartStatic(XO("Track Settings"));
168 // {
169
170
172 if (mWt) {
173 /* i18n-hint: use is a verb */
174 mDefaultsCheckbox = S.Id(ID_DEFAULTS).TieCheckBox(XXO("&Use Preferences"), mDefaulted);
175 }
176
177 S.StartMultiColumn(2,wxEXPAND);
178 {
179 S.SetStretchyCol( 0 );
180 S.SetStretchyCol( 1 );
181 S.StartStatic(XO("Scale"),1);
182 {
183 S.StartMultiColumn(2,wxEXPAND);
184 {
185 S.SetStretchyCol( 0 );
186 S.SetStretchyCol( 1 );
187 S.Id(ID_SCALE).TieChoice(XXO("S&cale:"),
190 mMinFreq =
191 S.Id(ID_MINIMUM).TieNumericTextBox(XXO("Mi&n Frequency (Hz):"),
193 12);
194 mMaxFreq =
195 S.Id(ID_MAXIMUM).TieNumericTextBox(XXO("Ma&x Frequency (Hz):"),
197 12);
198 }
199 S.EndMultiColumn();
200 }
201 S.EndStatic();
202
203 S.StartStatic(XO("Colors"),1);
204 {
205 S.StartMultiColumn(2,wxEXPAND);
206 {
207 S.SetStretchyCol( 0 );
208 S.SetStretchyCol( 1 );
209 mGain =
210 S.Id(ID_GAIN).TieNumericTextBox(XXO("&Gain (dB):"),
212 8);
213 mRange =
214 S.Id(ID_RANGE).TieNumericTextBox(XXO("&Range (dB):"),
216 8);
217
219 S.Id(ID_FREQUENCY_GAIN).TieNumericTextBox(XXO("High &boost (dB/dec):"),
221 8);
222
223 // i18n-hint Scheme refers to a color scheme for spectrogram colors
224 S.Id(ID_COLOR_SCHEME).TieChoice(XC("Sche&me", "spectrum prefs"),
227 }
228 S.EndMultiColumn();
229 }
230 S.EndStatic();
231 }
232 S.EndMultiColumn();
233
234 S.StartStatic(XO("Algorithm"));
235 {
236 S.StartMultiColumn(2);
237 {
239 S.Id(ID_ALGORITHM).TieChoice(XXO("A&lgorithm:"),
242
243 S.Id(ID_WINDOW_SIZE).TieChoice(XXO("Window &size:"),
245 {
246 XO("8 - most wideband"),
247 XO("16"),
248 XO("32"),
249 XO("64"),
250 XO("128"),
251 XO("256"),
252 XO("512"),
253 XO("1024 - default"),
254 XO("2048"),
255 XO("4096"),
256 XO("8192"),
257 XO("16384"),
258 XO("32768 - most narrowband"),
259 }
260 );
261
262 S.Id(ID_WINDOW_TYPE).TieChoice(XXO("Window &type:"),
265
267 S.Id(ID_PADDING_SIZE).TieChoice(XXO("&Zero padding factor:"),
270 }
271 S.EndMultiColumn();
272 }
273 S.EndStatic();
274
275#ifndef SPECTRAL_SELECTION_GLOBAL_SWITCH
276 S.Id(ID_SPECTRAL_SELECTION).TieCheckBox(XXO("Ena&ble Spectral Selection"),
278#endif
279
280#ifdef EXPERIMENTAL_FFT_Y_GRID
281 S.TieCheckBox(XO("Show a grid along the &Y-axis"),
282 mTempSettings.fftYGrid);
283#endif //EXPERIMENTAL_FFT_Y_GRID
284
285#ifdef EXPERIMENTAL_FIND_NOTES
286 /* i18n-hint: FFT stands for Fast Fourier Transform and probably shouldn't be translated*/
287 S.StartStatic(XO("FFT Find Notes"));
288 {
289 S.StartTwoColumn();
290 {
291 mFindNotesMinA =
292 S.TieNumericTextBox(XXO("Minimum Amplitude (dB):"),
293 mTempSettings.findNotesMinA,
294 8);
295
296 mFindNotesN =
297 S.TieNumericTextBox(XXO("Max. Number of Notes (1..128):"),
298 mTempSettings.numberOfMaxima,
299 8);
300 }
301 S.EndTwoColumn();
302
303 S.TieCheckBox(XXO("&Find Notes"),
304 mTempSettings.fftFindNotes);
305
306 S.TieCheckBox(XXO("&Quantize Notes"),
307 mTempSettings.findNotesQuantize);
308 }
309 S.EndStatic();
310#endif //EXPERIMENTAL_FIND_NOTES
311 // S.EndStatic();
312
313#ifdef SPECTRAL_SELECTION_GLOBAL_SWITCH
314 S.StartStatic(XO("Global settings"));
315 {
316 S.TieCheckBox(XXO("Ena&ble spectral selection"),
317 SpectrogramSettings::Globals::Get().spectralSelection);
318 }
319 S.EndStatic();
320#endif
321
322 } S.EndScroller();
323
324 // Enabling and disabling belongs outside this function.
325 if( S.GetMode() != eIsGettingMetadata )
327
328 mPopulating = false;
329}
330
332{
333 // Do checking for whole numbers
334
335 // ToDo: use wxIntegerValidator<unsigned> when available
336
337 long maxFreq;
338 if (!mMaxFreq->GetValue().ToLong(&maxFreq)) {
339 AudacityMessageBox( XO("The maximum frequency must be an integer") );
340 return false;
341 }
342
343 long minFreq;
344 if (!mMinFreq->GetValue().ToLong(&minFreq)) {
345 AudacityMessageBox( XO("The minimum frequency must be an integer") );
346 return false;
347 }
348
349 long gain;
350 if (!mGain->GetValue().ToLong(&gain)) {
351 AudacityMessageBox( XO("The gain must be an integer") );
352 return false;
353 }
354
355 long range;
356 if (!mRange->GetValue().ToLong(&range)) {
357 AudacityMessageBox( XO("The range must be a positive integer") );
358 return false;
359 }
360
361 long frequencygain;
362 if (!mFrequencyGain->GetValue().ToLong(&frequencygain)) {
363 AudacityMessageBox( XO("The frequency gain must be an integer") );
364 return false;
365 }
366
367#ifdef EXPERIMENTAL_FIND_NOTES
368 long findNotesMinA;
369 if (!mFindNotesMinA->GetValue().ToLong(&findNotesMinA)) {
370 AudacityMessageBox( XO("The minimum amplitude (dB) must be an integer") );
371 return false;
372 }
373
374 long findNotesN;
375 if (!mFindNotesN->GetValue().ToLong(&findNotesN)) {
376 AudacityMessageBox( XO("The maximum number of notes must be an integer") );
377 return false;
378 }
379 if (findNotesN < 1 || findNotesN > 128) {
381"The maximum number of notes must be in the range 1..128") );
382 return false;
383 }
384#endif //EXPERIMENTAL_FIND_NOTES
385
388
389 // Delegate range checking to SpectrogramSettings class
391 const bool result = mTempSettings.Validate(false);
393 return result;
394}
395
397{
398 if (mWt) {
399 auto channels = TrackList::Channels(mWt);
400
401 for (auto channel : channels) {
402 if (mOrigDefaulted) {
403 channel->SetSpectrogramSettings({});
404 channel->SetSpectrumBounds(-1, -1);
405 }
406 else {
407 auto &settings =
408 channel->GetIndependentSpectrogramSettings();
409 channel->SetSpectrumBounds(mOrigMin, mOrigMax);
411 }
412 }
413 }
414
415 if (!mWt || mOrigDefaulted) {
417 *pSettings = mOrigSettings;
418 }
419
420 const bool isOpenPage = this->IsShown();
421 if (mWt && isOpenPage) {
422 auto channels = TrackList::Channels(mWt);
423 for (auto channel : channels)
425 }
426
427 if (isOpenPage) {
428 if ( mProject ) {
429 auto &tp = TrackPanel::Get ( *mProject );
430 tp.UpdateVRulers();
431 tp.Refresh(false);
432 }
433 }
434}
435
437{
438 if (!Validate())
439 return;
440
441 const bool isOpenPage = this->IsShown();
442
445
446
448
449 if (mWt) {
450 for (auto channel : TrackList::Channels(mWt)) {
451 if (mDefaulted) {
452 channel->SetSpectrogramSettings({});
453 // ... and so that the vertical scale also defaults:
454 channel->SetSpectrumBounds(-1, -1);
455 }
456 else {
458 channel->GetIndependentSpectrogramSettings();
459 channel->SetSpectrumBounds(mTempSettings.minFreq, mTempSettings.maxFreq);
461 }
462 }
463 }
464
465 if (!mWt || mDefaulted) {
467 *pSettings = mTempSettings;
468 }
470
471 // Bug 2278
472 // This code destroys any Multi-view we had.
473 // Commenting it out as it seems not to be needed.
474 /*
475 if (mWt && isOpenPage) {
476 for (auto channel : TrackList::Channels(mWt))
477 WaveTrackView::Get( *channel )
478 .SetDisplay( WaveTrackViewConstants::Spectrum );
479 }
480 */
481
482 if (isOpenPage) {
483 if ( mProject ) {
484 auto &tp = TrackPanel::Get( *mProject );
485 tp.UpdateVRulers();
486 tp.Refresh(false);
487 }
488 }
489}
490
492{
493 if (!Validate())
494 return false;
495
496 mCommitted = true;
499 if (!mWt || mDefaulted) {
500 pSettings->SavePrefs();
501 }
502 pSettings->LoadPrefs(); // always; in case Globals changed
503
504 return true;
505}
506
508{
509 return mProject != nullptr;
510}
511
512void SpectrumPrefs::OnControl(wxCommandEvent&)
513{
514 // Common routine for most controls
515 // If any per-track setting is changed, break the association with defaults
516 // Skip this, and View Settings... will be able to change defaults instead
517 // when the checkbox is on, as in the original design.
518
520 mDefaulted = false;
521 mDefaultsCheckbox->SetValue(false);
522 }
523}
524
525void SpectrumPrefs::OnWindowSize(wxCommandEvent &evt)
526{
527 // Restrict choice of zero padding, so that product of window
528 // size and padding may not exceed the largest window size.
529 wxChoice *const pWindowSizeControl =
530 static_cast<wxChoice*>(wxWindow::FindWindowById(ID_WINDOW_SIZE, this));
531 size_t windowSize = 1 <<
532 (pWindowSizeControl->GetSelection() + SpectrogramSettings::LogMinWindowSize);
533 PopulatePaddingChoices(windowSize);
534
535 // Do the common part
536 OnControl(evt);
537}
538
539void SpectrumPrefs::OnDefaults(wxCommandEvent &)
540{
541 if (mDefaultsCheckbox->IsChecked()) {
544 mDefaulted = true;
547 }
548}
549
550void SpectrumPrefs::OnAlgorithm(wxCommandEvent &evt)
551{
553 OnControl(evt);
554}
555
557{
558 // Enable or disable other controls that are applicable only to STFT.
559 const bool STFT =
561 mGain->Enable(STFT);
562 mRange->Enable(STFT);
563 mFrequencyGain->Enable(STFT);
564 mZeroPaddingChoiceCtrl->Enable(STFT);
565}
566
567BEGIN_EVENT_TABLE(SpectrumPrefs, PrefsPanel)
571
572 // Several controls with common routine that unchecks the default box
583
585
586PrefsPanel::Factory
588{
589 return [=](wxWindow *parent, wxWindowID winid, AudacityProject *pProject)
590 {
591 wxASSERT(parent); // to justify safenew
592 return safenew SpectrumPrefs(parent, winid, pProject, wt);
593 };
594}
595
596namespace{
598 SpectrumPrefsFactory( nullptr ),
599 false,
600 // Place it at a lower tree level
601 { "Tracks" }
602};
603}
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:329
const TranslatableString WindowFuncName(int whichFunction)
Definition: FFT.cpp:334
#define XXO(s)
Definition: Internat.h:44
#define XO(s)
Definition: Internat.h:31
#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:41
@ eIsCreatingFromPrefs
Definition: ShuttleGui.h:48
@ eIsSavingToPrefs
Definition: ShuttleGui.h:49
@ eIsGettingMetadata
Definition: ShuttleGui.h:42
PrefsPanel::Factory SpectrumPrefsFactory(WaveTrack *wt)
@ 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:87
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:89
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:628
Spectrogram settings, either for one track or as defaults.
static SpectrogramSettings & defaults()
static const TranslatableStrings & GetAlgorithmNames()
static const EnumValueSymbols & GetScaleNames()
static const EnumValueSymbols & GetColorSchemeNames()
A PrefsPanel for spectrum settings.
Definition: SpectrumPrefs.h:42
std::vector< WaveTrackSubViewPlacement > mOrigPlacements
ComponentInterfaceSymbol GetSymbol() const override
AudacityProject * mProject
Definition: SpectrumPrefs.h:70
TranslatableStrings mZeroPaddingChoices
Definition: SpectrumPrefs.h:86
void Populate(size_t windowSize)
void Preview() override
WaveTrack *const mWt
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)
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
SpectrumPrefs(wxWindow *parent, wxWindowID winid, AudacityProject *pProject, WaveTrack *wt)
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
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 auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1541
static TrackPanel & Get(AudacityProject &project)
Definition: TrackPanel.cpp:230
Holds a msgid for the translation catalog; may also bind format arguments.
A Track that contains audio waveform data.
Definition: WaveTrack.h:57
const SpectrogramSettings & GetSpectrogramSettings() const
Definition: WaveTrack.cpp:799
void GetSpectrumBounds(float *min, float *max) const
Definition: WaveTrack.cpp:352
void RestorePlacements(const WaveTrackSubViewPlacements &placements)
const WaveTrackSubViewPlacements & SavePlacements() const
static WaveTrackView & Get(WaveTrack &track)
PrefsPanel::Registration sAttachment