Author |
Message |
ilSignorCarlo

Joined: Sep 17, 2007 Posts: 28 Location: Bologna
|
Posted: Mon Jun 30, 2008 4:11 am Post subject:
ChucK and Python |
 |
|
Hi,
I have searched in the forum and saw there are some posts where they talk about ChucK and Python integration. Still I didn't understand if it is possible.
Has anyone succeded in using ChucK functions in a Python program?
Using OSC? Or, better, MIDI? _________________ Self-referential phrases, like this one, are not so funny or good for a forum signature. |
|
Back to top
|
|
 |
Frostburn

Joined: Dec 12, 2007 Posts: 255 Location: Finland
Audio files: 9
|
Posted: Mon Jun 30, 2008 6:41 am Post subject:
|
 |
|
As far as I know there hasn't been any true integration of ChucK and Python. There is a an OSC library for Python called SimpleOsc that I tried and I could control ChucK with it.
PyChucK is a Python program that I'm working on. It uses the same Unit Generator chucking paradigm as ChucK does but so far it has no way of interacting with ChucK (or with anything for that matter, it's still in early development).
I do plan to implement MIDI and OSC at some point and if ChucK ever gets those "chuck-in"-plug-ins they may enable PyChucK and ChucK to work together. _________________ To boldly go where no man has bothered to go before. |
|
Back to top
|
|
 |
dewdrop_world

Joined: Aug 28, 2006 Posts: 858 Location: Guangzhou, China
Audio files: 4
|
|
Back to top
|
|
 |
Acoustic Interloper

Joined: Jul 07, 2007 Posts: 2073 Location: Berks County, PA
Audio files: 89
|
Posted: Mon Jul 14, 2008 5:36 pm Post subject:
|
 |
|
I posted a Python + ChucK program here that uses one Python process to serve a human-to-human chess game, one more more Python GUIs for the players (possibly on different computers on the same LAN), and a ChucK program to generate the tones. The chess server sends OSC messages to ChucK; OSC over UDP is pretty simple in Python; I didn't have to go fishing for any special Python libraries.
I like Python enough to find the idea of PyChuck interesting, but for this chess generator there's no advantage to doing it in one language. OSC is plenty fast enough.
Chuck basically knits together signal flows that (I believe) live in compiled C++ land, and there's no reason that Python couldn't do this. You probably want a good conceptual model for a C or C++ run-time engine that shovels samples through ugens, filters, etc., and an API for Python to tell this C/C++ engine what to interconnect.
For what I've been doing so far, though, Python to ChucK via OSC on the same machine works just fine. I guess I am used to multiple languages. _________________ When the stream is deep
my wild little dog frolics,
when shallow, she drinks. |
|
Back to top
|
|
 |
Acoustic Interloper

Joined: Jul 07, 2007 Posts: 2073 Location: Berks County, PA
Audio files: 89
|
Posted: Wed Jul 16, 2008 7:58 am Post subject:
|
 |
