This page was generated from examples/sclang-examples.ipynb.

Usage of sclang in sc3nb

You can send commands and receive data directly from the SuperCollider Language

[ ]:
import time
import numpy as np

import sc3nb as scn
[ ]:
sc = scn.startup()

sclang command execution

To send sc3 commands (i.e. program strings) to the language, either use the following functions

  • cmd() normal command sending.

[ ]:
# sc.cmd(cmdstr, pyvars)
sc.lang.cmd('"Hello World".postln')  # output will be printed
  • cmds() silent version without (alias for cmd(.., verbose=False))

[ ]:
sc.lang.cmds('"Hello User".postln')  # check jupyter console for output
  • cmdg() send command and get the output (alias for cmd(.., get_return=True)). More details below

[ ]:
string = sc.lang.cmdg('"sc3nb".postln')
print(f'We received the string = "{string}"')

or use the corresponding Magics in Jupyter

  • Jupyter line magics %sc, %scv, %scs, %scg, %scgv, %scgs

  • Jupyter cell magics %%sc, %%scv, %%scs, %%scg, %%scgv, %%scgs

which wrap the above functions: cmd{v,g,s} = %sc{v,g,s} and v=verbose, g=get, s=silent verbose is default, so %sc=%scv

Line magics can be placed within code just as the function calls as shown here:

[ ]:
for p in range(1, 10):  # a bouncing ball
    %scs Synth.new(\s1, [\freq, 200]) // this is SC code so use // instead of #
    time.sleep(1/p)

Use raw python strings for multi-line sc3-programs:

[ ]:
sc.lang.cmd(r"""
Routine({
    x = 5.collect{ |i|
        0.2.wait;
        Synth.new(\default, [\freq, 50+(50*i)]);
    };
    1.wait;
    x.do{|e|
        e.release;
        0.1.wait;};
}).play;
""")

alternatively, you can use the cell magics

[ ]:
%%sc
Routine({
    x = 5.collect{ |i|
        0.2.wait;
        Synth.new(\default, [\freq, 50+(50*i)]);
    };
    1.wait;
    x.do{|e|
        e.release;
        0.1.wait;};
}).play;

Note that the code is executed in sclang and Python is returning directly after sending the command.

sclang command execution with python variable injection

Python variables can be injected into sc3 commands by using the ^ special:

The following examples demonstrates it by setting frequencies by using python variables

[ ]:
for p in range(1, 50):  # a tone ladder
    freq = 50 + p*3
    dur = np.log(p)
    position = np.sign(p-25)
    %scs Synth.new(\s1, [\freq, ^freq, \dur, ^dur, \pan, ^position])
    time.sleep(0.05)

This is injection is done with

[ ]:
help(scn.util.convert_to_sc)

Here are some conversion examples

[ ]:
python_list = [1,2,3,4]
%sc ^python_list.class
[ ]:
complex_py = 1+1j
%sc ^complex_py.class
[ ]:
symbol = r"\\python"
%sc ^symbol.class

When using the cmd, cmdg and cmds functions you can also provide a dictionary with variable names as keys and content as values (which can use other python vars or statements)

[ ]:
sc.lang.cmdv("^name1 / ^name2", pyvars={'name1': 9,'name2': 9*2})

Without providing pyvars, variables are searched in the users namespace.

[ ]:
freq = 5
rate = 6
sc.lang.cmdv("(^freq + 1) * (^rate + 1)")

alternatively via the magic this is done as:

[ ]:
%scv (^freq + 1) * (^rate + 1)

Getting sclang output in python

  • To get the output of an sclang snippet into a python variable, use the cmdg function.

  • The following example shows how to transfer a synth’s nodeID

[ ]:
# start a Synth
sc.lang.cmd(r"""x = Synth.new(\default)""")
[ ]:
# get the nodeId to python
nodeID = sc.lang.cmdg("x.nodeID")
print(nodeID)
[ ]:
# use the nodeID to free the Synth via a message to scsynth audio server directly
sc.server.msg("/n_free", nodeID)

sc.cmdg(), resp. %scg return integers, floats, strings and lists * %scg can be assigned to a python variable within code

[ ]:
a = %scg 1234 + 23452
print(f"returned an {type(a)} of value {a}")
[ ]:
a = %scg 1234.5.squared
print(f"returned an {type(a)} of value {a}")
[ ]:
a = %scg "sonification".scramble
print(f"returned an {type(a)} of value {a}")
[ ]:
%scs ~retval = "sonification".scramble
%scg ~retval ++ "!"

You can combine your code in a single row.

[ ]:
scramble = %scg ~retval = "sonification".scramble; ~retval ++ "!";
scramble
[ ]:
a = %scg (1,1.1..2)

Note that floating-point numbers do only have limited precision

[ ]:
print(f"list with length: {len(a)}")
a

However they should be close

[ ]:
[round(num, 6) for num in a]
[ ]:
np.allclose(a, np.arange(1, 2, 0.1))

Some more usage examples

You can use the SuperCollider GUI features.

[ ]:
sc.lang.cmd(r"MouseX.help", timeout=10)
[ ]:
%sc {SinOsc.ar(MouseX.kr(200,400))}.play  // move mouse horizontally, CMD-. to stop
[ ]:
%sc s.scope()
[ ]:
sc.server.free_all()  # leaves the scope running
[ ]:
%%sc
{
    x = Synth.new(\s2, [\freq, 100, \num, 1]);
    250.do{|i|
        x.set(\freq, sin(0.2*i.pow(1.5))*100 + 200);
        0.02.wait;
    };
    x.free;
}.fork
[ ]:
sc.exit()