From 9e6cd1043eb6d4ecc057fa6d8ea9cc0a363a4199 Mon Sep 17 00:00:00 2001 From: falkTX Date: Fri, 6 Apr 2012 16:14:39 +0100 Subject: [PATCH] Carla old-lv2-midi API support (for zynadd) --- src/carla-includes/lv2/lv2-midifunctions.h | 132 +++++++++++ src/carla-includes/lv2/lv2-midiport.h | 177 ++++++++++++++ src/carla/carla_backend.h | 5 +- src/carla/carla_bridge.cpp | 2 +- src/carla/carla_plugin.h | 7 - src/carla/dssi.cpp | 4 +- src/carla/ladspa.cpp | 4 +- src/carla/lv2.cpp | 264 ++++++++++++++++----- src/carla/lv2_rdf.h | 40 ++-- src/carla/sf2.cpp | 7 +- src/carla/vst.cpp | 4 +- src/carla_backend.py | 5 +- 12 files changed, 553 insertions(+), 98 deletions(-) create mode 100644 src/carla-includes/lv2/lv2-midifunctions.h create mode 100644 src/carla-includes/lv2/lv2-midiport.h diff --git a/src/carla-includes/lv2/lv2-midifunctions.h b/src/carla-includes/lv2/lv2-midifunctions.h new file mode 100644 index 0000000..7e5508b --- /dev/null +++ b/src/carla-includes/lv2/lv2-midifunctions.h @@ -0,0 +1,132 @@ +/**************************************************************************** + + lv2-midifunctions.h - support file for using MIDI in LV2 plugins + + Copyright (C) 2006-2007 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 + +****************************************************************************/ + +/** @file + This file contains static helper functions for the LV2 MIDI datatype + extension. +*/ + +#ifndef LV2_MIDIFUNCTIONS +#define LV2_MIDIFUNCTIONS + +#include + +#include "lv2-midiport.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; + + +/** 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 = *(uint32_t*)(state->midi->data + state->position + sizeof(double)); + *data = state->midi->data + state->position + + sizeof(double) + sizeof(uint32_t); + return *timestamp; +} + + +/** 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_step(LV2_MIDIState* state) { + + if (state->position + sizeof(double) + sizeof(uint32_t) >= state->midi->size) { + state->position = state->midi->size; + return state->frame_count; + } + + state->position += sizeof(double); + uint32_t size = *(uint32_t*)(state->midi->data + state->position); + state->position += sizeof(uint32_t); + state->position += size; + + if (state->position >= state->midi->size) + return state->frame_count; + + return *(double*)(state->midi->data + state->position); +} + + +/** 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(uint32_t) + size) + return -1; + + *(double*)(state->midi->data + state->midi->size) = timestamp; + state->midi->size += sizeof(double); + *(uint32_t*)(state->midi->data + state->midi->size) = size; + state->midi->size += sizeof(uint32_t); + memcpy(state->midi->data + state->midi->size, data, size); + state->midi->size += size; + + ++state->midi->event_count; + + return 0; +} + + +#endif + diff --git a/src/carla-includes/lv2/lv2-midiport.h b/src/carla-includes/lv2/lv2-midiport.h new file mode 100644 index 0000000..30309b6 --- /dev/null +++ b/src/carla-includes/lv2/lv2-midiport.h @@ -0,0 +1,177 @@ +/**************************************************************************** + + lv2-midiport.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 + +****************************************************************************/ + +/** @file + This file contains the specification for an LV2 MIDI port extension. +*/ + +#ifndef LV2_MIDIPORT_H +#define LV2_MIDIPORT_H + + +/** This data structure is used to contain the MIDI events for one run() + cycle. The port buffer for an LV2 port of the type + 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): + @code + + uint32_t buffer_offset = 0; + *(double*)(midi_data->data + buffer_offset) = 12; + buffer_offset += sizeof(double); + *(uint32_t*)(midi_data->data + buffer_offset) = 3; + buffer_offset += sizeof(uint32_t); + midi_data->data[buffer_offset++] = 0x90; + midi_data->data[buffer_offset++] = 0x48; + midi_data->data[buffer_offset++] = 0x64; + ++midi_data->event_count; + + *(double*)(midi_data->data + buffer_offset) = 35.5; + buffer_offset += sizeof(double); + *(uint32_t*)(midi_data->data + buffer_offset) = 3; + buffer_offset += sizeof(uint32_t); + midi_data->data[buffer_offset++] = 0x90; + midi_data->data[buffer_offset++] = 0x55; + midi_data->data[buffer_offset++] = 0x64; + ++midi_data->event_count; + + midi_data->size = buffer_offset; + + @endcode + + This would be done by the host in the case of an input port, and by the + plugin in the case of an output port. Whoever is writing events to the + buffer must also take care not to exceed the capacity of the data buffer. + + To read events from a buffer, you could do something like this: + @code + + uint32_t buffer_offset = 0; + uint32_t i; + for (i = 0; i < midi_data->event_count; ++i) { + double timestamp = *(double*)(midi_data->data + buffer_offset); + buffer_offset += sizeof(double); + uint32_t size = *(uint32_t*)(midi_data->data + buffer_offset); + buffer_offset += sizeof(uint32_t); + do_something_with_event(timestamp, size, + midi_data->data + buffer_offset); + buffer_offset += size; + } + + @endcode + + If you think this looks like too much code to simply read and write MIDI + events, take a look at the helper functions in lv2-midifunctions.h. They + are not an official part of this extension, but they can be convenient. +*/ +typedef struct { + + /** The number of MIDI events in the data buffer. + INPUT PORTS: It's the host's responsibility to set this field to the + number of MIDI events contained in the data buffer before calling the + plugin's run() function. The plugin may not change this field. + OUTPUT PORTS: It's the plugin's responsibility to set this field to the + number of MIDI events it has stored in the data buffer before returning + from the run() function. Any initial value should be ignored by the + plugin. + */ + uint32_t event_count; + + /** The size of the data buffer in bytes. It is set by the host and may not + be changed by the plugin. The host is allowed to change this between + run() calls. + */ + uint32_t capacity; + + /** The size of the initial part of the data buffer that actually contains + data. + INPUT PORTS: It's the host's responsibility to set this field to the + number of bytes used by all MIDI events it has written to the buffer + (including timestamps and size fields) before calling the plugin's + run() function. The plugin may not change this field. + OUTPUT PORTS: It's the plugin's responsibility to set this field to + the number of bytes used by all MIDI events it has written to the + buffer (including timestamps and size fields) before returning from + the run() function. Any initial value should be ignored by the plugin. + */ + uint32_t size; + + /** The data buffer that is used to store MIDI events. The events are packed + after each other, and the format of each event is as follows: + + First there is a timestamp, which should have the type "double", + i.e. have the same bit size as a double and the same bit layout as a + double (whatever that is on the current platform). This timestamp gives + the offset from the beginning of the current cycle, in frames, that + the MIDI event occurs on. It must be strictly smaller than the 'nframes' + parameter to the current run() call. The MIDI events in the buffer must + be ordered by their timestamp, e.g. an event with a timestamp of 123.23 + must be stored after an event with a timestamp of 65.0. + + The second part of the event is a size field, which should have the type + "uint32_t" (as defined in the standard C header stddef.h). It should + contain the size of the MIDI data for this event, i.e. the number of + bytes used to store the actual MIDI event. The bytes used by the + timestamp and the size field should not be counted. + + The third part of the event is the actual MIDI data. There are some + requirements that must be followed: + + * Running status is not allowed. Every event must have its own status + byte. + * Note On events with velocity 0 are not allowed. These events are + equivalent to Note Off in standard MIDI streams, but in order to make + plugins and hosts easier to write, as well as more efficient, only + proper Note Off events are allowed as Note Off. + * "Realtime events" (status bytes 0xF8 to 0xFF) are allowed, but may not + occur inside other events like they are allowed to in hardware MIDI + streams. + * All events must be fully contained in a single data buffer, i.e. events + may not "wrap around" by storing the first few bytes in one buffer and + then wait for the next run() call to store the rest of the event. If + there isn't enough space in the current data buffer to store an event, + the event will either have to wait until next run() call, be ignored, + or compensated for in some more clever way. + * All events must be valid MIDI events. This means for example that + only the first byte in each event (the status byte) may have the eighth + bit set, that Note On and Note Off events are always 3 bytes long etc. + The MIDI writer (host or plugin) is responsible for writing valid MIDI + events to the buffer, and the MIDI reader (plugin or host) can assume + that all events are valid. + + On a platform where double is 8 bytes the data buffer layout for a + 3-byte event followed by a 4-byte event may look something like this: + _______________________________________________________________ + | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ... + |TIMESTAMP 1 |SIZE 1 |DATA |TIMESTAMP 2 |SIZE 2 |DATA | ... + + */ + unsigned char* data; + +} LV2_MIDI; + + + +#endif diff --git a/src/carla/carla_backend.h b/src/carla/carla_backend.h index 7a59ac7..fd9d64b 100644 --- a/src/carla/carla_backend.h +++ b/src/carla/carla_backend.h @@ -43,9 +43,8 @@ const unsigned int PLUGIN_CAN_BALANCE = 0x40; // parameter hints const unsigned int PARAMETER_IS_ENABLED = 0x01; const unsigned int PARAMETER_IS_AUTOMABLE = 0x02; -const unsigned int PARAMETER_HAS_STRICT_BOUNDS = 0x04; -const unsigned int PARAMETER_USES_SCALEPOINTS = 0x08; -const unsigned int PARAMETER_USES_SAMPLERATE = 0x10; +const unsigned int PARAMETER_USES_SCALEPOINTS = 0x04; +const unsigned int PARAMETER_USES_SAMPLERATE = 0x08; enum BinaryType { BINARY_NONE = 0, diff --git a/src/carla/carla_bridge.cpp b/src/carla/carla_bridge.cpp index b5fcbf2..25d4987 100644 --- a/src/carla/carla_bridge.cpp +++ b/src/carla/carla_bridge.cpp @@ -151,7 +151,7 @@ public: m_name = get_unique_name(info->name); m_filename = strdup(filename); - // TODO - get bridge binary here + // FIXME - verify if path exists, if not return false m_thread->setOscData(binarytype2str(m_binary), label, plugintype2str(m_type)); m_thread->start(); diff --git a/src/carla/carla_plugin.h b/src/carla/carla_plugin.h index dc6ae1e..b505855 100644 --- a/src/carla/carla_plugin.h +++ b/src/carla/carla_plugin.h @@ -357,12 +357,6 @@ public: return 0.0; } - // FIXME - remove this? -// double get_default_parameter_value(uint32_t param_id) -// { -// return param.ranges[param_id].def; -// } - virtual void get_label(char* buf_str) { *buf_str = 0; @@ -856,7 +850,6 @@ public: { post_events.lock.lock(); - // FIXME? memcpy(post_events_dst, post_events.data, sizeof(PluginPostEvent)*MAX_POST_EVENTS); for (unsigned short i=0; i < MAX_POST_EVENTS; i++) diff --git a/src/carla/dssi.cpp b/src/carla/dssi.cpp index 5c25f66..fff71bb 100644 --- a/src/carla/dssi.cpp +++ b/src/carla/dssi.cpp @@ -759,7 +759,7 @@ public: if (param.port_cin) { - jack_default_audio_sample_t* pin_buffer = (jack_default_audio_sample_t*)jack_port_get_buffer(param.port_cin, nframes); + void* pin_buffer = jack_port_get_buffer(param.port_cin, nframes); jack_midi_event_t pin_event; uint32_t n_pin_events = jack_midi_get_event_count(pin_buffer); @@ -1125,7 +1125,7 @@ public: if (param.port_cout) { - jack_default_audio_sample_t* cout_buffer = (jack_default_audio_sample_t*)jack_port_get_buffer(param.port_cout, nframes); + void* cout_buffer = jack_port_get_buffer(param.port_cout, nframes); jack_midi_clear_buffer(cout_buffer); double value; diff --git a/src/carla/ladspa.cpp b/src/carla/ladspa.cpp index 2758d4e..06516cb 100644 --- a/src/carla/ladspa.cpp +++ b/src/carla/ladspa.cpp @@ -643,7 +643,7 @@ public: if (param.port_cin) { - jack_default_audio_sample_t* pin_buffer = (jack_default_audio_sample_t*)jack_port_get_buffer(param.port_cin, nframes); + void* pin_buffer = jack_port_get_buffer(param.port_cin, nframes); jack_midi_event_t pin_event; uint32_t n_pin_events = jack_midi_get_event_count(pin_buffer); @@ -848,7 +848,7 @@ public: if (param.port_cout) { - jack_default_audio_sample_t* cout_buffer = (jack_default_audio_sample_t*)jack_port_get_buffer(param.port_cout, nframes); + void* cout_buffer = jack_port_get_buffer(param.port_cout, nframes); jack_midi_clear_buffer(cout_buffer); double value; diff --git a/src/carla/lv2.cpp b/src/carla/lv2.cpp index eae1e8f..4086123 100644 --- a/src/carla/lv2.cpp +++ b/src/carla/lv2.cpp @@ -30,30 +30,39 @@ #include "lv2/ui.h" #include "lv2_rdf.h" +#include "lv2/lv2-midiport.h" +#include "lv2/lv2-midifunctions.h" + // static max values -const unsigned int MAX_EVENT_BUFFER = 0x7FFF; // 32767 +const unsigned int MAX_EVENT_BUFFER = 8192; // 0x7FFF; // 32767 // extra plugin hints const unsigned int PLUGIN_HAS_EXTENSION_STATE = 0x1000; const unsigned int PLUGIN_HAS_EXTENSION_DYNPARAM = 0x2000; +// parameter hints +const unsigned int PARAMETER_HAS_STRICT_BOUNDS = 0x100; + // feature ids const uint32_t lv2_feature_id_uri_map = 0; const uint32_t lv2_feature_id_urid_map = 1; const uint32_t lv2_feature_id_urid_unmap = 2; const uint32_t lv2_feature_id_event = 3; -//const uint32_t lv2_feature_id_rtmempool = 4; +const uint32_t lv2_feature_id_rtmempool = 4; //const uint32_t lv2_feature_id_data_access = 5; //const uint32_t lv2_feature_id_instance_access = 6; //const uint32_t lv2_feature_id_ui_resize = 7; //const uint32_t lv2_feature_id_ui_parent = 8; //const uint32_t lv2_feature_id_external_ui = 9; //const uint32_t lv2_feature_id_external_ui_old = 10; -const uint32_t lv2_feature_count = 4; +const uint32_t lv2_feature_count = 5; -// event types -const unsigned int CARLA_EVENT_TYPE_MIDI = 0x1; -const unsigned int CARLA_EVENT_TYPE_TIME = 0x2; +// event data/types +const unsigned int CARLA_EVENT_DATA_ATOM = 0x01; +const unsigned int CARLA_EVENT_DATA_EVENT = 0x02; +const unsigned int CARLA_EVENT_DATA_MIDI_LL = 0x04; +const unsigned int CARLA_EVENT_TYPE_MIDI = 0x10; +const unsigned int CARLA_EVENT_TYPE_TIME = 0x20; // pre-set uri[d] map ids const uint32_t CARLA_URI_MAP_ID_NULL = 0; @@ -70,7 +79,10 @@ enum Lv2ParameterDataType { struct EventData { unsigned int types; jack_port_t* port; - LV2_Event_Buffer* buffer; + union { + LV2_Event_Buffer* e; + LV2_MIDI* m; + } buffer; }; struct PluginEventData { @@ -428,7 +440,7 @@ public: CarlaPlugin::set_custom_data(dtype, key, value, gui_send); } - virtual void set_gui_data(int, void* ptr) + virtual void set_gui_data(int, void* /*ptr*/) { // switch(gui.type) // { @@ -468,7 +480,7 @@ public: // } } - virtual void show_gui(bool yesno) + virtual void show_gui(bool /*yesno*/) { // switch(gui.type) // { @@ -597,6 +609,7 @@ public: ains = aouts = cv_ins = cv_outs = ev_ins = ev_outs = params = 0; const uint32_t PortCount = rdf_descriptor->PortCount; + unsigned int event_data_type = 0; for (uint32_t i=0; icapacity = MAX_EVENT_BUFFER; + evin.data[j].buffer.m->data = new unsigned char [MAX_EVENT_BUFFER]; + } + else + evin.data[j].types = 0; } } @@ -663,9 +703,27 @@ public: for (j=0; j < ev_outs; j++) { - evout.data[j].types = 0; - evout.data[j].port = nullptr; - evout.data[j].buffer = lv2_event_buffer_new(MAX_EVENT_BUFFER, LV2_EVENT_AUDIO_STAMP); + evout.data[j].port = nullptr; + + if (event_data_type == CARLA_EVENT_DATA_ATOM) + { + evout.data[j].types = CARLA_EVENT_DATA_ATOM; + // TODO + } + else if (event_data_type == CARLA_EVENT_DATA_EVENT) + { + evout.data[j].types = CARLA_EVENT_DATA_EVENT; + evout.data[j].buffer.e = lv2_event_buffer_new(MAX_EVENT_BUFFER, LV2_EVENT_AUDIO_STAMP); + } + else if (event_data_type == CARLA_EVENT_DATA_MIDI_LL) + { + evout.data[j].types = CARLA_EVENT_DATA_MIDI_LL; + evout.data[j].buffer.m = new LV2_MIDI; + evout.data[j].buffer.m->capacity = MAX_EVENT_BUFFER; + evout.data[j].buffer.m->data = new unsigned char [MAX_EVENT_BUFFER]; + } + else + evout.data[j].types = 0; } } @@ -685,7 +743,7 @@ public: { const LV2_Property PortType = rdf_descriptor->Ports[i].Type; - if (LV2_IS_PORT_AUDIO(PortType) || LV2_IS_PORT_CV(PortType) || LV2_IS_PORT_EVENT(PortType)) + if (LV2_IS_PORT_AUDIO(PortType) || LV2_IS_PORT_CV(PortType) || LV2_IS_PORT_EVENT(PortType) || LV2_IS_PORT_MIDI_LL(PortType)) { #ifndef BUILD_BRIDGE if (carla_options.global_jack_client) @@ -737,7 +795,7 @@ public: if (LV2_IS_PORT_INPUT(PortType)) { j = evin.count++; - descriptor->connect_port(handle, i, evin.data[j].buffer); + descriptor->connect_port(handle, i, evin.data[j].buffer.e); if (LV2_IS_PORT_EVENT_MIDI(PortType)) { @@ -747,13 +805,12 @@ public: if (LV2_IS_PORT_EVENT_TIME(PortType)) { evin.data[j].types |= CARLA_EVENT_TYPE_TIME; - //wants_time_pos = true; } } else if (LV2_IS_PORT_OUTPUT(PortType)) { j = evout.count++; - descriptor->connect_port(handle, i, evout.data[j].buffer); + descriptor->connect_port(handle, i, evout.data[j].buffer.e); if (LV2_IS_PORT_EVENT_MIDI(PortType)) { @@ -768,6 +825,27 @@ public: else qWarning("WARNING - Got a broken Port (Event, but not input or output)"); } + else if (LV2_IS_PORT_MIDI_LL(PortType)) + { + if (LV2_IS_PORT_INPUT(PortType)) + { + j = evin.count++; + descriptor->connect_port(handle, i, evin.data[j].buffer.m); + + evin.data[j].types |= CARLA_EVENT_TYPE_MIDI; + evin.data[j].port = jack_port_register(jack_client, port_name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); + } + else if (LV2_IS_PORT_OUTPUT(PortType)) + { + j = evout.count++; + descriptor->connect_port(handle, i, evout.data[j].buffer.m); + + evout.data[j].types |= CARLA_EVENT_TYPE_MIDI; + evout.data[j].port = jack_port_register(jack_client, port_name, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); + } + else + qWarning("WARNING - Got a broken Port (Midi, but not input or output)"); + } else if (LV2_IS_PORT_CONTROL(PortType)) { const LV2_Property PortProps = rdf_descriptor->Ports[i].Properties; @@ -997,11 +1075,13 @@ public: jack_default_audio_sample_t* ains_buffer[ain.count]; jack_default_audio_sample_t* aouts_buffer[aout.count]; - - LV2_Event_Iterator evin_iters[evin.count]; void* evins_buffer[evin.count]; void* evouts_buffer[evout.count]; + // different midi APIs + LV2_MIDIState evin_states[evin.count]; + LV2_Event_Iterator evin_iters[evin.count]; + for (i=0; i < ain.count; i++) ains_buffer[i] = (jack_default_audio_sample_t*)jack_port_get_buffer(ain.ports[i], nframes); @@ -1010,21 +1090,46 @@ public: for (i=0; i < evin.count; i++) { - lv2_event_buffer_reset(evin.data[i].buffer, LV2_EVENT_AUDIO_STAMP, (uint8_t*)(evin.data[i].buffer + 1)); - lv2_event_begin(&evin_iters[i], evin.data[i].buffer); + if (evin.data[i].types & CARLA_EVENT_DATA_ATOM) + { + } + else if (evin.data[i].types & CARLA_EVENT_DATA_EVENT) + { + lv2_event_buffer_reset(evin.data[i].buffer.e, LV2_EVENT_AUDIO_STAMP, (uint8_t*)(evin.data[i].buffer.e + 1)); + lv2_event_begin(&evin_iters[i], evin.data[i].buffer.e); + } + else if (evin.data[i].types & CARLA_EVENT_DATA_MIDI_LL) + { + evin_states[i].midi = evin.data[i].buffer.m; + evin_states[i].frame_count = nframes; + evin_states[i].position = 0; + + evin_states[i].midi->event_count = 0; + evin_states[i].midi->size = 0; + } if (evin.data[i].port) - evins_buffer[i] = (jack_default_audio_sample_t*)jack_port_get_buffer(evin.data[i].port, nframes); + evins_buffer[i] = jack_port_get_buffer(evin.data[i].port, nframes); else evins_buffer[i] = nullptr; } for (i=0; i < evout.count; i++) { - lv2_event_buffer_reset(evout.data[i].buffer, LV2_EVENT_AUDIO_STAMP, (uint8_t*)(evout.data[i].buffer + 1)); + if (evin.data[i].types & CARLA_EVENT_DATA_ATOM) + { + } + else if (evin.data[i].types & CARLA_EVENT_DATA_EVENT) + { + lv2_event_buffer_reset(evout.data[i].buffer.e, LV2_EVENT_AUDIO_STAMP, (uint8_t*)(evout.data[i].buffer.e + 1)); + } + else if (evin.data[i].types & CARLA_EVENT_DATA_MIDI_LL) + { + // not needed + } if (evout.data[i].port) - evouts_buffer[i] = (jack_default_audio_sample_t*)jack_port_get_buffer(evout.data[i].port, nframes); + evouts_buffer[i] = jack_port_get_buffer(evout.data[i].port, nframes); else evouts_buffer[i] = nullptr; } @@ -1052,7 +1157,7 @@ public: if (param.port_cin) { - jack_default_audio_sample_t* pin_buffer = (jack_default_audio_sample_t*)jack_port_get_buffer(param.port_cin, nframes); + void* pin_buffer = jack_port_get_buffer(param.port_cin, nframes); jack_midi_event_t pin_event; uint32_t n_pin_events = jack_midi_get_event_count(pin_buffer); @@ -1195,19 +1300,22 @@ public: { if (ext_midi_notes[i].valid) { + uint8_t midi_event[4] = { 0 }; + midi_event[0] = ext_midi_notes[i].onoff ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF; + midi_event[1] = ext_midi_notes[i].note; + midi_event[2] = ext_midi_notes[i].velo; + // send to all midi inputs for (k=0; k < evin.count; k++) { - if (evins_buffer[k] == nullptr || (evin.data[k].types & CARLA_EVENT_TYPE_MIDI) == 0) - continue; - - uint8_t* midi_event = lv2_event_reserve(&evin_iters[k], 0, 0, CARLA_URI_MAP_ID_EVENT_MIDI, 3); - - if (midi_event) + if (evin.data[k].types & CARLA_EVENT_TYPE_MIDI) { - midi_event[0] = ext_midi_notes[i].onoff ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF; - midi_event[1] = ext_midi_notes[i].note; - midi_event[2] = ext_midi_notes[i].velo; + if (evin.data[k].types & CARLA_EVENT_DATA_ATOM) + continue; // TODO + else if (evin.data[k].types & CARLA_EVENT_DATA_EVENT) + lv2_event_write(&evin_iters[k], 0, 0, CARLA_URI_MAP_ID_EVENT_MIDI, 3, midi_event); + else if (evin.data[k].types & CARLA_EVENT_DATA_MIDI_LL) + lv2midi_put_event(&evin_states[k], 0, 3, midi_event); } } @@ -1229,7 +1337,7 @@ public: for (i=0; i < evin.count; i++) { - if (evins_buffer[i] == nullptr || (evin.data[i].types & CARLA_EVENT_TYPE_MIDI) == 0) + if (evins_buffer[i] == nullptr) continue; jack_midi_event_t min_event; @@ -1252,7 +1360,12 @@ public: // write supported status types if (MIDI_IS_STATUS_NOTE_OFF(status) || MIDI_IS_STATUS_NOTE_ON(status) || MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status) || MIDI_IS_STATUS_AFTERTOUCH(status) || MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status)) { - lv2_event_write(&evin_iters[i], min_event.time, 0, CARLA_URI_MAP_ID_EVENT_MIDI, min_event.size, min_event.buffer); + if (evin.data[i].types & CARLA_EVENT_DATA_ATOM) + continue; // TODO + else if (evin.data[i].types & CARLA_EVENT_DATA_EVENT) + lv2_event_write(&evin_iters[i], min_event.time, 0, CARLA_URI_MAP_ID_EVENT_MIDI, min_event.size, min_event.buffer); + else if (evin.data[i].types & CARLA_EVENT_DATA_MIDI_LL) + lv2midi_put_event(&evin_states[i], min_event.time, min_event.size, min_event.buffer); if (MIDI_IS_STATUS_NOTE_OFF(status)) postpone_event(PostEventNoteOff, min_event.buffer[1], 0.0); @@ -1377,7 +1490,7 @@ public: if (param.port_cout) { - jack_default_audio_sample_t* cout_buffer = (jack_default_audio_sample_t*)jack_port_get_buffer(param.port_cout, nframes); + void* cout_buffer = jack_port_get_buffer(param.port_cout, nframes); jack_midi_clear_buffer(cout_buffer); double value, rvalue; @@ -1413,24 +1526,44 @@ public: for (i=0; i < evout.count; i++) { - if (evouts_buffer[i] == nullptr || (evout.data[i].types & CARLA_EVENT_TYPE_MIDI) == 0) + if (evouts_buffer[i] == nullptr) continue; jack_midi_clear_buffer(evouts_buffer[i]); - LV2_Event* ev; - uint8_t* data; + if (evin.data[i].types & CARLA_EVENT_DATA_ATOM) + { + } + else if (evin.data[i].types & CARLA_EVENT_DATA_EVENT) + { + LV2_Event* ev; + LV2_Event_Iterator iter; - LV2_Event_Iterator iter; - lv2_event_begin(&iter, evout.data[i].buffer); + uint8_t* data; + lv2_event_begin(&iter, evout.data[i].buffer.e); + + for (k=0; k < iter.buf->event_count; k++) + { + ev = lv2_event_get(&iter, &data); + if (ev && data) + jack_midi_event_write(evouts_buffer[i], ev->frames, data, ev->size); - for (k=0; k < iter.buf->event_count; k++) + lv2_event_increment(&iter); + } + } + else if (evin.data[i].types & CARLA_EVENT_DATA_MIDI_LL) { - ev = lv2_event_get(&iter, &data); - if (ev && data) - jack_midi_event_write(evouts_buffer[i], ev->frames, data, ev->size); + LV2_MIDIState state = { evout.data[i].buffer.m, nframes, 0 }; + + uint32_t event_size; + double event_timestamp; + unsigned char* event_data; - lv2_event_increment(&iter); + while (lv2midi_get_event(&state, &event_timestamp, &event_size, &event_data) < nframes) + { + jack_midi_event_write(evouts_buffer[i], event_timestamp, event_data, event_size); + lv2midi_step(&state); + } } } // End of MIDI Output @@ -1463,7 +1596,20 @@ public: if (evin.count > 0) { for (uint32_t i=0; i < evin.count; i++) - free(evin.data[i].buffer); + { + if (evin.data[i].types & CARLA_EVENT_DATA_ATOM) + { + } + else if (evin.data[i].types & CARLA_EVENT_DATA_EVENT) + { + free(evin.data[i].buffer.e); + } + else if (evin.data[i].types & CARLA_EVENT_DATA_MIDI_LL) + { + delete[] evin.data[i].buffer.m->data; + delete evin.data[i].buffer.m; + } + } delete[] evin.data; } @@ -1471,7 +1617,20 @@ public: if (evout.count > 0) { for (uint32_t i=0; i < evout.count; i++) - free(evout.data[i].buffer); + { + if (evout.data[i].types & CARLA_EVENT_DATA_ATOM) + { + } + else if (evout.data[i].types & CARLA_EVENT_DATA_EVENT) + { + free(evout.data[i].buffer.e); + } + else if (evout.data[i].types & CARLA_EVENT_DATA_MIDI_LL) + { + delete[] evout.data[i].buffer.m->data; + delete evout.data[i].buffer.m; + } + } delete[] evout.data; } @@ -1550,7 +1709,6 @@ public: uint32_t i = 0; while ((descriptor = descfn(i++))) { - qDebug("%s | %s", descriptor->URI, URI); if (strcmp(descriptor->URI, URI) == 0) break; } @@ -1563,7 +1721,7 @@ public: for (i=0; i < rdf_descriptor->PortCount; i++) { LV2_Property PortType = rdf_descriptor->Ports[i].Type; - if (bool(LV2_IS_PORT_AUDIO(PortType) || LV2_IS_PORT_CONTROL(PortType) || LV2_IS_PORT_EVENT(PortType)) == false) + if (bool(LV2_IS_PORT_AUDIO(PortType) || LV2_IS_PORT_CONTROL(PortType) || LV2_IS_PORT_EVENT(PortType) || LV2_IS_PORT_MIDI_LL(PortType)) == false) { if (! LV2_IS_PORT_OPTIONAL(rdf_descriptor->Ports[i].Properties)) { diff --git a/src/carla/lv2_rdf.h b/src/carla/lv2_rdf.h index 996b509..371cb89 100644 --- a/src/carla/lv2_rdf.h +++ b/src/carla/lv2_rdf.h @@ -766,26 +766,26 @@ inline bool is_lv2_feature_supported(const char* uri) return false; } -inline bool is_lv2_ui_feature_supported(const char */*uri*/) +inline bool is_lv2_ui_feature_supported(const char* uri) { -// if (strcmp(uri, "http://lv2plug.in/ns/lv2core#hardRTCapable") == 0) -// return true; -// else if (strcmp(uri, "http://lv2plug.in/ns/lv2core#inPlaceBroken") == 0) -// return true; -// else if (strcmp(uri, "http://lv2plug.in/ns/lv2core#isLive") == 0) -// return true; -// else if (strcmp(uri, "http://lv2plug.in/ns/ext/event") == 0) -// return true; -// else if (strcmp(uri, "http://lv2plug.in/ns/ext/state#makePath") == 0) -// return false; // TODO -// else if (strcmp(uri, "http://lv2plug.in/ns/ext/state#mapPath") == 0) -// return false; // TODO -// else if (strcmp(uri, "http://lv2plug.in/ns/ext/uri-map") == 0) -// return true; -// else if (strcmp(uri, "http://lv2plug.in/ns/ext/urid#map") == 0) -// return true; -// else if (strcmp(uri, "http://lv2plug.in/ns/ext/urid#unmap") == 0) -// return true; + if (strcmp(uri, "http://lv2plug.in/ns/lv2core#hardRTCapable") == 0) + return true; + else if (strcmp(uri, "http://lv2plug.in/ns/lv2core#inPlaceBroken") == 0) + return true; + else if (strcmp(uri, "http://lv2plug.in/ns/lv2core#isLive") == 0) + return true; + else if (strcmp(uri, "http://lv2plug.in/ns/ext/event") == 0) + return true; + else if (strcmp(uri, "http://lv2plug.in/ns/ext/state#makePath") == 0) + return false; // TODO + else if (strcmp(uri, "http://lv2plug.in/ns/ext/state#mapPath") == 0) + return false; // TODO + else if (strcmp(uri, "http://lv2plug.in/ns/ext/uri-map") == 0) + return true; + else if (strcmp(uri, "http://lv2plug.in/ns/ext/urid#map") == 0) + return true; + else if (strcmp(uri, "http://lv2plug.in/ns/ext/urid#unmap") == 0) + return true; // else if (strcmp(uri, "http://lv2plug.in/ns/ext/data-access") == 0) // return true; // else if (strcmp(uri, "http://lv2plug.in/ns/ext/instance-access") == 0) @@ -806,7 +806,7 @@ inline bool is_lv2_ui_feature_supported(const char */*uri*/) // return true; // else if (strcmp(uri, "http://nedko.arnaudov.name/lv2/external_ui/") == 0) // return true; -// else + else return false; } diff --git a/src/carla/sf2.cpp b/src/carla/sf2.cpp index 26777ad..9ac360f 100644 --- a/src/carla/sf2.cpp +++ b/src/carla/sf2.cpp @@ -366,9 +366,6 @@ public: param.port_cout = jack_port_register(jack_client, port_name, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); - // TODO - auto-assign midi ccs - // TODO - verify min/max values - // ---------------------- j = Sf2ReverbOnOff; param.data[j].index = j; @@ -714,7 +711,7 @@ public: // Parameters Input [Automation] { - jack_default_audio_sample_t* pin_buffer = (jack_default_audio_sample_t*)jack_port_get_buffer(param.port_cin, nframes); + void* pin_buffer = jack_port_get_buffer(param.port_cin, nframes); jack_midi_event_t pin_event; uint32_t n_pin_events = jack_midi_get_event_count(pin_buffer); @@ -1047,7 +1044,7 @@ public: // Control Output { - jack_default_audio_sample_t* cout_buffer = (jack_default_audio_sample_t*)jack_port_get_buffer(param.port_cout, nframes); + void* cout_buffer = jack_port_get_buffer(param.port_cout, nframes); jack_midi_clear_buffer(cout_buffer); k = Sf2VoiceCount; diff --git a/src/carla/vst.cpp b/src/carla/vst.cpp index 606e1be..0a0da90 100644 --- a/src/carla/vst.cpp +++ b/src/carla/vst.cpp @@ -637,7 +637,7 @@ public: if (param.port_cin) { - jack_default_audio_sample_t* pin_buffer = (jack_default_audio_sample_t*)jack_port_get_buffer(param.port_cin, nframes); + void* pin_buffer = jack_port_get_buffer(param.port_cin, nframes); jack_midi_event_t pin_event; uint32_t n_pin_events = jack_midi_get_event_count(pin_buffer); @@ -1208,7 +1208,7 @@ public: { VstEvents* events = (VstEvents*)ptr; - jack_default_audio_sample_t* mout_buffer = (jack_default_audio_sample_t*)jack_port_get_buffer(plugin->mout.ports[0], get_buffer_size()); + void* mout_buffer = jack_port_get_buffer(plugin->mout.ports[0], get_buffer_size()); jack_midi_clear_buffer(mout_buffer); for (int32_t i=0; i < events->numEvents; i++) diff --git a/src/carla_backend.py b/src/carla_backend.py index fc605e0..426d138 100644 --- a/src/carla_backend.py +++ b/src/carla_backend.py @@ -624,9 +624,8 @@ PLUGIN_CAN_BALANCE = 0x40 # parameter hints PARAMETER_IS_ENABLED = 0x01 PARAMETER_IS_AUTOMABLE = 0x02 -PARAMETER_HAS_STRICT_BOUNDS = 0x04 -PARAMETER_USES_SCALEPOINTS = 0x08 -PARAMETER_USES_SAMPLERATE = 0x10 +PARAMETER_USES_SCALEPOINTS = 0x04 +PARAMETER_USES_SAMPLERATE = 0x08 # enum BinaryType BINARY_NONE = 0