electro-music.com   Dedicated to experimental electro-acoustic
and electronic music
 
    Front Page  |  Radio
 |  Media  |  Forum  |  Wiki  |  Links
Forum with support of Syndicator RSS
 FAQFAQ   CalendarCalendar   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   LinksLinks
 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
functions as arguments to other functions
Post new topic   Reply to topic Moderators: Kassen
Page 1 of 1 [21 Posts]
View unread posts
View new posts in the last week
Mark the topic unread :: View previous topic :: View next topic
Author Message
wppk



Joined: Jan 25, 2008
Posts: 31
Location: Los Angeles

PostPosted: Wed Jan 30, 2008 5:33 pm    Post subject:  functions as arguments to other functions Reply with quote  Mark this post and the followings unread

i was wondering if it is possible to pass functions as arguments to other functions in Chuck.

Can anyone shed some light on this?

Thanks.
Back to top
View user's profile Send private message
Kassen
Janitor
Janitor


Joined: Jul 06, 2004
Posts: 7678
Location: The Hague, NL
G2 patch files: 3

PostPosted: Wed Jan 30, 2008 5:50 pm    Post subject: Reply with quote  Mark this post and the followings unread

do you mean like this?
Code:

SinOsc s => dac;

while(1)
  {
  //function with a function as a argument that has a function as a argument
  //picks a note number, translates it to a frequency and sets this to the oscillator's pitch
  s.freq( Std.mtof( Std.rand2(32, 64) ) );
  .5::second => now;
  }


If so then yes :¬). This could also be re-written using the ChucK operator which is often more readable but where a function takes two or more arguments you'll need the style I use above.

_________________
Kassen
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Kassen
Janitor
Janitor


Joined: Jul 06, 2004
Posts: 7678
Location: The Hague, NL
G2 patch files: 3

PostPosted: Wed Jan 30, 2008 5:51 pm    Post subject: Reply with quote  Mark this post and the followings unread

Welcome on board, BTW!
_________________
Kassen
Back to top
View user's profile Send private message Send e-mail Visit poster's website
wppk



Joined: Jan 25, 2008
Posts: 31
Location: Los Angeles

PostPosted: Wed Jan 30, 2008 10:26 pm    Post subject: Reply with quote  Mark this post and the followings unread

Thanks, I'm glad to be on board.

So basically if one writes a function that returns a specific type then any other function that returns that same type can be used as an argument?

here's what I've got going on.
it's a function for sweeping a midi cc.
I'm trying to write another function that will allow me to input this sweep function's arguments on the fly. i want to implement this new function as the sweep function's arguments.

//cc sweep

fun int sweep( int s, int e) {

s => int start;
e => int end;


for(0 => int i;;i++) {
while(true) {
e => end;
<<<start>>>;

100::ms => now;
if(start == end ) break; return start; }

while(true) {
s => start;
<<<end>>>;
100::ms => now;
if(end == start) break; return end; }}
}



MidiOut mout;
MidiMsg output;
mout.open(0);

while(true){
sweep(1, 10) => output.data3;
}



Also this sweep function works just fine when it is a void function but when i set it to return the integer then it only returns the value of the first argument.

For some reason the inc/dec operators or not showing up for <<<start>> and <<<end>> when I preview this, but they're supposed to be there. Just in case they're not when this posts.
Back to top
View user's profile Send private message
Kassen
Janitor
Janitor


Joined: Jul 06, 2004
Posts: 7678
Location: The Hague, NL
G2 patch files: 3

PostPosted: Wed Jan 30, 2008 10:56 pm    Post subject: Reply with quote  Mark this post and the followings unread

wppk wrote:

So basically if one writes a function that returns a specific type then any other function that returns that same type can be used as an argument?


First to clarify; the functions my example uses are build in ones but you could easily write your own that would do similar things and use them in the same way, yes.

Secondly; you can give a function A to another function B as a parameter if function A returns the same type as B takes as it's parameter. Functions don't have to return data of the same type as their parameter so this makes a difference.

Basically you can say that you can use a function wherever you'd use some value as long as the function returns something of the type of that value.

Quote:

Also this sweep function works just fine when it is a void function but when i set it to return the integer then it only returns the value of the first argument.


