アセンブリを読まずに音楽シーケンスを解析する方法

私はNDSのSSEQ向けツールを作成する際、当初アセンブリを読むことはおろかエミュレータを使うこともなく音楽シーケンスを探してデータを解析しました。ここではその解析ノウハウを紹介します。
なお、本文を読む前に、詳説MIDI規格などを読み、SMFの構造を少し理解しておくことをおすすめします。MIDI制作に触れたことがなければ、Cherryなどのシーケンサで人遊びしてみるといいかもしれません。また、本書ではコマンドによる操作を必要とします。難しい操作ではないので詳細な解説はしてありません。覚えておくと今後役立つことは間違いないので、コマンドプロンプトを使ってみよう!などでコマンド操作を覚えておくことをおすすめします。
また、採譜作業が必要になるので、(相対)音感がある方が簡単に作業が進められます。音感鑑定で遊んだりツールを探したりして、何らかの方法で採譜ができるようにしましょう。

ターゲットの決定と準備

まずは解析したいゲームと、解析に必要なツールを把握し、準備する必要があります。今回は、私の好きなゲームである「魔導物語 はなまる大幼稚園児(Madou Monogatari - BIG Kindergarten Kids)」をターゲットにします。このゲームの音楽はSPC700だけでは動作しないため、ターゲットとしては少々不適切です。しかし、動作可能なSPCファイルがSNESmusicに存在するため、今回はこの問題を無視することにします。
当然ながら、あなたは解析したいゲームのデータ(ROM、音楽データ)とエミュレータ(音楽プレーヤ)を用意しなければなりません。今回の場合は、SNES SPC700 Playerと、SPC700のサウンドステートファイル(*.spc)を利用することにします。今回はまず「ももんがでひこう(Flying Squirrel)」を解析することにします(選曲については後述)。
そして、解析を行うのに欠かせないのが、StirlingBzなどのヘキサエディタ(バイナリエディタ)です。あなたにとって使いやすいエディタを探し、基本的な使い方を学んでおいてください(参考: バイナリエディタの使い方)。また、今回は使用されませんが、ワイルドカード検索ができるエディタであるXVI32kasatは、普段用いるエディタとは別に用意しておいて損はありません。そして、本書ではdeltaというデータ検索補助のためのツールを用います。このプログラムは至ってシンプルなものですが、意外と強力です。詳細は後述します。

解析しやすい曲の選曲

さっそく自分のお気に入りの曲から解析したいところですが、楽に結果を得るためにも選曲を間違わないことは必要だと思います。本書の方法で解析しやすい曲は次のようなフレーズを持つ曲です。

  • 同じ間隔(音符)でリズムを刻んでいて、休符が出現しない
  • 多少音符ごとに音程が変化するが、音程差は大きくない(1オクターブ以内推奨)
  • 音符ごとの音量、その他の音の変化がない

今回はこれらを満たす「ももんがでひこう(Flying Squirrel)」をターゲットにします。チャンネル1(Bass)をソロにすると、あなたは休符(rest)のない、4分音符(note)のパターンを聴くことができます。MMLで書けば「l4o1bbbbbbbbbbbbaaa」といった感じです。このパターンを元に、まずは音符のデータを探してみましょう。

delta - 連続変化を持つデータの検索補助

本書ではdeltaというプログラムを用います。このプログラムによる入出力の例を以下に示します。

delta 1 <input> <output>
input : 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
output: 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01

delta 2 <input> <output>
input : 00 FF 01 FE 02 FD 03 FC 04 FB 05 FA 06 F9 07 F8
output: 00 FF 01 FF 01 FF 01 FF 01 FF 01 FF 01 FF 01 FF

連続的な変化が定数に置き換わるため、高度な検索機能を有しないエディタにおいても、連続変化を持つデータを検索できるようになります。

音符を探す

前章で解析のしやすそうなフレーズを見つけました。「l4o1bbbbbbbbbbbbaaa」つまり、四分音符によるシとラの音の連続です(文章でフレーズについて表現するのは難しい)。音程の表現にはいろいろありますが、たいていはMIDIのようにノート番号を用います(ただしMIDIのものと共通とは限らない)。そこで、相対的な音程の変化を元にデータを探す方法を考えます。
まずは音程の変化を定数に置き換えるためにdeltaを使用します。「ノート番号が何バイトごとに記録されているか」に応じて最初の定数を書き換える必要がありますが、サイズを抑えたいSNESのようなゲーム機であれば、たいていは1でいいと思われます。

