aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2013-02-18 03:05:55 +0000
committerDavid Robillard <d@drobilla.net>2013-02-18 03:05:55 +0000
commitf78962ae66a6e09bf372839665a150786fca8100 (patch)
treee37a41ab136e10263a951d3ae901f50aeb7a3942
parente5ffd577fced7c2d55b0298af8eb6a4581de82a6 (diff)
downloadlv2-f78962ae66a6e09bf372839665a150786fca8100.tar.xz
Clean up sampler exampler for book format.
-rw-r--r--plugins/eg03-metro.lv2/metro.c18
-rw-r--r--plugins/eg04-sampler.lv2/README.txt12
-rw-r--r--plugins/eg04-sampler.lv2/manifest.ttl.in6
-rw-r--r--plugins/eg04-sampler.lv2/sampler.c81
-rw-r--r--plugins/eg04-sampler.lv2/sampler.ttl17
5 files changed, 69 insertions, 65 deletions
diff --git a/plugins/eg03-metro.lv2/metro.c b/plugins/eg03-metro.lv2/metro.c
index 925c1e7..51125af 100644
--- a/plugins/eg03-metro.lv2/metro.c
+++ b/plugins/eg03-metro.lv2/metro.c
@@ -119,6 +119,10 @@ connect_port(LV2_Handle instance,
}
}
+/**
+ The activate() method resets the state completely, so the wave offset is
+ zero and the envelope is off.
+*/
static void
activate(LV2_Handle instance)
{
@@ -129,6 +133,12 @@ activate(LV2_Handle instance)
self->state = STATE_OFF;
}
+/**
+ This plugin does a bit more work in instantiate() than the previous
+ examples. The tempo updates from the host contain several URIs, so those
+ are mapped, and the sine wave to be played needs to be generated based on
+ the current sample rate.
+*/
static LV2_Handle
instantiate(const LV2_Descriptor* descriptor,
double rate,
@@ -191,6 +201,10 @@ cleanup(LV2_Handle instance)
free(instance);
}
+/**
+ Play back audio for the range [begin..end) relative to this cycle. This is
+ called by run() in-between events to output audio up until the current time.
+*/
static void
play(Metro* self, uint32_t begin, uint32_t end)
{
@@ -237,6 +251,10 @@ play(Metro* self, uint32_t begin, uint32_t end)
}
}
+/**
+ Update the current position based on a host message. This is called by
+ run() when a time:Position is received.
+*/
static void
update_position(Metro* self, const LV2_Atom_Object* obj)
{
diff --git a/plugins/eg04-sampler.lv2/README.txt b/plugins/eg04-sampler.lv2/README.txt
index c1cac46..4eed9e6 100644
--- a/plugins/eg04-sampler.lv2/README.txt
+++ b/plugins/eg04-sampler.lv2/README.txt
@@ -1 +1,13 @@
== Sampler ==
+
+This plugin loads a single sample from a .wav file and plays it back when a MIDI
+note on is received. Any sample on the system can be loaded via another event.
+A Gtk UI is included which does this, but the host can as well.
+
+This plugin illustrates:
+
+- UI <==> Plugin communication via events
+- Use of the worker extension for non-realtime tasks (sample loading)
+- Use of the log extension to print log messages via the host
+- Saving plugin state via the state extension
+- Dynamic plugin control via the same properties saved to state
diff --git a/plugins/eg04-sampler.lv2/manifest.ttl.in b/plugins/eg04-sampler.lv2/manifest.ttl.in
index b4fa23e..8a01428 100644
--- a/plugins/eg04-sampler.lv2/manifest.ttl.in
+++ b/plugins/eg04-sampler.lv2/manifest.ttl.in
@@ -1,3 +1,9 @@
+# Unlike the previous examples, this manifest lists more than one resource: the
+# plugin as usual, and the UI. The descriptions are similar, but have
+# different types, so the host can decide from this file alone whether or not
+# it is interested, and avoid following the `rdfs:seeAlso` link if not (though
+# in this case both are described in the same file).
+
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
diff --git a/plugins/eg04-sampler.lv2/sampler.c b/plugins/eg04-sampler.lv2/sampler.c
index 5bb4e54..9353d48 100644
--- a/plugins/eg04-sampler.lv2/sampler.c
+++ b/plugins/eg04-sampler.lv2/sampler.c
@@ -17,21 +17,6 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/**
- @file sampler.c Sampler Plugin
-
- A simple example of an LV2 sampler that dynamically loads a single sample
- (based on incoming events) and triggers their playback (based on incoming
- MIDI note events).
-
- This plugin illustrates:
- - UI <=> Plugin communication via events
- - Use of the worker extension for non-realtime tasks (sample loading)
- - Use of the log extension to print log messages via the host
- - Saving plugin state via the state extension
- - Dynamic plugin control via the same properties saved to state
-*/
-
#include <math.h>
#include <stdlib.h>
#include <string.h>
@@ -63,42 +48,42 @@ enum {
static const char* default_sample_file = "click.wav";
typedef struct {
- SF_INFO info; /**< Info about sample from sndfile */
- float* data; /**< Sample data in float */
- char* path; /**< Path of file */
- size_t path_len; /**< Length of path */
+ SF_INFO info; // Info about sample from sndfile
+ float* data; // Sample data in float
+ char* path; // Path of file
+ size_t path_len; // Length of path
} Sample;
typedef struct {
- /* Features */
+ // Features
LV2_URID_Map* map;
LV2_Worker_Schedule* schedule;
LV2_Log_Log* log;
- /* Forge for creating atoms */
+ // Forge for creating atoms
LV2_Atom_Forge forge;
- /* Logger convenience API */
+ // Logger convenience API
LV2_Log_Logger logger;
- /* Sample */
+ // Sample
Sample* sample;
- /* Ports */
+ // Ports
const LV2_Atom_Sequence* control_port;
LV2_Atom_Sequence* notify_port;
float* output_port;
- /* Forge frame for notify port (for writing worker replies). */
+ // Forge frame for notify port (for writing worker replies)
LV2_Atom_Forge_Frame notify_frame;
- /* URIs */
+ // URIs
SamplerURIs uris;
- /* Current position in run() */
+ // Current position in run()
uint32_t frame_offset;
- /* Playback state */
+ // Playback state
sf_count_t frame;
bool play;
} Sampler;
@@ -140,7 +125,7 @@ load_sample(Sampler* self, const char* path)
return NULL;
}
- /* Read data */
+ // Read data
float* const data = malloc(sizeof(float) * info->frames);
if (!data) {
lv2_log_error(&self->logger, "Failed to allocate memory for sample\n");
@@ -150,7 +135,7 @@ load_sample(Sampler* self, const char* path)
sf_read_float(sndfile, data, info->frames);
sf_close(sndfile);
- /* Fill sample struct and return it. */
+ // Fill sample struct and return it
sample->data = data;
sample->path = (char*)malloc(path_len + 1);
sample->path_len = path_len;
@@ -187,23 +172,23 @@ work(LV2_Handle instance,
Sampler* self = (Sampler*)instance;
const LV2_Atom* atom = (const LV2_Atom*)data;
if (atom->type == self->uris.eg_freeSample) {
- /* Free old sample */
+ // Free old sample
const SampleMessage* msg = (const SampleMessage*)data;
free_sample(self, msg->sample);
} else {
- /* Handle set message (load sample). */
+ // Handle set message (load sample).
const LV2_Atom_Object* obj = (const LV2_Atom_Object*)data;
- /* Get file path from message */
+ // Get file path from message
const LV2_Atom* file_path = read_set_file(&self->uris, obj);
if (!file_path) {
return LV2_WORKER_ERR_UNKNOWN;
}
- /* Load sample. */
+ // Load sample.
Sample* sample = load_sample(self, LV2_ATOM_BODY_CONST(file_path));
if (sample) {
- /* Loaded sample, send it to run() to be applied. */
+ // Loaded sample, send it to run() to be applied.
respond(handle, sizeof(sample), &sample);
}
}
@@ -228,13 +213,13 @@ work_response(LV2_Handle instance,
SampleMessage msg = { { sizeof(Sample*), self->uris.eg_freeSample },
self->sample };
- /* Send a message to the worker to free the current sample */
+ // Send a message to the worker to free the current sample
self->schedule->schedule_work(self->schedule->handle, sizeof(msg), &msg);
- /* Install the new sample */
+ // Install the new sample
self->sample = *(Sample*const*)data;
- /* Send a notification that we're using a new sample. */
+ // Send a notification that we're using a new sample.
lv2_atom_forge_frame_time(&self->forge, self->frame_offset);
write_set_file(&self->forge, &self->uris,
self->sample->path,
@@ -270,14 +255,14 @@ instantiate(const LV2_Descriptor* descriptor,
const char* path,
const LV2_Feature* const* features)
{
- /* Allocate and initialise instance structure. */
+ // Allocate and initialise instance structure.
Sampler* self = (Sampler*)malloc(sizeof(Sampler));
if (!self) {
return NULL;
}
memset(self, 0, sizeof(Sampler));
- /* Get host features */
+ // Get host features
for (int i = 0; features[i]; ++i) {
if (!strcmp(features[i]->URI, LV2_URID__map)) {
self->map = (LV2_URID_Map*)features[i]->data;
@@ -295,12 +280,12 @@ instantiate(const LV2_Descriptor* descriptor,
goto fail;
}
- /* Map URIs and initialise forge/logger */
+ // Map URIs and initialise forge/logger
map_sampler_uris(self->map, &self->uris);
lv2_atom_forge_init(&self->forge, self->map);
lv2_log_logger_init(&self->logger, self->map, self->log);
- /* Load the default sample file */
+ // Load the default sample file
const size_t path_len = strlen(path);
const size_t file_len = strlen(default_sample_file);
const size_t len = path_len + file_len;
@@ -334,16 +319,16 @@ run(LV2_Handle instance,
sf_count_t pos = 0;
float* output = self->output_port;
- /* Set up forge to write directly to notify output port. */
+ // Set up forge to write directly to notify output 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. */
+ // Start a sequence in the notify output port.
lv2_atom_forge_sequence_head(&self->forge, &self->notify_frame, 0);
- /* Read incoming events */
+ // Read incoming events
LV2_ATOM_SEQUENCE_FOREACH(self->control_port, ev) {
self->frame_offset = ev->time.frames;
if (ev->body.type == uris->midi_Event) {
@@ -360,7 +345,7 @@ run(LV2_Handle instance,
} 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. */
+ // Received a set message, send it to the worker.
lv2_log_trace(&self->logger, "Queueing set message\n");
self->schedule->schedule_work(self->schedule->handle,
lv2_atom_total_size(&ev->body),
@@ -375,7 +360,7 @@ run(LV2_Handle instance,
}
}
- /* Render the sample (possibly already in progress) */
+ // Render the sample (possibly already in progress)
if (self->play) {
uint32_t f = self->frame;
const uint32_t lf = self->sample->info.frames;
@@ -395,7 +380,7 @@ run(LV2_Handle instance,
}
}
- /* Add zeros to end if sample not long enough (or not playing) */
+ // Add zeros to end if sample not long enough (or not playing)
for (; pos < sample_count; ++pos) {
output[pos] = 0.0f;
}
diff --git a/plugins/eg04-sampler.lv2/sampler.ttl b/plugins/eg04-sampler.lv2/sampler.ttl
index e008de0..f705dd1 100644
--- a/plugins/eg04-sampler.lv2/sampler.ttl
+++ b/plugins/eg04-sampler.lv2/sampler.ttl
@@ -1,20 +1,3 @@
-# LV2 Sampler Example Plugin
-# Copyright 2011-2012 David Robillard <d@drobilla.net>
-# Copyright 2011 Gabriel M. Beddingfield <gabriel@teuton.org>
-# Copyright 2011 James Morris <jwm.art.net@gmail.com>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .