Skip to content

Instantly share code, notes, and snippets.

@jinjor
Created July 13, 2025 02:19
Show Gist options
  • Save jinjor/bb327a7c317077b37c44b1a1f874bc25 to your computer and use it in GitHub Desktop.
Save jinjor/bb327a7c317077b37c44b1a1f874bc25 to your computer and use it in GitHub Desktop.

リファクタリング計画書

概要

このドキュメントは大規模なリファクタリングの設計と実装計画を記録するものです。

現状分析

現在のアーキテクチャ

Join ノードの実装

  • C++側: src/Node.hJoinNodeクラスが定義
    • 複数の入力(最大 5 つ)を受け取り、それらを加算して 1 つの出力に
    • step()メソッドで L/R チャンネルを個別に加算処理
  • フロントエンド: frontend/src/App.tsxnodeInfoとして定義
    • numberOfInputs: 5, numberOfOutputs: 1
    • UI では「+」アイコンで表示
  • グラフ構築: src/Voice.cppupdateGraph()でノード間接続を管理
  • パス挿入: frontend/src/component/graph/Path.tsxで「Insert Join」オプション提供

現在の接続フロー

osc.0 ─→ join ─→ filter.0 ─→ destination
osc.1 ─→ join ─→ filter.0 ─→ destination

関連する定数・enum

  • Parameters.h: MAX_JOINS = 5, NODE_KIND::Join
  • Voice.h: std::vector<std::shared_ptr<JoinNode>> joins配列

問題点・課題

UI/UX の問題

  • Join ノードが常に表示されることで、シンプルな接続でも中間ノードが必要
  • 「+」ボタンが視覚的なノイズとなり、直感的でない操作感

アーキテクチャの複雑性

  • 単純な 1 対 1 接続でも Join ノードが必要
  • グラフ構築時の不要な中間処理
  • メモリ使用量の増加(未使用の Join ノードインスタンス)

目標

改善すべき点

  1. Join ノードの完全削除

    • UI から「+」ボタンを削除
    • C++コードから JoinNode クラスを削除
    • 関連する定数・enum・配列を削除
  2. 直接接続の実現

    • osc.0 -> filter.0 の直接接続を可能に
    • 複数入力が必要な場合の新しいアーキテクチャ設計
  3. UI の簡素化

    • パス挿入メニューから Join オプションを削除
    • グラフ表示の視覚的な改善

期待される効果

  • ユーザビリティ向上: より直感的な操作性
    • 「filter に音源を追加したい」→ filter の"Add Input"をクリック
    • 中間の「+」ボタンが不要になり、直接的な操作が可能
    • グラフがよりシンプルで理解しやすく
  • パフォーマンス改善: 不要な中間処理の削除
  • メモリ効率: 未使用ノードインスタンスの削除
  • コードの簡素化: 保守性の向上
  • UI 一貫性: すべての入力可能ノードで統一された操作方法

設計方針

アーキテクチャ変更

新しい接続フロー

# 1対1接続の場合(従来通り)
osc.0 ─→ filter.0 ─→ destination

# 複数入力が必要な場合(新方式)
# ユーザーの視点
osc.0 ──┐
         ├─→ filter.0 ─→ destination
osc.1 ──┘

# 内部実装
osc.0 ──┐
         ├─→ [内部JoinNode] ──→ filter.0 ─→ destination
osc.1 ──┘

ノード入力管理の変更

  • 各ノードのaddInput()メソッドを改良
  • 単一入力: 従来通りの処理
  • 複数入力: 内部的にJoinNodeを自動作成
  • removeAllInputs()で内部JoinNodeもリセット

実装方針

  1. 後方互換性の維持

    • 既存のプロジェクトファイルで動作するように配慮
    • 段階的な移行アプローチ
  2. 安全な削除手順

    • フロントエンドから先に削除
    • バックエンドは最後に削除
    • 各段階でのテスト実施

実装計画

フェーズ 1: 準備・分析

完了済み: 現状分析

  • Join ノードの実装詳細を確認
  • 複数入力を受け付けるノードの調査
  • 関連するファイルとコードの特定

次のステップ: 複数入力対応方針の決定

  • 採用方針: 内部的なJoinNodeの活用
  • コンセプト: UI から Join ノードを削除しつつ、バックエンドでは既存のJoinNodeを内部的に使用
  • 理由:
    • 既存の実装を最大限再利用
    • 各ノードの単一入力制約を保持
    • 大幅な変更を避けて安全にリファクタリング
    • UI 改善と実装安定性の両立
  • 改善点:
    • ユーザーには直感的な直接接続が見える
    • 複数入力時も内部的に安定した処理
    • 既存のJoinNodeのテスト済み実装を活用

フェーズ 2: 実装

2.1 フロントエンド削除・UI 改善(優先度: 高)

Join 関連の削除:

  • frontend/src/App.tsx: nodeInfo から join エントリを削除
  • frontend/src/component/graph/Path.tsx: "Insert Join"メニューオプションを削除
  • frontend/src/Icon.tsx: join アイコンを削除(または非使用にマーク)

