mirror of
https://github.com/cookiengineer/audacity
synced 2026-04-04 13:27:39 +02:00
Migrating the remaining effects
This brings the builtin, LV2, and VAMP effects inline with the Audio Units, LADSPA, and VST effects. All effects now share a common UI. This gives all effects (though not implemented for all): User and factory preset capability Preset import/export capability Shared or private configuration options Builtin effects can now be migrated to RTP, depending on algorithm. LV2 effects now support graphical interfaces if the plugin supplies one. Nyquist prompt enhanced to provide some features of the Nyquist Workbench. It may not look like it, but this was a LOT of work, so trust me, there WILL be problems and everything effect related should be suspect. Keep a sharp eye (or two) open.
This commit is contained in:
@@ -19,246 +19,150 @@
|
||||
|
||||
*//*******************************************************************/
|
||||
|
||||
|
||||
#include "../Audacity.h"
|
||||
|
||||
#include <wx/defs.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/validate.h>
|
||||
#include <wx/valtext.h>
|
||||
#include <float.h>
|
||||
|
||||
#include <wx/generic/textdlgg.h>
|
||||
#include <wx/intl.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "../widgets/valnum.h"
|
||||
|
||||
#include "Echo.h"
|
||||
#include "../WaveTrack.h"
|
||||
|
||||
// Define keys, defaults, minimums, and maximums for the effect parameters
|
||||
//
|
||||
// Name Type Key Def Min Max Scale
|
||||
Param( Delay, float, wxTRANSLATE("Delay"), 1.0, 0.0, FLT_MAX, 1 );
|
||||
Param( Decay, float, wxTRANSLATE("Decay"), 0.5, 1.0, 1.0, 1 );
|
||||
|
||||
EffectEcho::EffectEcho()
|
||||
{
|
||||
delay = float(1.0);
|
||||
decay = float(0.5);
|
||||
delay = DEF_Delay;
|
||||
decay = DEF_Decay;
|
||||
}
|
||||
|
||||
wxString EffectEcho::GetEffectDescription() {
|
||||
// Note: This is useful only after values have been set.
|
||||
return wxString::Format(_("Applied effect: %s delay = %f seconds, decay factor = %f"),
|
||||
this->GetEffectName().c_str(), delay, decay);
|
||||
}
|
||||
|
||||
bool EffectEcho::PromptUser()
|
||||
EffectEcho::~EffectEcho()
|
||||
{
|
||||
EchoDialog dlog(this, mParent);
|
||||
dlog.delay = delay;
|
||||
dlog.decay = decay;
|
||||
dlog.CentreOnParent();
|
||||
dlog.ShowModal();
|
||||
}
|
||||
|
||||
if (dlog.GetReturnCode() == wxID_CANCEL)
|
||||
return false;
|
||||
// IdentInterface implementation
|
||||
|
||||
delay = dlog.delay;
|
||||
decay = dlog.decay;
|
||||
wxString EffectEcho::GetSymbol()
|
||||
{
|
||||
return ECHO_PLUGIN_SYMBOL;
|
||||
}
|
||||
|
||||
wxString EffectEcho::GetDescription()
|
||||
{
|
||||
return wxTRANSLATE("Repeats the selected audio again and again");
|
||||
}
|
||||
|
||||
// EffectIdentInterface implementation
|
||||
|
||||
EffectType EffectEcho::GetType()
|
||||
{
|
||||
return EffectTypeProcess;
|
||||
}
|
||||
|
||||
// EffectClientInterface implementation
|
||||
|
||||
int EffectEcho::GetAudioInCount()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EffectEcho::GetAudioOutCount()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool EffectEcho::ProcessInitialize(sampleCount WXUNUSED(totalLen), ChannelNames WXUNUSED(chanMap))
|
||||
{
|
||||
histPos = 0;
|
||||
histLen = (sampleCount) (mSampleRate * delay);
|
||||
history = new float[histLen];
|
||||
memset(history, 0, sizeof(float) * histLen);
|
||||
|
||||
return history != NULL;
|
||||
}
|
||||
|
||||
bool EffectEcho::ProcessFinalize()
|
||||
{
|
||||
delete [] history;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EffectEcho::TransferParameters( Shuttle & shuttle )
|
||||
sampleCount EffectEcho::ProcessBlock(float **inBlock, float **outBlock, sampleCount blockLen)
|
||||
{
|
||||
shuttle.TransferFloat(wxT("Delay"),delay,1.0);
|
||||
shuttle.TransferFloat(wxT("Decay"),decay,0.5);
|
||||
return true;
|
||||
}
|
||||
float *ibuf = inBlock[0];
|
||||
float *obuf = outBlock[0];
|
||||
|
||||
bool EffectEcho::Process()
|
||||
{
|
||||
this->CopyInputTracks(); // Set up mOutputTracks.
|
||||
bool bGoodResult = true;
|
||||
|
||||
SelectedTrackListOfKindIterator iter(Track::Wave, mOutputTracks);
|
||||
WaveTrack *track = (WaveTrack *) iter.First();
|
||||
int count = 0;
|
||||
while (track) {
|
||||
double trackStart = track->GetStartTime();
|
||||
double trackEnd = track->GetEndTime();
|
||||
double t0 = mT0 < trackStart? trackStart: mT0;
|
||||
double t1 = mT1 > trackEnd? trackEnd: mT1;
|
||||
|
||||
if (t1 > t0) {
|
||||
sampleCount start = track->TimeToLongSamples(t0);
|
||||
sampleCount end = track->TimeToLongSamples(t1);
|
||||
sampleCount len = (sampleCount)(end - start);
|
||||
|
||||
if (!ProcessOne(count, track, start, len))
|
||||
{
|
||||
bGoodResult = false;
|
||||
break;
|
||||
}
|
||||
for (sampleCount i = 0; i < blockLen; i++, histPos++)
|
||||
{
|
||||
if (histPos == histLen)
|
||||
{
|
||||
histPos = 0;
|
||||
}
|
||||
|
||||
track = (WaveTrack *) iter.Next();
|
||||
count++;
|
||||
history[histPos] = obuf[i] = ibuf[i] + history[histPos] * decay;
|
||||
}
|
||||
|
||||
this->ReplaceProcessedTracks(bGoodResult);
|
||||
return bGoodResult;
|
||||
return blockLen;
|
||||
}
|
||||
|
||||
bool EffectEcho::ProcessOne(int count, WaveTrack * track,
|
||||
sampleCount start, sampleCount len)
|
||||
bool EffectEcho::GetAutomationParameters(EffectAutomationParameters & parms)
|
||||
{
|
||||
sampleCount s = 0;
|
||||
sampleCount blockSize = (sampleCount) (track->GetRate() * delay);
|
||||
|
||||
//do nothing if the delay is less than 1 sample or greater than
|
||||
//the length of the selection
|
||||
if (blockSize < 1 || blockSize > len)
|
||||
return true;
|
||||
|
||||
float *buffer0 = new float[blockSize];
|
||||
float *buffer1 = new float[blockSize];
|
||||
|
||||
float *ptr0 = buffer0;
|
||||
float *ptr1 = buffer1;
|
||||
|
||||
bool first = true;
|
||||
|
||||
while (s < len) {
|
||||
sampleCount block = blockSize;
|
||||
if (s + block > len)
|
||||
block = len - s;
|
||||
|
||||
track->Get((samplePtr)ptr0, floatSample, start + s, block);
|
||||
if (!first) {
|
||||
for (sampleCount i = 0; i < block; i++)
|
||||
ptr0[i] += ptr1[i] * decay;
|
||||
track->Set((samplePtr)ptr0, floatSample, start + s, block);
|
||||
}
|
||||
|
||||
float *ptrtemp = ptr0;
|
||||
ptr0 = ptr1;
|
||||
ptr1 = ptrtemp;
|
||||
|
||||
first = false;
|
||||
|
||||
s += block;
|
||||
|
||||
if (TrackProgress(count, s / (double) len)) {
|
||||
delete[]buffer0;
|
||||
delete[]buffer1;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
delete[]buffer0;
|
||||
delete[]buffer1;
|
||||
parms.WriteFloat(KEY_Delay, delay);
|
||||
parms.WriteFloat(KEY_Decay, decay);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// EchoDialog
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// event table for EchoDialog
|
||||
|
||||
BEGIN_EVENT_TABLE(EchoDialog, EffectDialog)
|
||||
EVT_BUTTON(ID_EFFECT_PREVIEW, EchoDialog::OnPreview)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
EchoDialog::EchoDialog(EffectEcho * effect, wxWindow * parent)
|
||||
: EffectDialog(parent, _("Echo"))
|
||||
bool EffectEcho::SetAutomationParameters(EffectAutomationParameters & parms)
|
||||
{
|
||||
m_bLoopDetect = false;
|
||||
m_pEffect = effect;
|
||||
ReadAndVerifyFloat(Delay);
|
||||
ReadAndVerifyFloat(Decay);
|
||||
|
||||
// NULL out these control members because there are some cases where the
|
||||
// event table handlers get called during this method, and those handlers that
|
||||
// can cause trouble check for NULL.
|
||||
m_pTextCtrl_Delay = NULL;
|
||||
m_pTextCtrl_Decay = NULL;
|
||||
delay = Delay;
|
||||
decay = Decay;
|
||||
|
||||
// effect parameters
|
||||
delay = float(1.0);
|
||||
decay = float(0.5);
|
||||
|
||||
// Initialize dialog
|
||||
Init();
|
||||
return true;
|
||||
}
|
||||
|
||||
void EchoDialog::PopulateOrExchange(ShuttleGui & S)
|
||||
void EffectEcho::PopulateOrExchange(ShuttleGui & S)
|
||||
{
|
||||
S.AddSpace(0, 5);
|
||||
|
||||
S.StartMultiColumn(2, wxALIGN_CENTER);
|
||||
{
|
||||
m_pTextCtrl_Delay = S.AddTextBox(_("Delay time (seconds):"),
|
||||
wxT("1.0"),
|
||||
10);
|
||||
m_pTextCtrl_Delay->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
|
||||
FloatingPointValidator<double> vldDelay(3, &delay, NUM_VAL_NO_TRAILING_ZEROES);
|
||||
vldDelay.SetRange(MIN_Delay, MAX_Delay);
|
||||
S.AddTextBox(_("Delay time (seconds):"), wxT(""), 10)->SetValidator(vldDelay);
|
||||
|
||||
m_pTextCtrl_Decay = S.AddTextBox(_("Decay factor:"),
|
||||
wxT("0.5"),
|
||||
10);
|
||||
m_pTextCtrl_Decay->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
|
||||
FloatingPointValidator<double> vldDecay(3, &decay, NUM_VAL_NO_TRAILING_ZEROES);
|
||||
vldDecay.SetRange(MIN_Decay, MAX_Decay);
|
||||
S.AddTextBox(_("Decay factor:"), wxT(""), 10)->SetValidator(vldDecay);
|
||||
}
|
||||
S.EndMultiColumn();
|
||||
}
|
||||
|
||||
bool EchoDialog::TransferDataToWindow()
|
||||
bool EffectEcho::TransferDataToWindow()
|
||||
{
|
||||
m_bLoopDetect = true;
|
||||
|
||||
wxString str;
|
||||
if (m_pTextCtrl_Delay) {
|
||||
str.Printf(wxT("%g"), delay);
|
||||
m_pTextCtrl_Delay->SetValue(str);
|
||||
}
|
||||
if (m_pTextCtrl_Decay) {
|
||||
str.Printf(wxT("%g"), decay);
|
||||
m_pTextCtrl_Decay->SetValue(str);
|
||||
if (!mUIParent->TransferDataToWindow())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_bLoopDetect = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EchoDialog::TransferDataFromWindow()
|
||||
bool EffectEcho::TransferDataFromWindow()
|
||||
{
|
||||
double newValue;
|
||||
wxString str;
|
||||
if (m_pTextCtrl_Delay) {
|
||||
str = m_pTextCtrl_Delay->GetValue();
|
||||
str.ToDouble(&newValue);
|
||||
delay = (float)(newValue);
|
||||
}
|
||||
if (m_pTextCtrl_Decay) {
|
||||
str = m_pTextCtrl_Decay->GetValue();
|
||||
str.ToDouble(&newValue);
|
||||
decay = (float)(newValue);
|
||||
if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// handler implementations for EchoDialog
|
||||
|
||||
void EchoDialog::OnPreview(wxCommandEvent & WXUNUSED(event))
|
||||
{
|
||||
TransferDataFromWindow();
|
||||
|
||||
// Save & restore parameters around Preview, because we didn't do OK.
|
||||
float oldDelay = m_pEffect->delay;
|
||||
float oldDecay = m_pEffect->decay;
|
||||
|
||||
m_pEffect->delay = delay;
|
||||
m_pEffect->decay = decay;
|
||||
|
||||
m_pEffect->Preview();
|
||||
|
||||
m_pEffect->delay = oldDelay;
|
||||
m_pEffect->decay = oldDecay;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user