electro-music.com   Dedicated to experimental electro-acoustic
and electronic music
 
    Front Page  |  Articles  |  Radio
 |  Media  |  Forum  |  Links  |  Store
Forum with support of Syndicator RSS
 FAQFAQ   CalendarCalendar   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   LinksLinks GalleryGallery 
 RegisterRegister   ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in  Chat RoomChat Room 
 Forum index » DIY Hardware and Software » ChucK programming language
distorsion
Post new topic   Reply to topic Moderators: Kassen
Page 2 of 2 [36 Posts]
View unread posts
View new posts in the last week
Mark the topic unread :: View previous topic :: View next topic
Goto page: Previous 1, 2
Author Message
kijjaz



Joined: Sep 20, 2004
Posts: 452
Location: bangkok, thailand
Audio files: 2

PostPosted: Sat Sep 01, 2007 12:19 pm    Post subject: Reply with quote  Mark this post and the followings unread

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
View user's profile Send private message Send e-mail Visit poster's website Yahoo Messenger MSN Messenger
Consul



Joined: May 05, 2007
Posts: 52
Location: Port Huron, Michigan, USA

PostPosted: Sat Sep 01, 2007 12:44 pm    Post subject: Reply with quote  Mark this post and the followings unread

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
View user's profile Send private message AIM Address
kijjaz



Joined: Sep 20, 2004
Posts: 452
Location: bangkok, thailand
Audio files: 2

PostPosted: Sat Sep 01, 2007 3:02 pm    Post subject: Reply with quote  Mark this post and the followings unread

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
View user's profile Send private message Send e-mail Visit poster's website Yahoo Messenger MSN Messenger
Consul



Joined: May 05, 2007
Posts: 52
Location: Port Huron, Michigan, USA

PostPosted: Sat Sep 01, 2007 3:46 pm    Post subject: Reply with quote  Mark this post and the followings unread

I really wish I had your math skills. Cool

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
View user's profile Send private message AIM Address
Frostburn



Joined: Dec 12, 2007
Posts: 211
Location: Finland
Audio files: 7

PostPosted: Tue Dec 18, 2007 3:46 am    Post subject: Reply with quote  Mark this post and the followings unread

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
View user's profile Send private message
Frostburn



Joined: Dec 12, 2007
Posts: 211
Location: Finland
Audio files: 7

PostPosted: Tue Dec 18, 2007 6:17 am    Post subject: Reply with quote  Mark this post and the followings unread

kijjaz wrote:

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.


Just replace x^3 with ( x+x^3 ) in that formula to get a slope of 1 at x=0.

(x+a*x^3) / (1 + |x + a*x^3|) //now the parameter a controls the tightness of the sound distortion.

You can play with f(y) = y / (1 + |y|) by replacing y with any function g(x) so that g(0) = 0 and dg/dx|(x = 0) = 1 (the slope is 1 at x = 0). Now also f(g(x)) will have a slope of 1 at zero. (it means that low aplitudes will output without any noticeable distortion).

EDIT:
I just made a hyberbolic tangent out of a Gain network using Gauss's continued fraction approximation.
If you need a tanh waveshaper now. Try it out.
Code:
//tanh(x) = x/(1+x²/(3+x²/(5+x²/(...

//Define the needed Gain network.
5 => int depth; //How big the resulting network will be.
Gain input;
Gain output;
Gain squared; squared.op(3); //Set operation to multiply
Gain square_dummy => squared; input => square_dummy; input => squared;
Step odd_numbers[depth];
Gain sum[depth];
Gain divider[depth];

make_tanh(); //Connect everything to get Gauss's continued fraction for the hyperbolic tangent.

//Test it:
SinOsc s => input; output => dac;

0.0 => float x;
while(x < 5.0){ //at depth = 5 the ouput follows tanh quite closely up to amplitudes 5.0, then it starts to drop. Increase deth if you need more than that.
x => s.gain;
x + 0.01 => x;
10::ms => now;
}


//---Functions---
fun void make_tanh(){
for(0 => int i; i < depth; i++){ divider[i].op(4); }//Set operation to divide;
input => divider[0];

for(0 => int i; i < depth - 1; i++){
2*i+1 => odd_numbers[i].next;
squared => divider[i+1] => sum[i];
odd_numbers[i] => sum[i] => divider[i];
}

depth*2-1 => odd_numbers[depth-1].next;
squared => sum[depth-1];
odd_numbers[depth-1] => sum[depth-1] => divider[depth -1];

divider[0] => output;
}

I also attached the above as a .ck filer for convenience.


tanhGain.ck
 Description:

Download
 Filename:  tanhGain.ck
 Filesize:  1.12 KB
 Downloaded:  28 Time(s)

Back to top
View user's profile Send private message
Frostburn



Joined: Dec 12, 2007
Posts: 211
Location: Finland
Audio files: 7

PostPosted: Sat Feb 02, 2008 8:44 am    Post subject: Reply with quote  Mark this post and the followings unread

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)

_________________
To boldly go where no man has bothered to go before.
Back to top
View user's profile Send private message
meestaplu



Joined: Apr 22, 2008
Posts: 1
Location: Connecticut

