diff options
Diffstat (limited to 'src/libs/engine')
-rw-r--r-- | src/libs/engine/MidiBuffer.cpp | 5 | ||||
-rw-r--r-- | src/libs/engine/MidiBuffer.hpp | 3 | ||||
-rw-r--r-- | src/libs/engine/OSCEngineReceiver.cpp | 63 | ||||
-rw-r--r-- | src/libs/engine/OSCEngineReceiver.hpp | 3 | ||||
-rw-r--r-- | src/libs/engine/QueuedEngineInterface.cpp | 27 | ||||
-rw-r--r-- | src/libs/engine/QueuedEngineInterface.hpp | 20 | ||||
-rw-r--r-- | src/libs/engine/events/SetPortValueEvent.cpp | 84 | ||||
-rw-r--r-- | src/libs/engine/events/SetPortValueEvent.hpp | 26 | ||||
-rw-r--r-- | src/libs/engine/events/SetPortValueQueuedEvent.cpp | 56 | ||||
-rw-r--r-- | src/libs/engine/events/SetPortValueQueuedEvent.hpp | 26 |
10 files changed, 232 insertions, 81 deletions
diff --git a/src/libs/engine/MidiBuffer.cpp b/src/libs/engine/MidiBuffer.cpp index 5a8dbc4e..0e10a44e 100644 --- a/src/libs/engine/MidiBuffer.cpp +++ b/src/libs/engine/MidiBuffer.cpp @@ -30,6 +30,7 @@ namespace Ingen { */ MidiBuffer::MidiBuffer(size_t capacity) : Buffer(DataType(DataType::MIDI), capacity) + , _latest_stamp(0) , _joined_buf(NULL) { if (capacity > UINT32_MAX) { @@ -167,7 +168,7 @@ MidiBuffer::increment() const /** Append a MIDI event to the buffer. * - * \a timestamp must be > the latest event in the buffer, + * \a timestamp must be >= the latest event in the buffer, * and < this_nframes() * * \return true on success @@ -182,6 +183,7 @@ MidiBuffer::append(double timestamp, assert(size > 0); assert(data[0] >= 0x80); + assert(timestamp >= _latest_stamp); *(double*)(_buf->data + _buf->size) = timestamp; _buf->size += sizeof(double); @@ -191,6 +193,7 @@ MidiBuffer::append(double timestamp, _buf->size += size; ++_buf->event_count; + _latest_stamp = timestamp; return true; } diff --git a/src/libs/engine/MidiBuffer.hpp b/src/libs/engine/MidiBuffer.hpp index 15548625..a7db7e77 100644 --- a/src/libs/engine/MidiBuffer.hpp +++ b/src/libs/engine/MidiBuffer.hpp @@ -57,18 +57,21 @@ public: inline void rewind() const { _position = 0; } inline void clear() { if (_joined_buf) reset(_this_nframes); } inline void reset(SampleCount nframes) { + _latest_stamp = 0; _position = 0; _buf->event_count = 0; _buf->size = 0; } double increment() const; + double latest_stamp() const { return _latest_stamp; } double get_event(double* timestamp, uint32_t* size, unsigned char** data) const; bool append(double timestamp, uint32_t size, const unsigned char* data); private: + double _latest_stamp; ///< Highest timestamp of all events uint32_t _this_nframes; ///< Current cycle nframes mutable uint32_t _position; ///< Index into _buf MidiBuffer* _joined_buf; ///< Buffer to mirror, if joined diff --git a/src/libs/engine/OSCEngineReceiver.cpp b/src/libs/engine/OSCEngineReceiver.cpp index 3229aed5..caaf0d73 100644 --- a/src/libs/engine/OSCEngineReceiver.cpp +++ b/src/libs/engine/OSCEngineReceiver.cpp @@ -98,7 +98,8 @@ OSCEngineReceiver::OSCEngineReceiver(Engine& engine, size_t queue_size, uint16_t lo_server_add_method(_server, "/ingen/disconnect_all", "is", disconnect_all_cb, this); lo_server_add_method(_server, "/ingen/set_port_value", "isf", set_port_value_cb, this); lo_server_add_method(_server, "/ingen/set_port_value", "isif", set_port_value_voice_cb, this); - lo_server_add_method(_server, "/ingen/set_port_value_queued", "isf", set_port_value_slow_cb, this); + lo_server_add_method(_server, "/ingen/set_port_value_immediate", "isf", set_port_value_immediate_cb, this); + lo_server_add_method(_server, "/ingen/set_port_value_immediate", "isif", set_port_value_immediate_voice_cb, this); lo_server_add_method(_server, "/ingen/note_on", "isii", note_on_cb, this); lo_server_add_method(_server, "/ingen/note_off", "isi", note_off_cb, this); lo_server_add_method(_server, "/ingen/all_notes_off", "isi", all_notes_off_cb, this); @@ -605,58 +606,90 @@ OSCEngineReceiver::_disconnect_all_cb(const char* path, const char* types, lo_ar /** \page engine_osc_namespace - * <p> \b /ingen/set_port_value - Sets the value of a port for all voices (both AR and CR) + * <p> \b /ingen/set_port_value_immediate - Sets the value of a port for all voices (both AR and CR) * \arg \b response-id (integer) * \arg \b port-path (string) - Name of port - * \arg \b value (float) - Value to set port to + * \arg \b value (float) - Value to set port to </p> \n \n */ int -OSCEngineReceiver::_set_port_value_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +OSCEngineReceiver::_set_port_value_immediate_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) { const char* port_path = &argv[1]->s; const float value = argv[2]->f; - set_port_value(port_path, value); + set_port_value_immediate(port_path, sizeof(float), &value); return 0; } /** \page engine_osc_namespace - * <p> \b /ingen/set_port_value - Sets the value of a port for a specific voice (both AR and CR) + * <p> \b /ingen/set_port_value_immediate - Sets the value of a port for a specific voice (both AR and CR) * \arg \b response-id (integer) * \arg \b port-path (string) - Name of port * \arg \b voice (integer) - Voice to set port value for - * \arg \b value (float) - Value to set port to + * \arg \b value (float) - Value to set port to </p> \n \n + * + * See documentation for set_port_value for the distinction between these two messages. */ int -OSCEngineReceiver::_set_port_value_voice_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +OSCEngineReceiver::_set_port_value_immediate_voice_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) { const char* port_path = &argv[1]->s; const int32_t voice = argv[2]->i; const float value = argv[3]->f; - set_port_value(port_path, voice, value); + set_port_value_immediate(port_path, voice, sizeof(float), &value); return 0; } /** \page engine_osc_namespace - * <p> \b /ingen/set_port_value_queued - Sets the value of a port for all voices (as a QueuedEvent) + * <p> \b /ingen/set_port_value - Sets the value of a port for all voices (as a QueuedEvent) * \arg \b response-id (integer) * \arg \b port-path (string) - Name of port * \arg \b value (float) - Value to set port to * - * \li This version exists so you can send it immediately after a QueuedEvent it may depend on (ie a - * node creation) and be sure it happens after the event (a normal set_port_value could beat the - * queued event and arrive out of order). </p> \n \n + * \li This is the queued way to set a port value (it is in the same threading class as e.g. + * node creation). This way the client can stream a sequence of events which depend on each + * other (e.g. a node creation followed by several set_port_value messages to set the node's + * controls) without needing to wait on a response to the first (node creation) message. + * + * There is also a fast "immediate" version of this message, set_port_value_immediate, which + * does not have this ordering guarantee.</p> \n \n */ int -OSCEngineReceiver::_set_port_value_slow_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +OSCEngineReceiver::_set_port_value_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) { const char* port_path = &argv[1]->s; const float value = argv[2]->f; - set_port_value_queued(port_path, value); + set_port_value(port_path, sizeof(float), &value); + return 0; +} + + +/** \page engine_osc_namespace + * <p> \b /ingen/set_port_value - Sets the value of a port for all voices (as a QueuedEvent) + * \arg \b response-id (integer) + * \arg \b port-path (string) - Name of port + * \arg \b value (float) - Value to set port to + * + * \li This is the queued way to set a port value (it is in the same threading class as e.g. + * node creation). This way the client can stream a sequence of events which depend on each + * other (e.g. a node creation followed by several set_port_value messages to set the node's + * controls) without needing to wait on a response to the first (node creation) message. + * + * There is also a fast "immediate" version of this message, set_port_value_immediate, which + * does not have this ordering guarantee.</p> \n \n + */ +int +OSCEngineReceiver::_set_port_value_voice_cb(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg) +{ + const char* port_path = &argv[1]->s; + const int32_t voice = argv[2]->i; + const float value = argv[3]->f; + + set_port_value(port_path, voice, sizeof(float), &value); return 0; } diff --git a/src/libs/engine/OSCEngineReceiver.hpp b/src/libs/engine/OSCEngineReceiver.hpp index 264b66c1..e6ecebac 100644 --- a/src/libs/engine/OSCEngineReceiver.hpp +++ b/src/libs/engine/OSCEngineReceiver.hpp @@ -100,7 +100,8 @@ private: LO_HANDLER(disconnect_all); LO_HANDLER(set_port_value); LO_HANDLER(set_port_value_voice); - LO_HANDLER(set_port_value_slow); + LO_HANDLER(set_port_value_immediate); + LO_HANDLER(set_port_value_immediate_voice); LO_HANDLER(note_on); LO_HANDLER(note_off); LO_HANDLER(all_notes_off); diff --git a/src/libs/engine/QueuedEngineInterface.cpp b/src/libs/engine/QueuedEngineInterface.cpp index badbf78d..41780e92 100644 --- a/src/libs/engine/QueuedEngineInterface.cpp +++ b/src/libs/engine/QueuedEngineInterface.cpp @@ -233,26 +233,39 @@ QueuedEngineInterface::disconnect_all(const string& node_path) void QueuedEngineInterface::set_port_value(const string& port_path, - float value) + uint32_t data_size, + const void* data) { - push_stamped(new SetPortValueEvent(_engine, _responder, now(), port_path, value)); + push_queued(new SetPortValueQueuedEvent(_engine, _responder, now(), port_path, data_size, data)); } void QueuedEngineInterface::set_port_value(const string& port_path, uint32_t voice, - float value) + uint32_t data_size, + const void* data) { - push_stamped(new SetPortValueEvent(_engine, _responder, now(), voice, port_path, value)); + push_queued(new SetPortValueQueuedEvent(_engine, _responder, now(), voice, port_path, data_size, data)); } void -QueuedEngineInterface::set_port_value_queued(const string& port_path, - float value) +QueuedEngineInterface::set_port_value_immediate(const string& port_path, + uint32_t data_size, + const void* data) { - push_queued(new SetPortValueQueuedEvent(_engine, _responder, now(), port_path, value)); + push_stamped(new SetPortValueEvent(_engine, _responder, now(), port_path, data_size, data)); +} + + +void +QueuedEngineInterface::set_port_value_immediate(const string& port_path, + uint32_t voice, + uint32_t data_size, + const void* data) +{ + push_stamped(new SetPortValueEvent(_engine, _responder, now(), voice, port_path, data_size, data)); } diff --git a/src/libs/engine/QueuedEngineInterface.hpp b/src/libs/engine/QueuedEngineInterface.hpp index 396615c0..06583186 100644 --- a/src/libs/engine/QueuedEngineInterface.hpp +++ b/src/libs/engine/QueuedEngineInterface.hpp @@ -119,14 +119,22 @@ public: virtual void disconnect_all(const string& node_path); virtual void set_port_value(const string& port_path, - float val); - + uint32_t data_size, + const void* data); + virtual void set_port_value(const string& port_path, uint32_t voice, - float val); - - virtual void set_port_value_queued(const string& port_path, - float val); + uint32_t data_size, + const void* data); + + virtual void set_port_value_immediate(const string& port_path, + uint32_t data_size, + const void* data); + + virtual void set_port_value_immediate(const string& port_path, + uint32_t voice, + uint32_t data_size, + const void* data); virtual void set_program(const string& node_path, uint32_t bank, diff --git a/src/libs/engine/events/SetPortValueEvent.cpp b/src/libs/engine/events/SetPortValueEvent.cpp index 581defa6..fa2238e2 100644 --- a/src/libs/engine/events/SetPortValueEvent.cpp +++ b/src/libs/engine/events/SetPortValueEvent.cpp @@ -15,6 +15,7 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <sstream> #include "Responder.hpp" #include "SetPortValueEvent.hpp" #include "Engine.hpp" @@ -23,31 +24,57 @@ #include "Node.hpp" #include "ObjectStore.hpp" #include "AudioBuffer.hpp" +#include "MidiBuffer.hpp" + +using namespace std; namespace Ingen { -/** Voice-specific control setting - */ -SetPortValueEvent::SetPortValueEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, size_t voice_num, const string& port_path, Sample val) +/** Omni (all voices) control setting */ +SetPortValueEvent::SetPortValueEvent(Engine& engine, + SharedPtr<Responder> responder, + SampleCount timestamp, + const string& port_path, + uint32_t data_size, + const void* data) : Event(engine, responder, timestamp), - _voice_num(voice_num), + _omni(true), + _voice_num(0), _port_path(port_path), - _val(val), + _data_size(data_size), + _data(malloc(data_size)), _port(NULL), _error(NO_ERROR) { + memcpy(_data, data, data_size); } -SetPortValueEvent::SetPortValueEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& port_path, Sample val) +/** Voice-specific control setting */ +SetPortValueEvent::SetPortValueEvent(Engine& engine, + SharedPtr<Responder> responder, + SampleCount timestamp, + uint32_t voice_num, + const string& port_path, + uint32_t data_size, + const void* data) : Event(engine, responder, timestamp), - _voice_num(-1), + _omni(false), + _voice_num(voice_num), _port_path(port_path), - _val(val), + _data_size(data_size), + _data(malloc(data_size)), _port(NULL), _error(NO_ERROR) { + memcpy(_data, data, data_size); +} + + +SetPortValueEvent::~SetPortValueEvent() +{ + free(_data); } @@ -62,16 +89,28 @@ SetPortValueEvent::execute(SampleCount nframes, FrameTime start, FrameTime end) if (_port == NULL) { _error = PORT_NOT_FOUND; - } else if (!(_port->type() == DataType::FLOAT)) { - _error = TYPE_MISMATCH; +/* } else if (_port->buffer(0)->size() < _data_size) { + _error = NO_SPACE;*/ } else { - AudioBuffer* const buf = (AudioBuffer*)_port->buffer(0); - const size_t offset = (buf->size() == 1) ? 0 : _time - start; - if (_voice_num == -1) - for (uint32_t i=0; i < _port->poly(); ++i) - ((AudioBuffer*)_port->buffer(i))->set(_val, offset); - else - ((AudioBuffer*)_port->buffer(_voice_num))->set(_val, offset); + Buffer* const buf = _port->buffer(0); + AudioBuffer* const abuf = dynamic_cast<AudioBuffer*>(buf); + if (abuf) { + const size_t offset = (buf->size() == 1) ? 0 : _time - start; + + if (_omni) + for (uint32_t i=0; i < _port->poly(); ++i) + ((AudioBuffer*)_port->buffer(i))->set(*(float*)_data, offset); + else + ((AudioBuffer*)_port->buffer(_voice_num))->set(*(float*)_data, offset); + + return; + } + + MidiBuffer* const mbuf = dynamic_cast<MidiBuffer*>(buf); + if (mbuf) { + const double stamp = std::max((double)_time, mbuf->latest_stamp()); + mbuf->append(stamp, _data_size, (const unsigned char*)_data); + } } } @@ -83,17 +122,18 @@ SetPortValueEvent::post_process() assert(_port != NULL); _responder->respond_ok(); - _engine.broadcaster()->send_control_change(_port_path, _val); + _engine.broadcaster()->send_control_change(_port_path, *(float*)_data); } else if (_error == PORT_NOT_FOUND) { string msg = "Unable to find port "; msg.append(_port_path).append(" for set_port_value"); _responder->respond_error(msg); - } else if (_error == TYPE_MISMATCH) { - string msg = "Attempt to set "; - msg.append(_port_path).append(" to incompatible type"); - _responder->respond_error(msg); + } else if (_error == NO_SPACE) { + std::ostringstream msg("Attempt to write "); + msg << _data_size << " bytes to " << _port_path << ", with capacity " + << _port->buffer_size() << endl; + _responder->respond_error(msg.str()); } } diff --git a/src/libs/engine/events/SetPortValueEvent.hpp b/src/libs/engine/events/SetPortValueEvent.hpp index da378347..4b6e8d92 100644 --- a/src/libs/engine/events/SetPortValueEvent.hpp +++ b/src/libs/engine/events/SetPortValueEvent.hpp @@ -35,18 +35,34 @@ class Port; class SetPortValueEvent : public Event { public: - SetPortValueEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& port_path, Sample val); - SetPortValueEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, size_t voice_num, const string& port_path, Sample val); + SetPortValueEvent(Engine& engine, + SharedPtr<Responder> responder, + SampleCount timestamp, + const string& port_path, + uint32_t data_size, + const void* data); + + SetPortValueEvent(Engine& engine, + SharedPtr<Responder> responder, + SampleCount timestamp, + uint32_t voice_num, + const string& port_path, + uint32_t data_size, + const void* data); + + ~SetPortValueEvent(); void execute(SampleCount nframes, FrameTime start, FrameTime end); void post_process(); private: - enum ErrorType { NO_ERROR, PORT_NOT_FOUND, TYPE_MISMATCH }; + enum ErrorType { NO_ERROR, PORT_NOT_FOUND, NO_SPACE }; - int _voice_num; + bool _omni; + uint32_t _voice_num; string _port_path; - float _val; + uint32_t _data_size; + void* _data; Port* _port; ErrorType _error; }; diff --git a/src/libs/engine/events/SetPortValueQueuedEvent.cpp b/src/libs/engine/events/SetPortValueQueuedEvent.cpp index 35c2f270..8940d4c5 100644 --- a/src/libs/engine/events/SetPortValueQueuedEvent.cpp +++ b/src/libs/engine/events/SetPortValueQueuedEvent.cpp @@ -15,6 +15,7 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <sstream> #include "SetPortValueQueuedEvent.hpp" #include "Responder.hpp" #include "Engine.hpp" @@ -28,27 +29,44 @@ namespace Ingen { -/** Voice-specific control setting - */ -SetPortValueQueuedEvent::SetPortValueQueuedEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, size_t voice_num, const string& port_path, Sample val) +/** Omni (all voices) control setting */ +SetPortValueQueuedEvent::SetPortValueQueuedEvent(Engine& engine, + SharedPtr<Responder> responder, + SampleCount timestamp, + const string& port_path, + uint32_t data_size, + const void* data) : QueuedEvent(engine, responder, timestamp), - _voice_num(voice_num), + _omni(true), + _voice_num(0), _port_path(port_path), - _val(val), + _data_size(data_size), + _data(malloc(data_size)), _port(NULL), _error(NO_ERROR) { + memcpy(_data, data, data_size); } -SetPortValueQueuedEvent::SetPortValueQueuedEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& port_path, Sample val) +/** Voice-specific control setting */ +SetPortValueQueuedEvent::SetPortValueQueuedEvent(Engine& engine, + SharedPtr<Responder> responder, + SampleCount timestamp, + uint32_t voice_num, + const string& port_path, + uint32_t data_size, + const void* data) : QueuedEvent(engine, responder, timestamp), - _voice_num(-1), + _omni(false), + _voice_num(voice_num), _port_path(port_path), - _val(val), + _data_size(data_size), + _data(malloc(data_size)), _port(NULL), _error(NO_ERROR) { + memcpy(_data, data, data_size); } @@ -60,8 +78,8 @@ SetPortValueQueuedEvent::pre_process() if (_port == NULL) { _error = PORT_NOT_FOUND; - } else if ( !(_port->type() == DataType::FLOAT) ) { - _error = TYPE_MISMATCH; +/* } else if (_port->buffer_size() < _data_size) { + _error = NO_SPACE;*/ } QueuedEvent::pre_process(); @@ -78,11 +96,12 @@ SetPortValueQueuedEvent::execute(SampleCount nframes, FrameTime start, FrameTime assert(_port); AudioBuffer* const buf = (AudioBuffer*)_port->buffer(0); const size_t offset = (buf->size() == 1) ? 0 : _time - start; - if (_voice_num == -1) + + if (_omni) for (uint32_t i=0; i < _port->poly(); ++i) - ((AudioBuffer*)_port->buffer(i))->set(_val, offset); + ((AudioBuffer*)_port->buffer(i))->set(*(float*)_data, offset); else - ((AudioBuffer*)_port->buffer(_voice_num))->set(_val, offset); + ((AudioBuffer*)_port->buffer(_voice_num))->set(*(float*)_data, offset); } } @@ -94,7 +113,7 @@ SetPortValueQueuedEvent::post_process() assert(_port != NULL); _responder->respond_ok(); - _engine.broadcaster()->send_control_change(_port_path, _val); + _engine.broadcaster()->send_control_change(_port_path, *(float*)_data); // Send patch port control change, if this is a bridge port /*Port* parent_port = _port->parent_node()->as_port(); @@ -108,10 +127,11 @@ SetPortValueQueuedEvent::post_process() msg.append(_port_path).append(" for set_port_value_slow"); _responder->respond_error(msg); - } else if (_error == TYPE_MISMATCH) { - string msg = "Attempt to set "; - msg.append(_port_path).append(" to incompatible type"); - _responder->respond_error(msg); + } else if (_error == NO_SPACE) { + std::ostringstream msg("Attempt to write "); + msg << _data_size << " bytes to " << _port_path << ", with capacity " + << _port->buffer_size() << endl; + _responder->respond_error(msg.str()); } } diff --git a/src/libs/engine/events/SetPortValueQueuedEvent.hpp b/src/libs/engine/events/SetPortValueQueuedEvent.hpp index 43e3d0f8..b64cf903 100644 --- a/src/libs/engine/events/SetPortValueQueuedEvent.hpp +++ b/src/libs/engine/events/SetPortValueQueuedEvent.hpp @@ -35,19 +35,33 @@ class Port; class SetPortValueQueuedEvent : public QueuedEvent { public: - SetPortValueQueuedEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, const string& port_path, Sample val); - SetPortValueQueuedEvent(Engine& engine, SharedPtr<Responder> responder, SampleCount timestamp, size_t voice_num, const string& port_path, Sample val); - + SetPortValueQueuedEvent(Engine& engine, + SharedPtr<Responder> responder, + SampleCount timestamp, + const string& port_path, + uint32_t data_size, + const void* data); + + SetPortValueQueuedEvent(Engine& engine, + SharedPtr<Responder> responder, + SampleCount timestamp, + uint32_t voice_num, + const string& port_path, + uint32_t data_size, + const void* data); + void pre_process(); void execute(SampleCount nframes, FrameTime start, FrameTime end); void post_process(); private: - enum ErrorType { NO_ERROR, PORT_NOT_FOUND, TYPE_MISMATCH }; + enum ErrorType { NO_ERROR, PORT_NOT_FOUND, NO_SPACE }; - int _voice_num; + bool _omni; + uint32_t _voice_num; string _port_path; - float _val; + uint32_t _data_size; + void* _data; Port* _port; ErrorType _error; }; |