Cleanup and fixes.

pull/4/head
Holger Wirtz 7 years ago
parent 548bbe3a02
commit 4fc98cde0b
  1. 37
      MicroDexed.ino
  2. 938
      dexed.cpp.offline
  3. 32
      dexed.h
  4. 931
      dexed.orig
  5. 369
      dexed_ttl.h.offline
  6. 3
      dx7note.cpp
  7. 216
      not_used/PluginFx.cpp
  8. 72
      not_used/PluginFx.h

@ -11,6 +11,8 @@
#define AUDIO_BUFFER_SIZE 128 #define AUDIO_BUFFER_SIZE 128
#define SAMPLEAUDIO_BUFFER_SIZE 44100 #define SAMPLEAUDIO_BUFFER_SIZE 44100
#define MIDI_QUEUE_LOCK_TIMEOUT_MS 5
#define TEST_MIDI 1 #define TEST_MIDI 1
#define TEST_NOTE1 60 #define TEST_NOTE1 60
#define TEST_NOTE2 68 #define TEST_NOTE2 68
@ -77,8 +79,13 @@ void setup()
dexed->activate(); dexed->activate();
#ifdef TEST_MIDI #ifdef TEST_MIDI
dexed->ProcessMidiMessage(0x90, TEST_NOTE1, 100); midi_queue_t m;
dexed->ProcessMidiMessage(0x90, TEST_NOTE2, 60); m.cmd = 0x90;
m.data1 = TEST_NOTE1;
m.data2 = 100;
midi_queue.enqueue(m);
m.data1 = TEST_NOTE2;
midi_queue.enqueue(m);
#endif #endif
threads.addThread(audio_thread, 1); threads.addThread(audio_thread, 1);
@ -103,9 +110,11 @@ void loop()
m.data1 = MIDI.getData1(); m.data1 = MIDI.getData1();
m.data2 = MIDI.getData2(); m.data2 = MIDI.getData2();
while (!midi_queue_lock.try_lock()); if (midi_queue_lock.lock(MIDI_QUEUE_LOCK_TIMEOUT_MS))
midi_queue.enqueue(m); {
midi_queue_lock.unlock(); midi_queue.enqueue(m);
midi_queue_lock.unlock();
}
} }
} }
@ -120,15 +129,19 @@ void audio_thread(void)
audio_buffer = queue1.getBuffer(); audio_buffer = queue1.getBuffer();
if (audio_buffer == NULL) if (audio_buffer == NULL)
{ {
Serial.println("audio_buffer allocation problems!"); Serial.println(F("audio_buffer allocation problems!"));
return; continue;
} }
while (!midi_queue.isEmpty ()) while (!midi_queue.isEmpty())
{ {
while (!midi_queue_lock.try_lock()); if (midi_queue_lock.lock(MIDI_QUEUE_LOCK_TIMEOUT_MS))
midi_queue_t m = midi_queue.dequeue(); {
dexed->ProcessMidiMessage(m.cmd, m.data1, m.data2); midi_queue_t m = midi_queue.dequeue();
midi_queue_lock.unlock(); dexed->ProcessMidiMessage(m.cmd, m.data1, m.data2);
midi_queue_lock.unlock();
}
else
break;
} }
dexed->GetSamples(AUDIO_BUFFER_SIZE, audio_buffer); dexed->GetSamples(AUDIO_BUFFER_SIZE, audio_buffer);

