diff options
author | Robert Jonsson <spamatica@gmail.com> | 2009-12-27 11:30:35 +0000 |
---|---|---|
committer | Robert Jonsson <spamatica@gmail.com> | 2009-12-27 11:30:35 +0000 |
commit | b703eab295330e6f81564fbb39a10a1a2fdd2f54 (patch) | |
tree | e46b5c9a6bc22fd661c15d1d2123f5bf631cef80 /muse_qt4_evolution/synti/zynaddsubfx/Misc/Master.C | |
parent | 5d5fa0fdf913907edbc3d2d29a7548f0cb658c94 (diff) |
moved old qt4 branch
Diffstat (limited to 'muse_qt4_evolution/synti/zynaddsubfx/Misc/Master.C')
-rw-r--r-- | muse_qt4_evolution/synti/zynaddsubfx/Misc/Master.C | 680 |
1 files changed, 680 insertions, 0 deletions
diff --git a/muse_qt4_evolution/synti/zynaddsubfx/Misc/Master.C b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Master.C new file mode 100644 index 00000000..99a1ac28 --- /dev/null +++ b/muse_qt4_evolution/synti/zynaddsubfx/Misc/Master.C @@ -0,0 +1,680 @@ +/* + ZynAddSubFX - a software synthesizer + + Master.C - It sends Midi Messages to Parts, receives samples from parts, + process them with system/insertion effects and mix them + 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 <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <unistd.h> + +Master::Master(){ + swaplr=0; + + busy = false; + fft=new FFTwrapper(OSCIL_SIZE); + + tmpmixl=new REALTYPE[SOUND_BUFFER_SIZE]; + tmpmixr=new REALTYPE[SOUND_BUFFER_SIZE]; + audiooutl=new REALTYPE[SOUND_BUFFER_SIZE]; + audiooutr=new REALTYPE[SOUND_BUFFER_SIZE]; + + ksoundbuffersamples=0; + ksoundbuffersamplelow=0.0; + oldsamplel=0.0;oldsampler=0.0; + shutup=0; + for (int npart=0;npart<NUM_MIDI_PARTS;npart++) { + vuoutpeakpart[npart]=1e-9; + fakepeakpart[npart]=0; + }; + + memset(audiooutl, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + memset(audiooutr, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + + for (int npart=0;npart<NUM_MIDI_PARTS;npart++) + part[npart]=new Part(µtonal,fft,this); + + + //Insertion Effects init + for (int nefx=0;nefx<NUM_INS_EFX;nefx++) + insefx[nefx]=new EffectMgr(1,this); + + //System Effects init + for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) { + sysefx[nefx]=new EffectMgr(0,this); + }; + + + defaults(); +}; + +void Master::defaults(){ + volume=1.0; + setPvolume(80); + setPkeyshift(64); + + for (int npart=0;npart<NUM_MIDI_PARTS;npart++){ + part[npart]->defaults(); + part[npart]->Prcvchn=npart%NUM_MIDI_CHANNELS; + }; + + partonoff(0,1);//enable the first part + + for (int nefx=0;nefx<NUM_INS_EFX;nefx++) { + insefx[nefx]->defaults(); + Pinsparts[nefx]=-1; + }; + + //System Effects init + for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) { + sysefx[nefx]->defaults(); + for (int npart=0;npart<NUM_MIDI_PARTS;npart++){ + if (nefx==0) setPsysefxvol(npart,nefx,64); + else setPsysefxvol(npart,nefx,0); + }; + for (int nefxto=0;nefxto<NUM_SYS_EFX;nefxto++) + setPsysefxsend(nefx,nefxto,0); + }; + + sysefx[0]->changeeffect(1); + microtonal.defaults(); + ShutUp(); +}; + +/* + * Note On Messages (velocity=0 for NoteOff) + */ +void Master::NoteOn(unsigned char chan,unsigned char note,unsigned char velocity){ + dump.dumpnote(chan,note,velocity); + + noteon(chan,note,velocity); +}; + +/* + * Internal Note On (velocity=0 for NoteOff) + */ +void Master::noteon(unsigned char chan,unsigned char note,unsigned char velocity){ + int npart; + if (velocity!=0){ + for (npart=0;npart<NUM_MIDI_PARTS;npart++){ + if (chan==part[npart]->Prcvchn){ + fakepeakpart[npart]=velocity*2; + if (part[npart]->Penabled!=0) part[npart]->NoteOn(note,velocity,keyshift); + }; + }; + }else{ + this->NoteOff(chan,note); + }; + HDDRecorder.triggernow(); +}; + +/* + * Note Off Messages + */ +void Master::NoteOff(unsigned char chan,unsigned char note){ + dump.dumpnote(chan,note,0); + + noteoff(chan,note); +}; + +/* + * Internal Note Off + */ +void Master::noteoff(unsigned char chan,unsigned char note){ + int npart; + for (npart=0;npart<NUM_MIDI_PARTS;npart++){ + if ((chan==part[npart]->Prcvchn) && (part[npart]->Penabled!=0)) + part[npart]->NoteOff(note); + }; +}; + +/* + * Controllers + */ +void Master::SetController(unsigned char chan,unsigned int type,int par){ + dump.dumpcontroller(chan,type,par); + + setcontroller(chan,type,par); +}; + +/* + * Internal Controllers + */ +void Master::setcontroller(unsigned char chan,unsigned int type,int par){ + if ((type==C_dataentryhi)||(type==C_dataentrylo)|| + (type==C_nrpnhi)||(type==C_nrpnlo)){//Process RPN and NRPN by the Master (ignore the chan) + ctl.setparameternumber(type,par); + + int parhi=-1,parlo=-1,valhi=-1,vallo=-1; + if (ctl.getnrpn(&parhi,&parlo,&valhi,&vallo)==0){//this is NRPN + //fprintf(stderr,"rcv. NRPN: %d %d %d %d\n",parhi,parlo,valhi,vallo); + switch (parhi){ + case 0x04://System Effects + if (parlo<NUM_SYS_EFX) { + sysefx[parlo]->seteffectpar_nolock(valhi,vallo); + }; + break; + case 0x08://Insertion Effects + if (parlo<NUM_INS_EFX) { + insefx[parlo]->seteffectpar_nolock(valhi,vallo); + }; + break; + + }; + }; + } else {//other controllers + for (int npart=0;npart<NUM_MIDI_PARTS;npart++){//Send the controller to all part assigned to the channel + if ((chan==part[npart]->Prcvchn) && (part[npart]->Penabled!=0)) + part[npart]->SetController(type,par); + }; + }; +}; + + +/* + * Enable/Disable a part + */ +void Master::partonoff(int npart,int what){ + if (npart>=NUM_MIDI_PARTS) return; + if (what==0){//disable part + fakepeakpart[npart]=0; + part[npart]->Penabled=0; + part[npart]->cleanup(); + for (int nefx=0;nefx<NUM_INS_EFX;nefx++){ + if (Pinsparts[nefx]==npart) { + insefx[nefx]->cleanup(); + }; + }; + } else {//enabled + part[npart]->Penabled=1; + fakepeakpart[npart]=0; + }; +}; + +/* + * Master audio out (the final sound) + */ + +void Master::AudioOut(REALTYPE* outl, REALTYPE* outr) + { + int i,npart,nefx; + + //Swaps the Left channel with Right Channel (if it is asked for) + if (swaplr != 0) { + REALTYPE *tmp=outl; + outl = outr; + outr = tmp; + } + + //clean up the output samples + memset(outl, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + memset(outr, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + + //Compute part samples and store them part[npart]->partoutl,partoutr + for (npart=0; npart<NUM_MIDI_PARTS; npart++) + if (part[npart]->Penabled != 0) + part[npart]->ComputePartSmps(); + + //Insertion effects + for (nefx=0;nefx<NUM_INS_EFX;nefx++){ + if (Pinsparts[nefx]>=0) { + int efxpart=Pinsparts[nefx]; + if (part[efxpart]->Penabled!=0) + insefx[nefx]->out(part[efxpart]->partoutl,part[efxpart]->partoutr); + } + } + + + //Apply the part volumes and pannings (after insertion effects) + for (npart = 0; npart < NUM_MIDI_PARTS; npart++) { + if (part[npart]->Penabled==0) + continue; + + REALTYPE newvol_l=part[npart]->volume; + REALTYPE newvol_r=part[npart]->volume; + REALTYPE oldvol_l=part[npart]->oldvolumel; + REALTYPE oldvol_r=part[npart]->oldvolumer; + REALTYPE pan=part[npart]->panning; + if (pan < 0.5) + newvol_l *= pan*2.0; + else + newvol_r *= (1.0-pan)*2.0; + + if (ABOVE_AMPLITUDE_THRESHOLD(oldvol_l,newvol_l)|| + ABOVE_AMPLITUDE_THRESHOLD(oldvol_r,newvol_r)){//the volume or the panning has changed and needs interpolation + + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + REALTYPE vol_l = INTERPOLATE_AMPLITUDE(oldvol_l,newvol_l,i,SOUND_BUFFER_SIZE); + REALTYPE vol_r = INTERPOLATE_AMPLITUDE(oldvol_r,newvol_r,i,SOUND_BUFFER_SIZE); + part[npart]->partoutl[i]*=vol_l; + part[npart]->partoutr[i]*=vol_r; + } + part[npart]->oldvolumel=newvol_l; + part[npart]->oldvolumer=newvol_r; + + } + else { + for (i=0;i<SOUND_BUFFER_SIZE;i++) {//the volume did not changed + part[npart]->partoutl[i] *= newvol_l; + part[npart]->partoutr[i] *= newvol_r; + } + } + } + + + //System effects + for (nefx=0;nefx<NUM_SYS_EFX;nefx++){ + if (sysefx[nefx]->geteffect()==0) continue;//the effect is disabled + + //Clean up the samples used by the system effects + memset(tmpmixl, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + memset(tmpmixr, 0, sizeof(REALTYPE) * SOUND_BUFFER_SIZE); + + //Mix the channels according to the part settings about System Effect + for (npart=0;npart<NUM_MIDI_PARTS;npart++){ + //skip if the part has no output to effect + if (Psysefxvol[nefx][npart]==0) continue; + + //skip if the part is disabled + if (part[npart]->Penabled==0) continue; + + //the output volume of each part to system effect + REALTYPE vol=sysefxvol[nefx][npart]; + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + tmpmixl[i]+=part[npart]->partoutl[i]*vol; + tmpmixr[i]+=part[npart]->partoutr[i]*vol; + }; + }; + + // system effect send to next ones + for (int nefxfrom=0;nefxfrom<nefx;nefxfrom++){ + if (Psysefxsend[nefxfrom][nefx]!=0){ + REALTYPE v=sysefxsend[nefxfrom][nefx]; + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + tmpmixl[i]+=sysefx[nefxfrom]->efxoutl[i]*v; + tmpmixr[i]+=sysefx[nefxfrom]->efxoutr[i]*v; + }; + }; + }; + + sysefx[nefx]->out(tmpmixl,tmpmixr); + + //Add the System Effect to sound output + REALTYPE outvol=sysefx[nefx]->sysefxgetvolume(); + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + outl[i]+=tmpmixl[i]*outvol; + outr[i]+=tmpmixr[i]*outvol; + }; + + }; + + //Mix all parts + for (npart=0;npart<NUM_MIDI_PARTS;npart++){ + for (i=0;i<SOUND_BUFFER_SIZE;i++) { //the volume did not changed + outl[i] += part[npart]->partoutl[i]; + outr[i] += part[npart]->partoutr[i]; + } + } + + //Insertion effects for Master Out + for (nefx=0;nefx<NUM_INS_EFX;nefx++) { + if (Pinsparts[nefx] == -2) + insefx[nefx]->out(outl, outr); + } + + //Master Volume + for (i = 0; i < SOUND_BUFFER_SIZE; i++) { + outl[i] *= volume; + outr[i] *= volume; + } + + //Peak computation (for vumeters) + vuoutpeakl=1e-12;vuoutpeakr=1e-12; + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + if (fabs(outl[i])>vuoutpeakl) vuoutpeakl=fabs(outl[i]); + if (fabs(outr[i])>vuoutpeakr) vuoutpeakr=fabs(outr[i]); + }; + if ((vuoutpeakl>1.0)||(vuoutpeakr>1.0)) vuclipped=1; + if (vumaxoutpeakl<vuoutpeakl) vumaxoutpeakl=vuoutpeakl; + if (vumaxoutpeakr<vuoutpeakr) vumaxoutpeakr=vuoutpeakr; + + //RMS Peak computation (for vumeters) + vurmspeakl=1e-12;vurmspeakr=1e-12; + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + vurmspeakl+=outl[i]*outl[i]; + vurmspeakr+=outr[i]*outr[i]; + }; + vurmspeakl=sqrt(vurmspeakl/SOUND_BUFFER_SIZE); + vurmspeakr=sqrt(vurmspeakr/SOUND_BUFFER_SIZE); + + //Part Peak computation (for Part vumeters or fake part vumeters) + for (npart=0;npart<NUM_MIDI_PARTS;npart++){ + vuoutpeakpart[npart]=1.0e-12; + if (part[npart]->Penabled!=0) { + REALTYPE *outl=part[npart]->partoutl, + *outr=part[npart]->partoutr; + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + REALTYPE tmp=fabs(outl[i]+outr[i]); + if (tmp>vuoutpeakpart[npart]) vuoutpeakpart[npart]=tmp; + }; + vuoutpeakpart[npart]*=volume; + } else { + if (fakepeakpart[npart]>1) fakepeakpart[npart]--; + }; + }; + + + //Shutup if it is asked (with fade-out) + if (shutup != 0) { + for (i = 0; i < SOUND_BUFFER_SIZE; i++) { + REALTYPE tmp=(SOUND_BUFFER_SIZE-i)/(REALTYPE) SOUND_BUFFER_SIZE; + outl[i] *= tmp; + outr[i] *= tmp; + } + ShutUp(); + } + + //update the LFO's time + LFOParams::time++; + + if (HDDRecorder.recording()) + HDDRecorder.recordbuffer(outl,outr); + dump.inctick(); + }; + +//--------------------------------------------------------- +// GetAudioOutSamples +//--------------------------------------------------------- + +void Master::GetAudioOutSamples(int nsamples, REALTYPE* outl, REALTYPE* outr) + { + int dstOffset = 0; + while (nsamples) { + if (ksoundbuffersamples <= 0) { + AudioOut(audiooutl, audiooutr); + ksoundbuffersamples = SOUND_BUFFER_SIZE; + } + int n = nsamples > ksoundbuffersamples ? ksoundbuffersamples : nsamples; + int srcOffset = SOUND_BUFFER_SIZE - ksoundbuffersamples; + memcpy(outl + dstOffset, audiooutl + srcOffset, n * sizeof(REALTYPE)); + memcpy(outr + dstOffset, audiooutr + srcOffset, n * sizeof(REALTYPE)); + nsamples -= n; + dstOffset += n; + ksoundbuffersamples -= n; + } + } + +Master::~Master(){ + for (int npart=0;npart<NUM_MIDI_PARTS;npart++) delete (part[npart]); + for (int nefx=0;nefx<NUM_INS_EFX;nefx++) delete (insefx[nefx]); + for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) delete (sysefx[nefx]); + + delete [] audiooutl; + delete [] audiooutr; + delete [] tmpmixl; + delete [] tmpmixr; + delete (fft); + +}; + + +/* + * Parameter control + */ +void Master::setPvolume(char Pvolume_){ + Pvolume=Pvolume_; + volume=dB2rap((Pvolume-96.0)/96.0*40.0); +}; + +void Master::setPkeyshift(char Pkeyshift_){ + Pkeyshift=Pkeyshift_; + keyshift=(int)Pkeyshift-64; +}; + + +void Master::setPsysefxvol(int Ppart,int Pefx,char Pvol){ + Psysefxvol[Pefx][Ppart]=Pvol; + sysefxvol[Pefx][Ppart]=pow(0.1,(1.0-Pvol/96.0)*2.0); +}; + +void Master::setPsysefxsend(int Pefxfrom,int Pefxto,char Pvol){ + Psysefxsend[Pefxfrom][Pefxto]=Pvol; + sysefxsend[Pefxfrom][Pefxto]=pow(0.1,(1.0-Pvol/96.0)*2.0); +}; + + +/* + * Panic! (Clean up all parts and effects) + */ +void Master::ShutUp(){ + for (int npart=0;npart<NUM_MIDI_PARTS;npart++) { + part[npart]->cleanup(); + fakepeakpart[npart]=0; + }; + for (int nefx=0;nefx<NUM_INS_EFX;nefx++) insefx[nefx]->cleanup(); + for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) sysefx[nefx]->cleanup(); + vuresetpeaks(); + shutup=0; +}; + + +/* + * Reset peaks and clear the "cliped" flag (for VU-meter) + */ +void Master::vuresetpeaks(){ + vuoutpeakl=1e-9;vuoutpeakr=1e-9;vumaxoutpeakl=1e-9;vumaxoutpeakr=1e-9; + vuclipped=0; +}; + + + +void Master::applyparameters(){ + for (int npart=0;npart<NUM_MIDI_PARTS;npart++){ + part[npart]->applyparameters(); + }; +}; + +void Master::add2XML(XMLwrapper *xml){ + xml->addpar("volume",Pvolume); + xml->addpar("key_shift",Pkeyshift); + xml->addparbool("nrpn_receive",ctl.NRPN.receive); + + xml->beginbranch("MICROTONAL"); + microtonal.add2XML(xml); + xml->endbranch(); + + for (int npart=0;npart<NUM_MIDI_PARTS;npart++){ + xml->beginbranch("PART",npart); + part[npart]->add2XML(xml); + xml->endbranch(); + }; + + xml->beginbranch("SYSTEM_EFFECTS"); + for (int nefx=0;nefx<NUM_SYS_EFX;nefx++){ + xml->beginbranch("SYSTEM_EFFECT",nefx); + xml->beginbranch("EFFECT"); + sysefx[nefx]->add2XML(xml); + xml->endbranch(); + + for (int pefx=0;pefx<NUM_MIDI_PARTS;pefx++){ + xml->beginbranch("VOLUME",pefx); + xml->addpar("vol",Psysefxvol[nefx][pefx]); + xml->endbranch(); + }; + + for (int tonefx=nefx+1;tonefx<NUM_SYS_EFX;tonefx++){ + xml->beginbranch("SENDTO",tonefx); + xml->addpar("send_vol",Psysefxsend[nefx][tonefx]); + xml->endbranch(); + }; + + + xml->endbranch(); + }; + xml->endbranch(); + + xml->beginbranch("INSERTION_EFFECTS"); + for (int nefx=0;nefx<NUM_INS_EFX;nefx++){ + xml->beginbranch("INSERTION_EFFECT",nefx); + xml->addpar("part",Pinsparts[nefx]); + + xml->beginbranch("EFFECT"); + insefx[nefx]->add2XML(xml); + xml->endbranch(); + xml->endbranch(); + }; + + xml->endbranch(); + +}; + + +int Master::getalldata(char **data){ + XMLwrapper *xml=new XMLwrapper(); + + xml->beginbranch("MASTER"); + + busy = true; + add2XML(xml); + busy = false; + + xml->endbranch(); + + *data=xml->getXMLdata(); + delete (xml); + return(strlen(*data)+1); +}; + +void Master::putalldata(char *data,int size){ + XMLwrapper *xml=new XMLwrapper(); + if (!xml->putXMLdata(data)) { + delete(xml); + return; + }; + + if (xml->enterbranch("MASTER")==0) return; + + busy = true; + getfromXML(xml); + busy = false; + + xml->exitbranch(); + + delete(xml); +}; + +int Master::saveXML(char *filename){ + XMLwrapper *xml=new XMLwrapper(); + + xml->beginbranch("MASTER"); + add2XML(xml); + xml->endbranch(); + + int result=xml->saveXMLfile(filename); + delete (xml); + return(result); +}; + + + +int Master::loadXML(char *filename){ + XMLwrapper *xml=new XMLwrapper(); + if (xml->loadXMLfile(filename)<0) { + delete(xml); + return(-1); + }; + + if (xml->enterbranch("MASTER")==0) return(-10); + getfromXML(xml); + xml->exitbranch(); + + delete(xml); + return(0); +}; + +void Master::getfromXML(XMLwrapper *xml){ + setPvolume(xml->getpar127("volume",Pvolume)); + setPkeyshift(xml->getpar127("key_shift",Pkeyshift)); + ctl.NRPN.receive=xml->getparbool("nrpn_receive",ctl.NRPN.receive); + + + part[0]->Penabled=0; + for (int npart=0;npart<NUM_MIDI_PARTS;npart++){ + if (xml->enterbranch("PART",npart)==0) continue; + part[npart]->getfromXML(xml); + xml->exitbranch(); + }; + + if (xml->enterbranch("MICROTONAL")){ + microtonal.getfromXML(xml); + xml->exitbranch(); + }; + + sysefx[0]->changeeffect(0); + if (xml->enterbranch("SYSTEM_EFFECTS")){ + for (int nefx=0;nefx<NUM_SYS_EFX;nefx++){ + if (xml->enterbranch("SYSTEM_EFFECT",nefx)==0) continue; + if (xml->enterbranch("EFFECT")){ + sysefx[nefx]->getfromXML(xml); + xml->exitbranch(); + }; + + for (int partefx=0;partefx<NUM_MIDI_PARTS;partefx++){ + if (xml->enterbranch("VOLUME",partefx)==0) continue; + setPsysefxvol(partefx,nefx,xml->getpar127("vol",Psysefxvol[partefx][nefx])); + xml->exitbranch(); + }; + + for (int tonefx=nefx+1;tonefx<NUM_SYS_EFX;tonefx++){ + if (xml->enterbranch("SENDTO",tonefx)==0) continue; + setPsysefxsend(nefx,tonefx,xml->getpar127("send_vol",Psysefxsend[nefx][tonefx])); + xml->exitbranch(); + }; + xml->exitbranch(); + }; + xml->exitbranch(); + }; + + + if (xml->enterbranch("INSERTION_EFFECTS")){ + for (int nefx=0;nefx<NUM_INS_EFX;nefx++){ + + if (xml->enterbranch("INSERTION_EFFECT",nefx)==0) continue; + Pinsparts[nefx]=xml->getpar("part",Pinsparts[nefx],-2,NUM_MIDI_PARTS); + if (xml->enterbranch("EFFECT")){ + insefx[nefx]->getfromXML(xml); + xml->exitbranch(); + }; + xml->exitbranch(); + + }; + + xml->exitbranch(); + }; + +}; + + + + |