«MIDI value recorder» by LFSaw
on 12 Mar'19 22:36 insimple MIDI data recorder. records MIDI into an array. Save data as ".mid" file (readable e.g. by Ableton Live).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
// requires SimpleMIDI from wslib quark "wslib".include; MIDIClient.init; MIDIIn.connectAll; /* MIDIFunc.trace; // show all MIDI messages coming in MIDIFunc.trace(false); // show all MIDI messages coming in */ q = (); ( q.data = []; // an array of the form // [ // [ 0 , type, channel, val1, val2 ], // [ dt, type, channel, val1, val2 ], // ... // ] q.startTime = nil; q.responders = [\noteOn, \noteOff, \polytouch, \cc, \program, \touch, \bend].collect{|msgType| MIDIFunc({|...args| var time = Date.getDate.rawSeconds; var val, ctlNum, chan, src; msgType.postln; // handle arguments for different msgTypes [\noteOn, \noteOff, \control, \polytouch ].includes(msgType).if({ # val, ctlNum, chan, src = args; args.postln; },{ # val, chan, src = args; }); // correct message type to correspond to SimpleMIDIFile format // [msgType, val, ctlNum, chan, src].postln; // for first element, set startTime to current raw seconds q.startTime.isNil.if({ q.startTime = time; }); // for each MIDI message, write an array to data: q.data = q.data.add( // [ time, type, channel, val1, val2 ] ctlNum.notNil.if({ [ time - q.startTime, msgType, chan, ctlNum, val ] }, { [ time - q.startTime, msgType, chan, val] }) ); }, msgType: (msgType == \cc).if({\control}, {msgType}); ) } ) // all your data // belongs to us q.data.printAll; // write data to MIDI file (requires wslib) q.writeData = { var filePath = thisProcess.nowExecutingPath.dirname +/+ "MIDI-%.mid".format(Date.getDate.stamp); var mFile = SimpleMIDIFile( filePath ); // create empty file mFile.init1( 1, 120, "4/4" ); // init for type 1 (multitrack); 3 tracks, 120bpm, 4/4 measures mFile.timeMode = \seconds; // change from default to something useful // m.pitchBendMode = ??? TODO mFile.addAllMIDIEvents( q.data.collect{|row| [0] ++ row }, true ); mFile.adjustEndOfTrack; // mFile.midiEvents.dopostln; // all midi events // mFile.metaEvents.dopostln; // notice the incorrect 'endOfTrack' events for track 1 & 2; mFile.write(filePath) } ////////////////////// WRITE DATA q.writeData // after usage, remove responders q.responders.do(_.free) ////////////////////// TEST /* MIDIClient.destinations; // list array of destinations */ m = MIDIOut(0); m.connect m.latency = 0 m.control(chan: 1, ctlNum: 2, val: 127.rand); m.noteOn(16, 127.rand, 128.rand); m.noteOff(16, 61, 60); m.allNotesOff(16);
reception
Thanks for this!