postln('Loading custom functions.'); /* * JACK specific helper functions * TODO: move to Quark */ // disconnect a port ~jackDisconnectPort = { arg source, sourceChannel, destination, destinationChannel; ("jack_disconnect "++source++":"++sourceChannel++" "++destination++":"++destinationChannel).unixCmd({ arg exitCode; if(exitCode != 0, { postln("Disconnecting "++source++":"++sourceChannel++" from "++destination++":"++destinationChannel++" was unsuccessful!"); }); }); }; // connect a port ~jackConnectPort = { arg source, sourceChannel, destination, destinationChannel; ("jack_connect "++source++":"++sourceChannel++" "++destination++":"++destinationChannel).unixCmd({ arg exitCode; if(exitCode != 0, { postln("Connecting "++source++":"++sourceChannel++" from "++destination++":"++destinationChannel++" was unsuccessful!"); }); }); }; // returns the amount of ports of a given client ~jackClientPorts = { arg clientName; ("jack_lsp "++clientName++"| wc -l").unixCmdGetStdOut.asInt; }; /* * SuperCollider specific helper functions * */ // adds one or more channels to Server.local.options.num{In,Out}putBusChannels // makes the tuple available in ~additionalChannels Dictionairy ~addAdditionalChannels = { arg type, name, channels; if( (name.isKindOf(Symbol) && channels.isArray), { switch (type, \input, { ~additionalChannels.at(\inputs).add(name -> channels); postln("Added additional input channels for '"++name++"': "++channels.asString); Server.local.options.numInputBusChannels = Server.local.options.numInputBusChannels + channels.size; postln("Setting numInputBusChannels to "++Server.local.options.numInputBusChannels); }, \output, { ~additionalChannels.at(\outputs).add(name -> channels); postln("Added additional output channels for '"++name++"': "++channels.asString); Server.local.options.numOutputBusChannels = Server.local.options.numOutputBusChannels + channels.size; postln("Setting numOutputBusChannels to "++Server.local.options.numOutputBusChannels); }, { error("Expecting \input or \output as type, got "++type.asString); }); },{ error('Expecting type Symbol for name and type Array for channels.'); }); }; /* * SSR specific helper functions * TODO: move to Quark */ // sets up the necessary OSC connection for an existing local or remote SSR // instance, subscribes to it and returns the NetAddr associated with it ~ssrSetupOSC = { arg host="localhost", port=50001; var ssr; // set ssr of the client instance ssr = NetAddr(host, port); // answer /poll messages with an /alive answer OSCdef( \pollreply, { arg msg, time, addr, recvPort; ~ssr.sendMsg("/alive"); }, '/poll', ssr ); // subscribe to server with MessageLevel::SERVER ssr.sendMsg("/subscribe", $T, 2); ssr; }; // clears the SSR scene, unsubscribes from the instance and removes alive // answers OSCdef ~ssrDismantleOSC = { arg ssr; if (ssr.isKindOf(NetAddr), { // remove all sources ssr.sendMsg("/scene/clear"); // unsubscribe from server ssr.sendMsg("/subscribe", $F); // disable alive answers OSCdef(\alive).disable; }); }; // adds a source to an SSR instance ~ssrAddSource = { arg ssr, name, model = "point", port, x = 0.0, y = 0.0, orientation = 0.0, gain = 1.0, movability = $F, orientationMovability = $F, mute = $F; if (ssr.isKindOf(NetAddr), { if (name.isString, { if (model.isString, { if (port.isString, { ssr.sendMsg("/source/new", name, model, port, x, y, orientation, gain, movability, orientationMovability, mute) },{ error("The port argument is not of type String: "++port.class); }); },{ error("The model argument is not of type String: "++model.class); }); },{ error("The name argument is not of type String: "++name.class); }); },{ error("The ssr argument is not of type NetAddr: "++ssr.class); }); }; /* * MIDI specific helper functions * TODO: move to Quark */ // map inputs of a given MIDI device's control messages to the values on a // control Bus ~midiControlToBus = { arg key, msgNum, chan, uid, bus; if(key.isKindOf(Symbol),{ if((msgNum.isArray),{ if (chan.isInteger, { if (uid.isInteger, { if (bus.isKindOf(Bus), { MIDIdef.new( key: key, func: { arg ...args; bus.setAt( msgNum.indexOf(args[1].asInteger), args[0].asInteger.lincurve(0, 127, 0.0, 1.0, 4, nil) ); }, msgNum: msgNum, chan: chan, msgType: \control, srcID: uid ); },{ error('Argument bus must be of type Bus: '++bus.class); }); },{ error('Argument uid must be of type Integer: '++uid.class); }); },{ error('Argument chan must be of type Integer: '++chan.class); }); },{ error('Argument msgNum must be of type Array: '++msgNum.class); }); },{ error('Argument key must be of type Symbol: '++key.class); }); }; // setting clock of ZZZES3 to bpm (in given range) ~midiControlToClockBPM = { arg key, msgNum, chan, uid, zzz, range; MIDIdef.new( key, { arg ...args; var bpm = args[0].linexp(0, 127, range[0], range[1]).asInteger; zzz.setClock( msgNum.indexOf(args[1].asInteger)+1, bpm/60 ); }, msgNum, chan, \control, uid ); };