はじめに

YouTubeで偶然見つけたCoding Tranceという動画に衝撃を受けた。

コード数十行で本格的なトランスミュージックを生成している。しかもライブコーディング環境で、リアルタイムに音を変化させながら。これこそ Vibe Codingではないか?

いったいどうなっているんだろう. 仕組みを理解したかったので、早速コードを写経してみた。

Strudelとは

TidalCycleは触ったことはあったが、そのJavaScriptポーティングのStrudelはつかったことがなかった.

Strudelとは、ブラウザで動作するライブコーディング音楽環境。TidalCyclesのJavaScript実装で、Webブラウザだけで本格的な音楽制作ができる。

特徴:

  • ブラウザだけで完結(インストール不要)
  • 豊富なサンプル音源とシンセサイザー
  • パターンベースの記述で直感的
  • リアルタイムに音を変更可能

https://strudel.cc/

ローカル環境構築

そもそもYoutubeどおりにコードをコピーしても動かないので、いろいろとAIに質問したいと思った。そこで、あえてローカル環境でコードを書いてみることにした。

VSCode拡張機能のインストール

Strudelには roipoussiere.tidal-strudel というVSCode拡張機能がある。

しかし、数年前からメンテナンスされていないため、Strudel最新版(v1.2+)のサンプル読み込み仕様に対応していなかった。

古いstrudel.jsの問題

拡張機能に同梱されている strudel.jsv0.8.1 と古く、以下の問題があった:

  1. 古いサンプル読み込みAPI(=samples()= の引数仕様が変更された)
  2. dough-samplesのJSON形式( _base フィールド)に未対応
  3. 最新の @strudel/web パッケージの機能が使えない

カスタムビルドで解決

Claude Codeに相談して、最新のStrudel(v1.2+)を使ったカスタムビルドを作成することにした。

vscode-strudel-bundle.jsを作成

新しいバンドルファイル vscode-strudel-bundle.js を作成し、以下の変更を加えた:

  1. 最新の@strudel/webを使用
// VS Code Strudel extension bundle - Latest version
// This replaces the old strudel.js (v0.8.1) with latest Strudel (v1.2+)

import { initStrudel, evaluate, hush, getAudioContext, samples } from "@strudel/web";
  1. dough-samplesをオンライン読み込み

従来はローカルサーバー(localhost:6543)が必要だったが、GitHubから直接読み込むように変更:

const ds = "https://raw.githubusercontent.com/felixroos/dough-samples/main/";
await initStrudel({
  prebake: async () => {
    try {
      const result = await Promise.all([
        samples(ds + "tidal-drum-machines.json"), // Use _base from JSON
        samples(ds + "piano.json"),
        samples(ds + "Dirt-Samples.json"),
        samples(ds + "EmuSP12.json"),
        samples(ds + "vcsl.json"),
        samples(ds + "mridangam.json")
      ]);
      return result;
    } catch (error) {
      console.error("Failed to load samples:", error);
      throw error;
    }
  }
});

最新版では、JSONファイル内の _base フィールドを自動的に読み取るため、第2引数(ベースパス)の指定が不要になった。

ビルドと差し替え

# プロジェクトでビルド
npm run build:vscode

# 拡張機能のディレクトリに差し替え(Windows)
cp dist-vscode/strudel.js    /c/Users/fox10/.vscode/extensions/roipoussiere.tidal-strudel-0.2.1/dist/strudel.js

# VSCodeをリロード
# Ctrl+Shift+P → "Developer: Reload Window"

これで、古いv0.8.1のstrudel.jsが最新版に置き換わり、正常に動作するようになった。

利用可能なサンプル

この設定で以下のサンプルが使える:

  • tidal-drum-machines: bd, sd, hh, oh, cp(ドラム音源)
  • piano: ピアノ音源
  • Dirt-Samples: TidalCycles標準サンプル
  • EmuSP12: サンプラー音源
  • VCSL: 各種楽器サンプル
  • mridangam: インド打楽器

カスタムスクリプトを読み込む

しかし、まだ動かない… さらに相談を続けると、どうもオリジナルの関数をたくさん使ってるようだった。そして、それこそtrancyな音楽を生み出す仕組みだった。

// read external scripts
await fetch("https://raw.githubusercontent.com/switchangel/strudel-scripts/main/allscripts.js")
    .then(r => r.text())
    .then(eval)

このスクリプトには trancegate などのカスタムエフェクトが定義されている。これがトランス音楽の核心だった!

