diff options
Diffstat (limited to 'plugins/eg-metro.lv2')
-rw-r--r-- | plugins/eg-metro.lv2/README.txt | 9 | ||||
-rw-r--r-- | plugins/eg-metro.lv2/manifest.ttl.in | 7 | ||||
-rw-r--r-- | plugins/eg-metro.lv2/metro.c | 347 | ||||
-rw-r--r-- | plugins/eg-metro.lv2/metro.ttl | 39 | ||||
l--------- | plugins/eg-metro.lv2/waf | 1 | ||||
-rw-r--r-- | plugins/eg-metro.lv2/wscript | 64 |
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 - |