delta 1 mam-11.spc mam-11.spc.1

mam-11.spc.1ファイルが生成されます。説明の理解を促すため、この操作でどのようなデータが出力されたのかを示します。

before: 23 E5 23 23 23 23 23 23 23 23 23 23 23 21 21 21
after : 40 C2 3E 00 00 00 00 00 00 00 00 00 00 FE 00 00

deltaをかけたデータに対し、音程の相対的な変化(最初の音符は付加情報が多いため除外)である「00 00 00 00 00 00 00 00 00 00 FE 00 00」で検索すれば、3CD4にあるノートにたどり着けることがわかるでしょうか。場合によっては検索結果が複数あることもあるでしょう。そこで、本当にノートを発見したことを確認するために、SPCファイルのデータ列を書き換えてみましょう。一例を以下に示します。

before:23 23 23 23 23 23 23 23 23 23 21 21 21
after :23 23 23 25 27 28 27 25 23 25 21 21 21

再生してみると、曲頭のベースの音が変化しているのが確認できると思います。
この方法で発見できない場合は、ノート番号が1バイトごとに連続していない可能性があります。

ノート番号が1バイトごとに連続していない場合

ノート番号が1バイトごとに連続していない場合も当然あります。たとえば、次のようなデータです。

23 E5 64 23 65 23 66 23 67 21 68 21 69 21 6A

この場合、ノート番号の間隔は2バイトなので、間隔2でdeltaを使用します。

delta 2 sample.bin sample.bin.2

すると、このようなデータが出力されます。

?? ?? 41 3E 01 00 01 00 01 FE 01 00 01 00 01

ノート番号の間にそれ以外のデータが含まれるため、定数検索で発見することはできません。このような場合に、ワイルドカードで検索できるkasatを用います。

0,*,0,*,-1,*,0,*,0

上記のパターンで検索すれば、該当部分が見つけられると思います。
これでも当該データがうまく発見できない場合、対象とするフレーズを変えるか、これとは異なる方法でデータを探す必要があります。どのような方法を用いれば簡単確実にデータが発見できるかはパズルのようなもので、発想力の勝負なのであります。

音楽シーケンスにありがちなこと

音楽シーケンスにありがちなパターンを紹介します。

  • 音程データの近くを探すと、音長(デュレーション)が見つかる
  • 音量・定位・プログラムチェンジ・ビブラートなどのコマンドがある
  • ループの実現やサイズ節約のため、繰り返しやジャンプ、サブルーチンジャンプのコマンドがある

たとえば今回の例であれば、連続する23以前のE5がデュレーションに相当するものであり、ここをE3などに書き換えると音符の長さが変化します。本書の方法ではとにかくデータを書き換えて確認することが重要です。

おわりに

いかに「簡単な方法」とはいえ、やはり2進数や16進数の世界なので、わかりやすい説明を行うのは容易ではありません(単なる私の実力不足でもありますが)。ですが、初歩の解析を行うための資料の一つとして役に立つことができれば光栄です。今回の例は多少SNESに特化していますが、基本はどのゲーム機でも変わりません。本書の方法はNDSのSSEQシーケンスを解析する際にも用いられたものなので、それなりに実用になると確信しています。「発見」に力を入れすぎて「解析」を薄い内容で終わらせすぎた気がしますが、実際のところ音符の発見に至れば仕事は半分終わったようなものです。
この方法ではアセンブリをまったく用いませんでした。しかし、やはりアセンブリを読むことができると解析の幅が広がりますので、その気があればアセンブリの読み方を学ぶというのは必ずやプラスにつながります。でも、アセンブリが読めるようになってもこの方法は重宝すると思います。アセンブリを読む前にシーケンスの概要がつかめていると読むのが楽ですから。
今回ターゲットにしたコンパイルのミュージックドライバの解析結果は、loveemu laboにある「Compile SPC works」にあります。また、gba2midiにはシーケンスの生リッピング機能がついていたと思うので、演奏内容と変換結果、元データを見比べて学習するのに向くかも知れません。先達のリソースから学習するのは上達の近道です。私が先達の方々の偉大な作品に影響され、Compile SPC worksやgba2midi、ssequtilを作成したのがその証拠です。
どうしたら簡単に発見できるか常に思案せよ」「(可能ならば)データの書き換え・実行を繰り返して検証を行え」という二つを最後にポイントとして示しておきます。解析には知識も必要ですが、それ以上に発想力・実践力が試されると私は思います。とにかく経験値を稼いでレベルアップしましょう。ファイト!