|
Thought I'd post the OSC communication code that's in the chess game link of my previous post above, just to show how simple this basic OSC communication is.
Here is the Python code that sends a list of integers and floats to ChucK. This also works and is tested with Supercollider (thanks to Dewdrop World) and Max/MSP.
Code: |
import socket
from threading import *
from binascii import a2b_hex, b2a_hex
from struct import pack
class tonegen(object):
def __init__(self, udphost, udpport):
self.udphost = udphost
self.udpport = udpport
self.skt = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.lock = RLock()
def send(self, tonelist):
"""
Transform list of ints and floats in tonelist parameter
into packed OSC values of corresponding types, put into an OSC
packet prececed by 'list\0\0\0\0,' and send out via UDP.
"""
if (len(tonelist) < 11):
raise ChessException, "invalid tonelist parameter: " \
+ str(tonelist)
listhead = a2b_hex('6c697374000000002c') # 'list\0\0\0\0,'
hdrlen = 9
listtail = ''
# print "DEBUG ABOUT TO SEND LIST: " + str(tonelist)
for val in tonelist:
if (type(val) == int):
listhead = listhead + a2b_hex('69') # 'i'
listtail = listtail + pack('>i', val)
elif (type(val) == float):
listhead = listhead + a2b_hex('66') # 'f'
listtail = listtail + pack('>f', val)
else:
raise ChessException, "invalid type for tonelist value " \
+ str(val) + ": " + str(type(val))
hdrlen = hdrlen + 1
if ((hdrlen % 4) == 0):
listhead = listhead + a2b_hex('00')
hdrlen = hdrlen + 1
while (hdrlen % 4):
listhead = listhead + a2b_hex('00')
hdrlen = hdrlen + 1
self.lock.acquire()
try:
# print "DEBUG UDP: " + str(b2a_hex(listhead+listtail))
self.skt.sendto(listhead+listtail, (self.udphost, self.udpport))
finally:
# m.kill() # DEBUG
self.lock.release()
t = tonegen('localhost', 57120)
|
1. The initial length check on the list of parameters is application specific. The "tonelist" is a list of ints and floats that application code passes to ChucK. The hard-coded "57120" UDP port number is specific to Supercollider; you could use any available port with ChucK or Max; you have to make sure ChucK or Max is listening to that port (see ChucK code below).
2. The packet starts out with the text "list" followed by four zeroes in order to fill the "function name" field out to a multiple of 4 bytes, followed by a comma. You could use a different "function name" as long as the listener is watching for that name (see ChucK code below). In fact, "list" is not strictly in line with OSC specs; the "function name" is supposed to start with a "/" for reasons of hierarchical naming, but this is how Max passes lists over OSC, so I stuck with it.
3. Next in the header comes an "i" type tag character for each integer that follows, and an "f" for each float. These type tags go into the list header "listhead" and they tell the receiver what types of data to expect.
4. In the actual payload "listtail" go the values corresponding to these type tags, i.e., the actual ints and floats in tonelist. '>i' means "big endian integer" and '>f" means "big endian float," both 4 bytes long. Endian has to do with byte order, but if you don't understand it, don't worry. This works on OSX and XP x86 machines, which are natively little endian, so I expect it should work fine with ChucK on any machine. I don't recall off the top of my head, but OSC probably requires big endian byte order.
5. After this function has all of the 'i' or 'f' type tags appended onto "listhead," it adds some more zeroes until "listhead's" length is a multiple of 4. It has to add at least one zero to mark the end of the type string, so if listhead is a multiple of 4 in length before adding the zero, you wind up adding 4 zeroes. I found this out the hard way.
6. The lock acquire and release ensure that only one thread tries to send an OSC/UDP datagram at a time.
7. The data actually sent are the concatenation of listhead, which is
"list\0\0\0\0," followed by 'i' and 'f' type tags, rounded up to a multiple of 4 length by appending \0's.
AND listtail, which is
a sequence of packed int and float values that correspond to the type tags above.
Quote: | Round and round and round it goes, and where it lands, nobody knows. | (UDP is a connectionless protocol, meaning there is no "handshake" or coordination between the sending and receiving processes at an application level. This Python code just lobs it out there, and hopes that someone is listening.
Here is the ChucK code, adapted from an on-line example at the ChucK site:
Code: |
// INITIALIZATION CODE:
// Create our OSC (Open Sound Control) receiver.
OscRecv recv;
// port 7401 used by the chess program
57120 => recv.port;
// start listening (launch thread)
recv.listen();
// create an address in the receiver, store in new variable
recv.event( "list, i i f f f f i i i i i i" ) @=> OscEvent @ oe;
// CODE RUNNING WITHIN A LOOP TO RECEIVE UDP MESSAGES:
// infinite event loop
while( true )
{
// wait for event to arrive
oe => now;
// grab the next message from the queue.
while( oe.nextMsg() )
{
int bank, osc, player, piecetype, relationship ;
int otherplayer, otherpiecetype, movenumber ;
int piecediff, attacker, attackee ;
float freq, phase, leftampl, rightampl ;
// getFloat fetches the expected float (as indicated by "i f")
oe.getInt() => bank ;
oe.getInt() => osc ;
oe.getFloat() => freq ;
oe.getFloat() => phase ;
oe.getFloat() => leftampl ;
oe.getFloat() => rightampl ;
oe.getInt() => player ;
oe.getInt() => piecetype ;
oe.getInt() => relationship ;
oe.getInt() => otherplayer ;
oe.getInt() => otherpiecetype ;
oe.getInt() => movenumber ;
// <<< "OSC:", bank, osc, freq, phase, leftampl, rightampl, playeetype, relationship, otherplayer, otherpiecetype, movenumber >>>; |
Unlike my Python library, which works with any combinations of ints and floats, this ChucK patch encodes exactly what to expect in terms of integers and floats (in the same order as sent by Python) for the patch. Likewise for Supercollider and Max. This isn't much of a limitation, since the patch has no know what parameters are coming in any case. Ultimately I should take the string "list" out of the Python function and make it a parameter like the ints and floats, but I haven't gotten to that yet.
Anyway you can see that the sequence if "i's" and "f's" in
recv.event( "list, i i f f f f i i i i i i" ) @=> OscEvent @ oe;
correspond to the sequence of ints and floats in
oe.getInt() => bank ;
oe.getInt() => osc ;
oe.getFloat() => freq ;
oe.getFloat() => phase ;
oe.getFloat() => leftampl ;
oe.getFloat() => rightampl ;
oe.getInt() => player ;
oe.getInt() => piecetype ;
oe.getInt() => relationship ;
oe.getInt() => otherplayer ;
oe.getInt() => otherpiecetype ;
oe.getInt() => movenumber ;
They also correspond to the parameter "tonelist" passed by the chessgame function that calls tonegen.send(tonelist).
I haven't tried sending from ChucK to an OSC receiver, but its probably about the same complexity. This is way more flexible than MIDI -- no special cables or virtual MIDI drivers -- and if you want to send MIDI data, just send it as a sequence of MIDI-valued ints over OSC.
OSC has a bunch of optional extensions for hierarchical function names and bundles of messages with time tags, but many tools don't support that (Max doesn't, and I doubt that ChucK does), and this simple stuff works fine over a LAN.
On a multi-core machine running Python on one core and ChucK on another, I wouldn't be surprised to learn that this is more responsive than having everything running in one process. The UDP datagrams are small and can be passed in memory, there is no network latency, and it gets some mileage out of having multiple cores. The same cannot be said for a multi-threaded processers (Intel uses the term "hyperthreading"), since hardware threads operate out of a single process using a shared memory image and shared processor resources.
Given the wealth of Python libraries available, including GUIs, and given ChucK's (and SC's and Max's) focus on audio, I wouldn't personally implement GUIs in the audio language, nor low level audio processing in a language like Python. Python is great for algorithmic composition, and this OSC approach is language agnostic, so you can replace Python with Java or whatever on one side of the datagram, and ChucK with SC or Max on the other. I like this way of working, but of course, there is no harm in exploring the design space alternatives. Have fun.
EDIT: Fixed my code escapes. _________________ When the stream is deep
my wild little dog frolics,
when shallow, she drinks. |
|
Back to top
|
|
 |
Antimon
Joined: Jan 18, 2005 Posts: 4145 Location: Sweden
Audio files: 371
G2 patch files: 100
|
Posted: Wed Jul 16, 2008 1:35 pm Post subject:
|
 |
|
Neato! OsC is very nice. When are we going to start seeing hardware controllers with network jacks instead of 5-pin DINs or USBs, eh?
/Stefan _________________ Antimon's Window
@soundcloud @Flattr home - you can't explain music |
|
Back to top
|
|
 |
Kassen
Janitor


Joined: Jul 06, 2004 Posts: 7678 Location: The Hague, NL
G2 patch files: 3
|
Posted: Wed Jul 16, 2008 1:47 pm Post subject:
|
 |
|
A few years ago, if you don't mind paying what could also amount to a second laptop? (search for Jazzmutant Lemur).
One of the good things about MIDI is that it's cheap... _________________ Kassen |
|
Back to top
|
|
 |
Antimon
Joined: Jan 18, 2005 Posts: 4145 Location: Sweden
Audio files: 371
G2 patch files: 100
|
Posted: Thu Jul 17, 2008 3:37 am Post subject:
|
 |
|
Yes, of course - if you have the money most things can be had. I was more thinking in the lines of e.g. a BCR2000 with a built-in network interface. I'm starting to get problems with my USB hubs being too many and too full. Although UDP communication ay become more unreliable if you increase the size of the network, it seems easier to save lost OSC messages (resends, ack when applicable etc) than deal with my confused USB gadgets.
/Stefan _________________ Antimon's Window
@soundcloud @Flattr home - you can't explain music |
|
Back to top
|
|
 |
Gabrielg
Joined: Aug 02, 2008 Posts: 23 Location: seattle
|
Posted: Sat Aug 02, 2008 5:43 pm Post subject:
How about Ruby and Chuck ? Subject description: How about Ruby and Chuck ? |
 |
|
I just read this post about using python and chuck and was wondering about ruby I have written sereral little midi apps Ruby and like to be able to make ruby and chuck talk to each other in some way or another
later everyone; |
|
Back to top
|
|
 |
blue hell
Site Admin

Joined: Apr 03, 2004 Posts: 24388 Location: The Netherlands, Enschede
Audio files: 296
G2 patch files: 320
|
|
Back to top
|
|
 |
|