pull/4/head
Holger Wirtz 7 years ago
parent 25862c59b1
commit d18b6bf1aa
  1. 1
      EngineMkI.cpp
  2. 1
      EngineMkI.h
  3. 32
      MicroDexed.ino
  4. 7
      controllers.h
  5. 238
      dexed.cpp
  6. 7
      dexed.h
  7. 1
      dx7note.h
  8. 1
      fm_core.h

@ -21,7 +21,6 @@
*
*/
#include <Arduino.h>
#include "EngineMkI.h"
#define _USE_MATH_DEFINES
#include <cmath>

@ -18,6 +18,7 @@
#ifndef ENGINEMKI_H_INCLUDED
#define ENGINEMKI_H_INCLUDED
#include <Arduino.h>
#include "synth.h"
#include "aligned_buf.h"
#include "fm_op_kernel.h"

@ -6,6 +6,7 @@
#define RATE 128
#define TEENSY 1
#define TEST_MIDI 1
#define TEST_NOTE 32
#ifdef TEENSY
#include <Audio.h>
@ -42,7 +43,7 @@ void setup()
AudioMemory(8);
sgtl5000_1.enable();
sgtl5000_1.volume(0.2);
sgtl5000_1.volume(0.3);
// Initialize processor and memory measurements
//AudioProcessorUsageMaxReset();
@ -59,10 +60,10 @@ void setup()
dexed->activate();
#ifdef TEST_MIDI
dexed->ProcessMidiMessage(0x90, 64, 100);
dexed->ProcessMidiMessage(0x90, TEST_NOTE, 100);
//dexed->ProcessMidiMessage(0x90, 66, 127);
#endif
Serial.println(dexed->getEngineType(), DEC);
Serial.println("Go");
}
@ -70,8 +71,18 @@ void loop()
{
int16_t* audio_buffer; // pointer for 128 * int16_t
#ifdef TEST_MIDI
if (millis() > 3000 && millis() < 3050)
dexed->ProcessMidiMessage(0x80, TEST_NOTE, 0);
#endif
#ifdef TEENSY
audio_buffer = queue1.getBuffer();
if (audio_buffer == NULL)
{
Serial.println("audio_buffer allocation problems!");
return;
}
#endif
// process midi->audio
@ -79,17 +90,10 @@ void loop()
{
dexed->ProcessMidiMessage(MIDI.getType(), MIDI.getData1(), MIDI.getData2());
}
uint8_t i = 0;
/* Serial.println("Before:");
for (i = 0; i < 128; i++)
{
Serial.print(audio_buffer[i]);
Serial.print(",");
}
Serial.println();*/
dexed->GetSamples(RATE, audio_buffer);
/* uint8_t i = 0;
for (i = 0; i < 128; i++)
{
if ((i % 16) == 0)
@ -105,14 +109,10 @@ void loop()
Serial.print(audio_buffer[i]);
Serial.print(" ");
}
Serial.println();
Serial.println();*/
#ifdef TEENSY
// play the current buffer
while (!queue1.available())
Serial.println("Block");
queue1.playBuffer();
#endif
delay(500);
}

