diff --git a/pd/src/x_array.c b/pd/src/x_array.c
new file mode 100644
index 0000000000000000000000000000000000000000..954cd3d965145afb37db2d431d00732fe5b6200b
--- /dev/null
+++ b/pd/src/x_array.c
@@ -0,0 +1,934 @@
+/* Copyright (c) 1997-2013 Miller Puckette and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
+
+/* The "array" object. */
+
+#include "m_pd.h"
+#include "g_canvas.h"
+#include <string.h>
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef _WIN32
+#include <io.h>
+#endif
+extern t_pd *newest;    /* OK - this should go into a .h file now :) */
+
+#ifdef _WIN32
+# include <malloc.h> /* MSVC or mingw on windows */
+#elif defined(__linux__) || defined(__APPLE__)
+# include <alloca.h> /* linux, mac, mingw, cygwin */
+#else
+# include <stdlib.h> /* BSDs for example */
+#endif
+
+#ifndef HAVE_ALLOCA     /* can work without alloca() but we never need it */
+#define HAVE_ALLOCA 1
+#endif
+#define TEXT_NGETBYTE 100 /* bigger that this we use alloc, not alloca */
+#if HAVE_ALLOCA
+#define ATOMS_ALLOCA(x, n) ((x) = (t_atom *)((n) < TEXT_NGETBYTE ?  \
+        alloca((n) * sizeof(t_atom)) : getbytes((n) * sizeof(t_atom))))
+#define ATOMS_FREEA(x, n) ( \
+    ((n) < TEXT_NGETBYTE || (freebytes((x), (n) * sizeof(t_atom)), 0)))
+#else
+#define ATOMS_ALLOCA(x, n) ((x) = (t_atom *)getbytes((n) * sizeof(t_atom)))
+#define ATOMS_FREEA(x, n) (freebytes((x), (n) * sizeof(t_atom)))
+#endif
+
+/* -- "table" - classic "array define" object by Guenter Geiger --*/
+
+static int tabcount = 0;
+
+extern t_symbol *sharptodollar(t_symbol *s);
+
+static void *table_donew(t_symbol *s, int size, int flags,
+    int xpix, int ypix)
+{
+    t_atom a[9];
+    t_atom at[4];
+    t_glist *gl;
+    t_canvas *x, *z = canvas_getcurrent();
+    if (s == &s_)
+    {
+         char  tabname[255];
+         t_symbol *t = gensym("table");
+         sprintf(tabname, "%s%d", t->s_name, tabcount++);
+         s = gensym(tabname);
+    }
+    if (size < 1)
+        size = 100;
+    SETFLOAT(a, 0);
+    SETFLOAT(a+1, 50);
+    SETFLOAT(a+2, xpix + 100);
+    SETFLOAT(a+3, ypix + 100);
+    SETSYMBOL(a+4, s);
+    SETFLOAT(a+5, 0);
+    x = canvas_new(0, 0, 6, a);
+
+    x->gl_owner = z;
+
+        /* create a graph for the table */
+    gl = glist_addglist((t_glist*)x, &s_, 0, -1, (size > 1 ? size-1 : 1), 1,
+        50, ypix+50, xpix+50, 50);
+
+    SETSYMBOL(at, sharptodollar(s));
+    SETFLOAT(at+1, size);
+    SETSYMBOL(at+2, &s_float);
+    SETFLOAT(at+3, flags);
+
+    graph_array(gl, gensym("array"), 4, at);
+    //graph_array(gl, s, &s_float, size, flags);
+
+    newest = &x->gl_pd;     /* mimic action of canvas_pop() */
+    pd_popsym(&x->gl_pd);
+    x->gl_loading = 0;
+
+    return (x);
+}
+
+static void *table_new(t_symbol *s, t_floatarg f)
+{
+    return (table_donew(s, f, 0, 500, 300));
+}
+
+    /* return true if the "canvas" object is a "table". */
+int canvas_istable(t_canvas *x)
+{
+    t_atom *argv = (x->gl_obj.te_binbuf? binbuf_getvec(x->gl_obj.te_binbuf):0);
+    int argc = (x->gl_obj.te_binbuf? binbuf_getnatom(x->gl_obj.te_binbuf) : 0);
+    int istable = (argc && argv[0].a_type == A_SYMBOL &&
+        argv[0].a_w.w_symbol == gensym("table"));
+    return (istable);
+}
+
+t_class *array_define_class;
+
+static void array_define_yrange(t_glist *x, t_floatarg ylo, t_floatarg yhi)
+{
+    t_glist *gl = (x->gl_list ? pd_checkglist(&x->gl_list->g_pd) : 0);
+    if (gl && gl->gl_list && pd_class(&gl->gl_list->g_pd) == garray_class)
+    {
+        int n = garray_getarray((t_garray *)gl->gl_list)->a_n;
+        vmess(&x->gl_list->g_pd, gensym("bounds"),
+            "ffff", 0., yhi, (double)(n == 1 ? n : n-1), ylo);
+        vmess(&x->gl_list->g_pd, gensym("xlabel"),
+            "fff", ylo + glist_pixelstoy(gl, 2) - glist_pixelstoy(gl, 0),
+                0., (float)(n-1));
+        vmess(&x->gl_list->g_pd, gensym("ylabel"),
+            "fff", glist_pixelstox(gl, 0) - glist_pixelstox(gl, 5), ylo, yhi);
+    }
+    else bug("array_define_yrange");
+}
+
+static void *array_define_new(t_symbol *s, int argc, t_atom *argv)
+{
+    t_symbol *arrayname = &s_;
+    float arraysize = 100;
+    t_glist *x;
+    int keep = 0;
+    float ylo = -1, yhi = 1;
+    float xpix = 500, ypix = 300;
+    while (argc && argv->a_type == A_SYMBOL &&
+        *argv->a_w.w_symbol->s_name == '-')
+    {
+        if (!strcmp(argv->a_w.w_symbol->s_name, "-k"))
+            keep = 1;
+        else if (!strcmp(argv->a_w.w_symbol->s_name, "-yrange") &&
+            argc >= 3 && argv[1].a_type == A_FLOAT &&
+                argv[2].a_type == A_FLOAT)
+        {
+            ylo = atom_getfloatarg(1, argc, argv);
+            yhi = atom_getfloatarg(2, argc, argv);
+            if (ylo == yhi)
+                ylo = -1, yhi = 1;
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(argv->a_w.w_symbol->s_name, "-pix") &&
+            argc >= 3 && argv[1].a_type == A_FLOAT &&
+                argv[2].a_type == A_FLOAT)
+        {
+            if ((xpix = atom_getfloatarg(1, argc, argv)) < 10)
+                xpix = 10;
+            if ((ypix = atom_getfloatarg(2, argc, argv)) < 10)
+                ypix = 10;
+            argc -= 2; argv += 2;
+        }
+        else
+        {
+            error("array define: unknown flag ...");
+            postatom(argc, argv); endpost();
+        }
+        argc--; argv++;
+    }
+    if (argc && argv->a_type == A_SYMBOL)
+    {
+        arrayname = argv->a_w.w_symbol;
+        argc--; argv++;
+    }
+    if (argc && argv->a_type == A_FLOAT)
+    {
+        arraysize = argv->a_w.w_float;
+        argc--; argv++;
+    }
+    if (argc)
+    {
+        post("warning: array define ignoring extra argument: ");
+        postatom(argc, argv); endpost();
+    }
+    x = (t_glist *)table_donew(arrayname, arraysize, keep, xpix, ypix);
+
+        /* bash the class to "array define".  We don't do this earlier in
+        part so that canvas_getcurrent() will work while the glist and
+        garray are being created.  There may be other, unknown side effects. */
+    x->gl_obj.ob_pd = array_define_class;
+    array_define_yrange(x, ylo, yhi);
+    return (x);
+}
+
+void garray_save(t_garray *x, t_binbuf *b);
+
+void array_define_save(t_gobj *z, t_binbuf *bb)
+{
+    t_glist *x = (t_glist *)z;
+    t_glist *gl = (x->gl_list ? pd_checkglist(&x->gl_list->g_pd) : 0);
+    binbuf_addv(bb, "ssff", &s__X, gensym("obj"),
+        (float)x->gl_obj.te_xpix, (float)x->gl_obj.te_ypix);
+    binbuf_addbinbuf(bb, x->gl_obj.ob_binbuf);
+    binbuf_addsemi(bb);
+
+    if (gl)
+    {
+        garray_save((t_gobj *)gl->gl_list, bb);
+        obj_saveformat(&x->gl_obj, bb);
+    }
+    else
+        bug("array_define_save");
+}
+
+t_scalar *garray_getscalar(t_garray *x);
+
+    /* send a pointer to the scalar that owns this array to
+    whomever is bound to the given symbol */
+static void array_define_send(t_glist *x, t_symbol *s)
+{
+    t_glist *gl = (x->gl_list ? pd_checkglist(&x->gl_list->g_pd) : 0);
+    if (!s->s_thing)
+        pd_error(x, "array_define_send: %s: no such object", s->s_name);
+    else if (gl && gl->gl_list && pd_class(&gl->gl_list->g_pd) == garray_class)
+    {
+        t_gpointer gp;
+        gpointer_init(&gp);
+        gpointer_setglist(&gp, gl,
+            //garray_getscalar((t_garray *)gl->gl_list));
+            (t_gobj *)gl->gl_list);
+        pd_pointer(s->s_thing, &gp);
+        gpointer_unset(&gp);
+    }
+    else bug("array_define_anything");
+}
+
+    /* just forward any messages to the garray */
+static void array_define_anything(t_glist *x,
+    t_symbol *s, int argc, t_atom *argv)
+{
+    t_glist *gl = (x->gl_list ? pd_checkglist(&x->gl_list->g_pd) : 0);
+    if (gl && gl->gl_list && pd_class(&gl->gl_list->g_pd) == garray_class)
+        typedmess(&gl->gl_list->g_pd, s, argc, argv);
+    else bug("array_define_anything");
+}
+
+    /* ignore messages like "editmode" */
+static void array_define_ignore(t_glist *x,
+    t_symbol *s, int argc, t_atom *argv)
+{
+}
+
+/* ---  array_client - common code for objects that refer to arrays -- */
+
+typedef struct _array_client
+{
+    t_object tc_obj;
+    t_symbol *tc_sym;
+    t_gpointer tc_gp;
+    t_symbol *tc_struct;
+    t_symbol *tc_field;
+    t_canvas *tc_canvas;
+} t_array_client;
+
+#define x_sym x_tc.tc_sym
+#define x_struct x_tc.tc_struct
+#define x_field x_tc.tc_field
+#define x_gp x_tc.tc_gp
+
+    /* find the array for this object.  Prints an error  message and returns
+        0 on failure. */
+static t_array *array_client_getbuf(t_array_client *x, t_glist **glist)
+{
+    if (x->tc_sym)       /* named array object */
+    {
+        t_garray *y = (t_garray *)pd_findbyclass(x->tc_sym, garray_class);
+        if (y)
+        {
+            *glist = garray_getglist(y);
+            return (garray_getarray(y));
+        }
+        else
+        {
+            pd_error(x, "array: couldn't find named array '%s'",
+                x->tc_sym->s_name);
+            *glist = 0;
+            return (0);
+        }
+    }
+    else if (x->tc_struct)   /* by pointer */
+    {
+        t_template *template = template_findbyname(x->tc_struct);
+        t_gstub *gs = x->tc_gp.gp_stub;
+        t_word *vec;
+        int onset, type;
+        t_symbol *arraytype;
+        if (!template)
+        {
+            pd_error(x, "array: couldn't find struct %s", x->tc_struct->s_name);
+            return (0);
+        }
+        if (!gpointer_check(&x->tc_gp, 0))
+        {
+            pd_error(x, "array: stale or empty pointer");
+            return (0);
+        }
+        if (gs->gs_which == GP_ARRAY)
+            vec = x->tc_gp.gp_un.gp_w;
+        else vec = ((t_scalar *)(x->tc_gp.gp_un.gp_gobj))->sc_vec;
+
+        if (!template_find_field(template,
+            x->tc_field, &onset, &type, &arraytype))
+        {
+            pd_error(x, "array: no field named %s", x->tc_field->s_name);
+            return (0);
+        }
+        if (type != DT_ARRAY)
+        {
+            pd_error(x, "array: field %s not of type array",
+                x->tc_field->s_name);
+            return (0);
+        }
+        if (gs->gs_which == GP_GLIST)
+            *glist = gs->gs_un.gs_glist;
+        else
+        {
+            t_array *owner_array = gs->gs_un.gs_array;
+            while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
+                owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
+            *glist = owner_array->a_gp.gp_stub->gs_un.gs_glist;
+        }
+        return (*(t_array **)(((char *)vec) + onset));
+    }
+    else return (0);    /* shouldn't happen */
+}
+
+static void array_client_senditup(t_array_client *x)
+{
+    t_glist *glist = 0;
+    t_array *a = array_client_getbuf(x, &glist);
+    if (glist)
+       array_redraw(a, glist);
+}
+
+static void array_client_free(t_array_client *x)
+{
+    gpointer_unset(&x->tc_gp);
+}
+
+/* ----------  array size : get or set size of an array ---------------- */
+static t_class *array_size_class;
+
+typedef struct _array_size
+{
+    t_array_client x_tc;
+} t_array_size;
+#define x_outlet x_tc.tc_obj.ob_outlet
+
+static void *array_size_new(t_symbol *s, int argc, t_atom *argv)
+{
+    t_array_size *x = (t_array_size *)pd_new(array_size_class);
+    x->x_sym = x->x_struct = x->x_field = 0;
+    gpointer_init(&x->x_gp);
+    while (argc && argv->a_type == A_SYMBOL &&
+        *argv->a_w.w_symbol->s_name == '-')
+    {
+        if (!strcmp(argv->a_w.w_symbol->s_name, "-s") &&
+            argc >= 3 && argv[1].a_type == A_SYMBOL &&
+                argv[2].a_type == A_SYMBOL)
+        {
+            x->x_struct = canvas_makebindsym(argv[1].a_w.w_symbol);
+            x->x_field = argv[2].a_w.w_symbol;
+            argc -= 2; argv += 2;
+        }
+        else
+        {
+            pd_error(x, "array setline: unknown flag ...");
+            postatom(argc, argv); endpost();
+        }
+        argc--; argv++;
+    }
+    if (argc && argv->a_type == A_SYMBOL)
+    {
+        if (x->x_struct)
+        {
+            pd_error(x, "array setline: extra names after -s..");
+            postatom(argc, argv); endpost();
+        }
+        else x->x_sym = argv->a_w.w_symbol;
+        argc--; argv++;
+    }
+    if (argc)
+    {
+        post("warning: array setline ignoring extra argument: ");
+        postatom(argc, argv); endpost();
+    }
+    if (x->x_struct)
+        pointerinlet_new(&x->x_tc.tc_obj, &x->x_gp);
+    else symbolinlet_new(&x->x_tc.tc_obj, &x->x_tc.tc_sym);
+    outlet_new(&x->x_tc.tc_obj, &s_float);
+    return (x);
+}
+
+static void array_size_bang(t_array_size *x)
+{
+    t_glist *glist;
+    t_array *a = array_client_getbuf(&x->x_tc, &glist);
+    if (a)
+        outlet_float(x->x_outlet, a->a_n);
+}
+
+static void array_size_float(t_array_size *x, t_floatarg f)
+{
+    t_glist *glist;
+    t_array *a = array_client_getbuf(&x->x_tc, &glist);
+    if (a)
+    {
+              /* if it's a named array object we have to go back and find the
+              garray (repeating work done in array_client_getbuf()) because
+              the garray might want to adjust.  Maybe array_client_getbuf
+              should have a return slot for the garray if any?  */
+        if (x->x_tc.tc_sym)
+        {
+            t_garray *y = (t_garray *)pd_findbyclass(x->x_tc.tc_sym,
+                garray_class);
+            garray_resize(y, f);
+        }
+        else
+        {
+            int n = f;
+            if (n < 1)
+                n = 1;
+             array_resize_and_redraw(a, glist, n);
+        }
+    }
+}
+
+/* ------  range operations - act on a specifiable range in an array ----- */
+static t_class *array_sum_class;
+
+typedef struct _array_rangeop   /* any operation meaningful on a subrange */
+{
+    t_array_client x_tc;
+    t_float x_onset;
+    t_float x_n;
+    t_symbol *x_elemfield;
+    t_symbol *x_elemtemplate;   /* unused - perhaps should at least check it */
+} t_array_rangeop;
+
+    /* generic creator for operations on ranges (array {get,set,sum,random,
+        quantile,search,...}  "onsetin" and "nin" are true if we should make
+        inlets for onset and n - if no inlet for 'n' we also won't allow
+        it to be specified as an argument.  Everything can take an onset but
+        sometimes we don't need an inlet because it's the inlet itself.  In
+        any case we allow onset to be specified as an argument (even if it's
+        the 'hot inlet') -- for the same reason as in the 'delay' object.
+        Finally we can optionally warn if there are extra arguments; some
+        specific arguments (e.g., search) allow them but most don't. */
+static void *array_rangeop_new(t_class *class,
+    t_symbol *s, int *argcp, t_atom **argvp,
+    int onsetin, int nin, int warnextra)
+{
+    int argc = *argcp;
+    t_atom *argv = *argvp;
+    t_array_rangeop *x = (t_array_rangeop *)pd_new(class);
+    x->x_sym = x->x_struct = x->x_field = 0;
+    gpointer_init(&x->x_gp);
+    x->x_elemtemplate = &s_;
+    x->x_elemfield = gensym("y");
+    x->x_onset = 0;
+    x->x_n = -1;
+    if (onsetin)
+        floatinlet_new(&x->x_tc.tc_obj, &x->x_onset);
+    if (nin)
+        floatinlet_new(&x->x_tc.tc_obj, &x->x_n);
+    while (argc && argv->a_type == A_SYMBOL &&
+        *argv->a_w.w_symbol->s_name == '-')
+    {
+        if (!strcmp(argv->a_w.w_symbol->s_name, "-s") &&
+            argc >= 3 && argv[1].a_type == A_SYMBOL &&
+                argv[2].a_type == A_SYMBOL)
+        {
+            x->x_struct = canvas_makebindsym(argv[1].a_w.w_symbol);
+            x->x_field = argv[2].a_w.w_symbol;
+            argc -= 2; argv += 2;
+        }
+        else if (!strcmp(argv->a_w.w_symbol->s_name, "-f") &&
+            argc >= 3 && argv[1].a_type == A_SYMBOL &&
+                argv[2].a_type == A_SYMBOL)
+        {
+            x->x_elemtemplate = argv[1].a_w.w_symbol;
+            x->x_elemfield = argv[2].a_w.w_symbol;
+            argc -= 2; argv += 2;
+        }
+        else
+        {
+            pd_error(x, "%s: unknown flag ...", class_getname(class));
+            postatom(argc, argv); endpost();
+        }
+        argc--; argv++;
+    }
+    if (argc && argv->a_type == A_SYMBOL)
+    {
+        if (x->x_struct)
+        {
+            pd_error(x, "%s: extra names after -s..", class_getname(class));
+            postatom(argc, argv); endpost();
+        }
+        else x->x_sym = argv->a_w.w_symbol;
+        argc--; argv++;
+    }
+    if (argc && argv->a_type == A_FLOAT)
+    {
+        x->x_onset = argv->a_w.w_float;
+        argc--; argv++;
+    }
+    if (argc && argv->a_type == A_FLOAT)
+    {
+        x->x_n = argv->a_w.w_float;
+        argc--; argv++;
+    }
+    if (argc && warnextra)
+    {
+        post("warning: %s ignoring extra argument: ", class_getname(class));
+        postatom(argc, argv); endpost();
+    }
+    if (x->x_struct)
+        pointerinlet_new(&x->x_tc.tc_obj, &x->x_gp);
+    else symbolinlet_new(&x->x_tc.tc_obj, &x->x_tc.tc_sym);
+    *argcp = argc;
+    *argvp = argv;
+    return (x);
+}
+
+static int array_rangeop_getrange(t_array_rangeop *x,
+    char **firstitemp, int *nitemp, int *stridep, int *arrayonsetp)
+{
+    t_glist *glist;
+    t_array *a = array_client_getbuf(&x->x_tc, &glist);
+    char *elemp;
+    int stride, fieldonset, arrayonset, nitem, i, type;
+    t_symbol *arraytype;
+    double sum;
+    t_template *template;
+    if (!a)
+        return (0);
+    template = template_findbyname(a->a_templatesym);
+    if (!template_find_field(template, x->x_elemfield, &fieldonset,
+        &type, &arraytype) || type != DT_FLOAT)
+    {
+        pd_error(x, "can't find field %s in struct %s",
+            x->x_elemfield->s_name, a->a_templatesym->s_name);
+        return (0);
+    }
+    stride = a->a_elemsize;
+    arrayonset = x->x_onset;
+    if (arrayonset < 0)
+        arrayonset = 0;
+    else if (arrayonset > a->a_n)
+        arrayonset = a->a_n;
+    if (x->x_n < 0)
+        nitem = a->a_n - arrayonset;
+    else
+    {
+        nitem = x->x_n;
+        if (nitem + arrayonset > a->a_n)
+            nitem = a->a_n - arrayonset;
+    }
+    *firstitemp = a->a_vec+(fieldonset+arrayonset*stride);
+    *nitemp = nitem;
+    *stridep = stride;
+    *arrayonsetp = arrayonset;
+    return (1);
+}
+
+/* --------  specific operations on ranges of arrays -------- */
+
+/* ----------------  array sum -- add them up ------------------- */
+static t_class *array_sum_class;
+
+#define t_array_sum t_array_rangeop
+
+static void *array_sum_new(t_symbol *s, int argc, t_atom *argv)
+{
+    t_array_sum *x = array_rangeop_new(array_sum_class, s, &argc, &argv,
+        0, 1, 1);
+    outlet_new(&x->x_tc.tc_obj, &s_float);
+    return (x);
+}
+
+static void array_sum_bang(t_array_rangeop *x)
+{
+    char *itemp, *firstitem;
+    int stride, nitem, arrayonset, i;
+    double sum;
+    if (!array_rangeop_getrange(x, &firstitem, &nitem, &stride, &arrayonset))
+        return;
+    for (i = 0, sum = 0, itemp = firstitem; i < nitem; i++, itemp += stride)
+        sum += *(t_float *)itemp;
+    outlet_float(x->x_outlet, sum);
+}
+
+static void array_sum_float(t_array_rangeop *x, t_floatarg f)
+{
+    x->x_onset = f;
+    array_sum_bang(x);
+}
+
+/* ----------------  array get -- output as list ------------------- */
+static t_class *array_get_class;
+
+#define t_array_get t_array_rangeop
+
+static void *array_get_new(t_symbol *s, int argc, t_atom *argv)
+{
+    t_array_get *x = array_rangeop_new(array_get_class, s, &argc, &argv,
+        0, 1, 1);
+    outlet_new(&x->x_tc.tc_obj, &s_float);
+    return (x);
+}
+
+static void array_get_bang(t_array_rangeop *x)
+{
+    char *itemp, *firstitem;
+    int stride, nitem, arrayonset, i;
+    t_atom *outv;
+    if (!array_rangeop_getrange(x, &firstitem, &nitem, &stride, &arrayonset))
+        return;
+    ATOMS_ALLOCA(outv, nitem);
+    for (i = 0, itemp = firstitem; i < nitem; i++, itemp += stride)
+        SETFLOAT(&outv[i],  *(t_float *)itemp);
+    outlet_list(x->x_outlet, 0, nitem, outv);
+    ATOMS_FREEA(outv, nitem);
+}
+
+static void array_get_float(t_array_rangeop *x, t_floatarg f)
+{
+    x->x_onset = f;
+    array_get_bang(x);
+}
+
+/* --------------  array set -- copy list to array -------------- */
+static t_class *array_set_class;
+
+#define t_array_set t_array_rangeop
+
+static void *array_set_new(t_symbol *s, int argc, t_atom *argv)
+{
+    t_array_set *x = array_rangeop_new(array_set_class, s, &argc, &argv,
+        1, 0, 1);
+    return (x);
+}
+
+static void array_set_list(t_array_rangeop *x, t_symbol *s,
+    int argc, t_atom *argv)
+{
+    char *itemp, *firstitem;
+    int stride, nitem, arrayonset, i;
+    if (!array_rangeop_getrange(x, &firstitem, &nitem, &stride, &arrayonset))
+        return;
+    if (nitem > argc)
+        nitem = argc;
+    for (i = 0, itemp = firstitem; i < nitem; i++, itemp += stride)
+        *(t_float *)itemp = atom_getfloatarg(i, argc, argv);
+    array_client_senditup(&x->x_tc);
+}
+
+/* -----  array quantile -- output quantile for input from 0 to 1 ------- */
+static t_class *array_quantile_class;
+
+#define t_array_quantile t_array_rangeop
+
+static void *array_quantile_new(t_symbol *s, int argc, t_atom *argv)
+{
+    t_array_quantile *x = array_rangeop_new(array_quantile_class, s,
+        &argc, &argv, 1, 1, 1);
+    outlet_new(&x->x_tc.tc_obj, &s_float);
+    return (x);
+}
+
+static void array_quantile_float(t_array_rangeop *x, t_floatarg f)
+{
+    char *itemp, *firstitem;
+    int stride, nitem, arrayonset, i;
+    double sum;
+    if (!array_rangeop_getrange(x, &firstitem, &nitem, &stride, &arrayonset))
+        return;
+    for (i = 0, sum = 0, itemp = firstitem; i < nitem; i++, itemp += stride)
+        sum += (*(t_float *)itemp > 0? *(t_float *)itemp : 0);
+    sum *= f;
+    for (i = 0, itemp = firstitem; i < (nitem-1); i++, itemp += stride)
+    {
+        sum -= (*(t_float *)itemp > 0? *(t_float *)itemp : 0);
+        if (sum < 0)
+            break;
+    }
+    outlet_float(x->x_outlet, i);
+}
+
+/* ----  array random -- output random value with array as distribution ---- */
+static t_class *array_random_class;
+
+typedef struct _array_random   /* any operation meaningful on a subrange */
+{
+    t_array_rangeop x_r;
+    unsigned int x_state;
+} t_array_random;
+
+static void *array_random_new(t_symbol *s, int argc, t_atom *argv)
+{
+    t_array_random *x = array_rangeop_new(array_random_class, s,
+        &argc, &argv, 0, 1, 1);
+    static unsigned int random_nextseed = 584926371;
+    random_nextseed = random_nextseed * 435898247 + 938284287;
+    x->x_state = random_nextseed;
+    outlet_new(&x->x_r.x_tc.tc_obj, &s_float);
+    return (x);
+}
+
+static void array_random_seed(t_array_random *x, t_floatarg f)
+{
+    x->x_state = f;
+}
+
+static void array_random_bang(t_array_random *x)
+{
+    char *itemp, *firstitem;
+    int stride, nitem, arrayonset, i;
+
+    if (!array_rangeop_getrange(&x->x_r, &firstitem, &nitem, &stride,
+        &arrayonset))
+            return;
+    x->x_state = x->x_state * 472940017 + 832416023;
+    array_quantile_float(&x->x_r, (1./4294967296.0) * (double)(x->x_state));
+}
+
+static void array_random_float(t_array_random *x, t_floatarg f)
+{
+    x->x_r.x_onset = f;
+    array_random_bang(x);
+}
+
+/* ----  array max -- output largest value and its index ------------ */
+static t_class *array_max_class;
+
+typedef struct _array_max
+{
+    t_array_rangeop x_rangeop;
+    t_outlet *x_out1;       /* value */
+    t_outlet *x_out2;       /* index */
+} t_array_max;
+
+static void *array_max_new(t_symbol *s, int argc, t_atom *argv)
+{
+    t_array_max *x = array_rangeop_new(array_max_class, s, &argc, &argv,
+        0, 1, 1);
+    x->x_out1 = outlet_new(&x->x_rangeop.x_tc.tc_obj, &s_float);
+    x->x_out2 = outlet_new(&x->x_rangeop.x_tc.tc_obj, &s_float);
+    return (x);
+}
+
+static void array_max_bang(t_array_max *x)
+{
+    char *itemp, *firstitem;
+    int stride, nitem, arrayonset, i, besti;
+    t_float bestf;
+    if (!array_rangeop_getrange(&x->x_rangeop, &firstitem, &nitem, &stride,
+        &arrayonset))
+            return;
+    for (i = 0, besti = -1, bestf= -1e30, itemp = firstitem;
+        i < nitem; i++, itemp += stride)
+            if (*(t_float *)itemp > bestf)
+                bestf = *(t_float *)itemp, besti = i+arrayonset;
+    outlet_float(x->x_out2, besti);
+    outlet_float(x->x_out1, bestf);
+}
+
+static void array_max_float(t_array_max *x, t_floatarg f)
+{
+    x->x_rangeop.x_onset = f;
+    array_max_bang(x);
+}
+
+/* ----  array min -- output largest value and its index ------------ */
+static t_class *array_min_class;
+
+typedef struct _array_min
+{
+    t_array_rangeop x_rangeop;
+    t_outlet *x_out1;       /* value */
+    t_outlet *x_out2;       /* index */
+} t_array_min;
+
+static void *array_min_new(t_symbol *s, int argc, t_atom *argv)
+{
+    t_array_min *x = array_rangeop_new(array_min_class, s, &argc, &argv,
+        0, 1, 1);
+    x->x_out1 = outlet_new(&x->x_rangeop.x_tc.tc_obj, &s_float);
+    x->x_out2 = outlet_new(&x->x_rangeop.x_tc.tc_obj, &s_float);
+    return (x);
+}
+
+static void array_min_bang(t_array_min *x)
+{
+    char *itemp, *firstitem;
+    int stride, nitem, i, arrayonset, besti;
+    t_float bestf;
+    if (!array_rangeop_getrange(&x->x_rangeop, &firstitem, &nitem, &stride,
+        &arrayonset))
+            return;
+    for (i = 0, besti = -1, bestf= 1e30, itemp = firstitem;
+        i < nitem; i++, itemp += stride)
+            if (*(t_float *)itemp < bestf)
+                bestf = *(t_float *)itemp, besti = i+arrayonset;
+    outlet_float(x->x_out2, besti);
+    outlet_float(x->x_out1, bestf);
+}
+
+static void array_min_float(t_array_min *x, t_floatarg f)
+{
+    x->x_rangeop.x_onset = f;
+    array_min_bang(x);
+}
+
+/* overall creator for "array" objects - dispatch to "array define" etc */
+static void *arrayobj_new(t_symbol *s, int argc, t_atom *argv)
+{
+    if (!argc || argv[0].a_type != A_SYMBOL)
+        newest = array_define_new(s, argc, argv);
+    else
+    {
+        char *str = argv[0].a_w.w_symbol->s_name;
+        if (!strcmp(str, "d") || !strcmp(str, "define"))
+            newest = array_define_new(s, argc-1, argv+1);
+        else if (!strcmp(str, "size"))
+            newest = array_size_new(s, argc-1, argv+1);
+        else if (!strcmp(str, "sum"))
+            newest = array_sum_new(s, argc-1, argv+1);
+        else if (!strcmp(str, "get"))
+            newest = array_get_new(s, argc-1, argv+1);
+        else if (!strcmp(str, "set"))
+            newest = array_set_new(s, argc-1, argv+1);
+        else if (!strcmp(str, "quantile"))
+            newest = array_quantile_new(s, argc-1, argv+1);
+        else if (!strcmp(str, "random"))
+            newest = array_random_new(s, argc-1, argv+1);
+        else if (!strcmp(str, "max"))
+            newest = array_max_new(s, argc-1, argv+1);
+        else if (!strcmp(str, "min"))
+            newest = array_min_new(s, argc-1, argv+1);
+        else
+        {
+            error("array %s: unknown function", str);
+            newest = 0;
+        }
+    }
+    return (newest);
+}
+
+void canvas_add_for_class(t_class *c);
+
+/* ---------------- global setup function -------------------- */
+
+void x_array_setup(void )
+{
+    array_define_class = class_new(gensym("array define"), 0,
+        (t_method)canvas_free, sizeof(t_canvas), 0, 0);
+    canvas_add_for_class(array_define_class);
+    class_addmethod(array_define_class, (t_method)array_define_send,
+        gensym("send"), A_SYMBOL, 0);
+    class_addanything(array_define_class, array_define_anything);
+    class_sethelpsymbol(array_define_class, gensym("array-object"));
+    class_setsavefn(array_define_class, array_define_save);
+
+    class_addmethod(array_define_class, (t_method)array_define_ignore,
+        gensym("editmode"), A_GIMME, 0);
+
+    class_addcreator((t_newmethod)arrayobj_new, gensym("array"), A_GIMME, 0);
+
+    class_addcreator((t_newmethod)table_new, gensym("table"),
+        A_DEFSYM, A_DEFFLOAT, 0);
+
+    array_size_class = class_new(gensym("array size"),
+        (t_newmethod)array_size_new, (t_method)array_client_free,
+            sizeof(t_array_size), 0, A_GIMME, 0);
+    class_addbang(array_size_class, array_size_bang);
+    class_addfloat(array_size_class, array_size_float);
+    class_sethelpsymbol(array_size_class, gensym("array-object"));
+
+    array_sum_class = class_new(gensym("array sum"),
+        (t_newmethod)array_sum_new, (t_method)array_client_free,
+            sizeof(t_array_sum), 0, A_GIMME, 0);
+    class_addbang(array_sum_class, array_sum_bang);
+    class_addfloat(array_sum_class, array_sum_float);
+    class_sethelpsymbol(array_sum_class, gensym("array-object"));
+
+    array_get_class = class_new(gensym("array get"),
+        (t_newmethod)array_get_new, (t_method)array_client_free,
+            sizeof(t_array_get), 0, A_GIMME, 0);
+    class_addbang(array_get_class, array_get_bang);
+    class_addfloat(array_get_class, array_get_float);
+    class_sethelpsymbol(array_get_class, gensym("array-object"));
+
+    array_set_class = class_new(gensym("array set"),
+        (t_newmethod)array_set_new, (t_method)array_client_free,
+            sizeof(t_array_set), 0, A_GIMME, 0);
+    class_addlist(array_set_class, array_set_list);
+    class_sethelpsymbol(array_set_class, gensym("array-object"));
+
+    array_quantile_class = class_new(gensym("array quantile"),
+        (t_newmethod)array_quantile_new, (t_method)array_client_free,
+            sizeof(t_array_quantile), 0, A_GIMME, 0);
+    class_addfloat(array_quantile_class, array_quantile_float);
+    class_sethelpsymbol(array_quantile_class, gensym("array-object"));
+
+    array_random_class = class_new(gensym("array random"),
+        (t_newmethod)array_random_new, (t_method)array_client_free,
+            sizeof(t_array_random), 0, A_GIMME, 0);
+    class_addmethod(array_random_class, (t_method)array_random_seed,
+        gensym("seed"), A_FLOAT, 0);
+    class_addfloat(array_random_class, array_random_float);
+    class_addbang(array_random_class, array_random_bang);
+    class_sethelpsymbol(array_random_class, gensym("array-object"));
+
+    array_max_class = class_new(gensym("array max"),
+        (t_newmethod)array_max_new, (t_method)array_client_free,
+            sizeof(t_array_max), 0, A_GIMME, 0);
+    class_addfloat(array_max_class, array_max_float);
+    class_addbang(array_max_class, array_max_bang);
+    class_sethelpsymbol(array_max_class, gensym("array-object"));
+
+    array_min_class = class_new(gensym("array min"),
+        (t_newmethod)array_min_new, (t_method)array_client_free,
+            sizeof(t_array_min), 0, A_GIMME, 0);
+    class_addfloat(array_min_class, array_min_float);
+    class_addbang(array_min_class, array_min_bang);
+    class_sethelpsymbol(array_min_class, gensym("array-object"));
+}