yuyu2midi.py - ゆゆシーケンサーの「ゆゆシケ・コード」を歌詞付きMIDIファイルにする
の「ゆゆシケ・コード」を VOCALOID2/3 Editor でインポートできる歌詞付きMIDIファイルにする Python スクリプトです。
Python 2.6 で使用してください。(Python 3.x は不可)
使い方
- Python をインストール(やり方は適当にぐぐって)
- 下のソースを BOM付き utf-8 で「vsqx2midi.py」という名前で保存 (メモ帳で文字コード「utf-8」にして保存すればOK)
- そのファイルを右クリックして「Edit with IDLE」を選択
- 「ゆゆシケ・コード」を「hoge.txt」という名前のテキストファイルとして保存
- IDLE で [F5] を押して Python スクリプトを実行
- 「hoge.mid」という名前で MIDI ができるので VOCALOID2/3 Editor でインポート
- 各トラック毎に「歌詞→発音記号変換」をする ※重要
u'''yuyu2midi - ゆゆシーケンサの「ゆゆシケ・コード」を歌詞付きMIDIファイルにする ''' __author__ = 'kadotanimitsuru' __version__='1.0.0' import struct FILENAME = 'hoge' # ファイル名 MIDIBASE = 58 # 基準になるMIDIノートナンバー # No.,音階・コード,構成音,ゆゆシケ・コード SOLO = u'''0,休符,-,0,ん 1,B,B,1,し 2,C,C,2,ど 3,C#,C#,E,ど 4,D,D,3,れ 5,D#,D#,F,れ 6,E,E,4,み 7,F,F,5,ふぁ 8,F#,F#,G,ふぁ 9,G,G,6,そ 10,G#,G#,H,そ 11,A,A,7,ら 12,A#,A#,I,ら 13,B↑,B↑,8,し 14,C↑,C↑,9,ど 15,C#↑,C#↑,J,ど 16,D↑,D↑,A,れ 17,D#↑,D#↑,K,れ 18,E↑,E↑,B,み 19,F↑,F↑,C,ふぁ 20,F#↑,F#↑,L,ふぁ 21,G↑,G↑,D,そ 22,G#↑,G#↑,M,そ''' Solo = {} for i in SOLO.split('\n'): noteno, scale, chord, yuyu, name = i.split(',') Solo[yuyu] = (int(noteno), scale, chord, name) CHORUS = u'''0,休符,-,0 1,Bm-5,B・D・F,1 2,C,C・E・G,2 3,Dm,D・F・A,3 4,Em,E・G・B↑,4 5,F,F・A・C↑,5 6,G,G・B↑・D↑,6 7,Am,A・C↑・E↑,7 8,Bm-5↑,B↑・D↑・F↑,8 9,C↑,C↑・E↑・G↑,9 10,Bm,B・D・F#,A 11,Cm,C・Eb・G,B 12,D,D・F#・A,C 13,E,E・G#・B↑,D 14,Fm,F・Ab・C↑,E 15,Gm,G・Bb↑・D↑,F 16,A,A・C#↑・E↑,G 17,Bm↑,B↑・D↑・F#↑,H 18,Cm↑,C↑・Eb↑・G↑,I 19,B,B・D#・F#,J 20,B↑,B・D#・F#,K 21,C#,C#・F・G#,L 22,D#m,D#・F#・A#,M 23,F#,F#・A#・C#↑,N 24,G#,G#・C↑・D#↑,O 25,A#m,A#・C#↑・F↑,P 26,C#↑,C#↑・F↑・G#↑,Q 27,C#m,C#・E・G#,R 28,D#,D#・G・A#,S 29,F#m,F#・A・C#↑,T 30,G#m,G#・B↑・D#↑,U 31,A#,A#・D↑・F↑,V 32,C#m↑,C#↑・E↑・G#↑,W''' Chorus = {} for i in CHORUS.split('\n'): no, scale, chord, yuyu = i.split(',') if yuyu == '0': Chorus[yuyu] = [0, 0, 0] continue notes = [] for n in chord.split(u'・'): note = 0 if n[-1] == u'↑': note += 12 n = n[0:-1] note += ' BC D EF G A'.find(n[0]) n = n[1:] if n: if n == '#': note += 1 elif n == 'b': note -= 1 else: raise ValueError(n) notes.append(note) Chorus[yuyu] = notes def chrs(s): return ''.join([chr(x) for x in s]) def i2(v): if v > 0xffff: raise ValueError(v) return struct.pack('>H', v) def i4(v): if v > 0xffffffff: raise ValueError(v) return struct.pack('>I', v) def delta(v): if v < 0: raise ValueError(v) a = [] while True: if v <= 0x7f: a.append(v) break else: a.append(v % 0x80) v //= 0x80 a.reverse() return ''.join([chr(x + 0x80) for x in a[0:-1]] + [chr(a[-1])]) def noteon(ch, nn, vel): return chr(0x90 + ch) + chr(nn) + chr(vel) def noteoff(ch, nn): return chr(0x80 + ch) + chr(nn) + chr(0) def lyrics(lyric): s = lyric.encode('shift-jis', 'replace') return '\xff\x05' + chr(len(s)) + s def trackname(name): s = name.encode('shift-jis', 'replace') return '\xff\x03' + chr(len(s)) + s def makemaintrack(yuyudata, ch): ch %= 16 # 16トラックを超えたら 0 に戻る notelen = 480 midi = [delta(0) + trackname(u'main')] tick = 0 for i in yuyudata: noteno, scale, chord, name = Solo[i] if noteno: midi.append( delta(tick) + lyrics(name) + delta(0) + noteon(ch, MIDIBASE + noteno, 64) + delta(notelen) + noteoff(ch, MIDIBASE + noteno)) tick = 0 else: tick += notelen data = ''.join(midi) + delta(0) + chrs([0xff, 0x2f, 0]) return 'MTrk' + i4(len(data)) + data def makechorustrack(notes, ch): ch %= 16 # 16トラックを超えたら 0 に戻る notelen = 480 midi = [delta(0) + trackname(u'chorus')] tick = 0 for n in notes: if n: midi.append( delta(tick) + lyrics(u'ら') + delta(0) + noteon(ch, MIDIBASE + n, 64) + delta(notelen) + noteoff(ch, MIDIBASE + n)) tick = 0 else: tick += notelen data = ''.join(midi) + delta(0) + chrs([0xff, 0x2f, 0]) return 'MTrk' + i4(len(data)) + data def makeconductor(): data = delta(0) + trackname(u'Conductor') + delta(0) + '\xff\x2f\x00' return 'MTrk' + i4(len(data)) + data def makemidifile(yuyudata): if yuyudata.startswith('YuyuSeqPlusCode'): data = yuyudata[len('YuyuSeqPlusCode'):] elif yuyudata.startswith('YuyuSeqCode'): data = yuyudata[len('YuyuSeqCode'):] else: ValueError(yuyudata) main, chorus = data.split('AngelCode') chorus, tempo = chorus.split('Tempo') print 'Tempo:', tempo tracks = [makeconductor()] tracks.append(makemaintrack(main, 0)) c1 = [] c2 = [] c3 = [] for i in chorus: a, b, c = Chorus[i] c1.append(a) c2.append(b) c3.append(c) tracks.append(makechorustrack(c1, 1)) tracks.append(makechorustrack(c2, 1)) tracks.append(makechorustrack(c3, 1)) header = 'MThd' + i4(6) + i2(1) + i2(len(tracks)) + i2(480) return header + ''.join(tracks) f = open(FILENAME + '.txt') text = f.read().strip() f.close() midi = makemidifile(unicode(text)) f = open(FILENAME + '.mid', 'wb') f.write(midi) f.close() ## パブリックドメイン。好きに流用してください
テンポには対応していません*1ので、自前で指定してください。
UTAUでも読み込めますが、テンポ情報が無いMIDIを演奏するとゼロ除算エラーが出るようですので、UTAUでは先にテンポを指定してから演奏してください。