diff options
| author | David Robillard <d@drobilla.net> | 2025-11-13 17:55:18 -0500 |
|---|---|---|
| committer | David Robillard <d@drobilla.net> | 2025-11-13 19:59:41 -0500 |
| commit | cbe7327ff36ca6b142c43c0e0491b989726ecc9b (patch) | |
| tree | acc598ee074a58152cc91953c272be728cc8c9c6 /plugins/eg-metro.lv2 | |
| parent | c664e354487332ba5f204c62a4a5df41b2cbda1f (diff) | |
| download | lv2-cbe7327ff36ca6b142c43c0e0491b989726ecc9b.tar.xz | |
Remove example plugins
These are now maintained in the separate "lv2-examples" project to keep the
dependencies of lv2 itself minimal.
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/meson.build | 42 | ||||
| -rw-r--r-- | plugins/eg-metro.lv2/metro.c | 341 | ||||
| -rw-r--r-- | plugins/eg-metro.lv2/metro.ttl | 30 |
5 files changed, 0 insertions, 429 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/meson.build b/plugins/eg-metro.lv2/meson.build deleted file mode 100644 index ee4016e..0000000 --- a/plugins/eg-metro.lv2/meson.build +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2022 David Robillard <d@drobilla.net> -# SPDX-License-Identifier: 0BSD OR ISC - -plugin_sources = files('metro.c') -bundle_name = 'eg-metro.lv2' -data_filenames = ['manifest.ttl.in', 'metro.ttl'] - -module = shared_library( - 'metro', - plugin_sources, - c_args: c_suppressions, - dependencies: [lv2_dep, m_dep], - gnu_symbol_visibility: 'hidden', - implicit_include_directories: false, - install: true, - install_dir: lv2dir / bundle_name, - name_prefix: '', -) - -config = configuration_data( - { - 'LIB_EXT': '.' + module.full_path().split('.')[-1], - }, -) - -foreach filename : data_filenames - if filename.endswith('.in') - configure_file( - configuration: config, - input: files(filename), - install_dir: lv2dir / bundle_name, - output: filename.substring(0, -3), - ) - else - configure_file( - copy: true, - input: files(filename), - install_dir: lv2dir / bundle_name, - output: filename, - ) - endif -endforeach diff --git a/plugins/eg-metro.lv2/metro.c b/plugins/eg-metro.lv2/metro.c deleted file mode 100644 index 8e4c738..0000000 --- a/plugins/eg-metro.lv2/metro.c +++ /dev/null @@ -1,341 +0,0 @@ -// Copyright 2012-2016 David Robillard <d@drobilla.net> -// SPDX-License-Identifier: ISC - -#include <lv2/atom/atom.h> -#include <lv2/atom/util.h> -#include <lv2/core/lv2.h> -#include <lv2/core/lv2_util.h> -#include <lv2/log/log.h> -#include <lv2/log/logger.h> -#include <lv2/time/time.h> -#include <lv2/urid/urid.h> - -#include <math.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.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_Object; - 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_OUT = 1 }; - -/** During execution this plugin can be in one of 3 states: */ -typedef enum { - STATE_ATTACK, // Envelope rising - STATE_DECAY, // Envelope lowering - STATE_OFF // Silent -} State; - -/** - This plugin must keep track of more state than previous examples to be able - to render audio. The basic idea is to generate a single cycle of a sine - wave which is conceptually played continuously. The 'tick' is generated by - enveloping the amplitude so there is a short attack/decay peak around a - tick, and silence the rest of the time. - - This example 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, the frequency of the wave, and so on. -*/ -typedef struct { - LV2_URID_Map* map; // URID map feature - LV2_Log_Logger logger; // Logger API - MetroURIs uris; // Cache of mapped URIDs - - struct { - LV2_Atom_Sequence* control; - float* output; - } ports; - - // Variables to keep track of the tempo information sent by the host - double rate; // Sample rate - float bpm; // Beats per minute (tempo) - float speed; // Transport speed (usually 0=stop, 1=play) - - uint32_t elapsed_len; // Frames since the start of the last click - uint32_t wave_offset; // Current play offset in the wave - State state; // Current play state - - // One cycle of a sine wave - float* wave; - uint32_t wave_len; - - // Envelope 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_OUT: - self->ports.output = (float*)data; - break; - default: - break; - } -} - -/** - The activate() method resets the state completely, so the wave offset is - zero and the envelope is off. -*/ -static void -activate(LV2_Handle instance) -{ - Metro* self = (Metro*)instance; - - self->elapsed_len = 0; - self->wave_offset = 0; - 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, - 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 - // clang-format off - const char* missing = lv2_features_query( - features, - LV2_LOG__log, &self->logger.log, false, - LV2_URID__map, &self->map, true, - NULL); - // clang-format on - - lv2_log_logger_set_map(&self->logger, self->map); - if (missing) { - lv2_log_error(&self->logger, "Missing feature <%s>\n", missing); - free(self); - return NULL; - } - - // Map URIS - MetroURIs* const uris = &self->uris; - LV2_URID_Map* const map = self->map; - uris->atom_Blank = map->map(map->handle, LV2_ATOM__Blank); - uris->atom_Float = map->map(map->handle, LV2_ATOM__Float); - uris->atom_Object = map->map(map->handle, LV2_ATOM__Object); - 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 instance fields - self->rate = rate; - self->bpm = 120.0f; - self->attack_len = (uint32_t)(attack_s * rate); - self->decay_len = (uint32_t)(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 = (uint32_t)(rate / freq); - self->wave = (float*)malloc(self->wave_len * sizeof(float)); - for (uint32_t i = 0; i < self->wave_len; ++i) { - self->wave[i] = (float)(sin(i * 2 * M_PI * freq / rate) * amp); - } - - return (LV2_Handle)self; -} - -static void -cleanup(LV2_Handle instance) -{ - Metro* self = (Metro*)instance; - free(self->wave); - free(self); -} - -/** - 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) -{ - float* const output = self->ports.output; - const uint32_t frames_per_beat = (uint32_t)(60.0f / self->bpm * self->rate); - const float attack_den = self->attack_len ? (float)self->attack_len : 1.0f; - - 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] * (float)self->elapsed_len / attack_den; - 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 - ((float)(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; - } - } -} - -/** - 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) -{ - const MetroURIs* uris = &self->uris; - - // Received new transport position/speed - LV2_Atom* beat = NULL; - LV2_Atom* bpm = NULL; - LV2_Atom* speed = NULL; - // clang-format off - lv2_atom_object_get(obj, - uris->time_barBeat, &beat, - uris->time_beatsPerMinute, &bpm, - uris->time_speed, &speed, - NULL); - // clang-format on - - 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 hard sync may cause clicks, a real plugin would be more graceful - const float frames_per_beat = (float)(60.0 / 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 = (uint32_t)(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; - - // 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 (const 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, (uint32_t)ev->time.frames); - - // Check if this event is an Object - // (or deprecated Blank to tolerate old hosts) - if (ev->body.type == uris->atom_Object || - ev->body.type == uris->atom_Blank) { - const LV2_Atom_Object* obj = (const 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 = (uint32_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) -{ - return index == 0 ? &descriptor : NULL; -} diff --git a/plugins/eg-metro.lv2/metro.ttl b/plugins/eg-metro.lv2/metro.ttl deleted file mode 100644 index 8b4af3d..0000000 --- a/plugins/eg-metro.lv2/metro.ttl +++ /dev/null @@ -1,30 +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:AudioPort , - lv2:OutputPort ; - lv2:index 1 ; - lv2:symbol "out" ; - lv2:name "Out" ; - ] . |