SLOW ORBIT 制作の備忘録(2)失敗と対策編 — 揺れの原因を3回取り違えた件、終端の縞、推測を事実として書いた4回

自分用の備忘録。制作の流れは(1)制作編に書いた。ここには次回同じ所で転ばないための記録だけを置く。 反省会は 10/6。対策はその日のうちに album-pipeline の道具・手順書・骨子のテンプレートに入れてある。

3作目のアルバム「SLOW ORBIT」は、就寝前用のインスト8曲(37分37秒)です。Suno で作ったクリップを数値で選別してつなぎ、星空の映像を付けて、YouTube とストリーミングで出しました。実装は Claude Code、PM 役はチャットの Claude、判断と聴取は自分、という分担です。

この記事はその反省会の記録です。前作 NEON DRIVE の失敗と対策編と同じく、件ごとに「起きたこと → 気づき方 → 対策」の順で書きました。制作の流れと前作からの変化は、姉妹記事の制作編にあります。


今作の手戻りは「壊した」ではなく「取り違えた」

前作の事故は、空のプリセットの保存や、確認用の出力が本番のレイヤーを上書きした件のように、ファイルを壊すものが中心でした。前作の後に、確認用の出力は check/ の下だけ、本番の生成物はハッシュで照合、という対策を入れています。今作の反省会で拾った手戻りの中に、ファイルを壊した件はありませんでした。

代わりに目立ったのは、原因や前提を取り違えて、往復が増えたものです。反省会で拾った手戻りは15件で、主なものを表にしました。

# 手戻り 何が起きたか 往復・所要
1 揺れの原因追跡 終盤の音量の揺れの原因を3回取り違え、最後は原因を追うのをやめて「ならす」に切り替えた 往復6回、約1.5日
2 硬さの2転 ピアノの硬さを合否の基準にして、翌日撤回。同じ日に、代わりに決めた順番も撤回した 9/30〜10/1
3 終端の縞 最後のフェードで空に段が出た。対策を入れても YouTube 上では薄い段が残った 10/3〜10/7
4 Ozone プリセットの件 書式の違うプリセットを Ozone が黙って無視し、「出力が完全に一致」に見えた 10/3
5 推測を事実として書いた4回 PM 役のチャットの Claude が、確かめていない推測を事実のように書いた 期間全体
6 動画の文字を決めていなかった アルバム名・曲名を焼き込むかを決めないまま、入れずに公開した —

1件ずつ振り返ります。


1. 揺れの原因追跡 — 3回取り違えて「ならす」へ

起きたこと: 27本で組んだ通しの音源を、連結点と曲の境界の14区間に切って聴く確認(seams)で、曲6〜8 にあたる区間10〜13 だけが、音量が揺れて凸凹に聞こえました(10/3)。

気づき方: この確認は、通しを聴いてダメ出しする工程の一部です。数値の検査(要試聴フラグ)には何も出ておらず、耳で見つかりました。

原因の追跡: ここから約1.5日、往復6回の迷走になりました。

  1. 重なりのうなり・クリップ単体・マスタリングを疑う(10/3)。どれも計測すると、区間10〜13 だけが揺れる理由になりませんでした。残ったのは「この区間は小さく暗い」ということだけです。実際、区間10〜13 は 1〜9 より K特性のレベルで約4dB 小さく、エネルギーの約76% が 120Hz 未満でした
  2. 「原因は低音量と確定」(10/4 の深夜)。音量だけを上げた版を聴いたら気にならなかったので、骨子の changelog にこう書きました。決裁メモは書いていません。後でこれは撤回することになります
  3. 「B 案だけ強く揺れる」(同じ夜)。終盤の目標 LUFS を変えた A 案・B 案を聴き比べたら、B 案だけ揺れて聞こえました。そこで Ozone がどれだけ音量を動かしているかを測ったところ、4つの版はゲインの差以外は同じ音でした(波形の相関 0.99999)。Ozone は実質何もしておらず、「B 案だけ揺れる」は聴き取りのばらつきでした

結局、揺れ(5〜9dB p-p、0.2〜0.7Hz)は、Suno の素材が元から持っていたものでした。終盤は目標の音量が小さいので、それが目立っていただけです。

