1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
|
<CsoundSynthesizer>
<CsOptions>
-odac -m3
</CsOptions>
<CsInstruments>
sr = 48000
ksmps = 100
nchnls = 1
gibegan rtclock
lua_opdef "moogladder", {{
local ffi = require("ffi")
local math = require("math")
local string = require("string")
local csoundApi = ffi.load("csoundandroid")
ffi.cdef[[
int csoundGetKsmps(void *);
float csoundGetSr(void *);
struct moogladder_t {
float *out;
float *inp;
float *freq;
float *res;
float *istor;
float sr;
float ksmps;
float thermal;
float f;
float fc;
float fc2;
float fc3;
float fcr;
float acr;
float tune;
float res4;
float input;
float i;
float j;
float k;
float kk;
float stg[6];
float delay[6];
float tanhstg[6];
};
]]
local moogladder_ct = ffi.typeof('struct moogladder_t *')
function moogladder_init(csound, opcode, carguments)
local p = ffi.cast(moogladder_ct, carguments)
p.sr = csoundApi.csoundGetSr(csound)
p.ksmps = csoundApi.csoundGetKsmps(csound)
if p.istor[0] == 0 then
for i = 0, 5 do
p.delay[i] = 0.0
end
for i = 0, 3 do
p.tanhstg[i] = 0.0
end
end
return 0
end
function moogladder_kontrol(csound, opcode, carguments)
local p = ffi.cast(moogladder_ct, carguments)
-- transistor thermal voltage
p.thermal = 1.0 / 40000.0
if p.res[0] < 0.0 then
p.res[0] = 0.0
end
-- sr is half the actual filter sampling rate
p.fc = p.freq[0] / p.sr
p.f = p.fc / 2.0
p.fc2 = p.fc * p.fc
p.fc3 = p.fc2 * p.fc
-- frequency & amplitude correction
p.fcr = 1.873 * p.fc3 + 0.4955 * p.fc2 - 0.6490 * p.fc + 0.9988
p.acr = -3.9364 * p.fc2 + 1.8409 * p.fc + 0.9968
-- filter tuning
p.tune = (1.0 - math.exp(-(2.0 * math.pi * p.f * p.fcr))) / p.thermal
p.res4 = 4.0 * p.res[0] * p.acr
-- Nested 'for' loops crash, not sure why.
-- Local loop variables also are problematic.
-- Lower-level loop constructs don't crash.
p.i = 0
while p.i < p.ksmps do
p.j = 0
while p.j < 2 do
p.k = 0
while p.k < 4 do
if p.k == 0 then
p.input = p.inp[p.i] - p.res4 * p.delay[5]
p.stg[p.k] = p.delay[p.k] + p.tune * (math.tanh(p.input * p.thermal) - p.tanhstg[p.k])
else
p.input = p.stg[p.k - 1]
p.tanhstg[p.k - 1] = math.tanh(p.input * p.thermal)
if p.k < 3 then
p.kk = p.tanhstg[p.k]
else
p.kk = math.tanh(p.delay[p.k] * p.thermal)
end
p.stg[p.k] = p.delay[p.k] + p.tune * (p.tanhstg[p.k - 1] - p.kk)
end
p.delay[p.k] = p.stg[p.k]
p.k = p.k + 1
end
-- 1/2-sample delay for phase compensation
p.delay[5] = (p.stg[3] + p.delay[4]) * 0.5
p.delay[4] = p.stg[3]
p.j = p.j + 1
end
p.out[p.i] = p.delay[5]
p.i = p.i + 1
end
return 0
end
}}
/*
Moogladder - An improved implementation of the Moog ladder filter
DESCRIPTION
This is an new digital implementation of the Moog ladder filter based on the work of Antti Huovilainen,
described in the paper \"Non-Linear Digital Implementation of the Moog Ladder Filter\" (Proceedings of DaFX04, Univ of Napoli).
This implementation is probably a more accurate digital representation of the original analogue filter.
This is version 2 (revised 14/DEC/04), with improved amplitude/resonance scaling and frequency correction using a couple of polynomials,as suggested by Antti.
SYNTAX
ar Moogladder asig, kcf, kres
PERFORMANCE
asig - input signal
kcf - cutoff frequency (Hz)
kres - resonance (0 - 1).
CREDITS
Victor Lazzarini
*/
opcode moogladderu, a, akk
asig, kcf, kres xin
setksmps 1
ipi = 4 * taninv(1)
/* filter delays */
az1 init 0
az2 init 0
az3 init 0
az4 init 0
az5 init 0
ay4 init 0
amf init 0
if kres > 1 then
kres = 1
elseif kres < 0 then
kres = 0
endif
/* twice the \'thermal voltage of a transistor\' */
i2v = 40000
/* sr is half the actual filter sampling rate */
kfc = kcf/sr
kf = kcf/(sr*2)
/* frequency & amplitude correction */
kfcr = 1.8730 * (kfc^3) + 0.4955 * (kfc^2) - 0.6490 * kfc + 0.9988
kacr = -3.9364 * (kfc^2) + 1.8409 * kfc + 0.9968;
/* filter tuning */
k2vg = i2v * (1 - exp(-2 * ipi * kfcr * kf))
/* cascade of 4 1st order sections */
ay1 = az1 + k2vg * (tanh((asig - 4 * kres * amf * kacr) / i2v) - tanh(az1 / i2v))
az1 = ay1
ay2 = az2 + k2vg * (tanh(ay1 / i2v) - tanh(az2 / i2v ))
az2 = ay2
ay3 = az3 + k2vg * (tanh(ay2 / i2v) - tanh(az3 / i2v))
az3 = ay3
ay4 = az4 + k2vg * (tanh(ay3 / i2v) - tanh(az4 / i2v))
az4 = ay4
/* 1/2-sample delay for phase compensation */
amf = (ay4 + az5) *0.5
az5 = ay4
/* oversampling */
ay1 = az1 + k2vg * (tanh((asig - 4 * kres * amf * kacr) / i2v) - tanh(az1 / i2v))
az1 = ay1
ay2 = az2 + k2vg * (tanh(ay1 / i2v) - tanh(az2 / i2v ))
az2 = ay2
ay3 = az3 + k2vg * (tanh(ay2 / i2v) - tanh(az3 / i2v))
az3 = ay3
ay4 = az4 + k2vg * (tanh(ay3 / i2v) - tanh(az4 / i2v))
az4 = ay4
amf = (ay4 + az5) * 0.5
az5 = ay4
xout amf
endop
instr 1
prints "No filter.\n"
kfe expseg 500, p3*0.9, 1800, p3*0.1, 3000
kenv linen 10000, 0.05, p3, 0.05
asig buzz kenv, 100, sr/(200), 1
; afil moogladder asig, kfe, 1
out asig
endin
instr 2
prints "Native moogladder.\n"
kfe expseg 500, p3*0.9, 1800, p3*0.1, 3000
kenv linen 10000, 0.05, p3, 0.05
asig buzz kenv, 100, sr/(200), 1
afil moogladder asig, kfe, 1
out afil
endin
instr 3
prints "UDO moogladder.\n"
kfe expseg 500, p3*0.9, 1800, p3*0.1, 3000
kenv linen 10000, 0.05, p3, 0.05
asig buzz kenv, 100, sr/(200), 1
afil moogladderu asig, kfe, 1
out afil
endin
instr 4
prints "Lua moogladder.\n"
kres init 1
istor init 0
kfe expseg 500, p3*0.9, 1800, p3*0.1, 3000
kenv linen 10000, 0.05, p3, 0.05
asig buzz kenv, 100, sr/(200), 1
afil init 0
lua_ikopcall "moogladder", afil, asig, kfe, kres, istor
out afil
endin
instr 5
giended rtclock
ielapsed = giended - gibegan
print ielapsed
gibegan rtclock
endin
</CsInstruments>
<CsScore>
f 1 0 65536 10 1
i 5.1 0 1
i 4 1 20
i 5.2 21 1
i 4 22 20
i 5.3 42 1
i 2 43 20
i 5.4 63 1
i 2 64 20
i 5.5 84 1
i 3 85 20
i 5.6 105 1
i 3 106 20
i 5.7 126 1
i 1 127 20
i 5.8 147 1
i 1 148 20
i 5.9 168 1
i 4 169 20
i 4 170 20
i 4 171 20
e
</CsScore>
</CsoundSynthesizer>
|