[{"data":1,"prerenderedAt":203},["ShallowReactive",2],{"content-/narration-bpm-beat-grid":3,"all-pages-for-dir":181,"related-/narration-bpm-beat-grid":182,"og-image-/narration-bpm-beat-grid":202},{"id":4,"title":5,"body":6,"category":161,"concepts":162,"description":163,"extension":164,"meta":165,"navigation":166,"ogImage":162,"path":167,"project_name":168,"published":169,"publishedAt":170,"seo":171,"source":172,"stem":173,"tags":174,"todo":162,"unpublished":169,"updatedAt":162,"__hash__":180},"pages/2026-08/2026-08-14/narration-bpm-beat-grid.md","ナレーションの話速をBPMで設計する。実測BPM98と、間をビートに乗せる試み",{"type":7,"value":8,"toc":149},"minimark",[9,13,17,20,23,26,30,33,41,44,48,51,54,57,60,63,66,69,72,76,79,82,85,88,91,94,97,100,103,106,121,140,143,146],[10,11,12],"p",{},"自分のサイトに置いてあるナレーション音声が、いま何拍で喋っているのかを知らなかった。\n頭にあるのはBPM120という数字だけで、手元の音声がそこに近いのか遠いのかも分からない。\nサンプルは何でもいいから1本測ってほしい、というところから今日が始まった。",[14,15,16],"h2",{"id":16},"手元の音声はいま何拍で喋っているのか",[10,18,19],{},"ffprobeで尺を取り、テキストと突き合わせて実測させた。\nchapter01の122件はそのまま測れた。\nchapter04だけ落ちたのは、対応表の末尾にカンマが無くてパーサが読み損ねていたからで、そこを直させた。\n発話の前後に入っている無音も測って、尺から差し引かせている。",[10,21,22],{},"出てきた答えは、全体でBPM98相当。\nBPM120に持っていくには1.22倍速が要る。\nやっぱり遅い、という感覚は当たっていた。\nただし話者別の内訳を出させると、遅いのはnarratorだけだった。\nnarratorがBPM74で、yuiとkaiは標準の範囲に収まっている。\n「全部が遅い」ではなく「ナレーターだけが遅い」である。",[10,24,25],{},"耳で「なんか遅い」と言っていたものが、「1.22倍足りない」という一つの数字になった。",[14,27,29],{"id":28},"bpm98とbpm120の差は耳でどう違うか","BPM98とBPM120の差は耳でどう違うか",[10,31,32],{},"98と120の差が耳にどう届くかは、換算表を眺めても分からない。\nHTMLを1枚だけ作らせて、現状とBPM120ベースを並べて聴けるようにした。\nページを持ち回れるように1ファイル完結にして、音声はdata URIで本文に埋め込ませている。\n再生はピッチを保ったまま鳴った。",[10,34,35,36,40],{},"描画を確認させたところ、コンソールにエラーが1件出ていた。\n原因は音声要素の ",[37,38,39],"code",{},"preload='none'"," で、外したら消えた。",[10,42,43],{},"聴いてみると、120のほうが自分には聞きやすい。\n1.2倍でこれか、というのが正直な感想だった。\nそして聞きやすさより先に気になったのは、この120が音楽で言うBPM120と同じ値だということだった。",[14,45,47],{"id":46},"bpm120の4つ打ちをナレーションに重ねる","BPM120の4つ打ちをナレーションに重ねる",[10,49,50],{},"音楽のBPM120が心地よいという話がある。\nだとすれば、ナレーションの裏で120の4つ打ちを鳴らしたときに、両者が一つのリズムとして噛み合うのかを確かめたくなった。\nWeb Audio APIでトラックを合成させて、ナレーションと同時に鳴らす構成にしてもらった。\nトラックのテンポを固定したままナレーションだけ現状の速度に落とせば、ズレていく感じもそのまま体験できる。",[10,52,53],{},"最初の版では、キックが2発しか出ていなかった。\n4つ打ちを名乗っていながら、4拍のうち2拍が空いている。\nパターンを直させたら、4拍すべてにエネルギーが乗った。",[10,55,56],{},"鳴らしてみると、ドゥンドゥドゥドゥン、と聞こえる。\nこの揺れを作っているのはキックではなくベースだった。\n低音だけを取り出させると、その形で鳴っている。",[10,58,59],{},"ここで手が止まった。\n自分の声で録るより、こちらのほうがテンポをコントロールできる。\n話す速さを気合いで揃えるのではなく、数値で決められる。\nそこにこのとき初めて実感が伴った。",[14,61,62],{"id":62},"文と文のあいだをどこに置くか",[10,64,65],{},"テンポが数値で決まるなら、文と文のあいだに置く間も同じグリッドに乗るはずだった。\n既存の音源を加工するのではなく、VOICEVOXを立ち上げて対象の一節を再合成させた（v0.25.1、narratorはspeaker 31）。",[10,67,68],{},"合成の作り方は一度検討させている。\n選んだのは、文全体を自然な抑揚のまま合成しておいて、音素長から分かるポーズ位置で切り出す方式だった。\n狙った位置と実際の切断点のずれは最大42msで、切断点はすべて無音の中に落ちた。",[10,70,71],{},"切り出したフレーズをビートのグリッドに置き直し、タイムラインを見られるページにさせた。\nここまでは狙いどおりに見えた。",[14,73,75],{"id":74},"_4分の3の先頭からと言いたくなるズレ","「4分の3の先頭から」と言いたくなるズレ",[10,77,78],{},"タイムラインを見ると、「そして会計期間」の手前に1.10秒の空きがあった。\n拍の途中から始まっていて、直前のフレーズは読点で終わっている。\n句点で終わっているならまだ間を長く取る理由があるが、読点でこの空きは長い。\n区間の途中で終わったなら、次の区間の頭から始めてほしい。",[10,80,81],{},"原因はグリッドの刻みだった。\nタイムラインの数字は小節番号で、間隔は2秒。\n細い線が1拍で0.5秒にあたる。\n配置の刻みが「2拍＝1.0秒」になっていたので、5.0秒という位置がそもそも選択肢に無く、6.0秒まで飛んでいた。\n刻みを1拍（0.5秒）に変えたら、5.0秒に置けるようになった。",[10,83,84],{},"前のバージョンを残させてから差し替えた。\n手前の空きは1.10秒から0.10秒になった。\n「そして会計期間」は5.00秒、3小節目の3拍目の頭から始まる。\nこのときのspeedScaleは1.38である。",[10,86,87],{},"そのあと、拍ではなく小節を単位にして置く設定も試した。\nこちらでは「そして会計期間」が6.00秒、4小節目の1拍目から始まる。\n小節の頭ちょうどから文が立ち上がる配置になった。",[14,89,90],{"id":90},"停止ボタンを押してもビートが鳴り続けた",[10,92,93],{},"配置を詰めている最中に、明らかなバグを踏んだ。\n停止ボタンを押すと、ナレーションは止まるのにバックグラウンドの4つ打ちだけが鳴り続ける。",[10,95,96],{},"原因は音のスケジュール方法にあった。\nビートを鳴らす処理は先の時刻まで音を予約しておく作りで、停止処理はナレーション側のノードしか止めていない。\n予約済みの音は誰にも止められないまま順番に鳴る。",[10,98,99],{},"ビート専用のバスを1本作らせて、停止時にそこを切断する形に直させた。\n同じ問題が前のバージョン2つにも残っていたので、まとめて直させている。\n検証は耳ではなく出力レベルの実測でやらせた。\n止めたあとにレベルが落ちていることを数値で確認して、ようやく直ったと言えた。",[14,101,102],{"id":102},"手順をスキルに落とす",[10,104,105],{},"ここまでの手順は、合成、ポーズ位置での切り出し、BPMグリッドへの配置、プレビューHTMLの生成、という並びで固まっていた。\n手元にTTS系のスキルは無かったので、新しく作らせた。\nスクリプトの出力がHTMLと完全に一致することも確認させている（音声は12.66秒で、配置12.16秒に末尾の0.5秒を足した長さ）。",[10,107,108,109,112,113,116,117,120],{},"この過程でもう1件、原因の分かりにくいバグが出た。\nHTML側に ",[37,110,111],{},"data-gridComma"," という属性を書いていた。\nところがHTMLのパーサは属性名を小文字にするので、JavaScript側の ",[37,114,115],{},"dataset.gridComma"," では読めず、値がNaNになる。\n",[37,118,119],{},"data-mode"," のような1語の属性は無事だったので、区切りの単位だけは動いていて、壊れていることに気づきにくかった。\nプリセットの選択表示が崩れていたのも同じ理由だった。",[10,122,123,124,127,128,131,132,135,136,139],{},"最後は、スキルのディレクトリにできた ",[37,125,126],{},"__pycache__"," を消そうとして、",[37,129,130],{},"~/.claude"," 配下の ",[37,133,134],{},"rm -rf"," を止めるガードに引っかかった。\n削除は実行されていない。\nキャッシュは自分で消してから、生成そのものが起きないように import の直前へ ",[37,137,138],{},"sys.dont_write_bytecode = True"," を入れさせた。",[14,141,142],{"id":142},"今日の残り",[10,144,145],{},"朝の質問は「いまどれくらいの速さか」だけだった。\n終わってみると、速さと間の両方を数値で決められる道具が手元にできている。",[10,147,148],{},"まだ手を付けていないのは、BPM74で喋っているnarratorの音源そのものである。\n全体を1.22倍にするのか、話者ごとに別の目標値を置くのかは、今日は決めていない。",{"title":150,"searchDepth":151,"depth":151,"links":152},"",2,[153,154,155,156,157,158,159,160],{"id":16,"depth":151,"text":16},{"id":28,"depth":151,"text":29},{"id":46,"depth":151,"text":47},{"id":62,"depth":151,"text":62},{"id":74,"depth":151,"text":75},{"id":90,"depth":151,"text":90},{"id":102,"depth":151,"text":102},{"id":142,"depth":151,"text":142},"dev",null,"サイトに置いてあるナレーション音声をffprobeで実測したらBPM98相当だった。BPM120ベースとの聞き比べページを作り、4つ打ちを重ねてテンポを確かめ、文の間を拍のグリッドに置き直すまでの記録。","md",{},true,"/narration-bpm-beat-grid","eurekapu-nuxt4",false,"2026-08-14T00:00:00.000Z",{"title":5,"description":163},"make-diary","2026-08/2026-08-14/narration-bpm-beat-grid",[175,176,177,178,179],"VOICEVOX","音声合成","Web Audio API","BPM","ナレーション","xZJCdRqO5SCIMqOK8IISTO7Yib69yhOhcBxWKiXcVMI",[],[183,187,191,195,198],{"title":184,"path":185,"publishedAt":186},"会計学習コンテンツのナレーション機能構築 - VOICEVOX・GCP TTS・Cloudflare R2","/narration-feature-voicevox-gcp-tts","2026-03-15T00:00:00.000Z",{"title":188,"path":189,"publishedAt":190},"自分の声を複製して、BPM120のビートに乗せる — TTSで講義音声を作る実験","/tts-narration-bpm120","2026-08-18T00:00:00.000Z",{"title":192,"path":193,"publishedAt":194},"2026年5月16日の開発日記 - 投資判断クイズ75問の音声化とマイクロン決算チャートの作り込み","/2026-05-16-diary","2026-05-16T00:00:00.000Z",{"title":196,"path":197,"publishedAt":194},"投資判断クイズ75問をVOICEVOXで音声化：WAV合成→MP3→Cloudflare R2まで一気通貫の自動化ログ","/quiz-narration-pipeline",{"title":199,"path":200,"publishedAt":201},"ずんだもん音声解説を財務3表コクピットに組み込む：132ステップ一括生成とR2デプロイ","/voicevox-zundamon-audio-r2","2026-05-06T00:00:00.000Z","https://log.eurekapu.com/favicon.svg",1787053849280]