diff options
Diffstat (limited to 'src/scripts/supercollider')
-rw-r--r-- | src/scripts/supercollider/Ingen.sc | 746 | ||||
-rw-r--r-- | src/scripts/supercollider/README | 11 | ||||
-rw-r--r-- | src/scripts/supercollider/example.sc | 27 |
3 files changed, 0 insertions, 784 deletions
diff --git a/src/scripts/supercollider/Ingen.sc b/src/scripts/supercollider/Ingen.sc deleted file mode 100644 index 873c8c2b..00000000 --- a/src/scripts/supercollider/Ingen.sc +++ /dev/null @@ -1,746 +0,0 @@ -// TODO: -// * Keep track of established connections. -Ingen : Model { - classvar <>program = "om", <>patchLoader = "om_patch_loader"; - classvar <>oscURL, <nodeTypeMap, <>uiClass; - var <addr; - var <>loadIntoJack = true; - var allocator, requestResponders, requestHandlers, notificationResponders; - var creatingNode, newNodeEnd; - var <registered = false, <booting = false; - var <root; - var <plugins, pluginParentEvent; - var onNewPatch; - *initClass { - Class.initClassTree(Event); - Class.initClassTree(NetAddr); - Event.parentEvents.default[\omcmd] = \noteOn; - Event.parentEvents.default[\omEventFunctions] = ( - noteOn: #{ arg midinote=60, amp=0.1; - [midinote, asInteger((amp * 127).clip(0, 127)) ] }, - noteOff: #{ arg midinote=60; [ midinote ] }, - setPortValue: #{|portValue=0| [portValue] } - ); - Event.parentEvents.default.eventTypes[\om]=#{|server| - var freqs, lag, dur, sustain, strum, target, bndl, omcmd; - freqs = ~freq = ~freq.value + ~detune; - if (freqs.isKindOf(Symbol).not) { - ~amp = ~amp.value; - strum = ~strum; - lag = ~lag + server.latency; - sustain = ~sustain = ~sustain.value; - omcmd = ~omcmd; - target = ~target; - ~midinote = ~midinote.value; - ~portValue = ~portValue.value; - bndl = ~omEventFunctions[omcmd].valueEnvir.asCollection; - bndl = bndl.flop; - bndl.do {|msgArgs, i| - var latency; - latency = i * strum + lag; - if(latency == 0.0) { - target.performList(omcmd, msgArgs) - } { - thisThread.clock.sched(latency, { - target.performList(omcmd, msgArgs); - }) - }; - if(omcmd === \noteOn) { - thisThread.clock.sched(sustain + latency, { - target.noteOff(msgArgs[0]) - }) - } - } - } - }; - oscURL="osc.udp://"++NetAddr.localAddr.ip++$:++NetAddr.localAddr.port; - nodeTypeMap = IdentityDictionary[ - \Internal -> IngenInternalNode, - \LADSPA -> IngenLADSPANode, - \DSSI -> IngenDSSINode - ]; - uiClass = IngenEmacsUI - } - *new { | netaddr | - ^super.new.init(netaddr) - } - gui { ^uiClass.new(this) } - init { |netaddr| - addr = netaddr ? NetAddr("127.0.0.1", 16180); - onNewPatch = IdentityDictionary.new; - allocator = StackNumberAllocator(0,1024); - requestHandlers = IdentityDictionary.new; - requestResponders = [ - "response/ok" -> {|id| - requestHandlers.removeAt(id).value; allocator.free(id) }, - "response/error" -> {|id,text| - requestHandlers.removeAt(id); - allocator.free(id); - ("Ingen"+text).error } - ].collect({|a| - var func = a.value; - OSCresponder(addr, "/om/"++a.key, {|time,resp,msg| - func.value(*msg[1..]) - }) - }); - notificationResponders = [ - "new_patch" -> {|path,poly| - var func = onNewPatch.removeAt(path); - if (func.notNil) { - func.value(this.getPatch(path,false).prSetPoly(poly)) - } - }, - "metadata/update" -> {|path,key,value| - this.getObject(path).metadata.prSetMetadata(key, value) }, - "new_node" -> {|path,poly,type,lib,label| - var patchPath, nodeName, patch, node; - var lastSlash = path.asString.inject(nil,{|last,char,i| - if(char==$/,i,last) - }); - if (lastSlash.notNil) { - patchPath = path.asString.copyFromStart(lastSlash-1); - nodeName = path.asString.copyToEnd(lastSlash+1); - patch = this.getPatch(patchPath); - if (patch.notNil) { - if (patch.hasNode(nodeName).not) { - node = nodeTypeMap[type].new - (nodeName, patch, poly, label, lib); - creatingNode = node; - patch.nodes[nodeName.asSymbol] = node; - patch.changed(\newNode, node); - } { - if (patch.getNode(nodeName).class != nodeTypeMap[type]) { - ("Ingen sent an existng node with differing type"+path).warn - } - } - } { - ("Ingen tried to create node in non-existing patch"+patchPath).warn - } - } { - ("Invalid path in node creation"+path).warn - } - }, - "new_node_end" -> { - newNodeEnd.value(creatingNode); - newNodeEnd = nil; - creatingNode = nil }, - "new_port" -> {|path,type,dir,hint,def,min,max| - var basePath, portName, parent, port; - var lastSlash = path.asString.inject(nil,{|last,char,i| - if(char==$/,i,last) - }); - if (lastSlash.notNil) { - basePath = path.asString.copyFromStart(lastSlash-1); - portName = path.asString.copyToEnd(lastSlash+1); - parent = this.getNode(basePath) ? this.getPatch(basePath); - if (parent.notNil) { - if (parent.hasPort(portName).not) { - port = IngenPort.new(portName, parent, type, dir, hint, def, min, max); - parent.ports[portName.asSymbol] = port; - parent.changed(\newPort, port) - } { - if (parent.getPort(portName).porttype != type) { - ("Ingen tried to create an already existing port with differing type" - +path).warn - } - } - } { - ("Ingen tried to create port on non-existing object"+basePath).warn - } - } { - ("Invalid path in port creation"+path).warn - } - }, - "control_change" -> {|path,value| - this.getPort(path).prSetValue(value) }, - "patch_enabled" -> {|path| this.getPatch(path).prSetEnabled(true) }, - "patch_disabled" -> {|path| this.getPatch(path).prSetEnabled(false) }, - "plugin" -> {|lib,label,name,type| - plugins.add(Event.new(4,nil,pluginParentEvent).putAll( - (type:type, lib:lib, label:label, name:name))) }, - "node_removal" -> {|path| - var node = this.getNode(path); - if (node.notNil) { - node.parent.nodes.removeAt(node.name.asSymbol).free - } { - ("Ingen attempting to remove non-existing node"+path).warn - } - }, - "port_removal" -> {|path| - var port = this.getPort(path); - if (port.notNil) { - port.parent.ports.removeAt(port.name.asSymbol).free - } { - ("Ingen attempting to remove non-existing port"+path).warn - } - }, - "patch_destruction" -> {|path| - var patch = this.getPatch(path); - if (patch.notNil) { - patch.parent.patches.removeAt(patch.name.asSymbol).free - } { - ("Ingen attempting to remove non-existing patch"+path).warn - } - }, - "program_add" -> {|path,bank,program,name| - var node = this.getNode(path); - if (node.respondsTo(\prProgramAdd)) { - node.prProgramAdd(bank,program,name) - } { - ("Ingen tried to add program info to"+node).warn - } - } - ].collect({|a| - var func = a.value; - OSCresponder(addr, "/om/"++a.key, {|time,resp,msg| - func.value(*msg[1..]) - }) - }); - pluginParentEvent = Event.new(2,nil,nil).putAll(( - engine:this, - new:{|self,path,poly=1,handler|self.engine.createNode(path?("/"++self.name),self.type,self.lib,self.label,poly,created:handler)} - )); - } - *waitForBoot {|func| ^this.new.waitForBoot(func) } - waitForBoot {|func| - var r, id = 727; - requestHandlers[id] = { - r.stop; - booting=false; - this.changed(\running, true); - func.value(this) - }; - if (booting.not) {this.boot}; - r = Routine.run { - 50.do { - 0.1.wait; - addr.sendMsg("/om/ping", id) - }; - requestHandlers.removeAt(id); - "Ingen engine boot failed".error; - } - } - getPatch {|path, mustExist=true| - var elements, currentPatch; - if (path.class == Array) { elements = path - } { elements = path.asString.split($/) }; - elements.do{|elem| - if (elem=="") { - currentPatch = root - } { - currentPatch = currentPatch.getPatch(elem,mustExist); - if (currentPatch.isNil) { ^nil } - } - }; - ^currentPatch; - } - getNode {|path| - var basePath, nodeName, patch; - if (path.class == Array) { basePath = path - } { basePath = path.asString.split($/) }; - nodeName = basePath.pop; - patch = this.getPatch(basePath,true); - if (patch.notNil) { - ^patch.getNode(nodeName) - }; - ^nil - } - getPort {|path| - var basePath, portName, node, patch; - basePath = path.asString.split($/); - portName = basePath.pop; - node = this.getNode(basePath.copy); - if (node.notNil) { ^node.getPort(portName) }; - patch = this.getPatch(basePath,true); - if (patch.notNil) { ^patch.getPort(portName) }; - ^nil - } - getObject {|path| - var patch,node,port; - patch = this.getPatch(path,true); - if (patch.notNil) { ^patch }; - node = this.getNode(path); - if (node.notNil) { ^node }; - port = this.getPort(path,true); - if (port.notNil) { ^port }; - ^nil - } - at {|path|^this.getObject(path.asString)} - *boot {|func| - ^Ingen.new.waitForBoot {|e| - e.activate { - e.register { - e.loadPlugins { - e.requestPlugins { - e.requestAllObjects { - func.value(e) - } - } - } - } - } - } - } - boot { - requestResponders.do({|resp| resp.add}); - booting = true; - if (addr.addr == 2130706433) { - if (loadIntoJack) { - ("jack_load"+"-i"+addr.port+"Ingen"+"om").unixCmd - } { - (program+"-p"+addr.port).unixCmd - } - } { - "You have to manually boot Ingen now".postln - } - } - loadPatch {|patchPath| (patchLoader + patchPath).unixCmd } - activate { | handler | - this.sendReq("engine/activate", { - root = IngenPatch("",nil,this); - this.changed(\newPatch, root); - handler.value - }) - } - register { | handler | - this.sendReq("engine/register_client", { - registered=true; - notificationResponders.do({|resp| resp.add}); - this.changed(\registered, registered); - handler.value(this) - }) - } - unregister { | handler | - this.sendReq("engine/unregister_client", { - registered=false; - notificationResponders.do({|resp| resp.remove}); - this.changed(\registered, registered); - handler.value(this) - }) - } - registered_ {|flag| - if (flag and: registered.not) { - this.register - } { - if (flag.not and: registered) { - this.unregister - } - } - } - loadPlugins { | handler | this.sendReq("engine/load_plugins", handler) } - requestPlugins {|handler| - var startTime = Main.elapsedTime; - plugins = Set.new; - this.sendReq("request/plugins", { - ("Received info about"+plugins.size+"plugins in"+(Main.elapsedTime-startTime)+"seconds").postln; - this.changed(\plugins, plugins); - handler.value(this); - }) - } - requestAllObjects { |handler| - this.sendReq("request/all_objects", handler) - } - createPatch { | path, poly=1, handler | - onNewPatch[path.asSymbol] = handler; - this.sendReq("synth/create_patch", nil, path.asString, poly.asInteger) - } - createNode { | path, type='LADSPA', lib, label, poly=1, created, handler | - newNodeEnd = created; - this.sendReq("synth/create_node",handler,path,type,lib,label,poly) - } - createAudioInput { | path, handler | - this.createNode(path,"Internal","","audio_input",0,handler) - } - createAudioOutput {|path,handler| - this.createNode(path,"Internal","","audio_output",0,handler) - } - createMIDIInput {|path,handler| - this.createNode(path,"Internal","","midi_input",1,handler) - } - createMIDIOutput {|path,handler| - this.createNode(path,"Internal","","midi_output",1,handler) - } - createNoteIn {|path| this.createNode(path,"Internal","","note_in") } - connect {|fromPath,toPath,handler| - this.sendReq("synth/connect",handler,fromPath.asString,toPath.asString) - } - disconnect { | fromPath, toPath, handler | - this.sendReq("synth/disconnect",handler,fromPath.asString,toPath.asString) - } - disconnectAll { | path, handler | - this.sendReq("synth/disconnect_all",handler,path); - } - sendReq { | path, handler...args | - var id = allocator.alloc; - requestHandlers[id] = handler; - addr.sendMsg("/om/"++path, id, *args) - } - quit { - if (loadIntoJack) { - ("jack_unload"+"Ingen").unixCmd; - booting=false; - requestResponders.do(_.remove); - notificationResponders.do(_.remove); - this.changed(\running, false); - } { - this.sendReq("engine/quit", { - booting=false; - requestResponders.do(_.remove); - notificationResponders.do(_.remove); - this.changed(\running, false); - }) - } - } - ping {| n=1, func | - var id, result, start; - id = allocator.alloc; - result = 0; - requestHandlers[id] = { - var end; - end = Main.elapsedTime; - result=max((end-start).postln,result); - n=n-1; - if (n > 0) { - start = Main.elapsedTime; - addr.sendMsg("/om/ping", id) - } { - allocator.free(id); - func.value(result) - } - }; - start = Main.elapsedTime; - addr.sendMsg("/om/ping", id) - } - setPortValue {|path, val| this.getPort(path.asString).value=val } - jackConnect {|path, jackPort| - this.getPort(path).jackConnect(jackPort) - } - noteOn {|path, note, vel| - var patch,node; - patch = this.getPatch(path,true); - if (patch.notNil) { patch.noteOn(note,vel) }; - node = this.getNode(path); - if (node.notNil) { node.noteOn(note,vel) }; - } - noteOff {|path, note| - var patch,node; - patch = this.getPatch(path,true); - if (patch.notNil) { patch.noteOff(note) }; - node = this.getNode(path); - if (node.notNil) { node.noteOff(note) }; - } - matchPlugins{ | label, lib, name, type | - ^plugins.select{ |p| - label.matchItem(p.label) and: { - lib.matchItem(p.lib) and: { - name.matchItem(p.name) and: { - type.matchItem(p.type) - } - } - } - } - } - dssiMsg {|path,reqType="program" ...args| - addr.sendMsg("/dssi"++path++$/++reqType,*args) - } -} - -IngenMetadata { - var object, dict; - *new {|obj|^super.new.metadataInit(obj)} - metadataInit {|obj| - dict=Dictionary.new; - object=obj - } - put {|key,val| - object.engine.sendReq("metadata/set", nil, - object.path, key.asString, val.asString) - } - at {|key|^dict.at(key.asSymbol)} - prSetMetadata {|key,val| - dict.put(key,val); - object.changed(\metadata, key, val) - } -} - -IngenObject : Model { - var <name, <parent, <metadata; - *new {|name, parent| - ^super.new.initIngenObject(name,parent); - } - initIngenObject {|argName, argParent| - name = argName; - parent = argParent; - metadata=IngenMetadata(this) - } - path { ^parent.notNil.if({ parent.path ++ $/ ++ name }, name).asString } - depth { ^parent.notNil.if({ parent.depth + 1 }, 0) } - engine { ^parent.engine } -} - -IngenPort : IngenObject { - var <porttype, <direction, <spec, <value, <connections; - *new {|name,parent,type,dir,hint,def,min,max| - ^super.new(name,parent).initPort(type,dir,hint,def,min,max) - } - initPort {|type,dir,hint,def,min,max| - porttype = type; - direction = dir; - spec = ControlSpec(min, max, - if (hint == 'LOGARITHMIC', 'exp', 'lin'), - if (hint == 'INTEGER', 1, 0), - def); - connections = IdentityDictionary.new; - } - jackConnect {|jackPort| - if (porttype.asSymbol != \AUDIO - || direction.asSymbol!=\OUTPUT) { - Error("Not a audio output port").throw - }; - ("jack_connect" + "Ingen:"++(this.path) + jackPort).unixCmd - } - value_ {|val| - if (porttype == \CONTROL and: {direction == \INPUT}) { - this.engine.sendReq("synth/set_port_value", nil, this.path, val) - } { - Error("Not a input control port"+this.path).throw - } - } - connectTo {|destPort| - if (this.direction!=destPort.direction) { - this.engine.connect(this,destPort) - } { - Error("Unable to connect ports with same direction").throw - } - } - - // Setters for OSC responders - prSetValue {|argValue| - if (value != argValue) { - value = argValue; - this.changed(\value, value) - } - } -} - -IngenNode : IngenObject { // Abstract class - var <ports, <polyphonic; - *new {|name,parent,poly| - ^super.new(name,parent).initNode(poly) - } - initNode {|argPoly| - polyphonic = argPoly; - ports = IdentityDictionary.new; - } - hasPort {|name| ^ports[name.asSymbol].notNil } - getPort {|name| ^ports[name.asSymbol] } - portArray {|type=\AUDIO,dir=\OUTPUT| - var result = Array.new(8); - ports.do {|port| - if (port.porttype==type and: {port.direction==dir}) { - result=result.add(port) - } - }; - ^result - } - audioOut { - ^this.portArray(\AUDIO, \OUTPUT) - } - audioIn { - ^this.portArray(\AUDIO, \INPUT) - } -} - -IngenInternalNode : IngenNode { - var <pluginlabel; - *new {|name,parent,poly,label| - ^super.new(name,parent,poly).initInternalNode(label) - } - initInternalNode {|label| - pluginlabel = label - } - noteOn { |note,vel| - if (pluginlabel == \note_in or: - {pluginlabel == \trigger_in and: {this.value == note}}) { - this.engine.sendReq("synth/note_on", nil, this.path, note, vel) - } { - Error("Not a trigger_in or note_in node").throw - } - } - noteOff {|note| - if (pluginlabel == \note_in or: - {pluginlabel == \trigger_in and: {this.value == note}}) { - this.engine.sendReq("synth/note_off", nil, this.path, note) - } { - Error("Not a trigger_in or note_in node").throw - } - } -} - -IngenLADSPANode : IngenNode { - var <pluginlabel, <libname; - *new {|name, parent, poly, label, lib| - ^super.new(name,parent,poly).initLADSPANode(label,lib) - } - initLADSPANode {|label,lib| - pluginlabel = label; - libname = lib - } -} - -IngenDSSINode : IngenLADSPANode { - var programs; - *new {|name,parent,poly,label,lib| - ^super.new(name,parent,poly,label,lib).initDSSI - } - initDSSI { - programs = Set.new; - } - program {|bank, prog| - this.engine.dssiMsg(this.path,"program",bank.asInteger,prog.asInteger) - } - prProgramAdd {|bank,program,name| - var info = (bank:bank, program:program, name:name); - if (programs.includes(info).not) { - programs.add(info); - this.changed(\programAdded, info) - } - } -} - -IngenPatch : IngenNode { - var <nodes, <patches, <poly, <enabled; - var om; - *new {|name,parent,engine| - ^super.new(name,parent).initPatch(engine); - } - initPatch {|argEngine| - nodes = IdentityDictionary.new; - patches = IdentityDictionary.new; - om = argEngine - } - hasNode {|name| - ^nodes[name.asSymbol].notNil - } - getNode {|name| - ^nodes[name.asSymbol] - } - hasPatch {|name| - ^patches[name.asSymbol].notNil - } - getPatch {|name,mustExist=false| - if (this.hasPatch(name).not) { - if (mustExist) { ^nil }; - patches[name.asSymbol] = IngenPatch(name,this); - }; - ^patches[name.asSymbol] - } - engine { - if (om.notNil) { ^om } { ^parent.engine }; - } - connect {|fromPort, toPort| - this.engine.connect(this.path++$/++fromPort, this.path++$/++toPort) - } - dumpX { - (String.fill(this.depth,$ )++"*"+this.path).postln; - nodes.do{|node| - (String.fill(node.depth,$ )++"**"+node.path).postln; - node.ports.do{|port| - (String.fill(port.depth,$ )++"***"+port.path).postln }; - }; - ports.do{|port| (String.fill(port.depth,$ )++"***"+port.path).postln }; - patches.do(_.dump) - } - noteOn {|note,vel| - var targetNode; - this.nodes.do{|node| - if (node.class == IngenInternalNode) { - node.pluginlabel.switch( - \trigger_in, { - if (node.ports['Note Number'].value == note) { - targetNode = node; - } - }, - \note_in, { - targetNode = node; - } - ) - } - }; - if (targetNode.notNil) { - targetNode.noteOn(note, vel) - } { - Error("Unable to find trigger_in for note "++note).throw - } - } - noteOff {|note| - var targetNode; - this.nodes.do{|node| - if (node.class == IngenInternalNode) { - node.pluginlabel.switch( - \trigger_in, { - if (node.ports['Note Number'].value == note) { - targetNode = node; - } - }, - \note_in, { - targetNode = node; - } - ) - } - }; - if (targetNode.notNil) { - targetNode.noteOff(note) - } { - Error("Unable to find node for note_off "++note).throw - } - } - newPatch {|name, poly=1, handler| - this.engine.createPatch(this.path++$/++name, poly, handler) - } - newNode {|name, poly=1, type, lib, label, fullname, handler| - var candidates = this.engine.matchPlugins(label,lib,fullname,type); - if (candidates.size == 1) { - candidates.pop.new(this.path++"/"++name, poly, handler) - } { - if (candidates.size==0) { - Error("Plugin not found").throw - } { - Error("Plugin info not unique").throw - } - } - } - - // Setters for OSC responders - prSetPoly {|argPoly| poly = argPoly } - prSetEnabled {|flag| - if (flag != enabled) { - enabled = flag; - this.changed(\enabled, flag) - } - } -} - - -IngenEmacsUI { - var engine, window, bootBtn; - *new {|engine| ^super.newCopyArgs(engine).init } - init { - window = EmacsBuffer("*Ingen -"+engine.addr.ip++$:++engine.addr.port); - bootBtn = EmacsButton(window, ["Boot","Quit"], {|value| - if (value==1) { - engine.boot - } { - engine.quit - } - }).value=engine.registered.binaryValue; - engine.addDependant(this); - window.front; - } - update {|who, what ... args| - Emacs.message(who.asString+what+args); - if (what == \newPatch or: {what == \newNode or: {what == \newPort}}) { - args[0].addDependant(this) - }; - } -} diff --git a/src/scripts/supercollider/README b/src/scripts/supercollider/README deleted file mode 100644 index 850bca6a..00000000 --- a/src/scripts/supercollider/README +++ /dev/null @@ -1,11 +0,0 @@ -Ingen bindings for SuperCollider ------------------------------ - -Installation: -Copy the Ingen.sc file into some directory in your SC class path and -reboot sclang. - -Usage: -See example.sc for inspiration. - - -- Mario Lang <mlang@delysid.org> diff --git a/src/scripts/supercollider/example.sc b/src/scripts/supercollider/example.sc deleted file mode 100644 index 80a72a7b..00000000 --- a/src/scripts/supercollider/example.sc +++ /dev/null @@ -1,27 +0,0 @@ -// Boot Ingen (inside SC) and the scsynth server -( -o=Ingen.boot { - o.loadPatch("/home/mlang/src/om-synth/src/clients/patches/303.om"); - s.boot; -} -) -// Connect patch output to one SC input -o.jackConnect("/303/output", "SuperCollider:in_3"); -// Play this input on the default output bus (most simple postprocessor) -{AudioIn.ar(3).dup}.play; -// A simple 303 pattern -( -Tempo.bpm=170; -Ppar([ - Pbind(\type, \om, \target, o.getPatch("/303",true), - \dur, 1/1, \octave,2,\degree, Pseq([Pshuf([0,2,4,6],16)],2)), - Pbind(\type, \om, \target, o.getPatch("/303",true), - \dur, Prand([Pshuf([1/2,1/4,1/4],4),Pshuf([1/3,1/3,1/6,1/6],4)],inf), - \legato, Prand((0.5,0.55..0.9),inf), - \octave,3,\degree, Pseq([Pshuf([0,2,4,6],2)],40)), - Pbind(\type, \om, \omcmd, \setPortValue, - \target, o.getPort("/303/cutoff",true), - \dur, 1/10, \portValue, Pseq((0,0.005..1).mirror,2)), - Pbind(\type, \om, \omcmd, \setPortValue, - \target, o.getPort("/303/resonance",true), \portValue, 1)]).play(quant:4) -) |