1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-16 16:10:06 +02:00

More effect changes to new format and realtime preview

Main effect host processing extended to support generate
effects and sync locked tracks.

Ladspa updated to utilize new generate support.

I'll address Analyze plugins when I get to the SBSMS ones.

Shared and private config changes are flushed immediately.

Cancel button restored to VST and Ladspa dialogs.  This
also restores the ESC button functionality.

Current parameters saved with Apply or Ok clicked...not
when Audacity ends.

Ladspa and VST effects with that reports no input and
no outputs are now ignored.

Ladspa effects providing a latency value is now handled.

Ladspa generator effects now use the TimeTextCtrl for
specifying duration.
This commit is contained in:
lllucius 2014-11-07 09:54:04 +00:00
parent ed1338cdec
commit 7bb4b7c941
8 changed files with 471 additions and 214 deletions

View File

@ -86,9 +86,9 @@ class EffectHostInterface : public EffectIdentInterface,
public: public:
virtual ~EffectHostInterface() {}; virtual ~EffectHostInterface() {};
// Both of these are pretty much hacks until everything has been converted and virtual double GetDuration() = 0;
// it's decided if the client will display the interface or if that'll be done virtual bool SetDuration(double seconds) = 0;
// by the host.
virtual bool Apply() = 0; virtual bool Apply() = 0;
virtual void Preview() = 0; virtual void Preview() = 0;
}; };

View File

@ -2006,7 +2006,6 @@ PluginDescriptor & PluginManager::CreatePlugin(IdentInterface *ident, PluginType
// This will either create a new entry or replace an existing entry // This will either create a new entry or replace an existing entry
mPlugins[plug.GetID()] = plug; mPlugins[plug.GetID()] = plug;
PluginDescriptor &p = mPlugins[plug.GetID()];
return mPlugins[plug.GetID()]; return mPlugins[plug.GetID()];
} }
@ -2116,6 +2115,10 @@ bool PluginManager::SetConfig(const wxString & key, const wxString & value)
{ {
wxString wxval = value.c_str(); wxString wxval = value.c_str();
result = mConfig->Write(key, wxval); result = mConfig->Write(key, wxval);
if (result)
{
result = mConfig->Flush();
}
} }
return result; return result;
@ -2128,6 +2131,10 @@ bool PluginManager::SetConfig(const wxString & key, const int & value)
if (mConfig && !key.empty()) if (mConfig && !key.empty())
{ {
result = mConfig->Write(key, value); result = mConfig->Write(key, value);
if (result)
{
result = mConfig->Flush();
}
} }
return result; return result;
@ -2140,6 +2147,10 @@ bool PluginManager::SetConfig(const wxString & key, const bool & value)
if (mConfig && !key.empty()) if (mConfig && !key.empty())
{ {
result = mConfig->Write(key, value); result = mConfig->Write(key, value);
if (result)
{
result = mConfig->Flush();
}
} }
return result; return result;
@ -2152,6 +2163,10 @@ bool PluginManager::SetConfig(const wxString & key, const float & value)
if (mConfig && !key.empty()) if (mConfig && !key.empty())
{ {
result = mConfig->Write(key, value); result = mConfig->Write(key, value);
if (result)
{
result = mConfig->Flush();
}
} }
return result; return result;
@ -2164,6 +2179,10 @@ bool PluginManager::SetConfig(const wxString & key, const double & value)
if (mConfig && !key.empty()) if (mConfig && !key.empty())
{ {
result = mConfig->Write(key, value); result = mConfig->Write(key, value);
if (result)
{
result = mConfig->Flush();
}
} }
return result; return result;
@ -2176,6 +2195,10 @@ bool PluginManager::SetConfig(const wxString & key, const sampleCount & value)
if (mConfig && !key.empty()) if (mConfig && !key.empty())
{ {
result = mConfig->Write(key, wxString::Format(wxT("%d"), (int) value)); result = mConfig->Write(key, wxString::Format(wxT("%d"), (int) value));
if (result)
{
result = mConfig->Flush();
}
} }
return result; return result;

View File

