From a513af4218d0a62a45960d04ff6ddeecb8d3d4f5 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 2 Oct 2016 23:56:47 -0400 Subject: Add event outputs to Trigger and Controller --- src/server/Buffer.cpp | 11 ++++-- src/server/Buffer.hpp | 5 ++- src/server/InputPort.cpp | 1 + src/server/internals/Controller.cpp | 69 +++++++++++++++++++++++------------ src/server/internals/Controller.hpp | 5 +-- src/server/internals/Trigger.cpp | 72 +++++++++++++++++++++++++------------ src/server/internals/Trigger.hpp | 7 ++-- 7 files changed, 117 insertions(+), 53 deletions(-) (limited to 'src/server') diff --git a/src/server/Buffer.cpp b/src/server/Buffer.cpp index 2e977845..e08510a5 100644 --- a/src/server/Buffer.cpp +++ b/src/server/Buffer.cpp @@ -1,6 +1,6 @@ /* This file is part of Ingen. - Copyright 2007-2015 David Robillard + Copyright 2007-2016 David Robillard Ingen is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free @@ -112,7 +112,8 @@ Buffer::recycle() void Buffer::set_type(LV2_URID type, LV2_URID value_type) { - _type = type; + _type = type; + _value_type = value_type; if (type == _factory.uris().atom_Sequence && value_type) { _value_buffer = _factory.get_buffer(value_type, 0, 0, false); } @@ -333,6 +334,12 @@ Buffer::append_event(int64_t frames, return true; } +bool +Buffer::append_event(int64_t frames, const LV2_Atom* body) +{ + return append_event(frames, body->size, body->type, (const uint8_t*)(body + 1)); +} + SampleCount Buffer::next_value_offset(SampleCount offset, SampleCount end) const { diff --git a/src/server/Buffer.hpp b/src/server/Buffer.hpp index 6944257f..12556714 100644 --- a/src/server/Buffer.hpp +++ b/src/server/Buffer.hpp @@ -1,6 +1,6 @@ /* This file is part of Ingen. - Copyright 2007-2015 David Robillard + Copyright 2007-2016 David Robillard Ingen is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free @@ -168,6 +168,9 @@ public: uint32_t type, const uint8_t* data); + /// Sequence buffers only + bool append_event(int64_t frames, const LV2_Atom* body); + /// Value buffer for numeric sequences BufferRef value_buffer() { return _value_buffer; } const BufferRef value_buffer() const { return _value_buffer; } diff --git a/src/server/InputPort.cpp b/src/server/InputPort.cpp index 71fd69e4..c4f44440 100644 --- a/src/server/InputPort.cpp +++ b/src/server/InputPort.cpp @@ -223,6 +223,7 @@ InputPort::next_value_offset(SampleCount offset, SampleCount end) const void InputPort::update_values(SampleCount offset, uint32_t voice) { + buffer(voice)->update_value_buffer(offset); } void diff --git a/src/server/internals/Controller.cpp b/src/server/internals/Controller.cpp index be015af5..4b6f9c02 100644 --- a/src/server/internals/Controller.cpp +++ b/src/server/internals/Controller.cpp @@ -1,6 +1,6 @@ /* This file is part of Ingen. - Copyright 2007-2015 David Robillard + Copyright 2007-2016 David Robillard Ingen is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free @@ -51,7 +51,7 @@ ControllerNode::ControllerNode(InternalPlugin* plugin, , _learning(false) { const Ingen::URIs& uris = bufs.uris(); - _ports = new Raul::Array(6); + _ports = new Raul::Array(7); const Atom zero = bufs.forge().make(0.0f); const Atom one = bufs.forge().make(1.0f); @@ -64,60 +64,72 @@ ControllerNode::ControllerNode(InternalPlugin* plugin, bufs.forge().make_urid(uris.midi_MidiEvent)); _ports->at(0) = _midi_in_port; - _param_port = new InputPort(bufs, this, Raul::Symbol("controller"), 1, 1, + _midi_out_port = new OutputPort(bufs, this, Raul::Symbol("event"), 1, 1, + PortType::ATOM, uris.atom_Sequence, Atom()); + _midi_out_port->set_property(uris.lv2_name, bufs.forge().alloc("Event")); + _midi_out_port->set_property(uris.atom_supports, + bufs.forge().make_urid(uris.midi_MidiEvent)); + _ports->at(1) = _midi_out_port; + + _param_port = new InputPort(bufs, this, Raul::Symbol("controller"), 2, 1, PortType::ATOM, uris.atom_Sequence, zero); _param_port->set_property(uris.atom_supports, atom_Float); _param_port->set_property(uris.lv2_minimum, zero); _param_port->set_property(uris.lv2_maximum, bufs.forge().make(127.0f)); _param_port->set_property(uris.lv2_portProperty, uris.lv2_integer); _param_port->set_property(uris.lv2_name, bufs.forge().alloc("Controller")); - _ports->at(1) = _param_port; + _ports->at(2) = _param_port; - _log_port = new InputPort(bufs, this, Raul::Symbol("logarithmic"), 2, 1, + _log_port = new InputPort(bufs, this, Raul::Symbol("logarithmic"), 3, 1, PortType::ATOM, uris.atom_Sequence, zero); _log_port->set_property(uris.atom_supports, atom_Float); _log_port->set_property(uris.lv2_portProperty, uris.lv2_toggled); _log_port->set_property(uris.lv2_name, bufs.forge().alloc("Logarithmic")); - _ports->at(2) = _log_port; + _ports->at(3) = _log_port; - _min_port = new InputPort(bufs, this, Raul::Symbol("minimum"), 3, 1, + _min_port = new InputPort(bufs, this, Raul::Symbol("minimum"), 4, 1, PortType::ATOM, uris.atom_Sequence, zero); _min_port->set_property(uris.atom_supports, atom_Float); _min_port->set_property(uris.lv2_name, bufs.forge().alloc("Minimum")); - _ports->at(3) = _min_port; + _ports->at(4) = _min_port; - _max_port = new InputPort(bufs, this, Raul::Symbol("maximum"), 4, 1, + _max_port = new InputPort(bufs, this, Raul::Symbol("maximum"), 5, 1, PortType::ATOM, uris.atom_Sequence, one); _max_port->set_property(uris.atom_supports, atom_Float); _max_port->set_property(uris.lv2_name, bufs.forge().alloc("Maximum")); - _ports->at(4) = _max_port; + _ports->at(5) = _max_port; - _audio_port = new OutputPort(bufs, this, Raul::Symbol("output"), 5, 1, + _audio_port = new OutputPort(bufs, this, Raul::Symbol("output"), 6, 1, PortType::ATOM, uris.atom_Sequence, zero); _audio_port->set_property(uris.atom_supports, atom_Float); _audio_port->set_property(uris.lv2_name, bufs.forge().alloc("Output")); - _ports->at(5) = _audio_port; + _ports->at(6) = _audio_port; } void ControllerNode::run(RunContext& context) { - Buffer* const midi_in = _midi_in_port->buffer(0).get(); - LV2_Atom_Sequence* seq = midi_in->get(); + const BufferRef midi_in = _midi_in_port->buffer(0); + LV2_Atom_Sequence* seq = midi_in->get(); + const BufferRef midi_out = _midi_out_port->buffer(0); LV2_ATOM_SEQUENCE_FOREACH(seq, ev) { const uint8_t* buf = (const uint8_t*)LV2_ATOM_BODY(&ev->body); if (ev->body.type == _midi_in_port->bufs().uris().midi_MidiEvent && ev->body.size >= 3 && lv2_midi_message_type(buf) == LV2_MIDI_MSG_CONTROLLER) { - control(context, buf[1], buf[2], ev->time.frames + context.start()); + if (control(context, buf[1], buf[2], ev->time.frames + context.start())) { + midi_out->append_event(ev->time.frames, &ev->body); + } + } } } -void +bool ControllerNode::control(RunContext& context, uint8_t control_num, uint8_t val, FrameTime time) { - Sample scaled_value; + assert(time >= context.start() && time <= context.end()); + const uint32_t offset = time - context.start(); const Sample nval = (val / 127.0f); // normalized [0, 1] @@ -125,12 +137,23 @@ ControllerNode::control(RunContext& context, uint8_t control_num, uint8_t val, F _param_port->set_control_value(context, time, control_num); _param_port->force_monitor_update(); _learning = false; + } else { + _param_port->update_values(offset, 0); + } + + if (control_num != _param_port->buffer(0)->value_at(offset)) { + return false; + } + + for (const auto& port : { _min_port, _max_port, _log_port }) { + port->update_values(offset, 0); } - const Sample min_port_val = _min_port->buffer(0)->value_at(0); - const Sample max_port_val = _max_port->buffer(0)->value_at(0); - const Sample log_port_val = _log_port->buffer(0)->value_at(0); + const Sample min_port_val = _min_port->buffer(0)->value_at(offset); + const Sample max_port_val = _max_port->buffer(0)->value_at(offset); + const Sample log_port_val = _log_port->buffer(0)->value_at(offset); + Sample scaled_value; if (log_port_val > 0.0f) { // haaaaack, stupid negatives and logarithms Sample log_offset = 0; @@ -143,9 +166,9 @@ ControllerNode::control(RunContext& context, uint8_t control_num, uint8_t val, F scaled_value = ((nval) * (max_port_val - min_port_val)) + min_port_val; } - if (control_num == _param_port->buffer(0)->value_at(0)) { - _audio_port->set_control_value(context, time, scaled_value); - } + _audio_port->set_control_value(context, time, scaled_value); + + return true; } } // namespace Internals diff --git a/src/server/internals/Controller.hpp b/src/server/internals/Controller.hpp index 31751658..720f78c0 100644 --- a/src/server/internals/Controller.hpp +++ b/src/server/internals/Controller.hpp @@ -1,6 +1,6 @@ /* This file is part of Ingen. - Copyright 2007-2015 David Robillard + Copyright 2007-2016 David Robillard Ingen is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free @@ -47,7 +47,7 @@ public: void run(RunContext& context); - void control(RunContext& context, uint8_t control_num, uint8_t val, FrameTime time); + bool control(RunContext& context, uint8_t control_num, uint8_t val, FrameTime time); void learn() { _learning = true; } @@ -55,6 +55,7 @@ public: private: InputPort* _midi_in_port; + OutputPort* _midi_out_port; InputPort* _param_port; InputPort* _log_port; InputPort* _min_port; diff --git a/src/server/internals/Trigger.cpp b/src/server/internals/Trigger.cpp index 49a3a2ed..dc703271 100644 --- a/src/server/internals/Trigger.cpp +++ b/src/server/internals/Trigger.cpp @@ -1,6 +1,6 @@ /* This file is part of Ingen. - Copyright 2007-2015 David Robillard + Copyright 2007-2016 David Robillard Ingen is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free @@ -51,7 +51,7 @@ TriggerNode::TriggerNode(InternalPlugin* plugin, , _learning(false) { const Ingen::URIs& uris = bufs.uris(); - _ports = new Raul::Array(5); + _ports = new Raul::Array(6); const Atom zero = bufs.forge().make(0.0f); @@ -62,7 +62,14 @@ TriggerNode::TriggerNode(InternalPlugin* plugin, bufs.forge().make_urid(uris.midi_MidiEvent)); _ports->at(0) = _midi_in_port; - _note_port = new InputPort(bufs, this, Raul::Symbol("note"), 1, 1, + _midi_out_port = new OutputPort(bufs, this, Raul::Symbol("event"), 1, 1, + PortType::ATOM, uris.atom_Sequence, Atom()); + _midi_out_port->set_property(uris.lv2_name, bufs.forge().alloc("Event")); + _midi_out_port->set_property(uris.atom_supports, + bufs.forge().make_urid(uris.midi_MidiEvent)); + _ports->at(1) = _midi_out_port; + + _note_port = new InputPort(bufs, this, Raul::Symbol("note"), 2, 1, PortType::ATOM, uris.atom_Sequence, bufs.forge().make(60.0f)); _note_port->set_property(uris.atom_supports, bufs.uris().atom_Float); @@ -70,69 +77,82 @@ TriggerNode::TriggerNode(InternalPlugin* plugin, _note_port->set_property(uris.lv2_maximum, bufs.forge().make(127.0f)); _note_port->set_property(uris.lv2_portProperty, uris.lv2_integer); _note_port->set_property(uris.lv2_name, bufs.forge().alloc("Note")); - _ports->at(1) = _note_port; + _ports->at(2) = _note_port; - _gate_port = new OutputPort(bufs, this, Raul::Symbol("gate"), 2, 1, + _gate_port = new OutputPort(bufs, this, Raul::Symbol("gate"), 3, 1, PortType::ATOM, uris.atom_Sequence, zero); _gate_port->set_property(uris.atom_supports, bufs.uris().atom_Float); _gate_port->set_property(uris.lv2_portProperty, uris.lv2_toggled); _gate_port->set_property(uris.lv2_name, bufs.forge().alloc("Gate")); - _ports->at(2) = _gate_port; + _ports->at(3) = _gate_port; - _trig_port = new OutputPort(bufs, this, Raul::Symbol("trigger"), 3, 1, + _trig_port = new OutputPort(bufs, this, Raul::Symbol("trigger"), 4, 1, PortType::ATOM, uris.atom_Sequence, zero); _trig_port->set_property(uris.atom_supports, bufs.uris().atom_Float); _trig_port->set_property(uris.lv2_portProperty, uris.lv2_toggled); _trig_port->set_property(uris.lv2_name, bufs.forge().alloc("Trigger")); - _ports->at(3) = _trig_port; + _ports->at(4) = _trig_port; - _vel_port = new OutputPort(bufs, this, Raul::Symbol("velocity"), 4, 1, + _vel_port = new OutputPort(bufs, this, Raul::Symbol("velocity"), 5, 1, PortType::ATOM, uris.atom_Sequence, zero); _vel_port->set_property(uris.atom_supports, bufs.uris().atom_Float); _vel_port->set_property(uris.lv2_minimum, zero); _vel_port->set_property(uris.lv2_maximum, bufs.forge().make(1.0f)); _vel_port->set_property(uris.lv2_name, bufs.forge().alloc("Velocity")); - _ports->at(4) = _vel_port; + _ports->at(5) = _vel_port; } void TriggerNode::run(RunContext& context) { - Buffer* const midi_in = _midi_in_port->buffer(0).get(); - LV2_Atom_Sequence* seq = midi_in->get(); + const BufferRef midi_in = _midi_in_port->buffer(0); + LV2_Atom_Sequence* const seq = midi_in->get(); + const BufferRef midi_out = _midi_out_port->buffer(0); + + // Initialise output to the empty sequence + midi_out->prepare_write(context); + LV2_ATOM_SEQUENCE_FOREACH(seq, ev) { - const uint8_t* buf = (const uint8_t*)LV2_ATOM_BODY(&ev->body); + const int64_t t = ev->time.frames; + const uint8_t* buf = (const uint8_t*)LV2_ATOM_BODY(&ev->body); + bool emit = false; if (ev->body.type == _midi_in_port->bufs().uris().midi_MidiEvent && ev->body.size >= 3) { - const FrameTime time = context.start() + ev->time.frames; + const FrameTime time = context.start() + t; switch (lv2_midi_message_type(buf)) { case LV2_MIDI_MSG_NOTE_ON: if (buf[2] == 0) { - note_off(context, buf[1], time); + emit = note_off(context, buf[1], time); } else { - note_on(context, buf[1], buf[2], time); + emit = note_on(context, buf[1], buf[2], time); } break; case LV2_MIDI_MSG_NOTE_OFF: - note_off(context, buf[1], time); + emit = note_off(context, buf[1], time); break; case LV2_MIDI_MSG_CONTROLLER: switch (buf[1]) { case LV2_MIDI_CTL_ALL_NOTES_OFF: case LV2_MIDI_CTL_ALL_SOUNDS_OFF: _gate_port->set_control_value(context, time, 0.0f); + emit = true; } default: break; } } + + if (emit) { + midi_out->append_event(t, &ev->body); + } } } -void +bool TriggerNode::note_on(RunContext& context, uint8_t note_num, uint8_t velocity, FrameTime time) { assert(time >= context.start() && time <= context.end()); + const uint32_t offset = time - context.start(); if (_learning) { _note_port->set_control_value(context, time, (float)note_num); @@ -140,22 +160,30 @@ TriggerNode::note_on(RunContext& context, uint8_t note_num, uint8_t velocity, Fr _learning = false; } - const Sample filter_note = _note_port->buffer(0)->value_at(0); - if (filter_note >= 0.0 && filter_note < 127.0 && (note_num == (uint8_t)filter_note)) { + _note_port->update_values(offset, 0); + if (note_num == lrintf(_note_port->buffer(0)->value_at(offset))) { _gate_port->set_control_value(context, time, 1.0f); _trig_port->set_control_value(context, time, 1.0f); _trig_port->set_control_value(context, time + 1, 0.0f); _vel_port->set_control_value(context, time, velocity / 127.0f); + return true; } + return false; } -void +bool TriggerNode::note_off(RunContext& context, uint8_t note_num, FrameTime time) { assert(time >= context.start() && time <= context.end()); + const uint32_t offset = time - context.start(); - if (note_num == lrintf(_note_port->buffer(0)->value_at(0))) + _note_port->update_values(offset, 0); + if (note_num == lrintf(_note_port->buffer(0)->value_at(offset))) { _gate_port->set_control_value(context, time, 0.0f); + return true; + } + + return false; } } // namespace Internals diff --git a/src/server/internals/Trigger.hpp b/src/server/internals/Trigger.hpp index 801e97f6..4d67395a 100644 --- a/src/server/internals/Trigger.hpp +++ b/src/server/internals/Trigger.hpp @@ -1,6 +1,6 @@ /* This file is part of Ingen. - Copyright 2007-2015 David Robillard + Copyright 2007-2016 David Robillard Ingen is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free @@ -50,8 +50,8 @@ public: void run(RunContext& context); - void note_on(RunContext& context, uint8_t note_num, uint8_t velocity, FrameTime time); - void note_off(RunContext& context, uint8_t note_num, FrameTime time); + bool note_on(RunContext& context, uint8_t note_num, uint8_t velocity, FrameTime time); + bool note_off(RunContext& context, uint8_t note_num, FrameTime time); void learn() { _learning = true; } @@ -61,6 +61,7 @@ private: bool _learning; InputPort* _midi_in_port; + OutputPort* _midi_out_port; InputPort* _note_port; OutputPort* _gate_port; OutputPort* _trig_port; -- cgit v1.2.1