From 141cf3c285a0dbd6f69c7dd96bd2e59a5797069a Mon Sep 17 00:00:00 2001 From: Miller Puckette <msp@ucsd.edu> Date: Fri, 5 Dec 2008 08:47:21 -0800 Subject: [PATCH] various upkeep --- doc/3.audio.examples/B15.tabread4~-onset.pd | 66 +++++++++ doc/3.audio.examples/B16.long-varispeed.pd | 156 ++++++++++++++++++++ doc/3.audio.examples/J07.oversampling.pd | 101 ++++++++----- doc/5.reference/tabread4~-help.pd | 59 ++++---- doc/7.stuff/tools/testtone.pd | 6 +- extra/pd~/pd~-help.pd | 95 +++++++++--- extra/pd~/pd~-subprocess.pd | 60 ++++++++ extra/pd~/pd~.c | 143 ++++++++---------- extra/pd~/test.pd | 29 ---- linux/cp-to-max.sh | 9 ++ src/d_array.c | 8 +- src/d_osc.c | 2 +- src/notes.txt | 2 + src/s_audio_alsa.c | 8 +- src/u_main.tk | 2 +- 15 files changed, 547 insertions(+), 199 deletions(-) create mode 100644 doc/3.audio.examples/B15.tabread4~-onset.pd create mode 100644 doc/3.audio.examples/B16.long-varispeed.pd create mode 100644 extra/pd~/pd~-subprocess.pd delete mode 100644 extra/pd~/test.pd create mode 100644 linux/cp-to-max.sh diff --git a/doc/3.audio.examples/B15.tabread4~-onset.pd b/doc/3.audio.examples/B15.tabread4~-onset.pd new file mode 100644 index 000000000..08eabd5ca --- /dev/null +++ b/doc/3.audio.examples/B15.tabread4~-onset.pd @@ -0,0 +1,66 @@ +#N canvas 88 58 563 680 12; +#X text 355 655 updated for Pd version 0.42; +#X text 28 36 Pd is usually compiled to work on 32-bit audio samples. +These do not \, in general \, have enough precision for use as indices +into an array of more than about 32K samples. This is because the mantissa +of a 23-bit floating point number has only 24 bits \, out of which +you would be using 16 bits or more to address a sample more than 32K +into the array \, so there would remain 8 or fewer bits to supply the +fraction. In the most extreme situation possible \, the sample could +contain a Nyquist frequency sinusoid and the output would then have +only about 8 bits of accuracy!; +#X text 29 196 You can use the "onset" inlet to tabread4~ to get good +accuracy reading longer arrays. The tabread4~ object adds the index +and the "main" (signal) inlet in 64-bit precision. So if \, for example +\, the onset inlet could specify an integer exactly up to about 8 million +(190 seconds at 44100 Hz) \, and the signal inlet could act as a displacement. +; +#X text 116 13 USING ONSETS INTO TABREAD4~ TO IMPROVE ACCURACY; +#X obj 41 587 output~; +#X obj 395 507 samplerate~; +#X obj 395 531 / 2; +#X obj 384 445 loadbang; +#X obj 384 582 tabwrite~ \$0-tab; +#X obj 40 557 tabread4~ \$0-tab; +#X obj 395 555 osc~; +#X obj 172 557 tabread4~ \$0-tab; +#X obj 173 589 output~; +#X obj 384 486 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X msg 408 468 \; pd dsp 1; +#X obj 41 474 *~ 10000; +#X obj 41 527 +~; +#X floatatom 192 476 6 0 0 0 - - -; +#X msg 247 446 1; +#X obj 383 610 table \$0-tab 200000; +#X obj 42 446 phasor~ 0.02; +#X msg 192 446 150001; +#X text 28 310 At left below an onset (1 or 150000 samples) is added +to the index of a table lookup. If you select the onset of 150001 \, +you should hear the truncation error. (The table contains a Nyquist +signal and the "correct" output should be a 100 Hz. tone.) At right +\, the onset is presented in the separate onset inlet. The worst-case +truncation error drops by about 30 dB.; +#X text 57 647 BAD; +#X text 190 646 GOOD; +#X text 193 425 ONSET INTO TABLE; +#X text 384 426 This loads the table:; +#X connect 5 0 6 0; +#X connect 6 0 10 0; +#X connect 7 0 13 0; +#X connect 7 0 14 0; +#X connect 9 0 4 0; +#X connect 9 0 4 1; +#X connect 10 0 8 0; +#X connect 11 0 12 0; +#X connect 11 0 12 1; +#X connect 13 0 5 0; +#X connect 13 0 8 0; +#X connect 15 0 16 0; +#X connect 15 0 11 0; +#X connect 16 0 9 0; +#X connect 17 0 11 1; +#X connect 17 0 16 1; +#X connect 18 0 17 0; +#X connect 20 0 15 0; +#X connect 21 0 17 0; diff --git a/doc/3.audio.examples/B16.long-varispeed.pd b/doc/3.audio.examples/B16.long-varispeed.pd new file mode 100644 index 000000000..5ee0afb8b --- /dev/null +++ b/doc/3.audio.examples/B16.long-varispeed.pd @@ -0,0 +1,156 @@ +#N canvas 202 17 779 858 12; +#X obj 399 526 metro 100; +#X obj 212 472 phasor~; +#X obj 399 556 snapshot~; +#X text 561 824 updated for Pd version 0.42; +#X obj 23 557 output~; +#X obj 23 461 phasor~; +#X floatatom 23 329 5 -100 1000 0 - - -; +#X obj 23 518 tabread4~ \$0-tab; +#X msg 281 330 0.5; +#X msg 326 329 0.01; +#X obj 398 455 loadbang; +#X msg 399 478 1; +#X obj 344 635 +; +#X obj 144 680 tabread4~ \$0-tab; +#X obj 375 634 f; +#X obj 312 612 t f f; +#X obj 145 712 output~; +#X floatatom 455 667 8 0 0 0 - - -; +#X obj 344 670 t f b; +#X obj 377 699 f; +#X obj 344 699 -; +#X floatatom 457 612 8 0 0 0 - - -; +#X obj 326 726 -; +#X obj 399 507 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1 +1; +#X obj 212 498 -~ 0.5; +#X obj 290 811 + 0.5; +#X obj 22 490 *~ 1e+06; +#X floatatom 326 753 8 0 0 0 - - -; +#X obj 530 519 samplerate~; +#X obj 484 546 /; +#X obj 484 519 t f b; +#X obj 451 589 +; +#X obj 295 787 / 10000; +#X obj 212 523 *~ 10000; +#X obj 484 570 * 10000; +#X obj 532 155 samplerate~; +#X obj 532 179 / 2; +#X obj 521 93 loadbang; +#X obj 521 230 tabwrite~ \$0-tab; +#X obj 532 203 osc~; +#X obj 521 134 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X msg 545 116 \; pd dsp 1; +#X obj 520 258 table \$0-tab 1e+06; +#X text 488 61 and will take about 20 seconds to fill.; +#X text 488 45 *** The table is now 1 million points \,; +#X obj 23 433 / 1e+06; +#X text 61 328 playback speed \, samples/sec; +#X text 89 460 naive way: just; +#X text 89 475 run a phasor; +#X text 88 491 into tabread4~; +#X text 454 680 new onset is phase plus old onset; +#X obj 341 357 * 1e+06; +#X text 458 626 extrapolated phase of next sample; +#X text 409 700 new onset minus old onset; +#X text 389 726 back up phasor output by amount the onset advanced +; +#X text 387 739 (approximately zero but not exactly because of; +#X text 389 753 truncation error!); +#X msg 340 408 0.5; +#X obj 341 383 t b f; +#X text 400 357 convert to samples; +#X text 385 384 set both last-onset and previous-onset; +#X text 385 407 ... and also reset phasor.; +#X text 354 791 convert phase back to range 0-1; +#X text 215 548 convert phase to; +#X text 215 562 range +/-5000; +#X obj 212 435 / 10000; +#X text 40 410 cycles/sec; +#X text 30 400 convert to; +#X text 216 412 cycles/sec; +#X text 206 402 convert to; +#X text 469 472 in order to change onset to reflect it; +#X text 469 456 Each 100 msec \, poll phase of phasor~; +#X text 24 36 Here is how to use the tabread~ "onset" input to allow +clean varispeed playback from a long table. At left \, a phasor~ is +naiveley rescaled to the size of the tble. At right \, the phasor~ +gets only a 10000-point range about a moving "onset". Ten times per +second \, we poll tha phasor~ phase \, sum its value into the onset +\, and back up the phase of the phasor~ correspondingly.; +#X text 25 150 The tricky bits are \, first \, that we need to poll +the phasor~ phase one sample into the future (so we add the per-sample +increment into the snapshot~ result). Second \, we can't just reset +the phasor~ to a fixed point - instead \, we measure how much the onset +has actually increased (which has truncation error from summing in +the phase snapshot) \, and subtract that increase from the phase \, +giving a value that differs from zero by the truncation error but reflects +the true phase we should reset to for continuity.; +#X text 26 290 The metronome rate is arbitrary but should be fast enough +that the phasor~ never has time to wrap.; +#X text 518 539 extrapolate snapshot of phase by one; +#X text 517 552 sample to sync with next block; +#X text 41 617 BAD; +#X text 160 770 GOOD; +#X text 195 9 VARIABLE SPEED PLAYBACK FROM LONG TABLES; +#X connect 0 0 2 0; +#X connect 1 0 24 0; +#X connect 2 0 31 0; +#X connect 5 0 26 0; +#X connect 6 0 45 0; +#X connect 6 0 65 0; +#X connect 7 0 4 0; +#X connect 7 0 4 1; +#X connect 8 0 5 1; +#X connect 8 0 51 0; +#X connect 9 0 5 1; +#X connect 9 0 51 0; +#X connect 10 0 11 0; +#X connect 11 0 23 0; +#X connect 12 0 14 0; +#X connect 12 0 18 0; +#X connect 12 0 13 1; +#X connect 12 0 17 0; +#X connect 13 0 16 0; +#X connect 13 0 16 1; +#X connect 14 0 12 1; +#X connect 15 0 22 0; +#X connect 15 1 12 0; +#X connect 18 0 19 1; +#X connect 18 0 20 0; +#X connect 18 1 19 0; +#X connect 19 0 20 1; +#X connect 20 0 22 1; +#X connect 22 0 27 0; +#X connect 22 0 32 0; +#X connect 23 0 0 0; +#X connect 24 0 33 0; +#X connect 25 0 1 1; +#X connect 26 0 7 0; +#X connect 28 0 29 1; +#X connect 29 0 34 0; +#X connect 30 0 29 0; +#X connect 30 1 28 0; +#X connect 31 0 15 0; +#X connect 31 0 21 0; +#X connect 32 0 25 0; +#X connect 33 0 2 0; +#X connect 33 0 13 0; +#X connect 34 0 31 1; +#X connect 35 0 36 0; +#X connect 36 0 39 0; +#X connect 37 0 40 0; +#X connect 37 0 41 0; +#X connect 39 0 38 0; +#X connect 40 0 35 0; +#X connect 40 0 38 0; +#X connect 45 0 5 0; +#X connect 51 0 58 0; +#X connect 57 0 1 1; +#X connect 58 0 57 0; +#X connect 58 1 19 1; +#X connect 58 1 12 1; +#X connect 65 0 1 0; +#X connect 65 0 30 0; diff --git a/doc/3.audio.examples/J07.oversampling.pd b/doc/3.audio.examples/J07.oversampling.pd index 0b124c035..4c5f3cc81 100644 --- a/doc/3.audio.examples/J07.oversampling.pd +++ b/doc/3.audio.examples/J07.oversampling.pd @@ -1,10 +1,5 @@ -#N canvas 343 48 578 498 12; -#N canvas 158 4 728 420 16x 0; -#X obj 21 151 *~ 0.064; -#X obj 21 174 rpole~ 0.93538; -#X obj 21 197 *~ 0.00431; -#X obj 21 220 cpole~ 0.96559 0.05592; -#X obj 21 246 cpole~ 0.96559 -0.05592; +#N canvas 378 114 542 534 12; +#N canvas 371 260 740 538 16x 0; #X obj 21 269 *~ 0.125; #X obj 21 292 rzero~ -1; #X obj 21 315 rzero~ -1; @@ -13,44 +8,84 @@ #X obj 204 29 block~ 1024 1 16; #X obj 21 31 inlet; #X obj 21 372 outlet~; -#X text 170 151 These objects make a 3-pole \, 3-zero Butterwirth low-pass -filter with cutoff at 15kHz (assuming 44100 sample rate.) The filter +#X obj 20 166 rpole~ 0.87467; +#X obj 20 143 *~ 0.12532; +#X obj 20 189 *~ 0.01668; +#X obj 279 358 buttercoef3; +#X floatatom 279 282 7 0 0 0 - - -; +#X obj 279 332 / 16; +#X floatatom 279 488 7 0 0 0 - - -; +#X obj 279 307 / 22050; +#X floatatom 293 468 7 0 0 0 - - -; +#X floatatom 308 448 7 0 0 0 - - -; +#X floatatom 323 428 7 0 0 0 - - -; +#X floatatom 338 408 7 0 0 0 - - -; +#X floatatom 353 388 7 0 0 0 - - -; +#X text 335 489 normalizer for rpole~; +#X text 352 468 normalizer for cpole~; +#X text 366 449 coef for rpole~; +#X text 382 430 coef for cpole~ real part; +#X text 413 390 coef for cpole~ imag part; +#X text 409 408 (same \, other cpole~); +#X obj 20 212 cpole~ 0.9293 0.10812; +#X obj 20 238 cpole~ 0.9293 -0.10812; +#X msg 279 257 15000; +#X text 329 256 desired cutoff frequency; +#X text 339 308 divide by nyquist frequency of this subpatch \, which +is 22050*16 because of the 16-times oversampling.; +#X text 273 225 Here is how to calculate the filter coefficients:; +#X text 143 123 These objects make a 3-pole \, 3-zero Butterworth low-pass +filter with cutoff at 15kHz (assuming 16x44100 sample rate). The filter was designed using the "buttercoef3" abstraction introduced in patch H13.butterworth.pd in this series.; #X connect 0 0 1 0; #X connect 1 0 2 0; #X connect 2 0 3 0; -#X connect 3 0 4 0; -#X connect 3 1 4 1; -#X connect 4 0 5 0; -#X connect 5 0 6 0; -#X connect 6 0 7 0; -#X connect 7 0 8 0; -#X connect 8 0 12 0; -#X connect 9 0 0 0; -#X connect 11 0 9 0; -#X restore 23 148 pd 16x; -#X floatatom 23 111 7 0 0 0 - - -; -#X obj 109 149 phasor~; -#X obj 22 194 output~; -#X obj 108 194 output~; -#X obj 23 83 mtof; -#X floatatom 23 59 3 -24 135 0 - - -; -#X text 131 18 UPSAMPLING TO CONTROL FOLDOVER; -#X text 56 57 <-- pitch; -#X text 126 250 not; -#X text 22 265 sampled; -#X text 26 249 16x up-; -#X text 20 293 The "pd 16x" subpatch at left contains a phasor~ object +#X connect 3 0 7 0; +#X connect 4 0 9 0; +#X connect 6 0 4 0; +#X connect 8 0 10 0; +#X connect 9 0 8 0; +#X connect 10 0 27 0; +#X connect 11 0 14 0; +#X connect 11 1 16 0; +#X connect 11 2 17 0; +#X connect 11 3 18 0; +#X connect 11 4 19 0; +#X connect 11 5 20 0; +#X connect 12 0 15 0; +#X connect 13 0 11 0; +#X connect 15 0 13 0; +#X connect 27 0 28 0; +#X connect 27 1 28 1; +#X connect 28 0 0 0; +#X connect 29 0 12 0; +#X restore 29 123 pd 16x; +#X floatatom 29 86 7 0 0 0 - - -; +#X obj 115 124 phasor~; +#X obj 28 169 output~; +#X obj 114 169 output~; +#X obj 29 58 mtof; +#X floatatom 29 34 3 -24 135 0 - - -; +#X text 158 15 UPSAMPLING TO CONTROL FOLDOVER; +#X text 62 32 <-- pitch; +#X text 132 225 not; +#X text 28 240 sampled; +#X text 32 224 16x up-; +#X text 26 268 The "pd 16x" subpatch at left contains a phasor~ object \, but is locally upsampled by a factor of sixteen. Without upsampling \, partials as low as 24 Khz. fold back over into the audible range. With upsampling \, the first audibly folding over partial is at almost 700 Hz \, 29 times higher. The relevant partials will be 29 times \, or almost 30 dB \, quieter when upsampled.; -#X text 21 403 A third-order Butterworth filter is used inside the +#X text 27 378 A third-order Butterworth filter is used inside the "pd 16x" subpatch - without that \, the internal signal would fold over as it gets downsampled at the outlet~ object.; -#X text 324 464 Updated for Pd version 0.39; +#X text 312 507 Updated for Pd version 0.42; +#X text 26 430 You can trade off cutoff frequency with foldover. Here +\, the filter is set for a cutoff of 15 kHz. Lowering it to 7500 Hz +would further reduce foldover by 18 dB at the expense of losing energy +in the range 7500-15000 Hz.; #X connect 0 0 3 0; #X connect 0 0 3 1; #X connect 1 0 0 0; diff --git a/doc/5.reference/tabread4~-help.pd b/doc/5.reference/tabread4~-help.pd index c28f580af..897fc64b1 100644 --- a/doc/5.reference/tabread4~-help.pd +++ b/doc/5.reference/tabread4~-help.pd @@ -1,30 +1,28 @@ -#N canvas 59 33 814 475 10; -#X obj 11 228 tabread4~ array99; -#X text 21 207 signal input x(n); -#X msg 727 51 \; pd dsp 0; -#X graph graph1 0 -1 9 1 514 373 764 173; -#X array array99 10 float 0; -#X pop; +#N canvas 323 179 845 474 12; +#X obj 11 249 tabread4~ array99; +#N canvas 0 0 450 300 (subpatch) 0; +#X array array99 10 float 3; +#A 0 -0.5 -0.5 -0.5 0.5 0.5 0.5 0 0 0 0; +#X coords 0 1 10 -1 250 200 1; +#X restore 561 167 graph; #X text 127 21 4-point-interpolating table lookup; -#X obj 11 316 snapshot~; -#X obj 30 290 metro 200; +#X obj 11 337 snapshot~; +#X obj 30 311 metro 200; #X obj 11 124 sig~; -#X floatatom 11 98 0 0 0; -#X obj 30 264 r readout; -#X floatatom 11 342 0 0 0; -#X msg 452 50 \; readout 1 \; array99 resize 10 \; array99 0 -0.5 -0.5 --0.5 0.5 0.5 0.5 \; pd dsp 1 \;; -#X text 49 94 incoming signal is index. Indices should range from 1 +#X floatatom 11 98 6 0 10 0 - - -; +#X obj 30 285 r readout; +#X floatatom 11 363 0 0 0 0 - - -; +#X text 59 92 incoming signal is index. Indices should range from 1 to (size-2) so that the 4-point interpolation is meaningful. You can shift-drag the number box to see the effect of interpolation.; -#X msg 34 158 set array99; -#X text 116 158 "set" message permits you to switch between arrays +#X msg 23 161 set array99; +#X text 113 160 "set" message permits you to switch between arrays ; -#X text 139 228 creation argument initializes array name; -#X text 5 392 see also the "array" tutorial in section 2 of the Pd +#X text 139 249 creation argument initializes array name; +#X text 11 403 see also the "array" tutorial in section 2 of the Pd documentation \, and these objects:; #X obj 47 21 tabread4~; -#X text 509 27 click here to test; +#X text 563 16 click here to test; #X obj 12 442 tabwrite~; #X obj 157 442 tabread; #X obj 216 442 tabwrite; @@ -32,12 +30,19 @@ documentation \, and these objects:; #X obj 346 442 tabreceive~; #X text 7 58 Tabread4~ is used to build samplers and other table lookup algorithms. The interpolation scheme is 4-point polynomial.; -#X text 616 460 updated for Pd version 0.29; #X obj 83 442 tabplay~; -#X connect 0 0 5 0; -#X connect 5 0 10 0; +#X text 626 451 updated for Pd version 0.42; +#X msg 582 40 \; readout 1 \; pd dsp 1 \;; +#X floatatom 111 190 3 0 10 0 - - -; +#X text 19 205 signal input; +#X text 138 183 inlet sets onset into table. You can use this to improve +the accuracy of indexing into the array. See B15.tabread4~-onset.pd +for details.; +#X connect 0 0 3 0; +#X connect 3 0 8 0; +#X connect 4 0 3 0; +#X connect 5 0 0 0; #X connect 6 0 5 0; -#X connect 7 0 0 0; -#X connect 8 0 7 0; -#X connect 9 0 6 0; -#X connect 13 0 0 0; +#X connect 7 0 4 0; +#X connect 10 0 0 0; +#X connect 25 0 0 1; diff --git a/doc/7.stuff/tools/testtone.pd b/doc/7.stuff/tools/testtone.pd index d286bb9db..f65dc8121 100644 --- a/doc/7.stuff/tools/testtone.pd +++ b/doc/7.stuff/tools/testtone.pd @@ -86,7 +86,7 @@ started" in the Help menu.; #X connect 4 0 3 0; #X restore 459 298 pd more; #X obj 399 135 tgl 20 0 tone-hipass set-tone-hipass input-hipass 25 -10 0 12 -262144 -1 -1 1 1; +10 0 12 -262144 -1 -1 0 1; #X obj 185 117 tgl 20 0 tone-ch3 tone-ch3 3 5 -8 0 12 -262144 -1 -1 1 1; #X obj 210 117 tgl 20 0 tone-ch4 tone-ch4 4 5 -8 0 12 -262144 -1 -1 @@ -112,7 +112,7 @@ started" in the Help menu.; #X obj 51 174 vradio 15 1 0 2 tone-type tone-type-set empty 0 -6 0 8 -262144 -1 -1 1; #X obj 51 104 vradio 15 1 0 3 tone-radio tone-radio-set empty 0 -6 -0 8 -262144 -1 -1 2; +0 8 -262144 -1 -1 0; #X obj 460 193 adc~; #X obj 459 240 print~; #X obj 468 217 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 @@ -123,7 +123,7 @@ started" in the Help menu.; 1 1; #X obj 308 117 tgl 20 0 tone-ch8 tone-ch8 8 5 -8 0 12 -262144 -1 -1 1 1; -#N canvas 233 399 903 462 audio 0; +#N canvas 233 399 321 422 audio 0; #X obj 25 303 s~ tone-mon; #X obj 25 277 line~; #X obj 25 249 pack 0 50; diff --git a/extra/pd~/pd~-help.pd b/extra/pd~/pd~-help.pd index a845f453f..8bc357e0c 100644 --- a/extra/pd~/pd~-help.pd +++ b/extra/pd~/pd~-help.pd @@ -1,20 +1,75 @@ -#N canvas 353 325 450 300 10; -#X msg 52 86 foo bar baz; -#X obj 209 52 osc~ 440; -#X obj 74 211 env~ 8192; -#X floatatom 77 243 5 0 0 0 - - -; -#X obj 285 204 r a; -#X obj 281 232 print a; -#X msg 315 81 \; pd dsp 1; -#X obj 70 166 pd~ test.pd; -#X msg 66 20 pd~ stop; -#X msg 77 42 pd~ start; -#X msg 86 61 pd~ restart; -#X connect 0 0 7 0; -#X connect 1 0 7 0; -#X connect 2 0 3 0; -#X connect 4 0 5 0; -#X connect 7 0 2 0; -#X connect 8 0 7 0; -#X connect 9 0 7 0; -#X connect 10 0 7 0; +#N canvas 12 0 566 872 12; +#X msg 31 406 foo bar baz; +#X obj 189 466 osc~ 440; +#X obj 127 645 env~ 8192; +#X floatatom 127 694 5 0 0 0 - - -; +#X msg 434 807 \; pd dsp 1; +#X msg 24 332 pd~ stop; +#X obj 127 670 i; +#X obj 241 643 env~ 8192; +#X floatatom 241 693 5 0 0 0 - - -; +#X obj 241 669 i; +#X obj 123 489 *~; +#X obj 158 490 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 189 490 *~; +#X obj 224 491 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 434 781 loadbang; +#X obj 14 691 print x; +#X msg 15 309 pd~ start pd~-subprocess.pd; +#X obj 14 532 pd~ -ninsig 2 -noutsig 2 -fifo 20; +#X obj 37 20 pd~; +#X text 69 22 - run a pd sub-process; +#X text 27 57 The pd~ object starts and manages a Pd sub-process that +can communicate with the super-process (this one) via audio channels +and/or Pd messages. In this way you can take advantage of multi-core +CPUs \, and/or use Pd features from within Max (if you're using the +Max version of pd~).; +#X text 24 251 Sending a new "start" message will stop the sub-process +and start a new one. If you just want to stop the sub-process \, send +"stop".; +#X text 33 353 Any message besides "pd~" is sent to the sub-process. +For instance \, the message below sends "bar baz" to any object in +the sub-process named "foo" \, such as a "receive" object.; +#X text 43 430 Audio signals appear in adc~ objects in the sub-process. +The sub-process doesn't open real audio devices.; +#X text 281 473 Creation args:; +#X text 265 490 -insig <n> sets input audio channels; +#X text 266 508 -outsig <n> sets output channels; +#X text 269 542 -fifo <n> sets round-trip delay in blocks; +#X text 272 559 -pddir <s> sets Pd directory \, e.g. \,; +#X text 299 574 .../Pd-0.42.app/Contents/Resources; +#X text 272 590 -scheddir <s> sets scheduler dir \, e.g. \,; +#X text 297 607 .../.../Resources/extra/pd~; +#X text 267 524 -sr <n> sets sample rate; +#X text 20 716 The first outlet reports messages the sub-process sends +us via "stdout" objects. Any other outlets are signals corresponding +to "dac~" objects in the sub-process.; +#X text 10 784 ATTENTION: DSP must be running in this process for the +sub-process to run. This is because its clock is slaved to audio I/O +it gets from us!; +#X text 359 849 Updated for Pd version 0.42.; +#X text 24 138 Messages with "pd~" selector control the sub-process. +"pd~ start" takes as arguments any startup arguments you wish to send +the sub-process. For example \, specify "-nogui" to stop the sub-process's +GUI from appearing. You don't have to specify the number of channels +in and out \, since that's set by creation arguments below. Audio config +arguments arguments (-audiobuf \, -audiodev \, etc.) are ignored.; +#X connect 0 0 17 0; +#X connect 1 0 10 0; +#X connect 1 0 12 0; +#X connect 2 0 6 0; +#X connect 5 0 17 0; +#X connect 6 0 3 0; +#X connect 7 0 9 0; +#X connect 9 0 8 0; +#X connect 10 0 17 0; +#X connect 11 0 10 1; +#X connect 12 0 17 1; +#X connect 13 0 12 1; +#X connect 14 0 4 0; +#X connect 16 0 17 0; +#X connect 17 0 15 0; +#X connect 17 1 2 0; +#X connect 17 2 7 0; diff --git a/extra/pd~/pd~-subprocess.pd b/extra/pd~/pd~-subprocess.pd new file mode 100644 index 000000000..1d883ab18 --- /dev/null +++ b/extra/pd~/pd~-subprocess.pd @@ -0,0 +1,60 @@ +#N canvas 577 21 563 559 12; +#X obj 202 395 r foo; +#X obj 202 423 print foo; +#X obj 87 174 adc~; +#X obj 72 442 stdout; +#X msg 72 364 a b c; +#X msg 455 441 \; pd dsp 1; +#X obj 87 201 env~ 8192; +#X floatatom 87 250 5 0 0 0 - - -; +#X obj 87 226 i; +#X obj 263 253 dac~; +#X obj 262 185 osc~ 440; +#X obj 262 219 *~; +#X obj 297 220 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 332 186 osc~ 440; +#X obj 332 220 *~; +#X obj 367 221 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X msg 86 411 bang; +#X obj 455 417 loadbang; +#X obj 160 201 env~ 8192; +#X floatatom 160 250 5 0 0 0 - - -; +#X obj 160 226 i; +#X msg 86 388 4; +#X text 62 8 This is a test patch to demonstrate the Pd~ object. It's +intended as the patch to run in the sub-process. The sub-process (which +is a separate instance of Pd) can be called from a Max or Pd super-process. +; +#X text 63 73 Audio inlets and outlets on the Pd~ object (in the super-process) +talk to adc~ and dac~ objects here - so \, for instance \, the first +adc~ here is the first inlet of the pd~ object \, and the first chanel +of dac~ goes to the second outlet of pd~ (because the first one is +for messages \, as shown further below.); +#X text 58 283 Any message sent to a stdout object in this sub-process +(below) appears on the first \, message outlet of the pd~ object in +the super-process. The super-process can send messages to any "receive" +object in this sub-process.; +#X text 137 478 We turn DSP on at load for convenience - control objects +in this patch will still work without it (unlike in the super-process +\, where DSP must be on for time to move forward in the sub-process.) +; +#X text 351 538 Updated for Pd version 0.42.; +#X connect 0 0 1 0; +#X connect 2 0 6 0; +#X connect 2 1 18 0; +#X connect 4 0 3 0; +#X connect 6 0 8 0; +#X connect 8 0 7 0; +#X connect 10 0 11 0; +#X connect 11 0 9 0; +#X connect 12 0 11 1; +#X connect 13 0 14 0; +#X connect 14 0 9 1; +#X connect 15 0 14 1; +#X connect 16 0 3 0; +#X connect 17 0 5 0; +#X connect 18 0 20 0; +#X connect 20 0 19 0; +#X connect 21 0 3 0; diff --git a/extra/pd~/pd~.c b/extra/pd~/pd~.c index 92783e8a8..223f3d1ea 100644 --- a/extra/pd~/pd~.c +++ b/extra/pd~/pd~.c @@ -70,14 +70,12 @@ typedef struct _pd_tilde #ifdef PD t_object x_obj; t_clock *x_clock; + t_outlet *x_outlet1; /* for messages back from subproc */ #endif /* PD */ #ifdef MSP t_pxobject x_obj; - void *obex; - void *x_cookedout; + void *x_outlet1; void *x_clock; - short x_vol; - #endif /* MSP */ FILE *x_infd; FILE *x_outfd; @@ -91,7 +89,6 @@ typedef struct _pd_tilde float x_sr; t_symbol *x_pddir; t_symbol *x_schedlibdir; - char *x_pdargs; t_sample **x_insig; t_sample **x_outsig; } t_pd_tilde; @@ -197,8 +194,9 @@ static void pd_tilde_donew(t_pd_tilde *x, char *pddir, char *schedlibdir, goto fail1; } } - snprintf(cmdbuf, MAXPDSTRING, "%s -schedlib %s/pdsched %s\n", - pdexecbuf, schedlibdir, pdargs); + snprintf(cmdbuf, MAXPDSTRING, +"%s -schedlib %s/pdsched -inchannels %d -outchannels %d -r %g %s\n", + pdexecbuf, schedlibdir, ninsig, noutsig, samplerate, pdargs); #if 0 #ifdef PD fprintf(stderr, "%s", cmdbuf); @@ -368,25 +366,49 @@ static void pd_tilde_dsp(t_pd_tilde *x, t_signal **sp) static void pd_tilde_pdtilde(t_pd_tilde *x, t_symbol *s, int argc, t_atom *argv) { - t_symbol *sel = ((argc > 0 && argv->a_type == A_SYMBOL) ? argv->a_w.w_symbol : gensym("?")); + t_symbol *sel = ((argc > 0 && argv->a_type == A_SYMBOL) ? + argv->a_w.w_symbol : gensym("?")); if (sel == gensym("start")) { - if (!x->x_infd) - pd_tilde_donew(x, x->x_pddir->s_name, x->x_schedlibdir->s_name, - x->x_pdargs, x->x_ninsig, x->x_noutsig, x->x_fifo, x->x_sr); - } - else if (sel == gensym("stop")) - { + char pdargstring[MAXPDSTRING]; if (x->x_infd) pd_tilde_close(x); + pdargstring[0] = 0; + argc--; argv++; +#ifdef PD + while (argc--) + { + atom_string(argv++, pdargstring + strlen(pdargstring), + MAXPDSTRING - strlen(pdargstring)); + if (strlen(pdargstring) < MAXPDSTRING-1) + strcat(pdargstring, " "); + } +#endif +#ifdef MAX + while (argc--) + { + if (argv->a_type == A_SYM) + strncat(pdargstring, argv->a_w.w_sym->s_name, + MAXPDSTRING - strlen(pdargstring)-3); + else if (argv->a_type == A_LONG) + snprintf(pdargstring+strlen(pdargstring), + MAXPDSTRING - strlen(pdargstring)-3, "%ld", + argv->a_w.w_long); + else if (argv->a_type == A_FLOAT) + snprintf(pdargstring+strlen(pdargstring), + MAXPDSTRING - strlen(pdargstring)-3, "%f", + argv->a_w.w_float); + strcat(pdargstring, " "); + argv++; + } +#endif + pd_tilde_donew(x, x->x_pddir->s_name, x->x_schedlibdir->s_name, + pdargstring, x->x_ninsig, x->x_noutsig, x->x_fifo, x->x_sr); } - else if (sel == gensym("restart")) + else if (sel == gensym("stop")) { if (x->x_infd) pd_tilde_close(x); - if (!x->x_infd) - pd_tilde_donew(x, x->x_pddir->s_name, x->x_schedlibdir->s_name, - x->x_pdargs, x->x_ninsig, x->x_noutsig, x->x_fifo, x->x_sr); } else ERROR "pd~: unknown control message: %s", sel->s_name); } @@ -398,7 +420,6 @@ static void pd_tilde_free(t_pd_tilde *x) #endif pd_tilde_close(x); clock_free(x->x_clock); - free(x->x_pdargs); } /* -------------------------- Pd glue ------------------------- */ @@ -420,19 +441,11 @@ static void pd_tilde_tick(t_pd_tilde *x) { if (vec[i].a_type == A_SEMI) { - if (i > messstart + 1) - { - t_pd *whom; - if (vec[messstart].a_type != A_SYMBOL) - bug("pd_tilde_tick"); - else if (!(whom = vec[messstart].a_w.w_symbol->s_thing)) - ERROR "%s: no such object", - vec[messstart].a_w.w_symbol->s_name); - else if (vec[messstart+1].a_type == A_SYMBOL) - typedmess(whom, vec[messstart+1].a_w.w_symbol, - i-messstart-2, vec+(messstart+2)); - else pd_list(whom, 0, i-messstart-1, vec+(messstart+1)); - } + if (i > messstart && vec[messstart].a_type == A_SYMBOL) + outlet_anything(x->x_outlet1, vec[messstart].a_w.w_symbol, + i-(messstart+1), vec+(messstart+1)); + else if (i > messstart) + outlet_list(x->x_outlet1, 0, i-messstart, vec+messstart); messstart = i+1; } } @@ -468,8 +481,7 @@ static void *pd_tilde_new(t_symbol *s, int argc, t_atom *argv) t_sample **g; t_symbol *pddir = sys_guidir, *scheddir = gensym(class_gethelpdir(pd_tilde_class)); - char pdargstring[MAXPDSTRING]; - fprintf(stderr, "pd %s, sched %s\n", pddir->s_name, scheddir->s_name); + /* fprintf(stderr, "pd %s, sched %s\n", pddir->s_name, scheddir->s_name); */ while (argc > 0) { t_symbol *firstarg = atom_getsymbolarg(0, argc, argv); @@ -505,24 +517,15 @@ static void *pd_tilde_new(t_symbol *s, int argc, t_atom *argv) } else break; } -#if 0 - { - pd_error(x, -"usage: pd~ [-sr #] [-ninsig #] [-noutsig #] [-fifo #] [-pddir <>]"); - post( -"... [-scheddir <>] [pd-argument...]"); - argc = 0; - } -#endif - - pdargstring[0] = 0; - while (argc--) + + if (argc) { - atom_string(argv++, pdargstring + strlen(pdargstring), - MAXPDSTRING - strlen(pdargstring)); - if (strlen(pdargstring) < MAXPDSTRING-1) - strcat(pdargstring, " "); + pd_error(x, +"usage: pd~ [-sr #] [-ninsig #] [-noutsig #] [-fifo #] [-pddir <>]"); + post( +"... [-scheddir <>]"); } + x->x_clock = clock_new(x, (t_method)pd_tilde_tick); x->x_insig = (t_sample **)getbytes(ninsig * sizeof(*x->x_insig)); x->x_outsig = (t_sample **)getbytes(noutsig * sizeof(*x->x_outsig)); @@ -532,15 +535,14 @@ static void *pd_tilde_new(t_symbol *s, int argc, t_atom *argv) x->x_sr = sr; x->x_pddir = pddir; x->x_schedlibdir = scheddir; - x->x_pdargs = malloc(strlen(pdargstring)+1); x->x_infd = 0; x->x_outfd = 0; x->x_outfd = 0; x->x_childpid = -1; x->x_msgbuf = 0; - strcpy(x->x_pdargs, pdargstring); for (j = 1, g = x->x_insig; j < ninsig; j++, g++) inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + x->x_outlet1 = outlet_new(&x->x_obj, 0); for (j = 0, g = x->x_outsig; j < noutsig; j++, g++) outlet_new(&x->x_obj, &s_signal); signal(SIGPIPE, SIG_IGN); @@ -556,7 +558,7 @@ void pd_tilde_setup(void) class_addmethod(pd_tilde_class, (t_method)pd_tilde_dsp, gensym("dsp"), 0); class_addmethod(pd_tilde_class, (t_method)pd_tilde_pdtilde, gensym("pd~"), A_GIMME, 0); class_addanything(pd_tilde_class, pd_tilde_anything); - post("pd~ version 0.1"); + post("pd~ version 0.2"); } #endif @@ -651,7 +653,8 @@ int main() class_register(CLASS_BOX, c); pd_tilde_class = c; - return (0); + post("pd~ version 0.2"); + return (0); } static void *pd_tilde_new(t_symbol *s, long ac, t_atom *av) @@ -659,7 +662,6 @@ static void *pd_tilde_new(t_symbol *s, long ac, t_atom *av) int ninsig = 2, noutsig = 2, fifo = 5, j; float sr = sys_getsr(); t_symbol *pddir = gensym("."), *scheddir = gensym("."); - char pdargstring[MAXPDSTRING]; t_pd_tilde *x; if (x = (t_pd_tilde *)object_alloc(pd_tilde_class)) @@ -705,30 +707,17 @@ static void *pd_tilde_new(t_symbol *s, long ac, t_atom *av) } if (scheddir == gensym(".") && pddir != gensym(".")) { - char *pds = pddir->s_name; + char *pds = pddir->s_name, scheddirstring[MAXPDSTRING]; int l = strlen(pds); if (l >= 4 && (!strcmp(pds+l-3, "bin") || !strcmp(pds+l-4, "bin/"))) - snprintf(pdargstring, MAXPDSTRING, "%s/../extra/pd~", pds); - else snprintf(pdargstring, MAXPDSTRING, "%s/extra/pd~", pds); - scheddir = gensym(pdargstring); - } - pdargstring[0] = 0; - while (ac--) - { - char buf[80]; - if (av->a_type == A_SYM) - strncat(pdargstring, av->a_w.w_sym->s_name, MAXPDSTRING - strlen(pdargstring)-3); - else if (av->a_type == A_LONG) - snprintf(pdargstring+strlen(pdargstring), MAXPDSTRING - strlen(pdargstring)-3, "%ld", - av->a_w.w_long); - else if (av->a_type == A_FLOAT) - snprintf(pdargstring+strlen(pdargstring), MAXPDSTRING - strlen(pdargstring)-3, "%f", - av->a_w.w_float); - strcat(pdargstring, " "); - av++; + snprintf(scheddirstring, MAXPDSTRING, "%s/../extra/pd~", pds); + else snprintf(scheddirstring, MAXPDSTRING, "%s/extra/pd~", pds); + scheddir = gensym(scheddirstring); } - post("pd~: pddir %s scheddir %s args %s", - pddir->s_name, scheddir->s_name, pdargstring); + if (ac) + post("pd~: warning: ignoring extra arguments"); + post("pd~: pddir %s scheddir %s", + pddir->s_name, scheddir->s_name); dsp_setup((t_pxobject *)x, ninsig); for (j = 0; j < noutsig; j++) outlet_new((t_pxobject *)x, "signal"); @@ -741,13 +730,11 @@ static void *pd_tilde_new(t_symbol *s, long ac, t_atom *av) x->x_sr = sr; x->x_pddir = pddir; x->x_schedlibdir = scheddir; - x->x_pdargs = malloc(strlen(pdargstring)+1); x->x_infd = 0; x->x_outfd = 0; x->x_outfd = 0; x->x_childpid = -1; x->x_msgbuf = 0; - strcpy(x->x_pdargs, pdargstring); } return (x); } diff --git a/extra/pd~/test.pd b/extra/pd~/test.pd deleted file mode 100644 index ca95baec2..000000000 --- a/extra/pd~/test.pd +++ /dev/null @@ -1,29 +0,0 @@ -#N canvas 643 132 450 300 10; -#X obj 65 58 r foo; -#X obj 62 100 print foo; -#X obj 244 59 adc~; -#X obj 238 102 env~ 8192; -#X floatatom 236 140 5 0 0 0 - - -; -#X obj 145 130 osc~ 440; -#X obj 287 204 stdout; -#X msg 307 153 a b c; -#X msg 307 42 \; pd dsp 1; -#X floatatom 238 173 5 0 0 0 - - -; -#X msg 149 34 a b c; -#X obj 62 157 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 --1; -#X obj 44 187 del 1000; -#X obj 26 249 print bang; -#X obj 59 219 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 --1; -#X obj 155 234 dac~ 1 2 3 4; -#X obj 168 189 sig~ 0.5; -#X connect 0 0 1 0; -#X connect 2 0 3 0; -#X connect 3 0 4 0; -#X connect 4 0 9 0; -#X connect 7 0 6 0; -#X connect 10 0 1 0; -#X connect 11 0 12 0; -#X connect 12 0 13 0; -#X connect 12 0 14 0; diff --git a/linux/cp-to-max.sh b/linux/cp-to-max.sh new file mode 100644 index 000000000..3a32fde71 --- /dev/null +++ b/linux/cp-to-max.sh @@ -0,0 +1,9 @@ +cd /home/msp/pd/extra +tar czf /tmp/z.tgz \ + pd~/pd~.c pd~/pd~-help.pd pd~/pd~-subprocess.pd \ + sigmund~/sigmund~.c sigmund~/sigmund~-help.pd \ + bonk~/bonk~.c bonk~/bonk~-help.pd + +ls -l /tmp/z.tgz + + diff --git a/src/d_array.c b/src/d_array.c index 73a18418f..11a55b5de 100644 --- a/src/d_array.c +++ b/src/d_array.c @@ -373,6 +373,7 @@ typedef struct _tabread4_tilde t_word *x_vec; t_symbol *x_arrayname; t_float x_f; + t_float x_onset; } t_tabread4_tilde; static void *tabread4_tilde_new(t_symbol *s) @@ -381,7 +382,9 @@ static void *tabread4_tilde_new(t_symbol *s) x->x_arrayname = s; x->x_vec = 0; outlet_new(&x->x_obj, gensym("signal")); + floatinlet_new(&x->x_obj, &x->x_onset); x->x_f = 0; + x->x_onset = 0; return (x); } @@ -393,6 +396,7 @@ static t_int *tabread4_tilde_perform(t_int *w) int n = (int)(w[4]); int maxindex; t_word *buf = x->x_vec, *wp; + double onset = x->x_onset; int i; maxindex = x->x_npoints - 3; @@ -417,7 +421,7 @@ static t_int *tabread4_tilde_perform(t_int *w) for (i = 0; i < n; i++) { - t_sample findex = *in++; + double findex = *in++ + onset; int index = findex; t_sample frac, a, b, c, d, cminusb; static int count; @@ -431,8 +435,6 @@ static t_int *tabread4_tilde_perform(t_int *w) b = wp[0].w_float; c = wp[1].w_float; d = wp[2].w_float; - /* if (!i && !(count++ & 1023)) - post("fp = %lx, shit = %lx, b = %f", fp, buf->b_shit, b); */ cminusb = c-b; *out++ = b + frac * ( cminusb - 0.1666667f * (1.-frac) * ( diff --git a/src/d_osc.c b/src/d_osc.c index 93b1a89ee..8336dd344 100644 --- a/src/d_osc.c +++ b/src/d_osc.c @@ -86,7 +86,7 @@ static t_int *phasor_perform(t_int *w) t_float *in = (t_float *)(w[2]); t_float *out = (t_float *)(w[3]); int n = (int)(w[4]); - double dphase = x->x_phase + UNITBIT32; + double dphase = x->x_phase + (double)UNITBIT32; union tabfudge tf; int normhipart; float conv = x->x_conv; diff --git a/src/notes.txt b/src/notes.txt index 70209b655..a64e02dc3 100644 --- a/src/notes.txt +++ b/src/notes.txt @@ -15,6 +15,8 @@ mac: Gnome: why don't windows pop up when clicked on? problems: +if .pdsettings asks for an alsa device out of range, dialog + comes up with empty list find asdf$1 (e.g.) doesn't work check real-time gaps in writesf~ fix declare to update current patch when changed diff --git a/src/s_audio_alsa.c b/src/s_audio_alsa.c index dad2c86f5..a5034c8dc 100644 --- a/src/s_audio_alsa.c +++ b/src/s_audio_alsa.c @@ -443,20 +443,20 @@ int alsa_send_dacs(void) if (alsa_outdev[iodev].a_sampwidth == 4) { for (i = 0; i < chans; i++, ch++, fp1 += DEFDACBLKSIZE) - for (j = ch, k = DEFDACBLKSIZE, fp2 = fp1; k--; + for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--; j += thisdevchans, fp2++) { float s1 = *fp2 * INT32_MAX; ((t_alsa_sample32 *)alsa_snd_buf)[j] = CLIP32(s1); } for (; i < thisdevchans; i++, ch++) - for (j = ch, k = DEFDACBLKSIZE; k--; j += thisdevchans) + for (j = i, k = DEFDACBLKSIZE; k--; j += thisdevchans) ((t_alsa_sample32 *)alsa_snd_buf)[j] = 0; } else if (alsa_outdev[iodev].a_sampwidth == 3) { for (i = 0; i < chans; i++, ch++, fp1 += DEFDACBLKSIZE) - for (j = ch, k = DEFDACBLKSIZE, fp2 = fp1; k--; + for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--; j += thisdevchans, fp2++) { int s = *fp2 * 8388352.; @@ -473,7 +473,7 @@ int alsa_send_dacs(void) #endif } for (; i < thisdevchans; i++, ch++) - for (j = ch, k = DEFDACBLKSIZE; k--; j += thisdevchans) + for (j = i, k = DEFDACBLKSIZE; k--; j += thisdevchans) ((char *)(alsa_snd_buf))[3*j] = ((char *)(alsa_snd_buf))[3*j+1] = ((char *)(alsa_snd_buf))[3*j+2] = 0; diff --git a/src/u_main.tk b/src/u_main.tk index 9d68b58ee..ee971e507 100644 --- a/src/u_main.tk +++ b/src/u_main.tk @@ -4449,7 +4449,7 @@ proc ddd_dialog {id dialogname} { set fieldname [lindex $ddd_fields $x 0] set $varname [lindex $ddd_fields $x 1] frame $id.frame$x - pack $id.frame$x -side top + pack $id.frame$x -side top -anchor e label $id.frame$x.label -text $fieldname entry $id.frame$x.entry -textvariable $varname -width 20 bind $id.frame$x.entry <KeyPress-Return> [concat ddd_ok $id] -- GitLab