-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Fri, Apr 06, 2007 at 05:21:27PM -0400, Spencer Salazar wrote:
Hi Ken,
Welcome to ChucK-land!
On Apr 6, 2007, at 12:10 AM, Ken Restivo wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
A couple random ChucK questions:
1) Is there a tutorial or example code recipe somewhere specifically showing how to sync ChucK with JACK Transport? I want to use ChucK to supplement other tools that are sync'ed together using JACK (i.e. Hydrogen, Ardour, Rosegarden). I saw a thread that said, basically "use OSC", but I don't see any ChucK sample code that shows how to use OSC for syncing ChucK's clock with an external OSC-based source, i.e. like JACK transport.
2) A related but possibly off-topic question is: how do I translate JACK transport into OSC so that it can be sent to ChucK? Ardour and Rosegarden can send timestamps via MIDI, so that's one possible solution. Perhaps ChucK can accept MIDI sync, eliminating the OSC middleman?
In general we (ChucK team) are pretty clueless about JACK and especially JACK Transport, as we just use RtAudio as our audio driver backend and let that do all of the work with ALSA, JACK, DirectSound, etc. There isn't any good supported method to make ChucK sample synchronous with something else. OSC works for synchronization at millisecond latencies, but for < 1::samp latency it might not be so great.
One thing that is worth trying would be to take advantage of ChucK's sample-accurate strong timing. I have no idea if this would actually work, but if you had some code like this running in one shred, you might be able to accurately sample-sync ChucK with some OSC source:
// warning: written in mail OscRecv recv; somePort => recv.port; recv.listen(); recv.event( "/sync, i" ) @=> OscEvent sync;
while( true ) { // wait for a message while( sync.nextMsg() == 0 ) me.yield(); // allow next sample to be calculated 1::samp => now; }
The basic idea here is that, in ChucK, the next sample is calculated only while each shred are in some kind of 'something => now;'. So in this program, for every "space between two samples," ChucK won't calculate the next sample until the /sync OSC message is received.
This would need some other program to send ChucK a "/sync, i" message for every sample. Also, OSC could easily be replaced with some sort of MIDI input here.
Thanks! I appreciate that the unique power of ChucK is its ability to sync at sample-level accuracy. It's a very cool new synthesis method, might even become as iconic as VCO's or FM or granular. However, for purposes of using ChucK as a sequencer or beatbox, mere millisecond-level accuracy is perfectly fine. With JACK and ALSA, I'm maybe at minimum 64ms of latency between when I hit a MIDI key and when sound comes out anyway. So that's the scale of sync'ing I'd need for these purposes.
3) The polyfony and gomidi examples are great, but they seem to want to initiate a connection. That doesn't work too well: I start up synths (ChucK being used as a synth) and then connect my keyboard or sequencer to them using aconnect or qjackctl. So I guess what I'm looking for is a code snippet of a loop that'll have ChucK sit around waiting for an incoming MIDI connection, rather than trying to initiate one. Likewise, better if the shred doesn't die or become unresponsive to MIDI if the connection is closed and then opened again, i.e. from a different keyboard or sequencer.
I think this is possible to an extent with the current ChucK release, but the device needs to be connected at the very beginning when ChucK executes min.open() for that particular device. From there, you should be able to hot-plug/unplug/start/restart your MIDI inputs as needed--I'm not able to test this with ALSA right now, but I know it can work on other platforms, sometimes.
Generally speaking, though, I think ChucK's MIDI implementation could use some improvement in a lot of areas, including the kinds of features that you are looking for.
Yep. It's kinda weird for a softsynth to try to reach out and connect to a keyboard controller. Which is pretty much what ChucK expects to do. It's more common for softsynths to hang around waiting patiently for connections from one or more MIDI controllers. The connections are usually done via some patch utility, using ALSA's built-in facilities, such as the many command-line and GUI tools available (aconnect, patchage, QJackCtl, etc.). But it seems that PD also behaves the same way as ChucK. I'll bet that CSound and SuperCollider do too. So, I found a great workaround by using the "Midi Thru" device, thanks to the PD list archives and some help from folks on the ALSA lists. Basically, using the "MIDI Thru" ALSA device solves the problem. ChucK connects to the Thru, and I can then use ALSA to patch in whatever is needed from there.
Another way to do this would be, instead of exiting when min.open() fails, to keep on trying min.open() until it succeeds, with some amount of wait time between each min.open() call, e.g.
while( !min.open( 0 ) ) 100::ms => now;
Thanks! That and the Midi Thru hack have got me up and running!
4) I'm really new to ChucK, but I didn't see any way to release a note. The sample code sounds like it stops the note hard at receipt of a note off message, or after 100ms, but reading the code, it doesn't seem to deal with note off at all! Most instruments need a release time, so I'd need a way to receive a note off, then start the note's release envelope, and I'm too new to ChucK yet to see how to do that.
The two polyfony examples will release the note when they receive a noteOn MIDI message with a velocity of 0 (lines 94-97 of polyfony.ck, lines 96-99 of polyfony2.ck). I think technically they should also release the corresponding note when they get a noteOff message.
Ah, thanks. Looking at MIDI output from my controller, it does in fact send NoteOn's with velocity 0, not NoteOff's. It seems like NoteOff's might be deprecated, nevermind...
There are a variety of ways to deal with note releases in ChucK's synthesis model. The ultra brute force method, used in polyfony.ck, is to disconnect the UGen. Another brute force method is to set the .gain parameter of the UGen to 0. A lot of the STK UGens have built-in envelopes and corresponding noteOn and noteOff methods. You can also use the Envelope and ADSR UGens to apply customized envelopes to your patches.
OK, thanks. I'll play with that then.
[...]
The built-in Ugens have lots of interesting parameters that seem to be already hard-coded to MIDI controller events,
Whoa, what? The Midi classes in ChucK only give you the 2 or 3 byte MIDI messages that MIDI inputs provide, and let you send messages back out. There isn't any default or hard-coded mapping from MIDI controller events to parameter changes in UGens, although its not too hard to write them in ChucK code.
It's right there in the source code! e.g., from ugen_stk.h: Control Change Numbers: - Bow Pressure = 2 - Bow Motion = 4 - Strike Position = 8 (not implemented) - Vibrato Frequency = 11 - Gain = 1 - Bow Velocity = 128 - Set Striking = 64 - Instrument Presets = 16 - Uniform Bar = 0 - Tuned Bar = 1 - Glass Harmonica = 2 - Tibetan Bowl = 3 And.. Control Change Numbers: - Control One = 2 - Control Two = 4 - LFO Speed = 11 - LFO Depth = 1 - ADSR 2 & 4 Target = 128 In fact, just about every STK UGen has these in their class declaration. I was also confused by stuff like this in the STK examples: bow.controlChange( 4, position ); Which looked to me like "controlChange" meant MIDI control change, and the number was the MIDI controller number. I thought that code assigned the "position" parameter to MIDI controller #4, but now I see that it simply sets that parameter to value of 4. But I can also see how easy it'd be to map those parameters to MIDI controllers, and I'll try doing that. Is there reflection in ChucK, or some way, for example, to print out a list of all the parameters in a STK UGen class and its parents?
It seems like ChucK could be a very expressive softsynth, with parameters controlled not through a software GUI, but through real rotary controllers and buttons on a MIDI keyboard-- nice for performance purposes.
Yes definitely!
The "plumbing" code I'd need (or need a lot of help writing), is the skeleton to handle waiting for incoming MIDI connnections instead of trying to open() them,
This is something would be nice like to have, but isn't quite there yet.
Again, so far the "MIDI Thru" device in ALSA is a pretty good workaround.
and to handle note off events with some kind of decay envelope.
As I mentioned earlier, take a look at Envelope and ADSR for details on how to do this.
Yep, thanks. Looks like many of the UGen's already have this built in.
From there, I think I can figure out the program change and controller change stuff myself.
My apologies if I'm the only person out there trying to use ChucK as basically a GUI-less softsynth controlled by MIDI.
No apologies necessary! ChucKers come in all varieties, and decent support for hardware controllers is an important goal of ChucK.
Thanks! I now have ChucK up as a MIDI synth. I'll start mapping MIDI controller and program changes and see where that gets me. - -ken -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) iD8DBQFGGGKKe8HF+6xeOIcRAjgBAJ9iwbivHOpqt2Jn9urjwxOE8Fx1ygCg1rZI YdgNXfd9bBAY8C82UKKKbtY= =cmOR -----END PGP SIGNATURE-----