diff options
-rw-r--r-- | lv2/lv2plug.in/ns/ext/log/log.h | 20 | ||||
-rw-r--r-- | lv2/lv2plug.in/ns/ext/log/log.ttl | 29 | ||||
-rw-r--r-- | plugins/eg-sampler.lv2/sampler.c | 152 | ||||
-rw-r--r-- | plugins/eg-sampler.lv2/uris.h | 5 | ||||
-rw-r--r-- | plugins/eg-sampler.lv2/wscript | 16 | ||||
-rw-r--r-- | wscript | 2 |
6 files changed, 131 insertions, 93 deletions
diff --git a/lv2/lv2plug.in/ns/ext/log/log.h b/lv2/lv2plug.in/ns/ext/log/log.h index 4682295..3c2ec40 100644 --- a/lv2/lv2plug.in/ns/ext/log/log.h +++ b/lv2/lv2plug.in/ns/ext/log/log.h @@ -25,10 +25,12 @@ #define LV2_LOG_URI "http://lv2plug.in/ns/ext/log" #define LV2_LOG_PREFIX LV2_LOG_URI "#" -#define LV2_LOG__Error LV2_LOG_PREFIX "Error" -#define LV2_LOG__Info LV2_LOG_PREFIX "Info" -#define LV2_LOG__Warn LV2_LOG_PREFIX "Warn" -#define LV2_LOG__log LV2_LOG_PREFIX "log" +#define LV2_LOG__Entry LV2_LOG_PREFIX "Entry" +#define LV2_LOG__Error LV2_LOG_PREFIX "Error" +#define LV2_LOG__Note LV2_LOG_PREFIX "Note" +#define LV2_LOG__Trace LV2_LOG_PREFIX "Trace" +#define LV2_LOG__Warning LV2_LOG_PREFIX "Warning" +#define LV2_LOG__log LV2_LOG_PREFIX "log" #include <stdarg.h> @@ -67,11 +69,12 @@ typedef struct _LV2_Log { The API of this function matches that of the standard C printf function, except for the addition of the first two parameters. This - function may be called from any non-realtime context. + function may be called from any non-realtime context, or from any + context if @p type is @ref LV2_LOG__Trace. */ LV2_LOG_FUNC(3, 4) int (*printf)(LV2_Log_Handle handle, - LV2_URID level, + LV2_URID type, const char* fmt, ...); /** @@ -79,11 +82,12 @@ typedef struct _LV2_Log { The API of this function matches that of the standard C vprintf function, except for the addition of the first two parameters. This - function may be called from any non-realtime context. + function may be called from any non-realtime context, or from any + context if @p type is @ref LV2_LOG__Trace. */ LV2_LOG_FUNC(3, 0) int (*vprintf)(LV2_Log_Handle handle, - LV2_URID level, + LV2_URID type, const char* fmt, va_list ap); } LV2_Log_Log; diff --git a/lv2/lv2plug.in/ns/ext/log/log.ttl b/lv2/lv2plug.in/ns/ext/log/log.ttl index a8d9caf..a3c3724 100644 --- a/lv2/lv2plug.in/ns/ext/log/log.ttl +++ b/lv2/lv2plug.in/ns/ext/log/log.ttl @@ -39,31 +39,44 @@ levels is unlimited, but implementations SHOULD use the levels defined in this extension unless they have a special reason to do otherwise.</p> """ . -log:Level +log:Entry a rdfs:Class ; lv2:documentation """ -<p>A log level. Subclasses of this class can be passed to LV2_Log_Log methods +<p>A log entry. Subclasses of this class can be passed to LV2_Log_Log methods to describe the nature of the log message.</p>""" . log:Error a rdfs:Class ; - rdfs:subClassOf log:Level ; + rdfs:subClassOf log:Entry ; rdfs:comment "An error" . -log:Info +log:Note a rdfs:Class ; - rdfs:subClassOf log:Level ; + rdfs:subClassOf log:Entry ; rdfs:comment "An informative message" . -log:Warn +log:Warning a rdfs:Class ; - rdfs:subClassOf log:Level ; + rdfs:subClassOf log:Entry ; rdfs:comment "A warning" . +log:Trace + a rdfs:Class ; + rdfs:subClassOf log:Entry ; + lv2:documentation """ +<p>A debugging trace. These entries should not be displayed during normal +operation, but the host may implement an option to display them for debugging +purposes.</p> + +<p>This entry type is special in that it may be written to in a real-time +thread. It is assumed that if debug tracing is enabled, real-time +considerations are not a concern.</p> +""" . + log:log a lv2:Feature ; lv2:documentation """ <p>A feature which plugins may use to log messages. To support this feature, the host must pass an LV2_Feature to LV2_Descriptor::instantiate() with URI -LV2_LOG_LOG_URI and data pointed to an instance of LV2_Log_Log.</p> +LV2_LOG__log and data pointed to an instance of LV2_Log_Log.</p> """ . diff --git a/plugins/eg-sampler.lv2/sampler.c b/plugins/eg-sampler.lv2/sampler.c index fa6adbe..154e717 100644 --- a/plugins/eg-sampler.lv2/sampler.c +++ b/plugins/eg-sampler.lv2/sampler.c @@ -41,6 +41,7 @@ #include "lv2/lv2plug.in/ns/ext/atom/forge.h" #include "lv2/lv2plug.in/ns/ext/atom/util.h" +#include "lv2/lv2plug.in/ns/ext/log/log.h" #include "lv2/lv2plug.in/ns/ext/patch/patch.h" #include "lv2/lv2plug.in/ns/ext/state/state.h" #include "lv2/lv2plug.in/ns/ext/urid/urid.h" @@ -68,6 +69,7 @@ typedef struct { /* Features */ LV2_URID_Map* map; LV2_Worker_Schedule* schedule; + LV2_Log_Log* log; /* Forge for creating atoms */ LV2_Atom_Forge forge; @@ -93,6 +95,23 @@ typedef struct { } Sampler; /** + Print an error message to the host log if available, or stderr otherwise. +*/ +LV2_LOG_FUNC(3, 4) +static void +print(Sampler* self, LV2_URID type, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + if (self->log) { + self->log->vprintf(self->log->handle, type, fmt, args); + } else { + vfprintf(stderr, fmt, args); + } + va_end(args); +} + +/** An atom-like message used internally to apply/free samples. This is only used internally to communicate with the worker, it is not an @@ -104,17 +123,20 @@ typedef struct { } SampleMessage; static Sample* -load_sample(Sampler* plugin, const char* path) +load_sample(Sampler* self, const char* path) { const size_t path_len = strlen(path); - printf("Loading sample %s\n", path); + print(self, self->uris.log_Trace, + "Loading sample %s\n", path); + Sample* const sample = (Sample*)malloc(sizeof(Sample)); SF_INFO* const info = &sample->info; SNDFILE* const sndfile = sf_open(path, SFM_READ, info); if (!sndfile || !info->frames || (info->channels != 1)) { - fprintf(stderr, "Failed to open sample '%s'.\n", path); + print(self, self->uris.log_Error, + "Failed to open sample '%s'.\n", path); free(sample); return NULL; } @@ -122,7 +144,8 @@ load_sample(Sampler* plugin, const char* path) /* Read data */ float* const data = malloc(sizeof(float) * info->frames); if (!data) { - fprintf(stderr, "Failed to allocate memory for sample.\n"); + print(self, self->uris.log_Error, + "Failed to allocate memory for sample.\n"); return NULL; } sf_seek(sndfile, 0ul, SEEK_SET); @@ -139,10 +162,10 @@ load_sample(Sampler* plugin, const char* path) } static void -free_sample(Sample* sample) +free_sample(Sampler* self, Sample* sample) { if (sample) { - fprintf(stderr, "Freeing %s\n", sample->path); + print(self, self->uris.log_Trace, "Freeing %s\n", sample->path); free(sample->path); free(sample->data); free(sample); @@ -162,7 +185,7 @@ work(LV2_Handle instance, if (atom->type == self->uris.eg_freeSample) { /* Free old sample */ SampleMessage* msg = (SampleMessage*)data; - free_sample(msg->sample); + free_sample(self, msg->sample); } else { /* Handle set message (load sample). */ LV2_Atom_Object* obj = (LV2_Atom_Object*)data; @@ -215,17 +238,17 @@ connect_port(LV2_Handle instance, uint32_t port, void* data) { - Sampler* plugin = (Sampler*)instance; + Sampler* self = (Sampler*)instance; switch (port) { case SAMPLER_CONTROL: - plugin->control_port = (LV2_Atom_Sequence*)data; + self->control_port = (LV2_Atom_Sequence*)data; break; case SAMPLER_RESPONSE: - plugin->notify_port = (LV2_Atom_Sequence*)data; + self->notify_port = (LV2_Atom_Sequence*)data; break; case SAMPLER_OUT: - plugin->output_port = (float*)data; + self->output_port = (float*)data; break; default: break; @@ -238,38 +261,40 @@ instantiate(const LV2_Descriptor* descriptor, const char* path, const LV2_Feature* const* features) { - Sampler* plugin = (Sampler*)malloc(sizeof(Sampler)); - if (!plugin) { + Sampler* self = (Sampler*)malloc(sizeof(Sampler)); + if (!self) { return NULL; } - memset(plugin, 0, sizeof(Sampler)); - plugin->sample = (Sample*)malloc(sizeof(Sample)); - if (!plugin->sample) { + memset(self, 0, sizeof(Sampler)); + self->sample = (Sample*)malloc(sizeof(Sample)); + if (!self->sample) { return NULL; } - memset(plugin->sample, 0, sizeof(Sample)); + memset(self->sample, 0, sizeof(Sample)); /* Scan and store host features */ for (int i = 0; features[i]; ++i) { if (!strcmp(features[i]->URI, LV2_URID__map)) { - plugin->map = (LV2_URID_Map*)features[i]->data; + self->map = (LV2_URID_Map*)features[i]->data; } else if (!strcmp(features[i]->URI, LV2_WORKER__schedule)) { - plugin->schedule = (LV2_Worker_Schedule*)features[i]->data; + self->schedule = (LV2_Worker_Schedule*)features[i]->data; + } else if (!strcmp(features[i]->URI, LV2_LOG__log)) { + self->log = (LV2_Log_Log*)features[i]->data; } } - if (!plugin->map) { - fprintf(stderr, "Host does not support urid:map.\n"); + if (!self->map) { + print(self, self->uris.log_Error, "Missing feature urid:map.\n"); goto fail; - } else if (!plugin->schedule) { - fprintf(stderr, "Host does not support work:schedule.\n"); + } else if (!self->schedule) { + print(self, self->uris.log_Error, "Missing feature work:schedule.\n"); goto fail; } /* Map URIS and initialise forge */ - map_sampler_uris(plugin->map, &plugin->uris); - lv2_atom_forge_init(&plugin->forge, plugin->map); + map_sampler_uris(self->map, &self->uris); + lv2_atom_forge_init(&self->forge, self->map); /* Load the default sample file */ const size_t path_len = strlen(path); @@ -277,87 +302,88 @@ instantiate(const LV2_Descriptor* descriptor, const size_t len = path_len + file_len; char* sample_path = (char*)malloc(len + 1); snprintf(sample_path, len + 1, "%s%s", path, default_sample_file); - plugin->sample = load_sample(plugin, sample_path); + self->sample = load_sample(self, sample_path); - return (LV2_Handle)plugin; + return (LV2_Handle)self; fail: - free(plugin); + free(self); return 0; } static void cleanup(LV2_Handle instance) { - Sampler* plugin = (Sampler*)instance; - - free_sample(plugin->sample); - free(plugin); + Sampler* self = (Sampler*)instance; + free_sample(self, self->sample); + free(self); } static void run(LV2_Handle instance, uint32_t sample_count) { - Sampler* plugin = (Sampler*)instance; - SamplerURIs* uris = &plugin->uris; + Sampler* self = (Sampler*)instance; + SamplerURIs* uris = &self->uris; sf_count_t start_frame = 0; sf_count_t pos = 0; - float* output = plugin->output_port; + float* output = self->output_port; /* Set up forge to write directly to notify output port. */ - const uint32_t notify_capacity = plugin->notify_port->atom.size; - lv2_atom_forge_set_buffer(&plugin->forge, - (uint8_t*)plugin->notify_port, + const uint32_t notify_capacity = self->notify_port->atom.size; + lv2_atom_forge_set_buffer(&self->forge, + (uint8_t*)self->notify_port, notify_capacity); /* Start a sequence in the notify output port. */ - lv2_atom_forge_sequence_head(&plugin->forge, &plugin->notify_frame, 0); + lv2_atom_forge_sequence_head(&self->forge, &self->notify_frame, 0); /* Read incoming events */ - LV2_SEQUENCE_FOREACH(plugin->control_port, i) { + LV2_SEQUENCE_FOREACH(self->control_port, i) { LV2_Atom_Event* const ev = lv2_sequence_iter_get(i); - plugin->frame_offset = ev->time.frames; + self->frame_offset = ev->time.frames; if (ev->body.type == uris->midi_Event) { uint8_t* const data = (uint8_t* const)(ev + 1); if ((data[0] & 0xF0) == 0x90) { start_frame = ev->time.frames; - plugin->frame = 0; - plugin->play = true; + self->frame = 0; + self->play = true; } } else if (is_object_type(uris, ev->body.type)) { const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body; if (obj->body.otype == uris->patch_Set) { /* Received a set message, send it to the worker. */ - fprintf(stderr, "Queueing set message\n"); - plugin->schedule->schedule_work(plugin->schedule->handle, + print(self, self->uris.log_Trace, "Queueing set message\n"); + self->schedule->schedule_work(self->schedule->handle, lv2_atom_total_size(&ev->body), &ev->body); } else { - fprintf(stderr, "Unknown object type %d\n", obj->body.otype); + print(self, self->uris.log_Trace, + "Unknown object type %d\n", obj->body.otype); } } else { - fprintf(stderr, "Unknown event type %d\n", ev->body.type); + print(self, self->uris.log_Trace, + "Unknown event type %d\n", ev->body.type); } } /* Render the sample (possibly already in progress) */ - if (plugin->play) { - uint32_t f = plugin->frame; - const uint32_t lf = plugin->sample->info.frames; + if (self->play) { + uint32_t f = self->frame; + const uint32_t lf = self->sample->info.frames; for (pos = 0; pos < start_frame; ++pos) { output[pos] = 0; } for (; pos < sample_count && f < lf; ++pos, ++f) { - output[pos] = plugin->sample->data[f]; + output[pos] = self->sample->data[f]; } - plugin->frame = f; + self->frame = f; if (f == lf) { - plugin->play = false; + self->play = false; } } @@ -381,15 +407,15 @@ save(LV2_Handle instance, } } - Sampler* plugin = (Sampler*)instance; + Sampler* self = (Sampler*)instance; char* apath = map_path->abstract_path(map_path->handle, - plugin->sample->path); + self->sample->path); store(handle, - plugin->uris.eg_file, + self->uris.eg_file, apath, - strlen(plugin->sample->path) + 1, - plugin->uris.atom_Path, + strlen(self->sample->path) + 1, + self->uris.atom_Path, LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); free(apath); @@ -404,7 +430,7 @@ restore(LV2_Handle instance, uint32_t flags, const LV2_Feature* const* features) { - Sampler* plugin = (Sampler*)instance; + Sampler* self = (Sampler*)instance; size_t size; uint32_t type; @@ -412,14 +438,14 @@ restore(LV2_Handle instance, const void* value = retrieve( handle, - plugin->uris.eg_file, + self->uris.eg_file, &size, &type, &valflags); if (value) { const char* path = (const char*)value; - printf("Restoring file %s\n", path); - free_sample(plugin->sample); - plugin->sample = load_sample(plugin, path); + print(self, self->uris.log_Trace, "Restoring file %s\n", path); + free_sample(self, self->sample); + self->sample = load_sample(self, path); } return LV2_STATE_SUCCESS; diff --git a/plugins/eg-sampler.lv2/uris.h b/plugins/eg-sampler.lv2/uris.h index 9372418..3f080ef 100644 --- a/plugins/eg-sampler.lv2/uris.h +++ b/plugins/eg-sampler.lv2/uris.h @@ -19,6 +19,7 @@ #define SAMPLER_URIS_H #include "lv2/lv2plug.in/ns/ext/state/state.h" +#include "lv2/lv2plug.in/ns/ext/log/log.h" #define LV2_MIDI__MidiEvent "http://lv2plug.in/ns/ext/midi#MidiEvent" @@ -36,6 +37,8 @@ typedef struct { LV2_URID eg_applySample; LV2_URID eg_file; LV2_URID eg_freeSample; + LV2_URID log_Error; + LV2_URID log_Trace; LV2_URID midi_Event; LV2_URID patch_Set; LV2_URID patch_body; @@ -52,6 +55,8 @@ map_sampler_uris(LV2_URID_Map* map, SamplerURIs* uris) uris->eg_applySample = map->map(map->handle, EG_SAMPLER__applySample); uris->eg_file = map->map(map->handle, EG_SAMPLER__file); uris->eg_freeSample = map->map(map->handle, EG_SAMPLER__freeSample); + uris->log_Error = map->map(map->handle, LV2_LOG__Error); + uris->log_Trace = map->map(map->handle, LV2_LOG__Trace); uris->midi_Event = map->map(map->handle, LV2_MIDI__MidiEvent); uris->patch_Set = map->map(map->handle, LV2_PATCH__Set); uris->patch_body = map->map(map->handle, LV2_PATCH__body); diff --git a/plugins/eg-sampler.lv2/wscript b/plugins/eg-sampler.lv2/wscript index dfbfdfc..7b5c7ad 100644 --- a/plugins/eg-sampler.lv2/wscript +++ b/plugins/eg-sampler.lv2/wscript @@ -22,17 +22,7 @@ def configure(conf): autowaf.display_header('Sampler Configuration') if not autowaf.is_child(): - autowaf.check_pkg(conf, 'lv2core', uselib_store='LV2CORE') - autowaf.check_pkg(conf, 'lv2-lv2plug.in-ns-ext-urid', - uselib_store='LV2_URID') - autowaf.check_pkg(conf, 'lv2-lv2plug.in-ns-ext-atom', - uselib_store='LV2_ATOM') - autowaf.check_pkg(conf, 'lv2-lv2plug.in-ns-ext-patch', - uselib_store='LV2_PATCH') - autowaf.check_pkg(conf, 'lv2-lv2plug.in-ns-ext-state', - uselib_store='LV2_STATE') - autowaf.check_pkg(conf, 'lv2-lv2plug.in-ns-ext-worker', - uselib_store='LV2_WORKER') + autowaf.check_pkg(conf, 'lv2', atleast_version='0.2.0', uselib_store='LV2') autowaf.check_pkg(conf, 'sndfile', uselib_store='SNDFILE', atleast_version='1.0.0', mandatory=True) @@ -86,7 +76,7 @@ def build(bld): name = 'sampler', target = '%s/sampler' % bundle, install_path = '${LV2DIR}/%s' % bundle, - use = 'SNDFILE LV2CORE LV2_URID LV2_ATOM LV2_STATE LV2_PATCH LV2_WORKER', + use = 'SNDFILE LV2', includes = includes) # Build UI library @@ -97,6 +87,6 @@ def build(bld): name = 'sampler_ui', target = '%s/sampler_ui' % bundle, install_path = '${LV2DIR}/%s' % bundle, - use = 'GTK2 LV2CORE LV2_URID LV2_ATOM LV2_PATCH', + use = 'GTK2 LV2', includes = includes) @@ -14,7 +14,7 @@ import waflib.Scripting as Scripting # Variables for 'waf dist' APPNAME = 'lv2' -VERSION = '0.1.0' +VERSION = '0.2.0' # Mandatory variables top = '.' |