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

Synth.cpp

00001 //
00002 //  SYNTOPIA. See http://Syntopia.sourceforge.net for details and documentation.        
00003 //
00004 //      Author of this file: Mikael Hvidtfeldt Christensen (mikaelc@users.sourceforge.net)
00005 //
00006 
00007 
00008 
00009 
00010 
00011 
00012 #include "Synth.h"
00013 #include "float.h"
00014 #include "waveshaper.h"
00015 
00016 namespace SynthCore {
00017 
00018 std::string Synth::getXML(int indent) {
00019 
00020         std::string S= "";
00021 
00022         S += "<?xml version=\"1.0\" ?>" +Utils::newline();
00023         S +=  "<?xml-stylesheet href=\"synth.css\" type=\"text/css\" ?>" + Utils::newline();
00024 
00025         S += Utils::space(indent)+"<Synth SyntopiaVersion=\"0.1\">"+Utils::newline();
00026         S += Utils::space(indent)+"  <Name>Alfa save</Name>"+Utils::newline();
00027         S += Utils::space(indent)+"  <Comment>This XML file can be loaded directly into Syntopia.</Comment>"+Utils::newline();
00028 
00029         SynthVoice * firstVoice = 0;
00030 
00031         for(ModuleMapIter it = totalMap.begin(); it != totalMap.end(); ++it)
00032         {
00033                 // Check if this is the first module that is part of a voice.
00034                 if ((*it)->hostVoice != 0)
00035                         if (firstVoice == 0) {firstVoice = (*it)->hostVoice;}
00036                 
00037                 //if ((*it)->hostVoice == 0 || (*it)->hostVoice == firstVoice)
00038                         S += Utils::space(indent)+(*it)->getXML(2);
00039         }
00040 
00041 
00042         S += Output1->getXML("Output1",indent);
00043         S += Output2->getXML("Output2",indent);
00044 
00045         S += Utils::space(indent)+"</Synth>"+Utils::newline();
00046         return S;
00047 }
00048 
00049 
00050 void Synth::loadXML(string fileName) {
00051         totalMap.clear();
00052                           cout << "ZTotalMap length:" << totalMap.size() << endl;
00053         XMLOutputs.clear();
00054         XMLDoc myDoc;
00055                 
00056         moduleRegistry::getInstance()->add(typeid(BiQuad).name(),BiQuad::newInstance);
00057         moduleRegistry::getInstance()->add(typeid(Envelope3).name(),Envelope3::newInstance);
00058         moduleRegistry::getInstance()->add(typeid(Sampler).name(),Sampler::newInstance);
00059         moduleRegistry::getInstance()->add(typeid(WaveShaper).name(),WaveShaper::newInstance);
00060         moduleRegistry::getInstance()->add(typeid(Polyphony).name(),Polyphony::newInstance);
00061         moduleRegistry::getInstance()->add(typeid(Tube).name(),Tube::newInstance);
00062 
00063         try {
00064                 myDoc.parseFile(fileName);
00065                 //cout << myDoc.rootNode->getXML(0).c_str();
00066                 cout << endl;
00067                 
00068                 
00069                 // Step 1: Scan the XML file for modules tags
00070                 // and create the respective module.
00071                                 
00072                 XMLSearch mods(&myDoc);
00073                 mods.find("/Synth/Module");
00074                 
00075                 // Create the SynthVoice
00076                 SynthVoice * myVoice = new SynthVoice(this, false);
00077 
00078                 for (int i = 0; i<mods.answer.size(); i++)
00079                 {                                                         
00080                   cout << endl << endl << "Found module:" ;
00081                   
00082                   string TypeID = mods.answer[i]->getTagText("TypeID") ;
00083                   cout << "TypeID:" << TypeID ;
00084 
00085                   int hostVoicePtr = Utils::stringToInt(mods.answer[i]->getTagText("hostVoice")) ;
00086 
00087                   SynthVoice * voice = 0;
00088                   if (hostVoicePtr != 0) {
00089                           voice = myVoice;
00090                          cout << "[SynthVoice]" << endl;
00091                   }
00092                   Module * newModule;
00093 
00094                   newModule = moduleRegistry::getInstance()->getNew(TypeID,voice);
00095 
00096                   cout << endl << "Created: " << typeid(*newModule).name() << "!" << endl;
00097                   if (newModule == 0)   throw parseError("Unknown module tag: "+TypeID);
00098                         
00099 
00100                   // Now the module must register its inputs and outputs to the following tables:
00101                   // Map<string, Input *> XMLInputs;
00102                   // Map<string, Output *> XMLOutputs;
00103                   //
00104                   // This is the first pass of readXML.
00105                   newModule->loadXML(mods.answer[i], true);
00106                         
00107                   // Register module on map
00108                   cout << "TotalMap length:" << totalMap.size() << endl;
00109                   totalMap.push_back(newModule);
00110 
00111         
00112                 }
00113 
00114                 cout << endl << "------------------------------------------------" << endl;
00115 
00116                 // Second pass. All Modules are created. All Input and Outputs are stored in the tables.
00117                 // Now init the Module settings
00118                 int j = 0;
00119                 cout << "TotalMap length:" << totalMap.size() << endl;
00120                 for(ModuleMapIter it = totalMap.begin(); it != totalMap.end(); ++it)
00121                 {
00122                         cout << endl << endl;
00123                         cout << "From Totalmap " << j << "[" << typeid(*(*it)).name() << "] " << mods.answer[j]->getTagText("TypeID") << endl;
00124                         cout << (*it)->getName() << endl;
00125                         (*it)->loadXML(mods.answer[j], false);  
00126                         j++;
00127                 }
00128 
00129                 // Finally connect the Synth Outputs
00130                 XMLNode * node = myDoc.rootNode->getTag("Output1") ;
00131 
00132                 if (node == 0) { throw parseError(" '/Synth/Output1' not found."); }
00133                 cout << "NODE: " << (int) node << endl << endl;
00134 
00135                 string Attr = ((TagNode *)node)->getAttribute("ID");    
00136                 if (Attr!="" && Attr!="\"0\"") {
00137                         Output * Out = SynthEngine::mySynth->XMLGetOutput(Attr);
00138                         if (Out != 0) {
00139                                 cout << "we found SYNTHOUT1: "<< Out->HostModule->getName();
00140                                 Output1 = Out;
00141                         } else {
00142                                 throw parseError("No legal '/Synth/Output1' found");
00143                         }
00144                 } else {
00145                         throw parseError("No legal '/Synth/Output1' found");
00146                 }
00147 
00148                 node = myDoc.rootNode->getTag("Output2") ;
00149 
00150                 if (node == 0) { parseError(" '/Synth/Output2' not found."); }
00151 
00152                 Attr = ((TagNode *)node)->getAttribute("ID");   
00153                 if (Attr!="" && Attr!="\"0\"") {
00154                         Output * Out = SynthEngine::mySynth->XMLGetOutput(Attr);
00155                         if (Out != 0) {
00156                                 cout << "we found SYNTHOUT2: "<< Out->HostModule->getName();
00157                                 Output2 = Out;
00158                         } else {
00159                                 throw parseError("No legal '/Synth/Output2' found");
00160                         }
00161                 } else {
00162                         throw parseError("No legal '/Synth/Output2' found");
00163                 }
00164 
00165                 
00166                 
00167 
00168 
00169                 // Now we must set up polyphony. IE clone the firstVoice.
00170 
00171                 //cout << mods.answer[0]->getXML(2) << endl;
00172 
00173 
00174         } catch (parseError pE) {
00175                         pE.print();
00176         }
00177 }
00178 
00179 void Synth::buildupdateMap() {  
00180         // For efficiency the map is copied to an array.
00181         int o = 0;
00182         for(it = itbegin; it != itend; it++)    
00183         {
00184                 if ((*it)->hostVoice == 0) { 
00185                         QuickMap[o]=(*it); o++; 
00186                 }
00187                 else if ((*it)->hostVoice->aLive) { 
00188                         QuickMap[o]=(*it); o++;
00189                 }
00190         }
00191         QuickMap[o]=0; PathLength = o;
00192 }
00193 
00194 bool Synth::isOnUpdateMap(Module * m)
00195 {       // Have we accounted for this instrument already?
00196         for(ModuleMapIter it = UpdateMap.begin(); it != UpdateMap.end(); ++it)
00197                 if ((*it) == m) { return true; }
00198                 return false;
00199 }
00200 
00201 
00202 void Synth::makemap(Module * m) {
00203         // Check if Module is on list
00204         if (!isOnUpdateMap(m))
00205         {
00206                 // Add Module to list
00207                 UpdateMap.push_front(m);
00208         
00209                 // Cycle Through Inputs in Module...
00210                 for (int i=0; i<(m->getNoInputs()); i++)
00211                 {
00212                   // Check if input is updated manually:        
00213                   if (m->getInput(i)->manualUpdate == false)
00214                         // If not, then add it to the map.  
00215                         // Check for unconnected inputs:
00216                         if (m->getInput(i)->ConFrom != 0)
00217                         makemap(m->getInput(i)->ConFrom->HostModule);
00218                 }
00219                 
00220         }
00221 }
00222 
00223 
00224 bool Synth::isOnTotalMap(Module * m)
00225 {       // Have we accounted for this instrument already?
00226         for(ModuleMapIter it = totalMap.begin(); it != totalMap.end(); ++it)
00227                 if ((*it) == m) { return true; }
00228                 return false;
00229 }
00230 
00231 void Synth::add(Module * m)
00232 {
00233         totalMap.push_back(m);
00234 }
00235 
00236 
00237 void Synth::update() {
00238         // Make the neccesary updates.
00239         for (ii = 0; ii<PathLength; ii++) { 
00240                 QuickMap[ii]->update(); 
00241         };
00242 }       
00243 
00244 Synth::Synth() {
00245         // For denormalized floats: enable this
00246         //_control87(_DN_FLUSH, _MCW_DN);
00247 
00248         myFreqTable = new FreqTable();
00249 
00250         SynthEngine::mySynth = this;
00251 
00252         availVoice = 0;
00253         noVoices = 4;
00254 
00255 
00256         // GENERALIZE:
00257         myPolyphony = new Polyphony();
00258         
00259         SynthVoice * firstVoice = new SynthVoice(this);
00260         myPolyphony->addVoice(firstVoice);
00261         voices[0] = firstVoice;
00262 
00263         SynthVoice * temp = 0;
00264         for (int t2=1; t2<noVoices; t2++) {
00265                 SynthVoice * temp = firstVoice->sharedClone();
00266                 myPolyphony->addVoice(temp);
00267                 voices[t2]=temp;
00268         }
00269         /*
00270         EnvData * firstEnvelope;
00271         EnvData * firstEnvelope2;
00272         for (int t2=0; t2<noVoices; t2++) {
00273                 Module::resetIDCount(1); // This resets the ModID everytime we create 
00274                                                                  // a synthVoice. This will give every voice
00275                                                                  // the same set of ID's
00276                 voices[t2]=new SynthVoice(this);
00277                 
00278                 // HACK: we force the envelope3's to share the envelope data
00279                 if (t2 == 0) { 
00280                         firstEnvelope = voices[t2]->myEnv2->myData; 
00281                         firstEnvelope2 = voices[t2]->myEnvelope->myData; 
00282                 
00283                 }
00284                 else {
00285                          voices[t2]->myEnv2->myData = firstEnvelope ;
00286                          voices[t2]->myEnvelope->myData = firstEnvelope2;
00287                 }
00288 
00289                 myPolyphony->addVoice(voices[t2]);
00290         }
00291         */
00292         
00293         this->add(myPolyphony);
00294 
00295         myWS = new WaveShaper(0);
00296         myWS->Input1->ConnectFrom(myPolyphony->Output1);
00297         this->add(myWS);
00298 
00299         myFilter = new BiQuad(0);
00300         myFilter->Input1->ConnectFrom(myPolyphony->Output1);
00301         myFilter->myFilter->bandpass2FreqAndQ(500.0f,0.142f);
00302         myFilter->myFilter2->clone(myFilter->myFilter);
00303         myFilter->HACK = true;
00304         this->add(myFilter);
00305 
00306         myComb = new Tube(0);
00307         myComb->Input1->ConnectFrom(myFilter->Output1);
00308         this->add(myComb);
00309         
00310         Output1 = myFilter->Output1;
00311         Output2 = myFilter->Output1;
00312         
00313         PathLength = 0;
00314         StateChange();
00315 
00316         active = true;
00317 }
00318 
00319 Synth::~Synth() {
00320         // Remove all registered modules.
00321         for(ModuleMapIter it = totalMap.begin(); it != totalMap.end(); ++it)
00322          delete (*it);
00323 
00324         //delete(voices[0]);
00325         //delete(voices[1]);
00326         //delete(voices[2]);
00327         //delete(voices[3]);    
00328 }
00329 
00330 void Synth::StateChange()
00331 {
00332         makemap(Output1->HostModule); 
00333         itbegin = UpdateMap.begin();
00334         itend = UpdateMap.end();
00335         buildupdateMap();
00336 }
00337 
00338 
00339 void Synth::noteOff(int note)
00340 {
00341         // Note Off
00342         for (int i=0; i<noVoices; i++)
00343         {
00344                 if (voices[i]->playingNote==note)       voices[i]->noteOn=false;
00345         }
00346 }
00347 
00348 
00349 
00350 void Synth::noteOn(int note)
00351 {
00352                                 
00353                                 // Cycle through synthVoices;
00354                                 int i=0;
00355                                 
00356                                 // We cycle until availVoice hits an empty synth
00357                                 // or we have tried noVoices times:
00358                                 // After that we have to stop a playing voice.
00359                                 do 
00360                                 { 
00361                                         availVoice++; i++; 
00362                                         if (availVoice==noVoices) {availVoice=0;}
00363                                 } 
00364                                 while  ((voices[availVoice]->aLive) && (i<noVoices+1));
00365                                 
00366                                 
00367                                 // Set noteOn (that is keypressed)
00368                                 voices[availVoice]->noteOn=true;
00369                                 
00370                                 // Set aLive (that is, we are still playing - maybe even after noteOff)
00371                                 voices[availVoice]->aLive=true;
00372 
00373                                 // Calculate frequency
00374                                 voices[availVoice]->setMidiFreq(myFreqTable->freqTab[note]);
00375                                 
00376                                 voices[availVoice]->setMidiNote(note);
00377 
00378 
00379 
00380                                 // Lets the SynthVoice informs its module of a new Midi Event.
00381                                 voices[availVoice]->newMidiEvent();
00382                                         
00383                                 StateChange();
00384                                                                 
00385 }
00386 
00387 
00388 
00389 void Synth::allNotesOff()
00390 {
00391         for (int i=0; i<availVoice; i++)
00392                                 {
00393                 voices[i]->noteOn=false;
00394                                 }
00395 }
00396 
00397 }; // end of namespace: SynthCore

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