コードの解説

動画のコードを写経したのがこちら:

// https://www.youtube.com/watch?v=GWXCCBsOMSg
setCpm(140/4)

// read external scripts
await fetch("https://raw.githubusercontent.com/switchangel/strudel-scripts/main/allscripts.js")
    .then(r => r.text())
    .then(eval)

stack(
// kick
s("bd:2!4").bank("RolandTR909"),

s("cp:2!4").o(5).beat("0,4,8,11,14",16),

// bass
n("<3@3 4 5 @3 6>".add(-14))
    .scale("g:minor")
    .s("supersaw")
    .rlpf(0.5).lpenv(2)
,
// lead
n("0@2 <-7 [-5 -2]>@3 <0 -3 2 1>@3".add(7)
    .add("<5 4 0 <0 -2>>")
    )
    .scale("g:minor")
    .s("supersaw").trancegate(1.5,45,1).o(2)
    .delay(.7).pan(rand)
    .fm(.5).fmwave("brown")
    .rlpf(0.593).lpenv(2),

s("pulse!16").dec(.1).fm(time).fmh(time).o(4),
)

構成の解説

このコードは4つのレイヤーで構成されている:

1. キック(BD)

s("bd:2!4").bank("RolandTR909")

Roland TR-909のバスドラム(2番)を4拍で繰り返し。トランスの基本リズム。

2. クラップ

s("cp:2!4").o(5).beat("0,4,8,11,14",16)

16分音符の特定タイミングでクラップを配置。トランス特有のオフビート感。

3. ベースライン

n("<3@3 4 5 @3 6>".add(-14))
    .scale("g:minor")
    .s("supersaw")
    .rlpf(0.5).lpenv(2)
  • Gマイナースケールでベースラインを生成
  • supersawシンセで厚みのある音色
  • ローパスフィルター(rlpf)とエンベロープで音作り

4. リード

n("0@2 <-7 [-5 -2]>@3 <0 -3 2 1>@3".add(7)
    .add("<5 4 0 <0 -2>>")
    )
    .scale("g:minor")
    .s("supersaw").trancegate(1.5,45,1).o(2)
    .delay(.7).pan(rand)
    .fm(.5).fmwave("brown")
    .rlpf(0.593).lpenv(2)
  • 複雑なメロディパターン
  • trancegate エフェクトでトランスらしいゲート効果
  • ディレイとランダムパンでステレオ感
  • FMシンセシスとローパスフィルターで音色調整

ポイント

  • BPM 140(=setCpm(140/4)=)はトランスの定番テンポ
  • trancegate エフェクトがトランスらしさの核心
  • ミニノーテーション記法(=<>= や @ )でパターンを簡潔に表現
  • 4つのレイヤーを stack で重ねる構造

感想

わたしはこの数年ずっとトランスが好きなので、プログラミングでトランスがつくれたらいいなと思っていたが、そんないいなを実際にやっていることにを衝撃をうけた.

催眠的なリフがトランス

TidalCycleの設計思想がパターンの繰り替えしなので、テクノには相性がいいことは予感していた. じゃあテクノとトランスの違いはなんだ?というと、催眠的な反復の雰囲気という点で、これはトランスだ.

しかし、トランスの別の側面の美しい旋律に酔いしれることだったり、ビルドアップとブレイクダウンという明確な楽曲構成で、ここはコードで再現するのは難しい部分だ. いや、そこも工夫次第で乗り越えることができるのか?

Live Codingにも音楽の知識が必要

いったん写経して思ったのは、そもそも演者のSwitch Engelさんの音楽知識レベルが高いのでは?秘蔵スクリプトを覗いてみたら、当然DAW(Bitwig Studioをつかっているようだった)の各種機能知りつつさらにそれをコードで実現させていることがみえる. さらにライブ配信をみると部屋にピアノもギターもある、雰囲気バイブではなくガチだった.

トランスがただつくりたいだけなのにDAWの王道からそれるべきか

このアプローチにとても魅力を感じるものの、これを深めるかは少し悩んでいる. 単純にわたしはトランスがつくりたくて、そのために1日30分以上はDTMに取り組むという目標を経てているものの、どうも遠回りな気がする.

そうはいっても、素人の猿真似でトランスをつくって自己満足しても誰も効かないだろうから、珍しいことに取り組むべきなのか?時間は有限だ. ただ、おもしろいというワクワク感はあり、もう少しだけ王道から外れて見ようとは思う.

See Also