Republic assemble participants in network ensembles (sclang + scserver)
Inherits from: Object : SimpleRepublic
Simplify synchronisation of networks and make it easy to join and quit a running live coding session.
In addition to SimpleRepublic, Republic maintains a server object for each participant,
so one can play sounds distributed across all servers.
See also: Server, NetAddr, OSCresponder
For the other methods, see SimpleRepublic
For a full discussion of installation and setup, see 0_Joining_the_Republic
For an example of a Republic startup file, see startup_republic_abc
Using MasterFX to filter bad values - (safety last :-) republic_MasterFX
Examples for playing distributed events: 1_Republic_distributedEvents
Examples for distributed continuous sounds: 2_Republic_continuousSounds
Examples for coupled control across members: 3_Republic_tandems
Examples for chain reactions across members: 4_Republic_Chains
Bonus tracks:
powerbooks_unplugged public workshop materials: startup_pbupublic
Pressure steam physics-based sounds: pressure_and_steam
Tutorials and how-to topics:
How to get to different servers in events and patterns: HowToGetToAllServers
How to add a SynthDef AddingASynthDef
Mouse movement sonification virus AnotherSynth_randMouse
Defining groups of players for sound distribution UsingPlayerGroups
join(nickname, clientID, serverPort)
Join the current republic under a given nickname.
clientID: when sharing servers, each participant needs a different client ID,
which is an integer between 0 and 31. If there are conflicting IDs in a group,
"duplicate node id" errors will result.
By default, clientID is nil, and a free clientID is chosen automatically.
One can also hand out unique ID numbers for each participant if desired, and pass them in.
serverPort: the port under which all servers are accessible (default: 57109).
servers
a dictionary of all available servers. The servers are instances of SharedServer, so that separate buses for different participants can be used.
addrs
a dictionary of all available (sclang) addresses.
allClientIDs
a dictionary of all known clientIDs in the republic.
onJoinAction_(func)
onJoinAction
A function that is called as soon as I am joined and the server is avaliable
The arguments passed are: republic, newServer
addSynthDef(synthDef)
Add a SynthDef to the repository. Participant servers and SynthDescLibs are kept updated. It is equivalent to calling add on that SynthDef on each computer.
A shortcut is the message share, which adds the SynthDef to the default Republic.
SynthDef(\x, { ... }).share;
removeSynthDef(name)
remove a given synthdef by name. (not yet implemented)
synthDescs
all synthDescs in the republic.
sendServer(name ... args)
Send an OSC message (args) to the server of the given name. If the name is \all, the message is sent to all participant's servers, if it is an array, the message is sent to each server of the given names.
r.sendServer(\alice, '/s_new', \default, 1900, 1,1);
r.sendServer(\all, '/chat', "alice speaking", "hi all");
r.sendServer([\bob, \charlie], '/chat', "alice speaking", "hi all");
leave(free)
leave the Republic, quit and remove my own server.
if free is true, also remove all other resources (skipjack, responders, addresses)
*usesRandIDs_()
*usesRandIDs
If set to true, the clientIDs may be set automatically (default: true)
*usesSeparateState_()
*usesSeparateState
If set to true, the servers are adjusted to allow for separate private buses. (default: true)
This needs to be the same in a group, and the group size should not exceed maxID + 1 (32).
*postSource_()
*postSource
If set to true, the incoming SynthDef source code is posted (default: true)
*maxID
Maximum possible clientID
Examples
r = Republic().makeDefault; // make a new instance
r.gui; // make a gui to monitor its state
r.join(\alice);
// individual status messages can come in before republic is joined:
(
r.broadcastAddr.sendMsg('/republic', \dada, 0);
r.broadcastAddr.sendMsg('/republic', \otto, 1);
r.broadcastAddr.sendMsg('/republic', \julio, 2);
)
r.addrs; // a dictionary of all net addresses.
// May take a second before all addrs have come in.
r.allClientIDs; // IDs currently in use
r.nextFreeID; // get a free ID (by default, random between 0 and 31 minus those in use)
r.usesRandIDs = false; // switch to get the lowest free ID
r.nextFreeID; // get the next free ID
// nickname and clientID - Each person in the group should have a unique ID from 0 to 31.
// one can either agree on unique IDs beforehand (e.g. with a deck of numbered cards),
// or rely on the default, lowestFreeID, which usually works unless many people join
// at the same time.
r.nameIsFree(\dada);
r.nameIsFree(\alice);
r.join(\alice);
r.join(\alice); // have joined already
r.join(\bob); // rejoin under different name - alice fades away
r.leave;
r.join(\bob);
r.nickname; // nickname
r.servers.collect(_.addr);
// make some OSC responder
g = OSCresponder(nil, '/chat', {|t,r,msg| (">" + msg[1] + ":" + msg[2]).postln }).add;
// send to one address. This may not yet exist and fail.
r.addrs[\alice].sendMsg('/chat', "alice", "hi all.");
// if you are not sure if a participant is perhaps absent
r.send(\alice, '/chat', \alice, "hi alice");
// if you want to send to everyone, use the name \all:
r.send(\all, '/chat', \alice, "hi all");
// multiple names
r.send([\alice, \john], '/chat', \alice, "hi alice, hi john");
g.remove; // remove responder
// server side:
r.servers; // a dictionary with all servers
r.servers.do { |server| server.makeWindow }; // make a window for each server
s.boot; // boot localhost
// share a SynthDef with all participants
(
SynthDef(\xxx, {|out, zzf = 440, sustain = 1, mod = 0.5, amp = 0.1, pan|
var env = Line.kr(1, 0, sustain, doneAction: 2);
Out.ar(out,
Pan2.ar(
RLPF.ar(
LFPulse.ar(zzf, 0, SinOsc.kr(mod * zzf)),
zzf * (env.cubed + mod + 0.5),
0.2
),
pan, env * amp
))
}).share;
)
r.synthDescs; // the available SynthDescs
a = SynthDescLib.global.synthDescs.at(\xxx); // it has arrived here, too.
a.metadata.at(\sentBy); // see who sent it
a.metadata.at(\sourceCode); // see the source code
(
Tdef(\x, {
loop {
0.12.wait;
(server: r.servers.choose, instrument: \xxx,
zzf: exprand(300, 11111), mod: 0.03, sustain: 0.1
).play;
}
}).play
);
// test if pattern works here:
(
Pdef(\x,
Pbind(
\instrument, \xxx,
\server, r.servers[r.nickname],
\zzf, Pseq([8700, 800, 720], inf),
\mod, Pwhite(0.1, 0.7, inf),
\dur, Prand([0.3, 0.5, Pn(0.04, 5)], inf)
)
).play
)
// send synth messages to random participants:
(
Pdef(\x,
Pbind(
\instrument, \xxx,
\server, Pfunc { r.servers.choose } .trace,
\zzf, Pseq([8700, 800, 720], inf),
\mod, Pwhite(0.1, 0.7, inf),
\dur, Prand([0.3, 0.5, Pn(0.04, 5)], inf)
)
).play
)
// leave republic.
r.leave;
// free all resources
r.free;