audacia/src/effects/Echo.cpp

289 lines
6.8 KiB
C++

/**********************************************************************
Audacity: A Digital Audio Editor
Echo.cpp
Dominic Mazzoni
Vaughan Johnson (dialog)
*******************************************************************//**
\class EffectEcho
\brief An Effect that causes an echo, variable delay and volume.
*//****************************************************************//**
\class EchoDialog
\brief EchoDialog used with EffectEcho
*//*******************************************************************/
#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 <wx/generic/textdlgg.h>
#include <wx/intl.h>
#include <math.h>
#include "Echo.h"
#include "../WaveTrack.h"
EffectEcho::EffectEcho()
{
delay = float(1.0);
decay = float(0.5);
}
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()
{
EchoDialog dlog(this, mParent);
dlog.delay = delay;
dlog.decay = decay;
dlog.CentreOnParent();
dlog.ShowModal();
if (dlog.GetReturnCode() == wxID_CANCEL)
return false;
delay = dlog.delay;
decay = dlog.decay;
return true;
}
bool EffectEcho::TransferParameters( Shuttle & shuttle )
{
shuttle.TransferFloat(wxT("Delay"),delay,1.0);
shuttle.TransferFloat(wxT("Decay"),decay,0.5);
return true;
}
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;
}
}
track = (WaveTrack *) iter.Next();
count++;
}
this->ReplaceProcessedTracks(bGoodResult);
return bGoodResult;
}
bool EffectEcho::ProcessOne(int count, WaveTrack * track,
sampleCount start, sampleCount len)
{
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;
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"))
{
m_bLoopDetect = false;
m_pEffect = effect;
// 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;
// effect parameters
delay = float(1.0);
decay = float(0.5);
// Initialize dialog
Init();
}
void EchoDialog::PopulateOrExchange(ShuttleGui & S)
{
S.StartHorizontalLay(wxCENTER, false);
{
/* i18n-hint: && in here is an escape character to get a single & on
* screen, so keep it as is */
S.AddTitle(_("by Dominic Mazzoni && Vaughan Johnson"));
}
S.EndHorizontalLay();
S.StartHorizontalLay(wxCENTER, false);
{
// Add a little space
}
S.EndHorizontalLay();
S.StartMultiColumn(2, wxALIGN_CENTER);
{
m_pTextCtrl_Delay = S.AddTextBox(_("Delay time (seconds):"),
wxT("1.0"),
10);
m_pTextCtrl_Delay->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
m_pTextCtrl_Decay = S.AddTextBox(_("Decay factor:"),
wxT("0.5"),
10);
m_pTextCtrl_Decay->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
}
S.EndMultiColumn();
}
bool EchoDialog::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);
}
m_bLoopDetect = false;
return true;
}
bool EchoDialog::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);
}
return true;
}
// handler implementations for EchoDialog
void EchoDialog::OnPreview(wxCommandEvent &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;
}
// Indentation settings for Vim and Emacs and unique identifier for Arch, a
// version control system. Please do not modify past this point.
//
// Local Variables:
// c-basic-offset: 3
// indent-tabs-mode: nil
// End:
//
// vim: et sts=3 sw=3
// arch-tag: 1c174e3a-7748-4045-8066-b394189a7ba7