ホスト API
ここに挙げるものはすべて runRenderCode(ホスト)が直接注入 します。libs/codes/*.js より前にロードされ、ユーザコードや lib から上書きすることはできません。
setNote({ pitch, velocity, startBeat, lengthBeats })
Section titled “setNote({ pitch, velocity, startBeat, lengthBeats })”ノートを 1 つ Render に出力します。すべてのフィールドは省略可能。
| フィールド | 既定値 | クランプ範囲 |
|---|---|---|
pitch | 60(C4) | 0..127(整数に丸め) |
velocity | 100 | 0..127(整数に丸め) |
startBeat | CLIP_BEAT(現在のフェーズの値) | クランプなし |
lengthBeats | 1 | 0.001 以上 |
id は crypto.randomUUID() で自動付与されます。同じピッチ・同じビートで複数回呼んでもそれぞれ別ノートとして記録されます。
最小例
onInit(() => setNote({ pitch: 60 })); // C4、1 拍、velocity=100、startBeat=0実用例
// 元ノートにオクターブ上のレイヤーを 70% velocity で足すonNote((n) => { setNote({ ...n }); // 元ノート保持 setNote({ ...n, pitch: n.pitch + 12, velocity: 70 }); // オクターブ上});[!CAUTION]
pitch/velocityは 整数に丸められた上でクランプ されます。lengthBeatsの最小値は0.001— それ未満を渡しても0.001になります(無音ノート防止)。
setCc({ ccNumber, beat?, value, curve? })
Section titled “setCc({ ccNumber, beat?, value, curve? })”CC イベントを 1 つ Render に出力します。同じ ccNumber への複数回の呼び出しは 1 つのレーンに集約 され、beat 昇順にソートされます。
| フィールド | 既定値 | クランプ範囲 |
|---|---|---|
ccNumber | (必須) | 0..127(整数に丸め) |
beat | CLIP_BEAT | クランプなし |
value | (必須) | 0..127(整数に丸め) |
curve | "linear" | "linear" / "hold" / "exp" / "expInv" / "scurve" |
最小例
onInit(() => setCc({ ccNumber: 11, beat: 0, value: 64 }));実用例
// 1 拍ごとに正弦波で Expression(CC11)を揺らすonBeat((b) => { const v = 64 + 32 * lfo(b / CLIP_LENGTH, "sin"); setCc({ ccNumber: 11, beat: b, value: v });});カーブ指定 (P-2)
curve は このポイントで終わるセグメント の形を指定します(前のポイントから「自分」まで補間する際の形)。
onInit(() => { // 0→100 までを smoothstep でゆっくり立ち上げる setCc({ ccNumber: 1, beat: 0, value: 0 }); setCc({ ccNumber: 1, beat: 4, value: 100, curve: "scurve" }); // ステップ状にホールドしてから跳ね上げる setCc({ ccNumber: 1, beat: 6, value: 30, curve: "hold" });});curve | 形 |
|---|---|
"linear" | 直線(既定) |
"hold" | A の値を保持し、B.beat で B の値に階段状にジャンプ |
"exp" | ease-in(最初遅く後で急、t**2.7) |
"expInv" | ease-out(最初急で後で緩む、exp の鏡像) |
"scurve" | smoothstep(両端で接線がフラット、中央で対称) |
[!TIP] 同じ
ccNumberに複数回setCcを呼ぶと、1 つのレーン内のイベント列に集約されます。異なるccNumberならレーンが別々に作られます。
setCcResolution(stepsPerBeat: number)
Section titled “setCcResolution(stepsPerBeat: number)”onCc のサンプリンググリッド解像度(1 拍を何分割するか)を設定します。[1, 256] にクランプ。トップレベル または onInit 内 から呼んだときだけ反映され、onBeat / onNote / onCc 内からの呼び出しは黙って無視されます(グリッドは onCc 掃引の直前にスナップショット)。
| 引数 | 意味 | 既定値 |
|---|---|---|
stepsPerBeat | 1 拍あたりの onCc 呼び出し回数 | 16(≈ 1/64 音符 ≈ 31ms @120bpm) |
onInit(() => setCcResolution(32)); // 1/32拍 ≈ 15.6ms @120bpmonCc(({ phase }) => setCc({ ccNumber: 1, value: 64 + 32 * Math.sin(phase * 2 * Math.PI) }),);[!CAUTION] 解像度 × クリップ長が 32,768 ticks を超えると Render は
Runtime error (onCc): grid sweep would emit ... ticks, exceeding capを返します。setCcResolutionを下げるかクリップを短くしてください。
コールバック登録
Section titled “コールバック登録”onInit(fn) / onBeat(fn) / onNote(fn) / onCc(fn)
Section titled “onInit(fn) / onBeat(fn) / onNote(fn) / onCc(fn)”それぞれのフェーズに任意個のコールバックを登録します。登録順 に呼ばれます。return 値は無視されます。
| 関数 | コールバック引数 | 呼ばれる回数 |
|---|---|---|
onInit(fn) | なし | レンダー先頭で 1 回 |
onBeat(fn) | (beat: number) | クリップ長 × stepsPerBeat(既定 16/拍) |
onNote(fn) | (note: MidiNote) | 元ノートの数 |
onCc(fn) | (ctx: { beat, time, phase }) | クリップ長 × CC 解像度(既定 16/拍。setCcResolution() で変更) |
例外を投げるとそのフェーズが中断 されます(前のフェーズの結果は保持)。詳しくは ライフサイクル:エラーが起きたら何が残るか を参照。
// 5 度上のハモリを足す(登録順に評価される)onNote((n) => setNote({ ...n })); // 1 番目:元ノート保持onNote((n) => setNote({ ...n, pitch: n.pitch + 7, velocity: 70 })); // 2 番目:5 度上[!TIP]
onCcは元 CC レーンの有無に関わらず、setCcResolutionで決まる固定グリッドで掃引されます。CC をゼロから生成する LFO もこの中で書けます。入力 CC を読みたいときはsampleCcを使ってください。
events: MidiNote[]
Section titled “events: MidiNote[]”PianoRoll タブに置かれた 元ノート の配列。レンダー時の clip.notes が 読み取り専用 で渡されます(並びは編集時のまま — onNote の引数だけが startBeat 昇順)。
interface MidiNote { id: string; pitch: number; // 0..127 velocity: number; // 0..127 startBeat: number; lengthBeats: number;}// 元ノートの数だけを記録onInit(() => console.log("source notes:", events.length));ccLanes: ClipCcLane[]
Section titled “ccLanes: ClipCcLane[]”クリップに保存されている 元 CC レーン の配列(PianoRoll タブの CC レーン、または手動入力)。
interface ClipCcLane { id: string; ccNumber: number; // 0..127 events: MidiCcEvent[]; // [{ id, beat, value }, ...]}// CC11 のレーンが存在するかチェックonInit(() => { const expr = ccLanes.find((l) => l.ccNumber === 11); console.log(expr ? `CC11 has ${expr.events.length} events` : "no CC11");});sampleCc(ccNumber, beat): number
Section titled “sampleCc(ccNumber, beat): number”入力 ccLanes から ccNumber のレーンを探し、beat の値を線形補間して返します(float、整数化やクランプは呼び出し側で)。Rust エンジンの再生時補間と同じセマンティクスなので、sampleCc で読んだ値に LFO を足して setCc で書き戻すと、聴こえる結果と数値が一致します。
| 状況 | 戻り値 |
|---|---|
ccNumber のレーンが存在しない / events が空 | 0 |
beat が最初の点より前 | 最初の点の value(hold-back) |
beat が最後の点より後 | 最後の点の value(hold-forward) |
同じ beat に複数点 | 配列順で最後の点(last-wins) |
// 既存 CC7 にゆらぎを足して書き戻すonCc(({ beat, phase }) => { const base = sampleCc(7, beat); setCc({ ccNumber: 7, value: clamp(base + 10 * lfo(phase, "sin"), 0, 127) });});[!CAUTION]
sampleCcは 入力ccLanesからだけ読みます。同じレンダー中にsetCcで書いた値は読み返せません(鶏卵問題)。
時間グローバル
Section titled “時間グローバル”| 名前 | 型 | 内容 |
|---|---|---|
CLIP_BEAT | number | 現在のフェーズに対応するビート(onInit=0, onBeat=グリッド位置, onNote=startBeat, onCc=サンプリンググリッドの位置) |
CLIP_TIME | number | CLIP_BEAT / bpm * 60(秒) |
CLIP_LENGTH | number | クリップ長(ビート数)。レンダー中は不変 |
更新の仕組みについては ライフサイクル:CLIP_BEAT / CLIP_TIME / CLIP_LENGTH の更新メカニズム を参照。
// クリップの最後の 4 分音符だけ強調onNote((n) => { const isLast = n.startBeat >= CLIP_LENGTH - 1; setNote({ ...n, velocity: isLast ? 120 : n.velocity });});seededRandom(): number
Section titled “seededRandom(): number”mulberry32 由来の [0, 1) の擬似乱数。デフォルトシードは「コード本文 + 元ノート + ロード中の lib」のハッシュ。再現可能。
// 同じコード・同じ元ノート・同じ lib なら毎回同じ並びconst r1 = seededRandom();const r2 = seededRandom();seed(n: number | string): void
Section titled “seed(n: number | string): void”シードを上書き。文字列は内部でハッシュされて 32 ビット整数シードになります。
seed("variation-A");const a = seededRandom(); // 同じ文字列なら毎回同じ値seed(42);const b = seededRandom();[!IMPORTANT]
factory.jsのrandom()/randomInt()/pick()/chance()/weighted()/shuffle()/urn()/drunk()はMath.random()ベース でシードの影響を受けません。再現性が必要な場面ではseededRandom()を直接使ってください。 詳しくは ヘルパー:数値・乱数・モジュレーション > 乱数 を参照。
console.log(...args)
Section titled “console.log(...args)”引数は文字列化されて Code タブのコンソールに表示されます。
- 文字列はそのまま
- それ以外は
JSON.stringifyで文字列化(循環参照・関数値は[object Object]等になる) console.warn/console.errorは提供されません
onNote((n) => console.log("note:", n.pitch, "@", n.startBeat));// → "note: 60 @ 0.5"[!TIP] 大量のログを出すと Code タブの描画が重くなります。デバッグが終わったら消しましょう。
内部仕様メモ
Section titled “内部仕様メモ”これらは普段意識しなくても問題ありませんが、トラブルシュート時に役立ちます。
- ユーザコードは
new Function("__api", ...)でコンパイルされる「スクリプトコンテキスト」で動きます。thisはグローバル、argumentsは使えますが、モジュールスコープではありません CLIP_BEAT/CLIP_TIMEはラッパー内のletバインディング。各コールバック直前に__sync()が更新するので、ユーザのクロージャは 呼び出し時点の値 を見ますsetNote/setCcのidはcrypto.randomUUID()で自動付与setCcの同じccNumberは内部Mapに bucket されたあと、レーンごとにbeat昇順でソートされて返されます