commit 60d4e1206803b32a229d5fc99ea3d1e2fba89a58
parent 0bbf5e081ea63220842b03135adaedd38f4ffc4b
Author: Alexandre Bique <bique.alexandre@gmail.com>
Date: Thu, 20 Nov 2014 02:24:52 +0100
Started a jack host
Diffstat:
8 files changed, 339 insertions(+), 68 deletions(-)
diff --git a/examples/thyns/plugin.c b/examples/thyns/plugin.c
@@ -9,7 +9,6 @@ struct thyns_plugin
{
struct thyns thyns;
struct clap_plugin plugin;
- struct clap_plugin_ports ports;
struct clap_host *host;
};
@@ -56,71 +55,28 @@ thyns_plugin_get_attribute(struct clap_plugin *plugin,
#undef attr
}
-uint32_t
-thyns_plugin_get_ports_configs_count(struct clap_plugin *plugin)
+enum clap_process_status
+thyns_plugin_process(struct clap_plugin *plugin,
+ struct clap_process *process)
{
- return 1;
+ return thyns_process(plugin->plugin_data, process);
}
-bool
-thyns_plugin_get_ports_config(struct clap_plugin *plugin,
- uint32_t config_index,
- struct clap_ports_config *config)
+void *
+thyns_plugin_extension(struct clap_plugin *plugin, const char *extension)
{
- switch (config_index) {
- case 0:
- snprintf(config->name, sizeof (config->name), "mono");
- config->inputs_count = 0;
- config->outputs_count = 1;
- return true;
-
- default:
- return false;
- }
+ return NULL;
}
bool
-thyns_plugin_get_port_info(struct clap_plugin *plugin,
- uint32_t config_index,
- uint32_t port_index,
- struct clap_port_info *port)
+thyns_plugin_activate(struct clap_plugin *plugin)
{
- switch (config_index) {
- case 0:
- switch (port_index) {
- case 0:
- snprintf(port->name, sizeof (port->name), "out");
- port->type = CLAP_PORT_MONO;
- port->role = CLAP_PORT_INOUT;
- port->is_repeatable = false;
- return true;;
- }
- return false;
-
- default:
- return false;
- }
return true;
}
-bool
-thyns_plugin_set_ports_config(struct clap_plugin *plugin,
- uint32_t config_index)
-{
- switch (config_index) {
- case 0:
- return true;
-
- default:
- return false;
- }
-}
-
-enum clap_process_status
-thyns_plugin_process(struct clap_plugin *plugin,
- struct clap_process *process)
+void
+thyns_plugin_deactivate(struct clap_plugin *plugin)
{
- return thyns_process(plugin->plugin_data, process);
}
struct thyns_plugin *
@@ -143,12 +99,10 @@ thyns_plugin_create(struct clap_host *host,
p->plugin.plugin_data = p;
p->plugin.get_attribute = thyns_plugin_get_attribute;
p->plugin.process = thyns_plugin_process;
+ p->plugin.extension = thyns_plugin_extension;
+ p->plugin.activate = thyns_plugin_activate;
+ p->plugin.deactivate = thyns_plugin_deactivate;
- // initialize ports extension
- p->ports.get_ports_configs_count = thyns_plugin_get_ports_configs_count;
- p->ports.get_ports_config = thyns_plugin_get_ports_config;
- p->ports.get_port_info = thyns_plugin_get_port_info;
- p->ports.set_ports_config = thyns_plugin_set_ports_config;
return p;
}
diff --git a/examples/thyns/thyns.h b/examples/thyns/thyns.h
@@ -135,6 +135,7 @@ thyns_process(struct thyns *thyns, struct clap_process *process)
// process
process->output[0][i] = thyns_step(thyns, process);
+ process->output[1][i] = process->output[0][i];
}
if (thyns->singing)
diff --git a/include/clap/clap-midi-parser.c b/include/clap/clap-midi-parser.c
@@ -61,6 +61,24 @@ clap_midi_parse_track(struct clap_midi_parser *parser)
}
static inline enum clap_midi_parser_status
+clap_midi_parse_channel_event(struct clap_midi_parser *parser)
+{
+ if (parser->size < 3)
+ return CLAP_MIDI_PARSER_EOB;
+
+ parser->channel.event_type = parser->in[0] & 0xf;
+ parser->channel.channel = parser->in[0] >> 4;
+ parser->channel.param1 = parser->in[1];
+ parser->channel.param2 = parser->in[2];
+
+ parser->in += 3;
+ parser->size -= 3;
+ parser->track.size -= 3;
+
+ return CLAP_MIDI_PARSER_CHANNEL;
+}
+
+static inline enum clap_midi_parser_status
clap_midi_parse_meta_event(struct clap_midi_parser *parser)
{
assert(parser->in[0] == 0xff);
@@ -86,6 +104,8 @@ clap_midi_parse_meta_event(struct clap_midi_parser *parser)
static inline enum clap_midi_parser_status
clap_midi_parse_event(struct clap_midi_parser *parser)
{
+ if ((parser->in[0] & 0xf) <= 0xe)
+ return clap_midi_parse_channel_event(parser);
if (parser->in[0] == 0xff)
return clap_midi_parse_meta_event(parser);
return CLAP_MIDI_PARSER_ERROR;
@@ -116,3 +136,41 @@ clap_midi_parse(struct clap_midi_parser *parser)
return CLAP_MIDI_PARSER_ERROR;
}
}
+
+static inline void
+clap_midi_convert(const uint8_t *in,
+ uint32_t size,
+ struct clap_event *event)
+{
+ struct clap_midi_parser parser;
+ parser.state = CLAP_MIDI_PARSER_TRACK;
+ parser.in = in;
+ parser.size = size;
+ parser.track.size = size;
+
+ enum clap_midi_parser_status status = clap_midi_parse(&parser);
+ switch (status) {
+ case CLAP_MIDI_PARSER_CHANNEL:
+ switch (parser.channel.event_type) {
+ case CLAP_MIDI_CHANNEL_NOTE_OFF:
+ event->type = CLAP_EVENT_NOTE_OFF;
+ event->note.key = parser.channel.param1;
+ event->note.velocity = ((float)parser.channel.param2) / 127.0f;
+ event->note.events = NULL;
+ break;
+
+ case CLAP_MIDI_CHANNEL_NOTE_ON:
+ event->type = CLAP_EVENT_NOTE_ON;
+ event->note.key = parser.channel.param1;
+ event->note.velocity = ((float)parser.channel.param2) / 127.0f;
+ event->note.events = NULL;
+ break;
+ }
+
+ default:
+ event->type = CLAP_EVENT_MIDI;
+ event->midi.buffer = in;
+ event->midi.size = size;
+ break;
+ }
+}
diff --git a/include/clap/clap-midi-parser.h b/include/clap/clap-midi-parser.h
@@ -10,6 +10,8 @@
# include <stdint.h>
# include <string.h>
+# include "clap.h"
+
enum clap_midi_parser_status
{
CLAP_MIDI_PARSER_EOB = -2,
@@ -78,6 +80,7 @@ struct clap_midi_parser
const uint8_t *in;
uint32_t size;
+ /* result */
struct clap_midi_header header;
struct clap_midi_track track;
struct clap_midi_channel_event channel;
@@ -88,6 +91,14 @@ struct clap_midi_parser
static inline enum clap_midi_parser_status
clap_midi_parse(struct clap_midi_parser *parser);
+/* Converts a midi buffer in the state track, into a clap_event.
+ * If the midi data can't be converted into clap's events, it is then
+ * converted as a clap_midi_event. */
+static inline void
+clap_midi_convert(const uint8_t *in,
+ uint32_t size,
+ struct clap_event *event);
+
# include "clap-midi-parser.c"
#endif /* !CLAP_MIDI_PARSER_H */
diff --git a/include/clap/clap.h b/include/clap/clap.h
@@ -130,6 +130,7 @@ struct clap_event_note
{
uint8_t key;
float pitch;
+ float velocity; // 0..1
struct clap_event *events; // events specific to this note
};
@@ -157,8 +158,8 @@ struct clap_event_preset
struct clap_event_midi
{
- uint32_t size;
- uint8_t *buffer;
+ const uint8_t *buffer;
+ uint32_t size;
};
struct clap_event_latency
@@ -200,9 +201,6 @@ enum clap_process_status
struct clap_process
{
- /* host custom ptr */
- void *host_data;
-
/* audio buffers */
float **input;
float **output;
@@ -213,6 +211,8 @@ struct clap_process
uint32_t tempo; // the tempo in samples
uint64_t song_time; // the song time in samples
uint64_t steady_time; // the steady time in samples
+ uint32_t loop_start_time;
+ uint32_t loop_end_time;
/* events */
struct clap_event *events;
@@ -227,10 +227,10 @@ struct clap_host
uint32_t clap_version; // initialized to CLAP_VERSION
/* returns the size of the original string, 0 if not string */
- uint32_t (*get_attribute)(struct clap_plugin *plugin,
- const char *attr,
- char *buffer,
- uint32_t size);
+ uint32_t (*get_attribute)(struct clap_host *host,
+ const char *attr,
+ char *buffer,
+ uint32_t size);
/* for events generated by the plugin. */
void (*events)(struct clap_host *host,
@@ -244,6 +244,7 @@ struct clap_host
/* Log a message through the host. */
void (*log)(struct clap_host *host,
+ struct clap_plugin *plugin,
enum clap_log_severity severity,
const char *msg);
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
@@ -1 +1,2 @@
add_subdirectory(clap-info)
+add_subdirectory(clap-jack-host)
diff --git a/tools/clap-jack-host/CMakeLists.txt b/tools/clap-jack-host/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_executable(clap-jack-host clap-jack-host.c)
+target_link_libraries(clap-jack-host jack dl)
diff --git a/tools/clap-jack-host/clap-jack-host.c b/tools/clap-jack-host/clap-jack-host.c
@@ -0,0 +1,243 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <dlfcn.h>
+#include <unistd.h>
+
+#include <clap/clap.h>
+#include <clap/clap-midi-parser.h>
+
+#include <jack/jack.h>
+#include <jack/midiport.h>
+
+struct clap_jack_host
+{
+ /* clap */
+ struct clap_host host;
+ struct clap_plugin *plugin;
+ void *library_handle;
+
+ /* host */
+ uint32_t sample_rate;
+ uint64_t steady_time;
+
+ /* jack */
+ jack_client_t *client;
+ jack_port_t *input_ports[2];
+ jack_port_t *output_ports[2];
+ jack_port_t *midi_in;
+};
+
+static void deinitialize(struct clap_jack_host *app);
+
+static void host_events(struct clap_host *host,
+ struct clap_plugin *plugin,
+ struct clap_event *events)
+{
+}
+
+static uint64_t host_steady_time(struct clap_host *host)
+{
+ return 0;
+}
+
+static void *host_extension(struct clap_host *host, const char *extension_id)
+{
+ return NULL;
+}
+
+static void host_log(struct clap_host *host,
+ struct clap_plugin *plugin,
+ enum clap_log_severity severity,
+ const char *msg)
+{
+ const char *severities[] = {
+ "debug",
+ "info",
+ "warning",
+ "error",
+ "fatal",
+ };
+
+ fprintf(stdout, "[%s] %s\n", severities[severity], msg);
+}
+
+static uint32_t host_attribute(struct clap_host *host,
+ const char *attr,
+ char *buffer,
+ uint32_t size)
+{
+ return 0;
+}
+
+int process(jack_nframes_t nframes, void *arg)
+{
+ struct clap_jack_host *app = arg;
+
+ /* get jack ports */
+ jack_default_audio_sample_t *in[2], *out[2];
+ for (int i = 0; i < 2; ++i) {
+ in[i] = jack_port_get_buffer(app->input_ports[i], nframes);
+ out[i] = jack_port_get_buffer(app->output_ports[i], nframes);
+ }
+ void *midi_in_buf = jack_port_get_buffer(app->midi_in, nframes);
+ uint32_t midi_in_count = jack_midi_get_event_count(midi_in_buf);
+
+ struct clap_process p;
+ p.input = in;
+ p.output = out;
+ p.samples_count = nframes;
+ p.is_offline = false;
+ // XXX add time info
+
+ /* convert midi events */
+ p.events = NULL;
+ struct clap_event *last_event = NULL;
+ for (uint32_t i = 0; i < midi_in_count; ++i) {
+ jack_midi_event_t midi;
+ jack_midi_event_get(&midi, midi_in_buf, i);
+
+ struct clap_event *event = calloc(1, sizeof (*event));
+ if (!event)
+ break;
+ if (last_event)
+ last_event->next = event;
+ else
+ p.events = event;
+ last_event = event;
+
+ clap_midi_convert(midi.buffer, midi.size, event);
+ event->steady_time = app->steady_time + midi.time;
+ }
+
+ /* process */
+ app->plugin->process(app->plugin, &p);
+
+ /* release events */
+ while (p.events) {
+ struct clap_event *next = p.events->next;
+ free(p.events);
+ p.events = next;
+ }
+
+ app->steady_time += nframes;
+ return 0;
+}
+
+void shutdown(void *arg)
+{
+ deinitialize(arg);
+}
+
+static bool initialize(struct clap_jack_host *app,
+ const char *plugin_path,
+ uint32_t plugin_index)
+{
+ /* jack */
+ jack_status_t jack_status;
+ app->client = jack_client_open("clap-host", JackNullOption, &jack_status, NULL);
+ if (app->client == NULL) {
+ fprintf(stderr, "jack_client_open() failed, status: %d\n", jack_status);
+ return false;
+ }
+
+ jack_set_process_callback(app->client, process, app);
+ jack_on_shutdown(app->client, shutdown, app);
+ app->input_ports[0] = jack_port_register(app->client, "input left",
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsInput, 0);
+ app->input_ports[1] = jack_port_register(app->client, "input right",
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsInput, 0);
+ app->output_ports[0] = jack_port_register(app->client, "output left",
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput, 0);
+ app->output_ports[1] = jack_port_register(app->client, "output right",
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput, 0);
+ app->midi_in = jack_port_register(app->client, "midi in", JACK_DEFAULT_MIDI_TYPE,
+ JackPortIsInput, 0);
+
+ printf("engine sample rate: %"PRIu32"\n", jack_get_sample_rate(app->client));
+
+ /* host initialization */
+ app->host.clap_version = CLAP_VERSION;
+ app->host.events = host_events;
+ app->host.steady_time = host_steady_time;
+ app->host.extension = host_extension;
+ app->host.get_attribute = host_attribute;
+ app->host.log = host_log;
+ app->steady_time = 0;
+ app->sample_rate = jack_get_sample_rate(app->client);
+
+ /* plugin initialization */
+ app->library_handle = dlopen(plugin_path, RTLD_NOW | RTLD_LOCAL);
+ if (!app->library_handle) {
+ fprintf(stderr, "failed to load %s: %s\n", plugin_path, dlerror());
+ goto fail_jack;
+ }
+
+ union {
+ void *ptr;
+ clap_create_f clap_create;
+ } symbol;
+
+ symbol.ptr = dlsym(app->library_handle, "clap_create");
+ if (!symbol.ptr) {
+ fprintf(stderr, "symbol not found: clap_create\n");
+ goto fail_dlclose;
+ }
+
+ uint32_t plugin_count;
+ app->plugin = symbol.clap_create(plugin_index, &app->host, app->sample_rate, &plugin_count);
+ if (!app->plugin) {
+ fprintf(stderr, "failed to create plugin\n");
+ goto fail_dlclose;
+ }
+
+ return true;
+
+fail_dlclose:
+ dlclose(app->library_handle);
+fail_jack:
+ jack_client_close(app->client);
+ return false;
+}
+
+static void deinitialize(struct clap_jack_host *app)
+{
+ /* clap */
+ app->plugin->destroy(app->plugin);
+ dlclose(app->library_handle);
+
+ /* jack */
+ jack_client_close(app->client);
+}
+
+int main(int argc, char **argv)
+{
+ struct clap_jack_host app;
+
+ if (argc != 3) {
+ fprintf(stderr, "usage: %s plugin.so index\n", argv[0]);
+ return 2;
+ }
+
+ if (!initialize(&app, argv[1], atoi(argv[2])))
+ return 1;
+
+ if (!app.plugin->activate(app.plugin)) {
+ fprintf(stderr, "can't activate the plugin\n");
+ return 1;
+ }
+
+ if (jack_activate(app.client)) {
+ fprintf(stderr, "can't activate jack.\n");
+ return 1;
+ }
+
+ // wait until application closes
+ sleep(-1);
+
+ deinitialize(&app);
+ return 0;
+}