Skip to content

Instantly share code, notes, and snippets.

@adcxyz
Last active October 19, 2017 17:17
Show Gist options
  • Save adcxyz/57c89fe1faed045e77b09a2ec1d23b34 to your computer and use it in GitHub Desktop.
Save adcxyz/57c89fe1faed045e77b09a2ec1d23b34 to your computer and use it in GitHub Desktop.
Testing Multiclient proposals
/*
This is a long test/demo sequence for multi-client-server setups.
It needs to be run by hand, as there is no way to automate all of them.
* It is designed to verify that the pull requests for 3.9 up to
topic-getMaxLoginsFromScsynth actually work as promised.
* It demonstrates the new features and their advantages.
* It also tests cross-compatibility for logins from multiple clients
and scsynth with differing versions, and shows to what extent which
features will work in mixed settings.
/////// - tests within single SC3.9dev app /////////
1. Start SC3.9dev with PR included
2. run setup script
3. test Server.local, clientID 0
4. test Server.local2, clientID 4
/////// - tests with SC3.9dev and SC3.9dev_copy - /////////
1. Start SC3.9 dev with PR included
2. run setup script
3. test Server.local, clientID 0
4. test Server.local2, clientID 4
/////// - tests with SC3.9dev and SC3.8.0 and SC3.7.2 - /////////
5. Start SC3.8 / 3.7.2 in parallel
6. in SC3.8 / 3.7.2, run prepare-script
7. test Server.local, clientID 0
8. test Server.local2, clientID 4 -> broken
9. leave 3.8 server booted, and run
*/
////////// 1. run ~setupScript once ///////
(
~setupScript = {
s.options.maxLogins = 4;
// in 3.9. try testing both NodeIDAllocator classes:
// // default is:
// Server.nodeAllocClass = NodeIDAllocator;
// // testable alternative
// Server.nodeAllocClass = ReadableNodeIDAllocator;
Tdef(\testAllWays).set(\server, s);
Tdef(\testAllWays, { |env|
var server = env.server;
defer { try { server.plotTree } };
0.5.wait;
"// Synth".postln;
x = Synth(\default, nil, server);
0.5.wait;
x.release;
0.5.wait;
"// Event/Pattern".postln;
Pbind(
\degree, Pseq((0..8).mirror),
\dur, 0.1,
\server, server.postcs
).play;
2.wait;
"// Function.play".postln;
x = { Dust.ar(1000!2).lag(0.002) }.play(server);
1.wait;
x.release(0.2);
0.5.wait;
p = ProxySpace.push(server);
"// nodeproxies".postln;
~x = { Dust.ar(10 ! 2) };
~x.play;
1.wait;
~x.filter(10, { |in| Ringz.ar(in, [600, 800], 0.03) }).play;
1.wait;
~x.end(1);
2.wait;
defer { Window.closeAll };
"done.".postln;
});
};
~setupScript.value;
)
///////// 2.a. test Server.local, no clientID, defaults to clientID 0 /////
/*
// when in doubt:
Server.killAll;
*/
s.reboot;
/* in 3.9dev, this posts:
...
Shared memory server interface initialized
Requested notification messages from server 'localhost'
localhost: scsynth maxLogins 4 match with my options.
localhost: keeping clientID 0 as confirmed from scsynth.
*/
// clientID and defaultGroup, and node allocation are unchanged
s.clientID; // -> 0
s.defaultGroup; // Group(1)
s.nextNodeID; // 1000
s.nextNodeID; // 1001
// it supports 4 clients, like maxLogins says
s.options.maxLogins;
s.numClients;
// and makes 4 defaultGroups for them.
s.defaultGroups;
// which already live on the server:
s.queryAllNodes;
// now test playing sounds in four ways,
// and watch the nodeID structure on plotTree window:
// a piano tone,
// a scale up and down,
// noise,
// and filtered dust
Tdef(\testAllWays).set(\server, s).play;
//////// 2.b. test Server.local2, with userSpecified clientID of 4
s.quit;
// remove server with that name, in case we made it before
~local2.remove;
~local2 = Server(\local2, s.addr, s.options, 2);
~local2.reboot;
/* in 3.9dev, this posts:
...
Requested notification messages from server 'local2'
Shared memory server interface initialized
local2: scsynth maxLogins 4 match with my options.
local2: keeping clientID 2 as confirmed from scsynth.
*/
// separate defaultGroup based on clientID:
~local2.clientID; // will remain 2
~local2.defaultGroupID; // == 134217729 == (2 ** 26 * 2) + 1
~local2.defaultGroup; // == Group(134217729)
~local2.nextNodeID; // == 134217728 + 1000, etc ...
// test playing sounds in four ways
Tdef(\testAllWays).set(\server, ~local2).play;
// remake defaultGroup with ReadableNodeIDAllocator ...
Server.nodeAllocClass = ReadableNodeIDAllocator;
~local2.reboot;
~local2.defaultGroupID; // 200000001
~local2.nextNodeID; // 200001000, 400001001, etc
// test playing sounds in four ways
Tdef(\testAllWays).set(\server, ~local2).play;
///////// 3. login to local scsynth as if sclang were a remote client /////
/// make sure scsynth runs, without remembering previous logins
s.reboot;
// then just for testing:
// disconnect sclang from its notification,
// such that scsynth has no clientID registered for s.addr:
s.statusWatcher.sendNotifyRequest(false).stopStatusWatcher;
// posts -> Switched off notification messages from server 'localhost'
// in case we had already made a \pseudoRem server, remove it:
~pseudoRem.remove;
// 3.a. - make ~pseudoRem as a remote Server;
// with a specific clientID, and with "wrong" settings for maxLogins:
~pseudoRem = Server.remote(\pseudoRem, s.addr, s.options.copy.maxLogins_(8), 3);
// this finds the running local scsynth and logs into it, so:
/* in 3.9dev, this posts:
...
Shared memory server interface initialized
Requested notification messages from server 'pseudoRem'
pseudoRem: scsynth has maxLogins 4 - adjusting my options accordingly.
pseudoRem: keeping clientID 2 as confirmed from scsynth.
*/
~pseudoRem.clientID; // keeps requested clientID
~pseudoRem.numClients; // adjusts to maxLogins which scsynth has sent!
// With default, NodeIDAllocator, this becomes:
~pseudoRem.defaultGroupID; // this is 1 << 26 (numIDs) * 3 (clientID) + 1 (group);
~pseudoRem.nextNodeID; // ~pseudoRem.defaultGroupID + 1000 + 1
// or if ReadableNodeIDAllocator
~pseudoRem.defaultGroup; // 300000001
~pseudoRem.nextNodeID; // 300001001
// test playing sounds in four ways
Tdef(\testAllWays).set(\server, ~pseudoRem).play;
////// 3.b. as-if remote login without a clientID and with matching maxLogins:
// unregister server notification
~pseudoRem.statusWatcher.sendNotifyRequest(false).stopStatusWatcher;
// remove server at \pseudoRem name
Server.named.removeAt(\pseudoRem); Server.all.remove(~pseudoRem);
// make ~pseudoRem with matching options and no clientID
~pseudoRem = Server.remote(\pseudoRem, s.addr, s.options);
/* in 3.9dev, this posts:
...
Shared memory server interface initialized
Requested notification messages from server 'pseudoRem'
pseudoRem: scsynth maxLogins 4 match with my options.
pseudoRem: setting clientID to 1, as obtained from scsynth.
pseudoRem : setting clientID to 1.
*/
Tdef(\testAllWays).set(\server, ~pseudoRem).play;
///////////////////////////////////////////////////////////////////////
///////////// 4. test playing from a copy of 3.9 on 3.9dev's scsynth ////
// in SC3.9 copy, run setup script, then do
~remFromCopy.remove;
~remFromCopy = Server.remote(\remFromCopy, s.addr, s.options.copy.maxLogins_(16), 2);
/* in 3.9 copy, this posts:
...
Requested notification messages from server 'remFromCopy'
remFromCopy: scsynth has maxLogins 4 - adjusting my options accordingly.
remFromCopy: keeping clientID 2 as confirmed from scsynth.
*/
~remFromCopy.clientID; // keeps requested clientID
~remFromCopy.numClients; // adjusts to maxLogins which scsynth has sent!
~remFromCopy.defaultGroup; // 134217729, >> 26 -> 2
~remFromCopy.nextNodeID; // 134217728 + 1000 + 1
// test playing sounds in four ways
Tdef(\testAllWays).set(\server, ~remFromCopy).play;
// 4.b - test login without clientID and matching maxLogins:
~remFromCopy.statusWatcher.sendNotifyRequest(false).stopStatusWatcher;
~remFromCopy.remove;
~remFromCopy = Server.remote(\remFromCopy, s.addr, s.options);
/* in 3.9 copy, this posts:
...
Requested notification messages from server 'remFromCopy'
remFromCopy: scsynth maxLogins 4 match with my options.
remFromCopy: setting clientID to 3, as obtained from scsynth.
remFromCopy : setting clientID to 3.
*/
~remFromCopy.clientID; // keeps requested clientID
~remFromCopy.numClients; // adjusts to maxLogins which scsynth has sent!
~remFromCopy.defaultGroup; // Group(201326593),
~remFromCopy.nextNodeID; // 201327619
Tdef(\testAllWays).set(\server, ~remFromCopy).play;
///////////////////////////////////////////////////////////////////////
///////////// 5. test playing from 3.9 on a remote server booted in 3.8 ////
/*
// 5. Start SC3.8 in parallel
// 6. in SC3.8, run prepare-script, then do:
Server.killAll;
s.reboot;
*/
// 7. Back in 3.9, log into server as remoteTo38, and test it:
// remove ~remoteTo38 in case you re-run tests
~remoteTo38.remove;
// scsynth 3.8 does not return maxLogins value, so that check
// cannot happen automatically - users have to get this right by hand.
// will get clientID 1 from scsynth 3.8, and lots of info posting
~remoteTo38 = Server.remote(\remoteTo38, s.addr, s.options, 3);
~remoteTo38.statusWatcher. sendNotifyRequest(false);
/*
// scsynth 3.8 does not support requesting a clientID, so it posts:
remoteTo38: no maxLogins info from scsynth.
// scsynth 3.8 does not support requesting a clientID,
// so it always hands out the next free clientID:
WARNING: remoteTo38 - userSpecifiedClientID 3 is not free!
Switching to free clientID obtained from scsynth: 1.
If that is problematic, please set clientID by hand before booting.
remoteTo38 : setting clientID to 1.
*/
~remoteTo38.clientID; // likely it got 1, depending on what it got 7
~remoteTo38.defaultGroup; // Group(67108865)
~remoteTo38.defaultGroup.nodeID >> 26; // == ~remoteTo38.clientID
~remoteTo38.nextNodeID; // 67108865 + 1001
// test playing sounds in four ways:
Tdef(\testAllWays).set(\server, ~remoteTo38).play;
///////////////////////////////////////////////////////////////////////
///////////// 5. test playing from 3.8 on remote server booted in 3.9 ////
// this works, with some unavoidable disadvantages
// because of things that were not implemented yet in 3.8:
// Still in 3.9, boot server:
Server.killAll;
s.reboot;
// In SC3.8, test logging in as remoteTo39:
// recompile,
// then load ~setupScript;
// then remove ~remoteTo39 in case we already used it
Server.named.removeAt(\remoteTo39); Server.all.remove(~remoteTo39);
~remoteTo39 = Server.remote(\remoteTo39, s.addr, s.options, 3);
// this does not reset clientID, whether userSpecified or not
~remoteTo39.clientID; // so this is still 3
~remoteTo39.defaultGroup; // Group(1) because of old allocator scheme
~remoteTo39.nextNodeID; // offset works here with allocators.
~remoteTo39.plotTree;
// test playing sounds in four ways:
// all four play, but all in Group(1)
// - this is confusing, but unavoidable.
Tdef(\testAllWays).set(\server, ~remoteTo39).play;
// in 3.8, freeAll kills all groups except Group(1);
// make a fake extra group in RootNode
~remoteTo39.sendMsg("g_new", 123456789, 0);
~remoteTo39.plotTree;
~remoteTo39.freeAll; // all gone except Group(1);
/////////// END OF TESTS //////////////////
///////////////////////////////////////////
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment