1 // see MIDIResponder help for all classes on this page
5 var <>function,<>swallowEvent=false,
6 <>matchEvent; // for matching ports, channels, and parameters
8 if(this.class.initialized.not,{ this.class.init });
9 matchEvent.port = matchEvent.port.asMIDIInPortUID;
10 if(install,{this.class.add(this);});
12 respond { arg src,chan,num,value;
13 if(this.match(src,chan,num,value),{
14 this.value(src,chan,num,value)
19 match { arg src,chan,num,value;
20 ^matchEvent.match(src,chan,num,value);
22 value { arg src,chan,a,b;
23 function.value(src, chan, a, b)
27 this.class.remove(this)
30 if(this == MIDIResponder,{
31 this.allSubclasses.do({ |responderClass| responderClass.removeAll })
40 NoteOnResponder : MIDIResponder {
41 classvar <norinit = false,<nonr;
43 *new { arg function, src, chan, num, veloc, install=true,swallowEvent=false;
44 ^super.new.function_(function)
45 .matchEvent_(MIDIEvent(nil, src, chan, num, veloc))
46 .swallowEvent_(swallowEvent)
49 *initialized { ^norinit }
52 if(MIDIClient.initialized.not,{ MIDIIn.connectAll });
54 MIDIIn.addFuncTo(\noteOn, { arg src, chan, note, veloc;
56 r.respond(src,chan,note,veloc)
64 nonr = nonr.add(resp);
71 oneShot = this.class.new({ |src,chan,num,value|
72 this.matchEvent_(MIDIEvent(nil,src,chan,nil,nil));
74 },nil,nil,nil,nil,true,true)
78 NoteOffResponder : NoteOnResponder {
79 classvar <noffinit = false,<noffr;
82 if(MIDIClient.initialized.not,{ MIDIIn.connectAll });
84 MIDIIn.addFuncTo(\noteOff, { arg src, chan, note, veloc;
86 r.respond(src,chan,note,veloc)
93 *initialized { ^noffinit }
94 *responders { ^noffr }
97 noffr = noffr.add(resp);
104 CCResponder : MIDIResponder {
105 classvar <ccinit = false,<ccr,<ccnumr;
107 *new { arg function, src, chan, num, value, install=true,swallowEvent=false;
108 ^super.new.function_(function).swallowEvent_(swallowEvent)
109 .matchEvent_(MIDIEvent(nil, src, chan, num, value))
112 *initialized { ^ccinit }
113 *responders { ^ccnumr.select(_.notNil).flat ++ ccr }
116 if(this.initialized.not,{ this.init });
117 if((temp = resp.matchEvent.ctlnum).isNumber) {
118 ccnumr[temp] = ccnumr[temp].add(resp);
125 if((temp = resp.matchEvent.ctlnum).isNumber) {
126 ccnumr[temp].remove(resp)
132 if(MIDIClient.initialized.not,{ MIDIIn.connectAll });
134 MIDIIn.addFuncTo(\control, { arg src,chan,num,val;
135 // first try cc num specific
136 // then try non-specific (matches any cc )
137 [ccnumr[num], ccr].any({ |stack|
138 stack.notNil and: {stack.any({ |r| r.respond(src,chan,num,val) })}
144 ccnumr = Array.newClear(128);
148 oneShot = CCResponder({ |src,chan,num,value|
149 this.matchEvent_(MIDIEvent(nil,src,chan,num,nil));
151 },nil,nil,nil,nil,true,true)
154 matchEvent_ { |midiEvent|
155 // if ctlnum changes from non-number to number, or vice versa,
156 // this responder is going to move between ccr and ccnumr
157 if(matchEvent.notNil and:
158 { matchEvent.ctlnum.isNumber !== midiEvent.ctlnum.isNumber })
161 matchEvent = midiEvent;
162 this.class.add(this);
164 matchEvent = midiEvent;
169 TouchResponder : MIDIResponder {
170 classvar <touchinit = false,<touchr;
172 *new { arg function, src, chan, value, install=true,swallowEvent=false;
173 ^super.new.function_(function).swallowEvent_(swallowEvent)
174 .matchEvent_(MIDIEvent(nil, src, chan, nil, value))
178 if(MIDIClient.initialized.not,{ MIDIIn.connectAll });
180 MIDIIn.addFuncTo(\touch, { arg src, chan, val;
182 r.respond(src,chan,nil,val)
189 value { arg src,chan,num,val;
191 function.value(src,chan,val);
193 *initialized { ^touchinit }
194 *responders { ^touchr }
197 touchr = touchr.add(resp);
204 oneShot = this.class.new({ |src,chan,num,value|
205 this.matchEvent_(MIDIEvent(nil,src,chan,nil,nil));
207 },nil,nil,nil,true,true)
211 BendResponder : TouchResponder {
212 classvar <bendinit = false,<bendr;
215 if(MIDIClient.initialized.not,{ MIDIIn.connectAll });
217 MIDIIn.addFuncTo(\bend, { arg src, chan, val;
219 r.respond(src,chan,nil,val)
226 *initialized { ^bendinit }
227 *responders { ^bendr }
230 bendr = bendr.add(resp);
239 the note on function would return an object which is stored.
240 when a matching note off event occurs, the object is passed into the note off function
246 ProgramChangeResponder : MIDIResponder {
247 classvar <pcinit = false,<pcr;
249 *new { arg function, src, chan, value, install=true;
250 ^super.new.function_(function)
251 .matchEvent_(MIDIEvent(nil, src.asMIDIInPortUID, chan, nil, value))
255 if(MIDIClient.initialized.not,{ MIDIIn.connectAll });
257 MIDIIn.addFuncTo(\program, { arg src, chan, val;
259 if(r.matchEvent.match(src, chan, nil, val))
260 { r.value(src,chan,val) };
267 value { arg src,chan,val;
268 function.value(src,chan,val);
270 *initialized { ^pcinit }