#N canvas 496 32 564 552 12;
#X declare -stdpath ./;
#X floatatom 274 372 4 0 1000 0 - - - 0;
#X floatatom 82 358 6 0 100 0 - - - 0;
#N canvas 453 53 560 665 fft-analysis 0;
#X obj 35 589 *~;
#X obj 142 287 *~;
#X obj 151 150 *~;
#X obj 35 72 *~;
#X obj 74 527 *~;
#X obj 35 44 inlet~;
#X obj 35 528 *~;
#X obj 34 101 rfft~;
#X obj 35 558 rifft~;
#X obj 36 616 outlet~;
#X obj 112 149 *~;
#X obj 112 176 +~;
#X obj 160 260 r mask-level;
#X obj 93 422 /~;
#X obj 355 23 block~ 1024 4;
#X text 169 446 is signal power and "m" is mask.;
#X obj 124 312 -~;
#X obj 124 338 max~ 0;
#X text 168 464 (zero if s < m).;
#X obj 142 236 tabreceive~ \$0-mask;
#X obj 76 72 tabreceive~ \$0-hann;
#X obj 69 590 tabreceive~ \$0-hann;
#N canvas 459 59 615 568 calculate-mask 0;
#X obj 37 99 inlet~;
#X msg 279 316 0;
#X msg 279 199 0;
#X obj 202 233 + 1;
#X obj 148 177 bang~;
#X obj 148 202 spigot;
#X floatatom 319 251 7 0 0 0 - - - 0;
#X obj 37 397 -~;
#X obj 279 286 sel 0;
#X obj 37 430 *~;
#X obj 102 488 +~;
#X floatatom 279 346 9 0 0 0 - - - 0;
#X obj 148 252 t f f;
#X obj 278 137 r make-mask;
#X obj 279 174 t b f;
#X obj 319 207 /;
#X floatatom 369 202 8 0 0 0 - - - 0;
#X obj 368 137 r window-msec;
#X obj 369 169 / 4;
#X text 409 166 hop size (analysis;
#X text 434 182 period) in msec;
#X obj 102 344 tabreceive~ \$0-mask;
#X obj 102 522 tabsend~ \$0-mask;
#X obj 279 251 <;
#X text 228 21 calculate a mask using N msec of background noise;
#X text 30 48 current power (for each channel), f 14;
#X text 164 425 average the current power into the last mask to get the new mask. The new value is weighted 1/n on the nth iteration.;
#X text 350 340 weight to average in new power to mask, f 20;
#X text 166 43 This loops for "make-mask" milliseconds \, averaging power in each channel over that amount of time. This is done by a moving average whose weight is adjusted to average each new value equally with each of the accumulating ones.;
#X text 391 245 number of frames;
#X text 61 191 loop counting to desired number of frames, f 10;
#X obj 148 229 f;
#X obj 180 278 + 1;
#X obj 180 302 expr 1/$f1;
#X connect 0 0 7 0;
#X connect 1 0 11 0;
#X connect 2 0 23 0;
#X connect 2 0 31 1;
#X connect 3 0 31 1;
#X connect 4 0 5 0;
#X connect 5 0 31 0;
#X connect 6 0 23 1;
#X connect 7 0 9 0;
#X connect 8 0 1 0;
#X connect 9 0 10 1;
#X connect 10 0 22 0;
#X connect 11 0 9 1;
#X connect 12 0 23 0;
#X connect 12 1 32 0;
#X connect 13 0 14 0;
#X connect 14 0 2 0;
#X connect 14 1 15 0;
#X connect 15 0 6 0;
#X connect 17 0 18 0;
#X connect 18 0 15 1;
#X connect 18 0 16 0;
#X connect 21 0 7 1;
#X connect 21 0 10 0;
#X connect 23 0 5 1;
#X connect 23 0 8 0;
#X connect 31 0 12 0;
#X connect 31 0 3 0;
#X connect 32 0 33 0;
#X connect 33 0 11 0;
#X restore 129 203 pd calculate-mask;
#X text 91 98 real Fourier transform;
#X obj 357 57 loadbang;
#X text 186 338 ... but not less than zero;
#X text 87 558 real inverse Fourier transform;
#X text 151 500 normalize by 2/(3N) where N is window size;
#X text 161 312 current power ("s") minus level-adjusted mask ("m");
#X text 149 175 compute power (call it "s") in each channel;
#X obj 111 398 +~ 1e-20;
#X text 177 398 protect against division by zero;
#X text 172 426 compute sqrt((s-m)/s) where "s";
#X obj 92 499 /~ 1536;
#X msg 357 80 \; window-size 1024;
#X text 257 203 <-- subwindow calculates noise mask;
#X obj 92 448 sqrt~;
#X connect 0 0 9 0;
#X connect 1 0 16 1;
#X connect 2 0 11 1;
#X connect 3 0 7 0;
#X connect 4 0 8 1;
#X connect 5 0 3 0;
#X connect 6 0 8 0;
#X connect 7 0 6 0;
#X connect 7 0 10 0;
#X connect 7 0 10 1;
#X connect 7 1 4 0;
#X connect 7 1 2 0;
#X connect 7 1 2 1;
#X connect 8 0 0 0;
#X connect 10 0 11 0;
#X connect 11 0 16 0;
#X connect 11 0 22 0;
#X connect 11 0 30 0;
#X connect 12 0 1 1;
#X connect 13 0 36 0;
#X connect 16 0 17 0;
#X connect 17 0 13 0;
#X connect 19 0 1 0;
#X connect 20 0 3 1;
#X connect 21 0 0 1;
#X connect 24 0 34 0;
#X connect 30 0 13 1;
#X connect 33 0 6 1;
#X connect 33 0 4 1;
#X connect 36 0 33 0;
#X restore 82 422 pd fft-analysis;
#N canvas 459 123 514 524 hann-window 0;
#N canvas 0 0 450 300 (subpatch) 0;
#X array \$0-hann 1024 float 0;
#X coords 0 1 1023 0 300 100 1;
#X restore 110 394 graph;
#X obj 327 184 osc~;
#X obj 327 209 *~ -0.5;
#X obj 327 233 +~ 0.5;
#X obj 310 276 tabwrite~ \$0-hann;
#X obj 86 113 r window-size;
#X obj 157 237 /;
#X obj 175 205 samplerate~;
#X obj 157 315 s window-sec;
#X obj 67 251 swap;
#X obj 67 275 /;
#X obj 67 299 s window-hz;
#X obj 168 265 * 1000;
#X obj 168 292 s window-msec;
#X obj 86 148 t f b f;
#X msg 175 155 resize \$1;
#X obj 175 179 s \$0-hann;
#X obj 279 122 r window-hz;
#X msg 352 154 0;
#X obj 279 150 t f b;
#X text 56 20 calculate Hann window table (variable window size) and constants window-hz (fundamental frequency of analysis) \, window-sec and window-msec (analysis window size in seconds and msec)., f 56;
#X connect 1 0 2 0;
#X connect 2 0 3 0;
#X connect 3 0 4 0;
#X connect 5 0 14 0;
#X connect 6 0 8 0;
#X connect 6 0 12 0;
#X connect 7 0 6 1;
#X connect 7 0 9 1;
#X connect 9 0 10 0;
#X connect 9 1 10 1;
#X connect 10 0 11 0;
#X connect 12 0 13 0;
#X connect 14 0 6 0;
#X connect 14 0 9 0;
#X connect 14 1 7 0;
#X connect 14 2 15 0;
#X connect 15 0 16 0;
#X connect 17 0 19 0;
#X connect 18 0 1 1;
#X connect 19 0 1 0;
#X connect 19 1 4 0;
#X connect 19 1 18 0;
#X restore 354 467 pd hann-window;
#X text 172 334 noise;
#N canvas 324 211 733 427 insample 0;
#N canvas 0 0 450 300 (subpatch) 0;
#X array \$0-sample 155944 float 2;
#X coords 0 1 155944 -1 400 150 1;
#X restore 282 77 graph;
#X obj 65 65 r read-sample;
#X obj 65 126 unpack s f;
#X obj 162 126 s insamprate;
#X obj 65 236 soundfiler;
#X obj 65 260 s insamplength;
#X text 159 304 read a sample;
#X obj 79 303 loadbang;
#X obj 65 152 t s b;
#X obj 118 158 symbol \$0-sample;
#X obj 65 187 pack s s;
#X msg 65 212 read -resize \$1 \$2;
#X msg 79 327 \; read-sample ../sound/bell.aiff;
#X msg 77 374 \; read-sample ../sound/voice.wav;
#X obj 65 99 t a b;
#X obj 162 98 f 44100;
#X connect 1 0 14 0;
#X connect 2 0 8 0;
#X connect 2 1 3 0;
#X connect 4 0 5 0;
#X connect 7 0 12 0;
#X connect 8 0 10 0;
#X connect 8 1 9 0;
#X connect 9 0 10 1;
#X connect 10 0 11 0;
#X connect 11 0 4 0;
#X connect 14 0 2 0;
#X connect 14 1 15 0;
#X connect 15 0 3 0;
#X restore 354 445 pd insample;
#X obj 274 397 s mask-level;
#X floatatom 177 358 6 0 100 0 - - - 0;
#X text 275 311 on;
#X text 320 312 off;
#X text 275 295 masking;
#X text 107 12 DENOISER;
#X msg 319 335 0;
#N canvas 500 29 431 582 test-signal 0;
#X obj 89 316 line~;
#X obj 213 152 r insamprate;
#X obj 246 451 *~;
#X obj 90 430 *~;
#X obj 246 342 noise~;
#X obj 228 483 +~;
#X obj 108 403 dbtorms;
#X obj 264 425 dbtorms;
#X obj 108 378 inlet;
#X obj 264 401 inlet;
#X obj 228 538 outlet~;
#X obj 198 127 r insamplength;
#X msg 89 292 0 \, \$1 \$2;
#X obj 198 236 /;
#X obj 213 178 * 0.001;
#X obj 213 207 t b f;
#X obj 228 509 hip~ 5;
#X obj 89 104 loadbang;
#X obj 89 160 metro 1000;
#X obj 246 367 bp~ 10000 3;
#X obj 89 129 tgl 19 0 empty empty empty 0 -6 0 8 #dfdfdf #000000 #000000 0 1;
#X text 232 235 sample duration \, msec;
#X text 95 69 looped sample playback;
#X obj 89 344 tabread4~ \$0-sample;
#X text 243 315 filtered noise;
#X text 56 20 TEST SIGNAL: looped sample plus noise. The inlets control amplitude of each in dB., f 42;
#X obj 89 265 pack float float;
#X obj 89 238 float;
#X connect 0 0 23 0;
#X connect 1 0 14 0;
#X connect 2 0 5 1;
#X connect 3 0 5 0;
#X connect 4 0 19 0;
#X connect 5 0 16 0;
#X connect 6 0 3 1;
#X connect 7 0 2 1;
#X connect 8 0 6 0;
#X connect 9 0 7 0;
#X connect 11 0 13 0;
#X connect 11 0 27 1;
#X connect 12 0 0 0;
#X connect 13 0 18 1;
#X connect 13 0 26 1;
#X connect 14 0 15 0;
#X connect 15 0 13 0;
#X connect 15 1 13 1;
#X connect 16 0 10 0;
#X connect 17 0 20 0;
#X connect 18 0 27 0;
#X connect 19 0 2 0;
#X connect 20 0 18 0;
#X connect 23 0 3 0;
#X connect 26 0 12 0;
#X connect 27 0 26 0;
#X restore 82 387 pd test-signal;
#X text 76 332 sampler;
#X text 418 323 calculate noise mask, f 10;
#X obj 82 459 output~;
#X msg 414 358 \; make-mask 2000;
#X msg 274 334 15;
#N canvas 647 275 498 424 mask-table 0;
#N canvas 0 0 450 300 (subpatch) 0;
#X array \$0-mask 512 float 0;
#X coords 0 500 511 0 400 300 1;
#X restore 49 96 graph;
#X text 108 22 This table is the average power measured in each channel of the spectrum \, presumed to represent the noise floor., f 41;
#X restore 354 489 pd mask-table;
#X text 99 301 amplitudes (dB);
#X text 50 47 This patch attempts to scrub the noise floor from a sample in two steps. First using the "make-mask" message (which is caught in the "fft-analysis" window) \, you estimate the background spectrum. You would normally do this at a moment when only the background noise is audible. Then \, turn on "masking" (to 15 by default \, but try other values) and the patch will try to clean the background noise out of a signal., f 65;
#X text 50 153 For this demonstration \, you control the amplitudes of a looping sample and a filtered noise source. Normally you'd hit "calculate noise mask" with only the noise turned on \, then turn both the noise and the sampler on \, and also "masking" \, to see if the patch can clean the noise out of the signal. Open the "fft-analysis" window to see the algorithm \, or the "insample" window to change samples \, or "mask-table" to see the current mask (the average signal power of the noise to clean out of the signal)., f 65;
#X obj 396 13 declare -stdpath ./;
#X connect 0 0 6 0;
#X connect 1 0 13 0;
#X connect 2 0 16 0;
#X connect 7 0 13 1;
#X connect 12 0 0 0;
#X connect 13 0 2 0;
#X connect 18 0 0 0;