@ -17,10 +17,10 @@
#ifndef __CONTROLLERS_H
#define __CONTROLLERS_H
#include <Arduino.h>
#include "synth.h"
#include <stdio.h>
#include <string.h>
#include "trace.h"
#ifdef _WIN32
#define snprintf _snprintf
@ -48,17 +48,14 @@ struct FmMod {
void setRange(uint8_t r) {
range = r < 0 && r > 127 ? 0 : r;
TRACE("range=%d",range);
}
void setTarget(uint8_t assign) {
TRACE("Target: %d", assign);
assign=assign < 0 && assign > 7 ? 0 : assign;
pitch=assign&1; // AMP
amp=assign&2; // PITCH
eg=assign&4; // EG
TRACE("pitch[%d] amp[%d] eg[%d]", pitch,amp,eg);
}
};
@ -66,8 +63,6 @@ class Controllers {
void applyMod(int cc, FmMod &mod) {
float range = 0.01 * mod.range;
uint8_t total = (float)cc * range;
TRACE("amp[%d]|pitch[%d]|eg[%d]",mod.amp,mod.pitch,mod.eg);
TRACE("range=%f mod.range=%d total=%d cc=%d",range,mod.range,total,cc);
if(mod.amp)
amp_mod = max(amp_mod, total);

@ -18,6 +18,7 @@
*/
#include "synth.h"
#include "dexed.h"
#include "EngineMkI.h"
#include "EngineOpl.h"
@ -26,12 +27,11 @@
#include "sin.h"
#include "freqlut.h"
#include "controllers.h"
//#include "PluginFx.h"
#include "trace.h"
#include <unistd.h>
#include <limits.h>
#include <math.h>
Dexed::Dexed(uint16_t num_samples)
Dexed::Dexed(uint8_t rate)
{
uint8_t i;
@ -39,18 +39,31 @@ Dexed::Dexed(uint16_t num_samples)
Tanh::init();
Sin::init();
_rate = num_samples;
Freqlut::init(_rate);
Lfo::init(_rate);
PitchEnv::init(_rate);
Env::init_sr(_rate);
//fx.init(_rate);
Freqlut::init(rate);
Lfo::init(rate);
PitchEnv::init(rate);
Env::init_sr(rate);
engineMkI = new EngineMkI;
engineOpl = new EngineOpl;
engineMsfa = new FmCore;
/*
if(!(engineMkI=new (std::nothrow) EngineMkI))
TRACE("Cannot not create engine EngineMkI");
if(!(engineOpl=new (std::nothrow) EngineOpl))
{
delete(engineMkI);
TRACE("Cannot not create engine EngineOpl");
}
if(!(engineMsfa=new (std::nothrow) FmCore))
{
delete(engineMkI);
delete(engineOpl);
TRACE("Cannot create engine FmCore");
}
*/
for (i = 0; i < MAX_ACTIVE_NOTES; i++) {
voices[i].dx7_note = new Dx7Note;
voices[i].keydown = false;
@ -58,6 +71,11 @@ Dexed::Dexed(uint16_t num_samples)
voices[i].live = false;
}
/* for(i=0;i<sizeof(data);++i)
{
data_float[i]=static_cast<float>(data[i]);
}*/
max_notes = 16;
currentNote = 0;
controllers.values_[kControllerPitch] = 0x2000;
@ -69,6 +87,11 @@ Dexed::Dexed(uint16_t num_samples)
controllers.aftertouch_cc = 0;
controllers.masterTune = 0;
controllers.opSwitch = 0x3f; // enable all operators
//controllers.opSwitch=0x00;
bufsize_ = 256;
outbuf_ = new float[bufsize_];
lfo.reset(data + 137);
@ -76,32 +99,24 @@ Dexed::Dexed(uint16_t num_samples)
sustain = false;
extra_buf_size_ = 0;
memset(&voiceStatus, 0, sizeof(VoiceStatus));
setEngineType(DEXED_ENGINE_MARKI);
setEngineType(DEXED_ENGINE_MODERN);
}
Dexed::~Dexed()
{
delete [] outbuf_;
currentNote = -1;
for (uint8_t note = 0; note < MAX_ACTIVE_NOTES; ++note)
{
if ( voices[note].dx7_note != NULL )
{
delete voices[note].dx7_note;
voices[note].dx7_note = NULL;
}
voices[note].keydown = false;
voices[note].sustained = false;
voices[note].live = false;
}
if (engineMsfa)
delete(engineMkI);
if (engineOpl)
delete(engineMkI);
if (engineMkI)
delete(engineMsfa);
delete(engineOpl);
delete(engineMkI);
}
@ -114,12 +129,12 @@ void Dexed::activate(void)
void Dexed::deactivate(void)
{
; // Nothing to do - please reboot ;-)
; // nothing to do...
}
void Dexed::GetSamples(uint32_t n_samples, int16_t* buffer)
void Dexed::GetSamples(uint16_t n_samples, int16_t* buffer)
{
uint32_t i;
uint16_t i;
if (refreshVoice) {
for (i = 0; i < max_notes; i++) {
@ -130,42 +145,65 @@ void Dexed::GetSamples(uint32_t n_samples, int16_t* buffer)
refreshVoice = false;
}
for (i = 0; i < n_samples; i += _N_) {
// flush first events
for (i = 0; i < n_samples && i < extra_buf_size_; i++) {
buffer[i] = extra_buf_[i];
}
// remaining buffer is still to be processed
if (extra_buf_size_ > n_samples) {
for (uint16_t j = 0; j < extra_buf_size_ - n_samples; j++) {
extra_buf_[j] = extra_buf_[j + n_samples];
}
extra_buf_size_ -= n_samples;
}
else
{
for (; i < n_samples; i += _N_) {
AlignedBuf<int32_t, _N_> audiobuf;
float sumbuf[_N_];
int16_t sumbuf[_N_];
for (uint32_t j = 0; j < _N_; ++j) {
for (uint8_t j = 0; j < _N_; ++j) {
audiobuf.get()[j] = 0;
sumbuf[j] = 0.0;
//sumbuf[j] = 0.0;
sumbuf[j] = 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) {
for (uint8_t j = 0; j < _N_; ++j) {
int32_t val = audiobuf.get()[j];
val = val >> 4;
//val = val >> 4;
int32_t clip_val = val < -(1 << 24) ? 0x8000 : val >= (1 << 24) ? 0x7fff : val >> 9;
float f = static_cast<float>(clip_val >> 1) / 0x8000;
/* float f = static_cast<float>(clip_val >> 1) / static_cast<float>(0x8000);
if (f > 1) f = 1;
if (f < -1) f = -1;
sumbuf[j] += f;
sumbuf[j] += f;*/
sumbuf[j] += clip_val;
audiobuf.get()[j] = 0;
}
}
}
for (uint32_t j = 0; j < _N_; ++j) {
buffer[j + (i * _N_)] = sumbuf[j];
uint16_t jmax = n_samples - i;
for (uint8_t j = 0; j < _N_; ++j) {
if (j < jmax)
{
//buffer[i + j] = static_cast<int16_t>(sumbuf[j]*0x8000);
buffer[i + j] = sumbuf[j];
Serial.println(buffer[i + j], DEC);
}
else
extra_buf_[j - jmax] = sumbuf[j];
}
}
extra_buf_size_ = i - n_samples;
}
// mark unused voice as not live
if (++_k_rate_counter % 32 && !monoMode)
{
uint8_t op_carrier = controllers.core->get_carrier_operators(data[134]); // look for carriers
@ -188,6 +226,8 @@ void Dexed::GetSamples(uint32_t n_samples, int16_t* buffer)
// this voice is a carrier!
op_carrier_num++;
//TRACE("Voice[%2d] OP [%d] amp=%ld,amp_step=%d,pitch_step=%d",i,op,voiceStatus.amp[op],voiceStatus.ampStep[op],voiceStatus.pitchStep);
if (voiceStatus.amp[op] <= 1069 && voiceStatus.ampStep[op] == 4) // this voice produces no audio output
op_amp++;
}
@ -198,8 +238,10 @@ void Dexed::GetSamples(uint32_t n_samples, int16_t* buffer)
voices[i].live = false;
voices[i].sustained = false;
voices[i].keydown = false;
TRACE("Shutted down Voice[%2d]", i);
}
}
// TRACE("Voice[%2d] live=%d keydown=%d",i,voices[i].live,voices[i].keydown);
}
}
}
@ -208,34 +250,38 @@ bool Dexed::ProcessMidiMessage(uint8_t cmd, uint8_t data1, uint8_t data2)
{
switch (cmd & 0xf0) {
case 0x80 :
// TRACE("MIDI keyup event: %d",buf[1]);
//TRACE("MIDI keyup event: %d", data1);
keyup(data1);
return (false);
break;
case 0x90 :
//TRACE("MIDI keydown event: %d %d", data1, data2);
keydown(data1, data2);
return (false);
break;
case 0xb0 : {
switch (data1) {
uint8_t ctrl = data1;
uint8_t value = data2;
switch (ctrl) {
case 1:
// TRACE("MIDI modwheel event: %d %d",ctrl,value);
controllers.modwheel_cc = data2;
//TRACE("MIDI modwheel event: %d %d", ctrl, value);
controllers.modwheel_cc = value;
controllers.refresh();
break;
case 2:
// TRACE("MIDI breath event: %d %d",ctrl,value);
controllers.breath_cc = data2;
//TRACE("MIDI breath event: %d %d", ctrl, value);
controllers.breath_cc = value;
controllers.refresh();
break;
case 4:
// TRACE("MIDI footsw event: %d %d",ctrl,value);
controllers.foot_cc = data2;
//TRACE("MIDI footsw event: %d %d", ctrl, value);
controllers.foot_cc = value;
controllers.refresh();
break;
case 64:
// TRACE("MIDI sustain event: %d %d",ctrl,value);
sustain = data2 > 63;
//TRACE("MIDI sustain event: %d %d", ctrl, value);
sustain = value > 63;
if (!sustain) {
for (uint8_t note = 0; note < max_notes; note++) {
if (voices[note].sustained && !voices[note].keydown) {
@ -246,12 +292,12 @@ bool Dexed::ProcessMidiMessage(uint8_t cmd, uint8_t data1, uint8_t data2)
}
break;
case 120:
// TRACE("MIDI all-sound-off: %d %d",ctrl,value);
//TRACE("MIDI all-sound-off: %d %d", ctrl, value);
panic();
return (true);
break;
case 123:
// TRACE("MIDI all-notes-off: %d %d",ctrl,value);
//TRACE("MIDI all-notes-off: %d %d", ctrl, value);
notes_off();
return (true);
break;
@ -265,22 +311,28 @@ bool Dexed::ProcessMidiMessage(uint8_t cmd, uint8_t data1, uint8_t data2)
// channel aftertouch
case 0xd0 :
//TRACE("MIDI aftertouch 0xd0 event: %d %d", data1);
controllers.aftertouch_cc = data1;
controllers.refresh();
break;
// pitchbend
case 0xe0 :
//TRACE("MIDI pitchbend 0xe0 event: %d %d", data1, data2);
controllers.values_[kControllerPitch] = data1 | (data2 << 7);
break;
default:
//TRACE("MIDI event unknown: cmd=%d, val1=%d, val2=%d", cmd, data1, data2);
break;
}
TRACE("Bye");
return (false);
}
void Dexed::keydown(uint8_t pitch, uint8_t velo) {
TRACE("Hi");
TRACE("pitch=%d, velo=%d\n", pitch, velo);
if ( velo == 0 ) {
keyup(pitch);
return;
@ -331,9 +383,13 @@ void Dexed::keydown(uint8_t pitch, uint8_t velo) {
}
voices[note].live = true;
TRACE("Bye");
}
void Dexed::keyup(uint8_t pitch) {
TRACE("Hi");
TRACE("pitch=%d\n", pitch);
pitch += data[144] - 24;
uint8_t note;
@ -346,6 +402,7 @@ void Dexed::keyup(uint8_t pitch) {
// note not found ?
if ( note >= max_notes ) {
TRACE("note-off not found???");
return;
}
@ -359,7 +416,7 @@ void Dexed::keyup(uint8_t pitch) {
}
}
if ( highNote != -1 ) {
if ( highNote != -1 && voices[note].live ) {
voices[note].live = false;
voices[target].live = true;
voices[target].dx7_note->transferState(*voices[note].dx7_note);
@ -371,59 +428,81 @@ void Dexed::keyup(uint8_t pitch) {
} else {
voices[note].dx7_note->keyup();
}
TRACE("Bye");
}
/*void Dexed::onParam(uint8_t param_num,float param_val)
/*
void Dexed::onParam(uint8_t param_num, float param_val)
{
int32_t tune;
if(param_val!=data_float[param_num])
if (param_val != data_float[param_num])
{
TRACE("Parameter %d change from %f to %f", param_num, data_float[param_num], param_val);
#ifdef DEBUG
uint8_t tmp = data[param_num];
#endif
_param_change_counter++;
if(param_num==144 || param_num==134 || param_num==172)
if (param_num == 144 || param_num == 134 || param_num == 172)
panic();
refreshVoice=true;
data[param_num]=static_cast<uint8_t>(param_val);
data_float[param_num]=param_val;
refreshVoice = true;
data[param_num] = static_cast<uint8_t>(param_val);
data_float[param_num] = param_val;
switch(param_num)
switch (param_num)
{
case 155:
controllers.values_[kControllerPitchRange]=data[param_num];
controllers.values_[kControllerPitchRange] = data[param_num];
break;
case 156:
controllers.values_[kControllerPitchStep]=data[param_num];
controllers.values_[kControllerPitchStep] = data[param_num];
break;
case 157:
// TRACE("wheel.setRange(%d)",data[param_num]);
controllers.wheel.setRange(data[param_num]);
controllers.wheel.setTarget(data[param_num + 1]);
controllers.refresh();
break;
case 158:
controllers.wheel.setRange(data[param_num - 1]);
controllers.wheel.setTarget(data[param_num]);
controllers.refresh();
break;
case 159:
controllers.foot.setRange(data[param_num]);
controllers.foot.setTarget(data[param_num + 1]);
controllers.refresh();
break;
case 160:
controllers.foot.setRange(data[param_num - 1]);
controllers.foot.setTarget(data[param_num]);
controllers.refresh();
break;
case 161:
controllers.breath.setRange(data[param_num]);
controllers.breath.setTarget(data[param_num + 1]);
controllers.refresh();
break;
case 162:
controllers.breath.setRange(data[param_num - 1]);
controllers.breath.setTarget(data[param_num]);
controllers.refresh();
break;
case 163:
controllers.at.setRange(data[param_num]);
controllers.at.setTarget(data[param_num + 1]);
controllers.refresh();
break;
case 164:
controllers.at.setRange(data[param_num - 1]);
controllers.at.setTarget(data[param_num]);
controllers.refresh();
break;
case 165:
tune=param_val*0x4000;
controllers.masterTune=(tune<<11)*(1.0/12);
tune = param_val * 0x4000;
controllers.masterTune = (tune << 11) * (1.0 / 12);
break;
case 166:
case 167:
@ -431,12 +510,14 @@ void Dexed::keyup(uint8_t pitch) {
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];
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];
max_notes = data[param_num];
break;
}
TRACE("Done: Parameter %d changed from %d to %d", param_num, tmp, data[param_num]);
}
}
*/
@ -446,17 +527,22 @@ uint8_t Dexed::getEngineType() {
}
void Dexed::setEngineType(uint8_t tp) {
TRACE("settings engine %d", tp);
if (engineType == tp && controllers.core != NULL)
return;
switch (tp) {
case DEXED_ENGINE_MARKI:
TRACE("DEXED_ENGINE_MARKI:%d", DEXED_ENGINE_MARKI);
controllers.core = engineMkI;
break;
case DEXED_ENGINE_OPL:
TRACE("DEXED_ENGINE_OPL:%d", DEXED_ENGINE_OPL);
controllers.core = engineOpl;
break;
default:
TRACE("DEXED_ENGINE_MODERN:%d", DEXED_ENGINE_MODERN);
controllers.core = engineMsfa;
tp = DEXED_ENGINE_MODERN;
break;
@ -499,9 +585,10 @@ void Dexed::notes_off(void) {
}
}
/*
void Dexed::set_params(void)
{
void Dexed::set_params(void)
{
/* //TRACE("Hi");
_param_change_counter=0;
bool polymono=bool(*p(p_polymono));
@ -716,6 +803,9 @@ void Dexed::notes_off(void) {
panic();
controllers.refresh();
}
}
*/
//TRACE("Bye");
*/
;
}

@ -21,6 +21,7 @@
#ifndef DEXED_H_INCLUDED
#define DEXED_H_INCLUDED
#include <Arduino.h>
#include "controllers.h"
#include "dx7note.h"
#include "lfo.h"
@ -54,7 +55,7 @@ enum DexedEngineResolution {
class Dexed
{
public:
Dexed(uint16_t rate);
Dexed(uint8_t rate);
~Dexed();
void activate(void);
void deactivate(void);
@ -63,7 +64,7 @@ class Dexed
bool isMonoMode(void);
void setMonoMode(bool mode);
void set_params(void);
void GetSamples(uint32_t n_samples, int16_t* buffer);
void GetSamples(uint16_t n_samples, int16_t* buffer);
bool ProcessMidiMessage(uint8_t cmd, uint8_t data1, uint8_t data2);
Controllers controllers;
@ -91,6 +92,8 @@ class Dexed
EngineOpl* engineOpl;
float* outbuf_;
uint32_t bufsize_;
float extra_buf_[_N_];
uint32_t extra_buf_size_;
private:
uint16_t _rate;

@ -24,6 +24,7 @@
// It will continue to evolve a bit, as note-stealing logic, scaling,
// and real-time control of parameters live here.
#include <Arduino.h>
#include "env.h"
#include "pitchenv.h"
#include "fm_core.h"

@ -17,6 +17,7 @@
#ifndef __FM_CORE_H
#define __FM_CORE_H
#include <Arduino.h>
#include "aligned_buf.h"
#include "fm_op_kernel.h"
#include "synth.h"

Loading…
Cancel
Save