Skip to content

生成パイプライン ​

generator.generate(config) を呼び出すと、作曲エンジンはリクエストを完全かつ決定論的な楽曲へと変換する固定のパイプラインを実行します。

このパイプラインでの音楽用語

このパイプラインでは、音楽を構造化データとして扱います。形式が声部と作譜済みノートキャリアを割り当て、和声が和音ターゲットを与え、検証が不正な声部関係を弾きます。短い用語集はエンジニアのための音楽用語入門にあります。

generate() の 7 ステップ左上から設定が入り、7 つの固定ステップ — 生成要求の解決、形式ディレクター、候補探索、規則検証、レンダラー、最終検証と表現、MIDI とイベントの書き出し — を通ります。最終化では、装飾、FinalScore と形式の予算の検証、速度の適用、作譜値の保存、アーティキュレーション、再レンダー、CC とテンポの追加をこの順に行います。3 番目のあと段が折り返して 4 番目に続きます。横に伸びる分岐は、阻害的な検証失敗が出た場合に出力を作らず報告を返して中断することを示します。BachConfigform, key, isMinor, character,bpm, seed, scale / targetBars1 · 生成要求の解決既定値を補い、シードを確定し、要求全体を検証する2 · 形式ディレクター設計値のアーチに沿って、小節スパンに声部意図を配置する3 · 候補探索全スパンを処理。出荷形式では記述済みの担体を再生する4 · 規則検証対位法と構造の違反を、対象のスパンとともに蓄積する5 · 初回レンダラー声部を 1 声部 1 トラックに変換。チャンネルと音色番号を付ける6 · 最終化と表現装飾 → FinalScore + 予算速度 → 記譜長 → アーティキュレーション再レンダー → CC / テンポ7 · MIDI とイベント出力出力調を適用し、Type 1 の SMFとイベントデータを書く阻害的な失敗が出たら、中断して報告を返すgetMidi() · getEvents()非ゼロの固定シードなら、同じ設定はこの経路をたどり、同じバイト列になる。シード 0 は実行時に新しく決まる。

パイプライン全体は、明示的な非ゼロのシードなら決定論的です。同じ設定とシードはバイト単位で同一の出力を生成します。seed: 0 の場合は実行時に新しいシードを選びます。

ステップ1: 作曲リクエスト ​

生の設定が作曲リクエストに解決されます。既定が補完され、シードが解決され(seed が 0 の場合は具体的な非ゼロ値となり、getInfo().seedUsed で報告)、リクエストが検証されます。

検証は厳格です。不明な form/character/instrument/scale の値や範囲外の bpm、および禁止された性格と形式の組み合わせ(chorale_prelude は playful/restless を、toccata_and_fugue は noble を拒否)は却下されます。form は声部数・拍子・基準長を固定し、scale/targetBars が最終的な小節数を解決します(形式の刻みにスナップし [最小, 128] に丸め込み)。

ステップ2: 形式ディレクター ​

形式ディレクターが楽曲をレイアウトします。選択された形式に対し、ボイスインテントを小節スパンに割り当てます — 主題と応答、グラウンドバス、定旋律、音型、変奏素材を解決された長さにわたって配置します。

小節スパンと素材

小節スパンは、連続する小節の範囲です。素材は、フーガ主題、対旋律、反復するグラウンドバスなど、キャリアがそのまま再生する作譜済みの音楽内容です。

4 つのレイアウト族4 段の図です。各段は 1 つのレイアウト族を、曲の小節にわたる 3 本の声部レーンとして示します。フーガ系は主題提示をずらして並べ、その合間にエピソードを置きます。固執低音の変奏系は、凍結された 1 本のバスの上で上声部を周期ごとに書き直します。定旋律系は中声に長い固定音を置き、その上で装飾音型が動き、下には独立したバスが付きます。線的な形式は、走り続ける線の上で 2 声が素材をやりとりします。主題提示・変奏素材形式が凍結する線エピソード・音型・自由な素材フーガ系fugue, prelude_and_fugue,toccata_and_fugue, fantasia_and_fugueずらした主題提示と、その合間のエピソード固執低音の変奏系passacaglia, chaconne,goldberg_variationsバスは 1 本のまま、上声部を書き直す定旋律系chorale_prelude中声に長い固定音、その上に装飾音型、下には独立したバス線的・音型系trio_sonata, cello_prelude走り続ける線の上で 2 声がやりとりする。チェロ前奏曲は同じことを 1 声で行う形式が族を決め、族が形を決める。だから声部数・拍子・自然な長さはオプションになっていない。

レイアウトはデザイン値のアーク — 提示、展開、スパンの約80%でのクライマックス、解決 — に従い、下流で使用する密度・音域・ベロシティの段階を駆動します。アークは形式により固定され、探索されません。

ステップ3: 候補探索 ​

