| | 1 | = Python and SuperCollider = |
| | 2 | |
| | 3 | I have written a significant amount of code to make it easy to interface with supercollider using python. |
| | 4 | |
| | 5 | '''Contents''' |
| | 6 | |
| | 7 | * [wiki:scosc] - Low-level OSC interface. |
| | 8 | * [wiki:scsynth] - High-level music interface (recommended). |
| | 9 | * [wiki:SuperColliderFAQ] - An account of my supercollider learning process. |
| | 10 | |
| | 11 | '''Learning''' |
| | 12 | |
| | 13 | The supercollider server responds to specialized OSC messages in order to create synths and manipulate audio graphs. the scosc module converts standard python types to supercollider osc messages. |
| | 14 | |
| | 15 | In order to play sounds in musical time, we have to send OSC messages with timestamps. Because the server has a limited message buffer (1024), we have to send messages as a stream in real-time. The challenge is getting the messages in early enough that the server can process them, while not sending too many as to override the buffer. We also have to take latency into account, which makes this a much bigger bundle of fun. |
| | 16 | |
| | 17 | In order to keep the server filled with messages we have to use a sliding time window to scan ahead and choose which messages to send from the various sources. Musical sequences are stored as notes in a ''Pattern'', which ''Sequencer'' translates patterns into timestamped messages. The messages are sent to the server using a ''Player'', which handles the gritty gory job of managing notes while they are playing. |
| | 18 | |
| | 19 | '''Basic Concepts''' |
| | 20 | * Store ''Notes'' in a ''Pattern''. |
| | 21 | * Sounds come from a ''Synth'', which is a dictionary of values to be passed to a synthdef. |
| | 22 | * A ''Sequencer'' repeatedly renders notes for a sliding time ''Window''. |
| | 23 | * ''Window'' parameters can be adjusted at any time. |
| | 24 | |
| | 25 | '''Major Components''' |
| | 26 | * [source:scsynth/server.py scsynth.start/scsynth.connect]: Manage supercollider server processes. |
| | 27 | * [source:scsynth/sequencer.py Sequencer]: Translate patterns to absolute times and pitch values |
| | 28 | * [source:scsynth/pattern.py Pattern(list)]: An ordered list of notes. |
| | 29 | * [source:scsynth/player.py Player(list)] : Manage synth nodes as notes while they play. |
| | 30 | * [source:scsynth/player.py Synth(dict)] : Contains values defining a synthesizer. |
| | 31 | |
| | 32 | '''Play A Sound''' |
| | 33 | |
| | 34 | (replace paths with your own) |
| | 35 | |
| | 36 | {{{ |
| | 37 | #!python |
| | 38 | server = scsynth.start() |
| | 39 | server.sendMsg('/d_load', '/Users/patrick/.pksampler/synthdefs/JASStereoSamplePlayer.scsyndef') |
| | 40 | server.sendMsg('/b_allocRead', 1, '/Users/patrick/.pksampler/loops/birdman/drums/4x4.wav') |
| | 41 | server.sendMsg('/s_new', 'JASStereoSamplePlayer', 1000, 1, 0, 'bufnum', 1) |
| | 42 | server.quit() |
| | 43 | }}} |
| | 44 | |
| | 45 | '''Play A Note''' |
| | 46 | |
| | 47 | {{{ |
| | 48 | #!python |
| | 49 | synth = scsynth.Synth() |
| | 50 | synth.name = 'MySineSynthDef' |
| | 51 | synth['freq'] = 440 |
| | 52 | server = scsynth.start() |
| | 53 | player = scsynth.Player(server) |
| | 54 | player.play(synth, time.time() + 1, time.time() + 2) |
| | 55 | server.quit() |
| | 56 | }}} |
| | 57 | |
| | 58 | '''Play A Pattern''' |
| | 59 | |
| | 60 | {{{ |
| | 61 | #!python |
| | 62 | synth = scsynth.Synth() |
| | 63 | synth.name = 'MySineSynthDef' |
| | 64 | pattern = scsynth.Pattern([note]) |
| | 65 | sequencer.add(synth, pattern).loop(True) |
| | 66 | |
| | 67 | while running: |
| | 68 | window.update() |
| | 69 | for synth, start, stop, pitch in sequencer.render(window): |
| | 70 | player.play(synth, start, stop) |
| | 71 | window.close() |
| | 72 | }}} |