プリセットを作る

🧩 プリセットの型と最小例

全378個に共通する型(BasePreset + 4メソッド)と、円が低音で膨らむ最小プリセット。

🧩 プリセットの型と最小例

🏗️ 378個は全部「同じ型」でできている

plasma-waveequalizerhypnotic も、骨格が完全に同じ。 BasePreset を継承して、メソッドを埋めるだけ。

import BasePreset from '../base-preset.js';

export default class XxxPreset extends BasePreset {
  constructor() {                    // ① 準備
    super();
    this.params = { barCount: 64 };  // 調整つまみ
    this.audio = { bass:0, mid:0, treble:0, rms:0, strength:0 };  // 音をしまう箱
    this.beatFlash = 0;              // 自分用の状態
  }

  setup(container) {                 // ② p5を起動
    this.destroy();
    const preset = this;             // ← this の罠よけ(下記)
    this.p5 = new p5((p) => {
      p.setup = () => { /* 最初に1回:canvas を作る */ };
      p.draw  = () => { /* 毎フレーム:絵を描く ← ここが本体 */ };
    }, container);
  }

  updateAudio(audioData) {           // ③ 音を受け取る(毎フレーム)
    this.audio.bass = audioData.bass || 0;   // 7つを箱にコピー
    // ...
  }

  onBeat(strength) {                 // ④ 拍が来たら
    this.beatFlash = strength;
  }
}

🎭 各パートの役割

  • constructor = 準備。つまみ(params)・音をしまう箱(audio)・状態変数を初期化
  • setup = p5 を起動。p.setup(最初に1回)と p.draw(毎フレーム)を定義
  • updateAudio = 配達されてくる音を箱にメモ(毎フレーム呼ばれる)
  • onBeat = 拍が来た瞬間に呼ばれる

👑 `BasePreset`(親クラス、`base-preset.js`)がやってくれること

  • 空の setup / updateAudio / onBeat を用意 → サブクラスが上書きする(これが「型」)
  • setParam(key, value) = つまみ調整
  • destroy() = 後片付け(WebGL コンテキストを解放 + p5.remove())。 プリセットは setup の頭で this.destroy() を呼ぶだけ。

⚠️ なぜ後片付けが必須か モバイルは GPU コンテキストが8個までで、掃除しないと「Too many active WebGL contexts」で落ちる。 だから destroy() で確実に解放する。これを BasePreset が肩代わりしてくれている。

🪤 `const preset = this;` の謎

p.draw の中に入ると、そこは p5 の世界になって this が p5 を指してしまう。 だから setup の頭で外側の this(プリセット本体)を preset に退避し、 draw からは preset.audio.bass で触る。全プリセット共通の定石。

⭕ 最小プリセット例:円が低音で膨らむ

説明用の世界一シンプルなプリセット。真ん中に円を描いて、低音が鳴ると大きくなるだけ。

import BasePreset from '../base-preset.js';

export default class MyCirclePreset extends BasePreset {
  constructor() {
    super();
    this.audio = { bass: 0 };          // ① 音をしまう箱
  }

  setup(container) {
    this.destroy();
    const preset = this;
    this.p5 = new p5((p) => {
      p.setup = () => {
        p.createCanvas(container.clientWidth, container.clientHeight);
      };
      p.draw = () => {
        p.background(0);                              // 画面を黒で塗る
        const size = 100 + preset.audio.bass * 300;  // 低音で大きく
        p.circle(p.width/2, p.height/2, size);       // 真ん中に円
      };
    }, container);
  }

  updateAudio(audioData) {
    this.audio.bass = audioData.bass || 0;           // ③ 低音を箱に入れる
  }
}

やっていることは3つだけ:

  1. 箱を用意する(this.audio = { bass: 0 })
  2. 円を描く(p.circle(...)p.draw の中で毎フレーム)
  3. 音を箱に入れて、円の大きさに使う(updateAudiopreset.audio.bass)

equalizer も hypnotic も plasma-wave も、この3つに飾りを足しただけ。骨はこの円と同じ。

📮 「音を箱に入れる」の流れ

音の数字は自分で作るのではなく、VJam 本体が毎フレーム配達してくる

① VJam本体「今の低音は 0.8!」
        ↓ updateAudio(audioData) で配達
② 箱にメモ:  this.audio.bass = 0.8
        ↓
③ p.draw が箱を見る:  size = 100 + preset.audio.bass * 300
                      = 100 + 0.8 * 300 = 340 → 円が大きくなる

郵便受けの例え:

  • updateAudio = 郵便受けに手紙(音)が届く瞬間
  • 箱(this.audio)= 机に手紙を置いておく
  • p.draw = その手紙を見て絵を描く

なぜ箱を経由する? → 音が届く場所(updateAudio)と絵を描く場所(p.draw)が別々だから。 届いた音を一旦メモしておかないと、draw が「今の音いくつ?」と見れない。

© 2022-2025 infoHiroki. All rights reserved.