Author |
Message |
wppk
Joined: Jan 25, 2008 Posts: 31 Location: Los Angeles
|
Posted: Wed Jan 30, 2008 5:33 pm Post subject:
functions as arguments to other functions |
 |
|
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
|
|
 |
Kassen
Janitor


Joined: Jul 06, 2004 Posts: 7678 Location: The Hague, NL
G2 patch files: 3
|
Posted: Wed Jan 30, 2008 5:50 pm Post subject:
|
 |
|
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
|
|
 |
Kassen
Janitor


Joined: Jul 06, 2004 Posts: 7678 Location: The Hague, NL
G2 patch files: 3
|
Posted: Wed Jan 30, 2008 5:51 pm Post subject:
|
 |
|
Welcome on board, BTW! _________________ Kassen |
|
Back to top
|
|
 |
wppk
Joined: Jan 25, 2008 Posts: 31 Location: Los Angeles
|
Posted: Wed Jan 30, 2008 10:26 pm Post subject:
|
 |
|
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
|
|
 |
Kassen
Janitor


Joined: Jul 06, 2004 Posts: 7678 Location: The Hague, NL
G2 patch files: 3
|
Posted: Wed Jan 30, 2008 10:56 pm Post subject:
|
 |
|
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
|
|
 |
Frostburn

Joined: Dec 12, 2007 Posts: 255 Location: Finland
Audio files: 9
|
Posted: Thu Jan 31, 2008 1:13 am Post subject:
|
 |
|
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
|
|
 |
wppk
Joined: Jan 25, 2008 Posts: 31 Location: Los Angeles
|
Posted: Thu Jan 31, 2008 10:26 am Post subject:
|
 |
|
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
|
|
 |
Kassen
Janitor


Joined: Jul 06, 2004 Posts: 7678 Location: The Hague, NL
G2 patch files: 3
|
Posted: Thu Jan 31, 2008 12:27 pm Post subject:
|
 |
|
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
|
|
 |
Blue Hell
Site Admin

Joined: Apr 03, 2004 Posts: 24008 Location: The Netherlands, Enschede
Audio files: 274
G2 patch files: 320
|
Posted: Fri Feb 01, 2008 7:22 am Post subject:
|
 |
|
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.
 |
|
Back to top
|
|
 |
Frostburn

Joined: Dec 12, 2007 Posts: 255 Location: Finland
Audio files: 9
|
Posted: Mon Feb 04, 2008 3:58 am Post subject:
|
 |
|
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
|
|
 |
Kassen
Janitor


Joined: Jul 06, 2004 Posts: 7678 Location: The Hague, NL
G2 patch files: 3
|
Posted: Tue Feb 05, 2008 3:14 pm Post subject:
|
 |
|
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
|
|
 |
Frostburn

Joined: Dec 12, 2007 Posts: 255 Location: Finland
Audio files: 9
|
Posted: Tue Feb 05, 2008 3:34 pm Post subject:
|
 |
|
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
|
|
 |
heuermh
Joined: Dec 15, 2006 Posts: 19 Location: minneapolis
|
Posted: Tue Feb 19, 2008 11:39 pm Post subject:
|
 |
|
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
Description: |
|
 Download |
Filename: |
looper.ck |
Filesize: |
3.12 KB |
Downloaded: |
308 Time(s) |
Description: |
|
 Download |
Filename: |
composite.ck |
Filesize: |
10.55 KB |
Downloaded: |
252 Time(s) |
Description: |
|
 Download |
Filename: |
functor.ck |
Filesize: |
5.63 KB |
Downloaded: |
246 Time(s) |
|
|
Back to top
|
|
 |
Frostburn

Joined: Dec 12, 2007 Posts: 255 Location: Finland
Audio files: 9
|
Posted: Wed Feb 20, 2008 1:31 am Post subject:
|
 |
|
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
|
|
 |
heuermh
Joined: Dec 15, 2006 Posts: 19 Location: minneapolis
|
Posted: Wed Feb 20, 2008 8:54 am Post subject:
|
 |
|
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.
michael |
|
Back to top
|
|
 |
heuermh
Joined: Dec 15, 2006 Posts: 19 Location: minneapolis
|
|
Back to top
|
|
 |
Kassen
Janitor


Joined: Jul 06, 2004 Posts: 7678 Location: The Hague, NL
G2 patch files: 3
|
Posted: Thu Feb 21, 2008 11:48 am Post subject:
|
 |
|
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
|
|
 |
heuermh
Joined: Dec 15, 2006 Posts: 19 Location: minneapolis
|
|
Back to top
|
|
 |
Kassen
Janitor


Joined: Jul 06, 2004 Posts: 7678 Location: The Hague, NL
G2 patch files: 3
|
Posted: Thu Feb 21, 2008 2:57 pm Post subject:
|
 |
|
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
|
|
 |
Acoustic Interloper

Joined: Jul 07, 2007 Posts: 2065 Location: Berks County, PA
Audio files: 89
|
Posted: Sat Aug 30, 2008 6:17 am Post subject:
|
 |
|
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
|
|
 |
Kassen
Janitor


Joined: Jul 06, 2004 Posts: 7678 Location: The Hague, NL
G2 patch files: 3
|
Posted: Tue Sep 02, 2008 2:06 pm Post subject:
|
 |
|
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
|
|
 |
|