# HG changeset patch # User František Kučera # Date 1589567557 -7200 # Node ID d6614ad97bed0fa6f739abfbb83c7503e40badc1 # Parent 2f84ed5f3abf2e3ebad5f79d490e86686e65cf54 LV2: modul zesilovače, dle oficiálního příkladu, ale bez závislosti na Pythonu – stačí gcc a make diff -r 2f84ed5f3abf -r d6614ad97bed c++/lv2-demo-modul/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/c++/lv2-demo-modul/Makefile Fri May 15 20:32:37 2020 +0200 @@ -0,0 +1,20 @@ +all: amp.so + +amp.so: amp.cpp + g++ -g -shared -fPIC amp.cpp -o amp.so + +clean: + rm -f amp.so + +info: amp.so + nm amp.so + ldd amp.so + file amp.so + +install: amp.so + mkdir -p ~/.lv2/amp/ + cp amp.so amp.ttl manifest.ttl ~/.lv2/amp/ + lv2info http://lv2plug.in/plugins/eg-amp + +uninstall: + rm -rf ~/.lv2/amp/ diff -r 2f84ed5f3abf -r d6614ad97bed c++/lv2-demo-modul/amp.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/c++/lv2-demo-modul/amp.cpp Fri May 15 20:32:37 2020 +0200 @@ -0,0 +1,222 @@ +/* + Copyright 2006-2016 David Robillard + Copyright 2006 Steve Harris + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + 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 , by + replacing `http:/` with `lv2` any header in the specification bundle can be + included, in this case `lv2.h`. + */ +#include + +/** Include standard C headers */ +#include +#include +#include + +/** + 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 + indentifier, 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) { + switch (index) { + case 0: return &descriptor; + default: return NULL; + } +} diff -r 2f84ed5f3abf -r d6614ad97bed c++/lv2-demo-modul/amp.ttl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/c++/lv2-demo-modul/amp.ttl Fri May 15 20:32:37 2020 +0200 @@ -0,0 +1,90 @@ +# 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: . +@prefix lv2: . +@prefix rdf: . +@prefix rdfs: . +@prefix 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. + + 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 , and is described +# elsewhere. Typical plugin collections will describe the project in +# manifest.ttl + lv2:project ; +# 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 ; + 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 -r 2f84ed5f3abf -r d6614ad97bed c++/lv2-demo-modul/manifest.ttl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/c++/lv2-demo-modul/manifest.ttl Fri May 15 20:32:37 2020 +0200 @@ -0,0 +1,68 @@ +# 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 +# ``. 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 ``. + +@prefix lv2: . +@prefix rdfs: . + +# ==== Describing a Plugin ==== + +# Turtle files contain a set of ``statements'' which describe resources. +# This file contains 3 statements: +# [options="header"] +# |================================================================ +# | Subject | Predicate | Object +# | | a | lv2:Plugin +# | | lv2:binary | +# | | rdfs:seeAlso | +# |================================================================ + +# Firstly, `` is an LV2 plugin: + a lv2:Plugin . + +# The predicate ```a`'' is a Turtle shorthand for `rdf:type`. + +# The binary of that plugin can be found at ``: + lv2:binary . + +# 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 ``. 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 ``: + rdfs:seeAlso . + +# ==== Abbreviation ==== +# +# This file shows these statements individually for instructive purposes, but +# the subject `` 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: + + + a lv2:Plugin ; + lv2:binary ; + rdfs:seeAlso .