#N canvas 42 28 657 564 12; #X floatatom 316 376 0 0 0 0 - - -; #X floatatom 81 384 0 0 100 0 - - -; #N canvas 98 0 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 - - -; #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 - - -; #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 - - -; #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 msg 357 80 \; pd dsp 1 \; window-size 1024; #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 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 32 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 36 0; #X connect 20 0 1 0; #X connect 21 0 3 1; #X connect 22 0 0 1; #X connect 25 0 26 0; #X connect 32 0 13 1; #X connect 36 0 6 1; #X connect 36 0 4 1; #X restore 80 441 pd fft-analysis; #N canvas 0 110 565 454 hann-window 0; #N canvas 0 0 450 300 graph1 0; #X array \$0-hann 1024 float 0; #X coords 0 1 1023 0 300 100 1; #X restore 82 311 graph; #X obj 378 165 osc~; #X obj 378 190 *~ -0.5; #X obj 378 214 +~ 0.5; #X obj 331 247 tabwrite~ \$0-hann; #X obj 37 88 r window-size; #X obj 38 173 /; #X obj 127 142 samplerate~; #X obj 38 251 s window-sec; #X obj 177 204 swap; #X obj 177 228 /; #X obj 177 252 s window-hz; #X obj 49 201 * 1000; #X obj 49 228 s window-msec; #X obj 38 115 t f b f; #X msg 173 92 resize \$1; #X obj 173 116 s \$0-hann; #X obj 330 105 r window-hz; #X msg 382 130 0; #X obj 330 131 t f b; #X text 15 8 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).; #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 331 478 pd hann-window; #X text 197 355 noise; #N canvas 132 255 660 373 insample 0; #N canvas 0 0 450 300 graph1 0; #X array \$0-sample 155948 float 0; #X coords 0 1 155947 -1 400 150 1; #X restore 236 25 graph; #X obj 19 23 r read-sample; #X obj 19 74 unpack s f; #X obj 116 74 s insamprate; #X obj 19 184 soundfiler; #X obj 19 208 s insamplength; #X text 113 252 read a sample; #X obj 33 251 loadbang; #X obj 19 100 t s b; #X obj 75 99 symbol \$0-sample; #X obj 19 135 pack s s; #X msg 19 160 read -resize \$1 \$2; #X obj 74 46 44100; #X msg 33 275 \; read-sample ../sound/bell.aiff; #X msg 31 322 \; read-sample ../sound/voice.wav; #X obj 19 47 t a b; #X connect 1 0 15 0; #X connect 2 0 8 0; #X connect 2 1 3 0; #X connect 4 0 5 0; #X connect 7 0 13 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 12 0 3 0; #X connect 15 0 2 0; #X connect 15 1 12 0; #X restore 331 456 pd insample; #X obj 316 401 s mask-level; #X floatatom 202 379 0 0 100 0 - - -; #X text 317 325 on; #X text 362 326 off; #X text 317 309 masking; #X text 290 5 DENOISER; #X msg 361 349 0; #N canvas 190 43 812 571 test-signal 0; #X obj 75 328 line~; #X obj 75 250 f; #X obj 251 164 r insamprate; #X obj 583 219 *~; #X obj 76 442 *~; #X obj 583 110 noise~; #X obj 370 493 +~; #X obj 98 415 dbtorms; #X obj 605 193 dbtorms; #X obj 98 390 inlet; #X obj 605 169 inlet; #X obj 371 541 outlet~; #X obj 236 139 r insamplength; #X msg 75 304 0 \, \$1 \$2; #X obj 75 276 pack 0 0; #X obj 236 248 /; #X obj 251 190 * 0.001; #X obj 251 219 t b f; #X obj 370 516 hip~ 5; #X obj 75 136 loadbang; #X obj 75 182 metro 1000; #X obj 583 135 bp~ 10000 3; #X obj 75 161 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1 ; #X text 270 247 sample duration \, msec; #X text 126 84 looped sample playback; #X obj 75 356 tabread4~ \$0-sample; #X text 580 83 filtered noise; #X text 105 15 TEST SIGNAL: looped sample plus noise. The inlets control amplitude of each in dB.; #X connect 0 0 25 0; #X connect 1 0 14 0; #X connect 2 0 16 0; #X connect 3 0 6 1; #X connect 4 0 6 0; #X connect 5 0 21 0; #X connect 6 0 18 0; #X connect 7 0 4 1; #X connect 8 0 3 1; #X connect 9 0 7 0; #X connect 10 0 8 0; #X connect 12 0 1 1; #X connect 12 0 15 0; #X connect 13 0 0 0; #X connect 14 0 13 0; #X connect 15 0 14 1; #X connect 15 0 20 1; #X connect 16 0 17 0; #X connect 17 0 15 0; #X connect 17 1 15 1; #X connect 18 0 11 0; #X connect 19 0 22 0; #X connect 20 0 1 0; #X connect 21 0 3 0; #X connect 22 0 20 0; #X connect 25 0 4 0; #X restore 81 409 pd test-signal; #X text 69 357 sampler; #X text 443 311 calculate noise mask; #X obj 80 488 output~; #X msg 462 338 \; make-mask 2000; #X msg 316 348 15; #N canvas 0 0 592 442 mask-table 0; #N canvas 0 0 450 300 graph1 0; #X array \$0-mask 512 float 0; #X coords 0 500 511 0 400 300 1; #X restore 110 76 graph; #X text 25 14 This table ($0-mask) is the average power measured in each channel of the spectrum \, presumed to represent the noise floor. ; #X restore 331 500 pd mask-table; #X text 80 322 amplitudes (dB); #X text 68 26 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.; #X text 67 149 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 hte 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).; #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;