aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2012-04-05 21:22:22 +0000
committerDavid Robillard <d@drobilla.net>2012-04-05 21:22:22 +0000
commitf0e080e9103bfd867826ecac22f39338d5f3e829 (patch)
treee032981decded362e4da3b87dbb5a9b7c008f494
parent17c6df0bc3043c57d2c02c58284ec4794f656b3c (diff)
downloadlv2-f0e080e9103bfd867826ecac22f39338d5f3e829.tar.xz
Twiddle log extension class hierarchy a bit, and all log:Trace level.
Use log extension in eg-sample if available.
-rw-r--r--lv2/lv2plug.in/ns/ext/log/log.h20
-rw-r--r--lv2/lv2plug.in/ns/ext/log/log.ttl29
-rw-r--r--plugins/eg-sampler.lv2/sampler.c152
-rw-r--r--plugins/eg-sampler.lv2/uris.h5
-rw-r--r--plugins/eg-sampler.lv2/wscript16
-rw-r--r--wscript2
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)
diff --git a/wscript b/wscript
index f73c912..12ba382 100644
--- a/wscript
+++ b/wscript
@@ -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 = '.'