Merge pull request #776 from jpcima/lv2-parameters
Present the controllers as LV2 parameters
This commit is contained in:
commit
539fbf6442
13 changed files with 450 additions and 83 deletions
|
|
@ -40,3 +40,59 @@ else()
|
|||
set(LV2PLUGIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib/lv2" CACHE STRING
|
||||
"Install destination for LV2 bundle [default: ${CMAKE_INSTALL_PREFIX}/lib/lv2]")
|
||||
endif()
|
||||
|
||||
include(StringUtility)
|
||||
|
||||
function(sfizz_lv2_generate_controllers_ttl FILE)
|
||||
file(WRITE "${FILE}" "# LV2 parameters for SFZ controllers
|
||||
@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
|
||||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
|
||||
@prefix midi: <http://lv2plug.in/ns/ext/midi#> .
|
||||
@prefix patch: <http://lv2plug.in/ns/ext/patch#> .
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||
@prefix sfizz: <${LV2PLUGIN_URI}#> .
|
||||
")
|
||||
math(EXPR _j "${SFIZZ_NUM_CCS}-1")
|
||||
foreach(_i RANGE "${_j}")
|
||||
string_left_pad(_i "${_i}" 3 0)
|
||||
file(APPEND "${FILE}" "
|
||||
sfizz:cc${_i}
|
||||
a lv2:Parameter ;
|
||||
rdfs:label \"Controller ${_i}\" ;
|
||||
rdfs:range atom:Float")
|
||||
|
||||
if(_i LESS 128)
|
||||
math(EXPR _digit1 "${_i}>>4")
|
||||
math(EXPR _digit2 "${_i}&15")
|
||||
string(SUBSTRING "0123456789ABCDEF" "${_digit1}" 1 _digit1)
|
||||
string(SUBSTRING "0123456789ABCDEF" "${_digit2}" 1 _digit2)
|
||||
file(APPEND "${FILE}" " ;
|
||||
midi:binding \"B0${_digit1}${_digit2}00\"^^midi:MidiEvent .
|
||||
")
|
||||
else()
|
||||
file(APPEND "${FILE}" " .
|
||||
")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
file(APPEND "${FILE}" "
|
||||
<${LV2PLUGIN_URI}>
|
||||
a lv2:Plugin ;
|
||||
")
|
||||
|
||||
file(APPEND "${FILE}" " patch:readable sfizz:cc000")
|
||||
foreach(_i RANGE 1 "${_j}")
|
||||
string_left_pad(_i "${_i}" 3 0)
|
||||
file(APPEND "${FILE}" ", sfizz:cc${_i}")
|
||||
endforeach()
|
||||
file(APPEND "${FILE}" " ;
|
||||
")
|
||||
|
||||
file(APPEND "${FILE}" " patch:writable sfizz:cc000")
|
||||
foreach(_i RANGE 1 "${_j}")
|
||||
string_left_pad(_i "${_i}" 3 0)
|
||||
file(APPEND "${FILE}" ", sfizz:cc${_i}")
|
||||
endforeach()
|
||||
file(APPEND "${FILE}" " .
|
||||
")
|
||||
endfunction()
|
||||
|
|
|
|||
11
cmake/StringUtility.cmake
Normal file
11
cmake/StringUtility.cmake
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
function(string_left_pad VAR INPUT LENGTH FILLCHAR)
|
||||
set(_output "${INPUT}")
|
||||
string(LENGTH "${_output}" _length)
|
||||
while(_length LESS "${LENGTH}")
|
||||
set(_output "${FILLCHAR}${_output}")
|
||||
string(LENGTH "${_output}" _length)
|
||||
endwhile()
|
||||
set("${VAR}" "${_output}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
|
@ -306,6 +306,12 @@ void Editor::close()
|
|||
}
|
||||
}
|
||||
|
||||
void Editor::sendQueuedOSC(const char* path, const char* sig, const sfizz_arg_t* args)
|
||||
{
|
||||
Impl& impl = *impl_;
|
||||
impl.sendQueuedOSC(path, sig, args);
|
||||
}
|
||||
|
||||
void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v)
|
||||
{
|
||||
switch (id) {
|
||||
|
|
@ -476,12 +482,18 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v)
|
|||
else if (editIdIsKeyswitchLabel(id)) {
|
||||
updateSWLastLabel(keyswitchLabelForEditId(id), v.to_string().c_str());
|
||||
}
|
||||
else if (editIdIsCC(id)) {
|
||||
updateCCValue(unsigned(ccForEditId(id)), v.to_float());
|
||||
}
|
||||
else if (editIdIsCCUsed(id)) {
|
||||
updateCCUsed(ccUsedForEditId(id), v.to_float() != 0);
|
||||
bool used = v.to_float() != 0;
|
||||
updateCCUsed(ccUsedForEditId(id), used);
|
||||
// TODO(jpc) remove value requests, when implementing CC automation
|
||||
char pathBuf[256];
|
||||
sprintf(pathBuf, "/cc%u/value", ccUsedForEditId(id));
|
||||
sendQueuedOSC(pathBuf, "", nullptr);
|
||||
if (used) {
|
||||
char pathBuf[256];
|
||||
sprintf(pathBuf, "/cc%u/value", ccUsedForEditId(id));
|
||||
sendQueuedOSC(pathBuf, "", nullptr);
|
||||
}
|
||||
}
|
||||
else if (editIdIsCCDefault(id)) {
|
||||
updateCCDefaultValue(ccDefaultForEditId(id), v.to_float());
|
||||
|
|
@ -1610,13 +1622,8 @@ void Editor::Impl::updateMemoryUsed(uint64_t mem)
|
|||
|
||||
void Editor::Impl::performCCValueChange(unsigned cc, float value)
|
||||
{
|
||||
// TODO(jpc) CC as parameters and automation
|
||||
|
||||
char pathBuf[256];
|
||||
sprintf(pathBuf, "/cc%u/value", cc);
|
||||
sfizz_arg_t args[1];
|
||||
args[0].f = value;
|
||||
sendQueuedOSC(pathBuf, "f", args);
|
||||
EditorController& ctrl = *ctrl_;
|
||||
ctrl.uiSendValue(editIdForCC(int(cc)), value);
|
||||
}
|
||||
|
||||
void Editor::Impl::performCCBeginEdit(unsigned cc)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||
|
||||
#pragma once
|
||||
#include <sfizz_message.h>
|
||||
#include <memory>
|
||||
class EditorController;
|
||||
|
||||
|
|
@ -24,6 +25,9 @@ public:
|
|||
void open(CFrame& frame);
|
||||
void close();
|
||||
|
||||
// TODO(jpc) remove me after doing parameter automations
|
||||
void sendQueuedOSC(const char* path, const char* sig, const sfizz_arg_t* args);
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl_;
|
||||
|
|
|
|||
|
|
@ -82,6 +82,9 @@ if(SFIZZ_USE_VCPKG OR SFIZZ_STATIC_DEPENDENCIES OR CMAKE_CXX_COMPILER_ID MATCHES
|
|||
file(COPY "lgpl-3.0.txt" DESTINATION ${PROJECT_BINARY_DIR})
|
||||
endif()
|
||||
|
||||
# Generate controllers.ttl
|
||||
sfizz_lv2_generate_controllers_ttl("${PROJECT_BINARY_DIR}/controllers.ttl")
|
||||
|
||||
# Copy resource files into the bundle
|
||||
set(LV2_RESOURCES
|
||||
DefaultInstrument.sfz
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<@LV2PLUGIN_URI@>
|
||||
a lv2:Plugin ;
|
||||
lv2:binary <Contents/Binary/@PROJECT_NAME@@CMAKE_SHARED_MODULE_SUFFIX@> ;
|
||||
rdfs:seeAlso <@PROJECT_NAME@.ttl> .
|
||||
rdfs:seeAlso <@PROJECT_NAME@.ttl>, <controllers.ttl> .
|
||||
|
||||
@LV2PLUGIN_IF_ENABLE_UI@<@LV2PLUGIN_URI@#ui>
|
||||
@LV2PLUGIN_IF_ENABLE_UI@ a ui:@LV2_UI_TYPE@ ;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#define CHANNEL_MASK 0x0F
|
||||
#define MIDI_CHANNEL(byte) (byte & CHANNEL_MASK)
|
||||
#define MIDI_STATUS(byte) (byte & ~CHANNEL_MASK)
|
||||
|
|
@ -201,6 +203,9 @@ connect_port(LV2_Handle instance,
|
|||
case SFIZZ_NOTIFY:
|
||||
self->notify_port = (LV2_Atom_Sequence *)data;
|
||||
break;
|
||||
case SFIZZ_AUTOMATE:
|
||||
self->automate_port = (LV2_Atom_Sequence *)data;
|
||||
break;
|
||||
case SFIZZ_LEFT:
|
||||
self->output_buffers[0] = (float *)data;
|
||||
break;
|
||||
|
|
@ -320,11 +325,12 @@ sfizz_lv2_receive_message(void* data, int delay, const char* path, const char* s
|
|||
if (osc_size > OSC_TEMP_SIZE)
|
||||
return;
|
||||
|
||||
LV2_Atom_Forge* forge = &self->forge_notify;
|
||||
bool write_ok =
|
||||
lv2_atom_forge_frame_time(&self->forge, 0) &&
|
||||
lv2_atom_forge_atom(&self->forge, osc_size, self->sfizz_osc_blob_uri) &&
|
||||
lv2_atom_forge_raw(&self->forge, osc_temp, osc_size);
|
||||
lv2_atom_forge_pad(&self->forge, osc_size);
|
||||
lv2_atom_forge_frame_time(forge, 0) &&
|
||||
lv2_atom_forge_atom(forge, osc_size, self->sfizz_osc_blob_uri) &&
|
||||
lv2_atom_forge_raw(forge, osc_temp, osc_size);
|
||||
lv2_atom_forge_pad(forge, osc_size);
|
||||
|
||||
(void)write_ok;
|
||||
}
|
||||
|
|
@ -426,7 +432,8 @@ instantiate(const LV2_Descriptor *descriptor,
|
|||
sfizz_lv2_map_required_uris(self);
|
||||
|
||||
// Initialize the forge
|
||||
lv2_atom_forge_init(&self->forge, self->map);
|
||||
lv2_atom_forge_init(&self->forge_notify, self->map);
|
||||
lv2_atom_forge_init(&self->forge_automate, self->map);
|
||||
lv2_atom_forge_init(&self->forge_secondary, self->map);
|
||||
|
||||
// Check the options for the block size and sample rate parameters
|
||||
|
|
@ -476,6 +483,10 @@ instantiate(const LV2_Descriptor *descriptor,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
self->ccmap = sfizz_lv2_ccmap_create(self->map);
|
||||
self->cc_current = new float[sfz::config::numCCs]();
|
||||
self->ccauto = new absl::optional<float>[sfz::config::numCCs];
|
||||
|
||||
self->synth = sfizz_create_synth();
|
||||
self->client = sfizz_create_client(self);
|
||||
self->synth_mutex = spin_mutex_create();
|
||||
|
|
@ -501,6 +512,9 @@ cleanup(LV2_Handle instance)
|
|||
spin_mutex_destroy(self->synth_mutex);
|
||||
sfizz_delete_client(self->client);
|
||||
sfizz_free(self->synth);
|
||||
delete[] self->ccauto;
|
||||
delete[] self->cc_current;
|
||||
sfizz_lv2_ccmap_free(self->ccmap);
|
||||
delete self;
|
||||
}
|
||||
|
||||
|
|
@ -521,24 +535,42 @@ deactivate(LV2_Handle instance)
|
|||
}
|
||||
|
||||
static void
|
||||
sfizz_lv2_send_file_path(sfizz_plugin_t *self, LV2_URID urid, const char *path)
|
||||
sfizz_lv2_send_file_path(sfizz_plugin_t *self, LV2_Atom_Forge* forge, LV2_URID urid, const char *path)
|
||||
{
|
||||
LV2_Atom_Forge_Frame frame;
|
||||
|
||||
bool write_ok =
|
||||
lv2_atom_forge_frame_time(&self->forge, 0) &&
|
||||
lv2_atom_forge_object(&self->forge, &frame, 0, self->patch_set_uri) &&
|
||||
lv2_atom_forge_key(&self->forge, self->patch_property_uri) &&
|
||||
lv2_atom_forge_urid(&self->forge, urid) &&
|
||||
lv2_atom_forge_key(&self->forge, self->patch_value_uri) &&
|
||||
lv2_atom_forge_path(&self->forge, path, (uint32_t)strlen(path));
|
||||
lv2_atom_forge_frame_time(forge, 0) &&
|
||||
lv2_atom_forge_object(forge, &frame, 0, self->patch_set_uri) &&
|
||||
lv2_atom_forge_key(forge, self->patch_property_uri) &&
|
||||
lv2_atom_forge_urid(forge, urid) &&
|
||||
lv2_atom_forge_key(forge, self->patch_value_uri) &&
|
||||
lv2_atom_forge_path(forge, path, (uint32_t)strlen(path));
|
||||
|
||||
if (write_ok)
|
||||
lv2_atom_forge_pop(&self->forge, &frame);
|
||||
lv2_atom_forge_pop(forge, &frame);
|
||||
}
|
||||
|
||||
static void
|
||||
sfizz_lv2_handle_atom_object(sfizz_plugin_t *self, const LV2_Atom_Object *obj)
|
||||
sfizz_lv2_send_controller(sfizz_plugin_t *self, LV2_Atom_Forge* forge, unsigned cc, float value)
|
||||
{
|
||||
LV2_URID urid = sfizz_lv2_ccmap_map(self->ccmap, int(cc));
|
||||
LV2_Atom_Forge_Frame frame;
|
||||
|
||||
bool write_ok =
|
||||
lv2_atom_forge_frame_time(forge, 0) &&
|
||||
lv2_atom_forge_object(forge, &frame, 0, self->patch_set_uri) &&
|
||||
lv2_atom_forge_key(forge, self->patch_property_uri) &&
|
||||
lv2_atom_forge_urid(forge, urid) &&
|
||||
lv2_atom_forge_key(forge, self->patch_value_uri) &&
|
||||
lv2_atom_forge_float(forge, value);
|
||||
|
||||
if (write_ok)
|
||||
lv2_atom_forge_pop(forge, &frame);
|
||||
}
|
||||
|
||||
static void
|
||||
sfizz_lv2_handle_atom_object(sfizz_plugin_t *self, int delay, const LV2_Atom_Object *obj)
|
||||
{
|
||||
const LV2_Atom *property = NULL;
|
||||
lv2_atom_object_get(obj, self->patch_property_uri, &property, 0);
|
||||
|
|
@ -575,7 +607,15 @@ sfizz_lv2_handle_atom_object(sfizz_plugin_t *self, const LV2_Atom_Object *obj)
|
|||
char body[MAX_PATH_SIZE];
|
||||
} sfizz_path_atom_buffer_t;
|
||||
|
||||
if (key == self->sfizz_sfz_file_uri)
|
||||
int cc = sfizz_lv2_ccmap_unmap(self->ccmap, key);
|
||||
if (cc != -1) {
|
||||
if (atom->type == self->atom_float_uri && atom->size == sizeof(float)) {
|
||||
float value = *(const float *)LV2_ATOM_BODY_CONST(atom);
|
||||
sfizz_send_hdcc(self->synth, delay, cc, value);
|
||||
self->cc_current[cc] = value;
|
||||
}
|
||||
}
|
||||
else if (key == self->sfizz_sfz_file_uri)
|
||||
{
|
||||
LV2_Atom_Forge *forge = &self->forge_secondary;
|
||||
sfizz_path_atom_buffer_t buffer;
|
||||
|
|
@ -629,12 +669,14 @@ sfizz_lv2_process_midi_event(sfizz_plugin_t *self, const LV2_Atom_Event *ev)
|
|||
(int)msg[1],
|
||||
msg[2]);
|
||||
break;
|
||||
case LV2_MIDI_MSG_CONTROLLER:
|
||||
// Note(jpc) CC must be mapped by host, not handled here.
|
||||
// See LV2 midi:binding.
|
||||
/*case LV2_MIDI_MSG_CONTROLLER:
|
||||
sfizz_send_cc(self->synth,
|
||||
(int)ev->time.frames,
|
||||
(int)msg[1],
|
||||
msg[2]);
|
||||
break;
|
||||
break;*/
|
||||
case LV2_MIDI_MSG_CHANNEL_PRESSURE:
|
||||
sfizz_send_aftertouch(self->synth,
|
||||
(int)ev->time.frames,
|
||||
|
|
@ -770,7 +812,7 @@ static void
|
|||
run(LV2_Handle instance, uint32_t sample_count)
|
||||
{
|
||||
sfizz_plugin_t *self = (sfizz_plugin_t *)instance;
|
||||
assert(self->control_port && self->notify_port);
|
||||
assert(self->control_port && self->notify_port && self->automate_port);
|
||||
|
||||
if (!spin_mutex_trylock(self->synth_mutex))
|
||||
{
|
||||
|
|
@ -779,13 +821,18 @@ run(LV2_Handle instance, uint32_t sample_count)
|
|||
return;
|
||||
}
|
||||
|
||||
// Set up forge to write directly to notify output port.
|
||||
// Set up dedicated forges to write on their respective ports.
|
||||
const size_t notify_capacity = self->notify_port->atom.size;
|
||||
lv2_atom_forge_set_buffer(&self->forge, (uint8_t *)self->notify_port, notify_capacity);
|
||||
lv2_atom_forge_set_buffer(&self->forge_notify, (uint8_t *)self->notify_port, notify_capacity);
|
||||
const size_t automate_capacity = self->automate_port->atom.size;
|
||||
lv2_atom_forge_set_buffer(&self->forge_automate, (uint8_t *)self->automate_port, automate_capacity);
|
||||
|
||||
// Start a sequence in the notify output port.
|
||||
// Start sequences in the respective output ports.
|
||||
LV2_Atom_Forge_Frame notify_frame;
|
||||
if (!lv2_atom_forge_sequence_head(&self->forge, ¬ify_frame, 0))
|
||||
if (!lv2_atom_forge_sequence_head(&self->forge_notify, ¬ify_frame, 0))
|
||||
assert(false);
|
||||
LV2_Atom_Forge_Frame automate_frame;
|
||||
if (!lv2_atom_forge_sequence_head(&self->forge_automate, &automate_frame, 0))
|
||||
assert(false);
|
||||
|
||||
LV2_ATOM_SEQUENCE_FOREACH(self->control_port, ev)
|
||||
|
|
@ -796,9 +843,10 @@ run(LV2_Handle instance, uint32_t sample_count)
|
|||
if (ev->body.type == self->atom_object_uri || ev->body.type == self->atom_blank_uri)
|
||||
{
|
||||
const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body;
|
||||
|
||||
if (obj->body.otype == self->patch_set_uri)
|
||||
{
|
||||
sfizz_lv2_handle_atom_object(self, obj);
|
||||
sfizz_lv2_handle_atom_object(self, delay, obj);
|
||||
}
|
||||
else if (obj->body.otype == self->patch_get_uri)
|
||||
{
|
||||
|
|
@ -806,16 +854,25 @@ run(LV2_Handle instance, uint32_t sample_count)
|
|||
lv2_atom_object_get(obj, self->patch_property_uri, &property, 0);
|
||||
if (!property) // Send the full state
|
||||
{
|
||||
sfizz_lv2_send_file_path(self, self->sfizz_sfz_file_uri, self->sfz_file_path);
|
||||
sfizz_lv2_send_file_path(self, self->sfizz_scala_file_uri, self->scala_file_path);
|
||||
sfizz_lv2_send_file_path(self, &self->forge_notify, self->sfizz_sfz_file_uri, self->sfz_file_path);
|
||||
sfizz_lv2_send_file_path(self, &self->forge_notify, self->sfizz_scala_file_uri, self->scala_file_path);
|
||||
|
||||
for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc)
|
||||
sfizz_lv2_send_controller(self, &self->forge_notify, cc, self->cc_current[cc]);
|
||||
}
|
||||
else if (property->body == self->sfizz_sfz_file_uri)
|
||||
{
|
||||
sfizz_lv2_send_file_path(self, self->sfizz_sfz_file_uri, self->sfz_file_path);
|
||||
sfizz_lv2_send_file_path(self, &self->forge_notify, self->sfizz_sfz_file_uri, self->sfz_file_path);
|
||||
}
|
||||
else if (property->body == self->sfizz_scala_file_uri)
|
||||
{
|
||||
sfizz_lv2_send_file_path(self, self->sfizz_scala_file_uri, self->scala_file_path);
|
||||
sfizz_lv2_send_file_path(self, &self->forge_notify, self->sfizz_scala_file_uri, self->scala_file_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
int cc = sfizz_lv2_ccmap_unmap(self->ccmap, property->body);
|
||||
if (cc != -1)
|
||||
sfizz_lv2_send_controller(self, &self->forge_notify, unsigned(cc), self->cc_current[cc]);
|
||||
}
|
||||
}
|
||||
else if (obj->body.otype == self->time_position_uri)
|
||||
|
|
@ -949,17 +1006,29 @@ run(LV2_Handle instance, uint32_t sample_count)
|
|||
sfizz_render_block(self->synth, self->output_buffers, 2, (int)sample_count);
|
||||
|
||||
// Request OSC updates
|
||||
sfizz_send_message(self->synth, self->client, 0, "/cc/changed~", "", nullptr);
|
||||
sfizz_send_message(self->synth, self->client, 0, "/sw/last/current", "", nullptr);
|
||||
|
||||
spin_mutex_unlock(self->synth_mutex);
|
||||
|
||||
if (self->midnam && self->must_update_midnam.exchange(0))
|
||||
{
|
||||
self->midnam->update(self->midnam->handle);
|
||||
}
|
||||
|
||||
lv2_atom_forge_pop(&self->forge, ¬ify_frame);
|
||||
if (self->have_ccauto)
|
||||
{
|
||||
for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) {
|
||||
absl::optional<float> value = self->ccauto[cc];
|
||||
if (value) {
|
||||
sfizz_lv2_send_controller(self, &self->forge_automate, cc, *value);
|
||||
self->ccauto[cc] = absl::nullopt;
|
||||
}
|
||||
}
|
||||
self->have_ccauto = false;
|
||||
}
|
||||
|
||||
spin_mutex_unlock(self->synth_mutex);
|
||||
|
||||
lv2_atom_forge_pop(&self->forge_notify, ¬ify_frame);
|
||||
lv2_atom_forge_pop(&self->forge_automate, &automate_frame);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
|
|
@ -1063,6 +1132,7 @@ sfizz_lv2_update_sfz_info(sfizz_plugin_t *self)
|
|||
{
|
||||
const std::string blob = getDescriptionBlob(self->synth);
|
||||
|
||||
// Update description blob that UI can fetch, thread-safely
|
||||
uint32_t size = uint32_t(blob.size());
|
||||
uint8_t *data = new uint8_t[size];
|
||||
memcpy(data, blob.data(), size);
|
||||
|
|
@ -1075,6 +1145,18 @@ sfizz_lv2_update_sfz_info(sfizz_plugin_t *self)
|
|||
self->sfz_blob_mutex->unlock();
|
||||
|
||||
delete[] old_data;
|
||||
|
||||
//
|
||||
const InstrumentDescription desc = parseDescriptionBlob(blob);
|
||||
for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) {
|
||||
if (desc.ccUsed.test(cc)) {
|
||||
// Mark all the used CCs for automation with default values
|
||||
self->ccauto[cc] = desc.ccDefault[cc];
|
||||
self->have_ccauto = true;
|
||||
// Update the current CCs
|
||||
self->cc_current[cc] = desc.ccDefault[cc];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
@ -1220,6 +1302,17 @@ restore(LV2_Handle instance,
|
|||
self->oversampling = oversampling;
|
||||
}
|
||||
|
||||
// Collect all CC values present in the state
|
||||
std::unique_ptr<absl::optional<float>[]> cc_values(
|
||||
new absl::optional<float>[sfz::config::numCCs]);
|
||||
|
||||
for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) {
|
||||
LV2_URID urid = sfizz_lv2_ccmap_map(self->ccmap, int(cc));
|
||||
value = retrieve(handle, urid, &size, &type, &val_flags);
|
||||
if (value && type == self->atom_float_uri)
|
||||
cc_values[cc] = *(const float *)value;
|
||||
}
|
||||
|
||||
// Sync the parameters to the synth
|
||||
spin_mutex_lock(self->synth_mutex);
|
||||
|
||||
|
|
@ -1258,6 +1351,20 @@ restore(LV2_Handle instance,
|
|||
lv2_log_note(&self->logger, "[sfizz] Restoring the oversampling to %d\n", self->oversampling);
|
||||
sfizz_set_oversampling_factor(self->synth, self->oversampling);
|
||||
|
||||
// Override default automation values with these from the state file
|
||||
for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) {
|
||||
absl::optional<float> value = cc_values[cc];
|
||||
if (value) {
|
||||
// Set CC in the synth
|
||||
sfizz_send_hdcc(self->synth, 0, int(cc), *value);
|
||||
// Mark CCs for automation with state values
|
||||
self->ccauto[cc] = *value;
|
||||
self->have_ccauto = true;
|
||||
// Update the current CCs
|
||||
self->cc_current[cc] = *value;
|
||||
}
|
||||
}
|
||||
|
||||
spin_mutex_unlock(self->synth_mutex);
|
||||
|
||||
return status;
|
||||
|
|
@ -1327,7 +1434,7 @@ save(LV2_Handle instance,
|
|||
&self->num_voices,
|
||||
sizeof(int),
|
||||
self->atom_int_uri,
|
||||
LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
|
||||
LV2_STATE_IS_POD);
|
||||
|
||||
// Save the preload size
|
||||
store(handle,
|
||||
|
|
@ -1335,7 +1442,7 @@ save(LV2_Handle instance,
|
|||
&self->preload_size,
|
||||
sizeof(unsigned int),
|
||||
self->atom_int_uri,
|
||||
LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
|
||||
LV2_STATE_IS_POD);
|
||||
|
||||
// Save the preload size
|
||||
store(handle,
|
||||
|
|
@ -1343,7 +1450,25 @@ save(LV2_Handle instance,
|
|||
&self->oversampling,
|
||||
sizeof(int),
|
||||
self->atom_int_uri,
|
||||
LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
|
||||
LV2_STATE_IS_POD);
|
||||
|
||||
// Save the CCs (used only)
|
||||
self->sfz_blob_mutex->lock();
|
||||
const InstrumentDescription desc = parseDescriptionBlob(
|
||||
absl::string_view((const char*)self->sfz_blob_data, self->sfz_blob_size));
|
||||
self->sfz_blob_mutex->unlock();
|
||||
|
||||
for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) {
|
||||
if (desc.ccUsed.test(cc)) {
|
||||
LV2_URID urid = sfizz_lv2_ccmap_map(self->ccmap, int(cc));
|
||||
store(handle,
|
||||
urid,
|
||||
&self->cc_current[cc],
|
||||
sizeof(float),
|
||||
self->atom_float_uri,
|
||||
LV2_STATE_IS_POD);
|
||||
}
|
||||
}
|
||||
|
||||
return LV2_STATE_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,29 +104,38 @@ midnam:update a lv2:Feature .
|
|||
a lv2:OutputPort, atom:AtomPort ;
|
||||
atom:bufferType atom:Sequence ;
|
||||
atom:supports patch:Message, <@LV2PLUGIN_URI@:OSCBlob> ;
|
||||
lv2:designation lv2:control ;
|
||||
lv2:index 1 ;
|
||||
lv2:symbol "notify" ;
|
||||
lv2:name "Notify",
|
||||
"Notification"@fr ;
|
||||
rsz:minimumSize 65536 ;
|
||||
] , [
|
||||
a lv2:AudioPort, lv2:OutputPort ;
|
||||
a lv2:OutputPort, atom:AtomPort ;
|
||||
atom:bufferType atom:Sequence ;
|
||||
atom:supports patch:Message ;
|
||||
lv2:designation lv2:control ;
|
||||
lv2:index 2 ;
|
||||
lv2:symbol "automate" ;
|
||||
lv2:name "Automate",
|
||||
"Automatisation"@fr ;
|
||||
rsz:minimumSize 65536 ;
|
||||
] , [
|
||||
a lv2:AudioPort, lv2:OutputPort ;
|
||||
lv2:index 3 ;
|
||||
lv2:symbol "out_left" ;
|
||||
lv2:name "Left Output",
|
||||
"Sortie gauche"@fr ,
|
||||
"Uscita Sinistra"@it
|
||||
] , [
|
||||
a lv2:AudioPort, lv2:OutputPort ;
|
||||
lv2:index 3 ;
|
||||
lv2:index 4 ;
|
||||
lv2:symbol "out_right" ;
|
||||
lv2:name "Right Output",
|
||||
"Sortie droite"@fr ,
|
||||
"Uscita Destra"@it
|
||||
] , [
|
||||
a lv2:InputPort, lv2:ControlPort ;
|
||||
lv2:index 4 ;
|
||||
lv2:index 5 ;
|
||||
lv2:symbol "volume" ;
|
||||
lv2:name "Volume" ;
|
||||
lv2:default 0.0 ;
|
||||
|
|
@ -135,7 +144,7 @@ midnam:update a lv2:Feature .
|
|||
units:unit units:db
|
||||
] , [
|
||||
a lv2:InputPort, lv2:ControlPort ;
|
||||
lv2:index 5 ;
|
||||
lv2:index 6 ;
|
||||
lv2:symbol "num_voices" ;
|
||||
lv2:name "Polyphony",
|
||||
"Polyphonie"@fr ,
|
||||
|
|
@ -180,7 +189,7 @@ midnam:update a lv2:Feature .
|
|||
] ;
|
||||
] , [
|
||||
a lv2:InputPort, lv2:ControlPort ;
|
||||
lv2:index 6 ;
|
||||
lv2:index 7 ;
|
||||
lv2:symbol "oversampling" ;
|
||||
lv2:name "Internal oversampling factor",
|
||||
"Facteur de suréchantillonnage interne"@fr ,
|
||||
|
|
@ -215,7 +224,7 @@ midnam:update a lv2:Feature .
|
|||
] ;
|
||||
] , [
|
||||
a lv2:InputPort, lv2:ControlPort ;
|
||||
lv2:index 7 ;
|
||||
lv2:index 8 ;
|
||||
lv2:symbol "preload_size" ;
|
||||
lv2:name "Preload size",
|
||||
"Taille préchargée"@fr ,
|
||||
|
|
@ -258,7 +267,7 @@ midnam:update a lv2:Feature .
|
|||
] ;
|
||||
] , [
|
||||
a lv2:InputPort, lv2:ControlPort ;
|
||||
lv2:index 8 ;
|
||||
lv2:index 9 ;
|
||||
lv2:symbol "freewheeling" ;
|
||||
lv2:name "Freewheeling",
|
||||
"En roue libre (freewheeling)"@fr ,
|
||||
|
|
@ -270,7 +279,7 @@ midnam:update a lv2:Feature .
|
|||
lv2:maximum 1 ;
|
||||
] , [
|
||||
a lv2:InputPort, lv2:ControlPort ;
|
||||
lv2:index 9 ;
|
||||
lv2:index 10 ;
|
||||
lv2:symbol "scala_root_key" ;
|
||||
lv2:name "Scala root key",
|
||||
"Tonalité de base Scala"@fr ,
|
||||
|
|
@ -283,7 +292,7 @@ midnam:update a lv2:Feature .
|
|||
units:unit units:midiNote
|
||||
] , [
|
||||
a lv2:InputPort, lv2:ControlPort ;
|
||||
lv2:index 10 ;
|
||||
lv2:index 11 ;
|
||||
lv2:symbol "tuning_frequency" ;
|
||||
lv2:name "Tuning frequency",
|
||||
"Fréquence d'accordage"@fr ,
|
||||
|
|
@ -295,7 +304,7 @@ midnam:update a lv2:Feature .
|
|||
units:unit units:hz
|
||||
] , [
|
||||
a lv2:InputPort, lv2:ControlPort ;
|
||||
lv2:index 11 ;
|
||||
lv2:index 12 ;
|
||||
lv2:symbol "stretched_tuning" ;
|
||||
lv2:name "Stretched tuning",
|
||||
"Accordage étiré"@fr ,
|
||||
|
|
@ -307,7 +316,7 @@ midnam:update a lv2:Feature .
|
|||
units:unit units:coef
|
||||
] , [
|
||||
a lv2:OutputPort, lv2:ControlPort ;
|
||||
lv2:index 12 ;
|
||||
lv2:index 13 ;
|
||||
lv2:symbol "active_voices" ;
|
||||
lv2:name "Active voices",
|
||||
"Voix utilisées"@fr ;
|
||||
|
|
@ -318,7 +327,7 @@ midnam:update a lv2:Feature .
|
|||
lv2:maximum 256 ;
|
||||
] , [
|
||||
a lv2:OutputPort, lv2:ControlPort ;
|
||||
lv2:index 13 ;
|
||||
lv2:index 14 ;
|
||||
lv2:symbol "num_curves" ;
|
||||
lv2:name "Number of curves",
|
||||
"Nombre de courbes"@fr ;
|
||||
|
|
@ -329,7 +338,7 @@ midnam:update a lv2:Feature .
|
|||
lv2:maximum 65535 ;
|
||||
] , [
|
||||
a lv2:OutputPort, lv2:ControlPort ;
|
||||
lv2:index 14 ;
|
||||
lv2:index 15 ;
|
||||
lv2:symbol "num_masters" ;
|
||||
lv2:name "Number of masters",
|
||||
"Nombre de maîtres"@fr ;
|
||||
|
|
@ -340,7 +349,7 @@ midnam:update a lv2:Feature .
|
|||
lv2:maximum 65535 ;
|
||||
] , [
|
||||
a lv2:OutputPort, lv2:ControlPort ;
|
||||
lv2:index 15 ;
|
||||
lv2:index 16 ;
|
||||
lv2:symbol "num_groups" ;
|
||||
lv2:name "Number of groups",
|
||||
"Nombre de groupes"@fr ;
|
||||
|
|
@ -351,7 +360,7 @@ midnam:update a lv2:Feature .
|
|||
lv2:maximum 65535 ;
|
||||
] , [
|
||||
a lv2:OutputPort, lv2:ControlPort ;
|
||||
lv2:index 16 ;
|
||||
lv2:index 17 ;
|
||||
lv2:symbol "num_regions" ;
|
||||
lv2:name "Number of regions",
|
||||
"Nombre de régions"@fr ;
|
||||
|
|
@ -362,7 +371,7 @@ midnam:update a lv2:Feature .
|
|||
lv2:maximum 65535 ;
|
||||
] , [
|
||||
a lv2:OutputPort, lv2:ControlPort ;
|
||||
lv2:index 17 ;
|
||||
lv2:index 18 ;
|
||||
lv2:symbol "num_samples" ;
|
||||
lv2:name "Number of samples",
|
||||
"Nombre d'échantillons"@fr ;
|
||||
|
|
@ -371,4 +380,6 @@ midnam:update a lv2:Feature .
|
|||
lv2:default 0 ;
|
||||
lv2:minimum 0 ;
|
||||
lv2:maximum 65535 ;
|
||||
] .
|
||||
] ;
|
||||
|
||||
rdfs:seeAlso <controllers.ttl> .
|
||||
|
|
|
|||
|
|
@ -49,22 +49,23 @@ enum
|
|||
{
|
||||
SFIZZ_CONTROL = 0,
|
||||
SFIZZ_NOTIFY = 1,
|
||||
SFIZZ_LEFT = 2,
|
||||
SFIZZ_RIGHT = 3,
|
||||
SFIZZ_VOLUME = 4,
|
||||
SFIZZ_POLYPHONY = 5,
|
||||
SFIZZ_OVERSAMPLING = 6,
|
||||
SFIZZ_PRELOAD = 7,
|
||||
SFIZZ_FREEWHEELING = 8,
|
||||
SFIZZ_SCALA_ROOT_KEY = 9,
|
||||
SFIZZ_TUNING_FREQUENCY = 10,
|
||||
SFIZZ_STRETCH_TUNING = 11,
|
||||
SFIZZ_ACTIVE_VOICES = 12,
|
||||
SFIZZ_NUM_CURVES = 13,
|
||||
SFIZZ_NUM_MASTERS = 14,
|
||||
SFIZZ_NUM_GROUPS = 15,
|
||||
SFIZZ_NUM_REGIONS = 16,
|
||||
SFIZZ_NUM_SAMPLES = 17,
|
||||
SFIZZ_AUTOMATE = 2,
|
||||
SFIZZ_LEFT = 3,
|
||||
SFIZZ_RIGHT = 4,
|
||||
SFIZZ_VOLUME = 5,
|
||||
SFIZZ_POLYPHONY = 6,
|
||||
SFIZZ_OVERSAMPLING = 7,
|
||||
SFIZZ_PRELOAD = 8,
|
||||
SFIZZ_FREEWHEELING = 9,
|
||||
SFIZZ_SCALA_ROOT_KEY = 10,
|
||||
SFIZZ_TUNING_FREQUENCY = 11,
|
||||
SFIZZ_STRETCH_TUNING = 12,
|
||||
SFIZZ_ACTIVE_VOICES = 13,
|
||||
SFIZZ_NUM_CURVES = 14,
|
||||
SFIZZ_NUM_MASTERS = 15,
|
||||
SFIZZ_NUM_GROUPS = 16,
|
||||
SFIZZ_NUM_REGIONS = 17,
|
||||
SFIZZ_NUM_SAMPLES = 18,
|
||||
};
|
||||
|
||||
// For use with instance-access
|
||||
|
|
@ -85,3 +86,14 @@ struct sfizz_plugin_t;
|
|||
bool sfizz_lv2_fetch_description(
|
||||
sfizz_plugin_t *self, const int *serial,
|
||||
uint8_t **descp, uint32_t *sizep, int *serialp);
|
||||
|
||||
// Mapping URID to CC and vice-versa
|
||||
struct sfizz_lv2_ccmap;
|
||||
sfizz_lv2_ccmap *sfizz_lv2_ccmap_create(LV2_URID_Map* map);
|
||||
void sfizz_lv2_ccmap_free(sfizz_lv2_ccmap *ccmap);
|
||||
LV2_URID sfizz_lv2_ccmap_map(const sfizz_lv2_ccmap *ccmap, int cc);
|
||||
int sfizz_lv2_ccmap_unmap(const sfizz_lv2_ccmap *ccmap, LV2_URID urid);
|
||||
|
||||
struct sfizz_lv2_ccmap_delete {
|
||||
void operator()(sfizz_lv2_ccmap* ccmap) const noexcept { sfizz_lv2_ccmap_free(ccmap); }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "sfizz_lv2.h"
|
||||
#include "sfizz_lv2_plugin.h"
|
||||
#include "sfizz/Config.h"
|
||||
|
||||
bool sfizz_lv2_fetch_description(
|
||||
sfizz_plugin_t *self, const int *serial,
|
||||
|
|
@ -29,3 +30,81 @@ bool sfizz_lv2_fetch_description(
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct sfizz_lv2_ccmap {
|
||||
LV2_URID *cc_to_urid;
|
||||
int *urid_to_cc;
|
||||
LV2_URID min_cc_urid;
|
||||
LV2_URID max_cc_urid;
|
||||
};
|
||||
|
||||
sfizz_lv2_ccmap *
|
||||
sfizz_lv2_ccmap_create(LV2_URID_Map* map)
|
||||
{
|
||||
// store the associations between CC number and parameter URID
|
||||
// construct it trivially in the form of a tabulated perfect hash function
|
||||
|
||||
LV2_URID* cc_to_urid = new LV2_URID[sfz::config::numCCs];
|
||||
int* urid_to_cc;
|
||||
int urid_to_cc_size;
|
||||
|
||||
LV2_URID min_cc_urid {};
|
||||
LV2_URID max_cc_urid {};
|
||||
for (int cc = 0; cc < sfz::config::numCCs; ++cc) {
|
||||
char name[256];
|
||||
sprintf(name, SFIZZ_URI "#cc%03d", cc);
|
||||
LV2_URID urid = map->map(map->handle, name);
|
||||
if (cc == 0) {
|
||||
min_cc_urid = urid;
|
||||
max_cc_urid = urid;
|
||||
}
|
||||
else {
|
||||
min_cc_urid = (urid < min_cc_urid) ? urid : min_cc_urid;
|
||||
max_cc_urid = (urid > max_cc_urid) ? urid : max_cc_urid;
|
||||
}
|
||||
cc_to_urid[cc] = urid;
|
||||
}
|
||||
|
||||
urid_to_cc_size = max_cc_urid - min_cc_urid + 1;
|
||||
urid_to_cc = new int[urid_to_cc_size];
|
||||
|
||||
for (int i = 0; i < urid_to_cc_size; ++i)
|
||||
urid_to_cc[i] = -1;
|
||||
|
||||
for (int cc = 0; cc < sfz::config::numCCs; ++cc) {
|
||||
LV2_URID urid = cc_to_urid[cc];
|
||||
urid_to_cc[urid - min_cc_urid] = cc;
|
||||
}
|
||||
|
||||
sfizz_lv2_ccmap *self = new sfizz_lv2_ccmap;
|
||||
self->cc_to_urid = cc_to_urid;
|
||||
self->urid_to_cc = urid_to_cc;
|
||||
self->min_cc_urid = min_cc_urid;
|
||||
self->max_cc_urid = max_cc_urid;
|
||||
return self;
|
||||
}
|
||||
|
||||
void sfizz_lv2_ccmap_free(sfizz_lv2_ccmap *ccmap)
|
||||
{
|
||||
if (ccmap) {
|
||||
delete[] ccmap->cc_to_urid;
|
||||
delete[] ccmap->urid_to_cc;
|
||||
delete ccmap;
|
||||
}
|
||||
}
|
||||
|
||||
LV2_URID sfizz_lv2_ccmap_map(const sfizz_lv2_ccmap *ccmap, int cc)
|
||||
{
|
||||
LV2_URID urid = 0;
|
||||
if (cc >= 0 && cc < sfz::config::numCCs)
|
||||
urid = ccmap->cc_to_urid[cc];
|
||||
return urid;
|
||||
}
|
||||
|
||||
int sfizz_lv2_ccmap_unmap(const sfizz_lv2_ccmap *ccmap, LV2_URID urid)
|
||||
{
|
||||
int cc = -1;
|
||||
if (urid >= ccmap->min_cc_urid && urid <= ccmap->max_cc_urid)
|
||||
cc = ccmap->urid_to_cc[urid - ccmap->min_cc_urid];
|
||||
return cc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <sfizz.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <absl/types/optional.h>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
|
|
@ -31,6 +32,7 @@ struct sfizz_plugin_t
|
|||
// Ports
|
||||
const LV2_Atom_Sequence *control_port {};
|
||||
LV2_Atom_Sequence *notify_port {};
|
||||
LV2_Atom_Sequence *automate_port {};
|
||||
float *output_buffers[2] {};
|
||||
const float *volume_port {};
|
||||
const float *polyphony_port {};
|
||||
|
|
@ -48,7 +50,8 @@ struct sfizz_plugin_t
|
|||
float *num_samples_port {};
|
||||
|
||||
// Atom forge
|
||||
LV2_Atom_Forge forge {}; ///< Forge for writing atoms in run thread
|
||||
LV2_Atom_Forge forge_notify {}; ///< Forge for writing notification atoms in run thread
|
||||
LV2_Atom_Forge forge_automate {}; ///< Forge for writing automation atoms in run thread
|
||||
LV2_Atom_Forge forge_secondary {}; ///< Forge for writing into other buffers
|
||||
|
||||
// Logger
|
||||
|
|
@ -92,6 +95,9 @@ struct sfizz_plugin_t
|
|||
LV2_URID time_beats_per_minute_uri {};
|
||||
LV2_URID time_speed_uri {};
|
||||
|
||||
// CC parameters
|
||||
sfizz_lv2_ccmap* ccmap {};
|
||||
|
||||
// Sfizz related data
|
||||
sfizz_synth_t *synth {};
|
||||
sfizz_client_t *client {};
|
||||
|
|
@ -108,6 +114,7 @@ struct sfizz_plugin_t
|
|||
int sample_counter {};
|
||||
float sample_rate {};
|
||||
std::atomic<int> must_update_midnam {};
|
||||
volatile bool must_automate_cc {};
|
||||
|
||||
// Current instrument description
|
||||
std::mutex *sfz_blob_mutex {};
|
||||
|
|
@ -115,6 +122,14 @@ struct sfizz_plugin_t
|
|||
const uint8_t *volatile sfz_blob_data {};
|
||||
volatile uint32_t sfz_blob_size {};
|
||||
|
||||
// Current CC values in the synth (synchronized by `synth_mutex`)
|
||||
// updated by hdcc or file load
|
||||
float *cc_current {};
|
||||
|
||||
// CC queued for automation on next run(). (synchronized by `synth_mutex`)
|
||||
absl::optional<float>* ccauto {};
|
||||
volatile bool have_ccauto {};
|
||||
|
||||
// Timing data
|
||||
int bar {};
|
||||
double bar_beat {};
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ struct sfizz_ui_t : EditorController, VSTGUIEditorInterface {
|
|||
LV2_Atom_Forge atom_forge;
|
||||
LV2_URID atom_event_transfer_uri;
|
||||
LV2_URID atom_object_uri;
|
||||
LV2_URID atom_float_uri;
|
||||
LV2_URID atom_path_uri;
|
||||
LV2_URID atom_urid_uri;
|
||||
LV2_URID midi_event_uri;
|
||||
|
|
@ -112,6 +113,7 @@ struct sfizz_ui_t : EditorController, VSTGUIEditorInterface {
|
|||
LV2_URID sfizz_sfz_file_uri;
|
||||
LV2_URID sfizz_scala_file_uri;
|
||||
LV2_URID sfizz_osc_blob_uri;
|
||||
std::unique_ptr<sfizz_lv2_ccmap, sfizz_lv2_ccmap_delete> ccmap;
|
||||
|
||||
uint8_t osc_temp[OSC_TEMP_SIZE];
|
||||
alignas(LV2_Atom) uint8_t atom_temp[ATOM_TEMP_SIZE];
|
||||
|
|
@ -201,6 +203,7 @@ instantiate(const LV2UI_Descriptor *descriptor,
|
|||
lv2_atom_forge_init(forge, map);
|
||||
self->atom_event_transfer_uri = map->map(map->handle, LV2_ATOM__eventTransfer);
|
||||
self->atom_object_uri = map->map(map->handle, LV2_ATOM__Object);
|
||||
self->atom_float_uri = map->map(map->handle, LV2_ATOM__Float);
|
||||
self->atom_path_uri = map->map(map->handle, LV2_ATOM__Path);
|
||||
self->atom_urid_uri = map->map(map->handle, LV2_ATOM__URID);
|
||||
self->midi_event_uri = map->map(map->handle, LV2_MIDI__MidiEvent);
|
||||
|
|
@ -211,6 +214,7 @@ instantiate(const LV2UI_Descriptor *descriptor,
|
|||
self->sfizz_sfz_file_uri = map->map(map->handle, SFIZZ__sfzFile);
|
||||
self->sfizz_scala_file_uri = map->map(map->handle, SFIZZ__tuningfile);
|
||||
self->sfizz_osc_blob_uri = map->map(map->handle, SFIZZ__OSCBlob);
|
||||
self->ccmap.reset(sfizz_lv2_ccmap_create(map));
|
||||
|
||||
// set up the resource path
|
||||
// * on Linux, this is determined by going 2 folders back from the SO path
|
||||
|
|
@ -348,7 +352,15 @@ port_event(LV2UI_Handle ui,
|
|||
const LV2_URID prop_uri = reinterpret_cast<const LV2_Atom_URID *>(prop)->body;
|
||||
auto *value_body = reinterpret_cast<const char *>(LV2_ATOM_BODY_CONST(value));
|
||||
|
||||
if (prop_uri == self->sfizz_sfz_file_uri && value->type == self->atom_path_uri) {
|
||||
int cc = sfizz_lv2_ccmap_unmap(self->ccmap.get(), prop_uri);
|
||||
|
||||
if (cc != -1) {
|
||||
if (value->type == self->atom_float_uri) {
|
||||
float ccvalue = *reinterpret_cast<const float*>(value_body);
|
||||
self->uiReceiveValue(editIdForCC(cc), ccvalue);
|
||||
}
|
||||
}
|
||||
else if (prop_uri == self->sfizz_sfz_file_uri && value->type == self->atom_path_uri) {
|
||||
std::string path(value_body, strnlen(value_body, value->size));
|
||||
self->uiReceiveValue(EditId::SfzFile, path);
|
||||
}
|
||||
|
|
@ -525,6 +537,22 @@ void sfizz_ui_t::uiSendValue(EditId id, const EditValue& v)
|
|||
}
|
||||
};
|
||||
|
||||
auto sendController = [this](LV2_URID property, float value) {
|
||||
LV2_Atom_Forge *forge = &atom_forge;
|
||||
LV2_Atom_Forge_Frame frame;
|
||||
auto *atom = reinterpret_cast<const LV2_Atom *>(atom_temp);
|
||||
lv2_atom_forge_set_buffer(forge, atom_temp, sizeof(atom_temp));
|
||||
if (lv2_atom_forge_object(forge, &frame, 0, patch_set_uri) &&
|
||||
lv2_atom_forge_key(forge, patch_property_uri) &&
|
||||
lv2_atom_forge_urid(forge, property) &&
|
||||
lv2_atom_forge_key(forge, patch_value_uri) &&
|
||||
lv2_atom_forge_float(forge, value))
|
||||
{
|
||||
lv2_atom_forge_pop(forge, &frame);
|
||||
write(con, SFIZZ_CONTROL, lv2_atom_total_size(atom), atom_event_transfer_uri, atom);
|
||||
}
|
||||
};
|
||||
|
||||
switch (id) {
|
||||
case EditId::Volume:
|
||||
sendFloat(SFIZZ_VOLUME, v.to_float());
|
||||
|
|
@ -554,6 +582,11 @@ void sfizz_ui_t::uiSendValue(EditId id, const EditValue& v)
|
|||
sendPath(sfizz_scala_file_uri, v.to_string());
|
||||
break;
|
||||
default:
|
||||
if (editIdIsCC(id)) {
|
||||
int cc = ccForEditId(id);
|
||||
LV2_URID urid = sfizz_lv2_ccmap_map(ccmap.get(), cc);
|
||||
sendController(urid, v.to_float());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -329,7 +329,18 @@ void SfizzVstEditor::processNoteEventQueue()
|
|||
///
|
||||
void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v)
|
||||
{
|
||||
if (id == EditId::SfzFile)
|
||||
if (editIdIsCC(id)) {
|
||||
int cc = ccForEditId(id);
|
||||
// TODO(jpc) CC as parameters and automation
|
||||
if (Editor* editor = editor_.get()) {
|
||||
char pathBuf[256];
|
||||
sprintf(pathBuf, "/cc%u/value", cc);
|
||||
sfizz_arg_t args[1];
|
||||
args[0].f = v.to_float();
|
||||
editor->sendQueuedOSC(pathBuf, "f", args);
|
||||
}
|
||||
}
|
||||
else if (id == EditId::SfzFile)
|
||||
loadSfzFile(v.to_string());
|
||||
else if (id == EditId::ScalaFile)
|
||||
loadScalaFile(v.to_string());
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue