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 |
}
|