SuperCollider Forum
May 20, 2013, 02:57:22 PM *
Welcome, Guest. Please login or register.

Login with username, password and session length
News: The SuperCollider forum is currently experiencing a rash of spambot registrations. New user requests may not be approved quickly as a result -- and if your email address looks like spam, it might not be approved at all. We are working to improve the security of the registration process, and to provide alternate means to contact the administrators to get a new account. Thanks for your patience.
 
   Home   Help Search Calendar Login Register  
Pages: [1]
  Print  
Author Topic: Viewing spectral data  (Read 3725 times)
0 Members and 1 Guest are viewing this topic.
eclectici
Newbie
*

Karma: 0
Posts: 4


View Profile
« on: October 29, 2008, 06:25:25 AM »

Hey all,

I just want to be able to take one FFT Window and view all the frequencies within it at the highest possible resolution as possible. Any suggestions?

cheers

- eclectici
Logged
dewdrop_world
AdminGroup
Full Member
*

Karma: 9
Posts: 193



View Profile WWW
« Reply #1 on: October 29, 2008, 08:10:32 AM »

If you want a graphical view, SCFreqScope (accessed more easily by s.freqscope -- on mac you must use the internal server) is pretty good.

If you want numbers... the math is very, very difficult. (How's your trigonometry of complex numbers?) FFT doesn't give you a straightforward set of frequencies, phases and amplitudes... sorry I don't have a good resource handy and not much time at the moment. I can explain more of the "why" next week (but not how to get around it), unless someone else jumps in.

hjh
Logged

eclectici
Newbie
*

Karma: 0
Posts: 4


View Profile
« Reply #2 on: October 29, 2008, 08:42:09 AM »

Thanks for the quick response dewdrop. I was really hoping there would be an object available which would just give me a table of each bin value and then...  The Frequency of each Bin = SampleRate/WindowSize *Bin Number - I think thats right.

Basically I want to be able to create a 'look up table' so that I would have all the frequency component data of say a cello playing a low G stored in a buffer, which I could then access and use to tell an eq what frequencies exist in that short sample of sound and target those frequencies.

From what I can gather UnpackFFT displays the Magnitude and Phase of each frequency bin but you can only post about 10 bins before it crashes, and I can't figure out how to permanently store all the data or limit it to a single high resolution window.

PV_RecordBuf records the data to a buffer, but I have no idea how to view the data on a buffer, all the examples I can find are to play back the data from a buffer.

PV_FreqBuffer seems to determine the frequency information and store it to a buffer, but again I can't figure out how to access the buffer to simply view the data stored there.

Any sugguestions/comments/questions welcome and appreciated

- eclectici

Logged
dewdrop_world
AdminGroup
Full Member
*

Karma: 9
Posts: 193



View Profile WWW
« Reply #3 on: October 29, 2008, 06:26:41 PM »

My understanding, from Gareth Loy's Musimathics, is that the FFT result shows the energy of frequencies in the input sound (that don't line up exactly with the center frequency of a bin) in multiple bins - part of the energy goes in the nearest bin, and the remainder goes into other bins (which may or may not be adjacent). FFT data are good for PV_ and IFFT operations, but not much else. They aren't human readable.

You can do an FFT of a single window in the client -

Code:
a = Signal.sineFill(128, [1]);
f = a.fft(Signal.newClear(a.size), Signal.fftCosTable(a.size));

... where a is the sample data (size must be a power of 2). f.real are magnitudes, f.imag are phases.

Posting a time-variant fft analysis using UnpackFFT is a good way to flood the post buffer (and crash the system) and give you way too much data to read. I'd suggest starting with time-invariant fft in the client as above to start with.

hjh
Logged

eclectici
Newbie
*

Karma: 0
Posts: 4


View Profile
« Reply #4 on: October 30, 2008, 08:17:00 AM »

Hey, I found the block of code I needed as part of the FFT overview, I just kept looking over it.

b = Buffer.alloc(s,1024);
   a = { FFT(b, LFSaw.ar(4000)); 0.0 }.play;
   (
   b.getn(0, 1024, { arg buf;
      var z, x;
      z = buf.clump(2).flop;
      z = [Signal.newFrom(z[0]), Signal.newFrom(z[1])];
      x = Complex(z[0], z[1]);
      {x.magnitude.plot}.defer
   })
   )
   a.free; b.free;

Its just a matter of replacing the plot with a post to get a read out. I don't entirely understand how it works though which is frustrating. I'm just going to have to research more.


I understand that a buffer is being allocated to the server with 1024 frames. An FFT analysis is then being done on an LFSaw and the data is being stored into that buffer with a window that doesn't overlap at all. The getn message is using the index 0 to just get the first window of data and returning all 1024 values/frames.

It's from here that I get fuzzy. The function is obviously the action to actually get the values and in this case plot the amplitude peaks. But I'm unfimilliar with the .clump and flop arguments and until dewdrops post I was unaware of the Signal and Complex classes. So I'm going to have to look at their help files to understand them better.

