From 9b33bf10bf254c52cef8918a495fc3e8aa7901f3 Mon Sep 17 00:00:00 2001 From: Christopher Arndt Date: Tue, 8 Oct 2024 19:42:50 +0200 Subject: [PATCH] feat: generate faust C code and Nim wrapper with faustpp Signed-off-by: Christopher Arndt --- README.md | 6 +- examples/{lpf.h => faustlpf.c} | 85 +++++++------- examples/faustlpf.h | 200 +++++++++++++++++++++++++++++++++ examples/faustlpf.nim | 33 ++++++ examples/faustlpf_plugin.nim | 20 +--- 5 files changed, 284 insertions(+), 60 deletions(-) rename examples/{lpf.h => faustlpf.c} (85%) create mode 100644 examples/faustlpf.h create mode 100644 examples/faustlpf.nim diff --git a/README.md b/README.md index 9807126..7958625 100644 --- a/README.md +++ b/README.md @@ -82,9 +82,9 @@ below. nim c --app:lib --noMain:on --mm:arc \ --out:mydsp.lv2/libmydsp.so mydsp_plugin.nim - See the definition of the `build_ex` task in the - [nymph.nimble](./nymph.nimble#L67) file on how to create a nimble task - to simplify compilation. + See the definition of the `build_ex` task in the + [nymph.nimble](./nymph.nimble#L67) file on how to create a nimble task + to simplify compilation and additional compiler args you might want to use. ## Dependencies diff --git a/examples/lpf.h b/examples/faustlpf.c similarity index 85% rename from examples/lpf.h rename to examples/faustlpf.c index dacfba6..f127c7e 100644 --- a/examples/lpf.h +++ b/examples/faustlpf.c @@ -1,31 +1,38 @@ -/* ------------------------------------------------------------ -author: "Christopher Arndt" -copyright: "Christopher Arndt, 2024" -license: "MIT" -name: "FaustLPF" -version: "0.1.0" -Code generated with Faust 2.74.6 (https://faust.grame.fr) -Compilation options: -a ./examples/minarch.h -lang c -rui -ct 1 -cn faustlpf -es 1 -mcd 16 -mdd 1024 -mdy 33 -single -ftz 0 -vec -lv 0 -vs 32 ------------------------------------------------------------- */ -#ifndef __faustlpf_H__ -#define __faustlpf_H__ - -/******************* BEGIN minarch.h ****************/ - -/************************************************************************ - FAUST Architecture File for generating a very minimal C interface - ************************************************************************/ - -#include "faust/gui/CInterface.h" - -/****************************************************************************** - VECTOR INTRINSICS -*******************************************************************************/ +//------------------------------------------------------------------------------ +// This file was generated using the Faust compiler (https://faust.grame.fr), +// and the Faust post-processor (https://github.com/SpotlightKid/faustpp). +// +// Source: lpf.dsp +// Name: FaustLPF +// Author: Christopher Arndt +// Copyright: Christopher Arndt, 2024 +// License: MIT +// Version: 0.1.0 +// FAUST version: 2.75.10 +// FAUST compilation options: -a /home/chris/tmp/tmp9v2ck7tz.c -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 +//------------------------------------------------------------------------------ -/**************************BEGIN USER SECTION **************************/ + +#include "faustlpf.h" + + + + +//------------------------------------------------------------------------------ +// Begin the Faust code section + + +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +// START INTRINSICS +// END INTRINSICS +// START CLASS CODE #ifndef FAUSTFLOAT #define FAUSTFLOAT float #endif @@ -41,6 +48,7 @@ extern "C" { #define RESTRICT __restrict__ #endif +#include "faust/dsp/fastmath.cpp" #include #include #include @@ -58,16 +66,7 @@ static float faustlpf_faustpower2_f(float value) { #define exp10 __exp10 #endif -typedef struct { - int fSampleRate; - float fConst0; - float fConst1; - float fConst2; - FAUSTFLOAT fHslider0; - float fRec1_perm[4]; - float fConst3; - float fRec0_perm[4]; -} faustlpf; + faustlpf* newfaustlpf() { faustlpf* dsp = (faustlpf*)calloc(1, sizeof(faustlpf)); @@ -80,7 +79,7 @@ void deletefaustlpf(faustlpf* dsp) { void metadatafaustlpf(MetaGlue* m) { m->declare(m->metaInterface, "author", "Christopher Arndt"); - m->declare(m->metaInterface, "compile_options", "-a ./examples/minarch.h -lang c -rui -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 /home/chris/tmp/tmp9v2ck7tz.c -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, "filename", "lpf.dsp"); m->declare(m->metaInterface, "filters.lib/fir:author", "Julius O. Smith III"); @@ -112,7 +111,7 @@ void metadatafaustlpf(MetaGlue* m) { m->declare(m->metaInterface, "platform.lib/name", "Generic Platform Library"); m->declare(m->metaInterface, "platform.lib/version", "1.3.0"); m->declare(m->metaInterface, "signals.lib/name", "Faust Signal Routing Library"); - m->declare(m->metaInterface, "signals.lib/version", "1.5.0"); + m->declare(m->metaInterface, "signals.lib/version", "1.6.0"); m->declare(m->metaInterface, "version", "0.1.0"); } @@ -230,7 +229,7 @@ void computefaustlpf(faustlpf* dsp, int count, FAUSTFLOAT** RESTRICT inputs, FAU { int i; 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 */ @@ -322,7 +321,7 @@ void computefaustlpf(faustlpf* dsp, int count, FAUSTFLOAT** RESTRICT inputs, FAU { int i; 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 */ @@ -383,7 +382,15 @@ void computefaustlpf(faustlpf* dsp, int count, FAUSTFLOAT** RESTRICT inputs, FAU #ifdef __cplusplus } #endif +// END CLASS CODE -/***************************END USER SECTION ***************************/ +#if defined(__GNUC__) +# pragma GCC diagnostic pop #endif + + +//------------------------------------------------------------------------------ +// End the Faust code section + + diff --git a/examples/faustlpf.h b/examples/faustlpf.h new file mode 100644 index 0000000..75f0c56 --- /dev/null +++ b/examples/faustlpf.h @@ -0,0 +1,200 @@ +#ifndef __faustlpf_H__ +#define __faustlpf_H__ + +#ifndef FAUSTFLOAT +#define FAUSTFLOAT float +#endif + +#ifndef FAUSTCLASS +#define FAUSTCLASS faustlpf +#endif + +#if defined(_WIN32) +#define RESTRICT __restrict +#else +#define RESTRICT __restrict__ +#endif + +#include +#include +#include "faust/gui/CInterface.h" + + +typedef struct { + int fSampleRate; + float fConst0; + float fConst1; + float fConst2; + FAUSTFLOAT fHslider0; + float fRec1_perm[4]; + float fConst3; + float fRec0_perm[4]; +} faustlpf; + + +faustlpf* newfaustlpf(); +void deletefaustlpf(faustlpf* dsp); +void metadatafaustlpf(MetaGlue* m); +int getSampleRatefaustlpf(faustlpf* RESTRICT dsp); +int getNumInputsfaustlpf(faustlpf* RESTRICT dsp); +int getNumOutputsfaustlpf(faustlpf* RESTRICT dsp); +void classInitfaustlpf(int sample_rate); +void instanceResetUserInterfacefaustlpf(faustlpf* dsp); +void instanceClearfaustlpf(faustlpf* dsp); +void instanceConstantsfaustlpf(faustlpf* dsp, int sample_rate); +void instanceInitfaustlpf(faustlpf* dsp, int sample_rate); +void initfaustlpf(faustlpf* dsp, int sample_rate); +void buildUserInterfacefaustlpf(faustlpf* dsp, UIGlue* ui_interface); +void computefaustlpf(faustlpf* dsp, int count, FAUSTFLOAT** RESTRICT inputs, FAUSTFLOAT** RESTRICT outputs); + + +int parameter_group(unsigned index) { + switch (index) { + + case 0: + return 0; + + default: + return -1; + } +} + +const char *parameter_label(unsigned index) { + switch (index) { + + case 0: + return "Cutoff"; + + default: + return 0; + } +} + +const char *parameter_short_label(unsigned index) { + switch (index) { + + case 0: + return "Cutoff"; + + default: + return 0; + } +} + +const char *parameter_style(unsigned index) { + switch (index) { + + case 0: { + return "knob"; + } + + default: + return ""; + } +} + +const char *parameter_symbol(unsigned index) { + switch (index) { + + case 0: + return "cutoff"; + + default: + return ""; + } +} + +const char *parameter_unit(unsigned index) { + switch (index) { + + case 0: + return "Hz"; + + default: + return 0; + } +} + + + +bool parameter_is_trigger(unsigned index) { + switch (index) { + + default: + return false; + } +} + +bool parameter_is_boolean(unsigned index) { + switch (index) { + + default: + return false; + } +} + +bool parameter_is_enum(unsigned index) { + switch (index) { + + default: + return false; + } +} + +bool parameter_is_integer(unsigned index) { + switch (index) { + + default: + return false; + } +} + +bool parameter_is_logarithmic(unsigned index) { + switch (index) { + + case 0: + return true; + + default: + return false; + } +} + +float get_parameter(faustlpf* dsp, unsigned index) { + switch (index) { + + case 0: + return dsp->fHslider0; + + default: + (void)dsp; + return 0.0; + } +} + +void set_parameter(faustlpf* dsp, unsigned index, float value) { + switch (index) { + + case 0: + dsp->fHslider0 = value; + break; + + default: + (void)dsp; + (void)value; + break; + } +} + + +float get_cutoff(faustlpf* dsp) { + return dsp->fHslider0; +} + + +void set_cutoff(faustlpf* dsp, float value) { + dsp->fHslider0 = value; +} + + +#endif /* __faustlpf_H__ */ \ No newline at end of file diff --git a/examples/faustlpf.nim b/examples/faustlpf.nim new file mode 100644 index 0000000..be63b06 --- /dev/null +++ b/examples/faustlpf.nim @@ -0,0 +1,33 @@ +{.compile: "faustlpf.c".} + +type + faustlpf* = object + SampleBuffer* = UncheckedArray[cfloat] + + +proc newfaustlpf*(): ptr faustlpf {.importc.} +proc deletefaustlpf*(dsp: ptr faustlpf) {.importc.} +proc initfaustlpf*(dsp: ptr faustlpf, sample_rate: cint) {.importc.} +proc instanceClearfaustlpf*(dsp: ptr faustlpf) {.importc.} +proc computefaustlpf*(dsp: ptr faustlpf, count: cint, inputs, outputs: ptr ptr SampleBuffer) {.importc.} + +proc parameter_group*(index: cuint): cint {.importc} +proc parameter_is_boolean*(index: cuint): bool {.importc} +proc parameter_is_enum*(index: cuint): bool {.importc} +proc parameter_is_integer*(index: cuint): bool {.importc} +proc parameter_is_logarithmic*(index: cuint): bool {.importc} +proc parameter_is_trigger*(index: cuint): bool {.importc} +proc parameter_label*(index: cuint): cstring {.importc} +proc parameter_short_label*(index: cuint): cstring {.importc} +proc parameter_style*(index: cuint): cstring {.importc} +proc parameter_symbol*(index: cuint): cstring {.importc} +proc parameter_unit*(index: cuint): cstring {.importc} + +proc get_parameter*(dsp: ptr faustlpf, index: cuint): cfloat {.importc} +proc set_parameter*(dsp: ptr faustlpf, index: cuint, value: cfloat) {.importc} + + +proc get_cutoff*(dsp: ptr faustlpf): cfloat {.importc} + + +proc set_cutoff*(dsp: ptr faustlpf, value: cfloat) {.importc} diff --git a/examples/faustlpf_plugin.nim b/examples/faustlpf_plugin.nim index 4f82f98..6aabebd 100644 --- a/examples/faustlpf_plugin.nim +++ b/examples/faustlpf_plugin.nim @@ -1,37 +1,21 @@ ## A FAUST standard library 2-pole lowpass filter LV2 plugin import nymph - -{.emit: """#include "lpf.h"""".} +import faustlpf const PluginUri = "urn:nymph:examples:faustlpf" type - faustlpf {.importc, header: "lpf.h".} = object - # struct field representing the value of the FAUST UI element, - # which controls the filter cutoff frequency - fHslider0: cfloat - PluginPort {.pure.} = enum Input, Output, Frequency - SampleBuffer = UncheckedArray[cfloat] - FaustLPFPlugin = object input: ptr SampleBuffer output: ptr SampleBuffer freq: ptr cfloat flt: ptr faustlpf - -# wrap only those functions from the C code, which we actually need -proc newfaustlpf(): ptr faustlpf {.importc.} -proc deletefaustlpf(dsp: ptr faustlpf) {.importc.} -proc initfaustlpf(dsp: ptr faustlpf, sample_rate: cint) {.importc.} -proc instanceClearfaustlpf(dsp: ptr faustlpf) {.importc.} -proc computefaustlpf(dsp: ptr faustlpf, count: cint, inputs, outputs: ptr ptr SampleBuffer) {.importc.} - proc NimMain() {.cdecl, importc.} @@ -66,7 +50,7 @@ proc activate(instance: Lv2Handle) {.cdecl.} = proc run(instance: Lv2Handle; nSamples: cuint) {.cdecl.} = let plug = cast[ptr FaustLPFPlugin](instance) - plug.flt.fHslider0 = plug.freq[] + set_cutoff(plug.flt, plug.freq[]) computefaustlpf(plug.flt, nSamples.cint, addr plug.input, addr plug.output)