Compare commits
2 Commits
f40df2491e
...
38dc236740
Author | SHA1 | Date |
---|---|---|
Christopher Arndt | 38dc236740 | |
Christopher Arndt | e6c66ed72c |
55
README.md
55
README.md
|
@ -1,6 +1,7 @@
|
||||||
# nymph
|
# nymph
|
||||||
|
|
||||||
A [Nim] library for writing audio and MIDI plugins conforming to the [LV2] standard
|
A [Nim] library for writing audio and MIDI plugins conforming to the [LV2]
|
||||||
|
standard
|
||||||
|
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
@ -27,51 +28,59 @@ 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`: shows how to handle receiving and sending MIDI events.
|
* [`miditranspose`](./examples/miditranspose_plugin.nim): shows how to handle
|
||||||
* `multimodefilter`: shows a multimode state-variable filter implementation
|
receiving and sending MIDI events.
|
||||||
ported from C++ to Nim.
|
* [`multimodefilter`](./examples/multimodefilter_plugin.nim): shows a
|
||||||
* `tiltfilter`: shows a multimode tilt equalizer filter implementation ported
|
multimode state-variable filter implementation ported from C++ to Nim.
|
||||||
from Rust to Nim.
|
* [`tiltfilter`](./examples/titltfilter_plugin.nim): shows a multimode tilt
|
||||||
* `faustlpf`: shows how to integrate DSP C code generated from a [FAUST]
|
equalizer filter implementation ported from Rust to Nim.
|
||||||
source file in Nim (in this example the FAUST code implements a simple
|
* [`faustlpf`](./examples/faustlpf_plugin.nim): shows how to integrate DSP C
|
||||||
non-resonant low-pass filter from the FAUST standard library).
|
code generated from a [FAUST] source file in Nim (in this example the FAUST
|
||||||
|
code implements a simple non-resonant low-pass filter from the FAUST
|
||||||
|
standard library).
|
||||||
|
|
||||||
|
|
||||||
## How To
|
## How To
|
||||||
|
|
||||||
* Install this library:
|
**Note:** I'll use `mydsp` as the base name for the new plugin in the
|
||||||
|
examples below. Substitute your own plugin basename wherever you see it used
|
||||||
|
below.
|
||||||
|
|
||||||
nimble install https://git.0x20.eu/chris/nymph
|
1. Install this library:
|
||||||
|
|
||||||
* Copy `examples/amp.lv2` and `examples/amp.nim` into your project and rename
|
nimble install https://github.com/SpotlightKid/nymph.git
|
||||||
them as you like (also rename `amp.lv2/amp.ttl`). I'll use `myplugin` as the
|
|
||||||
base name in the examples below.
|
|
||||||
|
|
||||||
* Edit `myplugin.lv2/manifest.ttl`:
|
1. Make a directory named `mydsp.lv2` and copy `examples/amp.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
|
||||||
`libmyplugin.so`.
|
`libmydsp.so`.
|
||||||
* Change file name referenced via `rdfs:seeAlso` to `myplugin.ttl`.
|
* Change file name referenced via `rdfs:seeAlso` to `mydsp.ttl`.
|
||||||
|
|
||||||
* Edit `myplugin.lv2/myplugin.ttl`:
|
1. Edit `mydsp.lv2/mydsp.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.
|
||||||
|
|
||||||
* Edit `myplugin.nim`:
|
1. Edit `mydsp_plugin.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
|
||||||
`myplugin.ttl`.
|
`mydsp.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 type for the plugin port
|
define its members with the appropriate data types for the plugin ports
|
||||||
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.
|
||||||
|
|
||||||
* Compile the plugin shared library object with:
|
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:myplugin.lv2/libmyplugin.so myplugin.nim
|
--out:mydsp.lv2/libmydsp.so mydsp_plugin.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
|
||||||
|
|
|
@ -2,24 +2,22 @@
|
||||||
|
|
||||||
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, which represents the value of the
|
# struct field representing the value of the FAUST UI element,
|
||||||
# FAUST UI element, which controls the cutoff
|
# which controls the filter cutoff frequency
|
||||||
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
|
||||||
|
@ -34,6 +32,8 @@ 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,8 +66,7 @@ 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[].clamp(minFreq, maxFreq)
|
plug.flt.fHslider0 = plug.freq[]
|
||||||
|
|
||||||
computefaustlpf(plug.flt, nSamples.cint, addr plug.input, addr plug.output)
|
computefaustlpf(plug.flt, nSamples.cint, addr plug.input, addr plug.output)
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,9 +84,6 @@ 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()
|
||||||
|
|
|
@ -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 -ct 1 -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 -rui -ct 1 -fm def -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,14 +17,8 @@ Compilation options: -a ./examples/minarch.h -lang c -ct 1 -cn faustlpf -es 1 -m
|
||||||
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
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
@ -47,6 +41,7 @@ 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>
|
||||||
|
@ -86,7 +81,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 -ct 1 -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 -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, "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");
|
||||||
|
@ -191,7 +186,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 * (float)(dsp->fHslider0);
|
float fSlow0 = dsp->fConst1 * fmaxf(16.0f, fminf(1.5e+04f, (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];
|
||||||
|
@ -236,7 +231,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] = tanf(dsp->fConst3 * fRec1[i]);
|
fZec0[i] = fast_tanf(dsp->fConst3 * fRec1[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Vectorizable loop 2 */
|
/* Vectorizable loop 2 */
|
||||||
|
@ -328,7 +323,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] = tanf(dsp->fConst3 * fRec1[i]);
|
fZec0[i] = fast_tanf(dsp->fConst3 * fRec1[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Vectorizable loop 2 */
|
/* Vectorizable loop 2 */
|
||||||
|
|
|
@ -4,14 +4,8 @@
|
||||||
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
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
Loading…
Reference in New Issue