候補探索は、各ボイスインテントのスパンを処理経路へ振り分けます。出荷時の既定形式では、すべてのスパンがキャリアです。各キャリアは形式ビルダーが組み立てたノートをそのまま再生するため、採点付き探索が通常の出力に加えるノートは0です。

採点付き探索は既定で無効の診断用オプションです。bach_cli --free-counterpoint は、パッサカリア V1(voice == 1)の対旋律だけを、拍ごとに和声音へ固定する探索へ切り替えます。グラウンドと主要変奏はキャリアのままです。ほかの形式には切り替え可能なスパンがないため、自由対位法を要求すると FreeCounterpointUnavailable を返します。

自由な Compose スパンがある位置ですべての候補を使い果たした場合、エンジンはフォールバック音を選ばず休符を出力し、saturated_positions を増やします。飽和は密度の指標であり、それ自体は検証失敗ではありません。キャリアのスパンが飽和することはありません。

和音、転調、カデンツ

和音は各時点の縦のターゲットです。転調は音楽上の中心を別の調へ移すことです。カデンツ、つまり終止はフレーズの終わり方で、典型的には V から I のような属和音から主和音への到着です。

ステップ4: ルール検証器 ​

検証器は組み上がった声部を対位法・構造ルールに対して検査します。その検証処理で見つかった失敗をまとめて記録し、該当スパンを特定できるようルール識別子とともに報告します。音楽上の考え方は対位法コースで学び、特定のルール ID を調べるときは検証器ルール一覧を使います。

生成検証で停止させる失敗が見つかったあとの動作

公開生成経路は処理を中止して検証レポートを返します。スコアの修復、探索の再試行、別候補への切り替えは行いません。装飾後の FinalScore 監査には、別の停止点があります。

ステップ5: レンダラー ​

Composer::run() の最後に、組み立てた声部が初回の声部ごとのトラックへレンダリングされます。この時点でチャンネルとノートタイミングが決まります。公開 FinalScore と予算の検査に合格した後、生成経路は楽器別のベロシティカーブを適用し、記譜上のノートを保存し、性格に応じたアーティキュレーションを適用して、General MIDI プログラムを設定したトラックを再レンダリングします。

source タグはレンダリング後も残ります

レンダリングされた音は由来を保ちます。キャリア素材は "material"、任意の採点付き探索で選ばれた音は "compose"、後から追加された装飾は "ornament" です。検証結果がどの素材に由来するかを調べるときに役立ちます。

ステップ6: 最終化と表現(後処理) ​

公開生成経路は Composer::run() のあと、装飾の適用、FinalScore 検証、形式の対位法予算の適用、速度曲線の適用、generated.v1 用の記譜上のノートの保存、アーティキュレーションの適用、トラックの再レンダー、コントローラーイベントの追加、テンポイベントの追加、MIDI と公開イベントデータの出力、という順に処理します。FinalScore または閉じた予算の検証で停止させる失敗が見つかると、ベロシティ、アーティキュレーション、コントローラー、テンポ、MIDI、公開イベントの出力には進みません。

  • 装飾 — トリル(終止での開始音と最後のナッハシュラークを含む)、アポジャトゥーラ、ターン、スライド、モルデント。密度は性格と楽器に依存します。主唱・応唱・ストレッタ、および拡大・縮小・反行した主唱提示は、同一性を保つため素のままです。中間提示は装飾対象に残ります。グラウンドキャリアは免除され、定旋律は小節頭を素のままにします。小節内の対象音は Severe 以外で装飾できます。Severe では定旋律全体を素のままにします。
  • ベロシティ — 最終検証後に楽器別のフレーズカーブを適用します。MIDI と getEvents() が更新後の値を共有するよう、トラックを再レンダリングします。
  • 表現 — オルガンとチェンバロには MIDI のレベルを段階的に変える CC 7 とアークを、ピアノ、ヴァイオリン、チェロには CC 11 の連続表現を加えます。これは再生時のレベル/表現イベントであり、CC 7 はオルガンのストップ選択(レジストレーション)ではありません。ギターにはベロシティカーブだけを適用し、連続表現プロファイルは適用しません。
  • テンポ — 形式に応じて終結のリタルダンドを加えます(トリオ・ソナタにはありません)。前奏曲、トッカータ、ファンタジア系の形式では、フーガ入りでセクションテンポも変わります。

source: "ornament" 由来タグを持つのは、装飾処理が追加したノートだけです。ベロシティとアーティキュレーションは既存ノートを変更しますが source は変えず、CC とテンポの処理はノートではなくイベントを追加します。

検証には記譜上の長さを使います

FinalScore 検証とそのテクスチュア指標はアーティキュレーション前の記譜上のノート配列で実行します。generated.v1 はその記譜上の長さを保持し、公開イベントデータと MIDI はアーティキュレーションで短くなった再生時の長さを使います。

装飾

