aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/eg-metro.lv2
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2013-02-11 00:18:55 +0000
committerDavid Robillard <d@drobilla.net>2013-02-11 00:18:55 +0000
commitb91e1a81db7b45d0460da1c8a134d855e0ff265c (patch)
tree3da714cd19b9171bc48614f1442c82383550ffca /plugins/eg-metro.lv2
parent5367f7265e123aa8a26f8e3d3fb964f18c3250b2 (diff)
downloadlv2-b91e1a81db7b45d0460da1c8a134d855e0ff265c.tar.xz
Order examples in a sensible progression for the book.
Diffstat (limited to 'plugins/eg-metro.lv2')
-rw-r--r--plugins/eg-metro.lv2/README.txt9
-rw-r--r--plugins/eg-metro.lv2/manifest.ttl.in7
-rw-r--r--plugins/eg-metro.lv2/metro.c347
-rw-r--r--plugins/eg-metro.lv2/metro.ttl39
l---------plugins/eg-metro.lv2/waf1
-rw-r--r--plugins/eg-metro.lv2/wscript64
6 files changed, 0 insertions, 467 deletions
diff --git a/plugins/eg-metro.lv2/README.txt b/plugins/eg-metro.lv2/README.txt
deleted file mode 100644
index 5e9a84a..0000000
--- a/plugins/eg-metro.lv2/README.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-== Metronome ==
-
-This plugin demonstrates tempo synchronisation by clicking on every beat. The
-host sends this information to the plugin as events, so an event with new time
-and tempo information will be received whenever there is a change.
-
-Time is assumed to continue rolling at the tempo and speed defined by the last
-received tempo event, even across cycles, until a new tempo event is received
-or the plugin is deactivated.
diff --git a/plugins/eg-metro.lv2/manifest.ttl.in b/plugins/eg-metro.lv2/manifest.ttl.in
deleted file mode 100644
index bd93f66..0000000
--- a/plugins/eg-metro.lv2/manifest.ttl.in
+++ /dev/null
@@ -1,7 +0,0 @@
-@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
-@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
-
-<http://lv2plug.in/plugins/eg-metro>
- a lv2:Plugin ;
- lv2:binary <metro@LIB_EXT@> ;
- rdfs:seeAlso <metro.ttl> .
diff --git a/plugins/eg-metro.lv2/metro.c b/plugins/eg-metro.lv2/metro.c
deleted file mode 100644
index 97821a1..0000000
--- a/plugins/eg-metro.lv2/metro.c
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- LV2 Metronome Example Plugin
- Copyright 2012 David Robillard <d@drobilla.net>
-
- 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.
-*/
-
-#include <math.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifndef __cplusplus
-# include <stdbool.h>
-#endif
-
-#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
-#include "lv2/lv2plug.in/ns/ext/atom/util.h"
-#include "lv2/lv2plug.in/ns/ext/time/time.h"
-#include "lv2/lv2plug.in/ns/ext/urid/urid.h"
-#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
-
-#ifndef M_PI
-# define M_PI 3.14159265
-#endif
-
-#define EG_METRO_URI "http://lv2plug.in/plugins/eg-metro"
-
-typedef struct {
- LV2_URID atom_Blank;
- LV2_URID atom_Float;
- LV2_URID atom_Path;
- LV2_URID atom_Resource;
- LV2_URID atom_Sequence;
- LV2_URID time_Position;
- LV2_URID time_barBeat;
- LV2_URID time_beatsPerMinute;
- LV2_URID time_speed;
-} MetroURIs;
-
-static const double attack_s = 0.005;
-static const double decay_s = 0.075;
-
-enum {
- METRO_CONTROL = 0,
- METRO_NOTIFY = 1,
- METRO_OUT = 2
-};
-
-typedef enum {
- STATE_ATTACK,
- STATE_DECAY,
- STATE_OFF
-} State;
-
-typedef struct {
- /* Features */
- LV2_URID_Map* map;
-
- /* URIs */
- MetroURIs uris;
-
- /* Ports */
- struct {
- LV2_Atom_Sequence* control;
- LV2_Atom_Sequence* notify;
- float* output;
- } ports;
-
- /** The rate, bpm, and speed are the basic information sent by the host. */
- double rate;
- float bpm;
- float speed;
-
- /** To keep track of when to play the next click, we need to keep track of
- a few pieces of information: */
-
- /** - The frames since the start of the last click is stored */
- uint32_t elapsed_len;
-
- /** - The current play offset in the wave */
- uint32_t wave_offset;
-
- /** - The current play state (attack, decay, or off) */
- State state;
-
- /** The wave to play is a simple sine wave generated at instantiation time
- based on the sample rate. The length in frames is stored in order to
- continuously play the wave in a cycle to avoid discontinuity clicks. */
- float* wave;
- uint32_t wave_len;
-
- /** The continuously playing sine wave is enveloped to provide an actual
- metronome tick. This plugin uses a simple AD envelope with fixed
- parameters. A more sophisticated implementation might use a more
- advanced envelope and allow the user to modify these parameters. */
- uint32_t attack_len;
- uint32_t decay_len;
-} Metro;
-
-static void
-connect_port(LV2_Handle instance,
- uint32_t port,
- void* data)
-{
- Metro* self = (Metro*)instance;
-
- switch (port) {
- case METRO_CONTROL:
- self->ports.control = (LV2_Atom_Sequence*)data;
- break;
- case METRO_NOTIFY:
- self->ports.notify = (LV2_Atom_Sequence*)data;
- break;
- case METRO_OUT:
- self->ports.output = (float*)data;
- break;
- default:
- break;
- }
-}
-
-static void
-activate(LV2_Handle instance)
-{
- Metro* self = (Metro*)instance;
-
- self->elapsed_len = 0;
- self->wave_offset = 0;
- self->state = STATE_OFF;
-}
-
-static LV2_Handle
-instantiate(const LV2_Descriptor* descriptor,
- double rate,
- const char* path,
- const LV2_Feature* const* features)
-{
- Metro* self = (Metro*)calloc(1, sizeof(Metro));
- if (!self) {
- return NULL;
- }
-
- /** Scan host features for URID map */
- LV2_URID_Map* map = NULL;
- for (int i = 0; features[i]; ++i) {
- if (!strcmp(features[i]->URI, LV2_URID_URI "#map")) {
- map = (LV2_URID_Map*)features[i]->data;
- }
- }
- if (!map) {
- fprintf(stderr, "Host does not support urid:map.\n");
- free(self);
- return NULL;
- }
-
- /** Map URIS */
- MetroURIs* const uris = &self->uris;
- self->map = map;
- uris->atom_Blank = map->map(map->handle, LV2_ATOM__Blank);
- uris->atom_Float = map->map(map->handle, LV2_ATOM__Float);
- uris->atom_Path = map->map(map->handle, LV2_ATOM__Path);
- uris->atom_Resource = map->map(map->handle, LV2_ATOM__Resource);
- uris->atom_Sequence = map->map(map->handle, LV2_ATOM__Sequence);
- uris->time_Position = map->map(map->handle, LV2_TIME__Position);
- uris->time_barBeat = map->map(map->handle, LV2_TIME__barBeat);
- uris->time_beatsPerMinute = map->map(map->handle, LV2_TIME__beatsPerMinute);
- uris->time_speed = map->map(map->handle, LV2_TIME__speed);
-
- /** Initialise fields */
- self->rate = rate;
- self->bpm = 120.0f;
- self->attack_len = attack_s * rate;
- self->decay_len = decay_s * rate;
- self->state = STATE_OFF;
-
- /** Generate one cycle of a sine wave at the desired frequency. */
- const double freq = 440.0 * 2.0;
- const double amp = 0.5;
- self->wave_len = rate / freq;
- self->wave = (float*)malloc(self->wave_len * sizeof(float));
- for (uint32_t i = 0; i < self->wave_len; ++i) {
- self->wave[i] = sin(i * 2 * M_PI * freq / rate) * amp;
- }
-
- return (LV2_Handle)self;
-}
-
-static void
-cleanup(LV2_Handle instance)
-{
- free(instance);
-}
-
-static void
-play(Metro* self, uint32_t begin, uint32_t end)
-{
- float* const output = self->ports.output;
- const uint32_t frames_per_beat = 60.0f / self->bpm * self->rate;
-
- if (self->speed == 0.0f) {
- memset(output, 0, (end - begin) * sizeof(float));
- return;
- }
-
- for (uint32_t i = begin; i < end; ++i) {
- switch (self->state) {
- case STATE_ATTACK:
- /** Amplitude increases from 0..1 until attack_len */
- output[i] = self->wave[self->wave_offset] *
- self->elapsed_len / (float)self->attack_len;
- if (self->elapsed_len >= self->attack_len) {
- self->state = STATE_DECAY;
- }
- break;
- case STATE_DECAY:
- /** Amplitude decreases from 1..0 until attack_len + decay_len */
- output[i] = 0.0f;
- output[i] = self->wave[self->wave_offset] *
- (1 - ((self->elapsed_len - self->attack_len) /
- (float)self->decay_len));
- if (self->elapsed_len >= self->attack_len + self->decay_len) {
- self->state = STATE_OFF;
- }
- break;
- case STATE_OFF:
- output[i] = 0.0f;
- }
-
- /** We continuously play the sine wave regardless of envelope */
- self->wave_offset = (self->wave_offset + 1) % self->wave_len;
-
- /** Update elapsed time and start attack if necessary */
- if (++self->elapsed_len == frames_per_beat) {
- self->state = STATE_ATTACK;
- self->elapsed_len = 0;
- }
- }
-}
-
-static void
-update_position(Metro* self, const LV2_Atom_Object* obj)
-{
- const MetroURIs* uris = &self->uris;
-
- /** Received new transport position/speed */
- LV2_Atom *beat = NULL, *bpm = NULL, *speed = NULL;
- lv2_atom_object_get(obj,
- uris->time_barBeat, &beat,
- uris->time_beatsPerMinute, &bpm,
- uris->time_speed, &speed,
- NULL);
- if (bpm && bpm->type == uris->atom_Float) {
- /** Tempo changed, update BPM */
- self->bpm = ((LV2_Atom_Float*)bpm)->body;
- }
- if (speed && speed->type == uris->atom_Float) {
- /** Speed changed, e.g. 0 (stop) to 1 (play) */
- self->speed = ((LV2_Atom_Float*)speed)->body;
- }
- if (beat && beat->type == uris->atom_Float) {
- /** Received a beat position, synchronise.
- This is a simple hard sync that may cause clicks.
- A real plugin would do something more graceful.
- */
- const float frames_per_beat = 60.0f / self->bpm * self->rate;
- const float bar_beats = ((LV2_Atom_Float*)beat)->body;
- const float beat_beats = bar_beats - floorf(bar_beats);
- self->elapsed_len = beat_beats * frames_per_beat;
- if (self->elapsed_len < self->attack_len) {
- self->state = STATE_ATTACK;
- } else if (self->elapsed_len < self->attack_len + self->decay_len) {
- self->state = STATE_DECAY;
- } else {
- self->state = STATE_OFF;
- }
- }
-}
-
-static void
-run(LV2_Handle instance, uint32_t sample_count)
-{
- Metro* self = (Metro*)instance;
- const MetroURIs* uris = &self->uris;
-
- /** Empty notify output for now */
- LV2_Atom_Sequence* notify = self->ports.notify;
- notify->atom.type = self->uris.atom_Sequence;
- notify->atom.size = sizeof(LV2_Atom_Sequence_Body);
- notify->body.unit = notify->body.pad = 0;
-
- /** Work forwards in time frame by frame, handling events as we go */
- const LV2_Atom_Sequence* in = self->ports.control;
- uint32_t last_t = 0;
- for (LV2_Atom_Event* ev = lv2_atom_sequence_begin(&in->body);
- !lv2_atom_sequence_is_end(&in->body, in->atom.size, ev);
- ev = lv2_atom_sequence_next(ev)) {
-
- /** Play the click for the time slice from last_t until now */
- play(self, last_t, ev->time.frames);
-
- if (ev->body.type == uris->atom_Blank) {
- const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body;
- if (obj->body.otype == uris->time_Position) {
- /** Received position information, update */
- update_position(self, obj);
- }
- }
-
- /** Update time for next iteration and move to next event*/
- last_t = ev->time.frames;
- }
-
- /** Play for remainder of cycle */
- play(self, last_t, sample_count);
-}
-
-static const LV2_Descriptor descriptor = {
- EG_METRO_URI,
- instantiate,
- connect_port,
- activate,
- run,
- NULL, // deactivate,
- cleanup,
- NULL, // extension_data
-};
-
-LV2_SYMBOL_EXPORT const LV2_Descriptor*
-lv2_descriptor(uint32_t index)
-{
- switch (index) {
- case 0:
- return &descriptor;
- default:
- return NULL;
- }
-}
diff --git a/plugins/eg-metro.lv2/metro.ttl b/plugins/eg-metro.lv2/metro.ttl
deleted file mode 100644
index a6f297f..0000000
--- a/plugins/eg-metro.lv2/metro.ttl
+++ /dev/null
@@ -1,39 +0,0 @@
-@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
-@prefix doap: <http://usefulinc.com/ns/doap#> .
-@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
-@prefix time: <http://lv2plug.in/ns/ext/time#> .
-@prefix urid: <http://lv2plug.in/ns/ext/urid#> .
-
-<http://lv2plug.in/plugins/eg-metro>
- a lv2:Plugin ;
- doap:name "Example Metronome" ;
- doap:license <http://opensource.org/licenses/isc> ;
- lv2:project <http://lv2plug.in/ns/lv2> ;
- lv2:requiredFeature urid:map ;
- lv2:optionalFeature lv2:hardRTCapable ;
- lv2:port [
- a lv2:InputPort ,
- atom:AtomPort ;
- atom:bufferType atom:Sequence ;
-# Since this port supports time:Position, the host knows to deliver time and
-# tempo information
- atom:supports time:Position ;
- lv2:index 0 ;
- lv2:symbol "control" ;
- lv2:name "Control" ;
- ] , [
- a lv2:OutputPort ,
- atom:AtomPort ;
- atom:bufferType atom:Sequence ;
- atom:supports <http://lv2plug.in/ns/ext/patch#Patch> ;
- lv2:portProperty lv2:connectionOptional ;
- lv2:index 1 ;
- lv2:symbol "notify" ;
- lv2:name "Notify" ;
- ] , [
- a lv2:AudioPort ,
- lv2:OutputPort ;
- lv2:index 2 ;
- lv2:symbol "out" ;
- lv2:name "Out" ;
- ] .
diff --git a/plugins/eg-metro.lv2/waf b/plugins/eg-metro.lv2/waf
deleted file mode 120000
index 59a1ac9..0000000
--- a/plugins/eg-metro.lv2/waf
+++ /dev/null
@@ -1 +0,0 @@
-../../waf \ No newline at end of file
diff --git a/plugins/eg-metro.lv2/wscript b/plugins/eg-metro.lv2/wscript
deleted file mode 100644
index 40642b6..0000000
--- a/plugins/eg-metro.lv2/wscript
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/usr/bin/env python
-from waflib.extras import autowaf as autowaf
-import re
-
-# Variables for 'waf dist'
-APPNAME = 'eg-metro.lv2'
-VERSION = '1.0.0'
-
-# Mandatory variables
-top = '.'
-out = 'build'
-
-def options(opt):
- opt.load('compiler_c')
- autowaf.set_options(opt)
-
-def configure(conf):
- conf.load('compiler_c')
- autowaf.configure(conf)
- autowaf.set_c99_mode(conf)
- autowaf.display_header('Metro Configuration')
-
- if not autowaf.is_child():
- autowaf.check_pkg(conf, 'lv2', atleast_version='0.2.0', uselib_store='LV2')
-
- autowaf.display_msg(conf, 'LV2 bundle directory', conf.env.LV2DIR)
- print('')
-
-def build(bld):
- bundle = 'eg-metro.lv2'
-
- # Make a pattern for shared objects without the 'lib' prefix
- module_pat = re.sub('^lib', '', bld.env.cshlib_PATTERN)
- module_ext = module_pat[module_pat.rfind('.'):]
-
- # Build manifest.ttl by substitution (for portable lib extension)
- bld(features = 'subst',
- source = 'manifest.ttl.in',
- target = '%s/%s' % (bundle, 'manifest.ttl'),
- install_path = '${LV2DIR}/%s' % bundle,
- LIB_EXT = module_ext)
-
- # Copy other data files to build bundle (build/eg-metro.lv2)
- bld(features = 'subst',
- is_copy = True,
- source = 'metro.ttl',
- target = '%s/metro.ttl' % bundle,
- install_path = '${LV2DIR}/%s' % bundle)
-
- # Use LV2 headers from parent directory if building as a sub-project
- includes = ['.']
- if autowaf.is_child:
- includes += ['../..']
-
- # Build plugin library
- obj = bld(features = 'c cshlib',
- source = 'metro.c',
- name = 'metro',
- target = '%s/metro' % bundle,
- install_path = '${LV2DIR}/%s' % bundle,
- use = 'LV2',
- includes = includes)
- obj.env.cshlib_PATTERN = module_pat
-