@ -75,7 +75,7 @@ Effect::Effect()
mTracks = NULL; mTracks = NULL;
mOutputTracks = NULL; mOutputTracks = NULL;
mOutputTracksType = Track::None; mOutputTracksType = Track::None;
mLength = 0; mDuration = 0.0;
mNumTracks = 0; mNumTracks = 0;
mNumGroups = 0; mNumGroups = 0;
mProgress = NULL; mProgress = NULL;
@ -246,8 +246,33 @@ bool Effect::IsInteractive()
// EffectHostInterface implementation // EffectHostInterface implementation
double Effect::GetDuration()
{
if (mT1 > mT0)
{
return mT1 - mT0;
}
if (mClient->GetType() == EffectTypeGenerate)
{
return sDefaultGenerateLen;
}
return 0;
}
bool Effect::SetDuration(double seconds)
{
mDuration = seconds;
return true;
}
bool Effect::Apply() bool Effect::Apply()
{ {
// This is absolute hackage...but easy
//
// It should callback to the EffectManager to kick off the processing
GetActiveProject()->OnEffect(GetID(), true); GetActiveProject()->OnEffect(GetID(), true);
return true; return true;
@ -384,18 +409,20 @@ bool Effect::SetPrivateConfig(const wxString & group, const wxString & key, cons
bool Effect::Startup(EffectClientInterface *client) bool Effect::Startup(EffectClientInterface *client)
{ {
// Need to set host now so client startup can use our services
client->SetHost(this);
// Bail if the client startup fails
if (!client->Startup())
{
return false;
}
// Let destructor know we need to be shutdown // Let destructor know we need to be shutdown
mClient = client; mClient = client;
// Need to set host now so client startup can use our services
mClient->SetHost(this);
// Bail if the client startup fails
if (!mClient->Startup())
{
mClient = NULL;
return false;
}
mNumAudioIn = mClient->GetAudioInCount(); mNumAudioIn = mClient->GetAudioInCount();
mNumAudioOut = mClient->GetAudioOutCount(); mNumAudioOut = mClient->GetAudioOutCount();
@ -416,6 +443,8 @@ bool Effect::Startup(EffectClientInterface *client)
} }
SetEffectFlags(flags); SetEffectFlags(flags);
return true;
} }
// All legacy effects should have this overridden // All legacy effects should have this overridden
@ -588,7 +617,9 @@ bool Effect::Process()
return false; return false;
} }
CopyInputTracks(); bool isGenerator = mClient->GetType() == EffectTypeGenerate;
CopyInputTracks(Track::All);
bool bGoodResult = true; bool bGoodResult = true;
mInBuffer = NULL; mInBuffer = NULL;
@ -601,15 +632,34 @@ bool Effect::Process()
TrackListIterator iter(mOutputTracks); TrackListIterator iter(mOutputTracks);
int count = 0; int count = 0;
bool clear = false; bool clear = false;
WaveTrack *left = (WaveTrack *) iter.First(); Track* t = iter.First();
while (left)
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; WaveTrack *right;
sampleCount len; sampleCount len;
sampleCount leftStart; sampleCount leftStart;
sampleCount rightStart; sampleCount rightStart;
GetSamples(left, &leftStart, &len); if (!isGenerator)
{
GetSamples(left, &leftStart, &len);
}
else
{
len = 0;
leftStart = 0;
}
mNumChannels = 1; mNumChannels = 1;
@ -618,7 +668,10 @@ bool Effect::Process()
if (left->GetLinked() && mNumAudioIn > 1) if (left->GetLinked() && mNumAudioIn > 1)
{ {
right = (WaveTrack *) iter.Next(); right = (WaveTrack *) iter.Next();
GetSamples(right, &rightStart, &len); if (!isGenerator)
{
GetSamples(right, &rightStart, &len);
}
clear = false; clear = false;
mNumChannels = 2; mNumChannels = 2;
} }
@ -725,7 +778,6 @@ bool Effect::Process()
break; break;
} }
left = (WaveTrack *) iter.Next();
count++; count++;
} }
@ -797,6 +849,24 @@ bool Effect::ProcessTrack(int count,
sampleCount outputBufferCnt = 0; sampleCount outputBufferCnt = 0;
bool cleared = false; bool cleared = false;
WaveTrack *genLeft = NULL;
WaveTrack *genRight = NULL;
sampleCount genLength = 0;
bool isGenerator = mClient->GetType() == EffectTypeGenerate;
if (isGenerator)
{
genLength = left->GetRate() * mDuration;
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 // Call the effect until we run out of input or delayed samples
while (inputRemaining || delayRemaining) while (inputRemaining || delayRemaining)
{ {
@ -910,28 +980,31 @@ bool Effect::ProcessTrack(int count,
} }
// Get the current number of delayed samples and accumulate // Get the current number of delayed samples and accumulate
sampleCount delay = mClient->GetLatency(); if (!isGenerator)
curDelay += delay; {
delayRemaining += delay; sampleCount delay = mClient->GetLatency();
curDelay += delay;
delayRemaining += delay;
// If the plugin has delayed the output by more samples than our current // If the plugin has delayed the output by more samples than our current
// block size, then we leave the output pointers alone. This effectively // block size, then we leave the output pointers alone. This effectively
// removes those delayed samples from the output buffer. // removes those delayed samples from the output buffer.
if (curDelay >= curBlockSize) 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)
{
curBlockSize -= curDelay;
for (int i = 0; i < mNumChannels; i++)
{ {
memmove(mOutBufPos[i], mOutBufPos[i] + curDelay, SAMPLE_SIZE(floatSample) * 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)
{
curBlockSize -= curDelay;
for (int i = 0; i < mNumChannels; i++)
{
memmove(mOutBufPos[i], mOutBufPos[i] + curDelay, SAMPLE_SIZE(floatSample) * curBlockSize);
}
curDelay = 0;
} }
curDelay = 0;
} }
// //
@ -949,11 +1022,22 @@ bool Effect::ProcessTrack(int count,
// Output buffers have filled // Output buffers have filled
else else
{ {
// Write them out if (!isGenerator)
left->Set((samplePtr) mOutBuffer[0], floatSample, outLeftPos, outputBufferCnt);
if (right)
{ {
right->Set((samplePtr) mOutBuffer[1], floatSample, outRightPos, outputBufferCnt); // Write them out
left->Set((samplePtr) mOutBuffer[0], floatSample, outLeftPos, outputBufferCnt);
if (right)
{
right->Set((samplePtr) mOutBuffer[1], floatSample, outRightPos, outputBufferCnt);
}
}
else
{
genLeft->Append((samplePtr) mOutBuffer[0], floatSample, outputBufferCnt);
if (genRight)
{
genRight->Append((samplePtr) mOutBuffer[1], floatSample, outputBufferCnt);
}
} }
// Reset the output buffer positions // Reset the output buffer positions
@ -996,10 +1080,37 @@ bool Effect::ProcessTrack(int count,
// Put any remaining output // Put any remaining output
if (outputBufferCnt) if (outputBufferCnt)
{ {
left->Set((samplePtr) mOutBuffer[0], floatSample, outLeftPos, outputBufferCnt); if (!isGenerator)
if (right)
{ {
right->Set((samplePtr) mOutBuffer[1], floatSample, outRightPos, outputBufferCnt); left->Set((samplePtr) mOutBuffer[0], floatSample, outLeftPos, outputBufferCnt);
if (right)
{
right->Set((samplePtr) mOutBuffer[1], floatSample, outRightPos, outputBufferCnt);
}
}
else
{
genLeft->Append((samplePtr) mOutBuffer[0], floatSample, outputBufferCnt);
if (genRight)
{
genRight->Append((samplePtr) mOutBuffer[1], floatSample, outputBufferCnt);
}
}
}
if (isGenerator)
{
// Transfer the data from the temporary tracks to the actual ones
genLeft->Flush();
SetTimeWarper(new StepTimeWarper(mT0 + genLength, genLength - (mT1 - mT0)));
left->ClearAndPaste(mT0, mT1, genLeft, true, true, GetTimeWarper());
delete genLeft;
if (genRight)
{
genRight->Flush();
right->ClearAndPaste(mT0, mT1, genRight, true, true, GetTimeWarper());
delete genRight;
} }
} }
@ -1044,14 +1155,16 @@ void Effect::GetSamples(WaveTrack *track, sampleCount *start, sampleCount *len)
double t0 = mT0 < trackStart ? trackStart : mT0; double t0 = mT0 < trackStart ? trackStart : mT0;
double t1 = mT1 > trackEnd ? trackEnd : mT1; double t1 = mT1 > trackEnd ? trackEnd : mT1;
#if 0
if (GetType() & INSERT_EFFECT) { if (GetType() & INSERT_EFFECT) {
t1 = t0 + mLength; t1 = t0 + mDuration;
if (mT0 == mT1) { if (mT0 == mT1) {
// Not really part of the calculation, but convenient to put here // Not really part of the calculation, but convenient to put here
bool bResult = track->InsertSilence(t0, t1); bool bResult = track->InsertSilence(t0, t1);
wxASSERT(bResult); // TO DO: Actually handle this. wxASSERT(bResult); // TO DO: Actually handle this.
} }
} }
#endif
if (t1 > t0) { if (t1 > t0) {
*start = track->TimeToLongSamples(t0); *start = track->TimeToLongSamples(t0);

View File

@ -96,6 +96,9 @@ class AUDACITY_DLL_API Effect : public EffectHostInterface
// EffectHostInterface implementation // EffectHostInterface implementation
virtual double GetDuration();
virtual bool SetDuration(double duration);
virtual bool Apply(); virtual bool Apply();
virtual void Preview(); virtual void Preview();
@ -351,7 +354,7 @@ class AUDACITY_DLL_API Effect : public EffectHostInterface
protected: protected:
static double sDefaultGenerateLen; static double sDefaultGenerateLen;
int mFlags; int mFlags;
double mLength; double mDuration;
// type of the tracks on mOutputTracks // type of the tracks on mOutputTracks
int mOutputTracksType; int mOutputTracksType;

View File

@ -764,14 +764,10 @@ private:
void OnSlider(wxCommandEvent & evt); void OnSlider(wxCommandEvent & evt);
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
void OnApply(wxCommandEvent & evt); void OnApply(wxCommandEvent & evt);
#else
void OnOk(wxCommandEvent & evt); void OnOk(wxCommandEvent & evt);
void OnCancel(wxCommandEvent & evt); void OnCancel(wxCommandEvent & evt);
void OnPreview(wxCommandEvent & evt); void OnPreview(wxCommandEvent & evt);
#endif
void OnDefaults(wxCommandEvent & evt); void OnDefaults(wxCommandEvent & evt);
void OnClose(wxCloseEvent & evt); void OnClose(wxCloseEvent & evt);
@ -858,14 +854,10 @@ enum
BEGIN_EVENT_TABLE(VSTEffectDialog, wxDialog) BEGIN_EVENT_TABLE(VSTEffectDialog, wxDialog)
EVT_CLOSE(VSTEffectDialog::OnClose) EVT_CLOSE(VSTEffectDialog::OnClose)
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
EVT_BUTTON(wxID_APPLY, VSTEffectDialog::OnApply) EVT_BUTTON(wxID_APPLY, VSTEffectDialog::OnApply)
#else
EVT_BUTTON(wxID_OK, VSTEffectDialog::OnOk) EVT_BUTTON(wxID_OK, VSTEffectDialog::OnOk)
EVT_BUTTON(wxID_CANCEL, VSTEffectDialog::OnCancel) EVT_BUTTON(wxID_CANCEL, VSTEffectDialog::OnCancel)
EVT_BUTTON(ID_EFFECT_PREVIEW, VSTEffectDialog::OnPreview) EVT_BUTTON(ePreviewID, VSTEffectDialog::OnPreview)
#endif
EVT_BUTTON(eDefaultsID, VSTEffectDialog::OnDefaults) EVT_BUTTON(eDefaultsID, VSTEffectDialog::OnDefaults)
EVT_COMBOBOX(ID_VST_PROGRAM, VSTEffectDialog::OnProgram) EVT_COMBOBOX(ID_VST_PROGRAM, VSTEffectDialog::OnProgram)
@ -1511,7 +1503,7 @@ void VSTEffectDialog::BuildFancy()
// Add the standard button bar at the bottom // Add the standard button bar at the bottom
#if defined(EXPERIMENTAL_REALTIME_EFFECTS) #if defined(EXPERIMENTAL_REALTIME_EFFECTS)
vs->Add(CreateStdButtonSizer(this, eApplyButton | eDefaultsButton), 0, wxEXPAND); vs->Add(CreateStdButtonSizer(this, eApplyButton | eCancelButton | eDefaultsButton), 0, wxEXPAND);
#else #else
vs->Add(CreateStdButtonSizer(this, ePreviewButton | eDefaultsButton |eCancelButton | eOkButton), 0, wxEXPAND); vs->Add(CreateStdButtonSizer(this, ePreviewButton | eDefaultsButton |eCancelButton | eOkButton), 0, wxEXPAND);
#endif #endif
@ -1561,11 +1553,14 @@ void VSTEffectDialog::BuildPlain()
vSizer->Add(sw, 1, wxEXPAND | wxALL, 5); vSizer->Add(sw, 1, wxEXPAND | wxALL, 5);
// Add the standard button bar at the bottom // Add the standard button bar at the bottom
#if defined(EXPERIMENTAL_REALTIME_EFFECTS) if (mEffect->IsRealtimeCapable())
vSizer->Add(CreateStdButtonSizer(this, eApplyButton | eDefaultsButton), 0, wxEXPAND); {
#else vSizer->Add(CreateStdButtonSizer(this, eDefaultsButton | eCancelButton | eApplyButton), 0, wxEXPAND);
vSizer->Add(CreateStdButtonSizer(this, ePreviewButton|eDefaultsButton|eCancelButton|eOkButton), 0, wxEXPAND); }
#endif else
{
vSizer->Add(CreateStdButtonSizer(this, ePreviewButton | eDefaultsButton | eCancelButton | eOkButton), 0, wxEXPAND);
}
SetSizer(vSizer); SetSizer(vSizer);
@ -2586,7 +2581,6 @@ void VSTEffectDialog::OnClose(wxCloseEvent & evt)
#endif #endif
} }
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
void VSTEffectDialog::OnApply(wxCommandEvent & WXUNUSED(evt)) void VSTEffectDialog::OnApply(wxCommandEvent & WXUNUSED(evt))
{ {
#if defined(__WXMAC__) #if defined(__WXMAC__)
@ -2595,9 +2589,11 @@ void VSTEffectDialog::OnApply(wxCommandEvent & WXUNUSED(evt))
Show(false); Show(false);
#endif #endif
mEffect->SaveParameters(wxT("Current"));
mEffect->mHost->Apply(); mEffect->mHost->Apply();
} }
#else
void VSTEffectDialog::OnPreview(wxCommandEvent & WXUNUSED(evt)) void VSTEffectDialog::OnPreview(wxCommandEvent & WXUNUSED(evt))
{ {
mEffect->mHost->Preview(); mEffect->mHost->Preview();
@ -2611,6 +2607,8 @@ void VSTEffectDialog::OnOk(wxCommandEvent & WXUNUSED(evt))
Show(false); Show(false);
#endif #endif
mEffect->SaveParameters(wxT("Current"));
if (mGui) if (mGui)
{ {
// mEffect->PowerOff(); // mEffect->PowerOff();
@ -2636,9 +2634,11 @@ void VSTEffectDialog::OnCancel(wxCommandEvent & WXUNUSED(evt))
// mEffect->callDispatcher(effEditClose, 0, 0, NULL, 0.0); // mEffect->callDispatcher(effEditClose, 0, 0, NULL, 0.0);
} }
EndModal(false); if (IsModal())
{
EndModal(false);
}
} }
#endif
void VSTEffectDialog::OnDefaults(wxCommandEvent & WXUNUSED(evt)) void VSTEffectDialog::OnDefaults(wxCommandEvent & WXUNUSED(evt))
{ {
@ -3229,6 +3229,11 @@ wxString VSTEffect::GetDescription()
EffectType VSTEffect::GetType() EffectType VSTEffect::GetType()
{ {
if (mAudioIns == 0 && mAudioOuts == 0 && mMidiIns == 0 && mMidiOuts == 0)
{
return EffectTypeNone;
}
if (mAudioIns == 0 && mMidiIns == 0) if (mAudioIns == 0 && mMidiIns == 0)
{ {
return EffectTypeGenerate; return EffectTypeGenerate;

View File

@ -141,7 +141,7 @@ void LadspaEffectsModule::Terminate()
return; return;
} }
bool LadspaEffectsModule::AutoRegisterPlugins(PluginManagerInterface & pm) bool LadspaEffectsModule::AutoRegisterPlugins(PluginManagerInterface & WXUNUSED(pm))
{ {
return false; return false;
} }
@ -310,7 +310,7 @@ bool LadspaEffectsModule::RegisterPlugin(PluginManagerInterface & pm, const wxSt
int index = 0; int index = 0;
LADSPA_Descriptor_Function mainFn = NULL; LADSPA_Descriptor_Function mainFn = NULL;
wxDynamicLibrary lib; wxDynamicLibrary lib;
if (lib.Load(path, wxDL_LAZY)) { if (lib.Load(path, wxDL_NOW)) {
wxLogNull logNo; wxLogNull logNo;
mainFn = (LADSPA_Descriptor_Function) lib.GetSymbol(wxT("ladspa_descriptor")); mainFn = (LADSPA_Descriptor_Function) lib.GetSymbol(wxT("ladspa_descriptor"));
@ -369,12 +369,15 @@ LadspaEffect::LadspaEffect(const wxString & path, int index)
mAudioIns = 0; mAudioIns = 0;
mAudioOuts = 0; mAudioOuts = 0;
mNumInputControls = 0; mNumInputControls = 0;
mSampleRate = 44100;
mInputPorts = NULL; mInputPorts = NULL;
mOutputPorts = NULL; mOutputPorts = NULL;
mInputControls = NULL; mInputControls = NULL;
mOutputControls = NULL; mOutputControls = NULL;
mLatencyPort = -1;
mDlg = NULL; mDlg = NULL;
} }
@ -442,6 +445,11 @@ wxString LadspaEffect::GetDescription()
// //
EffectType LadspaEffect::GetType() EffectType LadspaEffect::GetType()
{ {
if (mAudioIns == 0 && mAudioOuts == 0)
{
return EffectTypeNone;
}
if (mAudioIns == 0) if (mAudioIns == 0)
{ {
return EffectTypeGenerate; return EffectTypeGenerate;
@ -477,7 +485,7 @@ bool LadspaEffect::IsLegacy()
bool LadspaEffect::IsRealtimeCapable() bool LadspaEffect::IsRealtimeCapable()
{ {
return true; return GetType() == EffectTypeProcess;
} }
// //
@ -503,6 +511,7 @@ bool LadspaEffect::Startup()
for (unsigned long p = 0; p < mData->PortCount; p++) for (unsigned long p = 0; p < mData->PortCount; p++)
{ {
LADSPA_PortDescriptor d = mData->PortDescriptors[p]; LADSPA_PortDescriptor d = mData->PortDescriptors[p];
// Collect the audio ports
if (LADSPA_IS_PORT_AUDIO(d)) if (LADSPA_IS_PORT_AUDIO(d))
{ {
if (LADSPA_IS_PORT_INPUT(d)) if (LADSPA_IS_PORT_INPUT(d))
@ -514,8 +523,8 @@ bool LadspaEffect::Startup()
mOutputPorts[mAudioOuts++] = p; mOutputPorts[mAudioOuts++] = p;
} }
} }
// Determine the port's default value
if (LADSPA_IS_PORT_CONTROL(d) && LADSPA_IS_PORT_INPUT(d)) else if (LADSPA_IS_PORT_CONTROL(d) && LADSPA_IS_PORT_INPUT(d))
{ {
mInteractive = true; mInteractive = true;
@ -585,6 +594,16 @@ bool LadspaEffect::Startup()
mNumInputControls++; mNumInputControls++;
mInputControls[p] = val; mInputControls[p] = val;
} }
// Ladspa effects have a convention of providing latency on an output
// control port whose name is "latency".
else if (LADSPA_IS_PORT_CONTROL(d) && LADSPA_IS_PORT_OUTPUT(d))
{
if (strcmp(mData->PortNames[p], "latency") == 0)
{
mLatencyPort = p;
mOutputControls[p] = 0;
}
}
} }
// mHost will be null during registration // mHost will be null during registration
@ -609,12 +628,6 @@ bool LadspaEffect::Startup()
bool LadspaEffect::Shutdown() bool LadspaEffect::Shutdown()
{ {
// mHost will be null during registration
if (mHost)
{
SaveParameters(wxT("Current"));
}
if (mInputPorts) if (mInputPorts)
{ {
delete [] mInputPorts; delete [] mInputPorts;
@ -686,8 +699,12 @@ sampleCount LadspaEffect::GetBlockSize(sampleCount maxBlockSize)
sampleCount LadspaEffect::GetLatency() sampleCount LadspaEffect::GetLatency()
{ {
// Ladspa effects have a convention of providing latency on an output if (mLatencyPort >= 0 && !mLatencyDone)
// control port name "latency". {
mLatencyDone = true;
return mOutputControls[mLatencyPort] * 2;
}
return 0; return 0;
} }
@ -707,9 +724,15 @@ bool LadspaEffect::ProcessInitialize()
if (!mReady) if (!mReady)
{ {
mMaster = InitInstance(mSampleRate); mMaster = InitInstance(mSampleRate);
if (!mMaster)
{
return false;
}
mReady = true; mReady = true;
} }
mLatencyDone = false;
return true; return true;
} }
@ -797,6 +820,11 @@ sampleCount LadspaEffect::RealtimeProcess(int group,
bool LadspaEffect::RealtimeAddProcessor(int numChannels, float sampleRate) bool LadspaEffect::RealtimeAddProcessor(int numChannels, float sampleRate)
{ {
LADSPA_Handle slave = InitInstance(sampleRate); LADSPA_Handle slave = InitInstance(sampleRate);
if (!slave)
{
return false;
}
mSlaves.Add(slave); mSlaves.Add(slave);
mSlaveChannels.Add(numChannels); mSlaveChannels.Add(numChannels);
@ -809,7 +837,12 @@ bool LadspaEffect::ShowInterface(void *parent)
return false; return false;
} }
double length = 0; //mT1 > mT0 ? mT1 - mT0 : sDefaultGenerateLen; double length = 0;
if (!IsRealtimeCapable())
{
length = mHost->GetDuration();
}
if (!mDlg) if (!mDlg)
{ {
@ -817,18 +850,23 @@ bool LadspaEffect::ShowInterface(void *parent)
mDlg->CentreOnParent(); mDlg->CentreOnParent();
} }
#if defined(EXPERIMENTAL_REALTIME_EFFECTS) if (IsRealtimeCapable())
mDlg->Show(!mDlg->IsShown()); {
mDlg->Show(!mDlg->IsShown());
return true;
}
return true;
#else
mDlg->ShowModal(); mDlg->ShowModal();
bool ret = mDlg->GetReturnCode() != 0; bool ret = mDlg->GetReturnCode() != 0;
if (ret)
{
mHost->SetDuration(mDlg->GetLength());
}
mDlg->Destroy(); mDlg->Destroy();
mDlg = NULL; mDlg = NULL;
return ret; return ret;
#endif
} }
// //
@ -842,7 +880,7 @@ bool LadspaEffect::Load()
} }
LADSPA_Descriptor_Function mainFn = NULL; LADSPA_Descriptor_Function mainFn = NULL;
if (mLib.Load(mPath, wxDL_LAZY)) if (mLib.Load(mPath, wxDL_NOW))
{ {
wxLogNull logNo; wxLogNull logNo;
@ -908,6 +946,10 @@ LADSPA_Handle LadspaEffect::InitInstance(float sampleRate)
{ {
/* Instantiate the plugin */ /* Instantiate the plugin */
LADSPA_Handle handle = mData->instantiate(mData, sampleRate); LADSPA_Handle handle = mData->instantiate(mData, sampleRate);
if (!handle)
{
return NULL;
}
for (unsigned long p = 0; p < mData->PortCount; p++) for (unsigned long p = 0; p < mData->PortCount; p++)
{ {
@ -958,14 +1000,14 @@ class Slider:public wxSlider
{ {
}; };
void OnSetFocus(wxFocusEvent &event) void OnSetFocus(wxFocusEvent & evt)
{ {
wxScrolledWindow *p = (wxScrolledWindow *) GetParent(); wxScrolledWindow *p = (wxScrolledWindow *) GetParent();
wxRect r = GetRect(); wxRect r = GetRect();
wxRect rv = p->GetRect(); wxRect rv = p->GetRect();
rv.y = 0; rv.y = 0;
event.Skip(); evt.Skip();
int y; int y;
int yppu; int yppu;
@ -1008,14 +1050,14 @@ class TextCtrl:public wxTextCtrl
{ {
}; };
void OnSetFocus(wxFocusEvent &event) void OnSetFocus(wxFocusEvent & evt)
{ {
wxScrolledWindow *p = (wxScrolledWindow *) GetParent(); wxScrolledWindow *p = (wxScrolledWindow *) GetParent();
wxRect r = GetRect(); wxRect r = GetRect();
wxRect rv = p->GetRect(); wxRect rv = p->GetRect();
rv.y = 0; rv.y = 0;
event.Skip(); evt.Skip();
int y; int y;
int yppu; int yppu;
@ -1041,22 +1083,20 @@ class TextCtrl:public wxTextCtrl
}; };
BEGIN_EVENT_TABLE(TextCtrl, wxTextCtrl) BEGIN_EVENT_TABLE(TextCtrl, wxTextCtrl)
EVT_SET_FOCUS(TextCtrl::OnSetFocus) EVT_SET_FOCUS(TextCtrl::OnSetFocus)
END_EVENT_TABLE() END_EVENT_TABLE()
const int LADSPA_SECONDS_ID = 13101; const int LADSPA_SECONDS_ID = 13101;
BEGIN_EVENT_TABLE(LadspaEffectDialog, wxDialog) BEGIN_EVENT_TABLE(LadspaEffectDialog, wxDialog)
#if defined(EXPERIMENTAL_REALTIME_EFFECTS) EVT_BUTTON(wxID_APPLY, LadspaEffectDialog::OnApply)
EVT_BUTTON(wxID_APPLY, LadspaEffectDialog::OnApply) EVT_BUTTON(wxID_OK, LadspaEffectDialog::OnOK)
#else EVT_BUTTON(wxID_CANCEL, LadspaEffectDialog::OnCancel)
EVT_BUTTON(wxID_OK, LadspaEffectDialog::OnOK) EVT_BUTTON(ePreviewID, LadspaEffectDialog::OnPreview)
EVT_BUTTON(wxID_CANCEL, LadspaEffectDialog::OnCancel) EVT_BUTTON(eDefaultsID, LadspaEffectDialog::OnDefaults)
EVT_BUTTON(ID_EFFECT_PREVIEW, LadspaEffectDialog::OnPreview) EVT_SLIDER(wxID_ANY, LadspaEffectDialog::OnSlider)
#endif EVT_TEXT(wxID_ANY, LadspaEffectDialog::OnTextCtrl)
EVT_SLIDER(wxID_ANY, LadspaEffectDialog::OnSlider) EVT_CHECKBOX(wxID_ANY, LadspaEffectDialog::OnCheckBox)
EVT_TEXT(wxID_ANY, LadspaEffectDialog::OnTextCtrl)
EVT_CHECKBOX(wxID_ANY, LadspaEffectDialog::OnCheckBox)
END_EVENT_TABLE() END_EVENT_TABLE()
IMPLEMENT_CLASS(LadspaEffectDialog, wxDialog) IMPLEMENT_CLASS(LadspaEffectDialog, wxDialog)
@ -1070,17 +1110,16 @@ LadspaEffectDialog::LadspaEffectDialog(LadspaEffect *eff,
:wxDialog(parent, -1, LAT1CTOWX(data->Name), :wxDialog(parent, -1, LAT1CTOWX(data->Name),
wxDefaultPosition, wxDefaultSize, wxDefaultPosition, wxDefaultSize,
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
effect(eff) mEffect(eff)
{ {
mLength = length; mNumParams = 0;
numParams = 0;
mData = data; mData = data;
mInputControls = inputControls; mInputControls = inputControls;
sampleRate = sampleRate; mSampleRate = sampleRate;
#ifdef __WXMSW__ #ifdef __WXMSW__
// On Windows, for some reason, wxWidgets calls OnTextCtrl during creation // On Windows, for some reason, wxWidgets calls OnTextCtrl during creation
// of the text control, and LadspaEffectDialog::OnTextCtrl calls HandleText, // of the text control, and LadspaEffectDialog::OnTextCtrl calls HandleText,
// which assumes all the fields have been initialized. // which assumes all the mFields have been initialized.
// This can give us a bad pointer crash, so manipulate inSlider to // This can give us a bad pointer crash, so manipulate inSlider to
// no-op HandleText during creation. // no-op HandleText during creation.
inSlider = true; inSlider = true;
@ -1089,19 +1128,19 @@ LadspaEffectDialog::LadspaEffectDialog(LadspaEffect *eff,
#endif #endif
inText = false; inText = false;
toggles = new wxCheckBox*[mData->PortCount]; mToggles = new wxCheckBox*[mData->PortCount];
sliders = new wxSlider*[mData->PortCount]; mSliders = new wxSlider*[mData->PortCount];
fields = new wxTextCtrl*[mData->PortCount]; mFields = new wxTextCtrl*[mData->PortCount];
labels = new wxStaticText*[mData->PortCount]; mLabels = new wxStaticText*[mData->PortCount];
ports = new unsigned long [mData->PortCount]; mPorts = new unsigned long [mData->PortCount];
unsigned long p; unsigned long p;
for(p=0; p<mData->PortCount; p++) { for(p=0; p<mData->PortCount; p++) {
LADSPA_PortDescriptor d = mData->PortDescriptors[p]; LADSPA_PortDescriptor d = mData->PortDescriptors[p];
if (LADSPA_IS_PORT_CONTROL(d) && if (LADSPA_IS_PORT_CONTROL(d) &&
LADSPA_IS_PORT_INPUT(d)) { LADSPA_IS_PORT_INPUT(d)) {
ports[numParams] = p; mPorts[mNumParams] = p;
numParams++; mNumParams++;
} }
} }
@ -1141,11 +1180,12 @@ LadspaEffectDialog::LadspaEffectDialog(LadspaEffect *eff,
vSizer->Add(w, 1, wxEXPAND|wxALL, 5); vSizer->Add(w, 1, wxEXPAND|wxALL, 5);
// Preview, OK, & Cancel buttons // Preview, OK, & Cancel buttons
#if defined(EXPERIMENTAL_REALTIME_EFFECTS) if (mEffect->IsRealtimeCapable()) {
vSizer->Add(CreateStdButtonSizer(this, eApplyButton | eDefaultsButton), 0, wxEXPAND); vSizer->Add(CreateStdButtonSizer(this, eApplyButton | eCancelButton | eDefaultsButton), 0, wxEXPAND);
#else }
vSizer->Add(CreateStdButtonSizer(this, ePreviewButton | eDefaultsButton |eCancelButton | eOkButton), 0, wxEXPAND); else {
#endif vSizer->Add(CreateStdButtonSizer(this, ePreviewButton | eDefaultsButton | eCancelButton | eOkButton), 0, wxEXPAND);
}
SetSizer(vSizer); SetSizer(vSizer);
@ -1156,36 +1196,26 @@ LadspaEffectDialog::LadspaEffectDialog(LadspaEffect *eff,
new wxFlexGridSizer(5, 0, 0); new wxFlexGridSizer(5, 0, 0);
gridSizer->AddGrowableCol(3); gridSizer->AddGrowableCol(3);
for (p = 0; p < numParams; p++) { for (p = 0; p < mNumParams; p++) {
wxString labelText = LAT1CTOWX(mData->PortNames[ports[p]]); wxString labelText = LAT1CTOWX(mData->PortNames[mPorts[p]]);
item = new wxStaticText(w, 0, labelText + wxT(":")); item = new wxStaticText(w, 0, labelText + wxT(":"));
gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5); gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5);
wxString fieldText; wxString fieldText;
LADSPA_PortRangeHint hint = mData->PortRangeHints[ports[p]]; LADSPA_PortRangeHint hint = mData->PortRangeHints[mPorts[p]];
if (LADSPA_IS_HINT_TOGGLED(hint.HintDescriptor)) { if (LADSPA_IS_HINT_TOGGLED(hint.HintDescriptor)) {
toggles[p] = new wxCheckBox(w, p, wxT("")); mToggles[p] = new wxCheckBox(w, p, wxT(""));
toggles[p]->SetName(labelText); mToggles[p]->SetName(labelText);
toggles[p]->SetValue(mInputControls[ports[p]] > 0); mToggles[p]->SetValue(mInputControls[mPorts[p]] > 0);
gridSizer->Add(toggles[p], 0, wxALL, 5); gridSizer->Add(mToggles[p], 0, wxALL, 5);
ConnectFocus(toggles[p]); ConnectFocus(mToggles[p]);
gridSizer->Add(1, 1, 0); gridSizer->Add(1, 1, 0);
gridSizer->Add(1, 1, 0); gridSizer->Add(1, 1, 0);
gridSizer->Add(1, 1, 0); gridSizer->Add(1, 1, 0);
} }
else { else {
if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor))
fieldText.Printf(wxT("%d"), (int)(mInputControls[ports[p]] + 0.5));
else
fieldText = Internat::ToDisplayString(mInputControls[ports[p]]);
fields[p] = new wxTextCtrl(w, p, fieldText);
fields[p]->SetName(labelText);
gridSizer->Add(fields[p], 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
ConnectFocus(fields[p]);
wxString bound; wxString bound;
double lower = 0.0; double lower = 0.0;
double upper = 0.0; double upper = 0.0;
@ -1202,11 +1232,21 @@ LadspaEffectDialog::LadspaEffectDialog(LadspaEffect *eff,
hashi = true; hashi = true;
} }
if (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor)) { if (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor)) {
lower *= sampleRate * 1000; lower *= mSampleRate;
upper *= sampleRate; upper *= mSampleRate;
forceint = true; forceint = true;
} }
if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint)
fieldText.Printf(wxT("%d"), (int)(mInputControls[mPorts[p]] + 0.5));
else
fieldText = Internat::ToDisplayString(mInputControls[mPorts[p]]);
mFields[p] = new wxTextCtrl(w, p, fieldText);
mFields[p]->SetName(labelText);
gridSizer->Add(mFields[p], 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
ConnectFocus(mFields[p]);
wxString str; wxString str;
if (haslo) { if (haslo) {
if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint) if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint)
@ -1220,14 +1260,14 @@ LadspaEffectDialog::LadspaEffectDialog(LadspaEffect *eff,
gridSizer->Add(1, 1, 0); gridSizer->Add(1, 1, 0);
} }
sliders[p] = mSliders[p] =
new wxSlider(w, p, new wxSlider(w, p,
0, 0, 1000, 0, 0, 1000,
wxDefaultPosition, wxDefaultPosition,
wxSize(200, -1)); wxSize(200, -1));
sliders[p]->SetName(labelText); mSliders[p]->SetName(labelText);
gridSizer->Add(sliders[p], 0, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxALL, 5); gridSizer->Add(mSliders[p], 0, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxALL, 5);
ConnectFocus(sliders[p]); ConnectFocus(mSliders[p]);
if (hashi) { if (hashi) {
if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint) if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint)
@ -1244,11 +1284,19 @@ LadspaEffectDialog::LadspaEffectDialog(LadspaEffect *eff,
} }
// Now add the length control // Now add the length control
if (effect->GetType() == EffectTypeGenerate) { if (mEffect->GetType() == EffectTypeGenerate) {
item = new wxStaticText(w, 0, _("Length (seconds)")); item = new wxStaticText(w, 0, _("Length (seconds):"));
gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5);
mSeconds = new wxTextCtrl(w, LADSPA_SECONDS_ID, Internat::ToDisplayString(length)); mSeconds = new TimeTextCtrl(w,
mSeconds->SetName(_("Length (seconds)")); wxID_ANY,
_("hh:mm:ss + milliseconds"),
length,
mSampleRate,
wxDefaultPosition,
wxDefaultSize,
true);
mSeconds->SetName(_("Duration"));
mSeconds->EnableMenu();
gridSizer->Add(mSeconds, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); gridSizer->Add(mSeconds, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
gridSizer->Add(1, 1, 0); gridSizer->Add(1, 1, 0);
gridSizer->Add(1, 1, 0); gridSizer->Add(1, 1, 0);
@ -1256,10 +1304,11 @@ LadspaEffectDialog::LadspaEffectDialog(LadspaEffect *eff,
ConnectFocus(mSeconds); ConnectFocus(mSeconds);
} }
// Set all of the sliders based on the value in the // Set all of the mSliders based on the value in the
// text fields // text mFields
inSlider = false; // Now we're ready for HandleText to actually do something. inSlider = false; // Now we're ready for HandleText to actually do something.
HandleText(); mEffect->LoadParameters(wxT("Current"));
// HandleText();
paramSizer->Add(gridSizer, 1, wxEXPAND | wxALL, 5); paramSizer->Add(gridSizer, 1, wxEXPAND | wxALL, 5);
w->SetSizer(paramSizer); w->SetSizer(paramSizer);
@ -1271,23 +1320,23 @@ LadspaEffectDialog::LadspaEffectDialog(LadspaEffect *eff,
LadspaEffectDialog::~LadspaEffectDialog() LadspaEffectDialog::~LadspaEffectDialog()
{ {
delete[]toggles; delete[]mToggles;
delete[]sliders; delete[]mSliders;
delete[]fields; delete[]mFields;
delete[]labels; delete[]mLabels;
delete[]ports; delete[]mPorts;
} }
void LadspaEffectDialog::OnCheckBox(wxCommandEvent &event) void LadspaEffectDialog::OnCheckBox(wxCommandEvent & evt)
{ {
int p = event.GetId(); int p = evt.GetId();
mInputControls[ports[p]] = toggles[p]->GetValue(); mInputControls[mPorts[p]] = mToggles[p]->GetValue();
} }
void LadspaEffectDialog::OnSlider(wxCommandEvent &event) void LadspaEffectDialog::OnSlider(wxCommandEvent & evt)
{ {
int p = event.GetId(); int p = evt.GetId();
// if we don't add the following three lines, changing // if we don't add the following three lines, changing
// the value of the slider will change the text, which // the value of the slider will change the text, which
@ -1303,20 +1352,20 @@ void LadspaEffectDialog::OnSlider(wxCommandEvent &event)
float range; float range;
bool forceint = false; bool forceint = false;
LADSPA_PortRangeHint hint = mData->PortRangeHints[ports[p]]; LADSPA_PortRangeHint hint = mData->PortRangeHints[mPorts[p]];
if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor)) if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor))
lower = hint.LowerBound; lower = hint.LowerBound;
if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor)) if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor))
upper = hint.UpperBound; upper = hint.UpperBound;
if (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor)) { if (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor)) {
lower *= sampleRate; lower *= mSampleRate;
upper *= sampleRate; upper *= mSampleRate;
forceint = true; forceint = true;
} }
range = upper - lower; range = upper - lower;
val = (sliders[p]->GetValue() / 1000.0) * range + lower; val = (mSliders[p]->GetValue() / 1000.0) * range + lower;
wxString str; wxString str;
if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint) if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint)
@ -1324,14 +1373,14 @@ void LadspaEffectDialog::OnSlider(wxCommandEvent &event)
else else
str = Internat::ToDisplayString(val); str = Internat::ToDisplayString(val);
fields[p]->SetValue(str); mFields[p]->SetValue(str);
mInputControls[ports[p]] = val; mInputControls[mPorts[p]] = val;
inSlider = false; inSlider = false;
} }
void LadspaEffectDialog::OnTextCtrl(wxCommandEvent & WXUNUSED(event)) void LadspaEffectDialog::OnTextCtrl(wxCommandEvent & WXUNUSED(evt))
{ {
HandleText(); HandleText();
} }
@ -1346,19 +1395,19 @@ void LadspaEffectDialog::HandleText()
if (inSlider) if (inSlider)
return; return;
inText = true; inText = true;
for (unsigned long p = 0; p < numParams; p++) { for (unsigned long p = 0; p < mNumParams; p++) {
double dval; double dval;
float val; float val;
float lower = float(0.0); float lower = float(0.0);
float upper = float(10.0); float upper = float(10.0);
float range; float range;
LADSPA_PortRangeHint hint = mData->PortRangeHints[ports[p]]; LADSPA_PortRangeHint hint = mData->PortRangeHints[mPorts[p]];
if (LADSPA_IS_HINT_TOGGLED(hint.HintDescriptor)) { if (LADSPA_IS_HINT_TOGGLED(hint.HintDescriptor)) {
continue; continue;
} }
dval = Internat::CompatibleToDouble(fields[p]->GetValue()); dval = Internat::CompatibleToDouble(mFields[p]->GetValue());
val = dval; val = dval;
if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor)) if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor))
@ -1366,8 +1415,8 @@ void LadspaEffectDialog::HandleText()
if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor)) if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor))
upper = hint.UpperBound; upper = hint.UpperBound;
if (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor)) { if (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor)) {
lower *= sampleRate; lower *= mSampleRate;
upper *= sampleRate; upper *= mSampleRate;
} }
range = upper - lower; range = upper - lower;
@ -1376,15 +1425,14 @@ void LadspaEffectDialog::HandleText()
if (val > upper) if (val > upper)
val = upper; val = upper;
mInputControls[ports[p]] = val; mInputControls[mPorts[p]] = val;
sliders[p]->SetValue((int)(((val-lower)/range) * 1000.0 + 0.5)); mSliders[p]->SetValue((int)(((val-lower)/range) * 1000.0 + 0.5));
} }
inText = false; inText = false;
} }
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
void LadspaEffectDialog::OnApply(wxCommandEvent & WXUNUSED(evt)) void LadspaEffectDialog::OnApply(wxCommandEvent & WXUNUSED(evt))
{ {
#if defined(__WXMAC__) #if defined(__WXMAC__)
@ -1392,25 +1440,85 @@ void LadspaEffectDialog::OnApply(wxCommandEvent & WXUNUSED(evt))
#else #else
Show(false); Show(false);
#endif #endif
mEffect->SaveParameters(wxT("Current"));
effect->mHost->Apply(); mEffect->mHost->Apply();
} }
#else
void LadspaEffectDialog::OnOK(wxCommandEvent & WXUNUSED(event)) void LadspaEffectDialog::OnOK(wxCommandEvent & WXUNUSED(evt))
{ {
mEffect->SaveParameters(wxT("Current"));
EndModal(TRUE); EndModal(TRUE);
} }
void LadspaEffectDialog::OnCancel(wxCommandEvent & WXUNUSED(event)) void LadspaEffectDialog::OnCancel(wxCommandEvent & WXUNUSED(evt))
{ {
EndModal(FALSE); if (IsModal())
{
EndModal(FALSE);
}
else
{
#if defined(__WXMAC__)
Close();
#else
Show(false);
#endif
}
} }
void LadspaEffectDialog::OnPreview(wxCommandEvent & WXUNUSED(event)) void LadspaEffectDialog::OnPreview(wxCommandEvent & WXUNUSED(evt))
{ {
effect->Preview(); mEffect->mHost->Preview();
}
void LadspaEffectDialog::OnDefaults(wxCommandEvent & WXUNUSED(evt))
{
mEffect->LoadParameters(wxT("Default"));
RefreshParaemters();
}
void LadspaEffectDialog::RefreshParaemters()
{
for (unsigned long p = 0; p < mNumParams; p++) {
LADSPA_PortRangeHint hint = mData->PortRangeHints[mPorts[p]];
if (LADSPA_IS_HINT_TOGGLED(hint.HintDescriptor)) {
mToggles[p]->SetValue(mInputControls[mPorts[p]] > 0);
}
else {
wxString bound;
double lower = 0.0;
double upper = 0.0;
bool haslo = false;
bool hashi = false;
bool forceint = false;
if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor)) {
lower = hint.LowerBound;
haslo = true;
}
if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor)) {
upper = hint.UpperBound;
hashi = true;
}
if (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor)) {
lower *= mSampleRate;
upper *= mSampleRate;
forceint = true;
}
wxString fieldText;
if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint)
fieldText.Printf(wxT("%d"), (int)(mInputControls[mPorts[p]] + 0.5));
else
fieldText = Internat::ToDisplayString(mInputControls[mPorts[p]]);
mFields[p]->ChangeValue(fieldText);
}
}
HandleText();
} }
#endif
void LadspaEffectDialog::ConnectFocus(wxControl *c) void LadspaEffectDialog::ConnectFocus(wxControl *c)
{ {
@ -1424,15 +1532,15 @@ void LadspaEffectDialog::DisconnectFocus(wxControl *c)
wxFocusEventHandler(LadspaEffectDialog::ControlSetFocus)); wxFocusEventHandler(LadspaEffectDialog::ControlSetFocus));
} }
void LadspaEffectDialog::ControlSetFocus(wxFocusEvent &event) void LadspaEffectDialog::ControlSetFocus(wxFocusEvent & evt)
{ {
wxControl *c = (wxControl *) event.GetEventObject(); wxControl *c = (wxControl *) evt.GetEventObject();
wxScrolledWindow *p = (wxScrolledWindow *) c->GetParent(); wxScrolledWindow *p = (wxScrolledWindow *) c->GetParent();
wxRect r = c->GetRect(); wxRect r = c->GetRect();
wxRect rv = p->GetRect(); wxRect rv = p->GetRect();
rv.y = 0; rv.y = 0;
event.Skip(); evt.Skip();
int y; int y;
int yppu; int yppu;
@ -1456,9 +1564,9 @@ void LadspaEffectDialog::ControlSetFocus(wxFocusEvent &event)
double LadspaEffectDialog::GetLength() double LadspaEffectDialog::GetLength()
{ {
if (effect->GetType() == EffectTypeGenerate) { if (mEffect->GetType() == EffectTypeGenerate) {
mLength = Internat::CompatibleToDouble(mSeconds->GetValue()); return mSeconds->GetTimeValue();
} }
return mLength; return 0;
} }

View File

@ -19,6 +19,8 @@ class wxCheckBox;
#include "audacity/ModuleInterface.h" #include "audacity/ModuleInterface.h"
#include "audacity/PluginInterface.h" #include "audacity/PluginInterface.h"
#include "../../widgets/TimeTextCtrl.h"
#include "ladspa.h" #include "ladspa.h"
#define LADSPAEFFECTS_VERSION wxT("1.0.0.0"); #define LADSPAEFFECTS_VERSION wxT("1.0.0.0");
@ -126,6 +128,9 @@ private:
float *mInputControls; float *mInputControls;
float *mOutputControls; float *mOutputControls;
int mLatencyPort;
bool mLatencyDone;
// Realtime processing // Realtime processing
LadspaSlaveArray mSlaves; LadspaSlaveArray mSlaves;
wxArrayInt mSlaveChannels; wxArrayInt mSlaveChannels;
@ -185,39 +190,39 @@ class LadspaEffectDialog : public wxDialog
~LadspaEffectDialog(); ~LadspaEffectDialog();
void OnCheckBox(wxCommandEvent & event);
void OnSlider(wxCommandEvent & event);
void OnTextCtrl(wxCommandEvent & event);
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
void OnApply(wxCommandEvent & evt);
#else
void OnOk(wxCommandEvent & evt);
void OnCancel(wxCommandEvent & evt);
void OnPreview(wxCommandEvent & evt);
#endif
void ControlSetFocus(wxFocusEvent & event);
double GetLength(); double GetLength();
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
private: private:
void OnCheckBox(wxCommandEvent & evt);
void OnSlider(wxCommandEvent & evt);
void OnTextCtrl(wxCommandEvent & evt);
void OnApply(wxCommandEvent & evt);
void OnOK(wxCommandEvent & evt);
void OnCancel(wxCommandEvent & evt);
void OnPreview(wxCommandEvent & evt);
void OnDefaults(wxCommandEvent & evt);
void HandleText(); void HandleText();
void RefreshParaemters();
void ConnectFocus(wxControl *c); void ConnectFocus(wxControl *c);
void DisconnectFocus(wxControl *c); void DisconnectFocus(wxControl *c);
void ControlSetFocus(wxFocusEvent & evt);
private:
bool inSlider; bool inSlider;
bool inText; bool inText;
double mLength; int mSampleRate;
int sampleRate;
const LADSPA_Descriptor *mData; const LADSPA_Descriptor *mData;
wxSlider **sliders; wxSlider **mSliders;
wxTextCtrl **fields; wxTextCtrl **mFields;
wxStaticText **labels; wxStaticText **mLabels;
wxCheckBox **toggles; wxCheckBox **mToggles;
unsigned long *ports; unsigned long *mPorts;
unsigned long numParams; unsigned long mNumParams;
float *mInputControls; float *mInputControls;
LadspaEffect *effect; LadspaEffect *mEffect;
wxTextCtrl *mSeconds; TimeTextCtrl *mSeconds;
}; };

View File

@ -79,7 +79,7 @@ LV2Effect::LV2Effect(const LilvPlugin *data,
fInBuffer = NULL; fInBuffer = NULL;
fOutBuffer = NULL; fOutBuffer = NULL;
mLength = 0; mDuration = 0;
// Allocate buffers for the port indices and the default control values // Allocate buffers for the port indices and the default control values
int numPorts = lilv_plugin_get_num_ports(mData); int numPorts = lilv_plugin_get_num_ports(mData);
@ -386,7 +386,7 @@ bool LV2Effect::PromptUser()
return false; return false;
} }
mLength = dlog.GetLength(); mDuration = dlog.GetLength();
mNoteLength = dlog.GetNoteLength(); mNoteLength = dlog.GetNoteLength();
mNoteVelocity = dlog.GetNoteVelocity(); mNoteVelocity = dlog.GetNoteVelocity();
mNoteKey = dlog.GetNoteKey(); mNoteKey = dlog.GetNoteKey();