Skip to content

Yasuna-Ide/bitcode

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 

Repository files navigation

BITCODE — Chiptune Live Coder

1. コンセプト

BITCODE は、初代 Game Boy(DMG-01)のサウンドチップ LR35902 の4チャンネル構成を制約として積極的に活用する、ブラウザベースのチップチューン・ライブコーディング言語である。

設計の核心

Strudel が TidalCycles のパターン言語を Web に持ち込んだように、BITCODE は DMG音源の制約そのものをパターン言語として再定義 する。自由度の高い汎用シンセシスではなく、4bit音量・矩形波のデューティ比・32サンプル波形メモリ・LFSRノイズという限られたパラメータ空間のなかでパターンを操作することが、この言語の美学的・設計的なアイデンティティとなる。

UIは完全な1bitモノクロ(#fff / #000 の2色のみ)で構成され、視覚面でも「制約の美学」を体現する。

Strudel との関係

  • 共有するもの: サイクルベースのパターン・モデル、ミニノーテーション風の簡潔な記法、メソッドチェーンによる変換の合成、ブラウザ完結
  • 異なるもの: 音源が Web Audio API の汎用ノードではなく DMG の4チャンネルに固定される。チャンネルの物理的制約(同時に1音しか鳴らないモノフォニック構造)がパターン設計に影響する。パラメータ空間が離散的・有限(4bitの16段階音量、4種のデューティ比 etc.)

2. チャンネル・アーキテクチャ

┌─────────────────────────────────────────┐
│             BITCODE Engine              │
│                                         │
│  p1  ──▶  [CH1: Pulse+Sweep]  ──┐       │
│  p2  ──▶  [CH2: Pulse      ]  ──┤       │
│  p3  ──▶  [CH3: Wave Memory]  ──┼──▶ 🔊 │
│  n1  ──▶  [CH4: Noise      ]  ──┘       │
│                                         │
│  Each channel: 1 persistent oscillator  │
│  New event→ immediately overwrites prev │
│  Master gain: 2.5                       │
└─────────────────────────────────────────┘

4つの関数が4つのチャンネルに1対1で対応する。各チャンネルは固定の発音体を1つだけ保持し、新しいイベントが到達すると前の音(リリース途中であっても)を強制的に上書きする。これは DMG 実機と同じ動作であり、「4チャンネルをどう使い分けるか」という作曲的思考を強制する設計上の意図的な制約である。

3. 言語構文

3.1 基本:ノートパターン

// CH1: 矩形波でメロディ
p1("c4 e4 g4 c5")

// CH2: 矩形波でハーモニー / 対旋律
p2("c3 ~ e3 ~")

// CH3: 波形メモリで低音
p3("c2 c2 g2 g2")

// CH4: ノイズでリズム
n1("h l ~ h")   // h=high(短周期/7bit), l=low(長周期/15bit)

3.2 ミニノーテーション

TidalCycles / Strudel のミニノーテーション構文を採用する:

記法 意味
スペース区切り サイクル内の等分割
~ 休符
[ ] サブディビジョン(時間の細分化)
< > オルタネート(サイクルごとに交替)
*n 繰り返し
? 確率的発音(50%の確率)
// サブディビジョン:16分音符的な動き
p1("c4 [e4 g4] a4 [g4 e4]")

// オルタネート:サイクルごとに交替
p1("<c4 e4 g4 c5> <e4 g4 b4 e5>")

// 繰り返し
n1("h*4 l*2 h l")

// 確率的発音
n1("h l? h ~")   // l が50%の確率で発音

3.3 チップチューン固有パラメータ

デューティ比(CH1, CH2)

p1("c4 e4 g4 c5").duty(50)            // 全ノート一律 50%
p1("c4 e4 g4 c5").duty("12 25 50 75") // 音ごとにパターン化
// 値: 12(=12.5%), 25, 50, 75

音量(全チャンネル)

p1("c4 e4 g4 c5").vol(8)              // 一律 (0-15)
p1("c4 e4 g4 c5").vol("15 12 8 4")    // パターン化

音量エンベロープ(全チャンネル)

DMG のエンベロープ: 初期音量(0-15)、方向(up/down)、速度(1-7)

p1("c4 e4 g4 c5").env(15, "down", 3)
// 音量15から減衰、速度3

波形メモリ(CH3 のみ)

// プリセット波形
p3("c3 e3 g3 c4").wave("tri")       // 三角波
p3("c3 e3 g3 c4").wave("saw")       // 鋸歯波
p3("c3 e3 g3 c4").wave("sin")       // 正弦波風
p3("c3 e3 g3 c4").wave("sqr")       // 矩形波

// 波形を16進数で直接記述(32文字 = 32サンプル × 4bit)
p3("c3").wave("0123456789abcdeffedcba9876543210")

// 波形のパターン化(サイクルごとに交替)
p3("c3 e3 g3 c4").wave("<tri saw sin>")

ノイズモード(CH4)

n1("h l h l")                     // h=短周期(7bit), l=長周期(15bit)
n1("h l h l").env(15, "down", 1)  // エンベロープ付き

3.4 パターン変換

変換 構文 説明
倍速 .fast(n) パターンをn倍速で繰り返す
減速 .slow(n) パターンをn倍遅く
逆行 .rev() パターンを逆順再生
周期的変換 .every(n, fn) nサイクルごとにfnを適用
確率的変換 .sometimes(fn) 50%の確率でfnを適用
高確率変換 .often(fn) 75%の確率でfnを適用
低確率変換 .rarely(fn) 25%の確率でfnを適用
回文 .palindrome() 偶数サイクルで逆行
回転 .rotate(n) パターンをn要素分ずらす
p1("c4 e4 g4 c5").fast(2)
p1("c4 e4 g4 c5").every(4, x => x.fast(2))
p1("c4 e4 g4 c5").sometimes(x => x.duty(12))
p1("c4 e4 g4 c5").palindrome()
p1("c4 e4 g4 c5").rotate(2)

// 変換の合成:4サイクルごとに逆行の倍速
p1("c4 e4 g4 c5").every(4, x => x.rev().fast(2))

3.5 チップチューン固有エフェクト

// アルペジオ:1ノートを高速にピッチ切替(半音間隔で指定)
p1("c4 e4").arp("0 4 7")          // 長三和音アルペジオ

// スウィープ:周波数を連続的に変化(CH1推奨)
p1("c4 ~ c4 ~").sweep(3, "up")    // 上昇スウィープ、速度3
p1("c5 ~ c5 ~").sweep(3, "down")  // 下降スウィープ

// エコー:音量減衰の擬似ディレイ
p1("c4 e4 g4 c5").echo(3, 0.25)   // 3回反復、間隔0.25

// グリッサンド:次のノートへ離散的にスライド
p1("c4 ~ c5 ~").gliss(4)          // 4ステップでスライド

3.6 チャンネル制御

p1("c4 e4 g4 c5").solo()   // このチャンネルのみ再生
p2("c3 e3 g3 c4").mute()   // このチャンネルをミュート

4. グローバル制御

bpm(140)        // テンポ設定
hush()          // 全チャンネル停止

5. UI 設計

レイアウト

┌──────────────────────────────────────────┐
│  BITCODE  v0.3      ▶ PLAY  ■ STOP  BPM  │  ← ヘッダー(固定)
├──────────────────────────────────────────┤
│ 1│ bpm(104)                              │
│ 2│                                       │
│ 3│ p1("~ a4 c5 ~ e5 ~ d5 c5 ~ a4 ~ g4")  │
│ 4│   .duty("<50 25 50 25>")              │  ← CodeMirror エディタ
│ 5│   .env(11, "down", 4)                 │    行番号・ハイライト付き
│ 6│   .rotate(1)                          │
│ 7│   .every(4, x => x.rev())             │
│  │                                       │
│  │ Error message (inline display)        │
├──────────────────────────────────────────┤
│  [CH1]   [CH2]   [CH3]   [CH4]           │  ← チャンネルモニタ
│  ------------ Waveform Scope ----------- │  ← AnalyserNode波形表示
│  p1 p2 pulse · p3 wave · n1 noise  │ ... │  ← ヘルプ
└──────────────────────────────────────────┘

カラーパレット

完全1bitモノクロ:

  • #ffffff — 背景
  • #000000 — テキスト、ボーダー、すべてのUI要素

中間色を一切使わない。この制約がBITCODEの視覚的アイデンティティとなる。

CodeMirror エディタ

CodeMirror 5 を統合し、カスタム bitcode モードによるシンタックスハイライトを実装。1bitモノクロ制約の中で、太字・イタリック・透明度の3軸で構文要素を視覚的に分離する。

構文要素 スタイル
p1 p2 p3 n1 チャンネル名 太字
bpm hush グローバル関数 太字
.duty() .fast() 等メソッド イタリック
// コメント 薄い(opacity 35%)
ミニノーテーション内ノート c4 e5 太字
ノイズトークン h l 太字
休符 ~ 薄い(opacity 30%)
[ ] < > ( ) 括弧 太字
=> アロー 太字
コールバック変数 x イタリック

追加機能:

  • 行番号表示
  • 括弧の対応ハイライト(matchBrackets
  • 括弧の自動閉じ(autoCloseBrackets
  • アクティブ行のハイライト(styleActiveLine

エラー表示

エラーはエディタ最下行の直下に CodeMirror のインラインウィジェットとして表示する。メソッド名のスペルミスに対しては、レーベンシュタイン距離による「did you mean ...?」サジェストを提供する。

  .evry(4, x => x.fast(2))
✕ x.evry is not a function — did you mean .every()?

チャンネルモニタ

各チャンネルのアクティブ状態をモノクロ反転で表示する。.solo() 時は「S」、.mute() 時は「M」を表示。

波形スコープ

AnalyserNode に接続されたリアルタイム波形スコープ。HiDPI(devicePixelRatio)対応。

操作

  • Ctrl+Enter (Mac: ⌘+Enter): コードを評価し再生開始 / パターン更新
  • ▶ PLAY / ⟳ EVAL: ボタンによる評価
  • ■ STOP: 全停止

6. 技術アーキテクチャ

┌───────────────────────────────────────────┐
│                 Browser                   │
│                                           │
│  ┌───────────┐   ┌──────────────────┐     │
│  │ CodeMirror│──▶│  Pattern Engine  │     │
│  │ Editor    │   │                  │     │
│  │           │   │ - Mini-notation  │     │
│  │ bitcode   │   │   Tokenizer      │     │
│  │ mode +    │   │ - Pattern class  │     │
│  │ 1bit theme│   │   (query model)  │     │
│  └───────────┘   │ - Transforms     │     │
│                  └───────┬──────────┘     │
│                          │ events         │
│                  ┌───────▼──────────┐     │
│                  │   Scheduler      │     │
│                  │ 150ms lookahead  │     │
│                  │ 50ms interval    │     │
│                  └───────┬──────────┘     │
│                          │ noteOn/Off     │
│                  ┌───────▼──────────┐     │
│                  │  GB Sound Engine │     │
│                  │  (Persistent     │     │
│                  │   Oscillators)   │     │
│                  │                  │     │
│                  │ CH1: OscNode     │     │
│                  │    + PeriodicWave│     │
│                  │ CH2: OscNode     │     │
│                  │    + PeriodicWave│     │
│                  │ CH3: OscNode     │     │
│                  │    + PeriodicWave│     │
│                  │ CH4: BufSrc × 2  │     │
│                  │    + LFSR xfade  │     │
│                  │                  │     │
│                  │ Master (2.5) ──▶ │     │
│                  │  AnalyserNode ──▶│     │
│                  │   Destination    │     │
│                  │                  │     │
│                  │ Web Audio API    │     │
│                  └──────────────────┘     │
└───────────────────────────────────────────┘

CodeMirror エディタ

  • CodeMirror 5.65.7 を CDN から読み込み
  • カスタム bitcode モードで構文トークナイズ(文字列内のミニノーテーション構文も認識)
  • カスタム bitcode テーマ(完全1bitモノクロ、太字/イタリック/透明度による分離)
  • アドオン: matchBrackets, autoCloseBrackets, styleActiveLine
  • エラー表示: addLineWidget によるインラインウィジェット
  • Ctrl+Enter / ⌘+EnterextraKeys で評価にバインド

パターンエンジン

  • Pattern<T>: 時間区間 → イベント列 の関数。Strudel と同じ「時間を問い合わせるとイベントが返る」モデル
  • MiniNotation Tokenizer: 再帰的トークナイザ。[ ] でネスト、< > でオルタネート、*n で繰り返し、? で確率的発音
  • パラメータ: .duty() 等で返される新しい Pattern インスタンスにパラメータが付与される(イミュータブルチェーン)
  • 変換: .fast(), .rev(), .sometimes(), .palindrome(), .rotate() 等は元の Pattern を包む新しい Pattern を返す(関数合成)
  • Proxy バインディング: チャンネルに紐づいた Pattern のメソッドチェーンが、自動的にスケジューラのチャンネルスロットを更新する

スケジューラ

  • AudioContext.currentTime を参照し、150ms 先読みでイベントを発行
  • 50ms 間隔の setTimeout ループ
  • サイクル単位でパターンにクエリを投げ、イベントを Web Audio API の時間に変換
  • パラメータ文字列パターン(duty, vol)をステップインデックスで解決
  • .solo() / .mute() フラグによるチャンネルフィルタリング

GB Sound Engine — 永続オシレーター・アーキテクチャ

実機 DMG と同じく、各チャンネルに固定の発音体を1つだけ保持する。新しいイベントが到達すると、前の音のリリース途中であっても即座に上書きされる(モノフォニック強制切替)。ノードの生成・破棄が不要なため、効率的かつクリーンな停止が可能。

  • CH1/CH2: 永続 OscillatorNode + GainNode(各1組)
    • PeriodicWave でデューティ比を合成(フーリエ係数、結果キャッシュ)
    • ノートオン: frequency.setValueAtTime() でピッチ即時切替、gain で音量セット
    • ノートオフ: gain をゼロにセット(前の音は強制的に上書きされる)
    • アルペジオ: 同一 Oscillator の frequency.setValueAtTime() を35ms間隔で連続切替
    • スウィープ: 周波数を段階的に変化、音量も同時に減衰
    • エコー: 同一チャンネル上で音量減衰させた複数イベントをスケジュール
    • グリッサンド: 2ノート間を離散ステップで周波数遷移
  • CH3: 永続 OscillatorNode + GainNode
    • 32サンプル×4bit の波形データを DFT で PeriodicWave に変換
    • 波形が変更された時のみ setPeriodicWave() で更新
    • プリセット4種(tri, saw, sin, sqr)+ 16進数直接記述 + <> パターン化
    • サイクル番号を受け取り、波形オルタネートを解決
  • CH4: 永続 AudioBufferSourceNode × 2(短周期7bit + 長周期15bit を常時ループ再生)
    • GainNode のクロスフェードで短周期/長周期を即時切替
    • 両ソースを同時に走らせ、不使用側はゲイン0で無音化
  • エンベロープ: GainNode.gain.setValueAtTime() で離散ステップ制御
  • マスター: GainNode(gain: 2.5)→ AnalyserNodeAudioContext.destination
  • 停止処理: cancelScheduledValues() + 即時ゼロで全ボイスを無音化。ノード破棄不要

エラー処理

  • new Function() による eval で例外をキャッチ
  • "is not a function" エラーに対し、レーベンシュタイン距離2以内の既知メソッド名をサジェスト
  • エラーは CodeMirror の addLineWidget でエディタ末尾にインライン表示
  • 次の評価時に前のウィジェットを自動クリア

7. 実装状態

Phase 1: MVP ✅ 完了

  • p1〜p3 のノートパターン + n1 のノイズパターン
  • ミニノーテーション(スペース区切り、[ ]~
  • .duty(), .wave(), .vol(), .env() の基本パラメータ
  • .fast(), .slow(), .rev(), .every() の基本変換
  • パラメータの文字列パターン化(duty, vol)
  • textarea エディタ + Ctrl+Enter 評価
  • チャンネルモニタ + 波形スコープ
  • 1bit モノクロ UI
  • bpm() / hush() グローバル制御

Phase 2: 表現力の拡張 ✅ 完了

  • < > オルタネート(ミニノーテーション内)
  • *n 繰り返し
  • ? 確率的発音(50%)
  • .sometimes() / .often() / .rarely() 確率的変換
  • .palindrome() 回文変換
  • .rotate(n) 回転変換
  • .arp() アルペジオ(半音間隔指定、35ms切替)
  • .sweep() 周波数スウィープ(速度・方向指定)
  • .echo() 擬似ディレイ(反復回数・間隔指定)
  • .gliss() グリッサンド(次ノートへの離散ステップ遷移)
  • 波形メモリの16進数直接記述(32文字)
  • 波形のパターン化 .wave("<tri saw>")
  • .solo() / .mute() チャンネル制御
  • AnalyserNode 接続によるリアルタイム波形スコープ(HiDPI対応)
  • サイクルカウンタ表示
  • 永続オシレーター・アーキテクチャ(モノフォニック強制切替)

Phase 3: ライブコーディング環境の整備 ✅ 完了

  • CodeMirror 5 統合
  • カスタム bitcode シンタックスハイライトモード
  • 1bitモノクロテーマ(太字/イタリック/透明度)
  • 行番号表示
  • 括弧の対応ハイライト(matchBrackets)
  • 括弧の自動閉じ(autoCloseBrackets)
  • アクティブ行ハイライト(styleActiveLine)
  • エラーのインラインウィジェット表示
  • スペルミスの「did you mean」サジェスト(レーベンシュタイン距離)

既知の制限

  • パラメータ文字列(.duty(), .vol())では < > オルタネート構文を使用不可。スペース区切りの数値列のみ対応
  • .gliss() は次のノートが同一パターン内に存在する場合のみ動作
  • .sweep() は全チャンネルで動作するが、実機準拠では CH1 のみの機能
  • CH4 の fast() 高倍率(4以上)で setValueAtTime が密集しグリッチが発生する場合がある

Phase 4: 共有・配布(進行中)

  • キーボードショートカット拡充
  • モバイル対応
  • URLエンコードによるシェア機能
  • プリセット / サンプルコード集(UI内選択)

8. 設計上の注目点

制約が生む創造性

DMG の4チャンネル制限は、ライブコーディングにおいて「制約がクリエイティビティを駆動する」という原理を体現する。Strudel では無制限にチャンネルを追加できるが、BITCODE では物理的に4つしかない。この制約が:

  1. 選択の緊迫感: メロディに2チャンネル使うか、ベースに回すか
  2. チャンネル配分の実験: 同じ4chを異なるアレンジで再配分する
  3. 擬似ポリフォニーの技法: .arp() による高速ピッチ切替で和音を表現する、チップチューンの伝統的技法の再発見

離散パラメータ空間の美学

DMG のパラメータはすべて離散的:

  • 音量: 16段階 (4bit)
  • デューティ比: 4種類
  • 波形: 32サンプル × 4bit
  • ノイズ: 2モード × 8レート

この「粗い」パラメータ空間をパターン操作の対象にすることで、.duty("12 25 50 75") のように離散値を巡回させるデジタル特有のテクスチャが生まれる。

1bit UI の意味

完全な白黒2色のUIは、単なる装飾的選択ではない。音源の制約(4bit, 4ch, 4 duty cycles)に呼応する視覚的制約であり、「制約のなかで表現する」というBITCODEの設計思想をインターフェースの層でも一貫させるものである。CodeMirror のシンタックスハイライトも、色を一切使わず太字・イタリック・透明度の3軸だけで構文を区別する設計は、この思想の延長にある。

パターン・パラダイムへの転換

チップチューン制作は従来トラッカー(LSDj, FamiTracker, MML等)で行われてきた。これらは本質的にシーケンスの直接配置——「結果としての音楽」を構成するアプローチ——だ。BITCODE はこれを TidalCycles 由来の「パターンの変換」というパラダイムに転換する。every(4, x => x.fast(2).rev()) のような記述は、音の配置ではなく変換規則を操作する。この認知的転換が、チップチューンの制作に新しい思考法をもたらす。

永続オシレーターが強制するモノフォニック思考

各チャンネルに固定の発音体を1つだけ保持し、新しいイベントが前の音を即座に上書きする。これは DMG 実機と同じ動作であり、以下の設計効果を持つ:

  1. リリースの断裁: エンベロープの減衰途中であっても新しいノートが容赦なく切り替わる。この「切れ方」がチップチューン特有のアーティキュレーションを生む
  2. チャンネルの物理性: 1チャンネル=1音という絶対的制約が、ノード生成ベースの実装では曖昧だった「同時にひとつしか鳴らない」原則を厳密に実現する
  3. パフォーマンス: ノードの生成・破棄がなく、setValueAtTime によるスケジューリングのみで動作するため、長時間のライブコーディングセッションでも安定する

Phase 2 → Phase 3 の質的変化

Phase 2 で表現力の拡張(確率変換、アルペジオ、波形パターン化等)が完了し、Phase 3 で CodeMirror 統合・エラー処理が加わったことで、BITCODE は「実験的な音源エンジン」から「ライブコーディング環境」への転換を遂げた。シンタックスハイライトは単なる見た目の改善ではなく、コードの構造を即座に把握しリアルタイムで書き換えるライブコーディングの実践において不可欠な認知的支援である。

9. サンプルセッション

// === "The Sealed Forest" ===
bpm(104)

// CH1: A winding melody through the trees
// rotate makes the path shift each cycle
p1("~ a4 c5 ~ e5 ~ d5 c5 ~ a4 ~ g4")
  .duty("<50 25 50 25>")
  .env(11, "down", 4)
  .rotate(1)
  .every(4, x => x.rev())
  .every(7, x => x.arp("0 3 7"))

// CH2: Distant bells, echoing through canopy
p2("~ ~ ~ e5 ~ ~ ~ ~ a5 ~ ~ ~")
  .duty(12)
  .vol(4)
  .echo(2, 0.2)
  .palindrome()
  .every(5, x => x.rotate(3))

// CH3: Ancient roots — Am-Em-F-Dm
p3("a3 a3 a3 e3 e3 e3 f3 f3 f3 d3 d3 d3")
  .wave("<tri tri saw tri>")
  .vol(6)
  .every(6, x => x.rev())
  .every(8, x => x.rotate(3))

// CH4: Leaves rustling, footsteps on moss
n1("~ l? ~ ~ h ~ ~ l? ~ h? ~ ~")
  .env(7, "down", 4)
  .every(3, x => x.rotate(1))
  .every(5, x => x.fast(2))

10. 外部依存

ライブラリ バージョン 用途
React 18.2.0 UI描画
ReactDOM 18.2.0 UI描画
Babel Standalone 7.23.9 JSXトランスパイル
CodeMirror 5.65.7 コードエディタ
CodeMirror matchbrackets 5.65.7 括弧対応表示
CodeMirror closebrackets 5.65.7 括弧自動閉じ
CodeMirror active-line 5.65.7 アクティブ行表示

すべて cdnjs.cloudflare.com から読み込み。インストール不要、ブラウザ完結。

11. 法的考慮事項

音源再現の合法性

BITCODE は DMG サウンドチップの動作原理を Web Audio API で再現するものであり、任天堂のファームウェア・BIOS・ROM を一切使用しない。矩形波・LFSRノイズ等の基本波形は自然法則に基づく生成であり、著作物には該当しない。チップに関連する特許は出願から20年以上経過し失効済み。半導体レイアウトの排他的権利も10年で消滅している。

商標

「Game Boy」は任天堂の登録商標のため、製品名・マーケティングでの使用を避ける。「BITCODE」は汎用的な名称であり、商標上のリスクはきわめて低い。ドキュメント内での技術的言及には「DMG-01」「LR35902」等のチップ型番を使用する。

About

BITCODE: live code chiptune in your browser. 4ch Game Boy sound × TidalCycles-style patterns. Zero install.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages