diff --git a/meson.build b/meson.build index 398b164..f750f17 100644 --- a/meson.build +++ b/meson.build @@ -162,6 +162,7 @@ executable('sfzload', install: true, ) + #basename -a *.h install_headers( meson.current_build_dir()+'/config.h', diff --git a/tools/clap-sfzload.c b/tools/clap-sfzload.c deleted file mode 100644 index 26f06a3..0000000 --- a/tools/clap-sfzload.c +++ /dev/null @@ -1,587 +0,0 @@ -// https://github.com/free-audio/clap/blob/main/src/plugin-template.c -//gcc -fPIC -shared -g -Wall -Wextra -Wno-unused-parameter -lcalfbox-lss-static `pkg-config --cflags --libs glib-2.0` -lm -luuid -lsndfile -o sfzload.clap clap-sfzload.c -//gcc -fPIC -shared -g -lcalfbox-lss-static `pkg-config --cflags --libs glib-2.0` -lm -luuid -lsndfile -o sfzload.clap clap-sfzload.c -// Symlink sfzload.clap to ~/.clap - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -///////////////////////////// -////////// CALFBOX ////////// -///////////////////////////// - - -struct cbox_environment -{ - struct cbox_document *document; - struct cbox_engine *engine; - struct cbox_rt *realtime; - struct cbox_io io; - struct cbox_open_params params; - - struct cbox_layer *layer; - struct cbox_scene *scene; - - void *arg; - gchar *context; -}; -struct cbox_environment env; - -struct program_double_buffer -{ - gboolean left_buffer_active; - char directory[PATH_MAX]; - char abs_path[PATH_MAX]; - struct sampler_module * module; - struct sampler_program *pgm_left; - struct sampler_program *pgm_right; - struct sampler_program *pgm_active; -}; -struct program_double_buffer prg_buf; - - -void switch_program_buffer() { - - GError *error = NULL; - if (prg_buf.left_buffer_active) { - //printf("switching to right buffer\n"); - prg_buf.pgm_active = prg_buf.pgm_right; - } - else { - //printf("switching to left buffer\n"); - prg_buf.pgm_active = prg_buf.pgm_left; - } - - sampler_module_load_program_sfz(prg_buf.module, prg_buf.pgm_active, prg_buf.abs_path, 0, &error); //0 means "is from string" - if (error) fprintf(stderr, "Cannot load program from sfz: %s\n", error ? error->message : "unknown error"); - - //Registering programs needs to be done after loading the programs from sfz - sampler_register_program(prg_buf.module, prg_buf.pgm_active); - - sampler_select_program(prg_buf.module, 0, prg_buf.pgm_active->name, &error); - if (error) fprintf(stderr, "Cannot select program: %s\n", error ? error->message : "unknown error"); - - //Setting the channel to a program needs to be done after registering programs - sampler_channel_set_program(&prg_buf.module->channels[0], prg_buf.pgm_active); - - prg_buf.left_buffer_active = !prg_buf.left_buffer_active; - - //Clean inactive buffer and replace with empty one for next switch - if (prg_buf.left_buffer_active) { - //printf("cleaning right buffer\n"); - //CBOX_DELETE(prg_buf.pgm_right); segfault from time to time - prg_buf.pgm_right = sampler_program_new(prg_buf.module, 0, "sfzload_right", NULL, prg_buf.directory, &error); //program number 0. tarfile is NULL. We only give the sample dir here, the actual sfz is in sampler_module_load_program_sfz - if (error) fprintf(stderr, "Cannot create new program: %s\n", error ? error->message : "unknown error"); - - } - else { - //printf("cleaning left buffer\n"); - //CBOX_DELETE(prg_buf.pgm_left); segfault from time to time - prg_buf.pgm_left = sampler_program_new(prg_buf.module, 0, "sfzload_left", NULL, prg_buf.directory, &error); //program number 0. tarfile is NULL. We only give the sample dir here, the actual sfz is in sampler_module_load_program_sfz - if (error) fprintf(stderr, "Cannot create new program: %s\n", error ? error->message : "unknown error"); - } - - if (error) g_error_free(error); - error = NULL; - -} - -gboolean on_idle(struct cbox_command_target *fb, GError **error) -{ - if (env.realtime) - { - // Process results of asynchronous commands - cbox_rt_handle_cmd_queue(env.realtime); - - if (!cbox_midi_appsink_send_to(&env.engine->appsink, fb, error)) - return FALSE; - } - return TRUE; -} - - -void cleanup_resources(struct cbox_environment *env) -{ - if (env == NULL) return; - - printf("Starting cleanup...\n"); - - if (env->realtime) { - cbox_rt_stop(env->realtime); - CBOX_DELETE(env->realtime); - env->realtime = NULL; - } - - if (env->engine) { - CBOX_DELETE(env->engine); - env->engine = NULL; - } - - if (env->document) { - cbox_document_destroy(env->document); - env->document = NULL; - } - - cbox_wavebank_close(); - cbox_config_close(); - - if (env->context) { - g_free(env->context); - env->context = NULL; - } - - printf("Cleanup complete.\n"); -} - -///////////////////////////// -//////////// CLAP /////////// -///////////////////////////// - - - -static const clap_plugin_descriptor_t s_my_plug_desc = { - .clap_version = CLAP_VERSION_INIT, - .id = "org.laborejo.sfzloader", - .name = "SFZ Loader", - .vendor = "Laborejo Software Suite", - .url = "https://git.laborejo.org/lss/libcalfbox-lss", - .manual_url = "https://git.laborejo.org/lss/libcalfbox-lss", - .support_url = "https://laborejo.org/", - .version = "1.0.0", - .description = "Load and play a single SFZ file.", - .features = (const char *[]){CLAP_PLUGIN_FEATURE_INSTRUMENT, CLAP_PLUGIN_FEATURE_STEREO, NULL}, -}; - -typedef struct { - clap_plugin_t plugin; - const clap_host_t *host; - const clap_host_latency_t *host_latency; - const clap_host_log_t *host_log; - const clap_host_thread_check_t *host_thread_check; - const clap_host_state_t *host_state; - float sampleRate; - int midiKey; - - uint32_t latency; -} my_plug_t; - -///////////////////////////// -// clap_plugin_audio_ports // -///////////////////////////// - -static uint32_t my_plug_audio_ports_count(const clap_plugin_t *plugin, bool is_input) { - // We just declare 1 audio input and 1 audio output - return 1; -} - -static bool my_plug_audio_ports_get(const clap_plugin_t *plugin, - uint32_t index, - bool is_input, - clap_audio_port_info_t *info) { - if (index > 0) - return false; - info->id = 0; - snprintf(info->name, sizeof(info->name), "%s", "My Port Name"); - info->channel_count = 2; - info->flags = CLAP_AUDIO_PORT_IS_MAIN; - info->port_type = CLAP_PORT_STEREO; - info->in_place_pair = CLAP_INVALID_ID; - return true; -} - -static const clap_plugin_audio_ports_t s_my_plug_audio_ports = { - .count = my_plug_audio_ports_count, - .get = my_plug_audio_ports_get, -}; - -//////////////////////////// -// clap_plugin_note_ports // -//////////////////////////// - -static uint32_t my_plug_note_ports_count(const clap_plugin_t *plugin, bool is_input) { - // We just declare 1 note input - return 1; -} - -static bool my_plug_note_ports_get(const clap_plugin_t *plugin, - uint32_t index, - bool is_input, - clap_note_port_info_t *info) { - if (index > 0) - return false; - info->id = 0; - snprintf(info->name, sizeof(info->name), "%s", "My Port Name"); - info->supported_dialects = - CLAP_NOTE_DIALECT_CLAP | CLAP_NOTE_DIALECT_MIDI_MPE | CLAP_NOTE_DIALECT_MIDI2; - info->preferred_dialect = CLAP_NOTE_DIALECT_CLAP; - return true; -} - -static const clap_plugin_note_ports_t s_my_plug_note_ports = { - .count = my_plug_note_ports_count, - .get = my_plug_note_ports_get, -}; - -////////////////// -// clap_latency // -////////////////// - -uint32_t my_plug_latency_get(const clap_plugin_t *plugin) { - my_plug_t *plug = plugin->plugin_data; - return plug->latency; -} - -static const clap_plugin_latency_t s_my_plug_latency = { - .get = my_plug_latency_get, -}; - -//////////////// -// clap_state // -//////////////// - -bool my_plug_state_save(const clap_plugin_t *plugin, const clap_ostream_t *stream) { - my_plug_t *plug = plugin->plugin_data; - // TODO: write the state into stream - return true; -} - -bool my_plug_state_load(const clap_plugin_t *plugin, const clap_istream_t *stream) { - my_plug_t *plug = plugin->plugin_data; - // TODO: read the state from stream - return true; -} - -static const clap_plugin_state_t s_my_plug_state = { - .save = my_plug_state_save, - .load = my_plug_state_load, -}; - -///////////////// -// clap_plugin // -///////////////// - -static bool my_plug_init(const struct clap_plugin *plugin) { - my_plug_t *plug = plugin->plugin_data; - - // Fetch host's extensions here - // Make sure to check that the interface functions are not null pointers - plug->host_log = (const clap_host_log_t *)plug->host->get_extension(plug->host, CLAP_EXT_LOG); - plug->host_thread_check = (const clap_host_thread_check_t *)plug->host->get_extension(plug->host, CLAP_EXT_THREAD_CHECK); - plug->host_latency = (const clap_host_latency_t *)plug->host->get_extension(plug->host, CLAP_EXT_LATENCY); - plug->host_state = (const clap_host_state_t *)plug->host->get_extension(plug->host, CLAP_EXT_STATE); - return true; -} - -static void my_plug_destroy(const struct clap_plugin *plugin) { - my_plug_t *plug = plugin->plugin_data; - free(plug); -} - -static bool my_plug_activate(const struct clap_plugin *plugin, - double sample_rate, - uint32_t min_frames_count, - uint32_t max_frames_count) { - - my_plug_t *plug = plugin->plugin_data; - plug->sampleRate = sample_rate; - plug->midiKey = 59; - return true; -} - -static void my_plug_deactivate(const struct clap_plugin *plugin) {} - -static bool my_plug_start_processing(const struct clap_plugin *plugin) { return true; } - -static void my_plug_stop_processing(const struct clap_plugin *plugin) {} - -static void my_plug_reset(const struct clap_plugin *plugin) {} - -static void my_plug_process_event(my_plug_t *plug, const clap_event_header_t *hdr) { - if (hdr->space_id == CLAP_CORE_EVENT_SPACE_ID) { - switch (hdr->type) { - case CLAP_EVENT_NOTE_ON: { - const clap_event_note_t *ev = (const clap_event_note_t *)hdr; - // TODO: handle note on - plug->midiKey = ev->key; - printf("Note On: MIDI Key = %d\n", plug->midiKey); - break; - } - - case CLAP_EVENT_NOTE_OFF: { - const clap_event_note_t *ev = (const clap_event_note_t *)hdr; - // TODO: handle note off - break; - } - - case CLAP_EVENT_NOTE_CHOKE: { - const clap_event_note_t *ev = (const clap_event_note_t *)hdr; - // TODO: handle note choke - break; - } - - case CLAP_EVENT_NOTE_EXPRESSION: { - const clap_event_note_expression_t *ev = (const clap_event_note_expression_t *)hdr; - // TODO: handle note expression - break; - } - - case CLAP_EVENT_PARAM_VALUE: { - const clap_event_param_value_t *ev = (const clap_event_param_value_t *)hdr; - // TODO: handle parameter change - break; - } - - case CLAP_EVENT_PARAM_MOD: { - const clap_event_param_mod_t *ev = (const clap_event_param_mod_t *)hdr; - // TODO: handle parameter modulation - break; - } - - case CLAP_EVENT_TRANSPORT: { - const clap_event_transport_t *ev = (const clap_event_transport_t *)hdr; - // TODO: handle transport event - break; - } - - case CLAP_EVENT_MIDI: { - const clap_event_midi_t *ev = (const clap_event_midi_t *)hdr; - // TODO: handle MIDI event - break; - } - - case CLAP_EVENT_MIDI_SYSEX: { - const clap_event_midi_sysex_t *ev = (const clap_event_midi_sysex_t *)hdr; - // TODO: handle MIDI Sysex event - break; - } - - case CLAP_EVENT_MIDI2: { - const clap_event_midi2_t *ev = (const clap_event_midi2_t *)hdr; - // TODO: handle MIDI2 event - break; - } - } - } -} - - -static double phase = 0.0; - -static clap_process_status my_plug_process(const struct clap_plugin *plugin, - const clap_process_t *process) { - my_plug_t *plug = plugin->plugin_data; - const uint32_t nframes = process->frames_count; - const uint32_t nev = process->in_events->size(process->in_events); - uint32_t ev_index = 0; - uint32_t next_ev_frame = nev > 0 ? 0 : nframes; - - double frequency = 440 * pow(2, (plug->midiKey - 69) / 12.0); - const double phase_step = (2.0 * M_PI * frequency) / plug->sampleRate; - - /* - - for (uint32_t i = 0; i < nframes;) { - // handle every events that happrens at the frame "i" - while (ev_index < nev && next_ev_frame == i) { - const clap_event_header_t *hdr = process->in_events->get(process->in_events, ev_index); - if (hdr->time != i) { - next_ev_frame = hdr->time; - break; - } - - my_plug_process_event(plug, hdr); - ++ev_index; - - if (ev_index == nev) { - // we reached the end of the event list - next_ev_frame = nframes; - break; - } - } - - // process every samples until the next event - for (; i < next_ev_frame; ++i) { - // fetch input samples - const float in_l = process->audio_inputs[0].data32[0][i]; - const float in_r = process->audio_inputs[0].data32[1][i]; - - // TODO: process samples, here we simply swap left and right channels - const float out_l = in_r; - const float out_r = in_l; - - // store output samples - process->audio_outputs[0].data32[0][i] = out_l; - process->audio_outputs[0].data32[1][i] = out_r; - } - } - */ - - for (uint32_t i = 0; i < nframes; ++i) { - // handle every events that happens at the frame "i" - while (ev_index < nev && next_ev_frame == i) { - const clap_event_header_t *hdr = process->in_events->get(process->in_events, ev_index); - if (hdr->time != i) { - next_ev_frame = hdr->time; - break; - } - - my_plug_process_event(plug, hdr); - ++ev_index; - - if (ev_index == nev) { - // we reached the end of the event list - next_ev_frame = nframes; - break; - } - } - - // Generate and output the sine wave - float sample = sin(phase); - phase += phase_step; - if (phase >= 2.0 * M_PI) phase -= 2.0 * M_PI; - - // Output the same sine wave on both left and right channels - process->audio_outputs[0].data32[0][i] = sample * 0.5; // Left channel - process->audio_outputs[0].data32[1][i] = sample * 0.5; // Right channel - } - - - return CLAP_PROCESS_CONTINUE; -} - -static const void *my_plug_get_extension(const struct clap_plugin *plugin, const char *id) { - if (!strcmp(id, CLAP_EXT_LATENCY)) - return &s_my_plug_latency; - if (!strcmp(id, CLAP_EXT_AUDIO_PORTS)) - return &s_my_plug_audio_ports; - if (!strcmp(id, CLAP_EXT_NOTE_PORTS)) - return &s_my_plug_note_ports; - if (!strcmp(id, CLAP_EXT_STATE)) - return &s_my_plug_state; - // TODO: add support to CLAP_EXT_PARAMS - return NULL; -} - -static void my_plug_on_main_thread(const struct clap_plugin *plugin) {} - -clap_plugin_t *my_plug_create(const clap_host_t *host) { - my_plug_t *p = calloc(1, sizeof(*p)); - p->host = host; - p->plugin.desc = &s_my_plug_desc; - p->plugin.plugin_data = p; - p->plugin.init = my_plug_init; - p->plugin.destroy = my_plug_destroy; - p->plugin.activate = my_plug_activate; - p->plugin.deactivate = my_plug_deactivate; - p->plugin.start_processing = my_plug_start_processing; - p->plugin.stop_processing = my_plug_stop_processing; - p->plugin.reset = my_plug_reset; - p->plugin.process = my_plug_process; - p->plugin.get_extension = my_plug_get_extension; - p->plugin.on_main_thread = my_plug_on_main_thread; - - // Don't call into the host here - - return &p->plugin; -} - -///////////////////////// -// clap_plugin_factory // -///////////////////////// - -static struct { - const clap_plugin_descriptor_t *desc; - clap_plugin_t *(CLAP_ABI *create)(const clap_host_t *host); -} s_plugins[] = { - { - .desc = &s_my_plug_desc, - .create = my_plug_create, - }, -}; - -static uint32_t plugin_factory_get_plugin_count(const struct clap_plugin_factory *factory) { - return sizeof(s_plugins) / sizeof(s_plugins[0]); -} - -static const clap_plugin_descriptor_t * -plugin_factory_get_plugin_descriptor(const struct clap_plugin_factory *factory, uint32_t index) { - return s_plugins[index].desc; -} - -static const clap_plugin_t *plugin_factory_create_plugin(const struct clap_plugin_factory *factory, - const clap_host_t *host, - const char *plugin_id) { - if (!clap_version_is_compatible(host->clap_version)) { - return NULL; - } - - const int N = sizeof(s_plugins) / sizeof(s_plugins[0]); - for (int i = 0; i < N; ++i) - if (!strcmp(plugin_id, s_plugins[i].desc->id)) - return s_plugins[i].create(host); - - return NULL; -} - -static const clap_plugin_factory_t s_plugin_factory = { - .get_plugin_count = plugin_factory_get_plugin_count, - .get_plugin_descriptor = plugin_factory_get_plugin_descriptor, - .create_plugin = plugin_factory_create_plugin, -}; - -//////////////// -// clap_entry // -//////////////// - -static bool entry_init(const char *plugin_path) { - // called only once, and very first - - cbox_dom_init(); - - env.document = cbox_document_new(); - env.realtime = cbox_rt_new(env.document); - env.engine = cbox_engine_new(env.document, env.realtime); - env.context = NULL; - env.realtime->engine = env.engine; //inject engine into realtime struct - - cbox_config_init(""); - - //Autoconnect our jack outputs to system out - cbox_config_set_string("io", "out_1", "#1"); - cbox_config_set_string("io", "out_2", "#2"); - cbox_config_set_string("io", "midi", "*a2j:.*"); - cbox_config_set_string("io", "client_name", "sfzload"); - cbox_config_set_int("io", "enable_common_midi_input", 1); //last is a bool. This is the default, let's call it anyway. - - return true; -} - -static void entry_deinit(void) { - // called before unloading the DSO -} - -static const void *entry_get_factory(const char *factory_id) { - if (!strcmp(factory_id, CLAP_PLUGIN_FACTORY_ID)) - return &s_plugin_factory; - return NULL; -} - -// This symbol will be resolved by the host -CLAP_EXPORT const clap_plugin_entry_t clap_entry = { - .clap_version = CLAP_VERSION_INIT, - .init = entry_init, - .deinit = entry_deinit, - .get_factory = entry_get_factory, -}; diff --git a/tools/jack-sfzload.c b/tools/sfzload.c similarity index 99% rename from tools/jack-sfzload.c rename to tools/sfzload.c index 8f9bb21..8736ca7 100644 --- a/tools/jack-sfzload.c +++ b/tools/sfzload.c @@ -457,6 +457,7 @@ int main(int argc, char *argv[]) cbox_config_set_string("io", "midi", "*a2j:.*"); cbox_config_set_string("io", "client_name", "sfzload"); cbox_config_set_int("io", "enable_common_midi_input", 1); //last is a bool. This is the default, let's call it anyway. + cbox_config_set_int("sampler", "disable_mixer_controls", 1); //Ignore CC7 Volume and CC10 Pan so that SFZ can use these CCs themselves. printf("Create JACK Client\n"); diff --git a/tools/sfzload.clap b/tools/sfzload.clap deleted file mode 100755 index 812e62f..0000000 Binary files a/tools/sfzload.clap and /dev/null differ