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 forcmd(.., verbose=False)
)
[ ]:
sc.lang.cmds('"Hello User".postln') # check jupyter console for output
cmdg()
send command and get the output (alias forcmd(.., 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()