A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 1546 lines 43 kB view raw
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