summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2016-10-02 23:56:47 -0400
committerDavid Robillard <d@drobilla.net>2016-10-02 23:56:47 -0400
commita513af4218d0a62a45960d04ff6ddeecb8d3d4f5 (patch)
tree928d0ded4a352403b01a5b6a20fdd2a47a56256d
parent05d89a68915df359fb50eae7e9a8e44a8bde7e7b (diff)
downloadingen-a513af4218d0a62a45960d04ff6ddeecb8d3d4f5.tar.gz
ingen-a513af4218d0a62a45960d04ff6ddeecb8d3d4f5.tar.bz2
ingen-a513af4218d0a62a45960d04ff6ddeecb8d3d4f5.zip
Add event outputs to Trigger and Controller
-rw-r--r--src/server/Buffer.cpp11
-rw-r--r--src/server/Buffer.hpp5
-rw-r--r--src/server/InputPort.cpp1
-rw-r--r--src/server/internals/Controller.cpp69
-rw-r--r--src/server/internals/Controller.hpp5
-rw-r--r--src/server/internals/Trigger.cpp72
-rw-r--r--src/server/internals/Trigger.hpp7
7 files changed, 117 insertions, 53 deletions
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 <http://drobilla.net/>
+ Copyright 2007-2016 David Robillard <http://drobilla.net/>
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 <http://drobilla.net/>
+ Copyright 2007-2016 David Robillard <http://drobilla.net/>
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 <http://drobilla.net/>
+ Copyright 2007-2016 David Robillard <http://drobilla.net/>
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<PortImpl*>(6);
+ _ports = new Raul::Array<PortImpl*>(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<LV2_Atom_Sequence>();
+ const BufferRef midi_in = _midi_in_port->buffer(0);
+ LV2_Atom_Sequence* seq = midi_in->get<LV2_Atom_Sequence>();
+ 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 <http://drobilla.net/>
+ Copyright 2007-2016 David Robillard <http://drobilla.net/>
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 <http://drobilla.net/>
+ Copyright 2007-2016 David Robillard <http://drobilla.net/>
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<PortImpl*>(5);
+ _ports = new Raul::Array<PortImpl*>(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<LV2_Atom_Sequence>();
+ const BufferRef midi_in = _midi_in_port->buffer(0);
+ LV2_Atom_Sequence* const seq = midi_in->get<LV2_Atom_Sequence>();
+ 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 <http://drobilla.net/>
+ Copyright 2007-2016 David Robillard <http://drobilla.net/>
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;