1from __future__ import division
2import os, quik
3
4
5class MyLoader(object):
6
7    def load_text(self, fname):
8        if fname.startswith("%"):
9            # hack for directly including guitarix gx_plugin.h
10            guitarix_headers = "../../../src/headers"
11            with open(os.path.join(guitarix_headers, fname[1:])) as f:
12                return "".join([line for line in f if not (line.startswith("#include") or line.startswith("#pragma once"))])
13        else:
14            with open(fname) as f:
15                return f.read()
16
17    def load_template(self, name):
18        return globals()[name]
19
20
21class Template(quik.Template):
22    def render(self, namespace, loader=MyLoader()):
23        return quik.Template.render(self, namespace, loader)
24
25c_template_top = Template("""\
26%if (@build_script)\
27// generated by @build_script
28%else\
29// generated automatically
30%end
31// DO NOT MODIFY!
32#include <iostream>
33#include <cmath>
34#include <list>
35%% %if (@method == "hybr" || @method == "lm")
36%if (@method == "lm")
37#include <cminpack.h>
38%else
39#include <float.h>
40%end
41#include <Eigen/Core>
42%if (@np > 0)
43#include <Eigen/LU>
44%end
45%if (@dev_interface)%% just for convenience, to make stand alone sources
46%include ("%gx_compiler.h")
47%include ("%gx_plugin.h")
48%else
49#include "gx_compiler.h"
50#include "gx_plugin.h"
51%end
52
53using namespace Eigen;
54
55#define N_(x) (x)
56
57#define creal @c_real
58
59static inline int sign(creal v) {
60    return v < 0 ? -1 : 1;
61}
62
63static inline int Heaviside(creal v) {
64    return v < 0 ? 0 : 1;  // Heaviside(0) == 1/2 in sympy but shouldn't matter
65}
66
67static Matrix<creal, @nx, 1> g_x;
68creal g_v_data[@nn];
69static Map<Matrix<creal, @nn, 1> >g_v(g_v_data);
70static int g_info;
71static int g_nfev;
72
73%if (@dev_interface)
74static creal g_fnorm;
75static Array<creal, @nni, 1> g_min;
76static Array<creal, @nni, 1> g_max;
77
78#define INTERFACE_VERSION 5
79
80extern "C" __attribute__ ((visibility ("default")))
81int get_interface_version() {
82    return INTERFACE_VERSION;
83}
84
85extern "C" __attribute__ ((visibility ("default")))
86void get_structure(const char **name, int *data_size, int *samplerate, const int **shapes, const int (**comp_sz)[6],
87                   const char ***pins, const char ***comp_names, const char **method, const char ***pot_vars,
88                   const double **pot, const char ***out_labels, const char **comment) {
89    static const char *n = "@name";
90    static int sz[] = { @nx, @ni, @no, @npl, @nn, @nni, @nno, @nc, -1 }; // nx, ni, no, npl, nn, nni, nno, nc, -1
91    static int nn_sz[][6] = { // component v_slice, p_slice, i_slice
92    %for @c in @components:\
93        {@c.v_slice.start, @c.v_slice.stop, @c.p_slice.start, @c.p_slice.stop, @c.i_slice.start, @c.i_slice.stop},
94    %end
95    };
96    static const char *nn_name[] = { // component names
97    %for @c in @components:\
98        "@c.name", "@c.namespace",
99    %end 0
100    };
101    static const char *nn_pins[] = { // component pins
102    %for @c in @nlin_elements:\
103        "@c",
104    %end 0
105    };
106    static const char *m = "@method";
107    static const char *pvars[] = {@pot_vars};
108    static double pvalues[] = {@pot};
109    static const char *ol[] = {@out_labels};
110    static const char *c = "@comment";
111    if (name) *name = n;
112    if (data_size) *data_size = sizeof(creal);
113    if (samplerate) *samplerate = @fs;
114    if (shapes) *shapes = sz;
115    if (comp_sz) *comp_sz = nn_sz;
116    if (pins) *pins = nn_pins;
117    if (comp_names) *comp_names = nn_name;
118    if (method) *method = m;
119    if (pot_vars) *pot_vars = pvars;
120    if (pot) *pot = pvalues;
121    if (out_labels) *out_labels = ol;
122    if (comment) *comment = c;
123}
124%end
125
126static creal x0_data[] = {@x0_data};
127%if (@dev_interface)
128static creal v0_data[] = {@v0_data};
129static creal p0_data[] = {@p0_data};
130static creal o0_data[] = {@o0_data};
131static creal op_data[] = {@op_data};
132
133extern "C" __attribute__ ((visibility ("default")))
134void get_dc(creal *v0, creal *x0, creal *p0, creal *o0, creal *op) {
135    if (v0) {
136        for (int i = 0; i < @nn; i++) {
137            v0[i] = v0_data[i];
138        }
139    }
140    if (x0) {
141        for (int i = 0; i < @nx; i++) {
142            x0[i] = x0_data[i];
143        }
144    }
145    if (p0) {
146        for (int i = 0; i < @nni; i++) {
147            p0[i] = p0_data[i];
148        }
149    }
150    if (o0) {
151        for (int i = 0; i < @no; i++) {
152            o0[i] = o0_data[i];
153        }
154    }
155    if (op) {
156        for (int i = 0; i < @ni; i++) {
157            op[i] = op_data[i];
158        }
159    }
160}
161
162extern "C" __attribute__ ((visibility ("default")))
163void get_info(creal *v, creal *x, creal *minval, creal *maxval, int *info, int *nfev, creal *fnorm) {
164    Map<Matrix<creal, @nn, 1> > V(v);
165    V = g_v;
166    Map<Matrix<creal, @nx, 1> > X(x);
167    X = g_x;
168    Map<Matrix<creal, @nni, 1> > Mi(minval);
169    Mi = g_min;
170    Map<Matrix<creal, @nni, 1> > Ma(maxval);
171    Ma = g_max;
172    *info = g_info;
173    *nfev = g_nfev;
174    *fnorm = g_fnorm;
175}
176
177extern "C" __attribute__ ((visibility ("default")))
178void set_state(creal *v, creal *x) {
179    Map<Matrix<creal, @nn, 1> > V(v);
180    g_v = V;
181    Map<Matrix<creal, @nx, 1> > X(x);
182    g_x = X;
183}
184%end
185
186#define real realtype  // real conflicts with Eigen::real of new eigen library version
187typedef double real;
188%if (@method == "table")
189%include ("intpp.h")
190#define NO_INTPP_INCLUDES
191%include ("intpp.cc")
192@extra_sources.intpp_inst
193%%@extra_sources.data_h
194@extra_sources.data_c
195%end
196
197@global_matrices
198
199static Matrix<creal, @npl, 1> last_pot;
200
201@struct_def
202
203%if (@dev_interface || @npl)
204void calc_inv_update(const creal *pot, nonlin_param& par) {
205    Map<const Matrix<creal, @npl, 1> >pm(pot);
206    last_pot = pm;
207    @update_pot
208}
209%end
210%if (@dev_interface)
211nonlin_param par@nonlin_mat_list;
212
213extern "C" __attribute__ ((visibility ("default")))
214void calc_inv_update(const creal *pot) {
215    calc_inv_update(pot, par);
216}
217%end
218
219@nonlin_code
220
221%if (@dev_interface)
222extern "C" __attribute__ ((visibility ("default")))
223int calc_stream(creal *u, creal *o, int n, int ii) {
224    Matrix<creal, @nn, 1> mi;
225%if (@nn)
226    g_min = Matrix<creal, @nni, 1>::Constant(HUGE_VAL);
227    g_max = Matrix<creal, @nni, 1>::Constant(-HUGE_VAL);
228    g_fnorm = 0;
229    par.v = &g_v;
230    par.i = &mi;
231    Array<creal, @nni, 1> p_val;
232    par.p_val = &p_val;
233    creal fnorm;
234    par.fnorm = &fnorm;
235    Matrix<creal, @nn, 1> mp;
236    par.p = &mp;
237%end
238    int nu = @ni;
239    if (ii >= 0) {
240        nu += 1;
241    }
242    for (int j = 0; j < n; j++) {
243#define GET_U (u+j*nu)
244#define DTP_U creal
245        @pre_filter
246%if (@nn)
247        Matrix<creal, @mp_cols, 1> dp;
248        dp << g_x, Map<Matrix<creal,@ni,1> >(GET_U);
249        @gen_mp
250        int ret = nonlin::nonlin_solve(par);
251        if (fnorm > g_fnorm) {
252            g_fnorm = fnorm;
253        }
254        if (ret != 0) {
255            return ret;
256        }
257        g_min = g_min.min(p_val.array());
258        g_max = g_max.max(p_val.array());
259        if (ii >= 0) {
260            mi(ii) += GET_U[@ni];
261        }
262%end
263        Matrix<creal, @m_cols, 1> d;
264%if (@nn)
265        d << g_x, Map<Matrix<creal,@ni,1> >(GET_U), mi@iblock;
266%else
267        d << g_x, Map<Matrix<creal,@ni,1> >(GET_U);
268%end
269%if (@nx)
270        Matrix<creal, @nx, 1>& xn = g_x;
271        @gen_xn
272%end
273        Map<Matrix<creal, @no, 1> > xo(o+@no*j);
274        @gen_xo
275#undef GET_U
276#undef DTP_U
277    }
278    return 0;
279}
280
281extern "C" __attribute__ ((visibility ("default")))
282int calc(creal *u, creal *x, creal *v, creal *x_new, creal *o, int *info, int *nfev, creal *fnorm) {
283#define GET_U (u)
284#define DTP_U creal
285    @pre_filter
286    int ret = 0;
287    Matrix<creal, @nn, 1> mi;
288%if (@nn)
289    par.fnorm = fnorm;
290    par.i = &mi;
291    Matrix<creal, @mp_cols, 1> dp;
292    dp << Map<Matrix<creal,@nx,1> >(x), Map<Matrix<creal,@ni,1> >(u);
293    Matrix<creal, @nn, 1> mp;
294    par.p = &mp;
295    Map<Matrix<creal, @nn, 1> >Mv(v);
296    par.v = &Mv;
297    Array<creal, @nni, 1> p_val;
298    par.p_val = &p_val;
299    @gen_mp
300    ret = nonlin::nonlin(par);
301%else
302    *info = 1;
303    *nfev = 0;
304    *fnorm = 0;
305%end
306    Matrix<creal, @m_cols, 1> d;
307    d << Map<Matrix<creal,@nx,1> >(x), Map<Matrix<creal,@ni,1> >(u), mi@iblock;
308    Map<Matrix<creal, @nx, 1> > xn(x_new);
309    @gen_xn
310    Map<Matrix<creal, @no, 1> > xo(o);
311    @gen_xo
312    return ret;
313#undef GET_U
314#undef DTP_U
315}
316%end
317
318%if (@resample)
319#include <zita-resampler/resampler.h>
320
321class FixedRateResampler {
322private:
323    Resampler r_up, r_down;
324    int inputRate, outputRate;
325    int last_in_count;
326public:
327    int setup(int _inputRate, int _outputRate);
328    int up(int count, float *input, float *output);
329    void down(float *input, float *output);
330    int max_out_count(int in_count) {
331        return static_cast<int>(ceil((in_count*static_cast<double>(outputRate))/inputRate)); }
332};
333
334int FixedRateResampler::setup(int _inputRate, int _outputRate)
335{
336    const int qual = 16; // resulting in a total delay of 2*qual (0.7ms @44100)
337    inputRate = _inputRate;
338    outputRate = _outputRate;
339    if (inputRate == outputRate) {
340        return 0;
341    }
342    // upsampler
343    int ret = r_up.setup(inputRate, outputRate, 1, qual);
344    if (ret) {
345        return ret;
346    }
347    // k == filtlen() == 2 * qual
348    // pre-fill with k-1 zeros
349    r_up.inp_count = r_up.filtlen() - 1;
350    r_up.out_count = 1;
351    r_up.inp_data = r_up.out_data = 0;
352    r_up.process();
353    // downsampler
354    ret = r_down.setup(outputRate, inputRate, 1, qual);
355    if (ret) {
356        return ret;
357    }
358    // k == filtlen() == 2 * qual * fact
359    // pre-fill with k-2 zeros
360    r_down.inp_count = r_down.filtlen() - 2;
361    r_down.out_count = 1;
362    r_down.inp_data = r_down.out_data = 0;
363    r_down.process();
364    return 0;
365}
366
367int FixedRateResampler::up(int count, float *input, float *output)
368{
369    if (inputRate == outputRate) {
370        memcpy(output, input, count*sizeof(float));
371        r_down.out_count = count;
372        return count;
373    }
374    r_up.inp_count = count;
375    r_down.out_count = count+1; // +1 == trick to drain input
376    r_up.inp_data = input;
377    int m = max_out_count(count);
378    r_up.out_count = m;
379    r_up.out_data = output;
380    r_up.process();
381    assert(r_up.inp_count == 0);
382    assert(r_up.out_count <= 1);
383    r_down.inp_count = m - r_up.out_count;
384    return r_down.inp_count;
385}
386
387void FixedRateResampler::down(float *input, float *output)
388{
389    if (inputRate == outputRate) {
390        memcpy(output, input, r_down.out_count*sizeof(float));
391        return;
392    }
393    r_down.inp_data = input;
394    r_down.out_data = output;
395    r_down.process();
396    assert(r_down.inp_count == 0);
397    assert(r_down.out_count == 1);
398}
399
400FixedRateResampler smp;
401%end
402
403class DKPlugin: public PluginDef {
404public:
405    float pots[@npl+@add_npl];
406private:
407    creal pots_last[@npl+@add_npl];
408    Matrix<creal, @nx, 1> x_last;
409    @DKPlugin_fields
410public:
411    EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
412    DKPlugin();
413    static void init(unsigned int samplingFreq, PluginDef *plugin);
414    static void process(int count, float *input, float *output, PluginDef *plugin);
415    static int registerparam(const ParamReg& reg);
416    static int uiloader(const UiBuilder& builder, int form);
417    static void del_instance(PluginDef *plugin);
418};
419
420DKPlugin::DKPlugin():
421    PluginDef(), pots(), pots_last(), x_last()@DKPlugin_init {
422    version = PLUGINDEF_VERSION;
423    flags = 0;
424    id = @plugindef.s_id;
425    name = @plugindef.l_name;
426    groups = 0;
427    description = @plugindef.l_description;
428    category = @plugindef.l_category;
429    shortname = @plugindef.l_shortname;
430    mono_audio = process;
431    set_samplerate = init;
432    register_params = registerparam;
433    load_ui = uiloader;
434    delete_instance = del_instance;
435    for (int i = 0; i < @nx; i++) {
436        x_last(i) = x0_data[i];
437    }
438}
439
440#define PARAM(p) ("@id" "." p)
441
442int DKPlugin::registerparam(const ParamReg& reg) {
443    %if (@regs)
444        DKPlugin& self = *static_cast<DKPlugin*>(reg.plugin);
445    %end
446    %for @r in @regs:
447        reg.registerFloatVar(PARAM("@r.id"), N_("@r.name"), "S", N_("@r.desc"), &self.pots[@r.varidx], 0.5, 0, 1, 0.01, nullptr);
448    %end
449    return 0;
450}
451
452void DKPlugin::init(unsigned int samplingFreq, PluginDef *plugin) {
453%if (@resample)
454    smp.setup(samplingFreq, @fs);
455%end
456%if (@filter_init)
457    DKPlugin& self = *static_cast<DKPlugin*>(plugin);
458    @filter_init
459%end
460}
461
462void DKPlugin::process(int n, float *u, float *o, PluginDef *plugin) {
463    DKPlugin& self = *static_cast<DKPlugin*>(plugin);
464%if (@npl || @add_npl)
465    creal t[@npl+@add_npl];
466    @calc_pots
467%end
468    @process_add
469// start copied and modified code
470    Matrix<creal, @nn, 1> mi;
471%if (@nn)
472%%    g_min = Matrix<creal, @nni, 1>::Constant(HUGE_VAL);
473%%    g_max = Matrix<creal, @nni, 1>::Constant(-HUGE_VAL);
474%%    g_fnorm = 0;
475    creal fnorm;
476    Matrix<creal, @nn, 1> mp;
477    Array<creal, @nni, 1> p_val;
478    nonlin_param par@nonlin_mat_list_calc;
479%end
480%if (@resample)
481    float buf[smp.max_out_count(n)];
482    n = smp.up(n, u, buf);
483#define GET_U (buf+j*@ni)
484%else
485#define GET_U (u+j*@ni)
486%end
487    for (int j = 0; j < n; j++) {
488#define DTP_U float
489        @pre_filter
490%if (@npl)
491        for (int k = 0; k < @npl; k++) {
492            self.pots_last[k] = @timecst * t[k] + (1-@timecst) * self.pots_last[k];
493        }
494        calc_inv_update(self.pots_last, par);
495%end
496%if (@nn)
497        Matrix<creal, @mp_cols, 1> dp;
498        dp << self.x_last, Map<Matrix<float,@ni,1> >(GET_U).cast<creal>();
499        @gen_mp
500        nonlin::nonlin(par);
501%%        int ret = nonlin::nonlin_solve(par);
502%%        if (fnorm > g_fnorm) {
503%%            g_fnorm = fnorm;
504%%        }
505%%        if (ret != 0) {
506%%            return;
507%%        }
508%end
509        Matrix<creal, @m_cols, 1> d;
510        d << self.x_last, Map<Matrix<float,@ni,1> >(GET_U).cast<creal>(), mi@iblock;
511%if (@nx)
512        Matrix<creal, @nx, 1>& xn = self.x_last;
513        @gen_xn
514%end
515%if (@resample)
516        Map<Matrix<float, @no, 1> > xo(buf+@no*j);
517%else
518        Map<Matrix<float, @no, 1> > xo(o+@no*j);
519%end
520        @gen_xo_float
521        @post_filter
522#undef GET_U
523#undef DTP_U
524    }
525%if (@resample)
526    smp.down(buf, o);
527%end
528    @post_process
529// end copied code
530}
531
532int DKPlugin::uiloader(const UiBuilder& b, int form) {
533    if (!(form & UI_FORM_STACK)) {
534        return -1;
535    }
536    %parse ("module_ui_template")
537    return 0;
538}
539
540void DKPlugin::del_instance(PluginDef *p)
541{
542    delete static_cast<DKPlugin*>(p);
543}
544
545%if (@dev_interface)
546extern "C" __attribute__ ((visibility ("default")))
547int get_gx_plugin(unsigned int idx, PluginDef **pplugin)
548{
549    const int count = 1;
550    if (!pplugin) {
551        return count;
552    }
553    switch (idx) {
554    case 0: *pplugin = new DKPlugin; return count;
555    default: *pplugin = 0; return -1;
556    }
557}
558%else
559namespace pluginlib { namespace @plugindef.namespace {
560PluginDef *plugin() {
561    return new DKPlugin;
562}
563}}
564%end
565
566%if (@{plugindef.lv2_plugin_type})
567%parse ("lv2_interface")
568%end
569""")
570
571lv2_manifest = Template("""
572\@prefix lv2:  <http://lv2plug.in/ns/lv2core#> .
573\@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
574
575<http://guitarix.sourceforge.net/plugins/@id#@{plugindef.lv2_versioned_id}>
576    a lv2:Plugin ;
577    lv2:binary <@{plugindef.lv2_versioned_id}.so>  ;
578    rdfs:seeAlso <@{plugindef.lv2_versioned_id}.ttl> .
579""")
580
581lv2_ttl = Template("""
582\@prefix doap: <http://usefulinc.com/ns/doap#> .
583\@prefix foaf: <http://xmlns.com/foaf/0.1/> .
584\@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
585\@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
586\@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
587\@prefix guiext: <http://lv2plug.in/ns/extensions/ui#>.
588
589<http://guitarix.sourceforge.net#devel>
590    a foaf:Group ;
591    foaf:name "Guitarix team" ;
592    foaf:mbox <mailto:guitarix-developer\@lists.sourceforge.net> ;
593    rdfs:seeAlso <http://guitarix.sourceforge.net> .
594
595<http://guitarix.sourceforge.net/plugins/@id>
596    a doap:Project ;
597    doap:maintainer <http://guitarix.sourceforge.net#devel> ;
598    doap:name "@{plugindef.name}" .
599
600<http://guitarix.sourceforge.net/plugins/@id#@{plugindef.lv2_versioned_id}>
601    a lv2:Plugin ,
602        lv2:@{plugindef.lv2_plugin_type} ;
603    doap:maintainer <http://guitarix.sourceforge.net#devel> ;
604    doap:name "@{plugindef.name}";
605    doap:license <http://usefulinc.com/doap/licenses/gpl> ;
606    lv2:project <http://guitarix.sourceforge.net/plugins/@id> ;
607    lv2:optionalFeature lv2:hardRTCapable ;
608    lv2:minorVersion @{plugindef.lv2_minor_version};
609    lv2:microVersion @{plugindef.lv2_micro_version};
610
611    lv2:port\
612%for @p in @lv2_ports:\
613 [
614        a @{p.type_list} ;
615        lv2:index @{p.index} ;
616        lv2:symbol "@{p.symbol}" ;
617        lv2:name "@{p.name}" ;
618%if (@{p.control_index} >= 0)\
619        lv2:default @{p.default} ;
620        lv2:minimum @{p.minimum} ;
621        lv2:maximum @{p.maximum} ;
622%end
623    ]%if(@velocityHasNext),%end\
624%end.
625""")
626
627lv2_interface = Template("""
628#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
629
630#define LV2_PLUGIN_URI "http://guitarix.sourceforge.net/plugins/@id#@{plugindef.lv2_versioned_id}"
631
632typedef enum {
633%for @p in @lv2_ports:\
634    PORT_@{p.symbol} = @{p.index},
635%end
636} PortIndex;
637
638class LV2_DKPlugin: public DKPlugin {
639public:
640    // Port buffers
641    float* ports[@{lv2_ports.port_count()}];
642public:
643    LV2_DKPlugin(): DKPlugin() {}
644};
645
646static LV2_Handle
647instantiate(const LV2_Descriptor*     descriptor,
648            double                    rate,
649            const char*               bundle_path,
650            const LV2_Feature* const* features)
651{
652    LV2_DKPlugin *p = new LV2_DKPlugin;
653    p->set_samplerate(rate, p);
654    return static_cast<LV2_Handle>(p);
655}
656
657static void
658connect_port(LV2_Handle instance,
659             uint32_t   port,
660             void*      data)
661{
662    static_cast<LV2_DKPlugin*>(instance)->ports[port] = static_cast<float*>(data);
663}
664
665static void
666activate(LV2_Handle instance)
667{
668}
669
670static void
671run(LV2_Handle instance, uint32_t n_samples)
672{
673    LV2_DKPlugin* p = static_cast<LV2_DKPlugin*>(instance);
674
675%for @p in @lv2_ports:\
676%if (@{p.control_index} >= 0)\
677    p->pots[@{p.control_index}] = *(p->ports[@{p.index}]);
678%end
679%end
680%if (@ni == 1 && @no == 1)
681    p->process(n_samples, p->ports[0], p->ports[1], p);
682%else
683    p->process(n_samples, p->ports[0], p->ports[1], p->ports[2], p->ports[3], p);
684%end
685}
686
687static void
688deactivate(LV2_Handle instance)
689{
690}
691
692static void
693cleanup(LV2_Handle instance)
694{
695    LV2_DKPlugin* p = static_cast<LV2_DKPlugin*>(instance);
696    p->delete_instance(p);
697}
698
699static const void*
700extension_data(const char* uri)
701{
702    return NULL;
703}
704
705static const LV2_Descriptor descriptor = {
706    LV2_PLUGIN_URI,
707    instantiate,
708    connect_port,
709    activate,
710    run,
711    deactivate,
712    cleanup,
713    extension_data
714};
715
716extern "C"
717LV2_SYMBOL_EXPORT
718const LV2_Descriptor*
719lv2_descriptor(uint32_t index){
720    switch (index){
721        case 0:
722            return &descriptor;
723        default:
724            return NULL;
725    }
726}
727
728
729
730""")
731
732c_template_calc_nonlin = Template("""
733%if (@dev_interface)
734extern "C" __attribute__ ((visibility ("default")))
735int calc_@{namespace}(int n, creal *p, creal *i, creal *v, int *info, int *nfev, creal *fnorm) {
736    int ret = 0;
737    Matrix<creal, @g_nn, 1> mp;
738    Matrix<creal, @g_nn, 1> mi;
739    Map<Matrix<creal, @g_nn, 1> >Mv(v);
740    Array<creal, @g_nni, 1> p_val;
741    nonlin_param par@nonlin_mat_list;
742    for (int k = 0; k < n; k++) {
743        calc_inv_update(p+k*(@nni+@npl), par);
744        mp@pblockV << Map<Matrix<creal, @nni, 1> >(p+k*(@nni+@npl)+@npl);
745        ret = @namespace::nonlin_solve(par);
746        Map<Matrix<creal, @nno, 1> >(i+k*@nno) << mi@iblockV;
747    }
748    return ret;
749}
750%end
751""")
752
753c_template_nonlin_func_hybr = Template("""
754static int fcn(void *p, int n, const creal *v, creal *fvec, int iflag ) {
755    nonlin_param& par = *static_cast<nonlin_param *>(p);
756    @expression
757    return 0;
758}
759""")
760
761c_template_nonlin_func_lm = Template("""
762static int fcn(void *p, int m, int n, const creal *v, creal *fvec, int iflag ) {
763    nonlin_param& par = *static_cast<nonlin_param *>(p);
764    @expression
765    return 0;
766}
767""")
768
769c_template_nonlin_func_hybrCC = Template("""
770typedef int root_fcn(void*p, const creal *v, creal *fvec, int iflag);
771static int fcn(void *p, const creal *v, creal *fvec, int iflag) {
772    nonlin_param& par = *static_cast<nonlin_param *>(p);
773    @expression
774    return 0;
775}
776""")
777
778c_template_nonlin_solver_hybr = Template("""
779static int nonlin(struct nonlin_param &par) {
780    int maxfev, mode, nprint, ldfjac;
781    creal xtol, epsfcn, factor;
782    creal __attribute__((aligned(16))) fvec[@nn];
783    creal __attribute__((aligned(16))) fjac[@nn*@nn];
784    creal __attribute__((aligned(16))) qtf[@nn];
785    creal __attribute__((aligned(16))) wa1[@nn];
786    creal __attribute__((aligned(16))) wa2[@nn];
787    creal __attribute__((aligned(16))) wa3[@nn];
788    creal __attribute__((aligned(16))) wa4[@nn];
789    creal diag[@nn] = {%for @j in @solver_diag:@j,%end};
790    int ml, mu, lr;
791    creal r[(@nn*(@nn+1))/2];
792    lr = (@nn*(@nn+1))/2;
793    ml = @nn-1; /* unbanded jacobian */
794    mu = @nn-1; /* unbanded jacobian */
795    ldfjac = @nn;
796
797    /* parameter */
798    xtol = @solver_xtol;
799    maxfev = @solver_maxfev;
800    epsfcn = 0.;
801    //mode = 2;  /* explicit variable scaling with diag */
802    mode = 1;  /* automatic variable scaling */
803    factor = @solver_factor;
804    nprint = 0;
805    /**/
806
807    @setup
808    @store_p
809    @p_transform
810    *par.info = __cminpack_func__(hybrd)(
811        fcn, &par, @nn, @var_v_ref, fvec, xtol, maxfev, ml, mu, epsfcn, diag,
812        mode, factor, nprint, par.nfev, fjac, ldfjac, r, lr, qtf, wa1, wa2, wa3, wa4);
813    *par.fnorm = __cminpack_func__(enorm)(@nn, fvec);
814    @i_transform
815    int ret = 0;
816    if (*par.info != 1) {
817        if (!(*par.info == 5 && *par.fnorm < 1e-20)) {
818            ret = -1;
819        }
820    }
821    @cleanup
822    return ret;
823}
824""")
825
826c_template_nonlin_solver_lm = Template("""
827static int nonlin(struct nonlin_param &par) {
828    int maxfev, mode, nprint, ldfjac;
829    creal xtol, epsfcn, factor;
830    creal __attribute__((aligned(16))) fvec[@nn];
831    creal __attribute__((aligned(16))) fjac[@nn*@nn];
832    creal __attribute__((aligned(16))) qtf[@nn];
833    creal __attribute__((aligned(16))) wa1[@nn];
834    creal __attribute__((aligned(16))) wa2[@nn];
835    creal __attribute__((aligned(16))) wa3[@nn];
836    creal __attribute__((aligned(16))) wa4[@nn];
837    creal diag[@nn] = {%for @j in @solver_diag:@j,%end};
838    int __attribute__((aligned(16))) ipvt[@nn];
839    creal ftol, gtol;
840    ftol = sqrt(__cminpack_func__(dpmpar)(1)); // parameter
841    gtol = 0.; // parameter
842    ldfjac = @nn;
843
844    /* parameter */
845    xtol = @solver_xtol;
846    maxfev = @solver_maxfev;
847    epsfcn = 0.;
848    //mode = 2;  /* explicit variable scaling with diag */
849    mode = 1;  /* automatic variable scaling */
850    factor = @solver_factor;
851    nprint = 0;
852    /**/
853
854    @setup
855    @store_p
856    @p_transform
857
858    *par.info = __cminpack_func__(lmdif)(
859        fcn, &par, @nn, @nn, @var_v_ref, fvec, ftol, xtol, gtol, maxfev, epsfcn, diag,
860        mode, factor, nprint, par.nfev, fjac, ldfjac, ipvt, qtf, wa1, wa2, wa3, wa4);
861    *par.fnorm = __cminpack_func__(enorm)(@nn, fvec);
862    @i_transform
863    @cleanup
864    return (*par.info < 1 || *par.info > 4) ? -1 : 0;
865}
866""")
867
868c_template_nonlin_solver_hybrCC = Template("""
869%include ("hybrd.cc")
870
871static int nonlin(struct nonlin_param &par) {
872    int maxfev, mode, nprint, ldfjac;
873    creal xtol, epsfcn, factor;
874    creal __attribute__((aligned(16))) fvec[@nn];
875    creal __attribute__((aligned(16))) fjac[@nn*@nn];
876    creal __attribute__((aligned(16))) qtf[@nn];
877    creal __attribute__((aligned(16))) wa1[@nn];
878    creal __attribute__((aligned(16))) wa2[@nn];
879    creal __attribute__((aligned(16))) wa3[@nn];
880    creal __attribute__((aligned(16))) wa4[@nn];
881    creal diag[@nn] = {%for @j in @solver_diag:@j,%end};
882    int ml, mu, lr;
883    creal r[(@nn*(@nn+1))/2];
884    lr = (@nn*(@nn+1))/2;
885    ml = @nn-1; /* unbanded jacobian */
886    mu = @nn-1; /* unbanded jacobian */
887    ldfjac = @nn;
888
889    /* parameter */
890    xtol = @solver_xtol;
891    maxfev = @solver_maxfev;
892    epsfcn = 0.;
893    //mode = 2;  /* explicit variable scaling with diag */
894    mode = 1;  /* automatic variable scaling */
895    factor = @solver_factor;
896    nprint = 0;
897    /**/
898
899    @setup
900    @store_p
901    @p_transform
902
903    *par.info = hybrdX<@nn>(fcn, &par, @var_v_ref, fvec, xtol, maxfev, ml, mu, epsfcn,
904                          diag, mode, factor, nprint, par.nfev, fjac, ldfjac, r, lr,
905                          qtf, wa1, wa2, wa3, wa4);
906    *par.fnorm = enorm<@nn>(fvec);
907    @i_transform
908    int ret = 0;
909    if (*par.info != 1) {
910        if (!(*par.info == 5 && *par.fnorm < 1e-20)) {
911            ret = -1;
912        }
913    }
914    @cleanup
915    return ret;
916}
917""")
918
919c_template_nonlin_chained = Template("""
920namespace @namespace {
921@global_data_def
922
923static int nonlin(struct nonlin_param &par) {
924    @chained_code
925}
926
927%if (@dev_interface)
928static inline int nonlin_solve(nonlin_param& par) {
929    return nonlin(par);
930}
931%end
932} // end namespace @namespace
933%if (@extern_nonlin)
934%parse ("c_template_calc_nonlin")
935%end
936""")
937
938c_template_nonlin_solver = Template("""
939namespace @namespace {
940@global_data_def
941
942@fcn_def
943
944@nonlin_def
945
946%if (@dev_interface)
947static Matrix<creal, @nni, 1> last_good;
948static Matrix<creal, @nn, 1> last_v0;
949
950int nonlin_homotopy(nonlin_param& par, creal f) {
951    Matrix<creal, @nni, 1> end = @par_p;
952    @par_p = last_good + (@par_p - last_good) * f;
953    @par_v = last_v0;
954    int ret = nonlin(par);
955    @par_p = end;
956    if (ret != 0) {
957        return ret;
958    }
959    last_v0 = @par_v;
960    return 0;
961}
962
963static inline int nonlin_solve(nonlin_param& par) {
964    @v0_guess
965    int ret = nonlin(par);
966    if (ret != 0) {
967        std::list<creal> points;
968        points.push_back(0);
969        points.push_back(0.5);
970        points.push_back(1);
971        for (int j = 0; j < @solver_max_homotopy_iter; j++) {
972            std::list<creal>::iterator it = points.begin();
973            ++it;
974            ret = nonlin_homotopy(par, *it);
975            if (ret != 0) {
976                points.insert(it, (*points.begin()+*it)/2);
977                continue;
978            }
979            if (points.size() == 2) {
980                break;
981            }
982            points.erase(points.begin());
983        }
984        if (ret != 0) {
985            return ret;
986        }
987    }
988    last_good = @par_p;
989    last_v0 = @par_v;
990    return 0;
991}
992%end
993} // end namespace @namespace
994
995%if (@extern_nonlin)
996%parse ("c_template_calc_nonlin")
997%end
998""")
999
1000c_template_table = Template("""
1001namespace @namespace {
1002static inline int nonlin(nonlin_param& par) {
1003    @call
1004    return 0;
1005}
1006
1007%if (@dev_interface)
1008static inline int nonlin_solve(nonlin_param& par) {
1009    return nonlin(par);
1010}
1011%end
1012
1013%parse ("c_template_calc_nonlin")
1014} // end @namespace
1015""")
1016
1017#
1018#-mavx -ffast-math
1019#
1020# ffast-math seems to trigger a compiler error on gcc 4.7.3
1021# according to documentation it expands into list of settings, including
1022# funsafe-math-optimizations, which seems to be responsible for the bug.
1023# But funsafe-math-optimizations in turn just expands into another list of
1024# settings. When using the expanded list of settings the bug is gone (?!).
1025#
1026# maybe -mavx is the culprit (removed for now)??
1027#
1028build_script_template = Template("""\
1029#! /bin/bash
1030cd `dirname $0`
1031fname="${1-@sourcename}"
1032lname="${2-@soname}"
1033lname_="${2-@soname_}"
1034mo="-fwrapv -ffast-math -msse2"
1035#mo="-fwrapv -fno-math-errno -ffinite-math-only -fno-rounding-math"
1036#mo="$mo -fno-signaling-nans -fcx-limited-range -fno-signed-zeros"
1037#mo="$mo -fno-trapping-math -fassociative-math -freciprocal-math"
1038: ${CC:=c++}
1039%if (@debug)
1040dbg="-g -O2"
1041%else
1042dbg="-O2 -Wl,--strip-all -DNDEBUG"
1043%end
1044co="-shared -fPIC -Wall -fvisibility=hidden"
1045lo="-Wl,-O1,-Bsymbolic-functions,-z,relro"
1046libs="@libraries"
1047inc="@includes"
1048def="@defines"
1049opt="-fno-stack-protector"
1050set -e
1051%if (@optimize)
1052$CC $co $lo $mo $opt -fprofile-arcs $dbg $CFLAGS $def $inc "$fname" -o "$lname_" $libs
1053python t.py
1054$CC $co $lo $mo $opt -fprofile-use $dbg $CFLAGS $def $inc "$fname" -o "$lname" $libs
1055%else
1056$CC $co $lo $mo $opt $dbg $CFLAGS $def $inc "$fname" -o "$lname" $libs
1057%end
1058""")
1059
1060faust_filter_template = Template("""\
1061%if (@build_script)\
1062// generated by @build_script
1063%else\
1064// generated automatically
1065%end
1066// DO NOT MODIFY!
1067declare id "@plugindef.id";
1068declare name "@plugindef.name";
1069declare category "@plugindef.category";
1070%if (@plugindef.shortname)\
1071declare shortname "@plugindef.shortname";
1072%end
1073%if (@plugindef.description)\
1074declare description "@plugindef.description";
1075%end
1076%if (@plugindef.samplerate)\
1077declare samplerate "@plugindef.samplerate";
1078%end
1079%if (@plugindef.oversample)\
1080declare oversample "@plugindef.oversample";
1081%end
1082%if (@plugindef.fixedrate)\
1083declare samplerate "@plugindef.fixedrate";
1084%end
1085
1086import("stdfaust.lib");
1087//TABLE
1088process = pre : fi.iir((@b_list),(@a_list)) with {
1089    LogPot(a, x) = ba.if(a, (exp(a * x) - 1) / (exp(a) - 1), x);
1090    Inverted(b, x) = ba.if(b, 1 - x, x);
1091    s = 0.993;
1092    fs = float(ma.SR);
1093    pre = @pre_filter;
1094
1095%for @sl in @sliders:
1096%if (@sl.loga)
1097    @sl.id = vslider("@sl.id[name:@sl.name][style:knob]", 0.5, 0, 1, 0.01) : Inverted(@sl.inv) : LogPot(@sl.loga) : si.smooth(s);
1098%else
1099    @sl.id = vslider("@sl.id[name:@sl.name][style:knob]", 0.5, 0, 1, 0.01) : Inverted(@sl.inv) : si.smooth(s);
1100%end
1101%end
1102
1103    @coeffs
1104};
1105""")
1106
1107module_ui_template = Template("""
1108b.openHorizontalhideBox("");
1109%if (@have_master_slider)
1110    b.create_master_slider(PARAM("@master_slider_id"), "@master_slider_id");
1111%end
1112b.closeBox();
1113b.openHorizontalBox("");
1114%for @k in @knob_ids:
1115    b.create_small_rackknobr(PARAM("@k"), "@k");
1116%end
1117b.closeBox();
1118""")
1119
1120faust_simple_filter_template = Template("""\
1121//TABLE
1122process = pre : fi.iir((@b_list),(@a_list)) with {
1123    LogPot(a, x) = ba.if(a, (exp(a * x) - 1) / (exp(a) - 1), x);
1124    Inverted(b, x) = ba.if(b, 1 - x, x);
1125    s = 0.993;
1126    fs = float(ma.SR);
1127    pre = @pre_filter;
1128
1129%for @sl in @sliders:
1130%if (@sl.loga)
1131    @sl.id = vslider("@sl.id[name:@sl.name][style:knob]", 0.5, 0, 1, 0.01) : Inverted(@sl.inv) : LogPot(@sl.loga) : si.smooth(s);
1132%else
1133    @sl.id = vslider("@sl.id[name:@sl.name][style:knob]", 0.5, 0, 1, 0.01) : Inverted(@sl.inv) : si.smooth(s);
1134%end
1135%end
1136
1137    @coeffs
1138};
1139""")
1140
1141module_simple_ui_template = Template("""
1142b.openHorizontalBox("");
1143%for @k in @knob_ids:
1144    b.create_small_rackknobr(PARAM("@k"), "@k");
1145%end
1146b.closeBox();
1147""")
1148
1149faust_filter_dry_wet_template = Template("""\
1150%if (@build_script)\
1151// generated by @build_script
1152%else\
1153// generated automatically
1154%end
1155// DO NOT MODIFY!
1156declare id "@plugindef.id";
1157declare name "@plugindef.name";
1158declare category "@plugindef.category";
1159%if (@plugindef.shortname)\
1160declare shortname "@plugindef.shortname";
1161%end
1162%if (@plugindef.description)\
1163declare description "@plugindef.description";
1164%end
1165
1166import("stdfaust.lib");
1167//TABLE
1168process = pre : _<:*(dry),(*(wet) : fi.iir((@b_list),(@a_list))):>_ with {
1169    LogPot(a, x) = ba.if(a, (exp(a * x) - 1) / (exp(a) - 1), x);
1170    Inverted(b, x) = ba.if(b, 1 - x, x);
1171    s = 0.993;
1172    fs = float(ma.SR);
1173    pre = @pre_filter;
1174    wet = vslider("wet_dry[name:wet/dry][tooltip:percentage of processed signal in output signal]",  100, 0, 100, 1) : /(100);
1175    dry = 1 - wet;
1176
1177%for @sl in @sliders:
1178%if (@sl.loga)
1179    @sl.id = vslider("@sl.id[name:@sl.name][style:knob]", 0.5, 0, 1, 0.01) : Inverted(@sl.inv) : LogPot(@sl.loga) : si.smooth(s);
1180%else
1181    @sl.id = vslider("@sl.id[name:@sl.name][style:knob]", 0.5, 0, 1, 0.01) : Inverted(@sl.inv) : si.smooth(s);
1182%end
1183%end
1184
1185    @coeffs
1186};
1187""")
1188
1189module_ui_dry_wet_template = Template("""
1190b.openHorizontalhideBox("");
1191%if (@have_master_slider)
1192    b.create_master_slider(PARAM("@master_slider_id"), "@master_slider_id");
1193%end
1194b.closeBox();
1195b.openHorizontalBox("");
1196%for @k in @knob_ids:
1197    b.create_small_rackknobr(PARAM("@k"), "@k");
1198%end
1199    b.create_small_rackknobr(PARAM("wet_dry"), "dry/wet");
1200b.closeBox();
1201""")
1202
1203faust_simple_filter_dry_wet_template = Template("""\
1204//TABLE
1205process = pre : _<:*(dry),(*(wet) : fi.iir((@b_list),(@a_list))):>_ with {
1206    LogPot(a, x) = ba.if(a, (exp(a * x) - 1) / (exp(a) - 1), x);
1207    Inverted(b, x) = ba.if(b, 1 - x, x);
1208    s = 0.993;
1209    fs = float(ma.SR);
1210    pre = @pre_filter;
1211    wet = vslider("wet_dry[name:wet/dry][tooltip:percentage of processed signal in output signal]",  100, 0, 100, 1) : /(100);
1212    dry = 1 - wet;
1213
1214    %for @sl in @sliders:
1215        @sl.id = vslider("@sl.id[name:@sl.name][style:knob]", 0.5, 0, 1, 0.01) : Inverted(@sl.inv) : LogPot(@sl.loga) : si.smooth(s);
1216    %end
1217
1218    @coeffs
1219};
1220""")
1221
1222module_simple_ui_dry_wet_template = Template("""
1223b.openHorizontalBox("");
1224%for @k in @knob_ids:
1225    b.create_small_rackknobr(PARAM("@k"), "@k");
1226%end
1227    b.create_small_rackknobr(PARAM("wet_dry"), "dry/wet");
1228b.closeBox();
1229""")
1230