From 2cd11ebb24f2b33d117dc3148f38a4edc0cad5d6 Mon Sep 17 00:00:00 2001 From: Nil Geisweiller Date: Tue, 26 Sep 2006 15:46:30 +0000 Subject: DeicsOnze 0.4.5 : 4 levels of quailty --- muse/ChangeLog | 8 +- muse/synti/deicsonze/TODO | 3 +- muse/synti/deicsonze/deicsonze.cpp | 620 +++++++++++++++++-------------- muse/synti/deicsonze/deicsonze.h | 19 +- muse/synti/deicsonze/deicsonzegui.cpp | 6 +- muse/synti/deicsonze/deicsonzegui.h | 2 +- muse/synti/deicsonze/deicsonzegui.ui | 9 +- muse/synti/deicsonze/deicsonzepreset.cpp | 2 +- muse/synti/deicsonze/deicsonzepreset.h | 2 +- 9 files changed, 380 insertions(+), 291 deletions(-) diff --git a/muse/ChangeLog b/muse/ChangeLog index 2ffa972e..3d928e0a 100644 --- a/muse/ChangeLog +++ b/muse/ChangeLog @@ -1,10 +1,12 @@ -24.9 (ng) DeicsOnze 4.0.3 +26.9 (ng) DeicsOnze 0.4.5 + - add four level of quality +24.9 (ng) DeicsOnze 0.4.3 - add monophony - finish to clean SutulaBank.dei -23.9 (ng) DeicsOnze 4.0.2 +23.9 (ng) DeicsOnze 0.4.2 - add pitch envelope (but does not sound yet like DeicsOnze's) - keep cleaning SutulaBank.dei -17.9 (ng) DeicsOnze 4.0.1 +17.9 (ng) DeicsOnze 0.4.1 - add optimization -O3, execution twice faster, but compilation longer - add portamento - started to clean SutulaBank.dei diff --git a/muse/synti/deicsonze/TODO b/muse/synti/deicsonze/TODO index d9f0dea4..657af78c 100644 --- a/muse/synti/deicsonze/TODO +++ b/muse/synti/deicsonze/TODO @@ -7,9 +7,8 @@ - Change presetName subcategoryName category with SysEx - Internal restructure, private vs public, add comment, etc - getPatchInfo... -- Optimize the code, make 3 level of quality sound +- Optimize the code - Remember the last directory - Pan per voices - Load BUMP preset -- Correct portamento for different samplerates - calibrate portamento and pitch envelope to fit real DX11 diff --git a/muse/synti/deicsonze/deicsonze.cpp b/muse/synti/deicsonze/deicsonze.cpp index 09f1ab11..9592e120 100644 --- a/muse/synti/deicsonze/deicsonze.cpp +++ b/muse/synti/deicsonze/deicsonze.cpp @@ -2,7 +2,7 @@ // // DeicsOnze an emulator of the YAMAHA DX11 synthesizer // -// Version 0.4.3 +// Version 0.4.5 // // // @@ -177,6 +177,11 @@ void DeicsOnze::getGeometry(int* x, int* y, int* w, int* h) const { *h = size.height(); } +void DeicsOnze::setSampleRate(int sr) { + Mess::setSampleRate(sr); + setQuality(_global.quality); +} + //--------------------------------------------------------- // setGeometry //--------------------------------------------------------- @@ -516,6 +521,8 @@ inline bool isPitchEnv(PitchEg* pe) { //--------------------------------------------------------- inline double getPitchEnvCoefInct(int pl) { /* + pl = 0 <--> -4oct, pl = 50 <--> 0oct, pl = 100 <--> 4oct + y = a * exp((pl - 50)/b) 1.0 = a*exp(0) ==> a = 1.0 8.0 = exp(50/b) ==> log 8.0 = 50/b ==> b = 50/log(8.0) @@ -527,13 +534,14 @@ inline double getPitchEnvCoefInct(int pl) { //--------------------------------------------------------- // getPitchEnvCoefInctInct //--------------------------------------------------------- -inline double getPitchEnvCoefInctInct(int pl1, int pl2, int pr) { +inline double getPitchEnvCoefInctInct(int pl1, int pl2, int pr, double sr) { //TODO : depending on the sampleRate int a = pr; - double coef = 0.00000025/*COEFPITCHENV*/; - if(pl1pl2) - return 1.0/(1.0+coef*((double)(a*a)+1.0)); + return(1.0/inctInct); else return 1.0; } @@ -725,7 +733,7 @@ void DeicsOnze::setLfo(int c/*channel*/) //Pitch LFO _global.channel[c].lfoMaxIndex = (_global.channel[c].lfoFreq==0?0:(int)((1.0/_global.channel[c].lfoFreq) - *(double)sampleRate())); + *(double)_global.deiSampleRate)); _global.channel[c].lfoPitch = (((double)_preset[c]->lfo.pModDepth/(double)MAXPMODDEPTH) *(COEFPLFO(_preset[c]->sensitivity.pitch))); @@ -766,7 +774,7 @@ void DeicsOnze::setEnvAttack(int c, int v, int k) { _global.channel[c].voices[v].op[k].envInct= (_preset[c]->eg[k].ar==0?0: (double)(RESOLUTION/4)/(envAR2s(_preset[c]->eg[k].ar) - *(double)sampleRate())) + *_global.deiSampleRate)) *coefAttack(_global.channel[c].attack); } void DeicsOnze::setEnvAttack(int c, int k) { @@ -781,7 +789,7 @@ void DeicsOnze::setEnvAttack(int c) { void DeicsOnze::setEnvRelease(int c, int v, int k) { if(_global.channel[c].voices[v].op[k].envState==RELEASE) _global.channel[c].voices[v].op[k].coefVLevel = - envRR2coef(_preset[c]->eg[k].rr, sampleRate(), + envRR2coef(_preset[c]->eg[k].rr, _global.deiSampleRate, _global.channel[c].release); } void DeicsOnze::setEnvRelease(int c, int k) { @@ -798,13 +806,15 @@ void DeicsOnze::setPitchEnvRelease(int c, int v) { if(_global.channel[c].voices[v].pitchEnvCoefInct > _global.channel[c].voices[v].pitchEnvCoefInctPhase1) { _global.channel[c].voices[v].pitchEnvCoefInctInct = - getPitchEnvCoefInctInct(1, 0, _preset[c]->pitchEg.pr3); + getPitchEnvCoefInctInct(1, 0, _preset[c]->pitchEg.pr3, + _global.deiSampleRate); _global.channel[c].voices[v].pitchEnvState = RELEASE_PE; } else if(_global.channel[c].voices[v].pitchEnvCoefInct < _global.channel[c].voices[v].pitchEnvCoefInctPhase1) { _global.channel[c].voices[v].pitchEnvCoefInctInct = - getPitchEnvCoefInctInct(0, 1, _preset[c]->pitchEg.pr3); + getPitchEnvCoefInctInct(0, 1, _preset[c]->pitchEg.pr3, + _global.deiSampleRate); _global.channel[c].voices[v].pitchEnvState = RELEASE_PE; } else { @@ -813,6 +823,33 @@ void DeicsOnze::setPitchEnvRelease(int c, int v) { } } } + +//----------------------------------------------------------------- +// setQuality +//----------------------------------------------------------------- +void DeicsOnze::setQuality(Quality q) { + _global.quality = q; + switch(q) { + case high : + _global.qualityCounterTop = 1; + break; + case middle : + _global.qualityCounterTop = 2; + break; + case low : + _global.qualityCounterTop = 4; + break; + case ultralow : + _global.qualityCounterTop = 6; + break; + default : printf("Error switch setQuality : out of value\n"); + break; + } + _global.deiSampleRate = (double)sampleRate() + / (double)_global.qualityCounterTop; + _global.qualityCounter = 0; +} + //----------------------------------------------------------------- // brightness2Amp //----------------------------------------------------------------- @@ -1250,8 +1287,30 @@ int DeicsOnze::pitchOn2Voice(int c, int pitch) { //--------------------------------------------------------- // getAttractor //--------------------------------------------------------- -inline double getAttractor(int portamentoTime) { - return(1.0 + COEFPORTA/(double)(portamentoTime*portamentoTime)); +inline double getAttractor(int portamentoTime, double sr) { + /* some explanations + + c(48000) = c > 1 + + f_sr(0) = 1000, f_sr(t) = 2000 + + f_sr*2(0) = 1000, f_sr*2(t*2) = 2000 + + f_sr(t) = exp(t*ln(c(sr))) * 1000 + + 2000 = exp(t*ln(c(48000))) * 1000 + + 2000 = exp(t*2*ln(c(48000*2))) * 1000 + + t*ln(c(48000)) = t*2*ln(c(48000*2)) + + c(48000*m) = exp(ln(c)/m) + + sr = 48000*m + */ + double c; + c = 1.0 + COEFPORTA/(double)(portamentoTime*portamentoTime); + return(exp(log(c)*48000.0/sr)); } //--------------------------------------------------------- @@ -1395,7 +1454,7 @@ inline void portamentoUpdate(Channel* p_c, Voice* p_v) { //--------------------------------------------------------- // pitchEnvelopeUpdate //--------------------------------------------------------- -inline void pitchEnvelopeUpdate(Voice* v, PitchEg* pe) { +inline void pitchEnvelopeUpdate(Voice* v, PitchEg* pe, double sr) { if(v->pitchEnvState != OFF_PE) { switch(v->pitchEnvState) { case PHASE1 : @@ -1410,7 +1469,7 @@ inline void pitchEnvelopeUpdate(Voice* v, PitchEg* pe) { v->pitchEnvState = PHASE2; v->pitchEnvCoefInct = getPitchEnvCoefInct(pe->pl2); v->pitchEnvCoefInctInct = - getPitchEnvCoefInctInct(pe->pl2, pe->pl3, pe->pr2); + getPitchEnvCoefInctInct(pe->pl2, pe->pl3, pe->pr2, sr); } else v->pitchEnvCoefInct *= v->pitchEnvCoefInctInct; break; @@ -1489,7 +1548,7 @@ inline double envAR2s(int ar) { // return the coefficient for the exponential decrease // with respect to d1r and sampleRate, sr //--------------------------------------------------------- -inline double envD1R2coef(int d1r, int sr) { +inline double envD1R2coef(int d1r, double sr) { double dt;//such that amp(t+dt)=amp(t)/2 double alpha;//such that amp(t)=exp(alpha*t) @@ -1505,7 +1564,7 @@ inline double envD1R2coef(int d1r, int sr) { //amp(t+mt) //following the above equational system we found : alpha=-log(2)/dt; - return exp(alpha/(double)sr); + return exp(alpha/sr); } } @@ -1524,7 +1583,7 @@ inline double coefRelease(unsigned char release) { // return the coefficient for the exponential decrease // with respect to rr and sampleRate, sr //--------------------------------------------------------- -inline double envRR2coef(int rr, int sr, unsigned char release) { +inline double envRR2coef(int rr, double sr, unsigned char release) { double dt;//such that amp(t+dt)=amp(t)/2 double alpha;//such that amp(t)=exp(alpha*t) @@ -1539,7 +1598,7 @@ inline double envRR2coef(int rr, int sr, unsigned char release) { //amp(t+mt) //following the above equational system we found : alpha=-log(2)/dt; - return exp(alpha/(double)sr); + return exp(alpha/sr); } //--------------------------------------------------------- @@ -1558,7 +1617,7 @@ inline double coefAttack(unsigned char attack) { // envelope state, making evoluate the envelope // sr is the sample rate and st the sine_table //--------------------------------------------------------- -inline double env2AmpR(int sr, float* wt, Eg eg, OpVoice* p_opVoice) { +inline double env2AmpR(double sr, float* wt, Eg eg, OpVoice* p_opVoice) { switch(p_opVoice->envState) { case ATTACK: @@ -1720,7 +1779,9 @@ void DeicsOnze::readConfiguration(QDomNode qdn) { //quality if(qdEl.tagName()==QUALITYSTR) { _global.quality = (qdEl.text()==HIGHSTR?high: - (qdEl.text()==MIDDLESTR?middle:low)); + (qdEl.text()==MIDDLESTR?middle: + (qdEl.text()==LOWSTR?low:ultralow))); + setQuality(_global.quality); unsigned char *dataQuality = new unsigned char[2]; dataQuality[0]=SYSEX_QUALITY; dataQuality[1]=(unsigned char)_global.quality; @@ -1886,7 +1947,8 @@ void DeicsOnze::writeConfiguration(AL::Xml* xml) { //xml->strTag(CHANNELNUMSTR, (_global.channelNum==-1?ALLSTR: // str.setNum(_global.channelNum+1))); xml->strTag(QUALITYSTR, (_global.quality==high?HIGHSTR: - (_global.quality==middle?MIDDLESTR:LOWSTR))); + (_global.quality==middle?MIDDLESTR: + (_global.quality==low?LOWSTR:ULTRALOWSTR)))); xml->intTag(FONTSIZESTR, _global.fontSize); xml->strTag(SAVECONFIGSTR, (_saveConfig?YESSTRDEI:NOSTRDEI)); xml->strTag(SAVEONLYUSEDSTR, (_saveOnlyUsed?YESSTRDEI:NOSTRDEI)); @@ -2096,6 +2158,7 @@ void DeicsOnze::parseInitData(int length, const unsigned char* data) { unsigned char dataQuality[2]; dataQuality[0]=SYSEX_QUALITY; dataQuality[1]=data[NUMQUALITY]; + setQuality((Quality)data[NUMQUALITY]); MidiEvent evQuality(0, ME_SYSEX, (const unsigned char*)dataQuality, 2); _gui->writeEvent(evQuality); //font size @@ -2249,7 +2312,7 @@ bool DeicsOnze::sysex(int length, const unsigned char* data, bool fromGui) { //} //break; case SYSEX_QUALITY: - _global.quality = (Quality)data[1]; + setQuality((Quality)data[1]); if(!fromGui) { MidiEvent evSysex(0, ME_SYSEX, data, length); _gui->writeEvent(evSysex); @@ -2989,7 +3052,8 @@ bool DeicsOnze::playNote(int ch, int pitch, int velo) { if(_preset[ch]->function.portamentoTime!=0) { _global.channel[ch].voices[newVoice].hasAttractor = true; _global.channel[ch].voices[newVoice].attractor = - getAttractor(_preset[ch]->function.portamentoTime); + getAttractor(_preset[ch]->function.portamentoTime, + _global.deiSampleRate); } else _global.channel[ch].voices[newVoice].hasAttractor = false; //feedback @@ -3045,7 +3109,8 @@ bool DeicsOnze::playNote(int ch, int pitch, int velo) { (_preset[ch]->function.portamento==FINGER && existsKeyOn(ch))) { _global.channel[ch].voices[newVoice].hasAttractor = true; _global.channel[ch].voices[newVoice].attractor = - getAttractor(_preset[ch]->function.portamentoTime); + getAttractor(_preset[ch]->function.portamentoTime, + _global.deiSampleRate); } else _global.channel[ch].voices[newVoice].hasAttractor = false; @@ -3069,7 +3134,8 @@ bool DeicsOnze::playNote(int ch, int pitch, int velo) { _global.channel[ch].voices[newVoice].pitchEnvCoefInctInct = getPitchEnvCoefInctInct(_preset[ch]->pitchEg.pl1, _preset[ch]->pitchEg.pl2, - _preset[ch]->pitchEg.pr1); + _preset[ch]->pitchEg.pr1, + _global.deiSampleRate); } else { _global.channel[ch].voices[newVoice].pitchEnvState = OFF_PE; @@ -3151,7 +3217,7 @@ bool DeicsOnze::playNote(int ch, int pitch, int velo) { //---- //compute inct _global.channel[ch].voices[newVoice].op[i].targetInct = - (double)RESOLUTION / ( (double)sampleRate() / tempTargetFreq ); + (double)RESOLUTION / ( _global.deiSampleRate / tempTargetFreq ); if(_global.channel[ch].voices[newVoice].hasAttractor && !_preset[ch]->frequency[i].isFix) _global.channel[ch].voices[newVoice].op[i].inct = @@ -3217,260 +3283,266 @@ void DeicsOnze::process(float** buffer, int offset, int n) { float sampleOp[NBROP]; float ampOp[NBROP]; for(int i = 0; i < n; i++) { - tempLeftOutput = 0.0; - tempRightOutput = 0.0; - //per channel - for(int c = 0; c < NBRCHANNELS; c++) { - tempChannelOutput = 0.0; - if(_global.channel[c].isEnable) { - //lfo, trick : we use the first quater of the wave W2 - lfoUpdate(_preset[c], &_global.channel[c], waveTable[W2]); - - //optimization - tempIncChannel = - _global.channel[c].lfoCoefInct * _global.channel[c].pitchBendCoef; - - //per voice - for(int j=0; j<_global.channel[c].nbrVoices; j++) { - if (_global.channel[c].voices[j].isOn) { - //portamento - portamentoUpdate(&_global.channel[c], - &_global.channel[c].voices[j]); - //pitch envelope - pitchEnvelopeUpdate(&_global.channel[c].voices[j], - &_preset[c]->pitchEg); - //per op - for(int k=0; ksensitivity.ampOn[k]? - _global.channel[c].lfoAmp:1.0) - *env2AmpR(sampleRate(), waveTable[W2], - _preset[c]->eg[k], - &_global.channel[c].voices[j].op[k]); - } - switch(_preset[c]->algorithm) { - case FIRST : - sampleOp[3]=ampOp[3] - *waveTable[_preset[c]->oscWave[3]] - [(int)plusMod(_global.channel[c].voices[j].op[3].index, - (float)RESOLUTION - *_global.channel[c].voices[j].sampleFeedback)]; - sampleOp[2]=ampOp[2] - *waveTable[_preset[c]->oscWave[2]] - [(int)plusMod(_global.channel[c].voices[j].op[2].index, - (float)RESOLUTION*sampleOp[3])]; - sampleOp[1]=ampOp[1] - *waveTable[_preset[c]->oscWave[1]] - [(int)plusMod(_global.channel[c].voices[j].op[1].index, - (float)RESOLUTION*sampleOp[2])]; - sampleOp[0]=ampOp[0] - *waveTable[_preset[c]->oscWave[0]] - [(int)plusMod(_global.channel[c].voices[j].op[0].index, - (float)RESOLUTION*sampleOp[1])]; - - sample[j]=sampleOp[0];///COEFLEVEL; - - _global.channel[c].voices[j].isOn = - (_global.channel[c].voices[j].op[0].envState!=OFF); - break; - case SECOND : - sampleOp[3]=ampOp[3] - *waveTable[_preset[c]->oscWave[3]] - [(int)plusMod(_global.channel[c].voices[j].op[3].index, - (float)RESOLUTION - *_global.channel[c].voices[j].sampleFeedback)]; - sampleOp[2]=ampOp[2] - *waveTable[_preset[c]->oscWave[2]] - [(int)_global.channel[c].voices[j].op[2].index]; - sampleOp[1]=ampOp[1] - *waveTable[_preset[c]->oscWave[1]] - [(int)plusMod(_global.channel[c].voices[j].op[1].index, - (float)RESOLUTION - *(sampleOp[2]+sampleOp[3])/2.0)]; - sampleOp[0]=ampOp[0] - *waveTable[_preset[c]->oscWave[0]] - [(int)plusMod(_global.channel[c].voices[j].op[0].index, - (float)RESOLUTION - *sampleOp[1])]; - - sample[j]=sampleOp[0];///COEFLEVEL; - - _global.channel[c].voices[j].isOn = - (_global.channel[c].voices[j].op[0].envState!=OFF); - break; - case THIRD : - sampleOp[3]=ampOp[3] - *waveTable[_preset[c]->oscWave[3]] - [(int)plusMod(_global.channel[c].voices[j].op[3].index, - (float)RESOLUTION - *_global.channel[c].voices[j].sampleFeedback)]; - sampleOp[2]=ampOp[2] - *waveTable[_preset[c]->oscWave[2]] - [(int)_global.channel[c].voices[j].op[2].index]; - sampleOp[1]=ampOp[1] - *waveTable[_preset[c]->oscWave[1]] - [(int)plusMod(_global.channel[c].voices[j].op[1].index, - (float)RESOLUTION*sampleOp[2])]; - sampleOp[0]=ampOp[0] - *waveTable[_preset[c]->oscWave[0]] - [(int)plusMod(_global.channel[c].voices[j].op[0].index, - (float)RESOLUTION - *(sampleOp[3]+sampleOp[1])/2.0)]; - - sample[j]=sampleOp[0];///COEFLEVEL; - - _global.channel[c].voices[j].isOn = - (_global.channel[c].voices[j].op[0].envState!=OFF); - break; - case FOURTH : - sampleOp[3]=ampOp[3] - *waveTable[_preset[c]->oscWave[3]] - [(int)plusMod(_global.channel[c].voices[j].op[3].index, - (float)RESOLUTION - *_global.channel[c].voices[j].sampleFeedback)]; - sampleOp[2]=ampOp[2] - *waveTable[_preset[c]->oscWave[2]] - [(int)plusMod(_global.channel[c].voices[j].op[2].index, - (float)RESOLUTION - *sampleOp[3])]; - sampleOp[1]=ampOp[1] - *waveTable[_preset[c]->oscWave[1]] - [(int)_global.channel[c].voices[j].op[1].index]; - sampleOp[0]=ampOp[0] - *waveTable[_preset[c]->oscWave[0]] - [(int)plusMod(_global.channel[c].voices[j].op[0].index, - (float)RESOLUTION - *(sampleOp[1]+sampleOp[2])/2.0)]; - - sample[j]=sampleOp[0];///COEFLEVEL; - - _global.channel[c].voices[j].isOn = - (_global.channel[c].voices[j].op[0].envState!=OFF); - break; - case FIFTH : - sampleOp[3]=ampOp[3] - *waveTable[_preset[c]->oscWave[3]] - [(int)plusMod(_global.channel[c].voices[j].op[3].index, - (float)RESOLUTION - *_global.channel[c].voices[j].sampleFeedback)]; - sampleOp[2]=ampOp[2] - *waveTable[_preset[c]->oscWave[2]] - [(int)plusMod(_global.channel[c].voices[j].op[2].index, - (float)RESOLUTION*sampleOp[3])]; - sampleOp[1]=ampOp[1] - *waveTable[_preset[c]->oscWave[1]] - [(int)_global.channel[c].voices[j].op[1].index]; - sampleOp[0]=ampOp[0] - *waveTable[_preset[c]->oscWave[0]] - [(int)plusMod(_global.channel[c].voices[j].op[0].index, - (float)RESOLUTION*sampleOp[1])]; - - sample[j]=(sampleOp[0]+sampleOp[2])/2.0;///COEFLEVEL; - - _global.channel[c].voices[j].isOn = - (_global.channel[c].voices[j].op[0].envState!=OFF - ||_global.channel[c].voices[j].op[2].envState!=OFF); - break; - case SIXTH : - sampleOp[3]=ampOp[3] - *waveTable[_preset[c]->oscWave[3]] - [(int)plusMod(_global.channel[c].voices[j].op[3].index, - (float)RESOLUTION - *_global.channel[c].voices[j].sampleFeedback)]; - sampleOp[2]=ampOp[2] - *waveTable[_preset[c]->oscWave[2]] - [(int)plusMod(_global.channel[c].voices[j].op[2].index, - (float)RESOLUTION*sampleOp[3])]; - sampleOp[1]=ampOp[1] - *waveTable[_preset[c]->oscWave[1]] - [(int)plusMod(_global.channel[c].voices[j].op[1].index, - (float)RESOLUTION*sampleOp[3])]; - sampleOp[0]=ampOp[0] - *waveTable[_preset[c]->oscWave[0]] - [(int)plusMod(_global.channel[c].voices[j].op[0].index, - (float)RESOLUTION*sampleOp[3])]; - - sample[j]=(sampleOp[0]+sampleOp[1]+sampleOp[2])/3.0; - - _global.channel[c].voices[j].isOn = - (_global.channel[c].voices[j].op[0].envState!=OFF); - break; - case SEVENTH : - sampleOp[3]=ampOp[3] - *waveTable[_preset[c]->oscWave[3]] - [(int)plusMod(_global.channel[c].voices[j].op[3].index, - (float)RESOLUTION - *_global.channel[c].voices[j].sampleFeedback)]; - sampleOp[2]=ampOp[2] - *waveTable[_preset[c]->oscWave[2]] - [(int)plusMod(_global.channel[c].voices[j].op[2].index, - (float)RESOLUTION*sampleOp[3])]; - sampleOp[1]=ampOp[1] - *waveTable[_preset[c]->oscWave[1]] - [(int)_global.channel[c].voices[j].op[1].index]; - sampleOp[0]=ampOp[0]*waveTable[_preset[c]->oscWave[0]] - [(int)_global.channel[c].voices[j].op[0].index]; - - sample[j]=(sampleOp[0]+sampleOp[1]+sampleOp[2])/3.0; + if(_global.qualityCounter == 0) { + tempLeftOutput = 0.0; + tempRightOutput = 0.0; + //per channel + for(int c = 0; c < NBRCHANNELS; c++) { + tempChannelOutput = 0.0; + if(_global.channel[c].isEnable) { + //lfo, trick : we use the first quater of the wave W2 + lfoUpdate(_preset[c], &_global.channel[c], waveTable[W2]); + + //optimization + tempIncChannel = + _global.channel[c].lfoCoefInct * _global.channel[c].pitchBendCoef; + + //per voice + for(int j=0; j<_global.channel[c].nbrVoices; j++) { + if (_global.channel[c].voices[j].isOn) { + //portamento + portamentoUpdate(&_global.channel[c], + &_global.channel[c].voices[j]); + //pitch envelope + pitchEnvelopeUpdate(&_global.channel[c].voices[j], + &_preset[c]->pitchEg, _global.deiSampleRate); + //per op + for(int k=0; ksensitivity.ampOn[k]? + _global.channel[c].lfoAmp:1.0) + *env2AmpR(_global.deiSampleRate, waveTable[W2], + _preset[c]->eg[k], + &_global.channel[c].voices[j].op[k]); + } + switch(_preset[c]->algorithm) { + case FIRST : + sampleOp[3]=ampOp[3] + *waveTable[_preset[c]->oscWave[3]] + [(int)plusMod(_global.channel[c].voices[j].op[3].index, + (float)RESOLUTION + *_global.channel[c].voices[j].sampleFeedback)]; + sampleOp[2]=ampOp[2] + *waveTable[_preset[c]->oscWave[2]] + [(int)plusMod(_global.channel[c].voices[j].op[2].index, + (float)RESOLUTION*sampleOp[3])]; + sampleOp[1]=ampOp[1] + *waveTable[_preset[c]->oscWave[1]] + [(int)plusMod(_global.channel[c].voices[j].op[1].index, + (float)RESOLUTION*sampleOp[2])]; + sampleOp[0]=ampOp[0] + *waveTable[_preset[c]->oscWave[0]] + [(int)plusMod(_global.channel[c].voices[j].op[0].index, + (float)RESOLUTION*sampleOp[1])]; + + sample[j]=sampleOp[0];///COEFLEVEL; + + _global.channel[c].voices[j].isOn = + (_global.channel[c].voices[j].op[0].envState!=OFF); + break; + case SECOND : + sampleOp[3]=ampOp[3] + *waveTable[_preset[c]->oscWave[3]] + [(int)plusMod(_global.channel[c].voices[j].op[3].index, + (float)RESOLUTION + *_global.channel[c].voices[j].sampleFeedback)]; + sampleOp[2]=ampOp[2] + *waveTable[_preset[c]->oscWave[2]] + [(int)_global.channel[c].voices[j].op[2].index]; + sampleOp[1]=ampOp[1] + *waveTable[_preset[c]->oscWave[1]] + [(int)plusMod(_global.channel[c].voices[j].op[1].index, + (float)RESOLUTION + *(sampleOp[2]+sampleOp[3])/2.0)]; + sampleOp[0]=ampOp[0] + *waveTable[_preset[c]->oscWave[0]] + [(int)plusMod(_global.channel[c].voices[j].op[0].index, + (float)RESOLUTION + *sampleOp[1])]; + + sample[j]=sampleOp[0];///COEFLEVEL; + + _global.channel[c].voices[j].isOn = + (_global.channel[c].voices[j].op[0].envState!=OFF); + break; + case THIRD : + sampleOp[3]=ampOp[3] + *waveTable[_preset[c]->oscWave[3]] + [(int)plusMod(_global.channel[c].voices[j].op[3].index, + (float)RESOLUTION + *_global.channel[c].voices[j].sampleFeedback)]; + sampleOp[2]=ampOp[2] + *waveTable[_preset[c]->oscWave[2]] + [(int)_global.channel[c].voices[j].op[2].index]; + sampleOp[1]=ampOp[1] + *waveTable[_preset[c]->oscWave[1]] + [(int)plusMod(_global.channel[c].voices[j].op[1].index, + (float)RESOLUTION*sampleOp[2])]; + sampleOp[0]=ampOp[0] + *waveTable[_preset[c]->oscWave[0]] + [(int)plusMod(_global.channel[c].voices[j].op[0].index, + (float)RESOLUTION + *(sampleOp[3]+sampleOp[1])/2.0)]; + + sample[j]=sampleOp[0];///COEFLEVEL; + + _global.channel[c].voices[j].isOn = + (_global.channel[c].voices[j].op[0].envState!=OFF); + break; + case FOURTH : + sampleOp[3]=ampOp[3] + *waveTable[_preset[c]->oscWave[3]] + [(int)plusMod(_global.channel[c].voices[j].op[3].index, + (float)RESOLUTION + *_global.channel[c].voices[j].sampleFeedback)]; + sampleOp[2]=ampOp[2] + *waveTable[_preset[c]->oscWave[2]] + [(int)plusMod(_global.channel[c].voices[j].op[2].index, + (float)RESOLUTION + *sampleOp[3])]; + sampleOp[1]=ampOp[1] + *waveTable[_preset[c]->oscWave[1]] + [(int)_global.channel[c].voices[j].op[1].index]; + sampleOp[0]=ampOp[0] + *waveTable[_preset[c]->oscWave[0]] + [(int)plusMod(_global.channel[c].voices[j].op[0].index, + (float)RESOLUTION + *(sampleOp[1]+sampleOp[2])/2.0)]; + + sample[j]=sampleOp[0];///COEFLEVEL; + + _global.channel[c].voices[j].isOn = + (_global.channel[c].voices[j].op[0].envState!=OFF); + break; + case FIFTH : + sampleOp[3]=ampOp[3] + *waveTable[_preset[c]->oscWave[3]] + [(int)plusMod(_global.channel[c].voices[j].op[3].index, + (float)RESOLUTION + *_global.channel[c].voices[j].sampleFeedback)]; + sampleOp[2]=ampOp[2] + *waveTable[_preset[c]->oscWave[2]] + [(int)plusMod(_global.channel[c].voices[j].op[2].index, + (float)RESOLUTION*sampleOp[3])]; + sampleOp[1]=ampOp[1] + *waveTable[_preset[c]->oscWave[1]] + [(int)_global.channel[c].voices[j].op[1].index]; + sampleOp[0]=ampOp[0] + *waveTable[_preset[c]->oscWave[0]] + [(int)plusMod(_global.channel[c].voices[j].op[0].index, + (float)RESOLUTION*sampleOp[1])]; + + sample[j]=(sampleOp[0]+sampleOp[2])/2.0;///COEFLEVEL; + + _global.channel[c].voices[j].isOn = + (_global.channel[c].voices[j].op[0].envState!=OFF + ||_global.channel[c].voices[j].op[2].envState!=OFF); + break; + case SIXTH : + sampleOp[3]=ampOp[3] + *waveTable[_preset[c]->oscWave[3]] + [(int)plusMod(_global.channel[c].voices[j].op[3].index, + (float)RESOLUTION + *_global.channel[c].voices[j].sampleFeedback)]; + sampleOp[2]=ampOp[2] + *waveTable[_preset[c]->oscWave[2]] + [(int)plusMod(_global.channel[c].voices[j].op[2].index, + (float)RESOLUTION*sampleOp[3])]; + sampleOp[1]=ampOp[1] + *waveTable[_preset[c]->oscWave[1]] + [(int)plusMod(_global.channel[c].voices[j].op[1].index, + (float)RESOLUTION*sampleOp[3])]; + sampleOp[0]=ampOp[0] + *waveTable[_preset[c]->oscWave[0]] + [(int)plusMod(_global.channel[c].voices[j].op[0].index, + (float)RESOLUTION*sampleOp[3])]; + + sample[j]=(sampleOp[0]+sampleOp[1]+sampleOp[2])/3.0; + + _global.channel[c].voices[j].isOn = + (_global.channel[c].voices[j].op[0].envState!=OFF); + break; + case SEVENTH : + sampleOp[3]=ampOp[3] + *waveTable[_preset[c]->oscWave[3]] + [(int)plusMod(_global.channel[c].voices[j].op[3].index, + (float)RESOLUTION + *_global.channel[c].voices[j].sampleFeedback)]; + sampleOp[2]=ampOp[2] + *waveTable[_preset[c]->oscWave[2]] + [(int)plusMod(_global.channel[c].voices[j].op[2].index, + (float)RESOLUTION*sampleOp[3])]; + sampleOp[1]=ampOp[1] + *waveTable[_preset[c]->oscWave[1]] + [(int)_global.channel[c].voices[j].op[1].index]; + sampleOp[0]=ampOp[0]*waveTable[_preset[c]->oscWave[0]] + [(int)_global.channel[c].voices[j].op[0].index]; + + sample[j]=(sampleOp[0]+sampleOp[1]+sampleOp[2])/3.0; + + _global.channel[c].voices[j].isOn = + (_global.channel[c].voices[j].op[0].envState!=OFF); + break; + case EIGHTH : + sampleOp[3]=ampOp[3] + *waveTable[_preset[c]->oscWave[3]] + [(int)plusMod(_global.channel[c].voices[j].op[3].index, + (float)RESOLUTION + *_global.channel[c].voices[j].sampleFeedback)]; + sampleOp[2]=ampOp[2] + *waveTable[_preset[c]->oscWave[2]] + [(int)_global.channel[c].voices[j].op[2].index]; + sampleOp[1]=ampOp[1] + *waveTable[_preset[c]->oscWave[1]] + [(int)_global.channel[c].voices[j].op[1].index]; + sampleOp[0]=ampOp[0] + *waveTable[_preset[c]->oscWave[0]] + [(int)_global.channel[c].voices[j].op[0].index]; + + sample[j]= + (sampleOp[0]+sampleOp[1]+sampleOp[2]+sampleOp[3]) + /4.0; + + _global.channel[c].voices[j].isOn = + (_global.channel[c].voices[j].op[0].envState!=OFF + || _global.channel[c].voices[j].op[1].envState!=OFF + || _global.channel[c].voices[j].op[2].envState!=OFF + || _global.channel[c].voices[j].op[3].envState!=OFF); + break; + default : printf("Error : No algorithm"); + break; + } - _global.channel[c].voices[j].isOn = - (_global.channel[c].voices[j].op[0].envState!=OFF); - break; - case EIGHTH : - sampleOp[3]=ampOp[3] - *waveTable[_preset[c]->oscWave[3]] - [(int)plusMod(_global.channel[c].voices[j].op[3].index, - (float)RESOLUTION - *_global.channel[c].voices[j].sampleFeedback)]; - sampleOp[2]=ampOp[2] - *waveTable[_preset[c]->oscWave[2]] - [(int)_global.channel[c].voices[j].op[2].index]; - sampleOp[1]=ampOp[1] - *waveTable[_preset[c]->oscWave[1]] - [(int)_global.channel[c].voices[j].op[1].index]; - sampleOp[0]=ampOp[0] - *waveTable[_preset[c]->oscWave[0]] - [(int)_global.channel[c].voices[j].op[0].index]; + _global.channel[c].voices[j].volume= + ampOp[0]+ampOp[1]+ampOp[2]+ampOp[3]; - sample[j]= - (sampleOp[0]+sampleOp[1]+sampleOp[2]+sampleOp[3]) - /4.0; + _global.channel[c].voices[j].sampleFeedback = + sampleOp[3]*_global.channel[c].feedbackAmp; - _global.channel[c].voices[j].isOn = - (_global.channel[c].voices[j].op[0].envState!=OFF - || _global.channel[c].voices[j].op[1].envState!=OFF - || _global.channel[c].voices[j].op[2].envState!=OFF - || _global.channel[c].voices[j].op[3].envState!=OFF); - break; - default : printf("Error : No algorithm"); - break; + tempChannelOutput += sample[j]; } - - _global.channel[c].voices[j].volume= - ampOp[0]+ampOp[1]+ampOp[2]+ampOp[3]; - - _global.channel[c].voices[j].sampleFeedback = - sampleOp[3]*_global.channel[c].feedbackAmp; - - tempChannelOutput += sample[j]; } + //printf("left out = %f, temp out = %f, left amp = %f\n", + //tempLeftOutput, tempChannelOutput, _global.channel[c].ampLeft); + tempLeftOutput += tempChannelOutput*_global.channel[c].ampLeft; + tempRightOutput += tempChannelOutput*_global.channel[c].ampRight; } - //printf("left out = %f, temp out = %f, left amp = %f\n", - //tempLeftOutput, tempChannelOutput, _global.channel[c].ampLeft); - tempLeftOutput += tempChannelOutput*_global.channel[c].ampLeft; - tempRightOutput += tempChannelOutput*_global.channel[c].ampRight; } + _global.lastLeftSample = tempLeftOutput*_global.masterVolume; + _global.lastRightSample = tempRightOutput*_global.masterVolume; } - leftOutput[i] += tempLeftOutput*_global.masterVolume; - rightOutput[i] += tempRightOutput*_global.masterVolume; + leftOutput[i] += _global.lastLeftSample; + rightOutput[i] += _global.lastRightSample; + _global.qualityCounter++; + _global.qualityCounter %= _global.qualityCounterTop; } } @@ -3491,8 +3563,8 @@ static Mess* instantiate(int sr, QWidget*, const char*) extern "C" { static MESS descriptor = { "DeicsOnze", - "DeicsOnze FM DX11 emulator", - "0.4.3", // version string + "DeicsOnze FM DX11/TX81Z emulator", + "0.4.5", // version string MESS_MAJOR_VERSION, MESS_MINOR_VERSION, instantiate }; diff --git a/muse/synti/deicsonze/deicsonze.h b/muse/synti/deicsonze/deicsonze.h index c16ba969..dd6353b1 100644 --- a/muse/synti/deicsonze/deicsonze.h +++ b/muse/synti/deicsonze/deicsonze.h @@ -2,7 +2,7 @@ // // DeicsOnze an emulator of the YAMAHA DX11 synthesizer // -// Version 0.4.3 +// Version 0.4.5 // // // @@ -71,7 +71,7 @@ #define COEFERRSUSREL 0.001 //from SUSTAIN or RELEASE until no sound //#define ERRPORTA 0.001 //dectection to stop portamento #define COEFPORTA 0.01 //adjusted such that 10 second/octave with max porta -#define COEFPITCHENV 0.000001 //adjust according to a real DX11....??? +#define COEFPITCHENV 0.00000025 //adjust according to a real DX11....??? #define COEFDECAY 1.0 #define COEFSUSTAIN 0.2 #define COEFRELEASE 1.0 @@ -100,6 +100,7 @@ #define HIGHSTR "High" #define MIDDLESTR "Middle" #define LOWSTR "Low" +#define ULTRALOWSTR "UltraLow" #define SYSEX_FONTSIZE 6 #define FONTSIZESTR "fontSize" #define SYSEX_SAVECONFIG 7 @@ -188,7 +189,7 @@ inline double coefAttack(unsigned char attack); // return the coefficient for the exponential decrease // with respect to rr and sampleRate, sr //--------------------------------------------------------- -inline double envRR2coef(int rr, int sr, unsigned char release); +inline double envRR2coef(int rr, double sr, unsigned char release); //-------------------------------------------------------- // DeicsOnzeCtrl @@ -310,13 +311,19 @@ struct Channel { enum Quality { high, middle, - low + low, + ultralow }; struct Global { float masterVolume; - Quality quality; + Quality quality; //high, middle, low + int qualityCounter; //counter to skip some sample depending on quality + int qualityCounterTop; //number of sample - 1 to skip + double deiSampleRate; //depending on quality deicsOnze sample rate varies int fontSize; + float lastLeftSample; + float lastRightSample; Channel channel[NBRCHANNELS]; }; @@ -354,6 +361,7 @@ class DeicsOnze : public Mess { //preset tree Set* _set; + void setSampleRate(int sr); Preset* findPreset(int hbank, int lbank, int prog); void initCtrls(); void initGlobal(); @@ -374,6 +382,7 @@ class DeicsOnze : public Mess { void setEnvRelease(int c, int k); //do the same for all voices of operator k void setEnvRelease(int c); //do the same for all voices all operators void setPitchEnvRelease(int c, int v); + void setQuality(Quality q); double brightness2Amp(int c, int k); //get the brightness of the operator k void loadSutulaPresets(); void loadSet(QString s); diff --git a/muse/synti/deicsonze/deicsonzegui.cpp b/muse/synti/deicsonze/deicsonzegui.cpp index ed1b99fd..05855d4b 100644 --- a/muse/synti/deicsonze/deicsonzegui.cpp +++ b/muse/synti/deicsonze/deicsonzegui.cpp @@ -2,7 +2,7 @@ // // DeicsOnze an emulator of the YAMAHA DX11 synthesizer // -// Version 0.4.3 +// Version 0.4.5 // // deicsonzegui.cpp // @@ -527,7 +527,9 @@ void DeicsOnzeGui::loadConfiguration() { void DeicsOnzeGui::setQuality(const QString& q) { unsigned char* message = new unsigned char[2]; message[0]=SYSEX_QUALITY; - message[1]=(unsigned char)(q=="High"?high:(q=="Middle"?middle:low)); + message[1]=(unsigned char)(q=="High"? + high:(q=="Middle"? + middle:(q=="Low"?low:ultralow))); sendSysex(message, 2); } //----------------------------------------------------------- diff --git a/muse/synti/deicsonze/deicsonzegui.h b/muse/synti/deicsonze/deicsonzegui.h index 57645d60..12accbcf 100644 --- a/muse/synti/deicsonze/deicsonzegui.h +++ b/muse/synti/deicsonze/deicsonzegui.h @@ -2,7 +2,7 @@ // // DeicsOnze an emulator of the YAMAHA DX11 synthesizer // -// Version 0.4.3 +// Version 0.4.5 // // deicsonzegui.h // diff --git a/muse/synti/deicsonze/deicsonzegui.ui b/muse/synti/deicsonze/deicsonzegui.ui index a1a55f98..3e3b5bd6 100644 --- a/muse/synti/deicsonze/deicsonzegui.ui +++ b/muse/synti/deicsonze/deicsonzegui.ui @@ -868,7 +868,7 @@ QFrame::Plain - DeicsOnze v0.4.3 Copyright (c) 2004-2006 Nil Geisweiller. Published under GPL licence. + DeicsOnze v0.4.5 Copyright (c) 2004-2006 Nil Geisweiller. Published under GPL licence. @@ -5941,7 +5941,7 @@ Wave form 8 = <i>if <b>t</b>&#060 pi then sin(2*<b>t</b>)*sin - false + true @@ -5958,6 +5958,11 @@ Wave form 8 = <i>if <b>t</b>&#060 pi then sin(2*<b>t</b>)*sin Low + + + Ultra low + + diff --git a/muse/synti/deicsonze/deicsonzepreset.cpp b/muse/synti/deicsonze/deicsonzepreset.cpp index 9b61a1bb..afa43e93 100644 --- a/muse/synti/deicsonze/deicsonzepreset.cpp +++ b/muse/synti/deicsonze/deicsonzepreset.cpp @@ -2,7 +2,7 @@ // // DeicsOnze an emulator of the YAMAHA DX11 synthesizer // -// Version 0.4.3 +// Version 0.4.5 // // deicsonzepreset.cpp // diff --git a/muse/synti/deicsonze/deicsonzepreset.h b/muse/synti/deicsonze/deicsonzepreset.h index 290a3e94..6b05939e 100644 --- a/muse/synti/deicsonze/deicsonzepreset.h +++ b/muse/synti/deicsonze/deicsonzepreset.h @@ -2,7 +2,7 @@ // // DeicsOnze an emulator of the YAMAHA DX11 synthesizer // -// Version 0.4.3 +// Version 0.4.5 // // deicsonzepreset.h // -- cgit v1.2.3