groovyでmidi演奏
MIDIライブラリ。CORBAとともに削除してほしい、モジュラーJREの登場後はぜひとも読み込まれてほしくないAPIナンバーワン
http://journal.mycom.co.jp/news/2009/04/22/018/index.html
不要No1がCORBAなのは同意だけど、midiを同列にするとは。こんな楽しいものを削除しようとするとは。。。
midi APIがjavaで使うのは面倒だけど、groovyからつかうとかなり簡略化されます。
以下は、さくらさくら(の一部)を演奏するプログラム:
import javax.sound.midi.* // compose sequence ticks = 16 // compose utils def addNote(track, pitch, start, duration=ticks, velocity=64) { // pitch: C=60, D=62, E=64, F=65, G=67, A=69, B=71, ... // start: absolute time // duration: 1/4 = ticks // velocity: 0 <= soft < 64 < hard <= 127 // returns: end time message = new ShortMessage() message.setMessage(ShortMessage.NOTE_ON, pitch, velocity) track.add(new MidiEvent(message, start)) message = new ShortMessage() message.setMessage(ShortMessage.NOTE_OFF, pitch, velocity) track.add(new MidiEvent(message, start + duration)) return start + duration } def instChange(track, instNo=0) { // instNo: 0-127, default 0 message = new ShortMessage() message.setMessage(ShortMessage.PROGRAM_CHANGE, 0, instNo, 0) track.add(new MidiEvent(message, 0)) } C1=60; D1=62; E1=64; F1=65; G1=67; A1=69; B1=71; C2=72 d1=ticks*4; d2=ticks*2; d4=ticks; d8=ticks/2 as int score = [ [A1, d4], [A1, d4], [B1, d2], [A1, d4], [A1, d4], [B1, d2], [A1, d4], [B1, d4], [C2, d4], [B1, d4], [A1, d4], [B1, d8], [A1, d8], [F1, d2], ] // edit track seq = new Sequence(Sequence.PPQ, ticks) track = seq.createTrack() instChange(track, 107) t = 0 score.each { pitch, duration -> t = addNote(track, pitch, t, duration) } // play seqr = MidiSystem.sequencer seqr.tempoInBPM = 72.0 seqr.sequence = seq seqr.open() seqr.start() while (seqr.isRunning()) Thread.sleep(1000) seqr.close()
groovyだと、mainクラスや変数型や例外処理が不要、getter/setter経由のアクセス、デフォルト変数やクロージャなどでだいぶすっきりかけます。groovyの大きな難点は int/intがBigDecimalになってしまい、intにキャストする必要がある点だろうか。
上記コードではinstは107と適当に設定してます。inst番号と種類の一覧は以下のようなコードで出せるかも
import javax.sound.midi.* seqr = MidiSystem.sequencer seqr.open() // list insts synth = MidiSystem.synthesizer println synth.deviceInfo.name sb = synth.getDefaultSoundbank() if (sb) { println sb.name sb.instruments.each {println "${it.patch.program} : ${it.name}" } } seqr.close()
midiは初心者にもとりつきやすい機能だと思うんですけどね。