/* ZynAddSubFX - a software synthesizer Part.C - Part implementation Copyright (C) 2002-2005 Nasca Octavian Paul Author: Nasca Octavian Paul This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License (version 2) for more details. You should have received a copy of the GNU General Public License (version 2) along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "Master.h" #include "Part.h" #include "Microtonal.h" #include <stdlib.h> #include <stdio.h> #include <string.h> Part::Part(Microtonal *microtonal_,FFTwrapper *fft_, Master* master_){ microtonal=microtonal_; fft=fft_; master=master_; partoutl=new REALTYPE [SOUND_BUFFER_SIZE]; partoutr=new REALTYPE [SOUND_BUFFER_SIZE]; tmpoutl=new REALTYPE [SOUND_BUFFER_SIZE]; tmpoutr=new REALTYPE [SOUND_BUFFER_SIZE]; for (int n=0;n<NUM_KIT_ITEMS;n++){ kit[n].Pname=new unsigned char [PART_MAX_NAME_LEN]; kit[n].adpars=NULL;kit[n].subpars=NULL;kit[n].padpars=NULL; }; kit[0].adpars=new ADnoteParameters(fft); kit[0].subpars=new SUBnoteParameters(); kit[0].padpars=new PADnoteParameters(fft,master); // ADPartParameters=kit[0].adpars; // SUBPartParameters=kit[0].subpars; //Part's Insertion Effects init for (int nefx=0;nefx<NUM_PART_EFX;nefx++) partefx[nefx]=new EffectMgr(1,master); for (int n=0;n<NUM_PART_EFX+1;n++) { partfxinputl[n]=new REALTYPE [SOUND_BUFFER_SIZE]; partfxinputr[n]=new REALTYPE [SOUND_BUFFER_SIZE]; Pefxbypass[n]=false; }; killallnotes=0; oldfreq=-1.0; int i,j; for (i=0;i<POLIPHONY;i++){ partnote[i].status=KEY_OFF; partnote[i].note=-1; partnote[i].itemsplaying=0; for (j=0;j<NUM_KIT_ITEMS;j++){ partnote[i].kititem[j].adnote=NULL; partnote[i].kititem[j].subnote=NULL; partnote[i].kititem[j].padnote=NULL; }; partnote[i].time=0; }; cleanup(); Pname=new unsigned char [PART_MAX_NAME_LEN]; oldvolumel=oldvolumer=0.5; lastnote=-1; defaults(); }; void Part::defaults(){ Penabled=0; Pminkey=0; Pmaxkey=127; Pnoteon=1; Ppolymode=1; setPvolume(96); Pkeyshift=64; Prcvchn=0; setPpanning(64); Pvelsns=64; Pveloffs=64; Pkeylimit=15; defaultsinstrument(); ctl.defaults(); }; void Part::defaultsinstrument(){ ZERO(Pname,PART_MAX_NAME_LEN); info.Ptype=0; ZERO(info.Pauthor,MAX_INFO_TEXT_SIZE+1); ZERO(info.Pcomments,MAX_INFO_TEXT_SIZE+1); Pkitmode=0; Pdrummode=0; for (int n=0;n<NUM_KIT_ITEMS;n++){ kit[n].Penabled=0;kit[n].Pmuted=0; kit[n].Pminkey=0;kit[n].Pmaxkey=127; kit[n].Padenabled=0;kit[n].Psubenabled=0;kit[n].Ppadenabled=0; ZERO(kit[n].Pname,PART_MAX_NAME_LEN); kit[n].Psendtoparteffect=0; if (n!=0) setkititemstatus(n,0); }; kit[0].Penabled=1; kit[0].Padenabled=1; kit[0].adpars->defaults(); kit[0].subpars->defaults(); kit[0].padpars->defaults(); for (int nefx=0;nefx<NUM_PART_EFX;nefx++) { partefx[nefx]->defaults(); Pefxroute[nefx]=0;//route to next effect }; }; /* * Cleanup the part */ void Part::cleanup(){ for (int k=0;k<POLIPHONY;k++) KillNotePos(k); memcpy(partoutl, denormalkillbuf, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); memcpy(partoutr, denormalkillbuf, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); memset(tmpoutl, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); memset(tmpoutr, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); ctl.resetall(); for (int nefx=0;nefx<NUM_PART_EFX;nefx++) partefx[nefx]->cleanup(); for (int n=0;n<NUM_PART_EFX+1;n++) { memcpy(partfxinputl[n], denormalkillbuf, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); memcpy(partfxinputr[n], denormalkillbuf, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); }; }; Part::~Part(){ cleanup(); for (int n=0;n<NUM_KIT_ITEMS;n++){ if (kit[n].adpars!=NULL) delete (kit[n].adpars); if (kit[n].subpars!=NULL) delete (kit[n].subpars); if (kit[n].padpars!=NULL) delete (kit[n].padpars); kit[n].adpars=NULL;kit[n].subpars=NULL;kit[n].padpars=NULL; delete(kit[n].Pname); }; delete (Pname); delete (partoutl); delete (partoutr); delete (tmpoutl); delete (tmpoutr); for (int nefx=0;nefx<NUM_PART_EFX;nefx++) delete (partefx[nefx]); for (int n=0;n<NUM_PART_EFX+1;n++) { delete (partfxinputl[n]); delete (partfxinputr[n]); }; }; /* * Note On Messages */ void Part::NoteOn(unsigned char note,unsigned char velocity,int masterkeyshift){ int i,pos; lastnote=note; if ((note<Pminkey)||(note>Pmaxkey)) return; pos=-1; for (i=0;i<POLIPHONY;i++){ if (partnote[i].status==KEY_OFF){ pos=i; break; }; }; if (Ppolymode==0){//if the mode is 'mono' turn off all other notes for (i=0;i<POLIPHONY;i++) if (partnote[i].status==KEY_PLAYING) NoteOff(partnote[i].note); RelaseSustainedKeys(); }; if (pos==-1){ //test fprintf(stderr,"%s","NOTES TOO MANY (> POLIPHONY) - (Part.C::NoteOn(..))\n"); } else { if (Pnoteon!=0){ //start the note partnote[pos].status=KEY_PLAYING; partnote[pos].note=note; //this computes the velocity sensing of the part REALTYPE vel=VelF(velocity/127.0,Pvelsns); //compute the velocity offset vel+=(Pveloffs-64.0)/64.0; if (vel<0.0) vel=0.0; else if (vel>1.0) vel=1.0; //compute the keyshift int partkeyshift=(int)Pkeyshift-64; int keyshift=masterkeyshift+partkeyshift; //initialise note frequency REALTYPE notebasefreq; if (Pdrummode==0){ notebasefreq=microtonal->getnotefreq(note,keyshift); if (notebasefreq<0.0) return;//the key is no mapped } else { notebasefreq=440.0*pow(2.0,(note-69.0)/12.0); }; //Portamento if (oldfreq<1.0) oldfreq=notebasefreq;//this is only the first note is played int portamento=ctl.initportamento(oldfreq,notebasefreq); if (portamento!=0) ctl.portamento.noteusing=pos; oldfreq=notebasefreq; partnote[pos].itemsplaying=0; if (Pkitmode==0){//init the notes for the "normal mode" partnote[pos].kititem[0].sendtoparteffect=0; if (kit[0].Padenabled!=0) partnote[pos].kititem[0].adnote=new ADnote(kit[0].adpars,&ctl,notebasefreq,vel,portamento,note); if (kit[0].Psubenabled!=0) partnote[pos].kititem[0].subnote=new SUBnote(kit[0].subpars,&ctl,notebasefreq,vel,portamento,note); if (kit[0].Ppadenabled!=0) partnote[pos].kititem[0].padnote=new PADnote(kit[0].padpars,&ctl,notebasefreq,vel,portamento,note); if ((kit[0].Padenabled!=0)||(kit[0].Psubenabled!=0)||(kit[0].Ppadenabled!=0)) partnote[pos].itemsplaying++; } else {//init the notes for the "kit mode" for (int item=0;item<NUM_KIT_ITEMS;item++){ if (kit[item].Pmuted!=0) continue; if ((note<kit[item].Pminkey)||(note>kit[item].Pmaxkey)) continue; int ci=partnote[pos].itemsplaying;//ci=current item partnote[pos].kititem[ci].sendtoparteffect=( kit[item].Psendtoparteffect<NUM_PART_EFX ? kit[item].Psendtoparteffect: NUM_PART_EFX);//if this parameter is 127 for "unprocessed" if ((kit[item].adpars!=NULL)&&(kit[item].Padenabled)!=0) partnote[pos].kititem[ci].adnote=new ADnote(kit[item].adpars,&ctl,notebasefreq,vel,portamento,note); if ((kit[item].subpars!=NULL)&&(kit[item].Psubenabled)!=0) partnote[pos].kititem[ci].subnote=new SUBnote(kit[item].subpars,&ctl,notebasefreq,vel,portamento,note); if ((kit[item].padpars!=NULL)&&(kit[item].Ppadenabled)!=0) partnote[pos].kititem[ci].padnote=new PADnote(kit[item].padpars,&ctl,notebasefreq,vel,portamento,note); if ((kit[item].adpars!=NULL)|| (kit[item].subpars!=NULL)) { partnote[pos].itemsplaying++; if ( ((kit[item].Padenabled!=0)||(kit[item].Psubenabled!=0)||(kit[item].Ppadenabled!=0)) && (Pkitmode==2) ) break; }; }; }; }; }; //this only relase the keys if there is maximum number of keys allowed setkeylimit(Pkeylimit); }; /* * Note Off Messages */ void Part::NoteOff(unsigned char note){//relase the key int i; for (i=POLIPHONY-1;i>=0;i--){ //first note in, is first out if there are same note multiple times if ((partnote[i].status==KEY_PLAYING)&&(partnote[i].note==note)) { if (ctl.sustain.sustain==0){ //the sustain pedal is not pushed RelaseNotePos(i); break; } else {//the sustain pedal is pushed partnote[i].status=KEY_RELASED_AND_SUSTAINED; }; }; }; }; /* * Controllers */ void Part::SetController(unsigned int type,int par){ switch (type){ case C_pitchwheel:ctl.setpitchwheel(par); break; case C_expression:ctl.setexpression(par); setPvolume(Pvolume);//update the volume break; case C_portamento:ctl.setportamento(par); break; case C_panning:ctl.setpanning(par); setPpanning(Ppanning);//update the panning break; case C_filtercutoff:ctl.setfiltercutoff(par); break; case C_filterq:ctl.setfilterq(par); break; case C_bandwidth:ctl.setbandwidth(par); break; case C_modwheel:ctl.setmodwheel(par); break; case C_fmamp:ctl.setfmamp(par); break; case C_volume:ctl.setvolume(par); if (ctl.volume.receive!=0) volume=ctl.volume.volume; else setPvolume(Pvolume); break; case C_sustain:ctl.setsustain(par); if (ctl.sustain.sustain==0) RelaseSustainedKeys(); break; case C_allsoundsoff:AllNotesOff();//Panic break; case C_resetallcontrollers: ctl.resetall(); RelaseSustainedKeys(); if (ctl.volume.receive!=0) volume=ctl.volume.volume; else setPvolume(Pvolume); setPvolume(Pvolume);//update the volume setPpanning(Ppanning);//update the panning for (int item=0;item<NUM_KIT_ITEMS;item++){ if (kit[item].adpars==NULL) continue; kit[item].adpars->GlobalPar.Reson-> sendcontroller(C_resonance_center,1.0); kit[item].adpars->GlobalPar.Reson-> sendcontroller(C_resonance_bandwidth,1.0); }; //more update to add here if I add controllers break; case C_allnotesoff:RelaseAllKeys(); break; case C_resonance_center: ctl.setresonancecenter(par); for (int item=0;item<NUM_KIT_ITEMS;item++){ if (kit[item].adpars==NULL) continue; kit[item].adpars->GlobalPar.Reson-> sendcontroller(C_resonance_center,ctl.resonancecenter.relcenter); }; break; case C_resonance_bandwidth: ctl.setresonancebw(par); kit[0].adpars->GlobalPar.Reson-> sendcontroller(C_resonance_bandwidth,ctl.resonancebandwidth.relbw); break; }; }; /* * Relase the sustained keys */ void Part::RelaseSustainedKeys(){ for (int i=0;i<POLIPHONY;i++) if (partnote[i].status==KEY_RELASED_AND_SUSTAINED) RelaseNotePos(i); }; /* * Relase all keys */ void Part::RelaseAllKeys(){ for (int i=0;i<POLIPHONY;i++){ if ((partnote[i].status!=KEY_RELASED)&& (partnote[i].status!=KEY_OFF)) //thanks to Frank Neumann RelaseNotePos(i); }; }; /* * Release note at position */ void Part::RelaseNotePos(int pos){ for (int j=0;j<NUM_KIT_ITEMS;j++){ if (partnote[pos].kititem[j].adnote!=NULL) if (partnote[pos].kititem[j].adnote) partnote[pos].kititem[j].adnote->relasekey(); if (partnote[pos].kititem[j].subnote!=NULL) if (partnote[pos].kititem[j].subnote!=NULL) partnote[pos].kititem[j].subnote->relasekey(); if (partnote[pos].kititem[j].padnote!=NULL) if (partnote[pos].kititem[j].padnote) partnote[pos].kititem[j].padnote->relasekey(); }; partnote[pos].status=KEY_RELASED; }; /* * Kill note at position */ void Part::KillNotePos(int pos){ partnote[pos].status=KEY_OFF; partnote[pos].note=-1; partnote[pos].time=0; partnote[pos].itemsplaying=0; for (int j=0;j<NUM_KIT_ITEMS;j++){ if (partnote[pos].kititem[j].adnote!=NULL) { delete(partnote[pos].kititem[j].adnote); partnote[pos].kititem[j].adnote=NULL; }; if (partnote[pos].kititem[j].subnote!=NULL) { delete(partnote[pos].kititem[j].subnote); partnote[pos].kititem[j].subnote=NULL; }; if (partnote[pos].kititem[j].padnote!=NULL) { delete(partnote[pos].kititem[j].padnote); partnote[pos].kititem[j].padnote=NULL; }; }; if (pos==ctl.portamento.noteusing) { ctl.portamento.noteusing=-1; ctl.portamento.used=0; }; }; /* * Set Part's key limit */ void Part::setkeylimit(unsigned char Pkeylimit){ this->Pkeylimit=Pkeylimit; int keylimit=Pkeylimit; if (keylimit==0) keylimit=POLIPHONY-5; //release old keys if the number of notes>keylimit if (Ppolymode!=0){ int notecount=0; for (int i=0;i<POLIPHONY;i++){ if ((partnote[i].status==KEY_PLAYING)||(partnote[i].status==KEY_RELASED_AND_SUSTAINED)) notecount++; }; int oldestnotepos=-1,maxtime=0; if (notecount>keylimit){//find out the oldest note for (int i=0;i<POLIPHONY;i++){ if ( ((partnote[i].status==KEY_PLAYING)||(partnote[i].status==KEY_RELASED_AND_SUSTAINED)) && (partnote[i].time>maxtime)){ maxtime=partnote[i].time; oldestnotepos=i; }; }; }; if (oldestnotepos!=-1) RelaseNotePos(oldestnotepos); }; }; /* * Prepare all notes to be turned off */ void Part::AllNotesOff(){ killallnotes=1; }; /* * Compute Part samples and store them in the partoutl[] and partoutr[] */ void Part::ComputePartSmps(){ int i, k; int noteplay;//0 if there is nothing activated for (int nefx=0;nefx<NUM_PART_EFX+1;nefx++){ memset(partfxinputl[nefx], 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); memset(partfxinputr[nefx], 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); }; for (k=0;k<POLIPHONY;k++){ if (partnote[k].status==KEY_OFF) continue; noteplay=0; partnote[k].time++; //get the sampledata of the note and kill it if it's finished for (int item=0;item<partnote[k].itemsplaying;item++){ int sendcurrenttofx=partnote[k].kititem[item].sendtoparteffect; ADnote *adnote=partnote[k].kititem[item].adnote; SUBnote *subnote=partnote[k].kititem[item].subnote; PADnote *padnote=partnote[k].kititem[item].padnote; //get from the ADnote if (adnote!=NULL) { noteplay++; if (adnote->ready!=0) adnote->noteout(&tmpoutl[0],&tmpoutr[0]); else { memset(tmpoutl, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); memset(tmpoutr, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); } if (adnote->finished()!=0){ delete (adnote); partnote[k].kititem[item].adnote=NULL; }; for (i=0;i<SOUND_BUFFER_SIZE;i++){//add the ADnote to part(mix) partfxinputl[sendcurrenttofx][i]+=tmpoutl[i]; partfxinputr[sendcurrenttofx][i]+=tmpoutr[i]; }; }; //get from the SUBnote if (subnote!=NULL) { noteplay++; if (subnote->ready!=0) subnote->noteout(&tmpoutl[0],&tmpoutr[0]); else { memset(tmpoutl, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); memset(tmpoutr, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); } for (i=0;i<SOUND_BUFFER_SIZE;i++){//add the SUBnote to part(mix) partfxinputl[sendcurrenttofx][i]+=tmpoutl[i]; partfxinputr[sendcurrenttofx][i]+=tmpoutr[i]; }; if (subnote->finished()!=0){ delete (subnote); partnote[k].kititem[item].subnote=NULL; }; }; //get from the PADnote if (padnote!=NULL) { noteplay++; if (padnote->ready!=0) padnote->noteout(&tmpoutl[0],&tmpoutr[0]); else { memset(tmpoutl, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); memset(tmpoutr, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); } if (padnote->finished()!=0){ delete (padnote); partnote[k].kititem[item].padnote=NULL; }; for (i=0;i<SOUND_BUFFER_SIZE;i++){//add the PADnote to part(mix) partfxinputl[sendcurrenttofx][i]+=tmpoutl[i]; partfxinputr[sendcurrenttofx][i]+=tmpoutr[i]; }; }; }; //Kill note if there is no synth on that note if (noteplay==0) KillNotePos(k); }; //Apply part's effects and mix them for (int nefx=0;nefx<NUM_PART_EFX;nefx++) { if (!Pefxbypass[nefx]) { partefx[nefx]->out(partfxinputl[nefx],partfxinputr[nefx]); if (Pefxroute[nefx]==2){ for (i=0;i<SOUND_BUFFER_SIZE;i++){ partfxinputl[nefx+1][i]+=partefx[nefx]->efxoutl[i]; partfxinputr[nefx+1][i]+=partefx[nefx]->efxoutr[i]; }; }; }; int routeto=((Pefxroute[nefx]==0) ? nefx+1 : NUM_PART_EFX); for (i=0;i<SOUND_BUFFER_SIZE;i++){ partfxinputl[routeto][i]+=partfxinputl[nefx][i]; partfxinputr[routeto][i]+=partfxinputr[nefx][i]; }; }; for (i=0;i<SOUND_BUFFER_SIZE;i++){ partoutl[i]=partfxinputl[NUM_PART_EFX][i]; partoutr[i]=partfxinputr[NUM_PART_EFX][i]; }; //Kill All Notes if killallnotes!=0 if (killallnotes!=0) { for (i=0;i<SOUND_BUFFER_SIZE;i++) { REALTYPE tmp=(SOUND_BUFFER_SIZE-i)/(REALTYPE) SOUND_BUFFER_SIZE; partoutl[i]*=tmp; partoutr[i]*=tmp; tmpoutl[i]=0.0; tmpoutr[i]=0.0; }; for (int k=0;k<POLIPHONY;k++) KillNotePos(k); killallnotes=0; for (int nefx=0;nefx<NUM_PART_EFX;nefx++) { partefx[nefx]->cleanup(); }; }; ctl.updateportamento(); }; /* * Parameter control */ void Part::setPvolume(char Pvolume_){ Pvolume=Pvolume_; volume=dB2rap((Pvolume-96.0)/96.0*40.0)*ctl.expression.relvolume; }; void Part::setPpanning(char Ppanning_){ Ppanning=Ppanning_; panning=Ppanning/127.0+ctl.panning.pan; if (panning<0.0) panning=0.0;else if (panning>1.0) panning=1.0; }; /* * Enable or disable a kit item */ void Part::setkititemstatus(int kititem,int Penabled_){ if ((kititem==0)&&(kititem>=NUM_KIT_ITEMS)) return;//nonexistent kit item and the first kit item is always enabled kit[kititem].Penabled=Penabled_; bool resetallnotes=false; if (Penabled_==0){ if (kit[kititem].adpars!=NULL) delete (kit[kititem].adpars); if (kit[kititem].subpars!=NULL) delete (kit[kititem].subpars); if (kit[kititem].padpars!=NULL) { delete (kit[kititem].padpars); resetallnotes=true; }; kit[kititem].adpars=NULL;kit[kititem].subpars=NULL;kit[kititem].padpars=NULL; kit[kititem].Pname[0]='\0'; } else { if (kit[kititem].adpars==NULL) kit[kititem].adpars=new ADnoteParameters(fft); if (kit[kititem].subpars==NULL) kit[kititem].subpars=new SUBnoteParameters(); if (kit[kititem].padpars==NULL) kit[kititem].padpars=new PADnoteParameters(fft,master); }; if (resetallnotes) for (int k=0;k<POLIPHONY;k++) KillNotePos(k); }; void Part::add2XMLinstrument(XMLwrapper *xml){ xml->beginbranch("INFO"); xml->addparstr("name",(char *)Pname); xml->addparstr("author",(char *)info.Pauthor); xml->addparstr("comments",(char *)info.Pcomments); xml->addpar("type",info.Ptype); xml->endbranch(); xml->beginbranch("INSTRUMENT_KIT"); xml->addpar("kit_mode",Pkitmode); xml->addparbool("drum_mode",Pdrummode); for (int i=0;i<NUM_KIT_ITEMS;i++){ xml->beginbranch("INSTRUMENT_KIT_ITEM",i); xml->addparbool("enabled",kit[i].Penabled); if (kit[i].Penabled!=0) { xml->addparstr("name",(char *)kit[i].Pname); xml->addparbool("muted",kit[i].Pmuted); xml->addpar("min_key",kit[i].Pminkey); xml->addpar("max_key",kit[i].Pmaxkey); xml->addpar("send_to_instrument_effect",kit[i].Psendtoparteffect); xml->addparbool("add_enabled",kit[i].Padenabled); if ((kit[i].Padenabled!=0)&&(kit[i].adpars!=NULL)){ xml->beginbranch("ADD_SYNTH_PARAMETERS"); kit[i].adpars->add2XML(xml); xml->endbranch(); }; xml->addparbool("sub_enabled",kit[i].Psubenabled); if ((kit[i].Psubenabled!=0)&&(kit[i].subpars!=NULL)){ xml->beginbranch("SUB_SYNTH_PARAMETERS"); kit[i].subpars->add2XML(xml); xml->endbranch(); }; xml->addparbool("pad_enabled",kit[i].Ppadenabled); if ((kit[i].Ppadenabled!=0)&&(kit[i].padpars!=NULL)){ xml->beginbranch("PAD_SYNTH_PARAMETERS"); kit[i].padpars->add2XML(xml); xml->endbranch(); }; }; xml->endbranch(); }; xml->endbranch(); xml->beginbranch("INSTRUMENT_EFFECTS"); for (int nefx=0;nefx<NUM_PART_EFX;nefx++){ xml->beginbranch("INSTRUMENT_EFFECT",nefx); xml->beginbranch("EFFECT"); partefx[nefx]->add2XML(xml); xml->endbranch(); xml->addpar("route",Pefxroute[nefx]); partefx[nefx]->setdryonly(Pefxroute[nefx]==2); xml->addparbool("bypass",Pefxbypass[nefx]); xml->endbranch(); }; xml->endbranch(); }; void Part::add2XML(XMLwrapper *xml){ //parameters xml->addparbool("enabled",Penabled); if ((Penabled==0)&&(xml->minimal)) return; xml->addpar("volume",Pvolume); xml->addpar("panning",Ppanning); xml->addpar("min_key",Pminkey); xml->addpar("max_key",Pmaxkey); xml->addpar("key_shift",Pkeyshift); xml->addpar("rcv_chn",Prcvchn); xml->addpar("velocity_sensing",Pvelsns); xml->addpar("velocity_offset",Pveloffs); xml->addparbool("note_on",Pnoteon); xml->addparbool("poly_mode",Ppolymode); xml->addpar("key_limit",Pkeylimit); xml->beginbranch("INSTRUMENT"); add2XMLinstrument(xml); xml->endbranch(); xml->beginbranch("CONTROLLER"); ctl.add2XML(xml); xml->endbranch(); }; int Part::saveXML(char *filename){ XMLwrapper *xml; xml=new XMLwrapper(); xml->beginbranch("INSTRUMENT"); add2XMLinstrument(xml); xml->endbranch(); int result=xml->saveXMLfile(filename); delete (xml); return(result); }; int Part::loadXMLinstrument(const char *filename){ XMLwrapper *xml=new XMLwrapper(); if (xml->loadXMLfile(filename)<0) { delete(xml); return(-1); }; if (xml->enterbranch("INSTRUMENT")==0) return(-10); getfromXMLinstrument(xml); xml->exitbranch(); delete(xml); return(0); }; void Part::applyparameters(){ for (int n=0;n<NUM_KIT_ITEMS;n++){ if ((kit[n].padpars!=NULL)&&(kit[n].Ppadenabled!=0)) kit[n].padpars->applyparameters(true); }; }; void Part::getfromXMLinstrument(XMLwrapper *xml){ if (xml->enterbranch("INFO")){ xml->getparstr("name",(char *)Pname,PART_MAX_NAME_LEN); xml->getparstr("author",(char *)info.Pauthor,MAX_INFO_TEXT_SIZE); xml->getparstr("comments",(char *)info.Pcomments,MAX_INFO_TEXT_SIZE); info.Ptype=xml->getpar("type",info.Ptype,0,16); xml->exitbranch(); }; if (xml->enterbranch("INSTRUMENT_KIT")){ Pkitmode=xml->getpar127("kit_mode",Pkitmode); Pdrummode=xml->getparbool("drum_mode",Pdrummode); setkititemstatus(0,0); for (int i=0;i<NUM_KIT_ITEMS;i++){ if (xml->enterbranch("INSTRUMENT_KIT_ITEM",i)==0) continue; setkititemstatus(i,xml->getparbool("enabled",kit[i].Penabled)); if (kit[i].Penabled==0) { xml->exitbranch(); continue; }; xml->getparstr("name",(char *)kit[i].Pname,PART_MAX_NAME_LEN); kit[i].Pmuted=xml->getparbool("muted",kit[i].Pmuted); kit[i].Pminkey=xml->getpar127("min_key",kit[i].Pminkey); kit[i].Pmaxkey=xml->getpar127("max_key",kit[i].Pmaxkey); kit[i].Psendtoparteffect=xml->getpar127("send_to_instrument_effect",kit[i].Psendtoparteffect); kit[i].Padenabled=xml->getparbool("add_enabled",kit[i].Padenabled); if (xml->enterbranch("ADD_SYNTH_PARAMETERS")){ kit[i].adpars->getfromXML(xml); xml->exitbranch(); }; kit[i].Psubenabled=xml->getparbool("sub_enabled",kit[i].Psubenabled); if (xml->enterbranch("SUB_SYNTH_PARAMETERS")){ kit[i].subpars->getfromXML(xml); xml->exitbranch(); }; kit[i].Ppadenabled=xml->getparbool("pad_enabled",kit[i].Ppadenabled); if (xml->enterbranch("PAD_SYNTH_PARAMETERS")){ kit[i].padpars->getfromXML(xml); xml->exitbranch(); }; xml->exitbranch(); }; xml->exitbranch(); }; if (xml->enterbranch("INSTRUMENT_EFFECTS")){ for (int nefx=0;nefx<NUM_PART_EFX;nefx++){ if (xml->enterbranch("INSTRUMENT_EFFECT",nefx)==0) continue; if (xml->enterbranch("EFFECT")){ partefx[nefx]->getfromXML(xml); xml->exitbranch(); }; Pefxroute[nefx]=xml->getpar("route",Pefxroute[nefx],0,NUM_PART_EFX); partefx[nefx]->setdryonly(Pefxroute[nefx]==2); Pefxbypass[nefx]=xml->getparbool("bypass",Pefxbypass[nefx]); xml->exitbranch(); }; xml->exitbranch(); }; }; void Part::getfromXML(XMLwrapper *xml){ Penabled=xml->getparbool("enabled",Penabled); setPvolume(xml->getpar127("volume",Pvolume)); setPpanning(xml->getpar127("panning",Ppanning)); Pminkey=xml->getpar127("min_key",Pminkey); Pmaxkey=xml->getpar127("max_key",Pmaxkey); Pkeyshift=xml->getpar127("key_shift",Pkeyshift); Prcvchn=xml->getpar127("rcv_chn",Prcvchn); Pvelsns=xml->getpar127("velocity_sensing",Pvelsns); Pveloffs=xml->getpar127("velocity_offset",Pveloffs); Pnoteon=xml->getparbool("note_on",Pnoteon); Ppolymode=xml->getparbool("poly_mode",Ppolymode); Pkeylimit=xml->getpar127("key_limit",Pkeylimit); if (xml->enterbranch("INSTRUMENT")){ getfromXMLinstrument(xml); xml->exitbranch(); }; if (xml->enterbranch("CONTROLLER")){ ctl.getfromXML(xml); xml->exitbranch(); }; };