#!/usr/bin/env kawa (import (class java.io File)) (import (class javax.sound.midi MidiSystem)) (define in-file ::String (cadr (command-line))) (define midi (MidiSystem:getSequence (File in-file))) (define tracks (midi:getTracks)) (define (bytes->u8vector (bytes ::byte[])) (let ((u8 (make-u8vector bytes:length))) (do ((i 0 (+ i 1))) ((>= i bytes:length)) (u8vector-set! u8 i (bitwise-and (bytes i) #xFF))) u8)) (define (midi-data->list u8) (if (= (u8vector-length u8) 3) (let* ((status (u8vector-ref u8 0)) (data1 (u8vector-ref u8 1)) (data2 (u8vector-ref u8 2)) (type (bitwise-bit-field status 4 8)) (channel (bitwise-bit-field status 0 4))) (case type ((#b1000) `(note-off (channel . ,channel) (key . ,data1) (velocity . ,data2))) ((#b1001) `(note-on (channel . ,channel) (key . ,data1) (velocity . ,data2))) ((#b1010) `(poly-key-pressure (channel . ,channel) (key . ,data1) (pressure . ,data2))) ((#b1011) `(controller-change (channel . ,channel) (controller . ,data1) (value . ,data2))) ((#b1100) `(program-change (channel . ,channel) (preset . ,data1))) ((#b1101) `(channel-pressure (channel . ,channel) (pressure . ,data1))) ((#b1110) `(pitch-bend (channel . ,channel) (coarse . ,data1) (fine . ,data2))) (else `(unknown (type . ,type) (channel . ,channel) (data1 . ,data1) (data2 . ,data2))))) `(unknown (data . ,(u8vector->list u8))))) (do ((i 0 (+ i 1))) ((>= i tracks:length)) (display (format "Track ~d:\n" i)) (let ((track (tracks i))) (do ((j 0 (+ j 1))) ((>= j (track:size))) (display (format "Event ~d: " j)) (let* ((event (track:get j)) (message (event:getMessage))) (display (format "Message ~a at ~d\n" (midi-data->list (bytes->u8vector (message:getMessage))) (event:getTick)))))))