c++/lv2-demo-modul/amp.cpp
author František Kučera <franta-hg@frantovo.cz>
Fri, 15 May 2020 20:32:37 +0200
changeset 59 d6614ad97bed
permissions -rw-r--r--
LV2: modul zesilovače, dle oficiálního příkladu, ale bez závislosti na Pythonu – stačí gcc a make
     1 /*
     2   Copyright 2006-2016 David Robillard <d@drobilla.net>
     3   Copyright 2006 Steve Harris <steve@plugin.org.uk>
     4 
     5   Permission to use, copy, modify, and/or distribute this software for any
     6   purpose with or without fee is hereby granted, provided that the above
     7   copyright notice and this permission notice appear in all copies.
     8 
     9   THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    10   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    11   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    12   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    13   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    14   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    15   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    16  */
    17 
    18 /**
    19    LV2 headers are based on the URI of the specification they come from, so a
    20    consistent convention can be used even for unofficial extensions.  The URI
    21    of the core LV2 specification is <http://lv2plug.in/ns/lv2core>, by
    22    replacing `http:/` with `lv2` any header in the specification bundle can be
    23    included, in this case `lv2.h`.
    24  */
    25 #include <lv2.h>
    26 
    27 /** Include standard C headers */
    28 #include <math.h>
    29 #include <stdint.h>
    30 #include <stdlib.h>
    31 
    32 /**
    33    The URI is the identifier for a plugin, and how the host associates this
    34    implementation in code with its description in data.  In this plugin it is
    35    only used once in the code, but defining the plugin URI at the top of the
    36    file is a good convention to follow.  If this URI does not match that used
    37    in the data files, the host will fail to load the plugin.
    38  */
    39 #define AMP_URI "http://lv2plug.in/plugins/eg-amp"
    40 
    41 /**
    42    In code, ports are referred to by index.  An enumeration of port indices
    43    should be defined for readability.
    44  */
    45 typedef enum {
    46 	AMP_GAIN = 0,
    47 	AMP_INPUT = 1,
    48 	AMP_OUTPUT = 2
    49 } PortIndex;
    50 
    51 /**
    52    Every plugin defines a private structure for the plugin instance.  All data
    53    associated with a plugin instance is stored here, and is available to
    54    every instance method.  In this simple plugin, only port buffers need to be
    55    stored, since there is no additional instance data.
    56  */
    57 typedef struct {
    58 	// Port buffers
    59 	const float* gain;
    60 	const float* input;
    61 	float* output;
    62 } Amp;
    63 
    64 /**
    65    The `instantiate()` function is called by the host to create a new plugin
    66    instance.  The host passes the plugin descriptor, sample rate, and bundle
    67    path for plugins that need to load additional resources (e.g. waveforms).
    68    The features parameter contains host-provided features defined in LV2
    69    extensions, but this simple plugin does not use any.
    70 
    71    This function is in the ``instantiation'' threading class, so no other
    72    methods on this instance will be called concurrently with it.
    73  */
    74 static LV2_Handle
    75 instantiate(const LV2_Descriptor* descriptor,
    76 		double rate,
    77 		const char* bundle_path,
    78 		const LV2_Feature * const* features) {
    79 	Amp* amp = (Amp*) calloc(1, sizeof (Amp));
    80 
    81 	return (LV2_Handle) amp;
    82 }
    83 
    84 /**
    85    The `connect_port()` method is called by the host to connect a particular
    86    port to a buffer.  The plugin must store the data location, but data may not
    87    be accessed except in run().
    88 
    89    This method is in the ``audio'' threading class, and is called in the same
    90    context as run().
    91  */
    92 static void
    93 connect_port(LV2_Handle instance,
    94 		uint32_t port,
    95 		void* data) {
    96 	Amp* amp = (Amp*) instance;
    97 
    98 	switch ((PortIndex) port) {
    99 		case AMP_GAIN:
   100 			amp->gain = (const float*) data;
   101 			break;
   102 		case AMP_INPUT:
   103 			amp->input = (const float*) data;
   104 			break;
   105 		case AMP_OUTPUT:
   106 			amp->output = (float*) data;
   107 			break;
   108 	}
   109 }
   110 
   111 /**
   112    The `activate()` method is called by the host to initialise and prepare the
   113    plugin instance for running.  The plugin must reset all internal state
   114    except for buffer locations set by `connect_port()`.  Since this plugin has
   115    no other internal state, this method does nothing.
   116 
   117    This method is in the ``instantiation'' threading class, so no other
   118    methods on this instance will be called concurrently with it.
   119  */
   120 static void
   121 activate(LV2_Handle instance) {
   122 }
   123 
   124 /** Define a macro for converting a gain in dB to a coefficient. */
   125 #define DB_CO(g) ((g) > -90.0f ? powf(10.0f, (g) * 0.05f) : 0.0f)
   126 
   127 /**
   128    The `run()` method is the main process function of the plugin.  It processes
   129    a block of audio in the audio context.  Since this plugin is
   130    `lv2:hardRTCapable`, `run()` must be real-time safe, so blocking (e.g. with
   131    a mutex) or memory allocation are not allowed.
   132  */
   133 static void
   134 run(LV2_Handle instance, uint32_t n_samples) {
   135 	const Amp* amp = (const Amp*) instance;
   136 
   137 	const float gain = *(amp->gain);
   138 	const float* const input = amp->input;
   139 	float* const output = amp->output;
   140 
   141 	const float coef = DB_CO(gain);
   142 
   143 	for (uint32_t pos = 0; pos < n_samples; pos++) {
   144 		output[pos] = input[pos] * coef;
   145 	}
   146 }
   147 
   148 /**
   149    The `deactivate()` method is the counterpart to `activate()`, and is called by
   150    the host after running the plugin.  It indicates that the host will not call
   151    `run()` again until another call to `activate()` and is mainly useful for more
   152    advanced plugins with ``live'' characteristics such as those with auxiliary
   153    processing threads.  As with `activate()`, this plugin has no use for this
   154    information so this method does nothing.
   155 
   156    This method is in the ``instantiation'' threading class, so no other
   157    methods on this instance will be called concurrently with it.
   158  */
   159 static void
   160 deactivate(LV2_Handle instance) {
   161 }
   162 
   163 /**
   164    Destroy a plugin instance (counterpart to `instantiate()`).
   165 
   166    This method is in the ``instantiation'' threading class, so no other
   167    methods on this instance will be called concurrently with it.
   168  */
   169 static void
   170 cleanup(LV2_Handle instance) {
   171 	free(instance);
   172 }
   173 
   174 /**
   175    The `extension_data()` function returns any extension data supported by the
   176    plugin.  Note that this is not an instance method, but a function on the
   177    plugin descriptor.  It is usually used by plugins to implement additional
   178    interfaces.  This plugin does not have any extension data, so this function
   179    returns NULL.
   180 
   181    This method is in the ``discovery'' threading class, so no other functions
   182    or methods in this plugin library will be called concurrently with it.
   183  */
   184 static const void*
   185 extension_data(const char* uri) {
   186 	return NULL;
   187 }
   188 
   189 /**
   190    Every plugin must define an `LV2_Descriptor`.  It is best to define
   191    descriptors statically to avoid leaking memory and non-portable shared
   192    library constructors and destructors to clean up properly.
   193  */
   194 static const LV2_Descriptor descriptor = {
   195 	AMP_URI,
   196 	instantiate,
   197 	connect_port,
   198 	activate,
   199 	run,
   200 	deactivate,
   201 	cleanup,
   202 	extension_data
   203 };
   204 
   205 /**
   206    The `lv2_descriptor()` function is the entry point to the plugin library.  The
   207    host will load the library and call this function repeatedly with increasing
   208    indices to find all the plugins defined in the library.  The index is not an
   209    indentifier, the URI of the returned descriptor is used to determine the
   210    identify of the plugin.
   211 
   212    This method is in the ``discovery'' threading class, so no other functions
   213    or methods in this plugin library will be called concurrently with it.
   214  */
   215 LV2_SYMBOL_EXPORT
   216 const LV2_Descriptor*
   217 lv2_descriptor(uint32_t index) {
   218 	switch (index) {
   219 		case 0: return &descriptor;
   220 		default: return NULL;
   221 	}
   222 }