Clap clap clap! Bravo, that was brilliant. Let's add it to the wiki somewhere!
~Kyle On 2/20/07, Frank Barknecht <[EMAIL PROTECTED]> wrote: > Hallo, > Kevin McCoy hat gesagt: // Kevin McCoy wrote: > > > I am still pretty new at FFT things but I am having a lot of fun. I know > > Tom Erbe's soundhack has something called a "spectral gate" so I thought I'd > > give it a shot and try to make my own in Pd after reading about it. Doesn't > > sound all that great, it actually ends up sounding like a really low quality > > wma file or something :) > > > > Is this technically a spectral gate? I'm using [>~] from zexy which in my > > mind says, "Look at all of the frequencies in the block and only allow those > > which are above value x to pass through." I've attached the patch here - > > any info or guidance is much appreciated. Any sound that goes through it > > pretty much loses all definition and clarity - is there a fix for this? > > I'm not really sure what spectral gate does, but you've probably seen > doc/3.audio.examples/I03.resynthesis.pd which is a kind of equalizer > or multiband-filter. > > Maybe you've taken this patch as a model for your patch. But then some > things are wrong in your adaption. First: [tabreceive $0-hann] will > not receive anything, because [table $0-hann] is missing. So it will > only output zeros. Either remove the multiplication with $0-hann, or > add the [pd Hann-window] to the patch. > > But the real (and imaginary) mistake is the actual "gating" with [>~]. > If you open the fft~-help.pd file (Help on rfft~), and print~ what > comes out of rfft~'s outlets, you will see something like this: > > real: > 0.00016968 -4.6019e-07 -2.1632e-07 -3.2469e-07 -9.2026e-07 32 > -7.499e-07 -3.2501e-07 > -3.1411e-07 -9.6657e-07 -6.2494e-05 -1.4388e-06 -5.035e-07 -5.0472e-07 > -1.665e-06 -2.3571e-05 > -5.8313e-07 -7.5066e-08 -6.2174e-07 -2.1764e-06 -1.0339e-05 -1.8991e-06 > -3.5305e-07 1.376e-07 > -2.2529e-06 -4.486e-06 -4.1878e-07 -1.9073e-06 -5.2361e-07 -1.7626e-06 > -2.8447e-06 -2.943e-07 > -7.6485e-08 0 0 0 0 0 0 0 > 0 0 0 0 0 0 0 0 > 0 0 0 0 0 0 0 0 > 0 0 0 0 0 0 0 0 > imaginary: > 0 -2.7462e-09 1.9217e-07 -1.4215e-06 -1.0745e-07 -0.00013828 > 1.4264e-07 -2.5163e-07 > 1.0069e-07 3.7871e-07 -5.0489e-06 2.0548e-06 -1.8181e-08 -4.5923e-07 > 1.5607e-07 -6.6416e-06 > -2.0862e-07 -5.8076e-07 6.2139e-08 -3.0756e-07 -4.1732e-06 6.2431e-07 > -2.9043e-07 -5.2873e-07 > -2.2713e-07 -3.1568e-06 -1.1066e-07 -0 -2.0931e-07 -3.162e-07 > -6.2198e-07 -2.3119e-07 > 0 0 0 0 0 0 0 0 > 0 0 0 0 0 0 0 0 > 0 0 0 0 0 0 0 0 > 0 0 0 0 0 0 0 0 > > Now if you clip this with [>~ 0.8] you will get a series of 0 and 1 in > each of these numbers. It might sound funky, but it's not what you > want to achieve. > > So lets first have a look at what [rfft~] does: It will give you two > signals. One is called the real, the other the imaginary part, but > lets forget about this for now and look at it from a bit afar: > > Generally a FFT will do a spectral analysis. It will calculate, what > sine waves you need to add up to get the same signal as that played in > the current signal block. Basically it will tell you the frequencies > and phases (first and second inlets) and amplitudes of a lot of [osc~] > objects that, if you add them all up, would resynthesize your current > signal. (You cannot directly use these [osc~] objects to resynthesize > what comes from rfft~ but lets for a moment assume that we could.) > > How many [osc~] objects you can control, will depend on the > block-size: The FFT will generate control data for blocksize/2 > oscillators. So with a blocksize of 64, you get frequencies, phase and > amplitudes for 32 osc~s. > > Now for some deep mathematical reasons all these [osc~] objects have > fixed tunings: They all are multiples (harmonics) of > Samplerate/Blocksize. So it starts at f0 = 0 Hertz, the next [osc~] > would have a frequency f1= 1 * SR/BS, the next at f2=2*SR/BS up to the > final one: f_final = (BS/2) * SR/BS == SR/2 or the Nyquist-frequency. > For a blocksize of 16 and a samplerate of 48000 Hz this would be: > > f0: 0 > f1: 1 * 48000/16 = 3000 > f2: 2 * 48000/16 = 6000 > ... > f32: 8 * 48000/16 = 24000 > > (Actually of course these are bs/2 + 1 frequencies, but 0 and Nyquist > are special anyway so I thought I could cheat a bit. ;)) > > Because the frequencies are fixed and known, the rfft~ object doesn't > need to specify them explicitly. It only needs to calculate the > amplitude and the phase of every partial [osc~]. > > Now the tricky parts to understand are these: > > [rfft~] will not directly output the amplitudes and the phases, but > this strange thing called real and imaginary part. These carry exactly > the same information about amplitude and phase, but encoded a bit > differently than you are probably used to from working with [osc~]: > > They are specified in a kind of polar coordinate system, where the > amplitude is the radius (or distance from origin) and the phase is the > angle of the polar coordinates. Re and Im however are cartesian > coordinates (in the complex plane). > > You can convert re/img-pairs to amplitude and phase using these > formulas: > > amp = sqrt(re^2 + im^2) > phs = arctan(re/im) > > This is a standard cartesian to polar conversion. > > Most of the time you can skip calculating the phase, but more on that > later. > > The amplitude calculation in Pd lingo looks like this: > > amp: > > [rfft~] > |\ |\ > [*~] [*~] > | / > | / > [+~ ] <= just inserted for clarity, you can also directly go to sqrt~ > | > [sqrt~] or [q8_sqrt~], which is much faster. > > > The real and imaginary part (or the phase and amplitudes) are encoded > inside the signal blocks, that [rfft~] outputs. The first pair of > samples of the left and right outlet~s of [rfft~] contains the info > about amplitude and phase for the first [osc~] in our big oscillator > bank, that has frequency f0. Each second sample pair contains info for > the next osc~ with frequency f1 and so on up to the sample pair number > "blocksize/2", which contains the amp and phase for the final > oscillator at Nyquist frequency. The rest of the block always is zero, > as we don't have oscillators for that. > > Some real world data might be useful: Assume we have a blocksize of 8. > Then a block of samples might look like this, when print~ed: > > orig: > 0.13004 0.26951 0.40352 0.52934 0.64446 0.74649 0.83341 0.90344 > > If you send this through [rfft~] you will get this: > > img: > 0 1.0317 0.41679 0.17191 0 0 0 0 > > re: > 4.4602 -0.58717 -0.46243 -0.44167 -0.43737 0 0 0 > > Sending these two to [rifft~] and dividing by blocksize 8 will give > you the the original signal block back. > > You can also calculate the amplitudes like above, which of course is > easy for our first sample: amp = sqrt(4.4602^2 + 0^2) = 4.4602 > > Actually to get the correct amplitudes you would need to normalize the > re/im pairs here as well by dividing them by 8, I just skipped that. > > Here's the full scoop: > > amp: > 4.4602 1.1871 0.62254 0.47394 0.43737 0 0 0 > > See attached "fft-up-close.pd" to try this on your own. > > This means, that resynthesizing this signal at SR=48000 would be > similar to using oscillators like this: > > [osc~ 0] > | > [*~ 4.4602] > > [osc~ 6000] > | > [*~ 1.1871] > > [osc~ 12000] > | > [*~ 0.62254] > > [osc~ 18000] > | > [*~ 0.47394] > > ... > > and so on (Note that without normalizing these values are to loud.) > > However: All these oscillators would also need to have their phases > set accordingly, so you cannot just use above oscillator bank directly > in real life. > > The inverse FFT objects like [rifft~] will accept the amplitude and > phase information in the real/imaginary format directly. This means, > you can think of the [rifft~] as a resynthesis bank of blocksize/2 > oscillators like above with real and imaginary inputs instead of > amplitude and phase input, and every oscillator inside [rifft~] is > spaced Samplerate/Blocksize Hertz apart. > > As fft~-help.pd and my calculation above shows, connecting an [rfft~] > to a [rifft~] will just pass the signal practically unchanged (it's > just a bit louder afterwards, that's why you normally normalize it by > dividing the output by the blocksize like [/~ 64]). Depending on > Windowing and Overlap you need to use a different normalization > factor. > > Of course it will only get interesting if we wreck havoc to the re/im > frequency data in the meantime. > > A simple FFT-based modification is shown in I03.resynthesis.pd: Here > every re/im sample pair (or every amplitude/phase-info for the > respective "oscillator" in rifft~) is multiplied by some value > retrieved from the gain table through tabreceive~. If this table has a > 1 at a certain sample, this data is passed unchanged, if it has a 0 at > another sample, than that oscillator is muted. This is a filter > operation, and it only affects the amplitudes of the internal > oscillators. > > You might ask: "Why only the amplitudes? What about the phases? You > said, they are also encoded in the re/im data? Are you cheating > again?!" Read on. > > If we scale the re/im pair by a value x, then the amplitudes will be > scaled by x as well: > > amp(x*re,x*im) = sqrt((x * re)^2 + (x * im)^2) > = sqrt (x^2 * (re^2+im^2)) > = sqrt(x^2) * sqrt(re^2+im^2) > = x * amp(re,im) > > However the phases will stay the same! Proof: > > phs(x*re,x*im) = atan(x*re/x*im) = atan(re/im) = phs(re,im) > > Get it? That's why for such modifications you can omit the phase > calculation with atan etc. > > Note that you need to do this multiplication *on every block* again > and again, because the data coming out of [rfft~] is constantly > updated - it still is an audio signal! That's why a [tabreceive~] is > used: Although the table received is not changing all the time, we > still need to read it again on every block and make a signal out of > it. > > Now for a simple, amplitude-dependent gating or filtering, you first > need to calculate the actual amplitude using the formula above. Then > compare it to a value and multiply the original re/im-pairs with 0 or > 1 depending on the result to change the amplitudes used in the > resynthesis. > > Attached specgate.pd illustrates this and also has a comparison of the > windowed and unwindowed fft, that affects the quality of the result > and also your normalization factors. > > Ciao > -- > Frank Barknecht _ ______footils.org_ __goto10.org__ > > _______________________________________________ > [email protected] mailing list > UNSUBSCRIBE and account-management -> > http://lists.puredata.info/listinfo/pd-list > > > -- http://theradioproject.com http://perhapsidid.blogspot.com (((())))(()()((((((((()())))()(((((((())()()())()))) (())))))(()))))))))))))(((((((((((()()))))))))((()))) ))(((((((((((())))())))))))))))))))__________ _____())))))(((((((((((((()))))))))))_______ ((((((())))))))))))((((((((000)))oOOOOOO _______________________________________________ [email protected] mailing list UNSUBSCRIBE and account-management -> http://lists.puredata.info/listinfo/pd-list