対策: 10/4 の朝、原因を追うのは打ち切りました。

  • 曲6〜8 の目標 LUFS を浅くした(−25/−26/−27 → −24.5/−25/−25.5)。下りが消える B 案(3曲とも −24)は捨てた
  • 揺れをならすレベラー(dewobble)を作り、4つの版をブラインドで聴いた。区間10・12 の両方で「揺れない」だったのは全帯域・残し幅1.5dB の版だけだったので、これを曲5〜8 に掛けた。曲全体の揺れは、曲6 で 7.78 → 1.47dB p-p まで下がった

副作用もあります。1.5dB の版は、低域の揺れを消す代わりに、中高域(120Hz より上)の揺れを増やします(曲8 で 5.8 → 7.9dB p-p)。区間8〜13 を AirPods Max で聴いた範囲では問題ありませんでした。骨伝導のイヤホンでは、区間9・11 がやや揺れ、12 は明らかに揺れて聞こえました。低域が届かない機器は判断に使わない、として 1.5dB 版で確定しています。通し全体を聴いての確認はしていません。

反省会で決めたこと:

  • 聴き比べは最初からブラインドで、同じ版を1組混ぜる(bin/listen-kit の --blind --dup)。「B 案だけ揺れる」のようなばらつきを、同じ版どうしの組で見抜くため
  • 「確定」と書くのは、計測で裏が取れたものだけ。changelog の書式もそれに合わせた
  • clip-measure に、ゆっくりした揺れの列(slow_wobble_pp_db)を足した。ただし参考の列止まりで、選別には使わない。揺れの聞こえ方は機器と日で変わり、選別の根拠にならないから(この列で合否を決める案は却下)
  • 判断に使う機器を決めた。基準は MDR-CD900ST、一般のリスナーの代表は AirPods Max。骨伝導・オープンイヤーは判断に使わない
  • 目標 LUFS の下限を −25.5 にした(骨子のテンプレートの既定。下回ると検査で止まる)

2. 硬さの2転 — 耳で区別できない数値で決めていた

起きたこと: テンプレート A(ピアノ)のクリップのうち1本(A.wav)の高域が硬い、と聴いて感じたのが始まりです(9/30)。2日のあいだに、硬さの扱いが3回変わりました。

  1. 9/30 追加: 2〜5kHz の比(硬さ)のしきい値を、A だけ −43dB に仮置きした。A.wav が −41.6dB、ほかの3本が −44.7〜−46.1dB だったので、A.wav だけを落とせる位置に置いた値です。この追加には決裁メモがありません
  2. 10/1 撤回: A の4本を聴き比べたら、どれも同じくらい少し硬く、区別がつきませんでした。硬さはテンプレート A の性格と見て、しきい値は外して参考の列にしました。代わりに「柔らかい順に曲1 から当てる」と決めました
  3. 10/1 同じ日にさらに撤回: 区別できない数値を振り分けの最優先にすると、重心(音の明るさ)が曲順に下る規則と、曲1 は1本で4分以上という規則が崩れます。硬さはタイブレークにだけ使うことにしました

気づき方: 2回目は、聴き比べで「区別がつかない」と分かったこと。3回目は、その順番で振り分けると、もっと大事な規則が崩れると分かったことです。硬さを最優先にする前提は、PM 役のチャットの Claude が確かめないまま事実のように書いたもので、これは5の4回のうちの1回です。

結果: A のプロンプトに soft felt piano, mellow, rounded tone を足し、プリセットの Dynamic EQ で 3kHz あたりを軽く下げました。新しいプロンプトの A 3本は、硬さの中央値が −45.1 → −47.0dB、LRA も 7.3〜7.7 → 5.7〜6.8 LU に下がっています。

反省会で決めたこと:

  • 順番は「計測 → 耳のブラインド校正 → しきい値」。耳で区別できない差で、合否や優先順位を決めない(手順書と、骨子のテンプレートの選別基準の頭に書いた)
  • 決定を覆したら、元の決裁メモに「撤回 →」を1行足す。硬さのメモにも遡って足した
  • プロンプトの変更は、1〜2本で試してから全体に入れる

この聴き比べには、オープンイヤー型のイヤホン(Bose Ultra Open)とカナル型(SHURE SE846)を使っていました。1で書いた「判断に使う機器を決める」は、ここにもつながっています。


