FAUST parameters and buttons

Our FAUST bindings are currently lacking a way to set or send output parameters, such as the CV outputs on Wizard and Magus.

There is however a ‘foreign function’ which allows you to control the OWL Modular trigger output. It looks like this:

push = ffunction(int owl_pushbutton(int), <owl.h>,"");

and you can then send an int to push to toggle the output.

We could generalise this to send arbitrary button and parameter changes. Maybe something like this:

owl_push = ffunction(int owl_pushbutton(int), <owl.h>,"");
owl_button = ffunction(int owl_button(int, int), <owl.h>,"");
owl_parameter = ffunction(int owl_parameter(int, float), <owl.h>,"");

and define some constants to identify the assignments:

OWL_A = fconstant(int PARAMETER_A, <owl.h>);
...
OWL_B1 = fconstant(int BUTTON_A, <owl.h>);
....

All this could be rolled into an owl.lib include file, so at the start of your FAUST patch you just need to

import("owl.lib");

and then if, for some reason, you wanted to route Button 1 input to Button 6 output you could just do this:

process = button("Button1[OWL:B1]") : owl_button(OWL_B6);

or with parameters:

process = hslider("[OWL:A]",0,0,1,0.01) : owl_parameter(OWL_G);

Of course the FAUST bindings, or architecture, also needs updating to support this. Oh and I’m planning to change the button names! No more ButtonA or ButtonB, they’ll be B1, B2 et c. Okay?

The examples above actually work, I’ve done the changes locally and tested it.
However I’m pretty useless with FAUST, so I can’t say if this is a great idea or a rubbish one.

In particular I’m not sure how to manage this in a FAUST graph, where these foreign functions are really identity functions with side effects. Do I have to add dummy signal paths to send data into the functions? Where do they end up going?

Uhm, scratch that! I see that @antisvin has already implemented output parameters. Lost that bit of information somewhere, somehow!

So the way to do it is with bargraph and attach, yeah?

https://github.com/antisvin/OpenWareLab/blob/faust-docs/Faust/Faust.md#parameter-output

bargraph is a much nicer way to do it than foreign functions, since the patches will still work on other FAUST targets.

I think the code could just be generalised to accept both button and parameter assignments in the bargraph declaration.

Here’s a branch with both foreign functions and bargraph buttons: GitHub - pingdynasty/OwlProgram at feature/faust-buttons

Yeah, no need to use FF for outputs. It’s still necessary to use “>” for output names in current implementation, but this probably could be changed by adding a service call to access setPortMode from patches.

Also, there’s a PR for V/oct support in Faust patches, I suspect it was forgotten. The funny thing is that it does add owl.lib with FF wrappers.

I mean, I usually troubleshoot non-trivial patches on desktop, so wouldn’t use non-portable code that can’t be built. And buttons support wasn’t added initially, because:

  1. this was intended for Magus that doesn’t have gate outputs
  2. Faust doesn’t have a dedicated widget for boolean outputs

But they should definitely be added for bargraphs too.

Another issue with foreign functions is that they could be called per sample if user changes input on audio rate (say, uses the gate as a comparator for audio). Of course, we would be only outputting data once per block, and Faust also updates UI once per block. So this is a more effective solution.

Okay so PR and changes are merged and deployed!

The foreign functions I added are still there but will probably be removed, in favour of bargraph.
But for now you can do crazy stuff like this:

import("stdfaust.lib");
import("owl.lib");

freq = hslider("freq[OWL:A]",220,20,1280,0.01) : si.smoo;
gain = hslider("gain[OWL:B]",0.5,0,1,0.01) : si.smoo;
gate = button("gate[OWL:PUSH]") : si.smoo;
cutoff = hslider("cutoff[OWL:C]",220,20,2000,0.01) : si.smoo;

osc = os.sawtooth(freq)*gain*gate : fi.lowpass(3,cutoff);
cv1 = hslider("cv[OWL:D]",0,0,1,0.01) : owl_parameter(OWL_F);
cv2 = hslider("cv[OWL:D]",0,0,1,0.01) : hbargraph("f[OWL:G]", 0, 1);
tr1 = button("tr[OWL:B2]") : owl_button(OWL_B5);
tr2 = button("tr2[OWL:B3]") : hbargraph("b5[OWL:B6]", 0, 1);

process = attach(osc, (cv1, cv2, tr1, tr2) :> _);