Main Page | Namespaces | Classes | Compounds | Files | Compound Members | Related Synth.cpp00001 // 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 Docs made by Doxygen. Email: Mikael Christensen |