3. 終端の縞 — 直しても YouTube 上では薄い段が残った

睡眠用なので、映像も最後は真っ黒に落ちていきます。その最後の数分で、手戻りが続きました。

最後のフレームが黒にならない(10/3)

起きたこと: 17本版のサンプル動画で、最後のフレームが黒になりませんでした。合成側で背景を落としていなかったので、背景も音と同じカーブで黒へ落とすようにしました。それでも黒の値が1残りました。

原因: 星のレイヤーを運ぶ ProRes(10bit)では、0〜3 が予約値です。黒の0が4に切り上がり、8bit に戻すと1になって、Screen 合成で背景に足されていました。

対策: 星のレイヤーを TV レンジ(黒 = 64)で運ぶようにしました。中間のレイヤーは、色の範囲まで決めて運びます。album-video --check で、レイヤーの色の範囲と最終フレームが黒(Y=0)かを検査します。

フェードの最中に空の段が見えた(10/4)

起きたこと: 限定公開の YouTube で見たら、最後の1分のフェードの最中に、空に段(縞)が見えました。

最初の対策が効かなかった: 指示は「フレームごとのノイズを足す+4K」でした。指示どおりフェードの後にノイズを足した試験では、段が残りました。2140秒の空の帯ごとの平均を測ると、上の5帯が 2.01 前後で平らに並び、その下で 2.54 へ跳んでいます。理想は 2.22〜3.14 のなめらかな下りです。8bit に丸めた後に平均0のノイズを足しても、段ごとの平均は変わらないからです。

対策: ノイズ(±1階調・三角分布・フレームごと)を、8bit に丸める前に足す形に直しました。帯ごとの平均は 1080p で 2.30〜3.22、4K で 2.19〜3.11 と、理想に近いなめらかな下りになりました。YouTube 用は 4K で書き出します。

丸める前にディザを入れた版。2140秒、暗部を4倍に持ち上げて表示

この修正は、最後の3分だけを 4K で書き出す試験(合成に約56分)で確かめました。ただ、その試験と本番のレンダリングが重なりました。縞の対策の追加指示で、走っていた本番を止めてレイヤーを焼き直し、4K の試験と並行したため、星のレイヤーが単独なら27分のところ86分かかっています。

それでも薄い段が残った(10/5〜10/7)

起きたこと: 直した版を限定公開の 4K で見ても、最後の1分に薄い段が残っていました。手元の計測では消えています。

判断: 最後の1分は、聴いている人が寝ている時間帯です。実害は無いと判断して、そのまま公開しました(10/5)。

その後、反省会の対策として、背景だけを60秒で落とす版も限定公開で見ました(10/7)。それでも段は残り、180秒版との差は見分けられませんでした。段は YouTube の再圧縮で出ていて、こちらの処理では消せない、と結論しています。

終わりの80秒前の比較。背景も星も180秒で落とす版(ほぼ黒)

同じ時刻の、背景60秒・星180秒の版(空はまだ紺で、星も見える)

※ 2枚は同じ時刻(終わりの80秒前)です。180秒で落とす版は、この時点で空の平均が 0.7 とほぼ黒です。60秒版は、ここではまだ背景をほとんど落としておらず(平均 30.4)、最後の60秒で一気に落とします。

反省会で決めたこと:

  • 終端は背景60秒・星180秒(次作の既定)。段が出る暗い領域にいる時間が、78秒から26秒に縮む。段は消せないので、出る時間を短くする
  • 丸める前のディザと 4K を既定にする。本番の前に、最後の数分の 4K 試験を限定公開で確かめる
  • 縞は「帯ごとの平均が理想どおりか」で測る(手順書に書いた。道具にはしていない)
  • レンダリング中の追加指示は、完走してから当てる。止めるのは、確実に捨てになるときだけ。試験と本番は同時に回さない。所要は「一晩」ではなく時間で見積もる

ビットレートは関係なかった

縞の原因はビットレートが足りないことだ、という見立てもありました。これも、PM 役のチャットの Claude が確かめないまま事実のように書いたものです(5の4回のうちの1回)。