Sorry about the rant, I'm working through my though processes as much as asking for help.

Thanks for all the help

p.s. I am aware that your code does much a similar thing dewdrop, but It doesn't seem to read from a buffer which I would like to do so I can analyse an audio file and this approach makes a bit more sense although still a little fuzzy. Again thanks for the help, it certainly gave me more perspective and pointed me in the right direction.

- Luke (eclectici)
« Last Edit: October 30, 2008, 08:30:35 AM by eclectici » Logged
dewdrop_world
AdminGroup
Full Member
*

Karma: 9
Posts: 193



View Profile WWW
« Reply #5 on: November 01, 2008, 07:31:58 AM »

If you .getn audio data, rather than fft data, from a buffer, then you can use the client-side Signal fft for a time-invariant fft analysis.

Code:
b.getn(0, n, action: { |data|
  f = data.as(Signal).fft(Signal.newClear(data.size), Signal.fftCosTable(data.size));
});

Then you can iterate or do whatever with f.real (magnitudes).

Something like that... don't have time to test now.
hjh
Logged

joshp
AdminGroup
Full Member
*

Karma: 5
Posts: 121



View Profile WWW
« Reply #6 on: November 02, 2008, 04:23:38 AM »

Using the getn approach, you can use PV_FreqBuffer, and the data will already be calc'd for you.

Josh
Logged
eclectici
Newbie
*

Karma: 0
Posts: 4


View Profile
« Reply #7 on: November 02, 2008, 05:04:25 AM »

Thanks Josh,

I have actually been trying with the PV_FreqBuffer, but I can't seem to get it to work with the getn approach. I think its the way I'm structuring the code, but am uncertain as to what I'm doing wrong.

Its throwing an error when I try and attach the rtf file so apologies for the excess of code on the screen.

Code:
/*
This is the example from FFT overview.
It plots the magnitude increases accross the bins.
It is also possible to  post the data.
Sample Rate/ Window Size * Bin Number determinse the frequency range of each bin. With a large window size this would make it possible to get a high frequency resolution. If I then ran all the bins through a mathmatical function to determine there frequency I would have a list of all the frequencies and there magnitude.
*/

b = Buffer.alloc(s,1024);
a = { FFT(b, LFSaw.ar(4000)); 0.0 }.play;
(
b.getn(0, 1024, { arg buf;
var z, x;
z = buf.clump(2).flop;
z = [Signal.newFrom(z[0]), Signal.newFrom(z[1])];
x = Complex(z[0], z[1]);
{x.magnitude.plot}.defer //x.magnitude.post
})
)
a.free; b.free;

/*
In this example I have tried to use the same approach to give a read out of the frequencies determined by the PV_FreqBuffer as to by pass trying to determine this myself. However This doesn't seem to work as it is still trying to determine a magnitude and I'm not sure how to alter the code to display frequency data
*/
b = Buffer.alloc(s,1024);
a = { FFT(b, LFSaw.ar(4000)); 0.0 }.play;
c = { PV_FreqBuffer(a, 512) }.play;
(
c.getn(0, 512, { arg buf;
var z, x;
z = buf.clump(2).flop;
z = [Signal.newFrom(z[0]), Signal.newFrom(z[1])];
x = Complex(z[0], z[1]);
{x.magnitude.plot}.defer
})
)
a.free; b.free;
/*
In this attempt I have tired to exclusively use the getn argument without the signal and complex numbers as I thought that they related to determining the magnitude of frequencies when I was attempting to get the frequencies allready determined and stored in the PV_FreqBuffer. Yet it is still returning the same results and will not plot a graph now, but throws an error.
*/
b = Buffer.alloc(s,1024);
a = { FFT(b, LFSaw.ar(4000)); 0.0 }.play;
c = { PV_FreqBuffer(a, 512) }.play;
(
c.getn(0, 512, { |msg| msg.post })
)
a.free; b.free;
/*
Allocating a buffer for PV_FreqBuffer
*/
b = Buffer.alloc(s,1024);
c = Buffer.alloc(s, 512);
a = { FFT(b, LFSaw.ar(4000)); 0.0 }.play;
d = { PV_FreqBuffer(a, c) }.play;
(
c.getn(0, 512, { |msg| msg.post })
)
a.free; b.free;
/*
Trying with original argument but with allocated PV_FreqBuffer. Just returns values of 0.
*/
b = Buffer.alloc(s,2048);
c = Buffer.alloc(s, 1024);
a = { FFT(b, LFSaw.ar(4000)); 0.0 }.play;
d = { PV_FreqBuffer(a, c) }.play;
(
c.getn(0, 1024, { arg buf;
var z, x;
z = buf.clump(2).flop;
z = [Signal.newFrom(z[0]), Signal.newFrom(z[1])];
x = Complex(z[0], z[1]);
{x.post}.defer
})
)
a.free; b.free;



Thanks again Smiley

- Luke
Logged
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.4 | SMF © 2006-2007, Simple Machines LLC Valid XHTML 1.0! Valid CSS!