Author |
Message |
Mercurial
Joined: Aug 24, 2009 Posts: 2 Location: Kenosha
|
Posted: Mon Aug 24, 2009 4:36 pm Post subject:
Finding input signal frequency in ChucK |
 |
|
Hey guys,
I'm really really new to ChucK and have done some limited programming with it, but am by no means new to programming. I'm trying to figure out the frequency of the incoming signal from a guitar or mic, but am at a loss for how to even begin. I've extensively read through the documentation for the language, but can't seem to see how to figure this out. I know that they have the analysis tools like the FFT, but I'm not really sure even in that case how to use that information for this purpose.
If anyone has any ideas, I sure would appreciate it! |
|
Back to top
|
|
 |
Kassen
Janitor


Joined: Jul 06, 2004 Posts: 7678 Location: The Hague, NL
G2 patch files: 3
|
Posted: Mon Aug 24, 2009 11:25 pm Post subject:
|
 |
|
Well, there is of course this;
http://chuck.cs.princeton.edu/doc/program/uana.html
and this;
http://chuck.cs.princeton.edu/doc/language/uana.html
And the relevant files of example code in the examples directory.
.... and when you covered those you'll have noticed that Ge and Rebecca never actually tell us how to simply take a guitar tone and get from that what note it is. They seem to avoid the issue.. we might even start to suspect that they don't know.
Well, the truth is that they actually don't and that that's because nobody does. The issue is that natural sounds are really complicated, that the A3 on your guitar may be perceived as a A by you and me but might not have 220 Hz as a particularly dominant frequency, it might instead contain mostly harmonics that our ear uses to figure out the fundamental. Our ears are amazingly clever at that and use a mixture of strategies to make sense of the sound around us.
Note detectors muck up, even professional ones that already know they will get a guitar tone will demand that you pluck the string in just the right way or the readings won't make sense, the Korg MS20 synth has a pitch detector that's actually famous for the way in which it mucks up.
So... that's why you can't find a simple easy solution that works everywhere; there are none.
So, is all lost now? Well no... we can often cheat and indeed stand a good chance for simple signals and can have fun with complex ones.
Ok, so what do those UAnae outputs mean? What you get in the arrays FFT yields is a series complex numbers that have two parts; a magnitude and a phase. You can look at the series magnitude like bars in a spectral analyser; the size of the frame gets divided over the frequencies that can be expressed at our sample rate. The magnitude expresses how much energy the sound has in that band.
Here is a example. This is from the set of examples that came with the last version of ChucK, why it doesn't come with the current is beyond me. Here the input signal is analysed using FFT, the band with the largest magnitude is found, based on that and the sample rate the corresponding frequency is detected and this is assigned to a oscillator to play. Note that this is the band with the highest magnitude; that need not be the perceived dominant frequency (or pitch) of the incoming sound.
Code: | // analysis
adc => PoleZero dcblock => FFT fft => blackhole;
// synthesis
SinOsc s => JCRev r => dac;
// set reverb mix
.05 => r.mix;
// set to block DC
.99 => dcblock.blockZero;
// set FFT params
1024 => fft.size;
// window
Windowing.hamming( fft.size() ) => fft.window;
// to hold result
UAnaBlob blob;
// find sample rate
second / samp => float srate;
// interpolate
float target_freq, curr_freq, target_gain, curr_gain;
spork ~ ramp_stuff();
// go for it
while( true )
{
// take fft
fft.upchuck() @=> blob;
// find peak
0 => float max; int where;
for( int i; i < blob.fvals().cap(); i++ )
{
// compare
if( blob.fvals()[i] > max )
{
// save
blob.fvals()[i] => max;
i => where;
}
}
// set freq
(where $ float) / fft.size() * srate => target_freq;
// set gain
(max / .8) => target_gain;
// hop
(fft.size()/2)::samp => now;
}
// interpolation
fun void ramp_stuff()
{
// mysterious 'slew'
0.025 => float slew;
// infinite time loop
while( true )
{
(target_freq - curr_freq) * 5 * slew + curr_freq => curr_freq => s.freq;
(target_gain - curr_gain) * slew + curr_gain => curr_gain => s.gain;
0.0025::second => now;
}
}
|
This example is a bit involved but with some study it shouldn't be too hard to follow what it does and to modify it into something that would suit your needs.... but as I mentioned; this is a hard subject no matter how you look at it. _________________ Kassen |
|
Back to top
|
|
 |
Antimon
Joined: Jan 18, 2005 Posts: 4145 Location: Sweden
Audio files: 371
G2 patch files: 100
|
Posted: Tue Aug 25, 2009 6:19 am Post subject:
|
 |
|
Thanks for that piece, Kassen! I've been wanting to try out some pitch detection for a while, but I tend to get a bit confused by the UAna stuff.
/Stefan _________________ Antimon's Window
@soundcloud @Flattr home - you can't explain music |
|
Back to top
|
|
 |
Mercurial
Joined: Aug 24, 2009 Posts: 2 Location: Kenosha
|
Posted: Tue Aug 25, 2009 6:08 pm Post subject:
|
 |
|
Thanks Kassen! I'll play around with it and see what I can do.
-Mercurial- |
|
Back to top
|
|
 |
|