ビットレートの下限を強制しようとしましたが、libx264 は固定ビットレート以外では -minrate を使わないので、下限は効きません(10/3 に撤回。上限 40Mbps の可変で確定)。17本版で、旧 1.6Mbps と新 2.9Mbps の版を等倍で並べても、どちらにも縞は見えませんでした。

17本版のビットレート比較(元の背景/旧 1.6Mbps/新 2.9Mbps、暗部4倍・等倍)。どちらにも縞は見えない


4. Ozone プリセットの件 — 黙って前の状態で動く

起きたこと: 前作では、Ozone のプリセットを作るときだけエディタの画面を開いていました。その保存中に Ctrl-C で中断して、空のプリセットが残る事故がありました(前作の失敗と対策編)。

今作は、プリセットも画面を開かずに作ることにしました(10/3)。睡眠用のプリセット SLOW_ORBIT_base は、前作の NEON_DRIVE_soft を元に、自分が別の Mac の Ozone 12 で作りました。それを書き出したユーザープリセットの xml から、Ozone が読む .state を組み立てます。.state は zlib で圧縮した JSON で、パラメータの名前が xml の ID と同じだったので、変換で作れました。画面で保存したものと出力を比べると、差は −122dBFS 以下です。

ところが、途中で罠を踏みました。JSON の書式が元と違うと、Ozone はエラーを出さずに受け付けず、前に読んだ状態のまま動きます。最初に「出力が完全に一致」と出たのは、変換がうまくいったからではなく、読み込まれていなかっただけでした。

気づき方: 素通し(何もしない)の状態から読み込ませたら、出力が変わらないことで分かりました。初期状態を土台にした版は、書式を合わせても受け付けられませんでした(原因は特定できていません)。

対策: 変換の道具は、後で master-preset の import にまとめました。プリセットを読み込めたかは、「前と同じ出力」ではなく、素通しの状態から読ませて出力が変わることで確かめます(チェックリストに入れました)。

「Ozone 11 だから読めない」という推測

このプリセットの件では、PM 役のチャットの Claude の推測にも振り回されました。「制作用の Mac(Studio)の Ozone は 11 なので、もう1台の Mac(Air)の Ozone 12 で作った xml は読めない。Studio で開いた 11 の画面で作り直して」と言われたのです。

実際には、9/21 の時点で Studio にも Ozone 12.1.0 を入れてあり、版の違いはありませんでした。最後は、xml を scp で Studio に送り、master-preset の import で取り込んで、画面を操作せずに解決しています。

なお、1の揺れの追跡で動作量を測ったら、曲6〜8 では Ozone はほとんど動いていませんでした(Dynamic EQ の 294Hz が最大 −0.40dB、Maximizer は −1.00dB の一定値)。


5. 推測を事実として書いた4回

今作で一番の反省点はこれです。PM 役のチャットの Claude が、確かめていない推測を、事実のように書いたことが4回ありました。

# 推測 実際
1 Studio の Ozone は 11 なので、Air の Ozone 12 で作った xml は読めない。11 の画面で作り直す必要がある Studio にも 9/21 に Ozone 12.1.0 を入れてあり、版の違いは無かった。xml を送って import し、画面操作なしで解決(4)
2 Air にも Studio で作ったはずのプリセットがあるのは、書類フォルダ(Documents)が iCloud で両方の Mac に同期されているから Studio の書類フォルダは iCloud 同期の対象外。プリセットはもともと Air の Logic/Ozone で作り、scp で送ったものだった
3 硬さを最優先にする 耳で区別できない差だった。タイブレークに格下げ(2)
4 縞の原因はビットレート 1.6Mbps と 2.9Mbps のどちらにも縞は見えなかった。効いたのは丸める前のディザで、残った薄い段は YouTube の再圧縮由来(3)

前作の失敗と対策編では、「ドキュメントの断定も仮説」と書きました。今作で外れたのは、ドキュメントではなく、指示を出す側の推測です。指示の形で降りてくると、実装する側(Claude Code)はそれを前提として作業に入ってしまいます。1の「原因は低音量と確定」も、計測の裏付けなしに「確定」と書いた点で同じ型です。