"Add Input"機能の移行:

  • frontend/src/component/graph/Node.tsx: 入力可能ノードの "Add Input" 表示ロジック変更
    • 現在: join ノードのみ "Add Input" 表示
    • 新方針: filter, pan, destination など入力可能な全ノードで "Add Input" 表示
    • 表示条件: hidden: numberOfConnectedInputs >= numberOfInputs(変更なし)
  • frontend/src/App.tsx: nodeInfo の numberOfInputs 調整
    const nodeInfo: Record<string, NodeInfo> = {
      filter: {
        numberOfInputs: 5, // 複数入力対応(内部的にJoinNode使用)
        numberOfOutputs: 1,
        icon: icons.filter,
        primary: true,
      },
      pan: {
        numberOfInputs: 5, // 複数入力対応
        numberOfOutputs: 1,
        icon: icons.pan,
        primary: true,
      },
      dest: {
        numberOfInputs: 5, // 複数入力対応
        numberOfOutputs: 0,
        icon: icons.dest,
        primary: false,
      },
      // join エントリは削除
    };
  • 動作確認: handleAddInputNode(node.index) の流れ
    1. ユーザーが filter の"Add Input"をクリック
    2. onAddInputNode()handlers.handleAddInputNode(node.index)
    3. addInputNode(toRefIndex) native function 呼び出し
    4. バックエンドで新しい osc が作成され、filter に接続
    5. バックエンドの FilterNode::addInput()で内部的に JoinNode を作成(2 つ目以降の入力)

2.2 バックエンド複数入力対応(優先度: 高)

  • src/Node.h: 複数入力を受け取る可能性のあるノードを内部JoinNode対応に変更
    • FilterNode, DestinationNode, PanNodeなどに適用
    • addInputが複数回呼ばれた場合に内部的にJoinNodeを作成
    • 既存の単一入力の場合はそのまま、複数入力の場合は自動的にJoinNode経由に
  • 実装例: FilterNode::addInput()の改良
    void addInput(std::shared_ptr<AudioNode> newInput) override {
        if (this->input == zero) {
            this->input = newInput;  // 最初の入力はそのまま
        } else if (this->internalJoin == nullptr) {
            // 2つ目の入力で内部JoinNodeを作成
            this->internalJoin = std::make_shared<JoinNode>();
            this->internalJoin->addInput(this->input);
            this->internalJoin->addInput(newInput);
            this->input = this->internalJoin;
        } else {
            // 3つ目以降は内部JoinNodeに追加
            this->internalJoin->addInput(newInput);
        }
    }

2.3 パラメータ・列挙型の整理(優先度: 中)

  • src/Parameters.h:
    • MAX_JOINS定数を削除(内部的なJoinNodeは動的に作成するため不要)
    • NODE_KIND::Joinを enum から削除
    • NODE_KIND_NAMESから join を削除
    • JoinParamsクラスを削除(UI からの制御が不要になるため)
  • src/Voice.h: joins配列を削除
  • src/Voice.cpp: joins の初期化・参照を削除

2.4 JoinNode クラスの保持と改良(優先度: 低)

  • src/Node.h: JoinNodeクラスはそのまま保持
    • 内部的な使用のため、インターフェースの調整のみ
  • 関連する switch 文から Join ケースを削除(UI からの作成は不要)
  • JoinNodeを内部専用クラスとしてリファクタリング

フェーズ 3: 検証・最適化

3.1 機能テスト

  • 基本的な音声出力の確認
  • 複数オシレーターからの直接接続テスト
  • 既存プロジェクトファイルの互換性テスト

3.2 パフォーマンステスト

  • メモリ使用量の削減確認
  • 処理速度の改善測定
  • 音声品質の確認

3.3 UI テスト

  • グラフ表示の動作確認
  • ノード追加・削除操作の確認
  • 直感的な操作性の向上確認

リスク管理

想定されるリスク

  1. 音声出力の不具合

    • 内部JoinNodeの動的作成によるメモリ管理の問題
    • 複数入力の加算処理でノイズや音量問題
    • 依存関係の順序が変わることによる音質変化
  2. 既存プロジェクトの互換性問題

    • 保存されたプロジェクトファイルが読み込めない
    • パラメータの参照エラー
  3. パフォーマンスの劣化

    • 予期しない処理負荷の増加
    • メモリリークの発生
  4. UI 操作の混乱

    • 既存ユーザーの操作方法の変更
    • グラフ表示の不具合

対応策

  1. 段階的なテスト実施

    • 各フェーズで十分な動作確認
    • 音声品質の詳細チェック
    • 内部JoinNodeの動的作成・削除のメモリリークテスト
  2. バックアップと復旧計画

    • 変更前の状態を git で管理
    • 問題発生時の即座な復旧手順
  3. 互換性保持

    • 既存の保存形式をサポート
    • 徐々に新形式へ移行
  4. ユーザーフィードバック

    • ベータ版での事前テスト
    • 操作性の改善点を収集

参考資料

関連ファイル

  • src/Node.h - オーディオノードの基底クラス
  • src/Voice.cpp - グラフ構築ロジック
  • src/Parameters.h - パラメータ管理
  • frontend/src/App.tsx - フロントエンドのメインコンポーネント
  • frontend/src/component/graph/Path.tsx - パス挿入 UI

技術的な参考

  • JUCE オーディオプロセッサーのアーキテクチャ
  • トポロジカルソートによるノード実行順序
  • React と C++の連携方法

Last updated: 2024 年 12 月現在

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment