| Author |
Message |
kijjaz

Joined: Sep 20, 2004 Posts: 409 Location: bangkok, thailand
Audio files: 2
|
Posted: Sat Sep 01, 2007 12:19 pm Post subject:
|
 |
|
Is it because "^" in that language needs a lot of calculations?
If it's the case, can you try using
in0 * in0 instead of in0 ^ 2
and in0 * in0 * in0 instead of in0 ^ 3?
(and also on another power signs)
If i'm not wrong, using multiplication straight ahead like this could really save a lot of CPU power. |
|
|
Back to top
|
|
 |
Consul

Joined: May 05, 2007 Posts: 52 Location: Port Huron, Michigan, USA
|
Posted: Sat Sep 01, 2007 12:44 pm Post subject:
|
 |
|
Yeah, I was thinking the same thing myself. I guess it's worth a try.
EDIT: Oh, yeah! HUGE difference. Both algos are down to 1.7-1.8% now. Time to integrate these into the new Compstortion code (which has log-based input gain and output attenuation in it now). _________________ Darren Landrum
"Never be afraid to try something new. Remember that a lone amateur built the Ark. A large group of professionals built the Titanic." - Dave Barry |
|
|
Back to top
|
|
 |
kijjaz

Joined: Sep 20, 2004 Posts: 409 Location: bangkok, thailand
Audio files: 2
|
Posted: Sat Sep 01, 2007 3:02 pm Post subject:
|
 |
|
Consul: I've got a new formula for you to try:
I've been playing around with these transfer functions:
x/(1+|x|) - - - (1)
x / (1 + x^2) - - - (2)
x^3 / (1 + |x^3|) - - - (3)
and I like their characters..
But there is a problem with the x^3 / (1 + |x^3|)
is that.. if the amplitude of the input signal is very low,
the output would be much lower
The plot of this function already shows what I mean, you can take a look at:
http://electro-music.com/forum/gallery2.php?g2_itemId=6344
Actually, I'm aware of this problem since I tested it,
but I just couldn't wait to spread it because it has such an interesting overdrive characteristic and I like it.
So.. This new one will be .. hmm
sort of.. a combination of (1) and (3) in character
but without the particular problem.
f(x) = x(1+x^2) / (1 + | x(1+x^2) | )
the plot of the function:
http://electro-music.com/forum/gallery2.php?g2_itemId=6346
If we replace x^2 with x^4, we'll get a more "squarish" sound,
or replace with x^2+x^4 to get that character but with smoother sound.
I'll display the implementation in ChucK here soon.
- - -
Here's the test of the above formula's implementation in ChucK
| Code: | class overdrive03_01_02
{
// this overdrive UGen applies f(x) = x(1+x^2) / (1 + abs(x(1+x^2))) waveshaping function
// to the "in"put signal and output to "out".
Gain in; Gain out; // chuck or unchuck this to the outside world to connect;
// prepare f(input) = input(1+input^2)
Step one => Gain f1;
1.0 => one.next; <-- 1
in => Gain f2;
in => Gain inDummy1 => f2;
3 => f2.op; <-- input ^ 2
f2 => f1; <-- 1 + input ^ 2
in => Gain f;
f1 => f;
3 => f.op; <-- input(1 + input^2)
one => Gain divisor;
f => FullRect Abs; <-- abs(f)
Abs => divisor; <-- 1 + abs(f)
// calculate f / (1 + abs(f)) and send to "out"
f => out;
divisor => out;
4 => out.op; <-- make out do a division of the inputs
}
// Testing by feeding Sine Wave at 110hz into the drive unit.
overdrive03_01_02 drive;
SinOsc s => drive.in;
drive.out => dac;
110.0 => s.freq;
for(int i; i < 10; i++)
{
i * .5 => s.gain;
second => now;
} |
and this is for the replacement of x^2 to x^4
| Code: | class overdrive03_01_03
{
// this overdrive UGen applies f(x) = x(1+x^4) / (1 + abs(x(1+x^4))) waveshaping function
// to the "in"put signal and output to "out".
Gain in; Gain out; // chuck or unchuck this to the outside world to connect;
// prepare f(input) = input(1+input^2)
Step one => Gain f1;
1.0 => one.next; <-- 1
in => Gain f2;
in => Gain inDummy1 => f2;
f2 => Gain f3;
f2 => Gain f2Dummy1 => f3;
3 => f2.op;
3 => f3.op; <-- input ^ 4
f2 => f1; <-- 1 + input ^ 4
in => Gain f;
f1 => f;
3 => f.op; <-- input(1 + input^4)
one => Gain divisor;
f => FullRect Abs; <-- abs(f)
Abs => divisor; <-- 1 + abs(f)
// calculate f / (1 + abs(f)) and send to "out"
f => out;
divisor => out;
4 => out.op; <-- make out do a division of the inputs
}
// Testing by feeding Sine Wave at 110hz into the drive unit.
overdrive03_01_03 drive;
SinOsc s => drive.in;
drive.out => dac;
110.0 => s.freq;
for(int i; i < 10; i++)
{
i * .5 => s.gain;
second => now;
} |
- - -
Hmm the sound's not that different while testing with SinOsc.
I'd better test it with more instruments soon..
Guitars, Rhodes, Organ, Synth, Drums, ETC.
NOTE: These example uses the new ChucK 1.2.1.0 comment feature:
using <-- is like commenting with // now
so if you're on an older ChucK version,
you can put // in front of every <-- I used for commenting. |
|
|
Back to top
|
|
 |
