[rai scribble docs
tom@zwizwa.be**20130529155037
Ignore-this: b03719f203fe82c12929c2b63c1a77bd
] move ./rai/doc/rai.html ./rai/doc/rai_merge_later.html
hunk ./meta.txt 29999
--load/-store doesn't work. Time to think a bit about it.
+-load/-store inside a loop doesn't work. Time to think a bit about
+it.
hunk ./meta.txt 30015
+
+Entry: Stream vs. param
+Date: Wed May 29 08:50:46 EDT 2013
+
+What about making inputs referred to in a `hold' automatically into a
+param?
+
+
+Entry: Time feedback
+Date: Wed May 29 08:51:49 EDT 2013
+
+Still doesn't sit well. Doing stuff behind the scenes seems
+unnatural. While composition of recursive systems is nice, it is not
+clear where the state goes. So having an explicit "capture" for the
+state feedback might be a better approach.
+
+Making the time loop explicit will also remove the awkward "hold" and
+"setup" constructs. But it will break stream semantics.
+
+Essentially, what is needed is some construct that will transform what
+we have now into an explicit loop form like this:
+
+(loop (t (t_endx 64))
+ ((acc ...))
+ ((in ...))
+ body)
+
+Where all the acc stuff is threaded.
+
+The threading really is an essential feature, but it has an intrinsic
+conflict: can't get at that which is hidden!
+
+So, the stream semantics is essential.
+
+
+Entry: RAI doc merge
+Date: Wed May 29 09:16:06 EDT 2013
+
+
+
+
+
+
+ RAI
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
RAI
+ Introduction
+
+
+
+
+
+
+
+
+
+
+
+
Go over FeldSpar and its goals and inspirations.
+This paper has a nice list of references to Spiral, Pan, Obsidian,
+
+
+
Compared to existing systems, RAI is probably most similar
+to Faust, a functional stream
+processor language developed at Grame in France. The main difference
+with Faust are:
+
+
RAI is an extention to an established programming language,
+i.e. Racket, a Scheme
+dialect with extensive support for writing embedded DSLs.
+
A core element of RAI is the ability to easily construct
+alternative language interpretations.
+
RAI supports control rate programming, allowing slow rate update of parameters that are expensive to compute.
+
Feedback in RAI follows a more traditional approach using a state-space update equation, while faust uses a 2-operand combinator.
+
On the practical side, Faust is over 10 years old and has a lot of support and libraries.
+
Faust has a more sophisticated compiler/optimizer.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
hunk ./rai/Makefile 45
+
+%.html: %.scrbl
+ scribble --html --dest $(dir $@) $<
+
+
addfile ./rai/demo.rkt
hunk ./rai/demo.rkt 1
+#lang scheme/base
+
addfile ./rai/doc/rai.scrbl
hunk ./rai/doc/rai.scrbl 1
+#lang scribble/doc
+@(require scribble/manual
+ scribble/eval
+)
+
+@(define-syntax-rule ($ id) (racket id))
+
+@title{RAI}
+
+@section{Introduction}
+
+Racket Abstract Interpretation (RAI), is a code analysis and
+generation system built around a domain specific language (DSL).
+
+The DSL is a purely functional dataflow language aimed at
+describing digital signal processing (DSP) algorithms, and is embedded
+in the @hyperlink["http://racket-lang.org" "Racket"] programming
+language as @codeblock|{#lang s-exp (planet zwizwa/rai/stream)}|
+
+The system allows for multiple abstract interpretations (AI) of
+programs expressed in the DSL. Some interpretations included are
+
+@itemlist[
+
+@item{Scheme code for interactive exploration}
+
+@item{Dependency-free C code to run on small target systems}
+
+@item{linear(ized) transfer function for frequency analysis}
+
+@item{Automatic Differentiation}
+
+@item{Racklog program for logic analysis}
+
+@item{Symbolic mathematical expressions}
+
+]
+
+Adding such interpretations is straightforward. The core language is
+represented as abstract syntax, parameterized by a structure
+describing the implementation of the language primitives. Writing a
+new interpretation involves the execution of a program parameterized
+by such a description, often in some form of context.
+
+Program interpretations can be constructed to be composable, i.e. an
+iterpretation can transform a RAI program into another RAI program.
+
+
+
+@section{Time and Space}
+
+The language consists mostly of two parts, reflecting the qualitative
+difference of time and space dimensions.
+
+@itemlist[
+
+@item{An arithmetic core that can be given both a scalar and a stream
+semantics, in that basic operators operate on scalar values or
+infinite stream values, possibly collected in finite, nested
+@emph{spatial} arrays.}
+
+@item{A a collection of primitives that allows the creation of
+@emph{causal temporal} relations, requiring a stream interpretation of
+the input/output data.}
+
+]
+
+The design of the temporal primitives is motivated by applications from
+the domain of musical signal processing (music DSP). Such applications
+
+@itemlist[
+
+@item{rely heavily on the composition of output feedback systems such
+as linear IIR filters and other state machines, and}
+
+@item{often use a parameter update scheme that executes at a lower
+sampling rate, i.e. the @emph{control rate}.} ]
+
+The semantics of the full stream processing language is quite close to
+that of @hyperlink["http://faust.grame.fr" "Faust"].
+
+
+@section{Memory--less Operations}
+
+@itemlist[
+@item{Arithmetic operations:
+@$[+]
+@$[-]
+@$[*]
+@$[/]
+@$[sin]
+@$[cos]
+@$[exp]
+@$[log]
+...
+}
+@item{Finite array traversal with accumulator and array output: @$[loop]}
+@item{Scheme language forms:
+@$[define]
+@$[lambda]
+@$[let]
+@$[let*]
+@$[let-values]
+@$[let*-values]
+@$[values]
+...
+}
+@item{Standard Scheme forms for @emph{unrolled} Metaprogramming}
+]
+
+@section{Causal Stream Operations}
+
+@itemlist[
+@item{Unit delay output-feedback form: @$[feedback]}
+@item{Control-rate operators: @$[hold] @$[setup]}
+@item{Support for variable length delay lines.}
+]
+
+
+@section{Unrolled Metaprogramming}
+
+In some cases it is desirable to specify an algorithm at a higher
+level using data structures and associated operations that are not
+supported on a target platform. E.g. in RAI the C target only
+supports operations on (nested) linear arrays, which is a
+straightforward translation of the @$[loop] construct.
+
+In this case, ideally one would want to relate the higher level data
+structures and manipulations to some optimized combination of loops
+over arrays. A good example of this is the way in which loop fusion
+is performed in the
+@hyperlink["http://dsl4dsp.inf.elte.hu/feldspar/index.html"
+"Feldspar"] language. Such an approach requires a certain amount of
+trickery to be implemented.
+
+There is another way to perform powerful code generation when one
+drops to manipulation of scalar values, which relate to variable nodes
+in a generated program. This approach could be called the generation
+of @emph{flat} or @emph{unrolled} code.
+
+The RAI language contains primitives for array construction and
+deconstruction that allows this form of flexible code generation to be
+combined with the C target's array datastructures. The automatic
+array unpacking is performed in the @$[map] operator.
+
+
+Keep in mind that while this can lead to efficient implementations if
+the unrolling exposes optimization opportunities, in general the
+unrolling can be quite inefficient concerning code size if it is
+applied to large collections of data.
+
+
+
+@section{Examples}
+@defmodule[(planet zwizwa/rai/demo)]
+
+
hunk ./rai/doc/rai_merge_later.html 1
-
-
-
-
-
- RAI
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
RAI
- Introduction
-
-
-
-
-
-
-
-
-
-
-
-
Go over FeldSpar and its goals and inspirations.
-This paper has a nice list of references to Spiral, Pan, Obsidian,
-
-
-
Compared to existing systems, RAI is probably most similar
-to Faust, a functional stream
-processor language developed at Grame in France. The main difference
-with Faust are:
-
-
RAI is an extention to an established programming language,
-i.e. Racket, a Scheme
-dialect with extensive support for writing embedded DSLs.
-
A core element of RAI is the ability to easily construct
-alternative language interpretations.
-
RAI supports control rate programming, allowing slow rate update of parameters that are expensive to compute.
-
Feedback in RAI follows a more traditional approach using a state-space update equation, while faust uses a 2-operand combinator.
-
On the practical side, Faust is over 10 years old and has a lot of support and libraries.
-
Faust has a more sophisticated compiler/optimizer.
-
-
-
-
-
-
-
-
-
-
-
rmfile ./rai/doc/rai_merge_later.html
addfile ./rai/doc/scribble-common.js
hunk ./rai/doc/scribble-common.js 1
+// Common functionality for PLT documentation pages
+
+// Page Parameters ------------------------------------------------------------
+
+var page_query_string =
+ (location.href.search(/\?([^#]+)(?:#|$)/) >= 0) && RegExp.$1;
+
+var page_args =
+ ((function(){
+ if (!page_query_string) return [];
+ var args = page_query_string.split(/[&;]/);
+ for (var i=0; i= 0) args[i] = [a.substring(0,p), a.substring(p+1)];
+ else args[i] = [a, false];
+ }
+ return args;
+ })());
+
+function GetPageArg(key, def) {
+ for (var i=0; i= 0 && cur.substring(0,eql) == key)
+ return unescape(cur.substring(eql+1));
+ }
+ return def;
+}
+
+function SetCookie(key, val) {
+ var d = new Date();
+ d.setTime(d.getTime()+(365*24*60*60*1000));
+ try {
+ document.cookie =
+ key + "=" + escape(val) + "; expires="+ d.toGMTString() + "; path=/";
+ } catch (e) {}
+}
+
+// note that this always stores a directory name, ending with a "/"
+function SetPLTRoot(ver, relative) {
+ var root = location.protocol + "//" + location.host
+ + NormalizePath(location.pathname.replace(/[^\/]*$/, relative));
+ SetCookie("PLT_Root."+ver, root);
+}
+
+// adding index.html works because of the above
+function GotoPLTRoot(ver, relative) {
+ var u = GetCookie("PLT_Root."+ver, null);
+ if (u == null) return true; // no cookie: use plain up link
+ // the relative path is optional, default goes to the toplevel start page
+ if (!relative) relative = "index.html";
+ location = u + relative;
+ return false;
+}
+
+// Utilities ------------------------------------------------------------------
+
+var normalize_rxs = [/\/\/+/g, /\/\.(\/|$)/, /\/[^\/]*\/\.\.(\/|$)/];
+function NormalizePath(path) {
+ var tmp, i;
+ for (i = 0; i < normalize_rxs.length; i++)
+ while ((tmp = path.replace(normalize_rxs[i], "/")) != path) path = tmp;
+ return path;
+}
+
+// `noscript' is problematic in some browsers (always renders as a
+// block), use this hack instead (does not always work!)
+// document.write("");
+
+// Interactions ---------------------------------------------------------------
+
+function DoSearchKey(event, field, ver, top_path) {
+ var val = field.value;
+ if (event && event.keyCode == 13) {
+ var u = GetCookie("PLT_Root."+ver, null);
+ if (u == null) u = top_path; // default: go to the top path
+ u += "search/index.html?q=" + escape(val);
+ if (page_query_string) u += "&" + page_query_string;
+ location = u;
+ return false;
+ }
+ return true;
+}
+
+function TocviewToggle(glyph, id) {
+ var s = document.getElementById(id).style;
+ var expand = s.display == "none";
+ s.display = expand ? "block" : "none";
+ glyph.innerHTML = expand ? "▼" : "►";
+}
+
+// Page Init ------------------------------------------------------------------
+
+// Note: could make a function that inspects and uses window.onload to chain to
+// a previous one, but this file needs to be required first anyway, since it
+// contains utilities for all other files.
+var on_load_funcs = [];
+function AddOnLoad(fun) { on_load_funcs.push(fun); }
+window.onload = function() {
+ for (var i=0; i
+ .techinside doesn't work with IE, so use both (and IE doesn't
+ work with inherit in the second one, so use blue directly) */
+.techinside { color: black; }
+.techinside:hover { color: blue; }
+.techoutside:hover>.techinside { color: inherit; }
+
+.SCentered {
+ text-align: center;
+}
+
+.imageleft {
+ float: left;
+ margin-right: 0.3em;
+}
+
+.Smaller{
+ font-size: 82%;
+}
+
+.Larger{
+ font-size: 122%;
+}
+
+/* A hack, inserted to break some Scheme ids: */
+.mywbr {
+ width: 0;
+ font-size: 1px;
+}
+
+.compact li p {
+ margin: 0em;
+ padding: 0em;
+}
+
+.noborder img {
+ border: 0;
+}
+
+.SAuthorListBox {
+ position: relative;
+ float: right;
+ left: 2em;
+ top: -2.5em;
+ height: 0em;
+ width: 13em;
+ margin: 0em -13em 0em 0em;
+}
+.SAuthorList {
+ font-size: 82%;
+}
+.SAuthorList:before {
+ content: "by ";
+}
+.author {
+ display: inline;
+ white-space: nowrap;
+}
+
+/* print styles : hide the navigation elements */
+@media print {
+ .tocset,
+ .navsettop,
+ .navsetbottom { display: none; }
+ .maincolumn {
+ width: auto;
+ margin-right: 13em;
+ margin-left: 0;
+ }
+}
hunk ./rai/rai.h 1
-#ifndef _RAI_H_
-#define _RAI_H_
-
-#include
-#include // host side depends on math.h, but prim.h does not.
-#include
-
-#define PROC_CMD_INFO -1
-
-typedef unsigned long long u64;
-typedef unsigned int u32;
-typedef unsigned char u8;
-typedef unsigned long word_t; // pointer-sized int
-#define CT_ASSERT(name,expr) typedef int _assert_##name[-(!(expr))]
-
-// Used for run-time loading
-#define RAI_MAGIC_SIZE 16
-#define RAI_MAGIC "rai/x86-64/1 "
-
-#define RAI_VERSION_SIZE 16
-
-
-/* The main approach for metadata is to keep the data dumb and
- non-reduntant. Interpretation of the format can be abstracted in a
- library.
-
- rai_info is structured data, where all pointers (to strings and
- substructures) are represented by a u64 file offset.
-*/
-typedef void (*rai_info_run)(float *state,
- float **in,
- float *param,
- float **out,
- float *store,
- int nb_samples);
-struct rai_info_param;
-struct rai_info_control;
-
-struct rai_info {
- u8 magic[RAI_MAGIC_SIZE];
- u8 version[RAI_VERSION_SIZE];
- rai_info_run entry;
-
- /* Node type info. */
- struct rai_info_param *info_state;
- struct rai_info_param *info_in;
- struct rai_info_param *info_param;
- struct rai_info_param *info_out;
- struct rai_info_param *info_store;
-
- /* param UI info. */
- struct rai_info_control *info_control;
-
- /* Misc info */
- u32 build_stamp;
- u32 __reserved;
-
-} __attribute__((__packed__));
-
-
-/* param meta info */
-enum rai_scale {
- rai_scale_lin = 0, // s0 + (s1 - s1) * v
- rai_scale_log = 1, // s1 * (s1 / s1) ^ v
- rai_scale_slog = 2, // s2 * (v/(1-v)) ^ s2 "squeezed log / stretched exp"
-};
-struct rai_info_control {
- int index;
- const char *desc;
- const char *unit;
- enum rai_scale scale;
- float s0; // minimum | center
- float s1; // maximum | exponent
- float range;
-} __attribute__((__packed__));
-
-struct rai_info_param {
- char *name;
- u32 *dims;
-} __attribute__((__packed__));
-
-struct rai_info_preset {
- u8 magic[RAI_MAGIC_SIZE];
- u32 header_bytes;
- u32 timestamp;
- u32 payload_bytes;
-} __attribute__((__packed__));
-
-/* Maps v \in [0,1] to the control parameter's user feedback scale. */
-static inline float rai_info_control_interpolate(const struct rai_info_control *p, float v) {
- float out_v;
- switch(p->scale) {
- case rai_scale_lin: out_v = p->s0 + (p->s1 - p->s0) * v; break;
- case rai_scale_log: out_v = p->s0 * pow(p->s1 / p->s0, v); break;
- case rai_scale_slog: out_v = p->s0 * pow(v / (1-v), p->s1); break;
- default: out_v = v; break;
- }
- return out_v;
-}
-
-
-/* Load .sp class */
-struct rai_info *rai_load_bin(const char *filename);
-
-/* Allocation size in nb floats */
-int rai_info_size(const struct rai_info_param *rp);
-
-/* Parameter offset and dimensions. */
-bool rai_info_find(const struct rai_info_param *pi,
- const char *name, int *offset, u32 **dims);
-
-/* Create proc instance. */
-struct rai_proc {
- const struct rai_info *info;
- float *state;
- float *param;
- float *store;
-};
-static inline void rai_proc_run(struct rai_proc *p, float **in, float **out, int n) {
- p->info->entry(p->state, in, p->param, out, p->store, n);
-}
-struct rai_proc *rai_proc_new(const struct rai_info *info,
- const struct rai_proc *proto);
-void rai_proc_free(struct rai_proc *p);
-
-void rai_proc_preset_save(const struct rai_proc *p, const char *filename);
-void rai_proc_preset_load(const struct rai_proc *p, const char *filename, int index);
-
-
-#ifndef PROC
-#define PROC(x) proc_##x
-#endif
-
-#define PROC_NB_EL(x,t) ((sizeof(x) / sizeof(t)))
-#define PROC_PARAM_DIM(name) PROC_NB_EL(((struct PROC(param) *)0)->name, float)
-
-#define proc_size_param PROC_NB_EL(struct proc_param, float)
-#define proc_size_in PROC_NB_EL(struct proc_in, float*)
-#define proc_size_out PROC_NB_EL(struct proc_out, float*)
-#define proc_size_state PROC_NB_EL(struct proc_si, float)
-#define proc_size_store PROC_NB_EL(struct proc_store, float)
-
-/* Synth stuff */
-struct rai_voice {
- int nb;
- float *gate;
- float *freq;
- int next;
-};
-/* Simple round-robin voice allocator.
- Some extensions:
- - "pedal" action to set the decay of all voices
- - voice stealing based on envelope decay
-*/
-
-static inline void rai_voice_init(struct rai_voice *v, int nb, float *gate, float *freq) {
- v->nb = nb;
- v->gate = gate;
- v->freq = freq;
- v->next = 0;
-}
-
-static inline void rai_voice_on(struct rai_voice *v, float freq) {
- v->gate[v->next] = 1;
- v->freq[v->next] = freq;
- v->next = (v->next + 1) % v->nb;
-}
-static inline void rai_voice_off(struct rai_voice *v, float freq) {
- /* Turn off 0 or 1 notes, start from oldest. */
- for (int i=1; i<=v->nb; i++) {
- int j = (v->nb + v->next - i) % v->nb;
- if (v->freq[j] == freq) {
- v->gate[j] = 0;
- break;
- }
- }
-}
-static inline float rai_midi_to_freq(int midi) {
- // 69 -> 440
- float fmidi = midi-69;
- return 440 * pow(2, fmidi/12);
-}
-
-
-
-
-/* DEBUG */
-typedef void (*rai_log)(const char *msg, ...);
-void rai_print_info(const struct rai_info *ri, rai_log log);
-
-#endif
-
-
rmfile ./rai/rai.h
hunk ./rai/rai.html 1
-
-
-
rmfile ./rai/rai.html
hunk ./rai/stream-syntax.rkt 144
+(define-syntax ai-feedback
+ (syntax-rules ()
+ ((_ (s0 ...) fn)
+ (ai-app ai-feedback/n
+ '((#f . s0) ...)
+ #f ;; get arity from fn
+ #f ;; get arity
+ fn))))
+
+