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;