PostPosted: Tue Apr 22, 2008 7:35 pm    Post subject: Reply with quote  Mark this post and the followings unread

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
View user's profile Send private message
Frostburn



Joined: Dec 12, 2007
Posts: 211
Location: Finland
Audio files: 7

PostPosted: Wed Apr 23, 2008 12:11 am    Post subject: Reply with quote  Mark this post and the followings unread

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?

_________________
To boldly go where no man has bothered to go before.
Back to top
View user's profile Send private message
kijjaz



Joined: Sep 20, 2004
Posts: 452
Location: bangkok, thailand
Audio files: 2

PostPosted: Wed Apr 23, 2008 12:29 am    Post subject: Reply with quote  Mark this post and the followings unread

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
View user's profile Send private message Send e-mail Visit poster's website Yahoo Messenger MSN Messenger
kijjaz



Joined: Sep 20, 2004
Posts: 452
Location: bangkok, thailand
Audio files: 2

PostPosted: Thu Jul 03, 2008 1:03 pm    Post subject: Reply with quote  Mark this post and the followings unread

Today I was chatting with avaruus (in #chuck in freenode irc) and we talked about distortion, so I came back to this topic.
After looking around seeing some general overdrive I prepared as classes in here,
I came up with the idea of joining some ideas in one new class.

here is the result:

overdrive transfer function:
f(x) = f(x) = (ax + bx^2 + cx^3) / (1 + |ax| + bx^2 + |cx^3|)
with initial value a = 1, b = 1, c = 1

here's the easy-to-use result:
Code:
class kjzGenOverdrive01
{
    // this class calculate overdrive transfer function from this function:
    // f(x) = (ax + bx^2 + cx^3) / (1 + bx^2 + |ax + cx^3|)
   
    // to set a, b, c
    // use aInit.next, bInit.next, cInit.next
   
    // or if you want to adjust a, b, c by multiplying with other signal,
    // chuck the signals to ax, bxx, cxxx (their .op's are all MULTIPLY in here)
   
    Gain input, output; // chuck or unchuck this to connect
   
    Step aInit; aInit.next(1); // initialize a
    Step bInit; bInit.next(1); // initialize b
    Step cInit; cInit.next(1); // initialize c
   
    aInit => Gain ax; input => ax; ax.op(3); // calculate ax
    bInit => Gain bxx; input => bxx; input => Gain dummyB1 => bxx; bxx.op(3); // calculate bx^2
    cInit => Gain cxxx; input => cxxx; input => Gain dummyC1 => cxxx; input => Gain dummyC2 => cxxx;
    cxxx.op(3); // calculate cx^3
   
    Gain UPPER; // prepare the upper part of the division
    ax => UPPER; bxx => UPPER; cxxx => UPPER; // calculate ax + bx^2 + cx^3
   
    Step one; // prepare 1
    ax => Gain axANDcxxx; cxxx => axANDcxxx; // calculate ax + cx^3
    axANDcxxx => FullRect ABSaxANDcxxx; // calculate |ax + cx^3|
   
    Gain LOWER; // prepare the lower part of the division
    one => LOWER; bxx => LOWER; ABSaxANDcxxx => LOWER; // calculate 1 + bx^2 + |ax + cx^3|
   
    UPPER => output;
    LOWER => output;
    output.op(4); // calculate f(x) by dividing UPPER with LOWER
}


and this.. the test code:
Code:
kjzGenOverdrive01 OD;

// change these to hear different drive characters
OD.aInit.next(2);
OD.bInit.next(3);
OD.cInit.next(5);
// - -

SinOsc s => OD.input;
OD.output => dac;

for(int i; i < 10; i++)
{
    (i + 1) => s.gain;
    second => now;
}


please feel free to test (over)drive.
- - - - -

There is also another thing, the easy clipper I posted quite some time ago on the wiki, you can check out also at http://wiki.cs.princeton.edu/forums.html/ChucK/kijjaz-utility-classes.ck
Code:
class kjzClipper01 // clip signal within -1 to 1 with simple UGens
{
   Gain input; // chuck input signal to this
   Gain output; // chuck this out to have the result
   
   Step one; 1 => one.next;
   input => HalfRect a;
   one => a; // calculate a from HalfRect(input + 1)
   one => Gain two; 2 => two.gain;
   -1 => a.gain;
   a => HalfRect b;
   two => b; // calculate b from HalfRect(2 - HalfRect(input + 1))
   -1 => b.gain;
   one => output;
   b => output; // the result we want: 1 - HalfRect(2 - HalfRect(input + 1))
}
Back to top
View user's profile Send private message Send e-mail Visit poster's website Yahoo Messenger MSN Messenger
Display posts from previous:   
Post new topic   Reply to topic Moderators: Kassen
Page 2 of 2 [36 Posts]
View unread posts
View new posts in the last week
Goto page: Previous 1, 2
Mark the topic unread :: View previous topic :: View next topic
 Forum index » DIY Hardware and Software » ChucK programming language
Jump to:  

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum
Buy N Save

Please support our site. If you click through and buy from
our affiliate partners, we earn a small commission.


Forum with support of Syndicator RSS
Powered by phpBB © 2001, 2005 phpBB Group
Copyright © 2003, 2004, 2005, 2006 and 2007 by electro-music.com