#N canvas 493 38 681 876 12;
#X declare -stdpath ./;
#X obj 40 562 cos~;
#X obj 40 509 *~;
#X obj 83 572 cos~;
#X obj 136 511 wrap~;
#X obj 100 514 -~;
#X obj 83 549 +~;
#X obj 83 610 -~;
#X obj 118 646 *~;
#X obj 100 676 +~;
#X obj 100 484 samphold~;
#X obj 148 371 / 10;
#X obj 148 418 line~;
#X obj 148 395 pack 0 50;
#X obj 40 415 phasor~;
#X text 37 361 fundamental;
#X obj 292 502 line~;
#X obj 223 546 *~;
#X obj 292 479 pack 0 50;
#N canvas 0 0 450 300 (subpatch) 0;
#X array bell-curve 200 float 0;
#A color 0;
#A width 1;
#X coords 0 1 199 0 256 130 1;
#X restore 387 610 graph;
#N canvas 371 467 325 360 make-table 0;
#X obj 75 86 t b b;
#X obj 168 175 f;
#X obj 206 175 + 1;
#X msg 186 145 0;
#X obj 75 125 until;
#X obj 168 210 t f f;
#X obj 70 309 tabwrite bell-curve;
#X obj 68 277 expr exp(-$f1*$f1);
#X obj 82 171 sel 199;
#X obj 68 248 expr ($f1-100)/25;
#X obj 75 55 bng 19 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000;
#X obj 75 24 loadbang;
#X text 101 53 <- rebuild the table;
#X connect 0 0 4 0;
#X connect 0 1 3 0;
#X connect 1 0 2 0;
#X connect 1 0 5 0;
#X connect 1 0 8 0;
#X connect 2 0 1 1;
#X connect 3 0 1 1;
#X connect 4 0 1 0;
#X connect 5 0 9 0;
#X connect 5 1 6 1;
#X connect 7 0 6 0;
#X connect 8 0 4 1;
#X connect 9 0 7 0;
#X connect 10 0 0 0;
#X connect 11 0 10 0;
#X restore 507 812 pd make-table;
#X obj 223 508 cos~;
#X obj 223 485 -~ 0.25;
#X obj 223 580 +~ 100;
#X obj 223 622 tabread4~ bell-curve, f 10;
#X obj 100 715 *~;
#X text 229 661 waveshaper;
#X text 385 744 0;
#X text 629 743 200;
#N canvas 0 0 450 300 (subpatch) 0;
#X array F12-spectrum 259 float 0;
#A color 0;
#A width 1;
#X coords 0 0.51 258 -0.008 256 130 1;
#X restore 387 430 graph;
#X text 384 562 0;
#X text 449 566 -- frequency --;
#X text 610 562 2700;
#X obj 100 796 output~;
#X obj 171 704 bng 19 250 50 0 empty empty empty 0 -6 0 8 #dfdfdf #000000 #000000;
#X obj 191 729 tgl 19 0 empty empty empty 0 -6 0 8 #dfdfdf #000000 #000000 0 1;
#X text 43 49 Instead of using the two cosines as FM carrier oscillators \, we can use them as ring modulators for a natural or synthetic tone. Here we use waveshaping - to wit \, a sinusoid looking up a Gaussian bell curve. This has the nice properties that the partials are always positive cosines in phase \, and the spectrum spreads out smoothly as the index changes., f 85;
#X obj 223 461 *~ 0.5;
#X text 186 343 center frequency (tenths of fundamental), f 16;
#X text 38 700 ring mod step -->, f 8;
#X text 192 703 <-- graph once;
#X text 212 730 <-- repeatedly;
#N canvas 605 126 529 576 fft 0;
#X obj 83 140 inlet~;
#X obj 197 410 inlet;
#X obj 83 272 rfft~;
#X obj 83 305 *~;
#X obj 115 305 *~;
#X obj 115 336 sqrt~;
#X obj 115 362 biquad~ 0 0 0 0 1;
#X text 135 272 Fourier series;
#X text 161 324 magnitude;
#X text 161 309 calculate;
#X text 62 23 This subpatch computes the spectrum of the incoming signal with a (rectangular windowed) FFT. FFTs aren't properly introduced until much later.;
#X text 76 105 signal to analyze, f 9;
#X text 244 357 delay two samples;
#X text 242 375 for better graphing;
#X obj 171 135 samplerate~;
#X obj 214 469 metro 500;
#X obj 214 446 inlet;
#X text 262 444 toggle to graph repeatedly;
#X text 241 411 bang to graph once;
#X obj 115 386 /~ 4096;
#X obj 171 158 / 4096;
#X obj 171 190 osc~;
#X obj 171 218 +~ 1;
#X obj 83 203 *~;
#X text 215 203 hanning window;
#X obj 373 271 block~ 4096;
#X text 375 246 window size;
#X obj 264 102 loadbang;
#X obj 171 242 *~ 0.5;
#X msg 264 148 0.5;
#X obj 197 506 tabwrite~ F12-spectrum;
#X connect 0 0 23 0;
#X connect 1 0 30 0;
#X connect 2 0 3 0;
#X connect 2 0 3 1;
#X connect 2 1 4 0;
#X connect 2 1 4 1;
#X connect 3 0 5 0;
#X connect 4 0 5 0;
#X connect 5 0 6 0;
#X connect 6 0 19 0;
#X connect 14 0 20 0;
#X connect 15 0 30 0;
#X connect 16 0 15 0;
#X connect 19 0 30 0;
#X connect 20 0 21 0;
#X connect 21 0 22 0;
#X connect 22 0 28 0;
#X connect 23 0 2 0;
#X connect 27 0 14 0;
#X connect 27 0 29 0;
#X connect 28 0 23 1;
#X connect 29 0 21 1;
#X restore 152 755 pd fft;
#X obj 77 8 cnv 5 5 25 empty empty PAF:\ Two-Cosine\ Ring\ Modulator\ for\ Waveshaper 15 13 0 16 #dfdfdf #202020 0;
#X floatatom 40 386 4 0 0 0 - \$0-fundamental - 0;
#X floatatom 148 348 4 0 200 0 - \$0-center-freq - 0;
#X floatatom 292 446 4 0 500 0 - \$0-index - 0;
#X text 289 406 index (percent), f 9;
#N canvas 238 316 365 358 init 0;
#X obj 125 294 declare -stdpath ./;
#X obj 131 97 loadbang;
#X text 81 28 This subpatch initializes the patch and loads a value in the number boxes., f 29;
#X obj 131 126 bng 19 250 50 0 empty empty empty 0 -10 0 12 #dfdfdf #000000 #000000;
#X obj 131 153 f \$0;
#X msg 131 183 \; \$1-fundamental 220 \; \$1-center-freq 20 \; \$1-index 10;
#X connect 1 0 3 0;
#X connect 3 0 4 0;
#X connect 4 0 5 0;
#X restore 439 812 pd init;
#X text 43 278 Then with [*~] we do the ring modulation by using the two cosines as the modulating signal and we're done! This is the PAF (phase-aligned formant) synthesis algorithm (patented 1993 by IRCAM \, the patent ran out in 2011)., f 85;
#X text 501 746 100;
#X text 274 567 offset to table's middle, f 9;
#X text 187 482 half sine, f 4;
#X text 43 125 For phase coherency \, the waveshaper and the cosine pair are driven from the same [phasor~] object. For each cycle of the [phasor~] we compute the first half-cycle of the sine function (by multiplying by 0.5 and subtracting 0.25 before the cosine lookup). We apply an index percent to the output of [cos~] and use it for a bell curve table lookup., f 85;
#X text 43 201 The table has 200 points but we're effectively just using the second half of it (a whole table is still desired to avoid interpolation issues with guard points). At phase "0" we start at the top of the gaussian table \, at phase "0.5" we move away to the limit (depending on the index percent parameter) \, then we move back to the center of the table until reaching phase "1"., f 85;
#X connect 0 0 6 1;
#X connect 0 0 8 0;
#X connect 1 0 5 0;
#X connect 1 0 0 0;
#X connect 2 0 6 0;
#X connect 3 0 4 1;
#X connect 3 0 7 1;
#X connect 4 0 1 1;
#X connect 5 0 2 0;
#X connect 6 0 7 0;
#X connect 7 0 8 1;
#X connect 8 0 24 0;
#X connect 9 0 4 0;
#X connect 9 0 3 0;
#X connect 10 0 12 0;
#X connect 11 0 9 0;
#X connect 12 0 11 0;
#X connect 13 0 9 1;
#X connect 13 0 5 1;
#X connect 13 0 1 0;
#X connect 13 0 36 0;
#X connect 15 0 16 1;
#X connect 16 0 22 0;
#X connect 17 0 15 0;
#X connect 20 0 16 0;
#X connect 21 0 20 0;
#X connect 22 0 23 0;
#X connect 23 0 24 1;
#X connect 24 0 41 0;
#X connect 24 0 32 0;
#X connect 33 0 41 1;
#X connect 34 0 41 2;
#X connect 36 0 21 0;
#X connect 43 0 13 0;
#X connect 44 0 10 0;
#X connect 45 0 17 0;