I have to look into this in more detail but right now I suspect the issue is that your program never gets to the "return" statements because it always "breaks" before those. I think you need curly brackets around all of the lines you want to depend on your "if" condition, even if they are on the same line.... but I'm not a 100% sure.


Quote:
For some reason the inc/dec operators or not showing up for <<<start>> and <<<end>> when I preview this, but they're supposed to be there. Just in case they're not when this posts.


Did you disable HTML? That might well be it. HTML should be disabled if posting code, the "code" tag doesn't protect you which is a bug and is very annoying indeed.

_________________
Kassen
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Frostburn



Joined: Dec 12, 2007
Posts: 255
Location: Finland
Audio files: 9

PostPosted: Thu Jan 31, 2008 1:13 am    Post subject: Reply with quote  Mark this post and the followings unread

I was wondering if it's possible to pass a reference to a function as an argument to a function:
Code:
fun void hi(){ <<<"hello!">>>; }
fun void do_stuff(fun function_as_argument){
 <<<"doing stuff...">>>;
 spork~function_as_argument();
}

//Go
do_stuff( hi );


It would make it so much easier if you could pass a sporkable instrument function to a sequencer shred. ( Instead of writing a sequencer for each of the instruments separately. )

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



Joined: Jan 25, 2008
Posts: 31
Location: Los Angeles

PostPosted: Thu Jan 31, 2008 10:26 am    Post subject: Reply with quote  Mark this post and the followings unread

Thanks Kassen and Frostburn for your help. You guys are on it!

I think I understand this a bit more.

Frostburn, When i tried to run your example code I keep getting a syntax error in line 2 character 20. The Fun argument. So, I am a bit confused there. I'm using Mini audicle. Don't know if that matters or is any different from the command line.
Back to top
View user's profile Send private message
Kassen
Janitor
Janitor


Joined: Jul 06, 2004
Posts: 7678
Location: The Hague, NL
G2 patch files: 3

PostPosted: Thu Jan 31, 2008 12:27 pm    Post subject: Reply with quote  Mark this post and the followings unread

The Mini uses the same ChucK VM, compiler and parser as the commandline version.

The issue with Frost's example is that it's fictional code, a illustration of what he'd like to be able to do.

