aboutsummaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2025-11-13 17:55:18 -0500
committerDavid Robillard <d@drobilla.net>2025-11-13 19:59:41 -0500
commitcbe7327ff36ca6b142c43c0e0491b989726ecc9b (patch)
treeacc598ee074a58152cc91953c272be728cc8c9c6 /plugins
parentc664e354487332ba5f204c62a4a5df41b2cbda1f (diff)
downloadlv2-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')
-rw-r--r--plugins/.clang-tidy16
-rw-r--r--plugins/README.txt26
-rw-r--r--plugins/eg-amp.lv2/README.txt19
-rw-r--r--plugins/eg-amp.lv2/amp.c203
-rw-r--r--plugins/eg-amp.lv2/amp.ttl90
-rw-r--r--plugins/eg-amp.lv2/manifest.ttl.in68
-rw-r--r--plugins/eg-amp.lv2/meson.build42
-rw-r--r--plugins/eg-fifths.lv2/README.txt3
-rw-r--r--plugins/eg-fifths.lv2/fifths.c167
-rw-r--r--plugins/eg-fifths.lv2/fifths.ttl30
-rw-r--r--plugins/eg-fifths.lv2/manifest.ttl.in8
-rw-r--r--plugins/eg-fifths.lv2/meson.build42
-rw-r--r--plugins/eg-fifths.lv2/uris.h40
-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/meson.build42
-rw-r--r--plugins/eg-metro.lv2/metro.c341
-rw-r--r--plugins/eg-metro.lv2/metro.ttl30
-rw-r--r--plugins/eg-midigate.lv2/README.txt10
-rw-r--r--plugins/eg-midigate.lv2/manifest.ttl.in10
-rw-r--r--plugins/eg-midigate.lv2/meson.build42
-rw-r--r--plugins/eg-midigate.lv2/midigate.c220
-rw-r--r--plugins/eg-midigate.lv2/midigate.ttl56
-rw-r--r--plugins/eg-params.lv2/README.txt21
-rw-r--r--plugins/eg-params.lv2/manifest.ttl.in7
-rw-r--r--plugins/eg-params.lv2/meson.build42
-rw-r--r--plugins/eg-params.lv2/params.c519
-rw-r--r--plugins/eg-params.lv2/params.ttl126
-rw-r--r--plugins/eg-params.lv2/state_map.h102
-rw-r--r--plugins/eg-sampler.lv2/README.txt14
-rw-r--r--plugins/eg-sampler.lv2/atom_sink.h34
-rw-r--r--plugins/eg-sampler.lv2/click.wavbin644 -> 0 bytes
-rw-r--r--plugins/eg-sampler.lv2/manifest.ttl.in19
-rw-r--r--plugins/eg-sampler.lv2/meson.build82
-rw-r--r--plugins/eg-sampler.lv2/peaks.h266
-rw-r--r--plugins/eg-sampler.lv2/sampler.c695
-rw-r--r--plugins/eg-sampler.lv2/sampler.ttl73
-rw-r--r--plugins/eg-sampler.lv2/sampler_ui.c458
-rw-r--r--plugins/eg-sampler.lv2/uris.h170
-rw-r--r--plugins/eg-scope.lv2/README.txt32
-rw-r--r--plugins/eg-scope.lv2/examploscope.c412
-rw-r--r--plugins/eg-scope.lv2/examploscope.ttl.in130
-rw-r--r--plugins/eg-scope.lv2/examploscope_ui.c667
-rw-r--r--plugins/eg-scope.lv2/manifest.ttl.in21
-rw-r--r--plugins/eg-scope.lv2/meson.build64
-rw-r--r--plugins/eg-scope.lv2/uris.h57
-rwxr-xr-xplugins/literasc.py143
-rw-r--r--plugins/meson.build82
48 files changed, 0 insertions, 5757 deletions
diff --git a/plugins/.clang-tidy b/plugins/.clang-tidy
deleted file mode 100644
index b327b36..0000000
--- a/plugins/.clang-tidy
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2020-2025 David Robillard <d@drobilla.net>
-# SPDX-License-Identifier: 0BSD OR ISC
-
-Checks: >
- -*-narrowing-conversions,
- -bugprone-assignment-in-if-condition,
- -bugprone-easily-swappable-parameters,
- -bugprone-multi-level-implicit-pointer-conversion,
- -bugprone-suspicious-realloc-usage,
- -cert-err33-c,
- -clang-analyzer-core.NullDereference,
- -hicpp-signed-bitwise,
- -llvm-header-guard,
- -misc-unused-parameters,
- -readability-function-cognitive-complexity,
-InheritParentConfig: true
diff --git a/plugins/README.txt b/plugins/README.txt
deleted file mode 100644
index 361460d..0000000
--- a/plugins/README.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-= Programming LV2 Plugins =
-David Robillard <d@drobilla.net>
-:Author Initials: DER
-:toc:
-:website: http://lv2plug.in/
-:doctype: book
-
-== Introduction ==
-
-This is a series of well-documented example plugins that demonstrate the various features of LV2.
-Starting with the most basic plugin possible,
-each adds new functionality and explains the features used from a high level perspective.
-
-API and vocabulary reference documentation explains details,
-but not the ``big picture''.
-This book is intended to complement the reference documentation by providing good reference implementations of plugins,
-while also conveying a higher-level understanding of LV2.
-
-The chapters/plugins are arranged so that each builds incrementally on its predecessor.
-Reading this book front to back is a good way to become familiar with modern LV2 programming.
-The reader is expected to be familiar with C, but otherwise no special knowledge is required;
-the first plugin describes the basics in detail.
-
-This book is compiled from plugin source code into a single document for pleasant reading and ease of reference.
-Each chapter corresponds to executable plugin code which can be found in the +plugins+ directory of the LV2 distribution.
-If you prefer to read actual source code, all the content here is also available in the source code as comments.
diff --git a/plugins/eg-amp.lv2/README.txt b/plugins/eg-amp.lv2/README.txt
deleted file mode 100644
index 41683d3..0000000
--- a/plugins/eg-amp.lv2/README.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-== Simple Amplifier ==
-
-This plugin is a simple example of a basic LV2 plugin with no additional features.
-It has audio ports which contain an array of `float`,
-and a control port which contains a single `float`.
-
-LV2 plugins are defined in two parts: code and data.
-The code is written in C, or any C compatible language such as C++.
-Static data is described separately in the human and machine friendly http://www.w3.org/TeamSubmission/turtle/[Turtle] syntax.
-
-Generally, the goal is to keep code minimal,
-and describe as much as possible in the static data.
-There are several advantages to this approach:
-
- * Hosts can discover and inspect plugins without loading or executing any plugin code.
- * Plugin data can be used from a wide range of generic tools like scripting languages and command line utilities.
- * The standard data model allows the use of existing vocabularies to describe plugins and related information.
- * The language is extensible, so authors may describe any data without requiring changes to the LV2 specification.
- * Labels and documentation are translatable, and available to hosts for display in user interfaces.
diff --git a/plugins/eg-amp.lv2/amp.c b/plugins/eg-amp.lv2/amp.c
deleted file mode 100644
index c85d6ab..0000000
--- a/plugins/eg-amp.lv2/amp.c
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2006-2016 David Robillard <d@drobilla.net>
-// Copyright 2006 Steve Harris <steve@plugin.org.uk>
-// SPDX-License-Identifier: ISC
-
-/**
- LV2 headers are based on the URI of the specification they come from, so a
- consistent convention can be used even for unofficial extensions. The URI
- of the core LV2 specification is <http://lv2plug.in/ns/lv2core>, by
- replacing `http:/` with `lv2` any header in the specification bundle can be
- included, in this case `lv2.h`.
-*/
-#include <lv2/core/lv2.h>
-
-/** Include standard C headers */
-#include <math.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-/**
- The URI is the identifier for a plugin, and how the host associates this
- implementation in code with its description in data. In this plugin it is
- only used once in the code, but defining the plugin URI at the top of the
- file is a good convention to follow. If this URI does not match that used
- in the data files, the host will fail to load the plugin.
-*/
-#define AMP_URI "http://lv2plug.in/plugins/eg-amp"
-
-/**
- In code, ports are referred to by index. An enumeration of port indices
- should be defined for readability.
-*/
-typedef enum { AMP_GAIN = 0, AMP_INPUT = 1, AMP_OUTPUT = 2 } PortIndex;
-
-/**
- Every plugin defines a private structure for the plugin instance. All data
- associated with a plugin instance is stored here, and is available to
- every instance method. In this simple plugin, only port buffers need to be
- stored, since there is no additional instance data.
-*/
-typedef struct {
- // Port buffers
- const float* gain;
- const float* input;
- float* output;
-} Amp;
-
-/**
- The `instantiate()` function is called by the host to create a new plugin
- instance. The host passes the plugin descriptor, sample rate, and bundle
- path for plugins that need to load additional resources (e.g. waveforms).
- The features parameter contains host-provided features defined in LV2
- extensions, but this simple plugin does not use any.
-
- This function is in the ``instantiation'' threading class, so no other
- methods on this instance will be called concurrently with it.
-*/
-static LV2_Handle
-instantiate(const LV2_Descriptor* descriptor,
- double rate,
- const char* bundle_path,
- const LV2_Feature* const* features)
-{
- Amp* amp = (Amp*)calloc(1, sizeof(Amp));
-
- return (LV2_Handle)amp;
-}
-
-/**
- The `connect_port()` method is called by the host to connect a particular
- port to a buffer. The plugin must store the data location, but data may not
- be accessed except in run().
-
- This method is in the ``audio'' threading class, and is called in the same
- context as run().
-*/
-static void
-connect_port(LV2_Handle instance, uint32_t port, void* data)
-{
- Amp* amp = (Amp*)instance;
-
- switch ((PortIndex)port) {
- case AMP_GAIN:
- amp->gain = (const float*)data;
- break;
- case AMP_INPUT:
- amp->input = (const float*)data;
- break;
- case AMP_OUTPUT:
- amp->output = (float*)data;
- break;
- }
-}
-
-/**
- The `activate()` method is called by the host to initialise and prepare the
- plugin instance for running. The plugin must reset all internal state
- except for buffer locations set by `connect_port()`. Since this plugin has
- no other internal state, this method does nothing.
-
- This method is in the ``instantiation'' threading class, so no other
- methods on this instance will be called concurrently with it.
-*/
-static void
-activate(LV2_Handle instance)
-{}
-
-/** Define a macro for converting a gain in dB to a coefficient. */
-#define DB_CO(g) ((g) > -90.0f ? powf(10.0f, (g) * 0.05f) : 0.0f)
-
-/**
- The `run()` method is the main process function of the plugin. It processes
- a block of audio in the audio context. Since this plugin is
- `lv2:hardRTCapable`, `run()` must be real-time safe, so blocking (e.g. with
- a mutex) or memory allocation are not allowed.
-*/
-static void
-run(LV2_Handle instance, uint32_t n_samples)
-{
- const Amp* amp = (const Amp*)instance;
-
- const float gain = *(amp->gain);
- const float* const input = amp->input;
- float* const output = amp->output;
-
- const float coef = DB_CO(gain);
-
- for (uint32_t pos = 0; pos < n_samples; pos++) {
- output[pos] = input[pos] * coef;
- }
-}
-
-/**
- The `deactivate()` method is the counterpart to `activate()`, and is called
- by the host after running the plugin. It indicates that the host will not
- call `run()` again until another call to `activate()` and is mainly useful
- for more advanced plugins with ``live'' characteristics such as those with
- auxiliary processing threads. As with `activate()`, this plugin has no use
- for this information so this method does nothing.
-
- This method is in the ``instantiation'' threading class, so no other
- methods on this instance will be called concurrently with it.
-*/
-static void
-deactivate(LV2_Handle instance)
-{}
-
-/**
- Destroy a plugin instance (counterpart to `instantiate()`).
-
- This method is in the ``instantiation'' threading class, so no other
- methods on this instance will be called concurrently with it.
-*/
-static void
-cleanup(LV2_Handle instance)
-{
- free(instance);
-}
-
-/**
- The `extension_data()` function returns any extension data supported by the
- plugin. Note that this is not an instance method, but a function on the
- plugin descriptor. It is usually used by plugins to implement additional
- interfaces. This plugin does not have any extension data, so this function
- returns NULL.
-
- This method is in the ``discovery'' threading class, so no other functions
- or methods in this plugin library will be called concurrently with it.
-*/
-static const void*
-extension_data(const char* uri)
-{
- return NULL;
-}
-
-/**
- Every plugin must define an `LV2_Descriptor`. It is best to define
- descriptors statically to avoid leaking memory and non-portable shared
- library constructors and destructors to clean up properly.
-*/
-static const LV2_Descriptor descriptor = {AMP_URI,
- instantiate,
- connect_port,
- activate,
- run,
- deactivate,
- cleanup,
- extension_data};
-
-/**
- The `lv2_descriptor()` function is the entry point to the plugin library. The
- host will load the library and call this function repeatedly with increasing
- indices to find all the plugins defined in the library. The index is not an
- identifier, the URI of the returned descriptor is used to determine the
- identify of the plugin.
-
- This method is in the ``discovery'' threading class, so no other functions
- or methods in this plugin library will be called concurrently with it.
-*/
-LV2_SYMBOL_EXPORT const LV2_Descriptor*
-lv2_descriptor(uint32_t index)
-{
- return index == 0 ? &descriptor : NULL;
-}
diff --git a/plugins/eg-amp.lv2/amp.ttl b/plugins/eg-amp.lv2/amp.ttl
deleted file mode 100644
index 9f522a1..0000000
--- a/plugins/eg-amp.lv2/amp.ttl
+++ /dev/null
@@ -1,90 +0,0 @@
-# The full description of the plugin is in this file, which is linked to from
-# `manifest.ttl`. This is done so the host only needs to scan the relatively
-# small `manifest.ttl` files to quickly discover all plugins.
-
-@prefix doap: <http://usefulinc.com/ns/doap#> .
-@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
-@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
-@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
-@prefix units: <http://lv2plug.in/ns/extensions/units#> .
-
-# First the type of the plugin is described. All plugins must explicitly list
-# `lv2:Plugin` as a type. A more specific type should also be given, where
-# applicable, so hosts can present a nicer UI for loading plugins. Note that
-# this URI is the identifier of the plugin, so if it does not match the one in
-# `manifest.ttl`, the host will not discover the plugin data at all.
-<http://lv2plug.in/plugins/eg-amp>
- a lv2:Plugin ,
- lv2:AmplifierPlugin ;
-# Plugins are associated with a project, where common information like
-# developers, home page, and so on are described. This plugin is part of the
-# LV2 project, which has URI <http://lv2plug.in/ns/lv2>, and is described
-# elsewhere. Typical plugin collections will describe the project in
-# manifest.ttl
- lv2:project <http://lv2plug.in/ns/lv2> ;
-# Every plugin must have a name, described with the doap:name property.
-# Translations to various languages can be added by putting a language tag
-# after strings as shown.
- doap:name "Simple Amplifier" ,
- "简单放大器"@zh ,
- "Einfacher Verstärker"@de ,
- "Simple Amplifier"@en-gb ,
- "Amplificador Simple"@es ,
- "Amplificateur de Base"@fr ,
- "Amplificatore Semplice"@it ,
- "簡単なアンプ"@jp ,
- "Просто Усилитель"@ru ;
- doap:license <http://opensource.org/licenses/isc> ;
- lv2:optionalFeature lv2:hardRTCapable ;
- lv2:port [
-# Every port must have at least two types, one that specifies direction
-# (lv2:InputPort or lv2:OutputPort), and another to describe the data type.
-# This port is a lv2:ControlPort, which means it contains a single float.
- a lv2:InputPort ,
- lv2:ControlPort ;
- lv2:index 0 ;
- lv2:symbol "gain" ;
- lv2:name "Gain" ,
- "收益"@zh ,
- "Verstärkung"@de ,
- "Gain"@en-gb ,
- "Aumento"@es ,
- "Gain"@fr ,
- "Guadagno"@it ,
- "利益"@jp ,
- "Увеличение"@ru ;
-# An lv2:ControlPort should always describe its default value, and usually a
-# minimum and maximum value. Defining a range is not strictly required, but
-# should be done wherever possible to aid host support, particularly for UIs.
- lv2:default 0.0 ;
- lv2:minimum -90.0 ;
- lv2:maximum 24.0 ;
-# Ports can describe units and control detents to allow better UI generation
-# and host automation.
- units:unit units:db ;
- lv2:scalePoint [
- rdfs:label "+5" ;
- rdf:value 5.0
- ] , [
- rdfs:label "0" ;
- rdf:value 0.0
- ] , [
- rdfs:label "-5" ;
- rdf:value -5.0
- ] , [
- rdfs:label "-10" ;
- rdf:value -10.0
- ]
- ] , [
- a lv2:AudioPort ,
- lv2:InputPort ;
- lv2:index 1 ;
- lv2:symbol "in" ;
- lv2:name "In"
- ] , [
- a lv2:AudioPort ,
- lv2:OutputPort ;
- lv2:index 2 ;
- lv2:symbol "out" ;
- lv2:name "Out"
- ] .
diff --git a/plugins/eg-amp.lv2/manifest.ttl.in b/plugins/eg-amp.lv2/manifest.ttl.in
deleted file mode 100644
index 4a22f95..0000000
--- a/plugins/eg-amp.lv2/manifest.ttl.in
+++ /dev/null
@@ -1,68 +0,0 @@
-# LV2 plugins are installed in a ``bundle'', a directory with a standard
-# structure. Each bundle has a Turtle file named `manifest.ttl` which lists
-# the contents of the bundle.
-#
-# Hosts typically read the manifest of every installed bundle to discover
-# plugins on start-up, so it should be as small as possible for performance
-# reasons. Details that are only useful if the host chooses to load the plugin
-# are stored in other files and linked to from `manifest.ttl`.
-#
-# ==== URIs ====
-#
-# LV2 makes use of URIs as globally-unique identifiers for resources. For
-# example, the ID of the plugin described here is
-# `<http://lv2plug.in/plugins/eg-amp>`. Note that URIs are only used as
-# identifiers and don't necessarily imply that something can be accessed at
-# that address on the web (though that may be the case).
-#
-# ==== Namespace Prefixes ====
-#
-# Turtle files contain many URIs, but prefixes can be defined to improve
-# readability. For example, with the `lv2:` prefix below, `lv2:Plugin` can be
-# written instead of `<http://lv2plug.in/ns/lv2core#Plugin>`.
-
-@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
-@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
-
-# ==== Describing a Plugin ====
-
-# Turtle files contain a set of ``statements'' which describe resources.
-# This file contains 3 statements:
-# [options="header"]
-# |================================================================
-# | Subject | Predicate | Object
-# | <http://lv2plug.in/plugins/eg-amp> | a | lv2:Plugin
-# | <http://lv2plug.in/plugins/eg-amp> | lv2:binary | <amp.so>
-# | <http://lv2plug.in/plugins/eg-amp> | rdfs:seeAlso | <amp.ttl>
-# |================================================================
-
-# Firstly, `<http://lv2plug.in/plugins/eg-amp>` is an LV2 plugin:
-<http://lv2plug.in/plugins/eg-amp> a lv2:Plugin .
-
-# The predicate ```a`'' is a Turtle shorthand for `rdf:type`.
-
-# The binary of that plugin can be found at `<amp.ext>`:
-<http://lv2plug.in/plugins/eg-amp> lv2:binary <amp@LIB_EXT@> .
-
-# This file is a template; the token `@LIB_EXT@` is replaced by the build
-# system with the appropriate extension for the current platform before
-# installation. For example, in the output `manifest.ttl`, the binary would be
-# listed as `<amp.so>`. Relative URIs in manifests are relative to the bundle
-# directory, so this refers to a binary with the given name in the same
-# directory as this manifest.
-
-# Finally, more information about this plugin can be found in `<amp.ttl>`:
-<http://lv2plug.in/plugins/eg-amp> rdfs:seeAlso <amp.ttl> .
-
-# ==== Abbreviation ====
-#
-# This file shows these statements individually for instructive purposes, but
-# the subject `<http://lv2plug.in/plugins/eg-amp>` is repetitive. Turtle
-# allows the semicolon to be used as a delimiter that repeats the previous
-# subject. For example, this manifest would more realistically be written like
-# so:
-
-<http://lv2plug.in/plugins/eg-amp>
- a lv2:Plugin ;
- lv2:binary <amp@LIB_EXT@> ;
- rdfs:seeAlso <amp.ttl> .
diff --git a/plugins/eg-amp.lv2/meson.build b/plugins/eg-amp.lv2/meson.build
deleted file mode 100644
index 2912e3f..0000000
--- a/plugins/eg-amp.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('amp.c')
-bundle_name = 'eg-amp.lv2'
-data_filenames = ['manifest.ttl.in', 'amp.ttl']
-
-module = shared_library(
- 'amp',
- 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-fifths.lv2/README.txt b/plugins/eg-fifths.lv2/README.txt
deleted file mode 100644
index 2154321..0000000
--- a/plugins/eg-fifths.lv2/README.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-== Fifths ==
-
-This plugin demonstrates simple MIDI event reading and writing.
diff --git a/plugins/eg-fifths.lv2/fifths.c b/plugins/eg-fifths.lv2/fifths.c
deleted file mode 100644
index 22d5f8a..0000000
--- a/plugins/eg-fifths.lv2/fifths.c
+++ /dev/null
@@ -1,167 +0,0 @@
-// Copyright 2014-2016 David Robillard <d@drobilla.net>
-// SPDX-License-Identifier: ISC
-
-#include "uris.h"
-
-#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/midi/midi.h>
-#include <lv2/urid/urid.h>
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-enum { FIFTHS_IN = 0, FIFTHS_OUT = 1 };
-
-typedef struct {
- // Features
- LV2_URID_Map* map;
- LV2_Log_Logger logger;
-
- // Ports
- const LV2_Atom_Sequence* in_port;
- LV2_Atom_Sequence* out_port;
-
- // URIs
- FifthsURIs uris;
-} Fifths;
-
-static void
-connect_port(LV2_Handle instance, uint32_t port, void* data)
-{
- Fifths* self = (Fifths*)instance;
- switch (port) {
- case FIFTHS_IN:
- self->in_port = (const LV2_Atom_Sequence*)data;
- break;
- case FIFTHS_OUT:
- self->out_port = (LV2_Atom_Sequence*)data;
- break;
- default:
- break;
- }
-}
-
-static LV2_Handle
-instantiate(const LV2_Descriptor* descriptor,
- double rate,
- const char* path,
- const LV2_Feature* const* features)
-{
- // Allocate and initialise instance structure.
- Fifths* self = (Fifths*)calloc(1, sizeof(Fifths));
- 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_fifths_uris(self->map, &self->uris);
-
- return (LV2_Handle)self;
-}
-
-static void
-cleanup(LV2_Handle instance)
-{
- free(instance);
-}
-
-static void
-run(LV2_Handle instance, uint32_t sample_count)
-{
- Fifths* self = (Fifths*)instance;
- const FifthsURIs* uris = &self->uris;
-
- // Struct for a 3 byte MIDI event, used for writing notes
- typedef struct {
- LV2_Atom_Event event;
- uint8_t msg[3];
- } MIDINoteEvent;
-
- // Initially self->out_port contains a Chunk with size set to capacity
-
- // Get the capacity
- const uint32_t out_capacity = self->out_port->atom.size;
-
- // Write an empty Sequence header to the output
- lv2_atom_sequence_clear(self->out_port);
- self->out_port->atom.type = self->in_port->atom.type;
-
- // Read incoming events
- LV2_ATOM_SEQUENCE_FOREACH (self->in_port, ev) {
- if (ev->body.type == uris->midi_Event) {
- const uint8_t* const msg = (const uint8_t*)(ev + 1);
- switch (lv2_midi_message_type(msg)) {
- case LV2_MIDI_MSG_NOTE_ON:
- case LV2_MIDI_MSG_NOTE_OFF:
- // Forward note to output
- lv2_atom_sequence_append_event(self->out_port, out_capacity, ev);
-
- if (msg[1] <= 127 - 7) {
- // Make a note one 5th (7 semitones) higher than input
- MIDINoteEvent fifth;
-
- // Could simply do fifth.event = *ev here instead...
- fifth.event.time.frames = ev->time.frames; // Same time
- fifth.event.body.type = ev->body.type; // Same type
- fifth.event.body.size = ev->body.size; // Same size
-
- fifth.msg[0] = msg[0]; // Same status
- fifth.msg[1] = msg[1] + 7; // Pitch up 7 semitones
- fifth.msg[2] = msg[2]; // Same velocity
-
- // Write 5th event
- lv2_atom_sequence_append_event(
- self->out_port, out_capacity, &fifth.event);
- }
- break;
- default:
- // Forward all other MIDI events directly
- lv2_atom_sequence_append_event(self->out_port, out_capacity, ev);
- break;
- }
- }
- }
-}
-
-static const void*
-extension_data(const char* uri)
-{
- return NULL;
-}
-
-static const LV2_Descriptor descriptor = {EG_FIFTHS_URI,
- instantiate,
- connect_port,
- NULL, // activate,
- run,
- NULL, // deactivate,
- cleanup,
- extension_data};
-
-LV2_SYMBOL_EXPORT const LV2_Descriptor*
-lv2_descriptor(uint32_t index)
-{
- return index == 0 ? &descriptor : NULL;
-}
diff --git a/plugins/eg-fifths.lv2/fifths.ttl b/plugins/eg-fifths.lv2/fifths.ttl
deleted file mode 100644
index 7f58a33..0000000
--- a/plugins/eg-fifths.lv2/fifths.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 urid: <http://lv2plug.in/ns/ext/urid#> .
-@prefix midi: <http://lv2plug.in/ns/ext/midi#> .
-
-<http://lv2plug.in/plugins/eg-fifths>
- a lv2:Plugin ;
- doap:name "Example Fifths" ;
- 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 ;
- atom:supports midi:MidiEvent ;
- lv2:index 0 ;
- lv2:symbol "in" ;
- lv2:name "In"
- ] , [
- a lv2:OutputPort ,
- atom:AtomPort ;
- atom:bufferType atom:Sequence ;
- atom:supports midi:MidiEvent ;
- lv2:index 1 ;
- lv2:symbol "out" ;
- lv2:name "Out"
- ] .
diff --git a/plugins/eg-fifths.lv2/manifest.ttl.in b/plugins/eg-fifths.lv2/manifest.ttl.in
deleted file mode 100644
index f87f2c1..0000000
--- a/plugins/eg-fifths.lv2/manifest.ttl.in
+++ /dev/null
@@ -1,8 +0,0 @@
-@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#> .
-
-<http://lv2plug.in/plugins/eg-fifths>
- a lv2:Plugin ;
- lv2:binary <fifths@LIB_EXT@> ;
- rdfs:seeAlso <fifths.ttl> .
diff --git a/plugins/eg-fifths.lv2/meson.build b/plugins/eg-fifths.lv2/meson.build
deleted file mode 100644
index d0cbc6a..0000000
--- a/plugins/eg-fifths.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('fifths.c')
-bundle_name = 'eg-fifths.lv2'
-data_filenames = ['manifest.ttl.in', 'fifths.ttl']
-
-module = shared_library(
- 'fifths',
- 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-fifths.lv2/uris.h b/plugins/eg-fifths.lv2/uris.h
deleted file mode 100644
index f32a6bd..0000000
--- a/plugins/eg-fifths.lv2/uris.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2014-2015 David Robillard <d@drobilla.net>
-// SPDX-License-Identifier: ISC
-
-#ifndef FIFTHS_URIS_H
-#define FIFTHS_URIS_H
-
-#include <lv2/atom/atom.h>
-#include <lv2/midi/midi.h>
-#include <lv2/patch/patch.h>
-#include <lv2/urid/urid.h>
-
-#define EG_FIFTHS_URI "http://lv2plug.in/plugins/eg-fifths"
-
-typedef struct {
- LV2_URID atom_Path;
- LV2_URID atom_Resource;
- LV2_URID atom_Sequence;
- LV2_URID atom_URID;
- LV2_URID atom_eventTransfer;
- LV2_URID midi_Event;
- LV2_URID patch_Set;
- LV2_URID patch_property;
- LV2_URID patch_value;
-} FifthsURIs;
-
-static inline void
-map_fifths_uris(LV2_URID_Map* map, FifthsURIs* uris)
-{
- 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->atom_URID = map->map(map->handle, LV2_ATOM__URID);
- uris->atom_eventTransfer = map->map(map->handle, LV2_ATOM__eventTransfer);
- uris->midi_Event = map->map(map->handle, LV2_MIDI__MidiEvent);
- uris->patch_Set = map->map(map->handle, LV2_PATCH__Set);
- uris->patch_property = map->map(map->handle, LV2_PATCH__property);
- uris->patch_value = map->map(map->handle, LV2_PATCH__value);
-}
-
-#endif // FIFTHS_URIS_H
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" ;
- ] .
diff --git a/plugins/eg-midigate.lv2/README.txt b/plugins/eg-midigate.lv2/README.txt
deleted file mode 100644
index 8f4a0f0..0000000
--- a/plugins/eg-midigate.lv2/README.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-== MIDI Gate ==
-
-This plugin demonstrates:
-
- * Receiving MIDI input
-
- * Processing audio based on MIDI events with sample accuracy
-
- * Supporting MIDI programs which the host can control/automate, or present a
- user interface for with human readable labels
diff --git a/plugins/eg-midigate.lv2/manifest.ttl.in b/plugins/eg-midigate.lv2/manifest.ttl.in
deleted file mode 100644
index d32f1dc..0000000
--- a/plugins/eg-midigate.lv2/manifest.ttl.in
+++ /dev/null
@@ -1,10 +0,0 @@
-# The manifest.ttl file follows the same template as the previous example.
-
-@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#> .
-
-<http://lv2plug.in/plugins/eg-midigate>
- a lv2:Plugin ;
- lv2:binary <midigate@LIB_EXT@> ;
- rdfs:seeAlso <midigate.ttl> .
diff --git a/plugins/eg-midigate.lv2/meson.build b/plugins/eg-midigate.lv2/meson.build
deleted file mode 100644
index fc6010b..0000000
--- a/plugins/eg-midigate.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('midigate.c')
-bundle_name = 'eg-midigate.lv2'
-data_filenames = ['manifest.ttl.in', 'midigate.ttl']
-
-module = shared_library(
- 'midigate',
- 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-midigate.lv2/midigate.c b/plugins/eg-midigate.lv2/midigate.c
deleted file mode 100644
index b4861db..0000000
--- a/plugins/eg-midigate.lv2/midigate.c
+++ /dev/null
@@ -1,220 +0,0 @@
-// Copyright 2013-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/midi/midi.h>
-#include <lv2/urid/urid.h>
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define MIDIGATE_URI "http://lv2plug.in/plugins/eg-midigate"
-
-typedef enum {
- MIDIGATE_CONTROL = 0,
- MIDIGATE_IN = 1,
- MIDIGATE_OUT = 2
-} PortIndex;
-
-typedef struct {
- // Port buffers
- const LV2_Atom_Sequence* control;
- const float* in;
- float* out;
-
- // Features
- LV2_URID_Map* map;
- LV2_Log_Logger logger;
-
- struct {
- LV2_URID midi_MidiEvent;
- } uris;
-
- unsigned n_active_notes;
- unsigned program; // 0 = normal, 1 = inverted
-} Midigate;
-
-static LV2_Handle
-instantiate(const LV2_Descriptor* descriptor,
- double rate,
- const char* bundle_path,
- const LV2_Feature* const* features)
-{
- Midigate* self = (Midigate*)calloc(1, sizeof(Midigate));
- 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;
- }
-
- self->uris.midi_MidiEvent =
- self->map->map(self->map->handle, LV2_MIDI__MidiEvent);
-
- return (LV2_Handle)self;
-}
-
-static void
-connect_port(LV2_Handle instance, uint32_t port, void* data)
-{
- Midigate* self = (Midigate*)instance;
-
- switch ((PortIndex)port) {
- case MIDIGATE_CONTROL:
- self->control = (const LV2_Atom_Sequence*)data;
- break;
- case MIDIGATE_IN:
- self->in = (const float*)data;
- break;
- case MIDIGATE_OUT:
- self->out = (float*)data;
- break;
- }
-}
-
-static void
-activate(LV2_Handle instance)
-{
- Midigate* self = (Midigate*)instance;
- self->n_active_notes = 0;
- self->program = 0;
-}
-
-/**
- A function to write a chunk of output, to be called from run(). If the gate
- is high, then the input will be passed through for this chunk, otherwise
- silence is written.
-*/
-static void
-write_output(Midigate* self, uint32_t offset, uint32_t len)
-{
- const bool active = (self->program == 0) ? (self->n_active_notes > 0)
- : (self->n_active_notes == 0);
- if (active) {
- memcpy(self->out + offset, self->in + offset, len * sizeof(float));
- } else {
- memset(self->out + offset, 0, len * sizeof(float));
- }
-}
-
-/**
- This plugin works through the cycle in chunks starting at offset zero. The
- +offset+ represents the current time within this this cycle, so
- the output from 0 to +offset+ has already been written.
-
- MIDI events are read in a loop. In each iteration, the number of active
- notes (on note on and note off) or the program (on program change) is
- updated, then the output is written up until the current event time. Then
- +offset+ is updated and the next event is processed. After the loop the
- final chunk from the last event to the end of the cycle is emitted.
-
- There is currently no standard way to describe MIDI programs in LV2, so the
- host has no way of knowing that these programs exist and should be presented
- to the user. A future version of LV2 will address this shortcoming.
-
- This pattern of iterating over input events and writing output along the way
- is a common idiom for writing sample accurate output based on event input.
-
- Note that this simple example simply writes input or zero for each sample
- based on the gate. A serious implementation would need to envelope the
- transition to avoid aliasing.
-*/
-static void
-run(LV2_Handle instance, uint32_t sample_count)
-{
- Midigate* self = (Midigate*)instance;
- uint32_t offset = 0;
-
- LV2_ATOM_SEQUENCE_FOREACH (self->control, ev) {
- write_output(self, offset, (uint32_t)(ev->time.frames - offset));
- offset = (uint32_t)ev->time.frames;
-
- if (ev->body.type == self->uris.midi_MidiEvent) {
- const uint8_t* const msg = (const uint8_t*)(ev + 1);
- switch (lv2_midi_message_type(msg)) {
- case LV2_MIDI_MSG_NOTE_ON:
- ++self->n_active_notes;
- break;
- case LV2_MIDI_MSG_NOTE_OFF:
- if (self->n_active_notes > 0) {
- --self->n_active_notes;
- }
- break;
- case LV2_MIDI_MSG_CONTROLLER:
- if (msg[1] == LV2_MIDI_CTL_ALL_NOTES_OFF) {
- self->n_active_notes = 0;
- }
- break;
- case LV2_MIDI_MSG_PGM_CHANGE:
- if (msg[1] == 0 || msg[1] == 1) {
- self->program = msg[1];
- }
- break;
- default:
- break;
- }
- }
- }
-
- write_output(self, offset, sample_count - offset);
-}
-
-/**
- We have no resources to free on deactivation.
- Note that the next call to activate will re-initialise the state, namely
- self->n_active_notes, so there is no need to do so here.
-*/
-static void
-deactivate(LV2_Handle instance)
-{}
-
-static void
-cleanup(LV2_Handle instance)
-{
- free(instance);
-}
-
-/**
- This plugin also has no extension data to return.
-*/
-static const void*
-extension_data(const char* uri)
-{
- return NULL;
-}
-
-static const LV2_Descriptor descriptor = {MIDIGATE_URI,
- instantiate,
- connect_port,
- activate,
- run,
- deactivate,
- cleanup,
- extension_data};
-
-LV2_SYMBOL_EXPORT const LV2_Descriptor*
-lv2_descriptor(uint32_t index)
-{
- return index == 0 ? &descriptor : NULL;
-}
diff --git a/plugins/eg-midigate.lv2/midigate.ttl b/plugins/eg-midigate.lv2/midigate.ttl
deleted file mode 100644
index e14a329..0000000
--- a/plugins/eg-midigate.lv2/midigate.ttl
+++ /dev/null
@@ -1,56 +0,0 @@
-# The same set of namespace prefixes with two additions for LV2 extensions this
-# plugin uses: atom and urid.
-
-@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
-@prefix doap: <http://usefulinc.com/ns/doap#> .
-@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
-@prefix midi: <http://lv2plug.in/ns/ext/midi#> .
-@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
-@prefix urid: <http://lv2plug.in/ns/ext/urid#> .
-
-<http://lv2plug.in/plugins/eg-midigate>
- a lv2:Plugin ;
- doap:name "Example MIDI Gate" ;
- doap:license <http://opensource.org/licenses/isc> ;
- lv2:project <http://lv2plug.in/ns/lv2> ;
- lv2:requiredFeature urid:map ;
- lv2:optionalFeature lv2:hardRTCapable ;
-# This plugin has three ports. There is an audio input and output as before,
-# as well as a new AtomPort. An AtomPort buffer contains an Atom, which is a
-# generic container for any type of data. In this case, we want to receive
-# MIDI events, so the (mandatory) +atom:bufferType+ is atom:Sequence, which is
-# a series of events with time stamps.
-#
-# Events themselves are also generic and can contain any type of data, but in
-# this case we are only interested in MIDI events. The (optional)
-# +atom:supports+ property describes which event types are supported. Though
-# not required, this information should always be given so the host knows what
-# types of event it can expect the plugin to understand.
-#
-# The (optional) +lv2:designation+ of this port is +lv2:control+, which
-# indicates that this is the "main" control port where the host should send
-# events it expects to configure the plugin, in this case changing the MIDI
-# program. This is necessary since it is possible to have several MIDI input
-# ports, though typically it is best to have one.
- lv2:port [
- a lv2:InputPort ,
- atom:AtomPort ;
- atom:bufferType atom:Sequence ;
- atom:supports midi:MidiEvent ;
- lv2:designation lv2:control ;
- lv2:index 0 ;
- lv2:symbol "control" ;
- lv2:name "Control"
- ] , [
- a lv2:AudioPort ,
- lv2:InputPort ;
- lv2:index 1 ;
- lv2:symbol "in" ;
- lv2:name "In"
- ] , [
- a lv2:AudioPort ,
- lv2:OutputPort ;
- lv2:index 2 ;
- lv2:symbol "out" ;
- lv2:name "Out"
- ] .
diff --git a/plugins/eg-params.lv2/README.txt b/plugins/eg-params.lv2/README.txt
deleted file mode 100644
index acf90c1..0000000
--- a/plugins/eg-params.lv2/README.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-== Params ==
-
-The basic LV2 mechanism for controls is
-http://lv2plug.in/ns/lv2core#ControlPort[lv2:ControlPort], inherited from
-LADSPA. Control ports are problematic because they are not sample accurate,
-support only one type (`float`), and require that plugins poll to know when a
-control has changed.
-
-Parameters can be used instead to address these issues. Parameters can be
-thought of as properties of a plugin instance; they are identified by URI and
-have a value of any type. This deliberately meshes with the concept of plugin
-state defined by the http://lv2plug.in/ns/ext/state[LV2 state extension].
-The state extension allows plugins to save and restore their parameters (along
-with other internal state information, if necessary).
-
-Parameters are accessed and manipulated using messages sent via a sequence
-port. The http://lv2plug.in/ns/ext/patch[LV2 patch extension] defines the
-standard messages for working with parameters. Typically, only two are used
-for simple plugins: http://lv2plug.in/ns/ext/patch#Set[patch:Set] sets a
-parameter to some value, and http://lv2plug.in/ns/ext/patch#Get[patch:Get]
-requests that the plugin send a description of its parameters.
diff --git a/plugins/eg-params.lv2/manifest.ttl.in b/plugins/eg-params.lv2/manifest.ttl.in
deleted file mode 100644
index 913de7c..0000000
--- a/plugins/eg-params.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-params>
- a lv2:Plugin ;
- lv2:binary <params@LIB_EXT@> ;
- rdfs:seeAlso <params.ttl> .
diff --git a/plugins/eg-params.lv2/meson.build b/plugins/eg-params.lv2/meson.build
deleted file mode 100644
index 83c6ef9..0000000
--- a/plugins/eg-params.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('params.c')
-bundle_name = 'eg-params.lv2'
-data_filenames = ['manifest.ttl.in', 'params.ttl']
-
-module = shared_library(
- 'params',
- 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-params.lv2/params.c b/plugins/eg-params.lv2/params.c
deleted file mode 100644
index 9fbaa46..0000000
--- a/plugins/eg-params.lv2/params.c
+++ /dev/null
@@ -1,519 +0,0 @@
-// Copyright 2014-2016 David Robillard <d@drobilla.net>
-// SPDX-License-Identifier: ISC
-
-#include "state_map.h"
-
-#include <lv2/atom/atom.h>
-#include <lv2/atom/forge.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/midi/midi.h>
-#include <lv2/patch/patch.h>
-#include <lv2/state/state.h>
-#include <lv2/urid/urid.h>
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define MAX_STRING 1024
-
-#define EG_PARAMS_URI "http://lv2plug.in/plugins/eg-params"
-
-#define N_PROPS 9
-
-typedef struct {
- LV2_URID plugin;
- LV2_URID atom_Path;
- LV2_URID atom_Sequence;
- LV2_URID atom_URID;
- LV2_URID atom_eventTransfer;
- LV2_URID eg_spring;
- LV2_URID midi_Event;
- LV2_URID patch_Get;
- LV2_URID patch_Set;
- LV2_URID patch_Put;
- LV2_URID patch_body;
- LV2_URID patch_subject;
- LV2_URID patch_property;
- LV2_URID patch_value;
-} URIs;
-
-typedef struct {
- LV2_Atom_Int aint;
- LV2_Atom_Long along;
- LV2_Atom_Float afloat;
- LV2_Atom_Double adouble;
- LV2_Atom_Bool abool;
- LV2_Atom astring;
- char string[MAX_STRING];
- LV2_Atom apath;
- char path[MAX_STRING];
- LV2_Atom_Float lfo;
- LV2_Atom_Float spring;
-} State;
-
-static inline void
-map_uris(LV2_URID_Map* map, URIs* uris)
-{
- uris->plugin = map->map(map->handle, EG_PARAMS_URI);
-
- uris->atom_Path = map->map(map->handle, LV2_ATOM__Path);
- uris->atom_Sequence = map->map(map->handle, LV2_ATOM__Sequence);
- uris->atom_URID = map->map(map->handle, LV2_ATOM__URID);
- uris->atom_eventTransfer = map->map(map->handle, LV2_ATOM__eventTransfer);
- uris->eg_spring = map->map(map->handle, EG_PARAMS_URI "#spring");
- uris->midi_Event = map->map(map->handle, LV2_MIDI__MidiEvent);
- uris->patch_Get = map->map(map->handle, LV2_PATCH__Get);
- uris->patch_Set = map->map(map->handle, LV2_PATCH__Set);
- uris->patch_Put = map->map(map->handle, LV2_PATCH__Put);
- uris->patch_body = map->map(map->handle, LV2_PATCH__body);
- uris->patch_subject = map->map(map->handle, LV2_PATCH__subject);
- uris->patch_property = map->map(map->handle, LV2_PATCH__property);
- uris->patch_value = map->map(map->handle, LV2_PATCH__value);
-}
-
-enum { PARAMS_IN = 0, PARAMS_OUT = 1 };
-
-typedef struct {
- // Features
- LV2_URID_Map* map;
- LV2_URID_Unmap* unmap;
- LV2_Log_Logger log;
-
- // Forge for creating atoms
- LV2_Atom_Forge forge;
-
- // Ports
- const LV2_Atom_Sequence* in_port;
- LV2_Atom_Sequence* out_port;
-
- // URIs
- URIs uris;
-
- // Plugin state
- StateMapItem props[N_PROPS];
- State state;
-
- // Buffer for making strings from URIDs if unmap is not provided
- char urid_buf[12];
-} Params;
-
-static void
-connect_port(LV2_Handle instance, uint32_t port, void* data)
-{
- Params* self = (Params*)instance;
- switch (port) {
- case PARAMS_IN:
- self->in_port = (const LV2_Atom_Sequence*)data;
- break;
- case PARAMS_OUT:
- self->out_port = (LV2_Atom_Sequence*)data;
- break;
- default:
- break;
- }
-}
-
-static LV2_Handle
-instantiate(const LV2_Descriptor* descriptor,
- double rate,
- const char* path,
- const LV2_Feature* const* features)
-{
- // Allocate instance
- Params* self = (Params*)calloc(1, sizeof(Params));
- if (!self) {
- return NULL;
- }
-
- // Get host features
- // clang-format off
- const char* missing = lv2_features_query(
- features,
- LV2_LOG__log, &self->log.log, false,
- LV2_URID__map, &self->map, true,
- LV2_URID__unmap, &self->unmap, false,
- NULL);
- // clang-format on
-
- lv2_log_logger_set_map(&self->log, self->map);
- if (missing) {
- lv2_log_error(&self->log, "Missing feature <%s>\n", missing);
- free(self);
- return NULL;
- }
-
- // Map URIs and initialise forge
- map_uris(self->map, &self->uris);
- lv2_atom_forge_init(&self->forge, self->map);
-
- // Initialise state dictionary
- // clang-format off
- State* state = &self->state;
- state_map_init(
- self->props, self->map, self->map->handle,
- EG_PARAMS_URI "#int", STATE_MAP_INIT(Int, &state->aint),
- EG_PARAMS_URI "#long", STATE_MAP_INIT(Long, &state->along),
- EG_PARAMS_URI "#float", STATE_MAP_INIT(Float, &state->afloat),
- EG_PARAMS_URI "#double", STATE_MAP_INIT(Double, &state->adouble),
- EG_PARAMS_URI "#bool", STATE_MAP_INIT(Bool, &state->abool),
- EG_PARAMS_URI "#string", STATE_MAP_INIT(String, &state->astring),
- EG_PARAMS_URI "#path", STATE_MAP_INIT(Path, &state->apath),
- EG_PARAMS_URI "#lfo", STATE_MAP_INIT(Float, &state->lfo),
- EG_PARAMS_URI "#spring", STATE_MAP_INIT(Float, &state->spring),
- NULL);
- // clang-format on
-
- return (LV2_Handle)self;
-}
-
-static void
-cleanup(LV2_Handle instance)
-{
- free(instance);
-}
-
-/** Helper function to unmap a URID if possible. */
-static const char*
-unmap(Params* self, LV2_URID urid)
-{
- if (self->unmap) {
- return self->unmap->unmap(self->unmap->handle, urid);
- }
-
- snprintf(self->urid_buf, sizeof(self->urid_buf), "%u", urid);
- return self->urid_buf;
-}
-
-static LV2_State_Status
-check_type(Params* self, LV2_URID key, LV2_URID type, LV2_URID required_type)
-{
- if (type != required_type) {
- lv2_log_trace(&self->log,
- "Bad type <%s> for <%s> (needs <%s>)\n",
- unmap(self, type),
- unmap(self, key),
- unmap(self, required_type));
- return LV2_STATE_ERR_BAD_TYPE;
- }
- return LV2_STATE_SUCCESS;
-}
-
-static LV2_State_Status
-set_parameter(Params* self,
- LV2_URID key,
- uint32_t size,
- LV2_URID type,
- const void* body,
- bool from_state)
-{
- // Look up property in state dictionary
- const StateMapItem* entry = state_map_find(self->props, N_PROPS, key);
- if (!entry) {
- lv2_log_trace(&self->log, "Unknown parameter <%s>\n", unmap(self, key));
- return LV2_STATE_ERR_NO_PROPERTY;
- }
-
- // Ensure given type matches property's type
- if (check_type(self, key, type, entry->value->type)) {
- return LV2_STATE_ERR_BAD_TYPE;
- }
-
- // Set property value in state dictionary
- lv2_log_trace(&self->log, "Set <%s>\n", entry->uri);
- memcpy(entry->value + 1, body, size);
- entry->value->size = size;
- return LV2_STATE_SUCCESS;
-}
-
-static const LV2_Atom*
-get_parameter(Params* self, LV2_URID key)
-{
- const StateMapItem* entry = state_map_find(self->props, N_PROPS, key);
- if (entry) {
- lv2_log_trace(&self->log, "Get <%s>\n", entry->uri);
- return entry->value;
- }
-
- lv2_log_trace(&self->log, "Unknown parameter <%s>\n", unmap(self, key));
- return NULL;
-}
-
-static LV2_State_Status
-write_param_to_forge(LV2_State_Handle handle,
- uint32_t key,
- const void* value,
- size_t size,
- uint32_t type,
- uint32_t flags)
-{
- LV2_Atom_Forge* forge = (LV2_Atom_Forge*)handle;
-
- if (!lv2_atom_forge_key(forge, key) ||
- !lv2_atom_forge_atom(forge, size, type) ||
- !lv2_atom_forge_write(forge, value, size)) {
- return LV2_STATE_ERR_UNKNOWN;
- }
-
- return LV2_STATE_SUCCESS;
-}
-
-static void
-store_prop(Params* self,
- LV2_State_Map_Path* map_path,
- LV2_State_Status* save_status,
- LV2_State_Store_Function store,
- LV2_State_Handle handle,
- LV2_URID key,
- const LV2_Atom* value)
-{
- LV2_State_Status st = LV2_STATE_SUCCESS;
- if (map_path && value->type == self->uris.atom_Path) {
- // Map path to abstract path for portable storage
- const char* path = (const char*)(value + 1);
- char* apath = map_path->abstract_path(map_path->handle, path);
- st = store(handle,
- key,
- apath,
- strlen(apath) + 1,
- self->uris.atom_Path,
- LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
- free(apath);
- } else {
- // Store simple property
- st = store(handle,
- key,
- value + 1,
- value->size,
- value->type,
- LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
- }
-
- if (save_status && !*save_status) {
- *save_status = st;
- }
-}
-
-/**
- State save method.
-
- This is used in the usual way when called by the host to save plugin state,
- but also internally for writing messages in the audio thread by passing a
- "store" function which actually writes the description to the forge.
-*/
-static LV2_State_Status
-save(LV2_Handle instance,
- LV2_State_Store_Function store,
- LV2_State_Handle handle,
- uint32_t flags,
- const LV2_Feature* const* features)
-{
- Params* self = (Params*)instance;
- LV2_State_Map_Path* map_path =
- (LV2_State_Map_Path*)lv2_features_data(features, LV2_STATE__mapPath);
-
- LV2_State_Status st = LV2_STATE_SUCCESS;
- for (unsigned i = 0; i < N_PROPS; ++i) {
- const StateMapItem* prop = &self->props[i];
- store_prop(self, map_path, &st, store, handle, prop->urid, prop->value);
- }
-
- return st;
-}
-
-static void
-retrieve_prop(Params* self,
- LV2_State_Status* restore_status,
- LV2_State_Retrieve_Function retrieve,
- LV2_State_Handle handle,
- LV2_URID key)
-{
- // Retrieve value from saved state
- size_t vsize = 0;
- uint32_t vtype = 0;
- uint32_t vflags = 0;
- const void* value = retrieve(handle, key, &vsize, &vtype, &vflags);
-
- // Set plugin instance state
- const LV2_State_Status st =
- value ? set_parameter(self, key, vsize, vtype, value, true)
- : LV2_STATE_ERR_NO_PROPERTY;
-
- if (!*restore_status) {
- *restore_status = st; // Set status if there has been no error yet
- }
-}
-
-/** State restore method. */
-static LV2_State_Status
-restore(LV2_Handle instance,
- LV2_State_Retrieve_Function retrieve,
- LV2_State_Handle handle,
- uint32_t flags,
- const LV2_Feature* const* features)
-{
- Params* self = (Params*)instance;
- LV2_State_Status st = LV2_STATE_SUCCESS;
-
- for (unsigned i = 0; i < N_PROPS; ++i) {
- retrieve_prop(self, &st, retrieve, handle, self->props[i].urid);
- }
-
- return st;
-}
-
-static inline bool
-subject_is_plugin(Params* self, const LV2_Atom_URID* subject)
-{
- // This simple plugin only supports one subject: itself
- return (!subject || (subject->atom.type == self->uris.atom_URID &&
- subject->body == self->uris.plugin));
-}
-
-static void
-run(LV2_Handle instance, uint32_t sample_count)
-{
- Params* self = (Params*)instance;
- URIs* uris = &self->uris;
-
- // Initially, self->out_port contains a Chunk with size set to capacity
- // Set up forge to write directly to output port
- const uint32_t out_capacity = self->out_port->atom.size;
- lv2_atom_forge_set_buffer(
- &self->forge, (uint8_t*)self->out_port, out_capacity);
-
- // Start a sequence in the output port
- LV2_Atom_Forge_Frame out_frame;
- lv2_atom_forge_sequence_head(&self->forge, &out_frame, 0);
-
- // Read incoming events
- LV2_ATOM_SEQUENCE_FOREACH (self->in_port, ev) {
- const LV2_Atom_Object* obj = (const LV2_Atom_Object*)&ev->body;
- if (obj->body.otype == uris->patch_Set) {
- // Get the property and value of the set message
- const LV2_Atom_URID* subject = NULL;
- const LV2_Atom_URID* property = NULL;
- const LV2_Atom* value = NULL;
-
- // clang-format off
- lv2_atom_object_get(obj,
- uris->patch_subject, (const LV2_Atom**)&subject,
- uris->patch_property, (const LV2_Atom**)&property,
- uris->patch_value, &value,
- 0);
- // clang-format on
-
- if (!subject_is_plugin(self, subject)) {
- lv2_log_error(&self->log, "Set for unknown subject\n");
- } else if (!property) {
- lv2_log_error(&self->log, "Set with no property\n");
- } else if (property->atom.type != uris->atom_URID) {
- lv2_log_error(&self->log, "Set property is not a URID\n");
- } else {
- // Set property to the given value
- const LV2_URID key = property->body;
- set_parameter(self, key, value->size, value->type, value + 1, false);
- }
- } else if (obj->body.otype == uris->patch_Get) {
- // Get the property of the get message
- const LV2_Atom_URID* subject = NULL;
- const LV2_Atom_URID* property = NULL;
-
- // clang-format off
- lv2_atom_object_get(obj,
- uris->patch_subject, (const LV2_Atom**)&subject,
- uris->patch_property, (const LV2_Atom**)&property,
- 0);
- // clang-format on
-
- if (!subject_is_plugin(self, subject)) {
- lv2_log_error(&self->log, "Get with unknown subject\n");
- } else if (!property) {
- // Get with no property, emit complete state
- lv2_atom_forge_frame_time(&self->forge, ev->time.frames);
- LV2_Atom_Forge_Frame pframe;
- lv2_atom_forge_object(&self->forge, &pframe, 0, uris->patch_Put);
- lv2_atom_forge_key(&self->forge, uris->patch_body);
-
- LV2_Atom_Forge_Frame bframe;
- lv2_atom_forge_object(&self->forge, &bframe, 0, 0);
- save(self, write_param_to_forge, &self->forge, 0, NULL);
-
- lv2_atom_forge_pop(&self->forge, &bframe);
- lv2_atom_forge_pop(&self->forge, &pframe);
- } else if (property->atom.type != uris->atom_URID) {
- lv2_log_error(&self->log, "Get property is not a URID\n");
- } else {
- // Get for a specific property
- const LV2_URID key = property->body;
- const LV2_Atom* value = get_parameter(self, key);
- if (value) {
- lv2_atom_forge_frame_time(&self->forge, ev->time.frames);
- LV2_Atom_Forge_Frame frame;
- lv2_atom_forge_object(&self->forge, &frame, 0, uris->patch_Set);
- lv2_atom_forge_key(&self->forge, uris->patch_property);
- lv2_atom_forge_urid(&self->forge, property->body);
- store_prop(self,
- NULL,
- NULL,
- write_param_to_forge,
- &self->forge,
- uris->patch_value,
- value);
- lv2_atom_forge_pop(&self->forge, &frame);
- }
- }
- } else {
- lv2_log_trace(
- &self->log, "Unknown object type <%s>\n", unmap(self, obj->body.otype));
- }
- }
-
- if (self->state.spring.body > 0.0f) {
- const float spring = self->state.spring.body;
- self->state.spring.body = (spring >= 0.001) ? spring - 0.001f : 0.0f;
- lv2_atom_forge_frame_time(&self->forge, 0);
- LV2_Atom_Forge_Frame frame;
- lv2_atom_forge_object(&self->forge, &frame, 0, uris->patch_Set);
-
- lv2_atom_forge_key(&self->forge, uris->patch_property);
- lv2_atom_forge_urid(&self->forge, uris->eg_spring);
- lv2_atom_forge_key(&self->forge, uris->patch_value);
- lv2_atom_forge_float(&self->forge, self->state.spring.body);
-
- lv2_atom_forge_pop(&self->forge, &frame);
- }
-
- lv2_atom_forge_pop(&self->forge, &out_frame);
-}
-
-static const void*
-extension_data(const char* uri)
-{
- static const LV2_State_Interface state = {save, restore};
- if (!strcmp(uri, LV2_STATE__interface)) {
- return &state;
- }
- return NULL;
-}
-
-static const LV2_Descriptor descriptor = {EG_PARAMS_URI,
- instantiate,
- connect_port,
- NULL, // activate,
- run,
- NULL, // deactivate,
- cleanup,
- extension_data};
-
-LV2_SYMBOL_EXPORT const LV2_Descriptor*
-lv2_descriptor(uint32_t index)
-{
- return (index == 0) ? &descriptor : NULL;
-}
diff --git a/plugins/eg-params.lv2/params.ttl b/plugins/eg-params.lv2/params.ttl
deleted file mode 100644
index 931c826..0000000
--- a/plugins/eg-params.lv2/params.ttl
+++ /dev/null
@@ -1,126 +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 param: <http://lv2plug.in/ns/ext/parameters#> .
-@prefix patch: <http://lv2plug.in/ns/ext/patch#> .
-@prefix plug: <http://lv2plug.in/plugins/eg-params#> .
-@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
-@prefix state: <http://lv2plug.in/ns/ext/state#> .
-@prefix urid: <http://lv2plug.in/ns/ext/urid#> .
-@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
-
-# An existing parameter or RDF property can be used as a parameter. The LV2
-# parameters extension <http://lv2plug.in/ns/ext/parameters> defines many
-# common audio parameters. Where possible, existing parameters should be used
-# so hosts can intelligently control plugins.
-
-# If no suitable parameter exists, one can be defined for the plugin like so:
-
-plug:int
- a lv2:Parameter ;
- rdfs:label "int" ;
- rdfs:range atom:Int .
-
-plug:long
- a lv2:Parameter ;
- rdfs:label "long" ;
- rdfs:range atom:Long .
-
-plug:float
- a lv2:Parameter ;
- rdfs:label "float" ;
- rdfs:range atom:Float .
-
-plug:double
- a lv2:Parameter ;
- rdfs:label "double" ;
- rdfs:range atom:Double .
-
-plug:bool
- a lv2:Parameter ;
- rdfs:label "bool" ;
- rdfs:range atom:Bool .
-
-plug:string
- a lv2:Parameter ;
- rdfs:label "string" ;
- rdfs:range atom:String .
-
-plug:path
- a lv2:Parameter ;
- rdfs:label "path" ;
- rdfs:range atom:Path .
-
-plug:lfo
- a lv2:Parameter ;
- rdfs:label "LFO" ;
- rdfs:range atom:Float ;
- lv2:minimum -1.0 ;
- lv2:maximum 1.0 .
-
-plug:spring
- a lv2:Parameter ;
- rdfs:label "spring" ;
- rdfs:range atom:Float .
-
-# Most of the plugin description is similar to the others we have seen, but
-# this plugin has only two ports, for receiving and sending messages used to
-# manipulate and access parameters.
-<http://lv2plug.in/plugins/eg-params>
- a lv2:Plugin ,
- lv2:UtilityPlugin ;
- doap:name "Example Parameters" ;
- doap:license <http://opensource.org/licenses/isc> ;
- lv2:project <http://lv2plug.in/ns/lv2> ;
- lv2:requiredFeature urid:map ;
- lv2:optionalFeature lv2:hardRTCapable ,
- state:loadDefaultState ;
- lv2:extensionData state:interface ;
- lv2:port [
- a lv2:InputPort ,
- atom:AtomPort ;
- atom:bufferType atom:Sequence ;
- atom:supports patch:Message ;
- lv2:designation lv2:control ;
- lv2:index 0 ;
- lv2:symbol "in" ;
- lv2:name "In"
- ] , [
- a lv2:OutputPort ,
- atom:AtomPort ;
- atom:bufferType atom:Sequence ;
- atom:supports patch:Message ;
- lv2:designation lv2:control ;
- lv2:index 1 ;
- lv2:symbol "out" ;
- lv2:name "Out"
- ] ;
-# The plugin must list all parameters that can be written (e.g. changed by the
-# user) as patch:writable:
- patch:writable plug:int ,
- plug:long ,
- plug:float ,
- plug:double ,
- plug:bool ,
- plug:string ,
- plug:path ,
- plug:spring ;
-# Similarly, parameters that may change internally must be listed as patch:readable,
-# meaning to host should watch for changes to the parameter's value:
- patch:readable plug:lfo ,
- plug:spring ;
-# Parameters map directly to properties of the plugin's state. So, we can
-# specify initial parameter values with the state:state property. The
-# state:loadDefaultState feature (required above) requires that the host loads
-# the default state after instantiation but before running the plugin.
- state:state [
- plug:int 0 ;
- plug:long "0"^^xsd:long ;
- plug:float "0.1234"^^xsd:float ;
- plug:double "0e0"^^xsd:double ;
- plug:bool false ;
- plug:string "Hello, world" ;
- plug:path <params.ttl> ;
- plug:spring "0.0"^^xsd:float ;
- plug:lfo "0.0"^^xsd:float
- ] .
diff --git a/plugins/eg-params.lv2/state_map.h b/plugins/eg-params.lv2/state_map.h
deleted file mode 100644
index c81ea29..0000000
--- a/plugins/eg-params.lv2/state_map.h
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2016 David Robillard <d@drobilla.net>
-// SPDX-License-Identifier: ISC
-
-#include <lv2/atom/atom.h>
-#include <lv2/urid/urid.h>
-
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-/** Entry in an array that serves as a dictionary of properties. */
-typedef struct {
- const char* uri;
- LV2_URID urid;
- LV2_Atom* value;
-} StateMapItem;
-
-/** Comparator for StateMapItems sorted by URID. */
-static int
-state_map_cmp(const void* a, const void* b)
-{
- const StateMapItem* ka = (const StateMapItem*)a;
- const StateMapItem* kb = (const StateMapItem*)b;
- if (ka->urid < kb->urid) {
- return -1;
- }
-
- if (kb->urid < ka->urid) {
- return 1;
- }
-
- return 0;
-}
-
-/** Helper macro for terse state map initialisation. */
-#define STATE_MAP_INIT(type, ptr) \
- (LV2_ATOM__##type), (sizeof(*(ptr)) - sizeof(LV2_Atom)), (ptr)
-
-/**
- Initialise a state map.
-
- The variable parameters list must be NULL terminated, and is a sequence of
- const char* uri, const char* type, uint32_t size, LV2_Atom* value. The
- value must point to a valid atom that resides elsewhere, the state map is
- only an index and does not contain actual state values. The macro
- STATE_MAP_INIT can be used to make simpler code when state is composed of
- standard atom types, for example:
-
- struct Plugin {
- LV2_URID_Map* map;
- StateMapItem props[3];
- // ...
- };
-
- state_map_init(
- self->props, self->map, self->map->handle,
- PLUG_URI "#gain", STATE_MAP_INIT(Float, &state->gain),
- PLUG_URI "#offset", STATE_MAP_INIT(Int, &state->offset),
- PLUG_URI "#file", STATE_MAP_INIT(Path, &state->file),
- NULL);
-*/
-static void
-state_map_init(
- StateMapItem dict[],
- LV2_URID_Map* map,
- LV2_URID_Map_Handle handle,
- /* const char* uri, const char* type, uint32_t size, LV2_Atom* value */...)
-{
- // Set dict entries from parameters
- unsigned i = 0;
- va_list args; // NOLINT(cppcoreguidelines-init-variables)
- va_start(args, handle);
- for (const char* uri = NULL; (uri = va_arg(args, const char*)); ++i) {
- const char* type = va_arg(args, const char*);
- const uint32_t size = va_arg(args, uint32_t);
- LV2_Atom* const value = va_arg(args, LV2_Atom*);
- dict[i].uri = uri;
- dict[i].urid = map->map(map->handle, uri);
- dict[i].value = value;
- dict[i].value->size = size;
- dict[i].value->type = map->map(map->handle, type);
- }
- va_end(args);
-
- // Sort for fast lookup by URID by state_map_find()
- qsort(dict, i, sizeof(StateMapItem), state_map_cmp);
-}
-
-/**
- Retrieve an item from a state map by URID.
-
- This takes O(lg(n)) time, and is useful for implementing generic property
- access with little code, for example to respond to patch:Get messages for a
- specific property.
-*/
-static StateMapItem*
-state_map_find(StateMapItem dict[], uint32_t n_entries, LV2_URID urid)
-{
- const StateMapItem key = {NULL, urid, NULL};
- return (StateMapItem*)bsearch(
- &key, dict, n_entries, sizeof(StateMapItem), state_map_cmp);
-}
diff --git a/plugins/eg-sampler.lv2/README.txt b/plugins/eg-sampler.lv2/README.txt
deleted file mode 100644
index 8d136fa..0000000
--- a/plugins/eg-sampler.lv2/README.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-== 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
-- Network-transparent waveform display with incremental peak transmission
diff --git a/plugins/eg-sampler.lv2/atom_sink.h b/plugins/eg-sampler.lv2/atom_sink.h
deleted file mode 100644
index 3319767..0000000
--- a/plugins/eg-sampler.lv2/atom_sink.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2016 David Robillard <d@drobilla.net>
-// SPDX-License-Identifier: ISC
-
-#include <lv2/atom/atom.h>
-#include <lv2/atom/forge.h>
-#include <lv2/atom/util.h>
-
-#include <stdint.h>
-#include <string.h>
-
-/**
- A forge sink that writes to an atom buffer.
-
- It is assumed that the handle points to an LV2_Atom large enough to store
- the forge output. The forged result is in the body of the buffer atom.
-*/
-static LV2_Atom_Forge_Ref
-atom_sink(LV2_Atom_Forge_Sink_Handle handle, const void* buf, uint32_t size)
-{
- LV2_Atom* atom = (LV2_Atom*)handle;
- const uint32_t offset = lv2_atom_total_size(atom);
- memcpy((char*)atom + offset, buf, size);
- atom->size += size;
- return offset;
-}
-
-/**
- Dereference counterpart to atom_sink().
-*/
-static LV2_Atom*
-atom_sink_deref(LV2_Atom_Forge_Sink_Handle handle, LV2_Atom_Forge_Ref ref)
-{
- return (LV2_Atom*)((char*)handle + ref);
-}
diff --git a/plugins/eg-sampler.lv2/click.wav b/plugins/eg-sampler.lv2/click.wav
deleted file mode 100644
index 520a18c..0000000
--- a/plugins/eg-sampler.lv2/click.wav
+++ /dev/null
Binary files differ
diff --git a/plugins/eg-sampler.lv2/manifest.ttl.in b/plugins/eg-sampler.lv2/manifest.ttl.in
deleted file mode 100644
index e688256..0000000
--- a/plugins/eg-sampler.lv2/manifest.ttl.in
+++ /dev/null
@@ -1,19 +0,0 @@
-# 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#> .
-
-<http://lv2plug.in/plugins/eg-sampler>
- a lv2:Plugin ;
- lv2:binary <sampler@LIB_EXT@> ;
- rdfs:seeAlso <sampler.ttl> .
-
-<http://lv2plug.in/plugins/eg-sampler#ui>
- a ui:GtkUI ;
- lv2:binary <sampler_ui@LIB_EXT@> ;
- rdfs:seeAlso <sampler.ttl> .
diff --git a/plugins/eg-sampler.lv2/meson.build b/plugins/eg-sampler.lv2/meson.build
deleted file mode 100644
index a0f8799..0000000
--- a/plugins/eg-sampler.lv2/meson.build
+++ /dev/null
@@ -1,82 +0,0 @@
-# Copyright 2022 David Robillard <d@drobilla.net>
-# SPDX-License-Identifier: 0BSD OR ISC
-
-plugin_sources = files('sampler.c')
-ui_sources = files('sampler_ui.c')
-bundle_name = 'eg-sampler.lv2'
-data_filenames = ['manifest.ttl.in', 'sampler.ttl', 'click.wav']
-
-samplerate_dep = dependency(
- 'samplerate',
- include_type: 'system',
- required: get_option('plugins'),
- version: '>= 0.1.0',
-)
-
-sndfile_dep = dependency(
- 'sndfile',
- include_type: 'system',
- required: get_option('plugins'),
- version: '>= 1.0.0',
-)
-
-gtk2_dep = dependency(
- 'gtk+-2.0',
- include_type: 'system',
- required: get_option('plugins'),
- version: '>= 2.18.0',
-)
-
-if samplerate_dep.found() and sndfile_dep.found()
- module = shared_library(
- 'sampler',
- plugin_sources,
- c_args: c_suppressions,
- dependencies: [lv2_dep, m_dep, samplerate_dep, sndfile_dep],
- gnu_symbol_visibility: 'hidden',
- implicit_include_directories: false,
- install: true,
- install_dir: lv2dir / bundle_name,
- name_prefix: '',
- )
-
- extension = '.' + module.full_path().split('.')[-1]
- config = configuration_data({'LIB_EXT': extension})
-
- 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
-
- if gtk2_dep.found()
- ui_suppressions = c_suppressions
- if cc.get_id() == 'gcc'
- ui_suppressions += ['-Wno-strict-overflow']
- endif
-
- shared_library(
- 'sampler_ui',
- ui_sources,
- c_args: ui_suppressions,
- dependencies: [lv2_dep, gtk2_dep],
- gnu_symbol_visibility: 'hidden',
- implicit_include_directories: false,
- install: true,
- install_dir: lv2dir / bundle_name,
- name_prefix: '',
- )
- endif
-endif
diff --git a/plugins/eg-sampler.lv2/peaks.h b/plugins/eg-sampler.lv2/peaks.h
deleted file mode 100644
index ff91546..0000000
--- a/plugins/eg-sampler.lv2/peaks.h
+++ /dev/null
@@ -1,266 +0,0 @@
-// Copyright 2016 David Robillard <d@drobilla.net>
-// SPDX-License-Identifier: ISC
-
-#ifndef PEAKS_H_INCLUDED
-#define PEAKS_H_INCLUDED
-
-/**
- This file defines utilities for sending and receiving audio peaks for
- waveform display. The functionality is divided into two objects:
- PeaksSender, for sending peaks updates from the plugin, and PeaksReceiver,
- for receiving such updates and caching the peaks.
-
- This allows peaks for a waveform of any size at any resolution to be
- requested, with reasonably sized incremental updates sent over plugin ports.
-*/
-
-#include <lv2/atom/atom.h>
-#include <lv2/atom/forge.h>
-#include <lv2/atom/util.h>
-#include <lv2/urid/urid.h>
-
-#include <math.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define PEAKS_URI "http://lv2plug.in/ns/peaks#"
-#define PEAKS__PeakUpdate PEAKS_URI "PeakUpdate"
-#define PEAKS__magnitudes PEAKS_URI "magnitudes"
-#define PEAKS__offset PEAKS_URI "offset"
-#define PEAKS__total PEAKS_URI "total"
-
-#ifndef MIN
-# define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-#ifndef MAX
-# define MAX(a, b) (((a) > (b)) ? (a) : (b))
-#endif
-
-typedef struct {
- LV2_URID atom_Float;
- LV2_URID atom_Int;
- LV2_URID atom_Vector;
- LV2_URID peaks_PeakUpdate;
- LV2_URID peaks_magnitudes;
- LV2_URID peaks_offset;
- LV2_URID peaks_total;
-} PeaksURIs;
-
-typedef struct {
- PeaksURIs uris; ///< URIDs used in protocol
- const float* samples; ///< Sample data
- uint32_t n_samples; ///< Total number of samples
- uint32_t n_peaks; ///< Total number of peaks
- uint32_t current_offset; ///< Current peak offset
- bool sending; ///< True iff currently sending
-} PeaksSender;
-
-typedef struct {
- PeaksURIs uris; ///< URIDs used in protocol
- float* peaks; ///< Received peaks, or zeroes
- uint32_t n_peaks; ///< Total number of peaks
-} PeaksReceiver;
-
-/**
- Map URIs used in the peaks protocol.
-*/
-static inline void
-peaks_map_uris(PeaksURIs* uris, LV2_URID_Map* map)
-{
- uris->atom_Float = map->map(map->handle, LV2_ATOM__Float);
- uris->atom_Int = map->map(map->handle, LV2_ATOM__Int);
- uris->atom_Vector = map->map(map->handle, LV2_ATOM__Vector);
- uris->peaks_PeakUpdate = map->map(map->handle, PEAKS__PeakUpdate);
- uris->peaks_magnitudes = map->map(map->handle, PEAKS__magnitudes);
- uris->peaks_offset = map->map(map->handle, PEAKS__offset);
- uris->peaks_total = map->map(map->handle, PEAKS__total);
-}
-
-/**
- Initialise peaks sender. The new sender is inactive and will do nothing
- when `peaks_sender_send()` is called, until a transmission is started with
- `peaks_sender_start()`.
-*/
-static inline PeaksSender*
-peaks_sender_init(PeaksSender* sender, LV2_URID_Map* map)
-{
- memset(sender, 0, sizeof(*sender));
- peaks_map_uris(&sender->uris, map);
- return sender;
-}
-
-/**
- Prepare to start a new peaks transmission. After this is called, the peaks
- can be sent with successive calls to `peaks_sender_send()`.
-*/
-static inline void
-peaks_sender_start(PeaksSender* sender,
- const float* samples,
- uint32_t n_samples,
- uint32_t n_peaks)
-{
- sender->samples = samples;
- sender->n_samples = n_samples;
- sender->n_peaks = n_peaks;
- sender->current_offset = 0;
- sender->sending = true;
-}
-
-/**
- Forge a message which sends a range of peaks. Writes a peaks:PeakUpdate
- object to `forge`, like:
-
- [source,turtle]
- ----
- []
- a peaks:PeakUpdate ;
- peaks:offset 256 ;
- peaks:total 1024 ;
- peaks:magnitudes [ 0.2f, 0.3f, ... ] .
- ----
-*/
-static inline bool
-peaks_sender_send(PeaksSender* sender,
- LV2_Atom_Forge* forge,
- uint32_t n_frames,
- uint32_t offset)
-{
- const PeaksURIs* uris = &sender->uris;
- if (!sender->sending || sender->current_offset >= sender->n_peaks) {
- return sender->sending = false;
- }
-
- // Start PeakUpdate object
- lv2_atom_forge_frame_time(forge, offset);
- LV2_Atom_Forge_Frame frame;
- lv2_atom_forge_object(forge, &frame, 0, uris->peaks_PeakUpdate);
-
- // eg:offset = OFFSET
- lv2_atom_forge_key(forge, uris->peaks_offset);
- lv2_atom_forge_int(forge, (int32_t)sender->current_offset);
-
- // eg:total = TOTAL
- lv2_atom_forge_key(forge, uris->peaks_total);
- lv2_atom_forge_int(forge, (int32_t)sender->n_peaks);
-
- // eg:magnitudes = Vector<Float>(PEAK, PEAK, ...)
- lv2_atom_forge_key(forge, uris->peaks_magnitudes);
- LV2_Atom_Forge_Frame vec_frame;
- lv2_atom_forge_vector_head(
- forge, &vec_frame, sizeof(float), uris->atom_Float);
-
- // Calculate how many peaks to send this update
- const uint32_t chunk_size = MAX(1U, sender->n_samples / sender->n_peaks);
- const uint32_t space = forge->size - forge->offset;
- const uint32_t remaining = sender->n_peaks - sender->current_offset;
- const uint32_t n_update =
- MIN(remaining, MIN(n_frames / 4U, space / sizeof(float)));
-
- // Calculate peak (maximum magnitude) for each chunk
- for (uint32_t i = 0; i < n_update; ++i) {
- const uint32_t start = (sender->current_offset + i) * chunk_size;
- float peak = 0.0f;
- for (uint32_t j = 0; j < chunk_size; ++j) {
- peak = fmaxf(peak, fabsf(sender->samples[start + j]));
- }
- lv2_atom_forge_float(forge, peak);
- }
-
- // Finish message
- lv2_atom_forge_pop(forge, &vec_frame);
- lv2_atom_forge_pop(forge, &frame);
-
- sender->current_offset += n_update;
- return true;
-}
-
-/**
- Initialise a peaks receiver. The receiver stores an array of all peaks,
- which is updated incrementally with peaks_receiver_receive().
-*/
-static inline PeaksReceiver*
-peaks_receiver_init(PeaksReceiver* receiver, LV2_URID_Map* map)
-{
- memset(receiver, 0, sizeof(*receiver));
- peaks_map_uris(&receiver->uris, map);
- return receiver;
-}
-
-/**
- Clear stored peaks and free all memory. This should be called when the
- peaks are to be updated with a different audio source.
-*/
-static inline void
-peaks_receiver_clear(PeaksReceiver* receiver)
-{
- free(receiver->peaks);
- receiver->peaks = NULL;
- receiver->n_peaks = 0;
-}
-
-/**
- Handle PeakUpdate message.
-
- The stored peaks array is updated with the slice of peaks in `update`,
- resizing if necessary while preserving contents.
-
- Returns 0 if peaks have been updated, negative on error.
-*/
-static inline int
-peaks_receiver_receive(PeaksReceiver* receiver, const LV2_Atom_Object* update)
-{
- const PeaksURIs* uris = &receiver->uris;
-
- // Get properties of interest from update
- const LV2_Atom_Int* offset = NULL;
- const LV2_Atom_Int* total = NULL;
- const LV2_Atom_Vector* peaks = NULL;
-
- // clang-format off
- lv2_atom_object_get_typed(update,
- uris->peaks_offset, &offset, uris->atom_Int,
- uris->peaks_total, &total, uris->atom_Int,
- uris->peaks_magnitudes, &peaks, uris->atom_Vector,
- 0);
- // clang-format on
-
- if (!offset || !total || !peaks ||
- peaks->body.child_type != uris->atom_Float) {
- return -1; // Invalid update
- }
-
- const uint32_t n = (uint32_t)total->body;
- if (receiver->n_peaks != n) {
- // Update is for a different total number of peaks, resize
- receiver->peaks = (float*)realloc(receiver->peaks, n * sizeof(float));
- if (receiver->n_peaks > 0 && receiver->n_peaks < n) {
- /* The peaks array is being expanded. Copy the old peaks,
- duplicating each as necessary to fill the new peaks buffer.
- This preserves the current peaks so that the peaks array can be
- reasonably drawn at any time, but the resolution will increase
- as new updates arrive. */
- const int64_t n_per = n / receiver->n_peaks;
- for (int64_t i = n - 1; i >= 0; --i) {
- receiver->peaks[i] = receiver->peaks[i / n_per];
- }
- } else if (receiver->n_peaks > 0) {
- /* The peak array is being shrunk. Similar to the above. */
- const int64_t n_per = receiver->n_peaks / n;
- for (int64_t i = n - 1; i >= 0; --i) {
- receiver->peaks[i] = receiver->peaks[i * n_per];
- }
- }
- receiver->n_peaks = n;
- }
-
- // Copy vector contents to corresponding range in peaks array
- memcpy(receiver->peaks + offset->body,
- peaks + 1,
- peaks->atom.size - sizeof(LV2_Atom_Vector_Body));
-
- return 0;
-}
-
-#endif // PEAKS_H_INCLUDED
diff --git a/plugins/eg-sampler.lv2/sampler.c b/plugins/eg-sampler.lv2/sampler.c
deleted file mode 100644
index 6fc04c5..0000000
--- a/plugins/eg-sampler.lv2/sampler.c
+++ /dev/null
@@ -1,695 +0,0 @@
-// Copyright 2011-2016 David Robillard <d@drobilla.net>
-// Copyright 2011 Gabriel M. Beddingfield <gabriel@teuton.org>
-// Copyright 2011 James Morris <jwm.art.net@gmail.com>
-// SPDX-License-Identifier: ISC
-
-#include "atom_sink.h"
-#include "peaks.h"
-#include "uris.h"
-
-#include <lv2/atom/atom.h>
-#include <lv2/atom/forge.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/midi/midi.h>
-#include <lv2/state/state.h>
-#include <lv2/urid/urid.h>
-#include <lv2/worker/worker.h>
-
-#include <samplerate.h>
-#include <sndfile.h>
-
-#include <math.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-enum { SAMPLER_CONTROL = 0, SAMPLER_NOTIFY = 1, SAMPLER_OUT = 2 };
-
-typedef struct {
- SF_INFO info; // Info about sample from sndfile
- float* data; // Sample data in float
- char* path; // Path of file
- uint32_t path_len; // Length of path
-} Sample;
-
-typedef struct {
- // Features
- LV2_URID_Map* map;
- LV2_Worker_Schedule* schedule;
- LV2_Log_Logger logger;
-
- // Ports
- const LV2_Atom_Sequence* control_port;
- LV2_Atom_Sequence* notify_port;
- float* output_port;
-
- // Communication utilities
- LV2_Atom_Forge_Frame notify_frame; ///< Cached for worker replies
- LV2_Atom_Forge forge; ///< Forge for writing atoms in run thread
- PeaksSender psend; ///< Audio peaks sender
-
- // URIs
- SamplerURIs uris;
-
- // Playback state
- Sample* sample;
- uint32_t frame_offset;
- float gain;
- float gain_dB;
- sf_count_t frame;
- bool play;
- bool activated;
- bool gain_changed;
- bool sample_changed;
- int sample_rate;
-} Sampler;
-
-/**
- An atom-like message used internally to apply/free samples.
-
- This is only used internally to communicate with the worker, it is never
- sent to the outside world via a port since it is not POD. It is convenient
- to use an Atom header so actual atoms can be easily sent through the same
- ringbuffer.
-*/
-typedef struct {
- LV2_Atom atom;
- Sample* sample;
-} SampleMessage;
-
-/**
- Convert an interleaved audio buffer to mono.
-
- This simply ignores the data on all channels but the first.
-*/
-static sf_count_t
-convert_to_mono(float* data, sf_count_t num_input_frames, uint32_t channels)
-{
- sf_count_t num_output_frames = 0;
-
- for (sf_count_t i = 0; i < num_input_frames * channels; i += channels) {
- data[num_output_frames++] = data[i];
- }
-
- return num_output_frames;
-}
-
-/**
- Load a new sample and return it.
-
- Since this is of course not a real-time safe action, this is called in the
- worker thread only. The sample is loaded and returned only, plugin state is
- not modified.
-*/
-static Sample*
-load_sample(LV2_Log_Logger* logger, const char* path, const int sample_rate)
-{
- lv2_log_trace(logger, "Loading %s\n", path);
-
- const size_t path_len = strlen(path);
- Sample* const sample = (Sample*)calloc(1, sizeof(Sample));
- SF_INFO* const info = &sample->info;
- SNDFILE* const sndfile = sf_open(path, SFM_READ, info);
- float* data = NULL;
- bool error = true;
- if (!sndfile || !info->frames) {
- lv2_log_error(logger, "Failed to open %s\n", path);
- } else if (!(data = (float*)malloc(sizeof(float) * info->frames *
- info->channels))) {
- lv2_log_error(logger, "Failed to allocate memory for sample\n");
- } else {
- error = false;
- }
-
- if (error) {
- free(sample);
- free(data);
- sf_close(sndfile);
- return NULL;
- }
-
- sf_seek(sndfile, 0UL, SEEK_SET);
- sf_read_float(sndfile, data, info->frames * info->channels);
- sf_close(sndfile);
-
- if (info->channels != 1) {
- info->frames = convert_to_mono(data, info->frames, info->channels);
- info->channels = 1;
- }
-
- if (info->samplerate != sample_rate) {
- lv2_log_trace(logger,
- "Converting from %d Hz to %d Hz\n",
- info->samplerate,
- sample_rate);
-
- const double src_ratio = (double)sample_rate / (double)info->samplerate;
- const double output_length = ceil((double)info->frames * src_ratio);
- const long output_frames = (long)output_length;
- float* const output_buffer = (float*)malloc(sizeof(float) * output_frames);
-
- SRC_DATA src_data = {
- data,
- output_buffer,
- info->frames,
- output_frames,
- 0,
- 0,
- 0,
- src_ratio,
- };
-
- if (src_simple(&src_data, SRC_SINC_BEST_QUALITY, 1) != 0) {
- lv2_log_error(logger, "Sample rate conversion failed\n");
- free(output_buffer);
- } else {
- // Replace original data with converted buffer
- free(data);
- data = output_buffer;
- info->frames = src_data.output_frames_gen;
- }
- } else {
- lv2_log_trace(
- logger, "Sample matches the current rate of %d Hz\n", sample_rate);
- }
-
- // Fill sample struct and return it
- sample->data = data;
- sample->path = (char*)malloc(path_len + 1);
- sample->path_len = (uint32_t)path_len;
- memcpy(sample->path, path, path_len + 1);
-
- return sample;
-}
-
-static void
-free_sample(Sampler* self, Sample* sample)
-{
- if (sample) {
- lv2_log_trace(&self->logger, "Freeing %s\n", sample->path);
- free(sample->path);
- free(sample->data);
- free(sample);
- }
-}
-
-/**
- Do work in a non-realtime thread.
-
- This is called for every piece of work scheduled in the audio thread using
- self->schedule->schedule_work(). A reply can be sent back to the audio
- thread using the provided `respond` function.
-*/
-static LV2_Worker_Status
-work(LV2_Handle instance,
- LV2_Worker_Respond_Function respond,
- LV2_Worker_Respond_Handle handle,
- uint32_t size,
- const void* data)
-{
- Sampler* self = (Sampler*)instance;
- const LV2_Atom* atom = (const LV2_Atom*)data;
- if (atom->type == self->uris.eg_freeSample) {
- // Free old sample
- const SampleMessage* msg = (const SampleMessage*)data;
- free_sample(self, msg->sample);
- } else if (atom->type == self->forge.Object) {
- // Handle set message (load sample).
- const LV2_Atom_Object* obj = (const LV2_Atom_Object*)data;
- const char* path = read_set_file(&self->uris, obj);
- if (!path) {
- lv2_log_error(&self->logger, "Malformed set file request\n");
- return LV2_WORKER_ERR_UNKNOWN;
- }
-
- // Load sample.
- Sample* sample = load_sample(&self->logger, path, self->sample_rate);
- if (sample) {
- // Send new sample to run() to be applied
- respond(handle, sizeof(Sample*), &sample);
- }
- }
-
- return LV2_WORKER_SUCCESS;
-}
-
-/**
- Handle a response from work() in the audio thread.
-
- When running normally, this will be called by the host after run(). When
- freewheeling, this will be called immediately at the point the work was
- scheduled.
-*/
-static LV2_Worker_Status
-work_response(LV2_Handle instance, uint32_t size, const void* data)
-{
- Sampler* self = (Sampler*)instance;
- Sample* old_sample = self->sample;
- const Sample* new_sample = *(Sample* const*)data;
-
- // Install the new sample
- self->sample = *(Sample* const*)data;
-
- // Stop playing previous sample, which can be larger than new one
- self->frame = 0;
- self->play = false;
-
- // Schedule work to free the old sample
- SampleMessage msg = {{sizeof(Sample*), self->uris.eg_freeSample}, old_sample};
- self->schedule->schedule_work(self->schedule->handle, sizeof(msg), &msg);
-
- // 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, new_sample->path, new_sample->path_len);
-
- return LV2_WORKER_SUCCESS;
-}
-
-static void
-connect_port(LV2_Handle instance, uint32_t port, void* data)
-{
- Sampler* self = (Sampler*)instance;
- switch (port) {
- case SAMPLER_CONTROL:
- self->control_port = (const LV2_Atom_Sequence*)data;
- break;
- case SAMPLER_NOTIFY:
- self->notify_port = (LV2_Atom_Sequence*)data;
- break;
- case SAMPLER_OUT:
- self->output_port = (float*)data;
- break;
- default:
- break;
- }
-}
-
-static LV2_Handle
-instantiate(const LV2_Descriptor* descriptor,
- double rate,
- const char* path,
- const LV2_Feature* const* features)
-{
- // Allocate and initialise instance structure.
- Sampler* self = (Sampler*)calloc(1, sizeof(Sampler));
- if (!self) {
- return NULL;
- }
-
- // Get host features
- // clang-format off
- const char* missing = lv2_features_query(
- features,
- LV2_LOG__log, &self->logger.log, false,
- LV2_URID__map, &self->map, true,
- LV2_WORKER__schedule, &self->schedule, 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 and initialise forge
- map_sampler_uris(self->map, &self->uris);
- lv2_atom_forge_init(&self->forge, self->map);
- peaks_sender_init(&self->psend, self->map);
-
- self->gain = 1.0f;
- self->gain_dB = 0.0f;
- self->sample_rate = (int)rate;
-
- return (LV2_Handle)self;
-}
-
-static void
-cleanup(LV2_Handle instance)
-{
- Sampler* self = (Sampler*)instance;
- free_sample(self, self->sample);
- free(self);
-}
-
-static void
-activate(LV2_Handle instance)
-{
- ((Sampler*)instance)->activated = true;
-}
-
-static void
-deactivate(LV2_Handle instance)
-{
- ((Sampler*)instance)->activated = false;
-}
-
-/** Define a macro for converting a gain in dB to a coefficient. */
-#define DB_CO(g) ((g) > -90.0f ? powf(10.0f, (g) * 0.05f) : 0.0f)
-
-/**
- Handle an incoming event in the audio thread.
-
- This performs any actions triggered by an event, such as the start of sample
- playback, a sample change, or responding to requests from the UI.
-*/
-static void
-handle_event(Sampler* self, LV2_Atom_Event* ev)
-{
- SamplerURIs* uris = &self->uris;
- PeaksURIs* peaks_uris = &self->psend.uris;
-
- if (ev->body.type == uris->midi_Event) {
- const uint8_t* const msg = (const uint8_t*)(ev + 1);
- switch (lv2_midi_message_type(msg)) {
- case LV2_MIDI_MSG_NOTE_ON:
- self->frame = 0;
- self->play = true;
- break;
- default:
- break;
- }
- } else if (lv2_atom_forge_is_object_type(&self->forge, ev->body.type)) {
- const LV2_Atom_Object* obj = (const LV2_Atom_Object*)&ev->body;
- if (obj->body.otype == uris->patch_Set) {
- // Get the property and value of the set message
- const LV2_Atom* property = NULL;
- const LV2_Atom* value = NULL;
-
- // clang-format off
- lv2_atom_object_get(obj,
- uris->patch_property, &property,
- uris->patch_value, &value,
- 0);
- // clang-format on
-
- if (!property) {
- lv2_log_error(&self->logger, "Set message with no property\n");
- return;
- }
-
- if (property->type != uris->atom_URID) {
- lv2_log_error(&self->logger, "Set property is not a URID\n");
- return;
- }
-
- const uint32_t key = ((const LV2_Atom_URID*)property)->body;
- if (key == uris->eg_sample) {
- // Sample change, send it to the worker.
- lv2_log_trace(&self->logger, "Scheduling sample change\n");
- self->schedule->schedule_work(
- self->schedule->handle, lv2_atom_total_size(&ev->body), &ev->body);
- } else if (key == uris->param_gain) {
- // Gain change
- if (value->type == uris->atom_Float) {
- self->gain_dB = ((LV2_Atom_Float*)value)->body;
- self->gain = DB_CO(self->gain_dB);
- }
- }
- } else if (obj->body.otype == uris->patch_Get && self->sample) {
- const LV2_Atom_URID* accept = NULL;
- const LV2_Atom_Int* n_peaks = NULL;
-
- // clang-format off
- lv2_atom_object_get_typed(
- obj,
- uris->patch_accept, &accept, uris->atom_URID,
- peaks_uris->peaks_total, &n_peaks, peaks_uris->atom_Int,
- 0);
- // clang-format on
-
- if (accept && accept->body == peaks_uris->peaks_PeakUpdate) {
- // Received a request for peaks, prepare for transmission
- peaks_sender_start(&self->psend,
- self->sample->data,
- self->sample->info.frames,
- n_peaks->body);
- } else {
- // Received a get message, emit our state (probably to UI)
- lv2_atom_forge_frame_time(&self->forge, self->frame_offset);
- write_set_file(&self->forge,
- &self->uris,
- self->sample->path,
- self->sample->path_len);
- }
- } else {
- lv2_log_trace(&self->logger, "Unknown object type %u\n", obj->body.otype);
- }
- } else {
- lv2_log_trace(&self->logger, "Unknown event type %u\n", ev->body.type);
- }
-}
-
-/**
- Output audio for a slice of the current cycle.
-*/
-static void
-render(Sampler* self, uint32_t start, uint32_t end)
-{
- float* output = self->output_port;
-
- if (self->play && self->sample) {
- // Start/continue writing sample to output
- for (; start < end; ++start) {
- output[start] = self->sample->data[self->frame] * self->gain;
- if (++self->frame == self->sample->info.frames) {
- self->play = false; // Reached end of sample
- break;
- }
- }
- }
-
- // Write silence to remaining buffer
- for (; start < end; ++start) {
- output[start] = 0.0f;
- }
-}
-
-static void
-run(LV2_Handle instance, uint32_t sample_count)
-{
- Sampler* self = (Sampler*)instance;
-
- // 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.
- lv2_atom_forge_sequence_head(&self->forge, &self->notify_frame, 0);
-
- // Send update to UI if gain has changed due to state restore
- if (self->gain_changed) {
- lv2_atom_forge_frame_time(&self->forge, 0);
- write_set_gain(&self->forge, &self->uris, self->gain_dB);
- self->gain_changed = false;
- }
-
- // Send update to UI if sample has changed due to state restore
- if (self->sample_changed) {
- lv2_atom_forge_frame_time(&self->forge, 0);
- write_set_file(
- &self->forge, &self->uris, self->sample->path, self->sample->path_len);
- self->sample_changed = false;
- }
-
- // Iterate over incoming events, emitting audio along the way
- self->frame_offset = 0;
- LV2_ATOM_SEQUENCE_FOREACH (self->control_port, ev) {
- // Render output up to the time of this event
- render(self, self->frame_offset, ev->time.frames);
-
- /* Update current frame offset to this event's time. This is stored in
- the instance because it is used for synchronous worker event
- execution. This allows a sample load event to be executed with
- sample accuracy when running in a non-realtime context (such as
- exporting a session). */
- self->frame_offset = ev->time.frames;
-
- // Process this event
- handle_event(self, ev);
- }
-
- // Use available space after any emitted events to send peaks
- peaks_sender_send(
- &self->psend, &self->forge, sample_count, self->frame_offset);
-
- // Render output for the rest of the cycle past the last event
- render(self, self->frame_offset, sample_count);
-}
-
-static LV2_State_Status
-save(LV2_Handle instance,
- LV2_State_Store_Function store,
- LV2_State_Handle handle,
- uint32_t flags,
- const LV2_Feature* const* features)
-{
- Sampler* self = (Sampler*)instance;
- if (!self->sample) {
- return LV2_STATE_SUCCESS;
- }
-
- LV2_State_Map_Path* map_path =
- (LV2_State_Map_Path*)lv2_features_data(features, LV2_STATE__mapPath);
- if (!map_path) {
- return LV2_STATE_ERR_NO_FEATURE;
- }
-
- // Map absolute sample path to an abstract state path
- char* apath = map_path->abstract_path(map_path->handle, self->sample->path);
-
- // Store eg:sample = abstract path
- store(handle,
- self->uris.eg_sample,
- apath,
- strlen(apath) + 1,
- self->uris.atom_Path,
- LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
-
- free(apath);
-
- // Store the gain value
- store(handle,
- self->uris.param_gain,
- &self->gain_dB,
- sizeof(self->gain_dB),
- self->uris.atom_Float,
- LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
-
- return LV2_STATE_SUCCESS;
-}
-
-static LV2_State_Status
-restore(LV2_Handle instance,
- LV2_State_Retrieve_Function retrieve,
- LV2_State_Handle handle,
- uint32_t flags,
- const LV2_Feature* const* features)
-{
- Sampler* self = (Sampler*)instance;
-
- // Get host features
- LV2_Worker_Schedule* schedule = NULL;
- LV2_State_Map_Path* paths = NULL;
-
- // clang-format off
- const char* missing = lv2_features_query(
- features,
- LV2_STATE__mapPath, &paths, true,
- LV2_WORKER__schedule, &schedule, false,
- NULL);
- // clang-format on
-
- if (missing) {
- lv2_log_error(&self->logger, "Missing feature <%s>\n", missing);
- return LV2_STATE_ERR_NO_FEATURE;
- }
-
- // Get eg:sample from state
- size_t size = 0;
- uint32_t type = 0;
- uint32_t valflags = 0;
- const void* value =
- retrieve(handle, self->uris.eg_sample, &size, &type, &valflags);
-
- if (!value) {
- lv2_log_error(&self->logger, "Missing eg:sample\n");
- return LV2_STATE_ERR_NO_PROPERTY;
- }
-
- if (type != self->uris.atom_Path) {
- lv2_log_error(&self->logger, "Non-path eg:sample\n");
- return LV2_STATE_ERR_BAD_TYPE;
- }
-
- // Map abstract state path to absolute path
- const char* apath = (const char*)value;
- char* path = paths->absolute_path(paths->handle, apath);
-
- // Replace current sample with the new one
- if (!self->activated || !schedule) {
- // No scheduling available, load sample immediately
- lv2_log_trace(&self->logger, "Synchronous restore\n");
- Sample* sample = load_sample(&self->logger, path, self->sample_rate);
- if (sample) {
- free_sample(self, self->sample);
- self->sample = sample;
- self->sample_changed = true;
- }
- } else {
- // Schedule sample to be loaded by the provided worker
- lv2_log_trace(&self->logger, "Scheduling restore\n");
- LV2_Atom_Forge forge;
- LV2_Atom* buf = (LV2_Atom*)calloc(1, strlen(path) + 128);
- lv2_atom_forge_init(&forge, self->map);
- lv2_atom_forge_set_sink(&forge, atom_sink, atom_sink_deref, buf);
- write_set_file(&forge, &self->uris, path, strlen(path));
-
- const uint32_t msg_size = lv2_atom_pad_size(buf->size);
- schedule->schedule_work(self->schedule->handle, msg_size, buf + 1);
- free(buf);
- }
-
- free(path);
-
- // Get param:gain from state
- value = retrieve(handle, self->uris.param_gain, &size, &type, &valflags);
-
- if (!value) {
- // Not an error, since older versions did not save this property
- lv2_log_note(&self->logger, "Missing param:gain\n");
- return LV2_STATE_SUCCESS;
- }
-
- if (type != self->uris.atom_Float) {
- lv2_log_error(&self->logger, "Non-float param:gain\n");
- return LV2_STATE_ERR_BAD_TYPE;
- }
-
- self->gain_dB = *(const float*)value;
- self->gain = DB_CO(self->gain_dB);
- self->gain_changed = true;
-
- return LV2_STATE_SUCCESS;
-}
-
-static const void*
-extension_data(const char* uri)
-{
- static const LV2_State_Interface state = {save, restore};
- static const LV2_Worker_Interface worker = {work, work_response, NULL};
-
- if (!strcmp(uri, LV2_STATE__interface)) {
- return &state;
- }
-
- if (!strcmp(uri, LV2_WORKER__interface)) {
- return &worker;
- }
-
- return NULL;
-}
-
-static const LV2_Descriptor descriptor = {EG_SAMPLER_URI,
- instantiate,
- connect_port,
- activate,
- run,
- deactivate,
- cleanup,
- extension_data};
-
-LV2_SYMBOL_EXPORT const LV2_Descriptor*
-lv2_descriptor(uint32_t index)
-{
- return index == 0 ? &descriptor : NULL;
-}
diff --git a/plugins/eg-sampler.lv2/sampler.ttl b/plugins/eg-sampler.lv2/sampler.ttl
deleted file mode 100644
index 4a3c24c..0000000
--- a/plugins/eg-sampler.lv2/sampler.ttl
+++ /dev/null
@@ -1,73 +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 param: <http://lv2plug.in/ns/ext/parameters#> .
-@prefix patch: <http://lv2plug.in/ns/ext/patch#> .
-@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
-@prefix state: <http://lv2plug.in/ns/ext/state#> .
-@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
-@prefix urid: <http://lv2plug.in/ns/ext/urid#> .
-@prefix work: <http://lv2plug.in/ns/ext/worker#> .
-@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
-
-<http://lv2plug.in/plugins/eg-sampler#sample>
- a lv2:Parameter ;
- rdfs:label "sample" ;
- rdfs:range atom:Path .
-
-<http://lv2plug.in/plugins/eg-sampler>
- a lv2:Plugin ;
- doap:name "Exampler" ;
- doap:license <http://opensource.org/licenses/isc> ;
- lv2:project <http://lv2plug.in/ns/lv2> ;
- lv2:requiredFeature state:loadDefaultState ,
- urid:map ,
- work:schedule ;
- lv2:optionalFeature lv2:hardRTCapable ,
- state:threadSafeRestore ;
- lv2:extensionData state:interface ,
- work:interface ;
- ui:ui <http://lv2plug.in/plugins/eg-sampler#ui> ;
- patch:writable <http://lv2plug.in/plugins/eg-sampler#sample> ,
- param:gain ;
- lv2:port [
- a lv2:InputPort ,
- atom:AtomPort ;
- atom:bufferType atom:Sequence ;
- atom:supports <http://lv2plug.in/ns/ext/midi#MidiEvent> ,
- patch:Message ;
- lv2:designation lv2:control ;
- lv2:index 0 ;
- lv2:symbol "control" ;
- lv2:name "Control"
- ] , [
- a lv2:OutputPort ,
- atom:AtomPort ;
- atom:bufferType atom:Sequence ;
- atom:supports patch:Message ;
- lv2:designation lv2:control ;
- lv2:index 1 ;
- lv2:symbol "notify" ;
- lv2:name "Notify"
- ] , [
- a lv2:AudioPort ,
- lv2:OutputPort ;
- lv2:index 2 ;
- lv2:symbol "out" ;
- lv2:name "Out"
- ] ;
- state:state [
- <http://lv2plug.in/plugins/eg-sampler#sample> <click.wav> ;
- param:gain "0.0"^^xsd:float
- ] .
-
-<http://lv2plug.in/plugins/eg-sampler#ui>
- a ui:GtkUI ;
- lv2:requiredFeature urid:map ;
- lv2:optionalFeature ui:requestValue ;
- lv2:extensionData ui:showInterface ;
- ui:portNotification [
- ui:plugin <http://lv2plug.in/plugins/eg-sampler> ;
- lv2:symbol "notify" ;
- ui:notifyType atom:Blank
- ] .
diff --git a/plugins/eg-sampler.lv2/sampler_ui.c b/plugins/eg-sampler.lv2/sampler_ui.c
deleted file mode 100644
index 769dde0..0000000
--- a/plugins/eg-sampler.lv2/sampler_ui.c
+++ /dev/null
@@ -1,458 +0,0 @@
-// Copyright 2011-2016 David Robillard <d@drobilla.net>
-// SPDX-License-Identifier: ISC
-
-#include "peaks.h"
-#include "uris.h"
-
-#include <lv2/atom/atom.h>
-#include <lv2/atom/forge.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/midi/midi.h>
-#include <lv2/ui/ui.h>
-#include <lv2/urid/urid.h>
-
-#include <cairo.h>
-#include <gdk/gdk.h>
-#include <glib-object.h>
-#include <glib.h>
-#include <gobject/gclosure.h>
-#include <gtk/gtk.h>
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define SAMPLER_UI_URI "http://lv2plug.in/plugins/eg-sampler#ui"
-
-#define MIN_CANVAS_W 128
-#define MIN_CANVAS_H 80
-
-typedef struct {
- LV2_Atom_Forge forge;
- LV2_URID_Map* map;
- LV2UI_Request_Value* request_value;
- LV2_Log_Logger logger;
- SamplerURIs uris;
- PeaksReceiver precv;
-
- LV2UI_Write_Function write;
- LV2UI_Controller controller;
-
- GtkWidget* box;
- GtkWidget* play_button;
- GtkWidget* file_button;
- GtkWidget* request_file_button;
- GtkWidget* button_box;
- GtkWidget* canvas;
-
- uint32_t width;
- uint32_t requested_n_peaks;
- char* filename;
-
- uint8_t forge_buf[1024];
-
- // Optional show/hide interface
- GtkWidget* window;
- bool did_init;
-} SamplerUI;
-
-static void
-on_file_set(GtkFileChooserButton* widget, void* handle)
-{
- SamplerUI* ui = (SamplerUI*)handle;
-
- // Get the filename from the file chooser
- char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
-
- // Write a set message to the plugin to load new file
- lv2_atom_forge_set_buffer(&ui->forge, ui->forge_buf, sizeof(ui->forge_buf));
- LV2_Atom* msg = (LV2_Atom*)write_set_file(
- &ui->forge, &ui->uris, filename, strlen(filename));
-
- assert(msg);
-
- ui->write(ui->controller,
- 0,
- lv2_atom_total_size(msg),
- ui->uris.atom_eventTransfer,
- msg);
-
- g_free(filename);
-}
-
-static void
-on_request_file(GtkButton* widget, void* handle)
-{
- SamplerUI* ui = (SamplerUI*)handle;
-
- ui->request_value->request(
- ui->request_value->handle, ui->uris.eg_sample, 0, NULL);
-}
-
-static void
-on_play_clicked(GtkFileChooserButton* widget, void* handle)
-{
- SamplerUI* ui = (SamplerUI*)handle;
- struct {
- LV2_Atom atom;
- uint8_t msg[3];
- } note_on;
-
- note_on.atom.type = ui->uris.midi_Event;
- note_on.atom.size = 3;
- note_on.msg[0] = LV2_MIDI_MSG_NOTE_ON;
- note_on.msg[1] = 60;
- note_on.msg[2] = 60;
- ui->write(ui->controller,
- 0,
- sizeof(LV2_Atom) + 3,
- ui->uris.atom_eventTransfer,
- &note_on);
-}
-
-static void
-request_peaks(SamplerUI* ui, uint32_t n_peaks)
-{
- if (n_peaks == ui->requested_n_peaks) {
- return;
- }
-
- lv2_atom_forge_set_buffer(&ui->forge, ui->forge_buf, sizeof(ui->forge_buf));
-
- LV2_Atom_Forge_Frame frame;
- lv2_atom_forge_object(&ui->forge, &frame, 0, ui->uris.patch_Get);
- lv2_atom_forge_key(&ui->forge, ui->uris.patch_accept);
- lv2_atom_forge_urid(&ui->forge, ui->precv.uris.peaks_PeakUpdate);
- lv2_atom_forge_key(&ui->forge, ui->precv.uris.peaks_total);
- lv2_atom_forge_int(&ui->forge, n_peaks);
- lv2_atom_forge_pop(&ui->forge, &frame);
-
- LV2_Atom* msg = lv2_atom_forge_deref(&ui->forge, frame.ref);
- ui->write(ui->controller,
- 0,
- lv2_atom_total_size(msg),
- ui->uris.atom_eventTransfer,
- msg);
-
- ui->requested_n_peaks = n_peaks;
-}
-
-/** Set Cairo color to a GDK color (to follow Gtk theme). */
-static void
-cairo_set_source_gdk(cairo_t* cr, const GdkColor* color)
-{
- cairo_set_source_rgb(
- cr, color->red / 65535.0, color->green / 65535.0, color->blue / 65535.0);
-}
-
-static gboolean
-on_canvas_expose(GtkWidget* widget, GdkEventExpose* event, gpointer data)
-{
- SamplerUI* ui = (SamplerUI*)data;
-
- GtkAllocation size;
- gtk_widget_get_allocation(widget, &size);
-
- ui->width = size.width;
- if (ui->width > 2 * ui->requested_n_peaks) {
- request_peaks(ui, 2 * ui->requested_n_peaks);
- }
-
- cairo_t* cr = gdk_cairo_create(gtk_widget_get_window(widget));
-
- cairo_set_line_width(cr, 1.0);
- cairo_translate(cr, 0.5, 0.5);
-
- const double mid_y = size.height / 2.0;
-
- const float* const peaks = ui->precv.peaks;
- const int32_t n_peaks = ui->precv.n_peaks;
- if (peaks) {
- // Draw waveform
- const double scale = size.width / ((double)n_peaks - 1.0f);
-
- // Start at left origin
- cairo_move_to(cr, 0, mid_y);
-
- // Draw line through top peaks
- for (int i = 0; i < n_peaks; ++i) {
- const float peak = peaks[i];
- cairo_line_to(cr, i * scale, mid_y + ((peak / 2.0f) * size.height));
- }
-
- // Continue through bottom peaks
- for (int i = n_peaks - 1; i >= 0; --i) {
- const float peak = peaks[i];
- cairo_line_to(cr, i * scale, mid_y - ((peak / 2.0f) * size.height));
- }
-
- // Close shape
- cairo_line_to(cr, 0, mid_y);
-
- cairo_set_source_gdk(cr, widget->style->mid);
- cairo_fill_preserve(cr);
-
- cairo_set_source_gdk(cr, widget->style->fg);
- cairo_stroke(cr);
- }
-
- cairo_destroy(cr);
- return TRUE;
-}
-
-static void
-destroy_window(SamplerUI* ui)
-{
- if (ui->window) {
- gtk_container_remove(GTK_CONTAINER(ui->window), ui->box);
- gtk_widget_destroy(ui->window);
- ui->window = NULL;
- }
-}
-
-static gboolean
-on_window_closed(GtkWidget* widget, GdkEvent* event, gpointer data)
-{
- SamplerUI* ui = (SamplerUI*)data;
-
- // Remove widget so Gtk doesn't delete it when the window is closed
- gtk_container_remove(GTK_CONTAINER(ui->window), ui->box);
- ui->window = NULL;
-
- return FALSE;
-}
-
-static LV2UI_Handle
-instantiate(const LV2UI_Descriptor* descriptor,
- const char* plugin_uri,
- const char* bundle_path,
- LV2UI_Write_Function write_function,
- LV2UI_Controller controller,
- LV2UI_Widget* widget,
- const LV2_Feature* const* features)
-{
- SamplerUI* ui = (SamplerUI*)calloc(1, sizeof(SamplerUI));
- if (!ui) {
- return NULL;
- }
-
- ui->write = write_function;
- ui->controller = controller;
- ui->width = MIN_CANVAS_W;
- *widget = NULL;
- ui->window = NULL;
- ui->did_init = false;
-
- // Get host features
- // clang-format off
- const char* missing = lv2_features_query(
- features,
- LV2_LOG__log, &ui->logger.log, false,
- LV2_URID__map, &ui->map, true,
- LV2_UI__requestValue, &ui->request_value, false,
- NULL);
- // clang-format on
-
- lv2_log_logger_set_map(&ui->logger, ui->map);
- if (missing) {
- lv2_log_error(&ui->logger, "Missing feature <%s>\n", missing);
- free(ui);
- return NULL;
- }
-
- // Map URIs and initialise forge
- map_sampler_uris(ui->map, &ui->uris);
- lv2_atom_forge_init(&ui->forge, ui->map);
- peaks_receiver_init(&ui->precv, ui->map);
-
- // Construct Gtk UI
- ui->box = gtk_vbox_new(FALSE, 4);
- ui->play_button = gtk_button_new_with_label("▶");
- ui->canvas = gtk_drawing_area_new();
- ui->button_box = gtk_hbox_new(FALSE, 4);
- ui->file_button =
- gtk_file_chooser_button_new("Load Sample", GTK_FILE_CHOOSER_ACTION_OPEN);
- ui->request_file_button = gtk_button_new_with_label("Request Sample");
- gtk_widget_set_size_request(ui->canvas, MIN_CANVAS_W, MIN_CANVAS_H);
- gtk_container_set_border_width(GTK_CONTAINER(ui->box), 4);
- gtk_box_pack_start(GTK_BOX(ui->box), ui->canvas, TRUE, TRUE, 0);
- gtk_box_pack_start(GTK_BOX(ui->box), ui->button_box, FALSE, TRUE, 0);
- gtk_box_pack_start(GTK_BOX(ui->button_box), ui->play_button, FALSE, FALSE, 0);
- gtk_box_pack_start(
- GTK_BOX(ui->button_box), ui->request_file_button, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(ui->button_box), ui->file_button, TRUE, TRUE, 0);
-
- g_signal_connect(ui->file_button, "file-set", G_CALLBACK(on_file_set), ui);
-
- g_signal_connect(
- ui->request_file_button, "clicked", G_CALLBACK(on_request_file), ui);
-
- g_signal_connect(ui->play_button, "clicked", G_CALLBACK(on_play_clicked), ui);
-
- g_signal_connect(
- G_OBJECT(ui->canvas), "expose_event", G_CALLBACK(on_canvas_expose), ui);
-
- // Request state (filename) from plugin
- lv2_atom_forge_set_buffer(&ui->forge, ui->forge_buf, sizeof(ui->forge_buf));
- LV2_Atom_Forge_Frame frame;
- LV2_Atom* msg =
- (LV2_Atom*)lv2_atom_forge_object(&ui->forge, &frame, 0, ui->uris.patch_Get);
-
- assert(msg);
-
- lv2_atom_forge_pop(&ui->forge, &frame);
-
- ui->write(ui->controller,
- 0,
- lv2_atom_total_size(msg),
- ui->uris.atom_eventTransfer,
- msg);
-
- *widget = ui->box;
-
- return ui;
-}
-
-static void
-cleanup(LV2UI_Handle handle)
-{
- SamplerUI* ui = (SamplerUI*)handle;
-
- if (ui->window) {
- destroy_window(ui);
- }
-
- gtk_widget_destroy(ui->canvas);
- gtk_widget_destroy(ui->play_button);
- gtk_widget_destroy(ui->file_button);
- gtk_widget_destroy(ui->request_file_button);
- gtk_widget_destroy(ui->button_box);
- gtk_widget_destroy(ui->box);
- free(ui);
-}
-
-static void
-port_event(LV2UI_Handle handle,
- uint32_t port_index,
- uint32_t buffer_size,
- uint32_t format,
- const void* buffer)
-{
- SamplerUI* ui = (SamplerUI*)handle;
- if (format == ui->uris.atom_eventTransfer) {
- const LV2_Atom* atom = (const LV2_Atom*)buffer;
- if (lv2_atom_forge_is_object_type(&ui->forge, atom->type)) {
- const LV2_Atom_Object* obj = (const LV2_Atom_Object*)atom;
- if (obj->body.otype == ui->uris.patch_Set) {
- const char* path = read_set_file(&ui->uris, obj);
- if (path && (!ui->filename || !!strcmp(path, ui->filename))) {
- g_free(ui->filename);
- ui->filename = g_strdup(path);
- gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(ui->file_button),
- path);
- peaks_receiver_clear(&ui->precv);
- ui->requested_n_peaks = 0;
- request_peaks(ui, ui->width / 2 * 2);
- } else if (!path) {
- lv2_log_warning(&ui->logger, "Set message has no path\n");
- }
- } else if (obj->body.otype == ui->precv.uris.peaks_PeakUpdate) {
- if (!peaks_receiver_receive(&ui->precv, obj)) {
- gtk_widget_queue_draw(ui->canvas);
- }
- }
- } else {
- lv2_log_error(&ui->logger, "Unknown message type\n");
- }
- } else {
- lv2_log_warning(&ui->logger, "Unknown port event format\n");
- }
-}
-
-/* Optional non-embedded UI show interface. */
-static int
-ui_show(LV2UI_Handle handle)
-{
- SamplerUI* ui = (SamplerUI*)handle;
-
- if (ui->window) {
- return 0;
- }
-
- if (!ui->did_init) {
- int argc = 0;
- gtk_init_check(&argc, NULL);
- g_object_ref(ui->box);
- ui->did_init = true;
- }
-
- ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_container_add(GTK_CONTAINER(ui->window), ui->box);
-
- g_signal_connect(
- G_OBJECT(ui->window), "delete-event", G_CALLBACK(on_window_closed), handle);
-
- gtk_widget_show_all(ui->window);
- gtk_window_present(GTK_WINDOW(ui->window));
-
- return 0;
-}
-
-/* Optional non-embedded UI hide interface. */
-static int
-ui_hide(LV2UI_Handle handle)
-{
- SamplerUI* ui = (SamplerUI*)handle;
-
- if (ui->window) {
- destroy_window(ui);
- }
-
- return 0;
-}
-
-/* Idle interface for optional non-embedded UI. */
-static int
-ui_idle(LV2UI_Handle handle)
-{
- const SamplerUI* ui = (const SamplerUI*)handle;
- if (ui->window) {
- gtk_main_iteration_do(false);
- }
- return 0;
-}
-
-static const void*
-extension_data(const char* uri)
-{
- static const LV2UI_Show_Interface show = {ui_show, ui_hide};
- static const LV2UI_Idle_Interface idle = {ui_idle};
-
- if (!strcmp(uri, LV2_UI__showInterface)) {
- return &show;
- }
-
- if (!strcmp(uri, LV2_UI__idleInterface)) {
- return &idle;
- }
-
- return NULL;
-}
-
-static const LV2UI_Descriptor descriptor = {SAMPLER_UI_URI,
- instantiate,
- cleanup,
- port_event,
- extension_data};
-
-LV2_SYMBOL_EXPORT const LV2UI_Descriptor*
-lv2ui_descriptor(uint32_t index)
-{
- return index == 0 ? &descriptor : NULL;
-}
diff --git a/plugins/eg-sampler.lv2/uris.h b/plugins/eg-sampler.lv2/uris.h
deleted file mode 100644
index 9922f51..0000000
--- a/plugins/eg-sampler.lv2/uris.h
+++ /dev/null
@@ -1,170 +0,0 @@
-// Copyright 2011-2016 David Robillard <d@drobilla.net>
-// SPDX-License-Identifier: ISC
-
-#ifndef SAMPLER_URIS_H
-#define SAMPLER_URIS_H
-
-#include <lv2/atom/atom.h>
-#include <lv2/atom/forge.h>
-#include <lv2/atom/util.h>
-#include <lv2/midi/midi.h>
-#include <lv2/parameters/parameters.h>
-#include <lv2/patch/patch.h>
-#include <lv2/urid/urid.h>
-
-#include <stdint.h>
-#include <stdio.h>
-
-#define EG_SAMPLER_URI "http://lv2plug.in/plugins/eg-sampler"
-#define EG_SAMPLER__applySample EG_SAMPLER_URI "#applySample"
-#define EG_SAMPLER__freeSample EG_SAMPLER_URI "#freeSample"
-#define EG_SAMPLER__sample EG_SAMPLER_URI "#sample"
-
-typedef struct {
- LV2_URID atom_Float;
- LV2_URID atom_Path;
- LV2_URID atom_Resource;
- LV2_URID atom_Sequence;
- LV2_URID atom_URID;
- LV2_URID atom_eventTransfer;
- LV2_URID eg_applySample;
- LV2_URID eg_freeSample;
- LV2_URID eg_sample;
- LV2_URID midi_Event;
- LV2_URID param_gain;
- LV2_URID patch_Get;
- LV2_URID patch_Set;
- LV2_URID patch_accept;
- LV2_URID patch_property;
- LV2_URID patch_value;
-} SamplerURIs;
-
-static inline void
-map_sampler_uris(LV2_URID_Map* map, SamplerURIs* uris)
-{
- 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->atom_URID = map->map(map->handle, LV2_ATOM__URID);
- uris->atom_eventTransfer = map->map(map->handle, LV2_ATOM__eventTransfer);
- uris->eg_applySample = map->map(map->handle, EG_SAMPLER__applySample);
- uris->eg_freeSample = map->map(map->handle, EG_SAMPLER__freeSample);
- uris->eg_sample = map->map(map->handle, EG_SAMPLER__sample);
- uris->midi_Event = map->map(map->handle, LV2_MIDI__MidiEvent);
- uris->param_gain = map->map(map->handle, LV2_PARAMETERS__gain);
- uris->patch_Get = map->map(map->handle, LV2_PATCH__Get);
- uris->patch_Set = map->map(map->handle, LV2_PATCH__Set);
- uris->patch_accept = map->map(map->handle, LV2_PATCH__accept);
- uris->patch_property = map->map(map->handle, LV2_PATCH__property);
- uris->patch_value = map->map(map->handle, LV2_PATCH__value);
-}
-
-/**
- Write a message like the following to `forge`:
- [source,turtle]
- ----
- []
- a patch:Set ;
- patch:property param:gain ;
- patch:value 0.0f .
- ----
-*/
-static inline LV2_Atom_Forge_Ref
-write_set_gain(LV2_Atom_Forge* forge, const SamplerURIs* uris, const float gain)
-{
- LV2_Atom_Forge_Frame frame;
- LV2_Atom_Forge_Ref set =
- lv2_atom_forge_object(forge, &frame, 0, uris->patch_Set);
-
- lv2_atom_forge_key(forge, uris->patch_property);
- lv2_atom_forge_urid(forge, uris->param_gain);
- lv2_atom_forge_key(forge, uris->patch_value);
- lv2_atom_forge_float(forge, gain);
-
- lv2_atom_forge_pop(forge, &frame);
- return set;
-}
-
-/**
- Write a message like the following to `forge`:
- [source,turtle]
- ----
- []
- a patch:Set ;
- patch:property eg:sample ;
- patch:value </home/me/foo.wav> .
- ----
-*/
-static inline LV2_Atom_Forge_Ref
-write_set_file(LV2_Atom_Forge* forge,
- const SamplerURIs* uris,
- const char* filename,
- const uint32_t filename_len)
-{
- LV2_Atom_Forge_Frame frame;
- LV2_Atom_Forge_Ref set =
- lv2_atom_forge_object(forge, &frame, 0, uris->patch_Set);
-
- lv2_atom_forge_key(forge, uris->patch_property);
- lv2_atom_forge_urid(forge, uris->eg_sample);
- lv2_atom_forge_key(forge, uris->patch_value);
- lv2_atom_forge_path(forge, filename, filename_len);
-
- lv2_atom_forge_pop(forge, &frame);
- return set;
-}
-
-/**
- Get the file path from `obj` which is a message like:
- [source,turtle]
- ----
- []
- a patch:Set ;
- patch:property eg:sample ;
- patch:value </home/me/foo.wav> .
- ----
-*/
-static inline const char*
-read_set_file(const SamplerURIs* uris, const LV2_Atom_Object* obj)
-{
- if (obj->body.otype != uris->patch_Set) {
- fprintf(stderr, "Ignoring unknown message type %u\n", obj->body.otype);
- return NULL;
- }
-
- /* Get property URI. */
- const LV2_Atom* property = NULL;
- lv2_atom_object_get(obj, uris->patch_property, &property, 0);
- if (!property) {
- fprintf(stderr, "Malformed set message has no body.\n");
- return NULL;
- }
-
- if (property->type != uris->atom_URID) {
- fprintf(stderr, "Malformed set message has non-URID property.\n");
- return NULL;
- }
-
- if (((const LV2_Atom_URID*)property)->body != uris->eg_sample) {
- fprintf(stderr, "Set message for unknown property.\n");
- return NULL;
- }
-
- /* Get value. */
- const LV2_Atom* value = NULL;
- lv2_atom_object_get(obj, uris->patch_value, &value, 0);
- if (!value) {
- fprintf(stderr, "Malformed set message has no value.\n");
- return NULL;
- }
-
- if (value->type != uris->atom_Path) {
- fprintf(stderr, "Set message value is not a Path.\n");
- return NULL;
- }
-
- return (const char*)&value[1];
-}
-
-#endif /* SAMPLER_URIS_H */
diff --git a/plugins/eg-scope.lv2/README.txt b/plugins/eg-scope.lv2/README.txt
deleted file mode 100644
index 122794c..0000000
--- a/plugins/eg-scope.lv2/README.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-== Simple Oscilloscope ==
-
-This plugin displays the waveform of an incoming audio signal using a simple
-GTK+Cairo GUI.
-
-This plugin illustrates:
-
-- UI <==> Plugin communication via http://lv2plug.in/ns/ext/atom/[LV2 Atom] events
-- Atom vector usage and resize-port extension
-- Save/Restore UI state by communicating state to backend
-- Saving simple key/value state via the http://lv2plug.in/ns/ext/state/[LV2 State] extension
-- Cairo drawing and partial exposure
-
-This plugin intends to outline the basics for building visualization plugins
-that rely on atom communication. The UI looks like an oscilloscope, but is not
-a real oscilloscope implementation:
-
-- There is no display synchronisation, results will depend on LV2 host.
-- It displays raw audio samples, which a proper scope must not do.
-- The display itself just connects min/max line segments.
-- No triggering or synchronization.
-- No labels, no scale, no calibration, no markers, no numeric readout, etc.
-
-Addressing these issues is beyond the scope of this example.
-
-Please see http://lac.linuxaudio.org/2013/papers/36.pdf for scope design,
-https://wiki.xiph.org/Videos/Digital_Show_and_Tell for background information,
-and http://lists.lv2plug.in/pipermail/devel-lv2plug.in/2013-November/000545.html
-for general LV2 related conceptual criticism regarding real-time visualizations.
-
-A proper oscilloscope based on this example can be found at
-https://github.com/x42/sisco.lv2
diff --git a/plugins/eg-scope.lv2/examploscope.c b/plugins/eg-scope.lv2/examploscope.c
deleted file mode 100644
index 5cdb610..0000000
--- a/plugins/eg-scope.lv2/examploscope.c
+++ /dev/null
@@ -1,412 +0,0 @@
-// Copyright 2016 David Robillard <d@drobilla.net>
-// Copyright 2013 Robin Gareus <robin@gareus.org>
-// SPDX-License-Identifier: ISC
-
-#include "uris.h"
-
-#include <lv2/atom/atom.h>
-#include <lv2/atom/forge.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/state/state.h>
-#include <lv2/urid/urid.h>
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-/**
- ==== Private Plugin Instance Structure ====
-
- In addition to the usual port buffers and features, this plugin stores the
- state of the UI here, so it can be opened and closed without losing the
- current settings. The UI state is communicated between the plugin and the
- UI using atom messages via a sequence port, similarly to MIDI I/O.
-*/
-typedef struct {
- // Port buffers
- float* input[2];
- float* output[2];
- const LV2_Atom_Sequence* control;
- LV2_Atom_Sequence* notify;
-
- // Atom forge and URI mapping
- LV2_URID_Map* map;
- ScoLV2URIs uris;
- LV2_Atom_Forge forge;
- LV2_Atom_Forge_Frame frame;
-
- // Log feature and convenience API
- LV2_Log_Logger logger;
-
- // Instantiation settings
- uint32_t n_channels;
- double rate;
-
- // UI state
- bool ui_active;
- bool send_settings_to_ui;
- float ui_amp;
- uint32_t ui_spp;
-} EgScope;
-
-/** ==== Port Indices ==== */
-typedef enum {
- SCO_CONTROL = 0, // Event input
- SCO_NOTIFY = 1, // Event output
- SCO_INPUT0 = 2, // Audio input 0
- SCO_OUTPUT0 = 3, // Audio output 0
- SCO_INPUT1 = 4, // Audio input 1 (stereo variant)
- SCO_OUTPUT1 = 5, // Audio input 2 (stereo variant)
-} PortIndex;
-
-/** ==== Instantiate Method ==== */
-static LV2_Handle
-instantiate(const LV2_Descriptor* descriptor,
- double rate,
- const char* bundle_path,
- const LV2_Feature* const* features)
-{
- (void)descriptor; // Unused variable
- (void)bundle_path; // Unused variable
-
- // Allocate and initialise instance structure.
- EgScope* self = (EgScope*)calloc(1, sizeof(EgScope));
- if (!self) {
- return NULL;
- }
-
- // Get host features
- // 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;
- }
-
- // Decide which variant to use depending on the plugin URI
- if (!strcmp(descriptor->URI, SCO_URI "#Stereo")) {
- self->n_channels = 2;
- } else if (!strcmp(descriptor->URI, SCO_URI "#Mono")) {
- self->n_channels = 1;
- } else {
- free(self);
- return NULL;
- }
-
- // Initialise local variables
- self->ui_active = false;
- self->send_settings_to_ui = false;
- self->rate = rate;
-
- // Set default UI settings
- self->ui_spp = 50;
- self->ui_amp = 1.0f;
-
- // Map URIs and initialise forge/logger
- map_sco_uris(self->map, &self->uris);
- lv2_atom_forge_init(&self->forge, self->map);
-
- return (LV2_Handle)self;
-}
-
-/** ==== Connect Port Method ==== */
-static void
-connect_port(LV2_Handle handle, uint32_t port, void* data)
-{
- EgScope* self = (EgScope*)handle;
-
- switch ((PortIndex)port) {
- case SCO_CONTROL:
- self->control = (const LV2_Atom_Sequence*)data;
- break;
- case SCO_NOTIFY:
- self->notify = (LV2_Atom_Sequence*)data;
- break;
- case SCO_INPUT0:
- self->input[0] = (float*)data;
- break;
- case SCO_OUTPUT0:
- self->output[0] = (float*)data;
- break;
- case SCO_INPUT1:
- self->input[1] = (float*)data;
- break;
- case SCO_OUTPUT1:
- self->output[1] = (float*)data;
- break;
- }
-}
-
-/**
- ==== Utility Function: `tx_rawaudio` ====
-
- This function forges a message for sending a vector of raw data. The object
- is a http://lv2plug.in/ns/ext/atom#Blank[Blank] with a few properties, like:
- [source,turtle]
- --------
- []
- a sco:RawAudio ;
- sco:channelID 0 ;
- sco:audioData [ 0.0, 0.0, ... ] .
- --------
-
- where the value of the `sco:audioData` property, `[ 0.0, 0.0, ... ]`, is a
- http://lv2plug.in/ns/ext/atom#Vector[Vector] of
- http://lv2plug.in/ns/ext/atom#Float[Float].
-*/
-static void
-tx_rawaudio(LV2_Atom_Forge* forge,
- const ScoLV2URIs* uris,
- const int32_t channel,
- const size_t n_samples,
- const float* data)
-{
- LV2_Atom_Forge_Frame frame;
-
- // Forge container object of type 'RawAudio'
- lv2_atom_forge_frame_time(forge, 0);
- lv2_atom_forge_object(forge, &frame, 0, uris->RawAudio);
-
- // Add integer 'channelID' property
- lv2_atom_forge_key(forge, uris->channelID);
- lv2_atom_forge_int(forge, channel);
-
- // Add vector of floats 'audioData' property
- lv2_atom_forge_key(forge, uris->audioData);
- lv2_atom_forge_vector(
- forge, sizeof(float), uris->atom_Float, n_samples, data);
-
- // Close off object
- lv2_atom_forge_pop(forge, &frame);
-}
-
-/** ==== Run Method ==== */
-static void
-run(LV2_Handle handle, uint32_t n_samples)
-{
- EgScope* self = (EgScope*)handle;
-
- /* Ensure notify port buffer is large enough to hold all audio-samples and
- configuration settings. A minimum size was requested in the .ttl file,
- but check here just to be sure.
-
- TODO: Explain these magic numbers.
- */
- const size_t size = (sizeof(float) * n_samples + 64) * self->n_channels;
- const uint32_t space = self->notify->atom.size;
- if (space < size + 128) {
- /* Insufficient space, report error and do nothing. Note that a
- real-time production plugin mustn't call log functions in run(), but
- this can be useful for debugging and example purposes.
- */
- lv2_log_error(&self->logger, "Buffer size is insufficient\n");
- return;
- }
-
- // Prepare forge buffer and initialize atom-sequence
- lv2_atom_forge_set_buffer(&self->forge, (uint8_t*)self->notify, space);
- lv2_atom_forge_sequence_head(&self->forge, &self->frame, 0);
-
- /* Send settings to UI
-
- The plugin can continue to run while the UI is closed and re-opened.
- The state and settings of the UI are kept here and transmitted to the UI
- every time it asks for them or if the user initializes a 'load preset'.
- */
- if (self->send_settings_to_ui && self->ui_active) {
- self->send_settings_to_ui = false;
- // Forge container object of type 'ui_state'
- LV2_Atom_Forge_Frame frame;
- lv2_atom_forge_frame_time(&self->forge, 0);
- lv2_atom_forge_object(&self->forge, &frame, 0, self->uris.ui_State);
-
- // Add UI state as properties
- lv2_atom_forge_key(&self->forge, self->uris.ui_spp);
- lv2_atom_forge_int(&self->forge, (int32_t)self->ui_spp);
- lv2_atom_forge_key(&self->forge, self->uris.ui_amp);
- lv2_atom_forge_float(&self->forge, self->ui_amp);
- lv2_atom_forge_key(&self->forge, self->uris.param_sampleRate);
- lv2_atom_forge_float(&self->forge, (float)self->rate);
- lv2_atom_forge_pop(&self->forge, &frame);
- }
-
- // Process incoming events from GUI
- if (self->control) {
- const LV2_Atom_Event* ev = lv2_atom_sequence_begin(&(self->control)->body);
- // For each incoming message...
- while (!lv2_atom_sequence_is_end(
- &self->control->body, self->control->atom.size, ev)) {
- // If the event is an atom:Blank object
- if (lv2_atom_forge_is_object_type(&self->forge, ev->body.type)) {
- const LV2_Atom_Object* obj = (const LV2_Atom_Object*)&ev->body;
- if (obj->body.otype == self->uris.ui_On) {
- // If the object is a ui-on, the UI was activated
- self->ui_active = true;
- self->send_settings_to_ui = true;
- } else if (obj->body.otype == self->uris.ui_Off) {
- // If the object is a ui-off, the UI was closed
- self->ui_active = false;
- } else if (obj->body.otype == self->uris.ui_State) {
- // If the object is a ui-state, it's the current UI settings
- const LV2_Atom* spp = NULL;
- const LV2_Atom* amp = NULL;
- lv2_atom_object_get(
- obj, self->uris.ui_spp, &spp, self->uris.ui_amp, &amp, 0);
- if (spp) {
- self->ui_spp = ((const LV2_Atom_Int*)spp)->body;
- }
- if (amp) {
- self->ui_amp = ((const LV2_Atom_Float*)amp)->body;
- }
- }
- }
- ev = lv2_atom_sequence_next(ev);
- }
- }
-
- // Process audio data
- for (uint32_t c = 0; c < self->n_channels; ++c) {
- if (self->ui_active) {
- // If UI is active, send raw audio data to UI
- tx_rawaudio(
- &self->forge, &self->uris, (int32_t)c, n_samples, self->input[c]);
- }
- // If not processing audio in-place, forward audio
- if (self->input[c] != self->output[c]) {
- memcpy(self->output[c], self->input[c], sizeof(float) * n_samples);
- }
- }
-
- // Close off sequence
- lv2_atom_forge_pop(&self->forge, &self->frame);
-}
-
-static void
-cleanup(LV2_Handle handle)
-{
- free(handle);
-}
-
-/**
- ==== State Methods ====
-
- This plugin's state consists of two basic properties: one `int` and one
- `float`. No files are used. Note these values are POD, but not portable,
- since different machines may have a different integer endianness or floating
- point format. However, since standard Atom types are used, a good host will
- be able to save them portably as text anyway.
-*/
-static LV2_State_Status
-state_save(LV2_Handle instance,
- LV2_State_Store_Function store,
- LV2_State_Handle handle,
- uint32_t flags,
- const LV2_Feature* const* features)
-{
- EgScope* self = (EgScope*)instance;
- if (!self) {
- return LV2_STATE_SUCCESS;
- }
-
- store(handle,
- self->uris.ui_spp,
- (void*)&self->ui_spp,
- sizeof(uint32_t),
- self->uris.atom_Int,
- LV2_STATE_IS_POD);
-
- store(handle,
- self->uris.ui_amp,
- (void*)&self->ui_amp,
- sizeof(float),
- self->uris.atom_Float,
- LV2_STATE_IS_POD);
-
- return LV2_STATE_SUCCESS;
-}
-
-static LV2_State_Status
-state_restore(LV2_Handle instance,
- LV2_State_Retrieve_Function retrieve,
- LV2_State_Handle handle,
- uint32_t flags,
- const LV2_Feature* const* features)
-{
- EgScope* self = (EgScope*)instance;
-
- size_t size = 0;
- uint32_t type = 0;
- uint32_t valflags = 0;
-
- const void* spp =
- retrieve(handle, self->uris.ui_spp, &size, &type, &valflags);
- if (spp && size == sizeof(uint32_t) && type == self->uris.atom_Int) {
- self->ui_spp = *((const uint32_t*)spp);
- self->send_settings_to_ui = true;
- }
-
- const void* amp =
- retrieve(handle, self->uris.ui_amp, &size, &type, &valflags);
- if (amp && size == sizeof(float) && type == self->uris.atom_Float) {
- self->ui_amp = *((const float*)amp);
- self->send_settings_to_ui = true;
- }
-
- return LV2_STATE_SUCCESS;
-}
-
-static const void*
-extension_data(const char* uri)
-{
- static const LV2_State_Interface state = {state_save, state_restore};
- if (!strcmp(uri, LV2_STATE__interface)) {
- return &state;
- }
- return NULL;
-}
-
-/** ==== Plugin Descriptors ==== */
-static const LV2_Descriptor descriptor_mono = {SCO_URI "#Mono",
- instantiate,
- connect_port,
- NULL,
- run,
- NULL,
- cleanup,
- extension_data};
-
-static const LV2_Descriptor descriptor_stereo = {SCO_URI "#Stereo",
- instantiate,
- connect_port,
- NULL,
- run,
- NULL,
- cleanup,
- extension_data};
-
-LV2_SYMBOL_EXPORT const LV2_Descriptor*
-lv2_descriptor(uint32_t index)
-{
- switch (index) {
- case 0:
- return &descriptor_mono;
- case 1:
- return &descriptor_stereo;
- default:
- return NULL;
- }
-}
diff --git a/plugins/eg-scope.lv2/examploscope.ttl.in b/plugins/eg-scope.lv2/examploscope.ttl.in
deleted file mode 100644
index 0b76962..0000000
--- a/plugins/eg-scope.lv2/examploscope.ttl.in
+++ /dev/null
@@ -1,130 +0,0 @@
-@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
-@prefix bufsz: <http://lv2plug.in/ns/ext/buf-size#> .
-@prefix doap: <http://usefulinc.com/ns/doap#> .
-@prefix foaf: <http://xmlns.com/foaf/0.1/> .
-@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#> .
-@prefix urid: <http://lv2plug.in/ns/ext/urid#> .
-@prefix rsz: <http://lv2plug.in/ns/ext/resize-port#> .
-@prefix state: <http://lv2plug.in/ns/ext/state#> .
-@prefix egscope: <http://lv2plug.in/plugins/eg-scope#> .
-
-<http://gareus.org/rgareus#me>
- a foaf:Person ;
- foaf:name "Robin Gareus" ;
- foaf:mbox <mailto:robin@gareus.org> ;
- foaf:homepage <http://gareus.org/> .
-
-<http://lv2plug.in/plugins/eg-scope>
- a doap:Project ;
- doap:maintainer <http://gareus.org/rgareus#me> ;
- doap:name "Example Scope" .
-
-egscope:Mono
- a lv2:Plugin, lv2:AnalyserPlugin ;
- doap:name "Example Scope (Mono)" ;
- lv2:project <http://lv2plug.in/plugins/eg-scope> ;
- doap:license <http://usefulinc.com/doap/licenses/gpl> ;
- lv2:requiredFeature urid:map ;
- lv2:optionalFeature lv2:hardRTCapable ;
- lv2:extensionData state:interface ;
- ui:ui egscope:ui ;
- lv2:port [
- a atom:AtomPort ,
- lv2:InputPort ;
- atom:bufferType atom:Sequence ;
- lv2:designation lv2:control ;
- lv2:index 0 ;
- lv2:symbol "control" ;
- lv2:name "Control"
- ] , [
- a atom:AtomPort ,
- lv2:OutputPort ;
- atom:bufferType atom:Sequence ;
- lv2:designation lv2:control ;
- lv2:index 1 ;
- lv2:symbol "notify" ;
- lv2:name "Notify" ;
- # 8192 * sizeof(float) + LV2-Atoms
- rsz:minimumSize 32832;
- ] , [
- a lv2:AudioPort ,
- lv2:InputPort ;
- lv2:index 2 ;
- lv2:symbol "in" ;
- lv2:name "In"
- ] , [
- a lv2:AudioPort ,
- lv2:OutputPort ;
- lv2:index 3 ;
- lv2:symbol "out" ;
- lv2:name "Out"
- ] .
-
-
-egscope:Stereo
- a lv2:Plugin, lv2:AnalyserPlugin ;
- doap:name "Example Scope (Stereo)" ;
- lv2:project <http://lv2plug.in/plugins/eg-scope> ;
- doap:license <http://usefulinc.com/doap/licenses/gpl> ;
- lv2:requiredFeature urid:map ;
- lv2:optionalFeature lv2:hardRTCapable ;
- lv2:extensionData state:interface ;
- ui:ui egscope:ui ;
- lv2:port [
- a atom:AtomPort ,
- lv2:InputPort ;
- atom:bufferType atom:Sequence ;
- lv2:designation lv2:control ;
- lv2:index 0 ;
- lv2:symbol "control" ;
- lv2:name "Control"
- ] , [
- a atom:AtomPort ,
- lv2:OutputPort ;
- atom:bufferType atom:Sequence ;
- lv2:designation lv2:control ;
- lv2:index 1 ;
- lv2:symbol "notify" ;
- lv2:name "Notify" ;
- rsz:minimumSize 65664;
- ] , [
- a lv2:AudioPort ,
- lv2:InputPort ;
- lv2:index 2 ;
- lv2:symbol "in0" ;
- lv2:name "InL"
- ] , [
- a lv2:AudioPort ,
- lv2:OutputPort ;
- lv2:index 3 ;
- lv2:symbol "out0" ;
- lv2:name "OutL"
- ] , [
- a lv2:AudioPort ,
- lv2:InputPort ;
- lv2:index 4 ;
- lv2:symbol "in1" ;
- lv2:name "InR"
- ] , [
- a lv2:AudioPort ,
- lv2:OutputPort ;
- lv2:index 5 ;
- lv2:symbol "out1" ;
- lv2:name "OutR"
- ] .
-
-
-egscope:ui
- a ui:GtkUI ;
- lv2:requiredFeature urid:map ;
- ui:portNotification [
- ui:plugin egscope:Mono ;
- lv2:symbol "notify" ;
- ui:notifyType atom:Blank
- ] , [
- ui:plugin egscope:Stereo ;
- lv2:symbol "notify" ;
- ui:notifyType atom:Blank
- ] .
diff --git a/plugins/eg-scope.lv2/examploscope_ui.c b/plugins/eg-scope.lv2/examploscope_ui.c
deleted file mode 100644
index 4f366aa..0000000
--- a/plugins/eg-scope.lv2/examploscope_ui.c
+++ /dev/null
@@ -1,667 +0,0 @@
-// Copyright 2013 Robin Gareus <robin@gareus.org>
-// SPDX-License-Identifier: ISC
-
-#include "uris.h"
-
-#include <lv2/atom/atom.h>
-#include <lv2/atom/forge.h>
-#include <lv2/atom/util.h>
-#include <lv2/core/lv2.h>
-#include <lv2/ui/ui.h>
-#include <lv2/urid/urid.h>
-
-#include <cairo.h>
-#include <gdk/gdk.h>
-#include <glib-object.h>
-#include <glib.h>
-#include <gobject/gclosure.h>
-#include <gtk/gtk.h>
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-// Drawing area size
-#define DAWIDTH (640)
-#define DAHEIGHT (200)
-
-/**
- Max continuous points on path. Many short-path segments are
- expensive|inefficient long paths are not supported by all surfaces (usually
- its a miter - not point - limit, depending on used cairo backend)
-*/
-#define MAX_CAIRO_PATH (128)
-
-/**
- Representation of the raw audio-data for display (min | max) values for a
- given 'index' position.
-*/
-typedef struct {
- float data_min[DAWIDTH];
- float data_max[DAWIDTH];
-
- uint32_t idx;
- uint32_t sub;
-} ScoChan;
-
-typedef struct {
- LV2_Atom_Forge forge;
- LV2_URID_Map* map;
- ScoLV2URIs uris;
-
- LV2UI_Write_Function write;
- LV2UI_Controller controller;
-
- GtkWidget* hbox;
- GtkWidget* vbox;
- GtkWidget* sep[2];
- GtkWidget* darea;
- GtkWidget* btn_pause;
- GtkWidget* lbl_speed;
- GtkWidget* lbl_amp;
- GtkWidget* spb_speed;
- GtkWidget* spb_amp;
- GtkAdjustment* spb_speed_adj;
- GtkAdjustment* spb_amp_adj;
-
- ScoChan chn[2];
- uint32_t stride;
- uint32_t n_channels;
- bool paused;
- float rate;
- bool updating;
-} EgScopeUI;
-
-/** Send current UI settings to backend. */
-static void
-send_ui_state(LV2UI_Handle handle)
-{
- EgScopeUI* ui = (EgScopeUI*)handle;
- const float gain = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ui->spb_amp));
-
- // Use local buffer on the stack to build atom
- uint8_t obj_buf[1024];
- lv2_atom_forge_set_buffer(&ui->forge, obj_buf, sizeof(obj_buf));
-
- // Start a ui:State object
- LV2_Atom_Forge_Frame frame;
- LV2_Atom* msg =
- (LV2_Atom*)lv2_atom_forge_object(&ui->forge, &frame, 0, ui->uris.ui_State);
-
- assert(msg);
-
- // msg[samples-per-pixel] = integer
- lv2_atom_forge_key(&ui->forge, ui->uris.ui_spp);
- lv2_atom_forge_int(&ui->forge, ui->stride);
-
- // msg[amplitude] = float
- lv2_atom_forge_key(&ui->forge, ui->uris.ui_amp);
- lv2_atom_forge_float(&ui->forge, gain);
-
- // Finish ui:State object
- lv2_atom_forge_pop(&ui->forge, &frame);
-
- // Send message to plugin port '0'
- ui->write(ui->controller,
- 0,
- lv2_atom_total_size(msg),
- ui->uris.atom_eventTransfer,
- msg);
-
- lv2_atom_forge_set_buffer(&ui->forge, NULL, 0);
-}
-
-/** Notify backend that UI is closed. */
-static void
-send_ui_disable(LV2UI_Handle handle)
-{
- EgScopeUI* ui = (EgScopeUI*)handle;
- send_ui_state(handle);
-
- uint8_t obj_buf[64];
- lv2_atom_forge_set_buffer(&ui->forge, obj_buf, sizeof(obj_buf));
-
- LV2_Atom_Forge_Frame frame;
- LV2_Atom* msg =
- (LV2_Atom*)lv2_atom_forge_object(&ui->forge, &frame, 0, ui->uris.ui_Off);
-
- assert(msg);
-
- lv2_atom_forge_pop(&ui->forge, &frame);
- ui->write(ui->controller,
- 0,
- lv2_atom_total_size(msg),
- ui->uris.atom_eventTransfer,
- msg);
-
- lv2_atom_forge_set_buffer(&ui->forge, NULL, 0);
-}
-
-/**
- Notify backend that UI is active.
-
- The plugin should send state and enable data transmission.
-*/
-static void
-send_ui_enable(LV2UI_Handle handle)
-{
- EgScopeUI* ui = (EgScopeUI*)handle;
-
- uint8_t obj_buf[64];
- lv2_atom_forge_set_buffer(&ui->forge, obj_buf, sizeof(obj_buf));
-
- LV2_Atom_Forge_Frame frame;
- LV2_Atom* msg =
- (LV2_Atom*)lv2_atom_forge_object(&ui->forge, &frame, 0, ui->uris.ui_On);
-
- assert(msg);
-
- lv2_atom_forge_pop(&ui->forge, &frame);
- ui->write(ui->controller,
- 0,
- lv2_atom_total_size(msg),
- ui->uris.atom_eventTransfer,
- msg);
-}
-
-/** Gtk widget callback. */
-static gboolean
-on_cfg_changed(GtkWidget* widget, gpointer data)
-{
- const EgScopeUI* ui = (const EgScopeUI*)data;
- if (!ui->updating) {
- // Only send UI state if the change is from user interaction
- send_ui_state(data);
- }
- return TRUE;
-}
-
-/**
- Gdk drawing area draw callback.
-
- Called in Gtk's main thread and uses Cairo to draw the data.
-*/
-static gboolean
-on_expose_event(GtkWidget* widget, GdkEventExpose* ev, gpointer data)
-{
- EgScopeUI* ui = (EgScopeUI*)data;
- const float gain = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ui->spb_amp));
-
- // Get cairo type for the gtk window
- cairo_t* cr = gdk_cairo_create(ui->darea->window);
-
- // Limit cairo-drawing to exposed area
- cairo_rectangle(cr, ev->area.x, ev->area.y, ev->area.width, ev->area.height);
- cairo_clip(cr);
-
- // Clear background
- cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
- cairo_rectangle(cr, 0, 0, DAWIDTH, DAHEIGHT * ui->n_channels);
- cairo_fill(cr);
-
- cairo_set_line_width(cr, 1.0);
-
- const uint32_t start = ev->area.x;
- const uint32_t end = ev->area.x + ev->area.width;
-
- assert(start < DAWIDTH);
- assert(end <= DAWIDTH);
- assert(start < end);
- assert(ui->n_channels <= 2U);
-
- for (uint32_t c = 0; c < ui->n_channels; ++c) {
- ScoChan* chn = &ui->chn[c];
-
- /* Drawing area Y-position of given sample-value.
- * Note: cairo-pixel at 0 spans -0.5 .. +0.5, hence (DAHEIGHT / 2.0 -0.5)
- * also the cairo Y-axis points upwards (hence 'minus value')
- *
- * == ( DAHEIGHT * (CHN) // channel offset
- * + (DAHEIGHT / 2) - 0.5 // vertical center -- '0'
- * - (DAHEIGHT / 2) * (VAL) * (GAIN)
- * )
- */
- const float chn_y_offset = (DAHEIGHT * c) + (DAHEIGHT * 0.5f) - 0.5f;
- const float chn_y_scale = (DAHEIGHT * 0.5f) * gain;
-
-#define CYPOS(VAL) (chn_y_offset - ((VAL) * chn_y_scale))
-
- cairo_save(cr);
-
- /* Restrict drawing to current channel area, don't bleed drawing into
- neighboring channels. */
- cairo_rectangle(cr, 0, DAHEIGHT * c, DAWIDTH, DAHEIGHT);
- cairo_clip(cr);
-
- // Set color of wave-form
- cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 1.0);
-
- /* This is a somewhat 'smart' mechanism to plot audio data using
- alternating up/down line-directions. It works well for both cases:
- 1 pixel <= 1 sample and 1 pixel represents more than 1 sample, but
- is not ideal for either. */
- if (start == chn->idx) {
- cairo_move_to(cr, start - 0.5, CYPOS(0));
- } else {
- cairo_move_to(cr, start - 0.5, CYPOS(chn->data_max[start]));
- }
-
- uint32_t pathlength = 0;
- for (uint32_t i = start; i < end; ++i) {
- if (i == chn->idx) {
- continue;
- }
-
- if (i % 2) {
- cairo_line_to(cr, i - .5, CYPOS(chn->data_min[i]));
- cairo_line_to(cr, i - .5, CYPOS(chn->data_max[i]));
- ++pathlength;
- } else {
- cairo_line_to(cr, i - .5, CYPOS(chn->data_max[i]));
- cairo_line_to(cr, i - .5, CYPOS(chn->data_min[i]));
- ++pathlength;
- }
-
- /** Limit the max cairo path length. This is an optimization trade
- off: too short path: high load CPU/GPU load. too-long path:
- bad anti-aliasing, or possibly lost points */
- if (pathlength > MAX_CAIRO_PATH) {
- pathlength = 0;
- cairo_stroke(cr);
- if (i % 2) {
- cairo_move_to(cr, i - .5, CYPOS(chn->data_max[i]));
- } else {
- cairo_move_to(cr, i - .5, CYPOS(chn->data_min[i]));
- }
- }
- }
-
- if (pathlength > 0) {
- cairo_stroke(cr);
- }
-
- // Draw current position vertical line if display is slow
- if (ui->stride >= ui->rate / 4800.0f || ui->paused) {
- cairo_set_source_rgba(cr, .9, .2, .2, .6);
- cairo_move_to(cr, chn->idx - .5, DAHEIGHT * c);
- cairo_line_to(cr, chn->idx - .5, DAHEIGHT * (c + 1));
- cairo_stroke(cr);
- }
-
- // Undo the 'clipping' restriction
- cairo_restore(cr);
-
- // Channel separator
- if (c > 0) {
- cairo_set_source_rgba(cr, .5, .5, .5, 1.0);
- cairo_move_to(cr, 0, (DAHEIGHT * c) - .5);
- cairo_line_to(cr, DAWIDTH, (DAHEIGHT * c) - .5);
- cairo_stroke(cr);
- }
-
- // Zero scale line
- cairo_set_source_rgba(cr, .3, .3, .7, .5);
- cairo_move_to(cr, 0, (DAHEIGHT * (c + .5)) - .5);
- cairo_line_to(cr, DAWIDTH, (DAHEIGHT * (c + .5)) - .5);
- cairo_stroke(cr);
- }
-
- cairo_destroy(cr);
- return TRUE;
-}
-
-/**
- Parse raw audio data and prepare for later drawing.
-
- Note this is a toy example, which is really a waveform display, not an
- oscilloscope. A serious scope would not display samples as is.
-
- Signals above ~ 1/10 of the sampling-rate will not yield a useful visual
- display and result in a rather unintuitive representation of the actual
- waveform.
-
- Ideally the audio-data would be buffered and upsampled here and after that
- written in a display buffer for later use.
-
- For more information, see
- https://wiki.xiph.org/Videos/Digital_Show_and_Tell
- http://lac.linuxaudio.org/2013/papers/36.pdf
- and https://github.com/x42/sisco.lv2
-*/
-static int
-process_channel(const EgScopeUI* ui,
- ScoChan* chn,
- const size_t n_elem,
- float const* data,
- uint32_t* idx_start,
- uint32_t* idx_end)
-{
- int overflow = 0;
- *idx_start = chn->idx;
- for (size_t i = 0; i < n_elem; ++i) {
- if (data[i] < chn->data_min[chn->idx]) {
- chn->data_min[chn->idx] = data[i];
- }
- if (data[i] > chn->data_max[chn->idx]) {
- chn->data_max[chn->idx] = data[i];
- }
- if (++chn->sub >= ui->stride) {
- chn->sub = 0;
- chn->idx = (chn->idx + 1) % DAWIDTH;
- if (chn->idx == 0) {
- ++overflow;
- }
- chn->data_min[chn->idx] = 1.0f;
- chn->data_max[chn->idx] = -1.0f;
- }
- }
- *idx_end = chn->idx;
- return overflow;
-}
-
-/**
- Called via port_event() which is called by the host, typically at a rate of
- around 25 FPS.
-*/
-static void
-update_scope(EgScopeUI* ui,
- const int32_t channel,
- const size_t n_elem,
- float const* data)
-{
- // Never trust input data which could lead to application failure.
- if (channel < 0 || (uint32_t)channel > ui->n_channels) {
- return;
- }
-
- // Update state in sync with 1st channel
- if (channel == 0) {
- ui->stride = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ui->spb_speed));
- const bool paused =
- gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ui->btn_pause));
-
- if (paused != ui->paused) {
- ui->paused = paused;
- gtk_widget_queue_draw(ui->darea);
- }
- }
- if (ui->paused) {
- return;
- }
-
- uint32_t idx_start = 0; // Display pixel start
- uint32_t idx_end = 0; // Display pixel end
- int overflow = 0; // Received more audio-data than display-pixel
-
- // Process this channel's audio-data for display
- ScoChan* chn = &ui->chn[channel];
- overflow = process_channel(ui, chn, n_elem, data, &idx_start, &idx_end);
-
- // Signal gtk's main thread to redraw the widget after the last channel
- if ((uint32_t)channel + 1 == ui->n_channels) {
- if (overflow > 1) {
- // Redraw complete widget
- gtk_widget_queue_draw(ui->darea);
- } else if (idx_end > idx_start) {
- // Redraw area between start -> end pixel
- gtk_widget_queue_draw_area(ui->darea,
- idx_start - 2,
- 0,
- 3 + idx_end - idx_start,
- DAHEIGHT * ui->n_channels);
- } else if (idx_end < idx_start) {
- // Wrap-around: redraw area between 0->start AND end->right-end
- gtk_widget_queue_draw_area(ui->darea,
- idx_start - 2,
- 0,
- 3 + DAWIDTH - idx_start,
- DAHEIGHT * ui->n_channels);
- gtk_widget_queue_draw_area(
- ui->darea, 0, 0, idx_end + 1, DAHEIGHT * ui->n_channels);
- }
- }
-}
-
-static LV2UI_Handle
-instantiate(const LV2UI_Descriptor* descriptor,
- const char* plugin_uri,
- const char* bundle_path,
- LV2UI_Write_Function write_function,
- LV2UI_Controller controller,
- LV2UI_Widget* widget,
- const LV2_Feature* const* features)
-{
- EgScopeUI* ui = (EgScopeUI*)calloc(1, sizeof(EgScopeUI));
-
- if (!ui) {
- fprintf(stderr, "EgScope.lv2 UI: out of memory\n");
- return NULL;
- }
-
- ui->map = NULL;
- *widget = NULL;
-
- if (!strcmp(plugin_uri, SCO_URI "#Mono")) {
- ui->n_channels = 1;
- } else if (!strcmp(plugin_uri, SCO_URI "#Stereo")) {
- ui->n_channels = 2;
- } else {
- free(ui);
- return NULL;
- }
-
- for (int i = 0; features[i]; ++i) {
- if (!strcmp(features[i]->URI, LV2_URID_URI "#map")) {
- ui->map = (LV2_URID_Map*)features[i]->data;
- }
- }
-
- if (!ui->map) {
- fprintf(stderr, "EgScope.lv2 UI: Host does not support urid:map\n");
- free(ui);
- return NULL;
- }
-
- // Initialize private data structure
- ui->write = write_function;
- ui->controller = controller;
-
- ui->vbox = NULL;
- ui->hbox = NULL;
- ui->darea = NULL;
- ui->stride = 25;
- ui->paused = false;
- ui->rate = 48000;
-
- ui->chn[0].idx = 0;
- ui->chn[0].sub = 0;
- ui->chn[1].idx = 0;
- ui->chn[1].sub = 0;
- memset(ui->chn[0].data_min, 0, sizeof(float) * DAWIDTH);
- memset(ui->chn[0].data_max, 0, sizeof(float) * DAWIDTH);
- memset(ui->chn[1].data_min, 0, sizeof(float) * DAWIDTH);
- memset(ui->chn[1].data_max, 0, sizeof(float) * DAWIDTH);
-
- map_sco_uris(ui->map, &ui->uris);
- lv2_atom_forge_init(&ui->forge, ui->map);
-
- // Setup UI
- ui->hbox = gtk_hbox_new(FALSE, 0);
- ui->vbox = gtk_vbox_new(FALSE, 0);
-
- ui->darea = gtk_drawing_area_new();
- gtk_widget_set_size_request(ui->darea, DAWIDTH, DAHEIGHT * ui->n_channels);
-
- ui->lbl_speed = gtk_label_new("Samples/Pixel");
- ui->lbl_amp = gtk_label_new("Amplitude");
-
- ui->sep[0] = gtk_hseparator_new();
- ui->sep[1] = gtk_label_new("");
- ui->btn_pause = gtk_toggle_button_new_with_label("Pause");
-
- ui->spb_speed_adj =
- (GtkAdjustment*)gtk_adjustment_new(25.0, 1.0, 1000.0, 1.0, 5.0, 0.0);
- ui->spb_speed = gtk_spin_button_new(ui->spb_speed_adj, 1.0, 0);
-
- ui->spb_amp_adj =
- (GtkAdjustment*)gtk_adjustment_new(1.0, 0.1, 6.0, 0.1, 1.0, 0.0);
- ui->spb_amp = gtk_spin_button_new(ui->spb_amp_adj, 0.1, 1);
-
- gtk_box_pack_start(GTK_BOX(ui->hbox), ui->darea, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(ui->hbox), ui->vbox, FALSE, FALSE, 4);
-
- gtk_box_pack_start(GTK_BOX(ui->vbox), ui->lbl_speed, FALSE, FALSE, 2);
- gtk_box_pack_start(GTK_BOX(ui->vbox), ui->spb_speed, FALSE, FALSE, 2);
- gtk_box_pack_start(GTK_BOX(ui->vbox), ui->sep[0], FALSE, FALSE, 8);
- gtk_box_pack_start(GTK_BOX(ui->vbox), ui->lbl_amp, FALSE, FALSE, 2);
- gtk_box_pack_start(GTK_BOX(ui->vbox), ui->spb_amp, FALSE, FALSE, 2);
- gtk_box_pack_start(GTK_BOX(ui->vbox), ui->sep[1], TRUE, FALSE, 8);
- gtk_box_pack_start(GTK_BOX(ui->vbox), ui->btn_pause, FALSE, FALSE, 2);
-
- g_signal_connect(
- G_OBJECT(ui->darea), "expose_event", G_CALLBACK(on_expose_event), ui);
- g_signal_connect(
- G_OBJECT(ui->spb_amp), "value-changed", G_CALLBACK(on_cfg_changed), ui);
- g_signal_connect(
- G_OBJECT(ui->spb_speed), "value-changed", G_CALLBACK(on_cfg_changed), ui);
-
- *widget = ui->hbox;
-
- /* Send UIOn message to plugin, which will request state and enable message
- transmission. */
- send_ui_enable(ui);
-
- return ui;
-}
-
-static void
-cleanup(LV2UI_Handle handle)
-{
- EgScopeUI* ui = (EgScopeUI*)handle;
- /* Send UIOff message to plugin, which will save state and disable message
- * transmission. */
- send_ui_disable(ui);
- gtk_widget_destroy(ui->darea);
- free(ui);
-}
-
-static int
-recv_raw_audio(EgScopeUI* ui, const LV2_Atom_Object* obj)
-{
- const LV2_Atom* chan_val = NULL;
- const LV2_Atom* data_val = NULL;
- const int n_props = lv2_atom_object_get(
- obj, ui->uris.channelID, &chan_val, ui->uris.audioData, &data_val, NULL);
-
- if (n_props != 2 || chan_val->type != ui->uris.atom_Int ||
- data_val->type != ui->uris.atom_Vector) {
- // Object does not have the required properties with correct types
- fprintf(stderr, "eg-scope.lv2 UI error: Corrupt audio message\n");
- return 1;
- }
-
- // Get the values we need from the body of the property value atoms
- const int32_t chn = ((const LV2_Atom_Int*)chan_val)->body;
- const LV2_Atom_Vector* vec = (const LV2_Atom_Vector*)data_val;
- if (vec->body.child_type != ui->uris.atom_Float) {
- return 1; // Vector has incorrect element type
- }
-
- // Number of elements = (total size - header size) / element size
- const size_t n_elem =
- ((data_val->size - sizeof(LV2_Atom_Vector_Body)) / sizeof(float));
-
- // Float elements immediately follow the vector body header
- const float* data = (const float*)(&vec->body + 1);
-
- // Update display
- update_scope(ui, chn, n_elem, data);
- return 0;
-}
-
-static int
-recv_ui_state(EgScopeUI* ui, const LV2_Atom_Object* obj)
-{
- const LV2_Atom* spp_val = NULL;
- const LV2_Atom* amp_val = NULL;
- const LV2_Atom* rate_val = NULL;
-
- const int n_props = lv2_atom_object_get(obj,
- ui->uris.ui_spp,
- &spp_val,
- ui->uris.ui_amp,
- &amp_val,
- ui->uris.param_sampleRate,
- &rate_val,
- NULL);
-
- if (n_props != 3 || spp_val->type != ui->uris.atom_Int ||
- amp_val->type != ui->uris.atom_Float ||
- rate_val->type != ui->uris.atom_Float) {
- // Object does not have the required properties with correct types
- fprintf(stderr, "eg-scope.lv2 UI error: Corrupt state message\n");
- return 1;
- }
-
- // Get the values we need from the body of the property value atoms
- const int32_t spp = ((const LV2_Atom_Int*)spp_val)->body;
- const float amp = ((const LV2_Atom_Float*)amp_val)->body;
- const float rate = ((const LV2_Atom_Float*)rate_val)->body;
-
- // Disable transmission and update UI
- ui->updating = true;
- gtk_spin_button_set_value(GTK_SPIN_BUTTON(ui->spb_speed), spp);
- gtk_spin_button_set_value(GTK_SPIN_BUTTON(ui->spb_amp), amp);
- ui->updating = false;
- ui->rate = rate;
-
- return 0;
-}
-
-/**
- Receive data from the DSP-backend.
-
- This is called by the host, typically at a rate of around 25 FPS.
-
- Ideally this happens regularly and with relatively low latency, but there
- are no hard guarantees about message delivery.
-*/
-static void
-port_event(LV2UI_Handle handle,
- uint32_t port_index,
- uint32_t buffer_size,
- uint32_t format,
- const void* buffer)
-{
- EgScopeUI* ui = (EgScopeUI*)handle;
- const LV2_Atom* atom = (const LV2_Atom*)buffer;
-
- /* Check type of data received
- * - format == 0: Control port event (float)
- * - format > 0: Message (atom)
- */
- if (format == ui->uris.atom_eventTransfer &&
- lv2_atom_forge_is_object_type(&ui->forge, atom->type)) {
- const LV2_Atom_Object* obj = (const LV2_Atom_Object*)atom;
- if (obj->body.otype == ui->uris.RawAudio) {
- recv_raw_audio(ui, obj);
- } else if (obj->body.otype == ui->uris.ui_State) {
- recv_ui_state(ui, obj);
- }
- }
-}
-
-static const LV2UI_Descriptor descriptor = {SCO_URI "#ui",
- instantiate,
- cleanup,
- port_event,
- NULL};
-
-LV2_SYMBOL_EXPORT const LV2UI_Descriptor*
-lv2ui_descriptor(uint32_t index)
-{
- return index == 0 ? &descriptor : NULL;
-}
diff --git a/plugins/eg-scope.lv2/manifest.ttl.in b/plugins/eg-scope.lv2/manifest.ttl.in
deleted file mode 100644
index 66c3c9d..0000000
--- a/plugins/eg-scope.lv2/manifest.ttl.in
+++ /dev/null
@@ -1,21 +0,0 @@
-@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#> .
-
-# ==== Mono plugin variant ====
-<http://lv2plug.in/plugins/eg-scope#Mono>
- a lv2:Plugin ;
- lv2:binary <examploscope@LIB_EXT@> ;
- rdfs:seeAlso <examploscope.ttl> .
-
-# ==== Stereo plugin variant ====
-<http://lv2plug.in/plugins/eg-scope#Stereo>
- a lv2:Plugin ;
- lv2:binary <examploscope@LIB_EXT@> ;
- rdfs:seeAlso <examploscope.ttl> .
-
-# ==== Gtk 2.0 UI ====
-<http://lv2plug.in/plugins/eg-scope#ui>
- a ui:GtkUI ;
- lv2:binary <examploscope_ui@LIB_EXT@> ;
- rdfs:seeAlso <examploscope.ttl> .
diff --git a/plugins/eg-scope.lv2/meson.build b/plugins/eg-scope.lv2/meson.build
deleted file mode 100644
index 84e17ba..0000000
--- a/plugins/eg-scope.lv2/meson.build
+++ /dev/null
@@ -1,64 +0,0 @@
-# Copyright 2022 David Robillard <d@drobilla.net>
-# SPDX-License-Identifier: 0BSD OR ISC
-
-plugin_sources = files('examploscope.c')
-ui_sources = files('examploscope_ui.c')
-bundle_name = 'eg-scope.lv2'
-data_filenames = ['manifest.ttl.in', 'examploscope.ttl.in']
-
-gtk2_dep = dependency(
- 'gtk+-2.0',
- include_type: 'system',
- required: get_option('plugins'),
- version: '>= 2.18.0',
-)
-
-module = shared_library(
- 'examploscope',
- 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
-
-if gtk2_dep.found()
- shared_library(
- 'examploscope_ui',
- ui_sources,
- c_args: c_suppressions,
- dependencies: [lv2_dep, gtk2_dep],
- gnu_symbol_visibility: 'hidden',
- implicit_include_directories: false,
- install: true,
- install_dir: lv2dir / bundle_name,
- name_prefix: '',
- )
-endif
diff --git a/plugins/eg-scope.lv2/uris.h b/plugins/eg-scope.lv2/uris.h
deleted file mode 100644
index d9d94be..0000000
--- a/plugins/eg-scope.lv2/uris.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2013 Robin Gareus <robin@gareus.org>
-// SPDX-License-Identifier: ISC
-
-#ifndef SCO_URIS_H
-#define SCO_URIS_H
-
-#include <lv2/atom/atom.h>
-#include <lv2/parameters/parameters.h>
-#include <lv2/urid/urid.h>
-
-#define SCO_URI "http://lv2plug.in/plugins/eg-scope"
-
-typedef struct {
- // URIs defined in LV2 specifications
- LV2_URID atom_Vector;
- LV2_URID atom_Float;
- LV2_URID atom_Int;
- LV2_URID atom_eventTransfer;
- LV2_URID param_sampleRate;
-
- /* URIs defined for this plugin. It is best to reuse existing URIs as
- much as possible, but plugins may need more vocabulary specific to their
- needs. These are used as types and properties for plugin:UI
- communication, as well as for saving state. */
- LV2_URID RawAudio;
- LV2_URID channelID;
- LV2_URID audioData;
- LV2_URID ui_On;
- LV2_URID ui_Off;
- LV2_URID ui_State;
- LV2_URID ui_spp;
- LV2_URID ui_amp;
-} ScoLV2URIs;
-
-static inline void
-map_sco_uris(LV2_URID_Map* map, ScoLV2URIs* uris)
-{
- uris->atom_Vector = map->map(map->handle, LV2_ATOM__Vector);
- uris->atom_Float = map->map(map->handle, LV2_ATOM__Float);
- uris->atom_Int = map->map(map->handle, LV2_ATOM__Int);
- uris->atom_eventTransfer = map->map(map->handle, LV2_ATOM__eventTransfer);
- uris->param_sampleRate = map->map(map->handle, LV2_PARAMETERS__sampleRate);
-
- /* Note the convention that URIs for types are capitalized, and URIs for
- everything else (mainly properties) are not, just as in LV2
- specifications. */
- uris->RawAudio = map->map(map->handle, SCO_URI "#RawAudio");
- uris->audioData = map->map(map->handle, SCO_URI "#audioData");
- uris->channelID = map->map(map->handle, SCO_URI "#channelID");
- uris->ui_On = map->map(map->handle, SCO_URI "#UIOn");
- uris->ui_Off = map->map(map->handle, SCO_URI "#UIOff");
- uris->ui_State = map->map(map->handle, SCO_URI "#UIState");
- uris->ui_spp = map->map(map->handle, SCO_URI "#ui-spp");
- uris->ui_amp = map->map(map->handle, SCO_URI "#ui-amp");
-}
-
-#endif /* SCO_URIS_H */
diff --git a/plugins/literasc.py b/plugins/literasc.py
deleted file mode 100755
index 74b13a7..0000000
--- a/plugins/literasc.py
+++ /dev/null
@@ -1,143 +0,0 @@
-#!/usr/bin/env python3
-
-# Copyright 2012-2022 David Robillard <d@drobilla.net>
-# SPDX-License-Identifier: ISC
-
-"""
-A simple literate programming tool for C, C++, and Turtle.
-
-Unlike many LP tools, this tool uses normal source code as input, there is no
-tangle/weave and no special file format. The literate parts of the program are
-written in comments, which are emitted as paragraphs of regular text
-interleaved with code. Asciidoc is both the comment and output syntax.
-"""
-
-import os
-import re
-import sys
-
-
-def format_text(text):
- "Format a text (comment) fragment and return it as a marked up string."
- return "\n\n" + re.sub("\n *", "\n", text.strip()) + "\n\n"
-
-
-def format_code(lang, code):
- "Format a block of code and return it as a marked up string."
-
- if code.strip() == "":
- return code
-
- head = f"[source,{lang}]"
- code = code.strip("\n")
- sep = "-" * len(head)
- return "\n".join([head, sep, code, sep]) + "\n"
-
-
-def format_c_source(filename, in_file):
- "Format an annotated C source file as a marked up string."
-
- output = f"=== {os.path.basename(filename)} ===\n"
- chunk = ""
- prev_c = 0
- in_comment = False
- in_comment_start = False
- n_stars = 0
- code = "".join(in_file)
-
- # Skip initial license comment
- if code[0:2] == "/*":
- end = code.find("*/") + 2
- code = code[end:]
-
- def last_chunk(chunk):
- length = len(chunk) - 1
- return chunk[0:length]
-
- for char in code:
- if prev_c == "/" and char == "*":
- in_comment_start = True
- n_stars = 1
- elif in_comment_start:
- if char == "*":
- n_stars += 1
- else:
- if n_stars > 1:
- output += format_code("c", last_chunk(chunk))
- chunk = ""
- in_comment = True
- else:
- chunk += "*" + char
- in_comment_start = False
- elif in_comment and prev_c == "*" and char == "/":
- if n_stars > 1:
- output += format_text(last_chunk(chunk))
- else:
- output += format_code("c", "/* " + last_chunk(chunk) + "*/")
- in_comment = False
- in_comment_start = False
- chunk = ""
- else:
- chunk += char
-
- prev_c = char
-
- return output + format_code("c", chunk)
-
-
-def format_ttl_source(filename, in_file):
- "Format an annotated Turtle source file as a marked up string."
-
- output = f"=== {os.path.basename(filename)} ===\n"
-
- in_comment = False
- chunk = ""
- for line in in_file:
- is_comment = line.strip().startswith("#")
- if in_comment:
- if is_comment:
- chunk += line.strip().lstrip("# ") + " \n"
- else:
- output += format_text(chunk)
- in_comment = False
- chunk = line
- else:
- if is_comment:
- output += format_code("turtle", chunk)
- in_comment = True
- chunk = line.strip().lstrip("# ") + " \n"
- else:
- chunk += line
-
- if in_comment:
- return output + format_text(chunk)
-
- return output + format_code("turtle", chunk)
-
-
-def gen(out, filenames):
- "Write markup generated from filenames to an output file."
-
- for filename in filenames:
- with open(filename, "r", encoding="utf-8") as in_file:
- if filename.endswith(".c") or filename.endswith(".h"):
- out.write(format_c_source(filename, in_file))
- elif filename.endswith(".ttl") or filename.endswith(".ttl.in"):
- out.write(format_ttl_source(filename, in_file))
- elif filename.endswith(".txt"):
- for line in in_file:
- out.write(line)
- out.write("\n")
- else:
- sys.stderr.write(
- f"Unknown source format `{filename.splitext()[1]}`\n"
- )
-
-
-if __name__ == "__main__":
- if len(sys.argv) < 2:
- sys.stderr.write(f"Usage: {sys.argv[0]} OUT_FILE IN_FILE...\n")
- sys.exit(1)
-
- with open(sys.argv[1], "w", encoding="utf-8") as out_file:
- gen(out_file, sys.argv[2:])
diff --git a/plugins/meson.build b/plugins/meson.build
deleted file mode 100644
index ff70af1..0000000
--- a/plugins/meson.build
+++ /dev/null
@@ -1,82 +0,0 @@
-# Copyright 2022 David Robillard <d@drobilla.net>
-# SPDX-License-Identifier: 0BSD OR ISC
-
-if not get_option('plugins').disabled()
- m_dep = cc.find_library('m', required: false)
-
- subdir('eg-amp.lv2')
- subdir('eg-fifths.lv2')
- subdir('eg-metro.lv2')
- subdir('eg-midigate.lv2')
- subdir('eg-params.lv2')
- subdir('eg-sampler.lv2')
- subdir('eg-scope.lv2')
-endif
-
-if not get_option('docs').disabled()
- literasc_py = files('literasc.py')
- asciidoc = find_program('asciidoc', required: get_option('docs'))
-
- if asciidoc.found()
- book_inputs = files('README.txt')
- book_inputs += files(
- 'eg-amp.lv2/README.txt',
- 'eg-amp.lv2/amp.c',
- 'eg-amp.lv2/amp.ttl',
- 'eg-fifths.lv2/README.txt',
- 'eg-fifths.lv2/fifths.c',
- 'eg-fifths.lv2/fifths.ttl',
- 'eg-fifths.lv2/uris.h',
- 'eg-metro.lv2/README.txt',
- 'eg-metro.lv2/metro.c',
- 'eg-metro.lv2/metro.ttl',
- 'eg-midigate.lv2/README.txt',
- 'eg-midigate.lv2/midigate.c',
- 'eg-midigate.lv2/midigate.ttl',
- 'eg-params.lv2/README.txt',
- 'eg-params.lv2/params.c',
- 'eg-params.lv2/params.ttl',
- 'eg-params.lv2/state_map.h',
- 'eg-sampler.lv2/README.txt',
- 'eg-sampler.lv2/atom_sink.h',
- 'eg-sampler.lv2/peaks.h',
- 'eg-sampler.lv2/sampler.c',
- 'eg-sampler.lv2/sampler.ttl',
- 'eg-sampler.lv2/sampler_ui.c',
- 'eg-sampler.lv2/uris.h',
- 'eg-scope.lv2/README.txt',
- 'eg-scope.lv2/examploscope.c',
- 'eg-scope.lv2/examploscope_ui.c',
- 'eg-scope.lv2/uris.h',
- )
-
- # Compile book sources into book.txt asciidoc source
- book_txt = custom_target(
- 'book.txt',
- command: [
- literasc_py,
- '@OUTPUT@',
- '@INPUT@',
- ],
- input: book_inputs,
- output: 'book.txt',
- )
-
- # Run asciidoc to generate book.html
- book_html = custom_target(
- 'book.html',
- build_by_default: true,
- command: [
- asciidoc,
- '-a', 'stylesdir=' + lv2_source_root / 'doc' / 'style',
- '-a', 'source-highlighter=pygments',
- '-a', 'pygments-style=' + lv2_source_root / 'doc' / 'style' / 'style.css',
- '-b', 'html',
- '-o', '@OUTPUT@',
- '@INPUT@',
- ],
- input: book_txt,
- output: 'book.html',
- )
- endif
-endif