Make open() posix compliant api-wise. A few calls (those with O_CREAT) need the addit...
[kugel-rb.git] / apps / plugins / pdbox / PDa / src / g_array.c
blobf0359e465abd0988e9358409be15526bd076169b
1 /* Copyright (c) 1997-1999 Miller Puckette.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
5 #ifdef ROCKBOX
6 #include "plugin.h"
7 #include "../../pdbox.h"
8 #include "m_pd.h"
9 #include "g_canvas.h"
10 #ifdef SIMULATOR
11 int printf(const char *fmt, ...);
12 #endif /* SIMULATOR */
13 #else /* ROCKBOX */
14 #include <stdlib.h>
15 #include <string.h>
16 #include <stdio.h> /* for read/write to files */
17 #include "m_pd.h"
18 #include "g_canvas.h"
19 #include <math.h>
20 #endif /* ROCKBOX */
22 /* see also the "plot" object in g_scalar.c which deals with graphing
23 arrays which are fields in scalars. Someday we should unify the
24 two, but how? */
26 /* aux routine to bash leading '#' to '$' for dialogs in u_main.tk
27 which can't send symbols starting with '$' (because the Pd message
28 interpreter would change them!) */
30 static t_symbol *sharptodollar(t_symbol *s)
32 if (*s->s_name == '#')
34 char buf[MAXPDSTRING];
35 strncpy(buf, s->s_name, MAXPDSTRING);
36 buf[MAXPDSTRING-1] = 0;
37 buf[0] = '$';
38 return (gensym(buf));
40 else return (s);
43 /* --------- "pure" arrays with scalars for elements. --------------- */
45 /* Pure arrays have no a priori graphical capabilities.
46 They are instantiated by "garrays" below or can be elements of other
47 scalars (g_scalar.c); their graphical behavior is defined accordingly. */
49 t_array *array_new(t_symbol *templatesym, t_gpointer *parent)
51 t_array *x = (t_array *)getbytes(sizeof (*x));
52 t_template *template;
53 #ifndef ROCKBOX
54 t_gpointer *gp;
55 #endif
56 template = template_findbyname(templatesym);
57 x->a_templatesym = templatesym;
58 x->a_n = 1;
59 x->a_elemsize = sizeof(t_word) * template->t_n;
60 x->a_vec = (char *)getbytes(x->a_elemsize);
61 /* note here we blithely copy a gpointer instead of "setting" a
62 new one; this gpointer isn't accounted for and needn't be since
63 we'll be deleted before the thing pointed to gets deleted anyway;
64 see array_free. */
65 x->a_gp = *parent;
66 x->a_stub = gstub_new(0, x);
67 word_init((t_word *)(x->a_vec), template, parent);
68 return (x);
71 void array_resize(t_array *x, t_template *template, int n)
73 int elemsize, oldn;
74 #ifndef ROCKBOX
75 t_gpointer *gp;
76 #endif
78 if (n < 1)
79 n = 1;
80 oldn = x->a_n;
81 elemsize = sizeof(t_word) * template->t_n;
83 x->a_vec = (char *)resizebytes(x->a_vec, oldn * elemsize,
84 n * elemsize);
85 x->a_n = n;
86 if (n > oldn)
88 char *cp = x->a_vec + elemsize * oldn;
89 int i = n - oldn;
90 for (; i--; cp += elemsize)
92 t_word *wp = (t_word *)cp;
93 word_init(wp, template, &x->a_gp);
98 void word_free(t_word *wp, t_template *template);
100 void array_free(t_array *x)
102 int i;
103 t_template *scalartemplate = template_findbyname(x->a_templatesym);
104 /* we don't unset our gpointer here since it was never "set." */
105 /* gpointer_unset(&x->a_gp); */
106 gstub_cutoff(x->a_stub);
107 for (i = 0; i < x->a_n; i++)
109 t_word *wp = (t_word *)(x->a_vec + x->a_elemsize * i);
110 word_free(wp, scalartemplate);
112 freebytes(x->a_vec, x->a_elemsize * x->a_n);
113 freebytes(x, sizeof *x);
116 /* --------------------- graphical arrays (garrays) ------------------- */
118 t_class *garray_class;
119 static int gcount = 0;
121 struct _garray
123 t_gobj x_gobj;
124 t_glist *x_glist;
125 t_array x_array; /* actual array; note only 4 fields used as below */
126 t_symbol *x_name;
127 t_symbol *x_realname; /* name with "$" expanded */
128 t_float x_firstx; /* X value of first item */
129 t_float x_xinc; /* X increment */
130 char x_usedindsp; /* true if some DSP routine is using this */
131 char x_saveit; /* true if we should save this with parent */
134 /* macros to get into the "array" structure */
135 #define x_n x_array.a_n
136 #define x_elemsize x_array.a_elemsize
137 #define x_vec x_array.a_vec
138 #define x_templatesym x_array.a_templatesym
140 t_garray *graph_array(t_glist *gl, t_symbol *s, t_symbol *templatesym,
141 t_floatarg f, t_floatarg saveit)
143 int n = f, i;
144 int zz, nwords;
145 t_garray *x;
146 t_pd *x2;
147 t_template *template;
148 char *str;
149 if (s == &s_)
151 char buf[40];
152 #ifdef ROCKBOX
153 snprintf(buf, sizeof(buf), "array%d", ++gcount);
154 #else
155 sprintf(buf, "array%d", ++gcount);
156 #endif
157 s = gensym(buf);
158 templatesym = &s_float;
159 n = 100;
161 else if (!strncmp((str = s->s_name), "array", 5)
162 && (zz = atoi(str + 5)) > gcount) gcount = zz;
163 template = template_findbyname(templatesym);
164 if (!template)
166 error("array: couldn't find template %s", templatesym->s_name);
167 return (0);
169 nwords = template->t_n;
170 for (i = 0; i < nwords; i++)
172 /* we can't have array or list elements yet because what scalar
173 can act as their "parent"??? */
174 if (template->t_vec[i].ds_type == DT_ARRAY
175 || template->t_vec[i].ds_type == DT_LIST)
177 error("array: template %s can't have sublists or arrays",
178 templatesym->s_name);
179 return (0);
182 x = (t_garray *)pd_new(garray_class);
184 if (n <= 0) n = 100;
185 x->x_n = n;
186 x->x_elemsize = nwords * sizeof(t_word);
187 x->x_vec = getbytes(x->x_n * x->x_elemsize);
188 memset(x->x_vec, 0, x->x_n * x->x_elemsize);
189 /* LATER should check that malloc */
190 x->x_name = s;
191 x->x_realname = canvas_realizedollar(gl, s);
192 pd_bind(&x->x_gobj.g_pd, x->x_realname);
193 x->x_templatesym = templatesym;
194 x->x_firstx = 0;
195 x->x_xinc = 1; /* LATER make methods to set this... */
196 glist_add(gl, &x->x_gobj);
197 x->x_glist = gl;
198 x->x_usedindsp = 0;
199 x->x_saveit = (saveit != 0);
200 if((x2 = pd_findbyclass(gensym("#A"), garray_class)))
201 pd_unbind(x2, gensym("#A"));
203 pd_bind(&x->x_gobj.g_pd, gensym("#A"));
205 return (x);
208 /* called from array menu item to create a new one */
209 void canvas_menuarray(t_glist *canvas)
211 #ifdef ROCKBOX
212 (void) canvas;
213 #else /* ROCKBOX */
214 t_glist *x = (t_glist *)canvas;
215 char cmdbuf[200];
216 sprintf(cmdbuf, "pdtk_array_dialog %%s array%d 100 1 1\n",
217 ++gcount);
218 gfxstub_new(&x->gl_pd, x, cmdbuf);
219 #endif /* ROCKBOX */
222 /* called from graph_dialog to set properties */
223 void garray_properties(t_garray *x)
225 #ifdef ROCKBOX
226 (void) x;
227 #else /* ROCKBOX */
228 char cmdbuf[200];
229 gfxstub_deleteforkey(x);
230 /* create dialog window. LATER fix this to escape '$'
231 properly; right now we just detect a leading '$' and escape
232 it. There should be a systematic way of doing this. */
233 if (x->x_name->s_name[0] == '$')
234 sprintf(cmdbuf, "pdtk_array_dialog %%s \\%s %d %d 0\n",
235 x->x_name->s_name, x->x_n, x->x_saveit);
236 else sprintf(cmdbuf, "pdtk_array_dialog %%s %s %d %d 0\n",
237 x->x_name->s_name, x->x_n, x->x_saveit);
238 gfxstub_new(&x->x_gobj.g_pd, x, cmdbuf);
239 #endif /* ROCKBOX */
242 /* this is called back from the dialog window to create a garray.
243 The otherflag requests that we find an existing graph to put it in. */
244 void glist_arraydialog(t_glist *parent, t_symbol *name, t_floatarg size,
245 t_floatarg saveit, t_floatarg otherflag)
247 t_glist *gl;
248 t_garray *a;
249 if (size < 1)
250 size = 1;
251 if (otherflag == 0 || (!(gl = glist_findgraph(parent))))
252 gl = glist_addglist(parent, &s_, 0, 1,
253 (size > 1 ? size-1 : size), -1, 0, 0, 0, 0);
254 a = graph_array(gl, sharptodollar(name), &s_float, size, saveit);
257 /* this is called from the properties dialog window for an existing array */
258 void garray_arraydialog(t_garray *x, t_symbol *name, t_floatarg fsize,
259 t_floatarg saveit, t_floatarg deleteit)
261 if (deleteit != 0)
263 glist_delete(x->x_glist, &x->x_gobj);
265 else
267 int size;
268 t_symbol *argname = sharptodollar(name);
269 if (argname != x->x_name)
271 x->x_name = argname;
272 pd_unbind(&x->x_gobj.g_pd, x->x_realname);
273 x->x_realname = canvas_realizedollar(x->x_glist, argname);
274 pd_bind(&x->x_gobj.g_pd, x->x_realname);
276 size = fsize;
277 if (size < 1)
278 size = 1;
279 if (size != x->x_n)
280 garray_resize(x, size);
281 garray_setsaveit(x, (saveit != 0));
282 garray_redraw(x);
286 static void garray_free(t_garray *x)
288 t_pd *x2;
289 #ifndef ROCKBOX
290 gfxstub_deleteforkey(x);
291 #endif
292 pd_unbind(&x->x_gobj.g_pd, x->x_realname);
293 /* LATER find a way to get #A unbound earlier (at end of load?) */
294 while((x2 = pd_findbyclass(gensym("#A"), garray_class)))
295 pd_unbind(x2, gensym("#A"));
296 freebytes(x->x_vec, x->x_n * x->x_elemsize);
299 /* ------------- code used by both array and plot widget functions ---- */
301 /* routine to get screen coordinates of a point in an array */
302 void array_getcoordinate(t_glist *glist,
303 char *elem, int xonset, int yonset, int wonset, int indx,
304 float basex, float basey, float xinc,
305 float *xp, float *yp, float *wp)
307 float xval, yval, ypix, wpix;
308 if (xonset >= 0)
309 xval = fixtof(*(t_sample *)(elem + xonset));
310 else xval = indx * xinc;
311 if (yonset >= 0)
312 yval = fixtof(*(t_sample *)(elem + yonset));
313 else yval = 0;
314 ypix = glist_ytopixels(glist, basey + yval);
315 if (wonset >= 0)
317 /* found "w" field which controls linewidth. */
318 float wval = *(float *)(elem + wonset);
319 wpix = glist_ytopixels(glist, basey + yval + wval) - ypix;
320 if (wpix < 0)
321 wpix = -wpix;
323 else wpix = 1;
324 *xp = glist_xtopixels(glist, basex + xval);
325 *yp = ypix;
326 *wp = wpix;
329 static float array_motion_xcumulative;
330 static float array_motion_ycumulative;
331 static t_symbol *array_motion_xfield;
332 static t_symbol *array_motion_yfield;
333 static t_glist *array_motion_glist;
334 static t_gobj *array_motion_gobj;
335 static t_word *array_motion_wp;
336 static t_template *array_motion_template;
337 static int array_motion_npoints;
338 static int array_motion_elemsize;
339 #ifndef ROCKBOX
340 static int array_motion_altkey;
341 #endif
342 static float array_motion_initx;
343 static float array_motion_xperpix;
344 static float array_motion_yperpix;
345 static int array_motion_lastx;
346 static int array_motion_fatten;
348 /* LATER protect against the template changing or the scalar disappearing
349 probably by attaching a gpointer here ... */
351 static void array_motion(void *z, t_floatarg dx, t_floatarg dy)
353 #ifdef ROCKBOX
354 (void) z;
355 #endif
356 array_motion_xcumulative += dx * array_motion_xperpix;
357 array_motion_ycumulative += dy * array_motion_yperpix;
358 if (*array_motion_xfield->s_name)
360 /* it's an x, y plot; can drag many points at once */
361 int i;
362 char *charword = (char *)array_motion_wp;
363 for (i = 0; i < array_motion_npoints; i++)
365 t_word *thisword = (t_word *)(charword + i * array_motion_elemsize);
366 if (*array_motion_xfield->s_name)
368 float xwas = template_getfloat(array_motion_template,
369 array_motion_xfield, thisword, 1);
370 template_setfloat(array_motion_template,
371 array_motion_xfield, thisword, xwas + dx, 1);
373 if (*array_motion_yfield->s_name)
375 float ywas = template_getfloat(array_motion_template,
376 array_motion_yfield, thisword, 1);
377 if (array_motion_fatten)
379 if (i == 0)
381 float newy = ywas + dy * array_motion_yperpix;
382 if (newy < 0)
383 newy = 0;
384 template_setfloat(array_motion_template,
385 array_motion_yfield, thisword, newy, 1);
388 else
390 template_setfloat(array_motion_template,
391 array_motion_yfield, thisword,
392 ywas + dy * array_motion_yperpix, 1);
397 else
399 /* a y-only plot. */
400 int thisx = array_motion_initx +
401 array_motion_xcumulative, x2;
402 int increment, i, nchange;
403 char *charword = (char *)array_motion_wp;
404 float newy = array_motion_ycumulative,
405 oldy = template_getfloat(
406 array_motion_template, array_motion_yfield,
407 (t_word *)(charword + array_motion_elemsize * array_motion_lastx), 1);
408 float ydiff = newy - oldy;
409 if (thisx < 0) thisx = 0;
410 else if (thisx >= array_motion_npoints)
411 thisx = array_motion_npoints - 1;
412 increment = (thisx > array_motion_lastx ? -1 : 1);
413 nchange = 1 + increment * (array_motion_lastx - thisx);
415 for (i = 0, x2 = thisx; i < nchange; i++, x2 += increment)
417 template_setfloat(array_motion_template,
418 array_motion_yfield,
419 (t_word *)(charword + array_motion_elemsize * x2),
420 newy, 1);
421 if (nchange > 1)
422 newy -= ydiff * (1./(nchange - 1));
424 array_motion_lastx = thisx;
426 glist_redrawitem(array_motion_glist, array_motion_gobj);
429 int array_doclick(t_array *array, t_glist *glist, t_gobj *gobj,
430 t_symbol *elemtemplatesym,
431 float linewidth, float xloc, float xinc, float yloc,
432 int xpix, int ypix, int shift, int alt, int dbl, int doit)
434 t_canvas *elemtemplatecanvas;
435 t_template *elemtemplate;
436 int elemsize, yonset, wonset, xonset, i;
438 #ifdef ROCKBOX
439 (void) linewidth;
440 (void) shift;
441 (void) dbl;
442 #endif
444 if (!array_getfields(elemtemplatesym, &elemtemplatecanvas,
445 &elemtemplate, &elemsize, &xonset, &yonset, &wonset))
447 float best = 100;
448 int incr;
449 /* if it has more than 2000 points, just check 300 of them. */
450 if (array->a_n < 2000)
451 incr = 1;
452 else incr = array->a_n / 300;
453 for (i = 0; i < array->a_n; i += incr)
455 float pxpix, pypix, pwpix, dx, dy;
456 array_getcoordinate(glist, (char *)(array->a_vec) + i * elemsize,
457 xonset, yonset, wonset, i, xloc, yloc, xinc,
458 &pxpix, &pypix, &pwpix);
459 if (pwpix < 4)
460 pwpix = 4;
461 dx = pxpix - xpix;
462 if (dx < 0) dx = -dx;
463 if (dx > 8)
464 continue;
465 dy = pypix - ypix;
466 if (dy < 0) dy = -dy;
467 if (dx + dy < best)
468 best = dx + dy;
469 if (wonset >= 0)
471 dy = (pypix + pwpix) - ypix;
472 if (dy < 0) dy = -dy;
473 if (dx + dy < best)
474 best = dx + dy;
475 dy = (pypix - pwpix) - ypix;
476 if (dy < 0) dy = -dy;
477 if (dx + dy < best)
478 best = dx + dy;
481 if (best > 8)
482 return (0);
483 best += 0.001; /* add truncation error margin */
484 for (i = 0; i < array->a_n; i += incr)
486 float pxpix, pypix, pwpix, dx, dy, dy2, dy3;
487 array_getcoordinate(glist, (char *)(array->a_vec) + i * elemsize,
488 xonset, yonset, wonset, i, xloc, yloc, xinc,
489 &pxpix, &pypix, &pwpix);
490 if (pwpix < 4)
491 pwpix = 4;
492 dx = pxpix - xpix;
493 if (dx < 0) dx = -dx;
494 dy = pypix - ypix;
495 if (dy < 0) dy = -dy;
496 if (wonset >= 0)
498 dy2 = (pypix + pwpix) - ypix;
499 if (dy2 < 0) dy2 = -dy2;
500 dy3 = (pypix - pwpix) - ypix;
501 if (dy3 < 0) dy3 = -dy3;
502 if (yonset <= 0)
503 dy = 100;
505 else dy2 = dy3 = 100;
506 if (dx + dy <= best || dx + dy2 <= best || dx + dy3 <= best)
508 if (dy < dy2 && dy < dy3)
509 array_motion_fatten = 0;
510 else if (dy2 < dy3)
511 array_motion_fatten = -1;
512 else array_motion_fatten = 1;
513 if (doit)
515 char *elem = (char *)array->a_vec;
516 array_motion_elemsize = elemsize;
517 array_motion_glist = glist;
518 array_motion_gobj = gobj;
519 array_motion_template = elemtemplate;
520 array_motion_xperpix = glist_dpixtodx(glist, 1);
521 array_motion_yperpix = glist_dpixtody(glist, 1);
522 if (alt && xpix < pxpix) /* delete a point */
524 if (array->a_n <= 1)
525 return (0);
526 memmove((char *)(array->a_vec) + elemsize * i,
527 (char *)(array->a_vec) + elemsize * (i+1),
528 (array->a_n - 1 - i) * elemsize);
529 array_resize(array, elemtemplate, array->a_n - 1);
530 glist_redrawitem(array_motion_glist, array_motion_gobj);
531 return (0);
533 else if (alt)
535 /* add a point (after the clicked-on one) */
536 array_resize(array, elemtemplate, array->a_n + 1);
537 elem = (char *)array->a_vec;
538 memmove(elem + elemsize * (i+1),
539 elem + elemsize * i,
540 (array->a_n - i - 1) * elemsize);
541 i++;
543 if (xonset >= 0)
545 array_motion_xfield = gensym("x");
546 array_motion_xcumulative =
547 *(float *)((elem + elemsize * i) + xonset);
548 array_motion_wp = (t_word *)(elem + i * elemsize);
549 array_motion_npoints = array->a_n - i;
551 else
553 array_motion_xfield = &s_;
554 array_motion_xcumulative = 0;
555 array_motion_wp = (t_word *)elem;
556 array_motion_npoints = array->a_n;
558 array_motion_initx = i;
559 array_motion_lastx = i;
560 array_motion_xperpix *= (xinc == 0 ? 1 : 1./xinc);
562 if (array_motion_fatten)
564 array_motion_yfield = gensym("w");
565 array_motion_ycumulative =
566 *(float *)((elem + elemsize * i) + wonset);
567 array_motion_yperpix *= array_motion_fatten;
569 else if (yonset >= 0)
571 array_motion_yfield = gensym("y");
572 array_motion_ycumulative =
573 *(float *)((elem + elemsize * i) + yonset);
575 else
577 array_motion_yfield = &s_;
578 array_motion_ycumulative = 0;
580 glist_grab(glist, 0, array_motion, 0, xpix, ypix);
582 if (alt)
584 if (xpix < pxpix)
585 return (CURSOR_EDITMODE_DISCONNECT);
586 else return (CURSOR_RUNMODE_ADDPOINT);
588 else return (array_motion_fatten ?
589 CURSOR_RUNMODE_THICKEN : CURSOR_RUNMODE_CLICKME);
593 return (0);
596 /* -------------------- widget behavior for garray ------------ */
598 static void garray_getrect(t_gobj *z, t_glist *glist,
599 int *xp1, int *yp1, int *xp2, int *yp2)
601 t_garray *x = (t_garray *)z;
602 float x1 = 0x7fffffff, y1 = 0x7fffffff, x2 = -0x7fffffff, y2 = -0x7fffffff;
603 t_canvas *elemtemplatecanvas;
604 t_template *elemtemplate;
605 int elemsize, yonset, wonset, xonset, i;
607 if (!array_getfields(x->x_templatesym, &elemtemplatecanvas,
608 &elemtemplate, &elemsize, &xonset, &yonset, &wonset))
610 int incr;
611 /* if it has more than 2000 points, just check 300 of them. */
612 if (x->x_array.a_n < 2000)
613 incr = 1;
614 else incr = x->x_array.a_n / 300;
615 for (i = 0; i < x->x_array.a_n; i += incr)
617 #ifdef ROCKBOX
618 float pxpix, pypix, pwpix;
619 #else /* ROCKBOX */
620 float pxpix, pypix, pwpix, dx, dy;
621 #endif /* ROCKBOX */
622 array_getcoordinate(glist, (char *)(x->x_array.a_vec) +
623 i * elemsize,
624 xonset, yonset, wonset, i, 0, 0, 1,
625 &pxpix, &pypix, &pwpix);
626 if (pwpix < 2)
627 pwpix = 2;
628 if (pxpix < x1)
629 x1 = pxpix;
630 if (pxpix > x2)
631 x2 = pxpix;
632 if (pypix - pwpix < y1)
633 y1 = pypix - pwpix;
634 if (pypix + pwpix > y2)
635 y2 = pypix + pwpix;
638 *xp1 = x1;
639 *yp1 = y1;
640 *xp2 = x2;
641 *yp2 = y2;
644 static void garray_displace(t_gobj *z, t_glist *glist, int dx, int dy)
646 #ifdef ROCKBOX
647 (void) z;
648 (void) glist;
649 (void) dx;
650 (void) dy;
651 #endif
652 /* refuse */
655 static void garray_select(t_gobj *z, t_glist *glist, int state)
657 #ifdef ROCKBOX
658 (void) z;
659 (void) glist;
660 (void) state;
661 #else /* ROCKBOX */
662 t_garray *x = (t_garray *)z;
663 #endif /* ROCKBOX */
664 /* fill in later */
667 static void garray_activate(t_gobj *z, t_glist *glist, int state)
669 #ifdef ROCKBOX
670 (void) z;
671 (void) glist;
672 (void) state;
673 #endif
676 static void garray_delete(t_gobj *z, t_glist *glist)
678 #ifdef ROCKBOX
679 (void) z;
680 (void) glist;
681 #endif
682 /* nothing to do */
685 static void garray_vis(t_gobj *z, t_glist *glist, int vis)
687 t_garray *x = (t_garray *)z;
688 if (vis)
690 int i, xonset, yonset, type;
691 t_symbol *arraytype;
692 t_template *template = template_findbyname(x->x_templatesym);
693 if (!template)
694 return;
695 if (!template_find_field(template, gensym("y"), &yonset, &type,
696 &arraytype) || type != DT_FLOAT)
698 error("%s: needs floating-point 'y' field",
699 x->x_templatesym->s_name);
700 #ifndef ROCKBOX
701 sys_vgui(".x%x.c create text 50 50 -text foo\
702 -tags .x%x.a%x\n",
703 glist_getcanvas(glist), glist_getcanvas(glist), x);
704 #endif
706 else if (!template_find_field(template, gensym("x"), &xonset, &type,
707 &arraytype) || type != DT_FLOAT)
709 float firsty, xcum = x->x_firstx;
710 int lastpixel = -1, ndrawn = 0;
711 float yval = 0, xpix;
712 int ixpix = 0;
713 #ifndef ROCKBOX
714 sys_vgui(".x%x.c create line \\\n", glist_getcanvas(glist));
715 #endif
716 for (i = 0; i < x->x_n; i++)
718 yval = fixtof(*(t_sample *)(x->x_vec +
719 template->t_n * i * sizeof (t_word) + yonset));
720 xpix = glist_xtopixels(glist, xcum);
721 ixpix = xpix + 0.5;
722 if (ixpix != lastpixel)
724 #ifndef ROCKBOX
725 sys_vgui("%d %f \\\n", ixpix,
726 glist_ytopixels(glist, yval));
727 #endif
728 ndrawn++;
730 lastpixel = ixpix;
731 if (ndrawn >= 1000) break;
732 xcum += x->x_xinc;
734 /* TK will complain if there aren't at least 2 points... */
735 #ifndef ROCKBOX
736 if (ndrawn == 0) sys_vgui("0 0 0 0 \\\n");
737 else if (ndrawn == 1) sys_vgui("%d %f \\\n", ixpix,
738 glist_ytopixels(glist, yval));
739 sys_vgui("-tags .x%x.a%x\n", glist_getcanvas(glist), x);
740 #endif
741 firsty = fixtof(*(t_sample *)(x->x_vec + yonset));
742 #ifndef ROCKBOX
743 sys_vgui(".x%x.c create text %f %f -text {%s} -anchor e\
744 -font -*-courier-bold--normal--%d-* -tags .x%x.a%x\n",
745 glist_getcanvas(glist),
746 glist_xtopixels(glist, x->x_firstx) - 5.,
747 glist_ytopixels(glist, firsty),
748 x->x_name->s_name, glist_getfont(glist),
749 glist_getcanvas(glist), x);
750 #endif
752 else
754 post("x, y arrays not yet supported");
757 else
759 #ifndef ROCKBOX
760 sys_vgui(".x%x.c delete .x%x.a%x\n",
761 glist_getcanvas(glist), glist_getcanvas(glist), x);
762 #endif
766 static int garray_click(t_gobj *z, struct _glist *glist,
767 int xpix, int ypix, int shift, int alt, int dbl, int doit)
769 t_garray *x = (t_garray *)z;
770 return (array_doclick(&x->x_array, glist, z, x->x_templatesym, 1, 0, 1, 0,
771 xpix, ypix, shift, alt, dbl, doit));
774 #define ARRAYWRITECHUNKSIZE 1000
776 static void garray_save(t_gobj *z, t_binbuf *b)
778 t_garray *x = (t_garray *)z;
779 binbuf_addv(b, "sssisi;", gensym("#X"), gensym("array"),
780 x->x_name, x->x_n, x->x_templatesym, x->x_saveit);
781 #ifdef ROCKBOX
782 #ifdef SIMULATOR
783 printf("array save\n");
784 #endif /* SIMULATOR */
785 #else /* ROCKBOX */
786 fprintf(stderr,"array save\n");
787 #endif /* ROCKBOX */
788 if (x->x_saveit)
790 int n = x->x_n, n2 = 0;
791 if (x->x_templatesym != &s_float)
793 pd_error(x, "sorry, you can only save 'float' arrays now");
794 return;
796 if (n > 200000)
797 post("warning: I'm saving an array with %d points!\n", n);
798 while (n2 < n)
800 int chunk = n - n2, i;
801 if (chunk > ARRAYWRITECHUNKSIZE)
802 chunk = ARRAYWRITECHUNKSIZE;
803 binbuf_addv(b, "si", gensym("#A"), n2);
804 for (i = 0; i < chunk; i++)
805 binbuf_addv(b, "f", fixtof(((t_sample *)(x->x_vec))[n2+i]));
806 binbuf_addv(b, ";");
807 n2 += chunk;
812 t_widgetbehavior garray_widgetbehavior =
814 garray_getrect,
815 garray_displace,
816 garray_select,
817 garray_activate,
818 garray_delete,
819 garray_vis,
820 garray_click
823 /* ----------------------- public functions -------------------- */
825 void garray_usedindsp(t_garray *x)
827 x->x_usedindsp = 1;
830 void garray_redraw(t_garray *x)
832 if (glist_isvisible(x->x_glist))
834 garray_vis(&x->x_gobj, x->x_glist, 0);
835 garray_vis(&x->x_gobj, x->x_glist, 1);
839 /* This functiopn gets the template of an array; if we can't figure
840 out what template an array's elements belong to we're in grave trouble
841 when it's time to free or resize it. */
842 t_template *garray_template(t_garray *x)
844 t_template *template = template_findbyname(x->x_templatesym);
845 if (!template)
846 bug("garray_template");
847 return (template);
850 int garray_npoints(t_garray *x) /* get the length */
852 return (x->x_n);
855 char *garray_vec(t_garray *x) /* get the contents */
857 return ((char *)(x->x_vec));
860 /* routine that checks if we're just an array of floats and if
861 so returns the goods */
863 int garray_getfloatarray(t_garray *x, int *size, t_sample **vec)
865 t_template *template = garray_template(x);
866 int yonset, type;
867 t_symbol *arraytype;
868 if (!template_find_field(template, gensym("y"), &yonset,
869 &type, &arraytype) || type != DT_FLOAT)
870 error("%s: needs floating-point 'y' field",
871 x->x_templatesym->s_name);
872 else if (template->t_n != 1)
873 error("%s: has more than one field", x->x_templatesym->s_name);
874 else
876 *size = garray_npoints(x);
877 *vec = (t_sample *)garray_vec(x);
878 return (1);
880 return (0);
883 /* get any floating-point field of any element of an array */
884 float garray_get(t_garray *x, t_symbol *s, t_int indx)
886 t_template *template = garray_template(x);
887 int yonset, type;
888 t_symbol *arraytype;
889 if (!template_find_field(template, gensym("y"), &yonset,
890 &type, &arraytype) || type != DT_FLOAT)
892 error("%s: needs floating-point '%s' field", x->x_templatesym->s_name,
893 s->s_name);
894 return (0);
896 if (indx < 0) indx = 0;
897 else if (indx >= x->x_n) indx = x->x_n - 1;
898 return (*(float *)((x->x_vec + sizeof(t_word) * indx) + yonset));
901 /* set the "saveit" flag */
902 void garray_setsaveit(t_garray *x, int saveit)
904 if (x->x_saveit && !saveit)
905 post("warning: array %s: clearing save-in-patch flag",
906 x->x_name->s_name);
907 x->x_saveit = saveit;
910 /*------------------- Pd messages ------------------------ */
911 static void garray_const(t_garray *x, t_floatarg g)
913 t_template *template = garray_template(x);
914 int yonset, type, i;
915 t_symbol *arraytype;
916 if (!template_find_field(template, gensym("y"), &yonset,
917 &type, &arraytype) || type != DT_FLOAT)
918 error("%s: needs floating-point 'y' field",
919 x->x_templatesym->s_name);
920 else for (i = 0; i < x->x_n; i++)
921 *(float *)(((char *)x->x_vec + sizeof(t_word) * i) + yonset) = g;
922 garray_redraw(x);
925 /* sum of Fourier components; called from routines below */
926 static void garray_dofo(t_garray *x, int npoints, float dcval,
927 int nsin, t_float *vsin, int sineflag)
929 t_template *template = garray_template(x);
930 int yonset, type, i, j;
931 t_symbol *arraytype;
932 double phase, phaseincr, fj;
933 if (npoints == 0)
934 npoints = 512; /* dunno what a good default would be... */
935 if (npoints != (1 << ilog2(npoints)))
936 post("%s: rounnding to %d points", x->x_templatesym->s_name,
937 (npoints = (1<<ilog2(npoints))));
938 garray_resize(x, npoints + 3);
939 phaseincr = 2. * 3.14159 / npoints;
940 if (!template_find_field(template, gensym("y"), &yonset,
941 &type, &arraytype) || type != DT_FLOAT)
943 error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
944 return;
946 for (i = 0, phase = -phaseincr; i < x->x_n; i++, phase += phaseincr )
948 double sum = dcval;
949 if (sineflag)
950 for (j = 0, fj = phase; j < nsin; j++, fj += phase)
951 sum += vsin[j] * sin(fj);
952 else
953 for (j = 0, fj = 0; j < nsin; j++, fj += phase)
954 sum += vsin[j] * cos(fj);
955 *(float *)((x->x_vec + sizeof(t_word) * i) + yonset) = sum;
957 garray_redraw(x);
960 static void garray_sinesum(t_garray *x, t_symbol *s, int argc, t_atom *argv)
962 #ifdef ROCKBOX
963 (void) s;
964 #else
965 t_template *template = garray_template(x);
966 #endif
968 t_float *svec = (t_float *)t_getbytes(sizeof(t_float) * argc);
969 int npoints, i;
970 if (argc < 2)
972 error("sinesum: %s: need number of points and partial strengths",
973 x->x_templatesym->s_name);
974 return;
977 npoints = atom_getfloatarg(0, argc, argv);
978 argv++, argc--;
980 svec = (t_float *)t_getbytes(sizeof(t_float) * argc);
981 if (!svec) return;
983 for (i = 0; i < argc; i++)
984 svec[i] = atom_getfloatarg(i, argc, argv);
985 garray_dofo(x, npoints, 0, argc, svec, 1);
986 t_freebytes(svec, sizeof(t_float) * argc);
989 static void garray_cosinesum(t_garray *x, t_symbol *s, int argc, t_atom *argv)
991 #ifdef ROCKBOX
992 (void) s;
993 #else
994 t_template *template = garray_template(x);
995 #endif
997 t_float *svec = (t_float *)t_getbytes(sizeof(t_float) * argc);
998 int npoints, i;
999 if (argc < 2)
1001 error("sinesum: %s: need number of points and partial strengths",
1002 x->x_templatesym->s_name);
1003 return;
1006 npoints = atom_getfloatarg(0, argc, argv);
1007 argv++, argc--;
1009 svec = (t_float *)t_getbytes(sizeof(t_float) * argc);
1010 if (!svec) return;
1012 for (i = 0; i < argc; i++)
1013 svec[i] = atom_getfloatarg(i, argc, argv);
1014 garray_dofo(x, npoints, 0, argc, svec, 0);
1015 t_freebytes(svec, sizeof(t_float) * argc);
1018 static void garray_normalize(t_garray *x, t_float f)
1020 t_template *template = garray_template(x);
1021 #ifdef ROCKBOX
1022 int yonset, type, i;
1023 #else
1024 int yonset, type, npoints, i;
1025 #endif
1026 double maxv, renormer;
1027 t_symbol *arraytype;
1029 if (f <= 0)
1030 f = 1;
1032 if (!template_find_field(template, gensym("y"), &yonset,
1033 &type, &arraytype) || type != DT_FLOAT)
1035 error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
1036 return;
1038 for (i = 0, maxv = 0; i < x->x_n; i++)
1040 double v = *(float *)((x->x_vec + sizeof(t_word) * i) + yonset);
1041 if (v > maxv)
1042 maxv = v;
1043 if (-v > maxv)
1044 maxv = -v;
1046 if (maxv >= 0)
1048 renormer = f / maxv;
1049 for (i = 0; i < x->x_n; i++)
1051 *(float *)((x->x_vec + sizeof(t_word) * i) + yonset)
1052 *= renormer;
1055 garray_redraw(x);
1058 /* list -- the first value is an index; subsequent values are put in
1059 the "y" slot of the array. This generalizes Max's "table", sort of. */
1060 static void garray_list(t_garray *x, t_symbol *s, int argc, t_atom *argv)
1062 t_template *template = garray_template(x);
1063 int yonset, type, i;
1064 t_symbol *arraytype;
1065 #ifdef ROCKBOX
1066 (void) s;
1067 #endif
1068 if (!template_find_field(template, gensym("y"), &yonset,
1069 &type, &arraytype) || type != DT_FLOAT)
1070 error("%s: needs floating-point 'y' field",
1071 x->x_templatesym->s_name);
1072 else if (argc < 2) return;
1073 else
1075 int firstindex = atom_getfloat(argv);
1076 argc--;
1077 argv++;
1078 /* drop negative x values */
1079 if (firstindex < 0)
1081 argc += firstindex;
1082 argv -= firstindex;
1083 firstindex = 0;
1084 if (argc <= 0) return;
1086 if (argc + firstindex > x->x_n)
1088 argc = x->x_n - firstindex;
1089 if (argc <= 0) return;
1091 for (i = 0; i < argc; i++)
1092 *(t_sample *)((x->x_vec + sizeof(t_word) * (i + firstindex)) + yonset) =
1093 ftofix(atom_getfloat(argv + i));
1095 garray_redraw(x);
1098 /* forward a "bounds" message to the owning graph */
1099 static void garray_bounds(t_garray *x, t_floatarg x1, t_floatarg y1,
1100 t_floatarg x2, t_floatarg y2)
1102 vmess(&x->x_glist->gl_pd, gensym("bounds"), "ffff", x1, y1, x2, y2);
1105 /* same for "xticks", etc */
1106 static void garray_xticks(t_garray *x,
1107 t_floatarg point, t_floatarg inc, t_floatarg f)
1109 vmess(&x->x_glist->gl_pd, gensym("xticks"), "fff", point, inc, f);
1112 static void garray_yticks(t_garray *x,
1113 t_floatarg point, t_floatarg inc, t_floatarg f)
1115 vmess(&x->x_glist->gl_pd, gensym("yticks"), "fff", point, inc, f);
1118 static void garray_xlabel(t_garray *x, t_symbol *s, int argc, t_atom *argv)
1120 typedmess(&x->x_glist->gl_pd, s, argc, argv);
1123 static void garray_ylabel(t_garray *x, t_symbol *s, int argc, t_atom *argv)
1125 typedmess(&x->x_glist->gl_pd, s, argc, argv);
1127 /* change the name of a garray. */
1128 static void garray_rename(t_garray *x, t_symbol *s)
1130 pd_unbind(&x->x_gobj.g_pd, x->x_realname);
1131 pd_bind(&x->x_gobj.g_pd, x->x_realname = x->x_name = s);
1132 garray_redraw(x);
1135 static void garray_read(t_garray *x, t_symbol *filename)
1137 int nelem = x->x_n, filedesc;
1138 #ifdef ROCKBOX
1139 int fd = 0;
1140 #else
1141 FILE *fd;
1142 #endif
1143 char buf[MAXPDSTRING], *bufptr;
1144 t_template *template = garray_template(x);
1145 int yonset, type, i;
1146 t_symbol *arraytype;
1147 if (!template_find_field(template, gensym("y"), &yonset,
1148 &type, &arraytype) || type != DT_FLOAT)
1150 error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
1151 return;
1153 if ((filedesc = open_via_path(
1154 canvas_getdir(glist_getcanvas(x->x_glist))->s_name,
1155 filename->s_name, "", buf, &bufptr, MAXPDSTRING, 0)) < 0
1156 #ifdef ROCKBOX
1158 #else
1159 || !(fd = fdopen(filedesc, "r")))
1160 #endif
1162 error("%s: can't open", filename->s_name);
1163 return;
1165 for (i = 0; i < nelem; i++)
1167 #ifdef ROCKBOX
1168 if(rb_fscanf_f(fd, (float*)((x->x_vec + sizeof(t_word) * i) + yonset)))
1169 #else
1170 if (!fscanf(fd, "%f", (float *)((x->x_vec + sizeof(t_word) * i) +
1171 yonset)))
1172 #endif
1174 post("%s: read %d elements into table of size %d",
1175 filename->s_name, i, nelem);
1176 break;
1179 while (i < nelem)
1180 *(float *)((x->x_vec + sizeof(t_word) * i) + yonset) = 0, i++;
1181 #ifdef ROCKBOX
1182 close(fd);
1183 #else
1184 fclose(fd);
1185 #endif
1186 garray_redraw(x);
1189 /* this should be renamed and moved... */
1190 int garray_ambigendian(void)
1192 unsigned short s = 1;
1193 unsigned char c = *(char *)(&s);
1194 return (c==0);
1197 #define BINREADMODE "rb"
1198 #define BINWRITEMODE "wb"
1200 static void garray_read16(t_garray *x, t_symbol *filename,
1201 t_symbol *endian, t_floatarg fskip)
1203 int skip = fskip, filedesc;
1204 int i, nelem;
1205 t_sample *vec;
1206 #ifdef ROCKBOX
1207 int fd = 0;
1208 #else
1209 FILE *fd;
1210 #endif
1211 char buf[MAXPDSTRING], *bufptr;
1212 short s;
1213 int cpubig = garray_ambigendian(), swap = 0;
1214 char c = endian->s_name[0];
1215 if (c == 'b')
1217 if (!cpubig) swap = 1;
1219 else if (c == 'l')
1221 if (cpubig) swap = 1;
1223 else if (c)
1225 error("array_read16: endianness is 'l' (low byte first ala INTEL)");
1226 post("... or 'b' (high byte first ala MIPS,DEC,PPC)");
1228 if (!garray_getfloatarray(x, &nelem, &vec))
1230 error("%s: not a float array", x->x_templatesym->s_name);
1231 return;
1233 if ((filedesc = open_via_path(
1234 canvas_getdir(glist_getcanvas(x->x_glist))->s_name,
1235 filename->s_name, "", buf, &bufptr, MAXPDSTRING, 1)) < 0
1236 #ifdef ROCKBOX
1238 #else
1239 || !(fd = fdopen(filedesc, BINREADMODE)))
1240 #endif
1242 error("%s: can't open", filename->s_name);
1243 return;
1245 if (skip)
1247 #ifdef ROCKBOX
1248 long pos = lseek(fd, (long)skip, SEEK_SET);
1249 #else
1250 long pos = fseek(fd, (long)skip, SEEK_SET);
1251 #endif
1252 if (pos < 0)
1254 error("%s: can't seek to byte %d", buf, skip);
1255 #ifdef ROCKBOX
1256 close(fd);
1257 #else
1258 fclose(fd);
1259 #endif
1260 return;
1264 for (i = 0; i < nelem; i++)
1266 #ifdef ROCKBOX
1267 if(read(fd, &s, sizeof(s)) < 1)
1268 #else
1269 if (fread(&s, sizeof(s), 1, fd) < 1)
1270 #endif
1272 post("%s: read %d elements into table of size %d",
1273 filename->s_name, i, nelem);
1274 break;
1276 if (swap) s = ((s & 0xff) << 8) | ((s & 0xff00) >> 8);
1277 vec[i] = s * (1./32768.);
1279 while (i < nelem) vec[i++] = 0;
1280 #ifdef ROCKBOX
1281 close(fd);
1282 #else
1283 fclose(fd);
1284 #endif
1285 garray_redraw(x);
1288 static void garray_write(t_garray *x, t_symbol *filename)
1290 #ifdef ROCKBOX
1291 int fd;
1292 #else
1293 FILE *fd;
1294 #endif
1295 char buf[MAXPDSTRING];
1296 t_template *template = garray_template(x);
1297 int yonset, type, i;
1298 t_symbol *arraytype;
1299 if (!template_find_field(template, gensym("y"), &yonset,
1300 &type, &arraytype) || type != DT_FLOAT)
1302 error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
1303 return;
1305 canvas_makefilename(glist_getcanvas(x->x_glist), filename->s_name,
1306 buf, MAXPDSTRING);
1307 sys_bashfilename(buf, buf);
1308 #ifdef ROCKBOX
1309 if(!(fd = open(buf, O_WRONLY|O_CREAT|O_TRUNC, 0666)))
1310 #else
1311 if (!(fd = fopen(buf, "w")))
1312 #endif
1314 error("%s: can't create", buf);
1315 return;
1317 for (i = 0; i < x->x_n; i++)
1319 #ifdef ROCKBOX
1320 if(rb_fprintf_f(fd,
1321 #else /* ROCKBOX */
1322 if (fprintf(fd, "%g\n",
1323 #endif /* ROCKBOX */
1324 *(float *)((x->x_vec + sizeof(t_word) * i) + yonset)) < 1)
1326 post("%s: write error", filename->s_name);
1327 break;
1330 #ifdef ROCKBOX
1331 close(fd);
1332 #else
1333 fclose(fd);
1334 #endif
1337 static unsigned char waveheader[] = {
1338 0x52, 0x49, 0x46, 0x46,
1339 0x00, 0x00, 0x00, 0x00,
1340 0x57, 0x41, 0x56, 0x45,
1341 0x66, 0x6d, 0x74, 0x20,
1343 0x10, 0x00, 0x00, 0x00,
1344 0x01, 0x00, 0x01, 0x00,
1345 0x44, 0xac, 0x00, 0x00,
1346 0x88, 0x58, 0x01, 0x00,
1348 0x02, 0x00, 0x10, 0x00,
1349 0x64, 0x61, 0x74, 0x61,
1350 0x00, 0x00, 0x00, 0x00,
1353 /* wave format only so far */
1354 static void garray_write16(t_garray *x, t_symbol *filename, t_symbol *format)
1356 t_template *template = garray_template(x);
1357 int yonset, type, i;
1358 t_symbol *arraytype;
1359 #ifdef ROCKBOX
1360 int fd;
1361 #else
1362 FILE *fd;
1363 #endif
1364 int aiff = (format == gensym("aiff"));
1365 char filenamebuf[MAXPDSTRING], buf2[MAXPDSTRING];
1366 int swap = garray_ambigendian(); /* wave is only little endian */
1367 int intbuf;
1368 strncpy(filenamebuf, filename->s_name, MAXPDSTRING-10);
1369 filenamebuf[MAXPDSTRING-10] = 0;
1370 if (sizeof(int) != 4) post("write16: only works on 32-bit machines");
1371 if (aiff)
1373 if (strcmp(filenamebuf + strlen(filenamebuf)-5, ".aiff"))
1374 strcat(filenamebuf, ".aiff");
1376 else
1378 if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".wav"))
1379 strcat(filenamebuf, ".wav");
1381 if (!template_find_field(template, gensym("y"), &yonset,
1382 &type, &arraytype) || type != DT_FLOAT)
1384 error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
1385 return;
1387 canvas_makefilename(glist_getcanvas(x->x_glist), filenamebuf,
1388 buf2, MAXPDSTRING);
1389 sys_bashfilename(buf2, buf2);
1390 #ifdef ROCKBOX
1391 if(!(fd = open(buf2, O_WRONLY|O_CREAT|O_TRUNC, 0666)))
1392 #else
1393 if (!(fd = fopen(buf2, BINWRITEMODE)))
1394 #endif
1396 error("%s: can't create", buf2);
1397 return;
1399 intbuf = 2 * x->x_n + 36;
1400 if (swap)
1402 unsigned char *foo = (unsigned char *)&intbuf, xxx;
1403 xxx = foo[0]; foo[0] = foo[3]; foo[3] = xxx;
1404 xxx = foo[1]; foo[1] = foo[2]; foo[2] = xxx;
1406 memcpy((void *)(waveheader + 4), (void *)(&intbuf), 4);
1407 intbuf = 2 * x->x_n;
1408 if (swap)
1410 unsigned char *foo = (unsigned char *)&intbuf, xxx;
1411 xxx = foo[0]; foo[0] = foo[3]; foo[3] = xxx;
1412 xxx = foo[1]; foo[1] = foo[2]; foo[2] = xxx;
1414 memcpy((void *)(waveheader + 40), (void *)(&intbuf), 4);
1415 #ifdef ROCKBOX
1416 if(write(fd, waveheader, sizeof(waveheader)) < 1)
1417 #else
1418 if (fwrite(waveheader, sizeof(waveheader), 1, fd) < 1)
1419 #endif
1421 post("%s: write error", buf2);
1422 goto closeit;
1424 for (i = 0; i < x->x_n; i++)
1426 float f = 32767. * *(float *)((x->x_vec + sizeof(t_word) * i) + yonset);
1427 short sh;
1428 if (f < -32768) f = -32768;
1429 else if (f > 32767) f = 32767;
1430 sh = f;
1431 if (swap)
1433 unsigned char *foo = (unsigned char *)&sh, xxx;
1434 xxx = foo[0]; foo[0] = foo[1]; foo[1] = xxx;
1436 #ifdef ROCKBOX
1437 if(write(fd, &sh, sizeof(sh)) < 1)
1438 #else
1439 if (fwrite(&sh, sizeof(sh), 1, fd) < 1)
1440 #endif
1442 post("%s: write error", buf2);
1443 goto closeit;
1446 closeit:
1447 #ifdef ROCKBOX
1448 close(fd);
1449 #else
1450 fclose(fd);
1451 #endif
1454 void garray_resize(t_garray *x, t_floatarg f)
1456 int was = x->x_n, elemsize;
1457 t_glist *gl;
1458 #ifndef ROCKBOX
1459 int dspwas;
1460 #endif
1461 int n = f;
1462 char *nvec;
1464 if (n < 1) n = 1;
1465 elemsize = template_findbyname(x->x_templatesym)->t_n * sizeof(t_word);
1466 nvec = t_resizebytes(x->x_vec, was * elemsize, n * elemsize);
1467 if (!nvec)
1469 pd_error(x, "array resize failed: out of memory");
1470 return;
1472 x->x_vec = nvec;
1473 /* LATER should check t_resizebytes result */
1474 if (n > was)
1475 memset(x->x_vec + was*elemsize,
1476 0, (n - was) * elemsize);
1477 x->x_n = n;
1479 /* if this is the only array in the graph,
1480 reset the graph's coordinates */
1481 gl = x->x_glist;
1482 if (gl->gl_list == &x->x_gobj && !x->x_gobj.g_next)
1484 vmess(&gl->gl_pd, gensym("bounds"), "ffff",
1485 0., gl->gl_y1, (double)(n > 1 ? n-1 : 1), gl->gl_y2);
1486 /* close any dialogs that might have the wrong info now... */
1487 #ifndef ROCKBOX
1488 gfxstub_deleteforkey(gl);
1489 #endif
1491 else garray_redraw(x);
1492 if (x->x_usedindsp) canvas_update_dsp();
1495 static void garray_print(t_garray *x)
1497 post("garray %s: template %s, length %d",
1498 x->x_name->s_name, x->x_templatesym->s_name, x->x_n);
1501 void g_array_setup(void)
1503 garray_class = class_new(gensym("array"), 0, (t_method)garray_free,
1504 sizeof(t_garray), CLASS_GOBJ, 0);
1505 class_setwidget(garray_class, &garray_widgetbehavior);
1506 class_addmethod(garray_class, (t_method)garray_const, gensym("const"),
1507 A_DEFFLOAT, A_NULL);
1508 class_addlist(garray_class, garray_list);
1509 class_addmethod(garray_class, (t_method)garray_bounds, gensym("bounds"),
1510 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
1511 class_addmethod(garray_class, (t_method)garray_xticks, gensym("xticks"),
1512 A_FLOAT, A_FLOAT, A_FLOAT, 0);
1513 class_addmethod(garray_class, (t_method)garray_xlabel, gensym("xlabel"),
1514 A_GIMME, 0);
1515 class_addmethod(garray_class, (t_method)garray_yticks, gensym("yticks"),
1516 A_FLOAT, A_FLOAT, A_FLOAT, 0);
1517 class_addmethod(garray_class, (t_method)garray_ylabel, gensym("ylabel"),
1518 A_GIMME, 0);
1519 class_addmethod(garray_class, (t_method)garray_rename, gensym("rename"),
1520 A_SYMBOL, 0);
1521 class_addmethod(garray_class, (t_method)garray_read, gensym("read"),
1522 A_SYMBOL, A_NULL);
1523 class_addmethod(garray_class, (t_method)garray_read16, gensym("read16"),
1524 A_SYMBOL, A_DEFFLOAT, A_DEFSYM, A_NULL);
1525 class_addmethod(garray_class, (t_method)garray_write, gensym("write"),
1526 A_SYMBOL, A_NULL);
1527 class_addmethod(garray_class, (t_method)garray_write16, gensym("write16"),
1528 A_SYMBOL, A_DEFSYM, A_NULL);
1529 class_addmethod(garray_class, (t_method)garray_resize, gensym("resize"),
1530 A_FLOAT, A_NULL);
1531 class_addmethod(garray_class, (t_method)garray_print, gensym("print"),
1532 A_NULL);
1533 class_addmethod(garray_class, (t_method)garray_sinesum, gensym("sinesum"),
1534 A_GIMME, 0);
1535 class_addmethod(garray_class, (t_method)garray_cosinesum,
1536 gensym("cosinesum"), A_GIMME, 0);
1537 class_addmethod(garray_class, (t_method)garray_normalize,
1538 gensym("normalize"), A_DEFFLOAT, 0);
1539 class_addmethod(garray_class, (t_method)garray_arraydialog,
1540 gensym("arraydialog"), A_SYMBOL, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
1541 class_setsavefn(garray_class, garray_save);