289 lines
6.8 KiB
C++
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
|
|
|