Browse Source

Clean up sampler exampler for book format.

zrythm_meson
David Robillard 10 years ago
parent
commit
f78962ae66
  1. 18
      plugins/eg03-metro.lv2/metro.c
  2. 12
      plugins/eg04-sampler.lv2/README.txt
  3. 6
      plugins/eg04-sampler.lv2/manifest.ttl.in
  4. 81
      plugins/eg04-sampler.lv2/sampler.c
  5. 17
      plugins/eg04-sampler.lv2/sampler.ttl

18
plugins/eg03-metro.lv2/metro.c

@ -119,6 +119,10 @@ connect_port(LV2_Handle instance, @@ -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) @@ -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) @@ -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) @@ -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)
{

12
plugins/eg04-sampler.lv2/README.txt

@ -1 +1,13 @@ @@ -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

6
plugins/eg04-sampler.lv2/manifest.ttl.in

@ -1,3 +1,9 @@ @@ -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#> .

81
plugins/eg04-sampler.lv2/sampler.c

@ -17,21 +17,6 @@ @@ -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 { @@ -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) @@ -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) @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, @@ -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;
}

17
plugins/eg04-sampler.lv2/sampler.ttl

@ -1,20 +1,3 @@ @@ -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#> .

Loading…
Cancel
Save