/********************************************************************** 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 #include #include #include #include #include #include #include #include #include #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