-
Notifications
You must be signed in to change notification settings - Fork 5
/
7_OSC.scd
174 lines (113 loc) · 6.38 KB
/
7_OSC.scd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// OpenSoundControl (OSC):
// OSC is a new protocol that was invented in the 2000's to allow music software and devices to talk to each other.
// The protocol can support any kind of messages, and the messages are usually transported through UDP or TCP.
// SuperCollider uses OSC to communicate between the language (sclang) and the server (scsynth).
// the language can also talk to other programs, or get commands from them, or you can have several instances of the language talk to each other.
// the server can also support various clients talking to it, e.g. multiple SC-users sending messages to one scsynth instance, or other programming language (haskel, ruby, C++) talking to scsynth.
// SuperCollider opens up an OSC-port at startup; normally this is port 57120, but when this one is not available (e.g. when already another instance of sclang is running, or one did not close the port properly) it may be the next one up (57121), or the next, until it finds one that opens without problems. You can retrieve always retrieve the current port with:
NetAddr.langPort;
// Or you can retrieve both the IP and the port with:
NetAddr.localAddr; // retrieve the current IP and port (since 3.5)
Main.version;
// since SC 3.5 you can open up additional ports:
thisProcess.openUDPPort(1121); // attempt to open 1121
// return true when it succeeded, false if not
thisProcess.openPorts; // list all open custom ports
// OSC messages are sent from one application to another via the UDP ports they have opened, e.g.
// max-msp sends a message from it's outgoing port to sclangs incoming port:
// max-msp -> udp port out -> udp port in -> sclang
// SuperCollider uses the same port to send from, as that is listens to.
// sclang -> udp port out (57120) -> udp port (e.g. 6000) -> max-msp
// max-msp -> udp port out (?? can't control this from max/msp) -> udp port in (57120) -> sclang
// to send a message to yourself:
// set the target address:
b = NetAddr( "127.0.0.1", NetAddr.langPort );
// or:
b = NetAddr( "127.0.0.1", 57120 );
b.sendMsg( "/hello", "there", 3, 6, 0, 2.0 );
// osc message is defined as:
// tag (/hello)
// a number of parameters... strings, integers, floats
// listen to this (3.5):
o = OSCFunc({ arg ...args; args.postln; }, "/hello", NetAddr( "127.0.0.1", 57120 ) );
b.sendMsg( "/hello", "there" );
// the NetAddr in the OSCFunc is the NetAddr of the sender, so where the message comes from.
// if the udp port of the sender is not constant, you can set the NetAddr of the sender to nil, and the OSCFunc will still fire:
~onil = OSCFunc({ arg ...args; args.postln; }, "/hello", nil );
// you can also set the port on which to listen (e.g. if the sender can only send to a specific port)
~oport = OSCFunc({ arg ...args; args.postln; }, "/hello", NetAddr( "127.0.0.1", nil ), 7771 );
// the function that you define, gets the arguments:
// msg - an array, starting with the osc-tag (/hello), and then the other values that are sent
// a time - this is the time the message arrived, or the time tag (compare with Process.elapsedTime)
// a NetAddr - this is the address of the sender (where the message came from)
// the recvport - the port that the message came into
Process.elapsedTime
// to track which messages come in, you can do:
OSCFunc.trace( true );
// with sendBundle, you can add a timestamp to the OSC message. Compare the time's of these messages:
b.sendBundle(0.2, ["/good/news", 1, 1.3, 77]); b.sendMsg( "/hello", "there" );
// turn tracing off:
OSCFunc.trace( false );
// CmdPeriod releases all OSCFunc's just like the MIDIFunc, unless you made them permanent or fixed them.
~onil.fix;
// as with MIDIFunc's - where you can use named versions with MIDIdef, you can use OSCdef for OSC:
// the advantage is that the OSCdef is replaced, if you change the function for an OSCdef with the same name.
OSCdef( \onlymine, { arg ...args; args.postln; }, "/hello", NetAddr( "127.0.0.1", 57120 ) );
OSCdef( \anyport, { arg ...args; args.postln; }, "/hello", NetAddr( "127.0.0.1", nil ) );
OSCdef( \otherreceiveport, { arg ...args; args.postln; }, "/hello", NetAddr( "127.0.0.1", nil ), 7771 );
OSCdef( \anywhere, { arg ...args; args.postln; }, "/hello", nil );
OSCdef.all;
OSCdef.freeAll;
// in 3.4, OSCFunc does not yet exist, instead you have to use OSCresponderNode, the argument list is in a different order though:
~orn = OSCresponderNode.new( NetAddr( "127.0.0.1", nil ), "/hello", { arg ...args; args.postln; } );
// and you need to add it:
~orn.add;
b.sendMsg( "/hello", "there" );
// the function is passed:
// a time - this is the time the message arrived, or the time tag
// the responder
// a NetAddr - this is the address of the sender (where the message came from)
// msg - an array, starting with the osc-tag (/hello), and then the other values that are sent
// the same kind of filtering happens based on sender:
// fixed sender ip, fixed port
~ormy = OSCresponderNode.new( NetAddr( "127.0.0.1", 57120 ), "/hello", { arg ...args; args.postln; } ).add;
// fixed sender ip, any port
~oranyport = OSCresponderNode.new( NetAddr( "127.0.0.1", nil ), "/hello", { arg ...args; args.postln; } ).add;
// from anywhere
~oranywhere = OSCresponderNode.new( nil, "/hello", { arg ...args; args.postln; } ).add;
// in 3.4 you cannot set the receiveport, you can only use the default language port:
NetAddr.langPort;
// and you can remove the OSCresponderNode:
~orn.remove;
// or remove all:
OSCresponderNode.all.do{ |it| it.remove };
b.sendMsg( "/hello", "there" );
// example with Iannix:
NetAddr.langPort;
OSCFunc.trace( true );
OSCFunc.trace( false );
~cursors = IdentityDictionary.new;
(
OSCdef( \iannixcursor, {
arg msg, time, netaddr, port;
~cursors.put( msg[1].asInteger, msg.copyToEnd(2) );
if ( msg[1].asInteger == 1 ){
x.set( \freq, ~cursors[1][0].linexp( 0, 1, 500, 1000 ) );
x.set( \amp, ~cursors[1][1].linlin( 0, 1, 0, 0.2 ) );
};
if ( msg[1].asInteger == 2 ){
y.set( \freq, ~cursors[2][0].linexp( 0, 1, 1000, 1500 ) );
y.set( \amp, ~cursors[2][1].linlin( 0, 1, 0, 0.2 ) );
}
}, "/cursor", NetAddr( "127.0.0.1", 1234 ) );
);
~cursors[1]
~cursors[2]
s.boot;
SynthDef( \cursorSound, { |out=0, freq=500, rq=0.1, amp=0.1| Out.ar( out, BPF.ar( WhiteNoise.ar( amp ), freq, rq ) ) } ).add;
x = Synth.new( \cursorSound );
y = Synth.new( \cursorSound, [\out,1] );
x.set( \freq, ~cursors[1][0].linexp( 0, 1, 500, 1000 ) );
x.set( \amp, ~cursors[1][1].linlin( 0, 1, 0, 1 ) );
x.set( \amp, 0.5 );
x.free;