Browse Source

Repair tool files after clap experiment

master
Nils 2 months ago
parent
commit
a24ad80e13
  1. 1
      meson.build
  2. 587
      tools/clap-sfzload.c
  3. 1
      tools/sfzload.c
  4. BIN
      tools/sfzload.clap

1
meson.build

@ -162,6 +162,7 @@ executable('sfzload',
install: true,
)
#basename -a *.h
install_headers(
meson.current_build_dir()+'/config.h',

587
tools/clap-sfzload.c

@ -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 <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <calfbox/module.h>
#include <calfbox/engine.h>
#include <calfbox/sampler.h>
#include <calfbox/instr.h>
#include <calfbox/layer.h>
#include <calfbox/scene.h>
#include <calfbox/sfzloader.h>
#include <clap/clap.h>
/////////////////////////////
////////// 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,
};

1
tools/jack-sfzload.c → 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");

BIN
tools/sfzload.clap

Binary file not shown.
Loading…
Cancel
Save