diff options
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/d_ugen.c')
-rw-r--r-- | apps/plugins/pdbox/PDa/src/d_ugen.c | 1126 |
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 | |||
1156 | extern t_class *vinlet_class, *voutlet_class, *canvas_class; | ||
1157 | t_sample *obj_findsignalscalar(t_object *x, int m); | ||
1158 | static int ugen_loud; | ||
1159 | EXTERN_STRUCT _vinlet; | ||
1160 | EXTERN_STRUCT _voutlet; | ||
1161 | |||
1162 | void 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); | ||
1165 | void 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); | ||
1168 | void 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 | |||
1172 | t_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 | |||
1180 | t_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 | |||
1199 | void 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, | ||
1210 | calling it at a super- or sub-multiple of the containing canvas's | ||
1211 | calling frequency. The block~'s creation arguments specify block size | ||
1212 | and overlap. Block~ does no "dsp" computation in its own right, but it | ||
1213 | adds prolog and epilog code before and after the canvas's unit generators. | ||
1214 | |||
1215 | A subcanvas need not have a block~ at all; if there's none, its | ||
1216 | ugens are simply put on the list without any prolog or epilog code. | ||
1217 | |||
1218 | Block~ may be invoked as switch~, in which case it also acts to switch the | ||
1219 | subcanvas on and off. The overall order of scheduling for a subcanvas | ||
1220 | is 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 | |||
1228 | where (1) means, "if reblocked" and (2) means, "if reblocked or switched". | ||
1229 | |||
1230 | If we're reblocked, the inlet prolog and outlet epilog code takes care of | ||
1231 | overlapping and buffering to deal with vector size changes. If we're switched | ||
1232 | but not reblocked, the inlet prolog is not needed, and the output epilog is | ||
1233 | ONLY run when the block is switched off; in this case the epilog code simply | ||
1234 | copies zeros to all signal outlets. | ||
1235 | */ | ||
1236 | |||
1237 | static int dsp_phase; | ||
1238 | static t_class *block_class; | ||
1239 | |||
1240 | typedef 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 | |||
1259 | static void block_set(t_block *x, t_floatarg fvecsize, t_floatarg foverlap, | ||
1260 | t_floatarg fupsample); | ||
1261 | |||
1262 | static 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 | |||
1275 | static 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 | |||
1331 | static 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 | |||
1340 | static 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 | |||
1348 | static 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 | |||
1370 | static 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 | |||
1385 | static void block_dsp(t_block *x, t_signal **sp) | ||
1386 | { | ||
1387 | /* do nothing here */ | ||
1388 | } | ||
1389 | |||
1390 | /* ------------------ DSP call list ----------------------- */ | ||
1391 | |||
1392 | static t_int *dsp_chain; | ||
1393 | static int dsp_chainsize; | ||
1394 | |||
1395 | void 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 */ | ||
1412 | void 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 | |||
1425 | void 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 | |||
1437 | int 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 */ | ||
1450 | static t_signal *signal_freelist[MAXLOGSIG+1]; | ||
1451 | /* list of reusable "borrowed" signals (which don't own sample buffers) */ | ||
1452 | static t_signal *signal_freeborrowed; | ||
1453 | /* list of all signals allocated (not including "borrowed" ones) */ | ||
1454 | static t_signal *signal_usedlist; | ||
1455 | |||
1456 | /* call this when DSP is stopped to free all the signals */ | ||
1457 | void 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." */ | ||
1474 | void 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 | |||
1524 | t_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 | |||
1569 | static t_signal *signal_newlike(const t_signal *sig) | ||
1570 | { | ||
1571 | return (signal_new(sig->s_n, sig->s_sr)); | ||
1572 | } | ||
1573 | |||
1574 | void 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 | |||
1585 | int 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 | |||
1592 | typedef 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 | |||
1604 | typedef struct _siginlet | ||
1605 | { | ||
1606 | int i_nconnect; | ||
1607 | int i_ngot; | ||
1608 | t_signal *i_signal; | ||
1609 | } t_siginlet; | ||
1610 | |||
1611 | typedef struct _sigoutconnect | ||
1612 | { | ||
1613 | t_ugenbox *oc_who; | ||
1614 | int oc_inno; | ||
1615 | struct _sigoutconnect *oc_next; | ||
1616 | } t_sigoutconnect; | ||
1617 | |||
1618 | typedef 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 | |||
1627 | struct _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 | |||
1644 | static int ugen_sortno = 0; | ||
1645 | static t_dspcontext *ugen_currentcontext; | ||
1646 | |||
1647 | void 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 | |||
1660 | void 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 | |||
1670 | int ugen_getsortno(void) | ||
1671 | { | ||
1672 | return (ugen_sortno); | ||
1673 | } | ||
1674 | |||
1675 | #if 0 | ||
1676 | void 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 */ | ||
1702 | t_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... */ | ||
1722 | void 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. */ | ||
1743 | void 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 */ | ||
1786 | static 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. */ | ||
1797 | static 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 | |||
1952 | void 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 | |||
2230 | t_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 | |||
2241 | void 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 | |||