
/* faustui.pure: Provide access to the control descriptions of a Faust dsp. */

/* Copyright (c) 2009-2012 by Albert Graef <Dr.Graef@t-online.de>.

   This file is part of the Pure standard library.

   The Pure standard library is free software: you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public License as
   published by the Free Software Foundation, either version 3 of the License,
   or (at your option) any later version.

   Pure is distributed in the hope that it will be useful, but WITHOUT ANY
   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
   more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>. */

/* Note that Pure's new internal Faust interface uses the same format of UI
   description as the pure-faust module, so the code below works with both the
   internal interface and pure-faust. */

/* Constructors for control descriptions. Such descriptions are returned by
   the 'info' function of a Faust dsp.

   There are various basic control elements, each associated with a control
   variable 'ref', metadata 'meta' and a parameter tuple 'args'. The latter
   are the arguments of the control element as given in the Faust program.
   Thus, e.g., 'button ref meta "Push me!"' would denote a button with label
   "Push me!", and 'hslider ref meta ("gain",1.0,0.0,10.0,0.1) a horizontal
   slider with label "gain" and the given initial, min, max and step size
   values.

   The control variable itself is implemented as a C pointer 'ref' which,
   depending on the dsp's sample format, points either to a C float or a C
   double value. Changing the value pointed to by 'ref' using 'put_double' or
   'put_float' (before invoking the dsp's 'compute' function) assigns a new
   value to the corresponding control element in the Faust dsp. Passive
   control elements such as 'vbargraph' have their value updated during
   invocation of the 'compute' function, and can then be read using
   'get_double' or 'get_float'.

   The 'meta' argument is a list of key=>val string pairs holding any metadata
   associated with the control, such as MIDI controller assignments, layout
   instructions, etc.; please check the Faust documentation for details.

   There are also three constructors for denoting groups of controls,
   'vgroup', 'hgroup' and 'tgroup'. These take two arguments: 'meta' has the
   metadata associated with the group, in the same format as above, and 'args'
   is a pair (label,elems) consisting of the label of the group, as given in
   the Faust program, and the list of all control elements in that group. The
   toplevel control element is always a group (a 'vgroup' by default). */

public button checkbox vslider hslider nentry vbargraph hbargraph
  vgroup hgroup tgroup;

/* Convenience functions to retrieve the components of a control description.
   The control_type, control_ref, control_meta and control_label functions
   return the type (i.e., constructor), reference (a C double* or float*
   pointer), metadata (a list of key=>val string pairs) and label of a
   control, respectively. control_args yields the remaining control
   parameters. */

control_type (f@_ ptr meta args) |
control_type (f@_ meta args) = f;

control_ref (_ ptr meta args) = ptr;

control_meta (_ ptr meta args) |
control_meta (_ meta args) = meta;

control_label (_ ptr meta (label,args)) |
control_label (_ meta (label,args)) |
control_label (_ ptr meta label::string) |
control_label (_ ptr label::string) = label;

control_args (_ ptr meta (label,args)) |
control_args (_ meta (label,args)) = args;
control_args (_ ptr meta label::string) |
control_args (_ ptr label::string) = ();

/* The following function returns a flat representation of a control group as
   a list of basic control descriptions, which provides a quick way to access
   all the control values of a Faust DSP. The grouping controls themselves are
   omitted. */

controls (_ _ (_,ctls::rlist)) = catmap controls ctls;
controls x = [x] otherwise;

/* The following function works like the controls function above, but also
   replaces the label of each basic control with a fully qualified path
   consisting of all control labels leading up to the given control. Thus,
   e.g., the label of a slider "gain" inside a group "voice#0" inside the
   main "faust" group will be denoted by the label "faust/voice#0/gain". */

pcontrols x = controls "" x with
  controls path x =
    case x of
      _ _ (label::string,ctls::rlist) =
	catmap (controls (join path label)) ctls;
      f@_ ptr meta (label::string,args) = [f ptr meta (join path label,args)];
      f@_ ptr meta label::string = [f ptr meta (join path label)];
      _ = [x]; // bad control description
    end;
  join "" s::string |
  join s::string "" = s;
  join s::string t::string = s+"/"+t otherwise;
end;

/* Convenience function to turn a control list (as returned by controls or
   pcontrols above) into a record mapping control names to the corresponding
   pointers. */

control_map ui = { control_label c => control_ref c | c = ui };

/* Same for the metadata. */

control_metamap ui = { control_label c => control_meta c | c = ui };

/* Convenience functions to get and set a control value, based on the actual
   pointer type of the control. */

get_control x::pointer = get_float x if get_ptrtag x == __C::floatp_t;
	    	       = get_double x if get_ptrtag x == __C::doublep_t;

put_control x::pointer = put_float x if get_ptrtag x == __C::floatp_t;
	    	       = put_double x if get_ptrtag x == __C::doublep_t;

/* As of Pure 0.45, the Faust interface now also offers some rudimentary
   reflection capabilities, which are declared below. Currently the following
   functions are provided (note that for cosmetic purposes these have slightly
   different names than in the runtime API):

   - dsp_name and dsp_doublep return the module name (as a string) and the
     sample format of the given dsp object. The latter is just a flag which is
     true iff double samples and control values are used; false indicates
     single precision.

   - dsp_fun gives access to the visible interface functions of a Faust dsp.
     The given name may be any of the supported operations, such as "new",
     "init", "compute", etc. The first argument must either be the name of a
     dsp class (a string) or a dsp object (as returned with 'new' or
     'newinit'). The result is usually a closure. E.g., dsp_fun "organ"
     "newinit" returns organ::newinit (if it exists), while dsp_fun dsp
     "compute" returns the compute function for the class of the given dsp
     object. The only exception from this rule is the 'new' function which
     takes no arguments and thus is evaluated immediately. E.g., dsp_fun
     "organ" "new" doesn't return organ::new itself, but its value, i.e., a
     new dsp instance of the "organ" class.

   - dsp_modules builds a list of all Faust modules currently loaded. It
     returns a list of hash pairs name=>dbl, where name is the module name and
     dbl the sample format. This information is useful if you need to create
     and manipulate Faust dsps dynamically.

   All these functions work both in the interpreter and in batch-compiled
   scripts. */

extern expr *faust_name(expr *dsp) = dsp_name;
extern expr *faust_dbl(expr *dsp) = dsp_doublep;
extern expr *faust_method(expr *dsp, char *name) = dsp_fun;
extern expr *faust_mods() = dsp_modules;
