supercollider icon indicating copy to clipboard operation
supercollider copied to clipboard

Sync server volume between multiple clients

Open adcxyz opened this issue 9 months ago • 2 comments

Purpose and Motivation

Currently, when multiple clients play on the same server, (as in network music), volume control is quite unusable: Multiple clients have separate groups, and each one gets its own volume ampSynth. But, as this is a single tree of synths, each ampSynth also scales volume of all earlier client groups! (For separate volume control for all clients, each client would need its own separate buses.)

With this PR, all remote clients use the same single ampSynth to get and set main volume, which runs in group with known fixed nodeID 2 and has a known fixed nodeID 3. Thus, even if multiple clients try to create the ampSynth simultaneously, only a single one will be made.

Current state:

// node tree
defaultgroup client2
 ... client 2 synths ...
 client2 volume
defaultgroup client1
 ... client 1 synths ...
 client1 volume
1 - defaultgroup client0 (usually local client)
  ... client 0 synths ...
 client 0 volume

With this PR, the structure is:

// node tree
defaultgroup client2
 ... client 2 synths ...
defaultgroup client1
 ... client 1 synths ...
1 - defaultgroup client0 (usually local client)
  ... client 0 synths ...
 client 0 volume, get- and settable by all clients eventually.

This PR takes up #4985, see discussion there, and closes #4157. It also fixes related inconsistencies:

  • remote clients are now blocked from quitting, booting, or rebooting a remote server
  • remote clients renew notification after being unresponsive, because the remote server may have been rebooted.

Types of changes

  • Inconsistency fixes

To-do list

  • [x] Code is tested
  • [x] All tests are passing
  • [x] Updated documentation
  • [x] This PR is ready for review
////// Tests with more explanations
// use ReadableNodeIDAllocator for multi-client readability
Server.nodeAllocClass = ReadableNodeIDAllocator;

// prepare localhost for multiclient
(
s.options.bindAddress = "0.0.0.0"; // allow connections from any address
s.options.maxLogins = 2; // set to correct number of clients
s.reboot;
// scsynth sends volume info to all clients, and when multiple clients, 
// a listener to these updates is created: 
s.volume.listener;
)

// Run on remote machine connecting to server,
// or on local machine to simulate remote client:
(
o = ServerOptions.new;
o.maxLogins = 2;
// set to correct local address and port on your machine:
t = Server.remote(\remote, NetAddr("192.168.178.39", 57110), o);
// info about returned client ID 1 should be posted in the post window ...

// need to set remoteControlled by hand for testing on same machine:
if (t.isLocal) {  t.remoteControlled = true };

t.makeWindow; 
)

/// test setting volume - should show on both s and t guis:
s.volume = -20;
s.volume = -10;
s.volume = -1;
s.volume = -0.1
// and stop ampSynth when 0
s.volume = 0;

s.volume = -1;
// volume should survive full stop on both
CmdPeriod.run;

s.scope;
// synths on s and t should be equally affected by volume
{ LFPulse.ar(5, 0, 0.2, 0.1) * PinkNoise.ar }.play(s, 0);

{ LFPulse.ar(8, 0, 0.2, 0.1) * PinkNoise.ar }.play(t, 1);

// check that this works after reboot too:

//////// remote server should not quit, boot, reboot
t.quit; // no
t.boot; //no
t.reboot; // no

// scsynth should send quit notifications to all clients, 
// but it seems it does not:
s.quit;
s.serverRunning;
t.serverRunning; // remote client thinks server is running,
t.unresponsive; // and only unresponsive.

Fixed with 0080f244 with by renewing notification on remote clients after unresponsive

adcxyz avatar May 17 '24 15:05 adcxyz