Les opcode Lua ont pour but de :
En utilisant la famille d'opcodes Lua, on peut interagir avec l'interpréteur Lua et le compilateur à la volée (LuaJIT) embarqués dans Csound de la manière suivante :
Lua signifie "lune" en portugais. Lua (http://www.lua.org ) est un langage de programmation dynamique léger et efficace, conçu pour être embarqué dans C/C++ et/ou pour être étendu avec C/C++. Lua a un mécanisme d'appel basé sur une pile et il fournit des fonctionnalités (tables, métatables, fonctions anonymes et fermetures) avec lesquelles on peut implémenter différents styles de programmation orientée objet et fonctionnelle. La syntaxe de Lua est à peine plus difficile que celle de Python.
Lua est un des langages dynamiques les plus rapides ; de plus, LuaJIT par Mike Pall ( http://luajit.org) va plus loin en fournissant à Lua un compilateur à la volée optimisé pour les architectures Intel. LuaJIT comprend une interface pour fonctions externes (FFI) efficace avec la possibilité de définir des tableaux C, des structures et d'autres types dans Lua. La vitesse de LuaJIT/FFI va de plusieurs fois celle de Lua à supérieure (dans certains contextes) à celle du C optimisé.
Voici un exemple d'opcode Lua, implémentant un filtre en échelle de Moog. Afin de pouvoir les comparer, un opcode défini par l'utilisateur et l'opcode natif de Csound produisant les mêmes sonorités avec le même algorithme sont également montrés et chronométrés... L'exemple utilise le fichier luamoog.csd.
Exemple 12. Exemple d'opcode Lua.
<CsoundSynthesizer> <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('csound64.dll.5.2') ffi.cdef[[ int csoundGetKsmps(void *); double csoundGetSr(void *); struct moogladder_t { double *out; double *inp; double *freq; double *res; double *istor; double sr; double ksmps; double thermal; double f; double fc; double fc2; double fc3; double fcr; double acr; double tune; double res4; double input; double i; double j; double k; double kk; double stg[6]; double delay[6]; double 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>
Copyright (c) 2011 par Michael Gogins. Tous droits réservés.