From 4f4acffad1d2dc9752a760eef4543116c75558d5 Mon Sep 17 00:00:00 2001 From: Leland Lucius Date: Sun, 26 Apr 2015 16:41:05 -0500 Subject: [PATCH] Allow chains to use current/factory presets/settings Also gives builtin effects a mean to determine if batch processing is active, IsBatchProcessing() returns true if so. --- include/audacity/ConfigInterface.h | 2 + include/audacity/EffectAutomationParameters.h | 10 + src/BatchCommandDialog.cpp | 42 +- src/BatchCommandDialog.h | 2 + src/BatchCommands.cpp | 41 +- src/BatchCommands.h | 2 + src/Menus.cpp | 3 +- src/Menus.h | 2 + src/PluginManager.cpp | 51 +- src/PluginManager.h | 3 + src/effects/Effect.cpp | 492 ++++++++++++++---- src/effects/Effect.h | 49 +- src/effects/EffectManager.cpp | 79 ++- src/effects/EffectManager.h | 12 +- src/effects/NoiseReduction.cpp | 2 +- src/effects/NoiseReduction.h | 2 +- 16 files changed, 620 insertions(+), 174 deletions(-) diff --git a/include/audacity/ConfigInterface.h b/include/audacity/ConfigInterface.h index 4bd255f9f..f97c90fa3 100644 --- a/include/audacity/ConfigInterface.h +++ b/include/audacity/ConfigInterface.h @@ -49,6 +49,7 @@ class AUDACITY_DLL_API ConfigClientInterface public: virtual ~ConfigClientInterface() {}; + virtual bool HasSharedConfigGroup(const wxString & group) = 0; virtual bool GetSharedConfigSubgroups(const wxString & group, wxArrayString & subgroups) = 0; virtual bool GetSharedConfig(const wxString & group, const wxString & key, wxString & value, const wxString & defval) = 0; @@ -68,6 +69,7 @@ public: virtual bool RemoveSharedConfigSubgroup(const wxString & group) = 0; virtual bool RemoveSharedConfig(const wxString & group, const wxString & key) = 0; + virtual bool HasPrivateConfigGroup(const wxString & group) = 0; virtual bool GetPrivateConfigSubgroups(const wxString & group, wxArrayString & subgroups) = 0; virtual bool GetPrivateConfig(const wxString & group, const wxString & key, wxString & value, const wxString & defval) = 0; diff --git a/include/audacity/EffectAutomationParameters.h b/include/audacity/EffectAutomationParameters.h index 70f200cc3..244a93468 100644 --- a/include/audacity/EffectAutomationParameters.h +++ b/include/audacity/EffectAutomationParameters.h @@ -62,6 +62,16 @@ public: { } + virtual bool HasGroup(const wxString & strName) const + { + return wxFileConfig::HasGroup(NormalizeName(strName)); + } + + virtual bool HasEntry(const wxString& strName) const + { + return wxFileConfig::HasEntry(NormalizeName(strName)); + } + virtual bool DoReadString(const wxString & key, wxString *pStr) const { return wxFileConfig::DoReadString(NormalizeName(key), pStr); diff --git a/src/BatchCommandDialog.cpp b/src/BatchCommandDialog.cpp index f5d355966..7cf7228cc 100644 --- a/src/BatchCommandDialog.cpp +++ b/src/BatchCommandDialog.cpp @@ -45,17 +45,20 @@ selected command. #define CommandsListID 7001 #define EditParamsButtonID 7002 +#define UsePresetButtonID 7003 BEGIN_EVENT_TABLE(BatchCommandDialog, wxDialog) EVT_BUTTON(wxID_OK, BatchCommandDialog::OnOk) EVT_BUTTON(wxID_CANCEL, BatchCommandDialog::OnCancel) EVT_BUTTON(EditParamsButtonID, BatchCommandDialog::OnEditParams) - EVT_LIST_ITEM_ACTIVATED(CommandsListID, BatchCommandDialog::OnItemSelected) + EVT_BUTTON(UsePresetButtonID, BatchCommandDialog::OnUsePreset) + EVT_LIST_ITEM_ACTIVATED(CommandsListID, BatchCommandDialog::OnItemSelected) + EVT_LIST_ITEM_SELECTED(CommandsListID, BatchCommandDialog::OnItemSelected) END_EVENT_TABLE(); BatchCommandDialog::BatchCommandDialog(wxWindow * parent, wxWindowID id): wxDialog(parent, id, _("Select Command"), - wxDefaultPosition, wxSize(250,200), + wxDefaultPosition, wxDefaultSize, wxCAPTION | wxRESIZE_BORDER) { SetLabel(_("Select Command")); // Provide visual label @@ -75,13 +78,15 @@ void BatchCommandDialog::PopulateOrExchange(ShuttleGui &S) { S.StartVerticalLay(true); { - S.StartMultiColumn(3, wxEXPAND); + S.StartMultiColumn(4, wxEXPAND); { S.SetStretchyCol(1); mCommand = S.AddTextBox(_("&Command"), wxT(""), 20); mCommand->SetEditable(false); mEditParams = S.Id(EditParamsButtonID).AddButton(_("&Edit Parameters")); - mEditParams->Enable( false ); // disable button as box is empty + mEditParams->Enable(false); // disable button as box is empty + mUsePreset = S.Id(UsePresetButtonID).AddButton(_("&Use Preset")); + mUsePreset->Enable(false); // disable button as box is empty } S.EndMultiColumn(); @@ -104,14 +109,10 @@ void BatchCommandDialog::PopulateOrExchange(ShuttleGui &S) S.AddStandardButtons(); - for(int i=0;i<99;i++) - { - mChoices->InsertItem( i, wxString::Format(wxT("Item%02i"),i)); - } PopulateCommandList(); - SetSize(350, 400); - SetSizeHints(GetSize()); + SetMinSize(wxSize(500, 400)); + Fit(); Center(); } @@ -169,8 +170,12 @@ void BatchCommandDialog::OnItemSelected(wxListEvent &event) mCommand->SetValue( command ); wxString params = BatchCommands::GetCurrentParamsFor( command ); mParameters->SetValue( params ); - PluginID ID = EffectManager::Get().GetEffectByIdentifier( command ); - mEditParams->Enable( !ID.empty() ); + + EffectManager & em = EffectManager::Get(); + PluginID ID = em.GetEffectByIdentifier( command ); + wxASSERT(!ID.IsEmpty()); + mEditParams->Enable(true); + mUsePreset->Enable(em.HasPresets(ID)); } void BatchCommandDialog::OnEditParams(wxCommandEvent & WXUNUSED(event)) @@ -191,6 +196,19 @@ void BatchCommandDialog::OnEditParams(wxCommandEvent & WXUNUSED(event)) } } +void BatchCommandDialog::OnUsePreset(wxCommandEvent & WXUNUSED(event)) +{ + wxString command = mCommand->GetValue(); + wxString params = mParameters->GetValue(); + + wxString preset = BatchCommands::PromptForPresetFor(command, this); + if (!preset.IsEmpty()) + { + mParameters->SetValue(preset); + mParameters->Refresh(); + } +} + void BatchCommandDialog::SetCommandAndParams(const wxString &Command, const wxString &Params) { mCommand->SetValue( Command ); diff --git a/src/BatchCommandDialog.h b/src/BatchCommandDialog.h index abe7b77ad..6c32d01e3 100644 --- a/src/BatchCommandDialog.h +++ b/src/BatchCommandDialog.h @@ -48,6 +48,7 @@ class BatchCommandDialog:public wxDialog { void Populate(); void PopulateOrExchange(ShuttleGui &S); void OnEditParams(wxCommandEvent &event); + void OnUsePreset(wxCommandEvent &event); void OnChoice(wxCommandEvent &event); void OnOk(wxCommandEvent &event); void OnCancel(wxCommandEvent &event); @@ -58,6 +59,7 @@ class BatchCommandDialog:public wxDialog { int GetSelectedItem(); wxButton *mEditParams; + wxButton *mUsePreset; wxListCtrl *mChoices; wxTextCtrl * mCommand; wxTextCtrl * mParameters; diff --git a/src/BatchCommands.cpp b/src/BatchCommands.cpp index c8b2dc33a..601bf74bb 100644 --- a/src/BatchCommands.cpp +++ b/src/BatchCommands.cpp @@ -331,6 +331,18 @@ bool BatchCommands::PromptForParamsFor(wxString command, wxWindow *parent) return EffectManager::Get().PromptUser(ID, parent); } +wxString BatchCommands::PromptForPresetFor(wxString command, wxWindow *parent) +{ + const PluginID & ID = EffectManager::Get().GetEffectByIdentifier(command); + + if (ID.empty()) + { + return wxEmptyString; // effect not found. + } + + return EffectManager::Get().GetPreset(ID, parent); +} + double BatchCommands::GetEndTime() { AudacityProject *project = GetActiveProject(); @@ -557,23 +569,19 @@ bool BatchCommands::ApplySpecialCommand(int WXUNUSED(iCommand), const wxString & bool BatchCommands::SetCurrentParametersFor(const wxString & command, const wxString & params) { - // transfer the parameters to the effect... - if( !params.IsEmpty() ) + if (params.IsEmpty()) { - const PluginID & ID = EffectManager::Get().GetEffectByIdentifier(command); - if (ID.empty()) - { - return false; - } - if (!EffectManager::Get().SetEffectParameters(ID, params)) - { - wxMessageBox( - wxString::Format( - _("Could not set parameters of effect %s\n to %s."), command.c_str(),params.c_str() )); - return false; - } + return true; } - return true; + + // transfer the parameters to the effect... + const PluginID & ID = EffectManager::Get().GetEffectByIdentifier(command); + if (ID.empty()) + { + return false; + } + + return EffectManager::Get().SetEffectParameters(ID, params); } bool BatchCommands::ApplyEffectCommand(const PluginID & ID, const wxString & command, const wxString & params) @@ -594,7 +602,8 @@ bool BatchCommands::ApplyEffectCommand(const PluginID & ID, const wxString & com // NOW actually apply the effect. return project->OnEffect(ID, AudacityProject::OnEffectFlags::kConfigured | - AudacityProject::OnEffectFlags::kSkipState); + AudacityProject::OnEffectFlags::kSkipState | + AudacityProject::OnEffectFlags::kIsBatch ); } bool BatchCommands::ApplyCommand(const wxString & command, const wxString & params) diff --git a/src/BatchCommands.h b/src/BatchCommands.h index 983480970..033715c0c 100644 --- a/src/BatchCommands.h +++ b/src/BatchCommands.h @@ -43,6 +43,8 @@ class BatchCommands { static bool PromptForParamsFor( wxString command, wxWindow *parent ); static wxString GetCurrentParamsFor( wxString command ); static bool SetCurrentParametersFor(const wxString & command, const wxString & params); + static wxString PromptForPresetFor( wxString command, wxWindow *parent ); + static bool SetCurrentPresetFor(const wxString & command, const wxString & preset); static wxArrayString GetAllCommands(); // These commands do depend on the command list. diff --git a/src/Menus.cpp b/src/Menus.cpp index 6305d6602..f95bfbf28 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -3216,7 +3216,8 @@ bool AudacityProject::OnEffect(const PluginID & ID, int flags) bool success = em.DoEffect(ID, this, mRate, mTracks, mTrackFactory, &mViewInfo.selectedRegion, - !(flags & OnEffectFlags::kConfigured)); + (flags & OnEffectFlags::kConfigured) == 0, + (flags & OnEffectFlags::kIsBatch) != 0); if (!success) { if (newTrack) { diff --git a/src/Menus.h b/src/Menus.h index 20580eae4..9b32c285e 100644 --- a/src/Menus.h +++ b/src/Menus.h @@ -367,6 +367,8 @@ public: static const int kConfigured = 0x01; // Flag used to disable saving the state after processing. static const int kSkipState = 0x02; + // Flag used to designate batch processing is active. + static const int kIsBatch = 0x04; }; bool OnEffect(const PluginID & ID, int flags = OnEffectFlags::kNone); diff --git a/src/PluginManager.cpp b/src/PluginManager.cpp index 546855275..6843a3f1c 100644 --- a/src/PluginManager.cpp +++ b/src/PluginManager.cpp @@ -1236,6 +1236,11 @@ void PluginManager::FindFilesInPathList(const wxString & pattern, return; } +bool PluginManager::HasSharedConfigGroup(const PluginID & ID, const wxString & group) +{ + return HasGroup(SharedGroup(ID, group)); +} + bool PluginManager::GetSharedConfigSubgroups(const PluginID & ID, const wxString & group, wxArrayString & subgroups) { return GetSubgroups(SharedGroup(ID, group), subgroups); @@ -1323,6 +1328,11 @@ bool PluginManager::RemoveSharedConfig(const PluginID & ID, const wxString & gro return result; } +bool PluginManager::HasPrivateConfigGroup(const PluginID & ID, const wxString & group) +{ + return HasGroup(PrivateGroup(ID, group)); +} + bool PluginManager::GetPrivateConfigSubgroups(const PluginID & ID, const wxString & group, wxArrayString & subgroups) { return GetSubgroups(PrivateGroup(ID, group), subgroups); @@ -2277,29 +2287,34 @@ wxFileConfig *PluginManager::GetSettings() return mSettings; } +bool PluginManager::HasGroup(const wxString & group) +{ + return GetSettings()->HasGroup(group); +} + bool PluginManager::GetSubgroups(const wxString & group, wxArrayString & subgroups) { - bool result = false; - - if (!group.IsEmpty()) + if (group.IsEmpty() || !HasGroup(group)) { - wxString name = wxEmptyString; - long index = 0; - wxString path = GetSettings()->GetPath(); - GetSettings()->SetPath(group); - - if (GetSettings()->GetFirstGroup(name, index)) - { - do - { - subgroups.Add(name); - } while (GetSettings()->GetNextGroup(name, index)); - } - - GetSettings()->SetPath(path); + return false; } - return result; + wxString path = GetSettings()->GetPath(); + GetSettings()->SetPath(group); + + wxString name = wxEmptyString; + long index = 0; + if (GetSettings()->GetFirstGroup(name, index)) + { + do + { + subgroups.Add(name); + } while (GetSettings()->GetNextGroup(name, index)); + } + + GetSettings()->SetPath(path); + + return true; } bool PluginManager::GetConfig(const wxString & key, int & value, int defval) diff --git a/src/PluginManager.h b/src/PluginManager.h index 6256fd737..1fac803b7 100644 --- a/src/PluginManager.h +++ b/src/PluginManager.h @@ -189,6 +189,7 @@ public: wxArrayString & files, bool directories = false); + virtual bool HasSharedConfigGroup(const PluginID & ID, const wxString & group); virtual bool GetSharedConfigSubgroups(const PluginID & ID, const wxString & group, wxArrayString & subgroups); virtual bool GetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, wxString & value, const wxString & defval = _T("")); @@ -208,6 +209,7 @@ public: virtual bool RemoveSharedConfigSubgroup(const PluginID & ID, const wxString & group); virtual bool RemoveSharedConfig(const PluginID & ID, const wxString & group, const wxString & key); + virtual bool HasPrivateConfigGroup(const PluginID & ID, const wxString & group); virtual bool GetPrivateConfigSubgroups(const PluginID & ID, const wxString & group, wxArrayString & subgroups); virtual bool GetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, wxString & value, const wxString & defval = _T("")); @@ -280,6 +282,7 @@ private: wxFileConfig *GetSettings(); + bool HasGroup(const wxString & group); bool GetSubgroups(const wxString & group, wxArrayString & subgroups); bool GetConfig(const wxString & key, wxString & value, const wxString & defval = L""); diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp index 1a29cd4db..57d8f4155 100644 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -69,6 +69,11 @@ static const int kUserPresetsID = 31000; static const int kDeletePresetID = 32000; static const int kFactoryPresetsID = 33000; +const wxString Effect::kUserPresetIdent = wxT("User Preset:"); +const wxString Effect::kFactoryPresetIdent = wxT("Factory Preset:"); +const wxString Effect::kCurrentSettingsIdent = wxT(""); +const wxString Effect::kFactoryDefaultsIdent = wxT(""); + WX_DECLARE_VOIDPTR_HASH_MAP( bool, t2bHash ); Effect::Effect() @@ -110,15 +115,26 @@ Effect::Effect() AudacityProject *p = GetActiveProject(); mProjectRate = p ? p->GetRate() : 44100; + + mIsBatch = false; } Effect::~Effect() { - delete mOutputTracks; + if (mOutputTracks) + { + delete mOutputTracks; + } + if (mWarper != NULL) { delete mWarper; } + + if (mUIDialog) + { + mUIDialog->Close(); + } } // EffectIdentInterface implementation @@ -485,11 +501,24 @@ bool Effect::RealtimeProcessEnd() bool Effect::ShowInterface(wxWindow *parent, bool forceModal) { + if (!IsInteractive()) + { + return true; + } + + if (mUIDialog) + { + mUIDialog->Close(true); + return false; + } + if (mClient) { return mClient->ShowInterface(parent, forceModal); } + mParent = parent; + mUIDialog = CreateUI(parent, this); if (!mUIDialog) { @@ -500,9 +529,17 @@ bool Effect::ShowInterface(wxWindow *parent, bool forceModal) mUIDialog->Fit(); mUIDialog->SetMinSize(mUIDialog->GetSize()); - bool res = mUIDialog->ShowModal() != 0; + if (SupportsRealtime() && !forceModal) + { + mUIDialog->Show(); + // Return false to bypass effect processing + return false; + } + + bool res = mUIDialog->ShowModal() != 0; mUIDialog = NULL; + mParent = NULL; return res; } @@ -529,11 +566,6 @@ bool Effect::SetAutomationParameters(EffectAutomationParameters & parms) bool Effect::LoadUserPreset(const wxString & name) { - if (!SupportsAutomation()) - { - return true; - } - if (mClient) { return mClient->LoadUserPreset(name); @@ -550,11 +582,6 @@ bool Effect::LoadUserPreset(const wxString & name) bool Effect::SaveUserPreset(const wxString & name) { - if (!SupportsAutomation()) - { - return true; - } - if (mClient) { return mClient->SaveUserPreset(name); @@ -610,7 +637,7 @@ bool Effect::PopulateUI(wxWindow *parent) mUIParent = parent; mUIParent->PushEventHandler(this); - LoadUserPreset(GetCurrentSettingsGroup()); +// LoadUserPreset(GetCurrentSettingsGroup()); ShuttleGui S(mUIParent, eIsCreating); PopulateOrExchange(S); @@ -782,6 +809,10 @@ wxString Effect::GetFactoryDefaultsGroup() } // ConfigClientInterface implementation +bool Effect::HasSharedConfigGroup(const wxString & group) +{ + return PluginManager::Get().HasSharedConfigGroup(GetID(), group); +} bool Effect::GetSharedConfigSubgroups(const wxString & group, wxArrayString & subgroups) { @@ -858,6 +889,11 @@ bool Effect::RemoveSharedConfig(const wxString & group, const wxString & key) return PluginManager::Get().RemoveSharedConfig(GetID(), group, key); } +bool Effect::HasPrivateConfigGroup(const wxString & group) +{ + return PluginManager::Get().HasPrivateConfigGroup(GetID(), group); +} + bool Effect::GetPrivateConfigSubgroups(const wxString & group, wxArrayString & subgroups) { return PluginManager::Get().GetPrivateConfigSubgroups(GetID(), group, subgroups); @@ -997,17 +1033,45 @@ bool Effect::GetAutomationParameters(wxString & parms) bool Effect::SetAutomationParameters(const wxString & parms) { - EffectAutomationParameters eap(parms); - - if (!SetAutomationParameters(eap)) + wxString preset = parms; + bool success = false; + if (preset.StartsWith(kUserPresetIdent)) + { + preset.Replace(kUserPresetIdent, wxEmptyString, false); + success = LoadUserPreset(GetUserPresetsGroup(preset)); + } + else if (preset.StartsWith(kFactoryPresetIdent)) + { + preset.Replace(kFactoryPresetIdent, wxEmptyString, false); + wxArrayString presets = GetFactoryPresets(); + success = LoadFactoryPreset(presets.Index(preset)); + } + else if (preset.StartsWith(kCurrentSettingsIdent)) + { + preset.Replace(kCurrentSettingsIdent, wxEmptyString, false); + success = LoadUserPreset(GetCurrentSettingsGroup()); + } + else if (preset.StartsWith(kFactoryDefaultsIdent)) + { + preset.Replace(kFactoryDefaultsIdent, wxEmptyString, false); + success = LoadUserPreset(GetFactoryDefaultsGroup()); + } + else + { + EffectAutomationParameters eap(parms); + success = SetAutomationParameters(eap); + } + + if (!success) { wxMessageBox( wxString::Format( - _("Could not set parameters of effect %s\n to %s."), + _("Could not update effect \"%s\" with:\n%s"), GetName().c_str(), - parms.c_str() + preset.c_str() ) ); + return false; } @@ -1019,6 +1083,52 @@ bool Effect::SetAutomationParameters(const wxString & parms) return TransferDataToWindow(); } +wxArrayString Effect::GetUserPresets() +{ + wxArrayString presets; + + GetPrivateConfigSubgroups(GetUserPresetsGroup(wxEmptyString), presets); + + presets.Sort(); + + return presets; +} + +bool Effect::HasCurrentSettings() +{ + return HasPrivateConfigGroup(GetCurrentSettingsGroup()); +} + +bool Effect::HasFactoryDefaults() +{ + return HasPrivateConfigGroup(GetFactoryDefaultsGroup()); +} + +wxString Effect::GetPreset(wxWindow * parent) +{ + EffectPresetsDialog dlg(parent, this); + dlg.Layout(); + dlg.Fit(); + dlg.SetSize(dlg.GetMinSize()); + + if (dlg.ShowModal()) + { + return dlg.GetSelected(); + } + + return wxEmptyString; +} + +bool Effect::IsBatchProcessing() +{ + return mIsBatch; +} + +void Effect::SetBatchProcessing(bool enable) +{ + mIsBatch = enable; +} + bool Effect::DoEffect(wxWindow *parent, double projectRate, TrackList *list, @@ -1062,7 +1172,7 @@ bool Effect::DoEffect(wxWindow *parent, // Prompting will be bypassed when applying an effect that has already // been configured, e.g. repeating the last effect on a different selection. - if (shouldPrompt && !PromptUser(parent)) + if (shouldPrompt && IsInteractive() && !PromptUser(parent)) { return false; } @@ -1101,28 +1211,12 @@ bool Effect::Init() return true; } -bool Effect::PromptUser(wxWindow *parent, bool isBatch) +// Remove this method once NoiseReduction gets migrated +bool Effect::PromptUser(wxWindow *parent) { - if (IsInteractive()) - { - mParent = parent; - - bool res = ShowInterface(parent, isBatch); - - // Really need to clean this up...should get easier when - // all effects get converted. - if (!res || (SupportsRealtime() && isBatch)) - { - // Return false to force DoEffect() to skip processing since - // this UI has either been shown modeless or there was an error. - return false; - } - } - - return true; + return ShowInterface(parent, IsBatchProcessing()); } - int Effect::GetPass() { return mPass; @@ -2676,6 +2770,7 @@ bool EffectUIHost::Initialize() mSupportsRealtime = mEffect->SupportsRealtime(); mIsGUI = mClient->IsGraphicalUI(); + mIsBatch = mEffect->IsBatchProcessing(); wxBitmapButton *bb; @@ -2704,93 +2799,106 @@ bool EffectUIHost::Initialize() bs->Add(5, 5); - if (!mIsGUI) + if (!mIsBatch) { + if (!mIsGUI) + { + if (mSupportsRealtime) + { + mPlayToggleBtn = new wxButton(bar, kPlayID, _("Start &Playback")); + mPlayToggleBtn->SetToolTip(_("Start and stop playback")); + bs->Add(mPlayToggleBtn, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin); + } + else if (mEffect->GetType() != EffectTypeAnalyze) + { + mPlayToggleBtn = new wxButton(bar, kPlayID, _("&Preview")); + mPlayToggleBtn->SetToolTip(_("Preview effect")); + bs->Add(mPlayToggleBtn, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin); + } + } + else + { + mPlayBM = CreateBitmap(effect_play_xpm, true, false); + mPlayDisabledBM = CreateBitmap(effect_play_disabled_xpm, true, false); + mStopBM = CreateBitmap(effect_stop_xpm, true, false); + mStopDisabledBM = CreateBitmap(effect_stop_disabled_xpm, true, false); + bb = new wxBitmapButton(bar, kPlayID, mPlayBM); + bb->SetBitmapDisabled(mPlayDisabledBM); + mPlayBtn = bb; + bs->Add(mPlayBtn); + if (!mSupportsRealtime) + { + mPlayBtn->SetToolTip(_("Preview effect")); +#if defined(__WXMAC__) + mPlayBtn->SetName(_("Preview effect")); +#else + mPlayBtn->SetLabel(_("&Preview effect")); +#endif + } + } + if (mSupportsRealtime) { - mPlayToggleBtn = new wxButton(bar, kPlayID, _("Start &Playback")); - mPlayToggleBtn->SetToolTip(_("Start and stop playback")); - bs->Add(mPlayToggleBtn, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin); - } - else if (mEffect->GetType() != EffectTypeAnalyze) - { - mPlayToggleBtn = new wxButton(bar, kPlayID, _("&Preview")); - mPlayToggleBtn->SetToolTip(_("Preview effect")); - bs->Add(mPlayToggleBtn, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin); - } - } - else - { - mPlayBM = CreateBitmap(effect_play_xpm, true, false); - mPlayDisabledBM = CreateBitmap(effect_play_disabled_xpm, true, false); - mStopBM = CreateBitmap(effect_stop_xpm, true, false); - mStopDisabledBM = CreateBitmap(effect_stop_disabled_xpm, true, false); - bb = new wxBitmapButton(bar, kPlayID, mPlayBM); - bb->SetBitmapDisabled(mPlayDisabledBM); - mPlayBtn = bb; - bs->Add(mPlayBtn); - if (!mSupportsRealtime) - { - mPlayBtn->SetToolTip(_("Preview effect")); + if (!mIsGUI) + { + mRewindBtn = new wxButton(bar, kRewindID, _("Skip &Backward")); + bs->Add(mRewindBtn, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin); + } + else + { + bb = new wxBitmapButton(bar, kRewindID, CreateBitmap(effect_rewind_xpm, true, true)); + bb->SetBitmapDisabled(CreateBitmap(effect_rewind_disabled_xpm, true, true)); + mRewindBtn = bb; #if defined(__WXMAC__) - mPlayBtn->SetName(_("Preview effect")); + mRewindBtn->SetName(_("Skip &Backward")); #else - mPlayBtn->SetLabel(_("&Preview effect")); + mRewindBtn->SetLabel(_("Skip &Backward")); #endif - } - } + bs->Add(mRewindBtn); + } + mRewindBtn->SetToolTip(_("Skip backward")); - if (mSupportsRealtime) - { - if (!mIsGUI) - { - mRewindBtn = new wxButton(bar, kRewindID, _("Skip &Backward")); - bs->Add(mRewindBtn, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin); - } - else - { - bb = new wxBitmapButton(bar, kRewindID, CreateBitmap(effect_rewind_xpm, true, true)); - bb->SetBitmapDisabled(CreateBitmap(effect_rewind_disabled_xpm, true, true)); - mRewindBtn = bb; + if (!mIsGUI) + { + mFFwdBtn = new wxButton(bar, kFFwdID, _("Skip &Forward")); + bs->Add(mFFwdBtn, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin); + } + else + { + bb = new wxBitmapButton(bar, kFFwdID, CreateBitmap(effect_ffwd_xpm, true, true)); + bb->SetBitmapDisabled(CreateBitmap(effect_ffwd_disabled_xpm, true, true)); + mFFwdBtn = bb; #if defined(__WXMAC__) - mRewindBtn->SetName(_("Skip &Backward")); + mFFwdBtn->SetName(_("Skip &Foreward")); #else - mRewindBtn->SetLabel(_("Skip &Backward")); + mFFwdBtn->SetLabel(_("Skip &Foreward")); #endif - bs->Add(mRewindBtn); - } - mRewindBtn->SetToolTip(_("Skip backward")); + bs->Add(mFFwdBtn); + } + mFFwdBtn->SetToolTip(_("Skip forward")); - if (!mIsGUI) - { - mFFwdBtn = new wxButton(bar, kFFwdID, _("Skip &Forward")); - bs->Add(mFFwdBtn, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin); - } - else - { - bb = new wxBitmapButton(bar, kFFwdID, CreateBitmap(effect_ffwd_xpm, true, true)); - bb->SetBitmapDisabled(CreateBitmap(effect_ffwd_disabled_xpm, true, true)); - mFFwdBtn = bb; -#if defined(__WXMAC__) - mFFwdBtn->SetName(_("Skip &Foreward")); -#else - mFFwdBtn->SetLabel(_("Skip &Foreward")); -#endif - bs->Add(mFFwdBtn); - } - mFFwdBtn->SetToolTip(_("Skip forward")); + bs->Add(5, 5); - bs->Add(5, 5); - - mEnableCb = new wxCheckBox(bar, kEnableID, _("&Enable")); - mEnableCb->SetValue(mEnabled); - mEnableCb->SetName(_("Enable")); - bs->Add(mEnableCb, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin); + mEnableCb = new wxCheckBox(bar, kEnableID, _("&Enable")); + mEnableCb->SetValue(mEnabled); + mEnableCb->SetName(_("Enable")); + bs->Add(mEnableCb, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin); + } } bar->SetSizerAndFit(bs); - wxSizer *s = CreateStdButtonSizer(this, eApplyButton | /*eCloseButton | */(mEffect->mUIDebug ? eDebugButton : 0), bar); + long buttons = eApplyButton; + if (!mIsBatch) + { + // buttons += eCloseButton; + if (mEffect->mUIDebug) + { + buttons += eDebugButton; + } + } + + wxSizer *s = CreateStdButtonSizer(this, buttons, bar); vs->Add(s, 0, wxEXPAND | wxALIGN_CENTER_VERTICAL); SetSizer(vs); @@ -2853,7 +2961,7 @@ void EffectUIHost::OnApply(wxCommandEvent & evt) return; } - if (mEffect->GetType() != EffectTypeGenerate && mProject->mViewInfo.selectedRegion.isPoint()) + if (!mIsBatch && mEffect->GetType() != EffectTypeGenerate && mProject->mViewInfo.selectedRegion.isPoint()) { wxMessageBox(_("You must select audio in the project window.")); return; @@ -3305,6 +3413,11 @@ wxBitmap EffectUIHost::CreateBitmap(const char *xpm[], bool up, bool pusher) void EffectUIHost::UpdateControls() { + if (mIsBatch) + { + return; + } + if (mCapturing || mDisableTransport) { // Don't allow focus to get trapped @@ -3425,4 +3538,161 @@ void EffectUIHost::CleanupRealtime() mInitialized = false; } -} \ No newline at end of file +} + +/////////////////////////////////////////////////////////////////////////////// +// +// EffectPresetsDialog +// +/////////////////////////////////////////////////////////////////////////////// + +enum +{ + ID_Type = 10000 +}; + +BEGIN_EVENT_TABLE(EffectPresetsDialog, wxDialog) + EVT_CHOICE(ID_Type, EffectPresetsDialog::OnType) + EVT_LISTBOX_DCLICK(wxID_ANY, EffectPresetsDialog::OnOk) + EVT_BUTTON(wxID_OK, EffectPresetsDialog::OnOk) + EVT_BUTTON(wxID_CANCEL, EffectPresetsDialog::OnCancel) +END_EVENT_TABLE() + +EffectPresetsDialog::EffectPresetsDialog(wxWindow *parent, Effect *effect) +: wxDialog(parent, wxID_ANY, wxString(_("Select Preset"))) +{ + ShuttleGui S(this, eIsCreating); + S.StartVerticalLay(); + { + S.StartTwoColumn(); + S.SetStretchyCol(1); + { + wxArrayString empty; + + S.AddPrompt(_("Type:")); + mType = S.Id(ID_Type).AddChoice(wxT(""), wxT(""), &empty); + mType->SetSelection(0); + + S.AddPrompt(_("&Preset:")); + mPresets = S.AddListBox(&empty, wxLB_SINGLE | wxLB_NEEDED_SB ); + } + S.EndTwoColumn(); + + S.AddStandardButtons(); + } + S.EndVerticalLay(); + + mUserPresets = effect->GetUserPresets(); + mFactoryPresets = effect->GetFactoryPresets(); + + if (mUserPresets.GetCount() > 0) + { + mType->Append(_("User Presets")); + } + + if (mFactoryPresets.GetCount() > 0) + { + mType->Append(_("Factory Presets")); + } + + if (effect->HasCurrentSettings()) + { + mType->Append(_("Current Settings")); + } + + if (effect->HasFactoryDefaults()) + { + mType->Append(_("Factory Defaults")); + } + + UpdateUI(); +} + +EffectPresetsDialog::~EffectPresetsDialog() +{ +} + +void EffectPresetsDialog::UpdateUI() +{ + int selected = mType->GetSelection(); + if (selected == wxNOT_FOUND) + { + selected = 0; + mType->SetSelection(selected); + } + wxString type = mType->GetString(selected); + + if (type.IsSameAs(_("User Presets"))) + { + selected = mPresets->GetSelection(); + if (selected == wxNOT_FOUND) + { + selected = 0; + } + + mPresets->Clear(); + mPresets->Append(mUserPresets); + mPresets->Enable(true); + mPresets->SetSelection(selected); + mSelection = Effect::kUserPresetIdent + mPresets->GetString(selected); + } + else if (type.IsSameAs(_("Factory Presets"))) + { + selected = mPresets->GetSelection(); + if (selected == wxNOT_FOUND) + { + selected = 0; + } + + mPresets->Clear(); + for (size_t i = 0, cnt = mFactoryPresets.GetCount(); i < cnt; i++) + { + wxString label = mFactoryPresets[i]; + if (label.IsEmpty()) + { + label = _("None"); + } + mPresets->Append(label); + } + mPresets->Enable(true); + mPresets->SetSelection(selected); + mSelection = Effect::kFactoryPresetIdent + mPresets->GetString(selected); + } + else if (type.IsSameAs(_("Current Settings"))) + { + mPresets->Clear(); + mPresets->Enable(false); + mSelection = Effect::kCurrentSettingsIdent; + } + else if (type.IsSameAs(_("Factory Defaults"))) + { + mPresets->Clear(); + mPresets->Enable(false); + mSelection = Effect::kFactoryDefaultsIdent; + } +} + +void EffectPresetsDialog::OnType(wxCommandEvent & WXUNUSED(evt)) +{ + UpdateUI(); +} + +void EffectPresetsDialog::OnOk(wxCommandEvent & WXUNUSED(evt)) +{ + UpdateUI(); + + EndModal(true); +} + +void EffectPresetsDialog::OnCancel(wxCommandEvent & WXUNUSED(evt)) +{ + mSelection = wxEmptyString; + + EndModal(false); +} + +wxString EffectPresetsDialog::GetSelected() const +{ + return mSelection; +} + diff --git a/src/effects/Effect.h b/src/effects/Effect.h index 7d735b9f3..6b03c29e0 100644 --- a/src/effects/Effect.h +++ b/src/effects/Effect.h @@ -158,6 +158,7 @@ class AUDACITY_DLL_API Effect : public wxEvtHandler, // ConfigClientInterface implementation + virtual bool HasSharedConfigGroup(const wxString & group); virtual bool GetSharedConfigSubgroups(const wxString & group, wxArrayString & subgroups); virtual bool GetSharedConfig(const wxString & group, const wxString & key, wxString & value, const wxString & defval = wxEmptyString); @@ -177,6 +178,7 @@ class AUDACITY_DLL_API Effect : public wxEvtHandler, virtual bool RemoveSharedConfigSubgroup(const wxString & group); virtual bool RemoveSharedConfig(const wxString & group, const wxString & key); + virtual bool HasPrivateConfigGroup(const wxString & group); virtual bool GetPrivateConfigSubgroups(const wxString & group, wxArrayString & subgroups); virtual bool GetPrivateConfig(const wxString & group, const wxString & key, wxString & value, const wxString & defval = wxEmptyString); @@ -206,6 +208,14 @@ class AUDACITY_DLL_API Effect : public wxEvtHandler, virtual bool GetAutomationParameters(wxString & parms); virtual bool SetAutomationParameters(const wxString & parms); + virtual wxArrayString GetUserPresets(); + virtual bool HasCurrentSettings(); + virtual bool HasFactoryDefaults(); + virtual wxString GetPreset(wxWindow * parent); + + virtual bool IsBatchProcessing(); + virtual void SetBatchProcessing(bool enable); + void SetPresetParameters( const wxArrayString * Names, const wxArrayString * Values ){ if( Names ) mPresetNames = *Names; if( Values ) mPresetValues = *Values; @@ -228,7 +238,7 @@ class AUDACITY_DLL_API Effect : public wxEvtHandler, bool IsRealtimeActive(); virtual bool IsHidden(); - + // // protected virtual methods // @@ -245,7 +255,7 @@ protected: // This method will not always be called (for example if a user // repeats an effect) but if it is called, it will be called // after Init. - virtual bool PromptUser(wxWindow *parent = NULL, bool isBatch = false); + virtual bool PromptUser(wxWindow *parent); // Check whether effect should be skipped // Typically this is only useful in automation, for example @@ -374,6 +384,8 @@ protected: private: wxWindow *mParent; + bool mIsBatch; + double mDuration; bool mUIDebug; @@ -404,9 +416,15 @@ private: wxCriticalSection mRealtimeSuspendLock; int mRealtimeSuspendCount; + const static wxString kUserPresetIdent; + const static wxString kFactoryPresetIdent; + const static wxString kCurrentSettingsIdent; + const static wxString kFactoryDefaultsIdent; + friend class EffectManager;// so it can call PromptUser in support of batch commands. friend class EffectRack; friend class EffectUIHost; + friend class EffectPresetsDialog; }; @@ -507,6 +525,7 @@ private: bool mInitialized; bool mSupportsRealtime; bool mIsGUI; + bool mIsBatch; #if defined(__WXMAC__) bool mIsModal; @@ -540,6 +559,32 @@ private: DECLARE_EVENT_TABLE(); }; +class EffectPresetsDialog : public wxDialog +{ +public: + EffectPresetsDialog(wxWindow *parent, Effect *effect); + virtual ~EffectPresetsDialog(); + + wxString GetSelected() const; + +private: + void UpdateUI(); + + void OnType(wxCommandEvent & evt); + void OnOk(wxCommandEvent & evt); + void OnCancel(wxCommandEvent & evt); + +private: + wxChoice *mType; + wxListBox *mPresets; + + wxArrayString mFactoryPresets; + wxArrayString mUserPresets; + wxString mSelection; + + DECLARE_EVENT_TABLE(); +}; + // Utility functions inline float TrapFloat(float x, float min, float max) diff --git a/src/effects/EffectManager.cpp b/src/effects/EffectManager.cpp index 89386c9ca..958ac6104 100644 --- a/src/effects/EffectManager.cpp +++ b/src/effects/EffectManager.cpp @@ -77,7 +77,8 @@ bool EffectManager::DoEffect(const PluginID & ID, TrackList *list, TrackFactory *factory, SelectedRegion *selectedRegion, - bool shouldPrompt /* = true */) + bool shouldPrompt /* = true */, + bool isBatch /* = false */) { Effect *effect = GetEffect(ID); @@ -94,12 +95,18 @@ bool EffectManager::DoEffect(const PluginID & ID, } #endif - return effect->DoEffect(parent, - projectRate, - list, - factory, - selectedRegion, - shouldPrompt); + effect->SetBatchProcessing(isBatch); + + bool res = effect->DoEffect(parent, + projectRate, + list, + factory, + selectedRegion, + shouldPrompt); + + effect->SetBatchProcessing(false); + + return res; } wxString EffectManager::GetEffectName(const PluginID & ID) @@ -176,12 +183,19 @@ bool EffectManager::SetEffectParameters(const PluginID & ID, const wxString & pa { Effect *effect = GetEffect(ID); - if (effect) + if (!effect) { - return effect->SetAutomationParameters(params); + return false; } - return false; + EffectAutomationParameters eap(params); + + if (eap.HasEntry(wxT("Use Preset"))) + { + return effect->SetAutomationParameters(eap.Read(wxT("Use Preset"))); + } + + return effect->SetAutomationParameters(params); } bool EffectManager::PromptUser(const PluginID & ID, wxWindow *parent) @@ -191,12 +205,54 @@ bool EffectManager::PromptUser(const PluginID & ID, wxWindow *parent) if (effect) { - result = effect->PromptUser(parent, true); + effect->SetBatchProcessing(true); + + result = effect->PromptUser(parent); + + effect->SetBatchProcessing(false); } return result; } +bool EffectManager::HasPresets(const PluginID & ID) +{ + Effect *effect = GetEffect(ID); + + if (!effect) + { + return false; + } + + return effect->GetUserPresets().GetCount() > 0 || + effect->GetFactoryPresets().GetCount() > 0 || + effect->HasCurrentSettings() || + effect->HasFactoryDefaults(); +} + +wxString EffectManager::GetPreset(const PluginID & ID, wxWindow * parent) +{ + Effect *effect = GetEffect(ID); + + if (!effect) + { + return wxEmptyString; + } + + wxString preset = effect->GetPreset(parent); + if (preset.IsEmpty()) + { + return preset; + } + + EffectAutomationParameters eap; + + eap.Write(wxT("Use Preset"), preset); + eap.GetParameters(preset); + + return preset; +} + #if defined(EXPERIMENTAL_EFFECTS_RACK) EffectRack *EffectManager::GetRack() { @@ -633,3 +689,4 @@ const PluginID & EffectManager::GetEffectByIdentifier(const wxString & strTarget return empty;; } + diff --git a/src/effects/EffectManager.h b/src/effects/EffectManager.h index 501af1bb0..a388f69ce 100644 --- a/src/effects/EffectManager.h +++ b/src/effects/EffectManager.h @@ -21,6 +21,12 @@ effects. #ifndef __AUDACITY_EFFECTMANAGER__ #define __AUDACITY_EFFECTMANAGER__ +#include +#include +#include +#include +#include + #include "audacity/EffectInterface.h" #include "../PluginManager.h" #include "Effect.h" @@ -65,7 +71,8 @@ public: TrackList *list, TrackFactory *factory, SelectedRegion *selectedRegion, - bool shouldPrompt = true); + bool shouldPrompt = true, + bool isBatch = false); wxString GetEffectName(const PluginID & ID); wxString GetEffectIdentifier(const PluginID & ID); @@ -76,6 +83,8 @@ public: wxString GetEffectParameters(const PluginID & ID); bool SetEffectParameters(const PluginID & ID, const wxString & params); bool PromptUser(const PluginID & ID, wxWindow *parent); + bool HasPresets(const PluginID & ID); + wxString GetPreset(const PluginID & ID, wxWindow * parent); // Realtime effect processing bool RealtimeIsActive(); @@ -126,6 +135,7 @@ private: friend class EffectRack; #endif + }; diff --git a/src/effects/NoiseReduction.cpp b/src/effects/NoiseReduction.cpp index af6cbfdb2..1436f4208 100644 --- a/src/effects/NoiseReduction.cpp +++ b/src/effects/NoiseReduction.cpp @@ -446,7 +446,7 @@ bool EffectNoiseReduction::CheckWhetherSkipEffect() return false; } -bool EffectNoiseReduction::PromptUser(wxWindow *parent, bool isBatch) +bool EffectNoiseReduction::PromptUser(wxWindow *parent) { // We may want to twiddle the levels if we are setting // from an automation dialog, the only case in which we can diff --git a/src/effects/NoiseReduction.h b/src/effects/NoiseReduction.h index 6a496aa20..7880ecc76 100644 --- a/src/effects/NoiseReduction.h +++ b/src/effects/NoiseReduction.h @@ -40,7 +40,7 @@ public: // using Effect::TrackProgress; - virtual bool PromptUser(wxWindow *parent = NULL, bool isBatch = false); + virtual bool PromptUser(wxWindow *parent); virtual bool Init(); virtual bool CheckWhetherSkipEffect();