A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
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. */
4
5#ifdef ROCKBOX
6#include "plugin.h"
7#include "../../pdbox.h"
8#include "m_pd.h"
9#include "g_canvas.h"
10#ifdef SIMULATOR
11int 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 */
21
22/* see also the "plot" object in g_scalar.c which deals with graphing
23arrays which are fields in scalars. Someday we should unify the
24two, but how? */
25
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!) */
29
30static t_symbol *sharptodollar(t_symbol *s)
31{
32 if (*s->s_name == '#')
33 {
34 char buf[MAXPDSTRING];
35 strncpy(buf, s->s_name, MAXPDSTRING);
36 buf[MAXPDSTRING-1] = 0;
37 buf[0] = '$';
38 return (gensym(buf));
39 }
40 else return (s);
41}
42
43/* --------- "pure" arrays with scalars for elements. --------------- */
44
45/* Pure arrays have no a priori graphical capabilities.
46They are instantiated by "garrays" below or can be elements of other
47scalars (g_scalar.c); their graphical behavior is defined accordingly. */
48
49t_array *array_new(t_symbol *templatesym, t_gpointer *parent)
50{
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);
69}
70
71void array_resize(t_array *x, t_template *template, int n)
72{
73 int elemsize, oldn;
74#ifndef ROCKBOX
75 t_gpointer *gp;
76#endif
77
78 if (n < 1)
79 n = 1;
80 oldn = x->a_n;
81 elemsize = sizeof(t_word) * template->t_n;
82
83 x->a_vec = (char *)resizebytes(x->a_vec, oldn * elemsize,
84 n * elemsize);
85 x->a_n = n;
86 if (n > oldn)
87 {
88 char *cp = x->a_vec + elemsize * oldn;
89 int i = n - oldn;
90 for (; i--; cp += elemsize)
91 {
92 t_word *wp = (t_word *)cp;
93 word_init(wp, template, &x->a_gp);
94 }
95 }
96}
97
98void word_free(t_word *wp, t_template *template);
99
100void array_free(t_array *x)
101{
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++)
108 {
109 t_word *wp = (t_word *)(x->a_vec + x->a_elemsize * i);
110 word_free(wp, scalartemplate);
111 }
112 freebytes(x->a_vec, x->a_elemsize * x->a_n);
113 freebytes(x, sizeof *x);
114}
115
116/* --------------------- graphical arrays (garrays) ------------------- */
117
118t_class *garray_class;
119static int gcount = 0;
120
121struct _garray
122{
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 */
132};
133
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
139
140t_garray *graph_array(t_glist *gl, t_symbol *s, t_symbol *templatesym,
141 t_floatarg f, t_floatarg saveit)
142{
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_)
150 {
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;
160 }
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)
165 {
166 error("array: couldn't find template %s", templatesym->s_name);
167 return (0);
168 }
169 nwords = template->t_n;
170 for (i = 0; i < nwords; i++)
171 {
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)
176 {
177 error("array: template %s can't have sublists or arrays",
178 templatesym->s_name);
179 return (0);
180 }
181 }
182 x = (t_garray *)pd_new(garray_class);
183
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"));
202
203 pd_bind(&x->x_gobj.g_pd, gensym("#A"));
204
205 return (x);
206}
207
208 /* called from array menu item to create a new one */
209void canvas_menuarray(t_glist *canvas)
210{
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 */
220}
221
222 /* called from graph_dialog to set properties */
223void garray_properties(t_garray *x)
224{
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 */
240}
241
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. */
244void glist_arraydialog(t_glist *parent, t_symbol *name, t_floatarg size,
245 t_floatarg saveit, t_floatarg otherflag)
246{
247 t_glist *gl;
248 /* t_garray *a; unused */
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);
255}
256
257 /* this is called from the properties dialog window for an existing array */
258void garray_arraydialog(t_garray *x, t_symbol *name, t_floatarg fsize,
259 t_floatarg saveit, t_floatarg deleteit)
260{
261 if (deleteit != 0)
262 {
263 glist_delete(x->x_glist, &x->x_gobj);
264 }
265 else
266 {
267 int size;
268 t_symbol *argname = sharptodollar(name);
269 if (argname != x->x_name)
270 {
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);
275 }
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);
283 }
284}
285
286static void garray_free(t_garray *x)
287{
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);
297}
298
299/* ------------- code used by both array and plot widget functions ---- */
300
301 /* routine to get screen coordinates of a point in an array */
302void 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)
306{
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)
316 {
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;
322 }
323 else wpix = 1;
324 *xp = glist_xtopixels(glist, basex + xval);
325 *yp = ypix;
326 *wp = wpix;
327}
328
329static float array_motion_xcumulative;
330static float array_motion_ycumulative;
331static t_symbol *array_motion_xfield;
332static t_symbol *array_motion_yfield;
333static t_glist *array_motion_glist;
334static t_gobj *array_motion_gobj;
335static t_word *array_motion_wp;
336static t_template *array_motion_template;
337static int array_motion_npoints;
338static int array_motion_elemsize;
339#ifndef ROCKBOX
340static int array_motion_altkey;
341#endif
342static float array_motion_initx;
343static float array_motion_xperpix;
344static float array_motion_yperpix;
345static int array_motion_lastx;
346static int array_motion_fatten;
347
348 /* LATER protect against the template changing or the scalar disappearing
349 probably by attaching a gpointer here ... */
350
351static void array_motion(void *z, t_floatarg dx, t_floatarg dy)
352{
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)
359 {
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++)
364 {
365 t_word *thisword = (t_word *)(charword + i * array_motion_elemsize);
366 if (*array_motion_xfield->s_name)
367 {
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);
372 }
373 if (*array_motion_yfield->s_name)
374 {
375 float ywas = template_getfloat(array_motion_template,
376 array_motion_yfield, thisword, 1);
377 if (array_motion_fatten)
378 {
379 if (i == 0)
380 {
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);
386 }
387 }
388 else
389 {
390 template_setfloat(array_motion_template,
391 array_motion_yfield, thisword,
392 ywas + dy * array_motion_yperpix, 1);
393 }
394 }
395 }
396 }
397 else
398 {
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);
414
415 for (i = 0, x2 = thisx; i < nchange; i++, x2 += increment)
416 {
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));
423 }
424 array_motion_lastx = thisx;
425 }
426 glist_redrawitem(array_motion_glist, array_motion_gobj);
427}
428
429int 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)
433{
434 t_canvas *elemtemplatecanvas;
435 t_template *elemtemplate;
436 int elemsize, yonset, wonset, xonset, i;
437
438#ifdef ROCKBOX
439 (void) linewidth;
440 (void) shift;
441 (void) dbl;
442#endif
443
444 if (!array_getfields(elemtemplatesym, &elemtemplatecanvas,
445 &elemtemplate, &elemsize, &xonset, &yonset, &wonset))
446 {
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)
454 {
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)
470 {
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;
479 }
480 }
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)
485 {
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)
497 {
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;
504 }
505 else dy2 = dy3 = 100;
506 if (dx + dy <= best || dx + dy2 <= best || dx + dy3 <= best)
507 {
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)
514 {
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 */
523 {
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);
532 }
533 else if (alt)
534 {
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++;
542 }
543 if (xonset >= 0)
544 {
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;
550 }
551 else
552 {
553 array_motion_xfield = &s_;
554 array_motion_xcumulative = 0;
555 array_motion_wp = (t_word *)elem;
556 array_motion_npoints = array->a_n;
557
558 array_motion_initx = i;
559 array_motion_lastx = i;
560 array_motion_xperpix *= (xinc == 0 ? 1 : 1./xinc);
561 }
562 if (array_motion_fatten)
563 {
564 array_motion_yfield = gensym("w");
565 array_motion_ycumulative =
566 *(float *)((elem + elemsize * i) + wonset);
567 array_motion_yperpix *= array_motion_fatten;
568 }
569 else if (yonset >= 0)
570 {
571 array_motion_yfield = gensym("y");
572 array_motion_ycumulative =
573 *(float *)((elem + elemsize * i) + yonset);
574 }
575 else
576 {
577 array_motion_yfield = &s_;
578 array_motion_ycumulative = 0;
579 }
580 glist_grab(glist, 0, array_motion, 0, xpix, ypix);
581 }
582 if (alt)
583 {
584 if (xpix < pxpix)
585 return (CURSOR_EDITMODE_DISCONNECT);
586 else return (CURSOR_RUNMODE_ADDPOINT);
587 }
588 else return (array_motion_fatten ?
589 CURSOR_RUNMODE_THICKEN : CURSOR_RUNMODE_CLICKME);
590 }
591 }
592 }
593 return (0);
594}
595
596/* -------------------- widget behavior for garray ------------ */
597
598static void garray_getrect(t_gobj *z, t_glist *glist,
599 int *xp1, int *yp1, int *xp2, int *yp2)
600{
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;
606
607 if (!array_getfields(x->x_templatesym, &elemtemplatecanvas,
608 &elemtemplate, &elemsize, &xonset, &yonset, &wonset))
609 {
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)
616 {
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;
636 }
637 }
638 *xp1 = x1;
639 *yp1 = y1;
640 *xp2 = x2;
641 *yp2 = y2;
642}
643
644static void garray_displace(t_gobj *z, t_glist *glist, int dx, int dy)
645{
646#ifdef ROCKBOX
647 (void) z;
648 (void) glist;
649 (void) dx;
650 (void) dy;
651#endif
652 /* refuse */
653}
654
655static void garray_select(t_gobj *z, t_glist *glist, int state)
656{
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 */
665}
666
667static void garray_activate(t_gobj *z, t_glist *glist, int state)
668{
669#ifdef ROCKBOX
670 (void) z;
671 (void) glist;
672 (void) state;
673#endif
674}
675
676static void garray_delete(t_gobj *z, t_glist *glist)
677{
678#ifdef ROCKBOX
679 (void) z;
680 (void) glist;
681#endif
682 /* nothing to do */
683}
684
685static void garray_vis(t_gobj *z, t_glist *glist, int vis)
686{
687 t_garray *x = (t_garray *)z;
688 if (vis)
689 {
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)
697 {
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
705 }
706 else if (!template_find_field(template, gensym("x"), &xonset, &type,
707 &arraytype) || type != DT_FLOAT)
708 {
709 float xcum = x->x_firstx;
710 int lastpixel = -1, ndrawn = 0;
711 float xpix;
712#ifndef ROCKBOX
713 float firsty, yval = 0;
714#endif
715 int ixpix = 0;
716#ifndef ROCKBOX
717 sys_vgui(".x%x.c create line \\\n", glist_getcanvas(glist));
718#endif
719 for (i = 0; i < x->x_n; i++)
720 {
721#ifndef ROCKBOX
722 yval = fixtof(*(t_sample *)(x->x_vec +
723 template->t_n * i * sizeof (t_word) + yonset));
724#endif
725 xpix = glist_xtopixels(glist, xcum);
726 ixpix = xpix + 0.5;
727 if (ixpix != lastpixel)
728 {
729#ifndef ROCKBOX
730 sys_vgui("%d %f \\\n", ixpix,
731 glist_ytopixels(glist, yval));
732#endif
733 ndrawn++;
734 }
735 lastpixel = ixpix;
736 if (ndrawn >= 1000) break;
737 xcum += x->x_xinc;
738 }
739 /* TK will complain if there aren't at least 2 points... */
740#ifndef ROCKBOX
741 if (ndrawn == 0) sys_vgui("0 0 0 0 \\\n");
742 else if (ndrawn == 1) sys_vgui("%d %f \\\n", ixpix,
743 glist_ytopixels(glist, yval));
744 sys_vgui("-tags .x%x.a%x\n", glist_getcanvas(glist), x);
745 firsty = fixtof(*(t_sample *)(x->x_vec + yonset));
746 sys_vgui(".x%x.c create text %f %f -text {%s} -anchor e\
747 -font -*-courier-bold--normal--%d-* -tags .x%x.a%x\n",
748 glist_getcanvas(glist),
749 glist_xtopixels(glist, x->x_firstx) - 5.,
750 glist_ytopixels(glist, firsty),
751 x->x_name->s_name, glist_getfont(glist),
752 glist_getcanvas(glist), x);
753#endif
754 }
755 else
756 {
757 post("x, y arrays not yet supported");
758 }
759 }
760 else
761 {
762#ifndef ROCKBOX
763 sys_vgui(".x%x.c delete .x%x.a%x\n",
764 glist_getcanvas(glist), glist_getcanvas(glist), x);
765#endif
766 }
767}
768
769static int garray_click(t_gobj *z, struct _glist *glist,
770 int xpix, int ypix, int shift, int alt, int dbl, int doit)
771{
772 t_garray *x = (t_garray *)z;
773 return (array_doclick(&x->x_array, glist, z, x->x_templatesym, 1, 0, 1, 0,
774 xpix, ypix, shift, alt, dbl, doit));
775}
776
777#define ARRAYWRITECHUNKSIZE 1000
778
779static void garray_save(t_gobj *z, t_binbuf *b)
780{
781 t_garray *x = (t_garray *)z;
782 binbuf_addv(b, "sssisi;", gensym("#X"), gensym("array"),
783 x->x_name, x->x_n, x->x_templatesym, x->x_saveit);
784#ifdef ROCKBOX
785#ifdef SIMULATOR
786 printf("array save\n");
787#endif /* SIMULATOR */
788#else /* ROCKBOX */
789 fprintf(stderr,"array save\n");
790#endif /* ROCKBOX */
791 if (x->x_saveit)
792 {
793 int n = x->x_n, n2 = 0;
794 if (x->x_templatesym != &s_float)
795 {
796 pd_error(x, "sorry, you can only save 'float' arrays now");
797 return;
798 }
799 if (n > 200000)
800 post("warning: I'm saving an array with %d points!\n", n);
801 while (n2 < n)
802 {
803 int chunk = n - n2, i;
804 if (chunk > ARRAYWRITECHUNKSIZE)
805 chunk = ARRAYWRITECHUNKSIZE;
806 binbuf_addv(b, "si", gensym("#A"), n2);
807 for (i = 0; i < chunk; i++)
808 binbuf_addv(b, "f", fixtof(((t_sample *)(x->x_vec))[n2+i]));
809 binbuf_addv(b, ";");
810 n2 += chunk;
811 }
812 }
813}
814
815t_widgetbehavior garray_widgetbehavior =
816{
817 garray_getrect,
818 garray_displace,
819 garray_select,
820 garray_activate,
821 garray_delete,
822 garray_vis,
823 garray_click
824};
825
826/* ----------------------- public functions -------------------- */
827
828void garray_usedindsp(t_garray *x)
829{
830 x->x_usedindsp = 1;
831}
832
833void garray_redraw(t_garray *x)
834{
835 if (glist_isvisible(x->x_glist))
836 {
837 garray_vis(&x->x_gobj, x->x_glist, 0);
838 garray_vis(&x->x_gobj, x->x_glist, 1);
839 }
840}
841
842 /* This functiopn gets the template of an array; if we can't figure
843 out what template an array's elements belong to we're in grave trouble
844 when it's time to free or resize it. */
845t_template *garray_template(t_garray *x)
846{
847 t_template *template = template_findbyname(x->x_templatesym);
848 if (!template)
849 bug("garray_template");
850 return (template);
851}
852
853int garray_npoints(t_garray *x) /* get the length */
854{
855 return (x->x_n);
856}
857
858char *garray_vec(t_garray *x) /* get the contents */
859{
860 return ((char *)(x->x_vec));
861}
862
863 /* routine that checks if we're just an array of floats and if
864 so returns the goods */
865
866int garray_getfloatarray(t_garray *x, int *size, t_sample **vec)
867{
868 t_template *template = garray_template(x);
869 int yonset, type;
870 t_symbol *arraytype;
871 if (!template_find_field(template, gensym("y"), &yonset,
872 &type, &arraytype) || type != DT_FLOAT)
873 error("%s: needs floating-point 'y' field",
874 x->x_templatesym->s_name);
875 else if (template->t_n != 1)
876 error("%s: has more than one field", x->x_templatesym->s_name);
877 else
878 {
879 *size = garray_npoints(x);
880 *vec = (t_sample *)garray_vec(x);
881 return (1);
882 }
883 return (0);
884}
885
886 /* get any floating-point field of any element of an array */
887float garray_get(t_garray *x, t_symbol *s, t_int indx)
888{
889 t_template *template = garray_template(x);
890 int yonset, type;
891 t_symbol *arraytype;
892 if (!template_find_field(template, gensym("y"), &yonset,
893 &type, &arraytype) || type != DT_FLOAT)
894 {
895 error("%s: needs floating-point '%s' field", x->x_templatesym->s_name,
896 s->s_name);
897 return (0);
898 }
899 if (indx < 0) indx = 0;
900 else if (indx >= x->x_n) indx = x->x_n - 1;
901 return (*(float *)((x->x_vec + sizeof(t_word) * indx) + yonset));
902}
903
904 /* set the "saveit" flag */
905void garray_setsaveit(t_garray *x, int saveit)
906{
907 if (x->x_saveit && !saveit)
908 post("warning: array %s: clearing save-in-patch flag",
909 x->x_name->s_name);
910 x->x_saveit = saveit;
911}
912
913/*------------------- Pd messages ------------------------ */
914static void garray_const(t_garray *x, t_floatarg g)
915{
916 t_template *template = garray_template(x);
917 int yonset, type, i;
918 t_symbol *arraytype;
919 if (!template_find_field(template, gensym("y"), &yonset,
920 &type, &arraytype) || type != DT_FLOAT)
921 error("%s: needs floating-point 'y' field",
922 x->x_templatesym->s_name);
923 else for (i = 0; i < x->x_n; i++)
924 *(float *)(((char *)x->x_vec + sizeof(t_word) * i) + yonset) = g;
925 garray_redraw(x);
926}
927
928 /* sum of Fourier components; called from routines below */
929static void garray_dofo(t_garray *x, int npoints, float dcval,
930 int nsin, t_float *vsin, int sineflag)
931{
932 t_template *template = garray_template(x);
933 int yonset, type, i, j;
934 t_symbol *arraytype;
935 double phase, phaseincr, fj;
936 if (npoints == 0)
937 npoints = 512; /* dunno what a good default would be... */
938 if (npoints != (1 << ilog2(npoints)))
939 post("%s: rounnding to %d points", x->x_templatesym->s_name,
940 (npoints = (1<<ilog2(npoints))));
941 garray_resize(x, npoints + 3);
942 phaseincr = 2. * 3.14159 / npoints;
943 if (!template_find_field(template, gensym("y"), &yonset,
944 &type, &arraytype) || type != DT_FLOAT)
945 {
946 error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
947 return;
948 }
949 for (i = 0, phase = -phaseincr; i < x->x_n; i++, phase += phaseincr )
950 {
951 double sum = dcval;
952 if (sineflag)
953 for (j = 0, fj = phase; j < nsin; j++, fj += phase)
954 sum += vsin[j] * sin(fj);
955 else
956 for (j = 0, fj = 0; j < nsin; j++, fj += phase)
957 sum += vsin[j] * cos(fj);
958 *(float *)((x->x_vec + sizeof(t_word) * i) + yonset) = sum;
959 }
960 garray_redraw(x);
961}
962
963static void garray_sinesum(t_garray *x, t_symbol *s, int argc, t_atom *argv)
964{
965#ifdef ROCKBOX
966 (void) s;
967#else
968 t_template *template = garray_template(x);
969#endif
970
971 t_float *svec = (t_float *)t_getbytes(sizeof(t_float) * argc);
972 int npoints, i;
973 if (argc < 2)
974 {
975 error("sinesum: %s: need number of points and partial strengths",
976 x->x_templatesym->s_name);
977 return;
978 }
979
980 npoints = atom_getfloatarg(0, argc, argv);
981 argv++, argc--;
982
983 svec = (t_float *)t_getbytes(sizeof(t_float) * argc);
984 if (!svec) return;
985
986 for (i = 0; i < argc; i++)
987 svec[i] = atom_getfloatarg(i, argc, argv);
988 garray_dofo(x, npoints, 0, argc, svec, 1);
989 t_freebytes(svec, sizeof(t_float) * argc);
990}
991
992static void garray_cosinesum(t_garray *x, t_symbol *s, int argc, t_atom *argv)
993{
994#ifdef ROCKBOX
995 (void) s;
996#else
997 t_template *template = garray_template(x);
998#endif
999
1000 t_float *svec = (t_float *)t_getbytes(sizeof(t_float) * argc);
1001 int npoints, i;
1002 if (argc < 2)
1003 {
1004 error("sinesum: %s: need number of points and partial strengths",
1005 x->x_templatesym->s_name);
1006 return;
1007 }
1008
1009 npoints = atom_getfloatarg(0, argc, argv);
1010 argv++, argc--;
1011
1012 svec = (t_float *)t_getbytes(sizeof(t_float) * argc);
1013 if (!svec) return;
1014
1015 for (i = 0; i < argc; i++)
1016 svec[i] = atom_getfloatarg(i, argc, argv);
1017 garray_dofo(x, npoints, 0, argc, svec, 0);
1018 t_freebytes(svec, sizeof(t_float) * argc);
1019}
1020
1021static void garray_normalize(t_garray *x, t_float f)
1022{
1023 t_template *template = garray_template(x);
1024#ifdef ROCKBOX
1025 int yonset, type, i;
1026#else
1027 int yonset, type, npoints, i;
1028#endif
1029 double maxv, renormer;
1030 t_symbol *arraytype;
1031
1032 if (f <= 0)
1033 f = 1;
1034
1035 if (!template_find_field(template, gensym("y"), &yonset,
1036 &type, &arraytype) || type != DT_FLOAT)
1037 {
1038 error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
1039 return;
1040 }
1041 for (i = 0, maxv = 0; i < x->x_n; i++)
1042 {
1043 double v = *(float *)((x->x_vec + sizeof(t_word) * i) + yonset);
1044 if (v > maxv)
1045 maxv = v;
1046 if (-v > maxv)
1047 maxv = -v;
1048 }
1049 if (maxv >= 0)
1050 {
1051 renormer = f / maxv;
1052 for (i = 0; i < x->x_n; i++)
1053 {
1054 *(float *)((x->x_vec + sizeof(t_word) * i) + yonset)
1055 *= renormer;
1056 }
1057 }
1058 garray_redraw(x);
1059}
1060
1061 /* list -- the first value is an index; subsequent values are put in
1062 the "y" slot of the array. This generalizes Max's "table", sort of. */
1063static void garray_list(t_garray *x, t_symbol *s, int argc, t_atom *argv)
1064{
1065 t_template *template = garray_template(x);
1066 int yonset, type, i;
1067 t_symbol *arraytype;
1068#ifdef ROCKBOX
1069 (void) s;
1070#endif
1071 if (!template_find_field(template, gensym("y"), &yonset,
1072 &type, &arraytype) || type != DT_FLOAT)
1073 error("%s: needs floating-point 'y' field",
1074 x->x_templatesym->s_name);
1075 else if (argc < 2) return;
1076 else
1077 {
1078 int firstindex = atom_getfloat(argv);
1079 argc--;
1080 argv++;
1081 /* drop negative x values */
1082 if (firstindex < 0)
1083 {
1084 argc += firstindex;
1085 argv -= firstindex;
1086 firstindex = 0;
1087 if (argc <= 0) return;
1088 }
1089 if (argc + firstindex > x->x_n)
1090 {
1091 argc = x->x_n - firstindex;
1092 if (argc <= 0) return;
1093 }
1094 for (i = 0; i < argc; i++)
1095 *(t_sample *)((x->x_vec + sizeof(t_word) * (i + firstindex)) + yonset) =
1096 ftofix(atom_getfloat(argv + i));
1097 }
1098 garray_redraw(x);
1099}
1100
1101 /* forward a "bounds" message to the owning graph */
1102static void garray_bounds(t_garray *x, t_floatarg x1, t_floatarg y1,
1103 t_floatarg x2, t_floatarg y2)
1104{
1105 vmess(&x->x_glist->gl_pd, gensym("bounds"), "ffff", x1, y1, x2, y2);
1106}
1107
1108 /* same for "xticks", etc */
1109static void garray_xticks(t_garray *x,
1110 t_floatarg point, t_floatarg inc, t_floatarg f)
1111{
1112 vmess(&x->x_glist->gl_pd, gensym("xticks"), "fff", point, inc, f);
1113}
1114
1115static void garray_yticks(t_garray *x,
1116 t_floatarg point, t_floatarg inc, t_floatarg f)
1117{
1118 vmess(&x->x_glist->gl_pd, gensym("yticks"), "fff", point, inc, f);
1119}
1120
1121static void garray_xlabel(t_garray *x, t_symbol *s, int argc, t_atom *argv)
1122{
1123 typedmess(&x->x_glist->gl_pd, s, argc, argv);
1124}
1125
1126static void garray_ylabel(t_garray *x, t_symbol *s, int argc, t_atom *argv)
1127{
1128 typedmess(&x->x_glist->gl_pd, s, argc, argv);
1129}
1130 /* change the name of a garray. */
1131static void garray_rename(t_garray *x, t_symbol *s)
1132{
1133 pd_unbind(&x->x_gobj.g_pd, x->x_realname);
1134 pd_bind(&x->x_gobj.g_pd, x->x_realname = x->x_name = s);
1135 garray_redraw(x);
1136}
1137
1138static void garray_read(t_garray *x, t_symbol *filename)
1139{
1140 int nelem = x->x_n, filedesc;
1141#ifdef ROCKBOX
1142 int fd = 0;
1143#else
1144 FILE *fd;
1145#endif
1146 char buf[MAXPDSTRING], *bufptr;
1147 t_template *template = garray_template(x);
1148 int yonset, type, i;
1149 t_symbol *arraytype;
1150 if (!template_find_field(template, gensym("y"), &yonset,
1151 &type, &arraytype) || type != DT_FLOAT)
1152 {
1153 error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
1154 return;
1155 }
1156 if ((filedesc = open_via_path(
1157 canvas_getdir(glist_getcanvas(x->x_glist))->s_name,
1158 filename->s_name, "", buf, &bufptr, MAXPDSTRING, 0)) < 0
1159#ifdef ROCKBOX
1160 || !(fd = filedesc))
1161#else
1162 || !(fd = fdopen(filedesc, "r")))
1163#endif
1164 {
1165 error("%s: can't open", filename->s_name);
1166 return;
1167 }
1168 for (i = 0; i < nelem; i++)
1169 {
1170#ifdef ROCKBOX
1171 if(rb_fscanf_f(fd, (float*)((x->x_vec + sizeof(t_word) * i) + yonset)))
1172#else
1173 if (!fscanf(fd, "%f", (float *)((x->x_vec + sizeof(t_word) * i) +
1174 yonset)))
1175#endif
1176 {
1177 post("%s: read %d elements into table of size %d",
1178 filename->s_name, i, nelem);
1179 break;
1180 }
1181 }
1182 while (i < nelem)
1183 *(float *)((x->x_vec + sizeof(t_word) * i) + yonset) = 0, i++;
1184#ifdef ROCKBOX
1185 close(fd);
1186#else
1187 fclose(fd);
1188#endif
1189 garray_redraw(x);
1190}
1191
1192 /* this should be renamed and moved... */
1193int garray_ambigendian(void)
1194{
1195 unsigned short s = 1;
1196 unsigned char c = *(char *)(&s);
1197 return (c==0);
1198}
1199
1200#define BINREADMODE "rb"
1201#define BINWRITEMODE "wb"
1202
1203static void garray_read16(t_garray *x, t_symbol *filename,
1204 t_symbol *endian, t_floatarg fskip)
1205{
1206 int skip = fskip, filedesc;
1207 int i, nelem;
1208 t_sample *vec;
1209#ifdef ROCKBOX
1210 int fd = 0;
1211#else
1212 FILE *fd;
1213#endif
1214 char buf[MAXPDSTRING], *bufptr;
1215 short s;
1216 int cpubig = garray_ambigendian(), swap = 0;
1217 char c = endian->s_name[0];
1218 if (c == 'b')
1219 {
1220 if (!cpubig) swap = 1;
1221 }
1222 else if (c == 'l')
1223 {
1224 if (cpubig) swap = 1;
1225 }
1226 else if (c)
1227 {
1228 error("array_read16: endianness is 'l' (low byte first ala INTEL)");
1229 post("... or 'b' (high byte first ala MIPS,DEC,PPC)");
1230 }
1231 if (!garray_getfloatarray(x, &nelem, &vec))
1232 {
1233 error("%s: not a float array", x->x_templatesym->s_name);
1234 return;
1235 }
1236 if ((filedesc = open_via_path(
1237 canvas_getdir(glist_getcanvas(x->x_glist))->s_name,
1238 filename->s_name, "", buf, &bufptr, MAXPDSTRING, 1)) < 0
1239#ifdef ROCKBOX
1240 || !(fd = filedesc))
1241#else
1242 || !(fd = fdopen(filedesc, BINREADMODE)))
1243#endif
1244 {
1245 error("%s: can't open", filename->s_name);
1246 return;
1247 }
1248 if (skip)
1249 {
1250#ifdef ROCKBOX
1251 long pos = lseek(fd, (long)skip, SEEK_SET);
1252#else
1253 long pos = fseek(fd, (long)skip, SEEK_SET);
1254#endif
1255 if (pos < 0)
1256 {
1257 error("%s: can't seek to byte %d", buf, skip);
1258#ifdef ROCKBOX
1259 close(fd);
1260#else
1261 fclose(fd);
1262#endif
1263 return;
1264 }
1265 }
1266
1267 for (i = 0; i < nelem; i++)
1268 {
1269#ifdef ROCKBOX
1270 if(read(fd, &s, sizeof(s)) < (ssize_t) sizeof(s))
1271#else
1272 if (fread(&s, sizeof(s), 1, fd) < 1)
1273#endif
1274 {
1275 post("%s: read %d elements into table of size %d",
1276 filename->s_name, i, nelem);
1277 break;
1278 }
1279 if (swap) s = ((s & 0xff) << 8) | ((s & 0xff00) >> 8);
1280 vec[i] = s * (1./32768.);
1281 }
1282 while (i < nelem) vec[i++] = 0;
1283#ifdef ROCKBOX
1284 close(fd);
1285#else
1286 fclose(fd);
1287#endif
1288 garray_redraw(x);
1289}
1290
1291static void garray_write(t_garray *x, t_symbol *filename)
1292{
1293#ifdef ROCKBOX
1294 int fd;
1295#else
1296 FILE *fd;
1297#endif
1298 char buf[MAXPDSTRING];
1299 t_template *template = garray_template(x);
1300 int yonset, type, i;
1301 t_symbol *arraytype;
1302 if (!template_find_field(template, gensym("y"), &yonset,
1303 &type, &arraytype) || type != DT_FLOAT)
1304 {
1305 error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
1306 return;
1307 }
1308 canvas_makefilename(glist_getcanvas(x->x_glist), filename->s_name,
1309 buf, MAXPDSTRING);
1310 sys_bashfilename(buf, buf);
1311#ifdef ROCKBOX
1312 if(!(fd = open(buf, O_WRONLY|O_CREAT|O_TRUNC, 0666)))
1313#else
1314 if (!(fd = fopen(buf, "w")))
1315#endif
1316 {
1317 error("%s: can't create", buf);
1318 return;
1319 }
1320 for (i = 0; i < x->x_n; i++)
1321 {
1322#ifdef ROCKBOX
1323 if(rb_fprintf_f(fd,
1324#else /* ROCKBOX */
1325 if (fprintf(fd, "%g\n",
1326#endif /* ROCKBOX */
1327 *(float *)((x->x_vec + sizeof(t_word) * i) + yonset)) < 1)
1328 {
1329 post("%s: write error", filename->s_name);
1330 break;
1331 }
1332 }
1333#ifdef ROCKBOX
1334 close(fd);
1335#else
1336 fclose(fd);
1337#endif
1338}
1339
1340static unsigned char waveheader[] = {
13410x52, 0x49, 0x46, 0x46,
13420x00, 0x00, 0x00, 0x00,
13430x57, 0x41, 0x56, 0x45,
13440x66, 0x6d, 0x74, 0x20,
1345
13460x10, 0x00, 0x00, 0x00,
13470x01, 0x00, 0x01, 0x00,
13480x44, 0xac, 0x00, 0x00,
13490x88, 0x58, 0x01, 0x00,
1350
13510x02, 0x00, 0x10, 0x00,
13520x64, 0x61, 0x74, 0x61,
13530x00, 0x00, 0x00, 0x00,
1354};
1355
1356 /* wave format only so far */
1357static void garray_write16(t_garray *x, t_symbol *filename, t_symbol *format)
1358{
1359 t_template *template = garray_template(x);
1360 int yonset, type, i;
1361 t_symbol *arraytype;
1362#ifdef ROCKBOX
1363 int fd;
1364#else
1365 FILE *fd;
1366#endif
1367 int aiff = (format == gensym("aiff"));
1368 char filenamebuf[MAXPDSTRING], buf2[MAXPDSTRING];
1369 int swap = garray_ambigendian(); /* wave is only little endian */
1370 int intbuf;
1371 strncpy(filenamebuf, filename->s_name, MAXPDSTRING-10);
1372 filenamebuf[MAXPDSTRING-10] = 0;
1373 if (sizeof(int) != 4) post("write16: only works on 32-bit machines");
1374 if (aiff)
1375 {
1376 if (strcmp(filenamebuf + strlen(filenamebuf)-5, ".aiff"))
1377 strcat(filenamebuf, ".aiff");
1378 }
1379 else
1380 {
1381 if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".wav"))
1382 strcat(filenamebuf, ".wav");
1383 }
1384 if (!template_find_field(template, gensym("y"), &yonset,
1385 &type, &arraytype) || type != DT_FLOAT)
1386 {
1387 error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
1388 return;
1389 }
1390 canvas_makefilename(glist_getcanvas(x->x_glist), filenamebuf,
1391 buf2, MAXPDSTRING);
1392 sys_bashfilename(buf2, buf2);
1393#ifdef ROCKBOX
1394 if(!(fd = open(buf2, O_WRONLY|O_CREAT|O_TRUNC, 0666)))
1395#else
1396 if (!(fd = fopen(buf2, BINWRITEMODE)))
1397#endif
1398 {
1399 error("%s: can't create", buf2);
1400 return;
1401 }
1402 intbuf = 2 * x->x_n + 36;
1403 if (swap)
1404 {
1405 unsigned char *foo = (unsigned char *)&intbuf, xxx;
1406 xxx = foo[0]; foo[0] = foo[3]; foo[3] = xxx;
1407 xxx = foo[1]; foo[1] = foo[2]; foo[2] = xxx;
1408 }
1409 memcpy((void *)(waveheader + 4), (void *)(&intbuf), 4);
1410 intbuf = 2 * x->x_n;
1411 if (swap)
1412 {
1413 unsigned char *foo = (unsigned char *)&intbuf, xxx;
1414 xxx = foo[0]; foo[0] = foo[3]; foo[3] = xxx;
1415 xxx = foo[1]; foo[1] = foo[2]; foo[2] = xxx;
1416 }
1417 memcpy((void *)(waveheader + 40), (void *)(&intbuf), 4);
1418#ifdef ROCKBOX
1419 if(write(fd, waveheader, sizeof(waveheader)) < (ssize_t) sizeof(waveheader))
1420#else
1421 if (fwrite(waveheader, sizeof(waveheader), 1, fd) < 1)
1422#endif
1423 {
1424 post("%s: write error", buf2);
1425 goto closeit;
1426 }
1427 for (i = 0; i < x->x_n; i++)
1428 {
1429 float f = 32767. * *(float *)((x->x_vec + sizeof(t_word) * i) + yonset);
1430 short sh;
1431 if (f < -32768) f = -32768;
1432 else if (f > 32767) f = 32767;
1433 sh = f;
1434 if (swap)
1435 {
1436 unsigned char *foo = (unsigned char *)&sh, xxx;
1437 xxx = foo[0]; foo[0] = foo[1]; foo[1] = xxx;
1438 }
1439#ifdef ROCKBOX
1440 if(write(fd, &sh, sizeof(sh)) < (ssize_t) sizeof(sh))
1441#else
1442 if (fwrite(&sh, sizeof(sh), 1, fd) < 1)
1443#endif
1444 {
1445 post("%s: write error", buf2);
1446 goto closeit;
1447 }
1448 }
1449closeit:
1450#ifdef ROCKBOX
1451 close(fd);
1452#else
1453 fclose(fd);
1454#endif
1455}
1456
1457void garray_resize(t_garray *x, t_floatarg f)
1458{
1459 int was = x->x_n, elemsize;
1460 t_glist *gl;
1461#ifndef ROCKBOX
1462 int dspwas;
1463#endif
1464 int n = f;
1465 char *nvec;
1466
1467 if (n < 1) n = 1;
1468 elemsize = template_findbyname(x->x_templatesym)->t_n * sizeof(t_word);
1469 nvec = t_resizebytes(x->x_vec, was * elemsize, n * elemsize);
1470 if (!nvec)
1471 {
1472 pd_error(x, "array resize failed: out of memory");
1473 return;
1474 }
1475 x->x_vec = nvec;
1476 /* LATER should check t_resizebytes result */
1477 if (n > was)
1478 memset(x->x_vec + was*elemsize,
1479 0, (n - was) * elemsize);
1480 x->x_n = n;
1481
1482 /* if this is the only array in the graph,
1483 reset the graph's coordinates */
1484 gl = x->x_glist;
1485 if (gl->gl_list == &x->x_gobj && !x->x_gobj.g_next)
1486 {
1487 vmess(&gl->gl_pd, gensym("bounds"), "ffff",
1488 0., gl->gl_y1, (double)(n > 1 ? n-1 : 1), gl->gl_y2);
1489 /* close any dialogs that might have the wrong info now... */
1490#ifndef ROCKBOX
1491 gfxstub_deleteforkey(gl);
1492#endif
1493 }
1494 else garray_redraw(x);
1495 if (x->x_usedindsp) canvas_update_dsp();
1496}
1497
1498static void garray_print(t_garray *x)
1499{
1500 post("garray %s: template %s, length %d",
1501 x->x_name->s_name, x->x_templatesym->s_name, x->x_n);
1502}
1503
1504void g_array_setup(void)
1505{
1506 garray_class = class_new(gensym("array"), 0, (t_method)garray_free,
1507 sizeof(t_garray), CLASS_GOBJ, 0);
1508 class_setwidget(garray_class, &garray_widgetbehavior);
1509 class_addmethod(garray_class, (t_method)garray_const, gensym("const"),
1510 A_DEFFLOAT, A_NULL);
1511 class_addlist(garray_class, garray_list);
1512 class_addmethod(garray_class, (t_method)garray_bounds, gensym("bounds"),
1513 A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
1514 class_addmethod(garray_class, (t_method)garray_xticks, gensym("xticks"),
1515 A_FLOAT, A_FLOAT, A_FLOAT, 0);
1516 class_addmethod(garray_class, (t_method)garray_xlabel, gensym("xlabel"),
1517 A_GIMME, 0);
1518 class_addmethod(garray_class, (t_method)garray_yticks, gensym("yticks"),
1519 A_FLOAT, A_FLOAT, A_FLOAT, 0);
1520 class_addmethod(garray_class, (t_method)garray_ylabel, gensym("ylabel"),
1521 A_GIMME, 0);
1522 class_addmethod(garray_class, (t_method)garray_rename, gensym("rename"),
1523 A_SYMBOL, 0);
1524 class_addmethod(garray_class, (t_method)garray_read, gensym("read"),
1525 A_SYMBOL, A_NULL);
1526 class_addmethod(garray_class, (t_method)garray_read16, gensym("read16"),
1527 A_SYMBOL, A_DEFFLOAT, A_DEFSYM, A_NULL);
1528 class_addmethod(garray_class, (t_method)garray_write, gensym("write"),
1529 A_SYMBOL, A_NULL);
1530 class_addmethod(garray_class, (t_method)garray_write16, gensym("write16"),
1531 A_SYMBOL, A_DEFSYM, A_NULL);
1532 class_addmethod(garray_class, (t_method)garray_resize, gensym("resize"),
1533 A_FLOAT, A_NULL);
1534 class_addmethod(garray_class, (t_method)garray_print, gensym("print"),
1535 A_NULL);
1536 class_addmethod(garray_class, (t_method)garray_sinesum, gensym("sinesum"),
1537 A_GIMME, 0);
1538 class_addmethod(garray_class, (t_method)garray_cosinesum,
1539 gensym("cosinesum"), A_GIMME, 0);
1540 class_addmethod(garray_class, (t_method)garray_normalize,
1541 gensym("normalize"), A_DEFFLOAT, 0);
1542 class_addmethod(garray_class, (t_method)garray_arraydialog,
1543 gensym("arraydialog"), A_SYMBOL, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
1544 class_setsavefn(garray_class, garray_save);
1545}
1546