logo
Main Page | Namespaces | Classes | Compounds | Files | Compound Members | Related

envelope.cpp

00001 //  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

Syntopia Project. Visit the web page, or the SourceForge page.
Docs made by Doxygen. Email: Mikael Christensen