Consul

Joined: May 05, 2007 Posts: 52 Location: Port Huron, Michigan, USA
|
Posted: Sat Sep 01, 2007 3:46 pm Post subject:
|
 |
|
I really wish I had your math skills.
I'll play around with this and report back.
EDIT: Well, I'm reporting back, and I can barely hear the difference between this latest algo with x^2 and the bypassed state, to tell you the truth. With the x^4 variation at very high drives, it gives something of a subtle exciter sound more than anything, which is not bad in and of itself, really. I'm going to play around with that some more, and maybe make it it's own plugin.
In the end, I think I'll stick with the first two algos, and play around with this latest one later.
Now I get to figure out how to do a filter. I don't know if I'm up to it.
EDIT 2: The Jesusonic version of these algorithms are horribly program-dependent, to the point that it's frustrating me. I don't know what to do about that, other than let people decide what they want to do with it, if anything. _________________ Darren Landrum
"Never be afraid to try something new. Remember that a lone amateur built the Ark. A large group of professionals built the Titanic." - Dave Barry |
|
|
Back to top
|
|
 |
Frostburn

Joined: Dec 12, 2007 Posts: 166 Location: Finland
Audio files: 5
|
Posted: Tue Dec 18, 2007 3:46 am Post subject:
|
 |
|
Related to this topic I have a feature request for a WaveShaper class.
It would take a chucked input and output a shaped wave:
ouput = WaveShaper.function(input);
Different functions would at least include:
-Polynomial with user defined coefficients (up to 8th degree would propably be enough).
-Trigonometric (sin,cos,tan,asin,acos,atan)
-Exponential
-Logarithmic (natural)
-Hyperbolic (sinh,cosh,tanh,asinh,acosh,atanh) //These could be done with exp, ln and .op(4) but it's nice to have them predifined.
-Limit: if(input > upper_limit) output = upper_limit;
if(input < lower_limit) output = lower_limit;
else output = input; |
|
|
Back to top
|
|
 |
Frostburn

Joined: Dec 12, 2007 Posts: 166 Location: Finland
Audio files: 5
|
|
|
Back to top
|
|
 |
Frostburn

Joined: Dec 12, 2007 Posts: 166 Location: Finland
Audio files: 5
|
Posted: Sat Feb 02, 2008 8:44 am Post subject:
|
 |
