From bf4985c6a8d4c055f1390dd528b422776b3faa0e Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Fri, 18 Nov 2016 15:52:36 +0100 Subject: [PATCH] Tried another clip function. --- src/Makefile | 34 +-- src/dexed.cpp | 67 +++-- src/dexed.cpp.msfa | 641 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 701 insertions(+), 41 deletions(-) create mode 100644 src/dexed.cpp.msfa diff --git a/src/Makefile b/src/Makefile index 0f89dd6..0d76295 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,4 +1,4 @@ -#DEBUG=-DDEBUG=0 +#DEBUG=-DDEBUG BUNDLE=dexed.lv2 INSTALL_DIR=/home/pi/zynthian/zynthian-plugins/mod-lv2 TARGET=dexed.so @@ -8,7 +8,7 @@ LDFLAGS=-L/usr/local/lib -llvtk_plugin2 all: $(BUNDLE) Makefile -clean: +clean: Makefile rm -f *.o *~ *.bak *.gch dexed.peg *.so *.gch msfa/*.gch rm -rf $(BUNDLE) @@ -27,49 +27,49 @@ $(BUNDLE): manifest.ttl Dexed.ttl dexed.so dexed.so: $(OBJ) dexed.o $(CXX) -shared dexed.o $(OBJ) $(LDFLAGS) -o dexed.so -dexed.o: dexed.cpp dexed.peg +dexed.o: Makefile dexed.cpp dexed.peg $(CXX) $(CFLAGS) -Wall -c dexed.cpp -trace.o: trace.c trace.h +trace.o: Makefile trace.c trace.h $(CXX) $(CFLAGS) -Wall -c trace.c -ringbuffer.o: msfa/ringbuffer.cc +ringbuffer.o: Makefile msfa/ringbuffer.cc $(CXX) $(CFLAGS) -Wall -c msfa/ringbuffer.cc -fm_core.o: msfa/fm_core.cc +fm_core.o: Makefile msfa/fm_core.cc $(CXX) $(CFLAGS) -Wall -c msfa/fm_core.cc -env.o: msfa/env.cc +env.o: Makefile msfa/env.cc $(CXX) $(CFLAGS) -Wall -c msfa/env.cc -lfo.o: msfa/lfo.cc +lfo.o: Makefile msfa/lfo.cc $(CXX) $(CFLAGS) -Wall -c msfa/lfo.cc -dx7note.o: msfa/dx7note.cc +dx7note.o: Makefile msfa/dx7note.cc $(CXX) $(CFLAGS) -Wall -c msfa/dx7note.cc -sin.o: msfa/sin.cc +sin.o: Makefile msfa/sin.cc $(CXX) $(CFLAGS) -Wall -c msfa/sin.cc -pitchenv.o: msfa/pitchenv.cc +pitchenv.o: Makefile msfa/pitchenv.cc $(CXX) $(CFLAGS) -Wall -c msfa/pitchenv.cc -fm_op_kernel.o: msfa/fm_op_kernel.cc +fm_op_kernel.o: Makefile msfa/fm_op_kernel.cc $(CXX) $(CFLAGS) -Wall -c msfa/fm_op_kernel.cc -freqlut.o: msfa/freqlut.cc +freqlut.o: Makefile msfa/freqlut.cc $(CXX) $(CFLAGS) -Wall -c msfa/freqlut.cc -exp2.o: msfa/exp2.cc +exp2.o: Makefile msfa/exp2.cc $(CXX) $(CFLAGS) -Wall -c msfa/exp2.cc -EngineMkI.o: EngineMkI.cpp +EngineMkI.o: Makefile EngineMkI.cpp $(CXX) $(CFLAGS) -Wall -c EngineMkI.cpp -EngineOpl.o: EngineOpl.cpp +EngineOpl.o: Makefile EngineOpl.cpp $(CXX) $(CFLAGS) -Wall -c EngineOpl.cpp -PluginFx.o: PluginFx.cpp +PluginFx.o: Makefile PluginFx.cpp $(CXX) $(CFLAGS) -Wall -c PluginFx.cpp dexed.peg: Dexed.ttl diff --git a/src/dexed.cpp b/src/dexed.cpp index 752ac77..075a532 100644 --- a/src/dexed.cpp +++ b/src/dexed.cpp @@ -12,6 +12,7 @@ #include "msfa/ringbuffer.h" #include "PluginFx.h" #include +#include Dexed::Dexed(double rate) : lvtk::Synth(p_n_ports, p_midi_in) { @@ -60,6 +61,8 @@ Dexed::Dexed(double rate) : lvtk::Synth(p_n_ports, p_midi_in) add_voices(new DexedVoice(rate)); add_audio_outputs(p_audio_out); + + TRACE("Bye"); } Dexed::~Dexed() @@ -344,37 +347,46 @@ void Dexed::GetSamples(int n_samples, int16_t *buffer) extra_buf_[j] = extra_buf_[j + n_samples]; } extra_buf_size_ -= n_samples; - return; } - for (; i < n_samples; i += N) { - AlignedBuf audiobuf; - - for (int j = 0; j < N; ++j) { - audiobuf.get()[j] = 0; - } - int32_t lfovalue = lfo.getsample(); - int32_t lfodelay = lfo.getdelay(); + else + { + for (; i < n_samples; i += N) { + AlignedBuf audiobuf; + int16_t sumbuf[N]; + + for (int j = 0; j < N; ++j) { + audiobuf.get()[j] = 0; + sumbuf[j] = 0; + } + + int32_t lfovalue = lfo.getsample(); + int32_t lfodelay = lfo.getdelay(); - for (int note = 0; note < MAX_ACTIVE_NOTES; ++note) { - if (voices[note].live) { -TRACE("Voice-note: %d:%d\n",note,voices[note].midi_note); - voices[note].dx7_note->compute(audiobuf.get(), lfovalue, lfodelay, &controllers); + for (int note = 0; note < MAX_ACTIVE_NOTES; ++note) { + if (voices[note].live) { + voices[note].dx7_note->compute(audiobuf.get(), lfovalue, lfodelay, &controllers); + for (int j=0; j < N; ++j) { + int32_t val = audiobuf.get()[j]; + + val = val >> 4; + int clip_val = val < -(1 << 24) ? 0x8000 : val >= (1 << 24) ? 0x7fff : val >> 9; + sumbuf[j] += clip_val; + audiobuf.get()[j] = 0; + } + } } - } - int jmax = n_samples - i; - for (int j = 0; j < N; ++j) { - int32_t val = audiobuf.get()[j] >> 4; - int clip_val = val < -(1 << 24) ? 0x8000 : val >= (1 << 24) ? 0x7fff : val >> 9; - // TODO: maybe some dithering? - if (j < jmax) { - buffer[i + j] = clip_val; - } else { - extra_buf_[j - jmax] = clip_val; + int jmax = n_samples - i; + for (int 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; } - extra_buf_size_ = i - n_samples; } //void Dexed::processMidiMessage(const MidiMessage *msg) { @@ -462,6 +474,8 @@ void Dexed::ConsumeInput(size_t n_input_bytes) { } 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; @@ -509,9 +523,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; int note; @@ -550,6 +568,7 @@ void Dexed::keyup(uint8_t pitch) { } else { voices[note].dx7_note->keyup(); } +TRACE("Bye"); } void Dexed::onParam(int param_num,int param_val) diff --git a/src/dexed.cpp.msfa b/src/dexed.cpp.msfa new file mode 100644 index 0000000..28040fa --- /dev/null +++ b/src/dexed.cpp.msfa @@ -0,0 +1,641 @@ +// from: http://ll-plugins.nongnu.org/lv2pftci/#A_synth + +#include +#include "dexed.peg" +#include "dexed.h" +#include "EngineMkI.h" +#include "EngineOpl.h" +#include "msfa/exp2.h" +#include "msfa/sin.h" +#include "msfa/freqlut.h" +#include "msfa/controllers.h" +#include "msfa/ringbuffer.h" +#include "PluginFx.h" +#include + +Dexed::Dexed(double rate) : lvtk::Synth(p_n_ports, p_midi_in) +{ + TRACE("Hi"); + + bufsize_=256; + outbuf16_=new int16_t[bufsize_]; + + Exp2::init(); + Tanh::init(); + Sin::init(); + + lastStateSave = 0; + currentNote = -1; + engineType = -1; + monoMode = 0; + normalizeDxVelocity = false; + + memset(&voiceStatus, 0, sizeof(VoiceStatus)); + setEngineType(DEXED_ENGINE_MARKI); + + Freqlut::init(rate); + Lfo::init(rate); + PitchEnv::init(rate); + Env::init_sr(rate); + fx.init(rate); + + for (int note = 0; note < MAX_ACTIVE_NOTES; ++note) { + voices[note].dx7_note = new Dx7Note; + voices[note].keydown = false; + voices[note].sustained = false; + voices[note].live = false; + } + + currentNote = 0; + controllers.values_[kControllerPitch] = 0x2000; + controllers.modwheel_cc = 0; + controllers.foot_cc = 0; + controllers.breath_cc = 0; + controllers.aftertouch_cc = 0; + + sustain = false; + + lfo.reset(data + 137); + + add_voices(new DexedVoice(rate)); + + add_audio_outputs(p_audio_out); + + TRACE("Bye"); +} + +Dexed::~Dexed() +{ + TRACE("Hi"); + + delete [] outbuf16_; + + currentNote = -1; + + for (int 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; + } + + TRACE("Bye"); +} + +void Dexed::set_params(void) +{ + TRACE("Hi"); + + refreshVoice=true; + + // Dexed-Filter + fx.uiCutoff=*p(p_cutoff); + fx.uiReso=*p(p_resonance); + fx.uiGain=*p(p_output); + + // OP6 + onParam(0,static_cast(*p(p_op6_eg_rate_1))); + onParam(1,static_cast(*p(p_op6_eg_rate_2))); + onParam(2,static_cast(*p(p_op6_eg_rate_3))); + onParam(3,static_cast(*p(p_op6_eg_rate_4))); + onParam(4,static_cast(*p(p_op6_eg_level_1))); + onParam(5,static_cast(*p(p_op6_eg_level_2))); + onParam(6,static_cast(*p(p_op6_eg_level_3))); + onParam(7,static_cast(*p(p_op6_eg_level_4))); + onParam(8,static_cast(*p(p_op6_kbd_lev_scl_brk_pt))); + onParam(9,static_cast(*p(p_op6_kbd_lev_scl_lft_depth))); + onParam(10,static_cast(*p(p_op6_kbd_lev_scl_rht_depth))); + onParam(11,static_cast(*p(p_op6_kbd_lev_scl_lft_curve))); + onParam(12,static_cast(*p(p_op6_kbd_lev_scl_rht_curve))); + onParam(13,static_cast(*p(p_op6_kbd_rate_scaling))); + onParam(14,static_cast(*p(p_op6_amp_mod_sensitivity))); + onParam(15,static_cast(*p(p_op6_key_vel_sensitivity))); + onParam(16,static_cast(*p(p_op6_operator_output_level))); + onParam(17,static_cast(*p(p_op6_osc_mode))); + onParam(18,static_cast(*p(p_op6_osc_freq_coarse))); + onParam(19,static_cast(*p(p_op6_osc_freq_fine))); + onParam(20,static_cast(*p(p_op6_osc_detune)+7)); + // OP5 + onParam(21,static_cast(*p(p_op5_eg_rate_1))); + onParam(22,static_cast(*p(p_op5_eg_rate_2))); + onParam(23,static_cast(*p(p_op5_eg_rate_3))); + onParam(24,static_cast(*p(p_op5_eg_rate_4))); + onParam(25,static_cast(*p(p_op5_eg_level_1))); + onParam(26,static_cast(*p(p_op5_eg_level_2))); + onParam(27,static_cast(*p(p_op5_eg_level_3))); + onParam(28,static_cast(*p(p_op5_eg_level_4))); + onParam(29,static_cast(*p(p_op5_kbd_lev_scl_brk_pt))); + onParam(30,static_cast(*p(p_op5_kbd_lev_scl_lft_depth))); + onParam(31,static_cast(*p(p_op5_kbd_lev_scl_rht_depth))); + onParam(32,static_cast(*p(p_op5_kbd_lev_scl_lft_curve))); + onParam(33,static_cast(*p(p_op5_kbd_lev_scl_rht_curve))); + onParam(34,static_cast(*p(p_op5_kbd_rate_scaling))); + onParam(35,static_cast(*p(p_op5_amp_mod_sensitivity))); + onParam(36,static_cast(*p(p_op5_key_vel_sensitivity))); + onParam(37,static_cast(*p(p_op5_operator_output_level))); + onParam(38,static_cast(*p(p_op5_osc_mode))); + onParam(39,static_cast(*p(p_op5_osc_freq_coarse))); + onParam(40,static_cast(*p(p_op5_osc_freq_fine))); + onParam(41,static_cast(*p(p_op5_osc_detune)+7)); + // OP4 + onParam(42,static_cast(*p(p_op4_eg_rate_1))); + onParam(43,static_cast(*p(p_op4_eg_rate_2))); + onParam(44,static_cast(*p(p_op4_eg_rate_3))); + onParam(45,static_cast(*p(p_op4_eg_rate_4))); + onParam(46,static_cast(*p(p_op4_eg_level_1))); + onParam(47,static_cast(*p(p_op4_eg_level_2))); + onParam(48,static_cast(*p(p_op4_eg_level_3))); + onParam(49,static_cast(*p(p_op4_eg_level_4))); + onParam(50,static_cast(*p(p_op4_kbd_lev_scl_brk_pt))); + onParam(51,static_cast(*p(p_op4_kbd_lev_scl_lft_depth))); + onParam(52,static_cast(*p(p_op4_kbd_lev_scl_rht_depth))); + onParam(53,static_cast(*p(p_op4_kbd_lev_scl_lft_curve))); + onParam(54,static_cast(*p(p_op4_kbd_lev_scl_rht_curve))); + onParam(55,static_cast(*p(p_op4_kbd_rate_scaling))); + onParam(56,static_cast(*p(p_op4_amp_mod_sensitivity))); + onParam(57,static_cast(*p(p_op4_key_vel_sensitivity))); + onParam(58,static_cast(*p(p_op4_operator_output_level))); + onParam(59,static_cast(*p(p_op4_osc_mode))); + onParam(60,static_cast(*p(p_op4_osc_freq_coarse))); + onParam(61,static_cast(*p(p_op4_osc_freq_fine))); + onParam(62,static_cast(*p(p_op4_osc_detune)+7)); + // OP3 + onParam(63,static_cast(*p(p_op3_eg_rate_1))); + onParam(64,static_cast(*p(p_op3_eg_rate_2))); + onParam(65,static_cast(*p(p_op3_eg_rate_3))); + onParam(66,static_cast(*p(p_op3_eg_rate_4))); + onParam(67,static_cast(*p(p_op3_eg_level_1))); + onParam(68,static_cast(*p(p_op3_eg_level_2))); + onParam(69,static_cast(*p(p_op3_eg_level_3))); + onParam(70,static_cast(*p(p_op3_eg_level_4))); + onParam(71,static_cast(*p(p_op3_kbd_lev_scl_brk_pt))); + onParam(72,static_cast(*p(p_op3_kbd_lev_scl_lft_depth))); + onParam(73,static_cast(*p(p_op3_kbd_lev_scl_rht_depth))); + onParam(74,static_cast(*p(p_op3_kbd_lev_scl_lft_curve))); + onParam(75,static_cast(*p(p_op3_kbd_lev_scl_rht_curve))); + onParam(76,static_cast(*p(p_op3_kbd_rate_scaling))); + onParam(77,static_cast(*p(p_op3_amp_mod_sensitivity))); + onParam(78,static_cast(*p(p_op3_key_vel_sensitivity))); + onParam(79,static_cast(*p(p_op3_operator_output_level))); + onParam(80,static_cast(*p(p_op3_osc_mode))); + onParam(81,static_cast(*p(p_op3_osc_freq_coarse))); + onParam(82,static_cast(*p(p_op3_osc_freq_fine))); + onParam(83,static_cast(*p(p_op3_osc_detune)+7)); + // OP2 + onParam(84,static_cast(*p(p_op2_eg_rate_1))); + onParam(85,static_cast(*p(p_op2_eg_rate_2))); + onParam(86,static_cast(*p(p_op2_eg_rate_3))); + onParam(87,static_cast(*p(p_op2_eg_rate_4))); + onParam(88,static_cast(*p(p_op2_eg_level_1))); + onParam(89,static_cast(*p(p_op2_eg_level_2))); + onParam(90,static_cast(*p(p_op2_eg_level_3))); + onParam(91,static_cast(*p(p_op2_eg_level_4))); + onParam(92,static_cast(*p(p_op2_kbd_lev_scl_brk_pt))); + onParam(93,static_cast(*p(p_op2_kbd_lev_scl_lft_depth))); + onParam(94,static_cast(*p(p_op2_kbd_lev_scl_rht_depth))); + onParam(95,static_cast(*p(p_op2_kbd_lev_scl_lft_curve))); + onParam(96,static_cast(*p(p_op2_kbd_lev_scl_rht_curve))); + onParam(97,static_cast(*p(p_op2_kbd_rate_scaling))); + onParam(98,static_cast(*p(p_op2_amp_mod_sensitivity))); + onParam(99,static_cast(*p(p_op2_key_vel_sensitivity))); + onParam(100,static_cast(*p(p_op2_operator_output_level))); + onParam(101,static_cast(*p(p_op2_osc_mode))); + onParam(102,static_cast(*p(p_op2_osc_freq_coarse))); + onParam(103,static_cast(*p(p_op2_osc_freq_fine))); + onParam(104,static_cast(*p(p_op2_osc_detune)+7)); + // OP1 + onParam(105,static_cast(*p(p_op1_eg_rate_1))); + onParam(106,static_cast(*p(p_op1_eg_rate_2))); + onParam(107,static_cast(*p(p_op1_eg_rate_3))); + onParam(108,static_cast(*p(p_op1_eg_rate_4))); + onParam(109,static_cast(*p(p_op1_eg_level_1))); + onParam(110,static_cast(*p(p_op1_eg_level_2))); + onParam(111,static_cast(*p(p_op1_eg_level_3))); + onParam(112,static_cast(*p(p_op1_eg_level_4))); + onParam(113,static_cast(*p(p_op1_kbd_lev_scl_brk_pt))); + onParam(114,static_cast(*p(p_op1_kbd_lev_scl_lft_depth))); + onParam(115,static_cast(*p(p_op1_kbd_lev_scl_rht_depth))); + onParam(116,static_cast(*p(p_op1_kbd_lev_scl_lft_curve))); + onParam(117,static_cast(*p(p_op1_kbd_lev_scl_rht_curve))); + onParam(118,static_cast(*p(p_op1_kbd_rate_scaling))); + onParam(119,static_cast(*p(p_op1_amp_mod_sensitivity))); + onParam(120,static_cast(*p(p_op1_key_vel_sensitivity))); + onParam(121,static_cast(*p(p_op1_operator_output_level))); + onParam(122,static_cast(*p(p_op1_osc_mode))); + onParam(123,static_cast(*p(p_op1_osc_freq_coarse))); + onParam(124,static_cast(*p(p_op1_osc_freq_fine))); + onParam(125,static_cast(*p(p_op1_osc_detune)+7)); + // Global for all OPs + onParam(126,static_cast(*p(p_pitch_eg_rate_1))); + onParam(127,static_cast(*p(p_pitch_eg_rate_2))); + onParam(128,static_cast(*p(p_pitch_eg_rate_3))); + onParam(129,static_cast(*p(p_pitch_eg_rate_4))); + onParam(130,static_cast(*p(p_pitch_eg_level_1))); + onParam(131,static_cast(*p(p_pitch_eg_level_2))); + onParam(132,static_cast(*p(p_pitch_eg_level_3))); + onParam(133,static_cast(*p(p_pitch_eg_level_4))); + onParam(134,static_cast(*p(p_algorithm_num)-1)); + onParam(135,static_cast(*p(p_feedback))); + onParam(136,static_cast(*p(p_oscillator_sync))); + onParam(137,static_cast(*p(p_lfo_speed))); + onParam(138,static_cast(*p(p_lfo_delay))); + onParam(139,static_cast(*p(p_lfo_pitch_mod_depth))); + onParam(140,static_cast(*p(p_lfo_amp_mod_depth))); + onParam(141,static_cast(*p(p_lfo_sync))); + onParam(142,static_cast(*p(p_lfo_waveform))); + onParam(143,static_cast(*p(p_pitch_mod_sensitivity))); + onParam(144,static_cast(*p(p_transpose))); + // 10 bytes (145-154) are the name of the patch + onParam(155,0x3f); // operator on/off => All OPs on + + TRACE("Bye"); +} + +// override the run() method +void Dexed::run (uint32_t sample_count) +{ + const LV2_Atom_Sequence* seq = p (p_midi_in); + float* output = p(p_audio_out); + uint32_t last_frame = 0, num_this_time = 0; + + 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) + { + set_params(); // pre_process: copy actual voice params + ring_buffer_.Write ((uint8_t*) LV2_ATOM_BODY (&ev->body), ev->body.size); +#ifdef DEBUG + for(uint i=0;ibody.size;i++) + { + TRACE("midi msg %d: %d\n",i,((uint8_t*)LV2_ATOM_BODY(&ev->body))[i]); + } +#endif + } + + // render audio from the last frame until the timestamp of this event + GetSamples (num_this_time, outbuf16_); + + // 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] = (static_cast (outbuf16_[i])) * *p(p_output); + output[j] = (static_cast (outbuf16_[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, outbuf16_); + for (uint32_t i = 0, j = last_frame; i < num_this_time; ++i, ++j) + //output[j] = (static_cast (outbuf16_[i])) * *p(p_output); + output[j] = (static_cast (outbuf16_[i])); + } + + fx.process(output, sample_count); +} + +void Dexed::GetSamples(int n_samples, int16_t *buffer) +{ + size_t input_offset; + + TransferInput(); + for (input_offset = 0; input_offset < input_buffer_index_; ) { + int bytes_available = input_buffer_index_ - input_offset; + int bytes_consumed = ProcessMidiMessage(input_buffer_ + input_offset, bytes_available); + if (bytes_consumed == 0) { + break; + } + input_offset += bytes_consumed; + } + ConsumeInput(input_offset); + + int i; + if ( refreshVoice ) { + for(i=0;i < MAX_ACTIVE_NOTES;i++) { + if ( voices[i].live ) + voices[i].dx7_note->update(data, voices[i].midi_note, feedback_bitdepth); + } + 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 (int 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 audiobuf; + + for (int j = 0; j < N; ++j) { + audiobuf.get()[j] = 0; + } + int32_t lfovalue = lfo.getsample(); + int32_t lfodelay = lfo.getdelay(); + + for (int note = 0; note < MAX_ACTIVE_NOTES; ++note) { + if (voices[note].live) { + voices[note].dx7_note->compute(audiobuf.get(), lfovalue, lfodelay, &controllers); + + int jmax = n_samples - i; + for (int j = 0; j < N; ++j) { + int32_t val = audiobuf.get()[j] >> 4; + int clip_val = val < -(1 << 24) ? 0x8000 : val >= (1 << 24) ? 0x7fff : val >> 9; + // TODO: maybe some dithering? + if (j < jmax) { + buffer[i + j] = clip_val; + } else { + extra_buf_[j - jmax] = clip_val; + } + } + } + } + } + } + extra_buf_size_ = i - n_samples; +} + +//void Dexed::processMidiMessage(const MidiMessage *msg) { +int Dexed::ProcessMidiMessage(const uint8_t *buf, int buf_size) { + uint8_t cmd = buf[0]; + + switch(cmd & 0xf0) { + case 0x80 : + keyup(buf[1]); + return(3); + + case 0x90 : + keydown(buf[1], buf[2]); + return(3); + + case 0xb0 : { + int ctrl = buf[1]; + int value = buf[2]; + + switch(ctrl) { + case 1: + controllers.modwheel_cc = value; + controllers.refresh(); + break; + case 2: + controllers.breath_cc = value; + controllers.refresh(); + break; + case 4: + controllers.foot_cc = value; + controllers.refresh(); + break; + case 64: + sustain = value > 63; + if (!sustain) { + for (int note = 0; note < MAX_ACTIVE_NOTES; note++) { + if (voices[note].sustained && !voices[note].keydown) { + voices[note].dx7_note->keyup(); + voices[note].sustained = false; + } + } + } + break; + } + } + return(3); + + case 0xc0 : + //setCurrentProgram(buf[1]); + return(3); + + // aftertouch + case 0xd0 : + controllers.aftertouch_cc = buf[1]; + controllers.refresh(); + return(3); + + } + + switch (cmd) { + case 0xe0 : + controllers.values_[kControllerPitch] = buf[1] | (buf[2] << 7); + return(3); + break; + } + return(3); +} + +void Dexed::TransferInput() { + size_t bytes_available = ring_buffer_.BytesAvailable(); + int bytes_to_read = min(bytes_available, + sizeof(input_buffer_) - input_buffer_index_); + if (bytes_to_read > 0) { + ring_buffer_.Read(bytes_to_read, input_buffer_ + input_buffer_index_); + input_buffer_index_ += bytes_to_read; + } +} + +void Dexed::ConsumeInput(size_t n_input_bytes) { + if (n_input_bytes < input_buffer_index_) { + memmove(input_buffer_, input_buffer_ + n_input_bytes, + input_buffer_index_ - n_input_bytes); + } + input_buffer_index_ -= n_input_bytes; +} + +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; + + if ( normalizeDxVelocity ) { + velo = ((float)velo) * 0.7874015; // 100/127 + } + + int note = currentNote; + for (int i=0; iinit(data, pitch, velo, feedback_bitdepth); + if ( data[136] ) + voices[note].dx7_note->oscSync(); + break; + } + note = (note + 1) % MAX_ACTIVE_NOTES; + } + + if ( monoMode ) { + for(int i=0; itransferSignal(*voices[i].dx7_note); + break; + } + if ( voices[i].midi_note < pitch ) { + voices[i].live = false; + voices[note].dx7_note->transferState(*voices[i].dx7_note); + break; + } + return; + } + } + } + + voices[note].live = true; +TRACE("Bye"); +} + +void Dexed::keyup(uint8_t pitch) { +TRACE("Hi"); +TRACE("pitch=%d\n",pitch); + + pitch += data[144] - 24; + + int note; + for (note=0; note= MAX_ACTIVE_NOTES ) { + TRACE("note-off not found???"); + return; + } + + if ( monoMode ) { + int highNote = -1; + int target = 0; + for (int i=0; i highNote ) { + target = i; + highNote = voices[i].midi_note; + } + } + + if ( highNote != -1 ) { + voices[note].live = false; + voices[target].live = true; + voices[target].dx7_note->transferState(*voices[note].dx7_note); + } + } + + if ( sustain ) { + voices[note].sustained = true; + } else { + voices[note].dx7_note->keyup(); + } +TRACE("Bye"); +} + +void Dexed::onParam(int param_num,int param_val) +{ + data[param_num]=param_val; +} + +int Dexed::getEngineType() { + return engineType; +} + +void Dexed::setEngineType(int tp) { + TRACE("settings engine %d", tp); + + switch (tp) { + case DEXED_ENGINE_MARKI: + controllers.core = &engineMkI; + feedback_bitdepth = 11; + break; + case DEXED_ENGINE_OPL: + controllers.core = &engineOpl; + feedback_bitdepth = 11; + break; + default: + controllers.core = &engineMsfa; + feedback_bitdepth = 8; + break; + } + engineType = tp; +} + +void Dexed::setMonoMode(bool mode) { + monoMode = mode; +} + +//============================================================================== + +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);