Compare commits

..

No commits in common. "38dc236740becb999021d2999831054734d3d430" and "f40df2491ecc92628c7dd424d68f596ec33f8c71" have entirely different histories.

4 changed files with 64 additions and 58 deletions

View File

@ -1,7 +1,6 @@
# nymph # nymph
A [Nim] library for writing audio and MIDI plugins conforming to the [LV2] A [Nim] library for writing audio and MIDI plugins conforming to the [LV2] standard
standard
## Examples ## Examples
@ -28,59 +27,51 @@ the basename of the plugin's LV2 bundle dir.
Currently, there are just a few other example plugins: Currently, there are just a few other example plugins:
* [`miditranspose`](./examples/miditranspose_plugin.nim): shows how to handle * `miditranspose`: shows how to handle receiving and sending MIDI events.
receiving and sending MIDI events. * `multimodefilter`: shows a multimode state-variable filter implementation
* [`multimodefilter`](./examples/multimodefilter_plugin.nim): shows a ported from C++ to Nim.
multimode state-variable filter implementation ported from C++ to Nim. * `tiltfilter`: shows a multimode tilt equalizer filter implementation ported
* [`tiltfilter`](./examples/titltfilter_plugin.nim): shows a multimode tilt from Rust to Nim.
equalizer filter implementation ported from Rust to Nim. * `faustlpf`: shows how to integrate DSP C code generated from a [FAUST]
* [`faustlpf`](./examples/faustlpf_plugin.nim): shows how to integrate DSP C source file in Nim (in this example the FAUST code implements a simple
code generated from a [FAUST] source file in Nim (in this example the FAUST non-resonant low-pass filter from the FAUST standard library).
code implements a simple non-resonant low-pass filter from the FAUST
standard library).
## How To ## How To
**Note:** I'll use `mydsp` as the base name for the new plugin in the * Install this library:
examples below. Substitute your own plugin basename wherever you see it used
below.
1. Install this library: nimble install https://git.0x20.eu/chris/nymph
nimble install https://github.com/SpotlightKid/nymph.git * Copy `examples/amp.lv2` and `examples/amp.nim` into your project and rename
them as you like (also rename `amp.lv2/amp.ttl`). I'll use `myplugin` as the
base name in the examples below.
1. Make a directory named `mydsp.lv2` and copy `examples/amp.lv2/manifest.ttl` * Edit `myplugin.lv2/manifest.ttl`:
into it. Also copy `examples/amp.lv2/amp.ttl` to `mydsp.lv2/mydsp.ttl`.
1. Copy `examples/amp_plugin.nim` into your project as `mydsp_plugin.nim`.
1. Edit `mydsp.lv2/manifest.ttl`:
* Change the plugin URI. * Change the plugin URI.
* Change the plugin's shared library name defined via `lv2:binary` to * Change the plugin's shared library name defined via `lv2:binary` to
`libmydsp.so`. `libmyplugin.so`.
* Change file name referenced via `rdfs:seeAlso` to `mydsp.ttl`. * Change file name referenced via `rdfs:seeAlso` to `myplugin.ttl`.
1. Edit `mydsp.lv2/mydsp.ttl`: * Edit `myplugin.lv2/myplugin.ttl`:
* Change the plugin URI. * Change the plugin URI.
* Define audio, control and atom ports as needed. * Define audio, control and atom ports as needed.
1. Edit `mydsp_plugin.nim`: * Edit `myplugin.nim`:
* Change the `PluginUri` constant at the top. * Change the `PluginUri` constant at the top.
* Change the `PluginPort` enum and list the ports in the order defined in * Change the `PluginPort` enum and list the ports in the order defined in
`mydsp.ttl`. `myplugin.ttl`.
* Rename and update the definition of the `AmpPlugin` object type and * Rename and update the definition of the `AmpPlugin` object type and
define its members with the appropriate data types for the plugin ports define its members with the appropriate data type for the plugin port
they will be connected to. Update the type name in the `instantiate`, they will be connected to. Update the type name in the `instantiate`,
`deactivate`, `connectPorts` and `run` procs. `deactivate`, `connectPorts` and `run` procs.
* Update and extend the `case` statement in `connectPort` to connect ports * Update and extend the `case` statement in `connectPort` to connect ports
to your plugin object instance members. to your plugin object instance members.
* Implement your DSP code in the `run` proc. * Implement your DSP code in the `run` proc.
1. Compile the plugin shared library object with: * Compile the plugin shared library object with:
nim c --app:lib --noMain:on --mm:arc \ nim c --app:lib --noMain:on --mm:arc \
--out:mydsp.lv2/libmydsp.so mydsp_plugin.nim --out:myplugin.lv2/libmyplugin.so myplugin.nim
See the definition of the `build_ex` task in the See the definition of the `build_ex` task in the
[nymph.nimble](./nymph.nimble#L67) file on how to create a nimble task [nymph.nimble](./nymph.nimble#L67) file on how to create a nimble task

View File

@ -2,22 +2,24 @@
import nymph import nymph
{.emit: """#include "lpf.h"""".} {.emit: "#include \"lpf.h\"".}
const const
PluginUri = "urn:nymph:examples:faustlpf" PluginUri = "urn:nymph:examples:faustlpf"
minFreq = 16.0
maxFreq = 15_000.0
type type
SampleBuffer = UncheckedArray[cfloat]
faustlpf {.importc, header: "lpf.h".} = object faustlpf {.importc, header: "lpf.h".} = object
# struct field representing the value of the FAUST UI element, # struct field, which represents the value of the
# which controls the filter cutoff frequency # FAUST UI element, which controls the cutoff
fHslider0: cfloat fHslider0: cfloat
PluginPort {.pure.} = enum PluginPort {.pure.} = enum
Input, Output, Frequency Input, Output, Frequency
SampleBuffer = UncheckedArray[cfloat]
FaustLPFPlugin = object FaustLPFPlugin = object
input: ptr SampleBuffer input: ptr SampleBuffer
output: ptr SampleBuffer output: ptr SampleBuffer
@ -32,8 +34,6 @@ proc initfaustlpf(dsp: ptr faustlpf, sample_rate: cint) {.importc.}
proc instanceClearfaustlpf(dsp: ptr faustlpf) {.importc.} proc instanceClearfaustlpf(dsp: ptr faustlpf) {.importc.}
proc computefaustlpf(dsp: ptr faustlpf, count: cint, inputs, outputs: ptr ptr SampleBuffer) {.importc.} proc computefaustlpf(dsp: ptr faustlpf, count: cint, inputs, outputs: ptr ptr SampleBuffer) {.importc.}
proc NimMain() {.cdecl, importc.}
proc instantiate(descriptor: ptr Lv2Descriptor; sampleRate: cdouble; proc instantiate(descriptor: ptr Lv2Descriptor; sampleRate: cdouble;
bundlePath: cstring; features: ptr UncheckedArray[ptr Lv2Feature]): bundlePath: cstring; features: ptr UncheckedArray[ptr Lv2Feature]):
@ -66,7 +66,8 @@ proc activate(instance: Lv2Handle) {.cdecl.} =
proc run(instance: Lv2Handle; nSamples: cuint) {.cdecl.} = proc run(instance: Lv2Handle; nSamples: cuint) {.cdecl.} =
let plug = cast[ptr FaustLPFPlugin](instance) let plug = cast[ptr FaustLPFPlugin](instance)
plug.flt.fHslider0 = plug.freq[] plug.flt.fHslider0 = plug.freq[].clamp(minFreq, maxFreq)
computefaustlpf(plug.flt, nSamples.cint, addr plug.input, addr plug.output) computefaustlpf(plug.flt, nSamples.cint, addr plug.input, addr plug.output)
@ -84,6 +85,9 @@ proc extensionData(uri: cstring): pointer {.cdecl.} =
return nil return nil
proc NimMain() {.cdecl, importc.}
proc lv2Descriptor(index: cuint): ptr Lv2Descriptor {. proc lv2Descriptor(index: cuint): ptr Lv2Descriptor {.
cdecl, exportc, dynlib, extern: "lv2_descriptor".} = cdecl, exportc, dynlib, extern: "lv2_descriptor".} =
NimMain() NimMain()

View File

@ -5,7 +5,7 @@ license: "MIT"
name: "FaustLPF" name: "FaustLPF"
version: "0.1.0" version: "0.1.0"
Code generated with Faust 2.74.6 (https://faust.grame.fr) Code generated with Faust 2.74.6 (https://faust.grame.fr)
Compilation options: -a ./examples/minarch.h -lang c -rui -ct 1 -fm def -cn faustlpf -es 1 -mcd 16 -mdd 1024 -mdy 33 -single -ftz 0 -vec -lv 0 -vs 32 Compilation options: -a ./examples/minarch.h -lang c -ct 1 -cn faustlpf -es 1 -mcd 16 -mdd 1024 -mdy 33 -single -ftz 0 -vec -lv 0 -vs 32
------------------------------------------------------------ */ ------------------------------------------------------------ */
#ifndef __faustlpf_H__ #ifndef __faustlpf_H__
@ -17,8 +17,14 @@ Compilation options: -a ./examples/minarch.h -lang c -rui -ct 1 -fm def -cn faus
FAUST Architecture File for generating a very minimal C interface FAUST Architecture File for generating a very minimal C interface
************************************************************************/ ************************************************************************/
#include <math.h>
#include <stdio.h>
#include "faust/gui/CInterface.h" #include "faust/gui/CInterface.h"
#define max(a,b) ((a < b) ? b : a)
#define min(a,b) ((a < b) ? a : b)
/****************************************************************************** /******************************************************************************
VECTOR INTRINSICS VECTOR INTRINSICS
*******************************************************************************/ *******************************************************************************/
@ -41,7 +47,6 @@ extern "C" {
#define RESTRICT __restrict__ #define RESTRICT __restrict__
#endif #endif
#include "faust/dsp/fastmath.cpp"
#include <math.h> #include <math.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
@ -81,7 +86,7 @@ void deletefaustlpf(faustlpf* dsp) {
void metadatafaustlpf(MetaGlue* m) { void metadatafaustlpf(MetaGlue* m) {
m->declare(m->metaInterface, "author", "Christopher Arndt"); m->declare(m->metaInterface, "author", "Christopher Arndt");
m->declare(m->metaInterface, "compile_options", "-a ./examples/minarch.h -lang c -rui -ct 1 -fm def -cn faustlpf -es 1 -mcd 16 -mdd 1024 -mdy 33 -single -ftz 0 -vec -lv 0 -vs 32"); m->declare(m->metaInterface, "compile_options", "-a ./examples/minarch.h -lang c -ct 1 -cn faustlpf -es 1 -mcd 16 -mdd 1024 -mdy 33 -single -ftz 0 -vec -lv 0 -vs 32");
m->declare(m->metaInterface, "copyright", "Christopher Arndt, 2024"); m->declare(m->metaInterface, "copyright", "Christopher Arndt, 2024");
m->declare(m->metaInterface, "filename", "lpf.dsp"); m->declare(m->metaInterface, "filename", "lpf.dsp");
m->declare(m->metaInterface, "filters.lib/fir:author", "Julius O. Smith III"); m->declare(m->metaInterface, "filters.lib/fir:author", "Julius O. Smith III");
@ -186,7 +191,7 @@ void buildUserInterfacefaustlpf(faustlpf* dsp, UIGlue* ui_interface) {
void computefaustlpf(faustlpf* dsp, int count, FAUSTFLOAT** RESTRICT inputs, FAUSTFLOAT** RESTRICT outputs) { void computefaustlpf(faustlpf* dsp, int count, FAUSTFLOAT** RESTRICT inputs, FAUSTFLOAT** RESTRICT outputs) {
FAUSTFLOAT* input0_ptr = inputs[0]; FAUSTFLOAT* input0_ptr = inputs[0];
FAUSTFLOAT* output0_ptr = outputs[0]; FAUSTFLOAT* output0_ptr = outputs[0];
float fSlow0 = dsp->fConst1 * fmaxf(16.0f, fminf(1.5e+04f, (float)(dsp->fHslider0))); float fSlow0 = dsp->fConst1 * (float)(dsp->fHslider0);
float fRec1_tmp[36]; float fRec1_tmp[36];
float* fRec1 = &fRec1_tmp[4]; float* fRec1 = &fRec1_tmp[4];
float fZec0[32]; float fZec0[32];
@ -231,7 +236,7 @@ void computefaustlpf(faustlpf* dsp, int count, FAUSTFLOAT** RESTRICT inputs, FAU
{ {
int i; int i;
for (i = 0; i < vsize; i = i + 1) { for (i = 0; i < vsize; i = i + 1) {
fZec0[i] = fast_tanf(dsp->fConst3 * fRec1[i]); fZec0[i] = tanf(dsp->fConst3 * fRec1[i]);
} }
} }
/* Vectorizable loop 2 */ /* Vectorizable loop 2 */
@ -323,7 +328,7 @@ void computefaustlpf(faustlpf* dsp, int count, FAUSTFLOAT** RESTRICT inputs, FAU
{ {
int i; int i;
for (i = 0; i < vsize; i = i + 1) { for (i = 0; i < vsize; i = i + 1) {
fZec0[i] = fast_tanf(dsp->fConst3 * fRec1[i]); fZec0[i] = tanf(dsp->fConst3 * fRec1[i]);
} }
} }
/* Vectorizable loop 2 */ /* Vectorizable loop 2 */

View File

@ -4,8 +4,14 @@
FAUST Architecture File for generating a very minimal C interface FAUST Architecture File for generating a very minimal C interface
************************************************************************/ ************************************************************************/
#include <math.h>
#include <stdio.h>
#include "faust/gui/CInterface.h" #include "faust/gui/CInterface.h"
#define max(a,b) ((a < b) ? b : a)
#define min(a,b) ((a < b) ? a : b)
/****************************************************************************** /******************************************************************************
VECTOR INTRINSICS VECTOR INTRINSICS
*******************************************************************************/ *******************************************************************************/