OSC to SuperCollider

Example directory (scamp): examples/Tutorial/24_osc_to_supercollider

Download: 24_osc_to_supercollider.zip

Playing back notes by sending OSC messages to the SuperCollider, which receives them and spawns Synths in response. Start SuperCollider and run the code blocks in receive_from_supercollider.scd, then run osc_to_supercollider.py. Note that the easy way to receive note events from SCAMP in SuperCollider specifically is with the ScampUtils quark, as demonstrated by receive_from_supercollider_scamputils.scd.

Topics: Playback › Playback implementations

score
from scamp import *
import random

random.seed(42)

s = Session()

# on the other end, an OSC receiver is setup to play notes that take vibrato and OSC messages as well as the usual
vib = s.new_osc_part("vibrato", 57120)

s.start_transcribing()

# any property entries starting or ending with "param" will be treated as extra playback parameters
while s.beat < 20:
    note_length = random.uniform(0.3, 3)
    # glissando between three random values
    pitch_env = [random.randint(60, 82) for _ in range(3)]
    volume_env = random.choice([
        # percussive envelope
        Envelope.ar(0.1, note_length - 0.1),
        # fp crescendo envelope
        Envelope([1, 0.2, 1], [0.1, note_length - 0.1], curve_shapes=[-2, 3])
    ])
    vib_width_env = [random.uniform(0, 5) for _ in range(2)]
    vib_freq_env = [random.uniform(3, 13) for _ in range(2)]
    vib.play_note(
        pitch_env, volume_env, note_length,
        {"param_vibWidth": vib_width_env,
         "param_vibFreq": vib_freq_env},
        blocking=False
    )
    wait(random.uniform(0.5, 3))

wait_for_children_to_finish()

performance = s.stop_transcribing()

engraving_settings.max_voices_per_staff = 1
performance.to_score(max_divisor=6, simplicity_preference=3).show()
receive_from_supercollider.scd
// --------------------------------------------------------------------------------------------------
// Corresponding SuperCollider Code for OSC-to-SuperCollider SCAMP example. Run this before the Python
// script by booting the server and then running the code blocks below in order.
// --------------------------------------------------------------------------------------------------


// If it's not working, make sure the port printed here matches the port that the Python file is sending to
NetAddr.langPort.postln;


(
// ----------------------------- 1) Define vib synth ----------------------------------
SynthDef(\vibSynth, { |out=0, freq=440, gain=0.1, vibFreq=20, vibWidth=0.5, gate=1|
     var envelope = EnvGen.ar(Env.asr(releaseTime:0.5), gate, doneAction: 2);
     var vibHalfSteps = SinOsc.ar(vibFreq) * vibWidth;
     var vibFreqMul = 2.pow(vibHalfSteps / 12);
     var vibSine =  SinOsc.ar(freq * vibFreqMul) * gain;
     Out.ar(out, (envelope * vibSine / 5) ! 2);
}, [\ir, 0.1, 0.1, 0.1, 0.1, \kr]).add;
)


(
// ---------------------------- 2) Set up OSC Receivers -------------------------------

// This dictionary maps the note-id's sent by SCAMP to their associated Synths
~notesPlaying = Dictionary();

// START NOTE
OSCFunc({ arg msg, time, addr, recvPort;
     var id = msg[1], pitch = msg[2], volume = msg[3];
     // Start a new Synth and place it in the ~notesPlaying dictionary under its associated id
     ~notesPlaying.put(id, Synth(\vibSynth,
             [\freq, pitch.midicps,
              \gain, (-40 * (1-volume)).dbamp]
     ));
}, '/vibrato/start_note');

// END NOTE
OSCFunc({ arg msg, time, addr, recvPort;
     var id = msg[1];
     ~notesPlaying[id].set(\gate, 0);
}, '/vibrato/end_note');

// CHANGE PITCH
OSCFunc({ arg msg, time, addr, recvPort;
     var id = msg[1], pitch = msg[2];
     ~notesPlaying[id].set(\freq, pitch.midicps);
}, '/vibrato/change_pitch');

// CHANGE VOLUME
OSCFunc({ arg msg, time, addr, recvPort;
     var id = msg[1], volume = msg[2];
     ~notesPlaying[id].set(\gain,
             (-40 * (1-volume)).dbamp);
}, '/vibrato/change_volume');

// CHANGE VIBRATO FREQUENCY
OSCFunc({ arg msg, time, addr, recvPort;
     var id = msg[1], freq = msg[2];
     ~notesPlaying[id].set(\vibFreq, freq);
}, '/vibrato/change_parameter/vibFreq');

// CHANGE VIBRATO WIDTH
OSCFunc({ arg msg, time, addr, recvPort;
     var id = msg[1], width = msg[2];
     ~notesPlaying[id].set(\vibWidth, width);
}, '/vibrato/change_parameter/vibWidth');
)
receive_from_supercollider_scamputils.scd
// --------------------------------------------------------------------------------------------------
// Corresponding SuperCollider Code for OSC-to-SuperCollider SCAMP example. Run this before the Python
// script by booting the server and then running the code blocks below in order.
// --------------------------------------------------------------------------------------------------


// If it's not working, make sure the port printed here matches the port that the Python file is sending to
NetAddr.langPort.postln;


(
// ----------------------------- 1) Define vib synth ----------------------------------
ScampUtils.instrumentFromSynthDef(
     SynthDef(\vibSynth, { |out=0, freq=440, volume=0.1, vibFreq=20, vibWidth=0.5, gate=1|
             var envelope = EnvGen.ar(Env.asr(releaseTime:0.5), gate, doneAction: 2);
             var vibHalfSteps = SinOsc.ar(vibFreq) * vibWidth;
             var vibFreqMul = 2.pow(vibHalfSteps / 12);
             var vibSine =  SinOsc.ar(freq * vibFreqMul) * volume;
             Out.ar(out, (envelope * vibSine / 5) ! 2);
     }, [\ir, 0.1, 0.1, 0.1, 0.1, \kr]);
)
)