@ -1,938 +0,0 @@
/**
*
* Copyright (c) 2016-2017 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
*
*/
#include <lvtk/synth.hpp>
#include "dexed.h"
#include "dexed_ttl.h"
#include "EngineMkI.h"
#include "EngineOpl.h"
#include "msfa/fm_core.h"
#include "msfa/exp2.h"
#include "msfa/sin.h"
#include "msfa/freqlut.h"
#include "msfa/controllers.h"
#include "PluginFx.h"
#include <unistd.h>
#include <limits.h>
Dexed::Dexed(double rate) : lvtk::Synth<DexedVoice, Dexed>(p_n_ports, p_midi_in)
{
uint8_t i;
TRACE("--------------------------------------------------------------------------------");
TRACE("Hi");
Exp2::init();
Tanh::init();
Sin::init();
Freqlut::init(rate);
Lfo::init(rate);
PitchEnv::init(rate);
Env::init_sr(rate);
fx.init(rate);
if(!(engineMkI=new EngineMkI))
{
TRACE("Cannot not create engine EngineMkI");
exit(400);
}
if(!(engineOpl=new EngineOpl))
{
if(engineMkI)
delete(engineMkI);
TRACE("Cannot not create engine EngineOpl");
exit(401);
}
if(!(engineMsfa=new FmCore))
{
if(engineMkI)
delete(engineMkI);
if(engineOpl)
delete(engineOpl);
TRACE("Cannot create engine FmCore");
exit(402);
}
for(i=0; i<MAX_ACTIVE_NOTES; i++) {
if(!(voices[i].dx7_note = new Dx7Note))
{
TRACE("Cannot create DX7Note [%d]",i);
exit(403);
}
voices[i].keydown = false;
voices[i].sustained = false;
voices[i].live = false;
}
for(i=0;i<sizeof(data);++i)
{
data_float[i]=static_cast<float>(data[i]);
TRACE("%d->%f",i,data_float[i]);
}
max_notes=16;
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
//controllers.opSwitch=0x00;
bufsize_=256;
if(!(outbuf_=new float[bufsize_]))
{
TRACE("Cannot create outbuf_ buffer");
exit(404);
}
lfo.reset(data+137);
setMonoMode(false);
sustain = false;
extra_buf_size_ = 0;
memset(&voiceStatus, 0, sizeof(VoiceStatus));
setEngineType(DEXED_ENGINE_MODERN);
//add_voices(new DexedVoice(rate));
add_audio_outputs(p_audio_out);
TRACE("Bye");
}
Dexed::~Dexed()
{
TRACE("Hi");
if(outbuf_!=NULL)
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(engineMkI);
TRACE("Bye");
TRACE("--------------------------------------------------------------------------------");
}
void Dexed::activate(void)
{
TRACE("Hi");
Plugin::activate();
panic();
controllers.values_[kControllerPitchRange] = data[155];
controllers.values_[kControllerPitchStep] = data[156];
TRACE("Bye");
}
void Dexed::deactivate(void)
{
TRACE("Hi");
Plugin::deactivate();
TRACE("Bye");
}
void Dexed::set_params(void)
{
//TRACE("Hi");
_param_change_counter=0;
bool polymono=bool(*p(p_polymono));
uint8_t engine=uint8_t(*p(p_engine));
float f_gain=*p(p_output);
float f_cutoff=*p(p_cutoff);
float f_reso=*p(p_resonance);
// Dexed-Unisono
if(isMonoMode()!=polymono)
setMonoMode(polymono);
// Dexed-Engine
if(controllers.core==NULL || getEngineType()!=engine)
{
setEngineType(engine);
refreshVoice=true;
}
// Dexed-Filter
if(fx.uiCutoff!=f_cutoff)
{
fx.uiCutoff=f_cutoff;
refreshVoice=true;
}
if(fx.uiReso!=f_reso)
{
fx.uiReso=f_reso;
refreshVoice=true;
}
if(fx.uiGain!=f_gain)
{
fx.uiGain=f_gain;
refreshVoice=true;
}
// OP6
onParam(0,*p(p_op6_eg_rate_1));
onParam(1,*p(p_op6_eg_rate_2));
onParam(2,*p(p_op6_eg_rate_3));
onParam(3,*p(p_op6_eg_rate_4));
onParam(4,*p(p_op6_eg_level_1));
onParam(5,*p(p_op6_eg_level_2));
onParam(6,*p(p_op6_eg_level_3));
onParam(7,*p(p_op6_eg_level_4));
onParam(8,*p(p_op6_kbd_lev_scl_brk_pt));
onParam(9,*p(p_op6_kbd_lev_scl_lft_depth));
onParam(10,*p(p_op6_kbd_lev_scl_rht_depth));
onParam(11,*p(p_op6_kbd_lev_scl_lft_curve));
onParam(12,*p(p_op6_kbd_lev_scl_rht_curve));
onParam(13,*p(p_op6_kbd_rate_scaling));
onParam(14,*p(p_op6_amp_mod_sensitivity));
onParam(15,*p(p_op6_key_vel_sensitivity));
onParam(16,*p(p_op6_operator_output_level));
onParam(17,*p(p_op6_osc_mode));
onParam(18,*p(p_op6_osc_freq_coarse));
onParam(19,*p(p_op6_osc_freq_fine));
onParam(20,*p(p_op6_osc_detune)+7);
// OP5
onParam(21,*p(p_op5_eg_rate_1));
onParam(22,*p(p_op5_eg_rate_2));
onParam(23,*p(p_op5_eg_rate_3));
onParam(24,*p(p_op5_eg_rate_4));
onParam(25,*p(p_op5_eg_level_1));
onParam(26,*p(p_op5_eg_level_2));
onParam(27,*p(p_op5_eg_level_3));
onParam(28,*p(p_op5_eg_level_4));
onParam(29,*p(p_op5_kbd_lev_scl_brk_pt));
onParam(30,*p(p_op5_kbd_lev_scl_lft_depth));
onParam(31,*p(p_op5_kbd_lev_scl_rht_depth));
onParam(32,*p(p_op5_kbd_lev_scl_lft_curve));
onParam(33,*p(p_op5_kbd_lev_scl_rht_curve));
onParam(34,*p(p_op5_kbd_rate_scaling));
onParam(35,*p(p_op5_amp_mod_sensitivity));
onParam(36,*p(p_op5_key_vel_sensitivity));
onParam(37,*p(p_op5_operator_output_level));
onParam(38,*p(p_op5_osc_mode));
onParam(39,*p(p_op5_osc_freq_coarse));
onParam(40,*p(p_op5_osc_freq_fine));
onParam(41,*p(p_op5_osc_detune)+7);
// OP4
onParam(42,*p(p_op4_eg_rate_1));
onParam(43,*p(p_op4_eg_rate_2));
onParam(44,*p(p_op4_eg_rate_3));
onParam(45,*p(p_op4_eg_rate_4));
onParam(46,*p(p_op4_eg_level_1));
onParam(47,*p(p_op4_eg_level_2));
onParam(48,*p(p_op4_eg_level_3));
onParam(49,*p(p_op4_eg_level_4));
onParam(50,*p(p_op4_kbd_lev_scl_brk_pt));
onParam(51,*p(p_op4_kbd_lev_scl_lft_depth));
onParam(52,*p(p_op4_kbd_lev_scl_rht_depth));
onParam(53,*p(p_op4_kbd_lev_scl_lft_curve));
onParam(54,*p(p_op4_kbd_lev_scl_rht_curve));
onParam(55,*p(p_op4_kbd_rate_scaling));
onParam(56,*p(p_op4_amp_mod_sensitivity));
onParam(57,*p(p_op4_key_vel_sensitivity));
onParam(58,*p(p_op4_operator_output_level));
onParam(59,*p(p_op4_osc_mode));
onParam(60,*p(p_op4_osc_freq_coarse));
onParam(61,*p(p_op4_osc_freq_fine));
onParam(62,*p(p_op4_osc_detune)+7);
// OP3
onParam(63,*p(p_op3_eg_rate_1));
onParam(64,*p(p_op3_eg_rate_2));
onParam(65,*p(p_op3_eg_rate_3));
onParam(66,*p(p_op3_eg_rate_4));
onParam(67,*p(p_op3_eg_level_1));
onParam(68,*p(p_op3_eg_level_2));
onParam(69,*p(p_op3_eg_level_3));
onParam(70,*p(p_op3_eg_level_4));
onParam(71,*p(p_op3_kbd_lev_scl_brk_pt));
onParam(72,*p(p_op3_kbd_lev_scl_lft_depth));
onParam(73,*p(p_op3_kbd_lev_scl_rht_depth));
onParam(74,*p(p_op3_kbd_lev_scl_lft_curve));
onParam(75,*p(p_op3_kbd_lev_scl_rht_curve));
onParam(76,*p(p_op3_kbd_rate_scaling));
onParam(77,*p(p_op3_amp_mod_sensitivity));
onParam(78,*p(p_op3_key_vel_sensitivity));
onParam(79,*p(p_op3_operator_output_level));
onParam(80,*p(p_op3_osc_mode));
onParam(81,*p(p_op3_osc_freq_coarse));
onParam(82,*p(p_op3_osc_freq_fine));
onParam(83,*p(p_op3_osc_detune)+7);
// OP2
onParam(84,*p(p_op2_eg_rate_1));
onParam(85,*p(p_op2_eg_rate_2));
onParam(86,*p(p_op2_eg_rate_3));
onParam(87,*p(p_op2_eg_rate_4));
onParam(88,*p(p_op2_eg_level_1));
onParam(89,*p(p_op2_eg_level_2));
onParam(90,*p(p_op2_eg_level_3));
onParam(91,*p(p_op2_eg_level_4));
onParam(92,*p(p_op2_kbd_lev_scl_brk_pt));
onParam(93,*p(p_op2_kbd_lev_scl_lft_depth));
onParam(94,*p(p_op2_kbd_lev_scl_rht_depth));
onParam(95,*p(p_op2_kbd_lev_scl_lft_curve));
onParam(96,*p(p_op2_kbd_lev_scl_rht_curve));
onParam(97,*p(p_op2_kbd_rate_scaling));
onParam(98,*p(p_op2_amp_mod_sensitivity));
onParam(99,*p(p_op2_key_vel_sensitivity));
onParam(100,*p(p_op2_operator_output_level));
onParam(101,*p(p_op2_osc_mode));
onParam(102,*p(p_op2_osc_freq_coarse));
onParam(103,*p(p_op2_osc_freq_fine));
onParam(104,*p(p_op2_osc_detune)+7);
// OP1
onParam(105,*p(p_op1_eg_rate_1));
onParam(106,*p(p_op1_eg_rate_2));
onParam(107,*p(p_op1_eg_rate_3));
onParam(108,*p(p_op1_eg_rate_4));
onParam(109,*p(p_op1_eg_level_1));
onParam(110,*p(p_op1_eg_level_2));
onParam(111,*p(p_op1_eg_level_3));
onParam(112,*p(p_op1_eg_level_4));
onParam(113,*p(p_op1_kbd_lev_scl_brk_pt));
onParam(114,*p(p_op1_kbd_lev_scl_lft_depth));
onParam(115,*p(p_op1_kbd_lev_scl_rht_depth));
onParam(116,*p(p_op1_kbd_lev_scl_lft_curve));
onParam(117,*p(p_op1_kbd_lev_scl_rht_curve));
onParam(118,*p(p_op1_kbd_rate_scaling));
onParam(119,*p(p_op1_amp_mod_sensitivity));
onParam(120,*p(p_op1_key_vel_sensitivity));
onParam(121,*p(p_op1_operator_output_level));
onParam(122,*p(p_op1_osc_mode));
onParam(123,*p(p_op1_osc_freq_coarse));
onParam(124,*p(p_op1_osc_freq_fine));
onParam(125,*p(p_op1_osc_detune)+7);
// Global for all OPs
onParam(126,*p(p_pitch_eg_rate_1));
onParam(127,*p(p_pitch_eg_rate_2));
onParam(128,*p(p_pitch_eg_rate_3));
onParam(129,*p(p_pitch_eg_rate_4));
onParam(130,*p(p_pitch_eg_level_1));
onParam(131,*p(p_pitch_eg_level_2));
onParam(132,*p(p_pitch_eg_level_3));
onParam(133,*p(p_pitch_eg_level_4));
onParam(134,*p(p_algorithm_num)-1);
onParam(135,*p(p_feedback));
onParam(136,*p(p_oscillator_sync));
onParam(137,*p(p_lfo_speed));
onParam(138,*p(p_lfo_delay));
onParam(139,*p(p_lfo_pitch_mod_depth));
onParam(140,*p(p_lfo_amp_mod_depth));
onParam(141,*p(p_lfo_sync));
onParam(142,*p(p_lfo_waveform));
onParam(143,*p(p_pitch_mod_sensitivity));
onParam(144,*p(p_transpose));
// 10 bytes (145-154) are the name of the patch
// Controllers (added at the end of the data[])
onParam(155,*p(p_pitch_bend_range));
onParam(156,*p(p_pitch_bend_step));
onParam(157,*p(p_mod_wheel_range));
onParam(158,*p(p_mod_wheel_assign));
onParam(159,*p(p_foot_ctrl_range));
onParam(160,*p(p_foot_ctrl_assign));
onParam(161,*p(p_breath_ctrl_range));
onParam(162,*p(p_breath_ctrl_assign));
onParam(163,*p(p_aftertouch_range));
onParam(164,*p(p_aftertouch_assign));
onParam(165,*p(p_master_tune));
onParam(166,*p(p_op1_enable));
onParam(167,*p(p_op2_enable));
onParam(168,*p(p_op3_enable));
onParam(169,*p(p_op4_enable));
onParam(170,*p(p_op5_enable));
onParam(171,*p(p_op6_enable));
onParam(172,*p(p_number_of_voices));
if(_param_change_counter>PARAM_CHANGE_LEVEL)
{
panic();
controllers.refresh();
}
//TRACE("Bye");
}
// override the run() method
void Dexed::run (uint32_t sample_count)
{
const LV2_Atom_Sequence* seq = p<LV2_Atom_Sequence> (p_midi_in);
float* output = p(p_audio_out);
uint32_t last_frame = 0, num_this_time = 0;
bool drop_next_events=false;
Plugin::run(sample_count);
if(++_k_rate_counter%16)
set_params(); // pre_process: copy actual voice params
for (LV2_Atom_Event* ev = lv2_atom_sequence_begin (&seq->body);
!lv2_atom_sequence_is_end(&seq->body, seq->atom.size, ev);
ev = lv2_atom_sequence_next (ev))
{
num_this_time = ev->time.frames - last_frame;
// If it's midi, send it to the engine
if (ev->body.type == m_midi_type)
{
drop_next_events|=ProcessMidiMessage((uint8_t*) LV2_ATOM_BODY (&ev->body),ev->body.size);
if(drop_next_events==true)
continue;
}
// render audio from the last frame until the timestamp of this event
GetSamples (num_this_time, outbuf_);
// i is the index of the engine's buf, which always starts at 0 (i think)
// j is the index of the plugin's float output buffer which will be the timestamp
// of the last processed atom event.
for (uint32_t i = 0, j = last_frame; i < num_this_time; ++i, ++j)
output[j]=outbuf_[i];
last_frame = ev->time.frames;
}
// render remaining samples if any left
if (last_frame < sample_count)
{
// do the same thing as above except from last frame until the end of
// the processing cycles last sample. at this point, all events have
// already been handled.
num_this_time = sample_count - last_frame;
GetSamples (num_this_time, outbuf_);
for (uint32_t i = 0, j = last_frame; i < num_this_time; ++i, ++j)
output[j] = outbuf_[i];
}
fx.process(output, sample_count);
}
void Dexed::GetSamples(uint32_t n_samples, float* buffer)
{
uint32_t i;
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;
}
// 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 (uint32_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];
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<float>(clip_val>>1)/0x8000;
if(f>1) f=1;
if(f<-1) f=-1;
sumbuf[j]+=f;
audiobuf.get()[j]=0;
}
}
}
uint32_t jmax = n_samples - i;
for (uint32_t j = 0; j < N; ++j) {
if (j < jmax)
buffer[i + j] = sumbuf[j];
else
extra_buf_[j - jmax] = sumbuf[j];
}
}
extra_buf_size_ = i - n_samples;
}
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=static_cast<uint8_t>(pow(2,op));
if((op_carrier&op_bit)>0)
{
// 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++;
}
}
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;
TRACE("Shutted down Voice[%2d]",i);
}
}
// TRACE("Voice[%2d] live=%d keydown=%d",i,voices[i].live,voices[i].keydown);
}
}
}
bool Dexed::ProcessMidiMessage(const uint8_t *buf, uint32_t buf_size) {
TRACE("Hi");
uint8_t cmd = buf[0];
switch(cmd & 0xf0) {
case 0x80 :
TRACE("MIDI keyup event: %d",buf[1]);
keyup(buf[1]);
return(false);
break;
case 0x90 :
TRACE("MIDI keydown event: %d %d",buf[1],buf[2]);
keydown(buf[1], buf[2]);
return(false);
break;
case 0xb0 : {
uint8_t ctrl = buf[1];
uint8_t value = buf[2];
switch(ctrl) {
case 1:
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 = value;
controllers.refresh();
break;
case 4:
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 = 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;
}
}
}
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(buf[1]);
// break;
// channel aftertouch
case 0xd0 :
TRACE("MIDI aftertouch 0xd0 event: %d %d",buf[1]);
controllers.aftertouch_cc = buf[1];
controllers.refresh();
break;
// pitchbend
case 0xe0 :
TRACE("MIDI pitchbend 0xe0 event: %d %d",buf[1],buf[2]);
controllers.values_[kControllerPitch] = buf[1] | (buf[2] << 7);
break;
default:
TRACE("MIDI event unknown: cmd=%d, val1=%d, val2=%d",buf[0],buf[1],buf[2]);
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;
}
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++;
note = (note + 1) % max_notes;
}
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;
TRACE("Bye");
}
void Dexed::keyup(uint8_t pitch) {
TRACE("Hi");
TRACE("pitch=%d\n",pitch);
pitch += data[144] - 24;
uint8_t note;
for (note=0; note<max_notes; ++note) {
if ( voices[note].midi_note == pitch && voices[note].keydown ) {
voices[note].keydown = false;
break;
}
}
// note not found ?
if ( note >= max_notes ) {
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;
}
}
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();
}
TRACE("Bye");
}
void Dexed::onParam(uint8_t param_num,float param_val)
{
int32_t tune;
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)
panic();
refreshVoice=true;
data[param_num]=static_cast<uint8_t>(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;
}
TRACE("Done: Parameter %d changed from %d to %d",param_num, tmp, data[param_num]);
}
}
uint8_t Dexed::getEngineType() {
return engineType;
}
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;
}
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;i<MAX_ACTIVE_NOTES;i++)
{
if(voices[i].live == true) {
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;
}
}
}
//==============================================================================
DexedVoice::DexedVoice(double rate) : m_key(lvtk::INVALID_KEY), m_rate(rate)
{
TRACE("Hi");
TRACE("Bye");
}
DexedVoice::~DexedVoice()
{
TRACE("Hi");
TRACE("Bye");
}
void DexedVoice::on(unsigned char key, unsigned char velocity)
{
TRACE("Hi");
m_key = key;
TRACE("Bye");
}
void DexedVoice::off(unsigned char velocity)
{
TRACE("Hi");
m_key = lvtk::INVALID_KEY;
TRACE("Bye");
}
unsigned char DexedVoice::get_key(void) const
{
TRACE("Hi");
return m_key;
TRACE("Bye");
}
static int _ = Dexed::register_class(p_uri);

