lyric39.py - ポケット・ミクにテキストファイルの歌詞を歌わす。 #大人の科学ポケミク

D
Python 2.7.6 + Pygame 1.9.1 用

それと

から「IPA P明朝」を入手してスクリプトと同じフォルダに置いてください。

u'''lyric39.py - ポケミクにテキストの歌詞を歌わせる。

lyrics.txt という名のテキストファイルの歌詞を歌います。
ユーザーズマニュアル裏表紙の「デフォルト文字テーブル」の
「発音」「備考」にある語で歌詞を入れてください。
'''
import codecs
import pygame
import pygame.midi
from pygame.locals import *

FILENAME = 'lyrics.txt' # 読み込む歌詞テキスト(utf-8)
FONTFILE = 'ipamp.ttf'  # 使用する日本語TTFフォントファイル名
                        # このスクリプトと同じフォルダに入れる。

WIDTH, HEIGHT = 256, 128  # 画面の大きさ
COLOR = 0, 255, 200  # 文字色
BG_COLOR = 100, 0, 50  # 背景色
FONT_SIZE = HEIGHT
FPS = 60

## デフォルト文字テーブル
c = u'''
あ い う え お
か き く け こ
が ぎ ぐ げ ご
きゃ きゅ きょ
ぎゃ ぎゅ ぎょ
さ すぃ す せ そ
ざ ずぃ ず ぜ ぞ
しゃ し しゅ しぇ しょ
じゃ じ じゅ じぇ じょ
た てぃ とぅ て と
だ でぃ どぅ で ど
てゅ でゅ
ちゃ ち ちゅ ちぇ ちょ
つぁ つぃ つ つぇ つぉ
な に ぬ ね の
にゃ にゅ にょ
は ひ ふ へ ほ
ば び ぶ べ ぼ
ぱ ぴ ぷ ぺ ぽ
ひゃ ひゅ ひょ
びゃ びゅ びょ
ぴゃ ぴゅ ぴょ
ふぁ ふぃ ふゅ ふぇ ふぉ
ま み む め も
みゃ みゅ みょ
や ゆ よ
ら り る れ ろ
りゃ りゅ りょ
わ うぃ うぇ うぉ ん'''.strip().split()
CTABLE = dict([(text, i) for i, text in enumerate(c)])
CTABLE.update(dict([(text, i) for i, text in
               enumerate(u'づぁ づぃ づ づぇ づぉ'.split(), 0x1A)]))
CTABLE.update(dict([(text, i) for i, text in
               enumerate(u'ゐ ゑ を N\\ m N J n'.split(), 0x78)]))

def get_lyrics(filename):
    try:
        f = codecs.open(filename, encoding='utf_8_sig')
        t = f.read()
    except UnicodeDecodeError:
        f = codecs.open(filename, encoding='mbcs')
        t = f.read()
    f.close()
    print t
    lyrics = []
    while t:
        t = t.strip()
        c = t[:2]
        try:
            n = CTABLE[c]
            lyrics.append((c, n))
            t = t[2:]
        except KeyError:
            try:
                c = t[0]
                n = CTABLE[c]
                lyrics.append((c, n))
            except KeyError:
                print u'この文字は使えません:', c
            t = t[1:]
    return lyrics

def set_lyric(output, lyric):
    output.write_sys_ex(
        0, [0xF0, 0x43, 0x79, 0x09, 0x11, 0x0A, 0x00, lyric, 0xF7])

def set_lyric_endlless(output, lyrics, lyric_point):
    lyric_text, lyric_no = lyrics[lyric_point]
    set_lyric(output, lyric_no)
    lyric_point += 1
    if lyric_point >= len(lyrics):
        lyric_point = 0
    return lyric_point, lyric_text, lyric_no
    
def main():
    pygame.init()
    pygame.midi.init()
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    pygame.display.set_caption('lyric39.py')
    font = pygame.font.Font(FONTFILE, FONT_SIZE)
    for i in range(pygame.midi.get_count()):
        interf, name, input, output, opened = pygame.midi.get_device_info(i)
        if output and name == 'NSX-39 ':
            midiout = pygame.midi.Output(i)
        if input and name == 'NSX-39 ':
            midiin = pygame.midi.Input(i)
    lyrics = get_lyrics(FILENAME)
    lyric_point, lyric_text, lyric_no = set_lyric_endlless(
        midiout, lyrics, 0)
    text = lyric_text
    print lyric_text
    clock = pygame.time.Clock()
    clock.tick(FPS)
    while True:
        for e in pygame.event.get():
            if e.type is QUIT:
                return
            elif e.type is KEYDOWN and e.key is K_ESCAPE:
                return
        if midiin.poll():
            for e in midiin.read(1000):
                data, timestamp = e
                if (data[0] & 0xF0) == 0x90: # Note On
                    lyric_point, lyric_text, lyric_no = set_lyric_endlless(
                        midiout, lyrics, lyric_point)
                    next_text = lyric_text
                    print lyric_text
                if (data[0] & 0xF0) == 0x80: # Note Off
                    text = next_text
        screen.fill(BG_COLOR)
        s = font.render(text, True, COLOR)
        screen.blit(font.render(
            text, True, COLOR), ((WIDTH - s.get_width()) // 2, 0))
        clock.tick(FPS)
        pygame.display.flip()

if  __name__ == '__main__':
    try:
        main()
    finally:
        pygame.quit()

# Public Domain. 好きに流用してください。