#N canvas 575 45 564 552 12;
#X declare -stdpath ./;
#X floatatom 269 370 0 0 1000 0 - - - 0;
#X floatatom 94 359 0 0 100 0 - - - 0;
#N canvas 98 23 648 669 fft-analysis 0;
#X obj 35 589 *~;
#X obj 143 305 *~;
#X obj 158 150 *~;
#X obj 35 72 *~;
#X obj 76 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 119 149 *~;
#X obj 119 176 +~;
#X obj 165 278 r mask-level;
#X obj 100 422 /~;
#X obj 355 23 block~ 1024 4;
#X text 176 446 is signal power and "m" is mask.;
#X obj 131 332 -~;
#X obj 131 355 max~ 0;
#X obj 99 448 q8_sqrt~;
#X text 175 464 (zero if s < m).;
#X obj 144 256 tabreceive~ \$0-mask;
#X obj 76 72 tabreceive~ \$0-hann;
#X obj 69 590 tabreceive~ \$0-hann;
#N canvas 91 250 910 495 calculate-mask 0;
#X obj 125 379 inlet~;
#X msg 371 283 0;
#X msg 371 166 0;
#X obj 240 196 float;
#X obj 294 200 + 1;
#X obj 240 144 bang~;
#X obj 240 169 spigot;
#X floatatom 411 218 0 0 0 0 - - - 0;
#X obj 315 408 -~;
#X obj 371 258 sel 0;
#X obj 327 443 *~;
#X obj 293 443 +~;
#X floatatom 351 313 0 0 0 0 - - - 0;
#X obj 240 219 t f f;
#X obj 370 113 r make-mask;
#X obj 371 141 t b f;
#X obj 411 165 /;
#X text 483 212 number of;
#X text 491 227 frames;
#X floatatom 481 166 0 0 0 0 - - - 0;
#X obj 480 113 r window-msec;
#X obj 481 136 / 4;
#X text 521 133 hop size (analysis;
#X text 546 149 period) in msec;
#X obj 359 408 tabreceive~ \$0-mask;
#X obj 292 468 tabsend~ \$0-mask;
#X obj 371 218 <;
#X obj 235 258 expr 1/($f1+1);
#X text 134 17 calculate a mask using N msec of background noise;
#X text 43 354 current power (for each channel);
#X text 367 430 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 390 312 weight to average in new power to mask;
#X text 11 203 loop counting to desired;
#X text 78 219 number of frames;
#X text 72 39 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 connect 0 0 8 0;
#X connect 1 0 12 0;
#X connect 2 0 3 1;
#X connect 2 0 26 0;
#X connect 3 0 13 0;
#X connect 3 0 4 0;
#X connect 4 0 3 1;
#X connect 5 0 6 0;
#X connect 6 0 3 0;
#X connect 7 0 26 1;
#X connect 8 0 10 0;
#X connect 9 0 1 0;
#X connect 10 0 11 1;
#X connect 11 0 25 0;
#X connect 12 0 10 1;
#X connect 13 0 26 0;
#X connect 13 1 27 0;
#X connect 14 0 15 0;
#X connect 15 0 2 0;
#X connect 15 1 16 0;
#X connect 16 0 7 0;
#X connect 20 0 21 0;
#X connect 21 0 16 1;
#X connect 21 0 19 0;
#X connect 24 0 8 1;
#X connect 24 0 11 0;
#X connect 26 0 6 1;
#X connect 26 0 9 0;
#X connect 27 0 12 0;
#X restore 132 203 pd calculate-mask;
#X text 91 98 real Fourier transform;
#X obj 357 57 loadbang;
#X text 193 355 ... but not less than zero;
#X text 101 561 real inverse Fourier transform;
#X text 196 498 normalize by 2/(3N) where N is window size;
#X text 168 332 current power ("s") minus level-adjusted mask ("m")
;
#X text 156 175 compute power (call it "s") in each channel;
#X obj 123 395 +~ 1e-20;
#X text 203 395 protect against division by zero;
#X text 179 426 compute sqrt((s-m)/s) where "s";
#X text 296 204 <- subwindow calculates noise mask;
#X obj 98 499 /~ 1536;
#X msg 357 80 \; window-size 1024;
#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 23 0;
#X connect 11 0 31 0;
#X connect 12 0 1 1;
#X connect 13 0 18 0;
#X connect 16 0 17 0;
#X connect 17 0 13 0;
#X connect 18 0 35 0;
#X connect 20 0 1 0;
#X connect 21 0 3 1;
#X connect 22 0 0 1;
#X connect 25 0 36 0;
#X connect 31 0 13 1;
#X connect 35 0 6 1;
#X connect 35 0 4 1;
#X restore 94 423 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 184 335 noise;
#N canvas 324 211 733 427 insample 0;
#N canvas 0 0 450 300 (subpatch) 0;
#X array \$0-sample 155944 float 0;
#X coords 0 1 155943 -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 269 395 s mask-level;
#X floatatom 189 359 0 0 100 0 - - - 0;
#X text 270 319 on;
#X text 315 320 off;
#X text 270 303 masking;
#X text 107 12 DENOISER;
#X msg 314 343 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 114 loadbang;
#X obj 89 160 metro 1000;
#X obj 246 367 bp~ 10000 3;
#X obj 89 139 tgl 15 0 empty empty empty 0 -6 0 8 #fcfcfc #000000 #000000
0 1;
#X text 232 235 sample duration \, msec;
#X text 95 71 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 94 388 pd test-signal;
#X text 82 332 sampler;
#X text 391 325 calculate noise mask, f 10;
#X obj 94 460 output~;
#X msg 387 360 \; make-mask 2000;
#X msg 269 342 15;
#N canvas 647 275 592 442 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 113 97 graph;
#X text 28 35 This table (1002-mask) is the average power measured
in each channel of the spectrum \, presumed to represent the noise
floor.;
#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 2 0 16 1;
#X connect 7 0 13 1;
#X connect 12 0 0 0;
#X connect 13 0 2 0;
#X connect 18 0 0 0;
