diff options
author | David Robillard <d@drobilla.net> | 2011-04-20 16:26:40 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2011-04-20 16:26:40 +0000 |
commit | 138a87e915ad3aff184730415105f94c874174bf (patch) | |
tree | 0d942bdddfdbcc3d969b4fce5592e770ab851b86 /src/engine/internals | |
parent | 1f1758f4dda0ddaf01c0b1d3a756f9db8ddc979d (diff) | |
download | ingen-138a87e915ad3aff184730415105f94c874174bf.tar.gz ingen-138a87e915ad3aff184730415105f94c874174bf.tar.bz2 ingen-138a87e915ad3aff184730415105f94c874174bf.zip |
Rename Ingen::Engine to Ingen::Server (hopefully avoid odd name clases and fix #675).
git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@3184 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src/engine/internals')
-rw-r--r-- | src/engine/internals/Controller.cpp | 147 | ||||
-rw-r--r-- | src/engine/internals/Controller.hpp | 74 | ||||
-rw-r--r-- | src/engine/internals/Delay.cpp | 208 | ||||
-rw-r--r-- | src/engine/internals/Delay.hpp | 78 | ||||
-rw-r--r-- | src/engine/internals/Note.cpp | 416 | ||||
-rw-r--r-- | src/engine/internals/Note.hpp | 101 | ||||
-rw-r--r-- | src/engine/internals/Trigger.cpp | 168 | ||||
-rw-r--r-- | src/engine/internals/Trigger.hpp | 77 |
8 files changed, 0 insertions, 1269 deletions
diff --git a/src/engine/internals/Controller.cpp b/src/engine/internals/Controller.cpp deleted file mode 100644 index 15156f08..00000000 --- a/src/engine/internals/Controller.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2007-2011 David Robillard <http://drobilla.net> - * - * Ingen 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 2 of the License, or (at your option) any later - * version. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <math.h> -#include "raul/midi_events.h" -#include "shared/LV2URIMap.hpp" -#include "internals/Controller.hpp" -#include "PostProcessor.hpp" -#include "events/SendPortValue.hpp" -#include "InputPort.hpp" -#include "OutputPort.hpp" -#include "InternalPlugin.hpp" -#include "AudioBuffer.hpp" -#include "ProcessContext.hpp" -#include "EventBuffer.hpp" -#include "util.hpp" - -using namespace std; - -namespace Ingen { -namespace Engine { -namespace Internals { - -InternalPlugin* ControllerNode::internal_plugin(Shared::LV2URIMap& uris) { - return new InternalPlugin(uris, NS_INTERNALS "Controller", "controller"); -} - -ControllerNode::ControllerNode(InternalPlugin* plugin, - BufferFactory& bufs, - const string& path, - bool polyphonic, - PatchImpl* parent, - SampleRate srate) - : NodeImpl(plugin, path, false, parent, srate) - , _learning(false) -{ - const Ingen::Shared::LV2URIMap& uris = bufs.uris(); - _ports = new Raul::Array<PortImpl*>(6); - - _midi_in_port = new InputPort(bufs, this, "input", 0, 1, PortType::EVENTS, Raul::Atom()); - _midi_in_port->set_property(uris.lv2_name, "Input"); - _ports->at(0) = _midi_in_port; - - _param_port = new InputPort(bufs, this, "controller", 1, 1, PortType::CONTROL, 0.0f); - _param_port->set_property(uris.lv2_minimum, 0.0f); - _param_port->set_property(uris.lv2_maximum, 127.0f); - _param_port->set_property(uris.lv2_integer, true); - _param_port->set_property(uris.lv2_name, "Controller"); - _ports->at(1) = _param_port; - - _log_port = new InputPort(bufs, this, "logarithmic", 2, 1, PortType::CONTROL, 0.0f); - _log_port->set_property(uris.lv2_portProperty, uris.lv2_toggled); - _log_port->set_property(uris.lv2_name, "Logarithmic"); - _ports->at(2) = _log_port; - - _min_port = new InputPort(bufs, this, "minimum", 3, 1, PortType::CONTROL, 0.0f); - _min_port->set_property(uris.lv2_name, "Minimum"); - _ports->at(3) = _min_port; - - _max_port = new InputPort(bufs, this, "maximum", 4, 1, PortType::CONTROL, 1.0f); - _max_port->set_property(uris.lv2_name, "Maximum"); - _ports->at(4) = _max_port; - - _audio_port = new OutputPort(bufs, this, "ar_output", 5, 1, PortType::AUDIO, 0.0f); - _audio_port->set_property(uris.lv2_name, "Output"); - _ports->at(5) = _audio_port; -} - -void -ControllerNode::process(ProcessContext& context) -{ - NodeImpl::pre_process(context); - - uint32_t frames = 0; - uint32_t subframes = 0; - uint16_t type = 0; - uint16_t size = 0; - uint8_t* buf = NULL; - - EventBuffer* const midi_in = (EventBuffer*)_midi_in_port->buffer(0).get(); - - midi_in->rewind(); - - while (midi_in->get_event(&frames, &subframes, &type, &size, &buf)) { - // FIXME: type - if (size >= 3 && (buf[0] & 0xF0) == MIDI_CMD_CONTROL) - control(context, buf[1], buf[2], frames + context.start()); - - midi_in->increment(); - } - - NodeImpl::post_process(context); -} - -void -ControllerNode::control(ProcessContext& context, uint8_t control_num, uint8_t val, FrameTime time) -{ - Sample scaled_value; - - const Sample nval = (val / 127.0f); // normalized [0, 1] - - if (_learning) { - _param_port->set_value(control_num); - ((AudioBuffer*)_param_port->buffer(0).get())->set_value( - (float)control_num, context.start(), context.end()); - _param_port->broadcast_value(context, true); - _learning = false; - } - - const Sample min_port_val = ((AudioBuffer*)_min_port->buffer(0).get())->value_at(0); - const Sample max_port_val = ((AudioBuffer*)_max_port->buffer(0).get())->value_at(0); - const Sample log_port_val = ((AudioBuffer*)_log_port->buffer(0).get())->value_at(0); - - if (log_port_val > 0.0f) { - // haaaaack, stupid negatives and logarithms - Sample log_offset = 0; - if (min_port_val < 0) - log_offset = fabs(min_port_val); - const Sample min = log(min_port_val + 1 + log_offset); - const Sample max = log(max_port_val + 1 + log_offset); - scaled_value = expf(nval * (max - min) + min) - 1 - log_offset; - } else { - scaled_value = ((nval) * (max_port_val - min_port_val)) + min_port_val; - } - - if (control_num == ((AudioBuffer*)_param_port->buffer(0).get())->value_at(0)) - ((AudioBuffer*)_audio_port->buffer(0).get())->set_value(scaled_value, context.start(), time); -} - -} // namespace Internals -} // namespace Engine -} // namespace Ingen - diff --git a/src/engine/internals/Controller.hpp b/src/engine/internals/Controller.hpp deleted file mode 100644 index 54b1d3ac..00000000 --- a/src/engine/internals/Controller.hpp +++ /dev/null @@ -1,74 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2007-2011 David Robillard <http://drobilla.net> - * - * Ingen 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 2 of the License, or (at your option) any later - * version. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef INGEN_INTERNALS_CONTROLLER_HPP -#define INGEN_INTERNALS_CONTROLLER_HPP - -#include <string> -#include "NodeImpl.hpp" - -namespace Ingen { -namespace Engine { - -class InputPort; -class OutputPort; -class InternalPlugin; - -namespace Internals { - -/** MIDI control input node. - * - * Creating one of these nodes is how a user makes "MIDI Bindings". Note that - * this node will always be monophonic, the poly parameter is ignored. - * - * \ingroup engine - */ -class ControllerNode : public NodeImpl -{ -public: - ControllerNode( - InternalPlugin* plugin, - BufferFactory& bufs, - const std::string& path, - bool polyphonic, - PatchImpl* parent, - SampleRate srate); - - void process(ProcessContext& context); - - void control(ProcessContext& context, uint8_t control_num, uint8_t val, FrameTime time); - - void learn() { _learning = true; } - - static InternalPlugin* internal_plugin(Shared::LV2URIMap& uris); - -private: - bool _learning; - - InputPort* _midi_in_port; - InputPort* _param_port; - InputPort* _log_port; - InputPort* _min_port; - InputPort* _max_port; - OutputPort* _audio_port; -}; - -} // namespace Engine -} // namespace Ingen -} // namespace Internals - -#endif // INGEN_INTERNALS_CONTROLLER_HPP diff --git a/src/engine/internals/Delay.cpp b/src/engine/internals/Delay.cpp deleted file mode 100644 index bded108a..00000000 --- a/src/engine/internals/Delay.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2007-2011 David Robillard <http://drobilla.net> - * - * Ingen 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 2 of the License, or (at your option) any later - * version. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <cmath> -#include <limits.h> -#include "raul/log.hpp" -#include "raul/Array.hpp" -#include "raul/Maid.hpp" -#include "raul/midi_events.h" -#include "shared/LV2URIMap.hpp" -#include "internals/Delay.hpp" -#include "AudioBuffer.hpp" -#include "Driver.hpp" -#include "EventBuffer.hpp" -#include "InputPort.hpp" -#include "InternalPlugin.hpp" -#include "OutputPort.hpp" -#include "PatchImpl.hpp" -#include "ProcessContext.hpp" -#include "ingen-config.h" -#include "util.hpp" - -#define LOG(s) s << "[DelayNode] " - -#define CALC_DELAY(delaytime) \ - (f_clamp (delaytime * (float)sample_rate, 1.0f, (float)(buffer_mask + 1))) - -using namespace std; -using namespace Raul; - -namespace Ingen { -namespace Engine { -namespace Internals { - -static const float MAX_DELAY_SECONDS = 8.0f; - -InternalPlugin* DelayNode::internal_plugin(Shared::LV2URIMap& uris) { - return new InternalPlugin(uris, NS_INTERNALS "Delay", "delay"); -} - -DelayNode::DelayNode( - InternalPlugin* plugin, - BufferFactory& bufs, - const std::string& path, - bool polyphonic, - PatchImpl* parent, - SampleRate srate) - : NodeImpl(plugin, path, polyphonic, parent, srate) - , _buffer(0) - , _buffer_length(0) - , _buffer_mask(0) - , _write_phase(0) -{ - const Ingen::Shared::LV2URIMap& uris = bufs.uris(); - _ports = new Raul::Array<PortImpl*>(3); - - const float default_delay = 1.0f; - _last_delay_time = default_delay; - _delay_samples = default_delay; - - _delay_port = new InputPort(bufs, this, "delay", 1, _polyphony, PortType::CONTROL, default_delay); - _delay_port->set_property(uris.lv2_name, "Delay"); - _delay_port->set_property(uris.lv2_default, default_delay); - _delay_port->set_property(uris.lv2_minimum, (float)(1.0/(double)srate)); - _delay_port->set_property(uris.lv2_maximum, MAX_DELAY_SECONDS); - _ports->at(0) = _delay_port; - - _in_port = new InputPort(bufs, this, "in", 0, 1, PortType::AUDIO, 0.0f); - _in_port->set_property(uris.lv2_name, "Input"); - _ports->at(1) = _in_port; - - _out_port = new OutputPort(bufs, this, "out", 0, 1, PortType::AUDIO, 0.0f); - _out_port->set_property(uris.lv2_name, "Output"); - _ports->at(2) = _out_port; - - //_buffer = bufs.get(PortType::AUDIO, bufs.audio_buffer_size(buffer_length_frames), true); - -} - -DelayNode::~DelayNode() -{ - //_buffer.reset(); - free(_buffer); -} - -void -DelayNode::activate(BufferFactory& bufs) -{ - NodeImpl::activate(bufs); - const SampleCount min_size = MAX_DELAY_SECONDS * _srate; - - // Smallest power of two larger than min_size - SampleCount size = 1; - while (size < min_size) - size <<= 1; - - _buffer = (float*)calloc(size, sizeof(float)); - _buffer_mask = size - 1; - _buffer_length = size; - //_buffer->clear(); - _write_phase = 0; -} - -static inline float f_clamp(float x, float a, float b) -{ - const float x1 = fabs(x - a); - const float x2 = fabs(x - b); - - x = x1 + a + b; - x -= x2; - x *= 0.5; - - return x; -} - -static inline float cube_interp(const float fr, const float inm1, const float - in, const float inp1, const float inp2) -{ - return in + 0.5f * fr * (inp1 - inm1 + - fr * (4.0f * inp1 + 2.0f * inm1 - 5.0f * in - inp2 + - fr * (3.0f * (in - inp1) - inm1 + inp2))); -} - -void -DelayNode::process(ProcessContext& context) -{ - AudioBuffer* const delay_buf = (AudioBuffer*)_delay_port->buffer(0).get(); - AudioBuffer* const in_buf = (AudioBuffer*)_in_port->buffer(0).get(); - AudioBuffer* const out_buf = (AudioBuffer*)_out_port->buffer(0).get(); - - NodeImpl::pre_process(context); - - DelayNode* plugin_data = this; - - const float* const in = in_buf->data(); - float* const out = out_buf->data(); - const float delay_time = delay_buf->data()[0]; - const uint32_t buffer_mask = plugin_data->_buffer_mask; - const unsigned int sample_rate = plugin_data->_srate; - float delay_samples = plugin_data->_delay_samples; - long write_phase = plugin_data->_write_phase; - const uint32_t sample_count = context.nframes(); - - if (write_phase == 0) { - _last_delay_time = delay_time; - _delay_samples = delay_samples = CALC_DELAY(delay_time); - } - - if (delay_time == _last_delay_time) { - const long idelay_samples = (long)delay_samples; - const float frac = delay_samples - idelay_samples; - - for (uint32_t i = 0; i < sample_count; i++) { - long read_phase = write_phase - (long)delay_samples; - const float read = cube_interp(frac, - buffer_at(read_phase - 1), - buffer_at(read_phase), - buffer_at(read_phase + 1), - buffer_at(read_phase + 2)); - buffer_at(write_phase++) = in[i]; - out[i] = read; - } - } else { - const float next_delay_samples = CALC_DELAY(delay_time); - const float delay_samples_slope = (next_delay_samples - delay_samples) / sample_count; - - for (uint32_t i = 0; i < sample_count; i++) { - delay_samples += delay_samples_slope; - write_phase++; - const long read_phase = write_phase - (long)delay_samples; - const long idelay_samples = (long)delay_samples; - const float frac = delay_samples - idelay_samples; - const float read = cube_interp(frac, - buffer_at(read_phase - 1), - buffer_at(read_phase), - buffer_at(read_phase + 1), - buffer_at(read_phase + 2)); - buffer_at(write_phase) = in[i]; - out[i] = read; - } - - _last_delay_time = delay_time; - _delay_samples = delay_samples; - } - - _write_phase = write_phase; - - NodeImpl::post_process(context); -} - -} // namespace Internals -} // namespace Engine -} // namespace Ingen - diff --git a/src/engine/internals/Delay.hpp b/src/engine/internals/Delay.hpp deleted file mode 100644 index bc6f2682..00000000 --- a/src/engine/internals/Delay.hpp +++ /dev/null @@ -1,78 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2007-2011 David Robillard <http://drobilla.net> - * - * Ingen 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 2 of the License, or (at your option) any later - * version. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef INGEN_INTERNALS_DELAY_HPP -#define INGEN_INTERNALS_DELAY_HPP - -#include <string> -#include <math.h> -#include "types.hpp" -#include "NodeImpl.hpp" - -namespace Ingen { -namespace Engine { - -class InputPort; -class OutputPort; -class InternalPlugin; -class BufferFactory; - -namespace Internals { - -class DelayNode : public NodeImpl -{ -public: - DelayNode( - InternalPlugin* plugin, - BufferFactory& bufs, - const std::string& path, - bool polyphonic, - PatchImpl* parent, - SampleRate srate); - - ~DelayNode(); - - void activate(BufferFactory& bufs); - - void process(ProcessContext& context); - - static InternalPlugin* internal_plugin(Shared::LV2URIMap& uris); - - float delay_samples() const { return _delay_samples; } - -private: - inline float& buffer_at(long phase) const { return _buffer[phase & _buffer_mask]; } - - InputPort* _delay_port; - InputPort* _in_port; - OutputPort* _out_port; - - typedef long Phase; - - float* _buffer; - uint32_t _buffer_length; - uint32_t _buffer_mask; - Phase _write_phase; - float _last_delay_time; - float _delay_samples; -}; - -} // namespace Engine -} // namespace Ingen -} // namespace Internals - -#endif // INGEN_INTERNALS_DELAY_HPP diff --git a/src/engine/internals/Note.cpp b/src/engine/internals/Note.cpp deleted file mode 100644 index 8545857e..00000000 --- a/src/engine/internals/Note.cpp +++ /dev/null @@ -1,416 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2007-2011 David Robillard <http://drobilla.net> - * - * Ingen 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 2 of the License, or (at your option) any later - * version. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <cmath> -#include "raul/log.hpp" -#include "raul/Array.hpp" -#include "raul/Maid.hpp" -#include "raul/midi_events.h" -#include "shared/LV2URIMap.hpp" -#include "internals/Note.hpp" -#include "AudioBuffer.hpp" -#include "Driver.hpp" -#include "EventBuffer.hpp" -#include "InputPort.hpp" -#include "InternalPlugin.hpp" -#include "OutputPort.hpp" -#include "PatchImpl.hpp" -#include "ProcessContext.hpp" -#include "util.hpp" -#include "ingen-config.h" - -#define LOG(s) s << "[NoteNode] " - -using namespace std; -using namespace Raul; - -namespace Ingen { -namespace Engine { -namespace Internals { - -InternalPlugin* NoteNode::internal_plugin(Shared::LV2URIMap& uris) { - return new InternalPlugin(uris, NS_INTERNALS "Note", "note"); -} - -NoteNode::NoteNode( - InternalPlugin* plugin, - BufferFactory& bufs, - const std::string& path, - bool polyphonic, - PatchImpl* parent, - SampleRate srate) - : NodeImpl(plugin, path, polyphonic, parent, srate) - , _voices(new Raul::Array<Voice>(_polyphony)) - , _prepared_voices(NULL) - , _sustain(false) -{ - const Ingen::Shared::LV2URIMap& uris = bufs.uris(); - _ports = new Raul::Array<PortImpl*>(5); - - _midi_in_port = new InputPort(bufs, this, "input", 0, 1, PortType::EVENTS, Raul::Atom()); - _midi_in_port->set_property(uris.lv2_name, "Input"); - _ports->at(0) = _midi_in_port; - - _freq_port = new OutputPort(bufs, this, "frequency", 1, _polyphony, PortType::AUDIO, 440.0f); - _freq_port->set_property(uris.lv2_name, "Frequency"); - _ports->at(1) = _freq_port; - - _vel_port = new OutputPort(bufs, this, "velocity", 2, _polyphony, PortType::AUDIO, 0.0f); - _vel_port->set_property(uris.lv2_minimum, 0.0f); - _vel_port->set_property(uris.lv2_maximum, 1.0f); - _vel_port->set_property(uris.lv2_name, "Velocity"); - _ports->at(2) = _vel_port; - - _gate_port = new OutputPort(bufs, this, "gate", 3, _polyphony, PortType::AUDIO, 0.0f); - _gate_port->set_property(uris.lv2_portProperty, uris.lv2_toggled); - _gate_port->set_property(uris.lv2_name, "Gate"); - _ports->at(3) = _gate_port; - - _trig_port = new OutputPort(bufs, this, "trigger", 4, _polyphony, PortType::AUDIO, 0.0f); - _trig_port->set_property(uris.lv2_portProperty, uris.lv2_toggled); - _trig_port->set_property(uris.lv2_name, "Trigger"); - _ports->at(4) = _trig_port; -} - -NoteNode::~NoteNode() -{ - delete _voices; -} - -bool -NoteNode::prepare_poly(BufferFactory& bufs, uint32_t poly) -{ - if (!_polyphonic) - return true; - - NodeImpl::prepare_poly(bufs, poly); - - if (_prepared_voices && poly <= _prepared_voices->size()) - return true; - - _prepared_voices = new Raul::Array<Voice>(poly, *_voices, Voice()); - - return true; -} - -bool -NoteNode::apply_poly(Raul::Maid& maid, uint32_t poly) -{ - if (!NodeImpl::apply_poly(maid, poly)) - return false; - - if (_prepared_voices) { - assert(_polyphony <= _prepared_voices->size()); - maid.push(_voices); - _voices = _prepared_voices; - _prepared_voices = NULL; - } - assert(_polyphony <= _voices->size()); - - return true; -} - -void -NoteNode::process(ProcessContext& context) -{ - EventBuffer* const midi_in = (EventBuffer*)_midi_in_port->buffer(0).get(); - NodeImpl::pre_process(context); - - uint32_t frames = 0; - uint32_t subframes = 0; - uint16_t type = 0; - uint16_t size = 0; - uint8_t* buf = NULL; - - midi_in->rewind(); - - if (midi_in->event_count() > 0) - for (midi_in->rewind(); midi_in->get_event(&frames, &subframes, &type, &size, &buf); - midi_in->increment()) { - -#ifdef RAUL_LOG_DEBUG - LOG(debug) << "EVENT TYPE " << type << " @ " << frames << "." << subframes << ": "; - for (uint16_t i = 0; i < size; ++i) - debug << (int)((char)buf[i]) << " "; - debug << endl; -#endif - - if (frames < context.offset()) - continue; - if (frames > context.nframes()) - break; - - const FrameTime time = context.start() + (FrameTime)frames; - - if (size >= 3) { - switch (buf[0] & 0xF0) { - case MIDI_CMD_NOTE_ON: - if (buf[2] == 0) - note_off(context, buf[1], time); - else - note_on(context, buf[1], buf[2], time); - break; - case MIDI_CMD_NOTE_OFF: - note_off(context, buf[1], time); - break; - case MIDI_CMD_CONTROL: - switch (buf[1]) { - case MIDI_CTL_ALL_NOTES_OFF: - case MIDI_CTL_ALL_SOUNDS_OFF: - all_notes_off(context, time); - break; - case MIDI_CTL_SUSTAIN: - if (buf[2] > 63) - sustain_on(context, time); - else - sustain_off(context, time); - break; - case MIDI_CMD_BENDER: - // ? - break; - default: - //warn << "Ignored controller " << buf[1] << endl; - break; - } - break; - default: - //fprintf(stderr, "Unknown (size %d) MIDI event %X\n", size, buf[0]); - break; - } - } else { - //fprintf(stderr, "Unknown (size %d) MIDI event %X\n", size, buf[0]); - } - } - - NodeImpl::post_process(context); -} - -void -NoteNode::note_on(ProcessContext& context, uint8_t note_num, uint8_t velocity, FrameTime time) -{ - assert(time >= context.start() && time <= context.end()); - assert(note_num <= 127); - - Key* key = &_keys[note_num]; - Voice* voice = NULL; - uint32_t voice_num = 0; - - if (key->state != Key::OFF) { -#ifdef RAUL_LOG_DEBUG - LOG(debug) << "Double midi note received" << endl; -#endif - return; - } - - // Look for free voices - for (uint32_t i=0; i < _polyphony; ++i) { - if ((*_voices)[i].state == Voice::Voice::FREE) { - voice = &(*_voices)[i]; - voice_num = i; - break; - } - } - - // If we didn't find a free one, steal the oldest - if (voice == NULL) { - voice_num = 0; - voice = &(*_voices)[0]; - FrameTime oldest_time = (*_voices)[0].time; - for (uint32_t i=1; i < _polyphony; ++i) { - if ((*_voices)[i].time < oldest_time) { - voice = &(*_voices)[i]; - voice_num = i; - oldest_time = voice->time; - } - } - } - assert(voice != NULL); - assert(voice == &(*_voices)[voice_num]); - -#ifdef RAUL_LOG_DEBUG - LOG(debug) << "Note " << (int)note_num << " on @ " << time - << ". Voice " << voice_num << " / " << _polyphony << endl; -#endif - - // Update stolen key, if applicable - if (voice->state == Voice::Voice::ACTIVE) { - assert(_keys[voice->note].state == Key::ON_ASSIGNED); - assert(_keys[voice->note].voice == voice_num); - _keys[voice->note].state = Key::Key::ON_UNASSIGNED; -#ifdef RAUL_LOG_DEBUG - LOG(debug) << "Stole voice " << voice_num << endl; -#endif - } - - // Store key information for later reallocation on note off - key->state = Key::Key::ON_ASSIGNED; - key->voice = voice_num; - key->time = time; - - // Trigger voice - voice->state = Voice::Voice::ACTIVE; - voice->note = note_num; - voice->time = time; - - assert(_keys[voice->note].state == Key::Key::ON_ASSIGNED); - assert(_keys[voice->note].voice == voice_num); - - ((AudioBuffer*)_freq_port->buffer(voice_num).get())->set_value( - note_to_freq(note_num), context.start(), time); - ((AudioBuffer*)_vel_port->buffer(voice_num).get())->set_value( - velocity/127.0, context.start(), time); - ((AudioBuffer*)_gate_port->buffer(voice_num).get())->set_value( - 1.0f, context.start(), time); - - // trigger (one sample) - ((AudioBuffer*)_trig_port->buffer(voice_num).get())->set_value( - 1.0f, context.start(), time); - ((AudioBuffer*)_trig_port->buffer(voice_num).get())->set_value( - 0.0f, context.start(), time + 1); - - assert(key->state == Key::Key::ON_ASSIGNED); - assert(voice->state == Voice::Voice::ACTIVE); - assert(key->voice == voice_num); - assert((*_voices)[key->voice].note == note_num); -} - -void -NoteNode::note_off(ProcessContext& context, uint8_t note_num, FrameTime time) -{ - assert(time >= context.start() && time <= context.end()); - - Key* key = &_keys[note_num]; - -#ifdef RAUL_LOG_DEBUG - debug << "Note " << (int)note_num << " off @ " << time << endl; -#endif - - if (key->state == Key::ON_ASSIGNED) { - // Assigned key, turn off voice and key - if ((*_voices)[key->voice].state == Voice::ACTIVE) { - assert((*_voices)[key->voice].note == note_num); - - if ( ! _sustain) { -#ifdef RAUL_LOG_DEBUG - debug << "Free voice " << key->voice << endl; -#endif - free_voice(context, key->voice, time); - } else { -#ifdef RAUL_LOG_DEBUG - debug << "Hold voice " << key->voice << endl; -#endif - (*_voices)[key->voice].state = Voice::HOLDING; - } - - } else { -#ifdef RAUL_LOG_DEBUG - debug << "WARNING: Assigned key, but voice not active" << endl; -#endif - } - } - - key->state = Key::OFF; -} - -void -NoteNode::free_voice(ProcessContext& context, uint32_t voice, FrameTime time) -{ - assert(time >= context.start() && time <= context.end()); - - // Find a key to reassign to the freed voice (the newest, if there is one) - Key* replace_key = NULL; - uint8_t replace_key_num = 0; - - for (uint8_t i = 0; i <= 127; ++i) { - if (_keys[i].state == Key::ON_UNASSIGNED) { - if (replace_key == NULL || _keys[i].time > replace_key->time) { - replace_key = &_keys[i]; - replace_key_num = i; - } - } - } - - if (replace_key != NULL) { // Found a key to assign to freed voice - assert(&_keys[replace_key_num] == replace_key); - assert(replace_key->state == Key::ON_UNASSIGNED); - - // Change the freq but leave the gate high and don't retrigger - ((AudioBuffer*)_freq_port->buffer(voice).get())->set_value(note_to_freq(replace_key_num), context.start(), time); - - replace_key->state = Key::ON_ASSIGNED; - replace_key->voice = voice; - _keys[(*_voices)[voice].note].state = Key::ON_UNASSIGNED; - (*_voices)[voice].note = replace_key_num; - (*_voices)[voice].state = Voice::ACTIVE; - } else { - // No new note for voice, deactivate (set gate low) -#ifdef RAUL_LOG_DEBUG - LOG(debug) << "Note off: key " << (*_voices)[voice].note << " voice " << voice << endl; -#endif - ((AudioBuffer*)_gate_port->buffer(voice).get())->set_value(0.0f, context.start(), time); - (*_voices)[voice].state = Voice::FREE; - } -} - -void -NoteNode::all_notes_off(ProcessContext& context, FrameTime time) -{ - assert(time >= context.start() && time <= context.end()); - -#ifdef RAUL_LOG_DEBUG - LOG(debug) << "All notes off @ " << time << endl; -#endif - - // FIXME: set all keys to Key::OFF? - - for (uint32_t i = 0; i < _polyphony; ++i) { - ((AudioBuffer*)_gate_port->buffer(i).get())->set_value(0.0f, context.start(), time); - (*_voices)[i].state = Voice::FREE; - } -} - -float -NoteNode::note_to_freq(int num) -{ - static const float A4 = 440.0f; - if (num >= 0 && num <= 119) - return A4 * powf(2.0f, (float)(num - 57.0f) / 12.0f); - return 1.0f; // Frequency of zero causes numerical problems... -} - -void -NoteNode::sustain_on(ProcessContext& context, FrameTime time) -{ - _sustain = true; -} - -void -NoteNode::sustain_off(ProcessContext& context, FrameTime time) -{ - assert(time >= context.start() && time <= context.end()); - - _sustain = false; - - for (uint32_t i=0; i < _polyphony; ++i) - if ((*_voices)[i].state == Voice::HOLDING) - free_voice(context, i, time); -} - -} // namespace Internals -} // namespace Engine -} // namespace Ingen - diff --git a/src/engine/internals/Note.hpp b/src/engine/internals/Note.hpp deleted file mode 100644 index 7a47dc76..00000000 --- a/src/engine/internals/Note.hpp +++ /dev/null @@ -1,101 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2007-2011 David Robillard <http://drobilla.net> - * - * Ingen 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 2 of the License, or (at your option) any later - * version. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef INGEN_INTERNALS_NOTE_HPP -#define INGEN_INTERNALS_NOTE_HPP - -#include <string> -#include "types.hpp" -#include "NodeImpl.hpp" - -namespace Ingen { -namespace Engine { - -class InputPort; -class OutputPort; -class InternalPlugin; - -namespace Internals { - -/** MIDI note input node. - * - * For pitched instruments like keyboard, etc. - * - * \ingroup engine - */ -class NoteNode : public NodeImpl -{ -public: - NoteNode( - InternalPlugin* plugin, - BufferFactory& bufs, - const std::string& path, - bool polyphonic, - PatchImpl* parent, - SampleRate srate); - - ~NoteNode(); - - bool prepare_poly(BufferFactory& bufs, uint32_t poly); - bool apply_poly(Raul::Maid& maid, uint32_t poly); - - void process(ProcessContext& context); - - void note_on(ProcessContext& context, uint8_t note_num, uint8_t velocity, FrameTime time); - void note_off(ProcessContext& context, uint8_t note_num, FrameTime time); - void all_notes_off(ProcessContext& context, FrameTime time); - - void sustain_on(ProcessContext& context, FrameTime time); - void sustain_off(ProcessContext& context, FrameTime time); - - static InternalPlugin* internal_plugin(Shared::LV2URIMap& uris); - -private: - /** Key, one for each key on the keyboard */ - struct Key { - enum State { OFF, ON_ASSIGNED, ON_UNASSIGNED }; - Key() : state(OFF), voice(0), time(0) {} - State state; uint32_t voice; SampleCount time; - }; - - /** Voice, one of these always exists for each voice */ - struct Voice { - enum State { FREE, ACTIVE, HOLDING }; - Voice() : state(FREE), note(0), time(0) {} - State state; uint8_t note; SampleCount time; - }; - - float note_to_freq(int num); - void free_voice(ProcessContext& context, uint32_t voice, FrameTime time); - - Raul::Array<Voice>* _voices; - Raul::Array<Voice>* _prepared_voices; - Key _keys[128]; - bool _sustain; ///< Whether or not hold pedal is depressed - - InputPort* _midi_in_port; - OutputPort* _freq_port; - OutputPort* _vel_port; - OutputPort* _gate_port; - OutputPort* _trig_port; -}; - -} // namespace Engine -} // namespace Ingen -} // namespace Internals - -#endif // INGEN_INTERNALS_NOTE_HPP diff --git a/src/engine/internals/Trigger.cpp b/src/engine/internals/Trigger.cpp deleted file mode 100644 index 55474618..00000000 --- a/src/engine/internals/Trigger.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2007-2011 David Robillard <http://drobilla.net> - * - * Ingen 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 2 of the License, or (at your option) any later - * version. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <cmath> -#include "raul/log.hpp" -#include "raul/midi_events.h" -#include "shared/LV2URIMap.hpp" -#include "internals/Trigger.hpp" -#include "AudioBuffer.hpp" -#include "EventBuffer.hpp" -#include "InputPort.hpp" -#include "InternalPlugin.hpp" -#include "OutputPort.hpp" -#include "ProcessContext.hpp" -#include "util.hpp" -#include "ingen-config.h" - -#define LOG(s) s << "[TriggerNode] " - -using namespace std; -using namespace Raul; - -namespace Ingen { -namespace Engine { -namespace Internals { - -InternalPlugin* TriggerNode::internal_plugin(Shared::LV2URIMap& uris) { - return new InternalPlugin(uris, NS_INTERNALS "Trigger", "trigger"); -} - -TriggerNode::TriggerNode( - InternalPlugin* plugin, - BufferFactory& bufs, - const std::string& path, - bool polyphonic, - PatchImpl* parent, - SampleRate srate) - : NodeImpl(plugin, path, false, parent, srate) - , _learning(false) -{ - const Ingen::Shared::LV2URIMap& uris = bufs.uris(); - _ports = new Raul::Array<PortImpl*>(5); - - _midi_in_port = new InputPort(bufs, this, "input", 0, 1, PortType::EVENTS, Raul::Atom()); - _midi_in_port->set_property(uris.lv2_name, "Input"); - _ports->at(0) = _midi_in_port; - - _note_port = new InputPort(bufs, this, "note", 1, 1, PortType::CONTROL, 60.0f); - _note_port->set_property(uris.lv2_minimum, 0.0f); - _note_port->set_property(uris.lv2_maximum, 127.0f); - _note_port->set_property(uris.lv2_integer, true); - _note_port->set_property(uris.lv2_name, "Note"); - _ports->at(1) = _note_port; - - _gate_port = new OutputPort(bufs, this, "gate", 2, 1, PortType::AUDIO, 0.0f); - _gate_port->set_property(uris.lv2_portProperty, uris.lv2_toggled); - _gate_port->set_property(uris.lv2_name, "Gate"); - _ports->at(2) = _gate_port; - - _trig_port = new OutputPort(bufs, this, "trigger", 3, 1, PortType::AUDIO, 0.0f); - _trig_port->set_property(uris.lv2_portProperty, uris.lv2_toggled); - _trig_port->set_property(uris.lv2_name, "Trigger"); - _ports->at(3) = _trig_port; - - _vel_port = new OutputPort(bufs, this, "velocity", 4, 1, PortType::AUDIO, 0.0f); - _vel_port->set_property(uris.lv2_minimum, 0.0f); - _vel_port->set_property(uris.lv2_maximum, 1.0f); - _vel_port->set_property(uris.lv2_name, "Velocity"); - _ports->at(4) = _vel_port; -} - -void -TriggerNode::process(ProcessContext& context) -{ - NodeImpl::pre_process(context); - - uint32_t frames = 0; - uint32_t subframes = 0; - uint16_t type = 0; - uint16_t size = 0; - uint8_t* buf = NULL; - - EventBuffer* const midi_in = (EventBuffer*)_midi_in_port->buffer(0).get(); - - midi_in->rewind(); - - while (midi_in->get_event(&frames, &subframes, &type, &size, &buf)) { - const FrameTime time = context.start() + (FrameTime)frames; - - if (size >= 3) { - switch (buf[0] & 0xF0) { - case MIDI_CMD_NOTE_ON: - if (buf[2] == 0) - note_off(context, buf[1], time); - else - note_on(context, buf[1], buf[2], time); - break; - case MIDI_CMD_NOTE_OFF: - note_off(context, buf[1], time); - break; - case MIDI_CMD_CONTROL: - if (buf[1] == MIDI_CTL_ALL_NOTES_OFF - || buf[1] == MIDI_CTL_ALL_SOUNDS_OFF) - ((AudioBuffer*)_gate_port->buffer(0).get())->set_value(0.0f, context.start(), time); - default: - break; - } - } - - midi_in->increment(); - } - - NodeImpl::post_process(context); -} - -void -TriggerNode::note_on(ProcessContext& context, uint8_t note_num, uint8_t velocity, FrameTime time) -{ - assert(time >= context.start() && time <= context.end()); - - if (_learning) { - _note_port->set_value(note_num); - ((AudioBuffer*)_note_port->buffer(0).get())->set_value( - (float)note_num, context.start(), context.end()); - _note_port->broadcast_value(context, true); - _learning = false; - } - -#ifdef RAUL_LOG_DEBUG - LOG(debug) << path() << " note " << (int)note_num << " on @ " << time << endl; -#endif - - Sample filter_note = ((AudioBuffer*)_note_port->buffer(0).get())->value_at(0); - if (filter_note >= 0.0 && filter_note < 127.0 && (note_num == (uint8_t)filter_note)) { - ((AudioBuffer*)_gate_port->buffer(0).get())->set_value(1.0f, context.start(), time); - ((AudioBuffer*)_trig_port->buffer(0).get())->set_value(1.0f, context.start(), time); - ((AudioBuffer*)_trig_port->buffer(0).get())->set_value(0.0f, context.start(), time + 1); - ((AudioBuffer*)_vel_port->buffer(0).get())->set_value(velocity / 127.0f, context.start(), time); - assert(((AudioBuffer*)_trig_port->buffer(0).get())->data()[time - context.start()] == 1.0f); - } -} - -void -TriggerNode::note_off(ProcessContext& context, uint8_t note_num, FrameTime time) -{ - assert(time >= context.start() && time <= context.end()); - - if (note_num == lrintf(((AudioBuffer*)_note_port->buffer(0).get())->value_at(0))) - ((AudioBuffer*)_gate_port->buffer(0).get())->set_value(0.0f, context.start(), time); -} - -} // namespace Internals -} // namespace Engine -} // namespace Ingen diff --git a/src/engine/internals/Trigger.hpp b/src/engine/internals/Trigger.hpp deleted file mode 100644 index da796f5e..00000000 --- a/src/engine/internals/Trigger.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/* This file is part of Ingen. - * Copyright 2007-2011 David Robillard <http://drobilla.net> - * - * Ingen 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 2 of the License, or (at your option) any later - * version. - * - * Ingen 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 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef INGEN_INTERNALS_TRIGGER_HPP -#define INGEN_INTERNALS_TRIGGER_HPP - -#include <string> -#include "NodeImpl.hpp" - -namespace Ingen { -namespace Engine { - -class InputPort; -class OutputPort; -class InternalPlugin; - -namespace Internals { - -/** MIDI trigger input node. - * - * Just has a gate, for drums etc. A control port is used to select - * which note number is responded to. - * - * Note that this node is always monophonic, the poly parameter is ignored. - * (Should that change?) - * - * \ingroup engine - */ -class TriggerNode : public NodeImpl -{ -public: - TriggerNode( - InternalPlugin* plugin, - BufferFactory& bufs, - const std::string& path, - bool polyphonic, - PatchImpl* parent, - SampleRate srate); - - void process(ProcessContext& context); - - void note_on(ProcessContext& context, uint8_t note_num, uint8_t velocity, FrameTime time); - void note_off(ProcessContext& context, uint8_t note_num, FrameTime time); - - void learn() { _learning = true; } - - static InternalPlugin* internal_plugin(Shared::LV2URIMap& uris); - -private: - bool _learning; - - InputPort* _midi_in_port; - InputPort* _note_port; - OutputPort* _gate_port; - OutputPort* _trig_port; - OutputPort* _vel_port; -}; - -} // namespace Engine -} // namespace Ingen -} // namespace Internals - -#endif // INGEN_INTERNALS_TRIGGER_HPP |