
// Manifest constants.
const SR = 44100; // samplerate for the DSP
const n  = 10;    // #samples per block

/* The Faust dsp. This dsp just mixes its two input channels and applies a
   gain factor which can be set using a corresponding control. In this example
   we simply inline the Faust code. Of course, you can also compile the Faust
   code separately and then import it with a 'using' clause. The freeverb
   example in this directory shows how to do this.

   Note that we also added some metadata (dsp version, MIDI controller
   assignment) for illustration purposes. Faust simply records this data and
   makes it available. It's up to the application (i.e., the Pure script) to
   interpret the metadata as it sees fit. */

%< -*- dsp:test -*-
declare version "1.0";
gain = nentry("gain [midi:ctrl 0x01]", 0.3, 0, 10, 0.01);
process = + : *(gain);
%>

/* Create an instance of the Faust dsp and initialize it. This returns a
   pointer to a block of memory holding the dsp's internal state, which is
   then passed to the other operations of the Faust module. NOTE: These dsp
   pointers are always equipped with a sentry which takes care of deleting the
   object automatically when it gets garbage-collected, so that you don't have
   to worry about memory leaks. */

let dsp = test::newinit SR;

/* Get manifest information about the dsp. This returns the number of I/O
   channels and the description of the control variables (the "UI" of the dsp
   in Faust parlance) in a Pure-friendly format. The UI data is used below to
   get access to the control values. It takes the form of a tree data
   structure described in the faustui.pure module distributed with Pure.
   (Incidentally, this is the same format that the pure-faust module uses.)
   Here we employ one of the utility functions in the faustui module,
   'controls', to convert this data to a flat Pure list which is more
   convenient for our purposes.

   We also use the Faust RTTI interface in the faustui module to retrieve the
   name of the Faust module (as a string) as well as the sample and control
   data format of the dsp (this is simply a flag, true denotes double
   precision). NOTE: We recommend to always use double precision (faust
   -double) with Pure since this avoids conversion of the sample data and is
   thus more efficient. This is also the default with inlined Faust
   code. However, the code below will work with either double or single
   precision format. */

using faustui;
let k,l,ui = test::info dsp;
let ui = controls ui;
let name,dbl = dsp_name dsp, dsp_doublep dsp;

/* As of Pure 0.50 it is also possible to query the metadata of a Faust
   module. This takes the form of a list of key=>val string pairs, which comes
   in two flavours (please check the Faust documentation for details):

   Control metadata is associated with control variables and shows up in the
   UI part of the dsp info (see above). It provides auxiliary information
   about a control, such as hints about units, GUI layout or MIDI controller
   assignments.

   Global metadata is static data which applies to all dsps of a given
   class. It typically includes items such as the name, version and author of
   the dsp, which can optionally be included in a Faust programs by means of
   the 'declare' statement. Here we use this information to retrieve the
   version number of the dsp if it is available. */

let m = record test::meta;
let name = if member m "version" then name+" "+m!"version" else name;

// Print some information about the dsp.
using system;
printf "-- dsp: %s --\n" name;
printf "#inputs:  %d\n" k;    // => 2
printf "#outputs: %d\n" l;    // => 1
printf "sample format: %s\n" (if dbl then "double" else "float");
printf "controls: %s\n" $ str ui;

/* Set up some input and output buffers. On the Pure side, these are
   represented as double matrices with one row per input/output channel. The
   number of columns determines the block size (number of samples per channel
   to be processed) and must be the same for input and output. */

let in  = {i*10.0+j | i = 1..k; j = 1..n};
let out = {0.0 | i = 1..l; j = 1..n};

// Process some samples and print the result.
test::compute dsp n in out;
printf "in:  %s\n" $ str in;  // => {11.0,12.0,13.0,...;21.0,22.0,23.0,...}
printf "out: %s\n" $ str out; // => {9.6,10.2,10.8,...}

/* For easier access, we now turn the list of controls into a record mapping
   control names to the corresponding pointers. */

let ui = control_map ui;

// Play with the 'gain' control variable.
let gain = ui!"gain";
printf "old gain: %g\n" $ get_control gain;
put_control gain 1.0;
printf "new gain: %g\n" $ get_control gain;
// Compute some more samples with the new gain value.
test::compute dsp n in out;
printf "in:  %s\n" $ str in;  // => {11.0,12.0,13.0,...;21.0,22.0,23.0,...}
printf "out: %s\n" $ str out; // => {32.0,34.0,36.0,...}
