diff options
author | Peter D'Hoye <peter.dhoye@gmail.com> | 2009-05-24 21:28:16 +0000 |
---|---|---|
committer | Peter D'Hoye <peter.dhoye@gmail.com> | 2009-05-24 21:28:16 +0000 |
commit | 526b5580dabbfed7cfe5439dc3a90ec727f563c2 (patch) | |
tree | 22b1af92348785daad16714ee5e2b633017e0e48 /apps/plugins/pdbox/PDa/src/g_array.c | |
parent | 4f2dfcc01b260d946044ef2b6af5fe36cb772c8d (diff) | |
download | rockbox-526b5580dabbfed7cfe5439dc3a90ec727f563c2.tar.gz rockbox-526b5580dabbfed7cfe5439dc3a90ec727f563c2.zip |
Cut the files in half and it might work better (note to self: check your tree is really clean before patching)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21070 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/g_array.c')
-rw-r--r-- | apps/plugins/pdbox/PDa/src/g_array.c | 1368 |
1 files changed, 0 insertions, 1368 deletions
diff --git a/apps/plugins/pdbox/PDa/src/g_array.c b/apps/plugins/pdbox/PDa/src/g_array.c index f259ac8dcb..3e2225637a 100644 --- a/apps/plugins/pdbox/PDa/src/g_array.c +++ b/apps/plugins/pdbox/PDa/src/g_array.c | |||
@@ -1364,1371 +1364,3 @@ void g_array_setup(void) | |||
1364 | class_setsavefn(garray_class, garray_save); | 1364 | class_setsavefn(garray_class, garray_save); |
1365 | } | 1365 | } |
1366 | 1366 | ||
1367 | |||
1368 | /* Copyright (c) 1997-1999 Miller Puckette. | ||
1369 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
1370 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | ||
1371 | |||
1372 | #include <stdlib.h> | ||
1373 | #include <string.h> | ||
1374 | #include <stdio.h> /* for read/write to files */ | ||
1375 | #include "m_pd.h" | ||
1376 | #include "g_canvas.h" | ||
1377 | #include <math.h> | ||
1378 | |||
1379 | /* see also the "plot" object in g_scalar.c which deals with graphing | ||
1380 | arrays which are fields in scalars. Someday we should unify the | ||
1381 | two, but how? */ | ||
1382 | |||
1383 | /* aux routine to bash leading '#' to '$' for dialogs in u_main.tk | ||
1384 | which can't send symbols starting with '$' (because the Pd message | ||
1385 | interpreter would change them!) */ | ||
1386 | |||
1387 | static t_symbol *sharptodollar(t_symbol *s) | ||
1388 | { | ||
1389 | if (*s->s_name == '#') | ||
1390 | { | ||
1391 | char buf[MAXPDSTRING]; | ||
1392 | strncpy(buf, s->s_name, MAXPDSTRING); | ||
1393 | buf[MAXPDSTRING-1] = 0; | ||
1394 | buf[0] = '$'; | ||
1395 | return (gensym(buf)); | ||
1396 | } | ||
1397 | else return (s); | ||
1398 | } | ||
1399 | |||
1400 | /* --------- "pure" arrays with scalars for elements. --------------- */ | ||
1401 | |||
1402 | /* Pure arrays have no a priori graphical capabilities. | ||
1403 | They are instantiated by "garrays" below or can be elements of other | ||
1404 | scalars (g_scalar.c); their graphical behavior is defined accordingly. */ | ||
1405 | |||
1406 | t_array *array_new(t_symbol *templatesym, t_gpointer *parent) | ||
1407 | { | ||
1408 | t_array *x = (t_array *)getbytes(sizeof (*x)); | ||
1409 | t_template *template; | ||
1410 | t_gpointer *gp; | ||
1411 | template = template_findbyname(templatesym); | ||
1412 | x->a_templatesym = templatesym; | ||
1413 | x->a_n = 1; | ||
1414 | x->a_elemsize = sizeof(t_word) * template->t_n; | ||
1415 | x->a_vec = (char *)getbytes(x->a_elemsize); | ||
1416 | /* note here we blithely copy a gpointer instead of "setting" a | ||
1417 | new one; this gpointer isn't accounted for and needn't be since | ||
1418 | we'll be deleted before the thing pointed to gets deleted anyway; | ||
1419 | see array_free. */ | ||
1420 | x->a_gp = *parent; | ||
1421 | x->a_stub = gstub_new(0, x); | ||
1422 | word_init((t_word *)(x->a_vec), template, parent); | ||
1423 | return (x); | ||
1424 | } | ||
1425 | |||
1426 | void array_resize(t_array *x, t_template *template, int n) | ||
1427 | { | ||
1428 | int elemsize, oldn; | ||
1429 | t_gpointer *gp; | ||
1430 | |||
1431 | if (n < 1) | ||
1432 | n = 1; | ||
1433 | oldn = x->a_n; | ||
1434 | elemsize = sizeof(t_word) * template->t_n; | ||
1435 | |||
1436 | x->a_vec = (char *)resizebytes(x->a_vec, oldn * elemsize, | ||
1437 | n * elemsize); | ||
1438 | x->a_n = n; | ||
1439 | if (n > oldn) | ||
1440 | { | ||
1441 | char *cp = x->a_vec + elemsize * oldn; | ||
1442 | int i = n - oldn; | ||
1443 | for (; i--; cp += elemsize) | ||
1444 | { | ||
1445 | t_word *wp = (t_word *)cp; | ||
1446 | word_init(wp, template, &x->a_gp); | ||
1447 | } | ||
1448 | } | ||
1449 | } | ||
1450 | |||
1451 | void word_free(t_word *wp, t_template *template); | ||
1452 | |||
1453 | void array_free(t_array *x) | ||
1454 | { | ||
1455 | int i; | ||
1456 | t_template *scalartemplate = template_findbyname(x->a_templatesym); | ||
1457 | /* we don't unset our gpointer here since it was never "set." */ | ||
1458 | /* gpointer_unset(&x->a_gp); */ | ||
1459 | gstub_cutoff(x->a_stub); | ||
1460 | for (i = 0; i < x->a_n; i++) | ||
1461 | { | ||
1462 | t_word *wp = (t_word *)(x->a_vec + x->a_elemsize * i); | ||
1463 | word_free(wp, scalartemplate); | ||
1464 | } | ||
1465 | freebytes(x->a_vec, x->a_elemsize * x->a_n); | ||
1466 | freebytes(x, sizeof *x); | ||
1467 | } | ||
1468 | |||
1469 | /* --------------------- graphical arrays (garrays) ------------------- */ | ||
1470 | |||
1471 | t_class *garray_class; | ||
1472 | static int gcount = 0; | ||
1473 | |||
1474 | struct _garray | ||
1475 | { | ||
1476 | t_gobj x_gobj; | ||
1477 | t_glist *x_glist; | ||
1478 | t_array x_array; /* actual array; note only 4 fields used as below */ | ||
1479 | t_symbol *x_name; | ||
1480 | t_symbol *x_realname; /* name with "$" expanded */ | ||
1481 | t_float x_firstx; /* X value of first item */ | ||
1482 | t_float x_xinc; /* X increment */ | ||
1483 | char x_usedindsp; /* true if some DSP routine is using this */ | ||
1484 | char x_saveit; /* true if we should save this with parent */ | ||
1485 | }; | ||
1486 | |||
1487 | /* macros to get into the "array" structure */ | ||
1488 | #define x_n x_array.a_n | ||
1489 | #define x_elemsize x_array.a_elemsize | ||
1490 | #define x_vec x_array.a_vec | ||
1491 | #define x_templatesym x_array.a_templatesym | ||
1492 | |||
1493 | t_garray *graph_array(t_glist *gl, t_symbol *s, t_symbol *templatesym, | ||
1494 | t_floatarg f, t_floatarg saveit) | ||
1495 | { | ||
1496 | int n = f, i; | ||
1497 | int zz, nwords; | ||
1498 | t_garray *x; | ||
1499 | t_pd *x2; | ||
1500 | t_template *template; | ||
1501 | char *str; | ||
1502 | if (s == &s_) | ||
1503 | { | ||
1504 | char buf[40]; | ||
1505 | sprintf(buf, "array%d", ++gcount); | ||
1506 | s = gensym(buf); | ||
1507 | templatesym = &s_float; | ||
1508 | n = 100; | ||
1509 | } | ||
1510 | else if (!strncmp((str = s->s_name), "array", 5) | ||
1511 | && (zz = atoi(str + 5)) > gcount) gcount = zz; | ||
1512 | template = template_findbyname(templatesym); | ||
1513 | if (!template) | ||
1514 | { | ||
1515 | error("array: couldn't find template %s", templatesym->s_name); | ||
1516 | return (0); | ||
1517 | } | ||
1518 | nwords = template->t_n; | ||
1519 | for (i = 0; i < nwords; i++) | ||
1520 | { | ||
1521 | /* we can't have array or list elements yet because what scalar | ||
1522 | can act as their "parent"??? */ | ||
1523 | if (template->t_vec[i].ds_type == DT_ARRAY | ||
1524 | || template->t_vec[i].ds_type == DT_LIST) | ||
1525 | { | ||
1526 | error("array: template %s can't have sublists or arrays", | ||
1527 | templatesym->s_name); | ||
1528 | return (0); | ||
1529 | } | ||
1530 | } | ||
1531 | x = (t_garray *)pd_new(garray_class); | ||
1532 | |||
1533 | if (n <= 0) n = 100; | ||
1534 | x->x_n = n; | ||
1535 | x->x_elemsize = nwords * sizeof(t_word); | ||
1536 | x->x_vec = getbytes(x->x_n * x->x_elemsize); | ||
1537 | memset(x->x_vec, 0, x->x_n * x->x_elemsize); | ||
1538 | /* LATER should check that malloc */ | ||
1539 | x->x_name = s; | ||
1540 | x->x_realname = canvas_realizedollar(gl, s); | ||
1541 | pd_bind(&x->x_gobj.g_pd, x->x_realname); | ||
1542 | x->x_templatesym = templatesym; | ||
1543 | x->x_firstx = 0; | ||
1544 | x->x_xinc = 1; /* LATER make methods to set this... */ | ||
1545 | glist_add(gl, &x->x_gobj); | ||
1546 | x->x_glist = gl; | ||
1547 | x->x_usedindsp = 0; | ||
1548 | x->x_saveit = (saveit != 0); | ||
1549 | if (x2 = pd_findbyclass(gensym("#A"), garray_class)) | ||
1550 | pd_unbind(x2, gensym("#A")); | ||
1551 | |||
1552 | pd_bind(&x->x_gobj.g_pd, gensym("#A")); | ||
1553 | |||
1554 | return (x); | ||
1555 | } | ||
1556 | |||
1557 | /* called from array menu item to create a new one */ | ||
1558 | void canvas_menuarray(t_glist *canvas) | ||
1559 | { | ||
1560 | t_glist *x = (t_glist *)canvas; | ||
1561 | char cmdbuf[200]; | ||
1562 | sprintf(cmdbuf, "pdtk_array_dialog %%s array%d 100 1 1\n", | ||
1563 | ++gcount); | ||
1564 | gfxstub_new(&x->gl_pd, x, cmdbuf); | ||
1565 | } | ||
1566 | |||
1567 | /* called from graph_dialog to set properties */ | ||
1568 | void garray_properties(t_garray *x) | ||
1569 | { | ||
1570 | char cmdbuf[200]; | ||
1571 | gfxstub_deleteforkey(x); | ||
1572 | /* create dialog window. LATER fix this to escape '$' | ||
1573 | properly; right now we just detect a leading '$' and escape | ||
1574 | it. There should be a systematic way of doing this. */ | ||
1575 | if (x->x_name->s_name[0] == '$') | ||
1576 | sprintf(cmdbuf, "pdtk_array_dialog %%s \\%s %d %d 0\n", | ||
1577 | x->x_name->s_name, x->x_n, x->x_saveit); | ||
1578 | else sprintf(cmdbuf, "pdtk_array_dialog %%s %s %d %d 0\n", | ||
1579 | x->x_name->s_name, x->x_n, x->x_saveit); | ||
1580 | gfxstub_new(&x->x_gobj.g_pd, x, cmdbuf); | ||
1581 | } | ||
1582 | |||
1583 | /* this is called back from the dialog window to create a garray. | ||
1584 | The otherflag requests that we find an existing graph to put it in. */ | ||
1585 | void glist_arraydialog(t_glist *parent, t_symbol *name, t_floatarg size, | ||
1586 | t_floatarg saveit, t_floatarg otherflag) | ||
1587 | { | ||
1588 | t_glist *gl; | ||
1589 | t_garray *a; | ||
1590 | if (size < 1) | ||
1591 | size = 1; | ||
1592 | if (otherflag == 0 || (!(gl = glist_findgraph(parent)))) | ||
1593 | gl = glist_addglist(parent, &s_, 0, 1, | ||
1594 | (size > 1 ? size-1 : size), -1, 0, 0, 0, 0); | ||
1595 | a = graph_array(gl, sharptodollar(name), &s_float, size, saveit); | ||
1596 | } | ||
1597 | |||
1598 | /* this is called from the properties dialog window for an existing array */ | ||
1599 | void garray_arraydialog(t_garray *x, t_symbol *name, t_floatarg fsize, | ||
1600 | t_floatarg saveit, t_floatarg deleteit) | ||
1601 | { | ||
1602 | if (deleteit != 0) | ||
1603 | { | ||
1604 | glist_delete(x->x_glist, &x->x_gobj); | ||
1605 | } | ||
1606 | else | ||
1607 | { | ||
1608 | int size; | ||
1609 | t_symbol *argname = sharptodollar(name); | ||
1610 | if (argname != x->x_name) | ||
1611 | { | ||
1612 | x->x_name = argname; | ||
1613 | pd_unbind(&x->x_gobj.g_pd, x->x_realname); | ||
1614 | x->x_realname = canvas_realizedollar(x->x_glist, argname); | ||
1615 | pd_bind(&x->x_gobj.g_pd, x->x_realname); | ||
1616 | } | ||
1617 | size = fsize; | ||
1618 | if (size < 1) | ||
1619 | size = 1; | ||
1620 | if (size != x->x_n) | ||
1621 | garray_resize(x, size); | ||
1622 | garray_setsaveit(x, (saveit != 0)); | ||
1623 | garray_redraw(x); | ||
1624 | } | ||
1625 | } | ||
1626 | |||
1627 | static void garray_free(t_garray *x) | ||
1628 | { | ||
1629 | t_pd *x2; | ||
1630 | gfxstub_deleteforkey(x); | ||
1631 | pd_unbind(&x->x_gobj.g_pd, x->x_realname); | ||
1632 | /* LATER find a way to get #A unbound earlier (at end of load?) */ | ||
1633 | while (x2 = pd_findbyclass(gensym("#A"), garray_class)) | ||
1634 | pd_unbind(x2, gensym("#A")); | ||
1635 | freebytes(x->x_vec, x->x_n * x->x_elemsize); | ||
1636 | } | ||
1637 | |||
1638 | /* ------------- code used by both array and plot widget functions ---- */ | ||
1639 | |||
1640 | /* routine to get screen coordinates of a point in an array */ | ||
1641 | void array_getcoordinate(t_glist *glist, | ||
1642 | char *elem, int xonset, int yonset, int wonset, int indx, | ||
1643 | float basex, float basey, float xinc, | ||
1644 | float *xp, float *yp, float *wp) | ||
1645 | { | ||
1646 | float xval, yval, ypix, wpix; | ||
1647 | if (xonset >= 0) | ||
1648 | xval = fixtof(*(t_sample *)(elem + xonset)); | ||
1649 | else xval = indx * xinc; | ||
1650 | if (yonset >= 0) | ||
1651 | yval = fixtof(*(t_sample *)(elem + yonset)); | ||
1652 | else yval = 0; | ||
1653 | ypix = glist_ytopixels(glist, basey + yval); | ||
1654 | if (wonset >= 0) | ||
1655 | { | ||
1656 | /* found "w" field which controls linewidth. */ | ||
1657 | float wval = *(float *)(elem + wonset); | ||
1658 | wpix = glist_ytopixels(glist, basey + yval + wval) - ypix; | ||
1659 | if (wpix < 0) | ||
1660 | wpix = -wpix; | ||
1661 | } | ||
1662 | else wpix = 1; | ||
1663 | *xp = glist_xtopixels(glist, basex + xval); | ||
1664 | *yp = ypix; | ||
1665 | *wp = wpix; | ||
1666 | } | ||
1667 | |||
1668 | static float array_motion_xcumulative; | ||
1669 | static float array_motion_ycumulative; | ||
1670 | static t_symbol *array_motion_xfield; | ||
1671 | static t_symbol *array_motion_yfield; | ||
1672 | static t_glist *array_motion_glist; | ||
1673 | static t_gobj *array_motion_gobj; | ||
1674 | static t_word *array_motion_wp; | ||
1675 | static t_template *array_motion_template; | ||
1676 | static int array_motion_npoints; | ||
1677 | static int array_motion_elemsize; | ||
1678 | static int array_motion_altkey; | ||
1679 | static float array_motion_initx; | ||
1680 | static float array_motion_xperpix; | ||
1681 | static float array_motion_yperpix; | ||
1682 | static int array_motion_lastx; | ||
1683 | static int array_motion_fatten; | ||
1684 | |||
1685 | /* LATER protect against the template changing or the scalar disappearing | ||
1686 | probably by attaching a gpointer here ... */ | ||
1687 | |||
1688 | static void array_motion(void *z, t_floatarg dx, t_floatarg dy) | ||
1689 | { | ||
1690 | array_motion_xcumulative += dx * array_motion_xperpix; | ||
1691 | array_motion_ycumulative += dy * array_motion_yperpix; | ||
1692 | if (*array_motion_xfield->s_name) | ||
1693 | { | ||
1694 | /* it's an x, y plot; can drag many points at once */ | ||
1695 | int i; | ||
1696 | char *charword = (char *)array_motion_wp; | ||
1697 | for (i = 0; i < array_motion_npoints; i++) | ||
1698 | { | ||
1699 | t_word *thisword = (t_word *)(charword + i * array_motion_elemsize); | ||
1700 | if (*array_motion_xfield->s_name) | ||
1701 | { | ||
1702 | float xwas = template_getfloat(array_motion_template, | ||
1703 | array_motion_xfield, thisword, 1); | ||
1704 | template_setfloat(array_motion_template, | ||
1705 | array_motion_xfield, thisword, xwas + dx, 1); | ||
1706 | } | ||
1707 | if (*array_motion_yfield->s_name) | ||
1708 | { | ||
1709 | float ywas = template_getfloat(array_motion_template, | ||
1710 | array_motion_yfield, thisword, 1); | ||
1711 | if (array_motion_fatten) | ||
1712 | { | ||
1713 | if (i == 0) | ||
1714 | { | ||
1715 | float newy = ywas + dy * array_motion_yperpix; | ||
1716 | if (newy < 0) | ||
1717 | newy = 0; | ||
1718 | template_setfloat(array_motion_template, | ||
1719 | array_motion_yfield, thisword, newy, 1); | ||
1720 | } | ||
1721 | } | ||
1722 | else | ||
1723 | { | ||
1724 | template_setfloat(array_motion_template, | ||
1725 | array_motion_yfield, thisword, | ||
1726 | ywas + dy * array_motion_yperpix, 1); | ||
1727 | } | ||
1728 | } | ||
1729 | } | ||
1730 | } | ||
1731 | else | ||
1732 | { | ||
1733 | /* a y-only plot. */ | ||
1734 | int thisx = array_motion_initx + | ||
1735 | array_motion_xcumulative, x2; | ||
1736 | int increment, i, nchange; | ||
1737 | char *charword = (char *)array_motion_wp; | ||
1738 | float newy = array_motion_ycumulative, | ||
1739 | oldy = template_getfloat( | ||
1740 | array_motion_template, array_motion_yfield, | ||
1741 | (t_word *)(charword + array_motion_elemsize * array_motion_lastx), 1); | ||
1742 | float ydiff = newy - oldy; | ||
1743 | if (thisx < 0) thisx = 0; | ||
1744 | else if (thisx >= array_motion_npoints) | ||
1745 | thisx = array_motion_npoints - 1; | ||
1746 | increment = (thisx > array_motion_lastx ? -1 : 1); | ||
1747 | nchange = 1 + increment * (array_motion_lastx - thisx); | ||
1748 | |||
1749 | for (i = 0, x2 = thisx; i < nchange; i++, x2 += increment) | ||
1750 | { | ||
1751 | template_setfloat(array_motion_template, | ||
1752 | array_motion_yfield, | ||
1753 | (t_word *)(charword + array_motion_elemsize * x2), | ||
1754 | newy, 1); | ||
1755 | if (nchange > 1) | ||
1756 | newy -= ydiff * (1./(nchange - 1)); | ||
1757 | } | ||
1758 | array_motion_lastx = thisx; | ||
1759 | } | ||
1760 | glist_redrawitem(array_motion_glist, array_motion_gobj); | ||
1761 | } | ||
1762 | |||
1763 | int array_doclick(t_array *array, t_glist *glist, t_gobj *gobj, | ||
1764 | t_symbol *elemtemplatesym, | ||
1765 | float linewidth, float xloc, float xinc, float yloc, | ||
1766 | int xpix, int ypix, int shift, int alt, int dbl, int doit) | ||
1767 | { | ||
1768 | t_canvas *elemtemplatecanvas; | ||
1769 | t_template *elemtemplate; | ||
1770 | int elemsize, yonset, wonset, xonset, i; | ||
1771 | |||
1772 | if (!array_getfields(elemtemplatesym, &elemtemplatecanvas, | ||
1773 | &elemtemplate, &elemsize, &xonset, &yonset, &wonset)) | ||
1774 | { | ||
1775 | float best = 100; | ||
1776 | int incr; | ||
1777 | /* if it has more than 2000 points, just check 300 of them. */ | ||
1778 | if (array->a_n < 2000) | ||
1779 | incr = 1; | ||
1780 | else incr = array->a_n / 300; | ||
1781 | for (i = 0; i < array->a_n; i += incr) | ||
1782 | { | ||
1783 | float pxpix, pypix, pwpix, dx, dy; | ||
1784 | array_getcoordinate(glist, (char *)(array->a_vec) + i * elemsize, | ||
1785 | xonset, yonset, wonset, i, xloc, yloc, xinc, | ||
1786 | &pxpix, &pypix, &pwpix); | ||
1787 | if (pwpix < 4) | ||
1788 | pwpix = 4; | ||
1789 | dx = pxpix - xpix; | ||
1790 | if (dx < 0) dx = -dx; | ||
1791 | if (dx > 8) | ||
1792 | continue; | ||
1793 | dy = pypix - ypix; | ||
1794 | if (dy < 0) dy = -dy; | ||
1795 | if (dx + dy < best) | ||
1796 | best = dx + dy; | ||
1797 | if (wonset >= 0) | ||
1798 | { | ||
1799 | dy = (pypix + pwpix) - ypix; | ||
1800 | if (dy < 0) dy = -dy; | ||
1801 | if (dx + dy < best) | ||
1802 | best = dx + dy; | ||
1803 | dy = (pypix - pwpix) - ypix; | ||
1804 | if (dy < 0) dy = -dy; | ||
1805 | if (dx + dy < best) | ||
1806 | best = dx + dy; | ||
1807 | } | ||
1808 | } | ||
1809 | if (best > 8) | ||
1810 | return (0); | ||
1811 | best += 0.001; /* add truncation error margin */ | ||
1812 | for (i = 0; i < array->a_n; i += incr) | ||
1813 | { | ||
1814 | float pxpix, pypix, pwpix, dx, dy, dy2, dy3; | ||
1815 | array_getcoordinate(glist, (char *)(array->a_vec) + i * elemsize, | ||
1816 | xonset, yonset, wonset, i, xloc, yloc, xinc, | ||
1817 | &pxpix, &pypix, &pwpix); | ||
1818 | if (pwpix < 4) | ||
1819 | pwpix = 4; | ||
1820 | dx = pxpix - xpix; | ||
1821 | if (dx < 0) dx = -dx; | ||
1822 | dy = pypix - ypix; | ||
1823 | if (dy < 0) dy = -dy; | ||
1824 | if (wonset >= 0) | ||
1825 | { | ||
1826 | dy2 = (pypix + pwpix) - ypix; | ||
1827 | if (dy2 < 0) dy2 = -dy2; | ||
1828 | dy3 = (pypix - pwpix) - ypix; | ||
1829 | if (dy3 < 0) dy3 = -dy3; | ||
1830 | if (yonset <= 0) | ||
1831 | dy = 100; | ||
1832 | } | ||
1833 | else dy2 = dy3 = 100; | ||
1834 | if (dx + dy <= best || dx + dy2 <= best || dx + dy3 <= best) | ||
1835 | { | ||
1836 | if (dy < dy2 && dy < dy3) | ||
1837 | array_motion_fatten = 0; | ||
1838 | else if (dy2 < dy3) | ||
1839 | array_motion_fatten = -1; | ||
1840 | else array_motion_fatten = 1; | ||
1841 | if (doit) | ||
1842 | { | ||
1843 | char *elem = (char *)array->a_vec; | ||
1844 | array_motion_elemsize = elemsize; | ||
1845 | array_motion_glist = glist; | ||
1846 | array_motion_gobj = gobj; | ||
1847 | array_motion_template = elemtemplate; | ||
1848 | array_motion_xperpix = glist_dpixtodx(glist, 1); | ||
1849 | array_motion_yperpix = glist_dpixtody(glist, 1); | ||
1850 | if (alt && xpix < pxpix) /* delete a point */ | ||
1851 | { | ||
1852 | if (array->a_n <= 1) | ||
1853 | return (0); | ||
1854 | memmove((char *)(array->a_vec) + elemsize * i, | ||
1855 | (char *)(array->a_vec) + elemsize * (i+1), | ||
1856 | (array->a_n - 1 - i) * elemsize); | ||
1857 | array_resize(array, elemtemplate, array->a_n - 1); | ||
1858 | glist_redrawitem(array_motion_glist, array_motion_gobj); | ||
1859 | return (0); | ||
1860 | } | ||
1861 | else if (alt) | ||
1862 | { | ||
1863 | /* add a point (after the clicked-on one) */ | ||
1864 | array_resize(array, elemtemplate, array->a_n + 1); | ||
1865 | elem = (char *)array->a_vec; | ||
1866 | memmove(elem + elemsize * (i+1), | ||
1867 | elem + elemsize * i, | ||
1868 | (array->a_n - i - 1) * elemsize); | ||
1869 | i++; | ||
1870 | } | ||
1871 | if (xonset >= 0) | ||
1872 | { | ||
1873 | array_motion_xfield = gensym("x"); | ||
1874 | array_motion_xcumulative = | ||
1875 | *(float *)((elem + elemsize * i) + xonset); | ||
1876 | array_motion_wp = (t_word *)(elem + i * elemsize); | ||
1877 | array_motion_npoints = array->a_n - i; | ||
1878 | } | ||
1879 | else | ||
1880 | { | ||
1881 | array_motion_xfield = &s_; | ||
1882 | array_motion_xcumulative = 0; | ||
1883 | array_motion_wp = (t_word *)elem; | ||
1884 | array_motion_npoints = array->a_n; | ||
1885 | |||
1886 | array_motion_initx = i; | ||
1887 | array_motion_lastx = i; | ||
1888 | array_motion_xperpix *= (xinc == 0 ? 1 : 1./xinc); | ||
1889 | } | ||
1890 | if (array_motion_fatten) | ||
1891 | { | ||
1892 | array_motion_yfield = gensym("w"); | ||
1893 | array_motion_ycumulative = | ||
1894 | *(float *)((elem + elemsize * i) + wonset); | ||
1895 | array_motion_yperpix *= array_motion_fatten; | ||
1896 | } | ||
1897 | else if (yonset >= 0) | ||
1898 | { | ||
1899 | array_motion_yfield = gensym("y"); | ||
1900 | array_motion_ycumulative = | ||
1901 | *(float *)((elem + elemsize * i) + yonset); | ||
1902 | } | ||
1903 | else | ||
1904 | { | ||
1905 | array_motion_yfield = &s_; | ||
1906 | array_motion_ycumulative = 0; | ||
1907 | } | ||
1908 | glist_grab(glist, 0, array_motion, 0, xpix, ypix); | ||
1909 | } | ||
1910 | if (alt) | ||
1911 | { | ||
1912 | if (xpix < pxpix) | ||
1913 | return (CURSOR_EDITMODE_DISCONNECT); | ||
1914 | else return (CURSOR_RUNMODE_ADDPOINT); | ||
1915 | } | ||
1916 | else return (array_motion_fatten ? | ||
1917 | CURSOR_RUNMODE_THICKEN : CURSOR_RUNMODE_CLICKME); | ||
1918 | } | ||
1919 | } | ||
1920 | } | ||
1921 | return (0); | ||
1922 | } | ||
1923 | |||
1924 | /* -------------------- widget behavior for garray ------------ */ | ||
1925 | |||
1926 | static void garray_getrect(t_gobj *z, t_glist *glist, | ||
1927 | int *xp1, int *yp1, int *xp2, int *yp2) | ||
1928 | { | ||
1929 | t_garray *x = (t_garray *)z; | ||
1930 | float x1 = 0x7fffffff, y1 = 0x7fffffff, x2 = -0x7fffffff, y2 = -0x7fffffff; | ||
1931 | t_canvas *elemtemplatecanvas; | ||
1932 | t_template *elemtemplate; | ||
1933 | int elemsize, yonset, wonset, xonset, i; | ||
1934 | |||
1935 | if (!array_getfields(x->x_templatesym, &elemtemplatecanvas, | ||
1936 | &elemtemplate, &elemsize, &xonset, &yonset, &wonset)) | ||
1937 | { | ||
1938 | int incr; | ||
1939 | /* if it has more than 2000 points, just check 300 of them. */ | ||
1940 | if (x->x_array.a_n < 2000) | ||
1941 | incr = 1; | ||
1942 | else incr = x->x_array.a_n / 300; | ||
1943 | for (i = 0; i < x->x_array.a_n; i += incr) | ||
1944 | { | ||
1945 | float pxpix, pypix, pwpix, dx, dy; | ||
1946 | array_getcoordinate(glist, (char *)(x->x_array.a_vec) + | ||
1947 | i * elemsize, | ||
1948 | xonset, yonset, wonset, i, 0, 0, 1, | ||
1949 | &pxpix, &pypix, &pwpix); | ||
1950 | if (pwpix < 2) | ||
1951 | pwpix = 2; | ||
1952 | if (pxpix < x1) | ||
1953 | x1 = pxpix; | ||
1954 | if (pxpix > x2) | ||
1955 | x2 = pxpix; | ||
1956 | if (pypix - pwpix < y1) | ||
1957 | y1 = pypix - pwpix; | ||
1958 | if (pypix + pwpix > y2) | ||
1959 | y2 = pypix + pwpix; | ||
1960 | } | ||
1961 | } | ||
1962 | *xp1 = x1; | ||
1963 | *yp1 = y1; | ||
1964 | *xp2 = x2; | ||
1965 | *yp2 = y2; | ||
1966 | } | ||
1967 | |||
1968 | static void garray_displace(t_gobj *z, t_glist *glist, int dx, int dy) | ||
1969 | { | ||
1970 | /* refuse */ | ||
1971 | } | ||
1972 | |||
1973 | static void garray_select(t_gobj *z, t_glist *glist, int state) | ||
1974 | { | ||
1975 | t_garray *x = (t_garray *)z; | ||
1976 | /* fill in later */ | ||
1977 | } | ||
1978 | |||
1979 | static void garray_activate(t_gobj *z, t_glist *glist, int state) | ||
1980 | { | ||
1981 | } | ||
1982 | |||
1983 | static void garray_delete(t_gobj *z, t_glist *glist) | ||
1984 | { | ||
1985 | /* nothing to do */ | ||
1986 | } | ||
1987 | |||
1988 | static void garray_vis(t_gobj *z, t_glist *glist, int vis) | ||
1989 | { | ||
1990 | t_garray *x = (t_garray *)z; | ||
1991 | if (vis) | ||
1992 | { | ||
1993 | int i, xonset, yonset, type; | ||
1994 | t_symbol *arraytype; | ||
1995 | t_template *template = template_findbyname(x->x_templatesym); | ||
1996 | if (!template) | ||
1997 | return; | ||
1998 | if (!template_find_field(template, gensym("y"), &yonset, &type, | ||
1999 | &arraytype) || type != DT_FLOAT) | ||
2000 | { | ||
2001 | error("%s: needs floating-point 'y' field", | ||
2002 | x->x_templatesym->s_name); | ||
2003 | sys_vgui(".x%x.c create text 50 50 -text foo\ | ||
2004 | -tags .x%x.a%x\n", | ||
2005 | glist_getcanvas(glist), glist_getcanvas(glist), x); | ||
2006 | } | ||
2007 | else if (!template_find_field(template, gensym("x"), &xonset, &type, | ||
2008 | &arraytype) || type != DT_FLOAT) | ||
2009 | { | ||
2010 | float firsty, xcum = x->x_firstx; | ||
2011 | int lastpixel = -1, ndrawn = 0; | ||
2012 | float yval = 0, xpix; | ||
2013 | int ixpix = 0; | ||
2014 | sys_vgui(".x%x.c create line \\\n", glist_getcanvas(glist)); | ||
2015 | for (i = 0; i < x->x_n; i++) | ||
2016 | { | ||
2017 | yval = fixtof(*(t_sample *)(x->x_vec + | ||
2018 | template->t_n * i * sizeof (t_word) + yonset)); | ||
2019 | xpix = glist_xtopixels(glist, xcum); | ||
2020 | ixpix = xpix + 0.5; | ||
2021 | if (ixpix != lastpixel) | ||
2022 | { | ||
2023 | sys_vgui("%d %f \\\n", ixpix, | ||
2024 | glist_ytopixels(glist, yval)); | ||
2025 | ndrawn++; | ||
2026 | } | ||
2027 | lastpixel = ixpix; | ||
2028 | if (ndrawn >= 1000) break; | ||
2029 | xcum += x->x_xinc; | ||
2030 | } | ||
2031 | /* TK will complain if there aren't at least 2 points... */ | ||
2032 | if (ndrawn == 0) sys_vgui("0 0 0 0 \\\n"); | ||
2033 | else if (ndrawn == 1) sys_vgui("%d %f \\\n", ixpix, | ||
2034 | glist_ytopixels(glist, yval)); | ||
2035 | sys_vgui("-tags .x%x.a%x\n", glist_getcanvas(glist), x); | ||
2036 | firsty = fixtof(*(t_sample *)(x->x_vec + yonset)); | ||
2037 | sys_vgui(".x%x.c create text %f %f -text {%s} -anchor e\ | ||
2038 | -font -*-courier-bold--normal--%d-* -tags .x%x.a%x\n", | ||
2039 | glist_getcanvas(glist), | ||
2040 | glist_xtopixels(glist, x->x_firstx) - 5., | ||
2041 | glist_ytopixels(glist, firsty), | ||
2042 | x->x_name->s_name, glist_getfont(glist), | ||
2043 | glist_getcanvas(glist), x); | ||
2044 | } | ||
2045 | else | ||
2046 | { | ||
2047 | post("x, y arrays not yet supported"); | ||
2048 | } | ||
2049 | } | ||
2050 | else | ||
2051 | { | ||
2052 | sys_vgui(".x%x.c delete .x%x.a%x\n", | ||
2053 | glist_getcanvas(glist), glist_getcanvas(glist), x); | ||
2054 | } | ||
2055 | } | ||
2056 | |||
2057 | static int garray_click(t_gobj *z, struct _glist *glist, | ||
2058 | int xpix, int ypix, int shift, int alt, int dbl, int doit) | ||
2059 | { | ||
2060 | t_garray *x = (t_garray *)z; | ||
2061 | return (array_doclick(&x->x_array, glist, z, x->x_templatesym, 1, 0, 1, 0, | ||
2062 | xpix, ypix, shift, alt, dbl, doit)); | ||
2063 | } | ||
2064 | |||
2065 | #define ARRAYWRITECHUNKSIZE 1000 | ||
2066 | |||
2067 | static void garray_save(t_gobj *z, t_binbuf *b) | ||
2068 | { | ||
2069 | t_garray *x = (t_garray *)z; | ||
2070 | binbuf_addv(b, "sssisi;", gensym("#X"), gensym("array"), | ||
2071 | x->x_name, x->x_n, x->x_templatesym, x->x_saveit); | ||
2072 | fprintf(stderr,"array save\n"); | ||
2073 | if (x->x_saveit) | ||
2074 | { | ||
2075 | int n = x->x_n, n2 = 0; | ||
2076 | if (x->x_templatesym != &s_float) | ||
2077 | { | ||
2078 | pd_error(x, "sorry, you can only save 'float' arrays now"); | ||
2079 | return; | ||
2080 | } | ||
2081 | if (n > 200000) | ||
2082 | post("warning: I'm saving an array with %d points!\n", n); | ||
2083 | while (n2 < n) | ||
2084 | { | ||
2085 | int chunk = n - n2, i; | ||
2086 | if (chunk > ARRAYWRITECHUNKSIZE) | ||
2087 | chunk = ARRAYWRITECHUNKSIZE; | ||
2088 | binbuf_addv(b, "si", gensym("#A"), n2); | ||
2089 | for (i = 0; i < chunk; i++) | ||
2090 | binbuf_addv(b, "f", fixtof(((t_sample *)(x->x_vec))[n2+i])); | ||
2091 | binbuf_addv(b, ";"); | ||
2092 | n2 += chunk; | ||
2093 | } | ||
2094 | } | ||
2095 | } | ||
2096 | |||
2097 | t_widgetbehavior garray_widgetbehavior = | ||
2098 | { | ||
2099 | garray_getrect, | ||
2100 | garray_displace, | ||
2101 | garray_select, | ||
2102 | garray_activate, | ||
2103 | garray_delete, | ||
2104 | garray_vis, | ||
2105 | garray_click | ||
2106 | }; | ||
2107 | |||
2108 | /* ----------------------- public functions -------------------- */ | ||
2109 | |||
2110 | void garray_usedindsp(t_garray *x) | ||
2111 | { | ||
2112 | x->x_usedindsp = 1; | ||
2113 | } | ||
2114 | |||
2115 | void garray_redraw(t_garray *x) | ||
2116 | { | ||
2117 | if (glist_isvisible(x->x_glist)) | ||
2118 | { | ||
2119 | garray_vis(&x->x_gobj, x->x_glist, 0); | ||
2120 | garray_vis(&x->x_gobj, x->x_glist, 1); | ||
2121 | } | ||
2122 | } | ||
2123 | |||
2124 | /* This functiopn gets the template of an array; if we can't figure | ||
2125 | out what template an array's elements belong to we're in grave trouble | ||
2126 | when it's time to free or resize it. */ | ||
2127 | t_template *garray_template(t_garray *x) | ||
2128 | { | ||
2129 | t_template *template = template_findbyname(x->x_templatesym); | ||
2130 | if (!template) | ||
2131 | bug("garray_template"); | ||
2132 | return (template); | ||
2133 | } | ||
2134 | |||
2135 | int garray_npoints(t_garray *x) /* get the length */ | ||
2136 | { | ||
2137 | return (x->x_n); | ||
2138 | } | ||
2139 | |||
2140 | char *garray_vec(t_garray *x) /* get the contents */ | ||
2141 | { | ||
2142 | return ((char *)(x->x_vec)); | ||
2143 | } | ||
2144 | |||
2145 | /* routine that checks if we're just an array of floats and if | ||
2146 | so returns the goods */ | ||
2147 | |||
2148 | int garray_getfloatarray(t_garray *x, int *size, t_sample **vec) | ||
2149 | { | ||
2150 | t_template *template = garray_template(x); | ||
2151 | int yonset, type; | ||
2152 | t_symbol *arraytype; | ||
2153 | if (!template_find_field(template, gensym("y"), &yonset, | ||
2154 | &type, &arraytype) || type != DT_FLOAT) | ||
2155 | error("%s: needs floating-point 'y' field", | ||
2156 | x->x_templatesym->s_name); | ||
2157 | else if (template->t_n != 1) | ||
2158 | error("%s: has more than one field", x->x_templatesym->s_name); | ||
2159 | else | ||
2160 | { | ||
2161 | *size = garray_npoints(x); | ||
2162 | *vec = (t_sample *)garray_vec(x); | ||
2163 | return (1); | ||
2164 | } | ||
2165 | return (0); | ||
2166 | } | ||
2167 | |||
2168 | /* get any floating-point field of any element of an array */ | ||
2169 | float garray_get(t_garray *x, t_symbol *s, t_int indx) | ||
2170 | { | ||
2171 | t_template *template = garray_template(x); | ||
2172 | int yonset, type; | ||
2173 | t_symbol *arraytype; | ||
2174 | if (!template_find_field(template, gensym("y"), &yonset, | ||
2175 | &type, &arraytype) || type != DT_FLOAT) | ||
2176 | { | ||
2177 | error("%s: needs floating-point '%s' field", x->x_templatesym->s_name, | ||
2178 | s->s_name); | ||
2179 | return (0); | ||
2180 | } | ||
2181 | if (indx < 0) indx = 0; | ||
2182 | else if (indx >= x->x_n) indx = x->x_n - 1; | ||
2183 | return (*(float *)((x->x_vec + sizeof(t_word) * indx) + yonset)); | ||
2184 | } | ||
2185 | |||
2186 | /* set the "saveit" flag */ | ||
2187 | void garray_setsaveit(t_garray *x, int saveit) | ||
2188 | { | ||
2189 | if (x->x_saveit && !saveit) | ||
2190 | post("warning: array %s: clearing save-in-patch flag", | ||
2191 | x->x_name->s_name); | ||
2192 | x->x_saveit = saveit; | ||
2193 | } | ||
2194 | |||
2195 | /*------------------- Pd messages ------------------------ */ | ||
2196 | static void garray_const(t_garray *x, t_floatarg g) | ||
2197 | { | ||
2198 | t_template *template = garray_template(x); | ||
2199 | int yonset, type, i; | ||
2200 | t_symbol *arraytype; | ||
2201 | if (!template_find_field(template, gensym("y"), &yonset, | ||
2202 | &type, &arraytype) || type != DT_FLOAT) | ||
2203 | error("%s: needs floating-point 'y' field", | ||
2204 | x->x_templatesym->s_name); | ||
2205 | else for (i = 0; i < x->x_n; i++) | ||
2206 | *(float *)(((char *)x->x_vec + sizeof(t_word) * i) + yonset) = g; | ||
2207 | garray_redraw(x); | ||
2208 | } | ||
2209 | |||
2210 | /* sum of Fourier components; called from routines below */ | ||
2211 | static void garray_dofo(t_garray *x, int npoints, float dcval, | ||
2212 | int nsin, t_float *vsin, int sineflag) | ||
2213 | { | ||
2214 | t_template *template = garray_template(x); | ||
2215 | int yonset, type, i, j; | ||
2216 | t_symbol *arraytype; | ||
2217 | double phase, phaseincr, fj; | ||
2218 | if (npoints == 0) | ||
2219 | npoints = 512; /* dunno what a good default would be... */ | ||
2220 | if (npoints != (1 << ilog2(npoints))) | ||
2221 | post("%s: rounnding to %d points", x->x_templatesym->s_name, | ||
2222 | (npoints = (1<<ilog2(npoints)))); | ||
2223 | garray_resize(x, npoints + 3); | ||
2224 | phaseincr = 2. * 3.14159 / npoints; | ||
2225 | if (!template_find_field(template, gensym("y"), &yonset, | ||
2226 | &type, &arraytype) || type != DT_FLOAT) | ||
2227 | { | ||
2228 | error("%s: needs floating-point 'y' field", x->x_templatesym->s_name); | ||
2229 | return; | ||
2230 | } | ||
2231 | for (i = 0, phase = -phaseincr; i < x->x_n; i++, phase += phaseincr ) | ||
2232 | { | ||
2233 | double sum = dcval; | ||
2234 | if (sineflag) | ||
2235 | for (j = 0, fj = phase; j < nsin; j++, fj += phase) | ||
2236 | sum += vsin[j] * sin(fj); | ||
2237 | else | ||
2238 | for (j = 0, fj = 0; j < nsin; j++, fj += phase) | ||
2239 | sum += vsin[j] * cos(fj); | ||
2240 | *(float *)((x->x_vec + sizeof(t_word) * i) + yonset) = sum; | ||
2241 | } | ||
2242 | garray_redraw(x); | ||
2243 | } | ||
2244 | |||
2245 | static void garray_sinesum(t_garray *x, t_symbol *s, int argc, t_atom *argv) | ||
2246 | { | ||
2247 | t_template *template = garray_template(x); | ||
2248 | |||
2249 | t_float *svec = (t_float *)t_getbytes(sizeof(t_float) * argc); | ||
2250 | int npoints, i; | ||
2251 | if (argc < 2) | ||
2252 | { | ||
2253 | error("sinesum: %s: need number of points and partial strengths", | ||
2254 | x->x_templatesym->s_name); | ||
2255 | return; | ||
2256 | } | ||
2257 | |||
2258 | npoints = atom_getfloatarg(0, argc, argv); | ||
2259 | argv++, argc--; | ||
2260 | |||
2261 | svec = (t_float *)t_getbytes(sizeof(t_float) * argc); | ||
2262 | if (!svec) return; | ||
2263 | |||
2264 | for (i = 0; i < argc; i++) | ||
2265 | svec[i] = atom_getfloatarg(i, argc, argv); | ||
2266 | garray_dofo(x, npoints, 0, argc, svec, 1); | ||
2267 | t_freebytes(svec, sizeof(t_float) * argc); | ||
2268 | } | ||
2269 | |||
2270 | static void garray_cosinesum(t_garray *x, t_symbol *s, int argc, t_atom *argv) | ||
2271 | { | ||
2272 | t_template *template = garray_template(x); | ||
2273 | |||
2274 | t_float *svec = (t_float *)t_getbytes(sizeof(t_float) * argc); | ||
2275 | int npoints, i; | ||
2276 | if (argc < 2) | ||
2277 | { | ||
2278 | error("sinesum: %s: need number of points and partial strengths", | ||
2279 | x->x_templatesym->s_name); | ||
2280 | return; | ||
2281 | } | ||
2282 | |||
2283 | npoints = atom_getfloatarg(0, argc, argv); | ||
2284 | argv++, argc--; | ||
2285 | |||
2286 | svec = (t_float *)t_getbytes(sizeof(t_float) * argc); | ||
2287 | if (!svec) return; | ||
2288 | |||
2289 | for (i = 0; i < argc; i++) | ||
2290 | svec[i] = atom_getfloatarg(i, argc, argv); | ||
2291 | garray_dofo(x, npoints, 0, argc, svec, 0); | ||
2292 | t_freebytes(svec, sizeof(t_float) * argc); | ||
2293 | } | ||
2294 | |||
2295 | static void garray_normalize(t_garray *x, t_float f) | ||
2296 | { | ||
2297 | t_template *template = garray_template(x); | ||
2298 | int yonset, type, npoints, i; | ||
2299 | double maxv, renormer; | ||
2300 | t_symbol *arraytype; | ||
2301 | |||
2302 | if (f <= 0) | ||
2303 | f = 1; | ||
2304 | |||
2305 | if (!template_find_field(template, gensym("y"), &yonset, | ||
2306 | &type, &arraytype) || type != DT_FLOAT) | ||
2307 | { | ||
2308 | error("%s: needs floating-point 'y' field", x->x_templatesym->s_name); | ||
2309 | return; | ||
2310 | } | ||
2311 | for (i = 0, maxv = 0; i < x->x_n; i++) | ||
2312 | { | ||
2313 | double v = *(float *)((x->x_vec + sizeof(t_word) * i) + yonset); | ||
2314 | if (v > maxv) | ||
2315 | maxv = v; | ||
2316 | if (-v > maxv) | ||
2317 | maxv = -v; | ||
2318 | } | ||
2319 | if (maxv >= 0) | ||
2320 | { | ||
2321 | renormer = f / maxv; | ||
2322 | for (i = 0; i < x->x_n; i++) | ||
2323 | { | ||
2324 | *(float *)((x->x_vec + sizeof(t_word) * i) + yonset) | ||
2325 | *= renormer; | ||
2326 | } | ||
2327 | } | ||
2328 | garray_redraw(x); | ||
2329 | } | ||
2330 | |||
2331 | /* list -- the first value is an index; subsequent values are put in | ||
2332 | the "y" slot of the array. This generalizes Max's "table", sort of. */ | ||
2333 | static void garray_list(t_garray *x, t_symbol *s, int argc, t_atom *argv) | ||
2334 | { | ||
2335 | t_template *template = garray_template(x); | ||
2336 | int yonset, type, i; | ||
2337 | t_symbol *arraytype; | ||
2338 | if (!template_find_field(template, gensym("y"), &yonset, | ||
2339 | &type, &arraytype) || type != DT_FLOAT) | ||
2340 | error("%s: needs floating-point 'y' field", | ||
2341 | x->x_templatesym->s_name); | ||
2342 | else if (argc < 2) return; | ||
2343 | else | ||
2344 | { | ||
2345 | int firstindex = atom_getfloat(argv); | ||
2346 | argc--; | ||
2347 | argv++; | ||
2348 | /* drop negative x values */ | ||
2349 | if (firstindex < 0) | ||
2350 | { | ||
2351 | argc += firstindex; | ||
2352 | argv -= firstindex; | ||
2353 | firstindex = 0; | ||
2354 | if (argc <= 0) return; | ||
2355 | } | ||
2356 | if (argc + firstindex > x->x_n) | ||
2357 | { | ||
2358 | argc = x->x_n - firstindex; | ||
2359 | if (argc <= 0) return; | ||
2360 | } | ||
2361 | for (i = 0; i < argc; i++) | ||
2362 | *(t_sample *)((x->x_vec + sizeof(t_word) * (i + firstindex)) + yonset) = | ||
2363 | ftofix(atom_getfloat(argv + i)); | ||
2364 | } | ||
2365 | garray_redraw(x); | ||
2366 | } | ||
2367 | |||
2368 | /* forward a "bounds" message to the owning graph */ | ||
2369 | static void garray_bounds(t_garray *x, t_floatarg x1, t_floatarg y1, | ||
2370 | t_floatarg x2, t_floatarg y2) | ||
2371 | { | ||
2372 | vmess(&x->x_glist->gl_pd, gensym("bounds"), "ffff", x1, y1, x2, y2); | ||
2373 | } | ||
2374 | |||
2375 | /* same for "xticks", etc */ | ||
2376 | static void garray_xticks(t_garray *x, | ||
2377 | t_floatarg point, t_floatarg inc, t_floatarg f) | ||
2378 | { | ||
2379 | vmess(&x->x_glist->gl_pd, gensym("xticks"), "fff", point, inc, f); | ||
2380 | } | ||
2381 | |||
2382 | static void garray_yticks(t_garray *x, | ||
2383 | t_floatarg point, t_floatarg inc, t_floatarg f) | ||
2384 | { | ||
2385 | vmess(&x->x_glist->gl_pd, gensym("yticks"), "fff", point, inc, f); | ||
2386 | } | ||
2387 | |||
2388 | static void garray_xlabel(t_garray *x, t_symbol *s, int argc, t_atom *argv) | ||
2389 | { | ||
2390 | typedmess(&x->x_glist->gl_pd, s, argc, argv); | ||
2391 | } | ||
2392 | |||
2393 | static void garray_ylabel(t_garray *x, t_symbol *s, int argc, t_atom *argv) | ||
2394 | { | ||
2395 | typedmess(&x->x_glist->gl_pd, s, argc, argv); | ||
2396 | } | ||
2397 | /* change the name of a garray. */ | ||
2398 | static void garray_rename(t_garray *x, t_symbol *s) | ||
2399 | { | ||
2400 | pd_unbind(&x->x_gobj.g_pd, x->x_realname); | ||
2401 | pd_bind(&x->x_gobj.g_pd, x->x_realname = x->x_name = s); | ||
2402 | garray_redraw(x); | ||
2403 | } | ||
2404 | |||
2405 | static void garray_read(t_garray *x, t_symbol *filename) | ||
2406 | { | ||
2407 | int nelem = x->x_n, filedesc; | ||
2408 | FILE *fd; | ||
2409 | char buf[MAXPDSTRING], *bufptr; | ||
2410 | t_template *template = garray_template(x); | ||
2411 | int yonset, type, i; | ||
2412 | t_symbol *arraytype; | ||
2413 | if (!template_find_field(template, gensym("y"), &yonset, | ||
2414 | &type, &arraytype) || type != DT_FLOAT) | ||
2415 | { | ||
2416 | error("%s: needs floating-point 'y' field", x->x_templatesym->s_name); | ||
2417 | return; | ||
2418 | } | ||
2419 | if ((filedesc = open_via_path( | ||
2420 | canvas_getdir(glist_getcanvas(x->x_glist))->s_name, | ||
2421 | filename->s_name, "", buf, &bufptr, MAXPDSTRING, 0)) < 0 | ||
2422 | || !(fd = fdopen(filedesc, "r"))) | ||
2423 | { | ||
2424 | error("%s: can't open", filename->s_name); | ||
2425 | return; | ||
2426 | } | ||
2427 | for (i = 0; i < nelem; i++) | ||
2428 | { | ||
2429 | if (!fscanf(fd, "%f", (float *)((x->x_vec + sizeof(t_word) * i) + | ||
2430 | yonset))) | ||
2431 | { | ||
2432 | post("%s: read %d elements into table of size %d", | ||
2433 | filename->s_name, i, nelem); | ||
2434 | break; | ||
2435 | } | ||
2436 | } | ||
2437 | while (i < nelem) | ||
2438 | *(float *)((x->x_vec + sizeof(t_word) * i) + yonset) = 0, i++; | ||
2439 | fclose(fd); | ||
2440 | garray_redraw(x); | ||
2441 | } | ||
2442 | |||
2443 | /* this should be renamed and moved... */ | ||
2444 | int garray_ambigendian(void) | ||
2445 | { | ||
2446 | unsigned short s = 1; | ||
2447 | unsigned char c = *(char *)(&s); | ||
2448 | return (c==0); | ||
2449 | } | ||
2450 | |||
2451 | #define BINREADMODE "rb" | ||
2452 | #define BINWRITEMODE "wb" | ||
2453 | |||
2454 | static void garray_read16(t_garray *x, t_symbol *filename, | ||
2455 | t_symbol *endian, t_floatarg fskip) | ||
2456 | { | ||
2457 | int skip = fskip, filedesc; | ||
2458 | int i, nelem; | ||
2459 | t_sample *vec; | ||
2460 | FILE *fd; | ||
2461 | char buf[MAXPDSTRING], *bufptr; | ||
2462 | short s; | ||
2463 | int cpubig = garray_ambigendian(), swap = 0; | ||
2464 | char c = endian->s_name[0]; | ||
2465 | if (c == 'b') | ||
2466 | { | ||
2467 | if (!cpubig) swap = 1; | ||
2468 | } | ||
2469 | else if (c == 'l') | ||
2470 | { | ||
2471 | if (cpubig) swap = 1; | ||
2472 | } | ||
2473 | else if (c) | ||
2474 | { | ||
2475 | error("array_read16: endianness is 'l' (low byte first ala INTEL)"); | ||
2476 | post("... or 'b' (high byte first ala MIPS,DEC,PPC)"); | ||
2477 | } | ||
2478 | if (!garray_getfloatarray(x, &nelem, &vec)) | ||
2479 | { | ||
2480 | error("%s: not a float array", x->x_templatesym->s_name); | ||
2481 | return; | ||
2482 | } | ||
2483 | if ((filedesc = open_via_path( | ||
2484 | canvas_getdir(glist_getcanvas(x->x_glist))->s_name, | ||
2485 | filename->s_name, "", buf, &bufptr, MAXPDSTRING, 1)) < 0 | ||
2486 | || !(fd = fdopen(filedesc, BINREADMODE))) | ||
2487 | { | ||
2488 | error("%s: can't open", filename->s_name); | ||
2489 | return; | ||
2490 | } | ||
2491 | if (skip) | ||
2492 | { | ||
2493 | long pos = fseek(fd, (long)skip, SEEK_SET); | ||
2494 | if (pos < 0) | ||
2495 | { | ||
2496 | error("%s: can't seek to byte %d", buf, skip); | ||
2497 | fclose(fd); | ||
2498 | return; | ||
2499 | } | ||
2500 | } | ||
2501 | |||
2502 | for (i = 0; i < nelem; i++) | ||
2503 | { | ||
2504 | if (fread(&s, sizeof(s), 1, fd) < 1) | ||
2505 | { | ||
2506 | post("%s: read %d elements into table of size %d", | ||
2507 | filename->s_name, i, nelem); | ||
2508 | break; | ||
2509 | } | ||
2510 | if (swap) s = ((s & 0xff) << 8) | ((s & 0xff00) >> 8); | ||
2511 | vec[i] = s * (1./32768.); | ||
2512 | } | ||
2513 | while (i < nelem) vec[i++] = 0; | ||
2514 | fclose(fd); | ||
2515 | garray_redraw(x); | ||
2516 | } | ||
2517 | |||
2518 | static void garray_write(t_garray *x, t_symbol *filename) | ||
2519 | { | ||
2520 | FILE *fd; | ||
2521 | char buf[MAXPDSTRING]; | ||
2522 | t_template *template = garray_template(x); | ||
2523 | int yonset, type, i; | ||
2524 | t_symbol *arraytype; | ||
2525 | if (!template_find_field(template, gensym("y"), &yonset, | ||
2526 | &type, &arraytype) || type != DT_FLOAT) | ||
2527 | { | ||
2528 | error("%s: needs floating-point 'y' field", x->x_templatesym->s_name); | ||
2529 | return; | ||
2530 | } | ||
2531 | canvas_makefilename(glist_getcanvas(x->x_glist), filename->s_name, | ||
2532 | buf, MAXPDSTRING); | ||
2533 | sys_bashfilename(buf, buf); | ||
2534 | if (!(fd = fopen(buf, "w"))) | ||
2535 | { | ||
2536 | error("%s: can't create", buf); | ||
2537 | return; | ||
2538 | } | ||
2539 | for (i = 0; i < x->x_n; i++) | ||
2540 | { | ||
2541 | if (fprintf(fd, "%g\n", | ||
2542 | *(float *)((x->x_vec + sizeof(t_word) * i) + yonset)) < 1) | ||
2543 | { | ||
2544 | post("%s: write error", filename->s_name); | ||
2545 | break; | ||
2546 | } | ||
2547 | } | ||
2548 | fclose(fd); | ||
2549 | } | ||
2550 | |||
2551 | static unsigned char waveheader[] = { | ||
2552 | 0x52, 0x49, 0x46, 0x46, | ||
2553 | 0x00, 0x00, 0x00, 0x00, | ||
2554 | 0x57, 0x41, 0x56, 0x45, | ||
2555 | 0x66, 0x6d, 0x74, 0x20, | ||
2556 | |||
2557 | 0x10, 0x00, 0x00, 0x00, | ||
2558 | 0x01, 0x00, 0x01, 0x00, | ||
2559 | 0x44, 0xac, 0x00, 0x00, | ||
2560 | 0x88, 0x58, 0x01, 0x00, | ||
2561 | |||
2562 | 0x02, 0x00, 0x10, 0x00, | ||
2563 | 0x64, 0x61, 0x74, 0x61, | ||
2564 | 0x00, 0x00, 0x00, 0x00, | ||
2565 | }; | ||
2566 | |||
2567 | /* wave format only so far */ | ||
2568 | static void garray_write16(t_garray *x, t_symbol *filename, t_symbol *format) | ||
2569 | { | ||
2570 | t_template *template = garray_template(x); | ||
2571 | int yonset, type, i; | ||
2572 | t_symbol *arraytype; | ||
2573 | FILE *fd; | ||
2574 | int aiff = (format == gensym("aiff")); | ||
2575 | char filenamebuf[MAXPDSTRING], buf2[MAXPDSTRING]; | ||
2576 | int swap = garray_ambigendian(); /* wave is only little endian */ | ||
2577 | int intbuf; | ||
2578 | strncpy(filenamebuf, filename->s_name, MAXPDSTRING-10); | ||
2579 | filenamebuf[MAXPDSTRING-10] = 0; | ||
2580 | if (sizeof(int) != 4) post("write16: only works on 32-bit machines"); | ||
2581 | if (aiff) | ||
2582 | { | ||
2583 | if (strcmp(filenamebuf + strlen(filenamebuf)-5, ".aiff")) | ||
2584 | strcat(filenamebuf, ".aiff"); | ||
2585 | } | ||
2586 | else | ||
2587 | { | ||
2588 | if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".wav")) | ||
2589 | strcat(filenamebuf, ".wav"); | ||
2590 | } | ||
2591 | if (!template_find_field(template, gensym("y"), &yonset, | ||
2592 | &type, &arraytype) || type != DT_FLOAT) | ||
2593 | { | ||
2594 | error("%s: needs floating-point 'y' field", x->x_templatesym->s_name); | ||
2595 | return; | ||
2596 | } | ||
2597 | canvas_makefilename(glist_getcanvas(x->x_glist), filenamebuf, | ||
2598 | buf2, MAXPDSTRING); | ||
2599 | sys_bashfilename(buf2, buf2); | ||
2600 | if (!(fd = fopen(buf2, BINWRITEMODE))) | ||
2601 | { | ||
2602 | error("%s: can't create", buf2); | ||
2603 | return; | ||
2604 | } | ||
2605 | intbuf = 2 * x->x_n + 36; | ||
2606 | if (swap) | ||
2607 | { | ||
2608 | unsigned char *foo = (unsigned char *)&intbuf, xxx; | ||
2609 | xxx = foo[0]; foo[0] = foo[3]; foo[3] = xxx; | ||
2610 | xxx = foo[1]; foo[1] = foo[2]; foo[2] = xxx; | ||
2611 | } | ||
2612 | memcpy((void *)(waveheader + 4), (void *)(&intbuf), 4); | ||
2613 | intbuf = 2 * x->x_n; | ||
2614 | if (swap) | ||
2615 | { | ||
2616 | unsigned char *foo = (unsigned char *)&intbuf, xxx; | ||
2617 | xxx = foo[0]; foo[0] = foo[3]; foo[3] = xxx; | ||
2618 | xxx = foo[1]; foo[1] = foo[2]; foo[2] = xxx; | ||
2619 | } | ||
2620 | memcpy((void *)(waveheader + 40), (void *)(&intbuf), 4); | ||
2621 | if (fwrite(waveheader, sizeof(waveheader), 1, fd) < 1) | ||
2622 | { | ||
2623 | post("%s: write error", buf2); | ||
2624 | goto closeit; | ||
2625 | } | ||
2626 | for (i = 0; i < x->x_n; i++) | ||
2627 | { | ||
2628 | float f = 32767. * *(float *)((x->x_vec + sizeof(t_word) * i) + yonset); | ||
2629 | short sh; | ||
2630 | if (f < -32768) f = -32768; | ||
2631 | else if (f > 32767) f = 32767; | ||
2632 | sh = f; | ||
2633 | if (swap) | ||
2634 | { | ||
2635 | unsigned char *foo = (unsigned char *)&sh, xxx; | ||
2636 | xxx = foo[0]; foo[0] = foo[1]; foo[1] = xxx; | ||
2637 | } | ||
2638 | if (fwrite(&sh, sizeof(sh), 1, fd) < 1) | ||
2639 | { | ||
2640 | post("%s: write error", buf2); | ||
2641 | goto closeit; | ||
2642 | } | ||
2643 | } | ||
2644 | closeit: | ||
2645 | fclose(fd); | ||
2646 | } | ||
2647 | |||
2648 | void garray_resize(t_garray *x, t_floatarg f) | ||
2649 | { | ||
2650 | int was = x->x_n, elemsize; | ||
2651 | t_glist *gl; | ||
2652 | int dspwas; | ||
2653 | int n = f; | ||
2654 | char *nvec; | ||
2655 | |||
2656 | if (n < 1) n = 1; | ||
2657 | elemsize = template_findbyname(x->x_templatesym)->t_n * sizeof(t_word); | ||
2658 | nvec = t_resizebytes(x->x_vec, was * elemsize, n * elemsize); | ||
2659 | if (!nvec) | ||
2660 | { | ||
2661 | pd_error(x, "array resize failed: out of memory"); | ||
2662 | return; | ||
2663 | } | ||
2664 | x->x_vec = nvec; | ||
2665 | /* LATER should check t_resizebytes result */ | ||
2666 | if (n > was) | ||
2667 | memset(x->x_vec + was*elemsize, | ||
2668 | 0, (n - was) * elemsize); | ||
2669 | x->x_n = n; | ||
2670 | |||
2671 | /* if this is the only array in the graph, | ||
2672 | reset the graph's coordinates */ | ||
2673 | gl = x->x_glist; | ||
2674 | if (gl->gl_list == &x->x_gobj && !x->x_gobj.g_next) | ||
2675 | { | ||
2676 | vmess(&gl->gl_pd, gensym("bounds"), "ffff", | ||
2677 | 0., gl->gl_y1, (double)(n > 1 ? n-1 : 1), gl->gl_y2); | ||
2678 | /* close any dialogs that might have the wrong info now... */ | ||
2679 | gfxstub_deleteforkey(gl); | ||
2680 | } | ||
2681 | else garray_redraw(x); | ||
2682 | if (x->x_usedindsp) canvas_update_dsp(); | ||
2683 | } | ||
2684 | |||
2685 | static void garray_print(t_garray *x) | ||
2686 | { | ||
2687 | post("garray %s: template %s, length %d", | ||
2688 | x->x_name->s_name, x->x_templatesym->s_name, x->x_n); | ||
2689 | } | ||
2690 | |||
2691 | void g_array_setup(void) | ||
2692 | { | ||
2693 | garray_class = class_new(gensym("array"), 0, (t_method)garray_free, | ||
2694 | sizeof(t_garray), CLASS_GOBJ, 0); | ||
2695 | class_setwidget(garray_class, &garray_widgetbehavior); | ||
2696 | class_addmethod(garray_class, (t_method)garray_const, gensym("const"), | ||
2697 | A_DEFFLOAT, A_NULL); | ||
2698 | class_addlist(garray_class, garray_list); | ||
2699 | class_addmethod(garray_class, (t_method)garray_bounds, gensym("bounds"), | ||
2700 | A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL); | ||
2701 | class_addmethod(garray_class, (t_method)garray_xticks, gensym("xticks"), | ||
2702 | A_FLOAT, A_FLOAT, A_FLOAT, 0); | ||
2703 | class_addmethod(garray_class, (t_method)garray_xlabel, gensym("xlabel"), | ||
2704 | A_GIMME, 0); | ||
2705 | class_addmethod(garray_class, (t_method)garray_yticks, gensym("yticks"), | ||
2706 | A_FLOAT, A_FLOAT, A_FLOAT, 0); | ||
2707 | class_addmethod(garray_class, (t_method)garray_ylabel, gensym("ylabel"), | ||
2708 | A_GIMME, 0); | ||
2709 | class_addmethod(garray_class, (t_method)garray_rename, gensym("rename"), | ||
2710 | A_SYMBOL, 0); | ||
2711 | class_addmethod(garray_class, (t_method)garray_read, gensym("read"), | ||
2712 | A_SYMBOL, A_NULL); | ||
2713 | class_addmethod(garray_class, (t_method)garray_read16, gensym("read16"), | ||
2714 | A_SYMBOL, A_DEFFLOAT, A_DEFSYM, A_NULL); | ||
2715 | class_addmethod(garray_class, (t_method)garray_write, gensym("write"), | ||
2716 | A_SYMBOL, A_NULL); | ||
2717 | class_addmethod(garray_class, (t_method)garray_write16, gensym("write16"), | ||
2718 | A_SYMBOL, A_DEFSYM, A_NULL); | ||
2719 | class_addmethod(garray_class, (t_method)garray_resize, gensym("resize"), | ||
2720 | A_FLOAT, A_NULL); | ||
2721 | class_addmethod(garray_class, (t_method)garray_print, gensym("print"), | ||
2722 | A_NULL); | ||
2723 | class_addmethod(garray_class, (t_method)garray_sinesum, gensym("sinesum"), | ||
2724 | A_GIMME, 0); | ||
2725 | class_addmethod(garray_class, (t_method)garray_cosinesum, | ||
2726 | gensym("cosinesum"), A_GIMME, 0); | ||
2727 | class_addmethod(garray_class, (t_method)garray_normalize, | ||
2728 | gensym("normalize"), A_DEFFLOAT, 0); | ||
2729 | class_addmethod(garray_class, (t_method)garray_arraydialog, | ||
2730 | gensym("arraydialog"), A_SYMBOL, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL); | ||
2731 | class_setsavefn(garray_class, garray_save); | ||
2732 | } | ||
2733 | |||
2734 | |||