/** * * Copyright (c) 2016-2017 Holger Wirtz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * 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 for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "dexed.h" #include "EngineMkI.h" #include "EngineOpl.h" #include "fm_core.h" #include "exp2.h" #include "sin.h" #include "freqlut.h" #include "controllers.h" //#include "PluginFx.h" #include #include #include Dexed::Dexed(double num_samples) { uint8_t i; Exp2::init(); Tanh::init(); Sin::init(); _rate=num_samples; Freqlut::init(_rate); Lfo::init(_rate); PitchEnv::init(_rate); Env::init_sr(_rate); //fx.init(_rate); engineMkI=new EngineMkI; engineOpl=new EngineOpl; engineMsfa=new FmCore; for(i=0; iPARAM_CHANGE_LEVEL) { panic(); controllers.refresh(); } } */ /*void Dexed::run (uint8_t* midi_data) { static int16_t buffer; ProcessMidiMessage(midi_data); // render audio from the last frame until the timestamp of this event GetSamples(&buffer); //fx.process(&buffer,_rate); }*/ void Dexed::GetSamples(int16_t* buffer) { uint32_t i=0; if(refreshVoice) { for(i=0;i < max_notes;i++) { if ( voices[i].live ) voices[i].dx7_note->update(data, voices[i].midi_note, voices[i].velocity); } lfo.reset(data+137); refreshVoice = false; } // remaining buffer is still to be processed for (; i < _rate; i += _N_) { AlignedBuf audiobuf; float sumbuf[_N_]; for (uint32_t j = 0; j < _N_; ++j) { audiobuf.get()[j] = 0; sumbuf[j] = 0.0; } int32_t lfovalue = lfo.getsample(); int32_t lfodelay = lfo.getdelay(); for (uint8_t note = 0; note < max_notes; ++note) { if (voices[note].live) { voices[note].dx7_note->compute(audiobuf.get(), lfovalue, lfodelay, &controllers); for (uint32_t j=0; j < _N_; ++j) { int32_t val = audiobuf.get()[j]; val = val >> 4; int32_t clip_val = val < -(1 << 24) ? 0x8000 : val >= (1 << 24) ? 0x7fff : val >> 9; float f = static_cast(clip_val>>1)/0x8000; if(f>1) f=1; if(f<-1) f=-1; sumbuf[j]+=f; audiobuf.get()[j]=0; } } } for (uint32_t j = 0; j < _N_; ++j) buffer[i + j] = sumbuf[j]; } if(++_k_rate_counter%32 && !monoMode) { uint8_t op_carrier=controllers.core->get_carrier_operators(data[134]); // look for carriers for(i=0;i < max_notes;i++) { if(voices[i].live==true) { uint8_t op_amp=0; uint8_t op_carrier_num=0; voices[i].dx7_note->peekVoiceStatus(voiceStatus); for(uint8_t op=0;op<6;op++) { uint8_t op_bit=pow(2,op); if((op_carrier&op_bit)>0) { // this voice is a carrier! op_carrier_num++; if(voiceStatus.amp[op]<=1069 && voiceStatus.ampStep[op]==4) // this voice produces no audio output op_amp++; } } if(op_amp==op_carrier_num) { // all carrier-operators are silent -> disable the voice voices[i].live=false; voices[i].sustained=false; voices[i].keydown=false; } } } } } bool Dexed::ProcessMidiMessage(uint8_t cmd,uint8_t data1,uint8_t data2) { switch(cmd & 0xf0) { case 0x80 : // TRACE("MIDI keyup event: %d",buf[1]); keyup(data1); return(false); break; case 0x90 : // TRACE("MIDI keydown event: %d %d",buf[1],buf[2]); keydown(data1, data2); return(false); break; case 0xb0 : { switch(data1) { case 1: // TRACE("MIDI modwheel event: %d %d",ctrl,value); controllers.modwheel_cc = data2; controllers.refresh(); break; case 2: // TRACE("MIDI breath event: %d %d",ctrl,value); controllers.breath_cc = data2; controllers.refresh(); break; case 4: // TRACE("MIDI footsw event: %d %d",ctrl,value); controllers.foot_cc = data2; controllers.refresh(); break; case 64: // TRACE("MIDI sustain event: %d %d",ctrl,value); sustain = data2 > 63; if (!sustain) { for (uint8_t note = 0; note < max_notes; note++) { if (voices[note].sustained && !voices[note].keydown) { voices[note].dx7_note->keyup(); voices[note].sustained = false; } } } break; case 120: // TRACE("MIDI all-sound-off: %d %d",ctrl,value); panic(); return(true); break; case 123: // TRACE("MIDI all-notes-off: %d %d",ctrl,value); notes_off(); return(true); break; } break; } // case 0xc0 : // setCurrentProgram(data1); // break; // channel aftertouch case 0xd0 : controllers.aftertouch_cc = data1; controllers.refresh(); break; // pitchbend case 0xe0 : controllers.values_[kControllerPitch] = data1 | (data2 << 7); break; default: break; } return(false); } void Dexed::keydown(uint8_t pitch, uint8_t velo) { if ( velo == 0 ) { keyup(pitch); return; } pitch += data[144] - 24; uint8_t note = currentNote; uint8_t keydown_counter=0; for (uint8_t i=0; iinit(data, pitch, velo); if ( data[136] ) voices[note].dx7_note->oscSync(); break; } else keydown_counter++; note = (note + 1) % max_notes; } if(keydown_counter==0) lfo.keydown(); if ( monoMode ) { for(uint8_t i=0; itransferSignal(*voices[i].dx7_note); break; } if ( voices[i].midi_note < pitch ) { voices[i].live = false; voices[note].dx7_note->transferState(*voices[i].dx7_note); break; } return; } } } voices[note].live = true; } void Dexed::keyup(uint8_t pitch) { pitch += data[144] - 24; uint8_t note; for (note=0; note= max_notes ) { return; } if ( monoMode ) { int8_t highNote = -1; int8_t target = 0; for (int8_t i=0; i highNote ) { target = i; highNote = voices[i].midi_note; } } if ( highNote != -1 ) { voices[note].live = false; voices[target].live = true; voices[target].dx7_note->transferState(*voices[note].dx7_note); } } if ( sustain ) { voices[note].sustained = true; } else { voices[note].dx7_note->keyup(); } } /*void Dexed::onParam(uint8_t param_num,float param_val) { int32_t tune; if(param_val!=data_float[param_num]) { _param_change_counter++; if(param_num==144 || param_num==134 || param_num==172) panic(); refreshVoice=true; data[param_num]=static_cast(param_val); data_float[param_num]=param_val; switch(param_num) { case 155: controllers.values_[kControllerPitchRange]=data[param_num]; break; case 156: controllers.values_[kControllerPitchStep]=data[param_num]; break; case 157: // TRACE("wheel.setRange(%d)",data[param_num]); controllers.wheel.setRange(data[param_num]); break; case 158: controllers.wheel.setTarget(data[param_num]); break; case 159: controllers.foot.setRange(data[param_num]); break; case 160: controllers.foot.setTarget(data[param_num]); break; case 161: controllers.breath.setRange(data[param_num]); break; case 162: controllers.breath.setTarget(data[param_num]); break; case 163: controllers.at.setRange(data[param_num]); break; case 164: controllers.at.setTarget(data[param_num]); break; case 165: tune=param_val*0x4000; controllers.masterTune=(tune<<11)*(1.0/12); break; case 166: case 167: case 168: case 169: case 170: case 171: controllers.opSwitch=(data[166]<<5)|(data[167]<<4)|(data[168]<<3)|(data[169]<<2)|(data[170]<<1)|data[171]; break; case 172: max_notes=data[param_num]; break; } } } */ uint8_t Dexed::getEngineType() { return engineType; } void Dexed::setEngineType(uint8_t tp) { if(engineType==tp && controllers.core!=NULL) return; switch (tp) { case DEXED_ENGINE_MARKI: controllers.core = engineMkI; break; case DEXED_ENGINE_OPL: controllers.core = engineOpl; break; default: controllers.core = engineMsfa; tp=DEXED_ENGINE_MODERN; break; } engineType = tp; panic(); controllers.refresh(); } bool Dexed::isMonoMode(void) { return monoMode; } void Dexed::setMonoMode(bool mode) { if(monoMode==mode) return; monoMode = mode; } void Dexed::panic(void) { for(uint8_t i=0;ioscSync(); } } } } void Dexed::notes_off(void) { for(uint8_t i=0;i