Compare commits
8 Commits
af27abbaca
...
1f72523055
Author | SHA1 | Date |
---|---|---|
Christopher Arndt | 1f72523055 | |
Christopher Arndt | 521fefc531 | |
Christopher Arndt | eb814d16c3 | |
Christopher Arndt | f001184fea | |
Christopher Arndt | 75f3ce03b3 | |
Christopher Arndt | 4d60684b07 | |
Christopher Arndt | f71ec0d0df | |
Christopher Arndt | b88f75efce |
|
@ -2,3 +2,4 @@ nimble.paths
|
||||||
*.so
|
*.so
|
||||||
*.dll
|
*.dll
|
||||||
/.lv2/
|
/.lv2/
|
||||||
|
*.code-workspace
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
@prefix bufs: <http://lv2plug.in/ns/ext/buf-size#> .
|
||||||
|
@prefix doap: <http://usefulinc.com/ns/doap#> .
|
||||||
|
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
|
||||||
|
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
|
||||||
|
@prefix opts: <http://lv2plug.in/ns/ext/options#> .
|
||||||
|
@prefix params: <http://lv2plug.in/ns/ext/parameters#> .
|
||||||
|
@prefix props: <http://lv2plug.in/ns/ext/port-props#> .
|
||||||
|
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||||
|
@prefix units: <http://lv2plug.in/ns/extensions/units#> .
|
||||||
|
|
||||||
|
<urn:nymph:examples:faustlpf>
|
||||||
|
a lv2:Plugin , lv2:FilterPlugin , doap:Project ;
|
||||||
|
|
||||||
|
lv2:optionalFeature lv2:hardRTCapable , bufs:boundedBlockLength , opts:options ;
|
||||||
|
|
||||||
|
opts:supportedOption bufs:nominalBlockLength ,
|
||||||
|
bufs:maxBlockLength ,
|
||||||
|
params:sampleRate ;
|
||||||
|
|
||||||
|
lv2:port [
|
||||||
|
a lv2:InputPort, lv2:AudioPort ;
|
||||||
|
lv2:index 0 ;
|
||||||
|
lv2:name "Audio In" ;
|
||||||
|
lv2:symbol "in" ;
|
||||||
|
],
|
||||||
|
[
|
||||||
|
a lv2:OutputPort, lv2:AudioPort ;
|
||||||
|
lv2:index 1 ;
|
||||||
|
lv2:name "Audio Out" ;
|
||||||
|
lv2:symbol "out" ;
|
||||||
|
],
|
||||||
|
[
|
||||||
|
a lv2:InputPort, lv2:ControlPort ;
|
||||||
|
lv2:index 2 ;
|
||||||
|
lv2:name "Cutoff" ;
|
||||||
|
lv2:symbol "cutoff" ;
|
||||||
|
lv2:default 15000.0 ;
|
||||||
|
lv2:minimum 16.0 ;
|
||||||
|
lv2:maximum 15000.0 ;
|
||||||
|
lv2:portProperty props:logarithmic ;
|
||||||
|
units:unit units:hz ;
|
||||||
|
];
|
||||||
|
|
||||||
|
rdfs:comment """
|
||||||
|
A 2-pole lowpass filter from the FAUST standard library.
|
||||||
|
""" ;
|
||||||
|
|
||||||
|
doap:name "nymph faust LPF" ;
|
||||||
|
doap:license <https://spdx.org/licenses/MIT> ;
|
||||||
|
|
||||||
|
doap:maintainer [
|
||||||
|
foaf:name "Christopher Arndt" ;
|
||||||
|
foaf:mbox <mailto:info@chrisarndt.de> ;
|
||||||
|
foaf:homepage <https://gitlab.com/SpotlightKid/nymph> ;
|
||||||
|
] ;
|
||||||
|
|
||||||
|
lv2:microVersion 0 ;
|
||||||
|
lv2:minorVersion 1 .
|
|
@ -0,0 +1,8 @@
|
||||||
|
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
|
||||||
|
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||||
|
|
||||||
|
<urn:nymph:examples:faustlpf>
|
||||||
|
a lv2:Plugin ;
|
||||||
|
lv2:binary <libfaustlpf.so> ;
|
||||||
|
rdfs:seeAlso <faustlpf.ttl> .
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
## A FAUST standard library 2-pole lowpass filter LV2 plugin
|
||||||
|
|
||||||
|
import nymph
|
||||||
|
|
||||||
|
type
|
||||||
|
SampleBuffer = UncheckedArray[cfloat]
|
||||||
|
|
||||||
|
{.emit: "#include \"lpf.h\"".}
|
||||||
|
type
|
||||||
|
faustlpf {.importc, header: "lpf.h".}= object
|
||||||
|
fHslider0: 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 getNumInputsmydsp(dsp: ptr faustlpf): cint {.importc.}
|
||||||
|
#proc getNumOutputsmydsp(dsp: ptr faustlpf): cint {.importc.}
|
||||||
|
#proc getSampleRatefaustlpf(dsp: ptr faustlpf): cint {.importc.}
|
||||||
|
proc computefaustlpf(dsp: ptr faustlpf, count: cint, inputs, outputs: ptr ptr SampleBuffer) {.importc.}
|
||||||
|
|
||||||
|
type
|
||||||
|
PluginPort {.pure.} = enum
|
||||||
|
Input, Output, Frequency
|
||||||
|
|
||||||
|
FaustLPFPlugin = object
|
||||||
|
input: ptr SampleBuffer
|
||||||
|
output: ptr SampleBuffer
|
||||||
|
freq: ptr cfloat
|
||||||
|
flt: ptr faustlpf
|
||||||
|
|
||||||
|
|
||||||
|
const
|
||||||
|
PluginUri = "urn:nymph:examples:faustlpf"
|
||||||
|
minFreq = 16.0
|
||||||
|
maxFreq = 15_000.0
|
||||||
|
|
||||||
|
|
||||||
|
proc instantiate(descriptor: ptr Lv2Descriptor; sampleRate: cdouble;
|
||||||
|
bundlePath: cstring; features: ptr UncheckedArray[ptr Lv2Feature]):
|
||||||
|
Lv2Handle {.cdecl.} =
|
||||||
|
try:
|
||||||
|
let plug = cast[ptr FaustLPFPlugin](createShared(FaustLPFPlugin))
|
||||||
|
plug.flt = newfaustlpf()
|
||||||
|
initfaustlpf(plug.flt, sampleRate.cint)
|
||||||
|
return cast[Lv2Handle](plug)
|
||||||
|
except OutOfMemDefect:
|
||||||
|
return nil
|
||||||
|
|
||||||
|
|
||||||
|
proc connectPort(instance: Lv2Handle; port: cuint;
|
||||||
|
dataLocation: pointer) {.cdecl.} =
|
||||||
|
let plug = cast[ptr FaustLPFPlugin](instance)
|
||||||
|
case cast[PluginPort](port)
|
||||||
|
of PluginPort.Input:
|
||||||
|
plug.input = cast[ptr SampleBuffer](dataLocation)
|
||||||
|
of PluginPort.Output:
|
||||||
|
plug.output = cast[ptr SampleBuffer](dataLocation)
|
||||||
|
of PluginPort.Frequency:
|
||||||
|
plug.freq = cast[ptr cfloat](dataLocation)
|
||||||
|
|
||||||
|
|
||||||
|
proc activate(instance: Lv2Handle) {.cdecl.} =
|
||||||
|
let plug = cast[ptr FaustLPFPlugin](instance)
|
||||||
|
instanceClearfaustlpf(plug.flt)
|
||||||
|
|
||||||
|
|
||||||
|
proc run(instance: Lv2Handle; nSamples: cuint) {.cdecl.} =
|
||||||
|
let plug = cast[ptr FaustLPFPlugin](instance)
|
||||||
|
plug.flt.fHslider0 = plug.freq[].clamp(minFreq, maxFreq)
|
||||||
|
|
||||||
|
computefaustlpf(plug.flt, nSamples.cint, addr plug.input, addr plug.output)
|
||||||
|
|
||||||
|
|
||||||
|
proc deactivate(instance: Lv2Handle) {.cdecl.} =
|
||||||
|
discard
|
||||||
|
|
||||||
|
|
||||||
|
proc cleanup(instance: Lv2Handle) {.cdecl.} =
|
||||||
|
let plug = cast[ptr FaustLPFPlugin](instance)
|
||||||
|
deletefaustlpf(plug.flt)
|
||||||
|
freeShared(plug)
|
||||||
|
|
||||||
|
|
||||||
|
proc extensionData(uri: cstring): pointer {.cdecl.} =
|
||||||
|
return nil
|
||||||
|
|
||||||
|
|
||||||
|
proc NimMain() {.cdecl, importc.}
|
||||||
|
|
||||||
|
|
||||||
|
proc lv2Descriptor(index: cuint): ptr Lv2Descriptor {.
|
||||||
|
cdecl, exportc, dynlib, extern: "lv2_descriptor".} =
|
||||||
|
NimMain()
|
||||||
|
|
||||||
|
if index == 0:
|
||||||
|
result = createShared(Lv2Descriptor)
|
||||||
|
result.uri = cstring(PluginUri)
|
||||||
|
result.instantiate = instantiate
|
||||||
|
result.connectPort = connectPort
|
||||||
|
result.activate = activate
|
||||||
|
result.run = run
|
||||||
|
result.deactivate = deactivate
|
||||||
|
result.cleanup = cleanup
|
||||||
|
result.extensionData = extensionData
|
|
@ -0,0 +1,12 @@
|
||||||
|
declare name "FaustLPF";
|
||||||
|
declare author "Christopher Arndt";
|
||||||
|
declare copyright "Christopher Arndt, 2024";
|
||||||
|
declare license "MIT";
|
||||||
|
declare version "0.1.0";
|
||||||
|
|
||||||
|
import("stdfaust.lib");
|
||||||
|
|
||||||
|
cutoff = hslider("[1] Cutoff [symbol:cutoff] [unit:Hz] [scale:log] [style:knob] [tooltip:Low-pass filter cutoff frequency]",
|
||||||
|
15000, 16, 15000, 0.1) : si.smoo;
|
||||||
|
|
||||||
|
process = fi.lowpass(2, cutoff);
|
|
@ -0,0 +1,395 @@
|
||||||
|
/* ------------------------------------------------------------
|
||||||
|
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 -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 <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "faust/gui/CInterface.h"
|
||||||
|
|
||||||
|
#define max(a,b) ((a < b) ? b : a)
|
||||||
|
#define min(a,b) ((a < b) ? a : b)
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
VECTOR INTRINSICS
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/**************************BEGIN USER SECTION **************************/
|
||||||
|
|
||||||
|
#ifndef FAUSTFLOAT
|
||||||
|
#define FAUSTFLOAT float
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#define RESTRICT __restrict
|
||||||
|
#else
|
||||||
|
#define RESTRICT __restrict__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static float faustlpf_faustpower2_f(float value) {
|
||||||
|
return value * value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef FAUSTCLASS
|
||||||
|
#define FAUSTCLASS faustlpf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#define exp10f __exp10f
|
||||||
|
#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));
|
||||||
|
return dsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deletefaustlpf(faustlpf* dsp) {
|
||||||
|
free(dsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void metadatafaustlpf(MetaGlue* m) {
|
||||||
|
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, "copyright", "Christopher Arndt, 2024");
|
||||||
|
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:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
|
||||||
|
m->declare(m->metaInterface, "filters.lib/fir:license", "MIT-style STK-4.3 license");
|
||||||
|
m->declare(m->metaInterface, "filters.lib/iir:author", "Julius O. Smith III");
|
||||||
|
m->declare(m->metaInterface, "filters.lib/iir:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
|
||||||
|
m->declare(m->metaInterface, "filters.lib/iir:license", "MIT-style STK-4.3 license");
|
||||||
|
m->declare(m->metaInterface, "filters.lib/lowpass0_highpass1", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
|
||||||
|
m->declare(m->metaInterface, "filters.lib/lowpass0_highpass1:author", "Julius O. Smith III");
|
||||||
|
m->declare(m->metaInterface, "filters.lib/lowpass:author", "Julius O. Smith III");
|
||||||
|
m->declare(m->metaInterface, "filters.lib/lowpass:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
|
||||||
|
m->declare(m->metaInterface, "filters.lib/lowpass:license", "MIT-style STK-4.3 license");
|
||||||
|
m->declare(m->metaInterface, "filters.lib/name", "Faust Filters Library");
|
||||||
|
m->declare(m->metaInterface, "filters.lib/tf2:author", "Julius O. Smith III");
|
||||||
|
m->declare(m->metaInterface, "filters.lib/tf2:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
|
||||||
|
m->declare(m->metaInterface, "filters.lib/tf2:license", "MIT-style STK-4.3 license");
|
||||||
|
m->declare(m->metaInterface, "filters.lib/tf2s:author", "Julius O. Smith III");
|
||||||
|
m->declare(m->metaInterface, "filters.lib/tf2s:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
|
||||||
|
m->declare(m->metaInterface, "filters.lib/tf2s:license", "MIT-style STK-4.3 license");
|
||||||
|
m->declare(m->metaInterface, "filters.lib/version", "1.3.0");
|
||||||
|
m->declare(m->metaInterface, "license", "MIT");
|
||||||
|
m->declare(m->metaInterface, "maths.lib/author", "GRAME");
|
||||||
|
m->declare(m->metaInterface, "maths.lib/copyright", "GRAME");
|
||||||
|
m->declare(m->metaInterface, "maths.lib/license", "LGPL with exception");
|
||||||
|
m->declare(m->metaInterface, "maths.lib/name", "Faust Math Library");
|
||||||
|
m->declare(m->metaInterface, "maths.lib/version", "2.8.0");
|
||||||
|
m->declare(m->metaInterface, "name", "FaustLPF");
|
||||||
|
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, "version", "0.1.0");
|
||||||
|
}
|
||||||
|
|
||||||
|
int getSampleRatefaustlpf(faustlpf* RESTRICT dsp) {
|
||||||
|
return dsp->fSampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getNumInputsfaustlpf(faustlpf* RESTRICT dsp) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int getNumOutputsfaustlpf(faustlpf* RESTRICT dsp) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void classInitfaustlpf(int sample_rate) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void instanceResetUserInterfacefaustlpf(faustlpf* dsp) {
|
||||||
|
dsp->fHslider0 = (FAUSTFLOAT)(1.5e+04f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void instanceClearfaustlpf(faustlpf* dsp) {
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int l0;
|
||||||
|
for (l0 = 0; l0 < 4; l0 = l0 + 1) {
|
||||||
|
dsp->fRec1_perm[l0] = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int l1;
|
||||||
|
for (l1 = 0; l1 < 4; l1 = l1 + 1) {
|
||||||
|
dsp->fRec0_perm[l1] = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void instanceConstantsfaustlpf(faustlpf* dsp, int sample_rate) {
|
||||||
|
dsp->fSampleRate = sample_rate;
|
||||||
|
dsp->fConst0 = fminf(1.92e+05f, fmaxf(1.0f, (float)(dsp->fSampleRate)));
|
||||||
|
dsp->fConst1 = 44.1f / dsp->fConst0;
|
||||||
|
dsp->fConst2 = 1.0f - dsp->fConst1;
|
||||||
|
dsp->fConst3 = 3.1415927f / dsp->fConst0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void instanceInitfaustlpf(faustlpf* dsp, int sample_rate) {
|
||||||
|
instanceConstantsfaustlpf(dsp, sample_rate);
|
||||||
|
instanceResetUserInterfacefaustlpf(dsp);
|
||||||
|
instanceClearfaustlpf(dsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initfaustlpf(faustlpf* dsp, int sample_rate) {
|
||||||
|
classInitfaustlpf(sample_rate);
|
||||||
|
instanceInitfaustlpf(dsp, sample_rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void buildUserInterfacefaustlpf(faustlpf* dsp, UIGlue* ui_interface) {
|
||||||
|
ui_interface->openVerticalBox(ui_interface->uiInterface, "FaustLPF");
|
||||||
|
ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider0, "1", "");
|
||||||
|
ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider0, "scale", "log");
|
||||||
|
ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider0, "style", "knob");
|
||||||
|
ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider0, "symbol", "cutoff");
|
||||||
|
ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider0, "tooltip", "Low-pass filter cutoff frequency");
|
||||||
|
ui_interface->declare(ui_interface->uiInterface, &dsp->fHslider0, "unit", "Hz");
|
||||||
|
ui_interface->addHorizontalSlider(ui_interface->uiInterface, "Cutoff", &dsp->fHslider0, (FAUSTFLOAT)1.5e+04f, (FAUSTFLOAT)16.0f, (FAUSTFLOAT)1.5e+04f, (FAUSTFLOAT)0.1f);
|
||||||
|
ui_interface->closeBox(ui_interface->uiInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
void computefaustlpf(faustlpf* dsp, int count, FAUSTFLOAT** RESTRICT inputs, FAUSTFLOAT** RESTRICT outputs) {
|
||||||
|
FAUSTFLOAT* input0_ptr = inputs[0];
|
||||||
|
FAUSTFLOAT* output0_ptr = outputs[0];
|
||||||
|
float fSlow0 = dsp->fConst1 * (float)(dsp->fHslider0);
|
||||||
|
float fRec1_tmp[36];
|
||||||
|
float* fRec1 = &fRec1_tmp[4];
|
||||||
|
float fZec0[32];
|
||||||
|
float fZec1[32];
|
||||||
|
float fZec2[32];
|
||||||
|
float fRec0_tmp[36];
|
||||||
|
float* fRec0 = &fRec0_tmp[4];
|
||||||
|
int vindex = 0;
|
||||||
|
/* Main loop */
|
||||||
|
for (vindex = 0; vindex <= (count - 32); vindex = vindex + 32) {
|
||||||
|
FAUSTFLOAT* input0 = &input0_ptr[vindex];
|
||||||
|
FAUSTFLOAT* output0 = &output0_ptr[vindex];
|
||||||
|
int vsize = 32;
|
||||||
|
/* Recursive loop 0 */
|
||||||
|
/* Pre code */
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int j0;
|
||||||
|
for (j0 = 0; j0 < 4; j0 = j0 + 1) {
|
||||||
|
fRec1_tmp[j0] = dsp->fRec1_perm[j0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Compute code */
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < vsize; i = i + 1) {
|
||||||
|
fRec1[i] = fSlow0 + dsp->fConst2 * fRec1[i - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Post code */
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int j1;
|
||||||
|
for (j1 = 0; j1 < 4; j1 = j1 + 1) {
|
||||||
|
dsp->fRec1_perm[j1] = fRec1_tmp[vsize + j1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Vectorizable loop 1 */
|
||||||
|
/* Compute code */
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < vsize; i = i + 1) {
|
||||||
|
fZec0[i] = tanf(dsp->fConst3 * fRec1[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Vectorizable loop 2 */
|
||||||
|
/* Compute code */
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < vsize; i = i + 1) {
|
||||||
|
fZec1[i] = 1.0f / fZec0[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Vectorizable loop 3 */
|
||||||
|
/* Compute code */
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < vsize; i = i + 1) {
|
||||||
|
fZec2[i] = (fZec1[i] + 1.4142135f) / fZec0[i] + 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Recursive loop 4 */
|
||||||
|
/* Pre code */
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int j2;
|
||||||
|
for (j2 = 0; j2 < 4; j2 = j2 + 1) {
|
||||||
|
fRec0_tmp[j2] = dsp->fRec0_perm[j2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Compute code */
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < vsize; i = i + 1) {
|
||||||
|
fRec0[i] = (float)(input0[i]) - (fRec0[i - 2] * ((fZec1[i] + -1.4142135f) / fZec0[i] + 1.0f) + 2.0f * fRec0[i - 1] * (1.0f - 1.0f / faustlpf_faustpower2_f(fZec0[i]))) / fZec2[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Post code */
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int j3;
|
||||||
|
for (j3 = 0; j3 < 4; j3 = j3 + 1) {
|
||||||
|
dsp->fRec0_perm[j3] = fRec0_tmp[vsize + j3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Vectorizable loop 5 */
|
||||||
|
/* Compute code */
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < vsize; i = i + 1) {
|
||||||
|
output0[i] = (FAUSTFLOAT)((fRec0[i - 2] + fRec0[i] + 2.0f * fRec0[i - 1]) / fZec2[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Remaining frames */
|
||||||
|
if (vindex < count) {
|
||||||
|
FAUSTFLOAT* input0 = &input0_ptr[vindex];
|
||||||
|
FAUSTFLOAT* output0 = &output0_ptr[vindex];
|
||||||
|
int vsize = count - vindex;
|
||||||
|
/* Recursive loop 0 */
|
||||||
|
/* Pre code */
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int j0;
|
||||||
|
for (j0 = 0; j0 < 4; j0 = j0 + 1) {
|
||||||
|
fRec1_tmp[j0] = dsp->fRec1_perm[j0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Compute code */
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < vsize; i = i + 1) {
|
||||||
|
fRec1[i] = fSlow0 + dsp->fConst2 * fRec1[i - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Post code */
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int j1;
|
||||||
|
for (j1 = 0; j1 < 4; j1 = j1 + 1) {
|
||||||
|
dsp->fRec1_perm[j1] = fRec1_tmp[vsize + j1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Vectorizable loop 1 */
|
||||||
|
/* Compute code */
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < vsize; i = i + 1) {
|
||||||
|
fZec0[i] = tanf(dsp->fConst3 * fRec1[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Vectorizable loop 2 */
|
||||||
|
/* Compute code */
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < vsize; i = i + 1) {
|
||||||
|
fZec1[i] = 1.0f / fZec0[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Vectorizable loop 3 */
|
||||||
|
/* Compute code */
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < vsize; i = i + 1) {
|
||||||
|
fZec2[i] = (fZec1[i] + 1.4142135f) / fZec0[i] + 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Recursive loop 4 */
|
||||||
|
/* Pre code */
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int j2;
|
||||||
|
for (j2 = 0; j2 < 4; j2 = j2 + 1) {
|
||||||
|
fRec0_tmp[j2] = dsp->fRec0_perm[j2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Compute code */
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < vsize; i = i + 1) {
|
||||||
|
fRec0[i] = (float)(input0[i]) - (fRec0[i - 2] * ((fZec1[i] + -1.4142135f) / fZec0[i] + 1.0f) + 2.0f * fRec0[i - 1] * (1.0f - 1.0f / faustlpf_faustpower2_f(fZec0[i]))) / fZec2[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Post code */
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int j3;
|
||||||
|
for (j3 = 0; j3 < 4; j3 = j3 + 1) {
|
||||||
|
dsp->fRec0_perm[j3] = fRec0_tmp[vsize + j3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Vectorizable loop 5 */
|
||||||
|
/* Compute code */
|
||||||
|
/* C99 loop */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < vsize; i = i + 1) {
|
||||||
|
output0[i] = (FAUSTFLOAT)((fRec0[i - 2] + fRec0[i] + 2.0f * fRec0[i - 1]) / fZec2[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/***************************END USER SECTION ***************************/
|
||||||
|
|
||||||
|
#endif
|
|
@ -19,6 +19,11 @@ type
|
||||||
map: ptr UridMap
|
map: ptr UridMap
|
||||||
midi_urid: Urid
|
midi_urid: Urid
|
||||||
|
|
||||||
|
MidiEvent = object
|
||||||
|
size: uint32
|
||||||
|
frames: int64
|
||||||
|
data: ptr UncheckedArray[byte]
|
||||||
|
|
||||||
|
|
||||||
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]):
|
||||||
|
@ -26,7 +31,8 @@ proc instantiate(descriptor: ptr Lv2Descriptor; sampleRate: cdouble;
|
||||||
let amp: ptr MidiTransposePlugin = createShared(MidiTransposePlugin)
|
let amp: ptr MidiTransposePlugin = createShared(MidiTransposePlugin)
|
||||||
amp.map = cast[ptr UridMap](lv2FeaturesData(features, lv2UridMap))
|
amp.map = cast[ptr UridMap](lv2FeaturesData(features, lv2UridMap))
|
||||||
|
|
||||||
if amp.map == nil:
|
if amp.map.isNil:
|
||||||
|
freeShared(amp)
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
amp.midi_urid = amp.map.map(amp.map.handle, lv2MidiMidiEvent)
|
amp.midi_urid = amp.map.map(amp.map.handle, lv2MidiMidiEvent)
|
|
@ -0,0 +1,25 @@
|
||||||
|
/******************* BEGIN minarch.h ****************/
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
FAUST Architecture File for generating a very minimal C interface
|
||||||
|
************************************************************************/
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "faust/gui/CInterface.h"
|
||||||
|
|
||||||
|
#define max(a,b) ((a < b) ? b : a)
|
||||||
|
#define min(a,b) ((a < b) ? a : b)
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
VECTOR INTRINSICS
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
<<includeIntrinsic>>
|
||||||
|
|
||||||
|
/**************************BEGIN USER SECTION **************************/
|
||||||
|
|
||||||
|
<<includeclass>>
|
||||||
|
|
||||||
|
/***************************END USER SECTION ***************************/
|
|
@ -1,8 +0,0 @@
|
||||||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
|
|
||||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
|
||||||
|
|
||||||
<urn:nymph:examples:multimode-filter>
|
|
||||||
a lv2:Plugin ;
|
|
||||||
lv2:binary <libmultimode_filter.so> ;
|
|
||||||
rdfs:seeAlso <multimode_filter.ttl> .
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
|
||||||
|
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||||
|
|
||||||
|
<urn:nymph:examples:multimodefilter>
|
||||||
|
a lv2:Plugin ;
|
||||||
|
lv2:binary <libmultimodefilter.so> ;
|
||||||
|
rdfs:seeAlso <multimodefilter.ttl> .
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||||
@prefix units: <http://lv2plug.in/ns/extensions/units#> .
|
@prefix units: <http://lv2plug.in/ns/extensions/units#> .
|
||||||
|
|
||||||
<urn:nymph:examples:multimode-filter>
|
<urn:nymph:examples:multimodefilter>
|
||||||
a lv2:Plugin, lv2:AmplifierPlugin , doap:Project ;
|
a lv2:Plugin , lv2:FilterPlugin , doap:Project ;
|
||||||
|
|
||||||
lv2:optionalFeature lv2:hardRTCapable , bufs:boundedBlockLength , opts:options ;
|
lv2:optionalFeature lv2:hardRTCapable , bufs:boundedBlockLength , opts:options ;
|
||||||
|
|
|
@ -5,7 +5,7 @@ import nymph
|
||||||
import paramsmooth
|
import paramsmooth
|
||||||
import svf
|
import svf
|
||||||
|
|
||||||
const PluginUri = "urn:nymph:examples:multimode-filter"
|
const PluginUri = "urn:nymph:examples:multimodefilter"
|
||||||
|
|
||||||
type
|
type
|
||||||
SampleBuffer = UncheckedArray[cfloat]
|
SampleBuffer = UncheckedArray[cfloat]
|
||||||
|
@ -19,7 +19,7 @@ type
|
||||||
cutoff: ptr cfloat
|
cutoff: ptr cfloat
|
||||||
q: ptr cfloat
|
q: ptr cfloat
|
||||||
mode: ptr cfloat
|
mode: ptr cfloat
|
||||||
svf: FilterSV
|
svf: SVFilter
|
||||||
smoothCutoff: ParamSmooth
|
smoothCutoff: ParamSmooth
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ proc instantiate(descriptor: ptr Lv2Descriptor; sampleRate: cdouble;
|
||||||
Lv2Handle {.cdecl.} =
|
Lv2Handle {.cdecl.} =
|
||||||
try:
|
try:
|
||||||
let plug = createShared(SVFPlugin)
|
let plug = createShared(SVFPlugin)
|
||||||
plug.svf = initFilterSV(fmLowPass, sampleRate)
|
plug.svf = initSVFilter(fmLowPass, sampleRate)
|
||||||
plug.smoothCutoff = initParamSmooth(20.0, sampleRate)
|
plug.smoothCutoff = initParamSmooth(20.0, sampleRate)
|
||||||
return cast[Lv2Handle](plug)
|
return cast[Lv2Handle](plug)
|
||||||
except OutOfMemDefect:
|
except OutOfMemDefect:
|
|
@ -9,32 +9,32 @@ type
|
||||||
FilterMode* = enum
|
FilterMode* = enum
|
||||||
fmLowPass, fmHighPass, fmBandPass, fmBandReject
|
fmLowPass, fmHighPass, fmBandPass, fmBandReject
|
||||||
|
|
||||||
FilterSV* = object
|
SVFilter* = object
|
||||||
mode: FilterMode
|
mode: FilterMode
|
||||||
cutoff, q, lowPass, hiPass, bandPass, bandReject, a, b, maxCutoff: float
|
cutoff, q, lowPass, hiPass, bandPass, bandReject, a, b, maxCutoff: float
|
||||||
sampleRate: float64
|
sampleRate: float64
|
||||||
needs_update: bool
|
needsUpdate: bool
|
||||||
|
|
||||||
|
|
||||||
proc reset*(self: var FilterSV) =
|
proc reset*(self: var SVFilter) =
|
||||||
self.lowPass = 0.0
|
self.lowPass = 0.0
|
||||||
self.hiPass = 0.0
|
self.hiPass = 0.0
|
||||||
self.bandPass = 0.0
|
self.bandPass = 0.0
|
||||||
self.bandReject = 0.0
|
self.bandReject = 0.0
|
||||||
|
|
||||||
|
|
||||||
proc initFilterSV*(mode: FilterMode = fmLowPass, sampleRate: float64 = 48_000.0): FilterSV =
|
proc initSVFilter*(mode: FilterMode = fmLowPass, sampleRate: float64 = 48_000.0): SVFilter =
|
||||||
result.mode = mode
|
result.mode = mode
|
||||||
result.sampleRate = sampleRate
|
result.sampleRate = sampleRate
|
||||||
result.reset()
|
result.reset()
|
||||||
result.a = 0.0
|
result.a = 0.0
|
||||||
result.b = 0.0
|
result.b = 0.0
|
||||||
result.maxCutoff = sampleRate / 6.0
|
result.maxCutoff = sampleRate / 6.0
|
||||||
result.needs_update = true
|
result.needsUpdate = true
|
||||||
|
|
||||||
|
|
||||||
proc calcCoef*(self: var FilterSV) =
|
proc calcCoef*(self: var SVFilter) =
|
||||||
if self.needs_update:
|
if self.needsUpdate:
|
||||||
self.a = 2.0 * sin(PI * self.cutoff / self.sampleRate)
|
self.a = 2.0 * sin(PI * self.cutoff / self.sampleRate)
|
||||||
|
|
||||||
if self.q > 0.0:
|
if self.q > 0.0:
|
||||||
|
@ -42,36 +42,36 @@ proc calcCoef*(self: var FilterSV) =
|
||||||
else:
|
else:
|
||||||
self.b = 0.0
|
self.b = 0.0
|
||||||
|
|
||||||
self.needs_update = false
|
self.needsUpdate = false
|
||||||
|
|
||||||
|
|
||||||
proc setCutoff*(self: var FilterSV, cutoff: float) =
|
proc setCutoff*(self: var SVFilter, cutoff: float) =
|
||||||
let fc = min(self.maxCutoff, cutoff)
|
let fc = min(self.maxCutoff, cutoff)
|
||||||
|
|
||||||
if fc != self.cutoff:
|
if fc != self.cutoff:
|
||||||
self.cutoff = fc
|
self.cutoff = fc
|
||||||
self.needs_update = true
|
self.needsUpdate = true
|
||||||
|
|
||||||
|
|
||||||
proc setQ*(self: var FilterSV, q: float) =
|
proc setQ*(self: var SVFilter, q: float) =
|
||||||
if q != self.q:
|
if q != self.q:
|
||||||
self.q = q
|
self.q = q
|
||||||
self.needs_update = true
|
self.needsUpdate = true
|
||||||
|
|
||||||
|
|
||||||
proc setMode*(self: var FilterSV, mode: FilterMode) =
|
proc setMode*(self: var SVFilter, mode: FilterMode) =
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
|
|
||||||
|
|
||||||
proc setSampleRate*(self: var FilterSV, sampleRate: float) =
|
proc setSampleRate*(self: var SVFilter, sampleRate: float) =
|
||||||
if sampleRate != self.sampleRate:
|
if sampleRate != self.sampleRate:
|
||||||
self.sampleRate = sampleRate
|
self.sampleRate = sampleRate
|
||||||
self.needs_update = true
|
self.needsUpdate = true
|
||||||
self.reset()
|
self.reset()
|
||||||
self.calcCoef()
|
self.calcCoef()
|
||||||
|
|
||||||
|
|
||||||
proc process*(self: var FilterSV, sample: float): float =
|
proc process*(self: var SVFilter, sample: float): float =
|
||||||
self.lowPass += self.a * self.bandPass
|
self.lowPass += self.a * self.bandPass
|
||||||
self.hiPass = sample - (self.lowPass + (self.b * self.bandPass))
|
self.hiPass = sample - (self.lowPass + (self.b * self.bandPass))
|
||||||
self.bandPass += self.a * self.hiPass
|
self.bandPass += self.a * self.hiPass
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
|
||||||
|
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||||
|
|
||||||
|
<urn:nymph:examples:tiltfilter>
|
||||||
|
a lv2:Plugin ;
|
||||||
|
lv2:binary <libtiltfilter.so> ;
|
||||||
|
rdfs:seeAlso <tiltfilter.ttl> .
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
@prefix bufs: <http://lv2plug.in/ns/ext/buf-size#> .
|
||||||
|
@prefix doap: <http://usefulinc.com/ns/doap#> .
|
||||||
|
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
|
||||||
|
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
|
||||||
|
@prefix opts: <http://lv2plug.in/ns/ext/options#> .
|
||||||
|
@prefix params: <http://lv2plug.in/ns/ext/parameters#> .
|
||||||
|
@prefix props: <http://lv2plug.in/ns/ext/port-props#> .
|
||||||
|
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
||||||
|
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||||
|
@prefix units: <http://lv2plug.in/ns/extensions/units#> .
|
||||||
|
|
||||||
|
<urn:nymph:examples:tiltfilter>
|
||||||
|
a lv2:Plugin , lv2:FilterPlugin , doap:Project ;
|
||||||
|
|
||||||
|
lv2:optionalFeature lv2:hardRTCapable , bufs:boundedBlockLength , opts:options ;
|
||||||
|
|
||||||
|
opts:supportedOption bufs:nominalBlockLength ,
|
||||||
|
bufs:maxBlockLength ,
|
||||||
|
params:sampleRate ;
|
||||||
|
|
||||||
|
lv2:port [
|
||||||
|
a lv2:InputPort, lv2:AudioPort ;
|
||||||
|
lv2:index 0 ;
|
||||||
|
lv2:name "Audio In" ;
|
||||||
|
lv2:symbol "in" ;
|
||||||
|
],
|
||||||
|
[
|
||||||
|
a lv2:OutputPort, lv2:AudioPort ;
|
||||||
|
lv2:index 1 ;
|
||||||
|
lv2:name "Audio Out" ;
|
||||||
|
lv2:symbol "out" ;
|
||||||
|
],
|
||||||
|
[
|
||||||
|
a lv2:InputPort, lv2:ControlPort ;
|
||||||
|
lv2:index 2 ;
|
||||||
|
lv2:name "Cutoff" ;
|
||||||
|
lv2:symbol "cutoff" ;
|
||||||
|
lv2:default 10000.0 ;
|
||||||
|
lv2:minimum 20.0 ;
|
||||||
|
lv2:maximum 20000.0 ;
|
||||||
|
units:unit units:hz ;
|
||||||
|
],
|
||||||
|
[
|
||||||
|
a lv2:InputPort, lv2:ControlPort ;
|
||||||
|
lv2:index 3 ;
|
||||||
|
lv2:name "Steepness" ;
|
||||||
|
lv2:symbol "steepness" ;
|
||||||
|
lv2:default 1.0 ;
|
||||||
|
lv2:minimum 0.0 ;
|
||||||
|
lv2:maximum 1.0 ;
|
||||||
|
],
|
||||||
|
[
|
||||||
|
a lv2:InputPort, lv2:ControlPort ;
|
||||||
|
lv2:index 4 ;
|
||||||
|
lv2:name "Filter mode" ;
|
||||||
|
lv2:symbol "mode" ;
|
||||||
|
lv2:default 0 ;
|
||||||
|
lv2:minimum 0 ;
|
||||||
|
lv2:maximum 2 ;
|
||||||
|
lv2:portProperty lv2:enumeration, lv2:integer ;
|
||||||
|
lv2:scalePoint [
|
||||||
|
rdfs:label "Lowpass" ;
|
||||||
|
rdf:value 0 ;
|
||||||
|
],
|
||||||
|
[
|
||||||
|
rdfs:label "Highpass" ;
|
||||||
|
rdf:value 1 ;
|
||||||
|
],
|
||||||
|
[
|
||||||
|
rdfs:label "Bandpass" ;
|
||||||
|
rdf:value 2;
|
||||||
|
] ;
|
||||||
|
];
|
||||||
|
|
||||||
|
rdfs:comment """
|
||||||
|
A tilt EQ audio filter.
|
||||||
|
""" ;
|
||||||
|
|
||||||
|
doap:name "nymph tilt filter" ;
|
||||||
|
doap:license <https://spdx.org/licenses/MIT> ;
|
||||||
|
|
||||||
|
doap:maintainer [
|
||||||
|
foaf:name "Christopher Arndt" ;
|
||||||
|
foaf:mbox <mailto:info@chrisarndt.de> ;
|
||||||
|
foaf:homepage <https://gitlab.com/SpotlightKid/nymph> ;
|
||||||
|
] ;
|
||||||
|
|
||||||
|
lv2:microVersion 0 ;
|
||||||
|
lv2:minorVersion 1 .
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
##
|
||||||
|
## Tilt Filter
|
||||||
|
##
|
||||||
|
## Nim translation of this Rust implementation:
|
||||||
|
##
|
||||||
|
## https://github.com/ardura/Actuate/blob/main/src/fx/ArduraFilter.rs
|
||||||
|
##
|
||||||
|
## Inspired by https://www.musicdsp.org/en/latest/Filters/267-simple-tilt-equalizer.html
|
||||||
|
## Lowpass, Bandpass, Highpass based off tilt filter code
|
||||||
|
|
||||||
|
import math
|
||||||
|
|
||||||
|
const
|
||||||
|
slopeNeg = -60.0
|
||||||
|
amp = 6.0 / ln(2.0)
|
||||||
|
denorm = pow(10.0, -30.0)
|
||||||
|
minFreq = 20.0
|
||||||
|
maxFreq = 20_000.0
|
||||||
|
|
||||||
|
type
|
||||||
|
FilterMode* = enum
|
||||||
|
fmLowPass, fmBandPass, fmHighPass
|
||||||
|
|
||||||
|
TiltFilter* = object
|
||||||
|
# Filter parameters
|
||||||
|
sampleRate: float64
|
||||||
|
centerFreq: float
|
||||||
|
steepness: float
|
||||||
|
mode: FilterMode
|
||||||
|
# Filter tracking / internal
|
||||||
|
needsUpdate: bool
|
||||||
|
sampleRateX3: float64
|
||||||
|
lowGain: float
|
||||||
|
highGain: float
|
||||||
|
a: float
|
||||||
|
b: float
|
||||||
|
lpOut: float
|
||||||
|
# Band pass separate vars
|
||||||
|
bandALow: float
|
||||||
|
bandBLow: float
|
||||||
|
bandOutLow: float
|
||||||
|
bandAHigh: float
|
||||||
|
bandBHigh: float
|
||||||
|
bandOutHigh: float
|
||||||
|
|
||||||
|
|
||||||
|
# Super useful function to scale an sample 0-1 into other ranges
|
||||||
|
proc scaleRange(sample, minOutput, maxOutput: float): float =
|
||||||
|
result = clamp(sample * (maxOutput - minOutput) + minOutput, minOutput, maxOutput)
|
||||||
|
|
||||||
|
|
||||||
|
proc initTiltFilter*(centerFreq, steepness: float, mode: FilterMode = fmLowPass, sampleRate: float64 = 48_000.0): TiltFilter =
|
||||||
|
let sampleRateX3 = 3.0 * sampleRate
|
||||||
|
|
||||||
|
case mode:
|
||||||
|
# These are the gains for the slopes when math happens later
|
||||||
|
of fmLowPass:
|
||||||
|
result.lowGain = exp(0.0 / amp) - 1.0
|
||||||
|
result.highGain = exp(slopeNeg / amp) - 1.0
|
||||||
|
of fmBandPass:
|
||||||
|
result.lowGain = exp(0.0 / amp) - 1.0
|
||||||
|
result.highGain = exp(slopeNeg / amp) - 1.0
|
||||||
|
of fmHighPass:
|
||||||
|
result.lowGain = exp(slopeNeg / amp) - 1.0
|
||||||
|
result.highGain = exp(0.0 / amp) - 1.0
|
||||||
|
|
||||||
|
let omega = 2.0 * PI * centerFreq
|
||||||
|
let n = 1.0 / (scaleRange(steepness, 0.98, 1.2) * (sampleRateX3 + omega))
|
||||||
|
result.a = 2.0 * omega * n
|
||||||
|
result.bandALow = result.a
|
||||||
|
result.bandAHigh = result.a
|
||||||
|
result.b = (sampleRateX3 - omega) * n
|
||||||
|
result.bandBLow = result.b
|
||||||
|
result.bandBHigh = result.b
|
||||||
|
result.lpOut = 0.0
|
||||||
|
result.bandOutLow = 0.0
|
||||||
|
result.bandOutHigh = 0.0
|
||||||
|
result.centerFreq = centerFreq
|
||||||
|
result.sampleRateX3 = sampleRateX3
|
||||||
|
result.steepness = steepness
|
||||||
|
result.sampleRate = sampleRate
|
||||||
|
result.mode = mode
|
||||||
|
result.needsUpdate = true
|
||||||
|
|
||||||
|
|
||||||
|
proc setMode*(self: var TiltFilter, mode: FilterMode) =
|
||||||
|
if mode != self.mode:
|
||||||
|
self.mode = mode
|
||||||
|
self.needsUpdate = true
|
||||||
|
|
||||||
|
|
||||||
|
proc setCenterFreq*(self: var TiltFilter, value: float) =
|
||||||
|
let freq = value.clamp(minFreq, maxFreq)
|
||||||
|
|
||||||
|
if freq != self.centerFreq:
|
||||||
|
self.centerFreq = freq
|
||||||
|
self.needsUpdate = true
|
||||||
|
|
||||||
|
|
||||||
|
proc setSteepness*(self: var TiltFilter, value: float) =
|
||||||
|
let steepness = value.clamp(0.0, 1.0)
|
||||||
|
|
||||||
|
if steepness != self.steepness:
|
||||||
|
self.steepness = steepness
|
||||||
|
self.needsUpdate = true
|
||||||
|
|
||||||
|
|
||||||
|
proc setSampleRate*(self: var TiltFilter, sampleRate: float) =
|
||||||
|
if sampleRate != self.sampleRate:
|
||||||
|
self.sampleRate = sampleRate
|
||||||
|
self.sampleRateX3 = self.sampleRate * 3.0
|
||||||
|
self.needsUpdate = true
|
||||||
|
|
||||||
|
|
||||||
|
proc reset*(self: var TiltFilter) =
|
||||||
|
discard
|
||||||
|
|
||||||
|
|
||||||
|
proc update*(self: var TiltFilter) =
|
||||||
|
if self.needsUpdate:
|
||||||
|
case self.mode:
|
||||||
|
of fmLowPass:
|
||||||
|
let omega = 2.0 * PI * self.centerFreq
|
||||||
|
let n = 1.0 / (scaleRange(self.steepness, 0.98, 1.2) * (self.sample_rate_x3 + omega))
|
||||||
|
self.b = (self.sampleRateX3 - omega) * n
|
||||||
|
self.lowGain = exp(0.0 / amp) - 1.0
|
||||||
|
self.highGain = exp(slopeNeg / amp) - 1.0
|
||||||
|
of fmBandPass:
|
||||||
|
let width = self.steepness * self.steepness * 500.0
|
||||||
|
|
||||||
|
let lowOmega = 2.0 * PI * (self.centerFreq - width).clamp(20.0, 16_000.0)
|
||||||
|
let lowN = 1.0 / (scaleRange(self.steepness, 0.98, 1.2) * (self.sampleRateX3 + lowOmega))
|
||||||
|
self.bandALow = 2.0 * lowOmega * lowN
|
||||||
|
self.bandBLow = (self.sampleRateX3 - lowOmega) * lowN
|
||||||
|
|
||||||
|
let highOmega = 2.0 * PI * (self.centerFreq + width).clamp(20.0, 16_000.0);
|
||||||
|
let highN = 1.0 / (scaleRange(self.steepness, 0.98, 1.2) * (self.sampleRateX3 + highOmega))
|
||||||
|
self.bandAHigh = 2.0 * highOmega * highN
|
||||||
|
self.bandBHigh = (self.sampleRateX3 - highOmega) * highN
|
||||||
|
|
||||||
|
self.lowGain = exp(0.0 / amp) - 1.0
|
||||||
|
self.highGain = exp(slopeNeg / amp) - 1.0
|
||||||
|
of fmHighPass:
|
||||||
|
let omega = 2.0 * PI * self.centerFreq
|
||||||
|
let n = 1.0 / (scaleRange(self.steepness, 0.98, 1.2) * (self.sampleRateX3 + omega))
|
||||||
|
self.a = 2.0 * omega * n
|
||||||
|
self.b = (self.sampleRateX3 - omega) * n
|
||||||
|
self.lowGain = exp(slopeNeg / amp) - 1.0
|
||||||
|
self.highGain = exp(0.0 / amp) - 1.0
|
||||||
|
|
||||||
|
self.needsUpdate = false
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## Process the input sample using the tilt filter
|
||||||
|
##
|
||||||
|
proc process*(self: var TiltFilter, sample: float): float =
|
||||||
|
if self.mode == fmBandPass:
|
||||||
|
self.bandOutLow = self.bandALow * sample + self.bandBLow * self.bandOutLow
|
||||||
|
let temp = sample + self.highGain * self.bandOutLow + self.lowGain * (sample - self.bandOutLow)
|
||||||
|
self.bandOutHigh = self.bandAHigh * temp + self.bandBHigh * self.bandOutHigh
|
||||||
|
result = temp + self.lowGain * self.bandOutHigh + self.highGain * (temp - self.bandOutHigh) + denorm
|
||||||
|
else:
|
||||||
|
self.lpOut = self.a * sample + self.b * self.lpOut;
|
||||||
|
result = sample + self.lowGain * self.lpOut + self.highGain * (sample - self.lpOut) + denorm
|
|
@ -0,0 +1,104 @@
|
||||||
|
## A tilt EQ / filter LV2 plugin
|
||||||
|
|
||||||
|
import nymph
|
||||||
|
|
||||||
|
import paramsmooth
|
||||||
|
import tiltfilter
|
||||||
|
|
||||||
|
const
|
||||||
|
PluginUri = "urn:nymph:examples:tiltfilter"
|
||||||
|
minFreq = 20.0
|
||||||
|
maxFreq = 20_000.0
|
||||||
|
|
||||||
|
type
|
||||||
|
SampleBuffer = UncheckedArray[cfloat]
|
||||||
|
|
||||||
|
PluginPort {.pure.} = enum
|
||||||
|
Input, Output, Frequency, Steepness, Mode
|
||||||
|
|
||||||
|
TiltFilterPlugin = object
|
||||||
|
input: ptr SampleBuffer
|
||||||
|
output: ptr SampleBuffer
|
||||||
|
freq: ptr cfloat
|
||||||
|
steepness: ptr cfloat
|
||||||
|
mode: ptr cfloat
|
||||||
|
flt: TiltFilter
|
||||||
|
smoothFreq: ParamSmooth
|
||||||
|
|
||||||
|
|
||||||
|
proc instantiate(descriptor: ptr Lv2Descriptor; sampleRate: cdouble;
|
||||||
|
bundlePath: cstring; features: ptr UncheckedArray[ptr Lv2Feature]):
|
||||||
|
Lv2Handle {.cdecl.} =
|
||||||
|
try:
|
||||||
|
let plug = createShared(TiltFilterPlugin)
|
||||||
|
plug.flt = initTiltFilter(10_000.0, 1.0, fmLowPass, sampleRate)
|
||||||
|
plug.smoothFreq = initParamSmooth(20.0, sampleRate)
|
||||||
|
return cast[Lv2Handle](plug)
|
||||||
|
except OutOfMemDefect:
|
||||||
|
return nil
|
||||||
|
|
||||||
|
|
||||||
|
proc connectPort(instance: Lv2Handle; port: cuint;
|
||||||
|
dataLocation: pointer) {.cdecl.} =
|
||||||
|
let plug = cast[ptr TiltFilterPlugin](instance)
|
||||||
|
case cast[PluginPort](port)
|
||||||
|
of PluginPort.Input:
|
||||||
|
plug.input = cast[ptr SampleBuffer](dataLocation)
|
||||||
|
of PluginPort.Output:
|
||||||
|
plug.output = cast[ptr SampleBuffer](dataLocation)
|
||||||
|
of PluginPort.Frequency:
|
||||||
|
plug.freq = cast[ptr cfloat](dataLocation)
|
||||||
|
of PluginPort.Steepness:
|
||||||
|
plug.steepness = cast[ptr cfloat](dataLocation)
|
||||||
|
of PluginPort.Mode:
|
||||||
|
plug.mode = cast[ptr cfloat](dataLocation)
|
||||||
|
|
||||||
|
|
||||||
|
proc activate(instance: Lv2Handle) {.cdecl.} =
|
||||||
|
let plug = cast[ptr TiltFilterPlugin](instance)
|
||||||
|
plug.flt.reset()
|
||||||
|
|
||||||
|
|
||||||
|
proc run(instance: Lv2Handle; nSamples: cuint) {.cdecl.} =
|
||||||
|
let plug = cast[ptr TiltFilterPlugin](instance)
|
||||||
|
let freq = plug.freq[].clamp(minFreq, maxFreq)
|
||||||
|
|
||||||
|
plug.flt.setMode(plug.mode[].clamp(0.0, 2.0).FilterMode)
|
||||||
|
plug.flt.setSteepness(plug.steepness[])
|
||||||
|
|
||||||
|
for pos in 0 ..< nSamples:
|
||||||
|
plug.flt.setCenterFreq(plug.smoothFreq.process(freq))
|
||||||
|
plug.flt.update()
|
||||||
|
plug.output[pos] = plug.flt.process(plug.input[pos])
|
||||||
|
|
||||||
|
|
||||||
|
proc deactivate(instance: Lv2Handle) {.cdecl.} =
|
||||||
|
discard
|
||||||
|
|
||||||
|
|
||||||
|
proc cleanup(instance: Lv2Handle) {.cdecl.} =
|
||||||
|
freeShared(cast[ptr TiltFilterPlugin](instance))
|
||||||
|
|
||||||
|
|
||||||
|
proc extensionData(uri: cstring): pointer {.cdecl.} =
|
||||||
|
return nil
|
||||||
|
|
||||||
|
|
||||||
|
proc NimMain() {.cdecl, importc.}
|
||||||
|
|
||||||
|
|
||||||
|
proc lv2Descriptor(index: cuint): ptr Lv2Descriptor {.
|
||||||
|
cdecl, exportc, dynlib, extern: "lv2_descriptor".} =
|
||||||
|
NimMain()
|
||||||
|
|
||||||
|
if index == 0:
|
||||||
|
result = createShared(Lv2Descriptor)
|
||||||
|
result.uri = cstring(PluginUri)
|
||||||
|
result.instantiate = instantiate
|
||||||
|
result.connectPort = connectPort
|
||||||
|
result.activate = activate
|
||||||
|
result.run = run
|
||||||
|
result.deactivate = deactivate
|
||||||
|
result.cleanup = cleanup
|
||||||
|
result.extensionData = extensionData
|
||||||
|
|
10
nymph.nimble
10
nymph.nimble
|
@ -25,8 +25,10 @@ type Example = tuple
|
||||||
|
|
||||||
const examples = to_table({
|
const examples = to_table({
|
||||||
"amp": "urn:nymph:examples:amp",
|
"amp": "urn:nymph:examples:amp",
|
||||||
"multimode_filter": "urn:nymph:examples:multimode-filter",
|
"faustlpf": "urn:nymph:examples:faustlpf",
|
||||||
"miditranspose": "urn:nymph:examples:miditranspose",
|
"miditranspose": "urn:nymph:examples:miditranspose",
|
||||||
|
"multimodefilter": "urn:nymph:examples:multimodefilter",
|
||||||
|
"tiltfilter": "urn:nymph:examples:tiltfilter",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,7 +50,7 @@ proc getExample(task_name: string): Example =
|
||||||
result.name = changeFileExt(args[^1], "")
|
result.name = changeFileExt(args[^1], "")
|
||||||
|
|
||||||
let examplesDir = thisDir() / "examples"
|
let examplesDir = thisDir() / "examples"
|
||||||
result.source = examplesDir / changeFileExt(result.name, "nim")
|
result.source = examplesDir / result.name & "_plugin.nim"
|
||||||
|
|
||||||
if not fileExists(result.source):
|
if not fileExists(result.source):
|
||||||
quit(&"Example '{result.name}' not found.")
|
quit(&"Example '{result.name}' not found.")
|
||||||
|
@ -70,6 +72,9 @@ task build_ex, "Build given example plugin":
|
||||||
switch("mm", "arc")
|
switch("mm", "arc")
|
||||||
switch("out", ex.dll)
|
switch("out", ex.dll)
|
||||||
|
|
||||||
|
when defined(gcc):
|
||||||
|
switch("passC", "-fvisibility=hidden")
|
||||||
|
|
||||||
when not defined(release) and not defined(debug):
|
when not defined(release) and not defined(debug):
|
||||||
echo &"Compiling plugin {ex.name} in release mode."
|
echo &"Compiling plugin {ex.name} in release mode."
|
||||||
switch("define", "release")
|
switch("define", "release")
|
||||||
|
@ -113,4 +118,3 @@ task lv2bm, "Run lv2bm benchmark on given example plugin":
|
||||||
exec(&"lv2bm --full-test -i white \"{ex.uri}\"")
|
exec(&"lv2bm --full-test -i white \"{ex.uri}\"")
|
||||||
else:
|
else:
|
||||||
echo &"Example '{ex.name}' shared library not found. Use task 'build_ex' to build it."
|
echo &"Example '{ex.name}' shared library not found. Use task 'build_ex' to build it."
|
||||||
|
|
||||||
|
|
|
@ -10,40 +10,40 @@ import ptrmath
|
||||||
import urid
|
import urid
|
||||||
|
|
||||||
const
|
const
|
||||||
lv2AtomBaseUri ="http://lv2plug.in/ns/ext/atom"
|
lv2AtomBaseUri* ="http://lv2plug.in/ns/ext/atom"
|
||||||
lv2AtomPrefix = lv2AtomBaseUri & "#"
|
lv2AtomPrefix = lv2AtomBaseUri & "#"
|
||||||
|
|
||||||
lv2AtomAtom = lv2AtomPrefix & "Atom"
|
lv2AtomAtom* = lv2AtomPrefix & "Atom"
|
||||||
lv2AtomAtomport = lv2AtomPrefix & "AtomPort"
|
lv2AtomAtomPort* = lv2AtomPrefix & "AtomPort"
|
||||||
lv2AtomBlank = lv2AtomPrefix & "Blank"
|
lv2AtomBlank* = lv2AtomPrefix & "Blank"
|
||||||
lv2AtomBool = lv2AtomPrefix & "Bool"
|
lv2AtomBool* = lv2AtomPrefix & "Bool"
|
||||||
lv2AtomChunk = lv2AtomPrefix & "Chunk"
|
lv2AtomChunk* = lv2AtomPrefix & "Chunk"
|
||||||
lv2AtomDouble = lv2AtomPrefix & "Double"
|
lv2AtomDouble* = lv2AtomPrefix & "Double"
|
||||||
lv2AtomEvent = lv2AtomPrefix & "Event"
|
lv2AtomEvent* = lv2AtomPrefix & "Event"
|
||||||
lv2AtomFloat = lv2AtomPrefix & "Float"
|
lv2AtomFloat* = lv2AtomPrefix & "Float"
|
||||||
lv2AtomInt = lv2AtomPrefix & "Int"
|
lv2AtomInt* = lv2AtomPrefix & "Int"
|
||||||
lv2AtomLiteral = lv2AtomPrefix & "Literal"
|
lv2AtomLiteral* = lv2AtomPrefix & "Literal"
|
||||||
lv2AtomLong = lv2AtomPrefix & "Long"
|
lv2AtomLong* = lv2AtomPrefix & "Long"
|
||||||
lv2AtomNumber = lv2AtomPrefix & "Number"
|
lv2AtomNumber* = lv2AtomPrefix & "Number"
|
||||||
lv2AtomObject = lv2AtomPrefix & "Object"
|
lv2AtomObject* = lv2AtomPrefix & "Object"
|
||||||
lv2AtomPath = lv2AtomPrefix & "Path"
|
lv2AtomPath* = lv2AtomPrefix & "Path"
|
||||||
lv2AtomProperty = lv2AtomPrefix & "Property"
|
lv2AtomProperty* = lv2AtomPrefix & "Property"
|
||||||
lv2AtomResource = lv2AtomPrefix & "Resource"
|
lv2AtomResource* = lv2AtomPrefix & "Resource"
|
||||||
lv2AtomSequence = lv2AtomPrefix & "Sequence"
|
lv2AtomSequence* = lv2AtomPrefix & "Sequence"
|
||||||
lv2AtomSound = lv2AtomPrefix & "Sound"
|
lv2AtomSound* = lv2AtomPrefix & "Sound"
|
||||||
lv2AtomString = lv2AtomPrefix & "String"
|
lv2AtomString* = lv2AtomPrefix & "String"
|
||||||
lv2AtomTuple = lv2AtomPrefix & "Tuple"
|
lv2AtomTuple* = lv2AtomPrefix & "Tuple"
|
||||||
lv2AtomUri = lv2AtomPrefix & "URI"
|
lv2AtomUri* = lv2AtomPrefix & "URI"
|
||||||
lv2AtomUrid = lv2AtomPrefix & "URID"
|
lv2AtomUrid* = lv2AtomPrefix & "URID"
|
||||||
lv2AtomVector = lv2AtomPrefix & "Vector"
|
lv2AtomVector* = lv2AtomPrefix & "Vector"
|
||||||
lv2AtomAtomtransfer = lv2AtomPrefix & "atomTransfer"
|
lv2AtomAtomtransfer* = lv2AtomPrefix & "atomTransfer"
|
||||||
lv2AtomBeattime = lv2AtomPrefix & "beatTime"
|
lv2AtomBeattime* = lv2AtomPrefix & "beatTime"
|
||||||
lv2AtomBuffer= lv2AtomPrefix & "bufferType"
|
lv2AtomBuffer* = lv2AtomPrefix & "bufferType"
|
||||||
lv2AtomChild= lv2AtomPrefix & "childType"
|
lv2AtomChild* = lv2AtomPrefix & "childType"
|
||||||
lv2AtomEventtransfer = lv2AtomPrefix & "eventTransfer"
|
lv2AtomEventTransfer* = lv2AtomPrefix & "eventTransfer"
|
||||||
lv2AtomFrametime = lv2AtomPrefix & "frameTime"
|
lv2AtomFrameTime* = lv2AtomPrefix & "frameTime"
|
||||||
lv2AtomSupports = lv2AtomPrefix & "supports"
|
lv2AtomSupports* = lv2AtomPrefix & "supports"
|
||||||
lv2AtomTimeunit = lv2AtomPrefix & "timeUnit"
|
lv2AtomTimeUnit* = lv2AtomPrefix & "timeUnit"
|
||||||
|
|
||||||
##
|
##
|
||||||
## Return a pointer to the contents of an Atom. The "contents" of an atom
|
## Return a pointer to the contents of an Atom. The "contents" of an atom
|
||||||
|
|
|
@ -3,10 +3,6 @@
|
||||||
##
|
##
|
||||||
## Helper functions for the LV2 Atom extension.
|
## Helper functions for the LV2 Atom extension.
|
||||||
##
|
##
|
||||||
## Note these functions are all static inline, do not take their address.
|
|
||||||
##
|
|
||||||
## This header is non-normative, it is provided for convenience.
|
|
||||||
##
|
|
||||||
## Utilities for working with atoms.
|
## Utilities for working with atoms.
|
||||||
##
|
##
|
||||||
|
|
||||||
|
@ -31,7 +27,7 @@ proc atomTotalSize*(atom: ptr Atom): uint32 {.inline.} =
|
||||||
## Return true iff `atom` is null.
|
## Return true iff `atom` is null.
|
||||||
##
|
##
|
||||||
proc atomIsNull*(atom: ptr Atom): bool {.inline.} =
|
proc atomIsNull*(atom: ptr Atom): bool {.inline.} =
|
||||||
return atom == nil or (atom.`type` == Urid(0) and atom.size == 0)
|
return atom.isNil or (atom.`type` == Urid(0) and atom.size == 0)
|
||||||
|
|
||||||
##
|
##
|
||||||
## Return true iff `a` is equal to `b`.
|
## Return true iff `a` is equal to `b`.
|
||||||
|
@ -103,7 +99,7 @@ template atomSequenceIsEmpty*(seq: ptr AtomSequence): bool =
|
||||||
##
|
##
|
||||||
## This simply resets the size field, the other fields are left untouched.
|
## This simply resets the size field, the other fields are left untouched.
|
||||||
##
|
##
|
||||||
proc atomSequenceClear*(seq: ptr AtomSequence) {.inline.} =
|
template atomSequenceClear*(seq: ptr AtomSequence) =
|
||||||
seq.atom.size = sizeof(AtomSequenceBody).uint32
|
seq.atom.size = sizeof(AtomSequenceBody).uint32
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -115,7 +111,7 @@ proc atomSequenceClear*(seq: ptr AtomSequence) {.inline.} =
|
||||||
## @param event Event to write.
|
## @param event Event to write.
|
||||||
##
|
##
|
||||||
## @return A pointer to the newly written event in `seq`,
|
## @return A pointer to the newly written event in `seq`,
|
||||||
## or NULL on failure (insufficient space).
|
## or nil on failure (insufficient space).
|
||||||
##
|
##
|
||||||
proc atomSequenceAppendEvent*(seq: ptr AtomSequence; capacity: uint32;
|
proc atomSequenceAppendEvent*(seq: ptr AtomSequence; capacity: uint32;
|
||||||
event: ptr AtomEvent): ptr AtomEvent {.inline.} =
|
event: ptr AtomEvent): ptr AtomEvent {.inline.} =
|
||||||
|
|
|
@ -1,96 +1,96 @@
|
||||||
const
|
const
|
||||||
lv2CoreBaseUri = "http://lv2plug.in/ns/lv2core"
|
lv2CoreBaseUri* = "http://lv2plug.in/ns/lv2core"
|
||||||
lv2CorePrefix = lv2CoreBaseUri & "#"
|
lv2CorePrefix = lv2CoreBaseUri & "#"
|
||||||
|
|
||||||
# Classes (http://lv2plug.in/ns/lv2core#ref-classes):
|
# Classes (http://lv2plug.in/ns/lv2core#ref-classes):
|
||||||
lv2CoreClassAllpassPlugin = lv2CorePrefix & "AllpassPlugin"
|
lv2CoreClassAllpassPlugin* = lv2CorePrefix & "AllpassPlugin"
|
||||||
lv2CoreClassAmplifierPlugin = lv2CorePrefix & "AmplifierPlugin"
|
lv2CoreClassAmplifierPlugin* = lv2CorePrefix & "AmplifierPlugin"
|
||||||
lv2CoreClassAnalyserPlugin = lv2CorePrefix & "AnalyserPlugin"
|
lv2CoreClassAnalyserPlugin* = lv2CorePrefix & "AnalyserPlugin"
|
||||||
lv2CoreClassAudioPort = lv2CorePrefix & "AudioPort"
|
lv2CoreClassAudioPort* = lv2CorePrefix & "AudioPort"
|
||||||
lv2CoreClassBandpassPlugin = lv2CorePrefix & "BandpassPlugin"
|
lv2CoreClassBandpassPlugin* = lv2CorePrefix & "BandpassPlugin"
|
||||||
lv2CoreClassCVPort = lv2CorePrefix & "CVPort"
|
lv2CoreClassCVPort* = lv2CorePrefix & "CVPort"
|
||||||
lv2CoreClassChorusPlugin = lv2CorePrefix & "ChorusPlugin"
|
lv2CoreClassChorusPlugin* = lv2CorePrefix & "ChorusPlugin"
|
||||||
lv2CoreClassCombPlugin = lv2CorePrefix & "CombPlugin"
|
lv2CoreClassCombPlugin* = lv2CorePrefix & "CombPlugin"
|
||||||
lv2CoreClassCompressorPlugin = lv2CorePrefix & "CompressorPlugin"
|
lv2CoreClassCompressorPlugin* = lv2CorePrefix & "CompressorPlugin"
|
||||||
lv2CoreClassConstantPlugin = lv2CorePrefix & "ConstantPlugin"
|
lv2CoreClassConstantPlugin* = lv2CorePrefix & "ConstantPlugin"
|
||||||
lv2CoreClassControlPort = lv2CorePrefix & "ControlPort"
|
lv2CoreClassControlPort* = lv2CorePrefix & "ControlPort"
|
||||||
lv2CoreClassConverterPlugin = lv2CorePrefix & "ConverterPlugin"
|
lv2CoreClassConverterPlugin* = lv2CorePrefix & "ConverterPlugin"
|
||||||
lv2CoreClassDelayPlugin = lv2CorePrefix & "DelayPlugin"
|
lv2CoreClassDelayPlugin* = lv2CorePrefix & "DelayPlugin"
|
||||||
lv2CoreClassDistortionPlugin = lv2CorePrefix & "DistortionPlugin"
|
lv2CoreClassDistortionPlugin* = lv2CorePrefix & "DistortionPlugin"
|
||||||
lv2CoreClassDynamicsPlugin = lv2CorePrefix & "DynamicsPlugin"
|
lv2CoreClassDynamicsPlugin* = lv2CorePrefix & "DynamicsPlugin"
|
||||||
lv2CoreClassEQPlugin = lv2CorePrefix & "EQPlugin"
|
lv2CoreClassEQPlugin* = lv2CorePrefix & "EQPlugin"
|
||||||
lv2CoreClassEnvelopePlugin = lv2CorePrefix & "EnvelopePlugin"
|
lv2CoreClassEnvelopePlugin* = lv2CorePrefix & "EnvelopePlugin"
|
||||||
lv2CoreClassExpanderPlugin = lv2CorePrefix & "ExpanderPlugin"
|
lv2CoreClassExpanderPlugin* = lv2CorePrefix & "ExpanderPlugin"
|
||||||
lv2CoreClassExtensionData = lv2CorePrefix & "ExtensionData"
|
lv2CoreClassExtensionData* = lv2CorePrefix & "ExtensionData"
|
||||||
lv2CoreClassFeature = lv2CorePrefix & "Feature"
|
lv2CoreClassFeature* = lv2CorePrefix & "Feature"
|
||||||
lv2CoreClassFilterPlugin = lv2CorePrefix & "FilterPlugin"
|
lv2CoreClassFilterPlugin* = lv2CorePrefix & "FilterPlugin"
|
||||||
lv2CoreClassFlangerPlugin = lv2CorePrefix & "FlangerPlugin"
|
lv2CoreClassFlangerPlugin* = lv2CorePrefix & "FlangerPlugin"
|
||||||
lv2CoreClassFunctionPlugin = lv2CorePrefix & "FunctionPlugin"
|
lv2CoreClassFunctionPlugin* = lv2CorePrefix & "FunctionPlugin"
|
||||||
lv2CoreClassGatePlugin = lv2CorePrefix & "GatePlugin"
|
lv2CoreClassGatePlugin* = lv2CorePrefix & "GatePlugin"
|
||||||
lv2CoreClassGeneratorPlugin = lv2CorePrefix & "GeneratorPlugin"
|
lv2CoreClassGeneratorPlugin* = lv2CorePrefix & "GeneratorPlugin"
|
||||||
lv2CoreClassHighpassPlugin = lv2CorePrefix & "HighpassPlugin"
|
lv2CoreClassHighpassPlugin* = lv2CorePrefix & "HighpassPlugin"
|
||||||
lv2CoreClassInputPort = lv2CorePrefix & "InputPort"
|
lv2CoreClassInputPort* = lv2CorePrefix & "InputPort"
|
||||||
lv2CoreClassInstrumentPlugin = lv2CorePrefix & "InstrumentPlugin"
|
lv2CoreClassInstrumentPlugin* = lv2CorePrefix & "InstrumentPlugin"
|
||||||
lv2CoreClassLimiterPlugin = lv2CorePrefix & "LimiterPlugin"
|
lv2CoreClassLimiterPlugin* = lv2CorePrefix & "LimiterPlugin"
|
||||||
lv2CoreClassLowpassPlugin = lv2CorePrefix & "LowpassPlugin"
|
lv2CoreClassLowpassPlugin* = lv2CorePrefix & "LowpassPlugin"
|
||||||
lv2CoreClassMixerPlugin = lv2CorePrefix & "MixerPlugin"
|
lv2CoreClassMixerPlugin* = lv2CorePrefix & "MixerPlugin"
|
||||||
lv2CoreClassModulatorPlugin = lv2CorePrefix & "ModulatorPlugin"
|
lv2CoreClassModulatorPlugin* = lv2CorePrefix & "ModulatorPlugin"
|
||||||
lv2CoreClassMultiEQPlugin = lv2CorePrefix & "MultiEQPlugin"
|
lv2CoreClassMultiEQPlugin* = lv2CorePrefix & "MultiEQPlugin"
|
||||||
lv2CoreClassOscillatorPlugin = lv2CorePrefix & "OscillatorPlugin"
|
lv2CoreClassOscillatorPlugin* = lv2CorePrefix & "OscillatorPlugin"
|
||||||
lv2CoreClassOutputPort = lv2CorePrefix & "OutputPort"
|
lv2CoreClassOutputPort* = lv2CorePrefix & "OutputPort"
|
||||||
lv2CoreClassParaEQPlugin = lv2CorePrefix & "ParaEQPlugin"
|
lv2CoreClassParaEQPlugin* = lv2CorePrefix & "ParaEQPlugin"
|
||||||
lv2CoreClassPhaserPlugin = lv2CorePrefix & "PhaserPlugin"
|
lv2CoreClassPhaserPlugin* = lv2CorePrefix & "PhaserPlugin"
|
||||||
lv2CoreClassPitchPlugin = lv2CorePrefix & "PitchPlugin"
|
lv2CoreClassPitchPlugin* = lv2CorePrefix & "PitchPlugin"
|
||||||
lv2CoreClassPlugin = lv2CorePrefix & "Plugin"
|
lv2CoreClassPlugin* = lv2CorePrefix & "Plugin"
|
||||||
lv2CoreClassPluginBase = lv2CorePrefix & "PluginBase"
|
lv2CoreClassPluginBase* = lv2CorePrefix & "PluginBase"
|
||||||
lv2CoreClassPoint = lv2CorePrefix & "Point"
|
lv2CoreClassPoint* = lv2CorePrefix & "Point"
|
||||||
lv2CoreClassPort = lv2CorePrefix & "Port"
|
lv2CoreClassPort* = lv2CorePrefix & "Port"
|
||||||
lv2CoreClassPortProperty = lv2CorePrefix & "Port"
|
lv2CoreClassPortProperty* = lv2CorePrefix & "Port"
|
||||||
lv2CoreClassResource = lv2CorePrefix & "Resource"
|
lv2CoreClassResource* = lv2CorePrefix & "Resource"
|
||||||
lv2CoreClassReverbPlugin = lv2CorePrefix & "ReverbPlugin"
|
lv2CoreClassReverbPlugin* = lv2CorePrefix & "ReverbPlugin"
|
||||||
lv2CoreClassScalePoint = lv2CorePrefix & "ScalePoint"
|
lv2CoreClassScalePoint* = lv2CorePrefix & "ScalePoint"
|
||||||
lv2CoreClassSimulatorPlugin = lv2CorePrefix & "SimulatorPlugin"
|
lv2CoreClassSimulatorPlugin* = lv2CorePrefix & "SimulatorPlugin"
|
||||||
lv2CoreClassSpatialPlugin = lv2CorePrefix & "SpatialPlugin"
|
lv2CoreClassSpatialPlugin* = lv2CorePrefix & "SpatialPlugin"
|
||||||
lv2CoreClassSpecification = lv2CorePrefix & "Specification"
|
lv2CoreClassSpecification* = lv2CorePrefix & "Specification"
|
||||||
lv2CoreClassSpectralPlugin = lv2CorePrefix & "SpectralPlugin"
|
lv2CoreClassSpectralPlugin* = lv2CorePrefix & "SpectralPlugin"
|
||||||
lv2CoreClassUtilityPlugin = lv2CorePrefix & "UtilityPlugin"
|
lv2CoreClassUtilityPlugin* = lv2CorePrefix & "UtilityPlugin"
|
||||||
lv2CoreClassWaveshaperPlugin = lv2CorePrefix & "WaveshaperPlugin"
|
lv2CoreClassWaveshaperPlugin* = lv2CorePrefix & "WaveshaperPlugin"
|
||||||
|
|
||||||
# Properties (http://lv2plug.in/ns/lv2core#ref-properties):
|
# Properties (http://lv2plug.in/ns/lv2core#ref-properties):
|
||||||
lv2CorePropertyAppliesTo = lv2CorePrefix & "appliesTo"
|
lv2CorePropertyAppliesTo* = lv2CorePrefix & "appliesTo"
|
||||||
lv2CorePropertyBinary = lv2CorePrefix & "binary"
|
lv2CorePropertyBinary* = lv2CorePrefix & "binary"
|
||||||
lv2CorePropertyDefault = lv2CorePrefix & "default"
|
lv2CorePropertyDefault* = lv2CorePrefix & "default"
|
||||||
lv2CorePropertyDesignation = lv2CorePrefix & "designation"
|
lv2CorePropertyDesignation* = lv2CorePrefix & "designation"
|
||||||
lv2CorePropertyDocumentation = lv2CorePrefix & "documentation"
|
lv2CorePropertyDocumentation* = lv2CorePrefix & "documentation"
|
||||||
lv2CorePropertyExtensionData = lv2CorePrefix & "extensionData"
|
lv2CorePropertyExtensionData* = lv2CorePrefix & "extensionData"
|
||||||
lv2CorePropertyIndex = lv2CorePrefix & "index"
|
lv2CorePropertyIndex* = lv2CorePrefix & "index"
|
||||||
lv2CorePropertyLatency = lv2CorePrefix & "latency"
|
lv2CorePropertyLatency* = lv2CorePrefix & "latency"
|
||||||
lv2CorePropertyMaximum = lv2CorePrefix & "maximum"
|
lv2CorePropertyMaximum* = lv2CorePrefix & "maximum"
|
||||||
lv2CorePropertyMicroVersion = lv2CorePrefix & "microVersion"
|
lv2CorePropertyMicroVersion* = lv2CorePrefix & "microVersion"
|
||||||
lv2CorePropertyMinimum = lv2CorePrefix & "minimum"
|
lv2CorePropertyMinimum* = lv2CorePrefix & "minimum"
|
||||||
lv2CorePropertyMinorVersion = lv2CorePrefix & "minorVersion"
|
lv2CorePropertyMinorVersion* = lv2CorePrefix & "minorVersion"
|
||||||
lv2CorePropertyName = lv2CorePrefix & "name"
|
lv2CorePropertyName* = lv2CorePrefix & "name"
|
||||||
lv2CorePropertyOptionalFeature = lv2CorePrefix & "optionalFeature"
|
lv2CorePropertyOptionalFeature* = lv2CorePrefix & "optionalFeature"
|
||||||
lv2CorePropertyPort = lv2CorePrefix & "port"
|
lv2CorePropertyPort* = lv2CorePrefix & "port"
|
||||||
lv2CorePropertyPortProperty = lv2CorePrefix & "portProperty"
|
lv2CorePropertyPortProperty* = lv2CorePrefix & "portProperty"
|
||||||
lv2CorePropertyProject = lv2CorePrefix & "project"
|
lv2CorePropertyProject* = lv2CorePrefix & "project"
|
||||||
lv2CorePropertyPrototype = lv2CorePrefix & "prototype"
|
lv2CorePropertyPrototype* = lv2CorePrefix & "prototype"
|
||||||
lv2CorePropertyReportsLatency = lv2CorePrefix & "reportsLatency"
|
lv2CorePropertyReportsLatency* = lv2CorePrefix & "reportsLatency"
|
||||||
lv2CorePropertyRequiredFeature = lv2CorePrefix & "requiredFeature"
|
lv2CorePropertyRequiredFeature* = lv2CorePrefix & "requiredFeature"
|
||||||
lv2CorePropertyScalePoint = lv2CorePrefix & "scalePoint"
|
lv2CorePropertyScalePoint* = lv2CorePrefix & "scalePoint"
|
||||||
lv2CorePropertySymbol = lv2CorePrefix & "symbol"
|
lv2CorePropertySymbol* = lv2CorePrefix & "symbol"
|
||||||
|
|
||||||
# Instances (http://lv2plug.in/ns/lv2core#ref-instances)
|
# Instances (http://lv2plug.in/ns/lv2core#ref-instances)
|
||||||
lv2CoreInstanceConnectionOptional = lv2CorePrefix & "connectionOptional"
|
lv2CoreInstanceConnectionOptional* = lv2CorePrefix & "connectionOptional"
|
||||||
lv2CoreInstanceControl = lv2CorePrefix & "control"
|
lv2CoreInstanceControl* = lv2CorePrefix & "control"
|
||||||
lv2CoreInstanceEnumeration = lv2CorePrefix & "enumeration"
|
lv2CoreInstanceEnumeration* = lv2CorePrefix & "enumeration"
|
||||||
lv2CoreInstanceFreeWheeling = lv2CorePrefix & "freeWheeling"
|
lv2CoreInstanceFreeWheeling* = lv2CorePrefix & "freeWheeling"
|
||||||
lv2CoreInstanceHardRTCapable = lv2CorePrefix & "hardRTCapable"
|
lv2CoreInstanceHardRTCapable* = lv2CorePrefix & "hardRTCapable"
|
||||||
lv2CoreInstanceInPlaceBroken = lv2CorePrefix & "inPlaceBroken"
|
lv2CoreInstanceInPlaceBroken* = lv2CorePrefix & "inPlaceBroken"
|
||||||
lv2CoreInstanceInteger = lv2CorePrefix & "integer"
|
lv2CoreInstanceInteger* = lv2CorePrefix & "integer"
|
||||||
lv2CoreInstanceIsLive = lv2CorePrefix & "isLive"
|
lv2CoreInstanceIsLive* = lv2CorePrefix & "isLive"
|
||||||
lv2CoreInstanceSampleRateInstance = lv2CorePrefix & "sampleRate"
|
lv2CoreInstanceSampleRate* = lv2CorePrefix & "sampleRate"
|
||||||
lv2CoreInstanceToggledInstance = lv2CorePrefix & "toggled"
|
lv2CoreInstanceToggled* = lv2CorePrefix & "toggled"
|
||||||
|
|
||||||
type Lv2Handle* = pointer
|
type Lv2Handle* = pointer
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,11 @@ import core
|
||||||
## present but have nil data.
|
## present but have nil data.
|
||||||
|
|
||||||
proc lv2FeaturesData*(features: ptr UncheckedArray[ptr Lv2Feature], uri: string): pointer =
|
proc lv2FeaturesData*(features: ptr UncheckedArray[ptr Lv2Feature], uri: string): pointer =
|
||||||
if features != nil:
|
if not features.isNil:
|
||||||
var i = 0
|
var i = 0
|
||||||
while true:
|
while true:
|
||||||
let feature = features[i]
|
let feature = features[i]
|
||||||
if feature == nil:
|
if feature.isNil:
|
||||||
break
|
break
|
||||||
|
|
||||||
if feature[].uri == uri.cstring:
|
if feature[].uri == uri.cstring:
|
||||||
|
|
Loading…
Reference in New Issue