Hi chuckers, I've just tried to reproduce something I've done some time ago with guitar pedals : a feedback loop. input -> mixer -> delay -[wet]-> various effects -> back to the mixer `--> dekay -[dry]-> output by controling the amount of feedback on the mixer and the parameters of the effects in the loop you can create funny things. Now, for the ChucK part (not exactly the same, but quite similar) : ---- class MyDelay extends Delay { 1::second => max; } // feedback loop MyDelay d => JCRev r => Gain g => d; d => dac; fun void note() { SawOsc osc => Envelope e => d; 250 => osc.freq; 1 => e.value; e.keyOff(); 200::ms => e.duration => now; } 0.8 => g.gain; 0.2 => r.mix; 200::ms => d.delay; note(); 10::second => now; ---- with these parameters I get a positive feedback: sound is getting louder and louder, clipping and then silence. Using d.last(), I see the samples computed get outside the range [-1;+1] (thus the clipping) and then divert from 0 exponentially. To avoid this, I would like to truncate the sample values so they stay in the interval [-1;+1] : if s > 1 then s = 1, if s < -1 s = -1 I tried to use Dyno as a limiter, but it seems to do something more clever than that. That's all folks ! tom
On Fri, Sep 30, 2011 at 5:43 PM, Tomtom
I've just tried to reproduce something I've done some time ago with guitar pedals : a feedback loop.
input -> mixer -> delay -[wet]-> various effects -> back to the mixer `--> dekay -[dry]-> output
by controling the amount of feedback on the mixer and the parameters of the effects in the loop you can create funny things.
Now, for the ChucK part (not exactly the same, but quite similar) :
----
class MyDelay extends Delay { 1::second => max; }
// feedback loop MyDelay d => JCRev r => Gain g => d; d => dac;
fun void note() { SawOsc osc => Envelope e => d; 250 => osc.freq; 1 => e.value; e.keyOff(); 200::ms => e.duration => now; }
0.8 => g.gain; 0.2 => r.mix; 200::ms => d.delay;
note(); 10::second => now;
----
with these parameters I get a positive feedback: sound is getting louder and louder, clipping and then silence. Using d.last(), I see the samples computed get outside the range [-1;+1] (thus the clipping) and then divert from 0 exponentially.
To avoid this, I would like to truncate the sample values so they stay in the interval [-1;+1] :
if s > 1 then s = 1, if s < -1 s = -1
I tried to use Dyno as a limiter, but it seems to do something more clever than that.
That's all folks !
The lazy hacker in me would do it manually: SinOsc s => Gain clipper => blackhole; 100 => s.gain; fun void clippy() { Step steppy => dac; while(samp => now) { if(clipper.last() > 1) 1 => steppy.next; else if(clipper.last() < -1) -1 => steppy.next; else clipper.last() => steppy.next; } } spork ~ clippy(); day => now; But I felt guilty about hitting send after typing only that, so I looked at the docs for Dyno and I'm pretty sure this does the same thing: SinOsc s => Dyno d => dac; 100 => s.gain; 0 => d.slopeAbove; 1 => d.slopeBelow; 1 => d.thresh; 0::ms => d.attackTime; 0::ms => d.releaseTime; day => now; -- Tom Lieber http://AllTom.com/ http://infinite-sketchpad.com/
Hi.
SinOsc s => Dyno d => dac; 100 => s.gain; 0 => d.slopeAbove; 1 => d.slopeBelow; 1 => d.thresh; 0::ms => d.attackTime; 0::ms => d.releaseTime; day => now;
Unfortunately, this does not have the expected behaviour. note(); while (1){ 1::samp => now; <<< d.last() >>> ; } this will show values oscillating between -1 and -X, with X moving to -infinity. You are right, it can be simply done manually within the shred, but the performance cost is pretty high, isn't it ? Tom
On Sat, Oct 1, 2011 at 3:23 AM, Tomtom
SinOsc s => Dyno d => dac; 100 => s.gain; 0 => d.slopeAbove; 1 => d.slopeBelow; 1 => d.thresh; 0::ms => d.attackTime; 0::ms => d.releaseTime; day => now;
Unfortunately, this does not have the expected behaviour.
note(); while (1){ 1::samp => now; <<< d.last() >>> ; }
this will show values oscillating between -1 and -X, with X moving to -infinity.
Ah, you're right. Things looked fine when I checked in Audacity, but I forgot Audacity clips to [-1, 1] when it opens files anyway. I checked Dyno's source and it works differently than I imagined. double slope = d->xd > d->thresh ? d->slopeAbove : d->slopeBelow; double f = slope == 1.0 ? 1.0 : pow( d->xd / d->thresh, slope - 1.0 ); *out = f * in; I haven't been able to find a way to do what you want.
You are right, it can be simply done manually within the shred, but the performance cost is pretty high, isn't it ?
Maybe; I've rarely needed to optimize ChucK scripts, so I'm not the best person to answer this. :D -- Tom Lieber http://AllTom.com/ http://infinite-sketchpad.com/
Tricky. A limiter is a good idea in cases like this, but more as a emergency device. If your feedback loop keeps building a limiter won't prevent the cause, unless we set the limit so low that it'll also prevent the repeated echos that we do want. It will still cause a unpleasant result as long as the total amplification of the look is over 1. What's odd here (at least to me) is that it still builds, despite the .8 factor in the loop. I have one theory about the cause; with a length of 200::ms the feedback of the delay will have a period of (1 / 200::ms = ) 5Hz (plus one sample for the feedback). The signal used (being 250 Hz) is a exact multiple of that. I think that would mean that the output at peaks would build up to 1 (for the original signal) plus .8 of a peak for the first iteration, plus .8 * .8 for the second, plus .8 ^ 3 for the third, etc. That would be a finite number, but might be above ChucK's headroom. This, BTW, is also exactly what I experienced with some of the build-in reverbs; as those are based on networks of delay with feedback they'll heavily amplify the signal at some frequencies. That's not much of a issue with natural sounds like voice that fluctuate all the time, but often is with synthetic sounds that stay at the same frequency for a longer time. Look into whether that's not what you are seeing. BTW, unrelated to this issue, but rather exciting to me is that you wrote this; class MyDelay extends Delay { 1::second => max; } ...and that worked! It's correct, the language specs imply that it should work, but for ages it didn't and the resultant class couldn't be chucked to a input. Apparently now this works for you, which makes me wonder what version of ChucK is being used here and how long it's been out. Did I miss a memo? That's rather exciting. Yours, Kas.
Hi Kassen,
What's odd here (at least to me) is that it still builds, despite the .8 factor in the loop. I have one theory about the cause; with a length of 200::ms the feedback of the delay will have a period of (1 / 200::ms = ) 5Hz (plus one sample for the feedback). The signal used (being 250 Hz) is a exact multiple of that. I think that would mean that the output at peaks would build up to 1 (for the original signal) plus .8 of a peak for the first iteration, plus .8 * .8 for the second, plus .8 ^ 3 for the third, etc. That would be a finite number, but might be above ChucK's headroom.
If I change the delay to 123::ms for example, I get pretty much the same result.
This, BTW, is also exactly what I experienced with some of the build-in reverbs; as those are based on networks of delay with feedback they'll heavily amplify the signal at some frequencies. That's not much of a issue with natural sounds like voice that fluctuate all the time, but often is with synthetic sounds that stay at the same frequency for a longer time.
Right ! If I remove the reverb, I get a simple echo effect, thus the 0.8 gain works as expected. So the reverb must act as a strong amplifier, even with low parameters. This problem you describe with reverbs + synthetic sound totally makes sense here.
BTW, unrelated to this issue, but rather exciting to me is that you wrote this;
class MyDelay extends Delay { 1::second => max; }
...and that worked! It's correct, the language specs imply that it should work, but for ages it didn't and the resultant class couldn't be chucked to a input. Apparently now this works for you, which makes me wonder what version of ChucK is being used here and how long it's been out. Did I miss a memo? That's rather exciting.
I'm using chuck 1.2.1.3 (dracula). As for this part of my code, I didn't think it would work either. Reading the doc, I was like "what? But I've never derived from a UGen before! And ChucK don't really have constructors right ?" But obviously everything went better than expected ... Tom
Hi Kassen,
Hey Tom,
If I change the delay to 123::ms for example, I get pretty much the same result.
Ok, that's me estimating wrong, then.
Right ! If I remove the reverb, I get a simple echo effect, thus the 0.8 gain works as expected. So the reverb must act as a strong amplifier, even with low parameters. This problem you describe with reverbs + synthetic sound totally makes sense here.
Yes, it's a annoying property of the build-in reverbs. the magnitude of this effect varies wildly with the frequency of the material.
I'm using chuck 1.2.1.3 (dracula). As for this part of my code, I didn't think it would work either. Reading the doc, I was like "what? But I've never derived from a UGen before! And ChucK don't really have constructors right ?" But obviously everything went better than expected
Yes, it's nice, I'm currently running some tests on it. Of course this is proper behaviour; the extended class *should* also be a "Delay" (as well as a UGen) and so the chuck operator should automatically be overloaded to deal with this. At least that's what I feel the docs imply. In the past, however, this didn't work and there has been some discussion on that. You could extend a UGen, but the result wouldn't connect to the UGen graph (so that was quite useless). The odd thing is that I can't remember this working in 1.2.1.3 before. I have a gut feeling there was a update because of the issues with OSX Lion and some other changes also got pushed in, but the version number wasn't incremented and no changes were listed in the VERSIONS file... but that's pure speculation. It'd be nice to get some official word on this. In the meantime; very, very nice find you made here! Yours, Kas.
participants (3)
-
Kassen
-
Tom Lieber
-
Tomtom