装飾は、構造上の音の周辺に追加される小さな飾りの音型です。元の主旋律そのものではないため、イベントデータでは source: "ornament" として区別されます。

ステップ7: MIDI ライター ​

内部表現はすべて C で作曲・検証されます。出力ライターは指定された key と出力オクターヴシフトを適用します。MIDI ライターは拍子記号も書き込み(パッサカリアとシャコンヌは3/4、それ以外は4/4)、Type 1 の標準 MIDI ファイルを生成します。公開イベントライターも同じピッチ変換を適用します。

js
const midi = generator.getMidi()       // Uint8Array(選択した調に移調)
const events = generator.getEvents()   // イベントデータ(出力調のピッチ)

TIP

getEvents() は出力調のピッチを報告し、すべてのノートに source タグを付与します。内部診断用の generated.v1 は C のピッチを保持します。公開イベントの型定義はJavaScript APIを参照してください。

パイプラインの外側: 品質はどう測られるか ​

ここまでの7ステップが実行時のすべてです。既定では、パイプラインは実行中に「よりバッハらしい候補」を探索しません。形式ビルダーがキャリア素材を作譜し、検証器が不正な結果を弾きます。では、その設計値が実際にバッハらしい出力を生むことは、どうやって確かめているのでしょうか。

答えは開発側の品質ゲートです。エンジンの形式や音型に手が入るたびに、生成結果を2系統の自動チェックにかけます。どちらもエンジンリポジトリの Python ツール(bach_tools.py の texture-gate / closure コマンド)として公開されています。

コーパス統計モデル ​

生成された楽曲のイベントデータから5つの分布を取り、実曲コーパスから推定した参照分布との距離(負の対数尤度)で採点します。距離が校正済みの閾値を超えると不合格です。

特徴量見ているもの
ピッチクラスどの音名がどれだけ使われるか
旋律音程声部内の隣接音間の距離の分布
音価ノート長の分布
拍位置ノートが小節内のどこで発音されるか
縦の音程クラス同時に鳴る音同士の音程の分布

このうち最も重みが大きいのが旋律音程です。バッハの実曲では旋律音程の最頻値が圧倒的に順次進行(隣のスケール音への半音1〜2個分の移動 — 入門)なので、跳躍の多い線はこの距離をすぐに押し広げます。

横の順次性と縦の協和のせめぎ合い ​

ここに音型設計の核心的な緊張があります。

  • 横方向: 線は順次進行が支配的であるほどコーパスに近づく — 音階的なラン、波形の音型。
  • 縦方向: 拍頭はその小節の和音の構成音に固定されるほど、保続するバスに対して協和する(跳躍には回復が要るも参照)。

この二つは素朴に実装すると衝突します。自由に走る音階ランは拍頭で非和声音を踏み、逆に毎拍を最寄りの和声音へ飛ばすと跳躍だらけの線になります。エンジンの音型(音階波、ノコギリ波、分散和音)は、走行方向の前方にある和声音へ着地する・オシレーションの相手はまずバスに協和する隣接音から探すといった選び方で、順次性を保ったまま拍頭を協和させるように書かれています。

順次進行と縦の協和のせめぎ合い3 つのパネルはいずれも、持続するバスの上に置かれた 8 つの 8 分音符です。1 つ目では自由に走る音階がなめらかに動きますが、拍の頭のうち 2 つが和音外の音に着地します。2 つ目では拍の頭がすべて和音構成音になりますが、そこへ到達するために線が跳躍します。3 つ目では、進行方向の先にある和音構成音へ向かって順次進行するので、順次性と拍頭の協和が両立します。どのパネルも、持続するバス(下端の帯)の上に置かれた 8 つの 8 分音符を示します。破線はそのバスの和音構成音、赤い丸と赤い線分は破綻している箇所です。自由に走る音階横方向はコーパスに近いが、拍の頭が和音外の音に乗る拍の頭が 2 か所、和音から外れる拍の頭をすべて和音構成音に縦方向は清潔だが、そこへ届くために線が跳びまわるどの拍にも跳躍で到達しているエンジンの音型がやること進行方向の先にある和音構成音へ向かって順次に進む順次進行のまま、拍の頭は協和するコーパスのモデルは旋律音程をもっとも重く見るので跳躍の多い線は落ちる。だが不協和に踏み込み続ける線も同じように落ちる。

テクスチュアゲート ​

統計モデルと並んで、シード×形式の一括 sweep が構造指標を直接チェックします — 各声部の活動量、沈黙率、同音連打の長さ、平行完全協和音程の数、そして上記モデルスコアの閾値。1ケースでも落ちれば、その変更はマージされません。

これらは generate() の一部ではありません

コーパスモデルもテクスチュアゲートも実行時には走りません。生成は常に決定論的な一発出力で、品質はその出力を生む設計値の側で — 開発時に — 担保されています。

Dual-licensed: AGPL-3.0 · commercial licensing available. Generated MIDI is yours to use freely.