// to use the sc pattern system with eventstreams that send to the midiout
// this parent event can be used for that:

(
f = (
	noteOn:  #{ arg chan=0, midinote=1, amp=0.1;
							[chan, midinote, asInteger((amp * 127).clip(0, 127)) ]
						},
   	noteOff: #{ arg chan=0, midinote=1, amp=0.1;
							[ chan, midinote, asInteger((amp * 127).clip(0, 127)) ]
						},
  	polyTouch: #{ arg chan=0, midinote=1, polyTouch=125;
							[ chan, midinote, polyTouch ]
						},
   	control: #{ arg chan=0, ctlNum, control=125;
							[chan, ctlNum, control ]
						},
   	program:  #{ arg chan=0, progNum=1;
							[ chan, progNum ]
						},
	touch:  #{ arg chan=0, val=125;
							[ chan, val ]
						},
	bend:  #{ arg chan=0, val=125;
							[ chan, val ]
						},
	allNotesOff: #{ arg chan=0; 
							[chan] 
						},
	smpte:	#{ arg frames=0, seconds=0, minutes=0, hours=0, frameRate=25;
							[frames, seconds, minutes, hours, frameRate]
						},
	songPtr: #{ arg songPtr; 
							[songPtr] 
						},
	sysex: #{ arg uid, array;
							[uid, array] // Int8Array
						}
 );
	
/*
	also possible (without arguments):
	
	midiClock (  )
	startClock (  )
	continueClock (  )
	stopClock (  )
	reset (  )

*/

e =  #{
					var freqs, lag, dur, sustain, strum;
					var tempo, bndl, midiout, hasHate, midicmd;
					
					freqs = ~freq = ~freq.value + ~detune;
					
					tempo = ~tempo;
					if (tempo.notNil) {
						thisThread.clock.tempo = tempo;
					};
									
					if (freqs.isKindOf(Symbol).not) {
						~finish.value;
						~amp = ~amp.value;
						strum = ~strum;
						lag = ~lag;
						sustain = ~sustain = ~sustain.value;
						midiout = ~midiout;
						hasHate = ~hasGate ? true;
						midicmd = ~midicmd ? \noteOn;
						bndl =  f[midicmd].valueEnvir.asCollection;
						
						bndl = bndl.flop;
						
						bndl.do {|msgArgs, i|
								var latency;
								
								latency = i * strum + lag;
								
								if(latency == 0.0) {
									midiout.performList(midicmd, msgArgs)
								} {
									thisThread.clock.sched(latency, {
										midiout.performList(midicmd, msgArgs);
									})
								};
								if(hasHate and: { midicmd === \noteOn }) {
									thisThread.clock.sched(sustain, { 
										midiout.noteOff(*msgArgs)
									});
								};
						};
						}
};
			
Event.partialEvents.playerEvent.eventTypes[\midi] = e;
);

// test for midiless people
(
m = (forward: { arg ... args; args[1..].postln })
)

// for midi-havers : initialize midiout
(
MIDIClient.init;
m = MIDIOut(0, MIDIClient.destinations.at(0).uid);
)

m.allNotesOff;

(
Pbind(
	\type, \midi,
	\midiout, m,
	\midinote, Pseq([70, [74, 64, 67], 76], inf),
	\dur, Prand([0.25, 0.25],inf), 
	\amp, Prand([0.3, 0.6], inf),
	\strum,  Prand([0, 0.05], inf)
).play;
)

(
Pbind(
	\type, \midi,
	\midiout, m,
	\midicmd, \bend,
	\val, Pfunc({ [0, { 156.rand }].choose.value }),
	\dur, 1.5
).play;
)