|
Here's my take on a distortion class:
| Code: | class Distort{
Gain in => Gain overdrive;
Gain out;
Step unity; 1.0 => unity.next;
Event process;
fun UGen chuck(UGen @ u){
u => in;
return out;
}
fun void stop(){
process.broadcast();
}
fun void order1(){ // y = x / (abs(x)+1)
overdrive => Gain div => out;
4 => div.op;
unity => Gain sum => div;
overdrive => FullRect abs => sum;
process => now;
div =< out;
}
fun void order2(){ // y = (x*abs(x)+ x) / (x*x+abs(x)+1)
overdrive => Gain nominator_sum => Gain div => out;
4 => div.op;
unity => Gain denom_sum => div;
overdrive => FullRect abs => denom_sum;
overdrive => Gain abspow2 => nominator_sum;
3 => abspow2.op;
abs => abspow2;
abspow2 => FullRect pow2 => denom_sum;
process => now;
div =< out;
}
fun void ribbon(){ // y = x / (0.25*x*x + 1)
overdrive => Gain div => out;
4 => div.op;
unity => Gain sum => div;
overdrive => Gain pow2 => sum;
3 => pow2.op;
overdrive => Gain pow2dummy => pow2;
0.25 => pow2.gain;
process => now;
div =< out;
}
fun void remove_linear(){
in =< overdrive;
process => now;
in => overdrive;
}
fun void overdrive3(){ //Thanks to kijjaz for the idea
in => Gain pow3 => overdrive;
3 => pow3.op;
in => Gain pow3dummy1 => pow3;
in => Gain pow3dummy2 => pow3;
process => now;
pow3 =< overdrive;
}
fun void overdrive5(){
in => Gain pow5 => overdrive;
3 => pow5.op;
in => Gain pow2 => pow5;
3 => pow2.op;
in => Gain pow2dummy => pow2 => Gain pow4dummy => pow5;
process => now;
pow5 =< overdrive;
}
}
Distort d;
SinOsc s => d.chuck => dac; //Can be chucked almost like a real UGen :)
220.0 => s.freq;
//Play 3 second crescendos with the SinOsc
//Try order1
spork~d.order1();
0.0 => s.gain;
for(now + 3::second => time later;now < later; 10::ms => now){
s.gain() + 0.01 => s.gain;
}
d.stop();
second => now;
//Try order2
spork~d.order2();
0.0 => s.gain;
for(now + 3::second => time later;now < later; 10::ms => now){
s.gain() + 0.01 => s.gain;
}
d.stop();
second => now;
//Try some heavy overdrive with ribbon
spork~d.remove_linear();
spork~d.overdrive3();
spork~d.overdrive5();
spork~d.ribbon();
0.0 => s.gain;
for(now + 3::second => time later;now < later; 10::ms => now){
s.gain() + 0.01 => s.gain;
}
d.stop();
second => now;
d.out =< dac; //d.out is silent but let's unchuck for good measure
s =< d.in; //This is actually not necessary because after calling d.stop() d.in isn't connected to anything.
1.0 => s.gain;
s => dac; //Just a final unprocessed beep
second => now;
|
EDIT: I just tried this one in action in a song... It generates heavy garbage when called and sporked multiple times... you have been warned.
(Or my laptop is acting up again)
EDIT2: I fixed a bug with overdrive5 and added y = x/(0.25*x*x + 1) _________________ In Serendipity We Trust |
|
|
Back to top
|
|
 |
meestaplu
Joined: Apr 22, 2008 Posts: 1 Location: Connecticut
|
Posted: Tue Apr 22, 2008 7:35 pm Post subject:
|
 |
|
I implemented a lookup table in ChucK that lets you do a tanh distortion in less than 10 lines:
| Code: | int i;
float v;
2048 => int MAX;
1.03 => float nor;
for(-MAX => i; i<MAX; 1 +=> i) {
Math.tanh(7*(i+0.0)/MAX)/nor => v;
//(i+0.0)/MAX => float x;
//Math.sin(x*pi/2.0)*0.99 => v;
lut.set(i+MAX, v);
}
SinOsc sin_osc => lut => dac;
|
I left a sine distortion in there, commented out, so you can see how to use different values.
It's kind of crappy right now, but it works.
It's a unit generator called LUT (lookup table) that has 4096 buckets. Bucket 0 maps input value -1.0 to an output value...bucket 4095 maps input value 1.0 to an output value.
The idea is that you precompute your transfer function -- because of the precomputation it doesn't take much CPU to do real-time processing. When I get it decent, I'll submit it as a patch to the official build so others can use it -- I don't like my .set() function, though, and would rather have an array input so you don't have to keep in mind the secret number of buckets in the LUT.
What do you think on the interface?
Matt
[edit: disabled HTML] |
|
|
Back to top
|
|
 |
Frostburn

Joined: Dec 12, 2007 Posts: 166 Location: Finland
Audio files: 5
|
Posted: Wed Apr 23, 2008 12:11 am Post subject:
|
 |
|
A nice idea.
I'd really like to use chucks own float arrays as the lookup table and then just @=> it to the LookUpTable UGen.
Well actually I'm thinking about implementing DigitalTape,an interpolating lookup (and writeup :) ) table with fractional loop point control using chuck's float array as the samples.
But a CPU effecient UGen like you have in mind would come in handy too.
Btw. Where are you planning on posting the source once you're done? _________________ In Serendipity We Trust |
|
|
Back to top
|
|
 |
kijjaz

Joined: Sep 20, 2004 Posts: 409 Location: bangkok, thailand
Audio files: 2
|
Posted: Wed Apr 23, 2008 12:29 am Post subject:
|
 |
|
oh yeah.. that'd be great. if we can have lookup table ugen that can easily be used with a float array,
we'll have a lot more implementations. |
|
|
Back to top
|
|
 |
|