From 1ddbc0bc6822930e6968270fe45ddbdb2fe05f45 Mon Sep 17 00:00:00 2001 From: David Bailes Date: Tue, 2 Jun 2015 09:29:31 +0100 Subject: [PATCH 01/10] state field of status bar. Changed _()s to XO() and wxGetTranslation(), so that translations of strings are changed more promptly. --- src/toolbars/ControlToolBar.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/toolbars/ControlToolBar.cpp b/src/toolbars/ControlToolBar.cpp index b6b334bf8..2bf614f76 100644 --- a/src/toolbars/ControlToolBar.cpp +++ b/src/toolbars/ControlToolBar.cpp @@ -102,10 +102,10 @@ ControlToolBar::ControlToolBar() mCutPreviewTracks = NULL; // strings for status bar - mStatePlay = _("Playing"); - mStateStop = _("Stopped"); - mStateRecord = _("Recording"); - mStatePause = _("Paused"); + mStatePlay = XO("Playing"); + mStateStop = XO("Stopped"); + mStateRecord = XO("Recording"); + mStatePause = XO("Paused"); } ControlToolBar::~ControlToolBar() @@ -1092,15 +1092,18 @@ int ControlToolBar::WidthForStatusBar() int xMax = 0; int x, y; - sb->GetTextExtent(mStatePlay + wxT(" ") + mStatePause + wxT("."), &x, &y); + sb->GetTextExtent(wxString(wxGetTranslation(mStatePlay)) + wxT(" ") + + wxString(wxGetTranslation(mStatePause)) + wxT("."), &x, &y); if (x > xMax) xMax = x; - sb->GetTextExtent(mStateStop + wxT(" ") + mStatePause + wxT("."), &x, &y); + sb->GetTextExtent(wxString(wxGetTranslation(mStateStop)) + wxT(" ") + + wxString(wxGetTranslation(mStatePause)) + wxT("."), &x, &y); if (x > xMax) xMax = x; - sb->GetTextExtent(mStateRecord + wxT(" ") + mStatePause + wxT("."), &x, &y); + sb->GetTextExtent(wxString(wxGetTranslation(mStateRecord)) + wxT(" ") + + wxString(wxGetTranslation(mStatePause)) + wxT("."), &x, &y); if (x > xMax) xMax = x; @@ -1112,16 +1115,16 @@ void ControlToolBar::UpdateStatusBar() wxString state; if (mPlay->IsDown()) - state = mStatePlay; + state = wxGetTranslation(mStatePlay); else if (mRecord->IsDown()) - state = mStateRecord; + state = wxGetTranslation(mStateRecord); else - state = mStateStop; + state = wxGetTranslation(mStateStop); if (mPause->IsDown()) { state.Append(wxT(" ")); - state.Append(mStatePause); + state.Append(wxGetTranslation(mStatePause)); } state.Append(wxT(".")); From bddded0d2b9f3acb4cec291f863b977d1c167257 Mon Sep 17 00:00:00 2001 From: Steve Daulton Date: Tue, 2 Jun 2015 11:43:14 +0100 Subject: [PATCH 02/10] Update TracksPrefs.cpp Fix for bug 1000. --- src/prefs/TracksPrefs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prefs/TracksPrefs.cpp b/src/prefs/TracksPrefs.cpp index 2b480bc20..aa6046ca5 100644 --- a/src/prefs/TracksPrefs.cpp +++ b/src/prefs/TracksPrefs.cpp @@ -63,7 +63,7 @@ void TracksPrefs::Populate() mViewChoices.Add(_("Spectrogram")); mViewChoices.Add(_("Spectrogram log(f)")); mViewChoices.Add(_("Spectral Selection")); - mViewChoices.Add(_("Spectrogram Selection log(f)")); + mViewChoices.Add(_("Spectral Selection log(f)")); mViewChoices.Add(_("Pitch (EAC)")); //------------------------- Main section -------------------- From 14b860701719cfcfcd910b05771f7774a54fafd0 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 2 Jun 2015 09:16:07 -0400 Subject: [PATCH 03/10] compilation fix --- src/WaveClip.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/WaveClip.h b/src/WaveClip.h index bdaefa08b..b45c05bce 100644 --- a/src/WaveClip.h +++ b/src/WaveClip.h @@ -75,7 +75,7 @@ struct WaveDisplay Deallocate(); } - void WaveDisplay::Allocate(int w) + void Allocate(int w) { width = w; @@ -88,7 +88,7 @@ struct WaveDisplay bl = new int[width]; } - void WaveDisplay::Deallocate() + void Deallocate() { delete[] where; where = 0; From 391bd1691c7620e9435b73fa31109abba8fbca15 Mon Sep 17 00:00:00 2001 From: David Bailes Date: Tue, 2 Jun 2015 15:18:12 +0100 Subject: [PATCH 04/10] status bar state field. When you move to the menubar, the state field is no longer cleared. This was achieved by introducing a dummy field of width 0. When you first open a new audacity project, the state is stopped - previously the state only appeared after the first play/pause/etc command. --- src/Project.cpp | 32 ++++++++++++++++++++------------ src/Project.h | 6 ++++++ src/Screenshot.cpp | 2 +- src/commands/CommandTargets.h | 2 +- src/toolbars/ControlToolBar.cpp | 16 ++++++++-------- src/toolbars/ControlToolBar.h | 3 ++- 6 files changed, 38 insertions(+), 23 deletions(-) diff --git a/src/Project.cpp b/src/Project.cpp index d083c51b7..c64d0e0ef 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -781,7 +781,14 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, mMenuClose(false) , mbInitializingScrollbar(false) { - mStatusBar = CreateStatusBar(3); + // Note that the first field of the status bar is a dummy, and it's width is set + // to zero latter in the code. This field is needed for wxWidgets 2.8.12 because + // if you move to the menu bar, the first field of the menu bar is cleared, which + // is undesirable behaviour. + // In addition, the help strings of menu items are by default sent to the first + // field. Currently there are no such help strings, but it they were introduced, then + // there would need to be an event handler to send them to the appropriate field. + mStatusBar = CreateStatusBar(4); wxGetApp().SetMissingAliasedFileWarningShouldShow(true); @@ -1014,11 +1021,12 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, mTrackFactory = new TrackFactory(mDirManager); - int widths[] = {GetControlToolBar()->WidthForStatusBar(), -2, -1}; - mStatusBar->SetStatusWidths(3, widths); + int widths[] = {0, GetControlToolBar()->WidthForStatusBar(mStatusBar), -2, -1}; + mStatusBar->SetStatusWidths(4, widths); wxString msg = wxString::Format(_("Welcome to Audacity version %s"), AUDACITY_VERSION_STRING); - mStatusBar->SetStatusText(msg, 1); + mStatusBar->SetStatusText(msg, mainStatusBarField); + mStatusBar->SetStatusText(GetControlToolBar()->StateForStatusBar(), stateStatusBarField); mLastStatusUpdateTime = ::wxGetUTCTime(); mTimer = new wxTimer(this, AudacityProjectTimerID); @@ -3527,7 +3535,7 @@ bool AudacityProject::Save(bool overwrite /* = true */ , wxRemoveFile(safetyFileName); mStatusBar->SetStatusText(wxString::Format(_("Saved %s"), - mFileName.c_str()), 1); + mFileName.c_str()), mainStatusBarField); return true; } @@ -4345,7 +4353,7 @@ void AudacityProject::OnTimer(wxTimerEvent& WXUNUSED(event)) else msg.Printf(_("Out of disk space")); - mStatusBar->SetStatusText(msg, 1); + mStatusBar->SetStatusText(msg, mainStatusBarField); } } else if(ODManager::IsInstanceCreated()) @@ -4366,7 +4374,7 @@ void AudacityProject::OnTimer(wxTimerEvent& WXUNUSED(event)) msg.Printf(_("On-demand import and waveform calculation complete.")); - mStatusBar->SetStatusText(msg, 1); + mStatusBar->SetStatusText(msg, mainStatusBarField); } else if(numTasks>1) @@ -4377,7 +4385,7 @@ void AudacityProject::OnTimer(wxTimerEvent& WXUNUSED(event)) ratioComplete*100.0); - mStatusBar->SetStatusText(msg, 1); + mStatusBar->SetStatusText(msg, mainStatusBarField); } } } @@ -4566,7 +4574,7 @@ void AudacityProject::EditClipboardByLabel( WaveTrack::EditDestFunction action ) // TrackPanel callback method void AudacityProject::TP_DisplayStatusMessage(wxString msg) { - mStatusBar->SetStatusText(msg, 1); + mStatusBar->SetStatusText(msg, mainStatusBarField); mLastStatusUpdateTime = ::wxGetUTCTime(); } @@ -4813,9 +4821,9 @@ void AudacityProject::OnAudioIORate(int rate) display = wxString::Format(_("Actual Rate: %d"), rate); int x, y; mStatusBar->GetTextExtent(display, &x, &y); - int widths[] = {GetControlToolBar()->WidthForStatusBar(), -1, x+50}; - mStatusBar->SetStatusWidths(3, widths); - mStatusBar->SetStatusText(display, 2); + int widths[] = {0, GetControlToolBar()->WidthForStatusBar(mStatusBar), -1, x+50}; + mStatusBar->SetStatusWidths(4, widths); + mStatusBar->SetStatusText(display, rateStatusBarField); } void AudacityProject::OnAudioIOStartRecording() diff --git a/src/Project.h b/src/Project.h index 6029aa1fc..9afa280ec 100644 --- a/src/Project.h +++ b/src/Project.h @@ -109,6 +109,12 @@ enum PlayMode { loopedPlay }; +enum StatusBarField { + stateStatusBarField = 1, + mainStatusBarField = 2, + rateStatusBarField = 3 +}; + // XML handler for tag class ImportXMLTagHandler : public XMLTagHandler { diff --git a/src/Screenshot.cpp b/src/Screenshot.cpp index 0ac22fabf..890416132 100644 --- a/src/Screenshot.cpp +++ b/src/Screenshot.cpp @@ -563,7 +563,7 @@ void ScreenFrame::DoCapture(wxString captureMode) mCommand->SetParameter(wxT("CaptureMode"), captureMode); if (!mCommand->Apply(mContext)) - mStatus->SetStatusText(wxT("Capture failed!"), 1); + mStatus->SetStatusText(wxT("Capture failed!"), mainStatusBarField); Show(); } diff --git a/src/commands/CommandTargets.h b/src/commands/CommandTargets.h index ec3034290..ad158d358 100644 --- a/src/commands/CommandTargets.h +++ b/src/commands/CommandTargets.h @@ -117,7 +117,7 @@ public: {} virtual void Update(wxString message) { - mStatus.SetStatusText(message, 1); + mStatus.SetStatusText(message, mainStatusBarField); } }; diff --git a/src/toolbars/ControlToolBar.cpp b/src/toolbars/ControlToolBar.cpp index 2bf614f76..9c732e6a7 100644 --- a/src/toolbars/ControlToolBar.cpp +++ b/src/toolbars/ControlToolBar.cpp @@ -1082,13 +1082,8 @@ void ControlToolBar::ClearCutPreviewTracks() } // works out the width of the field in the status bar needed for the state (eg play, record pause) -int ControlToolBar::WidthForStatusBar() +int ControlToolBar::WidthForStatusBar(wxStatusBar* const sb) { - AudacityProject* p = GetActiveProject(); - if (!p) - return 100; // dummy value to keep things happy before the project is fully created - - wxStatusBar* sb = p->GetStatusBar(); int xMax = 0; int x, y; @@ -1110,7 +1105,7 @@ int ControlToolBar::WidthForStatusBar() return xMax + 30; // added constant needed because xMax isn't large enough for some reason, plus some space. } -void ControlToolBar::UpdateStatusBar() +wxString ControlToolBar::StateForStatusBar() { wxString state; @@ -1129,6 +1124,11 @@ void ControlToolBar::UpdateStatusBar() state.Append(wxT(".")); - GetActiveProject()->GetStatusBar()->SetStatusText(state); + return state; +} + +void ControlToolBar::UpdateStatusBar() +{ + GetActiveProject()->GetStatusBar()->SetStatusText(StateForStatusBar(), stateStatusBarField); } diff --git a/src/toolbars/ControlToolBar.h b/src/toolbars/ControlToolBar.h index 2c754a4f4..7245a85c6 100644 --- a/src/toolbars/ControlToolBar.h +++ b/src/toolbars/ControlToolBar.h @@ -85,7 +85,8 @@ class ControlToolBar:public ToolBar { virtual void ReCreateButtons(); void RegenerateToolsTooltips(); - int WidthForStatusBar(); + int WidthForStatusBar(wxStatusBar* const); + wxString StateForStatusBar(); private: From a4cc294158c5117fc728d8e1a255bb45452b54e7 Mon Sep 17 00:00:00 2001 From: David Bailes Date: Tue, 2 Jun 2015 15:50:08 +0100 Subject: [PATCH 05/10] state field in status bar. Previous commit caused linux build to fail. Included a file to hopefully fix. --- src/commands/CommandTargets.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/commands/CommandTargets.h b/src/commands/CommandTargets.h index ad158d358..ffdf70510 100644 --- a/src/commands/CommandTargets.h +++ b/src/commands/CommandTargets.h @@ -27,6 +27,7 @@ should be reference-counted. #include #include "../widgets/ProgressDialog.h" #include "../commands/ResponseQueue.h" +#include "../src/Project.h" /// Interface for objects that can receive command progress information class CommandProgressTarget From a25a8f8f26f2d6ea3477e64d73a5f170d0a798b5 Mon Sep 17 00:00:00 2001 From: David Bailes Date: Tue, 2 Jun 2015 16:21:51 +0100 Subject: [PATCH 06/10] state field of status bar. Previous commit failed to build on linux (again). Added forward declaration of class wxStatusBar to ControlBar.h. --- src/toolbars/ControlToolBar.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/toolbars/ControlToolBar.h b/src/toolbars/ControlToolBar.h index 7245a85c6..c9a27c650 100644 --- a/src/toolbars/ControlToolBar.h +++ b/src/toolbars/ControlToolBar.h @@ -24,6 +24,7 @@ class wxKeyEvent; class wxTimer; class wxTimerEvent; class wxWindow; +class wxStatusBar; class AButton; class AudacityProject; From 7d359ef0100dc726c66fcc22d2302347412cfd12 Mon Sep 17 00:00:00 2001 From: Leland Lucius Date: Tue, 2 Jun 2015 15:06:52 -0500 Subject: [PATCH 07/10] Fix bug #923 and allow for varying decimal sepatators in settings --- include/audacity/EffectAutomationParameters.h | 45 ++++-- src/effects/VST/VSTEffect.cpp | 54 ++++--- src/effects/audiounits/AudioUnitEffect.cpp | 132 +++--------------- src/effects/ladspa/LadspaEffect.cpp | 32 ++--- src/effects/lv2/LV2Effect.cpp | 30 ++-- 5 files changed, 107 insertions(+), 186 deletions(-) diff --git a/include/audacity/EffectAutomationParameters.h b/include/audacity/EffectAutomationParameters.h index 56a813581..0f6b519a8 100644 --- a/include/audacity/EffectAutomationParameters.h +++ b/include/audacity/EffectAutomationParameters.h @@ -44,6 +44,7 @@ #include #include +#include class EffectAutomationParameters : public wxFileConfig { @@ -82,6 +83,22 @@ public: return wxFileConfig::DoReadLong(NormalizeName(key), pl); } + virtual bool DoReadDouble(const wxString & key, double *pd) const + { + wxString str; + if (Read(key, &str)) + { + wxString dec = wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER); + + str.Replace(wxT(","), dec); + str.Replace(wxT("."), dec); + + return str.ToDouble(pd); + } + + return false; + } + virtual bool DoWriteString(const wxString & key, const wxString & szValue) { return wxFileConfig::DoWriteString(NormalizeName(key), szValue); @@ -94,7 +111,7 @@ public: virtual bool DoWriteDouble(const wxString & key, double value) { - return DoWriteString(key, wxString::Format(wxT("%.12g"), value)); + return DoWriteString(key, wxString::Format(wxT("%.12f"), value)); } bool ReadFloat(const wxString & key, float *pf) const @@ -209,19 +226,6 @@ public: return (*val != wxNOT_FOUND); } - wxString NormalizeName(const wxString & name) const - { - wxString cleaned = name; - - cleaned.Trim(true).Trim(false); - cleaned.Replace(wxT(" "), wxT("_")); - cleaned.Replace(wxT("/"), wxT("_")); - cleaned.Replace(wxT("\\"), wxT("_")); - cleaned.Replace(wxT(":"), wxT("_")); - - return cleaned; - } - bool GetParameters(wxString & parms) { wxFileConfig::SetPath(wxT("/")); @@ -270,6 +274,19 @@ public: return true; } + wxString NormalizeName(const wxString & name) const + { + wxString cleaned = name; + + cleaned.Trim(true).Trim(false); + cleaned.Replace(wxT(" "), wxT("_")); + cleaned.Replace(wxT("/"), wxT("_")); + cleaned.Replace(wxT("\\"), wxT("_")); + cleaned.Replace(wxT(":"), wxT("_")); + + return cleaned; + } + wxString Escape(wxString val) { val.Replace(wxT("\\"), wxT("\\\\"), true); diff --git a/src/effects/VST/VSTEffect.cpp b/src/effects/VST/VSTEffect.cpp index c51f8e3c4..4cd7e7531 100644 --- a/src/effects/VST/VSTEffect.cpp +++ b/src/effects/VST/VSTEffect.cpp @@ -2090,6 +2090,8 @@ bool VSTEffect::GetAutomationParameters(EffectAutomationParameters & parms) bool VSTEffect::SetAutomationParameters(EffectAutomationParameters & parms) { + size_t slaveCnt = mSlaves.GetCount(); + callDispatcher(effBeginSetProgram, 0, 0, NULL, 0.0); for (int i = 0; i < mAEffect->numParams; i++) { @@ -2105,7 +2107,14 @@ bool VSTEffect::SetAutomationParameters(EffectAutomationParameters & parms) return false; } - callSetParameter(i, d); + if (d >= -1.0 && d <= 1.0) + { + callSetParameter(i, d); + for (size_t i = 0; i < slaveCnt; i++) + { + mSlaves[i]->callSetParameter(i, d); + } + } } callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0); @@ -2797,38 +2806,19 @@ bool VSTEffect::LoadParameters(const wxString & group) return true; } - if (!mHost->GetPrivateConfig(group, wxT("Value"), value, wxEmptyString)) + wxString parms; + if (!mHost->GetPrivateConfig(group, wxT("Parameters"), parms, wxEmptyString)) { return false; } - if (callDispatcher(effBeginLoadProgram, 0, 0, &info, 0.0) == -1) + EffectAutomationParameters eap; + if (!eap.SetParameters(parms)) { return false; } - callDispatcher(effBeginSetProgram, 0, 0, NULL, 0.0); - size_t cnt = mSlaves.GetCount(); - - wxStringTokenizer st(value, wxT(',')); - for (int i = 0; st.HasMoreTokens(); i++) - { - double val = 0.0; - st.GetNextToken().ToDouble(&val); - - if (val >= -1.0 && val <= 1.0) - { - callSetParameter(i, val); - for (size_t i = 0; i < cnt; i++) - { - mSlaves[i]->callSetParameter(i, val); - } - } - } - - callDispatcher(effEndSetProgram, 0, 0, NULL, 0.0); - - return true; + return SetAutomationParameters(eap); } bool VSTEffect::SaveParameters(const wxString & group) @@ -2850,13 +2840,19 @@ bool VSTEffect::SaveParameters(const wxString & group) return true; } - wxString parms; - for (int i = 0; i < mAEffect->numParams; i++) + EffectAutomationParameters eap; + if (!GetAutomationParameters(eap)) { - parms += wxString::Format(wxT(",%f"), callGetParameter(i)); + return false; } - return mHost->SetPrivateConfig(group, wxT("Value"), parms.Mid(1)); + wxString parms; + if (!eap.GetParameters(parms)) + { + return false; + } + + return mHost->SetPrivateConfig(group, wxT("Parameters"), parms); } void VSTEffect::OnTimer() diff --git a/src/effects/audiounits/AudioUnitEffect.cpp b/src/effects/audiounits/AudioUnitEffect.cpp index 322fd470c..71380be96 100644 --- a/src/effects/audiounits/AudioUnitEffect.cpp +++ b/src/effects/audiounits/AudioUnitEffect.cpp @@ -1738,6 +1738,13 @@ bool AudioUnitEffect::SetAutomationParameters(EffectAutomationParameters & parms delete [] array; + AudioUnitParameter aup; + aup.mAudioUnit = mUnit; + aup.mParameterID = kAUParameterListener_AnyParameter; + aup.mScope = kAudioUnitScope_Global; + aup.mElement = 0; + AUParameterListenerNotify(NULL, NULL, &aup); + return true; } @@ -2163,135 +2170,36 @@ void AudioUnitEffect::RemoveHandler() bool AudioUnitEffect::LoadParameters(const wxString & group) { - OSStatus result; - UInt32 dataSize; - Boolean isWritable; - - wxString value; - if (!mHost->GetPrivateConfig(group, wxT("Value"), value, wxEmptyString)) - { - return false; - } - wxStringTokenizer tokens(value, wxT(',')); - - result = AudioUnitGetPropertyInfo(mUnit, - kAudioUnitProperty_ParameterList, - kAudioUnitScope_Global, - 0, - &dataSize, - &isWritable); - if (result != noErr) + wxString parms; + if (!mHost->GetPrivateConfig(group, wxT("Parameters"), parms, wxEmptyString)) { return false; } - UInt32 cnt = dataSize / sizeof(AudioUnitParameterID); - - if (cnt != tokens.CountTokens()) + EffectAutomationParameters eap; + if (!eap.SetParameters(parms)) { return false; } - AudioUnitParameterID *array = new AudioUnitParameterID[cnt]; - - result = AudioUnitGetProperty(mUnit, - kAudioUnitProperty_ParameterList, - kAudioUnitScope_Global, - 0, - array, - &dataSize); - if (result != noErr) - { - delete [] array; - return false; - } - - for (int i = 0; i < cnt; i++) - { - double d = 0.0; - tokens.GetNextToken().ToDouble(&d); - - AudioUnitParameterValue value = d; - result = AudioUnitSetParameter(mUnit, - array[i], - kAudioUnitScope_Global, - 0, - value, - 0); - if (result != noErr) - { - delete [] array; - return false; - } - } - - AudioUnitParameter aup; - aup.mAudioUnit = mUnit; - aup.mParameterID = kAUParameterListener_AnyParameter; - aup.mScope = kAudioUnitScope_Global; - aup.mElement = 0; - AUParameterListenerNotify(NULL, NULL, &aup); - - delete [] array; - - return true; + return SetAutomationParameters(eap); } bool AudioUnitEffect::SaveParameters(const wxString & group) { - OSStatus result; - UInt32 dataSize; - Boolean isWritable; + EffectAutomationParameters eap; + if (!GetAutomationParameters(eap)) + { + return false; + } + wxString parms; - - result = AudioUnitGetPropertyInfo(mUnit, - kAudioUnitProperty_ParameterList, - kAudioUnitScope_Global, - 0, - &dataSize, - &isWritable); - if (result != noErr) + if (!eap.GetParameters(parms)) { return false; } - UInt32 cnt = dataSize / sizeof(AudioUnitParameterID); - AudioUnitParameterID *array = new AudioUnitParameterID[cnt]; - - result = AudioUnitGetProperty(mUnit, - kAudioUnitProperty_ParameterList, - kAudioUnitScope_Global, - 0, - array, - &dataSize); - if (result != noErr) - { - delete [] array; - return false; - } - - for (int i = 0; i < cnt; i++) - { - AudioUnitParameterValue value; - result = AudioUnitGetParameter(mUnit, - array[i], - kAudioUnitScope_Global, - 0, - &value); - if (result != noErr) - { - delete [] array; - return false; - } - - parms += wxString::Format(wxT(",%f"), value); - } - - mHost->SetPrivateConfig(group, wxT("Value"), parms.Mid(1)); - - delete [] array; - - return true; + return mHost->SetPrivateConfig(group, wxT("Parameters"), parms); } bool AudioUnitEffect::SetRateAndChannels() diff --git a/src/effects/ladspa/LadspaEffect.cpp b/src/effects/ladspa/LadspaEffect.cpp index cb5a83ab5..403275a15 100644 --- a/src/effects/ladspa/LadspaEffect.cpp +++ b/src/effects/ladspa/LadspaEffect.cpp @@ -1539,38 +1539,36 @@ void LadspaEffect::Unload() bool LadspaEffect::LoadParameters(const wxString & group) { - wxString value; - - if (!mHost->GetPrivateConfig(group, wxT("Value"), value, wxEmptyString)) + wxString parms; + if (!mHost->GetPrivateConfig(group, wxT("Parameters"), parms, wxEmptyString)) { return false; } - wxStringTokenizer st(value, wxT(',')); - if (st.CountTokens() != mData->PortCount) + EffectAutomationParameters eap; + if (!eap.SetParameters(parms)) { return false; } - for (unsigned long p = 0; st.HasMoreTokens(); p++) - { - double val = 0.0; - st.GetNextToken().ToDouble(&val); - mInputControls[p] = val; - } - - return true; + return SetAutomationParameters(eap); } bool LadspaEffect::SaveParameters(const wxString & group) { - wxString parms; - for (unsigned long p = 0; p < mData->PortCount; p++) + EffectAutomationParameters eap; + if (!GetAutomationParameters(eap)) { - parms += wxString::Format(wxT(",%f"), mInputControls[p]); + return false; } - return mHost->SetPrivateConfig(group, wxT("Value"), parms.Mid(1)); + wxString parms; + if (!eap.GetParameters(parms)) + { + return false; + } + + return mHost->SetPrivateConfig(group, wxT("Parameters"), parms); } LADSPA_Handle LadspaEffect::InitInstance(float sampleRate) diff --git a/src/effects/lv2/LV2Effect.cpp b/src/effects/lv2/LV2Effect.cpp index 318d0d9d2..714148e9f 100644 --- a/src/effects/lv2/LV2Effect.cpp +++ b/src/effects/lv2/LV2Effect.cpp @@ -1282,34 +1282,36 @@ void LV2Effect::ShowOptions() bool LV2Effect::LoadParameters(const wxString & group) { - wxString value; - - if (!mHost->GetPrivateConfig(group, wxT("Value"), value, wxEmptyString)) + wxString parms; + if (!mHost->GetPrivateConfig(group, wxT("Parameters"), parms, wxEmptyString)) { return false; } - wxStringTokenizer st(value, wxT(',')); - for (size_t p = 0; st.HasMoreTokens(); p++) + EffectAutomationParameters eap; + if (!eap.SetParameters(parms)) { - double val = 0.0; - st.GetNextToken().ToDouble(&val); - mControls[p].mVal = (float) val; + return false; } - return true; + return SetAutomationParameters(eap); } bool LV2Effect::SaveParameters(const wxString & group) { - wxString parms; - - for (size_t i = 0, cnt = mControls.GetCount(); i < cnt; i++) + EffectAutomationParameters eap; + if (!GetAutomationParameters(eap)) { - parms += wxString::Format(wxT(",%f"), mControls[i].mVal); + return false; } - return mHost->SetPrivateConfig(group, wxT("Value"), parms.Mid(1)); + wxString parms; + if (!eap.GetParameters(parms)) + { + return false; + } + + return mHost->SetPrivateConfig(group, wxT("Parameters"), parms); } LV2_Options_Option *LV2Effect::AddOption(const char *key, uint32_t size, const char *type, void *value) From 4363b69c172dd685eb91a395a718f462d116a5c0 Mon Sep 17 00:00:00 2001 From: James Crook Date: Tue, 2 Jun 2015 23:20:30 +0100 Subject: [PATCH 08/10] Bug 974 - Register Effects GUI instructions are incorrect. I've changed the wording to give just enough information to be able to use the new interface. Mainly to close this P1 bug, and so not block proceeding to release. --- src/PluginManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PluginManager.cpp b/src/PluginManager.cpp index 93fdd57a5..8891d944d 100644 --- a/src/PluginManager.cpp +++ b/src/PluginManager.cpp @@ -516,7 +516,7 @@ void PluginRegistrationDialog::PopulateOrExchange(ShuttleGui &S) { /*i18n-hint: The dialog shows a list of plugins with check-boxes beside each one.*/ - S.StartStatic(_("Select Plugins then press ENTER to Install"), true); + S.StartStatic(_("Select Plugins, click the Enable or Disable button, then click OK."), true); { S.StartHorizontalLay(wxALIGN_LEFT,0 ); { From b68d716e7304cfe8e97e7ac435d244cc6259d372 Mon Sep 17 00:00:00 2001 From: Steve Daulton Date: Tue, 2 Jun 2015 22:28:29 +0100 Subject: [PATCH 09/10] Add Limiter and Crossfade Clips effects. --- Makefile.am | 2 + plug-ins/crossfadeclips.ny | 130 +++++++++++++++++++++++++++++++++++ plug-ins/limiter.ny | 134 +++++++++++++++++++++++++++++++++++++ 3 files changed, 266 insertions(+) create mode 100644 plug-ins/crossfadeclips.ny create mode 100644 plug-ins/limiter.ny diff --git a/Makefile.am b/Makefile.am index 749d335dd..8b2d65f7d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -62,10 +62,12 @@ nobase_dist_pkgdata_DATA = \ plug-ins/beat.ny \ plug-ins/clicktrack.ny \ plug-ins/clipfix.ny \ + plug-ins/crossfadeclips.ny \ plug-ins/crossfadetracks.ny \ plug-ins/delay.ny \ plug-ins/equalabel.ny \ plug-ins/highpass.ny \ + plug-ins/limiter.ny \ plug-ins/lowpass.ny \ plug-ins/notch.ny \ plug-ins/pluck.ny \ diff --git a/plug-ins/crossfadeclips.ny b/plug-ins/crossfadeclips.ny new file mode 100644 index 000000000..6548f0e7d --- /dev/null +++ b/plug-ins/crossfadeclips.ny @@ -0,0 +1,130 @@ +;nyquist plugin +;version 4 +;type process +;mergeclips 1 +;restoresplits 0 +;name "Crossfade Clips" +;action "Crossfading..." +;author "Steve Daulton" +;copyright "Released under terms of the GNU General Public License version 2" + + +;; crossfadeclips.ny by Steve Daulton Dec 2014. +;; Released under terms of the GNU General Public License version 2: +;; http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + +;; Instructions: +;; Place two audio clips into the same track. +;; Select (approximately) the same amount of audio from the +;; end of one clip and the start of the other. +;; Apply the effect. +;; The selected regions will be crossfaded. +;; +;; Note, the audio clips do not need to be touching. Any +;; white-space between the clips is ignored. +;; +;; If the selected region is continuous audio (no splits), +;; the the first and last halves of the selected audio +;; will be crossfaded. +;; +;; Advanced Tip: +;; A discontinuity in a waveform may be smoothed by applying +;; a short crossfade across the glitch. + +;; Limitations (should not occur in normal usage). +;; 1) There may be no more than two clips selected in each channel. +;; 2) The selection may not start or end in white-space. + + +(setf err1 "Error.\nInvalid selection.\nMore than 2 audio clips selected.") +(setf err2 "Error.\nInvalid selection.\nEmpty space at start/ end of the selection.") + + +(defun find-ends (T0 T1 clips) +"Look for a split or gap within the selection, or return the mid-point" + (let ((trk-ends ()) ;starts of clips + (trk-starts ())) ;ends of clips + (dolist (clip clips) + ;; look for clip enclosing the selection. + (when (and (>= (second clip) T1) (<= (first clip) T0)) + (psetq trk-ends (list (/ (+ T0 T1) 2)) + trk-starts (list (/ (+ T0 T1) 2))) + (return)) + ;; look for track starts. + (when (and (> (first clip) T0) (< (first clip) T1)) + (push (first clip) trk-starts)) + ;; look for track ends. + (when (and (> (second clip) T0) (< (second clip) T1)) + (push (second clip) trk-ends)) + ; stop looking when we have passed end of selection. + (when (> (first clip) T1) (return))) + ;; if exactly one split position for crossfading, + ;; return clip positions, else error. + (cond + ((and (= (length trk-ends) 1) + (= (length trk-starts) 1) + (<= (car trk-ends) (car trk-starts))) + (list (car trk-ends)(car trk-starts))) + ((or (> (length trk-ends) 1) + (> (length trk-starts) 1)) + (throw 'error err1)) + (T (throw 'error err2))))) + +(defun crossfade (sig out-end in-start end) +"Do the crossfade" + (abs-env + (control-srate-abs *sound-srate* + (let* ((fade-out (mult sig (env out-end 0))) + (cflen (max out-end (- end in-start))) ;crossfade length + (finstart (max (- out-end (- end in-start)) 0)) + (fade-in (mult (extract (- end cflen) end sig) + (env (- cflen finstart) 1 finstart)))) + (sim fade-out fade-in))))) + +(defun env (dur direction &optional (offset 0)) +"Generate envelope for crossfade" + (abs-env + (if (< dur 0.01) ;make it linear + (control-srate-abs *sound-srate* + (if (= direction 0) + (pwlv 1 dur 0) ;fade out + (pwlv 0 offset 0 (+ offset dur) 1))) ;fade in + (if (= direction 0) ;cosine curve + (cos-curve dur 0) + (seq (s-rest offset) + (cos-curve dur 1)))))) + +(defun cos-curve (dur direction) +"Generate cosine curve" + (if (= direction 0) ;fade out + (osc (hz-to-step (/ 0.25 dur)) dur *sine-table* 90) + (osc (hz-to-step (/ 0.25 dur)) dur *sine-table* 0))) + +(defun process (sig t0 t1 clips) +"Find the split positions and crossfade" + (setf fadeclips + (multichan-expand #'find-ends t0 t1 clips)) + (if (arrayp fadeclips) + (prog ((fade-out-end (min (first (aref fadeclips 0)) + (first (aref fadeclips 1)))) + (fade-in-start (max (second (aref fadeclips 0)) + (second (aref fadeclips 1))))) + (return + (multichan-expand #'crossfade sig + (- fade-out-end t0) + (- fade-in-start t0) + (- t1 t0)))) + (crossfade sig + (- (first fadeclips) t0) + (- (second fadeclips) t0) + (- t1 t0)))) + + +;;; Run the program. +(if (= (length (get '*selection* 'tracks)) 1) + (catch 'error + (process *track* + (get '*selection* 'start) + (get '*selection* 'end) + (get '*track* 'clips))) + "Error.\nCrossfade Clips may only be applied to one track.") diff --git a/plug-ins/limiter.ny b/plug-ins/limiter.ny new file mode 100644 index 000000000..4d0d2a655 --- /dev/null +++ b/plug-ins/limiter.ny @@ -0,0 +1,134 @@ +;nyquist plug-in +;version 4 +;type process +;categories "http://lv2plug.in/ns/lv2core/#DynamicsPlugin" +;name "Limiter..." +;action "Limiting..." +;preview enabled +;author "Steve Daulton" +;copyright "Released under terms of the GNU General Public License version 2" + +;; limiter.ny by Steve Daulton November 2011, updated May 2015. +;; Released under terms of the GNU General Public License version 2: +;; http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +;; +;; For information about writing and modifying Nyquist plug-ins: +;; http://wiki.audacityteam.org/wiki/Nyquist_Plug-ins_Reference + +;control type "Type" choice "Soft Limit,Hard Limit,Soft Clip,Hard Clip" 0 +;control gain-L "Input Gain (dB)\nmono/Left" real "" 0 0 10 +;control gain-R "Input Gain (dB)\nRight channel" real "" 0 0 10 +;control thresh "Limit to (dB)" real "" -3 -10 0 +;control hold "Hold (ms)" real "" 10 1 50 +;control makeup "Apply Make-up Gain" choice "No,Yes" 0 + +(if (not (boundp 'type)) + (setf type 0)) + +(if (boundp 'gain-L) + (setf gain-L (db-to-linear gain-L)) + (setf gain-L 1)) + +(if (boundp 'gain-R) + (setf gain-R (db-to-linear gain-R)) + (setf gain-R 1)) + +(if (boundp 'thresh) + (setf thresh (db-to-linear thresh)) + (setf thresh (db-to-linear -3.0))) + +(if (not (boundp 'hold)) + (setf hold 10.0)) + +(if (boundp 'makeup) + (if (= makeup 1) (setf makeup T) (setf makeup nil)) + (setf makeup nil)) + +;;; brick wall limiter +(defun hardlimit (sig limit hld) + (let* ((time (/ hld 3000.0)) ; lookahead time (seconds) + (samples (round (* time *sound-srate*))) ; lookahead in samples + (peak-env (get-env sig samples time limit))) + (mult sig + (snd-exp + (mult -1 (snd-log peak-env)))))) + +;;; Envelope follower for brick wall limiter +(defun get-env (sig step lookahead limit) + (let* ((sig (mult (/ limit) sig)) + (pad-time (* 3 lookahead)) ; padding required at start (seconds) + (pad-s (* 3 step)) ; padding smaples + (padding (snd-const (peak sig pad-s) 0 *sound-srate* pad-time)) + (peak-env (snd-avg sig (* 4 step) step OP-PEAK))) + (extract 0 1 + (s-max 1 + (sim padding + (at-abs pad-time (cue peak-env))))))) + +(defun softlimit (sig thresh hld) + (let* ((sig (hardlimit sig 1 hold)) + (step (truncate (* (/ hld 3000.0) *sound-srate*))) + (waveshape (snd-avg sig (* 4 step) step op-peak)) + (env (sum thresh (mult thresh (diff 1 waveshape)))) + (env (clip env 1)) + (offset (/ (* 3 step) *sound-srate*)) + (initial (peak sig (* 2 step))) + (pause-lev (sum thresh (mult thresh (diff 1 initial)))) + (pause-lev (clip pause-lev 0.9)) + (pause (snd-const pause-lev 0 *sound-srate* offset))) + (setf env + (sim + pause + (at-abs offset (cue env)))) + (mult sig env))) + + +(defun soft-clip-table () +"Lookup table for soft clipping wave-shaper" + (abs-env + (Control-srate-abs *sound-srate* + (let* ((knee (- 1 (/ 1.0 pi))) + (kcurve (mult knee (osc (hz-to-step (/ (* 4 knee))) knee))) + (ikcurve (mult knee (osc (hz-to-step (/ (* 4 knee))) knee *sine-table* -90))) + (lin (pwlv -0.5 knee -0.5 + (+ knee (/ 2.0 pi)) 0.5 + 2.0 0.5 + 2.0 (+ 0.5 knee) + 2.1 (+ 0.5 knee)))) + (mult (/ 2.0 pi) + (sim + (at-abs 0 (cue ikcurve)) + (at-abs 0 (cue lin)) + (at-abs (+ knee (/ 2.0 pi)) (cue kcurve)))))))) + +(defun soft-clip (sig) + (let* ((knee (- 1 (/ 1.0 pi))) + (clip-level (* (+ 0.5 knee)(/ 2.0 pi))) + (sig (mult clip-level (/ thresh) sig))) + (if makeup + (mult 0.999 + (/ clip-level) + (shape sig (soft-clip-table) 1.0)) + (mult thresh + (/ clip-level) + (shape sig (soft-clip-table) 1.0))))) + + +(defun makupgain (sig) + (if makeup + (mult (/ 0.999 thresh) sig) ;keep below 0dB + sig)) + +;; Pre-gain +(setf *track* + (if (arrayp *track*) + (vector (mult (aref *track* 0) gain-L) + (mult (aref *track* 1) gain-R)) + (mult *track* gain-L))) + + +(case type + (0 (makupgain (multichan-expand #'softlimit *track* thresh hold))) + (1 (makupgain (multichan-expand #'hardlimit *track* thresh hold))) + (2 (soft-clip *track*)) + (T (makupgain (clip *track* thresh)))) From dad2a56764a7f9c65c0625350475233fa372e27c Mon Sep 17 00:00:00 2001 From: Steve Daulton Date: Tue, 2 Jun 2015 22:32:54 +0100 Subject: [PATCH 10/10] Ran aclocal and automake as per Leland's instructions. --- Makefile.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile.in b/Makefile.in index 121aa0a59..8d6acc53f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -534,10 +534,12 @@ nobase_dist_pkgdata_DATA = \ plug-ins/beat.ny \ plug-ins/clicktrack.ny \ plug-ins/clipfix.ny \ + plug-ins/crossfadeclips.ny \ plug-ins/crossfadetracks.ny \ plug-ins/delay.ny \ plug-ins/equalabel.ny \ plug-ins/highpass.ny \ + plug-ins/limiter.ny \ plug-ins/lowpass.ny \ plug-ins/notch.ny \ plug-ins/pluck.ny \