Build LV2 with C++

This commit is contained in:
Jean Pierre Cimalando 2021-02-08 16:31:12 +01:00
parent f6d92916ae
commit af551ab96f
3 changed files with 139 additions and 201 deletions

View file

@ -19,8 +19,7 @@ source_group("Turtle Files" FILES
${LV2PLUGIN_TTL_SRC_FILES} ${LV2PLUGIN_TTL_SRC_FILES}
) )
add_library(${LV2PLUGIN_PRJ_NAME} MODULE add_library(${LV2PLUGIN_PRJ_NAME} MODULE
${PROJECT_NAME}.c ${PROJECT_NAME}.cpp
atomic_compat.h
${LV2PLUGIN_TTL_SRC_FILES}) ${LV2PLUGIN_TTL_SRC_FILES})
target_link_libraries(${LV2PLUGIN_PRJ_NAME} PRIVATE sfizz::sfizz sfizz::spin_mutex) target_link_libraries(${LV2PLUGIN_PRJ_NAME} PRIVATE sfizz::sfizz sfizz::spin_mutex)

View file

@ -1,64 +0,0 @@
/*
SPDX-License-Identifier: ISC
Sfizz LV2 plugin
Copyright 2019-2020, Paul Ferrand <paul@ferrand.cc>
This file was based on skeleton and example code from the LV2 plugin
distribution available at http://lv2plug.in/
The LV2 sample plugins have the following copyright and notice, which are
extended to the current work:
Copyright 2011-2016 David Robillard <d@drobilla.net>
Copyright 2011 Gabriel M. Beddingfield <gabriel@teuton.org>
Copyright 2011 James Morris <jwm.art.net@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
Compiling this plugin statically against libsndfile implies distributing it
under the terms of the LGPL v3 license. See the LICENSE.md file for more
information. If you did not receive a LICENSE.md file, inform the current
maintainer.
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#if defined(__cplusplus)
#include <atomic>
#elif defined(_MSC_VER)
#include <intrin.h>
typedef volatile int atomic_int;
inline int atomic_exchange(atomic_int *d, int x)
{
return _InterlockedExchange((volatile long *)d, (long)x);
}
inline void atomic_store(atomic_int *d, int x)
{
_InterlockedExchange((volatile long *)d, (long)x);
}
inline int atomic_load(const atomic_int *d)
{
return _InterlockedOr((volatile long *)d, 0);
}
#else
#include <stdatomic.h>
#endif

View file

@ -61,7 +61,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "atomic_compat.h" #include <atomic>
#define CHANNEL_MASK 0x0F #define CHANNEL_MASK 0x0F
#define MIDI_CHANNEL(byte) (byte & CHANNEL_MASK) #define MIDI_CHANNEL(byte) (byte & CHANNEL_MASK)
@ -86,110 +86,110 @@
#define LV2_DEBUG(...) #define LV2_DEBUG(...)
#endif #endif
typedef struct struct sfizz_plugin_t
{ {
// Features // Features
LV2_URID_Map *map; LV2_URID_Map *map {};
LV2_URID_Unmap *unmap; LV2_URID_Unmap *unmap {};
LV2_Worker_Schedule *worker; LV2_Worker_Schedule *worker {};
LV2_Log_Log *log; LV2_Log_Log *log {};
LV2_Midnam *midnam; LV2_Midnam *midnam {};
// Ports // Ports
const LV2_Atom_Sequence *control_port; const LV2_Atom_Sequence *control_port {};
LV2_Atom_Sequence *notify_port; LV2_Atom_Sequence *notify_port {};
float *output_buffers[2]; float *output_buffers[2] {};
const float *volume_port; const float *volume_port {};
const float *polyphony_port; const float *polyphony_port {};
const float *oversampling_port; const float *oversampling_port {};
const float *preload_port; const float *preload_port {};
const float *freewheel_port; const float *freewheel_port {};
const float *scala_root_key_port; const float *scala_root_key_port {};
const float *tuning_frequency_port; const float *tuning_frequency_port {};
const float *stretch_tuning_port; const float *stretch_tuning_port {};
float *active_voices_port; float *active_voices_port {};
float *num_curves_port; float *num_curves_port {};
float *num_masters_port; float *num_masters_port {};
float *num_groups_port; float *num_groups_port {};
float *num_regions_port; float *num_regions_port {};
float *num_samples_port; float *num_samples_port {};
// Atom forge // Atom forge
LV2_Atom_Forge forge; ///< Forge for writing atoms in run thread LV2_Atom_Forge forge {}; ///< Forge for writing atoms in run thread
LV2_Atom_Forge forge_secondary; ///< Forge for writing into other buffers LV2_Atom_Forge forge_secondary {}; ///< Forge for writing into other buffers
// Logger // Logger
LV2_Log_Logger logger; LV2_Log_Logger logger {};
// URIs // URIs
LV2_URID midi_event_uri; LV2_URID midi_event_uri {};
LV2_URID options_interface_uri; LV2_URID options_interface_uri {};
LV2_URID max_block_length_uri; LV2_URID max_block_length_uri {};
LV2_URID nominal_block_length_uri; LV2_URID nominal_block_length_uri {};
LV2_URID sample_rate_uri; LV2_URID sample_rate_uri {};
LV2_URID atom_object_uri; LV2_URID atom_object_uri {};
LV2_URID atom_blank_uri; LV2_URID atom_blank_uri {};
LV2_URID atom_float_uri; LV2_URID atom_float_uri {};
LV2_URID atom_double_uri; LV2_URID atom_double_uri {};
LV2_URID atom_int_uri; LV2_URID atom_int_uri {};
LV2_URID atom_long_uri; LV2_URID atom_long_uri {};
LV2_URID atom_urid_uri; LV2_URID atom_urid_uri {};
LV2_URID atom_path_uri; LV2_URID atom_path_uri {};
LV2_URID patch_set_uri; LV2_URID patch_set_uri {};
LV2_URID patch_get_uri; LV2_URID patch_get_uri {};
LV2_URID patch_put_uri; LV2_URID patch_put_uri {};
LV2_URID patch_property_uri; LV2_URID patch_property_uri {};
LV2_URID patch_value_uri; LV2_URID patch_value_uri {};
LV2_URID patch_body_uri; LV2_URID patch_body_uri {};
LV2_URID state_changed_uri; LV2_URID state_changed_uri {};
LV2_URID sfizz_sfz_file_uri; LV2_URID sfizz_sfz_file_uri {};
LV2_URID sfizz_scala_file_uri; LV2_URID sfizz_scala_file_uri {};
LV2_URID sfizz_num_voices_uri; LV2_URID sfizz_num_voices_uri {};
LV2_URID sfizz_preload_size_uri; LV2_URID sfizz_preload_size_uri {};
LV2_URID sfizz_oversampling_uri; LV2_URID sfizz_oversampling_uri {};
LV2_URID sfizz_log_status_uri; LV2_URID sfizz_log_status_uri {};
LV2_URID sfizz_check_modification_uri; LV2_URID sfizz_check_modification_uri {};
LV2_URID sfizz_active_voices_uri; LV2_URID sfizz_active_voices_uri {};
LV2_URID sfizz_osc_blob_uri; LV2_URID sfizz_osc_blob_uri {};
LV2_URID time_position_uri; LV2_URID time_position_uri {};
LV2_URID time_bar_uri; LV2_URID time_bar_uri {};
LV2_URID time_bar_beat_uri; LV2_URID time_bar_beat_uri {};
LV2_URID time_beat_unit_uri; LV2_URID time_beat_unit_uri {};
LV2_URID time_beats_per_bar_uri; LV2_URID time_beats_per_bar_uri {};
LV2_URID time_beats_per_minute_uri; LV2_URID time_beats_per_minute_uri {};
LV2_URID time_speed_uri; LV2_URID time_speed_uri {};
// Sfizz related data // Sfizz related data
sfizz_synth_t *synth; sfizz_synth_t *synth {};
sfizz_client_t *client; sfizz_client_t *client {};
spin_mutex_t *synth_mutex; spin_mutex_t *synth_mutex {};
bool expect_nominal_block_length; bool expect_nominal_block_length {};
char sfz_file_path[MAX_PATH_SIZE]; char sfz_file_path[MAX_PATH_SIZE] {};
char scala_file_path[MAX_PATH_SIZE]; char scala_file_path[MAX_PATH_SIZE] {};
int num_voices; int num_voices {};
unsigned int preload_size; unsigned int preload_size {};
sfizz_oversampling_factor_t oversampling; sfizz_oversampling_factor_t oversampling {};
float stretch_tuning; float stretch_tuning {};
volatile bool check_modification; volatile bool check_modification {};
int max_block_size; int max_block_size {};
int sample_counter; int sample_counter {};
float sample_rate; float sample_rate {};
atomic_int must_update_midnam; std::atomic<int> must_update_midnam {};
// Timing data // Timing data
int bar; int bar {};
double bar_beat; double bar_beat {};
int beats_per_bar; int beats_per_bar {};
int beat_unit; int beat_unit {};
double bpm_tempo; double bpm_tempo {};
double speed; double speed {};
// Paths // Paths
char bundle_path[MAX_BUNDLE_PATH_SIZE]; char bundle_path[MAX_BUNDLE_PATH_SIZE] {};
// OSC // OSC
uint8_t osc_temp[OSC_TEMP_SIZE]; uint8_t osc_temp[OSC_TEMP_SIZE] {};
} sfizz_plugin_t; };
enum enum
{ {
@ -209,8 +209,8 @@ sfizz_lv2_state_free_path(LV2_State_Free_Path_Handle handle,
static LV2_State_Free_Path sfizz_State_Free_Path = static LV2_State_Free_Path sfizz_State_Free_Path =
{ {
.handle = NULL, NULL,
.free_path = &sfizz_lv2_state_free_path, &sfizz_lv2_state_free_path,
}; };
static void static void
@ -467,7 +467,7 @@ instantiate(const LV2_Descriptor *descriptor,
bool supports_fixed_block_size = false; bool supports_fixed_block_size = false;
// Allocate and initialise instance structure. // Allocate and initialise instance structure.
sfizz_plugin_t *self = (sfizz_plugin_t *)calloc(1, sizeof(sfizz_plugin_t)); sfizz_plugin_t *self = new sfizz_plugin_t;
if (!self) if (!self)
return NULL; return NULL;
@ -500,31 +500,34 @@ instantiate(const LV2_Descriptor *descriptor,
// Get the features from the host and populate the structure // Get the features from the host and populate the structure
for (const LV2_Feature *const *f = features; *f; f++) for (const LV2_Feature *const *f = features; *f; f++)
{ {
const char *uri = (**f).URI;
void *data = (**f).data;
// lv2_log_note(&self->logger, "Feature URI: %s\n", (**f).URI); // lv2_log_note(&self->logger, "Feature URI: %s\n", (**f).URI);
if (!strcmp((**f).URI, LV2_URID__map)) if (!strcmp(uri, LV2_URID__map))
self->map = (**f).data; self->map = (LV2_URID_Map *)data;
if (!strcmp((**f).URI, LV2_URID__unmap)) if (!strcmp(uri, LV2_URID__unmap))
self->unmap = (**f).data; self->unmap = (LV2_URID_Unmap *)data;
if (!strcmp((**f).URI, LV2_BUF_SIZE__boundedBlockLength)) if (!strcmp(uri, LV2_BUF_SIZE__boundedBlockLength))
supports_bounded_block_size = true; supports_bounded_block_size = true;
if (!strcmp((**f).URI, LV2_BUF_SIZE__fixedBlockLength)) if (!strcmp(uri, LV2_BUF_SIZE__fixedBlockLength))
supports_fixed_block_size = true; supports_fixed_block_size = true;
if (!strcmp((**f).URI, LV2_OPTIONS__options)) if (!strcmp(uri, LV2_OPTIONS__options))
options = (**f).data; options = (LV2_Options_Option *)data;
if (!strcmp((**f).URI, LV2_WORKER__schedule)) if (!strcmp(uri, LV2_WORKER__schedule))
self->worker = (**f).data; self->worker = (LV2_Worker_Schedule *)data;
if (!strcmp((**f).URI, LV2_LOG__log)) if (!strcmp(uri, LV2_LOG__log))
self->log = (**f).data; self->log = (LV2_Log_Log *)data;
if (!strcmp((**f).URI, LV2_MIDNAM__update)) if (!strcmp(uri, LV2_MIDNAM__update))
self->midnam = (**f).data; self->midnam = (LV2_Midnam *)data;
} }
// Setup the loggers // Setup the loggers
@ -534,7 +537,7 @@ instantiate(const LV2_Descriptor *descriptor,
if (!self->map) if (!self->map)
{ {
lv2_log_error(&self->logger, "Map feature not found, aborting..\n"); lv2_log_error(&self->logger, "Map feature not found, aborting..\n");
free(self); delete self;
return NULL; return NULL;
} }
@ -542,7 +545,7 @@ instantiate(const LV2_Descriptor *descriptor,
if (!self->worker) if (!self->worker)
{ {
lv2_log_error(&self->logger, "Worker feature not found, aborting..\n"); lv2_log_error(&self->logger, "Worker feature not found, aborting..\n");
free(self); delete self;
return NULL; return NULL;
} }
@ -596,7 +599,7 @@ instantiate(const LV2_Descriptor *descriptor,
{ {
lv2_log_error(&self->logger, lv2_log_error(&self->logger,
"Bounded block size not supported and options gave no block size, aborting..\n"); "Bounded block size not supported and options gave no block size, aborting..\n");
free(self); delete self;
return NULL; return NULL;
} }
@ -624,7 +627,7 @@ cleanup(LV2_Handle instance)
spin_mutex_destroy(self->synth_mutex); spin_mutex_destroy(self->synth_mutex);
sfizz_delete_client(self->client); sfizz_delete_client(self->client);
sfizz_free(self->synth); sfizz_free(self->synth);
free(self); delete self;
} }
static void static void
@ -633,7 +636,7 @@ activate(LV2_Handle instance)
sfizz_plugin_t *self = (sfizz_plugin_t *)instance; sfizz_plugin_t *self = (sfizz_plugin_t *)instance;
sfizz_set_samples_per_block(self->synth, self->max_block_size); sfizz_set_samples_per_block(self->synth, self->max_block_size);
sfizz_set_sample_rate(self->synth, self->sample_rate); sfizz_set_sample_rate(self->synth, self->sample_rate);
atomic_store(&self->must_update_midnam, 1); self->must_update_midnam.store(1);
} }
static void static void
@ -703,7 +706,9 @@ sfizz_lv2_handle_atom_object(sfizz_plugin_t *self, const LV2_Atom_Object *obj)
LV2_Atom_Forge *forge = &self->forge_secondary; LV2_Atom_Forge *forge = &self->forge_secondary;
sfizz_path_atom_buffer_t buffer; sfizz_path_atom_buffer_t buffer;
lv2_atom_forge_set_buffer(forge, (uint8_t *)&buffer, sizeof(buffer)); lv2_atom_forge_set_buffer(forge, (uint8_t *)&buffer, sizeof(buffer));
if (lv2_atom_forge_typed_string(forge, self->sfizz_sfz_file_uri, LV2_ATOM_BODY_CONST(atom), strnlen(LV2_ATOM_BODY_CONST(atom), atom->size))) const char *body = (const char *)LV2_ATOM_BODY_CONST(atom);
uint32_t size = (uint32_t)strnlen(body, atom->size);
if (lv2_atom_forge_typed_string(forge, self->sfizz_sfz_file_uri, body, size))
self->worker->schedule_work(self->worker->handle, lv2_atom_total_size(&buffer.atom), &buffer.atom); self->worker->schedule_work(self->worker->handle, lv2_atom_total_size(&buffer.atom), &buffer.atom);
self->check_modification = false; self->check_modification = false;
} }
@ -712,7 +717,9 @@ sfizz_lv2_handle_atom_object(sfizz_plugin_t *self, const LV2_Atom_Object *obj)
LV2_Atom_Forge *forge = &self->forge_secondary; LV2_Atom_Forge *forge = &self->forge_secondary;
sfizz_path_atom_buffer_t buffer; sfizz_path_atom_buffer_t buffer;
lv2_atom_forge_set_buffer(forge, (uint8_t *)&buffer, sizeof(buffer)); lv2_atom_forge_set_buffer(forge, (uint8_t *)&buffer, sizeof(buffer));
if (lv2_atom_forge_typed_string(forge, self->sfizz_scala_file_uri, LV2_ATOM_BODY_CONST(atom), strnlen(LV2_ATOM_BODY_CONST(atom), atom->size))) const char *body = (const char *)LV2_ATOM_BODY_CONST(atom);
uint32_t size = (uint32_t)strnlen(body, atom->size);
if (lv2_atom_forge_typed_string(forge, self->sfizz_scala_file_uri, body, size))
self->worker->schedule_work(self->worker->handle, lv2_atom_total_size(&buffer.atom), &buffer.atom); self->worker->schedule_work(self->worker->handle, lv2_atom_total_size(&buffer.atom), &buffer.atom);
self->check_modification = false; self->check_modification = false;
} }
@ -798,11 +805,10 @@ sfizz_lv2_check_oversampling(sfizz_plugin_t* self)
self->oversampling = (sfizz_oversampling_factor_t)port_value; self->oversampling = (sfizz_oversampling_factor_t)port_value;
LV2_Atom_Int atom = { LV2_Atom_Int atom;
.atom.type = self->sfizz_oversampling_uri, atom.atom.type = self->sfizz_oversampling_uri;
.atom.size = sizeof(int), atom.atom.size = sizeof(int);
.body = self->oversampling atom.body = self->oversampling;
};
if (self->worker->schedule_work(self->worker->handle, if (self->worker->schedule_work(self->worker->handle,
lv2_atom_total_size((LV2_Atom *)&atom), lv2_atom_total_size((LV2_Atom *)&atom),
&atom) != LV2_WORKER_SUCCESS) &atom) != LV2_WORKER_SUCCESS)
@ -817,11 +823,10 @@ sfizz_lv2_check_preload_size(sfizz_plugin_t* self)
unsigned int preload_size = (int)*self->preload_port; unsigned int preload_size = (int)*self->preload_port;
if (preload_size != self->preload_size) if (preload_size != self->preload_size)
{ {
LV2_Atom_Int atom = { LV2_Atom_Int atom;
.atom.type = self->sfizz_preload_size_uri, atom.atom.type = self->sfizz_preload_size_uri;
.atom.size = sizeof(int), atom.atom.size = sizeof(int);
.body = preload_size atom.body = preload_size;
};
if (self->worker->schedule_work(self->worker->handle, if (self->worker->schedule_work(self->worker->handle,
lv2_atom_total_size((LV2_Atom *)&atom), lv2_atom_total_size((LV2_Atom *)&atom),
&atom) != LV2_WORKER_SUCCESS) &atom) != LV2_WORKER_SUCCESS)
@ -838,11 +843,10 @@ sfizz_lv2_check_num_voices(sfizz_plugin_t* self)
int num_voices = (int)*self->polyphony_port; int num_voices = (int)*self->polyphony_port;
if (num_voices != self->num_voices) if (num_voices != self->num_voices)
{ {
LV2_Atom_Int atom = { LV2_Atom_Int atom;
.atom.type = self->sfizz_num_voices_uri, atom.atom.type = self->sfizz_num_voices_uri;
.atom.size = sizeof(int), atom.atom.size = sizeof(int);
.body = num_voices atom.body = num_voices;
};
if (self->worker->schedule_work(self->worker->handle, if (self->worker->schedule_work(self->worker->handle,
lv2_atom_total_size((LV2_Atom *)&atom), lv2_atom_total_size((LV2_Atom *)&atom),
&atom) != LV2_WORKER_SUCCESS) &atom) != LV2_WORKER_SUCCESS)
@ -1061,7 +1065,7 @@ run(LV2_Handle instance, uint32_t sample_count)
spin_mutex_unlock(self->synth_mutex); spin_mutex_unlock(self->synth_mutex);
if (self->midnam && atomic_exchange(&self->must_update_midnam, 0)) if (self->midnam && self->must_update_midnam.exchange(0))
{ {
self->midnam->update(self->midnam->handle); self->midnam->update(self->midnam->handle);
} }
@ -1162,7 +1166,7 @@ sfizz_lv2_update_file_info(sfizz_plugin_t* self, const char *file_path)
lv2_log_note(&self->logger, "[sfizz] Number of groups: %d\n", sfizz_get_num_groups(self->synth)); lv2_log_note(&self->logger, "[sfizz] Number of groups: %d\n", sfizz_get_num_groups(self->synth));
lv2_log_note(&self->logger, "[sfizz] Number of regions: %d\n", sfizz_get_num_regions(self->synth)); lv2_log_note(&self->logger, "[sfizz] Number of regions: %d\n", sfizz_get_num_regions(self->synth));
atomic_store(&self->must_update_midnam, 1); self->must_update_midnam.store(1);
} }
static bool static bool
@ -1415,10 +1419,9 @@ sfizz_lv2_activate_file_checking(
LV2_Worker_Respond_Function respond, LV2_Worker_Respond_Function respond,
LV2_Worker_Respond_Handle handle) LV2_Worker_Respond_Handle handle)
{ {
LV2_Atom check_modification_atom = { LV2_Atom check_modification_atom;
.size = 0, check_modification_atom.size = 0;
.type = self->sfizz_check_modification_uri check_modification_atom.type = self->sfizz_check_modification_uri;
};
respond(handle, lv2_atom_total_size(&check_modification_atom), &check_modification_atom); respond(handle, lv2_atom_total_size(&check_modification_atom), &check_modification_atom);
} }
@ -1440,7 +1443,7 @@ work(LV2_Handle instance,
const LV2_Atom *atom = (const LV2_Atom *)data; const LV2_Atom *atom = (const LV2_Atom *)data;
if (atom->type == self->sfizz_sfz_file_uri) if (atom->type == self->sfizz_sfz_file_uri)
{ {
const char *sfz_file_path = LV2_ATOM_BODY_CONST(atom); const char *sfz_file_path = (const char *)LV2_ATOM_BODY_CONST(atom);
spin_mutex_lock(self->synth_mutex); spin_mutex_lock(self->synth_mutex);
bool success = sfizz_lv2_load_file(self, sfz_file_path); bool success = sfizz_lv2_load_file(self, sfz_file_path);
@ -1456,7 +1459,7 @@ work(LV2_Handle instance,
} }
else if (atom->type == self->sfizz_scala_file_uri) else if (atom->type == self->sfizz_scala_file_uri)
{ {
const char *scala_file_path = LV2_ATOM_BODY_CONST(atom); const char *scala_file_path = (const char *)LV2_ATOM_BODY_CONST(atom);
spin_mutex_lock(self->synth_mutex); spin_mutex_lock(self->synth_mutex);
bool success = sfizz_lv2_load_scala_file(self, scala_file_path); bool success = sfizz_lv2_load_scala_file(self, scala_file_path);
@ -1600,7 +1603,7 @@ work_response(LV2_Handle instance,
static char * static char *
midnam_model(LV2_Handle instance) midnam_model(LV2_Handle instance)
{ {
char *model = malloc(64); char *model = (char *)malloc(64);
if (!model) if (!model)
return NULL; return NULL;