@ -100,23 +100,23 @@ class Dexed
uint8_t _param_change_counter; uint8_t _param_change_counter;
uint8_t data[173] = { uint8_t data[173] = {
95, 29, 20, 50, 99, 95, 00, 00, 41, 00, 19, 00, 00, 03, 00, 06, 79, 00, 01, 00, 14, // OP 95, 29, 20, 50, 99, 95, 00, 00, 41, 00, 19, 00, 00, 03, 00, 06, 79, 00, 01, 00, 14, // OP6 eg_rate_1-4, level_1-4, kbd_lev_scl_brk_pt, kbd_lev_scl_lft_depth, kbd_lev_scl_rht_depth, kbd_lev_scl_lft_curve, kbd_lev_scl_rht_curve, kbd_rate_scaling, amp_mod_sensitivity, key_vel_sensitivity, operator_output_level, osc_mode, osc_freq_coarse, osc_freq_fine, osc_detune
95, 20, 20, 50, 99, 95, 00, 00, 00, 00, 00, 00, 00, 03, 00, 00, 99, 00, 01, 00, 00, // OP 95, 20, 20, 50, 99, 95, 00, 00, 00, 00, 00, 00, 00, 03, 00, 00, 99, 00, 01, 00, 00, // OP5
95, 29, 20, 50, 99, 95, 00, 00, 00, 00, 00, 00, 00, 03, 00, 06, 89, 00, 01, 00, 07, // OP 95, 29, 20, 50, 99, 95, 00, 00, 00, 00, 00, 00, 00, 03, 00, 06, 89, 00, 01, 00, 07, // OP4
95, 20, 20, 50, 99, 95, 00, 00, 00, 00, 00, 00, 00, 03, 00, 02, 99, 00, 01, 00, 07, // OP 95, 20, 20, 50, 99, 95, 00, 00, 00, 00, 00, 00, 00, 03, 00, 02, 99, 00, 01, 00, 07, // OP3
95, 50, 35, 78, 99, 75, 00, 00, 00, 00, 00, 00, 00, 03, 00, 07, 58, 00, 14, 00, 07, // OP 95, 50, 35, 78, 99, 75, 00, 00, 00, 00, 00, 00, 00, 03, 00, 07, 58, 00, 14, 00, 07, // OP2
96, 25, 25, 67, 99, 75, 00, 00, 00, 00, 00, 00, 00, 03, 00, 02, 99, 00, 01, 00, 10, // OP 96, 25, 25, 67, 99, 75, 00, 00, 00, 00, 00, 00, 00, 03, 00, 02, 99, 00, 01, 00, 10, // OP1
94, 67, 95, 60, 50, 50, 50, 50, 94, 67, 95, 60, 50, 50, 50, 50, // 4 * pitch EG rates, 4 *pitch EG level
04, 06, 00, 04, 06, 00, // algorithm, feedback, osc sync
34, 33, 00, 00, 00, 04, 34, 33, 00, 00, 00, 04, // lfo speed, lfo delay, lfo pitch_mod_depth, lfo_amp_mod_depth, lfo_sync, lfo_waveform
03, 24, 03, 24, // pitch_mod_sensitivity, transpose
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, // 10 * char for name
01, 00, 99, 00, 99, 00, 99, 00, 99, 00, 01, 00, 99, 00, 99, 00, 99, 00, 99, 00, // pitch_bend_range, pitch_bend_step, mod_wheel_range, mod_wheel_assign, foot_ctrl_range, foot_ctrl_assign, breath_ctrl_range, breath_ctrl_assign, aftertouch_range, aftertouch_assign
00, 00, // master tune
01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, // OP1-6 enable
16 16 // number of voices
}; // INIT }; // INIT
}; };
#endif // PLUGINPROCESSOR_H_INCLUDED #endif // PLUGINPROCESSOR_H_INCLUDED

