You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
MicroDexed/dexed.cpp

525 lines
13 KiB

6 years ago
/**
Copyright (c) 2016-2018 Holger Wirtz <dcoredump@googlemail.com>
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
*/
6 years ago
6 years ago
#include "synth.h"
6 years ago
#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"
6 years ago
#include "trace.h"
6 years ago
#include <unistd.h>
#include <limits.h>
Dexed::Dexed(int rate)
6 years ago
{
uint8_t i;
Exp2::init();
Tanh::init();
Sin::init();
6 years ago
Freqlut::init(rate);
Lfo::init(rate);
PitchEnv::init(rate);
Env::init_sr(rate);
6 years ago
engineMkI = new EngineMkI;
engineOpl = new EngineOpl;
engineMsfa = new FmCore;
6 years ago
6 years ago
/*
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++) {
6 years ago
voices[i].dx7_note = new Dx7Note;
voices[i].keydown = false;
voices[i].sustained = false;
voices[i].live = false;
}
max_notes = 16;
6 years ago
currentNote = 0;
controllers.values_[kControllerPitch] = 0x2000;
controllers.values_[kControllerPitchRange] = 0;
controllers.values_[kControllerPitchStep] = 0;
controllers.modwheel_cc = 0;
controllers.foot_cc = 0;
controllers.breath_cc = 0;
controllers.aftertouch_cc = 0;
controllers.masterTune = 0;
controllers.opSwitch = 0x3f; // enable all operators
6 years ago
//controllers.opSwitch=0x00;
lfo.reset(data + 137);
6 years ago
setMonoMode(false);
sustain = false;
6 years ago
setEngineType(DEXED_ENGINE_MODERN);
6 years ago
}
Dexed::~Dexed()
{
currentNote = -1;
for (uint8_t note = 0; note < MAX_ACTIVE_NOTES; note++)
6 years ago
delete voices[note].dx7_note;
6 years ago
6 years ago
delete(engineMsfa);
delete(engineOpl);
delete(engineMkI);
6 years ago
}
void Dexed::activate(void)
{
panic();
controllers.values_[kControllerPitchRange] = data[155];
controllers.values_[kControllerPitchStep] = data[156];
controllers.refresh();
6 years ago
}
void Dexed::deactivate(void)
{
panic();
6 years ago
}
6 years ago
void Dexed::GetSamples(uint16_t n_samples, int16_t* buffer)
6 years ago
{
6 years ago
uint16_t i;
6 years ago
if (refreshVoice) {
for (i = 0; i < max_notes; i++) {
6 years ago
if ( voices[i].live )
voices[i].dx7_note->update(data, voices[i].midi_note, voices[i].velocity);
}
lfo.reset(data + 137);
6 years ago
refreshVoice = false;
}
for (i = 0; i < n_samples; i += _N_) {
AlignedBuf<int32_t, _N_> audiobuf;
float sumbuf[_N_];
for (uint8_t j = 0; j < _N_; ++j) {
audiobuf.get()[j] = 0;
sumbuf[j] = 0.0;
6 years ago
}
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 (uint8_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<float>(clip_val >> 1) / 0x8000;
if (f > 1) f = 1;
if (f < -1) f = -1;
sumbuf[j] += f;
audiobuf.get()[j] = 0;
6 years ago
}
}
}
6 years ago
for (uint8_t j = 0; j < _N_; ++j) {
buffer[i + j] = static_cast<int16_t>(sumbuf[j] * 0x8000);
6 years ago
}
}
}
6 years ago
bool Dexed::ProcessMidiMessage(uint8_t type, uint8_t data1, uint8_t data2)
{
6 years ago
switch (type & 0xf0) {
case 0x80 :
6 years ago
//TRACE("MIDI keyup event: %d", data1);
keyup(data1);
return (false);
break;
case 0x90 :
6 years ago
//TRACE("MIDI keydown event: %d %d", data1, data2);
keydown(data1, data2);
return (false);
break;
case 0xb0 : {
6 years ago
uint8_t ctrl = data1;
uint8_t value = data2;
switch (ctrl) {
case 1:
6 years ago
//TRACE("MIDI modwheel event: %d %d", ctrl, value);
controllers.modwheel_cc = value;
controllers.refresh();
6 years ago
break;
case 2:
6 years ago
//TRACE("MIDI breath event: %d %d", ctrl, value);
controllers.breath_cc = value;
controllers.refresh();
6 years ago
break;
case 4:
6 years ago
//TRACE("MIDI footsw event: %d %d", ctrl, value);
controllers.foot_cc = value;
controllers.refresh();
break;
case 64:
6 years ago
//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) {
voices[note].dx7_note->keyup();
voices[note].sustained = false;
}
}
6 years ago
}
break;
case 120:
6 years ago
//TRACE("MIDI all-sound-off: %d %d", ctrl, value);
panic();
return (true);
6 years ago
break;
case 123:
6 years ago
//TRACE("MIDI all-notes-off: %d %d", ctrl, value);
notes_off();
return (true);
6 years ago
break;
}
break;
}
6 years ago
// case 0xc0 :
// setCurrentProgram(data1);
// break;
// channel aftertouch
case 0xd0 :
6 years ago
//TRACE("MIDI aftertouch 0xd0 event: %d %d", data1);
controllers.aftertouch_cc = data1;
controllers.refresh();
break;
// pitchbend
case 0xe0 :
6 years ago
//TRACE("MIDI pitchbend 0xe0 event: %d %d", data1, data2);
controllers.values_[kControllerPitch] = data1 | (data2 << 7);
break;
default:
6 years ago
//TRACE("MIDI event unknown: cmd=%d, val1=%d, val2=%d", cmd, data1, data2);
break;
}
6 years ago
6 years ago
TRACE("Bye");
return (false);
6 years ago
}
void Dexed::keydown(uint8_t pitch, uint8_t velo) {
6 years ago
TRACE("Hi");
TRACE("pitch=%d, velo=%d\n", pitch, 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; 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, (int)pitch, (int)velo);
if ( data[136] )
voices[note].dx7_note->oscSync();
break;
6 years ago
}
else
keydown_counter++;
6 years ago
note = (note + 1) % max_notes;
}
6 years ago
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;
6 years ago
}
if ( voices[i].midi_note < pitch ) {
voices[i].live = false;
voices[note].dx7_note->transferState(*voices[i].dx7_note);
break;
}
return;
}
6 years ago
}
}
voices[note].live = true;
6 years ago
TRACE("Bye");
6 years ago
}
void Dexed::keyup(uint8_t pitch) {
6 years ago
TRACE("Hi");
TRACE("pitch=%d\n", pitch);
pitch += data[144] - 24;
6 years ago
uint8_t note;
for (note = 0; note < max_notes; ++note) {
if ( voices[note].midi_note == pitch && voices[note].keydown ) {
voices[note].keydown = false;
break;
6 years ago
}
}
// note not found ?
if ( note >= max_notes ) {
6 years ago
TRACE("note-off not found???");
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;
}
6 years ago
}
6 years ago
if ( highNote != -1 && voices[note].live ) {
voices[note].live = false;
voices[target].live = true;
voices[target].dx7_note->transferState(*voices[note].dx7_note);
6 years ago
}
}
if ( sustain ) {
voices[note].sustained = true;
} else {
voices[note].dx7_note->keyup();
}
6 years ago
TRACE("Bye");
6 years ago
}
void Dexed::doRefreshVoice(void)
{
refreshVoice = true;
}
void Dexed::setOPs(uint8_t ops)
{
controllers.opSwitch = ops;
}
6 years ago
/*
void Dexed::onParam(uint8_t param_num, float param_val)
{
6 years ago
int32_t tune;
6 years ago
if (param_val != data_float[param_num])
6 years ago
{
6 years ago
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
6 years ago
_param_change_counter++;
6 years ago
if (param_num == 144 || param_num == 134 || param_num == 172)
6 years ago
panic();
6 years ago
refreshVoice = true;
data[param_num] = static_cast<uint8_t>(param_val);
data_float[param_num] = param_val;
6 years ago
6 years ago
switch (param_num)
6 years ago
{
case 155:
6 years ago
controllers.values_[kControllerPitchRange] = data[param_num];
6 years ago
break;
case 156:
6 years ago
controllers.values_[kControllerPitchStep] = data[param_num];
6 years ago
break;
case 157:
controllers.wheel.setRange(data[param_num]);
6 years ago
controllers.wheel.setTarget(data[param_num + 1]);
controllers.refresh();
6 years ago
break;
case 158:
6 years ago
controllers.wheel.setRange(data[param_num - 1]);
6 years ago
controllers.wheel.setTarget(data[param_num]);
6 years ago
controllers.refresh();
6 years ago
break;
case 159:
controllers.foot.setRange(data[param_num]);
6 years ago
controllers.foot.setTarget(data[param_num + 1]);
controllers.refresh();
6 years ago
break;
case 160:
6 years ago
controllers.foot.setRange(data[param_num - 1]);
6 years ago
controllers.foot.setTarget(data[param_num]);
6 years ago
controllers.refresh();
6 years ago
break;
case 161:
controllers.breath.setRange(data[param_num]);
6 years ago
controllers.breath.setTarget(data[param_num + 1]);
controllers.refresh();
6 years ago
break;
case 162:
6 years ago
controllers.breath.setRange(data[param_num - 1]);
6 years ago
controllers.breath.setTarget(data[param_num]);
6 years ago
controllers.refresh();
6 years ago
break;
case 163:
controllers.at.setRange(data[param_num]);
6 years ago
controllers.at.setTarget(data[param_num + 1]);
controllers.refresh();
6 years ago
break;
case 164:
6 years ago
controllers.at.setRange(data[param_num - 1]);
6 years ago
controllers.at.setTarget(data[param_num]);
6 years ago
controllers.refresh();
6 years ago
break;
case 165:
6 years ago
tune = param_val * 0x4000;
controllers.masterTune = (tune << 11) * (1.0 / 12);
6 years ago
break;
case 166:
case 167:
case 168:
case 169:
case 170:
case 171:
6 years ago
controllers.opSwitch = (data[166] << 5) | (data[167] << 4) | (data[168] << 3) | (data[169] << 2) | (data[170] << 1) | data[171];
6 years ago
break;
case 172:
6 years ago
max_notes = data[param_num];
break;
6 years ago
}
6 years ago
TRACE("Done: Parameter %d changed from %d to %d", param_num, tmp, data[param_num]);
6 years ago
}
}
6 years ago
*/
uint8_t Dexed::getEngineType() {
return engineType;
6 years ago
}
void Dexed::setEngineType(uint8_t tp) {
6 years ago
TRACE("settings engine %d", tp);
if (engineType == tp && controllers.core != NULL)
return;
switch (tp) {
case DEXED_ENGINE_MARKI:
6 years ago
TRACE("DEXED_ENGINE_MARKI:%d", DEXED_ENGINE_MARKI);
controllers.core = engineMkI;
break;
case DEXED_ENGINE_OPL:
6 years ago
TRACE("DEXED_ENGINE_OPL:%d", DEXED_ENGINE_OPL);
controllers.core = engineOpl;
break;
default:
6 years ago
TRACE("DEXED_ENGINE_MODERN:%d", DEXED_ENGINE_MODERN);
controllers.core = engineMsfa;
tp = DEXED_ENGINE_MODERN;
break;
}
engineType = tp;
panic();
controllers.refresh();
6 years ago
}
bool Dexed::isMonoMode(void) {
return monoMode;
6 years ago
}
void Dexed::setMonoMode(bool mode) {
if (monoMode == mode)
return;
6 years ago
monoMode = mode;
6 years ago
}
void Dexed::panic(void) {
for (uint8_t i = 0; i < MAX_ACTIVE_NOTES; i++)
6 years ago
{
if (voices[i].live == true) {
6 years ago
voices[i].keydown = false;
voices[i].live = false;
voices[i].sustained = false;
if ( voices[i].dx7_note != NULL ) {
voices[i].dx7_note->oscSync();
}
}
}
}
void Dexed::notes_off(void) {
for (uint8_t i = 0; i < MAX_ACTIVE_NOTES; i++) {
if (voices[i].live == true && voices[i].keydown == true) {
voices[i].keydown = false;
6 years ago
}
}
}
void Dexed::setMaxNotes(uint8_t n) {
if (n <= MAX_ACTIVE_NOTES)
{
notes_off();
max_notes = n;
panic();
controllers.refresh();
}
}