audacia/src/effects/Effect.cpp

4045 lines
100 KiB
C++
Raw Normal View History

/**********************************************************************
Audacity: A Digital Audio Editor
Effect.cpp
Dominic Mazzoni
Vaughan Johnson
Martyn Shaw
*******************************************************************//**
\class Effect
\brief Base class for many of the effects in Audacity.
*//****************************************************************//**
\class EffectDialog
2014-06-03 20:30:19 +00:00
\brief New (Jun-2006) base class for effects dialogs. Likely to get
greater use in future.
*//*******************************************************************/
#include "../Audacity.h"
#include "Effect.h"
#include <algorithm>
#include <wx/defs.h>
#include <wx/hashmap.h>
#include <wx/msgdlg.h>
#include <wx/sizer.h>
#include <wx/stockitem.h>
#include <wx/string.h>
#include <wx/tglbtn.h>
#include <wx/timer.h>
#include <wx/utils.h>
#include <wx/log.h>
#include "audacity/ConfigInterface.h"
#include "../AudacityException.h"
#include "../AudioIO.h"
#include "../LabelTrack.h"
#include "../Mix.h"
#include "../Prefs.h"
#include "../Project.h"
#include "../ShuttleGui.h"
#include "../WaveTrack.h"
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
#include "../toolbars/ControlToolBar.h"
#include "../widgets/AButton.h"
#include "../widgets/ProgressDialog.h"
#include "../ondemand/ODManager.h"
#include "TimeWarper.h"
#include "nyquist/Nyquist.h"
2017-05-15 21:00:33 +00:00
#include "../widgets/HelpSystem.h"
#include "../widgets/LinkingHtmlWindow.h"
#include "../widgets/ErrorDialog.h"
#include "../FileNames.h"
#if defined(__WXMAC__)
#include <Cocoa/Cocoa.h>
#endif
#include "../Experimental.h"
static const int kDummyID = 20000;
static const int kSaveAsID = 20001;
static const int kImportID = 20002;
static const int kExportID = 20003;
static const int kDefaultsID = 20004;
static const int kOptionsID = 20005;
static const int kUserPresetsDummyID = 20006;
static const int kDeletePresetDummyID = 20007;
static const int kMenuID = 20100;
static const int kEnableID = 20101;
static const int kPlayID = 20102;
static const int kRewindID = 20103;
static const int kFFwdID = 20104;
static const int kPlaybackID = 20105;
static const int kCaptureID = 20106;
static const int kUserPresetsID = 21000;
static const int kDeletePresetID = 22000;
static const int kFactoryPresetsID = 23000;
const wxString Effect::kUserPresetIdent = wxT("User Preset:");
const wxString Effect::kFactoryPresetIdent = wxT("Factory Preset:");
const wxString Effect::kCurrentSettingsIdent = wxT("<Current Settings>");
const wxString Effect::kFactoryDefaultsIdent = wxT("<Factory Defaults>");
WX_DECLARE_VOIDPTR_HASH_MAP( bool, t2bHash );
Effect::Effect()
{
mClient = NULL;
mTracks = NULL;
mOutputTracksType = Track::None;
mT0 = 0.0;
mT1 = 0.0;
mDuration = 0.0;
mIsPreview = false;
mIsLinearEffect = false;
mPreviewWithNotSelected = false;
mPreviewFullSelection = false;
mNumTracks = 0;
mNumGroups = 0;
mProgress = NULL;
mRealtimeSuspendLock.Enter();
mRealtimeSuspendCount = 1; // Effects are initially suspended
mRealtimeSuspendLock.Leave();
mUIParent = NULL;
mUIDialog = NULL;
mNumAudioIn = 0;
mNumAudioOut = 0;
mBufferSize = 0;
mBlockSize = 0;
mNumChannels = 0;
2015-04-22 20:55:58 +00:00
mUIDebug = false;
AudacityProject *p = GetActiveProject();
mProjectRate = p ? p->GetRate() : 44100;
mIsBatch = false;
}
Effect::~Effect()
{
if (mUIDialog)
{
mUIDialog->Close();
}
}
// EffectIdentInterface implementation
EffectType Effect::GetType()
{
if (mClient)
{
return mClient->GetType();
}
return EffectTypeNone;
}
wxString Effect::GetPath()
{
if (mClient)
{
return mClient->GetPath();
}
return BUILTIN_EFFECT_PREFIX + GetSymbol();
}
wxString Effect::GetSymbol()
{
if (mClient)
{
return mClient->GetSymbol();
}
return wxEmptyString;
}
wxString Effect::GetName()
{
if (mClient)
{
return mClient->GetName();
}
return GetSymbol();
}
wxString Effect::GetVendor()
{
if (mClient)
{
return mClient->GetVendor();
}
return XO("Audacity");
}
wxString Effect::GetVersion()
{
if (mClient)
{
return mClient->GetVersion();
}
return AUDACITY_VERSION_STRING;
}
wxString Effect::GetDescription()
{
if (mClient)
{
return mClient->GetDescription();
}
return wxEmptyString;
}
wxString Effect::GetFamily()
{
if (mClient)
{
return mClient->GetFamily();
}
return XO("Audacity");
}
bool Effect::IsInteractive()
{
if (mClient)
{
return mClient->IsInteractive();
}
return true;
}
bool Effect::IsDefault()
{
if (mClient)
{
return mClient->IsDefault();
}
return true;
}
bool Effect::IsLegacy()
{
if (mClient)
{
return false;
}
return true;
}
bool Effect::SupportsRealtime()
{
if (mClient)
{
return mClient->SupportsRealtime();
}
return false;
}
bool Effect::SupportsAutomation()
{
if (mClient)
{
return mClient->SupportsAutomation();
}
return true;
}
// EffectClientInterface implementation
bool Effect::SetHost(EffectHostInterface *host)
{
if (mClient)
{
return mClient->SetHost(host);
}
return true;
}
unsigned Effect::GetAudioInCount()
{
if (mClient)
{
return mClient->GetAudioInCount();
}
return 0;
}
unsigned Effect::GetAudioOutCount()
{
if (mClient)
{
return mClient->GetAudioOutCount();
}
return 0;
}
int Effect::GetMidiInCount()
{
if (mClient)
{
return mClient->GetMidiInCount();
}
return 0;
}
int Effect::GetMidiOutCount()
{
if (mClient)
{
return mClient->GetMidiOutCount();
}
return 0;
}
void Effect::SetSampleRate(double rate)
{
if (mClient)
{
mClient->SetSampleRate(rate);
}
mSampleRate = rate;
}
size_t Effect::SetBlockSize(size_t maxBlockSize)
{
if (mClient)
{
return mClient->SetBlockSize(maxBlockSize);
}
mBlockSize = maxBlockSize;
return mBlockSize;
}
sampleCount Effect::GetLatency()
{
if (mClient)
{
return mClient->GetLatency();
}
return 0;
}
size_t Effect::GetTailSize()
{
if (mClient)
{
return mClient->GetTailSize();
}
return 0;
}
bool Effect::IsReady()
{
if (mClient)
{
return mClient->IsReady();
}
return true;
}
bool Effect::ProcessInitialize(sampleCount totalLen, ChannelNames chanMap)
{
if (mClient)
{
return mClient->ProcessInitialize(totalLen, chanMap);
}
return true;
}
bool Effect::ProcessFinalize()
{
if (mClient)
{
return mClient->ProcessFinalize();
}
return true;
}
size_t Effect::ProcessBlock(float **inBlock, float **outBlock, size_t blockLen)
{
if (mClient)
{
return mClient->ProcessBlock(inBlock, outBlock, blockLen);
}
return 0;
}
bool Effect::RealtimeInitialize()
{
if (mClient)
{
mBlockSize = mClient->SetBlockSize(512);
return mClient->RealtimeInitialize();
}
mBlockSize = 512;
return false;
}
bool Effect::RealtimeAddProcessor(unsigned numChannels, float sampleRate)
{
if (mClient)
{
return mClient->RealtimeAddProcessor(numChannels, sampleRate);
}
return true;
}
bool Effect::RealtimeFinalize()
{
if (mClient)
{
return mClient->RealtimeFinalize();
}
return false;
}
bool Effect::RealtimeSuspend()
{
if (mClient)
{
if (mClient->RealtimeSuspend())
{
mRealtimeSuspendLock.Enter();
mRealtimeSuspendCount++;
mRealtimeSuspendLock.Leave();
return true;
}
return false;
}
mRealtimeSuspendLock.Enter();
mRealtimeSuspendCount++;
mRealtimeSuspendLock.Leave();
return true;
}
bool Effect::RealtimeResume()
{
if (mClient)
{
if (mClient->RealtimeResume())
{
mRealtimeSuspendLock.Enter();
mRealtimeSuspendCount--;
mRealtimeSuspendLock.Leave();
return true;
}
return false;
}
mRealtimeSuspendLock.Enter();
mRealtimeSuspendCount--;
mRealtimeSuspendLock.Leave();
return true;
}
bool Effect::RealtimeProcessStart()
{
if (mClient)
{
return mClient->RealtimeProcessStart();
}
return true;
}
size_t Effect::RealtimeProcess(int group,
float **inbuf,
float **outbuf,
size_t numSamples)
{
if (mClient)
{
return mClient->RealtimeProcess(group, inbuf, outbuf, numSamples);
}
return 0;
}
bool Effect::RealtimeProcessEnd()
{
if (mClient)
{
return mClient->RealtimeProcessEnd();
}
return true;
}
bool Effect::ShowInterface(wxWindow *parent, bool forceModal)
{
if (!IsInteractive())
{
return true;
}
if (mUIDialog)
{
if ( mUIDialog->Close(true) )
mUIDialog = nullptr;
return false;
}
if (mClient)
{
return mClient->ShowInterface(parent, forceModal);
}
// mUIDialog is null
auto cleanup = valueRestorer( mUIDialog );
mUIDialog = CreateUI(parent, this);
if (!mUIDialog)
{
return false;
}
mUIDialog->Layout();
mUIDialog->Fit();
mUIDialog->SetMinSize(mUIDialog->GetSize());
if (SupportsRealtime() && !forceModal)
{
mUIDialog->Show();
cleanup.release();
// Return false to bypass effect processing
return false;
}
bool res = mUIDialog->ShowModal() != 0;
return res;
}
bool Effect::GetAutomationParameters(EffectAutomationParameters & parms)
{
if (mClient)
{
return mClient->GetAutomationParameters(parms);
}
return true;
}
bool Effect::SetAutomationParameters(EffectAutomationParameters & parms)
{
if (mClient)
{
return mClient->SetAutomationParameters(parms);
}
return true;
}
bool Effect::LoadUserPreset(const wxString & name)
{
if (mClient)
{
return mClient->LoadUserPreset(name);
}
wxString parms;
if (!GetPrivateConfig(name, wxT("Parameters"), parms))
{
return false;
}
return SetAutomationParameters(parms);
}
bool Effect::SaveUserPreset(const wxString & name)
{
if (mClient)
{
return mClient->SaveUserPreset(name);
}
wxString parms;
if (!GetAutomationParameters(parms))
{
return false;
}
return SetPrivateConfig(name, wxT("Parameters"), parms);
}
wxArrayString Effect::GetFactoryPresets()
{
if (mClient)
{
return mClient->GetFactoryPresets();
}
return wxArrayString();
}
bool Effect::LoadFactoryPreset(int id)
{
if (mClient)
{
return mClient->LoadFactoryPreset(id);
}
return true;
}
bool Effect::LoadFactoryDefaults()
{
if (mClient)
{
return mClient->LoadFactoryDefaults();
}
return LoadUserPreset(GetFactoryDefaultsGroup());
}
// EffectUIClientInterface implementation
void Effect::SetHostUI(EffectUIHostInterface *WXUNUSED(host))
{
}
bool Effect::PopulateUI(wxWindow *parent)
{
mUIParent = parent;
mUIParent->PushEventHandler(this);
// LoadUserPreset(GetCurrentSettingsGroup());
ShuttleGui S(mUIParent, eIsCreating);
PopulateOrExchange(S);
mUIParent->SetMinSize(mUIParent->GetSizer()->GetMinSize());
return true;
}
bool Effect::IsGraphicalUI()
{
return false;
}
bool Effect::ValidateUI()
{
return mUIParent->Validate();
}
bool Effect::HideUI()
{
return true;
}
bool Effect::CloseUI()
{
2016-12-22 14:38:11 +00:00
if (mUIParent)
mUIParent->RemoveEventHandler(this);
mUIParent = NULL;
mUIDialog = NULL;
return true;
}
bool Effect::CanExportPresets()
{
return false;
}
void Effect::ExportPresets()
{
}
void Effect::ImportPresets()
{
}
bool Effect::HasOptions()
{
return false;
}
void Effect::ShowOptions()
{
}
// EffectHostInterface implementation
double Effect::GetDefaultDuration()
{
return 30.0;
}
double Effect::GetDuration()
{
if (mDuration < 0.0)
{
mDuration = 0.0;
}
return mDuration;
}
wxString Effect::GetDurationFormat()
{
return mDurationFormat;
}
2015-07-18 17:31:36 +00:00
wxString Effect::GetSelectionFormat()
{
return GetActiveProject()->GetSelectionFormat();
}
void Effect::SetDuration(double seconds)
{
if (seconds < 0.0)
{
seconds = 0.0;
}
if (GetType() == EffectTypeGenerate)
{
SetPrivateConfig(GetCurrentSettingsGroup(), wxT("LastUsedDuration"), seconds);
}
mDuration = seconds;
mIsSelection = false;
return;
}
bool Effect::Apply()
{
// This is absolute hackage...but easy and I can't think of another way just now.
//
// It should callback to the EffectManager to kick off the processing
return GetActiveProject()->OnEffect(GetID(), AudacityProject::OnEffectFlags::kConfigured);
}
void Effect::Preview()
{
Preview(false);
}
wxDialog *Effect::CreateUI(wxWindow *parent, EffectUIClientInterface *client)
{
Destroy_ptr<EffectUIHost> dlg
{ safenew EffectUIHost{ parent, this, client} };
if (dlg->Initialize())
{
// release() is safe because parent will own it
return dlg.release();
}
return NULL;
}
wxString Effect::GetUserPresetsGroup(const wxString & name)
{
wxString group = wxT("UserPresets");
if (!name.IsEmpty())
{
group += wxCONFIG_PATH_SEPARATOR + name;
}
return group;
}
wxString Effect::GetCurrentSettingsGroup()
{
return wxT("CurrentSettings");
}
wxString Effect::GetFactoryDefaultsGroup()
{
return wxT("FactoryDefaults");
}
wxString Effect::GetSavedStateGroup()
{
return wxT("SavedState");
}
// ConfigClientInterface implementation
bool Effect::HasSharedConfigGroup(const wxString & group)
{
return PluginManager::Get().HasSharedConfigGroup(GetID(), group);
}
bool Effect::GetSharedConfigSubgroups(const wxString & group, wxArrayString & subgroups)
{
return PluginManager::Get().GetSharedConfigSubgroups(GetID(), group, subgroups);
}
bool Effect::GetSharedConfig(const wxString & group, const wxString & key, wxString & value, const wxString & defval)
{
return PluginManager::Get().GetSharedConfig(GetID(), group, key, value, defval);
}
bool Effect::GetSharedConfig(const wxString & group, const wxString & key, int & value, int defval)
{
return PluginManager::Get().GetSharedConfig(GetID(), group, key, value, defval);
}
bool Effect::GetSharedConfig(const wxString & group, const wxString & key, bool & value, bool defval)
{
return PluginManager::Get().GetSharedConfig(GetID(), group, key, value, defval);
}
bool Effect::GetSharedConfig(const wxString & group, const wxString & key, float & value, float defval)
{
return PluginManager::Get().GetSharedConfig(GetID(), group, key, value, defval);
}
bool Effect::GetSharedConfig(const wxString & group, const wxString & key, double & value, double defval)
{
return PluginManager::Get().GetSharedConfig(GetID(), group, key, value, defval);
}
bool Effect::SetSharedConfig(const wxString & group, const wxString & key, const wxString & value)
{
return PluginManager::Get().SetSharedConfig(GetID(), group, key, value);
}
bool Effect::SetSharedConfig(const wxString & group, const wxString & key, const int & value)
{
return PluginManager::Get().SetSharedConfig(GetID(), group, key, value);
}
bool Effect::SetSharedConfig(const wxString & group, const wxString & key, const bool & value)
{
return PluginManager::Get().SetSharedConfig(GetID(), group, key, value);
}
bool Effect::SetSharedConfig(const wxString & group, const wxString & key, const float & value)
{
return PluginManager::Get().SetSharedConfig(GetID(), group, key, value);
}
bool Effect::SetSharedConfig(const wxString & group, const wxString & key, const double & value)
{
return PluginManager::Get().SetSharedConfig(GetID(), group, key, value);
}
bool Effect::RemoveSharedConfigSubgroup(const wxString & group)
{
return PluginManager::Get().RemoveSharedConfigSubgroup(GetID(), group);
}
bool Effect::RemoveSharedConfig(const wxString & group, const wxString & key)
{
return PluginManager::Get().RemoveSharedConfig(GetID(), group, key);
}
bool Effect::HasPrivateConfigGroup(const wxString & group)
{
return PluginManager::Get().HasPrivateConfigGroup(GetID(), group);
}
bool Effect::GetPrivateConfigSubgroups(const wxString & group, wxArrayString & subgroups)
{
return PluginManager::Get().GetPrivateConfigSubgroups(GetID(), group, subgroups);
}
bool Effect::GetPrivateConfig(const wxString & group, const wxString & key, wxString & value, const wxString & defval)
{
return PluginManager::Get().GetPrivateConfig(GetID(), group, key, value, defval);
}
bool Effect::GetPrivateConfig(const wxString & group, const wxString & key, int & value, int defval)
{
return PluginManager::Get().GetPrivateConfig(GetID(), group, key, value, defval);
}
bool Effect::GetPrivateConfig(const wxString & group, const wxString & key, bool & value, bool defval)
{
return PluginManager::Get().GetPrivateConfig(GetID(), group, key, value, defval);
}
bool Effect::GetPrivateConfig(const wxString & group, const wxString & key, float & value, float defval)
{
return PluginManager::Get().GetPrivateConfig(GetID(), group, key, value, defval);
}
bool Effect::GetPrivateConfig(const wxString & group, const wxString & key, double & value, double defval)
{
return PluginManager::Get().GetPrivateConfig(GetID(), group, key, value, defval);
}
bool Effect::SetPrivateConfig(const wxString & group, const wxString & key, const wxString & value)
{
return PluginManager::Get().SetPrivateConfig(GetID(), group, key, value);
}
bool Effect::SetPrivateConfig(const wxString & group, const wxString & key, const int & value)
{
return PluginManager::Get().SetPrivateConfig(GetID(), group, key, value);
}
bool Effect::SetPrivateConfig(const wxString & group, const wxString & key, const bool & value)
{
return PluginManager::Get().SetPrivateConfig(GetID(), group, key, value);
}
bool Effect::SetPrivateConfig(const wxString & group, const wxString & key, const float & value)
{
return PluginManager::Get().SetPrivateConfig(GetID(), group, key, value);
}
bool Effect::SetPrivateConfig(const wxString & group, const wxString & key, const double & value)
{
return PluginManager::Get().SetPrivateConfig(GetID(), group, key, value);
}
bool Effect::RemovePrivateConfigSubgroup(const wxString & group)
{
return PluginManager::Get().RemovePrivateConfigSubgroup(GetID(), group);
}
bool Effect::RemovePrivateConfig(const wxString & group, const wxString & key)
{
return PluginManager::Get().RemovePrivateConfig(GetID(), group, key);
}
// Effect implementation
PluginID Effect::GetID()
{
if (mClient)
{
return PluginManager::GetID(mClient);
}
return PluginManager::GetID(this);
}
bool Effect::Startup(EffectClientInterface *client)
{
// Let destructor know we need to be shutdown
mClient = client;
// Set host so client startup can use our services
if (!SetHost(this))
{
// Bail if the client startup fails
mClient = NULL;
return false;
}
mNumAudioIn = GetAudioInCount();
mNumAudioOut = GetAudioOutCount();
bool haveDefaults;
GetPrivateConfig(GetFactoryDefaultsGroup(), wxT("Initialized"), haveDefaults, false);
if (!haveDefaults)
{
SaveUserPreset(GetFactoryDefaultsGroup());
SetPrivateConfig(GetFactoryDefaultsGroup(), wxT("Initialized"), true);
}
LoadUserPreset(GetCurrentSettingsGroup());
return Startup();
}
bool Effect::Startup()
{
return true;
}
bool Effect::GetAutomationParameters(wxString & parms)
{
EffectAutomationParameters eap;
if (mUIDialog && !TransferDataFromWindow())
{
return false;
}
if (!GetAutomationParameters(eap))
{
return false;
}
return eap.GetParameters(parms);
}
bool Effect::SetAutomationParameters(const wxString & parms)
{
wxString preset = parms;
bool success = false;
if (preset.StartsWith(kUserPresetIdent))
{
preset.Replace(kUserPresetIdent, wxEmptyString, false);
success = LoadUserPreset(GetUserPresetsGroup(preset));
}
else if (preset.StartsWith(kFactoryPresetIdent))
{
preset.Replace(kFactoryPresetIdent, wxEmptyString, false);
wxArrayString presets = GetFactoryPresets();
success = LoadFactoryPreset(presets.Index(preset));
}
else if (preset.StartsWith(kCurrentSettingsIdent))
{
preset.Replace(kCurrentSettingsIdent, wxEmptyString, false);
success = LoadUserPreset(GetCurrentSettingsGroup());
}
else if (preset.StartsWith(kFactoryDefaultsIdent))
{
preset.Replace(kFactoryDefaultsIdent, wxEmptyString, false);
success = LoadUserPreset(GetFactoryDefaultsGroup());
}
else
{
EffectAutomationParameters eap(parms);
success = SetAutomationParameters(eap);
}
if (!success)
{
wxMessageBox(
wxString::Format(
_("%s: Could not load settings below. Default settings will be used.\n\n%s"),
GetName().c_str(),
preset.c_str()
)
);
return false;
}
if (!mUIDialog)
{
return true;
}
return TransferDataToWindow();
}
wxArrayString Effect::GetUserPresets()
{
wxArrayString presets;
GetPrivateConfigSubgroups(GetUserPresetsGroup(wxEmptyString), presets);
presets.Sort();
return presets;
}
bool Effect::HasCurrentSettings()
{
return HasPrivateConfigGroup(GetCurrentSettingsGroup());
}
bool Effect::HasFactoryDefaults()
{
return HasPrivateConfigGroup(GetFactoryDefaultsGroup());
}
wxString Effect::GetPreset(wxWindow * parent, const wxString & parms)
{
EffectPresetsDialog dlg(parent, this);
dlg.Layout();
dlg.Fit();
dlg.SetSize(dlg.GetMinSize());
dlg.CenterOnParent();
dlg.SetSelected(parms);
if (dlg.ShowModal())
{
return dlg.GetSelected();
}
return wxEmptyString;
}
2017-05-19 17:20:05 +00:00
wxString Effect::ManualPage()
{
return wxEmptyString;
}
wxString Effect::HelpPage()
2017-05-15 21:00:33 +00:00
{
return wxEmptyString;
}
bool Effect::IsBatchProcessing()
{
return mIsBatch;
}
void Effect::SetBatchProcessing(bool start)
{
mIsBatch = start;
if (start)
{
SaveUserPreset(GetSavedStateGroup());
}
else
{
LoadUserPreset(GetSavedStateGroup());
}
}
bool Effect::DoEffect(wxWindow *parent,
double projectRate,
TrackList *list,
TrackFactory *factory,
SelectedRegion *selectedRegion,
bool shouldPrompt /* = true */)
{
wxASSERT(selectedRegion->duration() >= 0.0);
mOutputTracks.reset();
mFactory = factory;
mProjectRate = projectRate;
mTracks = list;
bool isSelection = false;
mDuration = 0.0;
if (GetType() == EffectTypeGenerate)
{
GetPrivateConfig(GetCurrentSettingsGroup(), wxT("LastUsedDuration"), mDuration, GetDefaultDuration());
}
mT0 = selectedRegion->t0();
mT1 = selectedRegion->t1();
if (mT1 > mT0)
{
// there is a selection: let's fit in there...
// MJS: note that this is just for the TTC and is independent of the track rate
// but we do need to make sure we have the right number of samples at the project rate
double quantMT0 = QUANTIZED_TIME(mT0, mProjectRate);
double quantMT1 = QUANTIZED_TIME(mT1, mProjectRate);
mDuration = quantMT1 - quantMT0;
mT1 = mT0 + mDuration;
isSelection = true;
}
mDurationFormat = isSelection ? _("hh:mm:ss + samples") : _("hh:mm:ss + milliseconds");
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
mF0 = selectedRegion->f0();
mF1 = selectedRegion->f1();
wxArrayString Names;
if( mF0 != SelectedRegion::UndefinedFrequency )
Names.Add(wxT("control-f0"));
if( mF1 != SelectedRegion::UndefinedFrequency )
Names.Add(wxT("control-f1"));
SetPresetParameters( &Names, NULL );
#endif
CountWaveTracks();
// Note: Init may read parameters from preferences
if (!Init())
{
return false;
}
// Prompting will be bypassed when applying an effect that has already
// been configured, e.g. repeating the last effect on a different selection.
// Prompting may call Effect::Preview
if (shouldPrompt && IsInteractive() && !PromptUser(parent))
{
return false;
}
auto cleanup = finally( [&] {
End();
// In case of failed effect, be sure to free memory.
ReplaceProcessedTracks( false );
} );
bool returnVal = true;
bool skipFlag = CheckWhetherSkipEffect();
if (skipFlag == false)
{
ProgressDialog progress{
GetName(),
wxString::Format(_("Applying %s..."), GetName().c_str()),
pdlgHideStopButton
};
auto vr = valueRestorer( mProgress, &progress );
returnVal = Process();
}
if (returnVal)
{
selectedRegion->setTimes(mT0, mT1);
}
2014-06-03 20:30:19 +00:00
return returnVal;
}
2016-12-29 15:36:37 +00:00
bool Effect::Delegate( Effect &delegate,
wxWindow *parent, SelectedRegion *selectedRegion, bool shouldPrompt)
{
return delegate.DoEffect( parent, mProjectRate, mTracks, mFactory,
selectedRegion, shouldPrompt );
}
// All legacy effects should have this overridden
bool Effect::Init()
{
return true;
}
// Remove this method once NoiseReduction gets migrated
bool Effect::PromptUser(wxWindow *parent)
{
return ShowInterface(parent, IsBatchProcessing());
}
int Effect::GetPass()
{
return mPass;
}
bool Effect::InitPass1()
{
return true;
}
bool Effect::InitPass2()
{
return false;
}
bool Effect::Process()
{
CopyInputTracks(Track::All);
bool bGoodResult = true;
// It's possible that the number of channels the effect expects changed based on
// the parameters (the Audacity Reverb effect does when the stereo width is 0).
mNumAudioIn = GetAudioInCount();
mNumAudioOut = GetAudioOutCount();
mPass = 1;
if (InitPass1())
{
bGoodResult = ProcessPass();
mPass = 2;
if (bGoodResult && InitPass2())
{
bGoodResult = ProcessPass();
}
}
ReplaceProcessedTracks(bGoodResult);
return bGoodResult;
}
bool Effect::ProcessPass()
{
bool bGoodResult = true;
bool isGenerator = GetType() == EffectTypeGenerate;
FloatBuffers inBuffer, outBuffer;
ArrayOf<float *> inBufPos, outBufPos;
ChannelName map[3];
mBufferSize = 0;
mBlockSize = 0;
TrackListIterator iter(mOutputTracks.get());
int count = 0;
bool clear = false;
Track* t = iter.First();
for (t = iter.First(); t; t = iter.Next())
{
if (t->GetKind() != Track::Wave || !t->GetSelected())
{
if (t->IsSyncLockSelected())
{
t->SyncLockAdjust(mT1, mT0 + mDuration);
}
continue;
}
WaveTrack *left = (WaveTrack *)t;
WaveTrack *right;
sampleCount len;
sampleCount leftStart;
sampleCount rightStart;
if (!isGenerator)
{
GetSamples(left, &leftStart, &len);
mSampleCnt = len;
}
else
{
len = 0;
leftStart = 0;
mSampleCnt = left->TimeToLongSamples(mDuration);
}
mNumChannels = 1;
if (left->GetChannel() == Track::LeftChannel)
{
map[0] = ChannelNameFrontLeft;
}
else if (left->GetChannel() == Track::RightChannel)
{
map[0] = ChannelNameFrontRight;
}
else
{
map[0] = ChannelNameMono;
}
map[1] = ChannelNameEOL;
right = NULL;
rightStart = 0;
if (left->GetLinked() && mNumAudioIn > 1)
{
// Assume linked track is wave
right = static_cast<WaveTrack *>(iter.Next());
if (!isGenerator)
{
GetSamples(right, &rightStart, &len);
}
clear = false;
mNumChannels = 2;
if (right->GetChannel() == Track::LeftChannel)
{
map[1] = ChannelNameFrontLeft;
}
else if (right->GetChannel() == Track::RightChannel)
{
map[1] = ChannelNameFrontRight;
}
else
{
map[1] = ChannelNameMono;
}
map[2] = ChannelNameEOL;
}
// Let the client know the sample rate
SetSampleRate(left->GetRate());
// Get the block size the client wants to use
auto max = left->GetMaxBlockSize() * 2;
mBlockSize = SetBlockSize(max);
// Calculate the buffer size to be at least the max rounded up to the clients
// selected block size.
const auto prevBufferSize = mBufferSize;
mBufferSize = ((max + (mBlockSize - 1)) / mBlockSize) * mBlockSize;
// If the buffer size has changed, then (re)allocate the buffers
if (prevBufferSize != mBufferSize)
{
// Always create the number of input buffers the client expects even if we don't have
// the same number of channels.
inBufPos.reinit( mNumAudioIn );
inBuffer.reinit( mNumAudioIn, mBufferSize );
// We won't be using more than the first 2 buffers, so clear the rest (if any)
for (size_t i = 2; i < mNumAudioIn; i++)
{
for (size_t j = 0; j < mBufferSize; j++)
{
inBuffer[i][j] = 0.0;
}
}
// Always create the number of output buffers the client expects even if we don't have
// the same number of channels.
// Output buffers get an extra mBlockSize worth to give extra room if
// the plugin adds latency
outBufPos.reinit( mNumAudioOut );
outBuffer.reinit( mNumAudioOut, mBufferSize + mBlockSize );
}
// (Re)Set the input buffer positions
for (size_t i = 0; i < mNumAudioIn; i++)
{
inBufPos[i] = inBuffer[i].get();
}
// (Re)Set the output buffer positions
for (size_t i = 0; i < mNumAudioOut; i++)
{
outBufPos[i] = outBuffer[i].get();
}
// Clear unused input buffers
if (!right && !clear && mNumAudioIn > 1)
{
for (size_t j = 0; j < mBufferSize; j++)
{
inBuffer[1][j] = 0.0;
}
clear = true;
}
// Go process the track(s)
bGoodResult = ProcessTrack(
count, map, left, right, leftStart, rightStart, len,
inBuffer, outBuffer, inBufPos, outBufPos);
if (!bGoodResult)
{
break;
}
count++;
}
2015-05-05 01:52:25 +00:00
if (bGoodResult && GetType() == EffectTypeGenerate)
{
mT1 = mT0 + mDuration;
}
return bGoodResult;
}
bool Effect::ProcessTrack(int count,
ChannelNames map,
WaveTrack *left,
WaveTrack *right,
sampleCount leftStart,
sampleCount rightStart,
sampleCount len,
FloatBuffers &inBuffer,
FloatBuffers &outBuffer,
ArrayOf< float * > &inBufPos,
ArrayOf< float *> &outBufPos)
{
bool rc = true;
// Give the plugin a chance to initialize
if (!ProcessInitialize(len, map))
{
return false;
}
{ // Start scope for cleanup
auto cleanup = finally( [&] {
// Allow the plugin to cleanup
if (!ProcessFinalize())
{
// In case of non-exceptional flow of control, set rc
rc = false;
}
} );
// For each input block of samples, we pass it to the effect along with a
// variable output location. This output location is simply a pointer into a
// much larger buffer. This reduces the number of calls required to add the
// samples to the output track.
//
// Upon return from the effect, the output samples are "moved to the left" by
// the number of samples in the current latency setting, effectively removing any
// delay introduced by the effect.
//
// At the same time the total number of delayed samples are gathered and when
// there is no further input data to process, the loop continues to call the
// effect with an empty input buffer until the effect has had a chance to
// return all of the remaining delayed samples.
auto inLeftPos = leftStart;
auto inRightPos = rightStart;
auto outLeftPos = leftStart;
auto outRightPos = rightStart;
auto inputRemaining = len;
decltype(GetLatency()) curDelay = 0, delayRemaining = 0;
decltype(mBlockSize) curBlockSize = 0;
decltype(mBufferSize) inputBufferCnt = 0;
decltype(mBufferSize) outputBufferCnt = 0;
bool cleared = false;
auto chans = std::min<unsigned>(mNumAudioOut, mNumChannels);
std::unique_ptr<WaveTrack> genLeft, genRight;
decltype(len) genLength = 0;
bool isGenerator = GetType() == EffectTypeGenerate;
bool isProcessor = GetType() == EffectTypeProcess;
2016-08-20 22:13:49 +00:00
double genDur = 0;
if (isGenerator)
{
if (mIsPreview) {
gPrefs->Read(wxT("/AudioIO/EffectsPreviewLen"), &genDur, 6.0);
genDur = wxMin(mDuration, CalcPreviewInputLength(genDur));
}
else {
genDur = mDuration;
}
genLength = sampleCount((left->GetRate() * genDur) + 0.5); // round to nearest sample
delayRemaining = genLength;
cleared = true;
// Create temporary tracks
genLeft = mFactory->NewWaveTrack(left->GetSampleFormat(), left->GetRate());
if (right)
{
genRight = mFactory->NewWaveTrack(right->GetSampleFormat(), right->GetRate());
}
}
// Call the effect until we run out of input or delayed samples
while (inputRemaining != 0 || delayRemaining != 0)
{
// Still working on the input samples
if (inputRemaining != 0)
{
// Need to refill the input buffers
if (inputBufferCnt == 0)
{
// Calculate the number of samples to get
inputBufferCnt =
limitSampleBufferSize( mBufferSize, inputRemaining );
// Fill the input buffers
left->Get((samplePtr) inBuffer[0].get(), floatSample, inLeftPos, inputBufferCnt);
if (right)
{
right->Get((samplePtr) inBuffer[1].get(), floatSample, inRightPos, inputBufferCnt);
}
// Reset the input buffer positions
for (size_t i = 0; i < mNumChannels; i++)
{
inBufPos[i] = inBuffer[i].get();
}
}
// Calculate the number of samples to process
curBlockSize = mBlockSize;
if (curBlockSize > inputRemaining)
{
// We've reached the last block...set current block size to what's left
// inputRemaining is positive and bounded by a size_t
curBlockSize = inputRemaining.as_size_t();
inputRemaining = 0;
// Clear the remainder of the buffers so that a full block can be passed
// to the effect
auto cnt = mBlockSize - curBlockSize;
for (size_t i = 0; i < mNumChannels; i++)
{
for (decltype(cnt) j = 0 ; j < cnt; j++)
{
inBufPos[i][j + curBlockSize] = 0.0;
}
}
// Might be able to use up some of the delayed samples
if (delayRemaining != 0)
{
// Don't use more than needed
2016-08-27 02:02:58 +00:00
cnt = limitSampleBufferSize(cnt, delayRemaining);
delayRemaining -= cnt;
curBlockSize += cnt;
}
}
}
// We've exhausted the input samples and are now working on the delay
else if (delayRemaining != 0)
{
// Calculate the number of samples to process
2016-08-27 02:02:58 +00:00
curBlockSize = limitSampleBufferSize( mBlockSize, delayRemaining );
delayRemaining -= curBlockSize;
// From this point on, we only want to feed zeros to the plugin
if (!cleared)
{
// Reset the input buffer positions
for (size_t i = 0; i < mNumChannels; i++)
{
inBufPos[i] = inBuffer[i].get();
// And clear
for (size_t j = 0; j < mBlockSize; j++)
{
inBuffer[i][j] = 0.0;
}
}
cleared = true;
}
}
// Finally call the plugin to process the block
decltype(curBlockSize) processed;
try
{
processed = ProcessBlock(inBufPos.get(), outBufPos.get(), curBlockSize);
}
catch( const AudacityException &e )
{
// PRL: Bug 437:
// Pass this along to our application-level handler
throw;
}
catch(...)
{
// PRL:
// Exceptions for other reasons, maybe in third-party code...
// Continue treating them as we used to, but I wonder if these
// should now be treated the same way.
return false;
}
wxASSERT(processed == curBlockSize);
wxUnusedVar(processed);
// Bump to next input buffer position
if (inputRemaining != 0)
{
for (size_t i = 0; i < mNumChannels; i++)
{
inBufPos[i] += curBlockSize;
}
inputRemaining -= curBlockSize;
inputBufferCnt -= curBlockSize;
}
// "ls" and "rs" serve as the input sample index for the left and
// right channels when processing the input samples. If we flip
// over to processing delayed samples, they simply become counters
// for the progress display.
inLeftPos += curBlockSize;
inRightPos += curBlockSize;
// Get the current number of delayed samples and accumulate
if (isProcessor)
{
auto delay = GetLatency();
curDelay += delay;
delayRemaining += delay;
// If the plugin has delayed the output by more samples than our current
// block size, then we leave the output pointers alone. This effectively
// removes those delayed samples from the output buffer.
if (curDelay >= curBlockSize)
{
curDelay -= curBlockSize;
curBlockSize = 0;
}
// We have some delayed samples, at the beginning of the output samples,
// so overlay them by shifting the remaining output samples.
else if (curDelay > 0)
{
// curDelay is bounded by curBlockSize:
auto delay = curDelay.as_size_t();
curBlockSize -= delay;
for (size_t i = 0; i < chans; i++)
{
memmove(outBufPos[i], outBufPos[i] + delay, sizeof(float) * curBlockSize);
}
curDelay = 0;
}
}
// Adjust the number of samples in the output buffers
outputBufferCnt += curBlockSize;
// Still have room in the output buffers
if (outputBufferCnt < mBufferSize)
{
// Bump to next output buffer position
for (size_t i = 0; i < chans; i++)
{
outBufPos[i] += curBlockSize;
}
}
// Output buffers have filled
else
{
if (isProcessor)
{
// Write them out
left->Set((samplePtr) outBuffer[0].get(), floatSample, outLeftPos, outputBufferCnt);
if (right)
{
if (chans >= 2)
{
right->Set((samplePtr) outBuffer[1].get(), floatSample, outRightPos, outputBufferCnt);
}
else
{
right->Set((samplePtr) outBuffer[0].get(), floatSample, outRightPos, outputBufferCnt);
}
}
}
else if (isGenerator)
{
genLeft->Append((samplePtr) outBuffer[0].get(), floatSample, outputBufferCnt);
if (genRight)
{
genRight->Append((samplePtr) outBuffer[1].get(), floatSample, outputBufferCnt);
}
}
// Reset the output buffer positions
for (size_t i = 0; i < chans; i++)
{
outBufPos[i] = outBuffer[i].get();
}
// Bump to the next track position
outLeftPos += outputBufferCnt;
outRightPos += outputBufferCnt;
outputBufferCnt = 0;
}
if (mNumChannels > 1)
{
if (TrackGroupProgress(count,
(inLeftPos - leftStart).as_double() /
(isGenerator ? genLength : len).as_double()))
{
rc = false;
break;
}
}
else
{
if (TrackProgress(count,
(inLeftPos - leftStart).as_double() /
(isGenerator ? genLength : len).as_double()))
{
rc = false;
break;
}
}
}
// Put any remaining output
if (rc && outputBufferCnt)
{
if (isProcessor)
{
left->Set((samplePtr) outBuffer[0].get(), floatSample, outLeftPos, outputBufferCnt);
if (right)
{
if (chans >= 2)
{
right->Set((samplePtr) outBuffer[1].get(), floatSample, outRightPos, outputBufferCnt);
}
else
{
right->Set((samplePtr) outBuffer[0].get(), floatSample, outRightPos, outputBufferCnt);
}
}
}
else if (isGenerator)
{
genLeft->Append((samplePtr) outBuffer[0].get(), floatSample, outputBufferCnt);
if (genRight)
{
genRight->Append((samplePtr) outBuffer[1].get(), floatSample, outputBufferCnt);
}
}
}
if (rc && isGenerator)
{
AudacityProject *p = GetActiveProject();
2016-08-20 22:13:49 +00:00
// PRL: this code was here and could not have been the right
// intent, mixing time and sampleCount values:
// StepTimeWarper warper(mT0 + genLength, genLength - (mT1 - mT0));
// This looks like what it should have been:
// StepTimeWarper warper(mT0 + genDur, genDur - (mT1 - mT0));
// But rather than fix it, I will just disable the use of it for now.
// The purpose was to remap split lines inside the selected region when
// a generator replaces it with sound of different duration. But
// the "correct" version might have the effect of mapping some splits too
// far left, to before the selection.
2016-08-20 22:13:49 +00:00
// In practice the wrong version probably did nothing most of the time,
// because the cutoff time for the step time warper was 44100 times too
// far from mT0.
// Transfer the data from the temporary tracks to the actual ones
genLeft->Flush();
// mT1 gives us the NEW selection. We want to replace up to GetSel1().
2016-08-20 22:13:49 +00:00
left->ClearAndPaste(mT0, p->GetSel1(), genLeft.get(), true, true,
nullptr /* &warper */);
if (genRight)
{
genRight->Flush();
2016-08-20 22:13:49 +00:00
right->ClearAndPaste(mT0, mT1, genRight.get(), true, true,
nullptr /* &warper */);
}
}
} // End scope for cleanup
return rc;
}
void Effect::End()
{
}
void Effect::PopulateOrExchange(ShuttleGui & WXUNUSED(S))
{
return;
}
bool Effect::TransferDataToWindow()
{
return true;
}
bool Effect::TransferDataFromWindow()
{
return true;
}
bool Effect::EnableApply(bool enable)
{
// May be called during initialization, so try to find the dialog
wxWindow *dlg = mUIDialog;
if (!dlg && mUIParent)
{
dlg = wxGetTopLevelParent(mUIParent);
}
if (dlg)
{
wxWindow *apply = dlg->FindWindow(wxID_APPLY);
// Don't allow focus to get trapped
if (!enable)
{
wxWindow *focus = dlg->FindFocus();
if (focus == apply)
{
dlg->FindWindow(wxID_CLOSE)->SetFocus();
}
}
apply->Enable(enable);
}
EnablePreview(enable);
return enable;
}
bool Effect::EnablePreview(bool enable)
{
// May be called during initialization, so try to find the dialog
wxWindow *dlg = mUIDialog;
if (!dlg && mUIParent)
{
dlg = wxGetTopLevelParent(mUIParent);
}
if (dlg)
{
wxWindow *play = dlg->FindWindow(kPlayID);
if (play)
{
wxWindow *rewind = dlg->FindWindow(kRewindID);
wxWindow *ffwd = dlg->FindWindow(kFFwdID);
// Don't allow focus to get trapped
if (!enable)
{
wxWindow *focus = dlg->FindFocus();
if (focus && (focus == play || focus == rewind || focus == ffwd))
{
dlg->FindWindow(wxID_CLOSE)->SetFocus();
}
}
play->Enable(enable);
if (SupportsRealtime())
{
rewind->Enable(enable);
ffwd->Enable(enable);
}
}
}
return enable;
}
2015-04-22 20:55:58 +00:00
void Effect::EnableDebug(bool enable)
{
mUIDebug = enable;
}
void Effect::SetLinearEffectFlag(bool linearEffectFlag)
{
mIsLinearEffect = linearEffectFlag;
}
void Effect::SetPreviewFullSelectionFlag(bool previewDurationFlag)
{
mPreviewFullSelection = previewDurationFlag;
}
void Effect::IncludeNotSelectedPreviewTracks(bool includeNotSelected)
{
mPreviewWithNotSelected = includeNotSelected;
}
bool Effect::TotalProgress(double frac)
{
auto updateResult = (mProgress ?
mProgress->Update(frac) :
ProgressResult::Success);
return (updateResult != ProgressResult::Success);
}
bool Effect::TrackProgress(int whichTrack, double frac, const wxString &msg)
{
auto updateResult = (mProgress ?
mProgress->Update(whichTrack + frac, (double) mNumTracks, msg) :
ProgressResult::Success);
return (updateResult != ProgressResult::Success);
}
bool Effect::TrackGroupProgress(int whichGroup, double frac, const wxString &msg)
{
auto updateResult = (mProgress ?
2015-08-12 13:19:01 +00:00
mProgress->Update(whichGroup + frac, (double) mNumGroups, msg) :
ProgressResult::Success);
return (updateResult != ProgressResult::Success);
}
2017-02-22 19:23:35 +00:00
void Effect::GetSamples(
const WaveTrack *track, sampleCount *start, sampleCount *len)
{
double trackStart = track->GetStartTime();
double trackEnd = track->GetEndTime();
double t0 = mT0 < trackStart ? trackStart : mT0;
double t1 = mT1 > trackEnd ? trackEnd : mT1;
#if 0
if (GetType() & INSERT_EFFECT) {
t1 = t0 + mDuration;
if (mT0 == mT1) {
// Not really part of the calculation, but convenient to put here
track->InsertSilence(t0, t1);
}
}
#endif
if (t1 > t0) {
*start = track->TimeToLongSamples(t0);
auto end = track->TimeToLongSamples(t1);
*len = end - *start;
}
else {
*start = 0;
*len = 0;
}
}
//
// private methods
//
2014-06-03 20:30:19 +00:00
// Use these two methods to copy the input tracks to mOutputTracks, if
// doing the processing on them, and replacing the originals only on success (and not cancel).
// Copy the group tracks that have tracks selected
2015-07-03 04:20:21 +00:00
void Effect::CopyInputTracks()
{
CopyInputTracks(Track::Wave);
}
void Effect::CopyInputTracks(int trackType)
{
// Reset map
mIMap.clear();
mOMap.clear();
mOutputTracks = std::make_unique<TrackList>();
mOutputTracksType = trackType;
//iterate over tracks of type trackType (All types if Track::All)
TrackListOfKindIterator aIt(trackType, mTracks);
t2bHash added;
for (Track *aTrack = aIt.First(); aTrack; aTrack = aIt.Next())
{
// Include selected tracks, plus sync-lock selected tracks for Track::All.
if (aTrack->GetSelected() ||
(trackType == Track::All && aTrack->IsSyncLockSelected()))
{
Track *o = mOutputTracks->Add(aTrack->Duplicate());
mIMap.push_back(aTrack);
mOMap.push_back(o);
}
}
}
Track *Effect::AddToOutputTracks(std::unique_ptr<Track> &&t)
{
mIMap.push_back(NULL);
mOMap.push_back(t.get());
return mOutputTracks->Add(std::move(t));
}
Effect::AddedAnalysisTrack::AddedAnalysisTrack(Effect *pEffect, const wxString &name)
: mpEffect(pEffect)
{
LabelTrack::Holder pTrack{ pEffect->mFactory->NewLabelTrack() };
mpTrack = pTrack.get();
if (!name.empty())
pTrack->SetName(name);
pEffect->mTracks->Add(std::move(pTrack));
}
Effect::AddedAnalysisTrack::AddedAnalysisTrack(AddedAnalysisTrack &&that)
{
mpEffect = that.mpEffect;
mpTrack = that.mpTrack;
that.Commit();
}
void Effect::AddedAnalysisTrack::Commit()
{
mpEffect = nullptr;
}
Effect::AddedAnalysisTrack::~AddedAnalysisTrack()
{
if (mpEffect) {
// not committed -- DELETE the label track
mpEffect->mTracks->Remove(mpTrack);
}
}
auto Effect::AddAnalysisTrack(const wxString &name) -> std::shared_ptr<AddedAnalysisTrack>
{
return std::shared_ptr<AddedAnalysisTrack>
{ safenew AddedAnalysisTrack{ this, name } };
}
Effect::ModifiedAnalysisTrack::ModifiedAnalysisTrack
(Effect *pEffect, const LabelTrack *pOrigTrack, const wxString &name)
: mpEffect(pEffect)
{
// copy LabelTrack here, so it can be undone on cancel
auto newTrack = pOrigTrack->Copy(pOrigTrack->GetStartTime(), pOrigTrack->GetEndTime());
mpTrack = static_cast<LabelTrack*>(newTrack.get());
// Why doesn't LabelTrack::Copy complete the job? :
mpTrack->SetOffset(pOrigTrack->GetStartTime());
if (!name.empty())
mpTrack->SetName(name);
2016-03-01 00:54:21 +00:00
// mpOrigTrack came from mTracks which we own but expose as const to subclasses
// So it's okay that we cast it back to const
mpOrigTrack =
pEffect->mTracks->Replace(const_cast<LabelTrack*>(pOrigTrack),
#ifdef __AUDACITY_OLD_STD__
std::shared_ptr<Track>(newTrack.release())
#else
std::move(newTrack)
#endif
);
}
Effect::ModifiedAnalysisTrack::ModifiedAnalysisTrack(ModifiedAnalysisTrack &&that)
{
mpEffect = that.mpEffect;
mpTrack = that.mpTrack;
mpOrigTrack = std::move(that.mpOrigTrack);
that.Commit();
}
void Effect::ModifiedAnalysisTrack::Commit()
{
mpEffect = nullptr;
}
Effect::ModifiedAnalysisTrack::~ModifiedAnalysisTrack()
{
if (mpEffect) {
// not committed -- DELETE the label track
2016-03-01 00:54:21 +00:00
// mpOrigTrack came from mTracks which we own but expose as const to subclasses
// So it's okay that we cast it back to const
mpEffect->mTracks->Replace(mpTrack, std::move(mpOrigTrack));
}
}
auto Effect::ModifyAnalysisTrack
(const LabelTrack *pOrigTrack, const wxString &name) -> ModifiedAnalysisTrack
{
return{ this, pOrigTrack, name };
}
// If bGoodResult, replace mTracks tracks with successfully processed mOutputTracks copies.
// Else clear and DELETE mOutputTracks copies.
void Effect::ReplaceProcessedTracks(const bool bGoodResult)
{
if (!bGoodResult) {
// Free resources, unless already freed.
// Processing failed or was cancelled so throw away the processed tracks.
if ( mOutputTracks )
mOutputTracks->Clear();
2014-06-03 20:30:19 +00:00
// Reset map
mIMap.clear();
mOMap.clear();
mOutputTracksType = Track::None;
//TODO:undo the non-gui ODTask transfer
return;
}
// Assume resources need to be freed.
wxASSERT(mOutputTracks); // Make sure we at least did the CopyInputTracks().
auto iterOut = mOutputTracks->begin(), iterEnd = mOutputTracks->end();
size_t cnt = mOMap.size();
size_t i = 0;
for (; iterOut != iterEnd; ++i) {
ListOfTracks::value_type o = std::move(*iterOut);
// If tracks were removed from mOutputTracks, then there will be
// tracks in the map that must be removed from mTracks.
while (i < cnt && mOMap[i] != o.get()) {
const auto t = mIMap[i];
if (t) {
mTracks->Remove(t);
}
i++;
}
// This should never happen
wxASSERT(i < cnt);
// Remove the track from the output list...don't DELETE it
iterOut = mOutputTracks->erase(iterOut);
const auto t = mIMap[i];
if (t == NULL)
{
// This track is a NEW addition to output tracks; add it to mTracks
mTracks->Add(std::move(o));
}
else
{
// Replace mTracks entry with the NEW track
WaveTrack *newTrack = static_cast<WaveTrack*>(o.get());
mTracks->Replace(t, std::move(o));
// Swap the wavecache track the ondemand task uses, since now the NEW
// one will be kept in the project
if (ODManager::IsInstanceCreated()) {
ODManager::Instance()->ReplaceWaveTrack((WaveTrack *)t,
newTrack);
}
}
}
// If tracks were removed from mOutputTracks, then there may be tracks
// left at the end of the map that must be removed from mTracks.
while (i < cnt) {
const auto t = mIMap[i];
if (t) {
mTracks->Remove(t);
}
i++;
}
// Reset map
mIMap.clear();
mOMap.clear();
// Make sure we processed everything
wxASSERT(mOutputTracks->empty());
2014-06-03 20:30:19 +00:00
// The output list is no longer needed
mOutputTracks.reset();
mOutputTracksType = Track::None;
}
void Effect::CountWaveTracks()
{
mNumTracks = 0;
mNumGroups = 0;
TrackListOfKindIterator iter(Track::Wave, mTracks);
Track *t = iter.First();
while(t) {
if (!t->GetSelected()) {
t = iter.Next();
continue;
}
2014-06-03 20:30:19 +00:00
if (t->GetKind() == Track::Wave) {
mNumTracks++;
if (!t->GetLinked())
mNumGroups++;
}
t = iter.Next();
}
}
2013-02-15 00:24:43 +00:00
double Effect::CalcPreviewInputLength(double previewLength)
{
return previewLength;
}
// RealtimeAddProcessor and RealtimeProcess use the same method of
// determining the current processor index, so updates to one should
// be reflected in the other.
bool Effect::RealtimeAddProcessor(int group, unsigned chans, float rate)
{
auto ichans = chans;
auto ochans = chans;
auto gchans = chans;
// Reset processor index
if (group == 0)
{
mCurrentProcessor = 0;
mGroupProcessor.Clear();
}
// Remember the processor starting index
mGroupProcessor.Add(mCurrentProcessor);
// Call the client until we run out of input or output channels
while (ichans > 0 && ochans > 0)
{
// If we don't have enough input channels to accomodate the client's
// requirements, then we replicate the input channels until the
// client's needs are met.
if (ichans < mNumAudioIn)
{
// All input channels have been consumed
ichans = 0;
}
// Otherwise fullfil the client's needs with as many input channels as possible.
// After calling the client with this set, we will loop back up to process more
// of the input/output channels.
else if (ichans >= mNumAudioIn)
{
gchans = mNumAudioIn;
ichans -= gchans;
}
// If we don't have enough output channels to accomodate the client's
// requirements, then we provide all of the output channels and fulfill
// the client's needs with dummy buffers. These will just get tossed.
if (ochans < mNumAudioOut)
{
// All output channels have been consumed
ochans = 0;
}
// Otherwise fullfil the client's needs with as many output channels as possible.
// After calling the client with this set, we will loop back up to process more
// of the input/output channels.
else if (ochans >= mNumAudioOut)
{
ochans -= mNumAudioOut;
}
// Add a NEW processor
RealtimeAddProcessor(gchans, rate);
// Bump to next processor
mCurrentProcessor++;
}
return true;
}
// RealtimeAddProcessor and RealtimeProcess use the same method of
// determining the current processor group, so updates to one should
// be reflected in the other.
size_t Effect::RealtimeProcess(int group,
unsigned chans,
Round 3 of realtime changes. This gets meter type VST effects working again by extending the The master now maintains his own internal buffers and sums (mixes) all playing tracks into those buffers. The buffers are then fed into the VST effect that is presented to the user. This allows the effect to provide feedback to the user if it support it. Such effects may display meters or clipping indicators. Several issues with treading have also been corrected (hopefully ;-)). These showed up mostly on Linux, but could have happened on the others as well. The realtime support is no longer limited to 2 channels per logical track. Once support for more channels is added, this should be ready for it. The rack dialog can now be toggled via the edit toolbar button. It doesn't stay pressed because the closing of the dialog would have to be communicated back to the toolbar. As the rack is updated with new or removed effects or active state changed, all effects in the active list were shutdown and all effects in the updated list were initialized. This now shuts down only the effects no longer in the list and initializes only new ones. The rack now uses wxBitmapButton instead of Audacity's AButton. The AButton has a timing issue that prevents it from being deleted while processing the click event. I looked into it, but gave up and switched to the wxBitmapButton. Unfortunately, there's a problem with the wxBitmapButton as well...at least on my setup here. Either the bitmaps are being scaled or antialiased. Will have to get feedback on this. I finally figured out why some VSTs didn't seem to do anything in realtime, at least in my case anyway. I've installed a lot of demo VSTs and while they work in "batch/offline" mode, some of them will not work in realtime since vendors tend to remove automation as one of the demo limitations. More changes coming shortly...
2014-11-03 06:48:54 +00:00
float **inbuf,
float **outbuf,
size_t numSamples)
{
Round 3 of realtime changes. This gets meter type VST effects working again by extending the The master now maintains his own internal buffers and sums (mixes) all playing tracks into those buffers. The buffers are then fed into the VST effect that is presented to the user. This allows the effect to provide feedback to the user if it support it. Such effects may display meters or clipping indicators. Several issues with treading have also been corrected (hopefully ;-)). These showed up mostly on Linux, but could have happened on the others as well. The realtime support is no longer limited to 2 channels per logical track. Once support for more channels is added, this should be ready for it. The rack dialog can now be toggled via the edit toolbar button. It doesn't stay pressed because the closing of the dialog would have to be communicated back to the toolbar. As the rack is updated with new or removed effects or active state changed, all effects in the active list were shutdown and all effects in the updated list were initialized. This now shuts down only the effects no longer in the list and initializes only new ones. The rack now uses wxBitmapButton instead of Audacity's AButton. The AButton has a timing issue that prevents it from being deleted while processing the click event. I looked into it, but gave up and switched to the wxBitmapButton. Unfortunately, there's a problem with the wxBitmapButton as well...at least on my setup here. Either the bitmaps are being scaled or antialiased. Will have to get feedback on this. I finally figured out why some VSTs didn't seem to do anything in realtime, at least in my case anyway. I've installed a lot of demo VSTs and while they work in "batch/offline" mode, some of them will not work in realtime since vendors tend to remove automation as one of the demo limitations. More changes coming shortly...
2014-11-03 06:48:54 +00:00
//
// The caller passes the number of channels to process and specifies
// the number of input and output buffers. There will always be the
// same number of output buffers as there are input buffers.
//
// Effects always require a certain number of input and output buffers,
// so if the number of channels we're curently processing are different
// than what the effect expects, then we use a few methods of satisfying
Round 3 of realtime changes. This gets meter type VST effects working again by extending the The master now maintains his own internal buffers and sums (mixes) all playing tracks into those buffers. The buffers are then fed into the VST effect that is presented to the user. This allows the effect to provide feedback to the user if it support it. Such effects may display meters or clipping indicators. Several issues with treading have also been corrected (hopefully ;-)). These showed up mostly on Linux, but could have happened on the others as well. The realtime support is no longer limited to 2 channels per logical track. Once support for more channels is added, this should be ready for it. The rack dialog can now be toggled via the edit toolbar button. It doesn't stay pressed because the closing of the dialog would have to be communicated back to the toolbar. As the rack is updated with new or removed effects or active state changed, all effects in the active list were shutdown and all effects in the updated list were initialized. This now shuts down only the effects no longer in the list and initializes only new ones. The rack now uses wxBitmapButton instead of Audacity's AButton. The AButton has a timing issue that prevents it from being deleted while processing the click event. I looked into it, but gave up and switched to the wxBitmapButton. Unfortunately, there's a problem with the wxBitmapButton as well...at least on my setup here. Either the bitmaps are being scaled or antialiased. Will have to get feedback on this. I finally figured out why some VSTs didn't seem to do anything in realtime, at least in my case anyway. I've installed a lot of demo VSTs and while they work in "batch/offline" mode, some of them will not work in realtime since vendors tend to remove automation as one of the demo limitations. More changes coming shortly...
2014-11-03 06:48:54 +00:00
// the effects requirements.
float **clientIn = (float **) alloca(mNumAudioIn * sizeof(float *));
float **clientOut = (float **) alloca(mNumAudioOut * sizeof(float *));
float *dummybuf = (float *) alloca(numSamples * sizeof(float));
decltype(numSamples) len = 0;
auto ichans = chans;
auto ochans = chans;
auto gchans = chans;
unsigned indx = 0;
unsigned ondx = 0;
Round 3 of realtime changes. This gets meter type VST effects working again by extending the The master now maintains his own internal buffers and sums (mixes) all playing tracks into those buffers. The buffers are then fed into the VST effect that is presented to the user. This allows the effect to provide feedback to the user if it support it. Such effects may display meters or clipping indicators. Several issues with treading have also been corrected (hopefully ;-)). These showed up mostly on Linux, but could have happened on the others as well. The realtime support is no longer limited to 2 channels per logical track. Once support for more channels is added, this should be ready for it. The rack dialog can now be toggled via the edit toolbar button. It doesn't stay pressed because the closing of the dialog would have to be communicated back to the toolbar. As the rack is updated with new or removed effects or active state changed, all effects in the active list were shutdown and all effects in the updated list were initialized. This now shuts down only the effects no longer in the list and initializes only new ones. The rack now uses wxBitmapButton instead of Audacity's AButton. The AButton has a timing issue that prevents it from being deleted while processing the click event. I looked into it, but gave up and switched to the wxBitmapButton. Unfortunately, there's a problem with the wxBitmapButton as well...at least on my setup here. Either the bitmaps are being scaled or antialiased. Will have to get feedback on this. I finally figured out why some VSTs didn't seem to do anything in realtime, at least in my case anyway. I've installed a lot of demo VSTs and while they work in "batch/offline" mode, some of them will not work in realtime since vendors tend to remove automation as one of the demo limitations. More changes coming shortly...
2014-11-03 06:48:54 +00:00
int processor = mGroupProcessor[group];
Round 3 of realtime changes. This gets meter type VST effects working again by extending the The master now maintains his own internal buffers and sums (mixes) all playing tracks into those buffers. The buffers are then fed into the VST effect that is presented to the user. This allows the effect to provide feedback to the user if it support it. Such effects may display meters or clipping indicators. Several issues with treading have also been corrected (hopefully ;-)). These showed up mostly on Linux, but could have happened on the others as well. The realtime support is no longer limited to 2 channels per logical track. Once support for more channels is added, this should be ready for it. The rack dialog can now be toggled via the edit toolbar button. It doesn't stay pressed because the closing of the dialog would have to be communicated back to the toolbar. As the rack is updated with new or removed effects or active state changed, all effects in the active list were shutdown and all effects in the updated list were initialized. This now shuts down only the effects no longer in the list and initializes only new ones. The rack now uses wxBitmapButton instead of Audacity's AButton. The AButton has a timing issue that prevents it from being deleted while processing the click event. I looked into it, but gave up and switched to the wxBitmapButton. Unfortunately, there's a problem with the wxBitmapButton as well...at least on my setup here. Either the bitmaps are being scaled or antialiased. Will have to get feedback on this. I finally figured out why some VSTs didn't seem to do anything in realtime, at least in my case anyway. I've installed a lot of demo VSTs and while they work in "batch/offline" mode, some of them will not work in realtime since vendors tend to remove automation as one of the demo limitations. More changes coming shortly...
2014-11-03 06:48:54 +00:00
// Call the client until we run out of input or output channels
while (ichans > 0 && ochans > 0)
{
Round 3 of realtime changes. This gets meter type VST effects working again by extending the The master now maintains his own internal buffers and sums (mixes) all playing tracks into those buffers. The buffers are then fed into the VST effect that is presented to the user. This allows the effect to provide feedback to the user if it support it. Such effects may display meters or clipping indicators. Several issues with treading have also been corrected (hopefully ;-)). These showed up mostly on Linux, but could have happened on the others as well. The realtime support is no longer limited to 2 channels per logical track. Once support for more channels is added, this should be ready for it. The rack dialog can now be toggled via the edit toolbar button. It doesn't stay pressed because the closing of the dialog would have to be communicated back to the toolbar. As the rack is updated with new or removed effects or active state changed, all effects in the active list were shutdown and all effects in the updated list were initialized. This now shuts down only the effects no longer in the list and initializes only new ones. The rack now uses wxBitmapButton instead of Audacity's AButton. The AButton has a timing issue that prevents it from being deleted while processing the click event. I looked into it, but gave up and switched to the wxBitmapButton. Unfortunately, there's a problem with the wxBitmapButton as well...at least on my setup here. Either the bitmaps are being scaled or antialiased. Will have to get feedback on this. I finally figured out why some VSTs didn't seem to do anything in realtime, at least in my case anyway. I've installed a lot of demo VSTs and while they work in "batch/offline" mode, some of them will not work in realtime since vendors tend to remove automation as one of the demo limitations. More changes coming shortly...
2014-11-03 06:48:54 +00:00
// If we don't have enough input channels to accomodate the client's
// requirements, then we replicate the input channels until the
// client's needs are met.
if (ichans < mNumAudioIn)
{
for (size_t i = 0; i < mNumAudioIn; i++)
Round 3 of realtime changes. This gets meter type VST effects working again by extending the The master now maintains his own internal buffers and sums (mixes) all playing tracks into those buffers. The buffers are then fed into the VST effect that is presented to the user. This allows the effect to provide feedback to the user if it support it. Such effects may display meters or clipping indicators. Several issues with treading have also been corrected (hopefully ;-)). These showed up mostly on Linux, but could have happened on the others as well. The realtime support is no longer limited to 2 channels per logical track. Once support for more channels is added, this should be ready for it. The rack dialog can now be toggled via the edit toolbar button. It doesn't stay pressed because the closing of the dialog would have to be communicated back to the toolbar. As the rack is updated with new or removed effects or active state changed, all effects in the active list were shutdown and all effects in the updated list were initialized. This now shuts down only the effects no longer in the list and initializes only new ones. The rack now uses wxBitmapButton instead of Audacity's AButton. The AButton has a timing issue that prevents it from being deleted while processing the click event. I looked into it, but gave up and switched to the wxBitmapButton. Unfortunately, there's a problem with the wxBitmapButton as well...at least on my setup here. Either the bitmaps are being scaled or antialiased. Will have to get feedback on this. I finally figured out why some VSTs didn't seem to do anything in realtime, at least in my case anyway. I've installed a lot of demo VSTs and while they work in "batch/offline" mode, some of them will not work in realtime since vendors tend to remove automation as one of the demo limitations. More changes coming shortly...
2014-11-03 06:48:54 +00:00
{
if (indx == ichans)
{
indx = 0;
}
clientIn[i] = inbuf[indx++];
}
// All input channels have been consumed
ichans = 0;
}
Round 3 of realtime changes. This gets meter type VST effects working again by extending the The master now maintains his own internal buffers and sums (mixes) all playing tracks into those buffers. The buffers are then fed into the VST effect that is presented to the user. This allows the effect to provide feedback to the user if it support it. Such effects may display meters or clipping indicators. Several issues with treading have also been corrected (hopefully ;-)). These showed up mostly on Linux, but could have happened on the others as well. The realtime support is no longer limited to 2 channels per logical track. Once support for more channels is added, this should be ready for it. The rack dialog can now be toggled via the edit toolbar button. It doesn't stay pressed because the closing of the dialog would have to be communicated back to the toolbar. As the rack is updated with new or removed effects or active state changed, all effects in the active list were shutdown and all effects in the updated list were initialized. This now shuts down only the effects no longer in the list and initializes only new ones. The rack now uses wxBitmapButton instead of Audacity's AButton. The AButton has a timing issue that prevents it from being deleted while processing the click event. I looked into it, but gave up and switched to the wxBitmapButton. Unfortunately, there's a problem with the wxBitmapButton as well...at least on my setup here. Either the bitmaps are being scaled or antialiased. Will have to get feedback on this. I finally figured out why some VSTs didn't seem to do anything in realtime, at least in my case anyway. I've installed a lot of demo VSTs and while they work in "batch/offline" mode, some of them will not work in realtime since vendors tend to remove automation as one of the demo limitations. More changes coming shortly...
2014-11-03 06:48:54 +00:00
// Otherwise fullfil the client's needs with as many input channels as possible.
// After calling the client with this set, we will loop back up to process more
// of the input/output channels.
else if (ichans >= mNumAudioIn)
{
Round 3 of realtime changes. This gets meter type VST effects working again by extending the The master now maintains his own internal buffers and sums (mixes) all playing tracks into those buffers. The buffers are then fed into the VST effect that is presented to the user. This allows the effect to provide feedback to the user if it support it. Such effects may display meters or clipping indicators. Several issues with treading have also been corrected (hopefully ;-)). These showed up mostly on Linux, but could have happened on the others as well. The realtime support is no longer limited to 2 channels per logical track. Once support for more channels is added, this should be ready for it. The rack dialog can now be toggled via the edit toolbar button. It doesn't stay pressed because the closing of the dialog would have to be communicated back to the toolbar. As the rack is updated with new or removed effects or active state changed, all effects in the active list were shutdown and all effects in the updated list were initialized. This now shuts down only the effects no longer in the list and initializes only new ones. The rack now uses wxBitmapButton instead of Audacity's AButton. The AButton has a timing issue that prevents it from being deleted while processing the click event. I looked into it, but gave up and switched to the wxBitmapButton. Unfortunately, there's a problem with the wxBitmapButton as well...at least on my setup here. Either the bitmaps are being scaled or antialiased. Will have to get feedback on this. I finally figured out why some VSTs didn't seem to do anything in realtime, at least in my case anyway. I've installed a lot of demo VSTs and while they work in "batch/offline" mode, some of them will not work in realtime since vendors tend to remove automation as one of the demo limitations. More changes coming shortly...
2014-11-03 06:48:54 +00:00
gchans = 0;
for (size_t i = 0; i < mNumAudioIn; i++, ichans--, gchans++)
Round 3 of realtime changes. This gets meter type VST effects working again by extending the The master now maintains his own internal buffers and sums (mixes) all playing tracks into those buffers. The buffers are then fed into the VST effect that is presented to the user. This allows the effect to provide feedback to the user if it support it. Such effects may display meters or clipping indicators. Several issues with treading have also been corrected (hopefully ;-)). These showed up mostly on Linux, but could have happened on the others as well. The realtime support is no longer limited to 2 channels per logical track. Once support for more channels is added, this should be ready for it. The rack dialog can now be toggled via the edit toolbar button. It doesn't stay pressed because the closing of the dialog would have to be communicated back to the toolbar. As the rack is updated with new or removed effects or active state changed, all effects in the active list were shutdown and all effects in the updated list were initialized. This now shuts down only the effects no longer in the list and initializes only new ones. The rack now uses wxBitmapButton instead of Audacity's AButton. The AButton has a timing issue that prevents it from being deleted while processing the click event. I looked into it, but gave up and switched to the wxBitmapButton. Unfortunately, there's a problem with the wxBitmapButton as well...at least on my setup here. Either the bitmaps are being scaled or antialiased. Will have to get feedback on this. I finally figured out why some VSTs didn't seem to do anything in realtime, at least in my case anyway. I've installed a lot of demo VSTs and while they work in "batch/offline" mode, some of them will not work in realtime since vendors tend to remove automation as one of the demo limitations. More changes coming shortly...
2014-11-03 06:48:54 +00:00
{
clientIn[i] = inbuf[indx++];
}
}
Round 3 of realtime changes. This gets meter type VST effects working again by extending the The master now maintains his own internal buffers and sums (mixes) all playing tracks into those buffers. The buffers are then fed into the VST effect that is presented to the user. This allows the effect to provide feedback to the user if it support it. Such effects may display meters or clipping indicators. Several issues with treading have also been corrected (hopefully ;-)). These showed up mostly on Linux, but could have happened on the others as well. The realtime support is no longer limited to 2 channels per logical track. Once support for more channels is added, this should be ready for it. The rack dialog can now be toggled via the edit toolbar button. It doesn't stay pressed because the closing of the dialog would have to be communicated back to the toolbar. As the rack is updated with new or removed effects or active state changed, all effects in the active list were shutdown and all effects in the updated list were initialized. This now shuts down only the effects no longer in the list and initializes only new ones. The rack now uses wxBitmapButton instead of Audacity's AButton. The AButton has a timing issue that prevents it from being deleted while processing the click event. I looked into it, but gave up and switched to the wxBitmapButton. Unfortunately, there's a problem with the wxBitmapButton as well...at least on my setup here. Either the bitmaps are being scaled or antialiased. Will have to get feedback on this. I finally figured out why some VSTs didn't seem to do anything in realtime, at least in my case anyway. I've installed a lot of demo VSTs and while they work in "batch/offline" mode, some of them will not work in realtime since vendors tend to remove automation as one of the demo limitations. More changes coming shortly...
2014-11-03 06:48:54 +00:00
// If we don't have enough output channels to accomodate the client's
// requirements, then we provide all of the output channels and fulfill
// the client's needs with dummy buffers. These will just get tossed.
if (ochans < mNumAudioOut)
{
for (size_t i = 0; i < mNumAudioOut; i++)
Round 3 of realtime changes. This gets meter type VST effects working again by extending the The master now maintains his own internal buffers and sums (mixes) all playing tracks into those buffers. The buffers are then fed into the VST effect that is presented to the user. This allows the effect to provide feedback to the user if it support it. Such effects may display meters or clipping indicators. Several issues with treading have also been corrected (hopefully ;-)). These showed up mostly on Linux, but could have happened on the others as well. The realtime support is no longer limited to 2 channels per logical track. Once support for more channels is added, this should be ready for it. The rack dialog can now be toggled via the edit toolbar button. It doesn't stay pressed because the closing of the dialog would have to be communicated back to the toolbar. As the rack is updated with new or removed effects or active state changed, all effects in the active list were shutdown and all effects in the updated list were initialized. This now shuts down only the effects no longer in the list and initializes only new ones. The rack now uses wxBitmapButton instead of Audacity's AButton. The AButton has a timing issue that prevents it from being deleted while processing the click event. I looked into it, but gave up and switched to the wxBitmapButton. Unfortunately, there's a problem with the wxBitmapButton as well...at least on my setup here. Either the bitmaps are being scaled or antialiased. Will have to get feedback on this. I finally figured out why some VSTs didn't seem to do anything in realtime, at least in my case anyway. I've installed a lot of demo VSTs and while they work in "batch/offline" mode, some of them will not work in realtime since vendors tend to remove automation as one of the demo limitations. More changes coming shortly...
2014-11-03 06:48:54 +00:00
{
if (i < ochans)
{
clientOut[i] = outbuf[i];
}
else
{
clientOut[i] = dummybuf;
}
}
// All output channels have been consumed
ochans = 0;
}
Round 3 of realtime changes. This gets meter type VST effects working again by extending the The master now maintains his own internal buffers and sums (mixes) all playing tracks into those buffers. The buffers are then fed into the VST effect that is presented to the user. This allows the effect to provide feedback to the user if it support it. Such effects may display meters or clipping indicators. Several issues with treading have also been corrected (hopefully ;-)). These showed up mostly on Linux, but could have happened on the others as well. The realtime support is no longer limited to 2 channels per logical track. Once support for more channels is added, this should be ready for it. The rack dialog can now be toggled via the edit toolbar button. It doesn't stay pressed because the closing of the dialog would have to be communicated back to the toolbar. As the rack is updated with new or removed effects or active state changed, all effects in the active list were shutdown and all effects in the updated list were initialized. This now shuts down only the effects no longer in the list and initializes only new ones. The rack now uses wxBitmapButton instead of Audacity's AButton. The AButton has a timing issue that prevents it from being deleted while processing the click event. I looked into it, but gave up and switched to the wxBitmapButton. Unfortunately, there's a problem with the wxBitmapButton as well...at least on my setup here. Either the bitmaps are being scaled or antialiased. Will have to get feedback on this. I finally figured out why some VSTs didn't seem to do anything in realtime, at least in my case anyway. I've installed a lot of demo VSTs and while they work in "batch/offline" mode, some of them will not work in realtime since vendors tend to remove automation as one of the demo limitations. More changes coming shortly...
2014-11-03 06:48:54 +00:00
// Otherwise fullfil the client's needs with as many output channels as possible.
// After calling the client with this set, we will loop back up to process more
// of the input/output channels.
else if (ochans >= mNumAudioOut)
{
for (size_t i = 0; i < mNumAudioOut; i++, ochans--)
Round 3 of realtime changes. This gets meter type VST effects working again by extending the The master now maintains his own internal buffers and sums (mixes) all playing tracks into those buffers. The buffers are then fed into the VST effect that is presented to the user. This allows the effect to provide feedback to the user if it support it. Such effects may display meters or clipping indicators. Several issues with treading have also been corrected (hopefully ;-)). These showed up mostly on Linux, but could have happened on the others as well. The realtime support is no longer limited to 2 channels per logical track. Once support for more channels is added, this should be ready for it. The rack dialog can now be toggled via the edit toolbar button. It doesn't stay pressed because the closing of the dialog would have to be communicated back to the toolbar. As the rack is updated with new or removed effects or active state changed, all effects in the active list were shutdown and all effects in the updated list were initialized. This now shuts down only the effects no longer in the list and initializes only new ones. The rack now uses wxBitmapButton instead of Audacity's AButton. The AButton has a timing issue that prevents it from being deleted while processing the click event. I looked into it, but gave up and switched to the wxBitmapButton. Unfortunately, there's a problem with the wxBitmapButton as well...at least on my setup here. Either the bitmaps are being scaled or antialiased. Will have to get feedback on this. I finally figured out why some VSTs didn't seem to do anything in realtime, at least in my case anyway. I've installed a lot of demo VSTs and while they work in "batch/offline" mode, some of them will not work in realtime since vendors tend to remove automation as one of the demo limitations. More changes coming shortly...
2014-11-03 06:48:54 +00:00
{
clientOut[i] = outbuf[ondx++];
}
}
Round 3 of realtime changes. This gets meter type VST effects working again by extending the The master now maintains his own internal buffers and sums (mixes) all playing tracks into those buffers. The buffers are then fed into the VST effect that is presented to the user. This allows the effect to provide feedback to the user if it support it. Such effects may display meters or clipping indicators. Several issues with treading have also been corrected (hopefully ;-)). These showed up mostly on Linux, but could have happened on the others as well. The realtime support is no longer limited to 2 channels per logical track. Once support for more channels is added, this should be ready for it. The rack dialog can now be toggled via the edit toolbar button. It doesn't stay pressed because the closing of the dialog would have to be communicated back to the toolbar. As the rack is updated with new or removed effects or active state changed, all effects in the active list were shutdown and all effects in the updated list were initialized. This now shuts down only the effects no longer in the list and initializes only new ones. The rack now uses wxBitmapButton instead of Audacity's AButton. The AButton has a timing issue that prevents it from being deleted while processing the click event. I looked into it, but gave up and switched to the wxBitmapButton. Unfortunately, there's a problem with the wxBitmapButton as well...at least on my setup here. Either the bitmaps are being scaled or antialiased. Will have to get feedback on this. I finally figured out why some VSTs didn't seem to do anything in realtime, at least in my case anyway. I've installed a lot of demo VSTs and while they work in "batch/offline" mode, some of them will not work in realtime since vendors tend to remove automation as one of the demo limitations. More changes coming shortly...
2014-11-03 06:48:54 +00:00
// Finally call the plugin to process the block
len = 0;
for (decltype(numSamples) block = 0; block < numSamples; block += mBlockSize)
{
auto cnt = std::min(numSamples - block, mBlockSize);
len += RealtimeProcess(processor, clientIn, clientOut, cnt);
for (size_t i = 0 ; i < mNumAudioIn; i++)
{
clientIn[i] += cnt;
}
for (size_t i = 0 ; i < mNumAudioOut; i++)
{
clientOut[i] += cnt;
}
}
// Bump to next processor
processor++;
}
Round 3 of realtime changes. This gets meter type VST effects working again by extending the The master now maintains his own internal buffers and sums (mixes) all playing tracks into those buffers. The buffers are then fed into the VST effect that is presented to the user. This allows the effect to provide feedback to the user if it support it. Such effects may display meters or clipping indicators. Several issues with treading have also been corrected (hopefully ;-)). These showed up mostly on Linux, but could have happened on the others as well. The realtime support is no longer limited to 2 channels per logical track. Once support for more channels is added, this should be ready for it. The rack dialog can now be toggled via the edit toolbar button. It doesn't stay pressed because the closing of the dialog would have to be communicated back to the toolbar. As the rack is updated with new or removed effects or active state changed, all effects in the active list were shutdown and all effects in the updated list were initialized. This now shuts down only the effects no longer in the list and initializes only new ones. The rack now uses wxBitmapButton instead of Audacity's AButton. The AButton has a timing issue that prevents it from being deleted while processing the click event. I looked into it, but gave up and switched to the wxBitmapButton. Unfortunately, there's a problem with the wxBitmapButton as well...at least on my setup here. Either the bitmaps are being scaled or antialiased. Will have to get feedback on this. I finally figured out why some VSTs didn't seem to do anything in realtime, at least in my case anyway. I've installed a lot of demo VSTs and while they work in "batch/offline" mode, some of them will not work in realtime since vendors tend to remove automation as one of the demo limitations. More changes coming shortly...
2014-11-03 06:48:54 +00:00
return len;
}
bool Effect::IsRealtimeActive()
{
return mRealtimeSuspendCount == 0;
}
bool Effect::IsHidden()
{
return false;
}
void Effect::Preview(bool dryOnly)
{
if (mNumTracks == 0) { // nothing to preview
return;
}
if (gAudioIO->IsBusy()) {
return;
}
wxWindow *FocusDialog = wxWindow::FindFocus();
double previewDuration;
bool isNyquist = (GetFamily().IsSameAs(NYQUISTEFFECTS_FAMILY))? true : false;
bool isGenerator = GetType() == EffectTypeGenerate;
// Mix a few seconds of audio from all of the tracks
double previewLen;
gPrefs->Read(wxT("/AudioIO/EffectsPreviewLen"), &previewLen, 6.0);
2013-02-15 00:24:43 +00:00
const double rate = mProjectRate;
if (isNyquist && isGenerator) {
previewDuration = CalcPreviewInputLength(previewLen);
}
else {
previewDuration = wxMin(mDuration, CalcPreviewInputLength(previewLen));
}
double t1 = mT0 + previewDuration;
if ((t1 > mT1) && !(isNyquist && isGenerator)) {
t1 = mT1;
}
if (t1 <= mT0)
return;
bool success = true;
auto vr0 = valueRestorer( mT0 );
auto vr1 = valueRestorer( mT1 );
// Most effects should stop at t1.
if (!mPreviewFullSelection)
mT1 = t1;
// Save the original track list
TrackList *saveTracks = mTracks;
auto cleanup = finally( [&] {
mTracks = saveTracks;
// Effect is already inited; we will call Process, End, and then Init
// again, so the state is exactly the way it was before Preview
// was called.
if (!dryOnly) {
End();
GuardedCall< void >( [&]{ Init(); } );
}
if (FocusDialog) {
FocusDialog->SetFocus();
}
// In case of failed effect, be sure to free memory.
ReplaceProcessedTracks( false );
} );
// Build NEW tracklist from rendering tracks
auto uTracks = std::make_unique<TrackList>();
mTracks = uTracks.get();
// Linear Effect preview optimised by pre-mixing to one track.
// Generators need to generate per track.
if (mIsLinearEffect && !isGenerator) {
WaveTrack::Holder mixLeft, mixRight;
MixAndRender(saveTracks, mFactory, rate, floatSample, mT0, t1, mixLeft, mixRight);
if (!mixLeft)
return;
mixLeft->Offset(-mixLeft->GetStartTime());
mixLeft->InsertSilence(0.0, mT0);
mixLeft->SetSelected(true);
mixLeft->SetDisplay(WaveTrack::NoDisplay);
mTracks->Add(std::move(mixLeft));
if (mixRight) {
mixRight->Offset(-mixRight->GetStartTime());
mixRight->InsertSilence(0.0, mT0);
mixRight->SetSelected(true);
mTracks->Add(std::move(mixRight));
}
}
else {
TrackListOfKindIterator iter(Track::Wave, saveTracks);
WaveTrack *src = (WaveTrack *) iter.First();
while (src)
{
if (src->GetSelected() || mPreviewWithNotSelected) {
auto dest = src->Copy(mT0, t1);
dest->InsertSilence(0.0, mT0);
dest->SetSelected(src->GetSelected());
static_cast<WaveTrack*>(dest.get())->SetDisplay(WaveTrack::NoDisplay);
mTracks->Add(std::move(dest));
}
src = (WaveTrack *) iter.Next();
}
}
// Update track/group counts
CountWaveTracks();
// Apply effect
if (!dryOnly) {
ProgressDialog progress{
GetName(),
_("Preparing preview"),
pdlgHideCancelButton
}; // Have only "Stop" button.
auto vr = valueRestorer( mProgress, &progress );
auto vr2 = valueRestorer( mIsPreview, true );
success = Process();
}
if (success)
{
WaveTrackConstArray playbackTracks;
WaveTrackArray recordingTracks;
SelectedTrackListOfKindIterator iter(Track::Wave, mTracks);
WaveTrack *src = (WaveTrack *) iter.First();
while (src) {
playbackTracks.push_back(src);
src = (WaveTrack *) iter.Next();
}
// Some effects (Paulstretch) may need to generate more
// than previewLen, so take the min.
t1 = std::min(mT0 + previewLen, mT1);
2013-02-15 00:24:43 +00:00
#ifdef EXPERIMENTAL_MIDI_OUT
NoteTrackArray empty;
#endif
// Start audio playing
AudioIOStartStreamOptions options { rate };
int token =
2014-06-03 20:30:19 +00:00
gAudioIO->StartStream(playbackTracks, recordingTracks,
#ifdef EXPERIMENTAL_MIDI_OUT
empty,
#endif
mT0, t1, options);
if (token) {
auto previewing = ProgressResult::Success;
// The progress dialog must be deleted before stopping the stream
// to allow events to flow to the app during StopStream processing.
// The progress dialog blocks these events.
{
ProgressDialog progress
(GetName(), _("Previewing"), pdlgHideCancelButton);
while (gAudioIO->IsStreamActive(token) && previewing == ProgressResult::Success) {
::wxMilliSleep(100);
previewing = progress.Update(gAudioIO->GetStreamTime() - mT0, t1 - mT0);
}
}
gAudioIO->StopStream();
while (gAudioIO->IsBusy()) {
::wxMilliSleep(100);
}
}
else {
ShowErrorDialog(FocusDialog, _("Error"),
_("Error opening sound device.\nTry changing the audio host, playback device and the project sample rate."),
wxT("http://manual.audacityteam.org/man/faq_errors.html#sound_device"), false);
}
}
Round 3 of realtime changes. This gets meter type VST effects working again by extending the The master now maintains his own internal buffers and sums (mixes) all playing tracks into those buffers. The buffers are then fed into the VST effect that is presented to the user. This allows the effect to provide feedback to the user if it support it. Such effects may display meters or clipping indicators. Several issues with treading have also been corrected (hopefully ;-)). These showed up mostly on Linux, but could have happened on the others as well. The realtime support is no longer limited to 2 channels per logical track. Once support for more channels is added, this should be ready for it. The rack dialog can now be toggled via the edit toolbar button. It doesn't stay pressed because the closing of the dialog would have to be communicated back to the toolbar. As the rack is updated with new or removed effects or active state changed, all effects in the active list were shutdown and all effects in the updated list were initialized. This now shuts down only the effects no longer in the list and initializes only new ones. The rack now uses wxBitmapButton instead of Audacity's AButton. The AButton has a timing issue that prevents it from being deleted while processing the click event. I looked into it, but gave up and switched to the wxBitmapButton. Unfortunately, there's a problem with the wxBitmapButton as well...at least on my setup here. Either the bitmaps are being scaled or antialiased. Will have to get feedback on this. I finally figured out why some VSTs didn't seem to do anything in realtime, at least in my case anyway. I've installed a lot of demo VSTs and while they work in "batch/offline" mode, some of them will not work in realtime since vendors tend to remove automation as one of the demo limitations. More changes coming shortly...
2014-11-03 06:48:54 +00:00
}
BEGIN_EVENT_TABLE(EffectDialog, wxDialogWrapper)
EVT_BUTTON(wxID_OK, EffectDialog::OnOk)
END_EVENT_TABLE()
EffectDialog::EffectDialog(wxWindow * parent,
const wxString & title,
int type,
int flags,
int additionalButtons)
: wxDialogWrapper(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, flags)
{
mType = type;
mAdditionalButtons = additionalButtons;
}
void EffectDialog::Init()
{
ShuttleGui S(this, eIsCreating);
2014-06-03 20:30:19 +00:00
S.SetBorder(5);
S.StartVerticalLay(true);
{
PopulateOrExchange(S);
long buttons = eOkButton;
if (mType != EffectTypeAnalyze)
{
buttons |= eCancelButton;
if (mType == EffectTypeProcess)
{
buttons |= ePreviewButton;
}
}
S.AddStandardButtons(buttons|mAdditionalButtons);
}
S.EndVerticalLay();
Layout();
Fit();
SetMinSize(GetSize());
Center();
}
/// This is a virtual function which will be overridden to
/// provide the actual parameters that we want for each
/// kind of dialog.
void EffectDialog::PopulateOrExchange(ShuttleGui & WXUNUSED(S))
{
return;
}
bool EffectDialog::TransferDataToWindow()
{
ShuttleGui S(this, eIsSettingToDialog);
PopulateOrExchange(S);
return true;
}
bool EffectDialog::TransferDataFromWindow()
{
ShuttleGui S(this, eIsGettingFromDialog);
PopulateOrExchange(S);
return true;
}
bool EffectDialog::Validate()
{
return true;
}
void EffectDialog::OnPreview(wxCommandEvent & WXUNUSED(evt))
{
return;
}
void EffectDialog::OnOk(wxCommandEvent & WXUNUSED(evt))
{
// On wxGTK (wx2.8.12), the default action is still executed even if
// the button is disabled. This appears to affect all wxDialogs, not
// just our Effects dialogs. So, this is a only temporary workaround
// for legacy effects that disable the OK button. Hopefully this has
// been corrected in wx3.
if (FindWindow(wxID_OK)->IsEnabled() && Validate() && TransferDataFromWindow())
{
EndModal(true);
}
return;
}
///////////////////////////////////////////////////////////////////////////////
//
// EffectPanel
//
///////////////////////////////////////////////////////////////////////////////
class EffectPanel final : public wxPanelWrapper
{
public:
EffectPanel(wxWindow *parent)
: wxPanelWrapper(parent)
{
// This fools NVDA into not saying "Panel" when the dialog gets focus
SetName(wxT("\a"));
SetLabel(wxT("\a"));
mAcceptsFocus = true;
}
virtual ~EffectPanel()
{
}
// ============================================================================
// wxWindow implementation
// ============================================================================
bool AcceptsFocus() const override
{
return mAcceptsFocus;
}
// So that wxPanel is not included in Tab traversal, when required - see wxWidgets bug 15581
bool AcceptsFocusFromKeyboard() const override
{
return mAcceptsFocus;
}
// ============================================================================
// EffectPanel implementation
// ============================================================================
void SetAccept(bool accept)
{
mAcceptsFocus = accept;
}
private:
bool mAcceptsFocus;
};
///////////////////////////////////////////////////////////////////////////////
//
// EffectUIHost
//
///////////////////////////////////////////////////////////////////////////////
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
#include "../../images/Effect.h"
BEGIN_EVENT_TABLE(EffectUIHost, wxDialogWrapper)
EVT_INIT_DIALOG(EffectUIHost::OnInitDialog)
EVT_ERASE_BACKGROUND(EffectUIHost::OnErase)
EVT_PAINT(EffectUIHost::OnPaint)
EVT_CLOSE(EffectUIHost::OnClose)
EVT_BUTTON(wxID_APPLY, EffectUIHost::OnApply)
EVT_BUTTON(wxID_CANCEL, EffectUIHost::OnCancel)
2017-05-15 21:00:33 +00:00
EVT_BUTTON(wxID_HELP, EffectUIHost::OnHelp)
2015-04-22 20:55:58 +00:00
EVT_BUTTON(eDebugID, EffectUIHost::OnDebug)
EVT_BUTTON(kMenuID, EffectUIHost::OnMenu)
EVT_CHECKBOX(kEnableID, EffectUIHost::OnEnable)
EVT_BUTTON(kPlayID, EffectUIHost::OnPlay)
EVT_BUTTON(kRewindID, EffectUIHost::OnRewind)
EVT_BUTTON(kFFwdID, EffectUIHost::OnFFwd)
EVT_MENU(kSaveAsID, EffectUIHost::OnSaveAs)
EVT_MENU(kImportID, EffectUIHost::OnImport)
EVT_MENU(kExportID, EffectUIHost::OnExport)
EVT_MENU(kOptionsID, EffectUIHost::OnOptions)
EVT_MENU(kDefaultsID, EffectUIHost::OnDefaults)
EVT_MENU_RANGE(kUserPresetsID, kUserPresetsID + 999, EffectUIHost::OnUserPreset)
EVT_MENU_RANGE(kDeletePresetID, kDeletePresetID + 999, EffectUIHost::OnDeletePreset)
EVT_MENU_RANGE(kFactoryPresetsID, kFactoryPresetsID + 999, EffectUIHost::OnFactoryPreset)
END_EVENT_TABLE()
EffectUIHost::EffectUIHost(wxWindow *parent,
Effect *effect,
EffectUIClientInterface *client)
: wxDialogWrapper(parent, wxID_ANY, effect->GetName(),
wxDefaultPosition, wxDefaultSize,
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMINIMIZE_BOX | wxMAXIMIZE_BOX)
{
#if defined(__WXMAC__)
// Make sure the effect window actually floats above the main window
[[((NSView *)GetHandle()) window] setLevel:NSFloatingWindowLevel];
#endif
SetName(effect->GetName());
SetExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY);
mParent = parent;
mEffect = effect;
mClient = client;
mProject = GetActiveProject();
mInitialized = false;
mSupportsRealtime = false;
mDisableTransport = false;
mEnabled = true;
mPlayPos = 0.0;
mClient->SetHostUI(this);
}
EffectUIHost::~EffectUIHost()
{
CleanupRealtime();
if (mClient)
{
mClient->CloseUI();
mClient = NULL;
}
}
// ============================================================================
// wxWindow implementation
// ============================================================================
bool EffectUIHost::TransferDataToWindow()
{
return mEffect->TransferDataToWindow();
}
bool EffectUIHost::TransferDataFromWindow()
{
return mEffect->TransferDataFromWindow();
}
// ============================================================================
// wxDialog implementation
// ============================================================================
int EffectUIHost::ShowModal()
{
#if defined(__WXMSW__)
// Swap the Close and Apply buttons
wxSizer *sz = mApplyBtn->GetContainingSizer();
wxASSERT(mApplyBtn->GetParent()); // To justify safenew
wxButton *apply = safenew wxButton(mApplyBtn->GetParent(), wxID_APPLY);
sz->Replace(mCloseBtn, apply);
sz->Replace(mApplyBtn, mCloseBtn);
sz->Layout();
2016-08-10 05:40:31 +00:00
mApplyBtn->Destroy();
mApplyBtn = apply;
mApplyBtn->SetDefault();
mApplyBtn->SetLabel(wxGetStockLabel(wxID_OK, 0));
mCloseBtn->SetLabel(wxGetStockLabel(wxID_CANCEL, 0));
#else
mApplyBtn->SetLabel(wxGetStockLabel(wxID_OK));
mCloseBtn->SetLabel(wxGetStockLabel(wxID_CANCEL));
#endif
Layout();
return wxDialogWrapper::ShowModal();
}
// ============================================================================
// EffectUIHost implementation
// ============================================================================
bool EffectUIHost::Initialize()
{
EffectPanel *w = safenew EffectPanel(this);
{
auto vs = std::make_unique<wxBoxSizer>(wxVERTICAL);
{
auto hs = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
// Try to give the window a sensible default/minimum size
w->SetMinSize(wxSize(wxMax(600, mParent->GetSize().GetWidth() * 2 / 3),
mParent->GetSize().GetHeight() / 2));
mDisableTransport = !gAudioIO->IsAvailable(mProject);
mPlaying = gAudioIO->IsStreamActive(); // not exactly right, but will suffice
mCapturing = gAudioIO->IsStreamActive() && gAudioIO->GetNumCaptureChannels() > 0;
if (!mClient->PopulateUI(w))
{
return false;
}
hs->Add(w, 1, wxEXPAND);
vs->Add(hs.release(), 1, wxEXPAND);
}
wxPanel *buttonPanel = safenew wxPanelWrapper(this, wxID_ANY);
wxPanel *const bar = safenew wxPanelWrapper(buttonPanel, wxID_ANY);
// This fools NVDA into not saying "Panel" when the dialog gets focus
bar->SetName(wxT("\a"));
bar->SetLabel(wxT("\a"));
{
auto bs = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
mSupportsRealtime = mEffect->SupportsRealtime();
mIsGUI = mClient->IsGraphicalUI();
mIsBatch = mEffect->IsBatchProcessing();
wxBitmapButton *bb;
int margin = 0;
#if defined(__WXMAC__)
margin = 3; // I'm sure it's needed because of the order things are created...
#endif
if (!mIsGUI)
{
wxASSERT(bar); // To justify safenew
mMenuBtn = safenew wxButton(bar, kMenuID, _("&Manage"));
bs->Add(mMenuBtn, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin);
}
else
{
wxASSERT(bar); // To justify safenew
mMenuBtn = safenew wxBitmapButton(bar, kMenuID, CreateBitmap(effect_menu_xpm, true, false));
2014-12-19 09:05:32 +00:00
#if defined(__WXMAC__)
mMenuBtn->SetName(_("&Manage"));
2014-12-19 09:05:32 +00:00
#else
mMenuBtn->SetLabel(_("&Manage"));
2014-12-19 09:05:32 +00:00
#endif
bs->Add(mMenuBtn);
}
mMenuBtn->SetToolTip(_("Manage presets and options"));
bs->Add(5, 5);
if (!mIsBatch)
{
if (!mIsGUI)
{
if (mSupportsRealtime)
{
wxASSERT(bar); // To justify safenew
mPlayToggleBtn = safenew wxButton(bar, kPlayID, _("Start &Playback"));
mPlayToggleBtn->SetToolTip(_("Start and stop playback"));
bs->Add(mPlayToggleBtn, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin);
}
else if (mEffect->GetType() != EffectTypeAnalyze)
{
wxASSERT(bar); // To justify safenew
mPlayToggleBtn = safenew wxButton(bar, kPlayID, _("&Preview"));
mPlayToggleBtn->SetToolTip(_("Preview effect"));
bs->Add(mPlayToggleBtn, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin);
}
}
else
{
mPlayBM = CreateBitmap(effect_play_xpm, true, false);
mPlayDisabledBM = CreateBitmap(effect_play_disabled_xpm, true, false);
mStopBM = CreateBitmap(effect_stop_xpm, true, false);
mStopDisabledBM = CreateBitmap(effect_stop_disabled_xpm, true, false);
wxASSERT(bar); // To justify safenew
bb = safenew wxBitmapButton(bar, kPlayID, mPlayBM);
bb->SetBitmapDisabled(mPlayDisabledBM);
mPlayBtn = bb;
bs->Add(mPlayBtn);
if (!mSupportsRealtime)
{
mPlayBtn->SetToolTip(_("Preview effect"));
2014-12-19 09:05:32 +00:00
#if defined(__WXMAC__)
mPlayBtn->SetName(_("Preview effect"));
2014-12-19 09:05:32 +00:00
#else
mPlayBtn->SetLabel(_("&Preview effect"));
2014-12-19 09:05:32 +00:00
#endif
}
}
if (mSupportsRealtime)
{
if (!mIsGUI)
{
wxASSERT(bar); // To justify safenew
mRewindBtn = safenew wxButton(bar, kRewindID, _("Skip &Backward"));
bs->Add(mRewindBtn, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin);
}
else
{
wxASSERT(bar); // To justify safenew
bb = safenew wxBitmapButton(bar, kRewindID, CreateBitmap(effect_rewind_xpm, true, true));
bb->SetBitmapDisabled(CreateBitmap(effect_rewind_disabled_xpm, true, true));
mRewindBtn = bb;
#if defined(__WXMAC__)
mRewindBtn->SetName(_("Skip &Backward"));
#else
mRewindBtn->SetLabel(_("Skip &Backward"));
#endif
bs->Add(mRewindBtn);
}
mRewindBtn->SetToolTip(_("Skip backward"));
if (!mIsGUI)
{
wxASSERT(bar); // To justify safenew
mFFwdBtn = safenew wxButton(bar, kFFwdID, _("Skip &Forward"));
bs->Add(mFFwdBtn, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin);
}
else
{
wxASSERT(bar); // To justify safenew
bb = safenew wxBitmapButton(bar, kFFwdID, CreateBitmap(effect_ffwd_xpm, true, true));
bb->SetBitmapDisabled(CreateBitmap(effect_ffwd_disabled_xpm, true, true));
mFFwdBtn = bb;
2016-02-18 07:54:50 +00:00
#if defined(__WXMAC__)
mFFwdBtn->SetName(_("Skip &Foreward"));
2016-02-18 07:54:50 +00:00
#else
mFFwdBtn->SetLabel(_("Skip &Foreward"));
2016-02-18 07:54:50 +00:00
#endif
bs->Add(mFFwdBtn);
}
mFFwdBtn->SetToolTip(_("Skip forward"));
bs->Add(5, 5);
mEnableCb = safenew wxCheckBox(bar, kEnableID, _("&Enable"));
mEnableCb->SetValue(mEnabled);
mEnableCb->SetName(_("Enable"));
bs->Add(mEnableCb, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, margin);
}
}
bar->SetSizerAndFit(bs.release());
}
2017-05-15 21:00:33 +00:00
long buttons;
2017-05-19 17:20:05 +00:00
if ( mEffect->ManualPage().IsEmpty() && mEffect->HelpPage().IsEmpty()) {
buttons = eApplyButton + eCloseButton;
this->SetAcceleratorTable(wxNullAcceleratorTable);
}
else {
2017-05-15 21:00:33 +00:00
buttons = eApplyButton + eCloseButton + eHelpButton;
wxAcceleratorEntry entries[1];
#if defined(__WXMAC__)
// Is there a standard shortcut on Mac?
2017-05-15 21:00:33 +00:00
#else
entries[0].Set(wxACCEL_NORMAL, (int) WXK_F1, wxID_HELP);
#endif
wxAcceleratorTable accel(1, entries);
this->SetAcceleratorTable(accel);
}
if (mEffect->mUIDebug) {
buttons += eDebugButton;
}
2017-05-15 21:00:33 +00:00
buttonPanel->SetSizer(CreateStdButtonSizer(buttonPanel, buttons, bar).release());
vs->Add(buttonPanel, 0, wxEXPAND);
SetSizer(vs.release());
}
Layout();
Fit();
Center();
mApplyBtn = (wxButton *) FindWindow(wxID_APPLY);
mCloseBtn = (wxButton *) FindWindow(wxID_CANCEL);
UpdateControls();
w->SetAccept(!mIsGUI);
(!mIsGUI ? w : FindWindow(wxID_APPLY))->SetFocus();
LoadUserPresets();
InitializeRealtime();
SetMinSize(GetSize());
return true;
}
void EffectUIHost::OnInitDialog(wxInitDialogEvent & evt)
{
// Do default handling
wxDialogWrapper::OnInitDialog(evt);
#if wxCHECK_VERSION(3, 0, 0)
2015-05-16 20:40:29 +00:00
//#warning "check to see if this still needed in wx3"
#endif
// Pure hackage coming down the pike...
//
// I have no idea why, but if a wxTextCtrl is the first control in the
// panel, then its contents will not be automatically selected when the
// dialog is displayed.
//
// So, we do the selection manually.
wxTextCtrl *focused = wxDynamicCast(FindFocus(), wxTextCtrl);
if (focused)
{
focused->SelectAll();
}
}
void EffectUIHost::OnErase(wxEraseEvent & WXUNUSED(evt))
{
// Ignore it
}
void EffectUIHost::OnPaint(wxPaintEvent & WXUNUSED(evt))
{
wxPaintDC dc(this);
dc.Clear();
}
void EffectUIHost::OnClose(wxCloseEvent & WXUNUSED(evt))
{
DoCancel();
CleanupRealtime();
Hide();
mClient->CloseUI();
mClient = NULL;
Destroy();
}
2015-04-22 20:55:58 +00:00
void EffectUIHost::OnApply(wxCommandEvent & evt)
{
// On wxGTK (wx2.8.12), the default action is still executed even if
// the button is disabled. This appears to affect all wxDialogs, not
// just our Effects dialogs. So, this is a only temporary workaround
// for legacy effects that disable the OK button. Hopefully this has
// been corrected in wx3.
if (!FindWindow(wxID_APPLY)->IsEnabled())
{
return;
}
2015-05-17 06:02:52 +00:00
// Honor the "select all if none" preference...a little hackish, but whatcha gonna do...
if (!mIsBatch && mEffect->GetType() != EffectTypeGenerate && mProject->mViewInfo.selectedRegion.isPoint())
{
auto flags = AlwaysEnabledFlag;
2015-05-17 06:02:52 +00:00
bool allowed = mProject->TryToMakeActionAllowed(flags,
WaveTracksSelectedFlag | TimeSelectedFlag,
WaveTracksSelectedFlag | TimeSelectedFlag);
if (!allowed)
{
wxMessageBox(_("You must select audio in the project window."));
return;
}
}
if (!mClient->ValidateUI())
{
return;
}
// This will take care of calling TransferDataFromWindow()
if (!mEffect->SaveUserPreset(mEffect->GetCurrentSettingsGroup()))
{
return;
}
2015-04-22 20:55:58 +00:00
mEffect->mUIResultID = evt.GetId();
if (IsModal())
{
mDismissed = true;
EndModal(true);
Close();
return;
}
// Progress dialog no longer yields, so this "shouldn't" be necessary (yet to be proven
// for sure), but it is a nice visual cue that something is going on.
mApplyBtn->Disable();
auto cleanup = finally( [&] { mApplyBtn->Enable(); } );
mEffect->Apply();
return;
}
void EffectUIHost::DoCancel()
{
if (!mDismissed) {
mEffect->mUIResultID = wxID_CANCEL;
2015-04-22 20:55:58 +00:00
if (IsModal())
EndModal(false);
else
Hide();
mDismissed = true;
}
}
void EffectUIHost::OnCancel(wxCommandEvent & evt)
{
DoCancel();
Close();
return;
}
2017-05-15 21:00:33 +00:00
void EffectUIHost::OnHelp(wxCommandEvent & WXUNUSED(event))
{
2017-05-19 17:20:05 +00:00
if (mEffect->GetFamily().IsSameAs(NYQUISTEFFECTS_FAMILY) && (mEffect->ManualPage().IsEmpty())) {
// Old ShowHelpDialog required when there is no on-line manual.
// Always use default web browser to allow full-featured HTML pages.
HelpSystem::ShowHelpDialog(FindWindow(wxID_HELP), mEffect->HelpPage(), wxEmptyString, true, true);
}
else {
// otherwise use the new ShowHelpDialog
HelpSystem::ShowHelpDialog(FindWindow(wxID_HELP), mEffect->ManualPage(), true);
}
2017-05-15 21:00:33 +00:00
}
2015-04-22 20:55:58 +00:00
void EffectUIHost::OnDebug(wxCommandEvent & evt)
{
OnApply(evt);
mEffect->mUIResultID = evt.GetId();
return;
}
void EffectUIHost::OnMenu(wxCommandEvent & WXUNUSED(evt))
{
wxMenu menu;
LoadUserPresets();
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
if (mUserPresets.GetCount() == 0)
{
menu.Append(kUserPresetsDummyID, _("User Presets"))->Enable(false);
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
}
else
{
2016-08-10 05:32:13 +00:00
auto sub = std::make_unique<wxMenu>();
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
for (size_t i = 0, cnt = mUserPresets.GetCount(); i < cnt; i++)
{
sub->Append(kUserPresetsID + i, mUserPresets[i]);
}
2016-08-10 05:32:13 +00:00
menu.Append(0, _("User Presets"), sub.release());
}
menu.Append(kSaveAsID, _("Save Preset..."));
if (mUserPresets.GetCount() == 0)
{
menu.Append(kDeletePresetDummyID, _("Delete Preset"))->Enable(false);
}
else
{
2016-08-10 05:32:13 +00:00
auto sub = std::make_unique<wxMenu>();
for (size_t i = 0, cnt = mUserPresets.GetCount(); i < cnt; i++)
{
sub->Append(kDeletePresetID + i, mUserPresets[i]);
}
2016-08-10 05:32:13 +00:00
menu.Append(0, _("Delete Preset"), sub.release());
}
menu.AppendSeparator();
wxArrayString factory = mEffect->GetFactoryPresets();
{
2016-08-10 05:32:13 +00:00
auto sub = std::make_unique<wxMenu>();
sub->Append(kDefaultsID, _("Defaults"));
if (factory.GetCount() > 0)
{
2016-08-10 05:32:13 +00:00
sub->AppendSeparator();
for (size_t i = 0, cnt = factory.GetCount(); i < cnt; i++)
{
2016-08-10 05:32:13 +00:00
wxString label = factory[i];
if (label.IsEmpty())
{
label = _("None");
}
2016-08-10 05:32:13 +00:00
sub->Append(kFactoryPresetsID + i, label);
}
}
2016-08-10 05:32:13 +00:00
menu.Append(0, _("Factory Presets"), sub.release());
}
menu.AppendSeparator();
menu.Append(kImportID, _("Import..."))->Enable(mClient->CanExportPresets());
menu.Append(kExportID, _("Export..."))->Enable(mClient->CanExportPresets());
menu.AppendSeparator();
menu.Append(kOptionsID, _("Options..."))->Enable(mClient->HasOptions());
menu.AppendSeparator();
2016-08-10 05:32:13 +00:00
{
auto sub = std::make_unique<wxMenu>();
2016-08-10 05:32:13 +00:00
sub->Append(kDummyID, wxString::Format(_("Type: %s"), mEffect->GetFamily().c_str()));
sub->Append(kDummyID, wxString::Format(_("Name: %s"), mEffect->GetName().c_str()));
sub->Append(kDummyID, wxString::Format(_("Version: %s"), mEffect->GetVersion().c_str()));
sub->Append(kDummyID, wxString::Format(_("Vendor: %s"), mEffect->GetVendor().c_str()));
sub->Append(kDummyID, wxString::Format(_("Description: %s"), mEffect->GetDescription().c_str()));
2016-08-10 05:32:13 +00:00
menu.Append(0, _("About"), sub.release());
}
2015-05-24 09:47:24 +00:00
wxWindow *btn = FindWindow(kMenuID);
wxRect r = btn->GetRect();
btn->PopupMenu(&menu, r.GetLeft(), r.GetBottom());
}
void EffectUIHost::OnEnable(wxCommandEvent & WXUNUSED(evt))
{
mEnabled = mEnableCb->GetValue();
if (mEnabled)
{
if (!mClient->ValidateUI()) {
// If we're previewing we should still be able to stop playback
// so don't disable transport buttons.
// mEffect->EnableApply(false); // currently this would also disable transport buttons.
// The preferred behaviour is currently undecided, so for now
// just disallow enabling until settings are valid.
mEnabled = false;
mEnableCb->SetValue(mEnabled);
return;
}
mEffect->RealtimeResume();
}
else
{
mEffect->RealtimeSuspend();
}
UpdateControls();
}
void EffectUIHost::OnPlay(wxCommandEvent & WXUNUSED(evt))
{
if (!mSupportsRealtime)
{
if (!mClient->ValidateUI() || !mEffect->TransferDataFromWindow())
{
return;
}
mEffect->Preview(false);
return;
}
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
if (mPlaying)
{
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
mPlayPos = gAudioIO->GetStreamTime();
mProject->GetControlToolBar()->StopPlaying();
}
else
{
if (mProject->IsPlayRegionLocked())
{
double t0, t1;
mProject->GetPlayRegion(&t0, &t1);
mRegion.setTimes(t0, t1);
mPlayPos = mRegion.t0();
}
else if (mProject->mViewInfo.selectedRegion.t0() != mRegion.t0() ||
mProject->mViewInfo.selectedRegion.t1() != mRegion.t1())
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
{
mRegion = mProject->mViewInfo.selectedRegion;
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
mPlayPos = mRegion.t0();
}
if (mPlayPos > mRegion.t1())
{
mPlayPos = mRegion.t1();
}
mProject->GetControlToolBar()->PlayPlayRegion
(SelectedRegion(mPlayPos, mRegion.t1()),
mProject->GetDefaultPlayOptions(), PlayMode::normalPlay);
}
}
void EffectUIHost::OnRewind(wxCommandEvent & WXUNUSED(evt))
{
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
if (mPlaying)
{
double seek;
gPrefs->Read(wxT("/AudioIO/SeekShortPeriod"), &seek, 1.0);
double pos = gAudioIO->GetStreamTime();
if (pos - seek < mRegion.t0())
{
seek = pos - mRegion.t0();
}
gAudioIO->SeekStream(-seek);
}
else
{
mPlayPos = mRegion.t0();
}
}
void EffectUIHost::OnFFwd(wxCommandEvent & WXUNUSED(evt))
{
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
if (mPlaying)
{
double seek;
gPrefs->Read(wxT("/AudioIO/SeekShortPeriod"), &seek, 1.0);
double pos = gAudioIO->GetStreamTime();
if (mRegion.t0() < mRegion.t1() && pos + seek > mRegion.t1())
{
seek = mRegion.t1() - pos;
}
gAudioIO->SeekStream(seek);
}
else
{
// It allows to play past end of selection...probably useless
mPlayPos = mRegion.t1();
}
}
void EffectUIHost::OnPlayback(wxCommandEvent & evt)
{
evt.Skip();
if (evt.GetInt() != 0)
{
if (evt.GetEventObject() != mProject)
{
mDisableTransport = true;
}
else
{
mPlaying = true;
}
}
else
{
mDisableTransport = false;
mPlaying = false;
}
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
if (mPlaying)
{
mRegion = mProject->mViewInfo.selectedRegion;
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
mPlayPos = mRegion.t0();
}
UpdateControls();
}
void EffectUIHost::OnCapture(wxCommandEvent & evt)
{
evt.Skip();
if (evt.GetInt() != 0)
{
if (evt.GetEventObject() != mProject)
{
mDisableTransport = true;
}
else
{
mCapturing = true;
}
}
else
{
mDisableTransport = false;
mCapturing = false;
}
UpdateControls();
}
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
void EffectUIHost::OnUserPreset(wxCommandEvent & evt)
{
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
int preset = evt.GetId() - kUserPresetsID;
mEffect->LoadUserPreset(mEffect->GetUserPresetsGroup(mUserPresets[preset]));
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
return;
}
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
void EffectUIHost::OnFactoryPreset(wxCommandEvent & evt)
{
mEffect->LoadFactoryPreset(evt.GetId() - kFactoryPresetsID);
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
return;
}
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
void EffectUIHost::OnDeletePreset(wxCommandEvent & evt)
{
wxString preset = mUserPresets[evt.GetId() - kDeletePresetID];
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
int res = wxMessageBox(wxString::Format(_("Are you sure you want to delete \"%s\"?"), preset.c_str()),
_("Delete Preset"),
wxICON_QUESTION | wxYES_NO);
if (res == wxYES)
{
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
mEffect->RemovePrivateConfigSubgroup(mEffect->GetUserPresetsGroup(preset));
}
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
LoadUserPresets();
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
return;
}
void EffectUIHost::OnSaveAs(wxCommandEvent & WXUNUSED(evt))
{
wxTextCtrl *text;
wxString name;
wxDialogWrapper dlg(this, wxID_ANY, wxString(_("Save Preset")));
ShuttleGui S(&dlg, eIsCreating);
S.StartPanel();
{
S.StartVerticalLay(1);
{
S.StartHorizontalLay(wxALIGN_LEFT, 0);
{
text = S.AddTextBox(_("Preset name:"), name, 30);
}
S.EndHorizontalLay();
S.SetBorder(10);
S.AddStandardButtons();
}
S.EndVerticalLay();
}
S.EndPanel();
dlg.SetSize(dlg.GetSizer()->GetMinSize());
dlg.Center();
while (true)
{
int rc = dlg.ShowModal();
if (rc != wxID_OK)
{
break;
}
name = text->GetValue();
if (name.IsEmpty())
{
wxMessageDialog md(this,
_("You must specify a name"),
_("Save Preset"));
md.Center();
md.ShowModal();
continue;
}
if (mUserPresets.Index(name) != wxNOT_FOUND)
{
wxMessageDialog md(this,
_("Preset already exists.\n\nReplace?"),
_("Save Preset"),
wxYES_NO | wxCANCEL | wxICON_EXCLAMATION);
md.Center();
int choice = md.ShowModal();
if (choice == wxID_CANCEL)
{
break;
}
if (choice == wxID_NO)
{
continue;
}
}
mEffect->SaveUserPreset(mEffect->GetUserPresetsGroup(name));
LoadUserPresets();
break;
}
return;
}
void EffectUIHost::OnImport(wxCommandEvent & WXUNUSED(evt))
{
mClient->ImportPresets();
LoadUserPresets();
return;
}
void EffectUIHost::OnExport(wxCommandEvent & WXUNUSED(evt))
{
// may throw
// exceptions are handled in AudacityApp::OnExceptionInMainLoop
mClient->ExportPresets();
return;
}
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
void EffectUIHost::OnOptions(wxCommandEvent & WXUNUSED(evt))
{
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
mClient->ShowOptions();
return;
}
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
void EffectUIHost::OnDefaults(wxCommandEvent & WXUNUSED(evt))
{
mEffect->LoadFactoryDefaults();
return;
}
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
wxBitmap EffectUIHost::CreateBitmap(const char *xpm[], bool up, bool pusher)
{
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
wxMemoryDC dc;
wxBitmap pic(xpm);
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
wxBitmap mod(pic.GetWidth() + 6, pic.GetHeight() + 6);
dc.SelectObject(mod);
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
#if !defined(__WXMAC__)
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
#if defined(__WXGTK__)
wxColour newColour = wxSystemSettings::GetColour(wxSYS_COLOUR_BACKGROUND);
#elif defined(__WXMSW__)
wxColour newColour = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
#endif
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
dc.SetBackground(wxBrush(newColour));
dc.Clear();
#endif
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
int offset = 3;
if (pusher)
{
if (!up)
{
offset += 1;
}
}
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
dc.DrawBitmap(pic, offset, offset, true);
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
dc.SelectObject(wxNullBitmap);
return mod;
}
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
void EffectUIHost::UpdateControls()
{
if (mIsBatch)
{
return;
}
if (mCapturing || mDisableTransport)
{
// Don't allow focus to get trapped
wxWindow *focus = FindFocus();
if (focus == mRewindBtn || focus == mFFwdBtn || focus == mPlayBtn || focus == mEnableCb)
{
mCloseBtn->SetFocus();
}
}
Resolves reported bugs and (most) recommendations All: Export/Import now disabled if the Effect (family) doesn't support it Options disabled if the Effect (family) doesn't support it Standarized on "Latency compensation" instead of "Buffer delay compensation" Correct loading/saving of factory default settings Fixed "Mannage" to be "Manage" Removed conditional code since we're keeping the transport buttons Play bases state on actual playback status Play no longer monkeys with selection Play will now start from where it left off IF: The user stops the playback via the Effect Stop button If the user wants to restart from the beginning of the selection then the user can click Rewind while stopped. Rewind will not go past start of selection (sorry Steve ;-)) If Rewind is clicked while not playing, playback will next start at beginning of selection. Fast Forward will stop at end of selection However, if FFwd is clicked while not playing, it will put playback at the end of selection and the next time the user clicks the Effect play button, playback will continue from the end of selection to the end of track. Deleting a preset now prompts user to confirm Button faces should now look a little better Bypass (should we rename that???) button now grays when disabled Audio Units: Corrected all user visible "AudioUnit" strings to be "Audio Unit" Removed unneeded "Buffer Size" in settings dialog Only uses latency if user said it was okay Ladspa: Added settings dialog to allow control of latency usage Removed unused "user selectable" buffer size Only use latency if user wants it Refresh controls when presets are loaded VST: Removed unused "Rescan at startup" setting Propogate parameter loads to slave effects
2014-12-04 06:10:27 +00:00
mApplyBtn->Enable(!mCapturing);
if (mEffect->GetType() != EffectTypeAnalyze)
{
(!mIsGUI ? mPlayToggleBtn : mPlayBtn)->Enable(!(mCapturing || mDisableTransport));
}
if (mSupportsRealtime)
{
mRewindBtn->Enable(!(mCapturing || mDisableTransport));
mFFwdBtn->Enable(!(mCapturing || mDisableTransport));
mEnableCb->Enable(!(mCapturing || mDisableTransport));
wxBitmapButton *bb;
if (mPlaying)
{
if (!mIsGUI)
{
/* i18n-hint: The access key "&P" should be the same in
"Stop &Playback" and "Start &Playback" */
mPlayToggleBtn->SetLabel(_("Stop &Playback"));
mPlayToggleBtn->Refresh();
}
else
{
bb = (wxBitmapButton *) mPlayBtn;
bb->SetBitmapLabel(mStopBM);
bb->SetBitmapDisabled(mStopDisabledBM);
bb->SetToolTip(_("Stop"));
#if defined(__WXMAC__)
bb->SetName(_("Stop &Playback"));
#else
bb->SetLabel(_("Stop &Playback"));
#endif
}
}
else
{
if (!mIsGUI)
{
/* i18n-hint: The access key "&P" should be the same in
"Stop &Playback" and "Start &Playback" */
mPlayToggleBtn->SetLabel(_("Start &Playback"));
mPlayToggleBtn->Refresh();
}
else
{
bb = (wxBitmapButton *) mPlayBtn;
bb->SetBitmapLabel(mPlayBM);
bb->SetBitmapDisabled(mPlayDisabledBM);
bb->SetToolTip(_("Play"));
#if defined(__WXMAC__)
bb->SetName(_("Start &Playback"));
#else
bb->SetLabel(_("Start &Playback"));
#endif
}
}
}
}
void EffectUIHost::LoadUserPresets()
{
mUserPresets.Clear();
mEffect->GetPrivateConfigSubgroups(mEffect->GetUserPresetsGroup(wxEmptyString), mUserPresets);
mUserPresets.Sort();
return;
}
void EffectUIHost::InitializeRealtime()
{
if (mSupportsRealtime && !mInitialized)
{
EffectManager::Get().RealtimeAddEffect(mEffect);
wxTheApp->Connect(EVT_AUDIOIO_PLAYBACK,
wxCommandEventHandler(EffectUIHost::OnPlayback),
NULL,
this);
wxTheApp->Connect(EVT_AUDIOIO_CAPTURE,
wxCommandEventHandler(EffectUIHost::OnCapture),
NULL,
this);
mInitialized = true;
}
}
void EffectUIHost::CleanupRealtime()
{
if (mSupportsRealtime && mInitialized)
{
wxTheApp->Disconnect(EVT_AUDIOIO_PLAYBACK,
wxCommandEventHandler(EffectUIHost::OnPlayback),
NULL,
this);
wxTheApp->Disconnect(EVT_AUDIOIO_CAPTURE,
wxCommandEventHandler(EffectUIHost::OnCapture),
NULL,
this);
EffectManager::Get().RealtimeRemoveEffect(mEffect);
mInitialized = false;
}
}
///////////////////////////////////////////////////////////////////////////////
//
// EffectPresetsDialog
//
///////////////////////////////////////////////////////////////////////////////
enum
{
ID_Type = 10000
};
BEGIN_EVENT_TABLE(EffectPresetsDialog, wxDialogWrapper)
EVT_CHOICE(ID_Type, EffectPresetsDialog::OnType)
EVT_LISTBOX_DCLICK(wxID_ANY, EffectPresetsDialog::OnOk)
EVT_BUTTON(wxID_OK, EffectPresetsDialog::OnOk)
EVT_BUTTON(wxID_CANCEL, EffectPresetsDialog::OnCancel)
END_EVENT_TABLE()
EffectPresetsDialog::EffectPresetsDialog(wxWindow *parent, Effect *effect)
: wxDialogWrapper(parent, wxID_ANY, wxString(_("Select Preset")))
{
ShuttleGui S(this, eIsCreating);
S.StartVerticalLay();
{
S.StartTwoColumn();
S.SetStretchyCol(1);
{
wxArrayString empty;
S.AddPrompt(_("Type:"));
mType = S.Id(ID_Type).AddChoice(wxT(""), wxT(""), &empty);
mType->SetSelection(0);
S.AddPrompt(_("&Preset:"));
mPresets = S.AddListBox(&empty, wxLB_SINGLE | wxLB_NEEDED_SB );
}
S.EndTwoColumn();
S.AddStandardButtons();
}
S.EndVerticalLay();
mUserPresets = effect->GetUserPresets();
mFactoryPresets = effect->GetFactoryPresets();
if (mUserPresets.GetCount() > 0)
{
mType->Append(_("User Presets"));
}
if (mFactoryPresets.GetCount() > 0)
{
mType->Append(_("Factory Presets"));
}
if (effect->HasCurrentSettings())
{
mType->Append(_("Current Settings"));
}
if (effect->HasFactoryDefaults())
{
mType->Append(_("Factory Defaults"));
}
UpdateUI();
}
EffectPresetsDialog::~EffectPresetsDialog()
{
}
wxString EffectPresetsDialog::GetSelected() const
{
return mSelection;
}
void EffectPresetsDialog::SetSelected(const wxString & parms)
{
wxString preset = parms;
if (preset.StartsWith(Effect::kUserPresetIdent))
{
preset.Replace(Effect::kUserPresetIdent, wxEmptyString, false);
SetPrefix(_("User Presets"), preset);
}
else if (preset.StartsWith(Effect::kFactoryPresetIdent))
{
preset.Replace(Effect::kFactoryPresetIdent, wxEmptyString, false);
SetPrefix(_("Factory Presets"), preset);
}
else if (preset.StartsWith(Effect::kCurrentSettingsIdent))
{
SetPrefix(_("Current Settings"), wxEmptyString);
}
else if (preset.StartsWith(Effect::kFactoryDefaultsIdent))
{
SetPrefix(_("Factory Defaults"), wxEmptyString);
}
}
void EffectPresetsDialog::SetPrefix(const wxString & type, const wxString & prefix)
{
mType->SetStringSelection(type);
if (type.IsSameAs(_("User Presets")))
{
mPresets->Clear();
mPresets->Append(mUserPresets);
mPresets->Enable(true);
mPresets->SetStringSelection(prefix);
if (mPresets->GetSelection() == wxNOT_FOUND)
{
mPresets->SetSelection(0);
}
mSelection = Effect::kUserPresetIdent + mPresets->GetStringSelection();
}
else if (type.IsSameAs(_("Factory Presets")))
{
mPresets->Clear();
for (size_t i = 0, cnt = mFactoryPresets.GetCount(); i < cnt; i++)
{
wxString label = mFactoryPresets[i];
if (label.IsEmpty())
{
label = _("None");
}
mPresets->Append(label);
}
mPresets->Enable(true);
mPresets->SetStringSelection(prefix);
if (mPresets->GetSelection() == wxNOT_FOUND)
{
mPresets->SetSelection(0);
}
mSelection = Effect::kFactoryPresetIdent + mPresets->GetStringSelection();
}
else if (type.IsSameAs(_("Current Settings")))
{
mPresets->Clear();
mPresets->Enable(false);
mSelection = Effect::kCurrentSettingsIdent;
}
else if (type.IsSameAs(_("Factory Defaults")))
{
mPresets->Clear();
mPresets->Enable(false);
mSelection = Effect::kFactoryDefaultsIdent;
}
}
void EffectPresetsDialog::UpdateUI()
{
int selected = mType->GetSelection();
if (selected == wxNOT_FOUND)
{
selected = 0;
mType->SetSelection(selected);
}
wxString type = mType->GetString(selected);
if (type.IsSameAs(_("User Presets")))
{
selected = mPresets->GetSelection();
if (selected == wxNOT_FOUND)
{
selected = 0;
}
mPresets->Clear();
mPresets->Append(mUserPresets);
mPresets->Enable(true);
mPresets->SetSelection(selected);
mSelection = Effect::kUserPresetIdent + mPresets->GetString(selected);
}
else if (type.IsSameAs(_("Factory Presets")))
{
selected = mPresets->GetSelection();
if (selected == wxNOT_FOUND)
{
selected = 0;
}
mPresets->Clear();
for (size_t i = 0, cnt = mFactoryPresets.GetCount(); i < cnt; i++)
{
wxString label = mFactoryPresets[i];
if (label.IsEmpty())
{
label = _("None");
}
mPresets->Append(label);
}
mPresets->Enable(true);
mPresets->SetSelection(selected);
mSelection = Effect::kFactoryPresetIdent + mPresets->GetString(selected);
}
else if (type.IsSameAs(_("Current Settings")))
{
mPresets->Clear();
mPresets->Enable(false);
mSelection = Effect::kCurrentSettingsIdent;
}
else if (type.IsSameAs(_("Factory Defaults")))
{
mPresets->Clear();
mPresets->Enable(false);
mSelection = Effect::kFactoryDefaultsIdent;
}
}
void EffectPresetsDialog::OnType(wxCommandEvent & WXUNUSED(evt))
{
UpdateUI();
}
void EffectPresetsDialog::OnOk(wxCommandEvent & WXUNUSED(evt))
{
UpdateUI();
EndModal(true);
}
void EffectPresetsDialog::OnCancel(wxCommandEvent & WXUNUSED(evt))
{
mSelection = wxEmptyString;
EndModal(false);
}