diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 066c2702c..32f4fabb9 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -217,7 +217,8 @@ is time to refresh some aspect of the screen. #include "ondemand/ODManager.h" -#include "prefs/SpectrogramSettings.h" +#include "prefs/PrefsDialog.h" +#include "prefs/SpectrumPrefs.h" #include "toolbars/ControlToolBar.h" #include "toolbars/ToolManager.h" @@ -330,6 +331,7 @@ enum { OnSpectralSelID, OnSpectralSelLogID, OnPitchID, + OnViewSettingsID, OnSplitStereoID, OnSplitStereoMonoID, @@ -369,6 +371,7 @@ BEGIN_EVENT_TABLE(TrackPanel, wxWindow) EVT_MENU_RANGE(OnChannelLeftID, OnChannelMonoID, TrackPanel::OnChannelChange) EVT_MENU_RANGE(OnWaveformID, OnPitchID, TrackPanel::OnSetDisplay) + EVT_MENU(OnViewSettingsID, TrackPanel::OnViewSettings) EVT_MENU_RANGE(OnRate8ID, OnRate384ID, TrackPanel::OnRateChange) EVT_MENU_RANGE(On16BitID, OnFloatID, TrackPanel::OnFormatChange) EVT_MENU(OnRateOtherID, TrackPanel::OnRateOther) @@ -731,9 +734,10 @@ void TrackPanel::BuildMenus(void) mWaveTrackMenu->Append(OnSpectralSelID, _("S&pectral Selection")); /* i18n-hint: short form of 'logarithm'*/ mWaveTrackMenu->Append(OnSpectralSelLogID, _("Spectral Selection lo&g(f)")); - mWaveTrackMenu->Append(OnPitchID, _("Pitc&h (EAC)")); + mWaveTrackMenu->Append(OnViewSettingsID, _("View& Settings...")); // PRL: all the other letters already taken for accelerators! mWaveTrackMenu->AppendSeparator(); + mWaveTrackMenu->AppendRadioItem(OnChannelMonoID, _("&Mono")); mWaveTrackMenu->AppendRadioItem(OnChannelLeftID, _("&Left Channel")); mWaveTrackMenu->AppendRadioItem(OnChannelRightID, _("&Right Channel")); @@ -8569,6 +8573,7 @@ void TrackPanel::OnTrackMenu(Track *t) theMenu->Enable(OnSpectralSelID, display != WaveTrack::SpectralSelectionDisplay); theMenu->Enable(OnSpectralSelLogID, display != WaveTrack::SpectralSelectionLogDisplay); theMenu->Enable(OnPitchID, display != WaveTrack::PitchDisplay); + theMenu->Enable(OnViewSettingsID, true); WaveTrack * track = (WaveTrack *)t; SetMenuCheck(*mRateMenu, IdOfRate((int) track->GetRate())); @@ -9030,6 +9035,37 @@ void TrackPanel::OnMergeStereo(wxCommandEvent & WXUNUSED(event)) Refresh(false); } +class ViewSettingsDialog : public PrefsDialog +{ +public: + ViewSettingsDialog(wxWindow *parent, PrefsDialog::Factories &factories) + : PrefsDialog(parent, _("View Settings: "), factories) + { + } + + virtual long GetPreferredPage() + { + // Future: choose Spectrum or Waveform page + return 0; + } + + virtual void SavePreferredPage() + { + } +}; + +void TrackPanel::OnViewSettings(wxCommandEvent &) +{ + WaveTrack *const wt = static_cast(mPopupMenuTarget); + SpectrumPrefsFactory spectrumFactory(wt); + PrefsDialog::Factories factories; + factories.push_back(&spectrumFactory); + ViewSettingsDialog dialog(this, factories); + if (0 != dialog.ShowModal()) + // Redraw + Refresh(false); +} + /// Set the Display mode based on the menu choice in the Track Menu. /// Note that gModes MUST BE IN THE SAME ORDER AS THE MENU CHOICES!! /// const wxChar *gModes[] = { wxT("waveform"), wxT("waveformDB"), diff --git a/src/TrackPanel.h b/src/TrackPanel.h index 02e9eb4aa..c93eaab3c 100644 --- a/src/TrackPanel.h +++ b/src/TrackPanel.h @@ -459,6 +459,7 @@ protected: virtual void MoveTrack(Track* target, int eventId); virtual void OnChangeOctave (wxCommandEvent &event); virtual void OnChannelChange(wxCommandEvent &event); + virtual void OnViewSettings(wxCommandEvent &event); virtual void OnSetDisplay (wxCommandEvent &event); virtual void OnSetTimeTrackRange (wxCommandEvent &event); virtual void OnTimeTrackLin(wxCommandEvent &event); diff --git a/src/prefs/SpectrogramSettings.cpp b/src/prefs/SpectrogramSettings.cpp index ceffd4471..d67f1ed41 100644 --- a/src/prefs/SpectrogramSettings.cpp +++ b/src/prefs/SpectrogramSettings.cpp @@ -15,6 +15,10 @@ Paul Licameli #include "../Audacity.h" #include "SpectrogramSettings.h" + +#include +#include + #include "../FFT.h" #include "../Prefs.h" #include "../RealFFTf.h" @@ -26,7 +30,7 @@ SpectrogramSettings::SpectrogramSettings() : hFFT(0) , window(0) { - UpdatePrefs(); + LoadPrefs(); } SpectrogramSettings::SpectrogramSettings(const SpectrogramSettings &other) @@ -98,49 +102,82 @@ SpectrogramSettings& SpectrogramSettings::defaults() return instance; } -void SpectrogramSettings::UpdatePrefs() +bool SpectrogramSettings::Validate(bool quiet) { - bool destroy = false; + if (!quiet && + maxFreq < 100) { + wxMessageBox(_("Maximum frequency must be 100 Hz or above")); + return false; + } + else + maxFreq = std::max(100, maxFreq); + + if (!quiet && + minFreq < 0) { + wxMessageBox(_("Minimum frequency must be at least 0 Hz")); + return false; + } + else + minFreq = std::max(0, minFreq); + + if (!quiet && + maxFreq <= minFreq) { + wxMessageBox(_("Minimum frequency must be less than maximum frequency")); + return false; + } + else + maxFreq = std::max(1 + minFreq, maxFreq); + + if (!quiet && + range <= 0) { + wxMessageBox(_("The range must be at least 1 dB")); + return false; + } + else + range = std::max(1, range); + + if (!quiet && + frequencyGain < 0) { + wxMessageBox(_("The frequency gain cannot be negative")); + return false; + } + else if (!quiet && + frequencyGain > 60) { + wxMessageBox(_("The frequency gain must be no more than 60 dB/dec")); + return false; + } + else + frequencyGain = + std::max(0, std::min(60, frequencyGain)); + + // The rest are controlled by drop-down menus so they can't go wrong + // in the Preferences dialog, but we also come here after reading fom saved + // preference files, which could be or from future versions. Validate quietly. + windowType = + std::max(0, std::min(NumWindowFuncs() - 1, windowType)); + ConvertToEnumeratedWindowSizes(); + ConvertToActualWindowSizes(); + + return true; +} + +void SpectrogramSettings::LoadPrefs() +{ + minFreq = gPrefs->Read(wxT("/Spectrum/MinFreq"), 0L); - minFreq = gPrefs->Read(wxT("/Spectrum/MinFreq"), -1L); maxFreq = gPrefs->Read(wxT("/Spectrum/MaxFreq"), 8000L); - // These preferences are not written anywhere in the program as of now, - // but I keep this legacy here. Who knows, someone might edit prefs files - // directly. PRL - logMaxFreq = gPrefs->Read(wxT("/SpectrumLog/MaxFreq"), -1); - if (logMaxFreq < 0) - logMaxFreq = maxFreq; - logMinFreq = gPrefs->Read(wxT("/SpectrumLog/MinFreq"), -1); - if (logMinFreq < 0) - logMinFreq = minFreq; - if (logMinFreq < 1) - logMinFreq = 1; - range = gPrefs->Read(wxT("/Spectrum/Range"), 80L); gain = gPrefs->Read(wxT("/Spectrum/Gain"), 20L); frequencyGain = gPrefs->Read(wxT("/Spectrum/FrequencyGain"), 0L); - const int newWindowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256); - if (newWindowSize != windowSize) { - destroy = true; - windowSize = newWindowSize; - } + windowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256); #ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS - const int newZeroPaddingFactor = gPrefs->Read(wxT("/Spectrum/ZeroPaddingFactor"), 1); - if (newZeroPaddingFactor != zeroPaddingFactor) { - destroy = true; - zeroPaddingFactor = newZeroPaddingFactor; - } + zeroPaddingFactor = gPrefs->Read(wxT("/Spectrum/ZeroPaddingFactor"), 1); #endif - int newWindowType; - gPrefs->Read(wxT("/Spectrum/WindowType"), &newWindowType, 3); - if (newWindowType != windowType) { - destroy = true; - windowType = newWindowType; - } + gPrefs->Read(wxT("/Spectrum/WindowType"), &windowType, eWinFuncHanning); isGrayscale = (gPrefs->Read(wxT("/Spectrum/Grayscale"), 0L) != 0); @@ -155,8 +192,64 @@ void SpectrogramSettings::UpdatePrefs() findNotesQuantize = (gPrefs->Read(wxT("/Spectrum/FindNotesQuantize"), 0L) != 0); #endif //EXPERIMENTAL_FIND_NOTES - if (destroy) - DestroyWindows(); + // Enforce legal values + Validate(true); + + // These preferences are not written anywhere in the program as of now, + // but I keep this legacy here. Who knows, someone might edit prefs files + // directly. PRL + logMinFreq = gPrefs->Read(wxT("/SpectrumLog/MinFreq"), -1); + if (logMinFreq < 0) + logMinFreq = minFreq; + if (logMinFreq < 1) + logMinFreq = 1; + logMaxFreq = gPrefs->Read(wxT("/SpectrumLog/MaxFreq"), -1); + if (logMaxFreq < 0) + logMaxFreq = maxFreq; + logMaxFreq = + std::max(logMinFreq + 1, logMaxFreq); + + InvalidateCaches(); +} + +void SpectrogramSettings::SavePrefs() +{ + gPrefs->Write(wxT("/Spectrum/MinFreq"), minFreq); + gPrefs->Write(wxT("/Spectrum/MaxFreq"), maxFreq); + + // Nothing wrote these. They only varied from the linear scale bounds in-session. -- PRL + // gPrefs->Write(wxT("/SpectrumLog/MaxFreq"), logMinFreq); + // gPrefs->Write(wxT("/SpectrumLog/MinFreq"), logMaxFreq); + + gPrefs->Write(wxT("/Spectrum/Range"), range); + gPrefs->Write(wxT("/Spectrum/Gain"), gain); + gPrefs->Write(wxT("/Spectrum/FrequencyGain"), frequencyGain); + + gPrefs->Write(wxT("/Spectrum/FFTSize"), windowSize); + +#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS + gPrefs->Write(wxT("/Spectrum/ZeroPaddingFactor"), zeroPaddingFactor); +#endif + + gPrefs->Write(wxT("/Spectrum/WindowType"), windowType); + + gPrefs->Write(wxT("/Spectrum/Grayscale"), isGrayscale); + +#ifdef EXPERIMENTAL_FFT_Y_GRID + gPrefs->Write(wxT("/Spectrum/FFTYGrid"), fftYGrid); +#endif //EXPERIMENTAL_FFT_Y_GRID + +#ifdef EXPERIMENTAL_FIND_NOTES + gPrefs->Write(wxT("/Spectrum/FFTFindNotes"), fftFindNotes); + gPrefs->Write(wxT("/Spectrum/FindNotesMinA"), findNotesMinA); + gPrefs->Write(wxT("/Spectrum/FindNotesN"), numberOfMaxima); + gPrefs->Write(wxT("/Spectrum/FindNotesQuantize"), findNotesQuantize); +#endif //EXPERIMENTAL_FIND_NOTES +} + +void SpectrogramSettings::InvalidateCaches() +{ + DestroyWindows(); } SpectrogramSettings::~SpectrogramSettings() @@ -257,6 +350,38 @@ void SpectrogramSettings::CacheWindows() const #endif // EXPERIMENTAL_USE_REALFFTF } +void SpectrogramSettings::ConvertToEnumeratedWindowSizes() +{ + unsigned size; + int logarithm; + + logarithm = -LogMinWindowSize; + size = unsigned(windowSize); + while (size > 1) + size >>= 1, ++logarithm; + windowSize = std::max(0, std::min(NumWindowSizes - 1, logarithm)); + +#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS + // Choices for zero padding begin at 1 + logarithm = 0; + size = unsigned(zeroPaddingFactor); + while (zeroPaddingFactor > 1) + zeroPaddingFactor >>= 1, ++logarithm; + zeroPaddingFactor = std::max(0, + std::min(LogMaxWindowSize - (windowSize + LogMinWindowSize), + logarithm + )); +#endif +} + +void SpectrogramSettings::ConvertToActualWindowSizes() +{ + windowSize = 1 << (windowSize + LogMinWindowSize); +#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS + zeroPaddingFactor = 1 << zeroPaddingFactor; +#endif +} + int SpectrogramSettings::GetMinFreq(double rate) const { const int top = lrint(rate / 2.); diff --git a/src/prefs/SpectrogramSettings.h b/src/prefs/SpectrogramSettings.h index 3d13aa528..f67e47b70 100644 --- a/src/prefs/SpectrogramSettings.h +++ b/src/prefs/SpectrogramSettings.h @@ -14,19 +14,39 @@ Paul Licameli #include "../Experimental.h" struct FFTParam; +class SpectrumPrefs; class SpectrogramSettings { + friend class SpectrumPrefs; public: + + enum { + LogMinWindowSize = 3, + LogMaxWindowSize = 15, + + NumWindowSizes = LogMaxWindowSize - LogMinWindowSize + 1, + }; + static SpectrogramSettings &defaults(); SpectrogramSettings(); SpectrogramSettings(const SpectrogramSettings &other); SpectrogramSettings& operator= (const SpectrogramSettings &other); ~SpectrogramSettings(); - void UpdatePrefs(); + bool IsDefault() const + { + return this == &defaults(); + } + + bool Validate(bool quiet); + void LoadPrefs(); + void SavePrefs(); + void InvalidateCaches(); void DestroyWindows(); void CacheWindows() const; + void ConvertToEnumeratedWindowSizes(); + void ConvertToActualWindowSizes(); private: int minFreq; @@ -78,4 +98,5 @@ public: mutable float *window; #endif }; + #endif diff --git a/src/prefs/SpectrumPrefs.cpp b/src/prefs/SpectrumPrefs.cpp index 766a43747..c63847909 100644 --- a/src/prefs/SpectrumPrefs.cpp +++ b/src/prefs/SpectrumPrefs.cpp @@ -20,18 +20,33 @@ #include #include #include +#include -#include "../Prefs.h" +#include "../FFT.h" #include "../Project.h" #include "../ShuttleGui.h" -#include "../FFT.h" +#include "../WaveTrack.h" +#include "../TrackPanel.h" #include -SpectrumPrefs::SpectrumPrefs(wxWindow * parent) +SpectrumPrefs::SpectrumPrefs(wxWindow * parent, WaveTrack *wt) : PrefsPanel(parent, _("Spectrograms")) +, mWt(wt) +, mPopulating(false) { - int windowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256); + if (mWt) { + SpectrogramSettings &settings = wt->GetSpectrogramSettings(); + mDefaulted = (&SpectrogramSettings::defaults() == &settings); + mTempSettings = settings; + } + else { + mTempSettings = SpectrogramSettings::defaults(); + mDefaulted = false; + } + + const int windowSize = mTempSettings.windowSize; + mTempSettings.ConvertToEnumeratedWindowSizes(); Populate(windowSize); } @@ -39,13 +54,20 @@ SpectrumPrefs::~SpectrumPrefs() { } -enum { maxWindowSize = 32768 }; - enum { ID_WINDOW_SIZE = 10001, #ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS - ID_PADDING_SIZE = 10002, + ID_WINDOW_TYPE, + ID_PADDING_SIZE, + ID_MINIMUM, + ID_MAXIMUM, + ID_GAIN, + ID_RANGE, + ID_FREQUENCY_GAIN, + ID_GRAYSCALE, #endif + ID_DEFAULTS, + ID_APPLY, }; void SpectrumPrefs::Populate(int windowSize) @@ -63,26 +85,18 @@ void SpectrumPrefs::Populate(int windowSize) mSizeChoices.Add(wxT("8192")); mSizeChoices.Add(wxT("16384")); mSizeChoices.Add(_("32768 - most narrowband")); - - int lastCode = 0; - for (size_t i = 0; i < mSizeChoices.GetCount(); i++) { - mSizeCodes.Add(lastCode = 1 << (i + 3)); - } - wxASSERT(lastCode == maxWindowSize); + wxASSERT(mSizeChoices.size() == SpectrogramSettings::NumWindowSizes); PopulatePaddingChoices(windowSize); for (int i = 0; i < NumWindowFuncs(); i++) { mTypeChoices.Add(WindowFuncName(i)); - mTypeCodes.Add(i); } //------------------------- Main section -------------------- // Now construct the GUI itself. - // Use 'eIsCreatingFromPrefs' so that the GUI is - // initialised with values from gPrefs. - ShuttleGui S(this, eIsCreatingFromPrefs); + ShuttleGui S(this, eIsCreating); PopulateOrExchange(S); // ----------------------- End of main section -------------- } @@ -107,14 +121,12 @@ void SpectrumPrefs::PopulatePaddingChoices(int windowSize) pPaddingSizeControl->Clear(); } - mZeroPaddingCodes.Clear(); - int padding = 1; int numChoices = 0; + const int maxWindowSize = 1 << (SpectrogramSettings::LogMaxWindowSize); while (windowSize <= maxWindowSize) { const wxString numeral = wxString::Format(wxT("%d"), padding); mZeroPaddingChoices.Add(numeral); - mZeroPaddingCodes.Add(padding); if (pPaddingSizeControl) pPaddingSizeControl->Append(numeral); windowSize <<= 1; @@ -131,174 +143,156 @@ void SpectrumPrefs::PopulatePaddingChoices(int windowSize) void SpectrumPrefs::PopulateOrExchange(ShuttleGui & S) { + mPopulating = true; + S.SetBorder(2); - S.StartStatic(_("FFT Window")); + // S.StartStatic(_("Track Settings")); { - S.StartMultiColumn(2); + mDefaultsCheckbox = 0; + if (mWt) { + mDefaultsCheckbox = S.Id(ID_DEFAULTS).TieCheckBox(_("Defaults"), mDefaulted); + } + S.StartStatic(_("FFT Window")); { - S.Id(ID_WINDOW_SIZE).TieChoice(_("Window &size:"), - wxT("/Spectrum/FFTSize"), - 256, - mSizeChoices, - mSizeCodes); - S.SetSizeHints(mSizeChoices); + S.StartMultiColumn(2); + { + S.Id(ID_WINDOW_SIZE).TieChoice(_("Window &size:"), + mTempSettings.windowSize, + &mSizeChoices); + S.SetSizeHints(mSizeChoices); - S.TieChoice(_("Window &type:"), - wxT("/Spectrum/WindowType"), - 3, - mTypeChoices, - mTypeCodes); - S.SetSizeHints(mTypeChoices); + S.Id(ID_WINDOW_TYPE).TieChoice(_("Window &type:"), + mTempSettings.windowType, + &mTypeChoices); + S.SetSizeHints(mTypeChoices); #ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS - S.Id(ID_PADDING_SIZE).TieChoice(_("&Zero padding factor") + wxString(wxT(":")), - wxT("/Spectrum/ZeroPaddingFactor"), - mZeroPaddingChoice, - mZeroPaddingChoices, - mZeroPaddingCodes); - S.SetSizeHints(mZeroPaddingChoices); + S.Id(ID_PADDING_SIZE).TieChoice(_("&Zero padding factor") + wxString(wxT(":")), + mTempSettings.zeroPaddingFactor, + &mZeroPaddingChoices); + S.SetSizeHints(mZeroPaddingChoices); #endif + } + S.EndMultiColumn(); } - S.EndMultiColumn(); - } - S.EndStatic(); + S.EndStatic(); - S.StartStatic(_("Display")); - { - S.StartTwoColumn(); + S.StartStatic(_("Display")); { - mMinFreq = - S.TieNumericTextBox(_("Mi&nimum Frequency (Hz):"), - wxT("/Spectrum/MinFreq"), - 0, - 12); + S.StartTwoColumn(); + { + mMinFreq = + S.Id(ID_MINIMUM).TieNumericTextBox(_("Mi&nimum Frequency (Hz):"), + mTempSettings.minFreq, + 12); - mMaxFreq = - S.TieNumericTextBox(_("Ma&ximum Frequency (Hz):"), - wxT("/Spectrum/MaxFreq"), - 8000, - 12); + mMaxFreq = + S.Id(ID_MAXIMUM).TieNumericTextBox(_("Ma&ximum Frequency (Hz):"), + mTempSettings.maxFreq, + 12); - mGain = - S.TieNumericTextBox(_("&Gain (dB):"), - wxT("/Spectrum/Gain"), - 20, - 8); + mGain = + S.Id(ID_GAIN).TieNumericTextBox(_("&Gain (dB):"), + mTempSettings.gain, + 8); - mRange = - S.TieNumericTextBox(_("&Range (dB):"), - wxT("/Spectrum/Range"), - 80, - 8); + mRange = + S.Id(ID_RANGE).TieNumericTextBox(_("&Range (dB):"), + mTempSettings.range, + 8); - mFrequencyGain = - S.TieNumericTextBox(_("Frequency g&ain (dB/dec):"), - wxT("/Spectrum/FrequencyGain"), - 0, - 4); - } - S.EndTwoColumn(); + mFrequencyGain = + S.Id(ID_FREQUENCY_GAIN).TieNumericTextBox(_("Frequency g&ain (dB/dec):"), + mTempSettings.frequencyGain, + 4); + } + S.EndTwoColumn(); - S.TieCheckBox(_("S&how the spectrum using grayscale colors"), - wxT("/Spectrum/Grayscale"), - false); + S.Id(ID_GRAYSCALE).TieCheckBox(_("S&how the spectrum using grayscale colors"), + mTempSettings.isGrayscale); #ifdef EXPERIMENTAL_FFT_Y_GRID - S.TieCheckBox(_("Show a grid along the &Y-axis"), - wxT("/Spectrum/FFTYGrid"), - false); + S.TieCheckBox(_("Show a grid along the &Y-axis"), + mTempSettings.fftYGrid); #endif //EXPERIMENTAL_FFT_Y_GRID - } - S.EndStatic(); + } + S.EndStatic(); #ifdef EXPERIMENTAL_FIND_NOTES - /* i18n-hint: FFT stands for Fast Fourier Transform and probably shouldn't be translated*/ - S.StartStatic(_("FFT Find Notes")); - { - S.StartTwoColumn(); + /* i18n-hint: FFT stands for Fast Fourier Transform and probably shouldn't be translated*/ + S.StartStatic(_("FFT Find Notes")); { - mFindNotesMinA = - S.TieNumericTextBox(_("Minimum Amplitude (dB):"), - wxT("/Spectrum/FindNotesMinA"), - -30L, - 8); + S.StartTwoColumn(); + { + mFindNotesMinA = + S.TieNumericTextBox(_("Minimum Amplitude (dB):"), + mTempSettings.fftFindNotes, + 8); - mFindNotesN = - S.TieNumericTextBox(_("Max. Number of Notes (1..128):"), - wxT("/Spectrum/FindNotesN"), - 5L, - 8); + mFindNotesN = + S.TieNumericTextBox(_("Max. Number of Notes (1..128):"), + mTempSettings.findNotesMinA, + 8); + } + S.EndTwoColumn(); + + S.TieCheckBox(_("&Find Notes"), + mTempSettings.numberOfMaxima); + + S.TieCheckBox(_("&Quantize Notes"), + mTempSettings.findNotesQuantize); } - S.EndTwoColumn(); - - S.TieCheckBox(_("&Find Notes"), - wxT("/Spectrum/FFTFindNotes"), - false); - - S.TieCheckBox(_("&Quantize Notes"), - wxT("/Spectrum/FindNotesQuantize"), - false); - } - S.EndStatic(); + S.EndStatic(); #endif //EXPERIMENTAL_FIND_NOTES + } + // S.EndStatic(); + + S.StartMultiColumn(2, wxALIGN_RIGHT); + { + S.Id(ID_APPLY).AddButton(_("Appl&y")); + } + S.EndMultiColumn(); + + mPopulating = false; } bool SpectrumPrefs::Validate() { + // Do checking for whole numbers + + // ToDo: use wxIntegerValidator when available + long maxFreq; if (!mMaxFreq->GetValue().ToLong(&maxFreq)) { wxMessageBox(_("The maximum frequency must be an integer")); return false; } - if (maxFreq < 100) { - wxMessageBox(_("Maximum frequency must be 100 Hz or above")); - return false; - } long minFreq; if (!mMinFreq->GetValue().ToLong(&minFreq)) { wxMessageBox(_("The minimum frequency must be an integer")); return false; } - if (minFreq < 0) { - wxMessageBox(_("Minimum frequency must be at least 0 Hz")); - return false; - } - - if (maxFreq < minFreq) { - wxMessageBox(_("Minimum frequency must be less than maximum frequency")); - return false; - } long gain; if (!mGain->GetValue().ToLong(&gain)) { wxMessageBox(_("The gain must be an integer")); return false; } + long range; if (!mRange->GetValue().ToLong(&range)) { wxMessageBox(_("The range must be a positive integer")); return false; } - if (range <= 0) { - wxMessageBox(_("The range must be at least 1 dB")); - return false; - } long frequencygain; if (!mFrequencyGain->GetValue().ToLong(&frequencygain)) { wxMessageBox(_("The frequency gain must be an integer")); return false; } - if (frequencygain < 0) { - wxMessageBox(_("The frequency gain cannot be negative")); - return false; - } - if (frequencygain > 60) { - wxMessageBox(_("The frequency gain must be no more than 60 dB/dec")); - return false; - } + #ifdef EXPERIMENTAL_FIND_NOTES long findNotesMinA; if (!mFindNotesMinA->GetValue().ToLong(&findNotesMinA)) { @@ -317,32 +311,132 @@ bool SpectrumPrefs::Validate() } #endif //EXPERIMENTAL_FIND_NOTES - return true; + ShuttleGui S(this, eIsGettingFromDialog); + PopulateOrExchange(S); + + // Delegate range checking to SpectrogramSettings class + mTempSettings.ConvertToActualWindowSizes(); + const bool result = mTempSettings.Validate(false); + mTempSettings.ConvertToEnumeratedWindowSizes(); + return result; } bool SpectrumPrefs::Apply() { - ShuttleGui S(this, eIsSavingToPrefs); + const bool isOpenPage = this->IsShown(); + + WaveTrack *const partner = + mWt ? static_cast(mWt->GetLink()) : 0; + + ShuttleGui S(this, eIsGettingFromDialog); PopulateOrExchange(S); - SpectrogramSettings::defaults().UpdatePrefs(); + mTempSettings.ConvertToActualWindowSizes(); + if (mWt) { + if (mDefaulted) { + mWt->SetSpectrogramSettings(NULL); + if (partner) + partner->SetSpectrogramSettings(NULL); + } + else { + SpectrogramSettings *pSettings = + &mWt->GetIndependentSpectrogramSettings(); + *pSettings = mTempSettings; + if (partner) { + pSettings = &partner->GetIndependentSpectrogramSettings(); + *pSettings = mTempSettings; + } + } + } + + if (!mWt || mDefaulted) { + SpectrogramSettings *const pSettings = &SpectrogramSettings::defaults(); + *pSettings = mTempSettings; + pSettings->SavePrefs(); + } + mTempSettings.ConvertToEnumeratedWindowSizes(); + + if (mWt && isOpenPage) { + // Future: open page will determine the track view type + /* + mWt->SetDisplay(WaveTrack::Spectrum); + if (partner) + partner->SetDisplay(WaveTrack::Spectrum); + */ + } return true; } -void SpectrumPrefs::OnWindowSize(wxCommandEvent &) +void SpectrumPrefs::OnControl(wxCommandEvent&) { + // Common routine for most controls + // If any per-track setting is changed, break the association with defaults + // Skip this, and View Settings... will be able to change defaults instead + // when the checkbox is on, as in the original design. + + if (mDefaultsCheckbox && !mPopulating) { + mDefaulted = false; + mDefaultsCheckbox->SetValue(false); + } +} + +void SpectrumPrefs::OnWindowSize(wxCommandEvent &evt) +{ + // Restrict choice of zero padding, so that product of window + // size and padding may not exceed the largest window size. wxChoice *const pWindowSizeControl = static_cast(wxWindow::FindWindowById(ID_WINDOW_SIZE, this)); - int windowSize = 1 << (pWindowSizeControl->GetSelection() + 3); + int windowSize = 1 << + (pWindowSizeControl->GetSelection() + SpectrogramSettings::LogMinWindowSize); PopulatePaddingChoices(windowSize); + + // Do the common part + OnControl(evt); +} + +void SpectrumPrefs::OnDefaults(wxCommandEvent &) +{ + if (mDefaultsCheckbox->IsChecked()) { + mTempSettings = SpectrogramSettings::defaults(); + mTempSettings.ConvertToEnumeratedWindowSizes(); + mDefaulted = true; + ShuttleGui S(this, eIsSettingToDialog); + PopulateOrExchange(S); + } +} + +void SpectrumPrefs::OnApply(wxCommandEvent &) +{ + if (Validate()) { + Apply(); + ::GetActiveProject()->GetTrackPanel()->Refresh(false); + } } BEGIN_EVENT_TABLE(SpectrumPrefs, PrefsPanel) EVT_CHOICE(ID_WINDOW_SIZE, SpectrumPrefs::OnWindowSize) + EVT_CHECKBOX(ID_DEFAULTS, SpectrumPrefs::OnDefaults) + + // Several controls with common routine that unchecks the default box + EVT_CHOICE(ID_WINDOW_TYPE, SpectrumPrefs::OnControl) + EVT_CHOICE(ID_PADDING_SIZE, SpectrumPrefs::OnControl) + EVT_TEXT(ID_MINIMUM, SpectrumPrefs::OnControl) + EVT_TEXT(ID_MAXIMUM, SpectrumPrefs::OnControl) + EVT_TEXT(ID_GAIN, SpectrumPrefs::OnControl) + EVT_TEXT(ID_RANGE, SpectrumPrefs::OnControl) + EVT_TEXT(ID_FREQUENCY_GAIN, SpectrumPrefs::OnControl) + EVT_CHECKBOX(ID_GRAYSCALE, SpectrumPrefs::OnControl) + + EVT_BUTTON(ID_APPLY, SpectrumPrefs::OnApply) END_EVENT_TABLE() +SpectrumPrefsFactory::SpectrumPrefsFactory(WaveTrack *wt) +: mWt(wt) +{ +} + PrefsPanel *SpectrumPrefsFactory::Create(wxWindow *parent) { - return new SpectrumPrefs(parent); + return new SpectrumPrefs(parent, mWt); } diff --git a/src/prefs/SpectrumPrefs.h b/src/prefs/SpectrumPrefs.h index 8e316f36a..dc07c7115 100644 --- a/src/prefs/SpectrumPrefs.h +++ b/src/prefs/SpectrumPrefs.h @@ -30,14 +30,18 @@ #include "PrefsPanel.h" #include "SpectrogramSettings.h" +class wxChoice; +class wxCheckBox; class wxTextCtrl; struct FFTParam; class ShuttleGui; +class SpectrogramSettings; +class WaveTrack; class SpectrumPrefs:public PrefsPanel { public: - SpectrumPrefs(wxWindow * parent); + SpectrumPrefs(wxWindow * parent, WaveTrack *wt); virtual ~SpectrumPrefs(); virtual bool Apply(); virtual bool Validate(); @@ -47,9 +51,15 @@ class SpectrumPrefs:public PrefsPanel void PopulatePaddingChoices(int windowSize); void PopulateOrExchange(ShuttleGui & S); + void OnControl(wxCommandEvent &event); void OnWindowSize(wxCommandEvent &event); + void OnDefaults(wxCommandEvent&); + void OnApply(wxCommandEvent &); DECLARE_EVENT_TABLE() + WaveTrack *const mWt; + bool mDefaulted; + wxTextCtrl *mMinFreq; wxTextCtrl *mMaxFreq; wxTextCtrl *mGain; @@ -57,28 +67,35 @@ class SpectrumPrefs:public PrefsPanel wxTextCtrl *mFrequencyGain; wxArrayString mSizeChoices; - wxArrayInt mSizeCodes; #ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS int mZeroPaddingChoice; wxArrayString mZeroPaddingChoices; - wxArrayInt mZeroPaddingCodes; #endif wxArrayString mTypeChoices; - wxArrayInt mTypeCodes; #ifdef EXPERIMENTAL_FIND_NOTES wxTextCtrl *mFindNotesMinA; wxTextCtrl *mFindNotesN; #endif + + wxCheckBox *mDefaultsCheckbox; + + SpectrogramSettings mTempSettings; + + bool mPopulating; }; class SpectrumPrefsFactory : public PrefsPanelFactory { public: + explicit SpectrumPrefsFactory(WaveTrack *wt = 0); virtual PrefsPanel *Create(wxWindow *parent); + +private: + WaveTrack *const mWt; }; #endif