diff --git a/MicroDexed.ino b/MicroDexed.ino index 39ea6aa..b626e00 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -5,6 +5,7 @@ #define RATE 128 #define TEENSY 1 +#define TEST_MIDI #ifdef TEENSY #include @@ -16,8 +17,8 @@ // GUItool: begin automatically generated code AudioPlayQueue queue1; //xy=811,259 AudioOutputI2S i2s1; //xy=1185,252 -AudioConnection patchCord2(queue1, 0, i2s1, 0); -AudioConnection patchCord3(queue1, 0, i2s1, 1); +AudioConnection patchCord1(queue1, 0, i2s1, 0); +AudioConnection patchCord2(queue1, 0, i2s1, 1); AudioControlSGTL5000 sgtl5000_1; //xy=830,376 // GUItool: end automatically generated code #endif @@ -44,8 +45,18 @@ void setup() // Initialize processor and memory measurements //AudioProcessorUsageMaxReset(); //AudioMemoryUsageMaxReset(); + + // initial fill audio buffer + while (queue1.available()) + { + queue1.getBuffer(); + queue1.playBuffer(); + } #endif +#ifdef TEST_MIDI + dexed->ProcessMidiMessage(0x90, 64, 100); +#endif } void loop() @@ -66,8 +77,8 @@ void loop() #ifdef TEENSY // play the current buffer - while(!queue1.available()); - + while (!queue1.available()); + queue1.playBuffer(); #endif } diff --git a/dexed.cpp b/dexed.cpp index 3f0261f..29c5f50 100644 --- a/dexed.cpp +++ b/dexed.cpp @@ -1,22 +1,22 @@ /** - * - * 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 - * - */ + + 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" @@ -39,7 +39,7 @@ Dexed::Dexed(double num_samples) Tanh::init(); Sin::init(); - _rate=num_samples; + _rate = num_samples; Freqlut::init(_rate); Lfo::init(_rate); @@ -47,18 +47,18 @@ Dexed::Dexed(double num_samples) Env::init_sr(_rate); //fx.init(_rate); - engineMkI=new EngineMkI; - engineOpl=new EngineOpl; - engineMsfa=new FmCore; + engineMkI = new EngineMkI; + engineOpl = new EngineOpl; + engineMsfa = new FmCore; - for(i=0; iupdate(data, voices[i].midi_note, voices[i].velocity); } - lfo.reset(data+137); + lfo.reset(data + 137); refreshVoice = false; } @@ -366,7 +366,7 @@ void Dexed::GetSamples(int16_t* buffer) 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; @@ -374,19 +374,19 @@ void Dexed::GetSamples(int16_t* buffer) 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) { + 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; + 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; } } } @@ -395,216 +395,216 @@ void Dexed::GetSamples(int16_t* buffer) buffer[i + j] = sumbuf[j]; } - if(++_k_rate_counter%32 && !monoMode) + if (++_k_rate_counter % 32 && !monoMode) { - uint8_t op_carrier=controllers.core->get_carrier_operators(data[134]); // look for carriers + uint8_t op_carrier = controllers.core->get_carrier_operators(data[134]); // look for carriers - for(i=0;i < max_notes;i++) + for (i = 0; i < max_notes; i++) { - if(voices[i].live==true) + if (voices[i].live == true) { - uint8_t op_amp=0; - uint8_t op_carrier_num=0; + 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++) + for (uint8_t op = 0; op < 6; op++) { - uint8_t op_bit=pow(2,op); + uint8_t op_bit = pow(2, op); - if((op_carrier&op_bit)>0) + 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 + if (voiceStatus.amp[op] <= 1069 && voiceStatus.ampStep[op] == 4) // this voice produces no audio output op_amp++; } } - if(op_amp==op_carrier_num) - { + 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; + voices[i].live = false; + voices[i].sustained = false; + voices[i].keydown = false; } } } } } -bool Dexed::ProcessMidiMessage(uint8_t cmd,uint8_t data1,uint8_t data2) +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); + 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 0x90 : - // TRACE("MIDI keydown event: %d %d",buf[1],buf[2]); - keydown(data1, data2); - return(false); + case 2: + // TRACE("MIDI breath event: %d %d",ctrl,value); + controllers.breath_cc = data2; + controllers.refresh(); 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; + 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 0xc0 : -// setCurrentProgram(data1); -// break; - - // channel aftertouch - case 0xd0 : - controllers.aftertouch_cc = data1; - controllers.refresh(); + case 120: + // TRACE("MIDI all-sound-off: %d %d",ctrl,value); + panic(); + return (true); break; - // pitchbend - case 0xe0 : - controllers.values_[kControllerPitch] = data1 | (data2 << 7); + case 123: + // TRACE("MIDI all-notes-off: %d %d",ctrl,value); + notes_off(); + return (true); break; + } + break; + } - default: - 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); + return (false); } void Dexed::keydown(uint8_t pitch, uint8_t velo) { - if ( velo == 0 ) { - keyup(pitch); - return; + if ( velo == 0 ) { + keyup(pitch); + return; + } + + pitch += data[144] - 24; + + uint8_t note = currentNote; + uint8_t keydown_counter = 0; + + for (uint8_t i = 0; i < max_notes; i++) { + if (!voices[note].keydown) { + currentNote = (note + 1) % max_notes; + voices[note].midi_note = pitch; + voices[note].velocity = velo; + voices[note].sustained = sustain; + voices[note].keydown = true; + voices[note].dx7_note->init(data, pitch, velo); + if ( data[136] ) + voices[note].dx7_note->oscSync(); + break; } + else + keydown_counter++; - 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; + } - 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; - } + if (keydown_counter == 0) + lfo.keydown(); + if ( monoMode ) { + for (uint8_t i = 0; i < max_notes; i++) { + if ( voices[i].live ) { + // all keys are up, only transfer signal + if ( ! voices[i].keydown ) { + voices[i].live = false; + voices[note].dx7_note->transferSignal(*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; + } + + voices[note].live = true; } void Dexed::keyup(uint8_t pitch) { - pitch += data[144] - 24; + 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); - } + } + + // note not found ? + if ( note >= max_notes ) { + return; + } + + if ( monoMode ) { + int8_t highNote = -1; + int8_t target = 0; + for (int8_t i = 0; i < max_notes; i++) { + if ( voices[i].keydown && voices[i].midi_note > highNote ) { + target = i; + highNote = voices[i].midi_note; + } } - - if ( sustain ) { - voices[note].sustained = true; - } else { - voices[note].dx7_note->keyup(); + + 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]) @@ -668,49 +668,49 @@ void Dexed::keyup(uint8_t pitch) { break; } } -} + } */ uint8_t Dexed::getEngineType() { - return engineType; + 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(); + 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; + return monoMode; } void Dexed::setMonoMode(bool mode) { - if(monoMode==mode) - return; + if (monoMode == mode) + return; - monoMode = mode; + monoMode = mode; } void Dexed::panic(void) { - for(uint8_t i=0;i