From e96c36c1a7abb062e36efc0ac95c35fedcef922e Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 8 Apr 2007 06:04:32 +0000 Subject: De-template-ification of port types (req. for LV2 MIDI, but nice code size reduction). LV2 MIDI patching support (LV2 style MIDI throughout, inc. internal plugins). git-svn-id: http://svn.drobilla.net/lad/ingen@415 a436a847-0d15-0410-975c-d299462d15a1 --- src/common/lv2ext/Makefile.am | 2 +- src/common/lv2ext/lv2-midifunctions.h | 162 ++++++++++ src/common/lv2ext/lv2-miditype.h | 50 ++-- src/libs/engine/AlsaMidiDriver.cpp | 4 +- src/libs/engine/AlsaMidiDriver.h | 10 +- src/libs/engine/AudioBuffer.cpp | 300 +++++++++++++++++++ src/libs/engine/AudioBuffer.h | 82 ++++++ src/libs/engine/AudioDriver.h | 10 +- src/libs/engine/Buffer.cpp | 328 --------------------- src/libs/engine/Buffer.h | 56 ++-- src/libs/engine/BufferFactory.cpp | 39 +++ src/libs/engine/BufferFactory.h | 35 +++ src/libs/engine/ClientBroadcaster.cpp | 2 +- src/libs/engine/Connection.cpp | 79 ++++- src/libs/engine/Connection.h | 36 ++- src/libs/engine/DSSINode.cpp | 11 +- src/libs/engine/DSSINode.h | 30 +- src/libs/engine/DataType.h | 4 +- src/libs/engine/Driver.h | 16 +- src/libs/engine/DuplexPort.cpp | 15 +- src/libs/engine/DuplexPort.h | 7 +- src/libs/engine/Engine.cpp | 20 +- src/libs/engine/Engine.h | 7 +- src/libs/engine/InputPort.cpp | 86 +++--- src/libs/engine/InputPort.h | 33 +-- src/libs/engine/JackAudioDriver.cpp | 11 +- src/libs/engine/JackAudioDriver.h | 18 +- src/libs/engine/JackMidiDriver.cpp | 26 +- src/libs/engine/JackMidiDriver.h | 14 +- src/libs/engine/LADSPANode.cpp | 25 +- src/libs/engine/LADSPANode.h | 2 +- src/libs/engine/LV2Node.cpp | 35 +-- src/libs/engine/LV2Node.h | 2 +- src/libs/engine/Makefile.am | 10 +- src/libs/engine/MidiBuffer.cpp | 77 +++++ src/libs/engine/MidiBuffer.h | 88 ++++++ src/libs/engine/MidiControlNode.cpp | 58 ++-- src/libs/engine/MidiControlNode.h | 23 +- src/libs/engine/MidiDriver.h | 12 +- src/libs/engine/MidiMessage.h | 52 ---- src/libs/engine/MidiNoteNode.cpp | 95 +++--- src/libs/engine/MidiNoteNode.h | 16 +- src/libs/engine/MidiTriggerNode.cpp | 77 ++--- src/libs/engine/MidiTriggerNode.h | 17 +- src/libs/engine/Node.h | 11 +- src/libs/engine/NodeBase.h | 2 +- src/libs/engine/OSCClientSender.cpp | 2 +- src/libs/engine/ObjectSender.cpp | 8 +- src/libs/engine/OutputPort.h | 20 +- src/libs/engine/Patch.cpp | 8 +- src/libs/engine/Port.cpp | 71 ++++- src/libs/engine/Port.h | 23 +- src/libs/engine/TypedConnection.cpp | 123 -------- src/libs/engine/TypedConnection.h | 104 ------- src/libs/engine/TypedPort.cpp | 154 ---------- src/libs/engine/TypedPort.h | 79 ----- src/libs/engine/events/AddPortEvent.cpp | 4 +- src/libs/engine/events/ConnectionEvent.cpp | 146 +++------ src/libs/engine/events/ConnectionEvent.h | 62 ++-- src/libs/engine/events/DisconnectNodeEvent.cpp | 2 +- src/libs/engine/events/DisconnectNodeEvent.h | 5 +- src/libs/engine/events/DisconnectionEvent.cpp | 123 ++------ src/libs/engine/events/DisconnectionEvent.h | 63 ++-- src/libs/engine/events/RequestObjectEvent.cpp | 4 +- src/libs/engine/events/RequestPluginEvent.cpp | 4 +- src/libs/engine/events/RequestPortValueEvent.cpp | 7 +- src/libs/engine/events/SetPortValueEvent.cpp | 13 +- src/libs/engine/events/SetPortValueQueuedEvent.cpp | 14 +- src/libs/engine/types.h | 4 - src/progs/ingenuity/Makefile.am | 4 +- src/progs/ingenuity/ingenuity.glade | 1 + 71 files changed, 1520 insertions(+), 1623 deletions(-) create mode 100644 src/common/lv2ext/lv2-midifunctions.h create mode 100644 src/libs/engine/AudioBuffer.cpp create mode 100644 src/libs/engine/AudioBuffer.h delete mode 100644 src/libs/engine/Buffer.cpp create mode 100644 src/libs/engine/BufferFactory.cpp create mode 100644 src/libs/engine/BufferFactory.h create mode 100644 src/libs/engine/MidiBuffer.cpp create mode 100644 src/libs/engine/MidiBuffer.h delete mode 100644 src/libs/engine/MidiMessage.h delete mode 100644 src/libs/engine/TypedConnection.cpp delete mode 100644 src/libs/engine/TypedConnection.h delete mode 100644 src/libs/engine/TypedPort.cpp delete mode 100644 src/libs/engine/TypedPort.h (limited to 'src') diff --git a/src/common/lv2ext/Makefile.am b/src/common/lv2ext/Makefile.am index f346ae0f..6d6ebb6e 100644 --- a/src/common/lv2ext/Makefile.am +++ b/src/common/lv2ext/Makefile.am @@ -1 +1 @@ -noinst_HEADERS = lv2-miditype.h +noinst_HEADERS = lv2-miditype.h lv2-midifunctions.h diff --git a/src/common/lv2ext/lv2-midifunctions.h b/src/common/lv2ext/lv2-midifunctions.h new file mode 100644 index 00000000..2334eff3 --- /dev/null +++ b/src/common/lv2ext/lv2-midifunctions.h @@ -0,0 +1,162 @@ +/**************************************************************************** + + lv2-midifunctions.h - support file for using MIDI in LV2 plugins + + Copyright (C) 2006 Lars Luthman + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 01222-1307 USA + +****************************************************************************/ + +#ifndef LV2_MIDIFUNCTIONS +#define LV2_MIDIFUNCTIONS + +#include +#include + +#include "lv2-miditype.h" + + +/** This structure contains information about a MIDI port buffer, the + current period size, and the position in the MIDI data buffer that + we are currently reading from or writing to. It needs to be recreated + or at least reinitialised every process() call. */ +typedef struct { + + /** The MIDI port structure that we want to read or write. */ + LV2_MIDI* midi; + + /** The number of frames in this process cycle. */ + uint32_t frame_count; + + /** The current position in the data buffer. Should be initialised to 0. */ + uint32_t position; + +} LV2_MIDIState; + + +static LV2_MIDI* lv2midi_new(uint32_t capacity) +{ + LV2_MIDI* midi = (LV2_MIDI*)malloc(sizeof(LV2_MIDI)); + + midi->event_count = 0; + midi->capacity = capacity; + midi->size = 0; + midi->data = (unsigned char*)malloc(sizeof(unsigned char) * capacity); + + return midi; +} + + +static void lv2midi_free(LV2_MIDI* midi) +{ + free(midi->data); + free(midi); +} + + +static void lv2midi_reset_buffer(LV2_MIDI* midi) +{ + midi->event_count = 0; + midi->size = 0; +} + +static void lv2midi_reset_state(LV2_MIDIState* state, LV2_MIDI* midi, uint32_t frame_count) +{ + state->midi = midi; + state->frame_count = frame_count; + state->position = 0; +} + + +/** This function advances the read/write position in @c state to the next + event and returns its timestamp, or the @c frame_count member of @c state + is there are no more events. */ +static double lv2midi_increment(LV2_MIDIState* state) { + + if (state->position + sizeof(double) + sizeof(size_t) >= state->midi->size) { + state->position = state->midi->size; + return state->frame_count; + } + + state->position += sizeof(double); + size_t size = *(size_t*)(state->midi->data + state->position); + state->position += sizeof(size_t); + state->position += size; + + if (state->position >= state->midi->size) + return state->frame_count; + + return *(double*)(state->midi->data + state->position); +} + + +/** This function reads one event from the port associated with the @c state + parameter and writes its timestamp, size and a pointer to its data bytes + into the parameters @c timestamp, @c size and @c data, respectively. + It does not advance the read position in the MIDI data buffer, two + subsequent calls to lv2midi_get_event() will read the same event. + + The function returns the timestamp for the read event, or the @c frame_count + member of @c state if there are no more events in the buffer. */ +static double lv2midi_get_event(LV2_MIDIState* state, + double* timestamp, + uint32_t* size, + unsigned char** data) { + + if (state->position >= state->midi->size) { + state->position = state->midi->size; + *timestamp = state->frame_count; + *size = 0; + *data = NULL; + return *timestamp; + } + + *timestamp = *(double*)(state->midi->data + state->position); + *size = *(size_t*)(state->midi->data + state->position + sizeof(double)); + *data = state->midi->data + state->position + + sizeof(double) + sizeof(size_t); + return *timestamp; +} + + +/** This function writes one MIDI event to the port buffer associated with + @c state. It returns 0 when the event was written successfully to the + buffer, and -1 when there was not enough room. The read/write position + is advanced automatically. */ +static int lv2midi_put_event(LV2_MIDIState* state, + double timestamp, + uint32_t size, + const unsigned char* data) { + + if (state->midi->capacity - state->midi->size < + sizeof(double) + sizeof(size_t) + size) + return -1; + + *(double*)(state->midi->data + state->midi->size) = timestamp; + state->midi->size += sizeof(double); + *(size_t*)(state->midi->data + state->midi->size) = size; + state->midi->size += sizeof(size_t); + memcpy(state->midi->data + state->midi->size, data, (size_t)size); + state->midi->size += size; + + ++state->midi->event_count; + + return 0; +} + + +#endif + diff --git a/src/common/lv2ext/lv2-miditype.h b/src/common/lv2ext/lv2-miditype.h index 332e57f1..5350e4f7 100644 --- a/src/common/lv2ext/lv2-miditype.h +++ b/src/common/lv2ext/lv2-miditype.h @@ -1,37 +1,38 @@ -/************************************************************************ - - LV2 MIDI Data Type Extension - Copyright 2006 Lars Luthman in 2006 - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License - as published by the Free Software Foundation; either version 2.1 of - the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. +/**************************************************************************** + + lv2-miditype.h - header file for using MIDI in LV2 plugins + + Copyright (C) 2006 Lars Luthman + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 01222-1307 USA -*************************************************************************/ +****************************************************************************/ #ifndef LV2_MIDITYPE_H #define LV2_MIDITYPE_H +#include /** This data structure is used to contain the MIDI events for one run() cycle. The port buffer for a LV2 port that has the datatype - should be a pointer + should be a pointer to an instance of this struct. To store two Note On events on MIDI channel 0 in a buffer, with timestamps - 12 and 35.5, you could use something like this code (assuming that midi_data - is a variable of type LV2_MIDI): + 12 and 35.5, you could use something like this code (assuming that + midi_data is a variable of type LV2_MIDI): @code size_t buffer_offset = 0; @@ -71,7 +72,8 @@ buffer_offset += sizeof(double); size_t size = *(size_t*)(midi_data->data + buffer_offset); buffer_offset += sizeof(size_t); - do_something_with_event(timestamp, size, midi_data->data + buffer_offset); + do_something_with_event(timestamp, size, + midi_data->data + buffer_offset); buffer_offset += size; } diff --git a/src/libs/engine/AlsaMidiDriver.cpp b/src/libs/engine/AlsaMidiDriver.cpp index 93d9d803..bbec1ab1 100644 --- a/src/libs/engine/AlsaMidiDriver.cpp +++ b/src/libs/engine/AlsaMidiDriver.cpp @@ -23,7 +23,7 @@ #include #include "ThreadManager.h" #include "AudioDriver.h" -#include "MidiMessage.h" +#include "MidiBuffer.h" #include "DuplexPort.h" #ifdef HAVE_LASH #include "LashDriver.h" @@ -35,7 +35,7 @@ namespace Ingen { //// AlsaMidiPort //// -AlsaMidiPort::AlsaMidiPort(AlsaMidiDriver* driver, DuplexPort* patch_port) +AlsaMidiPort::AlsaMidiPort(AlsaMidiDriver* driver, DuplexPort* patch_port) : DriverPort(patch_port->is_input()), Raul::ListNode(this), _driver(driver), diff --git a/src/libs/engine/AlsaMidiDriver.h b/src/libs/engine/AlsaMidiDriver.h index 85d975b9..6c6debee 100644 --- a/src/libs/engine/AlsaMidiDriver.h +++ b/src/libs/engine/AlsaMidiDriver.h @@ -31,7 +31,7 @@ class Node; class SetPortValueEvent; class AlsaMidiDriver; class AudioDriver; -template class DuplexPort; +class DuplexPort; static const int MAX_MIDI_EVENT_SIZE = 3; @@ -43,7 +43,7 @@ static const int MAX_MIDI_EVENT_SIZE = 3; class AlsaMidiPort : public DriverPort, public Raul::ListNode { public: - AlsaMidiPort(AlsaMidiDriver* driver, DuplexPort* port); + AlsaMidiPort(AlsaMidiDriver* driver, DuplexPort* port); virtual ~AlsaMidiPort(); void event(snd_seq_event_t* const ev); @@ -53,11 +53,11 @@ public: void set_name(const std::string& name); int port_id() const { return _port_id; } - DuplexPort* patch_port() const { return _patch_port; } + DuplexPort* patch_port() const { return _patch_port; } private: AlsaMidiDriver* _driver; - DuplexPort* _patch_port; + DuplexPort* _patch_port; int _port_id; unsigned char** _midi_pool; ///< Pool of raw MIDI events for MidiMessage::buffer Raul::SRSWQueue _events; @@ -86,7 +86,7 @@ public: AudioDriver* audio_driver() { return _audio_driver; } - DriverPort* create_port(DuplexPort* patch_port) + DriverPort* create_port(DuplexPort* patch_port) { return new AlsaMidiPort(this, patch_port); } void add_port(DriverPort* port); diff --git a/src/libs/engine/AudioBuffer.cpp b/src/libs/engine/AudioBuffer.cpp new file mode 100644 index 00000000..525f0b41 --- /dev/null +++ b/src/libs/engine/AudioBuffer.cpp @@ -0,0 +1,300 @@ +/* This file is part of Ingen. + * Copyright (C) 2007 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 +#include +#include +#include "AudioBuffer.h" +using std::cerr; using std::endl; + +/* TODO: Be sure these functions are vectorized by GCC when it's vectorizer + * stops sucking. Probably a good idea to inline them as well */ + +namespace Ingen { + + +AudioBuffer::AudioBuffer(size_t size) + : Buffer(DataType::FLOAT, size) + , _data(NULL) + , _local_data(NULL) + , _joined_buf(NULL) + , _size(size) + , _filled_size(0) + , _state(OK) + , _set_value(0) +{ + assert(_size > 0); + allocate(); + assert(data()); +} + + +void +AudioBuffer::resize(size_t size) +{ + _size = size; + + Sample* const old_data = _data; + + const bool using_local_data = (_data == _local_data); + + deallocate(); + + const int ret = posix_memalign((void**)&_local_data, 16, _size * sizeof(Sample)); + if (ret != 0) { + cerr << "[Buffer] Failed to allocate buffer. Aborting." << endl; + exit(EXIT_FAILURE); + } + + assert(ret == 0); + assert(_local_data); + + if (using_local_data) + _data = _local_data; + else + _data = old_data; + + set(0, 0, _size-1); +} + + +/** Allocate and use a locally managed buffer (data). + */ +void +AudioBuffer::allocate() +{ + assert(!_joined_buf); + assert(_local_data == NULL); + assert(_size > 0); + + const int ret = posix_memalign((void**)&_local_data, 16, _size * sizeof(Sample)); + if (ret != 0) { + cerr << "[Buffer] Failed to allocate buffer. Aborting." << endl; + exit(EXIT_FAILURE); + } + + assert(ret == 0); + assert(_local_data); + + _data = _local_data; + + set(0, 0, _size-1); +} + + +/** Free locally allocated buffer. + */ +void +AudioBuffer::deallocate() +{ + assert(!_joined_buf); + free(_local_data); + _local_data = NULL; + _data = NULL; +} + + +/** Empty (ie zero) the buffer. + */ +void +AudioBuffer::clear() +{ + set(0, 0, _size-1); + _state = OK; + _filled_size = 0; +} + + +/** Set value of buffer to @a val after @a start_sample. + * + * The Buffer will handle setting the intial portion of the buffer to the + * value on the next cycle automatically (if @a start_sample is > 0), as + * long as pre_process() is called every cycle. + */ +void +AudioBuffer::set(Sample val, size_t start_sample) +{ + assert(start_sample < _size); + + set(val, start_sample, _size-1); + + if (start_sample > 0) + _state = HALF_SET_CYCLE_1; + + _set_value = val; +} + + +/** Set a block of buffer to @a val. + * + * @a start_sample and @a end_sample define the inclusive range to be set. + */ +void +AudioBuffer::set(Sample val, size_t start_sample, size_t end_sample) +{ + assert(end_sample >= start_sample); + assert(end_sample < _size); + + Sample* const buf = data(); + assert(buf); + + for (size_t i=start_sample; i <= end_sample; ++i) + buf[i] = val; +} + + +/** Scale a block of buffer by @a val. + * + * @a start_sample and @a end_sample define the inclusive range to be set. + */ +void +AudioBuffer::scale(Sample val, size_t start_sample, size_t end_sample) +{ + assert(end_sample >= start_sample); + assert(end_sample < _size); + + Sample* const buf = data(); + assert(buf); + + for (size_t i=start_sample; i <= end_sample; ++i) + buf[i] *= val; +} + + +/** Copy a block of @a src into buffer. + * + * @a start_sample and @a end_sample define the inclusive range to be set. + * This function only copies the same range in one buffer to another. + */ +void +AudioBuffer::copy(const AudioBuffer* src, size_t start_sample, size_t end_sample) +{ + assert(end_sample >= start_sample); + assert(end_sample < _size); + assert(src); + + Sample* const buf = data(); + assert(buf); + + const Sample* const src_buf = src->data(); + assert(src_buf); + + for (size_t i=start_sample; i <= end_sample; ++i) + buf[i] = src_buf[i]; +} + + +/** Accumulate a block of @a src into @a dst. + * + * @a start_sample and @a end_sample define the inclusive range to be accumulated. + * This function only adds the same range in one buffer to another. + */ +void +AudioBuffer::accumulate(const AudioBuffer* const src, size_t start_sample, size_t end_sample) +{ + assert(end_sample >= start_sample); + assert(end_sample < _size); + assert(src); + + Sample* const buf = data(); + assert(buf); + + const Sample* const src_buf = src->data(); + assert(src_buf); + + for (size_t i=start_sample; i <= end_sample; ++i) + buf[i] += src_buf[i]; + +} + + +/** Use another buffer's data instead of the local one. + * + * This buffer will essentially be identical to @a buf after this call. + */ +bool +AudioBuffer::join(Buffer* buf) +{ + AudioBuffer* abuf = dynamic_cast(buf); + if (!abuf) + return false; + + assert(abuf->size() == _size); + + _joined_buf = abuf; + _filled_size = abuf->filled_size(); + + assert(_filled_size <= _size); + + return true; +} + + +void +AudioBuffer::unjoin() +{ + _joined_buf = NULL; + _data = _local_data; +} + + +bool +AudioBuffer::is_joined_to(Buffer* buf) const +{ + AudioBuffer* abuf = dynamic_cast(buf); + if (abuf) + return (data() == abuf->data()); + + return false; +} + + +void +AudioBuffer::prepare(SampleCount nframes) +{ + // FIXME: nframes parameter doesn't actually work, + // writing starts from 0 every time + assert(_size == 1 || nframes == _size); + + switch (_state) { + case HALF_SET_CYCLE_1: + _state = HALF_SET_CYCLE_2; + break; + case HALF_SET_CYCLE_2: + set(_set_value, 0, _size-1); + _state = OK; + break; + default: + break; + } +} + + +/** Set the buffer (data) used. + * + * This is only to be used by Drivers (to provide zero-copy processing). + */ +void +AudioBuffer::set_data(Sample* buf) +{ + assert(buf); + assert(!_joined_buf); + _data = buf; +} + + +} // namespace Ingen diff --git a/src/libs/engine/AudioBuffer.h b/src/libs/engine/AudioBuffer.h new file mode 100644 index 00000000..fa946108 --- /dev/null +++ b/src/libs/engine/AudioBuffer.h @@ -0,0 +1,82 @@ +/* This file is part of Ingen. + * Copyright (C) 2007 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 + */ + +#ifndef AUDIOBUFFER_H +#define AUDIOBUFFER_H + +#include +#include +#include +#include "types.h" +#include "Buffer.h" + +namespace Ingen { + + +class AudioBuffer : public Buffer +{ +public: + AudioBuffer(size_t capacity); + + void clear(); + void set(Sample val, size_t start_sample); + void set(Sample val, size_t start_sample, size_t end_sample); + void scale(Sample val, size_t start_sample, size_t end_sample); + void copy(const AudioBuffer* src, size_t start_sample, size_t end_sample); + void accumulate(const AudioBuffer* src, size_t start_sample, size_t end_sample); + + bool join(Buffer* buf); + void unjoin(); + bool is_joined_to(Buffer* buf) const; + + /** For driver use only!! */ + void set_data(Sample* data); + + inline Sample* data() const + { return ((_joined_buf != NULL) ? _joined_buf->data() : _data); } + + inline Sample& value_at(size_t offset) const + { assert(offset < _size); return data()[offset]; } + + void prepare(SampleCount nframes); + + void filled_size(size_t size) { _filled_size = size; } + size_t filled_size() const { return _filled_size; } + bool is_joined() const { return (_joined_buf == NULL); } + size_t size() const { return _size; } + + void resize(size_t size); + +private: + enum State { OK, HALF_SET_CYCLE_1, HALF_SET_CYCLE_2 }; + + void allocate(); + void deallocate(); + + Sample* _data; ///< Used data pointer (probably same as _local_data) + Sample* _local_data; ///< Locally allocated buffer (possibly unused if joined or set_data used) + AudioBuffer* _joined_buf; ///< Buffer to mirror, if joined + size_t _size; ///< Allocated buffer size + size_t _filled_size; ///< Usable buffer size (for MIDI ports etc) + State _state; ///< State of buffer for setting values next cycle + Sample _set_value; ///< Value set by @ref set (may need to be set next cycle) +}; + + +} // namespace Ingen + +#endif // AUDIOBUFFER_H diff --git a/src/libs/engine/AudioDriver.h b/src/libs/engine/AudioDriver.h index 9128c2ed..d9807939 100644 --- a/src/libs/engine/AudioDriver.h +++ b/src/libs/engine/AudioDriver.h @@ -18,25 +18,27 @@ #ifndef AUDIODRIVER_H #define AUDIODRIVER_H -#include "Driver.h" -#include "types.h" #include #include +#include "Driver.h" +#include "types.h" +#include "DataType.h" namespace Ingen { class Patch; class AudioDriver; -template class TypedPort; +class Port; /** Audio driver abstract base class. * * \ingroup engine */ -class AudioDriver : public Driver +class AudioDriver : public Driver { public: + AudioDriver() : Driver(DataType::FLOAT) {} virtual void set_root_patch(Patch* patch) = 0; virtual Patch* root_patch() = 0; diff --git a/src/libs/engine/Buffer.cpp b/src/libs/engine/Buffer.cpp deleted file mode 100644 index 78b77635..00000000 --- a/src/libs/engine/Buffer.cpp +++ /dev/null @@ -1,328 +0,0 @@ -/* This file is part of Ingen. - * Copyright (C) 2007 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 "Buffer.h" -#include -#include -#include -#include "MidiMessage.h" -using std::cerr; using std::endl; - -/* TODO: Be sure these functions are vectorized by GCC when it's vectorizer - * stops sucking. Probably a good idea to inline them as well */ - -namespace Ingen { - - -template -Buffer::Buffer(size_t size) -: _data(NULL), - _local_data(NULL), - _joined_buf(NULL), - _size(size), - _filled_size(0), - _state(OK), - _set_value(0) -{ - assert(_size > 0); - allocate(); - assert(data()); -} -template Buffer::Buffer(size_t size); -template Buffer::Buffer(size_t size); - - -template -void -Buffer::resize(size_t size) -{ - _size = size; - - T* const old_data = _data; - - const bool using_local_data = (_data == _local_data); - - deallocate(); - - const int ret = posix_memalign((void**)&_local_data, 16, _size * sizeof(T)); - if (ret != 0) { - cerr << "[Buffer] Failed to allocate buffer. Aborting." << endl; - exit(EXIT_FAILURE); - } - - assert(ret == 0); - assert(_local_data); - - if (using_local_data) - _data = _local_data; - else - _data = old_data; - - set(0, 0, _size-1); -} -template void Buffer::resize(size_t size); -template void Buffer::resize(size_t size); - - -/** Allocate and use a locally managed buffer (data). - */ -template -void -Buffer::allocate() -{ - assert(!_joined_buf); - assert(_local_data == NULL); - assert(_size > 0); - - const int ret = posix_memalign((void**)&_local_data, 16, _size * sizeof(T)); - if (ret != 0) { - cerr << "[Buffer] Failed to allocate buffer. Aborting." << endl; - exit(EXIT_FAILURE); - } - - assert(ret == 0); - assert(_local_data); - - _data = _local_data; - - set(0, 0, _size-1); -} -template void Buffer::allocate(); -template void Buffer::allocate(); - - -/** Free locally allocated buffer. - */ -template -void -Buffer::deallocate() -{ - assert(!_joined_buf); - free(_local_data); - _local_data = NULL; - _data = NULL; -} -template void Buffer::deallocate(); -template void Buffer::deallocate(); - - -/** Empty (ie zero) the buffer. - */ -template -void -Buffer::clear() -{ - set(0, 0, _size-1); - _state = OK; - _filled_size = 0; -} -template void Buffer::clear(); -template void Buffer::clear(); - - -/** Set value of buffer to @a val after @a start_sample. - * - * The Buffer will handle setting the intial portion of the buffer to the - * value on the next cycle automatically (if @a start_sample is > 0), as - * long as pre_process() is called every cycle. - */ -template -void -Buffer::set(T val, size_t start_sample) -{ - assert(start_sample < _size); - - set(val, start_sample, _size-1); - - if (start_sample > 0) - _state = HALF_SET_CYCLE_1; - - _set_value = val; -} -template void Buffer::set(Sample val, size_t start_sample); -template void Buffer::set(MidiMessage val, size_t start_sample); - - -/** Set a block of buffer to @a val. - * - * @a start_sample and @a end_sample define the inclusive range to be set. - */ -template -void -Buffer::set(T val, size_t start_sample, size_t end_sample) -{ - assert(end_sample >= start_sample); - assert(end_sample < _size); - - T* const buf = data(); - assert(buf); - - for (size_t i=start_sample; i <= end_sample; ++i) - buf[i] = val; -} -template void Buffer::set(Sample val, size_t start_sample, size_t end_sample); -template void Buffer::set(MidiMessage val, size_t start_sample, size_t end_sample); - - -/** Scale a block of buffer by @a val. - * - * @a start_sample and @a end_sample define the inclusive range to be set. - */ -template -void -Buffer::scale(T val, size_t start_sample, size_t end_sample) -{ - assert(end_sample >= start_sample); - assert(end_sample < _size); - - T* const buf = data(); - assert(buf); - - for (size_t i=start_sample; i <= end_sample; ++i) - buf[i] *= val; -} -template void Buffer::scale(Sample val, size_t start_sample, size_t end_sample); - - -/** Copy a block of @a src into buffer. - * - * @a start_sample and @a end_sample define the inclusive range to be set. - * This function only copies the same range in one buffer to another. - */ -template -void -Buffer::copy(const Buffer* src, size_t start_sample, size_t end_sample) -{ - assert(end_sample >= start_sample); - assert(end_sample < _size); - assert(src); - - T* const buf = data(); - assert(buf); - - const T* const src_buf = src->data(); - assert(src_buf); - - for (size_t i=start_sample; i <= end_sample; ++i) - buf[i] = src_buf[i]; -} -template void Buffer::copy(const Buffer* const src, size_t start_sample, size_t end_sample); -template void Buffer::copy(const Buffer* const src, size_t start_sample, size_t end_sample); - - -/** Accumulate a block of @a src into @a dst. - * - * @a start_sample and @a end_sample define the inclusive range to be accumulated. - * This function only adds the same range in one buffer to another. - */ -template -void -Buffer::accumulate(const Buffer* const src, size_t start_sample, size_t end_sample) -{ - assert(end_sample >= start_sample); - assert(end_sample < _size); - assert(src); - - T* const buf = data(); - assert(buf); - - const T* const src_buf = src->data(); - assert(src_buf); - - for (size_t i=start_sample; i <= end_sample; ++i) - buf[i] += src_buf[i]; - -} -template void Buffer::accumulate(const Buffer* const src, size_t start_sample, size_t end_sample); - - -/** Use another buffer's data instead of the local one. - * - * This buffer will essentially be identical to @a buf after this call. - */ -template -void -Buffer::join(Buffer* buf) -{ - assert(buf->size() == _size); - - _joined_buf = buf; - _filled_size = buf->filled_size(); - - assert(_filled_size <= _size); -} -template void Buffer::join(Buffer* buf); -template void Buffer::join(Buffer* buf); - - -template -void -Buffer::unjoin() -{ - _joined_buf = NULL; - _data = _local_data; -} -template void Buffer::unjoin(); -template void Buffer::unjoin(); - - -template<> -void -Buffer::prepare(SampleCount nframes) -{ - // FIXME: nframes parameter doesn't actually work, - // writing starts from 0 every time - assert(_size == 1 || nframes == _size); - - switch (_state) { - case HALF_SET_CYCLE_1: - _state = HALF_SET_CYCLE_2; - break; - case HALF_SET_CYCLE_2: - set(_set_value, 0, _size-1); - _state = OK; - break; - default: - break; - } -} - - -template<> -void -Buffer::prepare(SampleCount nframes) -{ -} - - -/** Set the buffer (data) used. - * - * This is only to be used by Drivers (to provide zero-copy processing). - */ -template -void -Buffer::set_data(T* buf) -{ - assert(buf); - assert(!_joined_buf); - _data = buf; -} -template void Buffer::set_data(Sample* data); -template void Buffer::set_data(MidiMessage* data); - - -} // namespace Ingen diff --git a/src/libs/engine/Buffer.h b/src/libs/engine/Buffer.h index 3491b799..ee94b786 100644 --- a/src/libs/engine/Buffer.h +++ b/src/libs/engine/Buffer.h @@ -20,55 +20,39 @@ #include #include +#include #include "types.h" +#include "DataType.h" namespace Ingen { -template -class Buffer +class Buffer : public boost::noncopyable { public: - Buffer(size_t size); + Buffer(DataType type, size_t size) + : _type(type) + , _size(size) + {} - void clear(); - void set(T val, size_t start_sample); - void set(T val, size_t start_sample, size_t end_sample); - void scale(T val, size_t start_sample, size_t end_sample); - void copy(const Buffer* src, size_t start_sample, size_t end_sample); - void accumulate(const Buffer* src, size_t start_sample, size_t end_sample); + virtual ~Buffer() {} - void join(Buffer* buf); - void unjoin(); + virtual void clear() = 0; + virtual void prepare(SampleCount nframes) = 0; - /** For driver use only!! */ - void set_data(T* data); - - inline T& value_at(size_t offset) { assert(offset < _size); return data()[offset]; } - - void prepare(SampleCount nframes); - - void filled_size(size_t size) { _filled_size = size; } - size_t filled_size() const { return _filled_size; } - bool is_joined() const { return (_joined_buf == NULL); } - size_t size() const { return _size; } - inline T* data() const { return ((_joined_buf != NULL) ? _joined_buf->data() : _data); } - - void resize(size_t size); + virtual bool is_joined() const = 0; + virtual bool is_joined_to(Buffer* buf) const = 0; + virtual bool join(Buffer* buf) = 0; + virtual void unjoin() = 0; -private: - enum BufferState { OK, HALF_SET_CYCLE_1, HALF_SET_CYCLE_2 }; + virtual void resize(size_t size) { _size = size; } - void allocate(); - void deallocate(); + DataType type() const { return _type; } + size_t size() const { return _size; } - T* _data; ///< Used data pointer (probably same as _local_data) - T* _local_data; ///< Locally allocated buffer (possibly unused if joined or set_data used) - Buffer* _joined_buf; ///< Buffer to mirror, if joined - size_t _size; ///< Allocated buffer size - size_t _filled_size; ///< Usable buffer size (for MIDI ports etc) - BufferState _state; ///< State of buffer for setting values next cycle - T _set_value; ///< Value set by @ref set (may need to be set next cycle) +protected: + DataType _type; + size_t _size; }; diff --git a/src/libs/engine/BufferFactory.cpp b/src/libs/engine/BufferFactory.cpp new file mode 100644 index 00000000..f2761f08 --- /dev/null +++ b/src/libs/engine/BufferFactory.cpp @@ -0,0 +1,39 @@ +/* This file is part of Ingen. + * Copyright (C) 2007 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 "BufferFactory.h" +#include "AudioBuffer.h" +#include "MidiBuffer.h" + +namespace Ingen { +namespace BufferFactory { + + +Buffer* +create(DataType type, size_t size) +{ + if (type == DataType::FLOAT) + return new AudioBuffer(size); + else if (type == DataType::MIDI) + return new MidiBuffer(size); + else + return NULL; +} + + +} // namespace BufferFactory +} // namespace Ingen diff --git a/src/libs/engine/BufferFactory.h b/src/libs/engine/BufferFactory.h new file mode 100644 index 00000000..1887c27c --- /dev/null +++ b/src/libs/engine/BufferFactory.h @@ -0,0 +1,35 @@ +/* This file is part of Ingen. + * Copyright (C) 2007 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 + */ + +#ifndef BUFFERFACTORY_H +#define BUFFERFACTORY_H + +#include "Buffer.h" + +namespace Ingen { + + +namespace BufferFactory { + + Buffer* create(DataType type, size_t size); + +} + + +} // namespace Ingen + +#endif // BUFFERFACTORY_H diff --git a/src/libs/engine/ClientBroadcaster.cpp b/src/libs/engine/ClientBroadcaster.cpp index 0c66575c..f0205d9f 100644 --- a/src/libs/engine/ClientBroadcaster.cpp +++ b/src/libs/engine/ClientBroadcaster.cpp @@ -25,7 +25,7 @@ #include "Patch.h" #include "Node.h" #include "Plugin.h" -#include "TypedPort.h" +#include "Port.h" #include "Connection.h" #include "AudioDriver.h" #include "ObjectSender.h" diff --git a/src/libs/engine/Connection.cpp b/src/libs/engine/Connection.cpp index 1f5e0d21..992496c2 100644 --- a/src/libs/engine/Connection.cpp +++ b/src/libs/engine/Connection.cpp @@ -19,6 +19,8 @@ #include "util.h" #include "Node.h" #include "Port.h" +#include "BufferFactory.h" +#include "AudioBuffer.h" namespace Ingen { @@ -28,17 +30,82 @@ namespace Ingen { * This handles both polyphonic and monophonic nodes, transparently to the * user (InputPort). */ -Connection::Connection(Port* const src_port, Port* const dst_port) -: _src_port(src_port), - _dst_port(dst_port), - _pending_disconnection(false) +Connection::Connection(Port* src_port, Port* dst_port) + : _src_port(src_port) + , _dst_port(dst_port) + , _local_buffer(NULL) + , _buffer_size(dst_port->buffer_size()) + , _must_mix(src_port->poly() != dst_port->poly()) + , _pending_disconnection(false) { - assert(src_port != NULL); - assert(dst_port != NULL); + assert(src_port); + assert(dst_port); + assert(src_port->type() == dst_port->type()); assert((src_port->parent_node()->poly() == dst_port->parent_node()->poly()) || (src_port->parent_node()->poly() == 1 || dst_port->parent_node()->poly() == 1)); + + if (_must_mix) + _local_buffer = BufferFactory::create(dst_port->type(), dst_port->buffer(0)->size()); +} + + +Connection::~Connection() +{ + delete _local_buffer; } + + +void +Connection::set_buffer_size(size_t size) +{ + if (_must_mix) { + assert(_local_buffer); + delete _local_buffer; + + _local_buffer = BufferFactory::create(_dst_port->type(), _dst_port->buffer(0)->size()); + } + + _buffer_size = size; +} + + +void +Connection::process(SampleCount nframes, FrameTime start, FrameTime end) +{ + // FIXME: nframes parameter not used + assert(_buffer_size == 1 || _buffer_size == nframes); + + /* Thought: A poly output port can be connected to multiple mono input + * ports, which means this mix down would have to happen many times. + * Adding a method to OutputPort that mixes down all it's outputs into + * a buffer (if it hasn't been done already this cycle) and returns that + * would avoid having to mix multiple times. Probably not a very common + * case, but it would be faster anyway. */ + + // FIXME: Implement MIDI mixing + + if (_must_mix) { + assert(type() == DataType::FLOAT); + + AudioBuffer* mix_buf = (AudioBuffer*)_local_buffer; + + //cerr << "Mixing " << src_port()->buffer(0)->data() + // << " -> " << _local_buffer->data() << endl; + + mix_buf->copy((AudioBuffer*)src_port()->buffer(0), 0, _buffer_size-1); + + // Mix all the source's voices down into local buffer starting at the second + // voice (buffer is already set to first voice above) + for (size_t j=1; j < src_port()->poly(); ++j) + mix_buf->accumulate((AudioBuffer*)src_port()->buffer(j), 0, _buffer_size-1); + + // Scale the buffer down. + if (src_port()->poly() > 1) + mix_buf->scale(1.0f/(float)src_port()->poly(), 0, _buffer_size-1); + } +} + } // namespace Ingen diff --git a/src/libs/engine/Connection.h b/src/libs/engine/Connection.h index a7a2b3fa..7d109d88 100644 --- a/src/libs/engine/Connection.h +++ b/src/libs/engine/Connection.h @@ -21,11 +21,14 @@ #include #include #include +#include "DataType.h" +#include "Port.h" #include "types.h" namespace Ingen { class Port; +class Buffer; /** Represents a single inbound connection for an InputPort. @@ -41,7 +44,8 @@ class Port; class Connection : public Raul::Deletable { public: - virtual ~Connection() {} + Connection(Port* src_port, Port* dst_port); + virtual ~Connection(); Port* src_port() const { return _src_port; } Port* dst_port() const { return _dst_port; } @@ -50,17 +54,41 @@ public: bool pending_disconnection() { return _pending_disconnection; } void pending_disconnection(bool b) { _pending_disconnection = b; } - virtual void set_buffer_size(size_t size) {} + void process(SampleCount nframes, FrameTime start, FrameTime end); -protected: - Connection(Port* const src_port, Port* const dst_port); + /** Get the buffer for a particular voice. + * A Connection is smart - it knows the destination port requesting the + * buffer, and will return accordingly (ie the same buffer for every voice + * in a mono->poly connection). + */ + inline Buffer* buffer(size_t voice) const; + void set_buffer_size(size_t size); + + DataType type() const { return _src_port->type(); } + +protected: Port* const _src_port; Port* const _dst_port; + Buffer* _local_buffer; + size_t _buffer_size; + bool _must_mix; bool _pending_disconnection; }; +inline Buffer* +Connection::buffer(size_t voice) const +{ + if (_must_mix) + return _local_buffer; + else if (_src_port->poly() == 1) + return _src_port->buffer(0); + else + return _src_port->buffer(voice); +} + + } // namespace Ingen #endif // CONNECTION_H diff --git a/src/libs/engine/DSSINode.cpp b/src/libs/engine/DSSINode.cpp index 6f00af0c..5a23baba 100644 --- a/src/libs/engine/DSSINode.cpp +++ b/src/libs/engine/DSSINode.cpp @@ -22,6 +22,7 @@ #include "interface/ClientInterface.h" #include "InputPort.h" #include "types.h" +#include "AudioBuffer.h" using namespace std; @@ -63,7 +64,7 @@ DSSINode::instantiate() if (has_midi_input()) { _ports = new Raul::Array(_descriptor->PortCount + 1); - _midi_in_port = new InputPort(this, "MIDIIn", _ports->size()-1, 1, DataType::MIDI, _buffer_size); + _midi_in_port = new InputPort(this, "MIDIIn", _ports->size()-1, 1, DataType::MIDI, _buffer_size); _ports->at(_ports->size()-1) = _midi_in_port; } @@ -108,7 +109,8 @@ void DSSINode::set_control(size_t port_num, Sample val) { assert(port_num < _descriptor->PortCount); - ((TypedPort*)_ports->at(port_num))->set_value(val, 0); + cerr << "FIXME: set_control\n"; + //((TypedPort*)_ports->at(port_num))->set_value(val, 0); } @@ -137,7 +139,7 @@ DSSINode::convert_events() { assert(has_midi_input()); assert(_midi_in_port != NULL); - +#if 0 Buffer& buffer = *_midi_in_port->buffer(0); _encoded_events = 0; @@ -149,6 +151,7 @@ DSSINode::convert_events() if (_alsa_events[_encoded_events].type != SND_SEQ_EVENT_NONE) ++_encoded_events; } +#endif } @@ -242,7 +245,7 @@ DSSINode::send_update() // send "control"s for (size_t i=0; i < _ports->size(); ++i) if (_ports->at(i)->type() == DataType::FLOAT && _ports->at(i)->buffer_size() == 1) - send_control(_ports->at(i)->num(), ((TypedPort*)_ports->at(i))->buffer(0)->value_at(0)); + send_control(_ports->at(i)->num(), ((AudioBuffer*)_ports->at(i)->buffer(0))->value_at(0)); // send "show" FIXME: not to spec send_show(); diff --git a/src/libs/engine/DSSINode.h b/src/libs/engine/DSSINode.h index 2521693e..9070410e 100644 --- a/src/libs/engine/DSSINode.h +++ b/src/libs/engine/DSSINode.h @@ -22,11 +22,11 @@ #include #include #include "LADSPANode.h" +#include "MidiBuffer.h" namespace Ingen { -class MidiMessage; -template class InputPort; +class InputPort; namespace Shared { class ClientInterface; } using Shared::ClientInterface; @@ -71,7 +71,7 @@ private: // DSSI GUI messages void send_control(int port_num, float value); void send_program(int bank, int value); - void send_configure(const string& key, const string& val); + void send_configure(const std::string& key, const std::string& val); void send_show(); void send_hide(); void send_quit(); @@ -82,20 +82,20 @@ private: DSSI_Descriptor* _dssi_descriptor; - string _ui_url; - string _ui_base_path; - lo_address _ui_addr; + std::string _ui_url; + std::string _ui_base_path; + lo_address _ui_addr; // Current values - int _bank; - int _program; - std::map _configures; - std::map _banks; - - InputPort* _midi_in_port; - snd_seq_event_t* _alsa_events; - unsigned long _encoded_events; - snd_midi_event_t* _alsa_encoder; + int _bank; + int _program; + std::map _configures; + std::map _banks; + + InputPort* _midi_in_port; + snd_seq_event_t* _alsa_events; + unsigned long _encoded_events; + snd_midi_event_t* _alsa_encoder; }; diff --git a/src/libs/engine/DataType.h b/src/libs/engine/DataType.h index 62cec1af..469c48d8 100644 --- a/src/libs/engine/DataType.h +++ b/src/libs/engine/DataType.h @@ -36,10 +36,10 @@ public: MIDI = 2 }; - DataType(const string& uri) + DataType(const std::string& uri) : _symbol(UNKNOWN) { - if (uri== type_uris[MIDI]) { + if (uri == type_uris[MIDI]) { _symbol = MIDI; } else if (uri == type_uris[FLOAT]) { _symbol = FLOAT; diff --git a/src/libs/engine/Driver.h b/src/libs/engine/Driver.h index 6cbfbdff..fbddc828 100644 --- a/src/libs/engine/Driver.h +++ b/src/libs/engine/Driver.h @@ -21,10 +21,11 @@ #include #include #include "raul/Path.h" +#include "DataType.h" namespace Ingen { -template class DuplexPort; +class DuplexPort; /** Representation of a "system" (eg outside Ingen) port. @@ -58,15 +59,15 @@ protected: * interface for managing system ports. An implementation of Driver basically * needs to manage DriverPorts, and handle writing/reading data to/from them. * - * The template parameter T is the type of data this driver manages (ie the - * data type of the bridge ports it will handle). - * * \ingroup engine */ -template class Driver : boost::noncopyable { public: + Driver(DataType type) + : _type(type) + {} + virtual ~Driver() {} virtual void activate() = 0; @@ -78,10 +79,13 @@ public: * * May return NULL if the Driver can not drive the port for some reason. */ - virtual DriverPort* create_port(DuplexPort* patch_port) = 0; + virtual DriverPort* create_port(DuplexPort* patch_port) = 0; virtual void add_port(DriverPort* port) = 0; virtual DriverPort* remove_port(const Raul::Path& path) = 0; + +protected: + DataType _type; }; diff --git a/src/libs/engine/DuplexPort.cpp b/src/libs/engine/DuplexPort.cpp index 189e0d30..f4a71aae 100644 --- a/src/libs/engine/DuplexPort.cpp +++ b/src/libs/engine/DuplexPort.cpp @@ -19,7 +19,7 @@ #include #include #include -#include "TypedConnection.h" +#include "Connection.h" #include "OutputPort.h" #include "Node.h" #include "util.h" @@ -30,17 +30,14 @@ using std::cerr; using std::cout; using std::endl; namespace Ingen { -template -DuplexPort::DuplexPort(Node* parent, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size, bool is_output) -: TypedPort(parent, name, index, poly, type, buffer_size) -, InputPort(parent, name, index, poly, type, buffer_size) -, OutputPort(parent, name, index, poly, type, buffer_size) +DuplexPort::DuplexPort(Node* parent, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size, bool is_output) +: Port(parent, name, index, poly, type, buffer_size) +, InputPort(parent, name, index, poly, type, buffer_size) +, OutputPort(parent, name, index, poly, type, buffer_size) , _is_output(is_output) { - assert(TypedPort::_parent == parent); + assert(Port::_parent == parent); } -template DuplexPort::DuplexPort(Node* parent, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size, bool is_output); -template DuplexPort::DuplexPort(Node* parent, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size, bool is_output); } // namespace Ingen diff --git a/src/libs/engine/DuplexPort.h b/src/libs/engine/DuplexPort.h index 1c4e738d..10c305b4 100644 --- a/src/libs/engine/DuplexPort.h +++ b/src/libs/engine/DuplexPort.h @@ -28,7 +28,6 @@ using std::string; namespace Ingen { -class MidiMessage; class Node; @@ -40,8 +39,7 @@ class Node; * * \ingroup engine */ -template -class DuplexPort : public InputPort, public OutputPort +class DuplexPort : public InputPort, public OutputPort { public: DuplexPort(Node* parent, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size, bool is_output); @@ -57,9 +55,6 @@ protected: }; -template class DuplexPort; -template class DuplexPort; - } // namespace Ingen #endif // DUPLEXPORT_H diff --git a/src/libs/engine/Engine.cpp b/src/libs/engine/Engine.cpp index 387714f8..053528ff 100644 --- a/src/libs/engine/Engine.cpp +++ b/src/libs/engine/Engine.cpp @@ -88,16 +88,16 @@ Engine::~Engine() } -/* driver() template specializations. - * Due to the lack of RTTI, this needs to be implemented manually like this. - * If more types/drivers start getting added, it may be worth it to enable - * RTTI and put all the drivers into a map with typeid's as the key. That's - * more elegant and extensible, but this is faster and simpler - for now. - */ -template<> -Driver* Engine::driver() { return _midi_driver; } -template<> -Driver* Engine::driver() { return _audio_driver.get(); } +Driver* +Engine::driver(DataType type) +{ + if (type == DataType::FLOAT) + return _audio_driver.get(); + else if (type == DataType::MIDI) + return _midi_driver; + else + return NULL; +} int diff --git a/src/libs/engine/Engine.h b/src/libs/engine/Engine.h index 163adf68..38d638c3 100644 --- a/src/libs/engine/Engine.h +++ b/src/libs/engine/Engine.h @@ -21,6 +21,7 @@ #include #include #include +#include "DataType.h" template class Queue; @@ -39,7 +40,7 @@ class PostProcessor; class Event; class QueuedEvent; class LashDriver; -template class Driver; +class Driver; /** The main class for the Engine. @@ -77,8 +78,8 @@ public: NodeFactory* node_factory() const { return _node_factory; } LashDriver* lash_driver() const { return _lash_driver; } - /** Return the active driver for the given (template parameter) type */ - template Driver* driver(); + /** Return the active driver for the given type */ + Driver* driver(DataType type); private: SharedPtr _event_source; diff --git a/src/libs/engine/InputPort.cpp b/src/libs/engine/InputPort.cpp index 1a792c32..9326afd6 100644 --- a/src/libs/engine/InputPort.cpp +++ b/src/libs/engine/InputPort.cpp @@ -19,7 +19,8 @@ #include #include #include -#include "TypedConnection.h" +#include "AudioBuffer.h" +#include "Connection.h" #include "OutputPort.h" #include "Node.h" #include "util.h" @@ -30,13 +31,10 @@ using std::cerr; using std::cout; using std::endl; namespace Ingen { -template -InputPort::InputPort(Node* parent, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size) -: TypedPort(parent, name, index, poly, type, buffer_size) +InputPort::InputPort(Node* parent, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size) +: Port(parent, name, index, poly, type, buffer_size) { } -template InputPort::InputPort(Node* parent, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size); -template InputPort::InputPort(Node* parent, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size); /** Add a connection. Realtime safe. @@ -44,9 +42,8 @@ template InputPort::InputPort(Node* parent, const string& name, siz * The buffer of this port will be set directly to the connection's buffer * if there is only one connection, since no mixing needs to take place. */ -template void -InputPort::add_connection(Raul::ListNode*>* const c) +InputPort::add_connection(Raul::ListNode* const c) { _connections.push_back(c); @@ -61,7 +58,7 @@ InputPort::add_connection(Raul::ListNode*>* const c) _buffers.at(i)->join(c->elem()->buffer(i)); //if (_is_tied) // _tied_port->buffer(i)->join(_buffers.at(i)); - assert(_buffers.at(i)->data() == c->elem()->buffer(i)->data()); + //assert(_buffers.at(i)->data() == c->elem()->buffer(i)->data()); } } else if (_connections.size() == 2) { // Used to directly use single connection buffer, now there's two @@ -72,30 +69,26 @@ InputPort::add_connection(Raul::ListNode*>* const c) // _tied_port->buffer(i)->join(_buffers.at(i)); } } - TypedPort::connect_buffers(); + Port::connect_buffers(); } //assert( ! _is_tied || _tied_port != NULL); //assert( ! _is_tied || _buffers.at(0)->data() == _tied_port->buffer(0)->data()); } -template void InputPort::add_connection(Raul::ListNode*>* const c); -template void InputPort::add_connection(Raul::ListNode*>* const c); /** Remove a connection. Realtime safe. */ -template -Raul::ListNode*>* -InputPort::remove_connection(const OutputPort* const src_port) +Raul::ListNode* +InputPort::remove_connection(const OutputPort* src_port) { bool modify_buffers = !_fixed_buffers; //if (modify_buffers && _is_tied) // modify_buffers = !_tied_port->fixed_buffers(); - typedef typename Raul::List*>::iterator TypedConnectionListIterator; bool found = false; - Raul::ListNode*>* connection = NULL; - for (TypedConnectionListIterator i = _connections.begin(); i != _connections.end(); ++i) { + Raul::ListNode* connection = NULL; + for (Connections::iterator i = _connections.begin(); i != _connections.end(); ++i) { if ((*i)->src_port()->path() == src_port->path()) { connection = _connections.erase(i); found = true; @@ -103,7 +96,7 @@ InputPort::remove_connection(const OutputPort* const src_port) } if ( ! found) { - cerr << "WARNING: [InputPort::remove_connection] Connection not found !" << endl; + cerr << "WARNING: [InputPort::remove_connection] Connection not found !" << endl; exit(EXIT_FAILURE); } else { if (_connections.size() == 0) { @@ -126,63 +119,55 @@ InputPort::remove_connection(const OutputPort* const src_port) } if (modify_buffers) - TypedPort::connect_buffers(); + Port::connect_buffers(); //assert( ! _is_tied || _tied_port != NULL); //assert( ! _is_tied || _buffers.at(0)->data() == _tied_port->buffer(0)->data()); return connection; } -template Raul::ListNode*>* -InputPort::remove_connection(const OutputPort* const src_port); -template Raul::ListNode*>* -InputPort::remove_connection(const OutputPort* const src_port); /** Returns whether this port is connected to the passed port. */ -template bool -InputPort::is_connected_to(const OutputPort* const port) const +InputPort::is_connected_to(const OutputPort* port) const { - typedef typename Raul::List*>::const_iterator TypedConnectionListIterator; - for (TypedConnectionListIterator i = _connections.begin(); i != _connections.end(); ++i) + for (Connections::const_iterator i = _connections.begin(); i != _connections.end(); ++i) if ((*i)->src_port() == port) return true; return false; } -template bool InputPort::is_connected_to(const OutputPort* const port) const; -template bool InputPort::is_connected_to(const OutputPort* const port) const; /** Prepare buffer for access, mixing if necessary. Realtime safe. * FIXME: nframes parameter not used, */ -template<> void -InputPort::process(SampleCount nframes, FrameTime start, FrameTime end) +InputPort::process(SampleCount nframes, FrameTime start, FrameTime end) { + Port::process(nframes, start, end); + //assert(!_is_tied || _tied_port != NULL); - typedef Raul::List*>::iterator TypedConnectionListIterator; bool do_mixdown = true; if (_connections.size() == 0) return; - for (TypedConnectionListIterator c = _connections.begin(); c != _connections.end(); ++c) + for (Connections::iterator c = _connections.begin(); c != _connections.end(); ++c) (*c)->process(nframes, start, end); // If only one connection, buffer is (maybe) used directly (no copying) if (_connections.size() == 1) { // Buffer changed since connection - if (_buffers.at(0)->data() != (*_connections.begin())->buffer(0)->data()) { + if (!_buffers.at(0)->is_joined_to((*_connections.begin())->buffer(0))) { if (_fixed_buffers) { // || (_is_tied && _tied_port->fixed_buffers())) { // can't change buffer, must copy do_mixdown = true; } else { // zero-copy - assert(_buffers.at(0)->is_joined()); + //assert(_buffers.at(0)->is_joined()); _buffers.at(0)->join((*_connections.begin())->buffer(0)); do_mixdown = false; } @@ -195,7 +180,7 @@ InputPort::process(SampleCount nframes, FrameTime start, FrameTime end) //cerr << path() << " mixing: " << do_mixdown << endl; if (!do_mixdown) { - assert(_buffers.at(0)->data() == (*_connections.begin())->buffer(0)->data()); + assert(_buffers.at(0)->is_joined_to((*_connections.begin())->buffer(0))); return; } @@ -204,28 +189,30 @@ InputPort::process(SampleCount nframes, FrameTime start, FrameTime end) for (size_t voice=0; voice < _poly; ++voice) { // Copy first connection - _buffers.at(voice)->copy((*_connections.begin())->buffer(voice), 0, _buffer_size-1); + ((AudioBuffer*)_buffers.at(voice))->copy( + ((AudioBuffer*)(*_connections.begin())->buffer(voice)), 0, _buffer_size-1); // Accumulate the rest if (_connections.size() > 1) { - TypedConnectionListIterator c = _connections.begin(); + Connections::iterator c = _connections.begin(); for (++c; c != _connections.end(); ++c) - _buffers.at(voice)->accumulate((*c)->buffer(voice), 0, _buffer_size-1); + ((AudioBuffer*)_buffers.at(voice))->accumulate( + ((AudioBuffer*)(*c)->buffer(voice)), 0, _buffer_size-1); } } } +#if 0 /** Prepare buffer for access, realtime safe. * * MIDI mixing not yet implemented. */ -template <> void -InputPort::process(SampleCount nframes, FrameTime start, FrameTime end) -{ +InputPort::process(SampleCount nframes, FrameTime start, FrameTime end) +{ //assert(!_is_tied || _tied_port != NULL); const size_t num_ins = _connections.size(); @@ -233,10 +220,9 @@ InputPort::process(SampleCount nframes, FrameTime start, FrameTime assert(num_ins == 0 || num_ins == 1); - typedef Raul::List*>::iterator TypedConnectionListIterator; assert(_poly == 1); - for (TypedConnectionListIterator c = _connections.begin(); c != _connections.end(); ++c) + for (Connections::iterator c = _connections.begin(); c != _connections.end(); ++c) (*c)->process(nframes, start, end); @@ -298,21 +284,19 @@ InputPort::process(SampleCount nframes, FrameTime start, FrameTime for (size_t i=0; i < _buffers.at(0)->filled_size(); ++i) _buffers.at(0)[i] = (*_connections.begin())->buffer(0)[i]; } +#endif -template void -InputPort::set_buffer_size(size_t size) +InputPort::set_buffer_size(size_t size) { - TypedPort::set_buffer_size(size); + Port::set_buffer_size(size); assert(_buffer_size = size); - for (typename Raul::List*>::iterator c = _connections.begin(); c != _connections.end(); ++c) + for (Raul::List::iterator c = _connections.begin(); c != _connections.end(); ++c) (*c)->set_buffer_size(size); } -template void InputPort::set_buffer_size(size_t size); -template void InputPort::set_buffer_size(size_t size); } // namespace Ingen diff --git a/src/libs/engine/InputPort.h b/src/libs/engine/InputPort.h index 14efd605..284f976f 100644 --- a/src/libs/engine/InputPort.h +++ b/src/libs/engine/InputPort.h @@ -22,14 +22,14 @@ #include #include #include -#include "TypedPort.h" -#include "MidiMessage.h" +#include "Port.h" +#include "MidiBuffer.h" using std::string; namespace Ingen { -template class TypedConnection; -template class OutputPort; +class Connection; +class OutputPort; class Node; @@ -44,22 +44,22 @@ class Node; * * \ingroup engine */ -template -class InputPort : virtual public TypedPort +class InputPort : virtual public Port { public: InputPort(Node* parent, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size); virtual ~InputPort() {} - void add_connection(Raul::ListNode*>* const c); - Raul::ListNode*>* remove_connection(const OutputPort* const src_port); + void add_connection(Raul::ListNode* c); + Raul::ListNode* remove_connection(const OutputPort* src_port); - const Raul::List*>& connections() { return _connections; } + typedef Raul::List Connections; + const Connections& connections() { return _connections; } void process(SampleCount nframes, FrameTime start, FrameTime end); bool is_connected() const { return (_connections.size() > 0); } - bool is_connected_to(const OutputPort* const port) const; + bool is_connected_to(const OutputPort* port) const; bool is_input() const { return true; } bool is_output() const { return false; } @@ -67,21 +67,10 @@ public: virtual void set_buffer_size(size_t size); private: - - Raul::List*> _connections; - - // This is just stupid... - using TypedPort::_buffers; - using TypedPort::_poly; - using TypedPort::_index; - using TypedPort::_buffer_size; - using TypedPort::_fixed_buffers; + Connections _connections; }; -template class InputPort; -template class InputPort; - } // namespace Ingen #endif // INPUTPORT_H diff --git a/src/libs/engine/JackAudioDriver.cpp b/src/libs/engine/JackAudioDriver.cpp index df03dcb8..dd52d2b2 100644 --- a/src/libs/engine/JackAudioDriver.cpp +++ b/src/libs/engine/JackAudioDriver.cpp @@ -34,6 +34,7 @@ #include "MidiDriver.h" #include "DuplexPort.h" #include "EventSource.h" +#include "AudioBuffer.h" #ifdef HAVE_LASH #include "LashDriver.h" #endif @@ -46,7 +47,7 @@ namespace Ingen { //// JackAudioPort //// -JackAudioPort::JackAudioPort(JackAudioDriver* driver, DuplexPort* patch_port) +JackAudioPort::JackAudioPort(JackAudioDriver* driver, DuplexPort* patch_port) : DriverPort(patch_port->is_input()), Raul::ListNode(this), _driver(driver), @@ -83,9 +84,11 @@ JackAudioPort::prepare_buffer(jack_nframes_t nframes) */ jack_sample_t* jack_buf = (jack_sample_t*)jack_port_get_buffer(_jack_port, nframes); + AudioBuffer* patch_buf = (AudioBuffer*)_patch_port->buffer(0); + if (jack_buf != _jack_buffer) { //cerr << "Jack buffer: " << jack_buf << endl; - _patch_port->buffer(0)->set_data(jack_buf); + patch_buf->set_data(jack_buf); _jack_buffer = jack_buf; } @@ -100,7 +103,7 @@ JackAudioPort::prepare_buffer(jack_nframes_t nframes) //m_patch_port->fixed_buffers(true); //assert(_patch_port->buffer(0)->data() == _patch_port->tied_port()->buffer(0)->data()); - assert(_patch_port->buffer(0)->data() == jack_buf); + assert(patch_buf->data() == jack_buf); } @@ -257,7 +260,7 @@ JackAudioDriver::port(const Path& path) DriverPort* -JackAudioDriver::create_port(DuplexPort* patch_port) +JackAudioDriver::create_port(DuplexPort* patch_port) { if (patch_port->buffer_size() == _buffer_size) return new JackAudioPort(this, patch_port); diff --git a/src/libs/engine/JackAudioDriver.h b/src/libs/engine/JackAudioDriver.h index 8629335e..a54b4a88 100644 --- a/src/libs/engine/JackAudioDriver.h +++ b/src/libs/engine/JackAudioDriver.h @@ -31,7 +31,7 @@ namespace Ingen { class Engine; class Patch; class Port; -template class DuplexPort; +class DuplexPort; class JackAudioDriver; typedef jack_default_audio_sample_t jack_sample_t; @@ -43,21 +43,21 @@ typedef jack_default_audio_sample_t jack_sample_t; class JackAudioPort : public DriverPort, public Raul::ListNode { public: - JackAudioPort(JackAudioDriver* driver, DuplexPort* patch_port); + JackAudioPort(JackAudioDriver* driver, DuplexPort* patch_port); ~JackAudioPort(); void set_name(const std::string& name) { jack_port_set_name(_jack_port, name.c_str()); }; void prepare_buffer(jack_nframes_t nframes); - jack_port_t* jack_port() const { return _jack_port; } - DuplexPort* patch_port() const { return _patch_port; } + jack_port_t* jack_port() const { return _jack_port; } + DuplexPort* patch_port() const { return _patch_port; } private: - JackAudioDriver* _driver; - jack_port_t* _jack_port; - jack_sample_t* _jack_buffer; ///< Cached for output ports - DuplexPort* _patch_port; + JackAudioDriver* _driver; + jack_port_t* _jack_port; + jack_sample_t* _jack_buffer; ///< Cached for output ports + DuplexPort* _patch_port; }; @@ -85,7 +85,7 @@ public: void disable(); DriverPort* port(const Raul::Path& path); - DriverPort* create_port(DuplexPort* patch_port); + DriverPort* create_port(DuplexPort* patch_port); void add_port(DriverPort* port); DriverPort* remove_port(const Raul::Path& path); diff --git a/src/libs/engine/JackMidiDriver.cpp b/src/libs/engine/JackMidiDriver.cpp index e2f96ad7..ada9a439 100644 --- a/src/libs/engine/JackMidiDriver.cpp +++ b/src/libs/engine/JackMidiDriver.cpp @@ -24,7 +24,7 @@ #include "types.h" #include "ThreadManager.h" #include "AudioDriver.h" -#include "MidiMessage.h" +#include "MidiBuffer.h" #include "DuplexPort.h" #ifdef HAVE_LASH #include "LashDriver.h" @@ -36,7 +36,7 @@ namespace Ingen { //// JackMidiPort //// -JackMidiPort::JackMidiPort(JackMidiDriver* driver, DuplexPort* patch_port) +JackMidiPort::JackMidiPort(JackMidiDriver* driver, DuplexPort* patch_port) : DriverPort(patch_port->is_input()), Raul::ListNode(this), _driver(driver), @@ -75,25 +75,25 @@ JackMidiPort::prepare_block(const SampleCount block_start, const SampleCount blo void* jack_buffer = jack_port_get_buffer(_jack_port, nframes); const jack_nframes_t event_count = jack_midi_get_event_count(jack_buffer); - assert(event_count < _patch_port->buffer_size()); + assert(_patch_port->poly() == 1); + + MidiBuffer* patch_buf = dynamic_cast(_patch_port->buffer(0)); + assert(patch_buf); + + patch_buf->clear(); + patch_buf->reset_state(nframes); // Copy events from Jack port buffer into patch port buffer for (jack_nframes_t i=0; i < event_count; ++i) { - jack_midi_event_t* ev = (jack_midi_event_t*)&_patch_port->buffer(0)->value_at(i); - jack_midi_event_get(ev, jack_buffer, i); - - // MidiMessage and jack_midi_event_t* are the same thing :/ - MidiMessage* const message = &_patch_port->buffer(0)->data()[i]; - message->time = ev->time; - message->size = ev->size; - message->buffer = ev->buffer; + jack_midi_event_t ev; + jack_midi_event_get(&ev, jack_buffer, i); - assert(message->time < nframes); + patch_buf->put_event(ev.time, ev.size, ev.buffer); } //cerr << "Jack MIDI got " << event_count << " events." << endl; - _patch_port->buffer(0)->filled_size(event_count); + //_patch_port->buffer(0)->filled_size(event_count); //_patch_port->tied_port()->buffer(0)->filled_size(event_count); } diff --git a/src/libs/engine/JackMidiDriver.h b/src/libs/engine/JackMidiDriver.h index d6d2cf51..535a1f22 100644 --- a/src/libs/engine/JackMidiDriver.h +++ b/src/libs/engine/JackMidiDriver.h @@ -29,7 +29,7 @@ namespace Ingen { class Node; class SetPortValueEvent; class JackMidiDriver; -template class DuplexPort; +class DuplexPort; /** Representation of an JACK MIDI port. @@ -39,19 +39,19 @@ template class DuplexPort; class JackMidiPort : public DriverPort, public Raul::ListNode { public: - JackMidiPort(JackMidiDriver* driver, DuplexPort* port); + JackMidiPort(JackMidiDriver* driver, DuplexPort* port); virtual ~JackMidiPort(); void prepare_block(const SampleCount block_start, const SampleCount block_end); void set_name(const std::string& name) { jack_port_set_name(_jack_port, name.c_str()); }; - DuplexPort* patch_port() const { return _patch_port; } + DuplexPort* patch_port() const { return _patch_port; } private: - JackMidiDriver* _driver; - jack_port_t* _jack_port; - DuplexPort* _patch_port; + JackMidiDriver* _driver; + jack_port_t* _jack_port; + DuplexPort* _patch_port; }; @@ -78,7 +78,7 @@ public: void prepare_block(const SampleCount block_start, const SampleCount block_end); - JackMidiPort* create_port(DuplexPort* patch_port) + JackMidiPort* create_port(DuplexPort* patch_port) { return new JackMidiPort(this, patch_port); } void add_port(DriverPort* port); diff --git a/src/libs/engine/LADSPANode.cpp b/src/libs/engine/LADSPANode.cpp index d9b350b4..3ad197a4 100644 --- a/src/libs/engine/LADSPANode.cpp +++ b/src/libs/engine/LADSPANode.cpp @@ -15,13 +15,12 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - #include "LADSPANode.h" #include #include -#include "float.h" #include #include +#include "AudioBuffer.h" #include "InputPort.h" #include "OutputPort.h" #include "Plugin.h" @@ -106,10 +105,10 @@ LADSPANode::instantiate() || LADSPA_IS_PORT_OUTPUT(_descriptor->PortDescriptors[j])); if (LADSPA_IS_PORT_INPUT(_descriptor->PortDescriptors[j])) { - port = new InputPort(this, port_name, j, _poly, DataType::FLOAT, port_buffer_size); + port = new InputPort(this, port_name, j, _poly, DataType::FLOAT, port_buffer_size); _ports->at(j) = port; } else if (LADSPA_IS_PORT_OUTPUT(_descriptor->PortDescriptors[j])) { - port = new OutputPort(this, port_name, j, _poly, DataType::FLOAT, port_buffer_size); + port = new OutputPort(this, port_name, j, _poly, DataType::FLOAT, port_buffer_size); _ports->at(j) = port; } @@ -121,9 +120,8 @@ LADSPANode::instantiate() // Set default value if (port->buffer_size() == 1) { - ((TypedPort*)port)->set_value(default_val, 0); - } else { - ((TypedPort*)port)->set_value(0.0f, 0); + for (size_t i=0; i < _poly; ++i) + ((AudioBuffer*)port->buffer(i))->set(default_val, 0); } if (port->is_input() && port->buffer_size() == 1) { @@ -150,12 +148,9 @@ LADSPANode::activate() { NodeBase::activate(); - TypedPort* port = NULL; - for (size_t i=0; i < _poly; ++i) { for (unsigned long j=0; j < _descriptor->PortCount; ++j) { - port = static_cast*>(_ports->at(j)); - set_port_buffer(i, j, ((TypedPort*)_ports->at(j))->buffer(i)->data()); + set_port_buffer(i, j, _ports->at(j)->buffer(i)); /* if (port->type() == DataType::FLOAT && port->buffer_size() == 1) port->set_value(0.0f, 0); // FIXME else if (port->type() == DataType::FLOAT && port->buffer_size() > 1) @@ -188,13 +183,17 @@ LADSPANode::process(SampleCount nframes, FrameTime start, FrameTime end) void -LADSPANode::set_port_buffer(size_t voice, size_t port_num, void* buf) +LADSPANode::set_port_buffer(size_t voice, size_t port_num, Buffer* buf) { assert(voice < _poly); + AudioBuffer* audio_buffer = dynamic_cast(buf); + assert(audio_buffer); + // Could be a MIDI port after this if (port_num < _descriptor->PortCount) - _descriptor->connect_port(_instances[voice], port_num, (Sample*)buf); + _descriptor->connect_port(_instances[voice], port_num, + audio_buffer->data()); } #if 0 diff --git a/src/libs/engine/LADSPANode.h b/src/libs/engine/LADSPANode.h index 0f9d7ee9..ff813f4c 100644 --- a/src/libs/engine/LADSPANode.h +++ b/src/libs/engine/LADSPANode.h @@ -44,7 +44,7 @@ public: void process(SampleCount nframes, FrameTime start, FrameTime end); - void set_port_buffer(size_t voice, size_t port_num, void* buf); + void set_port_buffer(size_t voice, size_t port_num, Buffer* buf); const Plugin* plugin() const { return _plugin; } void plugin(const Plugin* const pi) { _plugin = pi; } diff --git a/src/libs/engine/LV2Node.cpp b/src/libs/engine/LV2Node.cpp index ebc6a72c..0baf41ef 100644 --- a/src/libs/engine/LV2Node.cpp +++ b/src/libs/engine/LV2Node.cpp @@ -24,6 +24,7 @@ #include "InputPort.h" #include "OutputPort.h" #include "Plugin.h" +#include "AudioBuffer.h" namespace Ingen { @@ -98,16 +99,16 @@ LV2Node::instantiate() port_buffer_size = 1; if (port_class == SLV2_CONTROL_INPUT || port_class == SLV2_AUDIO_INPUT) { - port = new InputPort(this, port_name, j, _poly, DataType::FLOAT, port_buffer_size); + port = new InputPort(this, port_name, j, _poly, DataType::FLOAT, port_buffer_size); _ports->at(j) = port; } else if (port_class == SLV2_CONTROL_OUTPUT || port_class == SLV2_AUDIO_OUTPUT) { - port = new OutputPort(this, port_name, j, _poly, DataType::FLOAT, port_buffer_size); + port = new OutputPort(this, port_name, j, _poly, DataType::FLOAT, port_buffer_size); _ports->at(j) = port; } else if (port_class == SLV2_MIDI_INPUT) { - port = new InputPort(this, port_name, j, _poly, DataType::MIDI, port_buffer_size); + port = new InputPort(this, port_name, j, _poly, DataType::MIDI, port_buffer_size); _ports->at(j) = port; } else if (port_class == SLV2_MIDI_OUTPUT) { - port = new OutputPort(this, port_name, j, _poly, DataType::MIDI, port_buffer_size); + port = new OutputPort(this, port_name, j, _poly, DataType::MIDI, port_buffer_size); _ports->at(j) = port; } @@ -140,16 +141,16 @@ LV2Node::activate() { NodeBase::activate(); - TypedPort* port = NULL; - for (size_t i=0; i < _poly; ++i) { for (unsigned long j=0; j < num_ports(); ++j) { - port = static_cast*>(_ports->at(j)); - set_port_buffer(i, j, ((TypedPort*)_ports->at(j))->buffer(i)->data()); - if (port->type() == DataType::FLOAT && port->buffer_size() == 1) - port->set_value(0.0f, 0); // FIXME - else if (port->type() == DataType::FLOAT && port->buffer_size() > 1) - port->set_value(0.0f, 0); + Port* const port = _ports->at(j); + set_port_buffer(i, j, port->buffer(i)); + if (port->type() == DataType::FLOAT && port->buffer_size() == 1) { + cerr << "FIXME: LV2 default value\n"; + ((AudioBuffer*)port->buffer(i))->set(0.0f, 0); // FIXME + } else if (port->type() == DataType::FLOAT && port->buffer_size() > 1) { + ((AudioBuffer*)port->buffer(i))->set(0.0f, 0); + } } slv2_instance_activate(_instances[i]); } @@ -176,14 +177,14 @@ LV2Node::process(SampleCount nframes, FrameTime start, FrameTime end) void -LV2Node::set_port_buffer(size_t voice, size_t port_num, void* buf) +LV2Node::set_port_buffer(size_t voice, size_t port_num, Buffer* buf) { assert(voice < _poly); - // Could be a MIDI port after this - if (port_num < num_ports()) { - slv2_instance_connect_port(_instances[voice], port_num, buf); - } + if (buf->type() == DataType::FLOAT) + slv2_instance_connect_port(_instances[voice], port_num, ((AudioBuffer*)buf)->data()); + else if (buf->type() == DataType::MIDI) + slv2_instance_connect_port(_instances[voice], port_num, ((MidiBuffer*)buf)->data()); } diff --git a/src/libs/engine/LV2Node.h b/src/libs/engine/LV2Node.h index f0547161..39b06939 100644 --- a/src/libs/engine/LV2Node.h +++ b/src/libs/engine/LV2Node.h @@ -50,7 +50,7 @@ public: void process(SampleCount nframes, FrameTime start, FrameTime end); - void set_port_buffer(size_t voice, size_t port_num, void* buf); + void set_port_buffer(size_t voice, size_t port_num, Buffer* buf); protected: //void get_port_vals(ulong port_index, PortInfo* info); diff --git a/src/libs/engine/Makefile.am b/src/libs/engine/Makefile.am index 03c42c52..29b601a9 100644 --- a/src/libs/engine/Makefile.am +++ b/src/libs/engine/Makefile.am @@ -38,11 +38,13 @@ libingen_la_SOURCES = \ OSCClientSender.h \ OSCClientSender.cpp \ Buffer.h \ - Buffer.cpp \ + AudioBuffer.h \ + AudioBuffer.cpp \ + MidiBuffer.h \ + MidiBuffer.cpp \ + BufferFactory.cpp \ Port.h \ Port.cpp \ - TypedPort.h \ - TypedPort.cpp \ InputPort.h \ InputPort.cpp \ OutputPort.h \ @@ -73,8 +75,6 @@ libingen_la_SOURCES = \ PostProcessor.cpp \ Connection.h \ Connection.cpp \ - TypedConnection.h \ - TypedConnection.cpp \ ObjectStore.h \ ObjectStore.cpp \ TransportNode.h \ diff --git a/src/libs/engine/MidiBuffer.cpp b/src/libs/engine/MidiBuffer.cpp new file mode 100644 index 00000000..7dfe72e6 --- /dev/null +++ b/src/libs/engine/MidiBuffer.cpp @@ -0,0 +1,77 @@ +/* This file is part of Ingen. + * Copyright (C) 2007 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 "MidiBuffer.h" + +namespace Ingen { + + +/** Use another buffer's data instead of the local one. + * + * This buffer will essentially be identical to @a buf after this call. + */ +bool +MidiBuffer::join(Buffer* buf) +{ + MidiBuffer* mbuf = dynamic_cast(buf); + if (!mbuf) + return false; + + //assert(mbuf->size() == _size); + + _joined_buf = mbuf; + + _buf = mbuf->data(); + _state = mbuf->state(); + + return true; +} + + +void +MidiBuffer::unjoin() +{ + _joined_buf = NULL; + _buf = _local_buf; + _state = &_local_state; +} + + +bool +MidiBuffer::is_joined_to(Buffer* buf) const +{ + MidiBuffer* mbuf = dynamic_cast(buf); + if (mbuf) + return (data() == mbuf->data()); + + return false; +} + + +void +MidiBuffer::prepare(SampleCount nframes) +{ + if (_joined_buf) + _local_state = *_joined_buf->state(); + else + reset_state(nframes); + + _this_nframes = nframes; +} + + +} // namespace Ingen diff --git a/src/libs/engine/MidiBuffer.h b/src/libs/engine/MidiBuffer.h new file mode 100644 index 00000000..459c1209 --- /dev/null +++ b/src/libs/engine/MidiBuffer.h @@ -0,0 +1,88 @@ +/* This file is part of Ingen. + * Copyright (C) 2007 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 + */ + +#ifndef MIDIBUFFER_H +#define MIDIBUFFER_H + +#include +#include +#include "Buffer.h" +#include "DataType.h" + +namespace Ingen { + + +class MidiBuffer : public Buffer { +public: + MidiBuffer(size_t capacity) + : Buffer(DataType(DataType::MIDI), capacity) + , _state(&_local_state) + , _buf(lv2midi_new((uint32_t)capacity)) + , _local_buf(NULL) + , _joined_buf(NULL) + { + clear(); + reset_state(0); + } + + ~MidiBuffer() { lv2midi_free(_buf); } + + void prepare(SampleCount nframes); + + bool is_joined_to(Buffer* buf) const; + bool is_joined() const { return (_joined_buf == NULL); } + bool join(Buffer* buf); + void unjoin(); + + uint32_t this_nframes() const { return _this_nframes; } + + inline LV2_MIDI* data() const + { return ((_joined_buf != NULL) ? _joined_buf->data() : _buf); } + + inline LV2_MIDIState* state() const + { return ((_joined_buf != NULL) ? _joined_buf->state() : _state); } + + inline void clear() + { lv2midi_reset_buffer(_buf); } + + inline void reset_state(uint32_t nframes) + { lv2midi_reset_state(_state, _buf, nframes); _this_nframes = nframes; } + + inline double increment() + { return lv2midi_increment(_state); } + + inline double get_event(double* timestamp, uint32_t* size, unsigned char** data) + { return lv2midi_get_event(_state, timestamp, size, data); } + + inline int put_event(double timestamp, uint32_t size, const unsigned char* data) + { return lv2midi_put_event(_state, timestamp, size, data); } + +private: + LV2_MIDIState* _state; + LV2_MIDIState _local_state; + LV2_MIDI* _buf; + LV2_MIDI* _local_buf; + + MidiBuffer* _joined_buf; ///< Buffer to mirror, if joined + + uint32_t _this_nframes; +}; + + +} // namespace Ingen + +#endif // MIDIBUFFER_H diff --git a/src/libs/engine/MidiControlNode.cpp b/src/libs/engine/MidiControlNode.cpp index 89a04c91..81df8e6c 100644 --- a/src/libs/engine/MidiControlNode.cpp +++ b/src/libs/engine/MidiControlNode.cpp @@ -24,7 +24,7 @@ #include "OutputPort.h" #include "Plugin.h" #include "util.h" - +#include "AudioBuffer.h" namespace Ingen { @@ -35,25 +35,25 @@ MidiControlNode::MidiControlNode(const string& path, size_t poly, Patch* parent, { _ports = new Raul::Array(7); - _midi_in_port = new InputPort(this, "MIDIIn", 0, 1, DataType::MIDI, _buffer_size); + _midi_in_port = new InputPort(this, "MIDIIn", 0, 1, DataType::MIDI, _buffer_size); _ports->at(0) = _midi_in_port; - _param_port = new InputPort(this, "ControllerNumber", 1, 1, DataType::FLOAT, 1); + _param_port = new InputPort(this, "ControllerNumber", 1, 1, DataType::FLOAT, 1); _ports->at(1) = _param_port; - _log_port = new InputPort(this, "Logarithmic", 2, 1, DataType::FLOAT, 1); + _log_port = new InputPort(this, "Logarithmic", 2, 1, DataType::FLOAT, 1); _ports->at(2) = _log_port; - _min_port = new InputPort(this, "Min", 3, 1, DataType::FLOAT, 1); + _min_port = new InputPort(this, "Min", 3, 1, DataType::FLOAT, 1); _ports->at(3) = _min_port; - _max_port = new InputPort(this, "Max", 4, 1, DataType::FLOAT, 1); + _max_port = new InputPort(this, "Max", 4, 1, DataType::FLOAT, 1); _ports->at(4) = _max_port; - _audio_port = new OutputPort(this, "Out(AR)", 5, 1, DataType::FLOAT, _buffer_size); + _audio_port = new OutputPort(this, "Out(AR)", 5, 1, DataType::FLOAT, _buffer_size); _ports->at(5) = _audio_port; - _control_port = new OutputPort(this, "Out(CR)", 6, 1, DataType::FLOAT, 1); + _control_port = new OutputPort(this, "Out(CR)", 6, 1, DataType::FLOAT, 1); _ports->at(6) = _control_port; plugin()->plug_label("midi_control_in"); @@ -66,14 +66,20 @@ void MidiControlNode::process(SampleCount nframes, FrameTime start, FrameTime end) { InternalNode::process(nframes, start, end); - - MidiMessage ev; - for (size_t i=0; i < _midi_in_port->buffer(0)->filled_size(); ++i) { - ev = _midi_in_port->buffer(0)->value_at(i); + double timestamp = 0; + uint32_t size = 0; + unsigned char* buffer = NULL; + + MidiBuffer* const midi_in = (MidiBuffer*)_midi_in_port->buffer(0); + assert(midi_in->this_nframes() == nframes); - if ((ev.buffer[0] & 0xF0) == MIDI_CMD_CONTROL) - control(ev.buffer[1], ev.buffer[2], ev.time); + while (midi_in->get_event(×tamp, &size, &buffer) < nframes) { + + const FrameTime time = start + (FrameTime)timestamp; + + if (size >= 3 && (buffer[0] & 0xF0) == MIDI_CMD_CONTROL) + control(buffer[1], buffer[2], time); } } @@ -102,23 +108,25 @@ MidiControlNode::control(uchar control_num, uchar val, SampleCount offset) #endif } - if (_log_port->buffer(0)->value_at(0) > 0.0f) { + const Sample min_port_val = ((AudioBuffer*)_min_port->buffer(0))->value_at(0); + const Sample max_port_val = ((AudioBuffer*)_max_port->buffer(0))->value_at(0); + const Sample log_port_val = ((AudioBuffer*)_log_port->buffer(0))->value_at(0); + + if (log_port_val > 0.0f) { // haaaaack, stupid negatives and logarithms Sample log_offset = 0; - if (_min_port->buffer(0)->value_at(0) < 0) - log_offset = fabs(_min_port->buffer(0)->value_at(0)); - const Sample min = log(_min_port->buffer(0)->value_at(0)+1+log_offset); - const Sample max = log(_max_port->buffer(0)->value_at(0)+1+log_offset); + 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 { - const Sample min = _min_port->buffer(0)->value_at(0); - const Sample max = _max_port->buffer(0)->value_at(0); - scaled_value = ((nval) * (max - min)) + min; + scaled_value = ((nval) * (max_port_val - min_port_val)) + min_port_val; } - if (control_num == _param_port->buffer(0)->value_at(0)) { - _control_port->set_value(scaled_value, offset); - _audio_port->set_value(scaled_value, offset); + if (control_num == ((AudioBuffer*)_param_port->buffer(0))->value_at(0)) { + ((AudioBuffer*)_control_port->buffer(0))->set(scaled_value, offset); + ((AudioBuffer*)_audio_port->buffer(0))->set(scaled_value, offset); } } diff --git a/src/libs/engine/MidiControlNode.h b/src/libs/engine/MidiControlNode.h index 997d5dd4..41d02dfb 100644 --- a/src/libs/engine/MidiControlNode.h +++ b/src/libs/engine/MidiControlNode.h @@ -21,14 +21,13 @@ #include #include "NodeBase.h" #include "InternalNode.h" -using std::string; +#include "MidiBuffer.h" namespace Ingen { class MidiLearnResponseEvent; -class MidiMessage; -template class InputPort; -template class OutputPort; +class InputPort; +class OutputPort; /** MIDI control input node. @@ -41,7 +40,7 @@ template class OutputPort; class MidiControlNode : public InternalNode { public: - MidiControlNode(const string& path, size_t poly, Patch* parent, SampleRate srate, size_t buffer_size); + MidiControlNode(const std::string& path, size_t poly, Patch* parent, SampleRate srate, size_t buffer_size); void process(SampleCount nframes, FrameTime start, FrameTime end); @@ -52,13 +51,13 @@ public: private: bool _learning; - InputPort* _midi_in_port; - InputPort* _param_port; - InputPort* _log_port; - InputPort* _min_port; - InputPort* _max_port; - OutputPort* _control_port; - OutputPort* _audio_port; + InputPort* _midi_in_port; + InputPort* _param_port; + InputPort* _log_port; + InputPort* _min_port; + InputPort* _max_port; + OutputPort* _control_port; + OutputPort* _audio_port; MidiLearnResponseEvent* _learn_event; }; diff --git a/src/libs/engine/MidiDriver.h b/src/libs/engine/MidiDriver.h index 1458aca5..ebee458c 100644 --- a/src/libs/engine/MidiDriver.h +++ b/src/libs/engine/MidiDriver.h @@ -21,20 +21,20 @@ #include "types.h" #include "Driver.h" #include -using std::cout; using std::endl; +#include "MidiBuffer.h" namespace Ingen { -class MidiMessage; - /** Midi driver abstract base class. * * \ingroup engine */ -class MidiDriver : public Driver +class MidiDriver : public Driver { public: + MidiDriver() : Driver(DataType::MIDI) {} + /** Prepare events (however neccessary) for the specified block (realtime safe) */ virtual void prepare_block(const SampleCount block_start, const SampleCount block_end) = 0; }; @@ -54,7 +54,7 @@ class DummyMidiDriver : public MidiDriver { public: DummyMidiDriver() { - cout << "[DummyMidiDriver] Started Dummy MIDI driver." << endl; + std::cout << "[DummyMidiDriver] Started Dummy MIDI driver." << std::endl; } ~DummyMidiDriver() {} @@ -68,7 +68,7 @@ public: void enable() {} void disable() {} - DriverPort* create_port(DuplexPort* patch_port) { return NULL; } + DriverPort* create_port(DuplexPort* patch_port) { return NULL; } void add_port(DriverPort* port) {} DriverPort* remove_port(const Raul::Path& path) { return NULL; } diff --git a/src/libs/engine/MidiMessage.h b/src/libs/engine/MidiMessage.h deleted file mode 100644 index 00082acd..00000000 --- a/src/libs/engine/MidiMessage.h +++ /dev/null @@ -1,52 +0,0 @@ -/* This file is part of Ingen. - * Copyright (C) 2007 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 - */ - -#ifndef MIDIMESSAGE_H -#define MIDIMESSAGE_H - -namespace Ingen { - - -/** Midi Message (the type a MIDI port connects to). - * - * For the time being (ie while it's still possible) this is binary - * compatible with jack_default_midi_event_t. Don't mess that up without - * dealing with all the repercussions (in the MidiDriver's). - * - * Note that with the current implementation one of these is NOT valid - * across process cycles (since the buffer is just a pointer to the bufferr - * given to us by Jack itself. In other words, if one of these needs to be - * stored, it needs to be deep copied. Less copying anyway.. :/ - */ -struct MidiMessage -{ -public: - MidiMessage() : time(0), size(0), buffer(NULL) {} - - // Really just to allow setting to zero for generic algos - MidiMessage(const int& i) : time(0), size(0), buffer(NULL) {} - - SampleCount time; - size_t size; - unsigned char* buffer; -}; - - -} // namespace Ingen - - -#endif // MIDIMESSAGE_H diff --git a/src/libs/engine/MidiNoteNode.cpp b/src/libs/engine/MidiNoteNode.cpp index f2b9e502..6a6b698c 100644 --- a/src/libs/engine/MidiNoteNode.cpp +++ b/src/libs/engine/MidiNoteNode.cpp @@ -20,7 +20,8 @@ #include #include #include -#include "MidiMessage.h" +#include "MidiBuffer.h" +#include "AudioBuffer.h" #include "InputPort.h" #include "OutputPort.h" #include "Plugin.h" @@ -40,22 +41,22 @@ MidiNoteNode::MidiNoteNode(const string& path, size_t poly, Patch* parent, Sampl { _ports = new Raul::Array(5); - _midi_in_port = new InputPort(this, "MIDIIn", 0, 1, DataType::MIDI, _buffer_size); + _midi_in_port = new InputPort(this, "MIDIIn", 0, 1, DataType::MIDI, _buffer_size); _ports->at(0) = _midi_in_port; - _freq_port = new OutputPort(this, "Frequency", 1, poly, DataType::FLOAT, _buffer_size); + _freq_port = new OutputPort(this, "Frequency", 1, poly, DataType::FLOAT, _buffer_size); // new PortInfo("Frequency", AUDIO, OUTPUT, 440, 0, 99999), _buffer_size); _ports->at(1) = _freq_port; - _vel_port = new OutputPort(this, "Velocity", 2, poly, DataType::FLOAT, _buffer_size); + _vel_port = new OutputPort(this, "Velocity", 2, poly, DataType::FLOAT, _buffer_size); // new PortInfo("Velocity", AUDIO, OUTPUT, 0, 0, 1), _buffer_size); _ports->at(2) = _vel_port; - _gate_port = new OutputPort(this, "Gate", 3, poly, DataType::FLOAT, _buffer_size); + _gate_port = new OutputPort(this, "Gate", 3, poly, DataType::FLOAT, _buffer_size); // new PortInfo("Gate", AUDIO, OUTPUT, 0, 0, 1), _buffer_size); _ports->at(3) = _gate_port; - _trig_port = new OutputPort(this, "Trigger", 4, poly, DataType::FLOAT, _buffer_size); + _trig_port = new OutputPort(this, "Trigger", 4, poly, DataType::FLOAT, _buffer_size); // new PortInfo("Trigger", AUDIO, OUTPUT, 0, 0, 1), _buffer_size); _ports->at(4) = _trig_port; @@ -76,42 +77,50 @@ MidiNoteNode::process(SampleCount nframes, FrameTime start, FrameTime end) { InternalNode::process(nframes, start, end); - MidiMessage ev; - - for (size_t i=0; i < _midi_in_port->buffer(0)->filled_size(); ++i) { - ev = _midi_in_port->buffer(0)->value_at(i); + double timestamp = 0; + uint32_t size = 0; + unsigned char* buffer = NULL; - const FrameTime time = ev.time + start; + MidiBuffer* const midi_in = (MidiBuffer*)_midi_in_port->buffer(0); + assert(midi_in->this_nframes() == nframes); - switch (ev.buffer[0] & 0xF0) { - case MIDI_CMD_NOTE_ON: - if (ev.buffer[2] == 0) - note_off(ev.buffer[1], time, nframes, start, end); - else - note_on(ev.buffer[1], ev.buffer[2], time, nframes, start, end); - break; - case MIDI_CMD_NOTE_OFF: - note_off(ev.buffer[1], time, nframes, start, end); - break; - case MIDI_CMD_CONTROL: - switch (ev.buffer[1]) { - case MIDI_CTL_ALL_NOTES_OFF: - case MIDI_CTL_ALL_SOUNDS_OFF: - all_notes_off(time, nframes, start, end); - break; - case MIDI_CTL_SUSTAIN: - if (ev.buffer[2] > 63) - sustain_on(time, nframes, start, end); + while (midi_in->get_event(×tamp, &size, &buffer) < nframes) { + + const FrameTime time = start + (FrameTime)timestamp; + + if (size >= 3) { + switch (buffer[0] & 0xF0) { + case MIDI_CMD_NOTE_ON: + if (buffer[2] == 0) + note_off(buffer[1], time, nframes, start, end); else - sustain_off(time, nframes, start, end); + note_on(buffer[1], buffer[2], time, nframes, start, end); break; - case MIDI_CMD_BENDER: - + case MIDI_CMD_NOTE_OFF: + note_off(buffer[1], time, nframes, start, end); + break; + case MIDI_CMD_CONTROL: + switch (buffer[1]) { + case MIDI_CTL_ALL_NOTES_OFF: + case MIDI_CTL_ALL_SOUNDS_OFF: + all_notes_off(time, nframes, start, end); + break; + case MIDI_CTL_SUSTAIN: + if (buffer[2] > 63) + sustain_on(time, nframes, start, end); + else + sustain_off(time, nframes, start, end); + break; + case MIDI_CMD_BENDER: + + break; + } + default: break; } - default: - break; } + + midi_in->increment(); } } @@ -183,13 +192,13 @@ MidiNoteNode::note_on(uchar note_num, uchar velocity, FrameTime time, SampleCoun if (offset == (SampleCount)(_buffer_size-1)) --offset; - _freq_port->buffer(voice_num)->set(note_to_freq(note_num), offset); - _vel_port->buffer(voice_num)->set(velocity/127.0, offset); - _gate_port->buffer(voice_num)->set(1.0f, offset); + ((AudioBuffer*)_freq_port->buffer(voice_num))->set(note_to_freq(note_num), offset); + ((AudioBuffer*)_vel_port->buffer(voice_num))->set(velocity/127.0, offset); + ((AudioBuffer*)_gate_port->buffer(voice_num))->set(1.0f, offset); // trigger (one sample) - _trig_port->buffer(voice_num)->set(1.0f, offset, offset); - _trig_port->buffer(voice_num)->set(0.0f, offset+1); + ((AudioBuffer*)_trig_port->buffer(voice_num))->set(1.0f, offset, offset); + ((AudioBuffer*)_trig_port->buffer(voice_num))->set(0.0f, offset+1); assert(key->state == Key::Key::ON_ASSIGNED); assert(voice->state == Voice::Voice::ACTIVE); @@ -246,7 +255,7 @@ MidiNoteNode::free_voice(size_t voice, FrameTime time, SampleCount nframes, Fram assert(replace_key->state == Key::ON_UNASSIGNED); // Change the freq but leave the gate high and don't retrigger - _freq_port->buffer(voice)->set(note_to_freq(replace_key_num), time - start); + ((AudioBuffer*)_freq_port->buffer(voice))->set(note_to_freq(replace_key_num), time - start); replace_key->state = Key::ON_ASSIGNED; replace_key->voice = voice; @@ -256,7 +265,7 @@ MidiNoteNode::free_voice(size_t voice, FrameTime time, SampleCount nframes, Fram } else { // No new note for voice, deactivate (set gate low) //cerr << "[MidiNoteNode] Note off. Key " << (int)note_num << ", Voice " << voice << " Killed" << endl; - _gate_port->buffer(voice)->set(0.0f, time - start); + ((AudioBuffer*)_gate_port->buffer(voice))->set(0.0f, time - start); _voices[voice].state = Voice::FREE; } } @@ -273,7 +282,7 @@ MidiNoteNode::all_notes_off(FrameTime time, SampleCount nframes, FrameTime start // FIXME: set all keys to Key::OFF? for (size_t i=0; i < _poly; ++i) { - _gate_port->buffer(i)->set(0.0f, time - start); + ((AudioBuffer*)_gate_port->buffer(i))->set(0.0f, time - start); _voices[i].state = Voice::FREE; } } diff --git a/src/libs/engine/MidiNoteNode.h b/src/libs/engine/MidiNoteNode.h index a4f22c7f..5be62995 100644 --- a/src/libs/engine/MidiNoteNode.h +++ b/src/libs/engine/MidiNoteNode.h @@ -21,14 +21,14 @@ #include #include "InternalNode.h" #include "types.h" +#include "MidiBuffer.h" using std::string; namespace Ingen { -class MidiMessage; -template class InputPort; -template class OutputPort; +class InputPort; +class OutputPort; /** MIDI note input node. @@ -74,11 +74,11 @@ private: 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; + InputPort* _midi_in_port; + OutputPort* _freq_port; + OutputPort* _vel_port; + OutputPort* _gate_port; + OutputPort* _trig_port; }; diff --git a/src/libs/engine/MidiTriggerNode.cpp b/src/libs/engine/MidiTriggerNode.cpp index d0beff60..9d78f7b8 100644 --- a/src/libs/engine/MidiTriggerNode.cpp +++ b/src/libs/engine/MidiTriggerNode.cpp @@ -15,9 +15,10 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "MidiTriggerNode.h" #include #include +#include "MidiTriggerNode.h" +#include "AudioBuffer.h" #include "InputPort.h" #include "OutputPort.h" #include "Plugin.h" @@ -31,22 +32,22 @@ MidiTriggerNode::MidiTriggerNode(const string& path, size_t poly, Patch* parent, { _ports = new Raul::Array(5); - _midi_in_port = new InputPort(this, "MIDIIn", 0, 1, DataType::MIDI, _buffer_size); + _midi_in_port = new InputPort(this, "MIDIIn", 0, 1, DataType::MIDI, _buffer_size); _ports->at(0) = _midi_in_port; - _note_port = new InputPort(this, "NoteNumber", 1, 1, DataType::FLOAT, 1); + _note_port = new InputPort(this, "NoteNumber", 1, 1, DataType::FLOAT, 1); // new PortInfo("Note Number", CONTROL, INPUT, INTEGER, 60, 0, 127), 1); _ports->at(1) = _note_port; - _gate_port = new OutputPort(this, "Gate", 2, 1, DataType::FLOAT, _buffer_size); + _gate_port = new OutputPort(this, "Gate", 2, 1, DataType::FLOAT, _buffer_size); // new PortInfo("Gate", AUDIO, OUTPUT, 0, 0, 1), _buffer_size); _ports->at(2) = _gate_port; - _trig_port = new OutputPort(this, "Trigger", 3, 1, DataType::FLOAT, _buffer_size); + _trig_port = new OutputPort(this, "Trigger", 3, 1, DataType::FLOAT, _buffer_size); // new PortInfo("Trigger", AUDIO, OUTPUT, 0, 0, 1), _buffer_size); _ports->at(3) = _trig_port; - _vel_port = new OutputPort(this, "Velocity", 4, poly, DataType::FLOAT, _buffer_size); + _vel_port = new OutputPort(this, "Velocity", 4, poly, DataType::FLOAT, _buffer_size); // new PortInfo("Velocity", AUDIO, OUTPUT, 0, 0, 1), _buffer_size); _ports->at(4) = _vel_port; @@ -61,27 +62,35 @@ MidiTriggerNode::process(SampleCount nframes, FrameTime start, FrameTime end) { InternalNode::process(nframes, start, end); - MidiMessage ev; - - for (size_t i=0; i < _midi_in_port->buffer(0)->filled_size(); ++i) { - ev = _midi_in_port->buffer(0)->value_at(i); - - switch (ev.buffer[0] & 0xF0) { - case MIDI_CMD_NOTE_ON: - if (ev.buffer[2] == 0) - note_off(ev.buffer[1], ev.time, nframes, start, end); - else - note_on(ev.buffer[1], ev.buffer[2], ev.time, nframes, start, end); - break; - case MIDI_CMD_NOTE_OFF: - note_off(ev.buffer[1], ev.time, nframes, start, end); - break; - case MIDI_CMD_CONTROL: - if (ev.buffer[1] == MIDI_CTL_ALL_NOTES_OFF - || ev.buffer[1] == MIDI_CTL_ALL_SOUNDS_OFF) - _gate_port->buffer(0)->set(0.0f, ev.time); - default: - break; + double timestamp = 0; + uint32_t size = 0; + unsigned char* buffer = NULL; + + MidiBuffer* const midi_in = (MidiBuffer*)_midi_in_port->buffer(0); + assert(midi_in->this_nframes() == nframes); + + while (midi_in->get_event(×tamp, &size, &buffer) < nframes) { + + const FrameTime time = start + (FrameTime)timestamp; + + if (size >= 3) { + switch (buffer[0] & 0xF0) { + case MIDI_CMD_NOTE_ON: + if (buffer[2] == 0) + note_off(buffer[1], time, nframes, start, end); + else + note_on(buffer[1], buffer[2], time, nframes, start, end); + break; + case MIDI_CMD_NOTE_OFF: + note_off(buffer[1], time, nframes, start, end); + break; + case MIDI_CMD_CONTROL: + if (buffer[1] == MIDI_CTL_ALL_NOTES_OFF + || buffer[1] == MIDI_CTL_ALL_SOUNDS_OFF) + ((AudioBuffer*)_gate_port->buffer(0))->set(0.0f, time); + default: + break; + } } } } @@ -95,7 +104,7 @@ MidiTriggerNode::note_on(uchar note_num, uchar velocity, FrameTime time, SampleC //std::cerr << "Note on starting at sample " << offset << std::endl; - const Sample filter_note = _note_port->buffer(0)->value_at(0); + const Sample filter_note = ((AudioBuffer*)_note_port->buffer(0))->value_at(0); if (filter_note >= 0.0 && filter_note < 127.0 && (note_num == (uchar)filter_note)){ // FIXME FIXME FIXME @@ -105,10 +114,10 @@ MidiTriggerNode::note_on(uchar note_num, uchar velocity, FrameTime time, SampleC if (offset == (SampleCount)(_buffer_size-1)) --offset; - _gate_port->buffer(0)->set(1.0f, offset); - _trig_port->buffer(0)->set(1.0f, offset, offset); - _trig_port->buffer(0)->set(0.0f, offset+1); - _vel_port->buffer(0)->set(velocity/127.0f, offset); + ((AudioBuffer*)_gate_port->buffer(0))->set(1.0f, offset); + ((AudioBuffer*)_trig_port->buffer(0))->set(1.0f, offset, offset); + ((AudioBuffer*)_trig_port->buffer(0))->set(0.0f, offset+1); + ((AudioBuffer*)_vel_port->buffer(0))->set(velocity/127.0f, offset); } } @@ -119,8 +128,8 @@ MidiTriggerNode::note_off(uchar note_num, FrameTime time, SampleCount nframes, F assert(time >= start && time <= end); assert(time - start < _buffer_size); - if (note_num == lrintf(_note_port->buffer(0)->value_at(0))) - _gate_port->buffer(0)->set(0.0f, time - start); + if (note_num == lrintf(((AudioBuffer*)_note_port->buffer(0))->value_at(0))) + ((AudioBuffer*)_gate_port->buffer(0))->set(0.0f, time - start); } diff --git a/src/libs/engine/MidiTriggerNode.h b/src/libs/engine/MidiTriggerNode.h index 308174fb..f46e6dee 100644 --- a/src/libs/engine/MidiTriggerNode.h +++ b/src/libs/engine/MidiTriggerNode.h @@ -15,20 +15,19 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - #ifndef MIDITRIGGERNODE_H #define MIDITRIGGERNODE_H #include #include "InternalNode.h" +#include "MidiBuffer.h" using std::string; namespace Ingen { -class MidiMessage; -template class InputPort; -template class OutputPort; +class InputPort; +class OutputPort; /** MIDI trigger input node. @@ -52,11 +51,11 @@ public: void note_off(uchar note_num, FrameTime time, SampleCount nframes, FrameTime start, FrameTime end); private: - InputPort* _midi_in_port; - InputPort* _note_port; - OutputPort* _gate_port; - OutputPort* _trig_port; - OutputPort* _vel_port; + InputPort* _midi_in_port; + InputPort* _note_port; + OutputPort* _gate_port; + OutputPort* _trig_port; + OutputPort* _vel_port; }; diff --git a/src/libs/engine/Node.h b/src/libs/engine/Node.h index 852751fb..4fe43d03 100644 --- a/src/libs/engine/Node.h +++ b/src/libs/engine/Node.h @@ -30,13 +30,12 @@ namespace Raul { template class List; } namespace Ingen { -class Port; -template class OutputPort; +class Buffer; class Plugin; class Patch; -namespace Shared { - class ClientInterface; -} +class Port; +class OutputPort; +namespace Shared { class ClientInterface; } /** A Node (or "module") in a Patch (which is also a Node). @@ -73,7 +72,7 @@ public: */ virtual void process(SampleCount nframes, FrameTime start, FrameTime end) = 0; - virtual void set_port_buffer(size_t voice, size_t port_num, void* buf) = 0; + virtual void set_port_buffer(size_t voice, size_t port_num, Buffer* buf) = 0; // FIXME: Only used by client senders. Remove? virtual const Raul::Array& ports() const = 0; diff --git a/src/libs/engine/NodeBase.h b/src/libs/engine/NodeBase.h index e78aaab2..8fed6196 100644 --- a/src/libs/engine/NodeBase.h +++ b/src/libs/engine/NodeBase.h @@ -55,7 +55,7 @@ public: virtual void process(SampleCount nframes, FrameTime start, FrameTime end); - virtual void set_port_buffer(size_t voice, size_t port_num, void* buf) {} + virtual void set_port_buffer(size_t voice, size_t port_num, Buffer* buf) {} virtual void set_buffer_size(size_t size); diff --git a/src/libs/engine/OSCClientSender.cpp b/src/libs/engine/OSCClientSender.cpp index ee4653e5..a1f82fd5 100644 --- a/src/libs/engine/OSCClientSender.cpp +++ b/src/libs/engine/OSCClientSender.cpp @@ -25,7 +25,7 @@ #include "Patch.h" #include "Node.h" #include "Plugin.h" -#include "TypedPort.h" +#include "Port.h" #include "Connection.h" #include "AudioDriver.h" #include "interface/ClientInterface.h" diff --git a/src/libs/engine/ObjectSender.cpp b/src/libs/engine/ObjectSender.cpp index ce480316..50e47c48 100644 --- a/src/libs/engine/ObjectSender.cpp +++ b/src/libs/engine/ObjectSender.cpp @@ -21,9 +21,11 @@ #include "Patch.h" #include "Node.h" #include "Port.h" -#include "TypedPort.h" +#include "Port.h" #include "Connection.h" #include "NodeFactory.h" +#include "DataType.h" +#include "AudioBuffer.h" namespace Ingen { @@ -144,8 +146,8 @@ ObjectSender::send_port(ClientInterface* client, const Port* port) // Send control value if (port->type() == DataType::FLOAT && port->buffer_size() == 1) { - Sample default_value = dynamic_cast*>( - port)->buffer(0)->value_at(0); + Sample default_value = dynamic_cast( + port->buffer(0))->value_at(0); //cerr << port->path() << " sending default value " << default_value << endl; client->control_change(port->path(), default_value); } diff --git a/src/libs/engine/OutputPort.h b/src/libs/engine/OutputPort.h index 6c029850..10118076 100644 --- a/src/libs/engine/OutputPort.h +++ b/src/libs/engine/OutputPort.h @@ -20,13 +20,11 @@ #include #include -#include "TypedPort.h" +#include "Port.h" #include "types.h" namespace Ingen { -template class InputPort; - /** An output port. * @@ -39,14 +37,16 @@ template class InputPort; * * \ingroup engine */ -template -class OutputPort : virtual public TypedPort +class OutputPort : virtual public Port { public: - OutputPort(Node* parent, const string& name, - size_t index, size_t poly, - DataType type, size_t buffer_size) - : TypedPort(parent, name, index, poly, type, buffer_size) + OutputPort(Node* parent, + const string& name, + size_t index, + size_t poly, + DataType type, + size_t buffer_size) + : Port(parent, name, index, poly, type, buffer_size) {} virtual ~OutputPort() {} @@ -56,8 +56,6 @@ public: }; -template class OutputPort; - } // namespace Ingen #endif // OUTPUTPORT_H diff --git a/src/libs/engine/Patch.cpp b/src/libs/engine/Patch.cpp index 9b32b74a..a2b5a85f 100644 --- a/src/libs/engine/Patch.cpp +++ b/src/libs/engine/Patch.cpp @@ -271,13 +271,7 @@ Patch::create_port(const string& name, DataType type, size_t buffer_size, bool i assert( !(type == DataType::UNKNOWN) ); - // FIXME: is it possible to just "pass" the type directly as the template parameter somehow? - if (type == DataType::FLOAT) - return new DuplexPort(this, name, 0, _poly, type, buffer_size, is_output); - else if (type == DataType::MIDI) - return new DuplexPort(this, name, 0, _poly, type, buffer_size, is_output); - else - return NULL; + return new DuplexPort(this, name, 0, _poly, type, buffer_size, is_output); } diff --git a/src/libs/engine/Port.cpp b/src/libs/engine/Port.cpp index 7ab811b2..4b9a014b 100644 --- a/src/libs/engine/Port.cpp +++ b/src/libs/engine/Port.cpp @@ -18,6 +18,8 @@ #include "Port.h" #include "Node.h" #include "DataType.h" +#include "Buffer.h" +#include "BufferFactory.h" namespace Ingen { @@ -27,14 +29,73 @@ const char* const DataType::type_uris[3] = { "UNKNOWN", "FLOAT", "MIDI" }; Port::Port(Node* const node, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size) -: GraphObject(node, name), - _index(index), - _poly(poly), - _type(type), - _buffer_size(buffer_size) + : GraphObject(node, name) + , _index(index) + , _poly(poly) + , _type(type) + , _buffer_size(buffer_size) + , _fixed_buffers(false) { assert(node != NULL); assert(_poly > 0); + + allocate_buffers(); + clear_buffers(); + + assert(_buffers.size() > 0); +} + + +Port::~Port() +{ + for (size_t i=0; i < _poly; ++i) + delete _buffers.at(i); +} + + +void +Port::allocate_buffers() +{ + _buffers.alloc(_poly); + + for (size_t i=0; i < _poly; ++i) + _buffers.at(i) = BufferFactory::create(_type, _buffer_size); +} + + +void +Port::set_buffer_size(size_t size) +{ + _buffer_size = size; + + for (size_t i=0; i < _poly; ++i) + _buffers.at(i)->resize(size); + + connect_buffers(); +} + + +void +Port::connect_buffers() +{ + for (size_t i=0; i < _poly; ++i) + Port::parent_node()->set_port_buffer(i, _index, _buffers.at(i)); +} + + +void +Port::clear_buffers() +{ + for (size_t i=0; i < _poly; ++i) + _buffers.at(i)->clear(); +} + + +void +Port::process(SampleCount nframes, FrameTime start, FrameTime end) +{ + for (size_t i=0; i < _poly; ++i) + _buffers.at(i)->prepare(nframes); } diff --git a/src/libs/engine/Port.h b/src/libs/engine/Port.h index 3473e054..b42231fe 100644 --- a/src/libs/engine/Port.h +++ b/src/libs/engine/Port.h @@ -20,6 +20,7 @@ #include #include +#include #include "types.h" #include "GraphObject.h" #include "DataType.h" @@ -29,6 +30,7 @@ using std::string; namespace Ingen { class Node; +class Buffer; /** A port on a Node. @@ -42,36 +44,45 @@ class Node; class Port : public GraphObject { public: - virtual ~Port() {} + virtual ~Port(); /** A port's parent is always a node, so static cast should be safe */ Node* parent_node() const { return (Node*)_parent; } + Buffer* buffer(size_t voice) const { return _buffers.at(voice); } + /** Called once per process cycle */ - virtual void process(SampleCount nframes, FrameTime start, FrameTime end) = 0; + virtual void process(SampleCount nframes, FrameTime start, FrameTime end); /** Empty buffer contents completely (ie silence) */ - virtual void clear_buffers() = 0; + virtual void clear_buffers(); virtual bool is_input() const = 0; virtual bool is_output() const = 0; - bool is_sample() const { return false; } size_t num() const { return _index; } size_t poly() const { return _poly; } DataType type() const { return _type; } size_t buffer_size() const { return _buffer_size; } - virtual void set_buffer_size(size_t size) = 0; - virtual void connect_buffers() = 0; + virtual void set_buffer_size(size_t size); + + void fixed_buffers(bool b) { _fixed_buffers = b; } + bool fixed_buffers() { return _fixed_buffers; } protected: Port(Node* const node, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size); + virtual void allocate_buffers(); + virtual void connect_buffers(); + size_t _index; size_t _poly; DataType _type; size_t _buffer_size; + bool _fixed_buffers; + + Raul::Array _buffers; }; diff --git a/src/libs/engine/TypedConnection.cpp b/src/libs/engine/TypedConnection.cpp deleted file mode 100644 index 677a5f4f..00000000 --- a/src/libs/engine/TypedConnection.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* This file is part of Ingen. - * Copyright (C) 2007 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 "TypedConnection.h" -#include "util.h" -#include "InputPort.h" -#include "OutputPort.h" -#include "Node.h" -#include "Port.h" - -namespace Ingen { - - -/** Constructor for a connection from a node's output port. - * - * This handles both polyphonic and monophonic nodes, transparently to the - * user (InputPort). - */ -template -TypedConnection::TypedConnection(OutputPort* const src_port, InputPort* const dst_port) -: Connection(src_port, dst_port), - _local_buffer(NULL), - _must_mix(true), - _buffer_size(src_port->buffer_size()), - _pending_disconnection(false) -{ - assert((src_port->parent_node()->poly() == dst_port->parent_node()->poly()) - || (src_port->parent_node()->poly() == 1 || dst_port->parent_node()->poly() == 1)); - - if (src_port->poly() == dst_port->poly()) - _must_mix = false; - else // Poly -> Mono connection, need a buffer to mix into - _local_buffer = new Buffer(_buffer_size); - - //cerr << "Connection " << src_port->path() << " -> " << dst_port->path() - // << "\t mixing: " << _must_mix << endl; -} -template TypedConnection::TypedConnection(OutputPort* const src_port, InputPort* const dst_port); -template TypedConnection::TypedConnection(OutputPort* const src_port, InputPort* const dst_port); - - -template -TypedConnection::~TypedConnection() -{ - delete _local_buffer; -} -template TypedConnection::~TypedConnection(); -template TypedConnection::~TypedConnection(); - - -/** Allocate a mixdown buffer if necessary */ -template -void -TypedConnection::set_buffer_size(size_t size) -{ - if (_must_mix) { - assert(_local_buffer); - delete _local_buffer; - - _local_buffer = new Buffer(size); - } - - _buffer_size = size; -} - - -template -void -TypedConnection::process(SampleCount nframes, FrameTime start, FrameTime end) -{ - // FIXME: nframes parameter not used - assert(_buffer_size == 1 || _buffer_size == nframes); - - /* Thought: A poly output port can be connected to multiple mono input - * ports, which means this mix down would have to happen many times. - * Adding a method to OutputPort that mixes down all it's outputs into - * a buffer (if it hasn't been done already this cycle) and returns that - * would avoid having to mix multiple times. Probably not a very common - * case, but it would be faster anyway. */ - - if (_must_mix) { - //cerr << "Mixing " << src_port()->buffer(0)->data() - // << " -> " << _local_buffer->data() << endl; - - _local_buffer->copy(src_port()->buffer(0), 0, _buffer_size-1); - - // Mix all the source's voices down into local buffer starting at the second - // voice (buffer is already set to first voice above) - for (size_t j=1; j < src_port()->poly(); ++j) - _local_buffer->accumulate(src_port()->buffer(j), 0, _buffer_size-1); - - // Scale the buffer down. - if (src_port()->poly() > 1) - _local_buffer->scale(1.0f/(float)src_port()->poly(), 0, _buffer_size-1); - } -} -template void TypedConnection::process(SampleCount nframes, FrameTime start, FrameTime end); - - -// FIXME: MIDI mixing not implemented -template <> -void -TypedConnection::process(SampleCount nframes, FrameTime start, FrameTime end) -{ -} - - -} // namespace Ingen - diff --git a/src/libs/engine/TypedConnection.h b/src/libs/engine/TypedConnection.h deleted file mode 100644 index 1c7f3dc7..00000000 --- a/src/libs/engine/TypedConnection.h +++ /dev/null @@ -1,104 +0,0 @@ -/* This file is part of Ingen. - * Copyright (C) 2007 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 - */ - -#ifndef TYPEDCONNECTION_H -#define TYPEDCONNECTION_H - -#include "types.h" -#include "OutputPort.h" -#include "Connection.h" - -namespace Ingen { - -class MidiMessage; -class Port; -template class InputPort; - - -/** A Connection with a type. - * - * \ingroup engine - */ -template -class TypedConnection : public Connection -{ -public: - TypedConnection(OutputPort* const src_port, InputPort* const dst_port); - virtual ~TypedConnection(); - - void process(SampleCount nframes, FrameTime start, FrameTime end); - - inline OutputPort* src_port() const { return dynamic_cast*>(_src_port); } - inline InputPort* dst_port() const { return dynamic_cast*>(_dst_port); } - - /** Used by some (recursive) events to prevent double disconnections */ - bool pending_disconnection() { return _pending_disconnection; } - void pending_disconnection(bool b) { _pending_disconnection = b; } - - /** Get the buffer for a particular voice. - * A TypedConnection is smart - it knows the destination port respondering the - * buffer, and will return accordingly (ie the same buffer for every voice - * in a mono->poly connection). - */ - inline Buffer* buffer(size_t voice) const; - - void set_buffer_size(size_t size); - -private: - Buffer* _local_buffer; ///< Only used for poly->mono connections - bool _must_mix; - size_t _buffer_size; - bool _pending_disconnection; -}; - - -template <> -inline Buffer* -TypedConnection::buffer(size_t voice) const -{ - TypedPort* const src_port = (TypedPort*)_src_port; - - if (_must_mix) { - return _local_buffer; - } else { - if (src_port->poly() == 1) - return src_port->buffer(0); - else - return src_port->buffer(voice); - } -} - - -template <> -inline Buffer* -TypedConnection::buffer(size_t voice) const -{ - // No such thing as polyphonic MIDI ports - assert(_src_port->poly() == 1); - assert(_dst_port->poly() == 1); - - TypedPort* const src_port = (TypedPort*)_src_port; - return src_port->buffer(0); -} - - -template class TypedConnection; -template class TypedConnection; - -} // namespace Ingen - -#endif // TYPEDCONNECTION_H diff --git a/src/libs/engine/TypedPort.cpp b/src/libs/engine/TypedPort.cpp deleted file mode 100644 index 0432ec4c..00000000 --- a/src/libs/engine/TypedPort.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* This file is part of Ingen. - * Copyright (C) 2007 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 "TypedPort.h" -#include -#include -#include -#include -#include -#include "util.h" -#include "Node.h" -#include "MidiMessage.h" - -namespace Ingen { - - -/** Constructor for a Port. - */ -template -TypedPort::TypedPort(Node* parent, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size) -: Port(parent, name, index, poly, type, buffer_size) -, _fixed_buffers(false) -{ - allocate_buffers(); - clear_buffers(); - - assert(_buffers.size() > 0); -} -template -TypedPort::TypedPort(Node* parent, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size); -template -TypedPort::TypedPort(Node* parent, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size); - - -template -TypedPort::~TypedPort() -{ - for (size_t i=0; i < _poly; ++i) - delete _buffers.at(i); -} -template TypedPort::~TypedPort(); -template TypedPort::~TypedPort(); - - -/** Set the port's value for all voices. - */ -template<> -void -TypedPort::set_value(Sample val, size_t offset) -{ - if (offset >= _buffer_size) - offset = 0; - assert(offset < _buffer_size); - - for (size_t v=0; v < _poly; ++v) - _buffers.at(v)->set(val, offset); -} - -/** Set the port's value for a specific voice. - */ -template<> -void -TypedPort::set_value(size_t voice, Sample val, size_t offset) -{ - if (offset >= _buffer_size) - offset = 0; - assert(offset < _buffer_size); - - cerr << path() << " setting voice value " << val << endl; - - _buffers.at(voice)->set(val, offset); -} - - -template -void -TypedPort::allocate_buffers() -{ - _buffers.alloc(_poly); - - for (size_t i=0; i < _poly; ++i) - _buffers.at(i) = new Buffer(_buffer_size); -} -template void TypedPort::allocate_buffers(); -template void TypedPort::allocate_buffers(); - - -template -void -TypedPort::set_buffer_size(size_t size) -{ - _buffer_size = size; - - for (size_t i=0; i < _poly; ++i) - _buffers.at(i)->resize(size); - - connect_buffers(); -} -template void TypedPort::set_buffer_size(size_t size); -template void TypedPort::set_buffer_size(size_t size); - - -/** Update any changed buffers with the plugin this is a port on. - * - * This calls ie the LADSPA connect_port function when buffers have been changed - * due to a connection, disconnection, resize, etc. - */ -template -void -TypedPort::connect_buffers() -{ - for (size_t i=0; i < _poly; ++i) - TypedPort::parent_node()->set_port_buffer(i, _index, _buffers.at(i)->data()); -} -template void TypedPort::connect_buffers(); -template void TypedPort::connect_buffers(); - - -template -void -TypedPort::clear_buffers() -{ - for (size_t i=0; i < _poly; ++i) - _buffers.at(i)->clear(); -} -template void TypedPort::clear_buffers(); -template void TypedPort::clear_buffers(); - - -template -void -TypedPort::process(SampleCount nframes, FrameTime start, FrameTime end) -{ - for (size_t i=0; i < _poly; ++i) - _buffers.at(i)->prepare(nframes); -} - - -} // namespace Ingen - diff --git a/src/libs/engine/TypedPort.h b/src/libs/engine/TypedPort.h deleted file mode 100644 index 2dc687a5..00000000 --- a/src/libs/engine/TypedPort.h +++ /dev/null @@ -1,79 +0,0 @@ -/* This file is part of Ingen. - * Copyright (C) 2007 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 - */ - -#ifndef TYPEDPORT_H -#define TYPEDPORT_H - -#include -#include "types.h" -#include -#include "Port.h" -#include "Buffer.h" - -using std::string; - -namespace Ingen { - -class MidiMessage; -class Node; - - -/** A port (with a type). - * - * This is basically just a buffer and a bunch of flags and helper methods. - * All the interesting functionality of ports is in InputPort. - * - * \ingroup engine - */ -template -class TypedPort : public Port -{ -public: - virtual ~TypedPort(); - - void set_value(size_t voice, T val, size_t offset); - void set_value(T val, size_t offset); - - Buffer* buffer(size_t voice) const { return _buffers.at(voice); } - - virtual void process(SampleCount nframes, FrameTime start, FrameTime end); - virtual void clear_buffers(); - - /** Used by drivers to prevent port from changing buffers */ - void fixed_buffers(bool b) { _fixed_buffers = b; } - bool fixed_buffers() { return _fixed_buffers; } - - virtual void set_buffer_size(size_t size); - -protected: - TypedPort(Node* parent, const string& name, size_t index, size_t poly, DataType type, size_t buffer_size); - - void allocate_buffers(); - void connect_buffers(); - - bool _fixed_buffers; - - Raul::Array*> _buffers; -}; - - -template class TypedPort; -template class TypedPort; - -} // namespace Ingen - -#endif // TYPEDPORT_H diff --git a/src/libs/engine/events/AddPortEvent.cpp b/src/libs/engine/events/AddPortEvent.cpp index 8ca2f85f..c9f22cd1 100644 --- a/src/libs/engine/events/AddPortEvent.cpp +++ b/src/libs/engine/events/AddPortEvent.cpp @@ -113,10 +113,10 @@ AddPortEvent::pre_process() if (!_patch->parent()) { if (_type == "ingen:audio") _driver_port = _engine.audio_driver()->create_port( - dynamic_cast*>(_patch_port)); + dynamic_cast(_patch_port)); else if (_type == "ingen:midi") _driver_port = _engine.midi_driver()->create_port( - dynamic_cast*>(_patch_port)); + dynamic_cast(_patch_port)); } assert(_ports_array->size() == _patch->num_ports()); diff --git a/src/libs/engine/events/ConnectionEvent.cpp b/src/libs/engine/events/ConnectionEvent.cpp index da723a8c..af35265b 100644 --- a/src/libs/engine/events/ConnectionEvent.cpp +++ b/src/libs/engine/events/ConnectionEvent.cpp @@ -22,7 +22,7 @@ #include "Responder.h" #include "types.h" #include "Engine.h" -#include "TypedConnection.h" +#include "Connection.h" #include "InputPort.h" #include "OutputPort.h" #include "Patch.h" @@ -34,9 +34,6 @@ using std::string; namespace Ingen { -//// ConnectionEvent //// - - ConnectionEvent::ConnectionEvent(Engine& engine, SharedPtr responder, SampleCount timestamp, const string& src_port_path, const string& dst_port_path) : QueuedEvent(engine, responder, timestamp), _src_port_path(src_port_path), @@ -44,18 +41,15 @@ ConnectionEvent::ConnectionEvent(Engine& engine, SharedPtr responder, _patch(NULL), _src_port(NULL), _dst_port(NULL), - _typed_event(NULL), + _process_order(NULL), + _connection(NULL), + _patch_listnode(NULL), + _port_listnode(NULL), _error(NO_ERROR) { } -ConnectionEvent::~ConnectionEvent() -{ - delete _typed_event; -} - - void ConnectionEvent::pre_process() { @@ -67,14 +61,6 @@ ConnectionEvent::pre_process() return; } - /*_patch = _engine.object_store()->find_patch(_src_port_path.parent().parent()); - - if (_patch == NULL) { - _error = PORT_NOT_FOUND; - QueuedEvent::pre_process(); - return; - }*/ - _src_port = _engine.object_store()->find_port(_src_port_path); _dst_port = _engine.object_store()->find_port(_dst_port_path); @@ -84,96 +70,33 @@ ConnectionEvent::pre_process() return; } - if (_src_port->type() != _dst_port->type() || _src_port->buffer_size() != _dst_port->buffer_size()) { + if (_src_port->type() != _dst_port->type()) { _error = TYPE_MISMATCH; QueuedEvent::pre_process(); return; } - - /*if (port1->is_output() && port2->is_input()) { - _src_port = port1; - _dst_port = port2; - } else if (port2->is_output() && port1->is_input()) { - _src_port = port2; - _dst_port = port1; - } else { + + // FIXME: MIDI buffer size is a kluge all around + if (_src_port->type() == DataType::FLOAT + && _src_port->buffer_size() != _dst_port->buffer_size()) { _error = TYPE_MISMATCH; QueuedEvent::pre_process(); return; - }*/ - - // Create the typed event to actually do the work - const DataType type = _src_port->type(); - if (type == DataType::FLOAT) { - _typed_event = new TypedConnectionEvent(_engine, _responder, _time, - dynamic_cast*>(_src_port), dynamic_cast*>(_dst_port)); - } else if (type == DataType::MIDI) { - _typed_event = new TypedConnectionEvent(_engine, _responder, _time, - dynamic_cast*>(_src_port), dynamic_cast*>(_dst_port)); - } else { + } + + /*if ( !( _src_port->is_output() && _dst_port->is_input() ) ) { _error = TYPE_MISMATCH; QueuedEvent::pre_process(); return; - } - - assert(_typed_event); - _typed_event->pre_process(); - assert(_typed_event->is_prepared()); - - QueuedEvent::pre_process(); -} - - -void -ConnectionEvent::execute(SampleCount nframes, FrameTime start, FrameTime end) -{ - QueuedEvent::execute(nframes, start, end); - - if (_error == NO_ERROR) - _typed_event->execute(nframes, start, end); -} - - -void -ConnectionEvent::post_process() -{ - if (_error == NO_ERROR) { - _typed_event->post_process(); - } else { - // FIXME: better error messages - string msg = "Unable to make connection "; - msg.append(_src_port_path + " -> " + _dst_port_path); - _responder->respond_error(msg); - } -} - - - -//// TypedConnectionEvent //// - - -template -TypedConnectionEvent::TypedConnectionEvent(Engine& engine, SharedPtr responder, SampleCount timestamp, OutputPort* src_port, InputPort* dst_port) -: QueuedEvent(engine, responder, timestamp), - _src_port(src_port), - _dst_port(dst_port), - _patch(NULL), - _process_order(NULL), - _connection(NULL), - _port_listnode(NULL), - _succeeded(true) -{ - assert(src_port != NULL); - assert(dst_port != NULL); -} + }*/ + _dst_input_port = dynamic_cast(_dst_port); + _src_output_port = dynamic_cast(_src_port); + assert(_src_output_port); + assert(_dst_input_port); -template -void -TypedConnectionEvent::pre_process() -{ - if (_dst_port->is_connected_to(_src_port)) { - _succeeded = false; + if (_dst_input_port->is_connected_to(_src_output_port)) { + _error = ALREADY_CONNECTED; QueuedEvent::pre_process(); return; } @@ -202,19 +125,19 @@ TypedConnectionEvent::pre_process() assert(_patch); if (src_node == NULL || dst_node == NULL) { - _succeeded = false; + _error = PARENTS_NOT_FOUND; QueuedEvent::pre_process(); return; } if (_patch != src_node && src_node->parent() != _patch && dst_node->parent() != _patch) { - _succeeded = false; + _error = PARENTS_NOT_FOUND; QueuedEvent::pre_process(); return; } - _connection = new TypedConnection(_src_port, _dst_port); - _port_listnode = new Raul::ListNode*>(_connection); + _connection = new Connection(_src_port, _dst_port); + _port_listnode = new Raul::ListNode(_connection); _patch_listnode = new Raul::ListNode(_connection); // Need to be careful about patch port connections here and adding a node's @@ -227,20 +150,18 @@ TypedConnectionEvent::pre_process() if (_patch->enabled()) _process_order = _patch->build_process_order(); - _succeeded = true; QueuedEvent::pre_process(); } -template void -TypedConnectionEvent::execute(SampleCount nframes, FrameTime start, FrameTime end) +ConnectionEvent::execute(SampleCount nframes, FrameTime start, FrameTime end) { QueuedEvent::execute(nframes, start, end); - if (_succeeded) { + if (_error == NO_ERROR) { // These must be inserted here, since they're actually used by the audio thread - _dst_port->add_connection(_port_listnode); + _dst_input_port->add_connection(_port_listnode); _patch->add_connection(_patch_listnode); if (_patch->process_order() != NULL) _engine.maid()->push(_patch->process_order()); @@ -249,18 +170,17 @@ TypedConnectionEvent::execute(SampleCount nframes, FrameTime start, FrameTime } -template void -TypedConnectionEvent::post_process() +ConnectionEvent::post_process() { - if (_succeeded) { - assert(_connection != NULL); - + if (_error == NO_ERROR) { _responder->respond_ok(); - _engine.broadcaster()->send_connection(_connection); } else { - _responder->respond_error("Unable to make connection."); + // FIXME: better error messages + string msg = "Unable to make connection "; + msg.append(_src_port_path + " -> " + _dst_port_path); + _responder->respond_error(msg); } } diff --git a/src/libs/engine/events/ConnectionEvent.h b/src/libs/engine/events/ConnectionEvent.h index 79ffeaa3..8f5e1cc2 100644 --- a/src/libs/engine/events/ConnectionEvent.h +++ b/src/libs/engine/events/ConnectionEvent.h @@ -36,10 +36,9 @@ class Node; class Connection; class MidiMessage; class Port; -template class TypedConnection; -template class InputPort; -template class OutputPort; -template class TypedConnectionEvent; // helper, defined below +class Connection; +class InputPort; +class OutputPort; /** Make a Connection between two Ports. @@ -50,7 +49,6 @@ class ConnectionEvent : public QueuedEvent { public: ConnectionEvent(Engine& engine, SharedPtr responder, SampleCount timestamp, const string& src_port_path, const string& dst_port_path); - ~ConnectionEvent(); void pre_process(); void execute(SampleCount nframes, FrameTime start, FrameTime end); @@ -58,52 +56,34 @@ public: private: - enum ErrorType { NO_ERROR, PARENT_PATCH_DIFFERENT, PORT_NOT_FOUND, TYPE_MISMATCH }; + enum ErrorType { + NO_ERROR, + PARENT_PATCH_DIFFERENT, + PORT_NOT_FOUND, + TYPE_MISMATCH, + ALREADY_CONNECTED, + PARENTS_NOT_FOUND + }; Raul::Path _src_port_path; Raul::Path _dst_port_path; - Patch* _patch; - Port* _src_port; - Port* _dst_port; - - QueuedEvent* _typed_event; - - ErrorType _error; -}; + Patch* _patch; + Port* _src_port; + Port* _dst_port; + OutputPort* _src_output_port; + InputPort* _dst_input_port; - -/** Templated ConnectionEvent. - * - * Intended to be called from ConnectionEvent so callers (ie OSCReceiver) - * can use ConnectionEvent without knowing anything about types (which - * they can't, since all they have is Port paths). - */ -template -class TypedConnectionEvent : public QueuedEvent -{ -public: - TypedConnectionEvent(Engine& engine, SharedPtr responder, FrameTime time, OutputPort* src_port, InputPort* dst_port); + Raul::Array* _process_order; ///< New process order for Patch - void pre_process(); - void execute(SampleCount nframes, FrameTime start, FrameTime end); - void post_process(); + Connection* _connection; + Raul::ListNode* _patch_listnode; + Raul::ListNode* _port_listnode; -private: - OutputPort* _src_port; - InputPort* _dst_port; - - Patch* _patch; - Raul::Array* _process_order; ///< New process order for Patch - TypedConnection* _connection; - Raul::ListNode* _patch_listnode; - Raul::ListNode*>* _port_listnode; - - bool _succeeded; + ErrorType _error; }; - } // namespace Ingen #endif // CONNECTIONEVENT_H diff --git a/src/libs/engine/events/DisconnectNodeEvent.cpp b/src/libs/engine/events/DisconnectNodeEvent.cpp index 916c1045..8f2a90f2 100644 --- a/src/libs/engine/events/DisconnectNodeEvent.cpp +++ b/src/libs/engine/events/DisconnectNodeEvent.cpp @@ -23,7 +23,7 @@ #include "Responder.h" #include "Engine.h" #include "Node.h" -#include "TypedConnection.h" +#include "Connection.h" #include "DisconnectionEvent.h" #include "Port.h" #include "InputPort.h" diff --git a/src/libs/engine/events/DisconnectNodeEvent.h b/src/libs/engine/events/DisconnectNodeEvent.h index bf4644ad..270fa960 100644 --- a/src/libs/engine/events/DisconnectNodeEvent.h +++ b/src/libs/engine/events/DisconnectNodeEvent.h @@ -31,10 +31,9 @@ class DisconnectionEvent; class Patch; class Node; class Connection; -template class TypedConnection; class Port; -template class InputPort; -template class OutputPort; +class InputPort; +class OutputPort; /** An event to disconnect all connections to a Node. diff --git a/src/libs/engine/events/DisconnectionEvent.cpp b/src/libs/engine/events/DisconnectionEvent.cpp index d5e788ef..aef271f4 100644 --- a/src/libs/engine/events/DisconnectionEvent.cpp +++ b/src/libs/engine/events/DisconnectionEvent.cpp @@ -21,7 +21,7 @@ #include #include "Responder.h" #include "Engine.h" -#include "TypedConnection.h" +#include "Connection.h" #include "InputPort.h" #include "OutputPort.h" #include "Patch.h" @@ -44,7 +44,7 @@ DisconnectionEvent::DisconnectionEvent(Engine& engine, SharedPtr resp _src_port(NULL), _dst_port(NULL), _lookup(true), - _typed_event(NULL), + _process_order(NULL), _error(NO_ERROR) { } @@ -58,7 +58,7 @@ DisconnectionEvent::DisconnectionEvent(Engine& engine, SharedPtr resp _src_port(src_port), _dst_port(dst_port), _lookup(false), - _typed_event(NULL), + _process_order(NULL), _error(NO_ERROR) { // FIXME: These break for patch ports.. is that ok? @@ -69,11 +69,6 @@ DisconnectionEvent::DisconnectionEvent(Engine& engine, SharedPtr resp == dst_port->parent_node()->parent_patch()); */ } -DisconnectionEvent::~DisconnectionEvent() -{ - delete _typed_event; -} - void DisconnectionEvent::pre_process() @@ -87,14 +82,6 @@ DisconnectionEvent::pre_process() return; } - /*_patch = _engine.object_store()->find_patch(_src_port_path.parent().parent()); - - if (_patch == NULL) { - _error = PORT_NOT_FOUND; - QueuedEvent::pre_process(); - return; - }*/ - _src_port = _engine.object_store()->find_port(_src_port_path); _dst_port = _engine.object_store()->find_port(_dst_port_path); } @@ -111,76 +98,13 @@ DisconnectionEvent::pre_process() return; } - // Create the typed event to actually do the work - const DataType type = _src_port->type(); - if (type == DataType::FLOAT) { - _typed_event = new TypedDisconnectionEvent(_engine, _responder, _time, - dynamic_cast*>(_src_port), dynamic_cast*>(_dst_port)); - } else if (type == DataType::MIDI) { - _typed_event = new TypedDisconnectionEvent(_engine, _responder, _time, - dynamic_cast*>(_src_port), dynamic_cast*>(_dst_port)); - } else { - _error = TYPE_MISMATCH; - QueuedEvent::pre_process(); - return; - } - - assert(_typed_event); - _typed_event->pre_process(); - assert(_typed_event->is_prepared()); - - QueuedEvent::pre_process(); -} - - -void -DisconnectionEvent::execute(SampleCount nframes, FrameTime start, FrameTime end) -{ - QueuedEvent::execute(nframes, start, end); - - if (_error == NO_ERROR) - _typed_event->execute(nframes, start, end); -} - - -void -DisconnectionEvent::post_process() -{ - if (_error == NO_ERROR) { - _typed_event->post_process(); - } else { - // FIXME: better error messages - string msg = "Unable to disconnect "; - msg.append(_src_port_path + " -> " + _dst_port_path); - _responder->respond_error(msg); - } -} - - - -//// TypedDisconnectionEvent //// - - -template -TypedDisconnectionEvent::TypedDisconnectionEvent(Engine& engine, SharedPtr responder, SampleCount timestamp, OutputPort* src_port, InputPort* dst_port) -: QueuedEvent(engine, responder, timestamp), - _src_port(src_port), - _dst_port(dst_port), - _patch(NULL), - _process_order(NULL), - _succeeded(true) -{ - assert(src_port != NULL); - assert(dst_port != NULL); -} - + _dst_input_port = dynamic_cast(_dst_port); + _src_output_port = dynamic_cast(_src_port); + assert(_src_output_port); + assert(_dst_input_port); -template -void -TypedDisconnectionEvent::pre_process() -{ - if (!_dst_port->is_connected_to(_src_port)) { - _succeeded = false; + if (!_dst_input_port->is_connected_to(_src_output_port)) { + _error = NOT_CONNECTED; QueuedEvent::pre_process(); return; } @@ -209,7 +133,7 @@ TypedDisconnectionEvent::pre_process() assert(_patch); if (src_node == NULL || dst_node == NULL) { - _succeeded = false; + _error = PARENTS_NOT_FOUND; QueuedEvent::pre_process(); return; } @@ -229,21 +153,18 @@ TypedDisconnectionEvent::pre_process() if (_patch->enabled()) _process_order = _patch->build_process_order(); - _succeeded = true; - QueuedEvent::pre_process(); + QueuedEvent::pre_process(); } -template void -TypedDisconnectionEvent::execute(SampleCount nframes, FrameTime start, FrameTime end) +DisconnectionEvent::execute(SampleCount nframes, FrameTime start, FrameTime end) { QueuedEvent::execute(nframes, start, end); - if (_succeeded) { - - Raul::ListNode*>* const port_connection - = _dst_port->remove_connection(_src_port); + if (_error == NO_ERROR) { + Raul::ListNode* const port_connection + = _dst_input_port->remove_connection(_src_output_port); if (port_connection != NULL) { Raul::ListNode* const patch_connection @@ -261,23 +182,23 @@ TypedDisconnectionEvent::execute(SampleCount nframes, FrameTime start, FrameT _engine.maid()->push(_patch->process_order()); _patch->process_order(_process_order); } else { - _succeeded = false; // Ports weren't connected + _error = CONNECTION_NOT_FOUND; } } } -template void -TypedDisconnectionEvent::post_process() +DisconnectionEvent::post_process() { - if (_succeeded) { - + if (_error == NO_ERROR) { _responder->respond_ok(); - _engine.broadcaster()->send_disconnection(_src_port->path(), _dst_port->path()); } else { - _responder->respond_error("Unable to disconnect ports."); + // FIXME: better error messages + string msg = "Unable to disconnect "; + msg.append(_src_port_path + " -> " + _dst_port_path); + _responder->respond_error(msg); } } diff --git a/src/libs/engine/events/DisconnectionEvent.h b/src/libs/engine/events/DisconnectionEvent.h index 01a72e85..3faeb23e 100644 --- a/src/libs/engine/events/DisconnectionEvent.h +++ b/src/libs/engine/events/DisconnectionEvent.h @@ -36,10 +36,9 @@ class Node; class Connection; class MidiMessage; class Port; -template class TypedConnection; -template class InputPort; -template class OutputPort; -template class TypedDisconnectionEvent; // helper, defined below +class Connection; +class InputPort; +class OutputPort; /** Make a Connection between two Ports. @@ -51,7 +50,6 @@ class DisconnectionEvent : public QueuedEvent public: DisconnectionEvent(Engine& engine, SharedPtr responder, SampleCount timestamp, const string& src_port_path, const string& dst_port_path); DisconnectionEvent(Engine& engine, SharedPtr responder, SampleCount timestamp, Port* const src_port, Port* const dst_port); - ~DisconnectionEvent(); void pre_process(); void execute(SampleCount nframes, FrameTime start, FrameTime end); @@ -59,50 +57,33 @@ public: private: - enum ErrorType { NO_ERROR, PARENT_PATCH_DIFFERENT, PORT_NOT_FOUND, TYPE_MISMATCH }; - - Path _src_port_path; - Path _dst_port_path; + enum ErrorType { + NO_ERROR, + PARENT_PATCH_DIFFERENT, + PORT_NOT_FOUND, + TYPE_MISMATCH, + NOT_CONNECTED, + PARENTS_NOT_FOUND, + CONNECTION_NOT_FOUND + }; - Patch* _patch; - Port* _src_port; - Port* _dst_port; - - bool _lookup; - QueuedEvent* _typed_event; + Path _src_port_path; + Path _dst_port_path; - ErrorType _error; -}; + Patch* _patch; + Port* _src_port; + Port* _dst_port; + OutputPort* _src_output_port; + InputPort* _dst_input_port; - -/** Templated DisconnectionEvent. - * - * Intended to be called from DisconnectionEvent so callers (ie OSCReceiver) - * can use DisconnectionEvent without knowing anything about types (which - * they can't, since all they have is Port paths). - */ -template -class TypedDisconnectionEvent : public QueuedEvent -{ -public: - TypedDisconnectionEvent(Engine& engine, SharedPtr responder, SampleCount timestamp, OutputPort* src_port, InputPort* dst_port); + bool _lookup; - void pre_process(); - void execute(SampleCount nframes, FrameTime start, FrameTime end); - void post_process(); - -private: - OutputPort* _src_port; - InputPort* _dst_port; - - Patch* _patch; - Raul::Array* _process_order; ///< New process order for Patch + Raul::Array* _process_order; ///< New process order for Patch - bool _succeeded; + ErrorType _error; }; - } // namespace Ingen #endif // DISCONNECTIONEVENT_H diff --git a/src/libs/engine/events/RequestObjectEvent.cpp b/src/libs/engine/events/RequestObjectEvent.cpp index d383fdbd..bd25f514 100644 --- a/src/libs/engine/events/RequestObjectEvent.cpp +++ b/src/libs/engine/events/RequestObjectEvent.cpp @@ -17,14 +17,14 @@ #include "RequestObjectEvent.h" #include +#include "interface/ClientInterface.h" #include "Responder.h" #include "Engine.h" -#include "interface/ClientInterface.h" -#include "TypedPort.h" #include "ObjectStore.h" #include "ClientBroadcaster.h" #include "Patch.h" #include "Node.h" +#include "Port.h" #include "ObjectSender.h" using std::string; diff --git a/src/libs/engine/events/RequestPluginEvent.cpp b/src/libs/engine/events/RequestPluginEvent.cpp index 9035cbc5..64a63aea 100644 --- a/src/libs/engine/events/RequestPluginEvent.cpp +++ b/src/libs/engine/events/RequestPluginEvent.cpp @@ -17,10 +17,10 @@ #include "RequestPluginEvent.h" #include +#include "interface/ClientInterface.h" #include "Responder.h" #include "Engine.h" -#include "interface/ClientInterface.h" -#include "TypedPort.h" +#include "Port.h" #include "ObjectStore.h" #include "ClientBroadcaster.h" #include "NodeFactory.h" diff --git a/src/libs/engine/events/RequestPortValueEvent.cpp b/src/libs/engine/events/RequestPortValueEvent.cpp index 3155e72f..533cac38 100644 --- a/src/libs/engine/events/RequestPortValueEvent.cpp +++ b/src/libs/engine/events/RequestPortValueEvent.cpp @@ -17,12 +17,13 @@ #include "RequestPortValueEvent.h" #include +#include "interface/ClientInterface.h" #include "Responder.h" #include "Engine.h" -#include "interface/ClientInterface.h" -#include "TypedPort.h" +#include "Port.h" #include "ObjectStore.h" #include "ClientBroadcaster.h" +#include "AudioBuffer.h" using std::string; @@ -55,7 +56,7 @@ RequestPortValueEvent::execute(SampleCount nframes, FrameTime start, FrameTime e assert(_time >= start && _time <= end); if (_port != NULL && _port->type() == DataType::FLOAT) - _value = ((TypedPort*)_port)->buffer(0)->value_at(0/*_time - start*/); + _value = ((AudioBuffer*)_port->buffer(0))->value_at(0/*_time - start*/); else _port = NULL; // triggers error response } diff --git a/src/libs/engine/events/SetPortValueEvent.cpp b/src/libs/engine/events/SetPortValueEvent.cpp index 4924caa0..5d8127e6 100644 --- a/src/libs/engine/events/SetPortValueEvent.cpp +++ b/src/libs/engine/events/SetPortValueEvent.cpp @@ -18,10 +18,11 @@ #include "SetPortValueEvent.h" #include "Responder.h" #include "Engine.h" -#include "TypedPort.h" +#include "Port.h" #include "ClientBroadcaster.h" #include "Node.h" #include "ObjectStore.h" +#include "AudioBuffer.h" namespace Ingen { @@ -64,11 +65,13 @@ SetPortValueEvent::execute(SampleCount nframes, FrameTime start, FrameTime end) } else if (!(_port->type() == DataType::FLOAT)) { _error = TYPE_MISMATCH; } else { - if (_voice_num == -1) - ((TypedPort*)_port)->set_value(_val, _time - start); + AudioBuffer* const buf = (AudioBuffer*)_port->buffer(0); + const size_t offset = (buf->size() == 1) ? 0 : _time - start; + if (_voice_num == -1) + for (size_t i=0; i < _port->poly(); ++i) + ((AudioBuffer*)_port->buffer(i))->set(_val, offset); else - ((TypedPort*)_port)->set_value(_voice_num, _val, _time - start); - //((TypedPort*)_port)->buffer(_voice_num)->set(_val, offset); // FIXME: check range + ((AudioBuffer*)_port->buffer(_voice_num))->set(_val, offset); } } diff --git a/src/libs/engine/events/SetPortValueQueuedEvent.cpp b/src/libs/engine/events/SetPortValueQueuedEvent.cpp index 139d63a2..1eaa33cb 100644 --- a/src/libs/engine/events/SetPortValueQueuedEvent.cpp +++ b/src/libs/engine/events/SetPortValueQueuedEvent.cpp @@ -18,11 +18,12 @@ #include "SetPortValueQueuedEvent.h" #include "Responder.h" #include "Engine.h" -#include "TypedPort.h" +#include "Port.h" #include "ClientBroadcaster.h" #include "Plugin.h" #include "Node.h" #include "ObjectStore.h" +#include "AudioBuffer.h" namespace Ingen { @@ -74,11 +75,14 @@ SetPortValueQueuedEvent::execute(SampleCount nframes, FrameTime start, FrameTime assert(_time >= start && _time <= end); if (_error == NO_ERROR) { - assert(_port != NULL); - if (_voice_num == -1) - ((TypedPort*)_port)->set_value(_val, _time - start); + assert(_port); + AudioBuffer* const buf = (AudioBuffer*)_port->buffer(0); + const size_t offset = (buf->size() == 1) ? 0 : _time - start; + if (_voice_num == -1) + for (size_t i=0; i < _port->poly(); ++i) + ((AudioBuffer*)_port->buffer(i))->set(_val, offset); else - ((TypedPort*)_port)->buffer(_voice_num)->set(_val, _time - start); // FIXME: check range + ((AudioBuffer*)_port->buffer(_voice_num))->set(_val, offset); } } diff --git a/src/libs/engine/types.h b/src/libs/engine/types.h index 73ad23f8..9aea18e8 100644 --- a/src/libs/engine/types.h +++ b/src/libs/engine/types.h @@ -30,8 +30,4 @@ typedef jack_nframes_t SampleCount; typedef jack_nframes_t SampleRate; typedef jack_nframes_t FrameTime; -/** A type that Ingen can process/patch (eg can be stored in a port) */ -enum DataType { FLOAT, MIDI, UNKNOWN }; - - #endif // TYPES_H diff --git a/src/progs/ingenuity/Makefile.am b/src/progs/ingenuity/Makefile.am index fb3c2539..98dff1f4 100644 --- a/src/progs/ingenuity/Makefile.am +++ b/src/progs/ingenuity/Makefile.am @@ -12,8 +12,8 @@ dist_desktopfiles_DATA = ingenuity.desktop globalpixmapsdir = $(datadir)/pixmaps dist_globalpixmaps_DATA = ingen.svg -ingenuity_CXXFLAGS = -DGTK_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -I$(top_srcdir)/src/common -I$(top_srcdir)/src/libs/client -DPKGDATADIR=\"$(pkgdatadir)\" @RAUL_CFLAGS@ @GTKMM_CFLAGS@ @LIBGLADEMM_CFLAGS@ @GNOMECANVASMM_CFLAGS@ @LOSC_CFLAGS@ @LASH_CFLAGS@ @FLOWCANVAS_CFLAGS@ -ingenuity_LDADD = @RAUL_LIBS@ @GTKMM_LIBS@ @LIBGLADEMM_LIBS@ @GNOMECANVASMM_LIBS@ @LOSC_LIBS@ @LASH_LIBS@ @FLOWCANVAS_LIBS@ ../../libs/client/libingenclient.la +ingenuity_CXXFLAGS = -DGTK_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -I$(top_srcdir)/src/common -I$(top_srcdir)/src/libs/client -DPKGDATADIR=\"$(pkgdatadir)\" @RAUL_CFLAGS@ @GTKMM_CFLAGS@ @LIBGLADEMM_CFLAGS@ @GNOMECANVASMM_CFLAGS@ @LOSC_CFLAGS@ @LASH_CFLAGS@ @FLOWCANVAS_CFLAGS@ @SLV2_CFLAGS@ +ingenuity_LDADD = @RAUL_LIBS@ @GTKMM_LIBS@ @LIBGLADEMM_LIBS@ @GNOMECANVASMM_LIBS@ @LOSC_LIBS@ @LASH_LIBS@ @FLOWCANVAS_LIBS@ @SLV2_LIBS@ ../../libs/client/libingenclient.la ingenuity_DEPENDENCIES = ../../libs/client/libingenclient.la # FIXME: make engine have a separate include dir diff --git a/src/progs/ingenuity/ingenuity.glade b/src/progs/ingenuity/ingenuity.glade index 393b3660..1b1539ad 100644 --- a/src/progs/ingenuity/ingenuity.glade +++ b/src/progs/ingenuity/ingenuity.glade @@ -708,6 +708,7 @@ True Search string to filter plugin list True + True True True 0 -- cgit v1.2.1