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