The problem here is that in ChucK functions aren't objects and so can't be referenced in that way. What you could try (I'm not sure this would fly) is make a dummy class with a single member function of type void named "do", then extend that towards new classes, one for every function you want, then write a function that takes a object of type "dummy" as a argument (I think this is legal), feed it a instance of one of the classes that extends dummy and run the .do() of that inside of the function.....

I suppose this might work but it's quite severe abuse, the idea is to have a class (which *is* a object) that's just a capsule for a single function and name all of those functions the same name so we can have them hitch a ride on the "object-ness" of the class.

I really wonder *why* functions aren't objects in ChucK, see also the topic Dewdrop World started a short while ago.

_________________
Kassen
Back to top
View user's profile Send private message Send e-mail Visit poster's website
blue hell
Site Admin


Joined: Apr 03, 2004
Posts: 24079
Location: The Netherlands, Enschede
Audio files: 278
G2 patch files: 320

PostPosted: Fri Feb 01, 2008 7:22 am    Post subject: Reply with quote  Mark this post and the followings unread

Kassen wrote:
I really wonder *why* functions aren't objects in ChucK, see also the topic Dewdrop World started a short while ago.


Also see : http://gafter.blogspot.com/2006/08/closures-for-java.html , which is a proposal for closures in Java, touching on the same stuff as mentioned above.

_________________
Jan
also .. could someone please turn down the thermostat a bit.
Posted Image, might have been reduced in size. Click Image to view fullscreen.
Back to top
View user's profile Send private message Visit poster's website
Frostburn



Joined: Dec 12, 2007
Posts: 255
Location: Finland
Audio files: 9

PostPosted: Mon Feb 04, 2008 3:58 am    Post subject: Reply with quote  Mark this post and the followings unread

Kassen wrote:
What you could try (I'm not sure this would fly) is make a dummy class with a single member function...

Thanks for the idea Kassen!
Works like a charm.
Here's an example with mathematical functions:
Notice how I can pass the lorenz equation to the runge kutta method as an argument.
(This propably isn't the simplest example to give but here goes!)
Code:
//Functions as objects!
//Pyry Pakkanen 2008

class Function{
    int input_order;
    int output_order;
   
    //TODO: Add checks that input and output are of correct order
    fun void func(float input[],float output[]){ <<<"This is a virtual class, silly :)">>>; }   
}
class LorenzEquation extends Function{
    3 => input_order;
    3 => output_order;
   
    //Parameters:
    10.0 => float sigma;
    28.0 => float rho;
    8.0/3.0 => float beta;   
   
    fun void func(float input[],float output[]){
        //input[0] => float x;
        //input[1] => float y;
        //input[2] => float z;
        sigma*(input[1]-input[0]) => output[0]; //x
        input[0]*(rho-input[2])-input[1] => output[1]; //y
        input[0]*input[1]-beta*input[2] => output[2]; //z
    }
}

//Implementation of the Runge-Kutta method for solving ordinary differential equations
class RungeKutta{
    //These will be initialized the first time you use any of the methods.
    float k1[];
    float k2[];
    float k3[];
    float k4[];
    float k_input[];
   
    false => int initialized;
    fun void init(int order){
        //TODO: Add sufficient amount of orders, or figure out some other way to make them arrays separate.
        if(order == 3){
            [0.0,0.0,0.0] @=> k1;
            [0.0,0.0,0.0] @=> k2;
            [0.0,0.0,0.0] @=> k3;
            [0.0,0.0,0.0] @=> k4;
            [0.0,0.0,0.0] @=> k_input;
        }
        true => initialized;
    }
   
    fun void rk4(Function f,float input[],float output[],float step_size){ //"The Runge Kutta method"
        //TODO: Check that everything fits together
        if(!initialized) init( input.cap() );
       
        f.func(input,k1); //Fill up k1
       
        for(0 => int i; i < k2.cap(); i++) input[i] + 0.5*step_size*k1[i] => k_input[i];
        f.func(k_input,k2); //Fill up k2
       
        for(0 => int i; i < k3.cap(); i++) input[i] + 0.5*step_size*k2[i] => k_input[i];
        f.func(k_input,k3); //Fill k3 up
       
        for(0 => int i; i < k4.cap(); i++) input[i] + step_size*k3[i] => k_input[i];
        f.func(k_input,k4); //Up-fill k4
       
        //And finally output everything
        for(0 => int i; i < output.cap(); i++) input[i] + step_size/6.0*(k1[i]+2.0*k2[i]+2.0*k3[i]+k4[i]) => output[i];       
    }
}

[0.0,5.0,10.0] @=> float xyz1[]; //Initial values
float xyz2[3]; //We need an another array to hold the results

0.01 => float delta_t;

LorenzEquation lorenz;
RungeKutta rk;

//Do ten steps along the lorenz attractor and print the results
for(0 => int elligence; elligence < 10; elligence++){
    rk.rk4(lorenz,xyz1,xyz2,delta_t);
    for(0 => int i; i < xyz2.cap(); i++) <<<xyz2[i]>>>;
    <<<"","">>>;
    rk.rk4(lorenz,xyz2,xyz1,delta_t);
    for(0 => int i; i < xyz1.cap(); i++) <<<xyz1[i]>>>;
    <<<"","">>>;
}

//Uncomment if you'd like to hear the lorenz attractors x-component
/*
500::samp/second => delta_t;
Step s => Gain g => dac; 0.01 => g.gain;
samp => dur rate;

for(now + second => time later; now < later;){
    rk.rk4(lorenz,xyz1,xyz2,delta_t);
    xyz2[0] => s.next;
    rate => now;
   
    rk.rk4(lorenz,xyz2,xyz1,delta_t);
    xyz1[0] => s.next;
    rate => now;
}*/

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


Joined: Jul 06, 2004
Posts: 7678
Location: The Hague, NL
G2 patch files: 3

PostPosted: Tue Feb 05, 2008 3:14 pm    Post subject: Reply with quote  Mark this post and the followings unread

Frostburn wrote:
Kassen wrote:
What you could try (I'm not sure this would fly) is make a dummy class with a single member function...

Thanks for the idea Kassen!
Works like a charm.


Cool!

Glad to have been of assistance. I'm still struggling with this concept because what I'd really like is get around some name-space issues. I'd like to use assignment combined with this trick to inject code into running shreds. I'm having some trouble with namespace and I think at least one bug that's linked to static Ugens in public classes but nothing I've been able to pinpoint yet.

Still, I think wrapper classes to make functions into objects (for practical purposes) is a technique that has a lot of potential. I hope somebody like Ge will comment on why functions aren't objects. I suppose some syntax would be needed to make a distinction between references and calls which may make the end result quite comparable to what we're doing now but still, this feels a bit cludgy to me.

_________________
Kassen
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Frostburn



Joined: Dec 12, 2007
Posts: 255
Location: Finland
Audio files: 9

PostPosted: Tue Feb 05, 2008 3:34 pm    Post subject: Reply with quote  Mark this post and the followings unread

I'd have to do it like this anyway because I need vector functions.
I'm now also working on a similar scheme to create vector patches to abuse ChucK's .op functionality and SinOscs with .sync(1) to create quick and stable self modulating oscillator networks. Actually it will allow using any Ordinary Differential Equation that has only polynomial and sine terms for the phase of a SinOsc.

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



Joined: Dec 15, 2006
Posts: 19
Location: minneapolis

PostPosted: Tue Feb 19, 2008 11:39 pm    Post subject: Reply with quote  Mark this post and the followings unread

Sweet thread.

I have been working in this direction since I found that you can't really chuck a gen into a variable. I am sorry the examples in the attachments aren't very interesting. Any help with the ease in/ease out transitions would be appreciated -- my math skills are poor.

michael


looper.ck
 Description:

Download
 Filename:  looper.ck
 Filesize:  3.12 KB
 Downloaded:  332 Time(s)


composite.ck
 Description:

Download
 Filename:  composite.ck
 Filesize:  10.55 KB
 Downloaded:  275 Time(s)


functor.ck
 Description:

Download
 Filename:  functor.ck
 Filesize:  5.63 KB
 Downloaded:  267 Time(s)

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



Joined: Dec 12, 2007
Posts: 255
Location: Finland
Audio files: 9

PostPosted: Wed Feb 20, 2008 1:31 am    Post subject: Reply with quote  Mark this post and the followings unread

One thing I can think of is overloading the functions so that you don't have too many classes floating around that basicly do the same thing:

Your code:
Code:
class Procedure // or Runnable
{
    fun void run()
    {
        // empty
    }
}

class FloatProcedure
{
    fun void run(float arg)
    {
        // empty
    }
}


Would become:
Code:
class Procedure // or Runnable
{
    fun void run()
    {
        // empty
    }

    fun void run(float arg)
    {
        // empty
    }
}


ChucK knows what function to use based on the type of arguments.

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



Joined: Dec 15, 2006
Posts: 19
Location: minneapolis

PostPosted: Wed Feb 20, 2008 8:54 am    Post subject: Reply with quote  Mark this post and the followings unread

Thanks for the reply.

One, I like small classes. Keep it simple, do one and only one thing, etc.

Two, the point of all of the different "functor" interfaces is to allow other methods to accept them as parameters.

Note the different loop methods in looper.ck, one takes a Procedure (no parameters) and the other takes a FloatProcedure (one float parameter). The first doesn't provide any information to the "callback" procedure whereas the second provides a float between 0.0 and 1.0 that lets the "callback" procedure know how far along in the loop duration the current call is.

The first one you might use to trigger a sample, the second you might use with an interpolation function to fiddle with a parameter.

I will post an example that makes some noise shortly. Smile

michael
Back to top
View user's profile Send private message
heuermh



Joined: Dec 15, 2006
Posts: 19
Location: minneapolis

PostPosted: Thu Feb 21, 2008 10:07 am    Post subject: Reply with quote  Mark this post and the followings unread

Here is a silly example. Note that the file would be much shorter with a proper import mechanism in ChucK.

Be sure to replace the file names with your own kick and snare samples.

Then try different interpolation functions, wire the interpolation functions to parameters other than freq, change loop rates, etc.

michael


example.ck
 Description:

Download
 Filename:  example.ck
 Filesize:  3.22 KB
 Downloaded:  211 Time(s)

Back to top
View user's profile Send private message
Kassen
Janitor
Janitor


Joined: Jul 06, 2004
Posts: 7678
Location: The Hague, NL
G2 patch files: 3

PostPosted: Thu Feb 21, 2008 11:48 am    Post subject: Reply with quote  Mark this post and the followings unread

Looks very clean and nice!

Now, if we could only get around the namespace issues we could assign such objects to objects in running code and we'd have true updates of code without flushing all data.

_________________
Kassen
Back to top
View user's profile Send private message Send e-mail Visit poster's website
heuermh



Joined: Dec 15, 2006
Posts: 19
Location: minneapolis

PostPosted: Thu Feb 21, 2008 1:58 pm    Post subject: Reply with quote  Mark this post and the followings unread

Not quite sure what you mean by that, but the following works as one might expect.

The procedure can be modified while the sporked function runs.

michael


mutable.ck
 Description:

Download
 Filename:  mutable.ck
 Filesize:  1.26 KB
 Downloaded:  188 Time(s)

Back to top
View user's profile Send private message
Kassen
Janitor
Janitor


Joined: Jul 06, 2004
Posts: 7678
Location: The Hague, NL
G2 patch files: 3

PostPosted: Thu Feb 21, 2008 2:57 pm    Post subject: Reply with quote  Mark this post and the followings unread

heuermh wrote:
Not quite sure what you mean by that, but the following works as one might expect.

The procedure can be modified while the sporked function runs.



Nice, but what I want is to do is set up a framework like this and make it run, then write some variation function and inject that into the running shred, while it runs and without it stopping/re-initiating.

So far my experiments have led to a complete maze of name-space issues and a lot of crashes.

_________________
Kassen
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Acoustic Interloper



Joined: Jul 07, 2007
Posts: 2067
Location: Berks County, PA
Audio files: 89

PostPosted: Sat Aug 30, 2008 6:17 am    Post subject: Reply with quote  Mark this post and the followings unread

Blue Hell wrote:
Kassen wrote:
I really wonder *why* functions aren't objects in ChucK, see also the topic Dewdrop World started a short while ago.


Also see : http://gafter.blogspot.com/2006/08/closures-for-java.html , which is a proposal for closures in Java, touching on the same stuff as mentioned above.

Thanks for this reference! I thought about the same limitation in Java when I started to read this thread today, and was unaware that Gosling, et. al. were addressing it at the language level. I'll be teaching an undergrad and a different grad course in programming language mechanics in the spring, am using Python in the course (or considering Ruby, with which I am unfamiliar) partly because it has closures, and haven't had time to keep up to date on plans for Java. This helps.

If the ChucK designers decide to implement closures in ChucK, that Java discussion is worth reading.

_________________
When the stream is deep
my wild little dog frolics,
when shallow, she drinks.
Back to top
View user's profile Send private message Visit poster's website
Kassen
Janitor
Janitor


Joined: Jul 06, 2004
Posts: 7678
Location: The Hague, NL
G2 patch files: 3

PostPosted: Tue Sep 02, 2008 2:06 pm    Post subject: Reply with quote  Mark this post and the followings unread

Acoustic Interloper wrote:

If the ChucK designers decide to implement closures in ChucK, that Java discussion is worth reading.


I feel that something in this vein would be a logical extension to ChucK. I can see many elements of music and musical performance that are analogue to functions and that would benefit from being able to pass them. For example a arbitrary element in playing (say intonation or melody or....) of one band member could inspire another to adopt it as well. Such aspects of playing may not be easily expressible in pre-defined data-types yet we may want to have on shred pass them to another in some way.

It's my opinion right now that we need something like this in time, we already have functions that act as objects in "Shreds" though they are a bit of a exception and while powerful in terms of concurrency not that powerful on their own in interacting with other bits of code because their name-space is closed-off.

We could have a different sort of "unusual function" that's more specialised in this sort of thing. Perhaps the main issue is name-space, I wouldn't be surprised if the syntax for "functions as objects" would fall into place quite smoothly once we deal with some of the questions there.

_________________
Kassen
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic Moderators: Kassen
Page 1 of 1 [21 Posts]
View unread posts
View new posts in the last week
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


Forum with support of Syndicator RSS
Powered by phpBB © 2001, 2005 phpBB Group
Copyright © 2003 through 2009 by electro-music.com - Conditions Of Use