友人が「歌ってみた」用の音源を、耳コピで自分から作っていると聞きました。そんな作り方があるのかと思ってから、ずっと気になっていました。
私が欲しかったのは、カラオケの練習用の伴奏です。作れたら、同じ曲を練習している人にも渡したい。渡せる形にすることが出発点でした。
ところが、人に渡すことを考えると選択肢がひとつ減ります。市販の音源からボーカルだけを抜いても、素材になっているのは他人が作った録音のままだからです。手元で練習に使う分にはいいとして、配るとなると話が変わります。
そこで作り方のほうを調べていて、思い込みがひとつ崩れました。私はカラオケ配信サービスの音源を、原盤に手を加えて歌だけ抜いたものだと思っていたのです。実際は、その曲をもう一度演奏し直して作られた、まったく別の録音でした。
だったら、と考えました。機械に演奏し直させれば、出てくる録音は私のものになります。
実際に OSS で組んでみると、聴けるものにはなりませんでした。ただ、うまくいかなかったこと自体より、どこで詰んでいるかの見立てが3回変わったことのほうが面白い話になりました。順に書きます。
配れる音源と配れない音源
権利には層が2つあります。楽曲そのものにかかる著作権と、録音そのものに発生する原盤権です。市販の音源を加工した場合、原盤権はレコード会社に残ります。
✕ 原盤からボーカルを抜く → 原盤権はレコード会社のまま → 配れない
◯ 採譜して演奏し直す → 私が生成した録音 → 配れる余地がある
楽曲の著作権のほうは、演奏し直しても消えません。JASRAC などの手続きは別途要ります。私は弁護士ではないので、どこからOKかNGかの断定はしません。確認したかったのは「録音を自分で作り直す」という道筋が技術的に成立するかどうかでした。
対象は wacci「恋だろ」1曲、4分50秒です。以降に出てくる音符数や音域の数字は、すべてこの曲を分析した結果です。バンド編成にシンセとコーラスが重なっていて、採譜の相手としては軽くありません。
配るための組み立て
3工程です。分離して、採譜して、鳴らします。
| 工程 | ツール | ライセンス |
|---|---|---|
| 音源分離 | Demucs htdemucs
|
MIT |
| 採譜 | Basic Pitch (Spotify) | Apache-2.0 |
| 合成 | FluidSynth 2.2.5 + FluidR3_GM.sf2 | 各配布条件による |
ライセンス列を最初に埋めたのは、配ることが目的だったからです。処理の途中に再配布できないものが1つでも混ざると、出口で全部止まります。
計算資源は思ったより要りませんでした。Demucs は CPU で実時間の 2.2 倍速で走ります。4分50秒の曲が 2分12秒で 4 stem に割れました。GPU を買う理由をひとつ失った気分です。
多楽器採譜としては MT3 や Omnizart も候補でしたが、私は実測していません。Basic Pitch で先に結果が出たので、比較する必要がなくなりました。以下に MT3 が出てきますが、それは README の記述の話であって、私が回した結果ではありません。
詰み1「採譜がポップスに届かない」は外れました
最初に疑ったのは採譜でした。単音のフレーズならともかく、シンセもギターもコーラスも重なったポップスを音符に起こせるとは思えなかったからです。
ここで効いたのが分離でした。MT3 の README には、歌声で学習していないのでボーカル入りを渡すと妙な結果になる、と書かれています。つまり分離を先に済ませれば、この制約はそもそも発生しません。
分離が実際に効いているかを、採点用のピッチ検出器を通して確かめました。原曲・伴奏・vocals stem の 3 本にかけて、検出の confidence 分布を比べます。
| 入力 | confidence 中央値 | 上位を占める音域 |
|---|---|---|
| 原曲 | 0.865 | A1〜E2(ベース) |
| 伴奏 | 0.893 | A1〜E2(ベース) |
| vocals stem | 0.976 | 歌の音域 |
原曲と伴奏はどちらもベースの低音を拾っていて、歌を追えていません。vocals stem にはその低音が残らず、vocals と no_vocals のヒストグラムの重なりは 0.09 まで落ちました。分離は効いています。
そのうえで 3 stem に Basic Pitch をかけました。妥当な音域に収まった割合を、こう定義しています。
#: 楽器として妥当な音域 (MIDI)
EXPECTED = {
"bass": (28, 55), # E1 〜 G3
"other": (48, 84), # C3 〜 C6
"vocals": (45, 79), # A2 〜 G5
}
low, high = EXPECTED[stem]
in_range = float(np.mean((pitches >= low) & (pitches <= high)))
結果です。
| stem | 音符 | 毎秒 | 想定音域内 | 多い音名 |
|---|---|---|---|---|
| bass | 794 | 2.8 | 88% | B, A, E, C#, G# |
| other | 3228 | 11.2 | 79% | E, B, A, G#, C# |
| vocals | 894 | 3.1 | 95% | E, B, F#, G# |
一番効いたのは右端の列でした。3 stem が独立に採譜されたのに、出てきた音名がすべて E メジャーの構成音(E F# G# A B C# D#)に収まっています。 互いの結果を参照していない 3 系統が同じ調に着地したので、偶然ではありません。vocals の結果は、別の経路(SwiftF0)で作ってあった既存の譜面とも一致しました。
採譜は動いていました。私が最初に疑ったのは、ずっと無実の側だったわけです。
詰み2「音色を上げれば聴ける」も外れました
採譜が動いたので、次は合成が壁だと考えました。MIDI をサイン波で鳴らせば当然ひどい音になります。まともな音源で鳴らせば聴けるはずだ、という筋です。
段階的に音色を上げて、そのつど聴いてもらいました。
| 版 | 合成方法 | 判定 |
|---|---|---|
| resynth | サイン波(bass + other) | 使えない |
| piano | FluidSynth ピアノ(bass + other) | 使えない |
| guide | FluidSynth ピアノ(主旋律のみ) | うーん |
| musicbox | FluidSynth オルゴール(主旋律のみ) | 微妙 |
音色を4段上げても、評価がほとんど動きませんでした。 サイン波から SoundFont のピアノに変えて何も変わらないなら、問題は音色ではないことになります。
濁りを疑って、音符を間引くフィルタも書きました。other stem は毎秒 11.2 音あります。厚い和音が鳴っているのかと思いましたが、実際は短い音が連続しているだけでした。シンセパッドやリバーブの尾を、音符として拾っています。
#: これより短い音は捨てる (秒)
MIN_DURATION = 0.2
#: これより弱い音は捨てる。弱い誤検出を落とす
MIN_VELOCITY = 50
#: 同時に鳴らす上限。伴奏なので土台の和音が要る
MAX_SIMULTANEOUS = 5
notes = [
n
for n in instrument.notes
if n.end - n.start >= MIN_DURATION and n.velocity >= MIN_VELOCITY
]
3228 音が 1770 音まで減って、多少ましにはなりました。ただ「多少ましな、聴けないもの」でした。
一番評価が高かったのがオルゴールだったのも、あとから考えると示唆的です。オルゴールは主旋律しか鳴らしていません。音数を減らしたものが一番マシだったということは、足りないのは音の質ではなかったのです。
詰み3 抜けていたのは編曲でした
そこで、カラオケ音源とオルゴールアレンジが実際どう作られているかを調べました。どちらも人が編曲して打ち込んでいます。
カラオケ音源の制作会社であるシーミュージックの三木康司社長が、制作の実態をこう話しています。
データ入力はすべて耳コピで行っていますよ。そのためレコード会社からMIDIデータをもらう、なんてことはありませんが、発売前の曲を事前にもらって作業を進めることはよくありますよ。
-- シーミュージック 三木康司氏 / DTMステーション(藤本健)
データは渡されず、人が耳で起こしています。MIDI 検定がそのまま役立つ職種として成立するくらい、専門の仕事です。
オルゴールも同じでした。YouTube にあるオルゴールアレンジのほとんどは、オルゴール風の音で自由に編曲された電子音です。実際のオルゴールを回して録音したものは、ほとんど見当たりません。
並べるとこうなります。
| 工程 | |
|---|---|
| カラオケ音源 | 人が耳コピ → 人が編曲 → 打ち込み |
| オルゴールアレンジ | 人が編曲(音を減らす・動きを整える・音域を移す)→ 打ち込み |
| この実験 | 機械が採譜 → そのまま鳴らす |
真ん中の列が丸ごと空でした。原曲をなぞることと、その楽器で鳴らして良い形に作り直すことは、別の作業です。オルゴールアレンジが成立するのは、オルゴールで成立する形に組み直しているからでした。採譜結果の音色だけ差し替えても、そこには届きません。
冒頭の友人がやっていたのも、この列でした。耳で音を取る部分は、機械が肩代わりできます。取った音をその楽器で成立する形に組み直す部分を、友人は手でやっていたわけです。私は聞いた時点で、そこを工程として数えていませんでした。耳コピという一語で、2つの作業をまとめて呼んでいたからです。
再現手順
ここまでの検証は、次の手順で再現できます。
# 1. 4 stem に分ける
python -m demucs -n htdemucs -d cpu -o <出力先> <音源>
# 2. 採譜用の venv を隔離して作る
uv venv --python 3.10 amt-venv
VIRTUAL_ENV=$PWD/amt-venv uv pip install basic-pitch 'numpy<2' 'setuptools<81' scipy
# 3. 場所を渡して実行する
export SONGFIT_STEMS=<Demucs の出力先>/htdemucs/<曲名>
export SONGFIT_WORK=<作業ディレクトリ>
./amt-venv/bin/python amt_check.py bass other vocals # 採譜と評価
./amt-venv/bin/python render_fluid.py all # 合成
引っかかったのは 2 番です。basic-pitch は numpy<2 を要求するので、numpy 2 系を使っているプロジェクトの venv に同居させると壊れます。採譜用の venv は必ず分けてください。
スクリプトが読む環境変数は次の 2 つです。
| 変数 | 中身 |
|---|---|
SONGFIT_STEMS |
Demucs が出した stem(bass.wav 等)の置き場所 |
SONGFIT_WORK |
中間ファイル(*.mid)と生成物の置き場所 |
パスを引数でなく環境変数にしたのは、生成物をうっかりリポジトリに入れないためです。著作物の派生になるものを、git add . の射程に置かない運用にしています。
まとめ 配れる音源に届かなかった3地点
見立ての変遷はこうなりました。
| 時点 | そのとき考えていた原因 | 実際 |
|---|---|---|
| 最初 | 採譜がポップスに届かない | 外れ。分離すれば 88 / 79 / 95% で動く |
| 分離後に採譜が動いた | 合成の質が壁 | 外れ。音色を4段上げても評価が動かない |
| 音色を上げても変わらない | 編曲の工程が抜けている | ここは合っている |
上の 2 行、つまり私が最初に疑った 2 つは、どちらも無実でした。手を入れやすい場所から順に疑っていたからです。採譜の精度も、合成の音色も、パラメータをいじれば数字が動きます。動く数字がある場所を疑うのは楽なのです。
実際に空いていたのは、パラメータが 1 つもない場所でした。工程そのものが無いところに、チューニングの余地は生まれません。
有効期限も書いておきます。2026 年 8 月時点の OSS での話です。
| 何が変われば | 効き方 |
|---|---|
| 採譜結果を編曲する工程を自分で書く | 本丸。なぞった音符を、その楽器で成立する形に組み直す |
| MIDI から音への合成が人手なしで自然になる | 音色の壁は下がるが、編曲は残る |
| 多楽器採譜の精度が上がる | 効かない。採譜はすでに足りている |
次に手を付けるなら other stem の和音推定です。3228 音から小節ごとのコードを起こせれば、伴奏を組み直す土台になります。同じところで詰まった方がいれば、どのあたりから崩したか聞かせてください。
この検証の全文は自分のサイトに置いています。上の表で「使えない」「うーん」「微妙」と判定した音源4版を、中途半端なまま埋め込んであります。どのくらい駄目だったのかは、聴いてもらうのが早いはずです。「編曲まで行うモデルを待つしかない」と思っていた私が、そのあとでもう一度間違えた話も足してあります。


