franta-hg@59: /* franta-hg@59: Copyright 2006-2016 David Robillard franta-hg@59: Copyright 2006 Steve Harris franta-hg@59: franta-hg@59: Permission to use, copy, modify, and/or distribute this software for any franta-hg@59: purpose with or without fee is hereby granted, provided that the above franta-hg@59: copyright notice and this permission notice appear in all copies. franta-hg@59: franta-hg@59: THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES franta-hg@59: WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF franta-hg@59: MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR franta-hg@59: ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES franta-hg@59: WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN franta-hg@59: ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF franta-hg@59: OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. franta-hg@59: */ franta-hg@59: franta-hg@59: /** franta-hg@59: LV2 headers are based on the URI of the specification they come from, so a franta-hg@59: consistent convention can be used even for unofficial extensions. The URI franta-hg@59: of the core LV2 specification is , by franta-hg@59: replacing `http:/` with `lv2` any header in the specification bundle can be franta-hg@59: included, in this case `lv2.h`. franta-hg@59: */ franta-hg@59: #include franta-hg@59: franta-hg@59: /** Include standard C headers */ franta-hg@59: #include franta-hg@59: #include franta-hg@59: #include franta-hg@59: franta-hg@59: /** franta-hg@59: The URI is the identifier for a plugin, and how the host associates this franta-hg@59: implementation in code with its description in data. In this plugin it is franta-hg@59: only used once in the code, but defining the plugin URI at the top of the franta-hg@59: file is a good convention to follow. If this URI does not match that used franta-hg@59: in the data files, the host will fail to load the plugin. franta-hg@59: */ franta-hg@59: #define AMP_URI "http://lv2plug.in/plugins/eg-amp" franta-hg@59: franta-hg@59: /** franta-hg@59: In code, ports are referred to by index. An enumeration of port indices franta-hg@59: should be defined for readability. franta-hg@59: */ franta-hg@59: typedef enum { franta-hg@59: AMP_GAIN = 0, franta-hg@59: AMP_INPUT = 1, franta-hg@59: AMP_OUTPUT = 2 franta-hg@59: } PortIndex; franta-hg@59: franta-hg@59: /** franta-hg@59: Every plugin defines a private structure for the plugin instance. All data franta-hg@59: associated with a plugin instance is stored here, and is available to franta-hg@59: every instance method. In this simple plugin, only port buffers need to be franta-hg@59: stored, since there is no additional instance data. franta-hg@59: */ franta-hg@59: typedef struct { franta-hg@59: // Port buffers franta-hg@59: const float* gain; franta-hg@59: const float* input; franta-hg@59: float* output; franta-hg@59: } Amp; franta-hg@59: franta-hg@59: /** franta-hg@59: The `instantiate()` function is called by the host to create a new plugin franta-hg@59: instance. The host passes the plugin descriptor, sample rate, and bundle franta-hg@59: path for plugins that need to load additional resources (e.g. waveforms). franta-hg@59: The features parameter contains host-provided features defined in LV2 franta-hg@59: extensions, but this simple plugin does not use any. franta-hg@59: franta-hg@59: This function is in the ``instantiation'' threading class, so no other franta-hg@59: methods on this instance will be called concurrently with it. franta-hg@59: */ franta-hg@59: static LV2_Handle franta-hg@59: instantiate(const LV2_Descriptor* descriptor, franta-hg@59: double rate, franta-hg@59: const char* bundle_path, franta-hg@59: const LV2_Feature * const* features) { franta-hg@59: Amp* amp = (Amp*) calloc(1, sizeof (Amp)); franta-hg@59: franta-hg@59: return (LV2_Handle) amp; franta-hg@59: } franta-hg@59: franta-hg@59: /** franta-hg@59: The `connect_port()` method is called by the host to connect a particular franta-hg@59: port to a buffer. The plugin must store the data location, but data may not franta-hg@59: be accessed except in run(). franta-hg@59: franta-hg@59: This method is in the ``audio'' threading class, and is called in the same franta-hg@59: context as run(). franta-hg@59: */ franta-hg@59: static void franta-hg@59: connect_port(LV2_Handle instance, franta-hg@59: uint32_t port, franta-hg@59: void* data) { franta-hg@59: Amp* amp = (Amp*) instance; franta-hg@59: franta-hg@59: switch ((PortIndex) port) { franta-hg@59: case AMP_GAIN: franta-hg@59: amp->gain = (const float*) data; franta-hg@59: break; franta-hg@59: case AMP_INPUT: franta-hg@59: amp->input = (const float*) data; franta-hg@59: break; franta-hg@59: case AMP_OUTPUT: franta-hg@59: amp->output = (float*) data; franta-hg@59: break; franta-hg@59: } franta-hg@59: } franta-hg@59: franta-hg@59: /** franta-hg@59: The `activate()` method is called by the host to initialise and prepare the franta-hg@59: plugin instance for running. The plugin must reset all internal state franta-hg@59: except for buffer locations set by `connect_port()`. Since this plugin has franta-hg@59: no other internal state, this method does nothing. franta-hg@59: franta-hg@59: This method is in the ``instantiation'' threading class, so no other franta-hg@59: methods on this instance will be called concurrently with it. franta-hg@59: */ franta-hg@59: static void franta-hg@59: activate(LV2_Handle instance) { franta-hg@59: } franta-hg@59: franta-hg@59: /** Define a macro for converting a gain in dB to a coefficient. */ franta-hg@59: #define DB_CO(g) ((g) > -90.0f ? powf(10.0f, (g) * 0.05f) : 0.0f) franta-hg@59: franta-hg@59: /** franta-hg@59: The `run()` method is the main process function of the plugin. It processes franta-hg@59: a block of audio in the audio context. Since this plugin is franta-hg@59: `lv2:hardRTCapable`, `run()` must be real-time safe, so blocking (e.g. with franta-hg@59: a mutex) or memory allocation are not allowed. franta-hg@59: */ franta-hg@59: static void franta-hg@59: run(LV2_Handle instance, uint32_t n_samples) { franta-hg@59: const Amp* amp = (const Amp*) instance; franta-hg@59: franta-hg@59: const float gain = *(amp->gain); franta-hg@59: const float* const input = amp->input; franta-hg@59: float* const output = amp->output; franta-hg@59: franta-hg@59: const float coef = DB_CO(gain); franta-hg@59: franta-hg@59: for (uint32_t pos = 0; pos < n_samples; pos++) { franta-hg@59: output[pos] = input[pos] * coef; franta-hg@59: } franta-hg@59: } franta-hg@59: franta-hg@59: /** franta-hg@59: The `deactivate()` method is the counterpart to `activate()`, and is called by franta-hg@59: the host after running the plugin. It indicates that the host will not call franta-hg@59: `run()` again until another call to `activate()` and is mainly useful for more franta-hg@59: advanced plugins with ``live'' characteristics such as those with auxiliary franta-hg@59: processing threads. As with `activate()`, this plugin has no use for this franta-hg@59: information so this method does nothing. franta-hg@59: franta-hg@59: This method is in the ``instantiation'' threading class, so no other franta-hg@59: methods on this instance will be called concurrently with it. franta-hg@59: */ franta-hg@59: static void franta-hg@59: deactivate(LV2_Handle instance) { franta-hg@59: } franta-hg@59: franta-hg@59: /** franta-hg@59: Destroy a plugin instance (counterpart to `instantiate()`). franta-hg@59: franta-hg@59: This method is in the ``instantiation'' threading class, so no other franta-hg@59: methods on this instance will be called concurrently with it. franta-hg@59: */ franta-hg@59: static void franta-hg@59: cleanup(LV2_Handle instance) { franta-hg@59: free(instance); franta-hg@59: } franta-hg@59: franta-hg@59: /** franta-hg@59: The `extension_data()` function returns any extension data supported by the franta-hg@59: plugin. Note that this is not an instance method, but a function on the franta-hg@59: plugin descriptor. It is usually used by plugins to implement additional franta-hg@59: interfaces. This plugin does not have any extension data, so this function franta-hg@59: returns NULL. franta-hg@59: franta-hg@59: This method is in the ``discovery'' threading class, so no other functions franta-hg@59: or methods in this plugin library will be called concurrently with it. franta-hg@59: */ franta-hg@59: static const void* franta-hg@59: extension_data(const char* uri) { franta-hg@59: return NULL; franta-hg@59: } franta-hg@59: franta-hg@59: /** franta-hg@59: Every plugin must define an `LV2_Descriptor`. It is best to define franta-hg@59: descriptors statically to avoid leaking memory and non-portable shared franta-hg@59: library constructors and destructors to clean up properly. franta-hg@59: */ franta-hg@59: static const LV2_Descriptor descriptor = { franta-hg@59: AMP_URI, franta-hg@59: instantiate, franta-hg@59: connect_port, franta-hg@59: activate, franta-hg@59: run, franta-hg@59: deactivate, franta-hg@59: cleanup, franta-hg@59: extension_data franta-hg@59: }; franta-hg@59: franta-hg@59: /** franta-hg@59: The `lv2_descriptor()` function is the entry point to the plugin library. The franta-hg@59: host will load the library and call this function repeatedly with increasing franta-hg@59: indices to find all the plugins defined in the library. The index is not an franta-hg@59: indentifier, the URI of the returned descriptor is used to determine the franta-hg@59: identify of the plugin. franta-hg@59: franta-hg@59: This method is in the ``discovery'' threading class, so no other functions franta-hg@59: or methods in this plugin library will be called concurrently with it. franta-hg@59: */ franta-hg@59: LV2_SYMBOL_EXPORT franta-hg@59: const LV2_Descriptor* franta-hg@59: lv2_descriptor(uint32_t index) { franta-hg@59: switch (index) { franta-hg@59: case 0: return &descriptor; franta-hg@59: default: return NULL; franta-hg@59: } franta-hg@59: }