diff options
Diffstat (limited to 'utils/lv2apply.c')
-rw-r--r-- | utils/lv2apply.c | 525 |
1 files changed, 262 insertions, 263 deletions
diff --git a/utils/lv2apply.c b/utils/lv2apply.c index 1d11c50..0a1123a 100644 --- a/utils/lv2apply.c +++ b/utils/lv2apply.c @@ -28,73 +28,71 @@ #include <string.h> #if defined(__GNUC__) -# define LILV_LOG_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1))) +# define LILV_LOG_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1))) #else -# define LILV_LOG_FUNC(fmt, arg1) +# define LILV_LOG_FUNC(fmt, arg1) #endif /** Control port value set from the command line */ typedef struct Param { - const char* sym; ///< Port symbol - float value; ///< Control value + const char* sym; ///< Port symbol + float value; ///< Control value } Param; /** Port type (only float ports are supported) */ -typedef enum { - TYPE_CONTROL, - TYPE_AUDIO -} PortType; +typedef enum { TYPE_CONTROL, TYPE_AUDIO } PortType; /** Runtime port information */ typedef struct { - const LilvPort* lilv_port; ///< Port description - PortType type; ///< Datatype - uint32_t index; ///< Port index - float value; ///< Control value (if applicable) - bool is_input; ///< True iff an input port - bool optional; ///< True iff connection optional + const LilvPort* lilv_port; ///< Port description + PortType type; ///< Datatype + uint32_t index; ///< Port index + float value; ///< Control value (if applicable) + bool is_input; ///< True iff an input port + bool optional; ///< True iff connection optional } Port; /** Application state */ typedef struct { - LilvWorld* world; - const LilvPlugin* plugin; - LilvInstance* instance; - const char* in_path; - const char* out_path; - SNDFILE* in_file; - SNDFILE* out_file; - unsigned n_params; - Param* params; - unsigned n_ports; - unsigned n_audio_in; - unsigned n_audio_out; - Port* ports; + LilvWorld* world; + const LilvPlugin* plugin; + LilvInstance* instance; + const char* in_path; + const char* out_path; + SNDFILE* in_file; + SNDFILE* out_file; + unsigned n_params; + Param* params; + unsigned n_ports; + unsigned n_audio_in; + unsigned n_audio_out; + Port* ports; } LV2Apply; -static int fatal(LV2Apply* self, int status, const char* fmt, ...); +static int +fatal(LV2Apply* self, int status, const char* fmt, ...); /** Open a sound file with error handling. */ static SNDFILE* sopen(LV2Apply* self, const char* path, int mode, SF_INFO* fmt) { - SNDFILE* file = sf_open(path, mode, fmt); - const int st = sf_error(file); - if (st) { - fatal(self, 1, "Failed to open %s (%s)\n", path, sf_error_number(st)); - return NULL; - } - return file; + SNDFILE* file = sf_open(path, mode, fmt); + const int st = sf_error(file); + if (st) { + fatal(self, 1, "Failed to open %s (%s)\n", path, sf_error_number(st)); + return NULL; + } + return file; } /** Close a sound file with error handling. */ static void sclose(const char* path, SNDFILE* file) { - int st = 0; - if (file && (st = sf_close(file))) { - fatal(NULL, 1, "Failed to close %s (%s)\n", path, sf_error_number(st)); - } + int st = 0; + if (file && (st = sf_close(file))) { + fatal(NULL, 1, "Failed to close %s (%s)\n", path, sf_error_number(st)); + } } /** @@ -106,24 +104,24 @@ sclose(const char* path, SNDFILE* file) static bool sread(SNDFILE* file, unsigned file_chans, float* buf, unsigned buf_chans) { - const sf_count_t n_read = sf_readf_float(file, buf, 1); - for (unsigned i = file_chans - 1; i < buf_chans; ++i) { - buf[i] = buf[i % file_chans]; - } - return n_read == 1; + const sf_count_t n_read = sf_readf_float(file, buf, 1); + for (unsigned i = file_chans - 1; i < buf_chans; ++i) { + buf[i] = buf[i % file_chans]; + } + return n_read == 1; } /** Clean up all resources. */ static int cleanup(int status, LV2Apply* self) { - sclose(self->in_path, self->in_file); - sclose(self->out_path, self->out_file); - lilv_instance_free(self->instance); - lilv_world_free(self->world); - free(self->ports); - free(self->params); - return status; + sclose(self->in_path, self->in_file); + sclose(self->out_path, self->out_file); + lilv_instance_free(self->instance); + lilv_world_free(self->world); + free(self->ports); + free(self->params); + return status; } /** Print a fatal error and clean up for exit. */ @@ -131,12 +129,12 @@ LILV_LOG_FUNC(3, 4) static int fatal(LV2Apply* self, int status, const char* fmt, ...) { - va_list args; - va_start(args, fmt); - fprintf(stderr, "error: "); - vfprintf(stderr, fmt, args); - va_end(args); - return self ? cleanup(status, self) : status; + va_list args; + va_start(args, fmt); + fprintf(stderr, "error: "); + vfprintf(stderr, fmt, args); + va_end(args); + return self ? cleanup(status, self) : status; } /** @@ -145,225 +143,226 @@ fatal(LV2Apply* self, int status, const char* fmt, ...) static int create_ports(LV2Apply* self) { - LilvWorld* world = self->world; - const uint32_t n_ports = lilv_plugin_get_num_ports(self->plugin); - - self->n_ports = n_ports; - self->ports = (Port*)calloc(self->n_ports, sizeof(Port)); - - /* Get default values for all ports */ - float* values = (float*)calloc(n_ports, sizeof(float)); - lilv_plugin_get_port_ranges_float(self->plugin, NULL, NULL, values); - - LilvNode* lv2_InputPort = lilv_new_uri(world, LV2_CORE__InputPort); - LilvNode* lv2_OutputPort = lilv_new_uri(world, LV2_CORE__OutputPort); - LilvNode* lv2_AudioPort = lilv_new_uri(world, LV2_CORE__AudioPort); - LilvNode* lv2_ControlPort = lilv_new_uri(world, LV2_CORE__ControlPort); - LilvNode* lv2_connectionOptional = lilv_new_uri(world, LV2_CORE__connectionOptional); - - for (uint32_t i = 0; i < n_ports; ++i) { - Port* port = &self->ports[i]; - const LilvPort* lport = lilv_plugin_get_port_by_index(self->plugin, i); - - port->lilv_port = lport; - port->index = i; - port->value = isnan(values[i]) ? 0.0f : values[i]; - port->optional = lilv_port_has_property( - self->plugin, lport, lv2_connectionOptional); - - /* Check if port is an input or output */ - if (lilv_port_is_a(self->plugin, lport, lv2_InputPort)) { - port->is_input = true; - } else if (!lilv_port_is_a(self->plugin, lport, lv2_OutputPort) && - !port->optional) { - return fatal(self, 1, "Port %u is neither input nor output\n", i); - } - - /* Check if port is an audio or control port */ - if (lilv_port_is_a(self->plugin, lport, lv2_ControlPort)) { - port->type = TYPE_CONTROL; - } else if (lilv_port_is_a(self->plugin, lport, lv2_AudioPort)) { - port->type = TYPE_AUDIO; - if (port->is_input) { - ++self->n_audio_in; - } else { - ++self->n_audio_out; - } - } else if (!port->optional) { - return fatal(self, 1, "Port %u has unsupported type\n", i); - } - } - - lilv_node_free(lv2_connectionOptional); - lilv_node_free(lv2_ControlPort); - lilv_node_free(lv2_AudioPort); - lilv_node_free(lv2_OutputPort); - lilv_node_free(lv2_InputPort); - free(values); - - return 0; + LilvWorld* world = self->world; + const uint32_t n_ports = lilv_plugin_get_num_ports(self->plugin); + + self->n_ports = n_ports; + self->ports = (Port*)calloc(self->n_ports, sizeof(Port)); + + /* Get default values for all ports */ + float* values = (float*)calloc(n_ports, sizeof(float)); + lilv_plugin_get_port_ranges_float(self->plugin, NULL, NULL, values); + + LilvNode* lv2_InputPort = lilv_new_uri(world, LV2_CORE__InputPort); + LilvNode* lv2_OutputPort = lilv_new_uri(world, LV2_CORE__OutputPort); + LilvNode* lv2_AudioPort = lilv_new_uri(world, LV2_CORE__AudioPort); + LilvNode* lv2_ControlPort = lilv_new_uri(world, LV2_CORE__ControlPort); + LilvNode* lv2_connectionOptional = + lilv_new_uri(world, LV2_CORE__connectionOptional); + + for (uint32_t i = 0; i < n_ports; ++i) { + Port* port = &self->ports[i]; + const LilvPort* lport = lilv_plugin_get_port_by_index(self->plugin, i); + + port->lilv_port = lport; + port->index = i; + port->value = isnan(values[i]) ? 0.0f : values[i]; + port->optional = + lilv_port_has_property(self->plugin, lport, lv2_connectionOptional); + + /* Check if port is an input or output */ + if (lilv_port_is_a(self->plugin, lport, lv2_InputPort)) { + port->is_input = true; + } else if (!lilv_port_is_a(self->plugin, lport, lv2_OutputPort) && + !port->optional) { + return fatal(self, 1, "Port %u is neither input nor output\n", i); + } + + /* Check if port is an audio or control port */ + if (lilv_port_is_a(self->plugin, lport, lv2_ControlPort)) { + port->type = TYPE_CONTROL; + } else if (lilv_port_is_a(self->plugin, lport, lv2_AudioPort)) { + port->type = TYPE_AUDIO; + if (port->is_input) { + ++self->n_audio_in; + } else { + ++self->n_audio_out; + } + } else if (!port->optional) { + return fatal(self, 1, "Port %u has unsupported type\n", i); + } + } + + lilv_node_free(lv2_connectionOptional); + lilv_node_free(lv2_ControlPort); + lilv_node_free(lv2_AudioPort); + lilv_node_free(lv2_OutputPort); + lilv_node_free(lv2_InputPort); + free(values); + + return 0; } static void print_version(void) { - printf( - "lv2apply (lilv) " LILV_VERSION "\n" - "Copyright 2007-2019 David Robillard <http://drobilla.net>\n" - "License: <http://www.opensource.org/licenses/isc-license>\n" - "This is free software: you are free to change and redistribute it.\n" - "There is NO WARRANTY, to the extent permitted by law.\n"); + printf("lv2apply (lilv) " LILV_VERSION "\n" + "Copyright 2007-2019 David Robillard <http://drobilla.net>\n" + "License: <http://www.opensource.org/licenses/isc-license>\n" + "This is free software: you are free to change and redistribute it.\n" + "There is NO WARRANTY, to the extent permitted by law.\n"); } static int print_usage(int status) { - fprintf(status ? stderr : stdout, - "Usage: lv2apply [OPTION]... PLUGIN_URI\n" - "Apply an LV2 plugin to an audio file.\n\n" - " -i IN_FILE Input file\n" - " -o OUT_FILE Output file\n" - " -c SYM VAL Control value\n" - " --help Display this help and exit\n" - " --version Display version information and exit\n"); - return status; + fprintf(status ? stderr : stdout, + "Usage: lv2apply [OPTION]... PLUGIN_URI\n" + "Apply an LV2 plugin to an audio file.\n\n" + " -i IN_FILE Input file\n" + " -o OUT_FILE Output file\n" + " -c SYM VAL Control value\n" + " --help Display this help and exit\n" + " --version Display version information and exit\n"); + return status; } int main(int argc, char** argv) { - LV2Apply self = { - NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, 0, 0, NULL - }; - - /* Parse command line arguments */ - const char* plugin_uri = NULL; - for (int i = 1; i < argc; ++i) { - if (!strcmp(argv[i], "--version")) { - free(self.params); - print_version(); - return 0; - } - - if (!strcmp(argv[i], "--help")) { - free(self.params); - return print_usage(0); - } - - if (!strcmp(argv[i], "-i")) { - self.in_path = argv[++i]; - } else if (!strcmp(argv[i], "-o")) { - self.out_path = argv[++i]; - } else if (!strcmp(argv[i], "-c")) { - if (argc < i + 3) { - return fatal(&self, 1, "Missing argument for -c\n"); - } - self.params = (Param*)realloc(self.params, - ++self.n_params * sizeof(Param)); - self.params[self.n_params - 1].sym = argv[++i]; - self.params[self.n_params - 1].value = atof(argv[++i]); - } else if (argv[i][0] == '-') { - free(self.params); - return print_usage(1); - } else if (i == argc - 1) { - plugin_uri = argv[i]; - } - } - - /* Check that required arguments are given */ - if (!self.in_path || !self.out_path || !plugin_uri) { - free(self.params); - return print_usage(1); - } - - /* Create world and plugin URI */ - self.world = lilv_world_new(); - LilvNode* uri = lilv_new_uri(self.world, plugin_uri); - if (!uri) { - return fatal(&self, 2, "Invalid plugin URI <%s>\n", plugin_uri); - } - - /* Discover world */ - lilv_world_load_all(self.world); - - /* Get plugin */ - const LilvPlugins* plugins = lilv_world_get_all_plugins(self.world); - const LilvPlugin* plugin = lilv_plugins_get_by_uri(plugins, uri); - lilv_node_free(uri); - if (!(self.plugin = plugin)) { - return fatal(&self, 3, "Plugin <%s> not found\n", plugin_uri); - } - - /* Open input file */ - SF_INFO in_fmt = { 0, 0, 0, 0, 0, 0 }; - if (!(self.in_file = sopen(&self, self.in_path, SFM_READ, &in_fmt))) { - return 4; - } - - /* Create port structures */ - if (create_ports(&self)) { - return 5; - } - - if (self.n_audio_in == 0 || - (in_fmt.channels != (int)self.n_audio_in && in_fmt.channels != 1)) { - return fatal(&self, 6, "Unable to map %d inputs to %u ports\n", - in_fmt.channels, self.n_audio_in); - } - - /* Set control values */ - for (unsigned i = 0; i < self.n_params; ++i) { - const Param* param = &self.params[i]; - LilvNode* sym = lilv_new_string(self.world, param->sym); - const LilvPort* port = lilv_plugin_get_port_by_symbol(plugin, sym); - lilv_node_free(sym); - if (!port) { - return fatal(&self, 7, "Unknown port `%s'\n", param->sym); - } - - self.ports[lilv_port_get_index(plugin, port)].value = param->value; - } - - /* Open output file */ - SF_INFO out_fmt = in_fmt; - out_fmt.channels = self.n_audio_out; - if (!(self.out_file = sopen(&self, self.out_path, SFM_WRITE, &out_fmt))) { - free(self.ports); - return 8; - } - - /* Instantiate plugin and connect ports */ - const uint32_t n_ports = lilv_plugin_get_num_ports(plugin); - float in_buf[self.n_audio_in > 0 ? self.n_audio_in : 1]; - float out_buf[self.n_audio_out > 0 ? self.n_audio_out : 1]; - self.instance = lilv_plugin_instantiate( - self.plugin, in_fmt.samplerate, NULL); - for (uint32_t p = 0, i = 0, o = 0; p < n_ports; ++p) { - if (self.ports[p].type == TYPE_CONTROL) { - lilv_instance_connect_port(self.instance, p, &self.ports[p].value); - } else if (self.ports[p].type == TYPE_AUDIO) { - if (self.ports[p].is_input) { - lilv_instance_connect_port(self.instance, p, in_buf + i++); - } else { - lilv_instance_connect_port(self.instance, p, out_buf + o++); - } - } else { - lilv_instance_connect_port(self.instance, p, NULL); - } - } - - /* Ports are now connected to buffers in interleaved format, so we can run - a single frame at a time and avoid having to interleave buffers to - read/write from/to sndfile. */ - - lilv_instance_activate(self.instance); - while (sread(self.in_file, in_fmt.channels, in_buf, self.n_audio_in)) { - lilv_instance_run(self.instance, 1); - if (sf_writef_float(self.out_file, out_buf, 1) != 1) { - return fatal(&self, 9, "Failed to write to output file\n"); - } - } - lilv_instance_deactivate(self.instance); - - return cleanup(0, &self); + LV2Apply self = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, 0, 0, NULL}; + + /* Parse command line arguments */ + const char* plugin_uri = NULL; + for (int i = 1; i < argc; ++i) { + if (!strcmp(argv[i], "--version")) { + free(self.params); + print_version(); + return 0; + } + + if (!strcmp(argv[i], "--help")) { + free(self.params); + return print_usage(0); + } + + if (!strcmp(argv[i], "-i")) { + self.in_path = argv[++i]; + } else if (!strcmp(argv[i], "-o")) { + self.out_path = argv[++i]; + } else if (!strcmp(argv[i], "-c")) { + if (argc < i + 3) { + return fatal(&self, 1, "Missing argument for -c\n"); + } + self.params = + (Param*)realloc(self.params, ++self.n_params * sizeof(Param)); + self.params[self.n_params - 1].sym = argv[++i]; + self.params[self.n_params - 1].value = atof(argv[++i]); + } else if (argv[i][0] == '-') { + free(self.params); + return print_usage(1); + } else if (i == argc - 1) { + plugin_uri = argv[i]; + } + } + + /* Check that required arguments are given */ + if (!self.in_path || !self.out_path || !plugin_uri) { + free(self.params); + return print_usage(1); + } + + /* Create world and plugin URI */ + self.world = lilv_world_new(); + LilvNode* uri = lilv_new_uri(self.world, plugin_uri); + if (!uri) { + return fatal(&self, 2, "Invalid plugin URI <%s>\n", plugin_uri); + } + + /* Discover world */ + lilv_world_load_all(self.world); + + /* Get plugin */ + const LilvPlugins* plugins = lilv_world_get_all_plugins(self.world); + const LilvPlugin* plugin = lilv_plugins_get_by_uri(plugins, uri); + lilv_node_free(uri); + if (!(self.plugin = plugin)) { + return fatal(&self, 3, "Plugin <%s> not found\n", plugin_uri); + } + + /* Open input file */ + SF_INFO in_fmt = {0, 0, 0, 0, 0, 0}; + if (!(self.in_file = sopen(&self, self.in_path, SFM_READ, &in_fmt))) { + return 4; + } + + /* Create port structures */ + if (create_ports(&self)) { + return 5; + } + + if (self.n_audio_in == 0 || + (in_fmt.channels != (int)self.n_audio_in && in_fmt.channels != 1)) { + return fatal(&self, + 6, + "Unable to map %d inputs to %u ports\n", + in_fmt.channels, + self.n_audio_in); + } + + /* Set control values */ + for (unsigned i = 0; i < self.n_params; ++i) { + const Param* param = &self.params[i]; + LilvNode* sym = lilv_new_string(self.world, param->sym); + const LilvPort* port = lilv_plugin_get_port_by_symbol(plugin, sym); + lilv_node_free(sym); + if (!port) { + return fatal(&self, 7, "Unknown port `%s'\n", param->sym); + } + + self.ports[lilv_port_get_index(plugin, port)].value = param->value; + } + + /* Open output file */ + SF_INFO out_fmt = in_fmt; + out_fmt.channels = self.n_audio_out; + if (!(self.out_file = sopen(&self, self.out_path, SFM_WRITE, &out_fmt))) { + free(self.ports); + return 8; + } + + /* Instantiate plugin and connect ports */ + const uint32_t n_ports = lilv_plugin_get_num_ports(plugin); + float in_buf[self.n_audio_in > 0 ? self.n_audio_in : 1]; + float out_buf[self.n_audio_out > 0 ? self.n_audio_out : 1]; + self.instance = lilv_plugin_instantiate(self.plugin, in_fmt.samplerate, NULL); + for (uint32_t p = 0, i = 0, o = 0; p < n_ports; ++p) { + if (self.ports[p].type == TYPE_CONTROL) { + lilv_instance_connect_port(self.instance, p, &self.ports[p].value); + } else if (self.ports[p].type == TYPE_AUDIO) { + if (self.ports[p].is_input) { + lilv_instance_connect_port(self.instance, p, in_buf + i++); + } else { + lilv_instance_connect_port(self.instance, p, out_buf + o++); + } + } else { + lilv_instance_connect_port(self.instance, p, NULL); + } + } + + /* Ports are now connected to buffers in interleaved format, so we can run + a single frame at a time and avoid having to interleave buffers to + read/write from/to sndfile. */ + + lilv_instance_activate(self.instance); + while (sread(self.in_file, in_fmt.channels, in_buf, self.n_audio_in)) { + lilv_instance_run(self.instance, 1); + if (sf_writef_float(self.out_file, out_buf, 1) != 1) { + return fatal(&self, 9, "Failed to write to output file\n"); + } + } + lilv_instance_deactivate(self.instance); + + return cleanup(0, &self); } |