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`. * Change the plugin URI.
* Change the plugin's shared library name defined via `lv2:binary` to
`libmyplugin.so`.
* Change file name referenced via `rdfs:seeAlso` to `myplugin.ttl`.
1. Copy `examples/amp_plugin.nim` into your project as `mydsp_plugin.nim`. * Edit `myplugin.lv2/myplugin.ttl`:
* Change the plugin URI.
* Define audio, control and atom ports as needed.
1. Edit `mydsp.lv2/manifest.ttl`: * Edit `myplugin.nim`:
* Change the plugin URI. * Change the `PluginUri` constant at the top.
* Change the plugin's shared library name defined via `lv2:binary` to * Change the `PluginPort` enum and list the ports in the order defined in
`libmydsp.so`. `myplugin.ttl`.
* Change file name referenced via `rdfs:seeAlso` to `mydsp.ttl`. * Rename and update the definition of the `AmpPlugin` object type and
define its members with the appropriate data type for the plugin port
they will be connected to. Update the type name in the `instantiate`,
`deactivate`, `connectPorts` and `run` procs.
* Update and extend the `case` statement in `connectPort` to connect ports
to your plugin object instance members.
* Implement your DSP code in the `run` proc.
1. Edit `mydsp.lv2/mydsp.ttl`: * Compile the plugin shared library object with:
* Change the plugin URI.
* Define audio, control and atom ports as needed.
1. Edit `mydsp_plugin.nim`:
* Change the `PluginUri` constant at the top.
* Change the `PluginPort` enum and list the ports in the order defined in
`mydsp.ttl`.
* Rename and update the definition of the `AmpPlugin` object type and
define its members with the appropriate data types for the plugin ports
they will be connected to. Update the type name in the `instantiate`,
`deactivate`, `connectPorts` and `run` procs.
* Update and extend the `case` statement in `connectPort` to connect ports
to your plugin object instance members.
* Implement your DSP code in the `run` proc.
1. 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
*******************************************************************************/ *******************************************************************************/