From faada59567f8cb252f4a909116595ce309ff5828 Mon Sep 17 00:00:00 2001 From: "N.N." Date: Fri, 23 May 2003 12:29:55 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r647, which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/miXed/; revision=648 --- cyclone/hammer/funbuff.c | 521 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 521 insertions(+) create mode 100644 cyclone/hammer/funbuff.c (limited to 'cyclone/hammer/funbuff.c') diff --git a/cyclone/hammer/funbuff.c b/cyclone/hammer/funbuff.c new file mode 100644 index 0000000..8d9d698 --- /dev/null +++ b/cyclone/hammer/funbuff.c @@ -0,0 +1,521 @@ +/* Copyright (c) 2002-2003 krzYszcz and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +#include "m_pd.h" +#include "unstable/fragile.h" +#include "common/loud.h" +#include "common/vefl.h" +#include "hammer/tree.h" +#include "hammer/file.h" + +typedef struct _funbuff +{ + t_object x_ob; + t_canvas *x_canvas; + t_symbol *x_defname; + t_float x_value; + int x_valueset; + /* CHECKED filling with a large set, then sending 'goto', 'read', 'next'... + outputs the previous, replaced contents (same with deletion) + -- apparently a node pointer is stored, corrupt in these cases */ + t_hammernode *x_pointer; + int x_pointerset; /* set-with-goto flag */ + int x_lastdelta; + int x_embedflag; + t_hammerfile *x_filehandle; + t_hammertree x_tree; + t_outlet *x_deltaout; + t_outlet *x_bangout; +} t_funbuff; + +static t_class *funbuff_class; + +static void funbuff_dooutput(t_funbuff *x, float value, float delta) +{ + /* CHECKED lastdelta sent for 'next', 'float', 'min', 'max', + 'interp', 'find' */ + outlet_float(x->x_deltaout, delta); + outlet_float(((t_object *)x)->ob_outlet, value); +} + +static void funbuff_bang(t_funbuff *x) +{ + t_hammernode *np; + int count = 0; + int xmin = 0, xmax = 0; + t_float ymin = 0, ymax = 0; + if (np = x->x_tree.t_first) + { + /* LATER consider using extra fields, updated on the fly */ + count = 1; + xmin = np->n_index; + xmax = x->x_tree.t_last->n_index; + ymin = ymax = np->n_value; + while (np = np->n_next) + { + if (np->n_value < ymin) ymin = np->n_value; + else if (np->n_value > ymax) ymax = np->n_value; + count++; + } + } + /* format CHECKED */ + post("funbuff info: %d elements long", count); /* CHECKED 0 and 1 */ + if (count) + { + post(" -> minX= %d maxX= %d", xmin, xmax); + post(" -> minY= %g maxY= %g", ymin, ymax); + post(" -> domain= %d range= %g", xmax - xmin, ymax - ymin); + } +} + +static void funbuff_float(t_funbuff *x, t_float f) +{ + int ndx = (int)f; /* CHECKED float is silently truncated */ + t_hammernode *np; + if (x->x_valueset) + { + if (np = hammertree_insert(&x->x_tree, ndx)) + np->n_value = x->x_value; + x->x_valueset = 0; + } + else if (np = hammertree_closest(&x->x_tree, ndx, 0)) + funbuff_dooutput(x, np->n_value, x->x_lastdelta); + /* CHECKED pointer is updated -- + 'next' outputs np also in a !valueset case (it is sent twice) */ + x->x_pointer = np; + x->x_pointerset = 0; +} + +static void funbuff_ft1(t_funbuff *x, t_floatarg f) +{ + /* this is incompatible -- CHECKED float is silently truncated */ + x->x_value = f; + x->x_valueset = 1; +} + +static void funbuff_clear(t_funbuff *x) +{ + hammertree_clear(&x->x_tree, 0); + /* CHECKED valueset is not cleared */ + x->x_pointer = 0; +} + +/* LATER dirty flag handling */ +static void funbuff_embed(t_funbuff *x, t_floatarg f) +{ + x->x_embedflag = (f != 0); +} + +static void funbuff_goto(t_funbuff *x, t_floatarg f) +{ + /* CHECKED truncation */ + x->x_pointer = hammertree_closest(&x->x_tree, (int)f, 1); + x->x_pointerset = 1; /* CHECKED delta output by 'next' will be zero */ +} + +/* LATER consider using an extra field, updated on the fly */ +static void funbuff_min(t_funbuff *x) +{ + t_hammernode *np; + if (np = x->x_tree.t_first) /* CHECKED nop if empty */ + { + t_float result = np->n_value; + while (np = np->n_next) + if (np->n_value < result) result = np->n_value; + funbuff_dooutput(x, result, x->x_lastdelta); + /* CHECKED pointer not updated */ + } +} + +/* LATER consider using an extra field, updated on the fly */ +static void funbuff_max(t_funbuff *x) +{ + t_hammernode *np; + if (np = x->x_tree.t_first) /* CHECKED nop if empty */ + { + t_float result = np->n_value; + while (np = np->n_next) + if (np->n_value > result) result = np->n_value; + funbuff_dooutput(x, result, x->x_lastdelta); + /* CHECKED pointer not updated */ + } +} + +static void funbuff_next(t_funbuff *x) +{ + t_hammernode *np; + if (!x->x_tree.t_root) + return; + if (!(np = x->x_pointer)) + { + outlet_bang(x->x_bangout); + /* CHECKED banging until reset */ + return; + } + if (x->x_pointerset) + x->x_lastdelta = 0; + else if (np->n_prev) + x->x_lastdelta = np->n_index - np->n_prev->n_index; + else + x->x_lastdelta = 0; /* CHECKED corrupt delta sent here... */ + funbuff_dooutput(x, np->n_value, x->x_lastdelta); + x->x_pointer = np->n_next; + x->x_pointerset = 0; +} + +static void funbuff_set(t_funbuff *x, t_symbol *s, int ac, t_atom *av) +{ + /* CHECKED symbols somehow bashed to zeros, + decreasing x coords corrupt the funbuff -- not emulated here... */ + int i = ac; + t_atom *ap = av; + while (i--) if (ap++->a_type != A_FLOAT) + { + loud_error((t_pd *)x, "bad input (not a number) -- no data to set"); + return; + } + if (!ac || (ac % 2)) + { + /* CHECKED odd/null ac loudly rejected, current contents preserved */ + loud_error((t_pd *)x, "bad input (%s) -- no data to set", + (ac ? "odd arg count" : "no input")); + return; + } + funbuff_clear(x); /* CHECKED the contents is replaced */ + while (ac--) + { + t_hammernode *np; + if (np = hammertree_insert(&x->x_tree, (int)av++->a_w.w_float)) + np->n_value = av++->a_w.w_float; + else return; + ac--; + } +} + +static void funbuff_doread(t_funbuff *x, t_symbol *fn) +{ + t_binbuf *bb = binbuf_new(); + int ac; + t_atom *av; + char buf[MAXPDSTRING]; + canvas_makefilename(x->x_canvas, fn->s_name, buf, MAXPDSTRING); + binbuf_read(bb, buf, "", 0); + if ((ac = binbuf_getnatom(bb)) && + (av = binbuf_getvec(bb)) && + av->a_type == A_SYMBOL && + av->a_w.w_symbol == gensym("funbuff")) + { + post("funbuff_read: %s read successful", fn->s_name); /* CHECKED */ + funbuff_set(x, 0, ac-1, av+1); + } + else /* CHECKED no complaints... */ + loud_error((t_pd *)x, "invalid file %s", fn->s_name); + binbuf_free(bb); +} + +static void funbuff_readhook(t_pd *z, t_symbol *fn, int ac, t_atom *av) +{ + funbuff_doread((t_funbuff *)z, fn); +} + +static void funbuff_dowrite(t_funbuff *x, t_symbol *fn) +{ + t_binbuf *bb = binbuf_new(); + char buf[MAXPDSTRING]; + t_hammernode *np; + binbuf_addv(bb, "s", gensym("funbuff")); + for (np = x->x_tree.t_first; np; np = np->n_next) + binbuf_addv(bb, "if", np->n_index, np->n_value); + canvas_makefilename(x->x_canvas, fn->s_name, buf, MAXPDSTRING); + binbuf_write(bb, buf, "", 0); + binbuf_free(bb); +} + +static void funbuff_writehook(t_pd *z, t_symbol *fn, int ac, t_atom *av) +{ + funbuff_dowrite((t_funbuff *)z, fn); +} + +static void funbuff_embedhook(t_pd *z, t_binbuf *bb, t_symbol *bindsym) +{ + t_funbuff *x = (t_funbuff *)z; + if (x->x_embedflag) + { + t_hammernode *np; + binbuf_addv(bb, "ssi;", bindsym, gensym("embed"), 1); + if (np = x->x_tree.t_first) + { + binbuf_addv(bb, "ss", bindsym, gensym("set")); + for (; np; np = np->n_next) + binbuf_addv(bb, "if", np->n_index, np->n_value); + binbuf_addsemi(bb); + } + } +} + +/* CHECKED symbol arg ok */ +static void funbuff_read(t_funbuff *x, t_symbol *s) +{ + if (s && s != &s_) + funbuff_doread(x, s); + else + hammerpanel_open(x->x_filehandle); +} + +/* CHECKED symbol arg not allowed -- + a bug? but CHECKME other classes (cf seq's filetype dilemma) */ +static void funbuff_write(t_funbuff *x, t_symbol *s) +{ + if (s && s != &s_) + funbuff_dowrite(x, s); + else /* CHECKME default name */ + hammerpanel_save(x->x_filehandle, + canvas_getdir(x->x_canvas), x->x_defname); +} + +static void funbuff_delete(t_funbuff *x, t_symbol *s, int ac, t_atom *av) +{ + if (ac && av->a_type == A_FLOAT && + (ac == 1 || (ac == 2 && av[1].a_type == A_FLOAT))) + { + /* CHECKED float is silently truncated */ + int ndx = (int)av->a_w.w_float; + t_hammernode *np; + if ((np = hammertree_search(&x->x_tree, ndx)) && + (ac == 1 || np->n_value == av[1].a_w.w_float)) + { + if (np == x->x_pointer) + x->x_pointer = 0; /* CHECKED corrupt pointer left here... */ + hammertree_delete(&x->x_tree, np); + } + /* CHECKED mismatch silently ignored */ + } + else loud_messarg((t_pd *)x, s); /* CHECKED */ +} + +static void funbuff_find(t_funbuff *x, t_floatarg f) +{ + t_hammernode *np; + if (np = x->x_tree.t_first) + { + do + { + /* CHECKED lastdelta preserved */ + if (np->n_value == f) + funbuff_dooutput(x, np->n_index, x->x_lastdelta); + } + while (np = np->n_next); + /* CHECKED no bangout, no complaint if nothing found */ + } + else loud_error((t_pd *)x, "nothing to find"); /* CHECKED */ +} + +static void funbuff_dump(t_funbuff *x) +{ + t_hammernode *np; + if (np = x->x_tree.t_first) + { + do + { + x->x_lastdelta = np->n_value; /* CHECKED */ + /* float value preserved (this is incompatible) */ + funbuff_dooutput(x, np->n_index, np->n_value); + } + while (np = np->n_next); + /* CHECKED no bangout */ + } + else loud_error((t_pd *)x, "nothing to dump"); /* CHECKED */ +} + +/* CHECKME if pointer is updated */ +static void funbuff_dointerp(t_funbuff *x, t_floatarg f, int vsz, t_float *vec) +{ + t_hammernode *np1; + int trunc = (int)f; + if (trunc > f) trunc--; /* CHECKME negative floats */ + if (np1 = hammertree_closest(&x->x_tree, trunc, 0)) + { + float value = np1->n_value; + t_hammernode *np2 = np1->n_next; + if (np2) + { + float delta = (float)(np2->n_index - np1->n_index); + /* this is incompatible -- CHECKED float argument is silently + truncated (which does not make much sense here), CHECKME again */ + float frac = f - np1->n_index; + if (frac < 0 || frac >= delta) + { + bug("funbuff_dointerp"); + return; + } + frac /= delta; + if (vec) + { + /* CHECKME */ + float vpos = (vsz - 1) * frac; + int vndx = (int)vpos; + float vfrac = vpos - vndx; + if (vndx < 0 || vndx >= vsz - 1) + { + bug("funbuff_dointerp redundant test..."); + return; + } + vec += vndx; + frac = *vec + (vec[1] - *vec) * vfrac; + } + value += (np2->n_value - np1->n_value) * frac; + } + funbuff_dooutput(x, value, x->x_lastdelta); /* CHECKME !np2 */ + } + else if (np1 = hammertree_closest(&x->x_tree, trunc, 1)) + funbuff_dooutput(x, np1->n_value, x->x_lastdelta); /* CHECKME */ +} + +static void funbuff_interp(t_funbuff *x, t_floatarg f) +{ + funbuff_dointerp(x, f, 0, 0); +} + +static void funbuff_interptab(t_funbuff *x, t_symbol *s, t_floatarg f) +{ + int vsz; + t_float *vec; + if (vec = vefl_get(s, &vsz, 0, (t_pd *)x)) + { + if (vsz > 2) + funbuff_dointerp(x, f, vsz, vec); + else + funbuff_dointerp(x, f, 0, 0); + } +} + +static void funbuff_reduce(t_funbuff *x, t_floatarg f) +{ + loud_notimplemented((t_pd *)x, "reduce"); +} + +static void funbuff_select(t_funbuff *x, t_floatarg f1, t_floatarg f2) +{ + loud_notimplemented((t_pd *)x, "select"); +} + +/* CHECKED (sub)buffer's copy is stored, as expected -- + 'delete' does not modify the clipboard */ +/* CHECKED cut entire contents if no selection */ +static void funbuff_cut(t_funbuff *x) +{ + loud_notimplemented((t_pd *)x, "cut"); +} + +/* CHECKED copy entire contents if no selection */ +static void funbuff_copy(t_funbuff *x) +{ + loud_notimplemented((t_pd *)x, "copy"); +} + +static void funbuff_paste(t_funbuff *x) +{ + loud_notimplemented((t_pd *)x, "paste"); +} + +static void funbuff_undo(t_funbuff *x) +{ + /* CHECKED apparently not working in 4.07 */ + loud_notimplemented((t_pd *)x, "undo"); +} + +#ifdef HAMMERTREE_DEBUG +static void funbuff_debug(t_funbuff *x, t_floatarg f) +{ + hammertree_debug(&x->x_tree, (int)f); +} +#endif + +static void funbuff_free(t_funbuff *x) +{ + hammerfile_free(x->x_filehandle); + hammertree_clear(&x->x_tree, 0); +} + +static void *funbuff_new(t_symbol *s) +{ + t_funbuff *x = (t_funbuff *)pd_new(funbuff_class); + x->x_canvas = canvas_getcurrent(); + x->x_valueset = 0; + x->x_pointer = 0; + x->x_pointerset = 0; + x->x_lastdelta = 0; + x->x_embedflag = 0; + hammertree_init(&x->x_tree, 0); + inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1")); + outlet_new((t_object *)x, &s_float); + x->x_deltaout = outlet_new((t_object *)x, &s_float); + x->x_bangout = outlet_new((t_object *)x, &s_bang); + if (s && s != &s_) + { + x->x_defname = s; /* CHECKME if 'read' changes this */ + funbuff_doread(x, s); + } + else x->x_defname = &s_; + x->x_filehandle = hammerfile_new((t_pd *)x, funbuff_embedhook, + funbuff_readhook, funbuff_writehook, 0); + return (x); +} + +void funbuff_setup(void) +{ + funbuff_class = class_new(gensym("funbuff"), + (t_newmethod)funbuff_new, + (t_method)funbuff_free, + sizeof(t_funbuff), 0, A_DEFSYM, 0); + class_addbang(funbuff_class, funbuff_bang); + class_addfloat(funbuff_class, funbuff_float); + class_addmethod(funbuff_class, (t_method)funbuff_ft1, + gensym("ft1"), A_FLOAT, 0); + class_addmethod(funbuff_class, (t_method)funbuff_clear, + gensym("clear"), 0); + class_addmethod(funbuff_class, (t_method)funbuff_goto, + gensym("goto"), A_FLOAT, 0); + class_addmethod(funbuff_class, (t_method)funbuff_min, + gensym("min"), 0); + class_addmethod(funbuff_class, (t_method)funbuff_max, + gensym("max"), 0); + class_addmethod(funbuff_class, (t_method)funbuff_next, + gensym("next"), 0); + class_addmethod(funbuff_class, (t_method)funbuff_embed, + gensym("embed"), A_FLOAT, 0); + class_addmethod(funbuff_class, (t_method)funbuff_read, + gensym("read"), A_DEFSYM, 0); + class_addmethod(funbuff_class, (t_method)funbuff_write, + gensym("write"), A_DEFSYM, 0); + class_addmethod(funbuff_class, (t_method)funbuff_set, + gensym("set"), A_GIMME, 0); + class_addmethod(funbuff_class, (t_method)funbuff_delete, + gensym("delete"), A_GIMME, 0); + class_addmethod(funbuff_class, (t_method)funbuff_find, + gensym("find"), A_FLOAT, 0); + class_addmethod(funbuff_class, (t_method)funbuff_dump, + gensym("dump"), 0); + class_addmethod(funbuff_class, (t_method)funbuff_interp, + gensym("interp"), A_FLOAT, 0); + class_addmethod(funbuff_class, (t_method)funbuff_interptab, + gensym("interptab"), A_FLOAT, A_SYMBOL, 0); + class_addmethod(funbuff_class, (t_method)funbuff_reduce, + gensym("reduce"), A_FLOAT, 0); + class_addmethod(funbuff_class, (t_method)funbuff_select, + gensym("select"), A_FLOAT, A_FLOAT, 0); + class_addmethod(funbuff_class, (t_method)funbuff_cut, + gensym("cut"), 0); + class_addmethod(funbuff_class, (t_method)funbuff_copy, + gensym("copy"), 0); + class_addmethod(funbuff_class, (t_method)funbuff_paste, + gensym("paste"), 0); + class_addmethod(funbuff_class, (t_method)funbuff_undo, + gensym("undo"), 0); +#ifdef HAMMERTREE_DEBUG + class_addmethod(funbuff_class, (t_method)funbuff_debug, + gensym("debug"), A_DEFFLOAT, 0); +#endif + hammerfile_setup(funbuff_class, 1); +} -- cgit v1.2.1