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 "../common_source.h" 00020 #include "Delay.h" 00021 00022 using std::ostringstream; 00023 using std::vector; 00024 00025 using namespace Marsyas; 00026 00027 //#define MTLB_DBG_LOG 00028 00029 static inline mrs_natural wrapCursor (mrs_natural unwrappedCursor, mrs_natural cursorMask) 00030 { 00031 // add delay line length to have a sort-of dealing with negative indices as well; should be a while loop really 00032 return (unwrappedCursor + (cursorMask+1)) & cursorMask; 00033 } 00034 00035 static inline mrs_real getValue (mrs_natural obs, mrs_real index, mrs_realvec& buffer, mrs_natural cursorMask) 00036 { 00037 mrs_natural integer = (mrs_natural)index + ((index < 0)? -1 : 0); 00038 mrs_real frac = index - integer; 00039 mrs_real retVal = buffer(obs, wrapCursor (integer, cursorMask)); 00040 00041 return retVal + frac * (buffer(obs, wrapCursor (integer+1, cursorMask))-retVal); 00042 } 00043 00044 Delay::Delay(mrs_string name):MarSystem("Delay",name) 00045 { 00046 00047 delayInSamples_.create(0); 00048 writeCursor_ = 0; 00049 00050 cursorMask_ = 1; 00051 00052 addControls(); 00053 } 00054 00055 00056 Delay::~Delay() 00057 { 00058 } 00059 00060 00061 MarSystem* 00062 Delay::clone() const 00063 { 00064 return new Delay(*this); 00065 } 00066 00067 Delay::Delay(const Delay& a) : MarSystem(a) 00068 { 00069 addControls(); 00070 maxDelayLengthInSamples_ = getctrl("mrs_real/maxDelaySamples")->to<mrs_real>(); // maximum delay in samples 00071 delayInSamples_ = getctrl("mrs_realvec/delaySamples")->to<mrs_realvec>(); // delay in samples 00072 } 00073 00074 void 00075 Delay::addControls() 00076 { 00077 mrs_realvec tmp(1); 00078 tmp(0) = 0; 00079 addctrl("mrs_real/maxDelaySamples", 32.0); // maximum delay in samples 00080 addctrl("mrs_real/maxDelaySeconds", 0.0); // maximum delay in seconds 00081 addctrl("mrs_real/delaySamples", 0.0); // delay in samples 00082 addctrl("mrs_real/delaySeconds", 0.0); // delay in seconds 00083 addctrl("mrs_realvec/delaySamples", tmp); // delay in samples 00084 addctrl("mrs_realvec/delaySeconds", tmp); // delay in samples 00085 setctrlState("mrs_real/maxDelaySamples", true); 00086 setctrlState("mrs_real/maxDelaySeconds", true); 00087 setctrlState("mrs_real/delaySeconds", true); 00088 setctrlState("mrs_real/delaySamples", true); 00089 setctrlState("mrs_realvec/delaySeconds", true); 00090 setctrlState("mrs_realvec/delaySamples", true); 00091 } 00092 00093 00094 void 00095 Delay::myUpdate(MarControlPtr sender) 00096 { 00097 (void) sender; //suppress warning of unused parameter(s) 00098 MRSDIAG("Delay.cpp - Delay:myUpdate"); 00099 00100 // for the following controls, check whether they have changed and update dependent controls accordingly 00101 if (samples2Seconds (maxDelayLengthInSamples_) != getctrl ("mrs_real/maxDelaySeconds")->to<mrs_real>()) 00102 { 00103 maxDelayLengthInSamples_ = seconds2Samples (getctrl ("mrs_real/maxDelaySeconds")->to<mrs_real>()); 00104 setctrl("mrs_real/maxDelaySamples", maxDelayLengthInSamples_); 00105 buffer_.stretch (getctrl("mrs_natural/inObservations")->to<mrs_natural>(), 00106 nextPowOfTwo((mrs_natural(.1+ceil(maxDelayLengthInSamples_))+1))); 00107 buffer_.setval(0); 00108 } 00109 if (maxDelayLengthInSamples_ != getctrl ("mrs_real/maxDelaySamples")->to<mrs_real>()) 00110 { 00111 maxDelayLengthInSamples_ = getctrl ("mrs_real/maxDelaySamples")->to<mrs_real>(); 00112 setctrl("mrs_real/maxDelaySeconds", samples2Seconds (maxDelayLengthInSamples_)); 00113 buffer_.stretch (getctrl("mrs_natural/inObservations")->to<mrs_natural>(), 00114 nextPowOfTwo((mrs_natural(.1+ceil(maxDelayLengthInSamples_))+1))); 00115 buffer_.setval(0); 00116 } 00117 00118 if (samples2Seconds (singleDelayInSamples_) != getctrl ("mrs_real/delaySeconds")->to<mrs_real>()) 00119 { 00120 mrs_realvec tmp(1); 00121 singleDelayInSamples_ = seconds2Samples (getctrl ("mrs_real/delaySeconds")->to<mrs_real>()); 00122 MRSASSERT(singleDelayInSamples_ >= 0); 00123 MRSASSERT(singleDelayInSamples_ <= maxDelayLengthInSamples_); 00124 00125 setctrl("mrs_real/delaySamples", singleDelayInSamples_); 00126 00127 // update vector 00128 tmp(0) = singleDelayInSamples_; 00129 setctrl("mrs_realvec/delaySamples", tmp); 00130 } 00131 if (singleDelayInSamples_ != getctrl ("mrs_real/delaySamples")->to<mrs_real>()) 00132 { 00133 mrs_realvec tmp(1); 00134 singleDelayInSamples_ = getctrl ("mrs_real/delaySamples")->to<mrs_real>(); 00135 MRSASSERT(singleDelayInSamples_ >= 0); 00136 MRSASSERT(singleDelayInSamples_ <= maxDelayLengthInSamples_); 00137 00138 setctrl("mrs_real/delaySeconds", samples2Seconds (singleDelayInSamples_)); 00139 00140 // update vector 00141 tmp(0) = singleDelayInSamples_; 00142 setctrl("mrs_realvec/delaySamples", tmp); 00143 } 00144 00145 if (delayInSamples_ != getctrl ("mrs_realvec/delaySamples")->to<mrs_realvec>()) 00146 { 00147 delayInSamples_ = getctrl ("mrs_realvec/delaySamples")->to<mrs_realvec>(); 00148 setctrl("mrs_realvec/delaySeconds", samples2Seconds (delayInSamples_)); 00149 } 00150 if (samples2Seconds (delayInSamples_) != getctrl ("mrs_realvec/delaySeconds")->to<mrs_realvec>()) 00151 { 00152 delayInSamples_ = seconds2Samples (getctrl ("mrs_realvec/delaySeconds")->to<mrs_realvec>()); 00153 setctrl("mrs_realvec/delaySamples", delayInSamples_); 00154 } 00155 00156 // allocate the delay line 00157 buffer_.stretch (getctrl("mrs_natural/inObservations")->to<mrs_natural>(), 00158 nextPowOfTwo((mrs_natural(.1+ceil(maxDelayLengthInSamples_))+1))); 00159 cursorMask_ = buffer_.getCols () - 1; // to ensure an efficient wrap around, buffer 00160 //length will be a power of two 00161 if (prevDelayInSamples_.getSize () != delayInSamples_.getSize ()) 00162 { 00163 // only do this update if needed... 00164 ctrlIncrement_.stretch (delayInSamples_.getSize (), delayInSamples_.getCols ()); 00165 prevDelayInSamples_ = delayInSamples_; 00166 00167 // initialize the delay line 00168 buffer_.stretch (getctrl("mrs_natural/inObservations")->to<mrs_natural>(), 00169 nextPowOfTwo((mrs_natural(.1+ceil(maxDelayLengthInSamples_))+1))); 00170 buffer_.setval(0); 00171 writeCursor_ = 0; 00172 00173 // set output names 00174 vector<mrs_string> indiChannels = stringSplit (getctrl("mrs_string/inObsNames")->to<mrs_string>(), ","); 00175 ostringstream outNames; 00176 for (mrs_natural c = 0; c < getctrl("mrs_natural/inObservations")->to<mrs_natural>(); ++c) 00177 for (mrs_natural i = 0; i < delayInSamples_.getSize (); ++i) 00178 { 00179 outNames << indiChannels.at(c) << "-delay_" << i << ","; 00180 } 00181 setctrl("mrs_string/onObsNames", outNames.str()); 00182 } 00183 00184 00185 setctrl("mrs_natural/onSamples", getctrl("mrs_natural/inSamples")); 00186 setctrl("mrs_real/osrate", getctrl("mrs_real/israte")); 00187 setctrl("mrs_natural/onObservations", 00188 (mrs_natural) delayInSamples_.getSize () * getctrl("mrs_natural/inObservations")->to<mrs_natural>()); 00189 00190 } 00191 00192 00193 void 00194 Delay::myProcess(realvec& in, realvec& out) 00195 { 00196 mrs_natural k, numDelayLines = delayInSamples_.getSize (); 00197 mrs_natural o,t; 00198 // first, get the interpolated delay update (linear interpolation only) 00199 getLinearInterPInc (prevDelayInSamples_, delayInSamples_, ctrlIncrement_, inSamples_); 00200 00201 #ifdef MARSYAS_MATLAB 00202 #ifdef MTLB_DBG_LOG 00203 MATLAB_PUT(in, "in"); 00204 MATLAB_EVAL("figure(41),subplot(211),plot(in'),axis('tight'),grid on, title('in')"); 00205 #endif 00206 #endif 00207 00208 for (t = 0; t < inSamples_; t++) 00209 { 00210 for (o=0; o < inObservations_; o++) 00211 { 00212 // write new sample to buffer 00213 buffer_(o, writeCursor_) = in(o,t); 00214 for (k = 0; k < numDelayLines; k++) 00215 { 00216 // read sample from buffer 00217 out(k+o*numDelayLines,t) = getValue (o, writeCursor_ - (prevDelayInSamples_(k) + t*ctrlIncrement_(k)), buffer_, cursorMask_); 00218 } 00219 00220 } 00221 writeCursor_ = wrapCursor (++writeCursor_, cursorMask_); 00222 } 00223 00224 prevDelayInSamples_ = delayInSamples_; 00225 00226 00227 #ifdef MARSYAS_MATLAB 00228 #ifdef MTLB_DBG_LOG 00229 MATLAB_PUT(out, "out"); 00230 MATLAB_EVAL("figure(41),subplot(212),plot(out'),axis('tight'),grid on, title('out')"); 00231 #endif 00232 #endif 00233 } 00234 00235 void Delay::getLinearInterPInc (const mrs_realvec startVal, const mrs_realvec stopVal, 00236 mrs_realvec &incVal, const mrs_natural numSamples) 00237 { 00238 incVal = (stopVal - startVal); 00239 incVal /= (1.0*numSamples); 00240 } 00241 00242 mrs_natural Delay::nextPowOfTwo (mrs_natural value) 00243 { 00244 mrs_natural order = 0; 00245 00246 while (value>>order) 00247 order++; 00248 00249 if (!order) 00250 return value; 00251 00252 if (!(value%(1<<(order-1)))) 00253 order--; 00254 00255 order = (order < 1)? 1 : order; 00256 00257 return (1<<(order)); 00258 } 00259 00260 mrs_real Delay::samples2Seconds (mrs_real samples) 00261 { 00262 if (israte_ > 0) 00263 return samples / israte_; 00264 else 00265 return 0; 00266 } 00267 mrs_real Delay::seconds2Samples (mrs_real seconds) 00268 { 00269 return seconds * israte_; 00270 } 00271 mrs_realvec Delay::samples2Seconds (mrs_realvec samples) 00272 { 00273 for (mrs_natural i = 0; i < samples.getSize (); ++i) 00274 samples(i) = samples(i)/ israte_; 00275 00276 return samples; 00277 } 00278 mrs_realvec Delay::seconds2Samples (mrs_realvec seconds) 00279 { 00280 for (mrs_natural i = 0; i < seconds.getSize (); ++i) 00281 seconds(i) = seconds(i) * israte_; 00282 00283 return seconds; 00284 }