対策: 推測は推測と明記し、確認を回す、というルールにしました。

  • PM 役は、確かめていないことを「推測」と書いて渡す
  • Claude Code は、推測と書かれたことを、着手の前に確かめて報告する
  • 「確定」と書くのは、計測や実物で裏が取れたものだけ

手順書(12章・15章)に入れています。


6. 動画にアルバム名・曲名を入れずに公開した

起きたこと: 動画に、アルバム名も曲名も焼き込まないまま公開しました。

気づき方: 反省会(10/6)の指摘で、入れるかどうかを決めていなかったことに気づきました。骨子に、それを決める欄が無かったためです。入れないと決めたのではなく、決めないまま進んでいました。

対策: 入れるかどうかを、骨子を作る最初の段階で決めることにしました。骨子のテンプレートに欄(album.video.overlay)を足し、睡眠系の既定の候補も書いています。曲が替わったら5秒だけ不透明度30%で曲名を出し、冒頭にアルバム名を10秒です。album-video には、曲の境界から N秒だけ文字を出すモード(on_change)を足しました。

on_change の試験。曲4→5 の2.5秒後、右上に曲名を不透明度30%で出す。本番には入っていない


小さな手戻り

ほかにも、反省会で拾った小さな手戻りがあります。

手戻り 対策
前作の tracks.json が実物と食い違っていた(2曲が手で差し替えられていた) 記録を実物に合わせ、album-master に照合(--check)を足した。今作の本番昇格の確認にもそのまま使えた
画像の決定が後追いで記録された(10/1・10/2 の確定が 10/3 に) 画像のセッションも、骨子の changelog に [art] の行だけは書いてよいことにした
配信パッケージを後から作った 本番の音を確定した日に、配信パッケージと登録シートを作る
拍・オンセット・強い立ち上がりの検出が、持続音や曲頭で誤検出した 定義を作り直し、2の順番(計測 → ブラインド校正 → しきい値)に揃えた(制作編に詳しく書いた)

残っていること

  • 終端の最後の1分に薄い段が残っている(YouTube の再圧縮由来。こちらでは消せない)
  • ストア版は、1曲だけ再生すると頭と末尾が唐突(通しを曲の途中で切っているため)。公開後の反応を見て決める
  • dewobble の副作用(中高域の揺れが少し増える)は、区間8〜13 を AirPods Max で聴いて問題なしとしたが、通し全体では確かめていない
  • YouTube で Content ID の申し立てがあった。配信開始後も「動画への影響なし」のまま。異議申し立ては出さないと判断した。却下が続くと削除や警告まで進み得るリスクに対して、得るものが無いから

次回やることチェックリスト

次の睡眠系のアルバムを始める前に見返すリストです。

  • 骨子の最初の段階で、動画に入れる文字(アルバム名・曲名の有無、出し方)を決める
  • 目標 LUFS の下限は −25.5。終盤を小さくしすぎない
  • しきい値は「計測 → 耳のブラインド校正 → しきい値」の順で決める。区別できない差で合否・優先順位を決めない
  • 聴き比べは最初からブラインドで、同じ版を1組混ぜる
  • 判断は MDR-CD900ST、一般リスナーの確認は AirPods Max。骨伝導・オープンイヤーで判断しない
  • 「確定」は計測で裏が取れたものだけ。推測は推測と書き、着手前に確かめる
  • 決定を覆したら、元の決裁メモに「撤回 →」を1行足す
  • プロンプトの変更は1〜2本で試してから
  • 中間レイヤーは色の範囲まで決めて運び、album-video --check で最終フレームの黒を見る
  • 終端は背景60秒・星180秒。丸める前のディザと 4K。本番の前に最後の数分を 4K で限定公開して見る
  • レンダリング中の追加指示は完走してから。試験と本番を同時に回さない
  • Ozone のプリセットは、素通しの状態から読ませて効いていることを確かめる
  • 本番の音を確定した日に、配信パッケージと登録シートを作る

前作はファイルを壊す事故が中心で、仕組みで塞げました。今作は、原因や前提を取り違える手戻りが中心で、これは仕組みだけでは塞ぎきれません。「推測は推測と書く」「確定は計測で裏を取ってから」という書き方の決まりで減らせるかどうかは、次のアルバムで確かめます。

制作の流れと、前作からの変化は制作編へ。