From 21de7016110081437ca0fbfdd6a14f41088da7b9 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Wed, 3 Jun 2009 01:37:29 +0000 Subject: Move internals to their own directory ala events. git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@2070 a436a847-0d15-0410-975c-d299462d15a1 --- src/engine/InternalNote.cpp | 392 -------------------------------------------- 1 file changed, 392 deletions(-) delete mode 100644 src/engine/InternalNote.cpp (limited to 'src/engine/InternalNote.cpp') diff --git a/src/engine/InternalNote.cpp b/src/engine/InternalNote.cpp deleted file mode 100644 index b2ab27b3..00000000 --- a/src/engine/InternalNote.cpp +++ /dev/null @@ -1,392 +0,0 @@ -/* This file is part of Ingen. - * Copyright (C) 2007-2009 Dave Robillard - * - * 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 "raul/Array.hpp" -#include "raul/Maid.hpp" -#include "raul/midi_events.h" -#include -#include -#include "AudioBuffer.hpp" -#include "AudioDriver.hpp" -#include "InputPort.hpp" -#include "InternalPlugin.hpp" -#include "EventBuffer.hpp" -#include "InternalNote.hpp" -#include "OutputPort.hpp" -#include "PatchImpl.hpp" -#include "ProcessContext.hpp" -#include "util.hpp" - -using namespace std; - -namespace Ingen { - -using namespace Shared; - -static InternalPlugin note_plugin(NS_INTERNALS "Note", "note"); - -NoteNode::NoteNode(const string& path, bool polyphonic, PatchImpl* parent, SampleRate srate, size_t buffer_size) - : NodeBase(¬e_plugin, path, polyphonic, parent, srate, buffer_size) - , _voices(new Raul::Array(_polyphony)) - , _prepared_voices(NULL) - , _sustain(false) -{ - _ports = new Raul::Array(5); - - _midi_in_port = new InputPort(this, "input", 0, 1, DataType::EVENT, Raul::Atom(), _buffer_size); - _ports->at(0) = _midi_in_port; - - _freq_port = new OutputPort(this, "frequency", 1, _polyphony, DataType::AUDIO, 440.0f, _buffer_size); - _ports->at(1) = _freq_port; - - _vel_port = new OutputPort(this, "velocity", 2, _polyphony, DataType::AUDIO, 0.0f, _buffer_size); - _vel_port->set_property("lv2:minimum", 0.0f); - _vel_port->set_property("lv2:maximum", 1.0f); - _ports->at(2) = _vel_port; - - _gate_port = new OutputPort(this, "gate", 3, _polyphony, DataType::AUDIO, 0.0f, _buffer_size); - _gate_port->set_property("lv2:toggled", true); - _ports->at(3) = _gate_port; - - _trig_port = new OutputPort(this, "trigger", 4, _polyphony, DataType::AUDIO, 0.0f, _buffer_size); - _trig_port->set_property("lv2:toggled", true); - _ports->at(4) = _trig_port; -} - - -NoteNode::~NoteNode() -{ - delete _voices; -} - - -bool -NoteNode::prepare_poly(uint32_t poly) -{ - if (!_polyphonic) - return true; - - NodeBase::prepare_poly(poly); - - if (_prepared_voices && poly <= _prepared_voices->size()) - return true; - - _prepared_voices = new Raul::Array(poly, *_voices); - - return true; -} - - -bool -NoteNode::apply_poly(Raul::Maid& maid, uint32_t poly) -{ - if (!_polyphonic) - return true; - - NodeBase::apply_poly(maid, poly); - - if (_prepared_voices) { - assert(poly <= _prepared_voices->size()); - maid.push(_voices); - _voices = _prepared_voices; - _prepared_voices = NULL; - } - - _polyphony = poly; - assert(_voices->size() >= _polyphony); - - return true; -} - - -void -NoteNode::process(ProcessContext& context) -{ - EventBuffer* const midi_in = (EventBuffer*)_midi_in_port->buffer(0); - NodeBase::pre_process(context); - - uint32_t frames = 0; - uint32_t subframes = 0; - uint16_t type = 0; - uint16_t size = 0; - uint8_t* buf = NULL; - - //assert(midi_in->this_nframes() == context.nframes()); - - midi_in->rewind(); - - if (midi_in->event_count() > 0) - while (midi_in->get_event(&frames, &subframes, &type, &size, &buf)) { - - /*cout << "EVENT TYPE " << type << " @ " << frames << "." << subframes << ": "; - for (uint16_t i = 0; i < size; ++i) - cout << (int)((char)buf[i]) << " "; - cout << endl;*/ - - 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: - //cerr << "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]); - } - - if (midi_in->increment() == midi_in->this_nframes()) - break; - } - - NodeBase::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(time - context.start() < _buffer_size); - assert(note_num <= 127); - - Key* key = &_keys[note_num]; - Voice* voice = NULL; - uint32_t voice_num = 0; - - if (key->state != Key::OFF) { - //cerr << "[NoteNode] Double midi note received" << endl; - 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]); - - /*cerr << "[NoteNode] Note " << (int)note_num << " on @ " << time - << ". Voice " << voice_num << " / " << _polyphony << endl;*/ - - // 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; - //cerr << "[NoteNode] Stole voice " << voice_num << endl; - } - - // 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))->set_value(note_to_freq(note_num), context.start(), time); - ((AudioBuffer*)_vel_port->buffer(voice_num))->set_value(velocity/127.0, context.start(), time); - ((AudioBuffer*)_gate_port->buffer(voice_num))->set_value(1.0f, context.start(), time); - - // trigger (one sample) - ((AudioBuffer*)_trig_port->buffer(voice_num))->set_value(1.0f, context.start(), time); - ((AudioBuffer*)_trig_port->buffer(voice_num))->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()); - assert(time - context.start() < _buffer_size); - - Key* key = &_keys[note_num]; - - //cerr << "[NoteNode] Note " << (int)note_num << " off @ " << time << endl; - - 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) { - //cerr << "... free voice " << key->voice << endl; - free_voice(context, key->voice, time); - } else { - //cerr << "... hold voice " << key->voice << endl; - (*_voices)[key->voice].state = Voice::HOLDING; - } - - } else { -#ifndef NDEBUG - cerr << "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()); - assert(time - context.start() < _buffer_size); - - // 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))->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) - //cerr << "[NoteNode] Note off. Key " << (int)note_num << ", Voice " << voice << " Killed" << endl; - ((AudioBuffer*)_gate_port->buffer(voice))->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()); - assert(time - context.start() < _buffer_size); - - //cerr << "All notes off @ " << offset << endl; - - // FIXME: set all keys to Key::OFF? - - for (uint32_t i = 0; i < _polyphony; ++i) { - ((AudioBuffer*)_gate_port->buffer(i))->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; // Some LADSPA plugins don't like freq=0 -} - - -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()); - assert(time - context.start() < _buffer_size); - - _sustain = false; - - for (uint32_t i=0; i < _polyphony; ++i) - if ((*_voices)[i].state == Voice::HOLDING) - free_voice(context, i, time); -} - - -} // namespace Ingen - -- cgit v1.2.1