summaryrefslogtreecommitdiff
path: root/apps/plugins/pdbox/PDa/src/d_ugen.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/d_ugen.c')
-rw-r--r--apps/plugins/pdbox/PDa/src/d_ugen.c1126
1 files changed, 0 insertions, 1126 deletions
diff --git a/apps/plugins/pdbox/PDa/src/d_ugen.c b/apps/plugins/pdbox/PDa/src/d_ugen.c
index 9820f190cc..2c359c384d 100644
--- a/apps/plugins/pdbox/PDa/src/d_ugen.c
+++ b/apps/plugins/pdbox/PDa/src/d_ugen.c
@@ -1124,1129 +1124,3 @@ void d_ugen_setup(void) /* really just block_setup */
1124 class_addfloat(block_class, block_float); 1124 class_addfloat(block_class, block_float);
1125} 1125}
1126 1126
1127/* Copyright (c) 1997-1999 Miller Puckette.
1128* For information on usage and redistribution, and for a DISCLAIMER OF ALL
1129* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
1130
1131/* These routines build a copy of the DSP portion of a graph, which is
1132 then sorted into a linear list of DSP operations which are added to
1133 the DSP duty cycle called by the scheduler. Once that's been done,
1134 we delete the copy. The DSP objects are represented by "ugenbox"
1135 structures which are parallel to the DSP objects in the graph and
1136 have vectors of siginlets and sigoutlets which record their
1137 interconnections.
1138*/
1139
1140/* hacked to run subpatches with different samplerates
1141 * only samplerates that are a power_of_2-multiple of the
1142 *
1143 * mfg.gfd.uil
1144 * IOhannes
1145 *
1146 * edited lines are marked with "IOhannes"
1147 *
1148 */
1149
1150
1151#include "m_pd.h"
1152#include "m_imp.h"
1153#include <stdlib.h>
1154#include <stdarg.h>
1155
1156extern t_class *vinlet_class, *voutlet_class, *canvas_class;
1157t_sample *obj_findsignalscalar(t_object *x, int m);
1158static int ugen_loud;
1159EXTERN_STRUCT _vinlet;
1160EXTERN_STRUCT _voutlet;
1161
1162void vinlet_dspprolog(struct _vinlet *x, t_signal **parentsigs,
1163 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
1164 int switched);
1165void voutlet_dspprolog(struct _voutlet *x, t_signal **parentsigs,
1166 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
1167 int switched);
1168void voutlet_dspepilog(struct _voutlet *x, t_signal **parentsigs,
1169 int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
1170 int switched);
1171
1172t_int *zero_perform(t_int *w) /* zero out a vector */
1173{
1174 t_float *out = (t_float *)(w[1]);
1175 int n = (int)(w[2]);
1176 while (n--) *out++ = 0;
1177 return (w+3);
1178}
1179
1180t_int *zero_perf8(t_int *w)
1181{
1182 t_float *out = (t_float *)(w[1]);
1183 int n = (int)(w[2]);
1184
1185 for (; n; n -= 8, out += 8)
1186 {
1187 out[0] = 0;
1188 out[1] = 0;
1189 out[2] = 0;
1190 out[3] = 0;
1191 out[4] = 0;
1192 out[5] = 0;
1193 out[6] = 0;
1194 out[7] = 0;
1195 }
1196 return (w+3);
1197}
1198
1199void dsp_add_zero(t_sample *out, int n)
1200{
1201 if (n&7)
1202 dsp_add(zero_perform, 2, out, n);
1203 else
1204 dsp_add(zero_perf8, 2, out, n);
1205}
1206
1207/* ---------------------------- block~ ----------------------------- */
1208
1209/* The "block~ object maintains the containing canvas's DSP computation,
1210calling it at a super- or sub-multiple of the containing canvas's
1211calling frequency. The block~'s creation arguments specify block size
1212and overlap. Block~ does no "dsp" computation in its own right, but it
1213adds prolog and epilog code before and after the canvas's unit generators.
1214
1215A subcanvas need not have a block~ at all; if there's none, its
1216ugens are simply put on the list without any prolog or epilog code.
1217
1218Block~ may be invoked as switch~, in which case it also acts to switch the
1219subcanvas on and off. The overall order of scheduling for a subcanvas
1220is thus,
1221
1222 inlet and outlet prologue code (1)
1223 block prologue (2)
1224 the objects in the subcanvas, including inlets and outlets
1225 block epilogue (2)
1226 outlet epilogue code (2)
1227
1228where (1) means, "if reblocked" and (2) means, "if reblocked or switched".
1229
1230If we're reblocked, the inlet prolog and outlet epilog code takes care of
1231overlapping and buffering to deal with vector size changes. If we're switched
1232but not reblocked, the inlet prolog is not needed, and the output epilog is
1233ONLY run when the block is switched off; in this case the epilog code simply
1234copies zeros to all signal outlets.
1235*/
1236
1237static int dsp_phase;
1238static t_class *block_class;
1239
1240typedef struct _block
1241{
1242 t_object x_obj;
1243 int x_vecsize;
1244 int x_overlap;
1245 int x_phase; /* from 0 to period-1; when zero we run the block */
1246 int x_period; /* submultiple of containing canvas */
1247 int x_frequency; /* supermultiple of comtaining canvas */
1248 int x_count;
1249 int x_blocklength; /* length of dspchain for this block */
1250 int x_epiloglength; /* length of epilog */
1251 char x_switched; /* true if we're acting as a a switch */
1252 char x_switchon; /* true if we're switched on */
1253 char x_reblock; /* true if inlets and outlets are reblocking */
1254 int x_upsample; /* IOhannes: upsampling-factor */
1255 int x_downsample; /* IOhannes: downsampling-factor */
1256
1257} t_block;
1258
1259static void block_set(t_block *x, t_floatarg fvecsize, t_floatarg foverlap,
1260 t_floatarg fupsample);
1261
1262static void *block_new(t_floatarg fvecsize, t_floatarg foverlap,
1263 t_floatarg fupsample) /* IOhannes */
1264{
1265 t_block *x = (t_block *)pd_new(block_class);
1266 x->x_phase = 0;
1267 x->x_period = 1;
1268 x->x_frequency = 1;
1269 x->x_switched = 0;
1270 x->x_switchon = 1;
1271 block_set(x, fvecsize, foverlap, fupsample);
1272 return (x);
1273}
1274
1275static void block_set(t_block *x, t_floatarg fvecsize, t_floatarg foverlap,
1276 t_floatarg fupsample)
1277{
1278 int upsample, downsample; /* IOhannes */
1279 int vecsize = fvecsize;
1280 int overlap = foverlap;
1281 int dspstate = canvas_suspend_dsp();
1282 if (overlap < 1)
1283 overlap = 1;
1284 if (vecsize < 0)
1285 vecsize = 0; /* this means we'll get it from parent later. */
1286
1287 /* IOhannes { */
1288 if (fupsample <= 0) upsample = downsample = 1;
1289 else if (fupsample >= 1) {
1290 upsample = fupsample;
1291 downsample = 1;
1292 } else {
1293 downsample = 1.0 / fupsample;
1294 upsample = 1;
1295 }
1296 /* } IOhannes */
1297
1298 if (vecsize && (vecsize != (1 << ilog2(vecsize))))
1299 {
1300 pd_error(x, "block~: vector size not a power of 2");
1301 vecsize = 64;
1302 }
1303 if (overlap != (1 << ilog2(overlap)))
1304 {
1305 pd_error(x, "block~: overlap not a power of 2");
1306 overlap = 1;
1307 }
1308 /* IOhannes { */
1309 if (downsample != (1 << ilog2(downsample)))
1310 {
1311 pd_error(x, "block~: downsampling not a power of 2");
1312 downsample = 1;
1313 }
1314 if (upsample != (1 << ilog2(upsample)))
1315 {
1316 pd_error(x, "block~: upsampling not a power of 2");
1317 upsample = 1;
1318 }
1319 /* } IOhannes */
1320
1321
1322 x->x_vecsize = vecsize;
1323 x->x_overlap = overlap;
1324 /* IOhannes { */
1325 x->x_upsample = upsample;
1326 x->x_downsample = downsample;
1327 /* } IOhannes */
1328 canvas_resume_dsp(dspstate);
1329}
1330
1331static void *switch_new(t_floatarg fvecsize, t_floatarg foverlap,
1332 t_floatarg fupsample) /* IOhannes */
1333{
1334 t_block *x = (t_block *)(block_new(fvecsize, foverlap, fupsample)); /* IOhannes */
1335 x->x_switched = 1;
1336 x->x_switchon = 0;
1337 return (x);
1338}
1339
1340static void block_float(t_block *x, t_floatarg f)
1341{
1342 if (x->x_switched)
1343 x->x_switchon = (f != 0);
1344}
1345#define PROLOGCALL 2
1346#define EPILOGCALL 2
1347
1348static t_int *block_prolog(t_int *w)
1349{
1350 t_block *x = (t_block *)w[1];
1351 int phase = x->x_phase;
1352 /* if we're switched off, jump past the epilog code */
1353 if (!x->x_switchon)
1354 return (w + x->x_blocklength);
1355 if (phase)
1356 {
1357 phase++;
1358 if (phase == x->x_period) phase = 0;
1359 x->x_phase = phase;
1360 return (w + x->x_blocklength); /* skip block; jump past epilog */
1361 }
1362 else
1363 {
1364 x->x_count = x->x_frequency;
1365 x->x_phase = (x->x_period > 1 ? 1 : 0);
1366 return (w + PROLOGCALL); /* beginning of block is next ugen */
1367 }
1368}
1369
1370static t_int *block_epilog(t_int *w)
1371{
1372 t_block *x = (t_block *)w[1];
1373 int count = x->x_count - 1;
1374 if (!x->x_reblock)
1375 return (w + x->x_epiloglength + EPILOGCALL);
1376 if (count)
1377 {
1378 x->x_count = count;
1379 return (w - (x->x_blocklength -
1380 (PROLOGCALL + EPILOGCALL))); /* go to ugen after prolog */
1381 }
1382 else return (w + EPILOGCALL);
1383}
1384
1385static void block_dsp(t_block *x, t_signal **sp)
1386{
1387 /* do nothing here */
1388}
1389
1390/* ------------------ DSP call list ----------------------- */
1391
1392static t_int *dsp_chain;
1393static int dsp_chainsize;
1394
1395void dsp_add(t_perfroutine f, int n, ...)
1396{
1397 int newsize = dsp_chainsize + n+1, i;
1398 va_list ap;
1399
1400 dsp_chain = t_resizebytes(dsp_chain, dsp_chainsize * sizeof (t_int),
1401 newsize * sizeof (t_int));
1402 dsp_chain[dsp_chainsize-1] = (t_int)f;
1403 va_start(ap, n);
1404 for (i = 0; i < n; i++)
1405 dsp_chain[dsp_chainsize + i] = va_arg(ap, t_int);
1406 va_end(ap);
1407 dsp_chain[newsize-1] = 0;
1408 dsp_chainsize = newsize;
1409}
1410
1411 /* at Guenter's suggestion, here's a vectorized version */
1412void dsp_addv(t_perfroutine f, int n, t_int *vec)
1413{
1414 int newsize = dsp_chainsize + n+1, i;
1415
1416 dsp_chain = t_resizebytes(dsp_chain, dsp_chainsize * sizeof (t_int),
1417 newsize * sizeof (t_int));
1418 dsp_chain[dsp_chainsize-1] = (t_int)f;
1419 for (i = 0; i < n; i++)
1420 dsp_chain[dsp_chainsize + i] = vec[i];
1421 dsp_chain[newsize-1] = 0;
1422 dsp_chainsize = newsize;
1423}
1424
1425void dsp_tick(void)
1426{
1427 if (dsp_chain)
1428 {
1429 t_int *ip;
1430 for (ip = dsp_chain; *ip; ) ip = (*(t_perfroutine)(*ip))(ip);
1431 dsp_phase++;
1432 }
1433}
1434
1435/* ---------------- signals ---------------------------- */
1436
1437int ilog2(int n)
1438{
1439 int r = -1;
1440 if (n <= 0) return(0);
1441 while (n)
1442 {
1443 r++;
1444 n >>= 1;
1445 }
1446 return (r);
1447}
1448
1449 /* list of signals which can be reused, sorted by buffer size */
1450static t_signal *signal_freelist[MAXLOGSIG+1];
1451 /* list of reusable "borrowed" signals (which don't own sample buffers) */
1452static t_signal *signal_freeborrowed;
1453 /* list of all signals allocated (not including "borrowed" ones) */
1454static t_signal *signal_usedlist;
1455
1456 /* call this when DSP is stopped to free all the signals */
1457void signal_cleanup(void)
1458{
1459 t_signal **svec, *sig, *sig2;
1460 int i;
1461 while (sig = signal_usedlist)
1462 {
1463 signal_usedlist = sig->s_nextused;
1464 if (!sig->s_isborrowed)
1465 t_freebytes(sig->s_vec, sig->s_n * sizeof (*sig->s_vec));
1466 t_freebytes(sig, sizeof *sig);
1467 }
1468 for (i = 0; i <= MAXLOGSIG; i++)
1469 signal_freelist[i] = 0;
1470 signal_freeborrowed = 0;
1471}
1472
1473 /* mark the signal "reusable." */
1474void signal_makereusable(t_signal *sig)
1475{
1476 int logn = ilog2(sig->s_n);
1477#if 1
1478 t_signal *s5;
1479 for (s5 = signal_freeborrowed; s5; s5 = s5->s_nextfree)
1480 {
1481 if (s5 == sig)
1482 {
1483 bug("signal_free 3");
1484 return;
1485 }
1486 }
1487 for (s5 = signal_freelist[logn]; s5; s5 = s5->s_nextfree)
1488 {
1489 if (s5 == sig)
1490 {
1491 bug("signal_free 4");
1492 return;
1493 }
1494 }
1495#endif
1496 if (ugen_loud) post("free %x: %d", sig, sig->s_isborrowed);
1497 if (sig->s_isborrowed)
1498 {
1499 /* if the signal is borrowed, decrement the borrowed-from signal's
1500 reference count, possibly marking it reusable too */
1501 t_signal *s2 = sig->s_borrowedfrom;
1502 if ((s2 == sig) || !s2)
1503 bug("signal_free");
1504 s2->s_refcount--;
1505 if (!s2->s_refcount)
1506 signal_makereusable(s2);
1507 sig->s_nextfree = signal_freeborrowed;
1508 signal_freeborrowed = sig;
1509 }
1510 else
1511 {
1512 /* if it's a real signal (not borrowed), put it on the free list
1513 so we can reuse it. */
1514 if (signal_freelist[logn] == sig) bug("signal_free 2");
1515 sig->s_nextfree = signal_freelist[logn];
1516 signal_freelist[logn] = sig;
1517 }
1518}
1519
1520 /* reclaim or make an audio signal. If n is zero, return a "borrowed"
1521 signal whose buffer and size will be obtained later via
1522 signal_setborrowed(). */
1523
1524t_signal *signal_new(int n, float sr)
1525{
1526 int logn, n2;
1527 t_signal *ret, **whichlist;
1528 t_sample *fp;
1529 logn = ilog2(n);
1530 if (n)
1531 {
1532 if (n != (1 << logn))
1533 bug("signal buffer not a power of 2");
1534 if (logn > MAXLOGSIG)
1535 bug("signal buffer too large");
1536 whichlist = signal_freelist + logn;
1537 }
1538 else
1539 whichlist = &signal_freeborrowed;
1540
1541 /* first try to reclaim one from the free list */
1542 if (ret = *whichlist)
1543 *whichlist = ret->s_nextfree;
1544 else
1545 {
1546 /* LATER figure out what to do for out-of-space here! */
1547 ret = (t_signal *)t_getbytes(sizeof *ret);
1548 if (n)
1549 {
1550 ret->s_vec = (t_sample *)getbytes(n * sizeof (*ret->s_vec));
1551 ret->s_isborrowed = 0;
1552 }
1553 else
1554 {
1555 ret->s_vec = 0;
1556 ret->s_isborrowed = 1;
1557 }
1558 ret->s_nextused = signal_usedlist;
1559 signal_usedlist = ret;
1560 }
1561 ret->s_n = n;
1562 ret->s_sr = sr;
1563 ret->s_refcount = 0;
1564 ret->s_borrowedfrom = 0;
1565 if (ugen_loud) post("new %x: %d", ret, ret->s_isborrowed);
1566 return (ret);
1567}
1568
1569static t_signal *signal_newlike(const t_signal *sig)
1570{
1571 return (signal_new(sig->s_n, sig->s_sr));
1572}
1573
1574void signal_setborrowed(t_signal *sig, t_signal *sig2)
1575{
1576 if (!sig->s_isborrowed || sig->s_borrowedfrom)
1577 bug("signal_setborrowed");
1578 if (sig == sig2)
1579 bug("signal_setborrowed 2");
1580 sig->s_borrowedfrom = sig2;
1581 sig->s_vec = sig2->s_vec;
1582 sig->s_n = sig2->s_n;
1583}
1584
1585int signal_compatible(t_signal *s1, t_signal *s2)
1586{
1587 return (s1->s_n == s2->s_n && s1->s_sr == s2->s_sr);
1588}
1589
1590/* ------------------ ugen ("unit generator") sorting ----------------- */
1591
1592typedef struct _ugenbox
1593{
1594 struct _siginlet *u_in;
1595 int u_nin;
1596 struct _sigoutlet *u_out;
1597 int u_nout;
1598 int u_phase;
1599 struct _ugenbox *u_next;
1600 t_object *u_obj;
1601 int u_done;
1602} t_ugenbox;
1603
1604typedef struct _siginlet
1605{
1606 int i_nconnect;
1607 int i_ngot;
1608 t_signal *i_signal;
1609} t_siginlet;
1610
1611typedef struct _sigoutconnect
1612{
1613 t_ugenbox *oc_who;
1614 int oc_inno;
1615 struct _sigoutconnect *oc_next;
1616} t_sigoutconnect;
1617
1618typedef struct _sigoutlet
1619{
1620 int o_nconnect;
1621 int o_nsent;
1622 t_signal *o_signal;
1623 t_sigoutconnect *o_connections;
1624} t_sigoutlet;
1625
1626
1627struct _dspcontext
1628{
1629 struct _ugenbox *dc_ugenlist;
1630 struct _dspcontext *dc_parentcontext;
1631 int dc_ninlets;
1632 int dc_noutlets;
1633 t_signal **dc_iosigs;
1634 float dc_srate;
1635 int dc_vecsize;
1636 char dc_toplevel; /* true if "iosigs" is invalid. */
1637 char dc_reblock; /* true if we have to reblock inlets/outlets */
1638 char dc_switched; /* true if we're switched */
1639
1640};
1641
1642#define t_dspcontext struct _dspcontext
1643
1644static int ugen_sortno = 0;
1645static t_dspcontext *ugen_currentcontext;
1646
1647void ugen_stop(void)
1648{
1649 t_signal *s;
1650 int i;
1651 if (dsp_chain)
1652 {
1653 freebytes(dsp_chain, dsp_chainsize * sizeof (t_int));
1654 dsp_chain = 0;
1655 }
1656 signal_cleanup();
1657
1658}
1659
1660void ugen_start(void)
1661{
1662 ugen_stop();
1663 ugen_sortno++;
1664 dsp_chain = (t_int *)getbytes(sizeof(*dsp_chain));
1665 dsp_chain[0] = 0;
1666 dsp_chainsize = 1;
1667 if (ugen_currentcontext) bug("ugen_start");
1668}
1669
1670int ugen_getsortno(void)
1671{
1672 return (ugen_sortno);
1673}
1674
1675#if 0
1676void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
1677{
1678 int i, count;
1679 t_signal *sig;
1680 for (count = 0, sig = signal_usedlist; sig;
1681 count++, sig = sig->s_nextused)
1682 ;
1683 post("used signals %d", count);
1684 for (i = 0; i < MAXLOGSIG; i++)
1685 {
1686 for (count = 0, sig = signal_freelist[i]; sig;
1687 count++, sig = sig->s_nextfree)
1688 ;
1689 if (count)
1690 post("size %d: free %d", (1 << i), count);
1691 }
1692 for (count = 0, sig = signal_freeborrowed; sig;
1693 count++, sig = sig->s_nextfree)
1694 ;
1695 post("free borrowed %d", count);
1696
1697 ugen_loud = argc;
1698}
1699#endif
1700
1701 /* start building the graph for a canvas */
1702t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp,
1703 int ninlets, int noutlets)
1704{
1705 t_dspcontext *dc = (t_dspcontext *)getbytes(sizeof(*dc));
1706 float parent_srate, srate;
1707 int parent_vecsize, vecsize;
1708
1709 if (ugen_loud) post("ugen_start_graph...");
1710
1711 dc->dc_ugenlist = 0;
1712 dc->dc_toplevel = toplevel;
1713 dc->dc_iosigs = sp;
1714 dc->dc_ninlets = ninlets;
1715 dc->dc_noutlets = noutlets;
1716 dc->dc_parentcontext = ugen_currentcontext;
1717 ugen_currentcontext = dc;
1718 return (dc);
1719}
1720
1721 /* first the canvas calls this to create all the boxes... */
1722void ugen_add(t_dspcontext *dc, t_object *obj)
1723{
1724 t_ugenbox *x = (t_ugenbox *)getbytes(sizeof *x);
1725 int i;
1726 t_sigoutlet *uout;
1727 t_siginlet *uin;
1728
1729 x->u_next = dc->dc_ugenlist;
1730 dc->dc_ugenlist = x;
1731 x->u_obj = obj;
1732 x->u_nin = obj_nsiginlets(obj);
1733 x->u_in = getbytes(x->u_nin * sizeof (*x->u_in));
1734 for (uin = x->u_in, i = x->u_nin; i--; uin++)
1735 uin->i_nconnect = 0;
1736 x->u_nout = obj_nsigoutlets(obj);
1737 x->u_out = getbytes(x->u_nout * sizeof (*x->u_out));
1738 for (uout = x->u_out, i = x->u_nout; i--; uout++)
1739 uout->o_connections = 0, uout->o_nconnect = 0;
1740}
1741
1742 /* and then this to make all the connections. */
1743void ugen_connect(t_dspcontext *dc, t_object *x1, int outno, t_object *x2,
1744 int inno)
1745{
1746 t_ugenbox *u1, *u2;
1747 t_sigoutlet *uout;
1748 t_siginlet *uin;
1749 t_sigoutconnect *oc;
1750 int sigoutno = obj_sigoutletindex(x1, outno);
1751 int siginno = obj_siginletindex(x2, inno);
1752 if (ugen_loud)
1753 post("%s -> %s: %d->%d",
1754 class_getname(x1->ob_pd),
1755 class_getname(x2->ob_pd), outno, inno);
1756 for (u1 = dc->dc_ugenlist; u1 && u1->u_obj != x1; u1 = u1->u_next);
1757 for (u2 = dc->dc_ugenlist; u2 && u2->u_obj != x2; u2 = u2->u_next);
1758 if (!u1 || !u2 || siginno < 0)
1759 {
1760 pd_error(u1->u_obj,
1761 "signal outlet connect to nonsignal inlet (ignored)");
1762 return;
1763 }
1764 if (sigoutno < 0 || sigoutno >= u1->u_nout || siginno >= u2->u_nin)
1765 {
1766 bug("ugen_connect %s %s %d %d (%d %d)",
1767 class_getname(x1->ob_pd),
1768 class_getname(x2->ob_pd), sigoutno, siginno, u1->u_nout,
1769 u2->u_nin);
1770 }
1771 uout = u1->u_out + sigoutno;
1772 uin = u2->u_in + siginno;
1773
1774 /* add a new connection to the outlet's list */
1775 oc = (t_sigoutconnect *)getbytes(sizeof *oc);
1776 oc->oc_next = uout->o_connections;
1777 uout->o_connections = oc;
1778 oc->oc_who = u2;
1779 oc->oc_inno = siginno;
1780 /* update inlet and outlet counts */
1781 uout->o_nconnect++;
1782 uin->i_nconnect++;
1783}
1784
1785 /* get the index of a ugenbox or -1 if it's not on the list */
1786static int ugen_index(t_dspcontext *dc, t_ugenbox *x)
1787{
1788 int ret;
1789 t_ugenbox *u;
1790 for (u = dc->dc_ugenlist, ret = 0; u; u = u->u_next, ret++)
1791 if (u == x) return (ret);
1792 return (-1);
1793}
1794
1795 /* put a ugenbox on the chain, recursively putting any others on that
1796 this one might uncover. */
1797static void ugen_doit(t_dspcontext *dc, t_ugenbox *u)
1798{
1799 t_sigoutlet *uout;
1800 t_siginlet *uin;
1801 t_sigoutconnect *oc, *oc2;
1802 t_class *class = pd_class(&u->u_obj->ob_pd);
1803 int i, n;
1804 /* suppress creating new signals for the outputs of signal
1805 inlets and subpatchs; except in the case we're an inlet and "blocking"
1806 is set. We don't yet know if a subcanvas will be "blocking" so there
1807 we delay new signal creation, which will be handled by calling
1808 signal_setborrowed in the ugen_done_graph routine below. */
1809 int nonewsigs = (class == canvas_class ||
1810 (class == vinlet_class) && !(dc->dc_reblock));
1811 /* when we encounter a subcanvas or a signal outlet, suppress freeing
1812 the input signals as they may be "borrowed" for the super or sub
1813 patch; same exception as above, but also if we're "switched" we
1814 have to do a copy rather than a borrow. */
1815 int nofreesigs = (class == canvas_class ||
1816 (class == voutlet_class) && !(dc->dc_reblock || dc->dc_switched));
1817 t_signal **insig, **outsig, **sig, *s1, *s2, *s3;
1818 t_ugenbox *u2;
1819
1820 if (ugen_loud) post("doit %s %d %d", class_getname(class), nofreesigs,
1821 nonewsigs);
1822 for (i = 0, uin = u->u_in; i < u->u_nin; i++, uin++)
1823 {
1824 if (!uin->i_nconnect)
1825 {
1826 t_sample *scalar;
1827 s3 = signal_new(dc->dc_vecsize, dc->dc_srate);
1828 /* post("%s: unconnected signal inlet set to zero",
1829 class_getname(u->u_obj->ob_pd)); */
1830 if (scalar = obj_findsignalscalar(u->u_obj, i))
1831 dsp_add_scalarcopy(scalar, s3->s_vec, s3->s_n);
1832 else
1833 dsp_add_zero(s3->s_vec, s3->s_n);
1834 uin->i_signal = s3;
1835 s3->s_refcount = 1;
1836 }
1837 }
1838 insig = (t_signal **)getbytes((u->u_nin + u->u_nout) * sizeof(t_signal *));
1839 outsig = insig + u->u_nin;
1840 for (sig = insig, uin = u->u_in, i = u->u_nin; i--; sig++, uin++)
1841 {
1842 int newrefcount;
1843 *sig = uin->i_signal;
1844 newrefcount = --(*sig)->s_refcount;
1845 /* if the reference count went to zero, we free the signal now,
1846 unless it's a subcanvas or outlet; these might keep the
1847 signal around to send to objects connected to them. In this
1848 case we increment the reference count; the corresponding decrement
1849 is in sig_makereusable(). */
1850 if (nofreesigs)
1851 (*sig)->s_refcount++;
1852 else if (!newrefcount)
1853 signal_makereusable(*sig);
1854 }
1855 for (sig = outsig, uout = u->u_out, i = u->u_nout; i--; sig++, uout++)
1856 {
1857 /* similarly, for outlets of subcanvases we delay creating
1858 them; instead we create "borrowed" ones so that the refcount
1859 is known. The subcanvas replaces the fake signal with one showing
1860 where the output data actually is, to avoid having to copy it.
1861 For any other object, we just allocate a new output vector;
1862 since we've already freed the inputs the objects might get called
1863 "in place." */
1864 if (nonewsigs)
1865 {
1866 *sig = uout->o_signal =
1867 signal_new(0, dc->dc_srate);
1868 }
1869 else
1870 *sig = uout->o_signal = signal_new(dc->dc_vecsize, dc->dc_srate);
1871 (*sig)->s_refcount = uout->o_nconnect;
1872 }
1873 /* now call the DSP scheduling routine for the ugen. This
1874 routine must fill in "borrowed" signal outputs in case it's either
1875 a subcanvas or a signal inlet. */
1876 mess1(&u->u_obj->ob_pd, gensym("dsp"), insig);
1877
1878 /* if any output signals aren't connected to anyone, free them
1879 now; otherwise they'll either get freed when the reference count
1880 goes back to zero, or even later as explained above. */
1881
1882 for (sig = outsig, uout = u->u_out, i = u->u_nout; i--; sig++, uout++)
1883 {
1884 if (!(*sig)->s_refcount)
1885 signal_makereusable(*sig);
1886 }
1887 if (ugen_loud)
1888 {
1889 if (u->u_nin + u->u_nout == 0) post("put %s %d",
1890 class_getname(u->u_obj->ob_pd), ugen_index(dc, u));
1891 else if (u->u_nin + u->u_nout == 1) post("put %s %d (%x)",
1892 class_getname(u->u_obj->ob_pd), ugen_index(dc, u), sig[0]);
1893 else if (u->u_nin + u->u_nout == 2) post("put %s %d (%x %x)",
1894 class_getname(u->u_obj->ob_pd), ugen_index(dc, u),
1895 sig[0], sig[1]);
1896 else post("put %s %d (%x %x %x ...)",
1897 class_getname(u->u_obj->ob_pd), ugen_index(dc, u),
1898 sig[0], sig[1], sig[2]);
1899 }
1900
1901 /* pass it on and trip anyone whose last inlet was filled */
1902 for (uout = u->u_out, i = u->u_nout; i--; uout++)
1903 {
1904 s1 = uout->o_signal;
1905 for (oc = uout->o_connections; oc; oc = oc->oc_next)
1906 {
1907 u2 = oc->oc_who;
1908 uin = &u2->u_in[oc->oc_inno];
1909 /* if there's already someone here, sum the two */
1910 if (s2 = uin->i_signal)
1911 {
1912 s1->s_refcount--;
1913 s2->s_refcount--;
1914 if (!signal_compatible(s1, s2))
1915 {
1916 pd_error(u->u_obj, "%s: incompatible signal inputs",
1917 class_getname(u->u_obj->ob_pd));
1918 return;
1919 }
1920 s3 = signal_newlike(s1);
1921 dsp_add_plus(s1->s_vec, s2->s_vec, s3->s_vec, s1->s_n);
1922 uin->i_signal = s3;
1923 s3->s_refcount = 1;
1924 if (!s1->s_refcount) signal_makereusable(s1);
1925 if (!s2->s_refcount) signal_makereusable(s2);
1926 }
1927 else uin->i_signal = s1;
1928 uin->i_ngot++;
1929 /* if we didn't fill this inlet don't bother yet */
1930 if (uin->i_ngot < uin->i_nconnect)
1931 goto notyet;
1932 /* if there's more than one, check them all */
1933 if (u2->u_nin > 1)
1934 {
1935 for (uin = u2->u_in, n = u2->u_nin; n--; uin++)
1936 if (uin->i_ngot < uin->i_nconnect) goto notyet;
1937 }
1938 /* so now we can schedule the ugen. */
1939 ugen_doit(dc, u2);
1940 notyet: ;
1941 }
1942 }
1943 t_freebytes(insig,(u->u_nin + u->u_nout) * sizeof(t_signal *));
1944 u->u_done = 1;
1945}
1946
1947 /* once the DSP graph is built, we call this routine to sort it.
1948 This routine also deletes the graph; later we might want to leave the
1949 graph around, in case the user is editing the DSP network, to save having
1950 to recreate it all the time. But not today. */
1951
1952void ugen_done_graph(t_dspcontext *dc)
1953{
1954 t_ugenbox *u, *u2;
1955 t_sigoutlet *uout;
1956 t_siginlet *uin;
1957 t_sigoutconnect *oc, *oc2;
1958 int i, n;
1959 t_block *blk;
1960 t_dspcontext *parent_context = dc->dc_parentcontext;
1961 float parent_srate;
1962 int parent_vecsize;
1963 int period, frequency, phase, vecsize;
1964 float srate;
1965 int chainblockbegin; /* DSP chain onset before block prolog code */
1966 int chainblockend; /* and after block epilog code */
1967 int chainafterall; /* and after signal outlet epilog */
1968 int reblock = 0, switched;
1969 int downsample = 1, upsample = 1; /* IOhannes */
1970 /* debugging printout */
1971
1972 if (ugen_loud)
1973 {
1974 post("ugen_done_graph...");
1975 for (u = dc->dc_ugenlist; u; u = u->u_next)
1976 {
1977 post("ugen: %s", class_getname(u->u_obj->ob_pd));
1978 for (uout = u->u_out, i = 0; i < u->u_nout; uout++, i++)
1979 for (oc = uout->o_connections; oc; oc = oc->oc_next)
1980 {
1981 post("... out %d to %s, index %d, inlet %d", i,
1982 class_getname(oc->oc_who->u_obj->ob_pd),
1983 ugen_index(dc, oc->oc_who), oc->oc_inno);
1984 }
1985 }
1986 }
1987
1988 /* search for an object of class "block~" */
1989 for (u = dc->dc_ugenlist, blk = 0; u; u = u->u_next)
1990 {
1991 t_pd *zz = &u->u_obj->ob_pd;
1992 if (pd_class(zz) == block_class)
1993 {
1994 if (blk)
1995 pd_error(blk, "conflicting block~ objects in same page");
1996 else blk = (t_block *)zz;
1997 }
1998 }
1999
2000 /* figure out block size, calling frequency, sample rate */
2001 if (parent_context)
2002 {
2003 parent_srate = parent_context->dc_srate;
2004 parent_vecsize = parent_context->dc_vecsize;
2005 }
2006 else
2007 {
2008 parent_srate = sys_getsr();
2009 parent_vecsize = sys_getblksize();
2010 }
2011 if (blk)
2012 {
2013 int realoverlap;
2014 vecsize = blk->x_vecsize;
2015 if (vecsize == 0)
2016 vecsize = parent_vecsize;
2017 realoverlap = blk->x_overlap;
2018 if (realoverlap > vecsize) realoverlap = vecsize;
2019 /* IOhannes { */
2020 downsample = blk->x_downsample;
2021 upsample = blk->x_upsample;
2022 if (downsample > parent_vecsize) downsample=parent_vecsize;
2023 period = (vecsize * downsample)/
2024 (parent_vecsize * realoverlap * upsample);
2025 frequency = (parent_vecsize * realoverlap * upsample)/
2026 (vecsize * downsample);
2027 /* } IOhannes*/
2028 phase = blk->x_phase;
2029 srate = parent_srate * realoverlap * upsample / downsample;
2030 /* IOhannes */
2031 if (period < 1) period = 1;
2032 if (frequency < 1) frequency = 1;
2033 blk->x_frequency = frequency;
2034 blk->x_period = period;
2035 blk->x_phase = dsp_phase & (period - 1);
2036 if (! parent_context || (realoverlap != 1) ||
2037 (vecsize != parent_vecsize) ||
2038 (downsample != 1) || (upsample != 1)) /* IOhannes */
2039 reblock = 1;
2040 switched = blk->x_switched;
2041 }
2042 else
2043 {
2044 srate = parent_srate;
2045 vecsize = parent_vecsize;
2046 downsample = upsample = 1;/* IOhannes */
2047 period = frequency = 1;
2048 phase = 0;
2049 if (!parent_context) reblock = 1;
2050 switched = 0;
2051 }
2052 dc->dc_reblock = reblock;
2053 dc->dc_switched = switched;
2054 dc->dc_srate = srate;
2055 dc->dc_vecsize = vecsize;
2056
2057 /* if we're reblocking or switched, we now have to create output
2058 signals to fill in for the "borrowed" ones we have now. This
2059 is also possibly true even if we're not blocked/switched, in
2060 the case that there was a signal loop. But we don't know this
2061 yet. */
2062
2063 if (dc->dc_iosigs && (switched || reblock))
2064 {
2065 t_signal **sigp;
2066 for (i = 0, sigp = dc->dc_iosigs + dc->dc_ninlets; i < dc->dc_noutlets;
2067 i++, sigp++)
2068 {
2069 if ((*sigp)->s_isborrowed && !(*sigp)->s_borrowedfrom)
2070 {
2071 signal_setborrowed(*sigp,
2072 signal_new(parent_vecsize, parent_srate));
2073 (*sigp)->s_refcount++;
2074
2075 if (ugen_loud) post("set %x->%x", *sigp,
2076 (*sigp)->s_borrowedfrom);
2077 }
2078 }
2079 }
2080
2081 if (ugen_loud)
2082 post("reblock %d, switched %d", reblock, switched);
2083
2084 /* schedule prologs for inlets and outlets. If the "reblock" flag
2085 is set, an inlet will put code on the DSP chain to copy its input
2086 into an internal buffer here, before any unit generators' DSP code
2087 gets scheduled. If we don't "reblock", inlets will need to get
2088 pointers to their corresponding inlets/outlets on the box we're inside,
2089 if any. Outlets will also need pointers, unless we're switched, in
2090 which case outlet epilog code will kick in. */
2091
2092 for (u = dc->dc_ugenlist; u; u = u->u_next)
2093 {
2094 t_pd *zz = &u->u_obj->ob_pd;
2095 t_signal **insigs = dc->dc_iosigs, **outsigs = dc->dc_iosigs;
2096 if (outsigs) outsigs += dc->dc_ninlets;
2097
2098 if (pd_class(zz) == vinlet_class)
2099 vinlet_dspprolog((struct _vinlet *)zz,
2100 dc->dc_iosigs, vecsize, dsp_phase, period, frequency,
2101 downsample, upsample, /* IOhannes */
2102 reblock, switched);
2103 else if (pd_class(zz) == voutlet_class)
2104 voutlet_dspprolog((struct _voutlet *)zz,
2105 outsigs, vecsize, dsp_phase, period, frequency,
2106 downsample, upsample, /* IOhannes */
2107 reblock, switched);
2108 }
2109 chainblockbegin = dsp_chainsize;
2110
2111 if (blk && (reblock || switched)) /* add the block DSP prolog */
2112 dsp_add(block_prolog, 1, blk);
2113
2114 /* Initialize for sorting */
2115 for (u = dc->dc_ugenlist; u; u = u->u_next)
2116 {
2117 u->u_done = 0;
2118 for (uout = u->u_out, i = u->u_nout; i--; uout++)
2119 uout->o_nsent = 0;
2120 for (uin = u->u_in, i = u->u_nin; i--; uin++)
2121 uin->i_ngot = 0, uin->i_signal = 0;
2122 }
2123
2124 /* Do the sort */
2125
2126 for (u = dc->dc_ugenlist; u; u = u->u_next)
2127 {
2128 /* check that we have no connected signal inlets */
2129 if (u->u_done) continue;
2130 for (uin = u->u_in, i = u->u_nin; i--; uin++)
2131 if (uin->i_nconnect) goto next;
2132
2133 ugen_doit(dc, u);
2134 next: ;
2135 }
2136
2137 /* check for a DSP loop, which is evidenced here by the presence
2138 of ugens not yet scheduled. */
2139
2140 for (u = dc->dc_ugenlist; u; u = u->u_next)
2141 if (!u->u_done)
2142 {
2143 t_signal **sigp;
2144 pd_error(u->u_obj,
2145 "DSP loop detected (some tilde objects not scheduled)");
2146 /* this might imply that we have unfilled "borrowed" outputs
2147 which we'd better fill in now. */
2148 for (i = 0, sigp = dc->dc_iosigs + dc->dc_ninlets; i < dc->dc_noutlets;
2149 i++, sigp++)
2150 {
2151 if ((*sigp)->s_isborrowed && !(*sigp)->s_borrowedfrom)
2152 {
2153 t_signal *s3 = signal_new(parent_vecsize, parent_srate);
2154 signal_setborrowed(*sigp, s3);
2155 (*sigp)->s_refcount++;
2156 dsp_add_zero(s3->s_vec, s3->s_n);
2157 if (ugen_loud)
2158 post("oops, belatedly set %x->%x", *sigp,
2159 (*sigp)->s_borrowedfrom);
2160 }
2161 }
2162 break; /* don't need to keep looking. */
2163 }
2164
2165 if (blk && (reblock || switched)) /* add block DSP epilog */
2166 dsp_add(block_epilog, 1, blk);
2167 chainblockend = dsp_chainsize;
2168
2169 /* add epilogs for outlets. */
2170
2171 for (u = dc->dc_ugenlist; u; u = u->u_next)
2172 {
2173 t_pd *zz = &u->u_obj->ob_pd;
2174 if (pd_class(zz) == voutlet_class)
2175 {
2176 t_signal **iosigs = dc->dc_iosigs;
2177 if (iosigs) iosigs += dc->dc_ninlets;
2178 voutlet_dspepilog((struct _voutlet *)zz,
2179 iosigs, vecsize, dsp_phase, period, frequency,
2180 downsample, upsample, /* IOhannes */
2181 reblock, switched);
2182 }
2183 }
2184
2185 chainafterall = dsp_chainsize;
2186 if (blk)
2187 {
2188 blk->x_blocklength = chainblockend - chainblockbegin;
2189 blk->x_epiloglength = chainafterall - chainblockend;
2190 blk->x_reblock = reblock;
2191 }
2192
2193 if (ugen_loud)
2194 {
2195 t_int *ip;
2196 if (!dc->dc_parentcontext)
2197 for (i = dsp_chainsize, ip = dsp_chain; i--; ip++)
2198 post("chain %x", *ip);
2199 post("... ugen_done_graph done.");
2200 }
2201 /* now delete everything. */
2202 while (dc->dc_ugenlist)
2203 {
2204 for (uout = dc->dc_ugenlist->u_out, n = dc->dc_ugenlist->u_nout;
2205 n--; uout++)
2206 {
2207 oc = uout->o_connections;
2208 while (oc)
2209 {
2210 oc2 = oc->oc_next;
2211 freebytes(oc, sizeof *oc);
2212 oc = oc2;
2213 }
2214 }
2215 freebytes(dc->dc_ugenlist->u_out, dc->dc_ugenlist->u_nout *
2216 sizeof (*dc->dc_ugenlist->u_out));
2217 freebytes(dc->dc_ugenlist->u_in, dc->dc_ugenlist->u_nin *
2218 sizeof(*dc->dc_ugenlist->u_in));
2219 u = dc->dc_ugenlist;
2220 dc->dc_ugenlist = u->u_next;
2221 freebytes(u, sizeof *u);
2222 }
2223 if (ugen_currentcontext == dc)
2224 ugen_currentcontext = dc->dc_parentcontext;
2225 else bug("ugen_currentcontext");
2226 freebytes(dc, sizeof(*dc));
2227
2228}
2229
2230t_signal *ugen_getiosig(int index, int inout)
2231{
2232 if (!ugen_currentcontext) bug("ugen_getiosig");
2233 if (ugen_currentcontext->dc_toplevel) return (0);
2234 if (inout) index += ugen_currentcontext->dc_ninlets;
2235 return (ugen_currentcontext->dc_iosigs[index]);
2236}
2237
2238
2239/* -------------------- setup routine -------------------------- */
2240
2241void d_ugen_setup(void) /* really just block_setup */
2242{
2243 block_class = class_new(gensym("block~"), (t_newmethod)block_new, 0,
2244 sizeof(t_block), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT/*IOhannes*/, 0);
2245 class_addcreator((t_newmethod)switch_new, gensym("switch~"),
2246 A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT/*IOhannes*/, 0);
2247 class_addmethod(block_class, (t_method)block_set, gensym("set"),
2248 A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
2249 class_addmethod(block_class, (t_method)block_dsp, gensym("dsp"), 0);
2250 class_addfloat(block_class, block_float);
2251}
2252