Marsyas
0.6.0-alpha
|
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 }