diff --git a/include/audacity/EffectInterface.h b/include/audacity/EffectInterface.h index 0d6d30773..7354a9f6c 100644 --- a/include/audacity/EffectInterface.h +++ b/include/audacity/EffectInterface.h @@ -81,9 +81,6 @@ public: // Whether the effect supports realtime previewing (while audio is playing). virtual bool SupportsRealtime() = 0; - // Whether the effect should be shown in menus right from the start. - virtual bool EnableFromGetGo(){ return false;}; - // Can the effect be used without the UI. virtual bool SupportsAutomation() = 0; }; diff --git a/plug-ins/SpectralEditMulti.ny b/plug-ins/SpectralEditMulti.ny index 6ef81d55e..473c32f76 100644 --- a/plug-ins/SpectralEditMulti.ny +++ b/plug-ins/SpectralEditMulti.ny @@ -1,4 +1,4 @@ -;nyquist plugin +;nyquist plug-in ;version 4 ;type process ;name "Spectral edit multi tool" diff --git a/plug-ins/SpectralEditParametricEQ.ny b/plug-ins/SpectralEditParametricEQ.ny index aaa59fad9..6c0f6ef87 100644 --- a/plug-ins/SpectralEditParametricEQ.ny +++ b/plug-ins/SpectralEditParametricEQ.ny @@ -1,4 +1,4 @@ -;nyquist plugin +;nyquist plug-in ;version 4 ;type process ;preview enabled diff --git a/plug-ins/SpectralEditShelves.ny b/plug-ins/SpectralEditShelves.ny index 825b9e144..ff89cc39f 100644 --- a/plug-ins/SpectralEditShelves.ny +++ b/plug-ins/SpectralEditShelves.ny @@ -1,4 +1,4 @@ -;nyquist plugin +;nyquist plug-in ;version 4 ;type process ;preview enabled diff --git a/plug-ins/clicktrack.ny b/plug-ins/clicktrack.ny index 79a6b2420..aea26c3c7 100644 --- a/plug-ins/clicktrack.ny +++ b/plug-ins/clicktrack.ny @@ -1,8 +1,9 @@ ;nyquist plug-in -;version 3 +;version 4 ;type generate ;categories "http://lv2plug.in/ns/lv2core#GeneratorPlugin" ;name "Click Track..." +;preview linear ;action "Generating Click Track..." ;info "For help, select one of two help screens in 'Action choice' below." ;author "Dominic Mazzoni" @@ -13,8 +14,8 @@ ;; http://www.gnu.org/licenses/old-licenses/gpl-2.0.html . ;; original clicktrack.ny by Dominic Mazzoni, ;; modified by David R. Sky and Steve Daulton. -;; Minimum Audacity version: 1.3.4 ;; +;; Updated to v4 by Steve Daulton May 2015 ;; bug fixes and restructured by Steve Daulton Sept 2011. ;; string input verification added by Steve Daulton, 2009. ;; added click pitch [user request] and sound types fields September 2007 (D.R.Sky). @@ -286,6 +287,12 @@ Use whole numbers only.~%")))) (if m-s (setq measures (/ (m-s-to-seconds m-s)(* sig beatlen)))) + ;if previewing, restrict number of measures + (let ((preview (/ (get '*project* 'preview-duration) + (* sig beatlen)))) + (if (not (get '*track* 'view)) ;NIL if preview + (setq measures (min preview measures)))) + ;round up number of measures (setq measures (round-up measures)) diff --git a/plug-ins/crossfadetracks.ny b/plug-ins/crossfadetracks.ny index d21c6da42..bdb627c88 100644 --- a/plug-ins/crossfadetracks.ny +++ b/plug-ins/crossfadetracks.ny @@ -1,4 +1,4 @@ -;nyquist plugin +;nyquist plug-in ;version 4 ;type process ;name "Crossfade Tracks..." diff --git a/plug-ins/pluck.ny b/plug-ins/pluck.ny index 6d3cd691e..eb52daab7 100644 --- a/plug-ins/pluck.ny +++ b/plug-ins/pluck.ny @@ -1,9 +1,9 @@ - ;nyquist plug-in -;version 3 +;version 4 ;type generate ;categories "http://lv2plug.in/ns/lv2core#GeneratorPlugin" ;name "Pluck..." +;preview linear ;action "Generating pluck sound..." ;info "MIDI values for C notes: 36, 48, 60 [middle C], 72, 84, 96." ;author "David R.Sky" @@ -12,7 +12,7 @@ ;; Released under terms of the GNU General Public License version 2: ;; http://www.gnu.org/licenses/old-licenses/gpl-2.0.html . -;control p "Pluck MIDI pitch" int "" 60 1 127 +;control pitch "Pluck MIDI pitch" int "" 60 1 120 ;control fade "Fade-out type" choice "abrupt,gradual" 0 ;control dur "Duration [seconds]" real "" 1 0.1 30 @@ -25,12 +25,24 @@ ; maximum amplitude. As defined in Audacity, 'pluck' has ; incorrect length duration and clipping at the start which gives ; rise to DC offset. Using 'snd-pluck' avoids the clipping and -; offset so we don't need the highpass8 filter that we used before. +; reduces offset so we don't need the highpass8 filter that we used before. +; Updated to v4 by Steve Daulton May 2015 ; set final-amp for abrupt or gradual fade (setf final-amp (if (= fade 1) 0.001 0.000001)) -(let* ((pluck-sound (snd-pluck *sound-srate* (step-to-hz p) 0 dur final-amp)) +;; Get length of preview +(setq pdur + (if (get '*track* 'view) ;NIL if preview + dur + (get '*project* 'preview-duration))) + +(let* ((pluck-sound (snd-pluck *sound-srate* (step-to-hz pitch) 0 dur final-amp)) + (pluck-sound (extract-abs 0 pdur pluck-sound)) ; shorten if necessary for preview. (max-peak (peak pluck-sound ny:all))) - (scale (/ 0.8 max-peak) pluck-sound)) + ;; snd-pluck has a random element and will occasionally produce + ;; zero amplitude at very high pitch settings. Avoid division by zero. + (if (> max-peak 0) + (scale (/ 0.8 max-peak) pluck-sound) + pluck-sound)) diff --git a/plug-ins/rissetdrum.ny b/plug-ins/rissetdrum.ny index 959839e58..32cfd1f74 100644 --- a/plug-ins/rissetdrum.ny +++ b/plug-ins/rissetdrum.ny @@ -1,14 +1,15 @@ ;nyquist plug-in -;version 3 +;version 4 ;type generate ;categories "http://lv2plug.in/ns/lv2core#GeneratorPlugin" +;preview linear ;name "Risset Drum..." ;action "Generating Risset Drum..." ;author "Steven Jones" ;copyright "Released under terms of the GNU General Public License version 2" ;; rissetdrum.ny by Steven Jones, after Jean Claude Risset. -;; Updated by Steve Daulton July 2012. +;; Updated by Steve Daulton July 2012 and May 2015. ;; Released under terms of the GNU General Public License version 2: ;; http://www.gnu.org/licenses/old-licenses/gpl-2.0.html ;; @@ -16,7 +17,7 @@ ;; http://wiki.audacityteam.org/wiki/Nyquist_Plug-ins_Reference ;control freq "Frequency (Hz)" real "" 100 50 2000 -;control decay "Decay (seconds)" real "" 2 0.125 10 +;control decay "Decay (seconds)" real "" 2 0.1 60 ;control cf "Center frequency of noise (Hz)" real "" 500 100 5000 ;control bw "Width of noise band (Hz)" real "" 400 10 1000 ;control noise "Amount of noise in mix (percent)" real "" 25 0 100 @@ -26,6 +27,8 @@ (defun sanitise (val minx maxx) (min (max val minx) maxx)) +;; Not required with validation in Audacity 2.1.1 but left +;; for compatibility. (setq freq (sanitise freq 1 (/ *sound-srate* 2))) (setq decay (sanitise decay 0.1 600)) (setq cf (sanitise cf 1 (/ *sound-srate* 2))) @@ -33,6 +36,12 @@ (setq noise (sanitise (/ noise 100) 0 1)) (setq gain (sanitise gain 0 1)) +;; Get length of preview +(setq pdur + (if (get '*track* 'view) ;NIL if preview + decay + (get '*project* 'preview-duration))) + (setq *rdrum-table* (list (mult 0.17 @@ -73,5 +82,6 @@ ;; Generate and normalize (let* ((output (risset-drum freq decay cf bw noise)) + (output (extract-abs 0 pdur output)) ; shorten if necessary for preview. (peakval (peak output ny:all))) (scale (/ gain peakval) output)) diff --git a/src/AutoRecovery.cpp b/src/AutoRecovery.cpp old mode 100644 new mode 100755 index 83ba56ca4..9711d7de0 --- a/src/AutoRecovery.cpp +++ b/src/AutoRecovery.cpp @@ -692,7 +692,7 @@ bool AutoSaveFile::Decode(const wxString & fileName) file.Close(); // Decode to a temporary file to preserve the orignal. - wxString tempName = fn.CreateTempFileName(fn.GetPath(true)); + wxString tempName = fn.CreateTempFileName(fn.GetPath()); XMLFileWriter out; diff --git a/src/Experimental.h b/src/Experimental.h old mode 100644 new mode 100755 diff --git a/src/FreqWindow.cpp b/src/FreqWindow.cpp old mode 100644 new mode 100755 index 6b5a54a6e..0ad678476 --- a/src/FreqWindow.cpp +++ b/src/FreqWindow.cpp @@ -557,6 +557,7 @@ void FreqWindow::GetAudio() { if (mData) { delete [] mData; + mData = NULL; } mDataLen = 0; diff --git a/src/LabelDialog.cpp b/src/LabelDialog.cpp index caf5402a8..c1979e899 100644 --- a/src/LabelDialog.cpp +++ b/src/LabelDialog.cpp @@ -39,6 +39,7 @@ #include "widgets/NumericTextCtrl.h" #include "FileDialog.h" +#include enum Column { @@ -380,7 +381,6 @@ void LabelDialog::FindAllLabels() TrackListIterator iter(mTracks); Track *t; - mInitialRow = -1; // Add labels from all label tracks for (t = iter.First(); t; t = iter.Next()) { @@ -389,6 +389,8 @@ void LabelDialog::FindAllLabels() } } + FindInitialRow(); + if (mData.GetCount() == 0) { wxCommandEvent e; OnInsert(e); @@ -414,9 +416,45 @@ void LabelDialog::AddLabels(LabelTrack *t) rd->title = ls->title; mData.Add(rd); + } +} - if (i == t->getSelectedIndex()) { - mInitialRow = mData.GetCount() - 1; +void LabelDialog::FindInitialRow() +{ + int cnt = mData.GetCount(); + mInitialRow = -1; + + if (cnt == 0) + return; + + // find closest previous label + + double distMin = std::numeric_limits::max(); + double dist; + double t0 = mViewInfo->selectedRegion.t0(); + int i; + for (i = 0; i < cnt; i++) + { + dist = t0 - mData[i]->selectedRegion.t0(); + if (dist >= 0.0 && dist < distMin) + { + mInitialRow = i; + distMin = dist; + } + } + + // if no previous label was found, find first label + + if (mInitialRow == -1) + { + double t0Min = std::numeric_limits::max(); + for (i = 0; i < cnt; i++) + { + if (mData[i]->selectedRegion.t0() < t0Min) + { + mInitialRow = i; + t0Min = mData[i]->selectedRegion.t0(); + } } } } diff --git a/src/LabelDialog.h b/src/LabelDialog.h index 7bff60cc0..29640d620 100644 --- a/src/LabelDialog.h +++ b/src/LabelDialog.h @@ -50,6 +50,7 @@ class LabelDialog:public wxDialog bool Validate(); void FindAllLabels(); void AddLabels(LabelTrack *t); + void FindInitialRow(); wxString TrackName(int & index, wxString dflt = _("Label Track")); void OnUpdate(wxCommandEvent &event); diff --git a/src/Menus.cpp b/src/Menus.cpp index 3b3c1c839..ce2333aef 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -844,7 +844,7 @@ void AudacityProject::CreateMenusAndCommands() c->BeginSubMenu(_("Add &New")); - c->AddItem(wxT("NewAudioTrack"), _("&Audio Track"), FN(OnNewWaveTrack), wxT("Ctrl+Shift+N")); + c->AddItem(wxT("NewMonoTrack"), _("&Mono Track"), FN(OnNewWaveTrack), wxT("Ctrl+Shift+N")); c->AddItem(wxT("NewStereoTrack"), _("&Stereo Track"), FN(OnNewStereoTrack)); c->AddItem(wxT("NewLabelTrack"), _("&Label Track"), FN(OnNewLabelTrack)); c->AddItem(wxT("NewTimeTrack"), _("&Time Track"), FN(OnNewTimeTrack)); @@ -1014,7 +1014,7 @@ void AudacityProject::CreateMenusAndCommands() PopulateEffectsMenu(c, EffectTypeProcess, AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag, - AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag | IsRealtimeNotActiveFlag); + IsRealtimeNotActiveFlag); #ifdef EXPERIMENTAL_EFFECT_MANAGEMENT c->AddSeparator(); // We could say Manage Effects on the menu, but More... is more intuitive. @@ -1039,7 +1039,7 @@ void AudacityProject::CreateMenusAndCommands() PopulateEffectsMenu(c, EffectTypeAnalyze, AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag, - AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag | IsRealtimeNotActiveFlag); + IsRealtimeNotActiveFlag); #ifdef EXPERIMENTAL_EFFECT_MANAGEMENT c->AddSeparator(); c->AddItem(wxT("ManageAnalyzers"), _("More..."), FN(OnManageAnalyzers)); @@ -3300,32 +3300,42 @@ void AudacityProject::OnRepeatLastEffect(int WXUNUSED(index)) -void AudacityProject::OnManagePluginsMenu(EffectType Type) +void AudacityProject::OnManagePluginsMenu(EffectType type) { - //gPrefs->Write( wxT("/Plugins/Rescan"), true); - //gPrefs->Read(wxT("/Plugins/CheckForUpdates"), &doCheck, true); - PluginManager::Get().CheckForUpdates(Type); + if (PluginManager::Get().ShowManager(this, type)) + { + for (size_t i = 0; i < gAudacityProjects.GetCount(); i++) { + AudacityProject *p = gAudacityProjects[i]; - for (size_t i = 0; i < gAudacityProjects.GetCount(); i++) { - AudacityProject *p = gAudacityProjects[i]; - - p->RebuildMenuBar(); + p->RebuildMenuBar(); #if defined(__WXGTK__) - // Workaround for: - // - // http://bugzilla.audacityteam.org/show_bug.cgi?id=458 - // - // This workaround should be removed when Audacity updates to wxWidgets 3.x which has a fix. - wxRect r = p->GetRect(); - p->SetSize(wxSize(1,1)); - p->SetSize(r.GetSize()); + // Workaround for: + // + // http://bugzilla.audacityteam.org/show_bug.cgi?id=458 + // + // This workaround should be removed when Audacity updates to wxWidgets 3.x which has a fix. + wxRect r = p->GetRect(); + p->SetSize(wxSize(1,1)); + p->SetSize(r.GetSize()); #endif + } } } -void AudacityProject::OnManageGenerators(){ OnManagePluginsMenu(EffectTypeGenerate); } -void AudacityProject::OnManageEffects(){ OnManagePluginsMenu(EffectTypeProcess); } -void AudacityProject::OnManageAnalyzers(){ OnManagePluginsMenu(EffectTypeAnalyze); } +void AudacityProject::OnManageGenerators() +{ + OnManagePluginsMenu(EffectTypeGenerate); +} + +void AudacityProject::OnManageEffects() +{ + OnManagePluginsMenu(EffectTypeProcess); +} + +void AudacityProject::OnManageAnalyzers() +{ + OnManagePluginsMenu(EffectTypeAnalyze); +} diff --git a/src/PluginManager.cpp b/src/PluginManager.cpp old mode 100644 new mode 100755 index e7c15f8c0..033555ced --- a/src/PluginManager.cpp +++ b/src/PluginManager.cpp @@ -20,32 +20,29 @@ #include #include #include -#include #include #include #include #include -#include -#include #include #include #include +#include #include #include #include -#include +#include #include "audacity/EffectInterface.h" #include "AudacityApp.h" -#include "effects/EffectManager.h" #include "FileNames.h" #include "ModuleManager.h" #include "PlatformCompatibility.h" #include "Prefs.h" #include "ShuttleGui.h" -#include "xml/XMLFileReader.h" -#include "xml/XMLWriter.h" +#include "effects/EffectManager.h" +#include "widgets/ProgressDialog.h" #include "PluginManager.h" @@ -132,8 +129,8 @@ private: int mLastId; }; -CheckListAx::CheckListAx( wxListCtrl * window ): - wxWindowAccessible( window ) +CheckListAx::CheckListAx( wxListCtrl * window ) +: wxWindowAccessible( window ) { mParent = window; mLastId = -1; @@ -316,7 +313,7 @@ wxAccStatus CheckListAx::GetState( int childId, long *state ) item.SetId( childId - 1 ); item.SetState( wxLIST_STATE_FOCUSED | wxLIST_STATE_SELECTED ); - item.SetMask( wxLIST_MASK_IMAGE | wxLIST_MASK_STATE ); + item.SetMask( wxLIST_MASK_STATE ); if( mParent->GetItem( item ) ) { @@ -333,11 +330,6 @@ wxAccStatus CheckListAx::GetState( int childId, long *state ) { flag |= wxACC_STATE_SYSTEM_SELECTED; } - - if( item.GetImage() != 0 ) - { - flag |= wxACC_STATE_SYSTEM_CHECKED; - } } } @@ -370,126 +362,141 @@ wxAccStatus CheckListAx::GetValue( int childId, wxString *strValue ) // // ============================================================================ -#include "../images/Unchecked.xpm" -#include "../images/Checked.xpm" -#include "../images/Arrow15x15.xpm" - -#define EffectListID 7001 -#define EffectClearAllID 7002 -#define EffectSelectAllID 7003 - -int wxCALLBACK SortCompare(long item1, long item2, long WXUNUSED(sortData)) +enum { - wxString *str1 = (wxString *) item1; - wxString *str2 = (wxString *) item2; + STATE_Enabled, + STATE_Disabled, + STATE_New, -#if defined(__WXMAC__) - return str2->Cmp(*str1); -#else - return str1->Cmp(*str2); -#endif -} + STATE_COUNT +}; + +struct ItemData +{ + PluginDescriptor *plug; + wxString name; + wxString path; + int state; + bool valid; + int nameWidth; + int pathWidth; + int stateWidth; +}; + +WX_DECLARE_STRING_HASH_MAP(ItemData, ItemDataMap); + +enum +{ + ID_ShowAll = 10000, + ID_ShowEnabled, + ID_ShowDisabled, + ID_ShowNew, + ID_List, + ID_ClearAll, + ID_SelectAll, + ID_Enable, + ID_Disable, +}; + +enum +{ + COL_Name, + COL_State, + COL_Path, + + COL_COUNT +}; class PluginRegistrationDialog : public wxDialog { public: // constructors and destructors - PluginRegistrationDialog(ProviderMap & map, EffectType TypeIn); + PluginRegistrationDialog(wxWindow *parent, EffectType type); virtual ~PluginRegistrationDialog(); private: void Populate(); void PopulateOrExchange(ShuttleGui & S); - void RegenerateEffectsList( int iShowWhat ); + void RegenerateEffectsList(int iShowWhat); + void SetState(int i, bool toggle, bool state = true); + static int wxCALLBACK SortCompare(long item1, long item2, long sortData); + int SortCompare(ItemData *item1, ItemData *item2); + void OnChangedVisibility(wxCommandEvent & evt); + void OnSort(wxListEvent & evt); + void OnListChar(wxKeyEvent & evt); void OnOK(wxCommandEvent & evt); void OnCancel(wxCommandEvent & evt); - void OnListChar(wxKeyEvent & evt); - void OnListMouseDown(wxMouseEvent & evt); void OnSelectAll(wxCommandEvent & evt); void OnClearAll(wxCommandEvent & evt); - void OnChangedVisibility(wxCommandEvent & evt); - - void SetBoldOrRegular(int i); - void SetState(int i, int state); - void ToggleItem(int i); + void OnEnable(wxCommandEvent & evt); + void OnDisable(wxCommandEvent & evt); private: ModuleInterface *mMod; EffectType mType; + int mFilter; + wxArrayString mStates; + ItemDataMap mItems; + + int mSortColumn; + int mSortDirection; + + wxString mLongestPath; + + wxListCtrl *mEffects; #if wxUSE_ACCESSIBILITY CheckListAx *mAx; #endif - wxListCtrl *mEffects; - PluginIDList mProvs; - wxArrayString mPathsInCategory; - wxArrayInt miState; - - wxArrayString mTickList; // Effects currently ticked - wxArrayString mRegisteredList; // Effects currently in menus. - - - bool mCancelClicked; - - ProviderMap & mMap; - DECLARE_EVENT_TABLE() }; -enum { - ID_ShowAll = 1000, - ID_ShowRegistered, - ID_ShowUnregistered -}; - BEGIN_EVENT_TABLE(PluginRegistrationDialog, wxDialog) + EVT_LIST_COL_CLICK(ID_List, PluginRegistrationDialog::OnSort) EVT_BUTTON(wxID_OK, PluginRegistrationDialog::OnOK) EVT_BUTTON(wxID_CANCEL, PluginRegistrationDialog::OnCancel) - EVT_BUTTON(EffectClearAllID, PluginRegistrationDialog::OnClearAll) - EVT_BUTTON(EffectSelectAllID, PluginRegistrationDialog::OnSelectAll) - EVT_RADIOBUTTON(ID_ShowAll, PluginRegistrationDialog::OnChangedVisibility ) - EVT_RADIOBUTTON(ID_ShowUnregistered, PluginRegistrationDialog::OnChangedVisibility ) - EVT_RADIOBUTTON(ID_ShowRegistered, PluginRegistrationDialog::OnChangedVisibility ) + EVT_BUTTON(ID_ClearAll, PluginRegistrationDialog::OnClearAll) + EVT_BUTTON(ID_SelectAll, PluginRegistrationDialog::OnSelectAll) + EVT_BUTTON(ID_Enable, PluginRegistrationDialog::OnEnable) + EVT_BUTTON(ID_Disable, PluginRegistrationDialog::OnDisable) + EVT_RADIOBUTTON(ID_ShowAll, PluginRegistrationDialog::OnChangedVisibility) + EVT_RADIOBUTTON(ID_ShowEnabled, PluginRegistrationDialog::OnChangedVisibility) + EVT_RADIOBUTTON(ID_ShowDisabled, PluginRegistrationDialog::OnChangedVisibility) + EVT_RADIOBUTTON(ID_ShowNew, PluginRegistrationDialog::OnChangedVisibility) END_EVENT_TABLE() -PluginRegistrationDialog::PluginRegistrationDialog(ProviderMap & map, EffectType TypeIn) -: wxDialog(wxGetApp().GetTopWindow(), +PluginRegistrationDialog::PluginRegistrationDialog(wxWindow *parent, EffectType type) +: wxDialog(parent, wxID_ANY, - _("Register Effects"), + _("Plugin Manager: Effects"), wxDefaultPosition, wxDefaultSize, - wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), - mMap(map), - mType(TypeIn) + wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) { + mType = type; mEffects = NULL; SetLabel(_("Register Effects")); // Provide visual label SetName(_("Register Effects")); // Provide audible label + + mStates.SetCount(STATE_COUNT); + mStates[STATE_Enabled] = _("Enabled"); + mStates[STATE_Disabled] = _("Disabled"); + mStates[STATE_New] = _("New"); + + mSortColumn = COL_Name; + mSortDirection = 1; + Populate(); - SetReturnCode(wxID_OK); } PluginRegistrationDialog::~PluginRegistrationDialog() { - mEffects->Disconnect(wxEVT_LEFT_DOWN, - wxMouseEventHandler(PluginRegistrationDialog::OnListMouseDown), - NULL, - this); mEffects->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler(PluginRegistrationDialog::OnListChar), NULL, this); - - for (int i = 0, cnt = mEffects->GetItemCount(); i < cnt; i++) - { - wxString *str = (wxString *) mEffects->GetItemData(i); - if (str) - { - delete str; - } - } } void PluginRegistrationDialog::Populate() @@ -503,19 +510,6 @@ void PluginRegistrationDialog::Populate() /// Defines the dialog and does data exchange with it. void PluginRegistrationDialog::PopulateOrExchange(ShuttleGui &S) { - wxImageList * pImageList = new wxImageList( 15, 15 ); - -#define SHOW_UNCHECKED (0) -#define SHOW_CHECKED (1) -#define SHOW_ARROW (2) - -#define COL_NAME (0) -#define COL_PATH (1) - - pImageList->Add(wxBitmap(unchecked_xpm)); - pImageList->Add(wxBitmap(checked_xpm)); - pImageList->Add(wxBitmap(arrow15x15_xpm)); - S.StartVerticalLay(true); { /*i18n-hint: The dialog shows a list of plugins with check-boxes @@ -530,21 +524,20 @@ void PluginRegistrationDialog::PopulateOrExchange(ShuttleGui &S) /* i18n-hint: Radio button to show all effects */ rb = S.Id(ID_ShowAll).AddRadioButton(_("&All")); rb->SetName(_("Show all")); - /* i18n-hint: Radio button to show just the currently unregistered effects */ - rb = S.Id(ID_ShowUnregistered).AddRadioButtonToGroup(_("&Unregistered")); - rb->SetName(_("Show unregistered")); - /* i18n-hint: Radio button to show just the currently registered effects */ - rb = S.Id(ID_ShowRegistered).AddRadioButtonToGroup(_("&Registered")); - rb->SetName(_("Show registered")); + /* i18n-hint: Radio button to show just the currently disabled effects */ + rb = S.Id(ID_ShowDisabled).AddRadioButtonToGroup(_("D&isabled")); + rb->SetName(_("Show disabled")); + /* i18n-hint: Radio button to show just the currently enabled effects */ + rb = S.Id(ID_ShowEnabled).AddRadioButtonToGroup(_("E&nabled")); + rb->SetName(_("Show enabled")); + /* i18n-hint: Radio button to show just the newly discovered effects */ + rb = S.Id(ID_ShowNew).AddRadioButtonToGroup(_("Ne&w")); + rb->SetName(_("Show new")); } S.EndHorizontalLay(); - S.SetStyle(wxSUNKEN_BORDER | wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_HRULES | wxLC_VRULES ); - mEffects = S.Id(EffectListID).AddListControlReportMode(); - mEffects->Connect(wxEVT_LEFT_DOWN, - wxMouseEventHandler(PluginRegistrationDialog::OnListMouseDown), - NULL, - this); + S.SetStyle(wxSUNKEN_BORDER | wxLC_REPORT | wxLC_HRULES | wxLC_VRULES ); + mEffects = S.Id(ID_List).AddListControlReportMode(); mEffects->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(PluginRegistrationDialog::OnListChar), NULL, @@ -553,179 +546,181 @@ void PluginRegistrationDialog::PopulateOrExchange(ShuttleGui &S) mAx = new CheckListAx(mEffects); mEffects->SetAccessible(mAx); #endif - mEffects->AssignImageList( pImageList, wxIMAGE_LIST_SMALL ); - mEffects->InsertColumn(COL_NAME, _("Plug-in Name")); - mEffects->InsertColumn(COL_PATH, _("Path")); + mEffects->InsertColumn(COL_Name, _("Name")); + mEffects->InsertColumn(COL_State, _("State")); + mEffects->InsertColumn(COL_Path, _("Path")); + + S.StartHorizontalLay(wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxEXPAND, 0); + { + S.Id(ID_SelectAll).AddButton(_("&Select All")); + S.Id(ID_ClearAll).AddButton(_("C&lear All")); + + S.StartHorizontalLay(wxALIGN_CENTER); + { + S.AddSpace(1); + } + S.EndHorizontalLay(); + + S.Id(ID_Enable).AddButton(_("&Enable")); + S.Id(ID_Disable).AddButton(_("&Disable")); + } + S.EndHorizontalLay(); } S.EndStatic(); - S.StartHorizontalLay(wxALIGN_LEFT | wxEXPAND, false); - { - S.SetBorder(10); - S.StartHorizontalLay(wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); - { - S.AddSpace(12); - S.SetBorder(6); - S.Id(EffectSelectAllID).AddButton(_("&Select All")); - S.Id(EffectClearAllID).AddButton(_("Cl&ear All")); - } - S.EndHorizontalLay(); - - S.StartHorizontalLay(wxALIGN_CENTER | wxEXPAND); - { - S.AddSpace(1); - } - S.EndHorizontalLay(); - - S.AddStandardButtons(eOkButton | eCancelButton); - } - S.EndHorizontalLay(); + S.AddStandardButtons(eOkButton | eCancelButton); } S.EndVerticalLay(); - PluginManager & pm = PluginManager::Get(); - - mPathsInCategory.Clear(); - - // Add ALL plug ins... - for (ProviderMap::iterator iter = mMap.begin(); iter != mMap.end(); ++iter) + wxArrayInt colWidths; + for (int i = 0, cnt = mEffects->GetColumnCount(); i < cnt; i++) { - wxString path = iter->first; - mPathsInCategory.Add( path ); + colWidths.Add(0); } - // Get the list of enabled plugins. - // We'll take away ones which we know have the wrong type. - - // This iteration is confusing, becuase registered effects appear twice, - // once as generics (unloaded) with no type and once, if they have been loaded, - // with their actual correct types. - PluginMap::iterator iter2 = pm.mPlugins.begin(); - while (iter2 != pm.mPlugins.end()) + for (int i = 0, cnt = mStates.GetCount(); i < cnt; i++) { - PluginDescriptor & plug = iter2->second; - EffectType Type=plug.GetEffectType(); - if( Type == mType ) + int x; + mEffects->GetTextExtent(mStates[i], &x, NULL); + colWidths[COL_State] = wxMax(colWidths[COL_State], x); + } + + PluginManager & pm = PluginManager::Get(); + for (PluginMap::iterator iter = pm.mPlugins.begin(); iter != pm.mPlugins.end(); ++iter) + { + PluginDescriptor & plug = iter->second; + + PluginType plugType = plug.GetPluginType(); + if (plugType != PluginTypeEffect && plugType != PluginTypeNone) { - // Initially all the registered menu items are ticked. - // So Ticklist and Registered list are the same. - if( plug.IsEnabled() ) + continue; + } + + wxString path = plug.GetPath(); + ItemData & item = mItems[path]; // will create new entry + item.plug = &plug; + item.path = path; + item.state = plug.IsEnabled() ? STATE_Enabled : STATE_Disabled; + item.valid = plug.IsValid(); + + if (plugType == PluginTypeEffect) + { + item.name = plug.GetName(); + } + // This is not right and will not work when other plugin types are added. + // But it's presumed that the plugin manager dialog will be fully developed + // by then. + else if (plugType == PluginTypeNone) + { + wxFileName fname = path; + item.name = fname.GetName(); + if (!plug.IsValid()) { - mTickList.Add( plug.GetPath()); - mRegisteredList.Add( plug.GetPath()); + item.state = STATE_New; } } - else if( Type != EffectTypeNone ) + + int x; + mEffects->GetTextExtent(item.name, &x, NULL); + colWidths[COL_Name] = wxMax(colWidths[COL_Name], x); + + mEffects->GetTextExtent(item.path, &x, NULL); + if (x > colWidths[COL_Path]) { - // Remove any that we know are the wrong type. - int ix = mPathsInCategory.Index( plug.GetPath() ); - if( ix != wxNOT_FOUND ) - { - mPathsInCategory.RemoveAt( ix ); - } + mLongestPath = item.path; } - iter2++; - }; - RegenerateEffectsList( ID_ShowAll ); + colWidths[COL_Path] = wxMax(colWidths[COL_Path], x); + } + + wxRect r = wxGetClientDisplayRect(); + + int maxW = 0; + for (int i = 0, cnt = mEffects->GetColumnCount(); i < cnt; i++) + { + int w = colWidths[i] + /* fudge */ 10; + mEffects->SetColumnWidth(i, w); + maxW += w; + } + + // Keep dialog from getting too wide + int w = r.GetWidth() - (GetClientSize().GetWidth() - mEffects->GetSize().GetWidth()); + mEffects->SetSizeHints(wxSize(wxMin(maxW, w), 200), wxSize(w, -1)); + + RegenerateEffectsList(ID_ShowAll); Layout(); Fit(); - wxRect r = wxGetClientDisplayRect(); + wxSize sz = GetSize(); sz.SetWidth(wxMin(sz.GetWidth(), r.GetWidth())); sz.SetHeight(wxMin(sz.GetHeight(), r.GetHeight())); SetMinSize(sz); + // Parent window is usually not there yet, so centre on screen rather than on parent. CenterOnScreen(); + if (mEffects->GetItemCount() > 0) + { + // Make sure first item is selected/focused. + mEffects->SetFocus(); + mEffects->SetItemState(0, wxLIST_STATE_FOCUSED | wxLIST_STATE_SELECTED, wxLIST_STATE_FOCUSED | wxLIST_STATE_SELECTED); +#if wxUSE_ACCESSIBILITY + mAx->SetSelected(0); +#endif + } + } -void PluginRegistrationDialog::RegenerateEffectsList( int iShowWhat ) +void PluginRegistrationDialog::RegenerateEffectsList(int filter) { - // The dc is used to compute the text width in pixels. - // FIXME: That works fine for PC, but apparently comes out too small for wxMAC. - // iLen is minimum width in pixels shown for the file names. 200 is reasonable. - int iNameLen = 0; - int iPathLen = 0; - int x, y; - wxRect iconrect; + mFilter = filter; - //PluginManager & pm = PluginManager::Get(); - - miState.Clear(); mEffects->DeleteAllItems(); + int i = 0; - for (ProviderMap::iterator iter = mMap.begin(); iter != mMap.end(); ++iter) + for (ItemDataMap::iterator iter = mItems.begin(); iter != mItems.end(); ++iter) { + ItemData & item = iter->second; + bool add = false; - wxFileName fname = iter->first; - wxString name = fname.GetName(); - wxString path = iter->first; - - if( mPathsInCategory.Index( path ) == wxNOT_FOUND ) - continue; - - if( mRegisteredList.Index( path ) == wxNOT_FOUND ){ - if( iShowWhat == ID_ShowRegistered ) - continue; - } else { - if( iShowWhat == ID_ShowUnregistered ) - continue; - } - - miState.Add( SHOW_UNCHECKED); - - bool bTicked = mTickList.Index( path ) != wxNOT_FOUND; - mEffects->InsertItem(i, name, bTicked? SHOW_CHECKED:SHOW_UNCHECKED); - mEffects->SetItemPtrData(i, (wxUIntPtr) new wxString(name)); - mEffects->SetItem(i, COL_PATH, path); - - // Only need to get the icon width once - if (i == 0) + switch (mFilter) { -#if defined(__WXMAC__) || defined(__WXGTK__) - // wxMac and wxGtk do not return a valid width. - // - // So, just guess. - wxIcon i1(unchecked_xpm); - wxIcon i2(checked_xpm); - wxIcon i3(arrow15x15_xpm); - iconrect.x = 4; - iconrect.width = wxMax(wxMax(i1.GetWidth(), i2.GetWidth()), i3.GetWidth()); -#else - mEffects->GetItemRect( i, iconrect, wxLIST_RECT_ICON ); -#endif + case ID_ShowAll: + add = true; + break; + case ID_ShowNew: + if (item.state == STATE_New) + { + add = true; + } + break; + case ID_ShowEnabled: + if (item.state == STATE_Enabled) + { + add = true; + } + break; + case ID_ShowDisabled: + if (item.state == STATE_Disabled) + { + add = true; + } + break; + } + + if (add) + { + mEffects->InsertItem(i, item.name); + mEffects->SetItem(i, COL_State, mStates[item.state]); + mEffects->SetItem(i, COL_Path, item.path); + mEffects->SetItemPtrData(i, (wxUIntPtr) &item); + + ++i; } - mEffects->GetTextExtent(name, &x, &y); - iNameLen = wxMax(iNameLen, x + iconrect.width + (iconrect.x * 2)); - mEffects->GetTextExtent(path, &x, &y ); - iPathLen = wxMax(iPathLen, x + iconrect.width + (iconrect.x * 2)); - i++; } -#if defined(__WXGTK__) - // Keep dialog from getting too wide - wxDisplay d(wxDisplay::GetFromWindow(GetParent())); - int w = d.GetGeometry().GetWidth() - 100; - iNameLen = wxMin(iNameLen, w); - iPathLen = wxMin(iPathLen, w - iNameLen); -#endif + mEffects->SortItems(SortCompare, (wxUIntPtr) this); - mEffects->SortItems(SortCompare, 0); - for(i=0;iGetItemCount();i++) - { - wxListItem item; - item.SetId( i ); - item.SetMask( wxLIST_MASK_IMAGE ); - mEffects->GetItem( item ); - if( item.GetImage() != 0 ) - miState[ i ] = SHOW_CHECKED; - } - - mEffects->SetColumnWidth(COL_NAME, iNameLen + /* fudge */ 5); - mEffects->SetColumnWidth(COL_PATH, iPathLen + /* fudge */ 5); - - mEffects->SetSizeHints(iNameLen + iPathLen + /* fudge */ 15, 200); if (mEffects->GetItemCount() > 0) { // Make sure first item is selected/focused. @@ -737,18 +732,114 @@ void PluginRegistrationDialog::RegenerateEffectsList( int iShowWhat ) } } -void PluginRegistrationDialog::OnListMouseDown(wxMouseEvent & evt) +void PluginRegistrationDialog::SetState(int i, bool toggle, bool state) { - wxPoint p = evt.GetPosition(); - int flags = wxLIST_HITTEST_ONITEM; - int item = mEffects->HitTest(p, flags); + wxListItem li; - if (item != wxNOT_FOUND) + li.m_mask = wxLIST_MASK_DATA; + li.m_itemId = i; + + mEffects->GetItem(li); + + ItemData *item = (ItemData *) li.m_data; + + // If changing the state of a "New" (placeholder) entry, then we mark it as valid + // since it will either be registered if "Enabled" or ignored if "Disabled". + if (item->state == STATE_New) { - ToggleItem(item); + item->valid = true; } - evt.Skip(); + if (toggle) + { + item->state = item->state == STATE_Enabled ? STATE_Disabled : STATE_Enabled; + } + else + { + item->state = state; + } + + if (mFilter == ID_ShowNew && item->state != STATE_New) + { + mEffects->DeleteItem(i); + } + else if (mFilter == ID_ShowDisabled && item->state != STATE_Disabled) + { + mEffects->DeleteItem(i); + } + else if (mFilter == ID_ShowEnabled && item->state != STATE_Enabled) + { + mEffects->DeleteItem(i); + } + else + { + mEffects->SetItem(i, COL_State, mStates[item->state]); +#if wxUSE_ACCESSIBILITY + mAx->SetSelected(i); +#endif + } +} + +int wxCALLBACK PluginRegistrationDialog::SortCompare(long item1, long item2, long sortData) +{ + PluginRegistrationDialog *dlg = (PluginRegistrationDialog *) sortData; + ItemData *i1 = (ItemData *) item1; + ItemData *i2 = (ItemData *) item2; + + return dlg->SortCompare(i1, i2); +} + +int PluginRegistrationDialog::SortCompare(ItemData *item1, ItemData *item2) +{ + wxString *str1; + wxString *str2; + + switch (mSortColumn) + { + case COL_Name: + str1 = &item1->name; + str2 = &item2->name; + break; + case COL_State: + str1 = &mStates[item1->state]; + str2 = &mStates[item2->state]; + break; + case COL_Path: + str1 = &item1->path; + str2 = &item2->path; + break; + default: + return 0; + } + +#if defined(__WXMAC__) + return str2->Cmp(*str1) * mSortDirection; +#else + return str1->Cmp(*str2) * mSortDirection; +#endif +} + +void PluginRegistrationDialog::OnChangedVisibility(wxCommandEvent & evt) +{ + // Go and show the relevant items. + RegenerateEffectsList(evt.GetId()); +} + +void PluginRegistrationDialog::OnSort(wxListEvent & evt) +{ + int col = evt.GetColumn(); + + if (col != mSortColumn) + { + mSortDirection = 1; + } + else + { + mSortDirection *= -1; + } + + mSortColumn = col; + mEffects->SortItems(SortCompare, (wxUIntPtr) this); } void PluginRegistrationDialog::OnListChar(wxKeyEvent & evt) @@ -757,11 +848,10 @@ void PluginRegistrationDialog::OnListChar(wxKeyEvent & evt) { case WXK_SPACE: { - int iItem = mEffects->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED); - - if (iItem != wxNOT_FOUND) + int item = mEffects->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED); + if (item != wxNOT_FOUND) { - ToggleItem(iItem); + SetState(item, true); } } break; @@ -778,166 +868,128 @@ void PluginRegistrationDialog::OnListChar(wxKeyEvent & evt) } } -void PluginRegistrationDialog::SetBoldOrRegular(int i) -{ - wxFont Font = mEffects->GetItemFont(i); - Font.SetWeight( (miState[i] == SHOW_CHECKED) ? wxFONTWEIGHT_BOLD : wxFONTWEIGHT_NORMAL); - mEffects->SetItemFont(i, Font); -} - -// We can't capture mouse clicks, only selected and deselected. -// Clicking on a selected item does not generate any event. -// Therefore our workaround solution is to NEVER actually select. -// So whenever the code tries to , we cancel the selection. -// That way we continue to get events. -void PluginRegistrationDialog::SetState(int i, int state) -{ - miState[i] = state; - mEffects->SetItemImage(i, miState[i]); -#if wxUSE_ACCESSIBILITY - mAx->SetSelected(i); -#endif -} - -void PluginRegistrationDialog::ToggleItem(int i) -{ - SetState(i, miState[i] == SHOW_CHECKED ? SHOW_UNCHECKED : SHOW_CHECKED); -} - -void PluginRegistrationDialog::OnChangedVisibility(wxCommandEvent & evt) -{ - int iShowWhat=evt.GetId(); - - // First update mTickList - // The effects list may only be showing some of the effects, so it is ONLY - // the ones in the list that may need to affect mTickList. - wxListItem li; - li.Clear(); - for (int i = 0, cnt = mEffects->GetItemCount(); i < cnt; i++) - { - mEffects->EnsureVisible(i); - li.SetId(i); - li.SetColumn(COL_PATH); - li.SetMask(wxLIST_MASK_TEXT); - mEffects->GetItem(li); - wxString path = li.GetText(); - int ix = mTickList.Index( path ); - if( miState[i] == SHOW_CHECKED ){ - if( ix == wxNOT_FOUND ) - mTickList.Add( path ); - } else { - if( ix != wxNOT_FOUND ) - mTickList.RemoveAt( ix ); - } - } - - // TickList has been updated. Go and show the relevant items. - RegenerateEffectsList( iShowWhat ); -} - - void PluginRegistrationDialog::OnSelectAll(wxCommandEvent & WXUNUSED(evt)) { - for (size_t i = 0, cnt = miState.size(); i < cnt; i++) + for (int i = 0, cnt = mEffects->GetItemCount(); i < cnt; i++) { - SetState(i, SHOW_CHECKED); + mEffects->SetItemState(i, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); } } void PluginRegistrationDialog::OnClearAll(wxCommandEvent & WXUNUSED(evt)) { - for (size_t i = 0, cnt = miState.size(); i < cnt; i++) + for (int i = 0, cnt = mEffects->GetItemCount(); i < cnt; i++) { - SetState(i, SHOW_UNCHECKED); + mEffects->SetItemState(i, 0, wxLIST_STATE_SELECTED); + } +} + +void PluginRegistrationDialog::OnEnable(wxCommandEvent & WXUNUSED(evt)) +{ + wxArrayLong items; + + long i = mEffects->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + while (i != wxNOT_FOUND) + { + items.Insert(i, 0); + i = mEffects->GetNextItem(i, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + } + + for (size_t i = 0, cnt = items.GetCount(); i < cnt; i++) + { + SetState(items[i], false, STATE_Enabled); + } +} + +void PluginRegistrationDialog::OnDisable(wxCommandEvent & WXUNUSED(evt)) +{ + wxArrayLong items; + + long i = mEffects->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + while (i != wxNOT_FOUND) + { + items.Insert(i, 0); + i = mEffects->GetNextItem(i, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + } + + for (size_t i = 0, cnt = items.GetCount(); i < cnt; i++) + { + SetState(items[i], false, STATE_Disabled); } } void PluginRegistrationDialog::OnOK(wxCommandEvent & WXUNUSED(evt)) { - - wxCommandEvent ShowAllEvent; - ShowAllEvent.SetId( ID_ShowAll ); - OnChangedVisibility(ShowAllEvent); - - mCancelClicked = false; - FindWindowById(EffectListID)->Disable(); - FindWindowById(wxID_OK)->Disable(); - FindWindowById(EffectListID)->Disable(); - FindWindowById(EffectClearAllID)->Disable(); - FindWindowById(EffectSelectAllID)->Disable(); - PluginManager & pm = PluginManager::Get(); ModuleManager & mm = ModuleManager::Get(); - // From here on, if we register an effect we want to enable it. - pm.mbRegisterAndEnable = true; - - // JKC: The following loop disables all the effects, which - // will in turn make them disappear from menus. - PluginMap::iterator iter = pm.mPlugins.begin(); - while (iter != pm.mPlugins.end()) + + int enableCount = 0; + for (ItemDataMap::iterator iter = mItems.begin(); iter != mItems.end(); ++iter) { - PluginDescriptor & plug = iter->second; - wxString path = plug.GetPath(); - if( mPathsInCategory.Index( path ) != wxNOT_FOUND ) + ItemData & item = iter->second; + wxString path = item.path; + + if (item.state == STATE_Enabled && item.plug->GetPluginType() == PluginTypeNone) { - plug.SetEnabled( false ); // clear out all the effects.... + enableCount++; } - iter++; - }; - - - wxListItem li; - li.Clear(); - for (int i = 0, cnt = mEffects->GetItemCount(); i < cnt && !mCancelClicked; i++) - { - mEffects->EnsureVisible(i); - li.SetId(i); - li.SetColumn(COL_PATH); - li.SetMask(wxLIST_MASK_TEXT); - mEffects->GetItem(li); - wxString path = li.GetText(); - if( mPathsInCategory.Index( path ) == wxNOT_FOUND ) - continue; - - // Create a placeholder descriptor to show we've seen this plugin before and not - // to show it as new the next time Audacity starts. - // - // Placeholder descriptors have a plugin type of PluginTypeNone and the ID is the - // path. - PluginDescriptor & plug = pm.mPlugins[path]; - - plug.SetID(path); - plug.SetPath(path); - plug.SetEnabled(false); - plug.SetValid(false); - - if (miState[i] == SHOW_CHECKED) - { - mEffects->SetItemImage(i, SHOW_ARROW); - wxArrayString providers = mMap[path]; - for (size_t j = 0, cnt = providers.GetCount(); j < cnt; j++) - { - if (mm.RegisterPlugin(providers[j], path)) - { - plug = pm.mPlugins[path]; - plug.SetEnabled( true ); - break; - } - } - mEffects->SetItemImage(i, SHOW_CHECKED); - } - - wxYield(); } - EndModal(mCancelClicked ? wxID_CANCEL : wxID_OK); + wxString last3 = mLongestPath + wxT("\n") + + mLongestPath + wxT("\n") + + mLongestPath + wxT("\n"); + + wxString msg; + msg.Printf(_("Enabling effects:\n\n%s"), last3.c_str()); + + ProgressDialog progress(_("Plugin Manager: Effects"), msg, pdlgHideStopButton); + progress.CenterOnParent(); + + int status; + int i = 0; + for (ItemDataMap::iterator iter = mItems.begin(); iter != mItems.end(); ++iter) + { + ItemData & item = iter->second; + wxString path = item.path; + + if (item.state == STATE_Enabled && item.plug->GetPluginType() == PluginTypeNone) + { + last3 = last3.AfterFirst(wxT('\n')) + item.path + wxT("\n"); + status = progress.Update(++i, enableCount, wxString::Format(_("Enabling effect:\n\n%s"), last3.c_str())); + if (!status) + { + break; + } + + if (mm.RegisterPlugin(item.plug->GetProviderID(), path)) + { + // Registration successful, so remove the placeholder + PluginMap::iterator iter = pm.mPlugins.find(path); + if (iter != pm.mPlugins.end()) + { + pm.mPlugins.erase(iter); + } + } + } + else if (item.state == STATE_New) + { + item.plug->SetValid(false); + } + else if (item.state != STATE_New) + { + item.plug->SetEnabled(item.state == STATE_Enabled); + item.plug->SetValid(item.valid); + } + } + + pm.Save(); + + EndModal(wxID_OK); } void PluginRegistrationDialog::OnCancel(wxCommandEvent & WXUNUSED(evt)) { - mCancelClicked = true; - - EndModal(mCancelClicked ? wxID_CANCEL : wxID_OK); + EndModal(wxID_CANCEL); } @@ -952,6 +1004,7 @@ PluginDescriptor::PluginDescriptor() { mPluginType = PluginTypeNone; mEnabled = false; + mValid = false; mInstance = NULL; mEffectType = EffectTypeNone; @@ -1298,7 +1351,7 @@ const PluginID & PluginManager::RegisterPlugin(ModuleInterface *provider, Effect plug.SetEffectRealtime(effect->SupportsRealtime()); plug.SetEffectAutomatable(effect->SupportsAutomation()); - plug.SetEnabled(mbRegisterAndEnable | effect->EnableFromGetGo()); + plug.SetEnabled(true); plug.SetValid(true); return plug.GetID(); @@ -1571,7 +1624,6 @@ PluginManager *PluginManager::mInstance = NULL; PluginManager::PluginManager() { mSettings = NULL; - mbRegisterAndEnable = false; } PluginManager::~PluginManager() @@ -1914,6 +1966,9 @@ void PluginManager::Save() // Create/Open the registry mRegistry = new wxFileConfig(wxEmptyString, wxEmptyString, FileNames::PluginRegistry()); + // Clear it out + mRegistry->DeleteAll(); + // Write the version string mRegistry->Write(REGVERKEY, REGVERCUR); @@ -2013,39 +2068,28 @@ void PluginManager::SaveGroup(PluginType type) return; } -void PluginManager::CheckForUpdates(EffectType UpdateWhat) +void PluginManager::CheckForUpdates() { // Get ModuleManager reference ModuleManager & mm = ModuleManager::Get(); - // Get the full scan and check for update settings - bool doRescan; - bool doCheck; - gPrefs->Read(wxT("/Plugins/Rescan"), &doRescan, true); - gPrefs->Read(wxT("/Plugins/CheckForUpdates"), &doCheck, true); - - if( UpdateWhat == EffectTypeGenerate ) - doRescan = true; - else if( UpdateWhat == EffectTypeProcess ) - doRescan = true; - else if( UpdateWhat == EffectTypeAnalyze ) - doRescan = true; - ProviderMap map; // Always check for and disable missing plugins // // Since the user's saved presets are in the registery, never delete them. That is - // a job for the plugin manager UI (once it is written) - // Check for plugins that are no longer valid + // a job for the plugin manager UI (once it is written). + // + // Also check for plugins that are no longer valid. PluginMap::iterator iter = mPlugins.begin(); while (iter != mPlugins.end()) { PluginDescriptor & plug = iter->second; const PluginID & plugID = plug.GetID(); const wxString & plugPath = plug.GetPath(); + PluginType plugType = plug.GetPluginType(); - if (plug.GetPluginType() == PluginTypeModule) + if (plugType == PluginTypeModule) { if (!mm.IsProviderValid(plugID, plugPath)) { @@ -2053,18 +2097,15 @@ void PluginManager::CheckForUpdates(EffectType UpdateWhat) } else { - // Only collect plugin paths if we're doing a full scan or checking for updates - if (doRescan || doCheck) + // Collect plugin paths + wxArrayString paths = mm.FindPluginsForProvider(plugID, plugPath); + for (size_t i = 0, cnt = paths.GetCount(); i < cnt; i++) { - wxArrayString paths = mm.FindPluginsForProvider(plugID, plugPath); - for (size_t i = 0, cnt = paths.GetCount(); i < cnt; i++) - { - map[paths[i]].Add(plugID); - } + map[paths[i]].Add(plugID); } } } - else + else if (plugType != PluginTypeNone) { plug.SetValid(mm.IsPluginValid(plug.GetProviderID(), plugPath)); } @@ -2072,30 +2113,33 @@ void PluginManager::CheckForUpdates(EffectType UpdateWhat) ++iter; } - // If we're only checking for new plugins, then remove all of the known ones - if (doCheck && !doRescan) + for (PluginMap::iterator iter = mPlugins.begin(); iter != mPlugins.end(); ++iter) { - for (PluginMap::iterator iter = mPlugins.begin(); iter != mPlugins.end(); ++iter) + PluginDescriptor & plug = iter->second; + const wxString & plugPath = plug.GetPath().BeforeFirst(wxT(';')); + ProviderMap::iterator mapiter = map.find(plugPath); + if (mapiter != map.end()) { - PluginDescriptor & plug = iter->second; - const wxString & plugPath = plug.GetPath(); - ProviderMap::iterator mapiter = map.find(plugPath); - if (mapiter != map.end()) - { - map.erase(mapiter); - } + map.erase(mapiter); } } - // Allow the user to choose which ones to enable - if (map.size() != 0) + for (ProviderMap::iterator iter = map.begin(); iter != map.end(); ++iter) { - - PluginRegistrationDialog dlg(map,UpdateWhat); - - if (dlg.ShowModal() == wxID_OK) + wxString & path = iter->first; + wxArrayString & providers = iter->second; + for (size_t i = 0, cnt = providers.GetCount(); i < cnt; i++) { - gPrefs->Write(wxT("/Plugins/Rescan"), false); + // Create placeholder descriptors to show we've seen this plugin before. + // + // Placeholder descriptors have a plugin type of PluginTypeNone and the ID + // is the path. + PluginDescriptor & plug = mPlugins[path]; + plug.SetID(path); + plug.SetProviderID(providers[i]); + plug.SetPath(path); + plug.SetEnabled(false); + plug.SetValid(false); } } @@ -2104,6 +2148,14 @@ void PluginManager::CheckForUpdates(EffectType UpdateWhat) return; } +bool PluginManager::ShowManager(wxWindow *parent, EffectType type) +{ + CheckForUpdates(); + + PluginRegistrationDialog dlg(parent, type); + return dlg.ShowModal() == wxID_OK; +} + // Here solely for the purpose of Nyquist Workbench until // a better solution is devised. const PluginID & PluginManager::RegisterPlugin(EffectIdentInterface *effect) diff --git a/src/PluginManager.h b/src/PluginManager.h index 913f1ffa5..fb148f7d0 100644 --- a/src/PluginManager.h +++ b/src/PluginManager.h @@ -156,13 +156,11 @@ private: // /////////////////////////////////////////////////////////////////////////////// -WX_DECLARE_STRING_HASH_MAP(wxArrayString, ArrayStringMap); - -//WX_DECLARE_STRING_HASH_MAP(PluginDescriptor, PluginMap); typedef std::map PluginMap; typedef wxArrayString PluginIDList; +class ProviderMap; class PluginRegistrationDialog; class PluginManager : public PluginManagerInterface @@ -256,24 +254,20 @@ public: wxString GetName(const PluginID & ID); IdentInterface *GetInstance(const PluginID & ID); - void CheckForUpdates(EffectType Type=EffectTypeNone); + void CheckForUpdates(); + + bool ShowManager(wxWindow *parent, EffectType type = EffectTypeNone); // Here solely for the purpose of Nyquist Workbench until // a better solution is devised. const PluginID & RegisterPlugin(EffectIdentInterface *effect); -public: - bool mbRegisterAndEnable; - private: void Load(); void LoadGroup(PluginType type); void Save(); void SaveGroup(PluginType type); - void DisableMissing(); - wxArrayString IsNewOrUpdated(const wxArrayString & paths); - PluginDescriptor & CreatePlugin(const PluginID & id, IdentInterface *ident, PluginType type); wxFileConfig *GetSettings(); diff --git a/src/ShuttleGui.cpp b/src/ShuttleGui.cpp old mode 100644 new mode 100755 index 7519c366c..deb98ed16 --- a/src/ShuttleGui.cpp +++ b/src/ShuttleGui.cpp @@ -2225,18 +2225,23 @@ wxSizer *CreateStdButtonSizer(wxWindow *parent, long buttons, wxWindow *extra) // Add any buttons that need to cuddle up to the right hand cluster if( buttons & eDebugButton ) { + size_t lastLastSpacer = 0; size_t lastSpacer = 0; wxSizerItemList & list = bs->GetChildren(); - for ( size_t i = 0, cnt = list.GetCount(); i < cnt; i++ ) + for( size_t i = 0, cnt = list.GetCount(); i < cnt; i++ ) { - if ( list[i]->IsSpacer() ) + if( list[i]->IsSpacer() ) { lastSpacer = i; } + else + { + lastLastSpacer = lastSpacer; + } } b = new wxButton( parent, eDebugID, _("Debu&g") ); - bs->Insert( lastSpacer + 1, b, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, margin ); + bs->Insert( lastLastSpacer + 1, b, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, margin ); } wxSizer * s; diff --git a/src/effects/Amplify.cpp b/src/effects/Amplify.cpp index af5cfeb0a..9fe293e5f 100644 --- a/src/effects/Amplify.cpp +++ b/src/effects/Amplify.cpp @@ -214,15 +214,15 @@ void EffectAmplify::PopulateOrExchange(ShuttleGui & S) // Peak S.StartMultiColumn(2, wxCENTER); { - FloatingPointValidator vldNewPeak(2, &mNewPeak); + int precission = 2; + FloatingPointValidator vldNewPeak(precission, &mNewPeak); double minAmp = MIN_Amp + (20.0 * log10(mPeak)); double maxAmp = MAX_Amp + (20.0 * log10(mPeak)); - // TODO: This is a hack that should be fixed in the validator: - // If MAX_Amp is negative, then the truncated text value will be greater - // than the actual float value. - // Add 0.05 to the max value, equivalent to rounding the right way. - if (maxAmp < 0) - maxAmp += 0.005; + + // min and max need same precision as what we're validating (bug 963) + minAmp = Internat::CompatibleToDouble(Internat::ToString(minAmp, precission)); + maxAmp = Internat::CompatibleToDouble(Internat::ToString(maxAmp, precission)); + vldNewPeak.SetRange(minAmp, maxAmp); mNewPeakT = S.Id(ID_Peak).AddTextBox(_("New Peak Amplitude (dB):"), wxT(""), 12); mNewPeakT->SetValidator(vldNewPeak); diff --git a/src/effects/AutoDuck.h b/src/effects/AutoDuck.h index 2c28a6a5c..b36f4ee9b 100644 --- a/src/effects/AutoDuck.h +++ b/src/effects/AutoDuck.h @@ -44,7 +44,6 @@ public: // EffectIdentInterface implementation virtual EffectType GetType(); - virtual bool EnableFromGetGo(){ return false;}; // EffectClientInterface implementation diff --git a/src/effects/ChangeTempo.cpp b/src/effects/ChangeTempo.cpp index 31b841e85..e274d6bb7 100644 --- a/src/effects/ChangeTempo.cpp +++ b/src/effects/ChangeTempo.cpp @@ -207,7 +207,8 @@ void EffectChangeTempo::PopulateOrExchange(ShuttleGui & S) // S.AddUnits(_("Length (seconds):")); - FloatingPointValidator vldFromLength(2, &m_FromLength, NUM_VAL_TWO_TRAILING_ZEROES); + int precission = 2; + FloatingPointValidator vldFromLength(precission, &m_FromLength, NUM_VAL_TWO_TRAILING_ZEROES); m_pTextCtrl_FromLength = S.Id(ID_FromLength) .AddTextBox(_("from"), wxT(""), 12); m_pTextCtrl_FromLength->SetName(_("From length in seconds")); @@ -215,8 +216,14 @@ void EffectChangeTempo::PopulateOrExchange(ShuttleGui & S) m_pTextCtrl_FromLength->Enable(false); // Disable because the value comes from the user selection. FloatingPointValidator vldToLength(2, &m_ToLength, NUM_VAL_TWO_TRAILING_ZEROES); - vldToLength.SetRange((m_FromLength * 100.0) / (100.0 + MAX_Percentage), - (m_FromLength * 100.0) / (100.0 + MIN_Percentage)); + + // min and max need same precision as what we're validating (bug 963) + double minLength = (m_FromLength * 100.0) / (100.0 + MAX_Percentage); + double maxLength = (m_FromLength * 100.0) / (100.0 + MIN_Percentage); + minLength = Internat::CompatibleToDouble(Internat::ToString(minLength, precission)); + maxLength = Internat::CompatibleToDouble(Internat::ToString(maxLength, precission)); + + vldToLength.SetRange(minLength, maxLength); m_pTextCtrl_ToLength = S.Id(ID_ToLength) .AddTextBox(_("to"), wxT(""), 12); m_pTextCtrl_ToLength->SetName(_("To length in seconds")); diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp old mode 100644 new mode 100755 index fe47430aa..98b5cded4 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -2396,15 +2396,19 @@ void Effect::Preview(bool dryOnly) gPrefs->Read(wxT("/AudioIO/EffectsPreviewLen"), &previewLen); double rate = mProjectRate; + double warpedPreviewLength = CalcPreviewInputLength(previewLen); double t0 = mT0; - double t1 = t0 + CalcPreviewInputLength(previewLen); + double t1 = t0 + warpedPreviewLength; // Generators can run without a selection. if (GetType() == EffectTypeGenerate) { // If a generator varies over time, it must use the selected duration. // otherwise set it as a linear effect and process no more than the preview length. // TODO: When previewing non-linear generate effect, calculate only the first 'preview length'. - double dur = (mIsLinearEffect)? wxMin(mSetDuration, CalcPreviewInputLength(previewLen)) : mSetDuration; + // For generate effects derived from the Nyquist Prompt, the duration is unknow, so + // ensure that we have at least preview length to copy. + double dur = (mIsLinearEffect)? wxMin(mSetDuration, warpedPreviewLength) : + wxMax(mSetDuration, warpedPreviewLength); t1 = t0 + dur; this->SetDuration(dur); } @@ -2446,8 +2450,7 @@ void Effect::Preview(bool dryOnly) mTracks->Add(mixRight); } - // TODO: Don't really think this is necessary, but doesn't hurt - // Reset times + // Reset t0 / t1 is required when source tracks have different start times. t0 = mixLeft->GetStartTime(); t1 = mixLeft->GetEndTime(); } @@ -2472,8 +2475,15 @@ void Effect::Preview(bool dryOnly) double t0save = mT0; double t1save = mT1; - mT0 = t0; - mT1 = t1; + + if (mIsLinearEffect) { + mT0 = t0; + mT1 = t1; + } + else { + mT0 = 0; + mT1 = t1 - t0; + } // Apply effect @@ -3184,6 +3194,24 @@ void EffectUIHost::OnMenu(wxCommandEvent & WXUNUSED(evt)) menu->Append(0, _("User Presets"), sub); } + menu->Append(kSaveAsID, _("Save Preset...")); + + if (mUserPresets.GetCount() == 0) + { + menu->Append(kDeletePresetDummyID, _("Delete Preset"))->Enable(false); + } + else + { + sub = new wxMenu(); + for (size_t i = 0, cnt = mUserPresets.GetCount(); i < cnt; i++) + { + sub->Append(kDeletePresetID + i, mUserPresets[i]); + } + menu->Append(0, _("Delete Preset"), sub); + } + + menu->AppendSeparator(); + wxArrayString factory = mEffect->GetFactoryPresets(); sub = new wxMenu(); @@ -3204,22 +3232,6 @@ void EffectUIHost::OnMenu(wxCommandEvent & WXUNUSED(evt)) } menu->Append(0, _("Factory Presets"), sub); - if (mUserPresets.GetCount() == 0) - { - menu->Append(kDeletePresetDummyID, _("Delete Preset"))->Enable(false); - } - else - { - sub = new wxMenu(); - for (size_t i = 0, cnt = mUserPresets.GetCount(); i < cnt; i++) - { - sub->Append(kDeletePresetID + i, mUserPresets[i]); - } - menu->Append(0, _("Delete Preset"), sub); - } - - menu->AppendSeparator(); - menu->Append(kSaveAsID, _("Save As...")); menu->AppendSeparator(); menu->Append(kImportID, _("Import..."))->Enable(mClient->CanExportPresets()); menu->Append(kExportID, _("Export..."))->Enable(mClient->CanExportPresets()); diff --git a/src/effects/Effect.h b/src/effects/Effect.h index f00ebeaa3..e61d43039 100644 --- a/src/effects/Effect.h +++ b/src/effects/Effect.h @@ -79,7 +79,6 @@ class AUDACITY_DLL_API Effect : public wxEvtHandler, virtual bool IsLegacy(); virtual bool SupportsRealtime(); virtual bool SupportsAutomation(); - virtual bool EnableFromGetGo(){ return true;}; // EffectClientInterface implementation diff --git a/src/effects/Leveller.h b/src/effects/Leveller.h index ee9ed5faf..1d4e310be 100644 --- a/src/effects/Leveller.h +++ b/src/effects/Leveller.h @@ -34,7 +34,6 @@ public: // EffectIdentInterface implementation virtual EffectType GetType(); - virtual bool EnableFromGetGo(){ return false;}; // EffectClientInterface implementation diff --git a/src/effects/LoadEffects.cpp b/src/effects/LoadEffects.cpp index a29d088a9..82195e543 100644 --- a/src/effects/LoadEffects.cpp +++ b/src/effects/LoadEffects.cpp @@ -128,14 +128,18 @@ EFFECT( TRUNCATESILENCE, EffectTruncSilence() ) \ EFFECT( WAHWAH, EffectWahwah() ) \ EFFECT( FINDCLIPPING, EffectFindClipping() ) \ + NOISEREDUCTION_EFFECT \ + SOUNDTOUCH_EFFECTS + +// +// Define the list of effects that do not get autoregistered +// +#define EXCLUDE_LIST \ EFFECT( AUTODUCK, EffectAutoDuck() ) \ EFFECT( LEVELLER, EffectLeveller() ) \ EFFECT( PAULSTRETCH, EffectPaulstretch() ) \ CLASSICFILTER_EFFECT \ - SBSMS_EFFECTS \ - NOISEREDUCTION_EFFECT \ - SOUNDTOUCH_EFFECTS - + SBSMS_EFFECTS // // Define the EFFECT() macro to generate enum names @@ -148,6 +152,7 @@ enum { EFFECT_LIST + EXCLUDE_LIST }; // @@ -164,6 +169,13 @@ static const wxChar *kEffectNames[] = EFFECT_LIST }; +// +// Create the effect name array of excluded effects +// +static const wxChar *kExcludedNames[] = +{ + EXCLUDE_LIST +}; // // Redefine EFFECT() to generate a case statement for the lookup switch @@ -257,6 +269,12 @@ bool BuiltinEffectsModule::Initialize() { mNames.Add(wxString(BUILTIN_EFFECT_PREFIX) + kEffectNames[i]); } + + for (size_t i = 0; i < WXSIZEOF(kExcludedNames); i++) + { + mNames.Add(wxString(BUILTIN_EFFECT_PREFIX) + kExcludedNames[i]); + } + return true; } @@ -331,6 +349,7 @@ Effect *BuiltinEffectsModule::Instantiate(const wxString & path) switch (mNames.Index(path)) { EFFECT_LIST; + EXCLUDE_LIST; } return NULL; diff --git a/src/effects/Normalize.cpp b/src/effects/Normalize.cpp old mode 100644 new mode 100755 index 51d486ca1..7b090d95f --- a/src/effects/Normalize.cpp +++ b/src/effects/Normalize.cpp @@ -33,7 +33,7 @@ // Define keys, defaults, minimums, and maximums for the effect parameters // // Name Type Key Def Min Max Scale -Param( Level, double, XO("Level"), 0.0, -145.0, 0.0, 1 ); +Param( Level, double, XO("Level"), -1.0, -145.0, 0.0, 1 ); Param( RemoveDC, bool, XO("RemoveDcOffset"), true, false, true, 1 ); Param( ApplyGain, bool, XO("ApplyGain"), true, false, true, 1 ); Param( StereoInd, bool, XO("StereoIndependent"), false, false, true, 1 ); diff --git a/src/effects/Paulstretch.h b/src/effects/Paulstretch.h index 456ee5e92..7a195f9fa 100644 --- a/src/effects/Paulstretch.h +++ b/src/effects/Paulstretch.h @@ -33,7 +33,6 @@ public: // EffectIdentInterface implementation virtual EffectType GetType(); - virtual bool EnableFromGetGo(){ return false;}; // EffectClientInterface implementation diff --git a/src/effects/SBSMSEffect.h b/src/effects/SBSMSEffect.h index f3949b295..205ece823 100644 --- a/src/effects/SBSMSEffect.h +++ b/src/effects/SBSMSEffect.h @@ -28,8 +28,6 @@ public: void setParameters(double rateStart, double rateEnd, double pitchStart, double pitchEnd, SlideType rateSlideType, SlideType pitchSlideType, bool bLinkRatePitch, bool bRateReferenceInput, bool bPitchReferenceInput); - virtual bool EnableFromGetGo(){ return false;}; - private: bool ProcessLabelTrack(Track *track); diff --git a/src/effects/ScienFilter.h b/src/effects/ScienFilter.h index d3e9c21e2..65558a81a 100644 --- a/src/effects/ScienFilter.h +++ b/src/effects/ScienFilter.h @@ -47,7 +47,6 @@ public: // EffectIdentInterface implementation virtual EffectType GetType(); - virtual bool EnableFromGetGo(){ return false;}; // EffectClientInterface implementation diff --git a/src/effects/audiounits/AudioUnitEffect.cpp b/src/effects/audiounits/AudioUnitEffect.cpp index 4e8267da2..186fac78f 100644 --- a/src/effects/audiounits/AudioUnitEffect.cpp +++ b/src/effects/audiounits/AudioUnitEffect.cpp @@ -871,6 +871,7 @@ AudioUnitEffect::AudioUnitEffect(const wxString & path, mUnit = NULL; mBlockSize = 0.0; + mInteractive = false; mUIHost = NULL; mDialog = NULL; @@ -970,6 +971,7 @@ wxString AudioUnitEffect::GetFamily() bool AudioUnitEffect::IsInteractive() { +printf("isinter %d\n", mInteractive); return mInteractive; } @@ -1179,6 +1181,32 @@ bool AudioUnitEffect::SetHost(EffectHostInterface *host) { return false; } + + AudioUnitCocoaViewInfo cocoaViewInfo; + dataSize = sizeof(AudioUnitCocoaViewInfo); + + // Check for a Cocoa UI + result = AudioUnitGetProperty(mUnit, + kAudioUnitProperty_CocoaUI, + kAudioUnitScope_Global, + 0, + &cocoaViewInfo, + &dataSize); + + bool hasCocoa = result == noErr; + + // Check for a Carbon UI + ComponentDescription compDesc; + dataSize = sizeof(compDesc); + result = AudioUnitGetProperty(mUnit, + kAudioUnitProperty_GetUIComponentList, + kAudioUnitScope_Global, + 0, + &compDesc, + &dataSize); + bool hasCarbon = result == noErr; + + mInteractive = (cnt > 0) || hasCocoa || hasCarbon; } return true; diff --git a/src/effects/ladspa/LadspaEffect.cpp b/src/effects/ladspa/LadspaEffect.cpp index 4269848a9..113dc0367 100644 --- a/src/effects/ladspa/LadspaEffect.cpp +++ b/src/effects/ladspa/LadspaEffect.cpp @@ -638,7 +638,7 @@ bool LadspaEffect::IsLegacy() bool LadspaEffect::SupportsRealtime() { - return GetType() == EffectTypeProcess; + return GetType() != EffectTypeGenerate; } bool LadspaEffect::SupportsAutomation() @@ -1356,8 +1356,8 @@ bool LadspaEffect::PopulateUI(wxWindow *parent) LADSPA_PortRangeHint hint = mData->PortRangeHints[p]; wxString bound; - float lower = -FLT_MAX; - float upper = FLT_MAX; + float lower = 0.0; + float upper = 1.0; bool haslo = false; bool hashi = false; bool forceint = false; diff --git a/src/effects/lv2/LV2Effect.h b/src/effects/lv2/LV2Effect.h index 11c00ac81..d8d623fd7 100644 --- a/src/effects/lv2/LV2Effect.h +++ b/src/effects/lv2/LV2Effect.h @@ -117,7 +117,6 @@ public: virtual bool IsLegacy(); virtual bool SupportsRealtime(); virtual bool SupportsAutomation(); - virtual bool EnableFromGetGo(){ return false;}; // EffectClientInterface implementation diff --git a/src/effects/nyquist/Nyquist.cpp b/src/effects/nyquist/Nyquist.cpp index 9076e1c82..60ea6b87a 100644 --- a/src/effects/nyquist/Nyquist.cpp +++ b/src/effects/nyquist/Nyquist.cpp @@ -521,6 +521,11 @@ bool NyquistEffect::Process() mProps += wxString::Format(wxT("(putprop '*PROJECT* %d 'MIDITRACKS)\n"), numMidi); mProps += wxString::Format(wxT("(putprop '*PROJECT* %d 'TIMETRACKS)\n"), numTime); + double previewLen = 6.0; + gPrefs->Read(wxT("/AudioIO/EffectsPreviewLen"), &previewLen); + mProps += wxString::Format(wxT("(putprop '*PROJECT* (float %s) 'PREVIEW-DURATION)\n"), + Internat::ToString(previewLen).c_str()); + SelectedTrackListOfKindIterator sel(Track::Wave, mOutputTracks); int numChannels = 0; for (WaveTrack *t = (WaveTrack *) sel.First(); t; t = (WaveTrack *) sel.Next()) { @@ -1263,10 +1268,10 @@ void NyquistEffect::Parse(wxString line) return; } - // As of version 4 plugins ";nyquist plug-in" is depricated in favour of ";nyquist plugin". - // The hyphenated version must be maintained while we support plugin versions < 4. + // Consistency decission is for "plug-in" as the correct spelling + // "plugin" is allowed as an undocumented convenience. if (len == 2 && tokens[0] == wxT("nyquist") && - (tokens[1] == wxT("plugin") || tokens[1] == wxT("plug-in"))) { + (tokens[1] == wxT("plug-in") || tokens[1] == wxT("plugin"))) { mOK = true; return; } @@ -1354,6 +1359,11 @@ void NyquistEffect::Parse(wxString line) if (len >= 2 && tokens[0] == wxT("preview")) { if (tokens[1] == wxT("enabled") || tokens[1] == wxT("true")) { mEnablePreview = true; + SetLinearEffectFlag(false); + } + else if (tokens[1] == wxT("linear")) { + mEnablePreview = true; + SetLinearEffectFlag(true); } else if (tokens[1] == wxT("disabled") || tokens[1] == wxT("false")) { mEnablePreview = false; diff --git a/src/effects/nyquist/Nyquist.h b/src/effects/nyquist/Nyquist.h index 32405cf06..47b9e2246 100644 --- a/src/effects/nyquist/Nyquist.h +++ b/src/effects/nyquist/Nyquist.h @@ -84,7 +84,6 @@ public: virtual wxString GetFamily(); virtual bool IsInteractive(); virtual bool IsDefault(); - virtual bool EnableFromGetGo(){ return true;}; // EffectClientInterface implementation diff --git a/src/effects/vamp/VampEffect.h b/src/effects/vamp/VampEffect.h index e9b2b82fa..7e4d08d59 100644 --- a/src/effects/vamp/VampEffect.h +++ b/src/effects/vamp/VampEffect.h @@ -56,8 +56,6 @@ public: virtual wxString GetFamily(); virtual bool IsInteractive(); virtual bool IsDefault(); - // May 21015: There aren't many analyse effects, so let us show them all (for now). - virtual bool EnableFromGetGo(){ return true;}; // EffectClientInterface implementation diff --git a/src/toolbars/ControlToolBar.cpp b/src/toolbars/ControlToolBar.cpp index af9f27d77..4a9349100 100644 --- a/src/toolbars/ControlToolBar.cpp +++ b/src/toolbars/ControlToolBar.cpp @@ -570,8 +570,8 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion, if (backwards) std::swap(t0, t1); - t0 = wxMax(t0, 0.0); - t1 = wxMin(t1, latestEnd); + t0 = std::max(0.0, std::min(t0, latestEnd)); + t1 = std::max(0.0, std::min(t1, latestEnd)); if (backwards) std::swap(t0, t1); diff --git a/src/widgets/ProgressDialog.cpp b/src/widgets/ProgressDialog.cpp old mode 100644 new mode 100755 index 5695bfac7..072a29a12 --- a/src/widgets/ProgressDialog.cpp +++ b/src/widgets/ProgressDialog.cpp @@ -1049,7 +1049,7 @@ ProgressDialog::ProgressDialog(const wxString & title, const wxString & message, wxDefaultSize, wxALIGN_LEFT); mMessage->SetName(message); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs) - v->Add(mMessage, 0, wxEXPAND | wxALL, 10); + v->Add(mMessage, 1, wxEXPAND | wxALL, 10); ds.y += mMessage->GetSize().y + 20; // @@ -1117,28 +1117,32 @@ ProgressDialog::ProgressDialog(const wxString & title, const wxString & message, if (!(flags & pdlgHideStopButton)) { w = new wxButton(this, wxID_OK, _("Stop")); - h->Add(w, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 10); - ds.x += w->GetSize().x + 10; + h->Add(w, 0, wxALIGN_RIGHT | wxRIGHT, 10); } if (!(flags & pdlgHideCancelButton)) { w = new wxButton(this, wxID_CANCEL, _("Cancel")); - h->Add(w, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 10); - ds.x += w->GetSize().x + 10; + h->Add(w, 0, wxALIGN_RIGHT | wxRIGHT, 10); } v->Add(h, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 10); + SetSizer(v); + Layout(); + + ds.x = wxMax(g->GetSize().x, h->GetSize().x) + 10; ds.y += w->GetSize().y + 10; - SetSizerAndFit(v); - wxClientDC dc(this); - dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); - wxCoord widthText = 0; - dc.GetTextExtent(message, &widthText, NULL, NULL, NULL, NULL); - ds.x = (wxCoord) wxMax(wxMax(3 * widthText / 2, 4 * ds.y / 3), 300); + dc.GetMultiLineTextExtent(message, &mLastW, &mLastH); + +#if defined(__WXMAC__) + mMessage->SetMinSize(wxSize(mLastW, mLastH)); +#endif + + // The 300 really isn't needed, but it keeps it at a decent width. + ds.x = wxMax(wxMax(wxMax(ds.x, mLastW) + 20, wxMax(ds.y, mLastH)), 300); SetClientSize(ds); Centre(wxCENTER_FRAME | wxBOTH); @@ -1508,15 +1512,42 @@ ProgressDialog::SetMessage(const wxString & message) { if (!message.IsEmpty()) { - wxSize sizeBefore = this->GetClientSize(); mMessage->SetLabel(message); - mMessage->Update(); - wxSize sizeAfter = this->GetBestSize(); - wxSize sizeNeeded; - sizeNeeded.x = wxMax(sizeBefore.x, sizeAfter.x); - sizeNeeded.y = wxMax(sizeBefore.y, sizeAfter.y); - this->SetClientSize(sizeNeeded); - wxDialog::Update(); + + int w, h; + wxClientDC dc(mMessage); + dc.GetMultiLineTextExtent(message, &w, &h); + + bool sizeUpdated = false; + wxSize ds = GetClientSize(); + + if (w > mLastW) + { + ds.x += (w - mLastW); + sizeUpdated = true; + mLastW = w; + } + + if (h > mLastH) + { + ds.y += (h - mLastH); + sizeUpdated = true; + mLastH = h; + } + + if (sizeUpdated) + { +#if defined(__WXMAC__) + wxSize sz = mMessage->GetSize(); + mMessage->SetMinSize(wxSize(wxMax(sz.x, mLastW), wxMax(sz.y, mLastH))); +#endif + // No need to adjust for the margin here since we only add + // to the existing dimensions. + ds.x = wxMax(wxMax(ds.x, mLastW), wxMax(ds.y, mLastH)); + SetClientSize(ds); + wxDialog::Update(); + } + } } diff --git a/src/widgets/ProgressDialog.h b/src/widgets/ProgressDialog.h index 857109d51..7d4d4998a 100644 --- a/src/widgets/ProgressDialog.h +++ b/src/widgets/ProgressDialog.h @@ -89,6 +89,9 @@ class AUDACITY_DLL_API ProgressDialog:public wxDialog wxStaticText *mMessage; wxWindowDisabler *mDisable; + int mLastW; + int mLastH; + DECLARE_EVENT_TABLE(); };