Hi, I have a number of relatively newbie Qs on my first-ever ChucK class I've written. the good thing is that it works, although it sounds pretty horrible. The bad thing is that I wish the ChucK language would have more features and might have discovered a bug related to null pointers. My idea in this class is to emulate the functionality of the various audio and event switch modules as well as the audio relay module in Reaktor. That is n inputs and one output such that you can select which input is patched to the output at any given time. The questions are: 1. Is the code in the class OK in terms of style and implementation i.e. is there something highly uncanonical in naming or some things that could be done smarter for such a simple thing? - In particular, I'm not sure if the gain module is needed in the output. - Is there a better way to grow the array on demand? In Perl I can just assign to higher indeces and it will grow, or use the push function to add an arbitraryly sized list at the end. And Java has array lists, too. - ALso in the test script, I would like to initialize my UGen array anonymously without having to make up variable names for each object and manully assign the indeces, I'm lazy I guess. - Is there a style manual for ChucK? Until we can inherit from UGen it would be great to have a common set of method names for UGen like modules. Currently I've drawn my influences from Java and Dinky.ck. - I've noticed that the names for most chuck properties are extremely short, for example. - Which reminds me, does chucK support duck typing? Abstractly put, Suppose a class or interface c with the method name m and an object o such that not o instanceof c. Does o.m() get called in its own class, even if o is not related to c by inheritance. Polymorphism that works based on a name is there in Perl and Python, I think, where as Java is stricter and requires that the object be a subclass or interface implementation of c, a common method name is not good enough. 2. How is ChucK naming like? Suppose we have a parameter p of type t. I would like to create its accessors as: - function void p(t i); // set function t p(); // get Yet although chucK supports overloading functions, it does not let them differ only by return type, right? In a test class I get stuff like: [test.ck]:line(5): function signatures differ in return type... The same thing with JAva really and I do understand it could often be ambiguous. Perl is one of the few languages in which this works well as scalar is the only primitive scalar type and it has list and void context to make things more or less unambiguous. But ChucK is not Perl, nough said. - As I think parameters with the verbs get and set are slightly redundant, if boolean stuff starts with e.g. is , I thought I would use: function t p(); function setP(t i); However, if there is already a data member named p chucK does not let me hav a member function named p in the same class, right? After modding my test class, I got: [test.ck]:line(4): function name 'p' is already used by another value 3. To save some duplicated code, and as there's no constructor support, it occurred to me I could write a function that given an array of UGens, instanciates my audio switch (OneOfN), populates it and returns a reference. Yet if I paste this at the top of my test script and try to run it ChucK claims UGen doesn't have the caps method, even though printing out the function argument says it is of type UGen[], that is an array. What might be wrong, i.e. why does it think an array of UGen is just a UGen rather than an array? I'm mightily confused here. The code: // Partially untested. function OneOfN newOneOfN(UGen choices[]) { // A pseudo-constructor for populating instances of OneOfN given an array. OneOfN selector; choices.caps() => int max; // Cache it, so only one method call. selector.setInputCount(max); for(0 => int i; i < max; ++i) selector.setInputAt(i, choices[i]); if(max > 0) // Array not empty. selector.selectInput(0); return selector; } // function 4. When I use my audio switch to determine whether audio flows through, i.e. as an audio relay one of whose inputs is practically disconnected (I've patched blackhole there), it seems to work OK i.e. I get the sound of silence when expected. However, if I change my array initializer in OneOfN.ck: from: blackhole @=> newIn[i]; // Not connected initially. to null @=> newIn[i]; // Not connected initially. Strange things start to happen. I don't get a null pointer exception at runtime as I would expect in my test script, as the unconnected input is actually null. In stead ChucK crashes spectacularly with the standard WIndows XP dialog about it. This happens at runtime, when the disconnected input is picked the first time. ChucK reports the version as: C:\audio\CHUCK-~1.7-E\bin>chuck.exe --version chuck version: 1.2.0.7b (dracula) exe target: microsoft win32 http://chuck.cs.princeton.edu/ [Speaking of Dracula, I'm just reading Frankenstein, talk about funny co-incidences. Hmm what's the code name for the next release?] I think these were my questions. As I tend to have a bad habbit of asking all too much, when someone who knows far more than I do is around, I'd actually be pleased if even half of these would get answered eventually, <smile>. And now finally the code: public class OneOfN { // A parameterizable audio multiplexer (switch). Todo: write user docs, -1 => int n; // Initially invalid. UGen in[]; Gain out; // Neede some Ugen for producing output? function void connect(UGen output) { out => output; } function void setInputAt(int i, UGen u) { u @=> in[i]; } function UGen getInputAt(int i) { return in[i]; } function UGen getOutput() { return out; } function int getSelectedInput() { return n; } function int getInputCount() { return in.cap(); } function void setSelectedInput(int i) { if(n > -1) in[n] =< out; // Disconnect only if size already set. i => n; // We have a new output. in[n] => out; } // function function void setInputCount(int newSize) { // Changes the size of the input array to accommodate that many inputs. UGen newIn[newSize]; for(0 => int i; i < newSize; ++i) blackhole @=> newIn[i]; // Not connected initially. newIn @=> in; // Not garbage collected, there's one ref left. } // function } // class And now the test script called patch.ck: I run it by saying C:\audio\CHUCK-~1.7-E\code>..\bin\chuck.exe OneOfN.ck patch.ck The code: // Use the switch to select one input and save CPU. OneOfN oscSelect; UGen @oscs[3]; // Our oscs. SinOsc o1 @=> oscs[0]; SawOsc o2 @=> oscs[1]; SqrOsc o3 @=> oscs[2]; oscSelect.setInputCount(oscs.cap()); // Tweak the gains to make an audible difference. for(0 => int i; i < oscs.cap(); ++i) { oscs[i].gain(1.0 / (i + 1)); // Avoid divide by 0! oscSelect.setInputAt(i, oscs[i]); } // for // Use the switch as an audio relay and do the patching. OneOfN audioRelay; audioRelay.setInputCount(2); // 1 real, 1 empty. audioRelay.setInputAt(0, oscSelect.getOutput()); audioRelay.connect(dac); // Times, they keep on changing. for(0 => int i; true; ++i) { Math.rand2(-10, 10) => int chance; oscSelect.setSelectedInput(i % oscs.cap()); // CYcle waveform. audioRelay.setSelectedInput(chance < 5 ? 0 : 1); // 1 is connected to GND0. 50::ms => now; } // for -- With kind regards Veli-Pekka Tätilä (vtatila@mail.student.oulu.fi) Accessibility, game music, synthesizers and programming: http://www.student.oulu.fi/~vtatila/
Hi Veli-Pekka, please see responses below. On Mar 16, 2007, at 6:55 PM, Veli-Pekka Tätilä wrote:
1. Is the code in the class OK in terms of style and implementation i.e. is there something highly uncanonical in naming or some things that could be done smarter for such a simple thing?
Looks pretty good from here. A disconnect method is something that I can see being useful, though.
- In particular, I'm not sure if the gain module is needed in the output.
It shouldnt be needed, but may be useful if you wanted to adjust the gain of the entire UGen unilaterally.
- Is there a better way to grow the array on demand? In Perl I can just assign to higher indeces and it will grow, or use the push function to add an arbitraryly sized list at the end. And Java has array lists, too.
Yes, your approach is currently the only way to grow the numeric part of the array. It is a goal to eventually have the ability to dynamically adjust the capacity of an array.
- ALso in the test script, I would like to initialize my UGen array anonymously without having to make up variable names for each object and manully assign the indeces, I'm lazy I guess.
I don't see this as laziness, necessarily--it is a completely legitimate thing to want to do. Fortunately, there is the 'new' operator, which, similar to its counterparts in Java and C++, anonymously allocates an object of the specified type. Amending part of your code below to use this operator would look something like this:
UGen @oscs[3]; // Our oscs. new SinOsc @=> oscs[0]; new SawOsc @=> oscs[1]; new SqrOsc @=> oscs[2];
or even this:
[ new SinOsc $ UGen, new SawOsc, new SqrOsc ] @=> UGen @oscs[];
Note that the initial $ UGen (typecast to UGen) is needed to tell the compiler that this is a UGen array, not a SinOsc array. One caveat to this technique is that you won't be able to set any parameters to your oscillators beyond those that are present in every UGen. Notably, UGen doesn't have a frequency parameter.
- Is there a style manual for ChucK? Until we can inherit from UGen it would be great to have a common set of method names for UGen like modules. Currently I've drawn my influences from Java and Dinky.ck.
There is no style manual, but I think following the lead of the examples and Java is probably the best approach at this point.
- Which reminds me, does chucK support duck typing? Abstractly put, Suppose a class or interface c with the method name m and an object o such that not o instanceof c. Does o.m() get called in its own class, even if o is not related to c by inheritance. Polymorphism that works based on a name is there in Perl and Python, I think, where as Java is stricter and requires that the object be a subclass or interface implementation of c, a common method name is not good enough.
ChucK follows the Java model, requiring explicit inheritance for polymorphism to be (ab)used.
2. How is ChucK naming like? Suppose we have a parameter p of type t. I would like to create its accessors as:
- function void p(t i); // set function t p(); // get Yet although chucK supports overloading functions, it does not let them differ only by return type, right? In a test class I get stuff like:
[test.ck]:line(5): function signatures differ in return type...
The same thing with JAva really and I do understand it could often be ambiguous. Perl is one of the few languages in which this works well as scalar is the only primitive scalar type and it has list and void context to make things more or less unambiguous. But ChucK is not Perl, nough said.
Yes, ChucK is a strongly typed language, which generally require return types of functions to be known at run-time. One practice you might consider adopting is returning the value of the parameter in your set method, i.e.
function t p(t i); // set function t p(); // get
This approach also makes things like this possible, which is sometimes appealing (or appalling): class myClass { int _p; fun int p( int __p ) { return __p => _p; } fun int p() { return _p; } } myClass a, b, c, d; 1 => a.p => b.p => c.p => d.p;
- As I think parameters with the verbs get and set are slightly redundant, if boolean stuff starts with e.g. is , I thought I would use: function t p(); function setP(t i); However, if there is already a data member named p chucK does not let me hav a member function named p in the same class, right? After modding my test class, I got:
[test.ck]:line(4): function name 'p' is already used by another value
Yes, this is similar semantically to many C-like languages. A common practice that I see is, for a given parameter p, to call it _p and then have the accessors use p, as in the myClass example above. m_p (for member variable p) is another popular approach.
3. To save some duplicated code, and as there's no constructor support, it occurred to me I could write a function that given an array of UGens, instanciates my audio switch (OneOfN), populates it and returns a reference.
Ah, yes, a "factory" method. You might consider making this function a static member function of the OneOfN class rather than a non-class function. This has the advantage of making the function accessible to all shreds if OneOfN is a public class. (Its also liable to satisfy any object oriented nitpickers reading your code.)
What might be wrong, i.e. why does it think an array of UGen is just a UGen rather than an array? I'm mightily confused here. The code: [...] choices.caps() => int max; // Cache it, so only one method call.
I believe this should be choices.cap() (no 's').
4. When I use my audio switch to determine whether audio flows through, i.e. as an audio relay one of whose inputs is practically disconnected (I've patched blackhole there), it seems to work OK i.e. I get the sound of silence when expected. However, if I change my array initializer in OneOfN.ck:
from:
blackhole @=> newIn[i]; // Not connected initially.
to
null @=> newIn[i]; // Not connected initially.
Strange things start to happen. I don't get a null pointer exception at runtime as I would expect in my test script, as the unconnected input is actually null. In stead ChucK crashes spectacularly with the standard WIndows XP dialog about it.
Yes! This is a known bug in the currently release version. It should be fixed in the current release candidate, and the upcoming release as well (feel free to test/try to break it at your convenience).
[Speaking of Dracula, I'm just reading Frankenstein, talk about funny co-incidences. Hmm what's the code name for the next release?]
Coincidentally, frankenstein was the code name of the original ChucK release. dracula is the code name for the current series of ChucK releases, whatever that means, so the name will probably be dracula for a while.
I think these were my questions. As I tend to have a bad habbit of asking all too much, when someone who knows far more than I do is around, I'd actually be pleased if even half of these would get answered eventually, <smile>.
No worries! We're all here to help. spencer
On Mar 16, 2007, at 6:55 PM, Veli-Pekka Tätilä wrote: A disconnect method is something that I can see being useful, Fair enough, especially as the module config can be changed in real time. WHich reminds me, we talked about growing arrays dynamically. If I change
Spencer Salazar wrote: the number of inputs on the fly for my OneOfN switch, and chuck new inputs to it, does this happen fast enough that I can run it in a 1::samp loop? I've never benchmarked it but somehow have an intuitive notion that allocating new memory might be heavy.
- In particular, I'm not sure if the gain module is needed in the output. It shouldnt be needed, but may be useful if you wanted to adjust the gain of the entire UGen unilaterally. Hmm I still think it might be needed. The code for my connect method is: function void connect(UGen output) { out => output; } Where out is the Gain module. That is I need something to chucK to my output. And I presume that must be another UGen. As I cannot inherit from a UGen, I guess the gain module might be my only choice.
- ALso in the test script, I would like to initialize my UGen array anonymously Fortunately, there is the 'new' operator, which, similar to its counterparts in Java and C++, anonymously allocates an object of the specified type. [ new SinOsc $ UGen, new SawOsc, new SqrOsc ] @=> UGen @oscs[]; Ah that's the ticket, thanks. In Java you need the new operator for every non-primitive type. But in C++ not using new means that the variables live in the stack just like other function arguments. So are chucK objects, not allocated with new, also stack variables? HOw's the VM like, by the way, would it make sensse to hand-code anything in ChucK assembler?
Note that the initial $ UGen (typecast to UGen) is needed to tell the compiler that this is a UGen array, not a SinOsc array. Ah I see, sort of. Is this dollar thing documented in the manual?
One caveat to this technique is that you won't be able to set any parameters to your oscillators beyond those that are present in every UGen. Notably, UGen doesn't have a frequency parameter. Ah, that's bad. I mean the arrays are homogenous then and each element must be of the specified type or some derived type. As polymorphism based on a method name, aka duck typing, is not supported as this is a Java:ish language, will there be a template mechanism or the ability to downcast arguments? For example, Java's ArrayList can store objects but you can then downcast them to the desired type or let the compiler do it for you which is called autoboxing I think.
There is no style manual, but I think following the lead of the examples and Java is probably the best approach at this point. Ah yes, that sounds reasonable. And Howabout the braces are they commonly
One practice you might consider adopting is returning the value of the parameter in your set method <snip> myClass a, b, c, d; 1 => a.p => b.p => c.p => d.p; Ah the good old chained assignments. ANother possibility would be to return
Another way to do it might be to add some reflection API through which you can ask for the method and call it for a particular object. I've noticed there's already a class named Class, based on some error messages. What ,members does it have? Which brings us to inheritance. You said that interfaces are considered as a future extension. IF it works like Java. does this mean I can currently inherit from only one class even if it would be abstract? Would it be feasible to keep track of how many instances a particular class has as a static member? Sure you can inc the count in a constructor, but one would need a ddestructor to know when to decrease the count? Or alternatively, have uggly method calls for upping and downing the count explicitly, as in COM. the K&R style or the BSD/Allman style? I think Java and most other C-like langs have adopted the former. I like the latter myself for some fairly specific reasons, although being a fan of the K&R book. In addition to preferring to comment decisions right after the opening brace, I use magnification and braille in coding which means a limited viewport. Only a handful of chars magnified and max 40 in braille, though you stil have to scan that with your fingers. So keeping the braces aligned makes them easier to spot. This is also why I comment end braces, as you can easily check Which brace it was using sspeech or braille. Though these are definitely minor things I guess I'd ideally take the ADA syntax foo some stuff end foo. I guess it might be slightly more musician friendly anyway, than C:ish things like braces, the pre and post dec and inc ops, augmented assignments and other such thingies, most of which are just syntactic sugar. But I've gotten used to them in C; Perl and java, so I ain't complaining. Speaking of operators, I really like the assignment operator in ChucK. AS I've never been a fan of doubling a symbol to give it another meaning, I once suggested that some language should have something similar to what ChucK has only right-associative. So I was very pleased to see => in ChucK: and that's even left-associative, meaning potentially more user-friendly. Which brings me to the chucK equality operator ==. Why two equals signs, one would be much more logical as we have a dedicated assignment operator anyway, and as >= has one equals sign, not two. Another thing I like is the syntactic sugar for handling setters as properties. That is: object.setter(firstArg); can be turned into firstArg => object.setter; So you don't have to know it is a function call behind the scenes. But could this also be exteneded to cover getters as well. Namely that as an l-value: object.getter() => itsValue; Could be reduced to: object.getter => itsValue; Where l-valueness and lack of braces Would imply a method call, provided that the class does not have a public data member named getter. But this is a bit more ambiguous I know, and there might be some pathological cases in the context of the whole language if this kind of addition is made. It is hard to judje the extent of such changes, though they are easy to suggest, from the user point of view. Is there a BNF grammar for chucK, by the way? I don't know Yacc yet, but should probably look into it some day. the object itself so you could chain method calls. A Perl module I saw recently did just that to let you construct English looking regular expressions via huge chains of method calls. Another funny consequence is in Java: String s = "foo"; s.toString().toString().toString(); Doesn't make any sense at all, but is legal, because all objects including String have a toString method. ChucK would benefit from one, too. As well as more formatted printing, hint sprintf is in very many languages these days including Java, C++, Perl, Python and even PHP.
function t p(); function setP(t i); However, if there is already a data member named p chucK does not let me hav a member function named p in the same class, right? [test.ck]:line(4): function name 'p' is already used by another value Yes, this is similar semantically to many C-like languages. A common practice that I see is, for a given parameter p, to call it _p and then have the accessors use p, as in the myClass example above. Why is the message talking about another value, though? Conceptually, one does not think of the function's formal argument as being a value. ONly when it is an actual one, it has a value at that point. But this is a minor semantic quibble.
There are various other practices for naming instance data. Although not really for oop use in Perl, I could use the prefix my for instance data and our for class data. And some Java styleguide recommended its and their, too, which I kinda like as well. I read code partially with synthetic speech so if it sounds like English that's a plus. You could infer from this i like SQL as well. Other practices, hmm, the SymbianOS uses a small i for instance and a small letter a for function arguments. SO a player class might have a member named iTunes, pun intended.
3. To save some duplicated code, and as there's no constructor support, it occurred to me I could write a function that given an array of UGens, instanciates my audio switch (OneOfN), populates it and returns a reference. Ah, yes, a "factory" method. You might consider making this function a static member function of the OneOfN class Ah yes, will do that. Although it means I'll have to call it explicitly anyway. Would be nice to have constructors some day, <sigh>.
snipped plenty of stuff here. Thanks for the rest of the ansers, too. Apparently the typos are my bad, again, and crashing in null pointers will be fixed. I think I'll wait for the official next release to try And see that it does not crash any more, as I'm pretty happy with this one. IS the manual updated in sync with the next release? -- With kind regards Veli-Pekka Tätilä (vtatila@mail.student.oulu.fi) Accessibility, game music, synthesizers and programming: http://www.student.oulu.fi/~vtatila/
On Mar 17, 2007, at 8:32 AM, Veli-Pekka Tätilä wrote:
On Mar 16, 2007, at 6:55 PM, Veli-Pekka Tätilä wrote: A disconnect method is something that I can see being useful, Fair enough, especially as the module config can be changed in real time. WHich reminds me, we talked about growing arrays dynamically. If I change
Spencer Salazar wrote: the number of inputs on the fly for my OneOfN switch, and chuck new inputs to it, does this happen fast enough that I can run it in a 1::samp loop? I've never benchmarked it but somehow have an intuitive notion that allocating new memory might be heavy.
It should be fast enough. Though you pretty much have to benchmark it on your own platform, because its all very much dependent on OS, hardware, audio driver, and the versions of everything. Anecdotally, allocating an array of 660,000 floats on OS X 10.4.8 on a MacBook will cause a short skip, but allocations an order of magnitude or so below that are likely to be okay. Additionally, you can save a little time/memory by using arrays of null UGen references, rather than arrays of UGens. In the former, each element of the array is initially null, while in the latter, each element in the array is initialized to a new UGen. So youd replace UGen in[]; [...] UGen newIn[newSize]; with UGen @ in[]; [...] UGen @ newIn[newSize]; And everything else should be the same.
- In particular, I'm not sure if the gain module is needed in the output. It shouldnt be needed, but may be useful if you wanted to adjust the gain of the entire UGen unilaterally. Hmm I still think it might be needed. The code for my connect method is: function void connect(UGen output) { out => output; } Where out is the Gain module. That is I need something to chucK to my output. And I presume that must be another UGen. As I cannot inherit from a UGen, I guess the gain module might be my only choice.
I was thinking you could store the output UGen in a UGen @ member variable, and then connect the appropriate UGen from UGen in[] as needed (essentially cutting out the middle man (where man is a Gain)). Either approach works well, though, there is very certainly no "one true way" to write ChucK code.
- ALso in the test script, I would like to initialize my UGen array anonymously Fortunately, there is the 'new' operator, which, similar to its counterparts in Java and C++, anonymously allocates an object of the specified type. [ new SinOsc $ UGen, new SawOsc, new SqrOsc ] @=> UGen @oscs[]; Ah that's the ticket, thanks. In Java you need the new operator for every non-primitive type. But in C++ not using new means that the variables live in the stack just like other function arguments. So are chucK objects, not allocated with new, also stack variables?
All ChucK objects are heap variables, regardless of instantiation method. Primitive types (int, float, time, dur) are on the stack.
HOw's the VM like, by the way, would it make sensse to hand-code anything in ChucK assembler?
Probably not. There isn't really any such ChucK assembler, although one could conceivably implement something like that.
Note that the initial $ UGen (typecast to UGen) is needed to tell the compiler that this is a UGen array, not a SinOsc array. Ah I see, sort of. Is this dollar thing documented in the manual?
It is, under the "operators" section of the language specification (its the cast operator). Its presented in the context of casting floats to ints, but you can also use it to move an Object up and down its inheritance hierarchy.
One caveat to this technique is that you won't be able to set any parameters to your oscillators beyond those that are present in every UGen. Notably, UGen doesn't have a frequency parameter. Ah, that's bad. I mean the arrays are homogenous then and each element must be of the specified type or some derived type. As polymorphism based on a method name, aka duck typing, is not supported as this is a Java:ish language, will there be a template mechanism or the ability to downcast arguments?
You can always cast them to back to what they were initially, using the $ operator. You just have to actually know what they are. Once interfaces are implemented there are probably a few tricks that could be used with those also.
Which brings us to inheritance. You said that interfaces are considered as a future extension. IF it works like Java. does this mean I can currently inherit from only one class even if it would be abstract?
Yes, thats correct.
There is no style manual, but I think following the lead of the examples and Java is probably the best approach at this point. Ah yes, that sounds reasonable. And Howabout the braces are they commonly the K&R style or the BSD/Allman style? I think Java and most other C-like langs have adopted the former. I like the latter myself for some fairly specific reasons, although being a fan of the K&R book. In addition to preferring to comment decisions right after the opening brace, I use magnification and braille in coding which means a limited viewport. Only a handful of chars magnified and max 40 in braille, though you stil have to scan that with your fingers. So keeping the braces aligned makes them easier to spot. This is also why I comment end braces, as you can easily check Which brace it was using sspeech or braille. Though these are definitely minor things I guess I'd ideally take the ADA syntax foo some stuff end foo. I guess it might be slightly more musician friendly anyway, than C:ish things like braces, the pre and post dec and inc ops, augmented assignments and other such thingies, most of which are just syntactic sugar. But I've gotten used to them in C; Perl and java, so I ain't complaining.
The trend seems to be towards BSD/Allman bracket style in ChucK, but you should go with whatever you feel most comfortable with. We should all be able to read your code either way.
Speaking of operators, I really like the assignment operator in ChucK. AS I've never been a fan of doubling a symbol to give it another meaning, I once suggested that some language should have something similar to what ChucK has only right-associative. So I was very pleased to see => in ChucK: and that's even left-associative, meaning potentially more user- friendly. Which brings me to the chucK equality operator ==. Why two equals signs, one would be much more logical as we have a dedicated assignment operator anyway, and as >= has one equals sign, not two.
I dont know the exact reasoning, but it seems logical to me when I consider that most programmers coming to ChucK will think that == makes the most sense, while arguably non-programmers won't have any particular predisposition to whether = or == is better. So to C/C++/ Java/Perl/etc. programmers, testing equality is business as usual, while for new programmers, its just one more thing to remember, like ending statements with semi-colons and having parentheses for function calls. Its also convenient for those (like me) that are used to = for assignment, as expressions involving = are caught with a compile-time error instead of a more subtle runtime error.
Another thing I like is the syntactic sugar for handling setters as properties. That is: object.setter(firstArg); can be turned into firstArg => object.setter; So you don't have to know it is a function call behind the scenes. But could this also be exteneded to cover getters as well. Namely that as an l-value: object.getter() => itsValue; Could be reduced to: object.getter => itsValue; Where l-valueness and lack of braces Would imply a method call, provided that the class does not have a public data member named getter. But this is a bit more ambiguous I know, and there might be some pathological cases in the context of the whole language if this kind of addition is made. It is hard to judje the extent of such changes, though they are easy to suggest, from the user point of view.
This is an interesting idea, but it wouldn't work right now because functions without parentheses are already rvalues (returning the function address I believe). You can't actually use this value for anything though, so maybe something like your suggestion could be implemented in the future.
Is there a BNF grammar for chucK, by the way? I don't know Yacc yet, but should probably look into it some day.
There is no official BNF grammar for ChucK available. I don't know yacc either, but in my experience its pretty easy to pick up the basics by just reading a .y file. spencer
Hi Spencer, Very useful info. I'll snip a lot and only comment the stuff I have more questions or additions for.
Additionally, you can save a little time/memory by using arrays of null UGen references, rather than arrays of UGens. Hmm isn't this a bit suspicious, in terms of semantics. I mean the default of instanciating arrays as though objects where already constructed. If they are added, that design cannot support classes that lack a parameterless constructor, singleton classes in which it is private, and abstract classes or interfaces which cannot b instanciated in the first place. IS string also a class? I read something to that effect but cannot find its methods anywhere. I don't seem to be able to do much apart from concatenating them.
will there be a template mechanism or the ability to downcast arguments? You can always cast them to back to what they were initially, using the $ operator. You just have to actually know what they are. Ah that's the question. Quite OK for homogenous stuff but I can already imagine a design in which this is not known. IN which I have to branch on a type name. That's a bad smell in OOPy circles often but not always. Many recursive data structure dumpers require, for example, that you know whether an element is a single item, some reference to an array or object or something else. Not very relevant to chucK right now, though, as there's no serialization support.
consider that most programmers coming to ChucK will think that == makes the most sense, while arguably non-programmers won't have any particular predisposition to whether = or == is better. OK, but then again one could claim the same about => if it didn't serve a dual or triplle role as a way to pass function arguments and connect uGens. I'd like to be able to overload => on my own classes some day, though.
used to = for assignment, as expressions involving = are caught with a compile-time error instead of a more subtle runtime error. Yes, agreed. Some forms of Basic are the worst, they use = in a boolean context to mean equality but if it is not in a control structureand looks like a plain assignment, that's what it is. Pascal has := too.
Another thing I like is the syntactic sugar for handling setters as properties. That is: object.setter(firstArg); can be turned into firstArg => object.setter; So you don't have to know it is a function call behind the scenes. But could this also be exteneded to cover getters as well. Namely that as an l-value: object.getter() => itsValue; Could be reduced to: object.getter => itsValue; Where l-valueness and lack of braces Would imply a method call, provided that the class does not have a public data member named getter. This is an interesting idea, but it wouldn't work right now because functions without parentheses are already rvalues (returning the function address I believe). Hmm interesting. FUnctions as a first-class datatype are very nice and that makes sense for just that, functions and static methods. But I don't see much sense in getting the address of an instance method as you cannot determine that its invocant is of the correct type anyway. I think perl let's you do that, but hey it's Perl, <smile>.
don't know yacc either, but in my experience its pretty easy to pick up the basics by just reading a .y file. Ah I'll take a look. I'll be lazy and ask if there's a direct URL to the current CHucK yacc grammar. I usually don't get the source, though in this case it might be beneficial.
-- With kind regards Veli-Pekka Tätilä (vtatila@mail.student.oulu.fi) Accessibility, game music, synthesizers and programming: http://www.student.oulu.fi/~vtatila/
hi list i made some sounds with the shakers ugen and was surprised that with some presets the sound was cutted away for all cycles after the first one. this happens not with all presets (eg. preset 5 works well, 3 not). i used this simple code: Shakers s => dac; s.preset(3); s.gain(2); s.freq(Note.C2); while(true) { s.noteOn(1); 2::second => now; s.noteOff(0); } is there anything i should consider using this ugen? thanks /moudi
Hi moudi, There are many aspects of Shakers that are opaque to me, but from what I can glean from the source, in the guiro (3) and wrench (10) presets of Shakers there is a notion of "ratchet position". This I assume is the position of the scraping object (the ratchet) along the notched surface. The position of the ratchet determines the number of individual ratchet sounds and thus the length of the produced sound. Taking a look at the source, the ratchet position starts out at 10 when you call preset(3); it is increased by 1 each time you call noteOn; it decreases for each actual ratchet sound that is heard; and it is set to 0 when you call noteOff. Thus, calling noteOn several times is one possible way to set the ratchet position to a certain level. Alternatively, you could call preset(3) to reset the position to 10 each time. I'm not sure if this is the best approach, but it works. spencer On Mar 21, 2007, at 3:36 PM, Leuthold Dominik wrote:
hi list
i made some sounds with the shakers ugen and was surprised that with some presets the sound was cutted away for all cycles after the first one. this happens not with all presets (eg. preset 5 works well, 3 not).
i used this simple code:
Shakers s => dac; s.preset(3); s.gain(2); s.freq(Note.C2);
while(true) { s.noteOn(1); 2::second => now; s.noteOff(0); }
is there anything i should consider using this ugen?
thanks /moudi
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
hi spencer aha, seems somehow logic. as i understand there is no function/property to set this position, so i need to do it with for-loop to set it to a desired value.
I'm not sure if this is the best approach, but it works. great. exactly what i need:-))
thanks for your effort /moudi
-----Ursprüngliche Nachricht----- Von: chuck-users-bounces@lists.cs.princeton.edu [mailto:chuck-users-bounces@lists.cs.princeton.edu] Im Auftrag von Spencer Salazar Gesendet: Freitag, 23. März 2007 02:33 An: ChucK Users Mailing List Betreff: Re: [chuck-users] strange behaviour of shakers ugen
Hi moudi, There are many aspects of Shakers that are opaque to me, but from what I can glean from the source, in the guiro (3) and wrench (10) presets of Shakers there is a notion of "ratchet position". This I assume is the position of the scraping object (the ratchet) along the notched surface. The position of the ratchet determines the number of individual ratchet sounds and thus the length of the produced sound. Taking a look at the source, the ratchet position starts out at 10 when you call preset(3); it is increased by 1 each time you call noteOn; it decreases for each actual ratchet sound that is heard; and it is set to 0 when you call noteOff. Thus, calling noteOn several times is one possible way to set the ratchet position to a certain level. Alternatively, you could call preset(3) to reset the position to 10 each time. I'm not sure if this is the best approach, but it works.
spencer
On Mar 21, 2007, at 3:36 PM, Leuthold Dominik wrote:
hi list
i made some sounds with the shakers ugen and was surprised that with some presets the sound was cutted away for all cycles after the first one. this happens not with all presets (eg. preset 5 works well, 3 not).
i used this simple code:
Shakers s => dac; s.preset(3); s.gain(2); s.freq(Note.C2);
while(true) { s.noteOn(1); 2::second => now; s.noteOff(0); }
is there anything i should consider using this ugen?
thanks /moudi
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
Howdy, On Mar 21, 2007, at 12:57 PM, Veli-Pekka Tätilä wrote:
Hi Spencer, Very useful info. I'll snip a lot and only comment the stuff I have more questions or additions for.
Additionally, you can save a little time/memory by using arrays of null UGen references, rather than arrays of UGens. Hmm isn't this a bit suspicious, in terms of semantics. I mean the default of instanciating arrays as though objects where already constructed. If they are added, that design cannot support classes that lack a parameterless constructor, singleton classes in which it is private, and abstract classes or interfaces which cannot b instanciated in the first place.
That should be okay--when constructors and abstract classes are finally implemented in ChucK, the gotchas you mentioned can and should be caught by the compiler.
IS string also a class? I read something to that effect but cannot find its methods anywhere. I don't seem to be able to do much apart from concatenating them.
It is a class, but it doesn't have any documented methods (yet).
will there be a template mechanism or the ability to downcast arguments? You can always cast them to back to what they were initially, using the $ operator. You just have to actually know what they are. Ah that's the question. Quite OK for homogenous stuff but I can already imagine a design in which this is not known. IN which I have to branch on a type name. That's a bad smell in OOPy circles often but not always. Many recursive data structure dumpers require, for example, that you know whether an element is a single item, some reference to an array or object or something else. Not very relevant to chucK right now, though, as there's no serialization support.
Yes, ChucK is definitely not the language for OO purists...
don't know yacc either, but in my experience its pretty easy to pick up the basics by just reading a .y file. Ah I'll take a look. I'll be lazy and ask if there's a direct URL to the current CHucK yacc grammar. I usually don't get the source, though in this case it might be beneficial.
You'll probably have to take a look at the source, as the repository is not online. If you have a cvs client on your machine, then something like cvs -d :ext:anon-chuck@cvs.cs.princeton.edu:/cvs checkout chuck_dev/ v2/chuck.y should also do the trick. Just be sure to replace the ' at ' with an actually 'at' sign, as I believe the list server automatically replaces at signs with ' at ' to foil the spam bots. spencer
-- With kind regards Veli-Pekka Tätilä (vtatila@mail.student.oulu.fi) Accessibility, game music, synthesizers and programming: http://www.student.oulu.fi/~vtatila/
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
participants (3)
-
Leuthold Dominik
-
Spencer Salazar
-
Veli-Pekka Tätilä