Author |
Message |
hanez
Joined: Feb 07, 2007 Posts: 10 Location: Austria
|
Posted: Thu Jul 05, 2007 3:38 am Post subject:
Envelope follower with SndBuf not working Subject description: Gain.op set to 3 (multiplication) yields negative output when used with SndBuf |
|
|
hi,
i needed an envelope follower. i found one under /examples/deep -> follower.ck, which follows the adc. it works. it goes like this:
Code: | // patch
adc => Gain g => OnePole p => blackhole;
// square the input
adc => g;
// multiply
3 => g.op;
// set pole position
0.9999 => p.pole;
// loop on
while( true ) {
<<< g.last() >>>;
if( p.last() > 0.1 )
<<< "BANG!!" >>>;
0.1::second => now;
} |
g.last() is always positive
but when i change it to follow a SndBuf instead of the adc the output of g sometimes is negative, which is not logical because a real number squared is alway positive. my code goes like this:
Code: | // patch
SndBuf buf1 => Gain g => OnePole p => blackhole;
// square the input
buf1 => g;
"c:/chuckmeup/somefile.wav" => buf1.read;
// multiply
3 => g.op;
// set pole position
0.9999 => p.pole;
// loop on
while( true ) {
<<< g.last() >>>;
if( p.last() > 0.1 )
<<< "BANG!!" >>>;
0.1::second => now;
} |
g.last() is positive AND NEGATIVE!
so whats wrong here?
thank you
Hannes |
|
Back to top
|
|
|
kijjaz
Joined: Sep 20, 2004 Posts: 765 Location: bangkok, thailand
Audio files: 4
|
Posted: Thu Jul 05, 2007 10:00 am Post subject:
|
|
|
Hmm.. Interesting! I'm gonna test with some wav right away. |
|
Back to top
|
|
|
kijjaz
Joined: Sep 20, 2004 Posts: 765 Location: bangkok, thailand
Audio files: 4
|
Posted: Thu Jul 05, 2007 10:15 am Post subject:
|
|
|
Ahh. I know what happened now.
Rechucking ..
(for example .. a => b;
and then a => b; again after that)
Works just like only a single chucking.
So your SndBuf buf1 => Gain g ..
and then buf1 => g again
Only mean one "buf1 => g"
I tried this and it did the multiplication correctly:
Routing buf1 to another dummy gain..
Let's try buf1 => Gain buf1dummy => g;
instead.
That'd work like two input sources into g.
^_^ |
|
Back to top
|
|
|
chuckles
Joined: Apr 02, 2007 Posts: 72 Location: San Diego, California
|
Posted: Thu Jul 05, 2007 3:38 pm Post subject:
Well, here's one way you might get around it... |
|
|
Here's what seemed to work for me:
Code: | SndBuf buf1 => FullRect f => Gain g => OnePole p => blackhole; |
FullRect and HalfRect aren't documented very well at present (i.e., essentially not at all!) but I just figured it couldn't hurt to try.
ChucK reminds me of Perl sometimes with the "T>1W2DI" philosophy ("There's More Than One Way To Do It")
Maybe the example with two adcs => to a UG works since adcs are different than SndBufs: i.e., they're "active" during the loop: whereas once you've read a file into a SndBuf, it's a static object.
But I still don't quite understand the point of the .op options. What exactly does it mean to multiply the inputs of a UG? Can someone give another example where that works (besides follower.ck)?
Cheers
...r... |
|
Back to top
|
|
|
kijjaz
Joined: Sep 20, 2004 Posts: 765 Location: bangkok, thailand
Audio files: 4
|
Posted: Thu Jul 05, 2007 5:36 pm Post subject:
|
|
|
chuckles: Hmm..
using FullRect (or even HalfRect)
is also useful in this suituation
although it has a specific quality.
i guess squaring this kind of data is quite poppular in analysing statistically,
but they all have different characters.
i am thinking about RMS vs PEAK value of the loudness hmmm..
and i don't know how to explain lolol.
- - -
chuckles: Oh..
the Gain .op function is like this:
by default, it adds all the input signal..
for example:
signal1 => Gain g;
signal2 => g;
signal3 => g;
g will has output just like the sum of signal1, 2, 3 combined..
this is basic.
this default mode can be set by setting the gain's .op to 1
(for example, 1 => g.op; )
Code: | Step s1, s2, s3; // prepare signals to connect to Gain
Gain g => blackhole; // prepare Gain (and force calculation with blackhole)
// 1 => g.op; is default: for normal signal summation
// connect all s to g
s1 => g;
s2 => g;
s3 => g;
0.1 => s1.next;
0.2 => s2.next;
0.4 => s3.next;
samp => now; // time passes..
<<< g.last() >>>; |
result: 0.700000 :(float)
(correctly, equals to .1 + .2 + .4)
- - -
now with op = 2, the first signal will be the primary signal,
but the following signal will subtract from the primary signal.
Step s1, s2, s3; // prepare signals to connect to Gain
Gain g => blackhole; // prepare Gain (and force calculation with blackhole)
2 => g.op; // for substract
Code: | Step s1, s2, s3; // prepare signals to connect to Gain
Gain g => blackhole; // prepare Gain (and force calculation with blackhole)
2 => g.op; // for substract
// connect all s to g
s1 => g;
s2 => g;
s3 => g;
0.1 => s1.next;
0.2 => s2.next;
0.4 => s3.next;
samp => now; // time passes..
<<< g.last() >>>;
s1 =< g; // disconnect s1 from g, and see what g will output
samp => now; // time passes..
<<< g.last() >>>; |
result:
-0.500000 :(float)
-0.200000 :(float)
the first comes from the last value of s1 - s2 - s3
= 0.1 - 0.2 - 0.4 = -0.5
the second, after unchucking s1 from g,
the s2 become the primary signal instead, thus ... g outputs s2 - s3
= 0.2 - 0.4 = -0.2
- - -
now, i'll try op = 3
this is gonna be easy.
Code: | Step s1, s2, s3; // prepare signals to connect to Gain
Gain g => blackhole; // prepare Gain (and force calculation with blackhole)
3 => g.op; // for multiplication
// connect all s to g
s1 => g;
s2 => g;
s3 => g;
3.0 => s1.next;
2.0 => s2.next;
5.0 => s3.next;
samp => now; // time passes..
<<< g.last() >>>; |
result: 30.000000 :(float)
(equals 3.0 * 2.0 * 5.0, plainly)
- - -
but the division behaves just like subtraction
only it's dividing.
Code: | Step s1, s2, s3; // prepare signals to connect to Gain
Gain g => blackhole; // prepare Gain (and force calculation with blackhole)
4 => g.op; // for division
// connect all s to g
s1 => g;
s2 => g;
s3 => g;
3.0 => s1.next;
2.0 => s2.next;
5.0 => s3.next;
samp => now; // time passes..
<<< g.last() >>>;
s1 =< g; // disconnect s1 from g, and see what g will output
samp => now; // time passes..
<<< g.last() >>>; |
result:
0.300000 :(float)
0.400000 :(float)
the first equals 3.0 / 2.0 / 5.0 = 0.3
and second 2.0 / 5.0 = 0.4, for real! |
|
Back to top
|
|
|
chuckles
Joined: Apr 02, 2007 Posts: 72 Location: San Diego, California
|
Posted: Fri Jul 06, 2007 7:48 am Post subject:
|
|
|
kijjaz: thanks for the detailed explanation of the way .ops work. I thought it might have something to do with multiple chucks but I wasn't clear on it.
The crucial thing is that all these computations are done on individual samples. I was trying to see if I could figure out a way to do it without having to process each single sample in buf1. Because you could certainly do it that way.
Cheers
...r... |
|
Back to top
|
|
|
Kassen
Janitor
Joined: Jul 06, 2004 Posts: 7678 Location: The Hague, NL
G2 patch files: 3
|
Posted: Sat Jul 07, 2007 12:51 pm Post subject:
|
|
|
Well, Ugens are usually MUCH cheaper then manual code in ChucK, at least in situations where they are suitable. "Gain" is realy simple and "OnePole" is a bit more involved but still only a few multiplications.
Another issue is that processing every Nth sample for a envelope follower would lead to problems. Say you'd poll it ever 10 ms, that would mean that from the perspective of the envelope follower a 100 Hz sine would look like pure dc-offset at a value dependant on how the wave syncs relative to your code... Clearly that would be undesireable. The results on musical material might be interesting but they wouldn't be a envelope follower per-se. _________________ Kassen |
|
Back to top
|
|
|
|