コンテンツにスキップ

トラブルシュート

new Function() のコンパイル時に構文エラー。

  • まず該当行の中括弧・括弧・セミコロンを確認
  • import ... を残しているとここで出ることがあります(user code 側ではなく lib 側で発生したケース)
  • 矢印関数の引数名が予約語(for, if 等)になっていないか

ユーザコードの トップレベル で例外。onInit 等の中ではなく、最初のスキャン時です。

const sc = scale("foo", 60); // ← unknown name 'foo' ここで死ぬ
onInit(() => { ... }); // ← ここまで届かない

Runtime error (onInit / onBeat / onNote / onCc): ...

Section titled “Runtime error (onInit / onBeat / onNote / onCc): ...”

そのフェーズのコールバック内で例外。

  • スタックトレースは出ません — エラーメッセージから推定してください
  • 例:pick([])pick(): array is emptyscale("foo", 60)scale: unknown name 'foo'degree([], 0)degree: empty scale
  • それまでに出たノート / CC は保持されます(ライフサイクル:エラーが起きたら何が残るか
  1. PianoRoll タブと Render タブを取り違えていないか確認。再生は Render の結果が使われます
  2. ▶ Render を実行したか — Code タブの編集だけでは反映されません
  3. setNote ではなく noteOn引数順pitch, lengthBeats, velocity, startBeat)を確認
  4. pitch0..127 の外だとクランプされるので、想定外の音高に丸まっていないか
  5. onNote 内で setNote(...) を呼んでいない場合、その元ノートは Render に出ません
  • onBeat のグリッドは 16 分音符固定。三連符など別解像度は b を見て間引く必要があります(ヘルパー:リズム > 解像度を変える
  • 浮動小数比較は < 1e-6 のトレランスで(b % 1 === 0.5 は誤差で落ちることがある)
  • onBeat の中でループを回すと指数的に増えがち。実数値で比較してから間引いてください
  • 1 クリップで 1000 ノート程度を上限の目安に
  1. onCc 自体が登録されているか — 登録ゼロなら掃引は走りません(入力 ccLanes の有無は無関係)
  2. setCcccNumber0..127 の範囲外で渡していないか
  3. value が小数なら Math.round 済みの値が出力されます(0..127 クランプ済み)

Runtime error (onCc): grid sweep would emit ... ticks, exceeding cap (32768)

Section titled “Runtime error (onCc): grid sweep would emit ... ticks, exceeding cap (32768)”

setCcResolution × CLIP_LENGTH の合計 tick 数が 32,768 を超えています。

  • 解像度を下げる(既定の 16 で大半の用途に十分)
  • クリップを短くする
  • 早期 onInit / onBeat / onNote で出した結果は保持されているので、エラー後も部分結果は残ります

setCcResolution を呼んでもグリッドが変わらない

Section titled “setCcResolution を呼んでもグリッドが変わらない”

トップレベル または onInit から呼んでください。onBeat / onNote / onCc の中での呼び出しは黙って無視されます(onCc 掃引の直前にスナップショットされるため)。

setCcccNumber で bucket されます。同じ ccNumber への複数呼び出しは 1 レーンに集約されます。意図的に別レーンにしたいなら ccNumber を変えてください。

毎回違う結果が出る(再現性が欲しい)

Section titled “毎回違う結果が出る(再現性が欲しい)”

factory.jsrandom() / randomInt() / pick() / chance() / weighted() / shuffle() / urn() / drunk()Math.random() ベース で、シードの影響を受けません。

対処

  • seededRandom() を直接使う(seededRandom
  • seed("ラベル") で明示的にシードを固定する
seed("v1");
const r = seededRandom(); // 同じ "v1" なら毎回同じ

コードを 1 文字変えただけで乱数が変わる

Section titled “コードを 1 文字変えただけで乱数が変わる”

デフォルトシードは hash(code + JSON.stringify(events) + libSources) です。コードを変えるとシードが変わります。結果を固定したいなら seed() で明示 してください。

libsLoaderpath + mtime + size をキーにキャッシュしており、.js ファイルを保存すると次回 Render から反映されます。ただし、

  • 開いているクリップは自動再 Render されません
  • ユーザコードを 1 文字編集して ▶ Render するか
  • ファイルブラウザで lib のチェックを off → on で再ロード

stripModuleSyntax()import / export 構文を行ベースで剥離します。export function add()function add() になり、user code から グローバル関数 として呼べます。

ただし、複数行にまたがる import 文(import {\n a,\n b,\n} from "...")は剥離できないので、1 行に圧縮するか削除してください。

  • ユーザコードはレンダーのたびに new Function() でコンパイルされます。コンパイル自体は数 ms 程度ですが、コードが長くなると増加 します
  • 大量の console.log は描画コストになります — デバッグ後は消す
  • ノート出力は数万件まで耐えますが、再生エンジン側の負荷は出力ノート数に比例します

実行時間に上限はありません。while (true) {}for (let i = 0; ; i++) は UI を完全に固めます。

  • CLIP_LENGTH を信頼してループ範囲を制限
  • アプリの再起動以外で抜ける手段はない(Cmd+Q / タスクマネージャ)ので注意
  1. console.log で各フェーズの実行回数や引数を確認
  2. 元ノートを 1 つだけにして最小再現を作る
  3. 最小コードで動くか確認 → 1 行ずつ足して切り分ける