Main Page | Namespaces | Classes | Compounds | Files | Compound Members | Related envelope.cpp00001 // Syntopia. See http://Syntopia.sourceforge.net for details and documentation. 00002 // 00003 // Author of this file: Mikael Hvidtfeldt Christensen (mikaelc@users.sourceforge.net) 00004 00005 #include "envelope.h" 00006 #include "math.h" 00007 #include <iostream> 00008 #include "SynthVoice.h" 00009 00010 // Envelope ---------------------------------------------------------------------------------------------------------- 00011 00012 namespace SynthCore { 00013 00014 Envelope3::Envelope3(SynthVoice * s) { 00015 // If we are part of a voice. 00016 hostVoice = s; 00017 00018 // Init envelope section with some standard values for Attack, Decay, Sustain, Release. 00019 Input1 = new Input(this); 00020 Output1 = new Output(this); 00021 myData = new EnvData(); 00022 00023 amp = 0; 00024 time = 0; 00025 00026 killVoice = false; 00027 00028 OldNoteOn=false; 00029 } 00030 00031 Module * Envelope3::sharedClone() { 00032 Envelope3 * Env = new Envelope3(hostVoice); 00033 00034 Env->killVoice = killVoice; 00035 00036 // This is considered a Hack 00037 if (Env->myData != 0) delete Env->myData; 00038 00039 Env->myData = myData; 00040 00041 Env->ModID = ModID; 00042 Env->firstVoice = false; 00043 00044 return Env; 00045 } 00046 00047 00048 Envelope3::~Envelope3() { 00049 delete(Input1); 00050 delete(Output1); 00051 delete(myData); 00052 } 00053 00054 00055 std::string Envelope3::getXML(int indent ) { 00056 00057 std::string S = Utils::space(indent) + "<Module ID=\""+Utils::intToString((int)this)+"\" >"+ Utils::newline(); 00058 S += Utils::space(indent+2) + "<TypeID>" + typeid(*this).name() + "</TypeID>" + Utils::newline(); 00059 S += myData->getXML(indent+2); 00060 00061 S += Output1->getXML("Output1", indent+2); 00062 S += Input1->getXML("Input1", indent+2); 00063 00064 S += saveParameter("killVoice",killVoice); 00065 S += saveID(indent+2); 00066 S += Utils::space(indent) + "</Module>" + Utils::newline(); 00067 return S; 00068 } 00069 00070 00071 void Envelope3::loadXML(XMLNode * n, bool firstPass) { 00072 cout << "Parsing Envelope XML" << endl; 00073 00074 string TypeID = n->getTagText("TypeID") ; 00075 if (typeid(*this).name() != TypeID) { 00076 throw parseError("Trying to put "+TypeID+" into "+typeid(*this).name()); 00077 } 00078 00079 if (firstPass) { 00080 loadParameter("killVoice",killVoice, n); 00081 Output1->loadXML("Output1", n); 00082 } else { 00083 Input1->loadXML("Input1", n); 00084 } 00085 00086 // TODO : what about the envelope? 00087 }; 00088 00089 00090 void Envelope3::setDuration(int calls) { 00091 myData->sampleLength = calls; 00092 } 00093 00094 00095 void Envelope3::update() { 00096 time++; 00097 00098 // Has our situtation changed? Key pressed or Key released? 00099 if (hostVoice->noteOn != OldNoteOn) 00100 { 00101 OldNoteOn=hostVoice->noteOn; 00102 00103 if (hostVoice->noteOn) { 00104 // We have just recieved a NoteOn event. 00105 time = 0; 00106 myData->endOfEnvelope = false; 00107 // Ensure that hostVoice is alive 00108 if (killVoice) hostVoice->aLive = true; 00109 } 00110 } 00111 00112 if (hostVoice->noteOn) { 00113 // Key pressed 00114 amp = myData->getValue(time,true); 00115 } else { 00116 // Key released 00117 amp = myData->getValue(time,false); 00118 00119 if (myData->endOfEnvelope) { 00120 // We have reached end of envelope. 00121 if (killVoice) hostVoice->aLive = false; 00122 } 00123 } 00124 00125 if (Input1->ConFrom != 0) 00126 { 00127 // Multiply the envelope with the input. 00128 Output1->value = Input1->ConFrom->value*amp; 00129 } else { 00130 // Just output envelope 00131 Output1->value = amp; 00132 } 00133 } 00134 00135 00136 // EnvData starts here --------------------------------------------------------------------------------------------- 00137 00138 void EnvData::getLimits(float &x0, float &y0, float &x1, float &y1) 00139 { 00140 00141 if (points.size()>1) { 00142 // Must be some points... 00143 x0 = points[0]->x; x1 = points[0]->x; 00144 y0 = points[0]->y; y1 = points[0]->y; 00145 } 00146 00147 for(int i = 0; i < points.size(); i++) 00148 { 00149 float x = points[i]->x; 00150 float y = points[i]->y; 00151 if ( x < x0) { x0=x; } 00152 if ( x > x1) { x1=x; } 00153 if ( y < y0) { y0=y; } 00154 if ( y > y1) { y1=y; } 00155 } 00156 } 00157 00158 std::string EnvData::getXML(int indent ) { 00159 00160 std::string S = Utils::space(indent) + "<EnvData ID=\""+Utils::intToString((int)this)+"\" >"+ Utils::newline(); 00161 S += Utils::space(indent+2) + "<TypeID>" + typeid(*this).name() + "</TypeID>" + Utils::newline(); 00162 S += Module::saveParameter("beginLP",beginLP, indent+2); 00163 S += Module::saveParameter("endLP",endLP, indent+2); 00164 S += Module::saveParameter("envSize",envsize, indent+2); 00165 S += Module::saveParameter("sampleLength",sampleLength, indent+2); 00166 00167 S += Utils::space(indent+2) + "<ControlPoints>" + Utils::newline(); 00168 00169 for (int j = 0; j < points.size();j++) 00170 { 00171 S += Utils::space(indent+4) + "<Point><x>" + Utils::floatToString(points[j]->x) 00172 + "</x><y>" + Utils::floatToString(points[j]->y) + "</y></Point>" + Utils::newline(); 00173 } 00174 00175 S += Utils::space(indent+2) + "</ControlPoints>" + Utils::newline(); 00176 00177 S += Utils::space(indent) + "</EnvData>" + Utils::newline(); 00178 return S; 00179 } 00180 00181 00182 00183 EnvData::EnvData() { 00184 00185 endOfEnvelope = false; 00186 00187 envsize = 1024; 00188 sampleLength = 100.0f; // The envelope spans 1 second 00189 00190 beginLP = 2; 00191 endLP = 3; 00192 00193 00194 00195 setChoosen(-1); 00196 00197 envdata = new float[envsize]; 00198 00199 // Init with a standard envelope. 00200 points.push_back(new coord(0.0f,0.0f)); 00201 points.push_back(new coord(0.2f,1.0f)); 00202 points.push_back(new coord(0.4f,0.5f)); 00203 00204 points.push_back(new coord(0.7f,0.1f)); 00205 points.push_back(new coord(0.8f,0.9f)); 00206 00207 points.push_back(new coord(1.0f,0.0f)); 00208 00209 00210 loopStart = -1; 00211 loopEnd = -1; 00212 loopState = sustainedLoop; 00213 00214 interpolateSpline(); 00215 } 00216 00217 00218 void EnvData::clearEnvelope() { 00219 // Clean up after points. 00220 for (int i=0; i < points.size(); i++) 00221 delete points[i]; 00222 00223 points.clear(); // This probably doesnt matter at all. 00224 beginLP = endLP = loopStart = loopEnd = -1; 00225 } 00226 00227 void EnvData::setADSR(float A, float D, float S, float R) { 00228 clearEnvelope(); 00229 points.push_back(new coord(0.0f,0.0f)); 00230 points.push_back(new coord(A,1.0f)); 00231 points.push_back(new coord(A+D,S)); 00232 points.push_back(new coord(A+D+A,S)); 00233 points.push_back(new coord(A+D+A+R,0.0f)); 00234 00235 beginLP = 2; 00236 endLP = 3; 00237 interpolate(); 00238 } 00239 00240 00241 EnvData::~EnvData() { 00242 delete[] envdata; 00243 clearEnvelope(); 00244 } 00245 00246 inline float EnvData::getValue(long &time, bool loop) { 00247 // The actual envelope module will access data through this routine. 00248 00249 // This must be updated to at least ASM-boosted linear interpolation. 00250 // Possible OVERFLOW! 00251 00252 // Convert time to array-index 00253 int idx = (int)((time*envsize)/sampleLength); 00254 00255 // should we loop? 00256 if ((loop) && (loopEnd != -1) && (loopStart != -1)) { 00257 // Are we in a loopzone? 00258 while (idx > loopEnd) { 00259 // MODIFY TIME INSTEAD 00260 time -= ((loopEnd-loopStart)*sampleLength/envsize); 00261 idx = (int)((time*envsize)/sampleLength); 00262 } 00263 } 00264 00265 if (idx > envsize -1) { idx = envsize -1 ; endOfEnvelope = true;} 00266 if (idx < 0) {idx = 0;} 00267 00268 return envdata[idx]; 00269 } 00270 00271 void EnvData::addPoint(float x, float y) { 00272 int before = 0; 00273 for (int j = 1; j < points.size();j++) 00274 { 00275 if (x>points[j]->x) { before = j; } 00276 } 00277 00278 points.insert(points.begin() + before + 1, new coord(x,y)); 00279 std::cout << " POINTS: " << std::endl; 00280 { for (int j = 0; j < points.size();j++) 00281 { 00282 std::cout << " I: " << j << " X: " << points[j]->x << " Y:" << points[j]->y << std::endl; 00283 }} 00284 } 00285 00286 void EnvData::removePoint(int p) { 00287 delete points[p]; 00288 points.erase(points.begin() + p); 00289 } 00290 00291 void EnvData::interpolateLinear() { 00292 float x0,y0,x1,y1; 00293 getLimits(x0,y0,x1,y1); 00294 int nr = 1; 00295 for (int i=0; i<envsize; i++) 00296 { 00297 float xpos = (((float) i/(float) envsize)-x0)*(x1-x0); 00298 if (points[nr]->x < xpos) {nr++;} 00299 envdata[i] = (points[nr]->y - points[nr-1]->y) 00300 * (xpos - points[nr-1]->x) 00301 /(points[nr]->x - points[nr-1]->x) 00302 + points[nr-1]->y; 00303 } 00304 } 00305 00306 00307 void EnvData::interpolateSpline() { 00308 float x0,y0,x1,y1; 00309 getLimits(x0,y0,x1,y1); 00310 int nr = 1; 00311 00312 loopStart = -1; 00313 loopEnd = -1; 00314 00315 if (beginLP != -1 ) 00316 { 00317 loopStart = (int) ((float)envsize* (points[beginLP]->x - x0)/(x1-x0) ); 00318 } 00319 00320 if (endLP != -1 ) 00321 { 00322 loopEnd = (int) ((float)envsize* (points[endLP]->x - x0)/(x1-x0) ); 00323 } 00324 00325 for (int i=0; i<envsize; i++) 00326 { 00327 float xpos = x0 + (((float) i/(float) envsize))*(x1-x0); 00328 if (points[nr]->x < xpos) {nr++;} 00329 float xd = (xpos - points[nr-1]->x) /(points[nr]->x - points[nr-1]->x); 00330 float y0, y3; 00331 if (nr-2>=0) { y0 = points[nr-1]->y; } else {y0 = points[0]->y; ;} 00332 float y1 = points[nr-1]->y; 00333 float y2 = points[nr]->y; 00334 if (nr+1<points.size()) { y3 = points[nr+1]->y; } else {y3 = points[points.size()-1]->y;} 00335 00336 float t = xd; 00337 float t2 = t * t; 00338 float t3 = t2 * t; 00339 00340 float alpha = 0.0; 00341 00342 float m0 = ((1 - alpha) / 2.0f) * ((y1 - y0) + y2 - y1); 00343 float m1 = ((1 - alpha) / 2.0f) * ((y2 - y1) + y3 - y2); 00344 00345 envdata[i] = (((2 * t3) - (3 * t2) + 1) * y1) + 00346 ((t3 - (2 * t2) + t) * m0) + 00347 ((t3 - t2) * m1) + 00348 (((-2 * t3) + (3 * t2)) * y2); 00349 } 00350 } 00351 00352 }; // end of namespace: SynthCore Docs made by Doxygen. Email: Mikael Christensen |