@ -1,931 +0,0 @@
/**
*
* Copyright (c) 2016-2017 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
*
*/
#include "synth.h"
#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 <unistd.h>
#include <limits.h>
Dexed::Dexed(double rate) : lvtk::Synth<DexedVoice, Dexed>(p_n_ports, p_midi_in)
{
uint8_t i;
TRACE("--------------------------------------------------------------------------------");
TRACE("Hi");
Exp2::init();
Tanh::init();
Sin::init();
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;
/*
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++) {
// if(!(voices[i].dx7_note = new (std::nothrow) Dx7Note))
// TRACE("Cannot create DX7Note [%d]",i);
voices[i].dx7_note = new Dx7Note;
voices[i].keydown = false;
voices[i].sustained = false;
voices[i].live = false;
}
for(i=0;i<sizeof(data);++i)
{
data_float[i]=static_cast<float>(data[i]);
TRACE("%d->%f",i,data_float[i]);
}
max_notes=16;
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
//controllers.opSwitch=0x00;
bufsize_=256;
outbuf_=new float[bufsize_];
//if(!(outbuf_=new (std::nothrow) float[bufsize_]))
// TRACE("Cannot create outbuf_ buffer");
lfo.reset(data+137);
setMonoMode(false);
sustain = false;
extra_buf_size_ = 0;
memset(&voiceStatus, 0, sizeof(VoiceStatus));
setEngineType(DEXED_ENGINE_MODERN);
//add_voices(new DexedVoice(rate));
add_audio_outputs(p_audio_out);
TRACE("Bye");
}
Dexed::~Dexed()
{
TRACE("Hi");
delete [] outbuf_;
currentNote = -1;
for (uint8_t note = 0; note < MAX_ACTIVE_NOTES; ++note)
delete voices[note].dx7_note;
delete(engineMsfa);
delete(engineOpl);
delete(engineMkI);
TRACE("Bye");
TRACE("--------------------------------------------------------------------------------");
}
void Dexed::activate(void)
{
TRACE("Hi");
Plugin::activate();
panic();
controllers.values_[kControllerPitchRange] = data[155];
controllers.values_[kControllerPitchStep] = data[156];
TRACE("Bye");
}
void Dexed::deactivate(void)
{
TRACE("Hi");
Plugin::deactivate();
TRACE("Bye");
}
void Dexed::set_params(void)
{
//TRACE("Hi");
_param_change_counter=0;
bool polymono=bool(*p(p_polymono));
uint8_t engine=uint8_t(*p(p_engine));
float f_gain=*p(p_output);
float f_cutoff=*p(p_cutoff);
float f_reso=*p(p_resonance);
// Dexed-Unisono
if(isMonoMode()!=polymono)
setMonoMode(polymono);
// Dexed-Engine
if(controllers.core==NULL || getEngineType()!=engine)
{
setEngineType(engine);
refreshVoice=true;
}
// Dexed-Filter
if(fx.uiCutoff!=f_cutoff)
{
fx.uiCutoff=f_cutoff;
refreshVoice=true;
}
if(fx.uiReso!=f_reso)
{
fx.uiReso=f_reso;
refreshVoice=true;
}
if(fx.uiGain!=f_gain)
{
fx.uiGain=f_gain;
refreshVoice=true;
}
// OP6
onParam(0,*p(p_op6_eg_rate_1));
onParam(1,*p(p_op6_eg_rate_2));
onParam(2,*p(p_op6_eg_rate_3));
onParam(3,*p(p_op6_eg_rate_4));
onParam(4,*p(p_op6_eg_level_1));
onParam(5,*p(p_op6_eg_level_2));
onParam(6,*p(p_op6_eg_level_3));
onParam(7,*p(p_op6_eg_level_4));
onParam(8,*p(p_op6_kbd_lev_scl_brk_pt));
onParam(9,*p(p_op6_kbd_lev_scl_lft_depth));
onParam(10,*p(p_op6_kbd_lev_scl_rht_depth));
onParam(11,*p(p_op6_kbd_lev_scl_lft_curve));
onParam(12,*p(p_op6_kbd_lev_scl_rht_curve));
onParam(13,*p(p_op6_kbd_rate_scaling));
onParam(14,*p(p_op6_amp_mod_sensitivity));
onParam(15,*p(p_op6_key_vel_sensitivity));
onParam(16,*p(p_op6_operator_output_level));
onParam(17,*p(p_op6_osc_mode));
onParam(18,*p(p_op6_osc_freq_coarse));
onParam(19,*p(p_op6_osc_freq_fine));
onParam(20,*p(p_op6_osc_detune)+7);
// OP5
onParam(21,*p(p_op5_eg_rate_1));
onParam(22,*p(p_op5_eg_rate_2));
onParam(23,*p(p_op5_eg_rate_3));
onParam(24,*p(p_op5_eg_rate_4));
onParam(25,*p(p_op5_eg_level_1));
onParam(26,*p(p_op5_eg_level_2));
onParam(27,*p(p_op5_eg_level_3));
onParam(28,*p(p_op5_eg_level_4));
onParam(29,*p(p_op5_kbd_lev_scl_brk_pt));
onParam(30,*p(p_op5_kbd_lev_scl_lft_depth));
onParam(31,*p(p_op5_kbd_lev_scl_rht_depth));
onParam(32,*p(p_op5_kbd_lev_scl_lft_curve));
onParam(33,*p(p_op5_kbd_lev_scl_rht_curve));
onParam(34,*p(p_op5_kbd_rate_scaling));
onParam(35,*p(p_op5_amp_mod_sensitivity));
onParam(36,*p(p_op5_key_vel_sensitivity));
onParam(37,*p(p_op5_operator_output_level));
onParam(38,*p(p_op5_osc_mode));
onParam(39,*p(p_op5_osc_freq_coarse));
onParam(40,*p(p_op5_osc_freq_fine));
onParam(41,*p(p_op5_osc_detune)+7);
// OP4
onParam(42,*p(p_op4_eg_rate_1));
onParam(43,*p(p_op4_eg_rate_2));
onParam(44,*p(p_op4_eg_rate_3));
onParam(45,*p(p_op4_eg_rate_4));
onParam(46,*p(p_op4_eg_level_1));
onParam(47,*p(p_op4_eg_level_2));
onParam(48,*p(p_op4_eg_level_3));
onParam(49,*p(p_op4_eg_level_4));
onParam(50,*p(p_op4_kbd_lev_scl_brk_pt));
onParam(51,*p(p_op4_kbd_lev_scl_lft_depth));
onParam(52,*p(p_op4_kbd_lev_scl_rht_depth));
onParam(53,*p(p_op4_kbd_lev_scl_lft_curve));
onParam(54,*p(p_op4_kbd_lev_scl_rht_curve));
onParam(55,*p(p_op4_kbd_rate_scaling));
onParam(56,*p(p_op4_amp_mod_sensitivity));
onParam(57,*p(p_op4_key_vel_sensitivity));
onParam(58,*p(p_op4_operator_output_level));
onParam(59,*p(p_op4_osc_mode));
onParam(60,*p(p_op4_osc_freq_coarse));
onParam(61,*p(p_op4_osc_freq_fine));
onParam(62,*p(p_op4_osc_detune)+7);
// OP3
onParam(63,*p(p_op3_eg_rate_1));
onParam(64,*p(p_op3_eg_rate_2));
onParam(65,*p(p_op3_eg_rate_3));
onParam(66,*p(p_op3_eg_rate_4));
onParam(67,*p(p_op3_eg_level_1));
onParam(68,*p(p_op3_eg_level_2));
onParam(69,*p(p_op3_eg_level_3));
onParam(70,*p(p_op3_eg_level_4));
onParam(71,*p(p_op3_kbd_lev_scl_brk_pt));
onParam(72,*p(p_op3_kbd_lev_scl_lft_depth));
onParam(73,*p(p_op3_kbd_lev_scl_rht_depth));
onParam(74,*p(p_op3_kbd_lev_scl_lft_curve));
onParam(75,*p(p_op3_kbd_lev_scl_rht_curve));
onParam(76,*p(p_op3_kbd_rate_scaling));
onParam(77,*p(p_op3_amp_mod_sensitivity));
onParam(78,*p(p_op3_key_vel_sensitivity));
onParam(79,*p(p_op3_operator_output_level));
onParam(80,*p(p_op3_osc_mode));
onParam(81,*p(p_op3_osc_freq_coarse));
onParam(82,*p(p_op3_osc_freq_fine));
onParam(83,*p(p_op3_osc_detune)+7);
// OP2
onParam(84,*p(p_op2_eg_rate_1));
onParam(85,*p(p_op2_eg_rate_2));
onParam(86,*p(p_op2_eg_rate_3));
onParam(87,*p(p_op2_eg_rate_4));
onParam(88,*p(p_op2_eg_level_1));
onParam(89,*p(p_op2_eg_level_2));
onParam(90,*p(p_op2_eg_level_3));
onParam(91,*p(p_op2_eg_level_4));
onParam(92,*p(p_op2_kbd_lev_scl_brk_pt));
onParam(93,*p(p_op2_kbd_lev_scl_lft_depth));
onParam(94,*p(p_op2_kbd_lev_scl_rht_depth));
onParam(95,*p(p_op2_kbd_lev_scl_lft_curve));
onParam(96,*p(p_op2_kbd_lev_scl_rht_curve));
onParam(97,*p(p_op2_kbd_rate_scaling));
onParam(98,*p(p_op2_amp_mod_sensitivity));
onParam(99,*p(p_op2_key_vel_sensitivity));
onParam(100,*p(p_op2_operator_output_level));
onParam(101,*p(p_op2_osc_mode));
onParam(102,*p(p_op2_osc_freq_coarse));
onParam(103,*p(p_op2_osc_freq_fine));
onParam(104,*p(p_op2_osc_detune)+7);
// OP1
onParam(105,*p(p_op1_eg_rate_1));
onParam(106,*p(p_op1_eg_rate_2));
onParam(107,*p(p_op1_eg_rate_3));
onParam(108,*p(p_op1_eg_rate_4));
onParam(109,*p(p_op1_eg_level_1));
onParam(110,*p(p_op1_eg_level_2));
onParam(111,*p(p_op1_eg_level_3));
onParam(112,*p(p_op1_eg_level_4));
onParam(113,*p(p_op1_kbd_lev_scl_brk_pt));
onParam(114,*p(p_op1_kbd_lev_scl_lft_depth));
onParam(115,*p(p_op1_kbd_lev_scl_rht_depth));
onParam(116,*p(p_op1_kbd_lev_scl_lft_curve));
onParam(117,*p(p_op1_kbd_lev_scl_rht_curve));
onParam(118,*p(p_op1_kbd_rate_scaling));
onParam(119,*p(p_op1_amp_mod_sensitivity));
onParam(120,*p(p_op1_key_vel_sensitivity));
onParam(121,*p(p_op1_operator_output_level));
onParam(122,*p(p_op1_osc_mode));
onParam(123,*p(p_op1_osc_freq_coarse));
onParam(124,*p(p_op1_osc_freq_fine));
onParam(125,*p(p_op1_osc_detune)+7);
// Global for all OPs
onParam(126,*p(p_pitch_eg_rate_1));
onParam(127,*p(p_pitch_eg_rate_2));
onParam(128,*p(p_pitch_eg_rate_3));
onParam(129,*p(p_pitch_eg_rate_4));
onParam(130,*p(p_pitch_eg_level_1));
onParam(131,*p(p_pitch_eg_level_2));
onParam(132,*p(p_pitch_eg_level_3));
onParam(133,*p(p_pitch_eg_level_4));
onParam(134,*p(p_algorithm_num)-1);
onParam(135,*p(p_feedback));
onParam(136,*p(p_oscillator_sync));
onParam(137,*p(p_lfo_speed));
onParam(138,*p(p_lfo_delay));
onParam(139,*p(p_lfo_pitch_mod_depth));
onParam(140,*p(p_lfo_amp_mod_depth));
onParam(141,*p(p_lfo_sync));
onParam(142,*p(p_lfo_waveform));
onParam(143,*p(p_pitch_mod_sensitivity));
onParam(144,*p(p_transpose));
// 10 bytes (145-154) are the name of the patch
// Controllers (added at the end of the data[])
onParam(155,*p(p_pitch_bend_range));
onParam(156,*p(p_pitch_bend_step));
onParam(157,*p(p_mod_wheel_range));
onParam(158,*p(p_mod_wheel_assign));
onParam(159,*p(p_foot_ctrl_range));
onParam(160,*p(p_foot_ctrl_assign));
onParam(161,*p(p_breath_ctrl_range));
onParam(162,*p(p_breath_ctrl_assign));
onParam(163,*p(p_aftertouch_range));
onParam(164,*p(p_aftertouch_assign));
onParam(165,*p(p_master_tune));
onParam(166,*p(p_op1_enable));
onParam(167,*p(p_op2_enable));
onParam(168,*p(p_op3_enable));
onParam(169,*p(p_op4_enable));
onParam(170,*p(p_op5_enable));
onParam(171,*p(p_op6_enable));
onParam(172,*p(p_number_of_voices));
if(_param_change_counter>PARAM_CHANGE_LEVEL)
{
panic();
controllers.refresh();
}
//TRACE("Bye");
}
// override the run() method
void Dexed::run (uint32_t sample_count)
{
const LV2_Atom_Sequence* seq = p<LV2_Atom_Sequence> (p_midi_in);
float* output = p(p_audio_out);
uint32_t last_frame = 0, num_this_time = 0;
bool drop_next_events=false;
Plugin::run(sample_count);
if(++_k_rate_counter%16)
set_params(); // pre_process: copy actual voice params
for (LV2_Atom_Event* ev = lv2_atom_sequence_begin (&seq->body);
!lv2_atom_sequence_is_end(&seq->body, seq->atom.size, ev);
ev = lv2_atom_sequence_next (ev))
{
num_this_time = ev->time.frames - last_frame;
// If it's midi, send it to the engine
if (ev->body.type == m_midi_type)
{
drop_next_events|=ProcessMidiMessage((uint8_t*) LV2_ATOM_BODY (&ev->body),ev->body.size);
if(drop_next_events==true)
continue;
}
// render audio from the last frame until the timestamp of this event
GetSamples (num_this_time, outbuf_);
// i is the index of the engine's buf, which always starts at 0 (i think)
// j is the index of the plugin's float output buffer which will be the timestamp
// of the last processed atom event.
for (uint32_t i = 0, j = last_frame; i < num_this_time; ++i, ++j)
output[j]=outbuf_[i];
last_frame = ev->time.frames;
}
// render remaining samples if any left
if (last_frame < sample_count)
{
// do the same thing as above except from last frame until the end of
// the processing cycles last sample. at this point, all events have
// already been handled.
num_this_time = sample_count - last_frame;
GetSamples (num_this_time, outbuf_);
for (uint32_t i = 0, j = last_frame; i < num_this_time; ++i, ++j)
output[j] = outbuf_[i];
}
fx.process(output, sample_count);
}
void Dexed::GetSamples(uint32_t n_samples, float* buffer)
{
uint32_t i;
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;
}
// 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 (uint32_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];
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<float>(clip_val>>1)/0x8000;
if(f>1) f=1;
if(f<-1) f=-1;
sumbuf[j]+=f;
audiobuf.get()[j]=0;
}
}
}
uint32_t jmax = n_samples - i;
for (uint32_t j = 0; j < N; ++j) {
if (j < jmax)
buffer[i + j] = sumbuf[j];
else
extra_buf_[j - jmax] = sumbuf[j];
}
}
extra_buf_size_ = i - n_samples;
}
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=static_cast<uint8_t>(pow(2,op));
if((op_carrier&op_bit)>0)
{
// 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++;
}
}
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;
TRACE("Shutted down Voice[%2d]",i);
}
}
// TRACE("Voice[%2d] live=%d keydown=%d",i,voices[i].live,voices[i].keydown);
}
}
}
bool Dexed::ProcessMidiMessage(const uint8_t *buf, uint32_t buf_size) {
TRACE("Hi");
uint8_t cmd = buf[0];
switch(cmd & 0xf0) {
case 0x80 :
TRACE("MIDI keyup event: %d",buf[1]);
keyup(buf[1]);
return(false);
break;
case 0x90 :
TRACE("MIDI keydown event: %d %d",buf[1],buf[2]);
keydown(buf[1], buf[2]);
return(false);
break;
case 0xb0 : {
uint8_t ctrl = buf[1];
uint8_t value = buf[2];
switch(ctrl) {
case 1:
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 = value;
controllers.refresh();
break;
case 4:
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 = 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;
}
}
}
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(buf[1]);
// break;
// channel aftertouch
case 0xd0 :
TRACE("MIDI aftertouch 0xd0 event: %d %d",buf[1]);
controllers.aftertouch_cc = buf[1];
controllers.refresh();
break;
// pitchbend
case 0xe0 :
TRACE("MIDI pitchbend 0xe0 event: %d %d",buf[1],buf[2]);
controllers.values_[kControllerPitch] = buf[1] | (buf[2] << 7);
break;
default:
TRACE("MIDI event unknown: cmd=%d, val1=%d, val2=%d",buf[0],buf[1],buf[2]);
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;
}
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++;
note = (note + 1) % max_notes;
}
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;
TRACE("Bye");
}
void Dexed::keyup(uint8_t pitch) {
TRACE("Hi");
TRACE("pitch=%d\n",pitch);
pitch += data[144] - 24;
uint8_t note;
for (note=0; note<max_notes; ++note) {
if ( voices[note].midi_note == pitch && voices[note].keydown ) {
voices[note].keydown = false;
break;
}
}
// note not found ?
if ( note >= max_notes ) {
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;
}
}
if ( highNote != -1 && voices[note].live ) {
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();
}
TRACE("Bye");
}
void Dexed::onParam(uint8_t param_num,float param_val)
{
int32_t tune;
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)
panic();
refreshVoice=true;
data[param_num]=static_cast<uint8_t>(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:
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);
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;
}
TRACE("Done: Parameter %d changed from %d to %d",param_num, tmp, data[param_num]);
}
}
uint8_t Dexed::getEngineType() {
return engineType;
}
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;
}
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;i<MAX_ACTIVE_NOTES;i++)
{
if(voices[i].live == true) {
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;
}
}
}
//==============================================================================
DexedVoice::DexedVoice(double rate) : m_key(lvtk::INVALID_KEY), m_rate(rate)
{
TRACE("Hi");
TRACE("Bye");
}
DexedVoice::~DexedVoice()
{
TRACE("Hi");
TRACE("Bye");
}
void DexedVoice::on(unsigned char key, unsigned char velocity)
{
TRACE("Hi");
m_key = key;
TRACE("Bye");
}
void DexedVoice::off(unsigned char velocity)
{
TRACE("Hi");
m_key = lvtk::INVALID_KEY;
TRACE("Bye");
}
unsigned char DexedVoice::get_key(void) const
{
TRACE("Hi");
return m_key;
TRACE("Bye");
}
static int _ = Dexed::register_class(p_uri);

@ -1,369 +0,0 @@
#ifndef dexed_ttl_h
#define dexed_ttl_h
#ifndef PEG_STRUCT
#define PEG_STRUCT
typedef struct {
float min;
float max;
float default_value;
char toggled;
char integer;
char logarithmic;
} peg_data_t;
#endif
/* <https://github.com/dcoredump/dexed.lv2> */
static const char p_uri[] = "https://github.com/dcoredump/dexed.lv2";
enum p_port_enum {
p_midi_in,
p_audio_out,
p_cutoff,
p_resonance,
p_output,
p_engine,
p_number_of_voices,
p_polymono,
p_pitch_bend_range,
p_pitch_bend_step,
p_mod_wheel_range,
p_mod_wheel_assign,
p_foot_ctrl_range,
p_foot_ctrl_assign,
p_breath_ctrl_range,
p_breath_ctrl_assign,
p_aftertouch_range,
p_aftertouch_assign,
p_master_tune,
p_algorithm_num,
p_feedback,
p_oscillator_sync,
p_lfo_speed,
p_lfo_delay,
p_lfo_pitch_mod_depth,
p_lfo_amp_mod_depth,
p_lfo_sync,
p_lfo_waveform,
p_transpose,
p_pitch_mod_sensitivity,
p_pitch_eg_rate_1,
p_pitch_eg_rate_2,
p_pitch_eg_rate_3,
p_pitch_eg_rate_4,
p_pitch_eg_level_1,
p_pitch_eg_level_2,
p_pitch_eg_level_3,
p_pitch_eg_level_4,
p_op1_eg_rate_1,
p_op1_eg_rate_2,
p_op1_eg_rate_3,
p_op1_eg_rate_4,
p_op1_eg_level_1,
p_op1_eg_level_2,
p_op1_eg_level_3,
p_op1_eg_level_4,
p_op1_operator_output_level,
p_op1_osc_mode,
p_op1_osc_freq_coarse,
p_op1_osc_freq_fine,
p_op1_osc_detune,
p_op1_kbd_lev_scl_brk_pt,
p_op1_kbd_lev_scl_lft_depth,
p_op1_kbd_lev_scl_rht_depth,
p_op1_kbd_lev_scl_lft_curve,
p_op1_kbd_lev_scl_rht_curve,
p_op1_kbd_rate_scaling,
p_op1_amp_mod_sensitivity,
p_op1_key_vel_sensitivity,
p_op2_eg_rate_1,
p_op2_eg_rate_2,
p_op2_eg_rate_3,
p_op2_eg_rate_4,
p_op2_eg_level_1,
p_op2_eg_level_2,
p_op2_eg_level_3,
p_op2_eg_level_4,
p_op2_operator_output_level,
p_op2_osc_mode,
p_op2_osc_freq_coarse,
p_op2_osc_freq_fine,
p_op2_osc_detune,
p_op2_kbd_lev_scl_brk_pt,
p_op2_kbd_lev_scl_lft_depth,
p_op2_kbd_lev_scl_rht_depth,
p_op2_kbd_lev_scl_lft_curve,
p_op2_kbd_lev_scl_rht_curve,
p_op2_kbd_rate_scaling,
p_op2_amp_mod_sensitivity,
p_op2_key_vel_sensitivity,
p_op3_eg_rate_1,
p_op3_eg_rate_2,
p_op3_eg_rate_3,
p_op3_eg_rate_4,
p_op3_eg_level_1,
p_op3_eg_level_2,
p_op3_eg_level_3,
p_op3_eg_level_4,
p_op3_operator_output_level,
p_op3_osc_mode,
p_op3_osc_freq_coarse,
p_op3_osc_freq_fine,
p_op3_osc_detune,
p_op3_kbd_lev_scl_brk_pt,
p_op3_kbd_lev_scl_lft_depth,
p_op3_kbd_lev_scl_rht_depth,
p_op3_kbd_lev_scl_lft_curve,
p_op3_kbd_lev_scl_rht_curve,
p_op3_kbd_rate_scaling,
p_op3_amp_mod_sensitivity,
p_op3_key_vel_sensitivity,
p_op4_eg_rate_1,
p_op4_eg_rate_2,
p_op4_eg_rate_3,
p_op4_eg_rate_4,
p_op4_eg_level_1,
p_op4_eg_level_2,
p_op4_eg_level_3,
p_op4_eg_level_4,
p_op4_operator_output_level,
p_op4_osc_mode,
p_op4_osc_freq_coarse,
p_op4_osc_freq_fine,
p_op4_osc_detune,
p_op4_kbd_lev_scl_brk_pt,
p_op4_kbd_lev_scl_lft_depth,
p_op4_kbd_lev_scl_rht_depth,
p_op4_kbd_lev_scl_lft_curve,
p_op4_kbd_lev_scl_rht_curve,
p_op4_kbd_rate_scaling,
p_op4_amp_mod_sensitivity,
p_op4_key_vel_sensitivity,
p_op5_eg_rate_1,
p_op5_eg_rate_2,
p_op5_eg_rate_3,
p_op5_eg_rate_4,
p_op5_eg_level_1,
p_op5_eg_level_2,
p_op5_eg_level_3,
p_op5_eg_level_4,
p_op5_operator_output_level,
p_op5_osc_mode,
p_op5_osc_freq_coarse,
p_op5_osc_freq_fine,
p_op5_osc_detune,
p_op5_kbd_lev_scl_brk_pt,
p_op5_kbd_lev_scl_lft_depth,
p_op5_kbd_lev_scl_rht_depth,
p_op5_kbd_lev_scl_lft_curve,
p_op5_kbd_lev_scl_rht_curve,
p_op5_kbd_rate_scaling,
p_op5_amp_mod_sensitivity,
p_op5_key_vel_sensitivity,
p_op6_eg_rate_1,
p_op6_eg_rate_2,
p_op6_eg_rate_3,
p_op6_eg_rate_4,
p_op6_eg_level_1,
p_op6_eg_level_2,
p_op6_eg_level_3,
p_op6_eg_level_4,
p_op6_operator_output_level,
p_op6_osc_mode,
p_op6_osc_freq_coarse,
p_op6_osc_freq_fine,
p_op6_osc_detune,
p_op6_kbd_lev_scl_brk_pt,
p_op6_kbd_lev_scl_lft_depth,
p_op6_kbd_lev_scl_rht_depth,
p_op6_kbd_lev_scl_lft_curve,
p_op6_kbd_lev_scl_rht_curve,
p_op6_kbd_rate_scaling,
p_op6_amp_mod_sensitivity,
p_op6_key_vel_sensitivity,
p_op1_enable,
p_op2_enable,
p_op3_enable,
p_op4_enable,
p_op5_enable,
p_op6_enable,
p_n_ports
};
static const peg_data_t p_ports[] = {
{ -3.40282e+38, 3.40282e+38, -3.40282e+38, 0, 0, 0 },
{ -3.40282e+38, 3.40282e+38, -3.40282e+38, 0, 0, 0 },
{ 0, 1, 1, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 0 },
{ 0, 2, 1, 0, 0, 0 },
{ 0, 2, 0, 0, 1, 0 },
{ 1, 32, 16, 0, 1, 0 },
{ 0, 1, 0, 1, 1, 0 },
{ 0, 12, 1, 0, 1, 0 },
{ 0, 12, 0, 0, 1, 0 },
{ 0, 99, 99, 0, 1, 0 },
{ 0, 7, 0, 0, 1, 0 },
{ 0, 99, 99, 0, 1, 0 },
{ 0, 7, 0, 0, 1, 0 },
{ 0, 99, 99, 0, 1, 0 },
{ 0, 7, 0, 0, 1, 0 },
{ 0, 99, 99, 0, 1, 0 },
{ 0, 7, 0, 0, 1, 0 },
{ -1, 1, 0, 0, 0, 0 },
{ 1, 32, 5, 0, 1, 0 },
{ 0, 7, 6, 0, 1, 0 },
{ 0, 1, 0, 1, 1, 0 },
{ 0, 99, 34, 0, 1, 0 },
{ 0, 99, 33, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 1, 0, 1, 1, 0 },
{ 0, 5, 4, 0, 1, 0 },
{ 0, 48, 24, 0, 1, 0 },
{ 0, 7, 3, 0, 1, 0 },
{ 0, 99, 94, 0, 1, 0 },
{ 0, 99, 67, 0, 1, 0 },
{ 0, 99, 95, 0, 1, 0 },
{ 0, 99, 60, 0, 1, 0 },
{ 0, 99, 50, 0, 1, 0 },
{ 0, 99, 50, 0, 1, 0 },
{ 0, 99, 50, 0, 1, 0 },
{ 0, 99, 50, 0, 1, 0 },
{ 0, 99, 96, 0, 1, 0 },
{ 0, 99, 25, 0, 1, 0 },
{ 0, 99, 25, 0, 1, 0 },
{ 0, 99, 67, 0, 1, 0 },
{ 0, 99, 99, 0, 1, 0 },
{ 0, 99, 75, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 99, 0, 1, 0 },
{ 0, 1, 0, 0, 1, 0 },
{ 0, 31, 1, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ -7, 7, 3, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 3, 0, 0, 1, 0 },
{ 0, 3, 0, 0, 1, 0 },
{ 0, 7, 3, 0, 1, 0 },
{ 0, 3, 0, 0, 1, 0 },
{ 0, 7, 2, 0, 1, 0 },
{ 0, 99, 95, 0, 1, 0 },
{ 0, 99, 50, 0, 1, 0 },
{ 0, 99, 35, 0, 1, 0 },
{ 0, 99, 78, 0, 1, 0 },
{ 0, 99, 99, 0, 1, 0 },
{ 0, 99, 75, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 58, 0, 1, 0 },
{ 0, 1, 0, 0, 1, 0 },
{ 0, 31, 14, 0, 1, 0 },
{ 0, 100, 0, 0, 1, 0 },
{ -7, 7, 0, 0, 1, 0 },
{ 0, 100, 0, 0, 1, 0 },
{ 0, 100, 0, 0, 1, 0 },
{ 0, 100, 0, 0, 1, 0 },
{ 0, 3, 0, 0, 1, 0 },
{ 0, 3, 0, 0, 1, 0 },
{ 0, 7, 3, 0, 1, 0 },
{ 0, 3, 0, 0, 1, 0 },
{ 0, 7, 7, 0, 1, 0 },
{ 0, 99, 95, 0, 1, 0 },
{ 0, 99, 20, 0, 1, 0 },
{ 0, 99, 20, 0, 1, 0 },
{ 0, 99, 50, 0, 1, 0 },
{ 0, 99, 99, 0, 1, 0 },
{ 0, 99, 95, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 99, 0, 1, 0 },
{ 0, 1, 0, 0, 1, 0 },
{ 0, 31, 1, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ -7, 7, 0, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 3, 0, 0, 1, 0 },
{ 0, 3, 0, 0, 1, 0 },
{ 0, 7, 3, 0, 1, 0 },
{ 0, 3, 0, 0, 1, 0 },
{ 0, 7, 2, 0, 1, 0 },
{ 0, 99, 95, 0, 1, 0 },
{ 0, 99, 29, 0, 1, 0 },
{ 0, 99, 20, 0, 1, 0 },
{ 0, 99, 50, 0, 1, 0 },
{ 0, 99, 99, 0, 1, 0 },
{ 0, 99, 95, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 89, 0, 1, 0 },
{ 0, 1, 0, 0, 1, 0 },
{ 0, 31, 1, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ -7, 7, 0, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 3, 0, 0, 1, 0 },
{ 0, 3, 0, 0, 1, 0 },
{ 0, 7, 3, 0, 1, 0 },
{ 0, 3, 0, 0, 1, 0 },
{ 0, 7, 6, 0, 1, 0 },
{ 0, 99, 95, 0, 1, 0 },
{ 0, 99, 20, 0, 1, 0 },
{ 0, 99, 20, 0, 1, 0 },
{ 0, 99, 50, 0, 1, 0 },
{ 0, 99, 99, 0, 1, 0 },
{ 0, 99, 95, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 99, 0, 1, 0 },
{ 0, 1, 0, 0, 1, 0 },
{ 0, 31, 1, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ -7, 7, -7, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 3, 0, 0, 1, 0 },
{ 0, 3, 0, 0, 1, 0 },
{ 0, 7, 3, 0, 1, 0 },
{ 0, 3, 0, 0, 1, 0 },
{ 0, 7, 0, 0, 1, 0 },
{ 0, 99, 95, 0, 1, 0 },
{ 0, 99, 29, 0, 1, 0 },
{ 0, 99, 20, 0, 1, 0 },
{ 0, 99, 50, 0, 1, 0 },
{ 0, 99, 99, 0, 1, 0 },
{ 0, 99, 95, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 79, 0, 1, 0 },
{ 0, 1, 0, 0, 1, 0 },
{ 0, 31, 1, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ -7, 7, 7, 0, 1, 0 },
{ 0, 99, 41, 0, 1, 0 },
{ 0, 99, 0, 0, 1, 0 },
{ 0, 99, 19, 0, 1, 0 },
{ 0, 3, 0, 0, 1, 0 },
{ 0, 3, 0, 0, 1, 0 },
{ 0, 7, 3, 0, 1, 0 },
{ 0, 3, 0, 0, 1, 0 },
{ 0, 7, 6, 0, 1, 0 },
{ 0, 1, 1, 0, 1, 0 },
{ 0, 1, 1, 0, 1, 0 },
{ 0, 1, 1, 0, 1, 0 },
{ 0, 1, 1, 0, 1, 0 },
{ 0, 1, 1, 0, 1, 0 },
{ 0, 1, 1, 0, 1, 0 },
};
#endif /* dexed_ttl_h */

@ -260,7 +260,8 @@ void Dx7Note::keyup() {
pitchenv_.keydown(false); pitchenv_.keydown(false);
} }
void Dx7Note::update(const uint8_t patch[156], int midinote, int velocity) { //void Dx7Note::update(const uint8_t patch[156], int midinote, int velocity) {
void Dx7Note::update(const uint8_t patch[173], int midinote, int velocity) {
int rates[4]; int rates[4];
int levels[4]; int levels[4];
for (int op = 0; op < 6; op++) { for (int op = 0; op < 6; op++) {

@ -1,216 +0,0 @@
/**
*
* Copyright (c) 2013-2014 Pascal Gauthier.
* Copyright (c) 2013-2014 Filatov Vadim.
*
* Filter taken from the Obxd project :
* https://github.com/2DaT/Obxd
*
* 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
*
*/
#define _USE_MATH_DEFINES
#include <math.h>
#include "PluginFx.h"
const float dc = 1e-18;
inline static float tptpc(float& state,float inp,float cutoff) {
double v = (inp - state) * cutoff / (1 + cutoff);
double res = v + state;
state = res + v;
return res;
}
inline static float tptlpupw(float & state , float inp , float cutoff , float srInv) {
cutoff = (cutoff * srInv)*M_PI;
double v = (inp - state) * cutoff / (1 + cutoff);
double res = v + state;
state = res + v;
return res;
}
//static float linsc(float param,const float min,const float max) {
// return (param) * (max - min) + min;
//}
static float logsc(float param, const float min,const float max,const float rolloff = 19.0f) {
return ((expf(param * logf(rolloff+1)) - 1.0f) / (rolloff)) * (max-min) + min;
}
PluginFx::PluginFx() {
uiCutoff = 1;
uiReso = 0;
uiGain = 1;
}
void PluginFx::init(int sr) {
mm=0;
s1=s2=s3=s4=c=d=0;
R24=0;
mmch = (int)(mm * 3);
mmt = mm*3-mmch;
sampleRate = sr;
sampleRateInv = 1/sampleRate;
float rcrate =sqrt((44000/sampleRate));
rcor24 = (970.0 / 44000)*rcrate;
rcor24Inv = 1 / rcor24;
bright = tan((sampleRate*0.5f-10) * M_PI * sampleRateInv);
R = 1;
rcor = (480.0 / 44000)*rcrate;
rcorInv = 1 / rcor;
bandPassSw = false;
pCutoff = -1;
pReso = -1;
dc_r = 1.0-(126.0/sr);
dc_id = 0;
dc_od = 0;
}
inline float PluginFx::NR24(float sample,float g,float lpc) {
float ml = 1 / (1+g);
float S = (lpc*(lpc*(lpc*s1 + s2) + s3) +s4)*ml;
float G = lpc*lpc*lpc*lpc;
float y = (sample - R24 * S) / (1 + R24*G);
return y + 1e-8;
};
inline float PluginFx::NR(float sample, float g) {
float y = ((sample- R * s1*2 - g*s1 - s2)/(1+ g*(2*R + g))) + dc;
return y;
}
void PluginFx::process(float *work, int sampleSize) {
// very basic DC filter
float t_fd = work[0];
work[0] = work[0] - dc_id + dc_r * dc_od;
dc_id = t_fd;
for (int i=1; i<sampleSize; i++) {
t_fd = work[i];
work[i] = work[i] - dc_id + dc_r * work[i-1];
dc_id = t_fd;
}
dc_od = work[sampleSize-1];
if ( uiGain != 1 ) {
for(int i=0; i < sampleSize; i++ )
work[i] *= uiGain;
}
// don't apply the LPF if the cutoff is to maximum
if ( uiCutoff == 1 )
return;
if ( uiCutoff != pCutoff || uiReso != pReso ) {
rReso = (0.991-logsc(1-uiReso,0,0.991));
R24 = 3.5 * rReso;
float cutoffNorm = logsc(uiCutoff,60,19000);
rCutoff = (float)tan(cutoffNorm * sampleRateInv * M_PI);
pCutoff = uiCutoff;
pReso = uiReso;
R = 1 - rReso;
}
// THIS IS MY FAVORITE 4POLE OBXd filter
// maybe smooth this value
float g = rCutoff;
float lpc = g / (1 + g);
for(int i=0; i < sampleSize; i++ ) {
float s = work[i];
s = s - 0.45*tptlpupw(c,s,15,sampleRateInv);
s = tptpc(d,s,bright);
float y0 = NR24(s,g,lpc);
//first low pass in cascade
double v = (y0 - s1) * lpc;
double res = v + s1;
s1 = res + v;
//damping
s1 =atan(s1*rcor24)*rcor24Inv;
float y1= res;
float y2 = tptpc(s2,y1,g);
float y3 = tptpc(s3,y2,g);
float y4 = tptpc(s4,y3,g);
float mc=0.0;
switch(mmch) {
case 0:
mc = ((1 - mmt) * y4 + (mmt) * y3);
break;
case 1:
mc = ((1 - mmt) * y3 + (mmt) * y2);
break;
case 2:
mc = ((1 - mmt) * y2 + (mmt) * y1);
break;
case 3:
mc = y1;
break;
}
//half volume comp
work[i] = mc * (1 + R24 * 0.45);
}
}
/*
// THIS IS THE 2POLE FILTER
for(int i=0; i < sampleSize; i++ ) {
float s = work[i];
s = s - 0.45*tptlpupw(c,s,15,sampleRateInv);
s = tptpc(d,s,bright);
//float v = ((sample- R * s1*2 - g2*s1 - s2)/(1+ R*g1*2 + g1*g2));
float v = NR(s,g);
float y1 = v*g + s1;
//damping
s1 = atan(s1 * rcor) * rcorInv;
float y2 = y1*g + s2;
s2 = y2 + y1*g;
double mc;
if(!bandPassSw)
mc = (1-mm)*y2 + (mm)*v;
else
{
mc =2 * ( mm < 0.5 ?
((0.5 - mm) * y2 + (mm) * y1):
((1-mm) * y1 + (mm-0.5) * v)
);
}
work[i] = mc;
}
*/

@ -1,72 +0,0 @@
/**
*
* Copyright (c) 2013 Pascal Gauthier.
*
* 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
*
*/
#ifndef PLUGINFX_H_INCLUDED
#define PLUGINFX_H_INCLUDED
class PluginFx {
float s1,s2,s3,s4;
float sampleRate;
float sampleRateInv;
float d, c;
float R24;
float rcor24,rcor24Inv;
float bright;
// 24 db multimode
float mm;
float mmt;
int mmch;
inline float NR24(float sample,float g,float lpc);
// preprocess values taken the UI
float rCutoff;
float rReso;
float rGain;
// thread values; if these are different from the UI,
// it needs to be recalculated.
float pReso;
float pCutoff;
float pGain;
// I am still keeping the 2pole w/multimode filter
inline float NR(float sample, float g);
bool bandPassSw;
float rcor,rcorInv;
int R;
float dc_id;
float dc_od;
float dc_r;
public:
PluginFx();
// this is set directly by the ui / parameter
float uiCutoff;
float uiReso;
float uiGain;
void init(int sampleRate);
void process(float *work, int sampleSize);
};
#endif // PLUGINFX_H_INCLUDED
Loading…
Cancel
Save