LV2: modul zesilovače, dle oficiálního příkladu, ale bez závislosti na Pythonu – stačí gcc a make default tip
authorFrantišek Kučera <franta-hg@frantovo.cz>
Fri, 15 May 2020 20:32:37 +0200
changeset 59d6614ad97bed
parent 58 2f84ed5f3abf
LV2: modul zesilovače, dle oficiálního příkladu, ale bez závislosti na Pythonu – stačí gcc a make
c++/lv2-demo-modul/Makefile
c++/lv2-demo-modul/amp.cpp
c++/lv2-demo-modul/amp.ttl
c++/lv2-demo-modul/manifest.ttl
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/c++/lv2-demo-modul/Makefile	Fri May 15 20:32:37 2020 +0200
     1.3 @@ -0,0 +1,20 @@
     1.4 +all: amp.so
     1.5 +
     1.6 +amp.so: amp.cpp
     1.7 +	g++ -g -shared -fPIC amp.cpp -o amp.so
     1.8 +
     1.9 +clean:
    1.10 +	rm -f amp.so
    1.11 +
    1.12 +info: amp.so
    1.13 +	nm amp.so
    1.14 +	ldd amp.so
    1.15 +	file amp.so
    1.16 +
    1.17 +install: amp.so
    1.18 +	mkdir -p ~/.lv2/amp/
    1.19 +	cp amp.so amp.ttl manifest.ttl ~/.lv2/amp/
    1.20 +	lv2info http://lv2plug.in/plugins/eg-amp
    1.21 +
    1.22 +uninstall:
    1.23 +	rm -rf ~/.lv2/amp/
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/c++/lv2-demo-modul/amp.cpp	Fri May 15 20:32:37 2020 +0200
     2.3 @@ -0,0 +1,222 @@
     2.4 +/*
     2.5 +  Copyright 2006-2016 David Robillard <d@drobilla.net>
     2.6 +  Copyright 2006 Steve Harris <steve@plugin.org.uk>
     2.7 +
     2.8 +  Permission to use, copy, modify, and/or distribute this software for any
     2.9 +  purpose with or without fee is hereby granted, provided that the above
    2.10 +  copyright notice and this permission notice appear in all copies.
    2.11 +
    2.12 +  THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    2.13 +  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    2.14 +  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    2.15 +  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    2.16 +  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    2.17 +  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    2.18 +  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    2.19 + */
    2.20 +
    2.21 +/**
    2.22 +   LV2 headers are based on the URI of the specification they come from, so a
    2.23 +   consistent convention can be used even for unofficial extensions.  The URI
    2.24 +   of the core LV2 specification is <http://lv2plug.in/ns/lv2core>, by
    2.25 +   replacing `http:/` with `lv2` any header in the specification bundle can be
    2.26 +   included, in this case `lv2.h`.
    2.27 + */
    2.28 +#include <lv2.h>
    2.29 +
    2.30 +/** Include standard C headers */
    2.31 +#include <math.h>
    2.32 +#include <stdint.h>
    2.33 +#include <stdlib.h>
    2.34 +
    2.35 +/**
    2.36 +   The URI is the identifier for a plugin, and how the host associates this
    2.37 +   implementation in code with its description in data.  In this plugin it is
    2.38 +   only used once in the code, but defining the plugin URI at the top of the
    2.39 +   file is a good convention to follow.  If this URI does not match that used
    2.40 +   in the data files, the host will fail to load the plugin.
    2.41 + */
    2.42 +#define AMP_URI "http://lv2plug.in/plugins/eg-amp"
    2.43 +
    2.44 +/**
    2.45 +   In code, ports are referred to by index.  An enumeration of port indices
    2.46 +   should be defined for readability.
    2.47 + */
    2.48 +typedef enum {
    2.49 +	AMP_GAIN = 0,
    2.50 +	AMP_INPUT = 1,
    2.51 +	AMP_OUTPUT = 2
    2.52 +} PortIndex;
    2.53 +
    2.54 +/**
    2.55 +   Every plugin defines a private structure for the plugin instance.  All data
    2.56 +   associated with a plugin instance is stored here, and is available to
    2.57 +   every instance method.  In this simple plugin, only port buffers need to be
    2.58 +   stored, since there is no additional instance data.
    2.59 + */
    2.60 +typedef struct {
    2.61 +	// Port buffers
    2.62 +	const float* gain;
    2.63 +	const float* input;
    2.64 +	float* output;
    2.65 +} Amp;
    2.66 +
    2.67 +/**
    2.68 +   The `instantiate()` function is called by the host to create a new plugin
    2.69 +   instance.  The host passes the plugin descriptor, sample rate, and bundle
    2.70 +   path for plugins that need to load additional resources (e.g. waveforms).
    2.71 +   The features parameter contains host-provided features defined in LV2
    2.72 +   extensions, but this simple plugin does not use any.
    2.73 +
    2.74 +   This function is in the ``instantiation'' threading class, so no other
    2.75 +   methods on this instance will be called concurrently with it.
    2.76 + */
    2.77 +static LV2_Handle
    2.78 +instantiate(const LV2_Descriptor* descriptor,
    2.79 +		double rate,
    2.80 +		const char* bundle_path,
    2.81 +		const LV2_Feature * const* features) {
    2.82 +	Amp* amp = (Amp*) calloc(1, sizeof (Amp));
    2.83 +
    2.84 +	return (LV2_Handle) amp;
    2.85 +}
    2.86 +
    2.87 +/**
    2.88 +   The `connect_port()` method is called by the host to connect a particular
    2.89 +   port to a buffer.  The plugin must store the data location, but data may not
    2.90 +   be accessed except in run().
    2.91 +
    2.92 +   This method is in the ``audio'' threading class, and is called in the same
    2.93 +   context as run().
    2.94 + */
    2.95 +static void
    2.96 +connect_port(LV2_Handle instance,
    2.97 +		uint32_t port,
    2.98 +		void* data) {
    2.99 +	Amp* amp = (Amp*) instance;
   2.100 +
   2.101 +	switch ((PortIndex) port) {
   2.102 +		case AMP_GAIN:
   2.103 +			amp->gain = (const float*) data;
   2.104 +			break;
   2.105 +		case AMP_INPUT:
   2.106 +			amp->input = (const float*) data;
   2.107 +			break;
   2.108 +		case AMP_OUTPUT:
   2.109 +			amp->output = (float*) data;
   2.110 +			break;
   2.111 +	}
   2.112 +}
   2.113 +
   2.114 +/**
   2.115 +   The `activate()` method is called by the host to initialise and prepare the
   2.116 +   plugin instance for running.  The plugin must reset all internal state
   2.117 +   except for buffer locations set by `connect_port()`.  Since this plugin has
   2.118 +   no other internal state, this method does nothing.
   2.119 +
   2.120 +   This method is in the ``instantiation'' threading class, so no other
   2.121 +   methods on this instance will be called concurrently with it.
   2.122 + */
   2.123 +static void
   2.124 +activate(LV2_Handle instance) {
   2.125 +}
   2.126 +
   2.127 +/** Define a macro for converting a gain in dB to a coefficient. */
   2.128 +#define DB_CO(g) ((g) > -90.0f ? powf(10.0f, (g) * 0.05f) : 0.0f)
   2.129 +
   2.130 +/**
   2.131 +   The `run()` method is the main process function of the plugin.  It processes
   2.132 +   a block of audio in the audio context.  Since this plugin is
   2.133 +   `lv2:hardRTCapable`, `run()` must be real-time safe, so blocking (e.g. with
   2.134 +   a mutex) or memory allocation are not allowed.
   2.135 + */
   2.136 +static void
   2.137 +run(LV2_Handle instance, uint32_t n_samples) {
   2.138 +	const Amp* amp = (const Amp*) instance;
   2.139 +
   2.140 +	const float gain = *(amp->gain);
   2.141 +	const float* const input = amp->input;
   2.142 +	float* const output = amp->output;
   2.143 +
   2.144 +	const float coef = DB_CO(gain);
   2.145 +
   2.146 +	for (uint32_t pos = 0; pos < n_samples; pos++) {
   2.147 +		output[pos] = input[pos] * coef;
   2.148 +	}
   2.149 +}
   2.150 +
   2.151 +/**
   2.152 +   The `deactivate()` method is the counterpart to `activate()`, and is called by
   2.153 +   the host after running the plugin.  It indicates that the host will not call
   2.154 +   `run()` again until another call to `activate()` and is mainly useful for more
   2.155 +   advanced plugins with ``live'' characteristics such as those with auxiliary
   2.156 +   processing threads.  As with `activate()`, this plugin has no use for this
   2.157 +   information so this method does nothing.
   2.158 +
   2.159 +   This method is in the ``instantiation'' threading class, so no other
   2.160 +   methods on this instance will be called concurrently with it.
   2.161 + */
   2.162 +static void
   2.163 +deactivate(LV2_Handle instance) {
   2.164 +}
   2.165 +
   2.166 +/**
   2.167 +   Destroy a plugin instance (counterpart to `instantiate()`).
   2.168 +
   2.169 +   This method is in the ``instantiation'' threading class, so no other
   2.170 +   methods on this instance will be called concurrently with it.
   2.171 + */
   2.172 +static void
   2.173 +cleanup(LV2_Handle instance) {
   2.174 +	free(instance);
   2.175 +}
   2.176 +
   2.177 +/**
   2.178 +   The `extension_data()` function returns any extension data supported by the
   2.179 +   plugin.  Note that this is not an instance method, but a function on the
   2.180 +   plugin descriptor.  It is usually used by plugins to implement additional
   2.181 +   interfaces.  This plugin does not have any extension data, so this function
   2.182 +   returns NULL.
   2.183 +
   2.184 +   This method is in the ``discovery'' threading class, so no other functions
   2.185 +   or methods in this plugin library will be called concurrently with it.
   2.186 + */
   2.187 +static const void*
   2.188 +extension_data(const char* uri) {
   2.189 +	return NULL;
   2.190 +}
   2.191 +
   2.192 +/**
   2.193 +   Every plugin must define an `LV2_Descriptor`.  It is best to define
   2.194 +   descriptors statically to avoid leaking memory and non-portable shared
   2.195 +   library constructors and destructors to clean up properly.
   2.196 + */
   2.197 +static const LV2_Descriptor descriptor = {
   2.198 +	AMP_URI,
   2.199 +	instantiate,
   2.200 +	connect_port,
   2.201 +	activate,
   2.202 +	run,
   2.203 +	deactivate,
   2.204 +	cleanup,
   2.205 +	extension_data
   2.206 +};
   2.207 +
   2.208 +/**
   2.209 +   The `lv2_descriptor()` function is the entry point to the plugin library.  The
   2.210 +   host will load the library and call this function repeatedly with increasing
   2.211 +   indices to find all the plugins defined in the library.  The index is not an
   2.212 +   indentifier, the URI of the returned descriptor is used to determine the
   2.213 +   identify of the plugin.
   2.214 +
   2.215 +   This method is in the ``discovery'' threading class, so no other functions
   2.216 +   or methods in this plugin library will be called concurrently with it.
   2.217 + */
   2.218 +LV2_SYMBOL_EXPORT
   2.219 +const LV2_Descriptor*
   2.220 +lv2_descriptor(uint32_t index) {
   2.221 +	switch (index) {
   2.222 +		case 0: return &descriptor;
   2.223 +		default: return NULL;
   2.224 +	}
   2.225 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/c++/lv2-demo-modul/amp.ttl	Fri May 15 20:32:37 2020 +0200
     3.3 @@ -0,0 +1,90 @@
     3.4 +# The full description of the plugin is in this file, which is linked to from
     3.5 +# `manifest.ttl`.  This is done so the host only needs to scan the relatively
     3.6 +# small `manifest.ttl` files to quickly discover all plugins.
     3.7 +
     3.8 +@prefix doap:  <http://usefulinc.com/ns/doap#> .
     3.9 +@prefix lv2:   <http://lv2plug.in/ns/lv2core#> .
    3.10 +@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
    3.11 +@prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .
    3.12 +@prefix units: <http://lv2plug.in/ns/extensions/units#> .
    3.13 +
    3.14 +# First the type of the plugin is described.  All plugins must explicitly list
    3.15 +# `lv2:Plugin` as a type.  A more specific type should also be given, where
    3.16 +# applicable, so hosts can present a nicer UI for loading plugins.  Note that
    3.17 +# this URI is the identifier of the plugin, so if it does not match the one in
    3.18 +# `manifest.ttl`, the host will not discover the plugin data at all.
    3.19 +<http://lv2plug.in/plugins/eg-amp>
    3.20 +	a lv2:Plugin ,
    3.21 +		lv2:AmplifierPlugin ;
    3.22 +# Plugins are associated with a project, where common information like
    3.23 +# developers, home page, and so on are described.  This plugin is part of the
    3.24 +# LV2 project, which has URI <http://lv2plug.in/ns/lv2>, and is described
    3.25 +# elsewhere.  Typical plugin collections will describe the project in
    3.26 +# manifest.ttl
    3.27 +	lv2:project <http://lv2plug.in/ns/lv2> ;
    3.28 +# Every plugin must have a name, described with the doap:name property.
    3.29 +# Translations to various languages can be added by putting a language tag
    3.30 +# after strings as shown.
    3.31 +	doap:name "Simple Amplifier" ,
    3.32 +		"简单放大器"@zh ,
    3.33 +		"Einfacher Verstärker"@de ,
    3.34 +		"Simple Amplifier"@en-gb ,
    3.35 +		"Amplificador Simple"@es ,
    3.36 +		"Amplificateur de Base"@fr ,
    3.37 +		"Amplificatore Semplice"@it ,
    3.38 +		"簡単なアンプ"@jp ,
    3.39 +		"Просто Усилитель"@ru ;
    3.40 +	doap:license <http://opensource.org/licenses/isc> ;
    3.41 +	lv2:optionalFeature lv2:hardRTCapable ;
    3.42 +	lv2:port [
    3.43 +# Every port must have at least two types, one that specifies direction
    3.44 +# (lv2:InputPort or lv2:OutputPort), and another to describe the data type.
    3.45 +# This port is a lv2:ControlPort, which means it contains a single float.
    3.46 +		a lv2:InputPort ,
    3.47 +			lv2:ControlPort ;
    3.48 +		lv2:index 0 ;
    3.49 +		lv2:symbol "gain" ;
    3.50 +		lv2:name "Gain" ,
    3.51 +			"收益"@zh ,
    3.52 +			"Verstärkung"@de ,
    3.53 +			"Gain"@en-gb ,
    3.54 +			"Aumento"@es ,
    3.55 +			"Gain"@fr ,
    3.56 +			"Guadagno"@it ,
    3.57 +			"利益"@jp ,
    3.58 +			"Увеличение"@ru ;
    3.59 +# An lv2:ControlPort should always describe its default value, and usually a
    3.60 +# minimum and maximum value.  Defining a range is not strictly required, but
    3.61 +# should be done wherever possible to aid host support, particularly for UIs.
    3.62 +		lv2:default 0.0 ;
    3.63 +		lv2:minimum -90.0 ;
    3.64 +		lv2:maximum 24.0 ;
    3.65 +# Ports can describe units and control detents to allow better UI generation
    3.66 +# and host automation.
    3.67 +		units:unit units:db ;
    3.68 +		lv2:scalePoint [
    3.69 +			rdfs:label "+5" ;
    3.70 +			rdf:value 5.0
    3.71 +		] , [
    3.72 +			rdfs:label "0" ;
    3.73 +			rdf:value 0.0
    3.74 +		] , [
    3.75 +			rdfs:label "-5" ;
    3.76 +			rdf:value -5.0
    3.77 +		] , [
    3.78 +			rdfs:label "-10" ;
    3.79 +			rdf:value -10.0
    3.80 +		]
    3.81 +	] , [
    3.82 +		a lv2:AudioPort ,
    3.83 +			lv2:InputPort ;
    3.84 +		lv2:index 1 ;
    3.85 +		lv2:symbol "in" ;
    3.86 +		lv2:name "In"
    3.87 +	] , [
    3.88 +		a lv2:AudioPort ,
    3.89 +			lv2:OutputPort ;
    3.90 +		lv2:index 2 ;
    3.91 +		lv2:symbol "out" ;
    3.92 +		lv2:name "Out"
    3.93 +	] .
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/c++/lv2-demo-modul/manifest.ttl	Fri May 15 20:32:37 2020 +0200
     4.3 @@ -0,0 +1,68 @@
     4.4 +# LV2 plugins are installed in a ``bundle'', a directory with a standard
     4.5 +# structure.  Each bundle has a Turtle file named `manifest.ttl` which lists
     4.6 +# the contents of the bundle.
     4.7 +#
     4.8 +# Hosts typically read the manifest of every installed bundle to discover
     4.9 +# plugins on start-up, so it should be as small as possible for performance
    4.10 +# reasons.  Details that are only useful if the host chooses to load the plugin
    4.11 +# are stored in other files and linked to from `manifest.ttl`.
    4.12 +#
    4.13 +# ==== URIs ====
    4.14 +#
    4.15 +# LV2 makes use of URIs as globally-unique identifiers for resources.  For
    4.16 +# example, the ID of the plugin described here is
    4.17 +# `<http://lv2plug.in/plugins/eg-amp>`.  Note that URIs are only used as
    4.18 +# identifiers and don't necessarily imply that something can be accessed at
    4.19 +# that address on the web (though that may be the case).
    4.20 +#
    4.21 +# ==== Namespace Prefixes ====
    4.22 +#
    4.23 +# Turtle files contain many URIs, but prefixes can be defined to improve
    4.24 +# readability.  For example, with the `lv2:` prefix below, `lv2:Plugin` can be
    4.25 +# written instead of `<http://lv2plug.in/ns/lv2core#Plugin>`.
    4.26 +
    4.27 +@prefix lv2:  <http://lv2plug.in/ns/lv2core#> .
    4.28 +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
    4.29 +
    4.30 +# ==== Describing a Plugin ====
    4.31 +
    4.32 +# Turtle files contain a set of ``statements'' which describe resources.
    4.33 +# This file contains 3 statements:
    4.34 +# [options="header"]
    4.35 +# |================================================================
    4.36 +# | Subject                             | Predicate    | Object
    4.37 +# | <http://lv2plug.in/plugins/eg-amp>  | a            | lv2:Plugin
    4.38 +# | <http://lv2plug.in/plugins/eg-amp>  | lv2:binary   | <amp.so>
    4.39 +# | <http://lv2plug.in/plugins/eg-amp>  | rdfs:seeAlso | <amp.ttl>
    4.40 +# |================================================================
    4.41 +
    4.42 +# Firstly, `<http://lv2plug.in/plugins/eg-amp>` is an LV2 plugin:
    4.43 +<http://lv2plug.in/plugins/eg-amp> a lv2:Plugin .
    4.44 +
    4.45 +# The predicate ```a`'' is a Turtle shorthand for `rdf:type`.
    4.46 +
    4.47 +# The binary of that plugin can be found at `<amp.ext>`:
    4.48 +<http://lv2plug.in/plugins/eg-amp> lv2:binary <amp.so> .
    4.49 +
    4.50 +# This file is a template; the token `@LIB_EXT@` is replaced by the build
    4.51 +# system with the appropriate extension for the current platform before
    4.52 +# installation.  For example, in the output `manifest.ttl`, the binary would be
    4.53 +# listed as `<amp.so>`.  Relative URIs in manifests are relative to the bundle
    4.54 +# directory, so this refers to a binary with the given name in the same
    4.55 +# directory as this manifest.
    4.56 +
    4.57 +# Finally, more information about this plugin can be found in `<amp.ttl>`:
    4.58 +<http://lv2plug.in/plugins/eg-amp> rdfs:seeAlso <amp.ttl> .
    4.59 +
    4.60 +# ==== Abbreviation ====
    4.61 +#
    4.62 +# This file shows these statements individually for instructive purposes, but
    4.63 +# the subject `<http://lv2plug.in/plugins/eg-amp>` is repetitive.  Turtle
    4.64 +# allows the semicolon to be used as a delimiter that repeats the previous
    4.65 +# subject.  For example, this manifest would more realistically be written like
    4.66 +# so:
    4.67 +
    4.68 +<http://lv2plug.in/plugins/eg-amp>
    4.69 +	a lv2:Plugin ;
    4.70 +	lv2:binary <amp.so>  ;
    4.71 +	rdfs:seeAlso <amp.ttl> .