@onjmin/dtm
    Preparing search index...

    Type Alias SectionSpec

    type SectionSpec = {
        barChoices?: number[];
        bars: number;
        density: number;
        landing: number | null;
        melody: boolean;
        progression: "a" | "b" | "c";
        registerShift: number;
        seconds?: { max: number; min: number };
    }
    Index

    Properties

    barChoices?: number[]

    seed ごとに引くセクション長の候補(要素の重複が重み)。

    定数にしない。 長さが定数だと、BPM も調もメロディ型も引き直しているのに曲の骨格だけが 全 seed で同一になる。曲の頭からの小節割りが毎回同じなのは生成器の指紋そのもの。加えて、 候補に一度も現れない長さは、採点の重みをどう変えても出てこない (scripts/README.md の4番)。

    4の倍数にする。 参考コーパスの主旋律のブロック長は7割が4の倍数で、8/16/24/32小節に山が 立つ。コード進行も4小節単位のまとまりで組んでいるので、4の倍数から外れた長さは締めの4小節が 途中で切れる。メロディの無いイントロだけは例外(SECTION_SPECS の intro)。

    イントロは長さを秒で決めるので(SectionSpec.seconds)、ここの候補はテンポで 絞られる前の母集団になる。0小節はここでは引かない——「イントロを作るか」は UI の チェックで表明されているので、チェックが付いているのに消すのは筋が違う。

    省略時は SectionSpec.bars 固定(外から独自の spec を渡す場合のため)。

    bars: number

    小節数の代表値。rnd を渡さずに buildSectionPlan を呼んだときの長さで、 「押す前に曲の長さを見せる」UI 表示などが使う。実際の作曲は SectionSpec.barChoices から seed ごとに引く。

    density: number

    音数の傾き。1より小さいと休符寄りの薄いセクション、大きいと詰める。 リズム型を選ぶときの「休符を含む型」の引きやすさに効く。

    landing: number | null

    セクションの終わりの着地音(主音からの音階度数)。 null はメロディが無いセクション。

    melody: boolean

    メロディを書くか。イントロと間奏は伴奏だけ。

    progression: "a" | "b" | "c"

    伴奏に使うコード進行の役割。

    registerShift: number

    メロディの音域の中心をどれだけずらすか(半音)。 サビが高く、Aメロが低いのが、セクションの差として最も分かりやすい。

    seconds?: { max: number; min: number }

    そのセクションが占めてよい秒数の帯。buildSectionPlan に BPM を渡したときだけ効き、 帯から外れる小節数は SectionSpec.barChoices から落とす。

    小節数は時間ではない。 同じ8小節でも BPM 112 なら 17秒、185 なら 10秒で、聴き手が 感じる長さは3倍近くぶれる。曲の中ほどならそれでよい(拍で数えて聴いているので)が、 歌が始まる前だけは違う——まだ曲が始まっていない聴き手は拍ではなく時計で待っている ので、ここが長い曲は歌に辿り着く前に閉じられる。