Last active
October 19, 2017 17:17
-
-
Save adcxyz/57c89fe1faed045e77b09a2ec1d23b34 to your computer and use it in GitHub Desktop.
Testing Multiclient proposals
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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