{
   "labels" : [
      "midi",
      "tool",
      "recoder"
   ],
   "code" : "// requires SimpleMIDI from wslib quark\r\n\"wslib\".include;\r\n\r\nMIDIClient.init;\r\nMIDIIn.connectAll;\r\n\r\n/*\r\nMIDIFunc.trace; // show all MIDI messages coming in\r\nMIDIFunc.trace(false); // show all MIDI messages coming in\r\n*/\r\n\r\nq = ();\r\n\r\n(\r\n\r\nq.data = [];\r\n\r\n// an array of the form\r\n// [\r\n//  [ 0 , type, channel, val1, val2 ],\r\n//  [ dt, type, channel, val1, val2 ],\r\n//  ...\r\n// ]\r\n\r\nq.startTime = nil;\r\nq.responders = [\\noteOn, \\noteOff, \\polytouch, \\cc, \\program, \\touch, \\bend].collect{|msgType|\r\n\tMIDIFunc({|...args|\r\n\t\tvar time = Date.getDate.rawSeconds;\r\n\t\tvar val, ctlNum, chan, src;\r\n\r\n\t\tmsgType.postln;\r\n\t\t// handle arguments for different msgTypes\r\n\t\t[\\noteOn, \\noteOff, \\control, \\polytouch ].includes(msgType).if({\r\n\t\t\t# val, ctlNum, chan, src = args;\r\n\t\t\targs.postln;\r\n\t\t},{\r\n\t\t\t# val, chan, src = args;\r\n\t\t});\r\n\r\n\r\n\t\t// correct message type to correspond to SimpleMIDIFile format\r\n\t\t// [msgType, val, ctlNum, chan, src].postln;\r\n\r\n\t\t// for first element, set startTime to current raw seconds\r\n\t\tq.startTime.isNil.if({\r\n\t\t\tq.startTime = time;\r\n\t\t});\r\n\r\n\t\t// for each MIDI message, write an array to data:\r\n\t\tq.data = q.data.add(\r\n\t\t\t// [ time, type, channel, val1, val2 ]\r\n\t\t\tctlNum.notNil.if({\r\n\t\t\t\t[ time - q.startTime, msgType, chan, ctlNum, val ]\r\n\t\t\t}, {\r\n\t\t\t\t[ time - q.startTime, msgType, chan, val]\r\n\t\t\t})\r\n\t\t);\r\n\t}, msgType: (msgType == \\cc).if({\\control}, {msgType});\r\n\t)\r\n}\r\n)\r\n\r\n\r\n// all your data\r\n// belongs to us\r\nq.data.printAll;\r\n\r\n// write data to MIDI file (requires wslib)\r\nq.writeData = {\r\n\tvar filePath = thisProcess.nowExecutingPath.dirname +/+ \"MIDI-%.mid\".format(Date.getDate.stamp);\r\n\tvar mFile = SimpleMIDIFile( filePath ); // create empty file\r\n\r\n\tmFile.init1( 1, 120, \"4/4\" );\t// init for type 1 (multitrack); 3 tracks, 120bpm, 4/4 measures\r\n\tmFile.timeMode = \\seconds;  // change from default to something useful\r\n\t// m.pitchBendMode = ??? TODO\r\n\tmFile.addAllMIDIEvents(\r\n\t\tq.data.collect{|row| [0] ++ row }, true\r\n\t);\r\n\tmFile.adjustEndOfTrack;\r\n\r\n\t// mFile.midiEvents.dopostln; // all midi events\r\n\t// mFile.metaEvents.dopostln; // notice the incorrect 'endOfTrack' events for track 1 & 2;\r\n\r\n\tmFile.write(filePath)\r\n}\r\n\r\n////////////////////// WRITE DATA\r\n\r\n\r\nq.writeData\r\n// after usage, remove responders\r\nq.responders.do(_.free)\r\n\r\n\r\n////////////////////// TEST\r\n\r\n/*\r\nMIDIClient.destinations; // list array of destinations\r\n*/\r\n\r\nm = MIDIOut(0);\r\nm.connect\r\nm.latency = 0\r\n\r\n\r\nm.control(chan: 1, ctlNum: 2, val: 127.rand);\r\nm.noteOn(16, 127.rand, 128.rand);\r\nm.noteOff(16, 61, 60);\r\nm.allNotesOff(16);",
   "is_private" : null,
   "id" : "1-5bv",
   "name" : "MIDI value recorder",
   "author" : "LFSaw",
   "description" : "simple MIDI data recorder. records MIDI into an array. Save data as \".mid\" file (readable e.g. by Ableton Live).",
   "ancestor_list" : []
}
