Marsyas  0.6.0-alpha
/usr/src/RPM/BUILD/marsyas-0.6.0/src/marsyas/marsystems/APDelayOsc.cpp
Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 1998-2010 George Tzanetakis <gtzan@cs.uvic.ca>
00003 **
00004 ** This program is free software; you can redistribute it and/or modify
00005 ** it under the terms of the GNU General Public License as published by
00006 ** the Free Software Foundation; either version 2 of the License, or
00007 ** (at your option) any later version.
00008 **
00009 ** This program is distributed in the hope that it will be useful,
00010 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 ** GNU General Public License for more details.
00013 **
00014 ** You should have received a copy of the GNU General Public License
00015 ** along with this program; if not, write to the Free Software
00016 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 */
00018 
00019 #include "APDelayOsc.h"
00020 #include "../common_source.h"
00021 
00022 using std::ostringstream;
00023 using namespace Marsyas;
00024 
00025 APDelayOsc::APDelayOsc(mrs_string name):MarSystem("APDelayOsc", name)
00026 {
00027   noteon_ = true;
00028 
00029   addControls();
00030 }
00031 
00032 APDelayOsc::APDelayOsc(const APDelayOsc& a) : MarSystem(a)
00033 {
00034   // IMPORTANT!
00037   // Otherwise this would result in trying to deallocate them twice!
00038 }
00039 
00040 
00041 APDelayOsc::~APDelayOsc()
00042 {
00043 }
00044 
00045 MarSystem* APDelayOsc::clone() const
00046 {
00047   // Every MarSystem should do this.
00048   return new APDelayOsc(*this);
00049 }
00050 
00051 void APDelayOsc::addControls()
00052 {
00053   addctrl("mrs_real/frequency", 440.0);
00054   addctrl("mrs_natural/type", 0);
00055   addctrl("mrs_bool/noteon", false);
00056 
00057   setctrlState("mrs_real/frequency", true);
00058   setctrlState("mrs_natural/type", true);
00059   setctrlState("mrs_bool/noteon", true);
00060 }
00061 
00062 void APDelayOsc::myUpdate(MarControlPtr sender)
00063 {
00064   MRSDIAG("APDelayOsc.cpp - APDelayOsc:myUpdate");
00065 
00066   frequency_ = (getctrl("mrs_real/frequency")->to<mrs_real>());
00067   noteon_ = (getctrl("mrs_bool/noteon")->to<mrs_bool>());
00068   type_ = (getctrl("mrs_natural/type")->to<mrs_natural>());
00069 
00070   israte_ = (getctrl("mrs_real/israte")->to<mrs_real>());
00071 
00072   // loweset frequency on a piano is 27.5Hz ... sample rate/27.5 for commute
00073   // this is the longest delay line required
00074   if (delaylineSize_ == 0)
00075   {
00076     delaylineSize_ = (mrs_natural) (israte_/10);
00077     delayline_.create((mrs_natural)delaylineSize_);
00078 
00079     for (mrs_natural t = 0; t < delaylineSize_; t++)
00080     {
00081       delayline_(t) = 0.0;
00082     }
00083   }
00084 
00085   if (noteon_)
00086   {
00087     // Allpass coefficient
00088     // Chosen through experimentation
00089     //ap1.delay(0.7);
00090 
00091     // The amount of delay to generate the correct pitch
00092     mrs_real d = (israte_/frequency_);
00093     N_ = (mrs_natural)floor(d);
00094     frac_ = d - N_;
00095     ap2.delay(frac_);
00096 
00097     // Choses the differences between generating saw
00098     // or square waves.
00099     switch (type_)
00100     {
00101     case 0: // Saw
00102       dc_ = frequency_ / israte_;
00103       neg_ = 1;
00104       break;
00105     case 1: // Square
00106       dc_ = 0;
00107       neg_ = -1;
00108       N_ = N_/2; // Because this is bipolar
00109       // we need to halve the period
00110       break;
00111     }
00112 
00113     // Initialize the delay line
00114     for (mrs_natural t = 0; t < N_; t++)
00115     {
00116       delayline_(t) = 0;
00117     }
00118     // initialize the system with an impulse
00119     delayline_(1) = 0.95;
00120 
00121     // Initialize our read and write pointers
00122     rp_ = 1;
00123     rpp_ = 0; // Not used, but could be used to do pitch shifting
00124     wp_ = N_-1;
00125   }
00127   MarSystem::myUpdate(sender);
00128 }
00129 
00130 void APDelayOsc::myProcess(realvec& in, realvec& out)
00131 {
00132   (void) in;
00133 
00134   mrs_natural t;
00135   mrs_real y, x = 0;
00136 
00137   for (t = 0; t < inSamples_; t++)
00138   {
00139     if (noteon_)
00140     {
00141       // rp holds the current sample
00142       x  = delayline_(rp_);
00143 
00144       y = ap2(ap1(x));
00145 
00146       // Write current sample back into the delay buffer.
00147       // If square each sample is negated.
00148       delayline_(wp_) = y * neg_;
00149 
00150       // The leaky Integrator is used to apply an
00151       // exponential decay as frequencies increase.
00152 
00153       out(0,t) = dcb(le1(y - dc_));
00154 
00155       // Increment the delay line pointers
00156       wp_ = (wp_ + 1)  % N_;
00157       rp_ = (rp_ + 1)  % N_;
00158 
00159     }
00160     else
00161     {
00162       out(0,t) = 0;
00163     }
00164   }
00165 }