ヤマハミュージックデータショップから 購入したSMF(スタンダード・ミディ・ファイル)から歌詞のデータを取り出して 表示してみたいと思います。 歌詞のデータはXFというフォーマットに従ってSMFファイルの中に書き込まれています。 SMFフォーマットほ1991年に決まった仕様です。 こちらのページ からダウンロードできるMIDI1.0規格書の中に記載があります。
一方、XFフォーマットはヤマハの決めた仕様です。
こちらから
ダウンロードできる仕様書は2000年のV2.03となっています。
どちらも古い仕様ですが未だ使われています。
この両方を見ないと、歌詞を読み出すことができません。
SMFファイルはバイナリファイルです。テキストエディタでは開いても内容がわかりません、 バイナリエディタ、例えばvimエディタで開くことで中身が読めます。
> vim -b filename.mid : を押してコマンドモードに入り %!xxd
SMFファイルのいくつかのブロック(チャンクと言う)が書き込まれています。 チャンクの先頭は4つのキャラクタで、その後にチャンクのサイズが入っています。
MThd <length of header data>
<header data>
MTrk <length of track data>
<track data>
MTrk <length of track data>
<track data>
...
さて、XFデータははMTrkチャンクの後に以下のように入っています。
XFIH <length of XF information header>
<information header data>
XFKM <length of XF karaoke message>
<karaoke message data>
例えば、あるファイルを開いて見ると以下のようになっていました。
歌詞情報はkaraoke messageの中の0xFF 0x05の後に入っています。 karaoke messageは次の順に書き込まれています。 delta-timeは一つ前の歌詞から、ここで定義される歌詞を表示するまでの時間を示しています。
<delta-time> 0xFF 0x05 <length of charactor> text text ...
テキストはShift-JISでエンコードされています。ですので2バイトの文字と、1バイドの文字の場合があります。 次に例を示します。
オレンジ色はdelta-time, 黄色がキャラクタの数、赤文字がテキストです。赤文字の下にデコードした文字を書きます。
歌詞を表示する際、改行などの表示制御用の記号が歌詞のテキストの中に1バイト文字で 書き込まれています。
| 記号 | 意味 | 内容 |
|---|---|---|
| "(" ")" | よみがな | かっこ"("および")"で囲まれた文字列は"("の直前の一文字のよみがなを表す |
| "[" "]" | ルビ | "["の直前の一文字のよみがなを表す。よみがなと違って通常の読み方とはちがった読み方に使う |
| "^" | 空白 | スペースの代わりに用いられる |
| "/" | 改行 | 改行コードの代わりに用いられる |
| "%" | 副改行 | 一行内での文章の意味的な区切りをあらわす |
| "<" | 改頁 | 文字列の先頭に記載、新しいページの先頭から歌詞を表示させる |
| ">" | タブ | 水平タブを表す |
| "\" | バックスラッシュ | その後の1文字を制御機能として扱わない |
XFに記載されている文字はShift-JIS、これをブラウザに表示する時はUTF-8に 変換する必要があります。以下のコードはChat GPTに書いてもらいました。
<script src="https://cdnjs.cloudflare.com/ajax/libs/encoding-japanese/2.0.0/encoding.min.js"></script>
<script
// Shift-JISのバイナリデータ(Uint8Array)をUTF-8の文字列に変換
function convertShiftJISToUTF8(sjisArrayBuffer) {
// ArrayBuffer → Uint8Array に変換
const sjisBytes = new Uint8Array(sjisArrayBuffer);
// Shift-JIS → Unicode(内部的にUTF-16)に変換
const unicodeString = Encoding.convert(sjisBytes, {
to: 'UNICODE',
from: 'SJIS',
type: 'string'
});
// これで JavaScript の文字列(UTF-8扱い)として使える
// console.log(unicodeString);
return unicodeString;
}
</script>
SMFファイルを再生するSMFPlayerに歌詞表示を組み込んでみました。