PyCodeDJ マニュアル

English manual

Python のコードを書くと、音が変わる


プログラムを書いたことがあれば、誰でも試せます。音楽の知識は不要です。SuperCollider は「名前も聞いたことがない」で大丈夫です。

このマニュアルを順番に読んでいくと、最終的に 自分が書いた Python コードから音が鳴る体験 ができます。セットアップも含めて 20〜30 分が目安です。


1. PyCodeDJ って何?

ひとことで言うと

「コードを書くこと」が「音楽を演奏すること」になるツールです。

for ループを増やすと音の揺らぎが速くなります。関数を 3 つ書くと 3 声のポリフォニーになります。コメントをたくさん書くと、リバーブが深くかかって空間が広がります。pattern("x . x .") と書けばそのリズムで音が鳴ります。

from pycodedj import loop, pattern

# コードの「構造」が音を決める
@loop("bass", interval=2.0)
def bass_line(volume=0.4):
    for i in range(8):
        if i % 2 == 0:
            pass

# pattern() でリズムと音程を明示的に指定する
@loop("kick", synth="floor_kick", dur=0.25)
def kick_drum():
    pattern("x . x .")

@loop("melody", synth="acid_lead", root="A3", scale="minor", dur=0.25)
def melody_line():
    pattern("0 . 3 . 5 . 7 .")

このコードをファイルに保存するだけで、音が変わります。追加説明もシンセの設定も必要ありません。

何に使えるの?

  • ライブコーディングパフォーマンス(コードを書きながら音楽を演奏する)
  • コードを書く「感触」を音で感じながら開発する
  • プログラミングの学習に音のフィードバックを加える

音はどこから出るの?

PyCodeDJ 自体は音を出しません。SuperCollider(無料のソフトウェア音響シンセサイザー)が音を出します。PyCodeDJ は「Python コードを分析して、SuperCollider にパラメーターを伝える橋渡し役」です。

あなたが書く Python コード
        |
        | pycodedj eval / watch を実行
        v
  PyCodeDJ がコードを分析
  (どれだけネストしているか、
    関数がいくつあるか、など)
        |
        | OSC という通信プロトコルで指示
        v
  SuperCollider が音を出す
        |
        v
     スピーカー

SuperCollider の操作は最小限で済みます。難しいことはしなくて大丈夫です。


2. インストールする

必要なもの

  • Python 3.10 以上(python --version で確認できます)
  • SuperCollider 3.12 以上(次のセクションでインストール方法を説明します)
  • ターミナル(コマンドを打てる環境)

PyCodeDJ をインストールする

pip install 'pycodedj[watch]'

[watch] を付けることで、ファイル保存を検知する watch コマンドも使えるようになります。これがあると演奏がずっとスムーズになるので、最初からインストールするのをおすすめします。

インストールできたか確認します。

pycodedj --help

次のように表示されれば成功です。

usage: pycodedj [-h] {eval,watch,panic,mute,unmute,solo,unsolo,status} ...

SuperCollider をインストールする

SuperCollider の公式サイト(supercollider.github.io)からインストーラーをダウンロードします。

  • macOS: .dmg ファイルをダウンロードしてインストール
  • Linux: パッケージマネージャーか公式サイトから
  • Windows: .exe インストーラーをダウンロード

インストール後に SuperCollider IDE(アプリ)を起動してください。画面が開けばインストール成功です。


3. SuperCollider をセットアップする

SuperCollider は「音を出す担当」です。最初に一度だけ設定すれば、あとは自動的に動きます。

SuperCollider で何をするの?

PyCodeDJ では、Python は音を直接鳴らしません。Python 側はコードを分析して、OSC という短いメッセージを SuperCollider に送ります。

SuperCollider 側では、次の 3 つを行います。

  1. audio server を起動する
  2. sc/synths.scd を読み込んで、PyCodeDJ 用のシンセを登録する
  3. Python から届く OSC メッセージを受け取り、音を鳴らす

SuperCollider IDE には主に 2 つの場所があります。

  • コードを書くドキュメント: s.boot;{ SinOsc... }.play; などを入力して実行する場所
  • Post window: 実行結果、エラー、PyCodeDJ synths loaded... などのログが表示される場所

このマニュアルで「SuperCollider で実行する」と書いてあるコードは、ターミナルではなく SuperCollider IDE のコードを書くドキュメントで実行します。

ステップ 1: サーバーを起動する

SuperCollider IDE を開き、メニューから Server > Boot Server を選びます。

または、コード入力欄に次を書いて Ctrl+Enter(Mac は Cmd+Enter)で実行します。

s.boot;

画面下部に localhost が緑色に変わったら起動成功です。

この audio server が起動していないと、Python 側のコマンドが成功しても音は出ません。

ステップ 2: シンセを読み込む

PyCodeDJ のプロジェクトフォルダにある sc/synths.scd を SuperCollider IDE で開きます。

File > Opensc/synths.scd を開いたら、Ctrl+A(Mac は Cmd+A)で全選択し、Ctrl+Enter(Mac は Cmd+Enter)で実行します。

右側の Post window に次のメッセージが出れば準備完了です。

PyCodeDJ synths loaded. Ready. OSC port: 57120

このメッセージが出ない場合は うまくいかないとき を参照してください。

sc/synths.scd は、PyCodeDJ 用の音色と OSC 受信処理を SuperCollider に登録するファイルです。SuperCollider を再起動した後は、もう一度このファイルを実行してください。

ステップ 3: 出力先を変更した場合

SuperCollider は audio server を起動した時点の出力先を使います。Mac/PC 側でスピーカー、イヤホン、オーディオインターフェースなどの出力先を変更した場合は、SuperCollider の audio server を起動し直してください。

まず SuperCollider IDE のコードを書くドキュメントで、使えるデバイス名を確認します。これはターミナルではなく SuperCollider で実行します。

ServerOptions.devices;

Post window にデバイス名の一覧が表示されます。使いたい出力先の名前を確認したら、同じく SuperCollider IDE のコードを書くドキュメントで次のように指定します。

s.quit;
s.options.outDevice = "ここに出力デバイス名を書く";
s.options.numInputBusChannels = 0;
s.boot;

入力を使わない場合は numInputBusChannels = 0 にしておくと、入力デバイスとのサンプルレート不一致を避けやすくなります。

boot 後、SuperCollider 単体で音が出るか確認します。

{ SinOsc.ar(110, 0, 0.03) ! 2 }.play;

音が出たら、sc/synths.scd をもう一度実行します(Ctrl+A → Ctrl+Enter、Mac は Cmd+A → Cmd+Enter)。

ステップ 4: 接続を確認する

ターミナルに戻り、次を実行します。

pycodedj eval examples/demo.py::bass

ターミナルに [pycodedj] bass ... と表示され、SuperCollider から音が出れば接続成功です。

SuperCollider はこのまま起動したままにしておいてください。


4. はじめての音を出す

ステップ 1: デモファイルを確認する

examples/demo.py を開いてみましょう。

from pycodedj import loop

@loop("bass", interval=2.0)
def bass(volume=0.4):
    for i in range(8):
        if i % 2 == 0:
            pass

@loop("melody", interval=0.5)
def melody(volume=0.3):
    x = 1
    y = 2
    return x + y

@loop("pad", interval=4.0)
def pad(volume=0.15):
    # ここに余白を置く
    # もう少し置く
    # 静寂も音楽
    pass

@loop("bass", ...) が付いた関数が「bass ループ」です。関数名(bass, melody, pad)は自由につけられます。OSC に送られる名前は @loop(...) の第一引数です。

ステップ 2: 音を出す

ターミナルで次を実行します。

pycodedj eval examples/demo.py::bass

eval は evaluate(評価する)の略です。このコマンドは examples/demo.pybass ループを今すぐ読み取り、コード構造を分析して SuperCollider に音のパラメーターを送ります。

成功すると次のように表示されます。

[pycodedj] bass  cutoff=418Hz  lfo=1.08Hz  reverb=0.00  voices=1  amp=0.40

これがあなたの最初のライブコーディングです。続けて melody と pad も評価してみましょう。

pycodedj eval examples/demo.py::melody
pycodedj eval examples/demo.py::pad

3 つのループが同時に鳴っています。それぞれが独立して動いているのがわかるでしょうか。

ステップ 3: コードを変えて音を変える

examples/demo.py をテキストエディタで開いて、bass ブロックを変えてみます。

変更前:

@loop("bass", interval=2.0)
def bass(volume=0.4):
    for i in range(8):
        if i % 2 == 0:
            pass

変更後(ネストを深くする):

@loop("bass", interval=2.0)
def bass(volume=0.4):
    for i in range(8):
        for j in range(4):      # 1 行追加
            if i % 2 == 0:
                if j > 2:       # 1 行追加
                    pass

ファイルを保存したら、ターミナルで再度評価します。

pycodedj eval examples/demo.py::bass
[pycodedj] bass  cutoff=1200Hz  lfo=2.16Hz  reverb=0.00  voices=1  amp=0.40

cutoff が上がって音が明るくなり、lfo も速くなりました。音量を変えたいときは volume= の値を変えます。

@loop("bass", interval=2.0)
def bass(volume=0.7):   # ← 大きくする
    ...

5. 保存するだけで音が変わる — watch モード

毎回 pycodedj eval を打つのは面倒です。watch コマンドを使うと、起動時に一度すべてのループを評価し、その後はファイルを保存するだけで自動的に全ループが再評価されます

起動方法

pycodedj watch examples/demo.py
[pycodedj] watching demo.py — save to reload (Ctrl+C to stop)
[pycodedj] reloaded demo.py (3 loop(s))

起動直後に一度音が鳴ります。あとはエディタでコードを書いて保存するだけです。保存のたびに次のように出力されます。

[pycodedj] reloaded demo.py (3 loop(s))

これがライブコーディングの本来のワークフローです。コードを書く → 保存する → 音が変わる、このサイクルを繰り返します。

止め方

ターミナルで Ctrl+C を押すと監視が止まります。SuperCollider の音はそのまま鳴り続けます。

デバウンスについて

連続して保存したとき(vim のような一部のエディタは保存時にテンポラリファイルを経由する)でも、短時間に複数回評価されないよう自動的に間引きます。--debounce オプションでその待機時間を変更できます(デフォルト 0.3 秒)。

pycodedj watch demo.py --debounce 0.5

6. コードの構造が音を変える

PyCodeDJ は Python コードの「構造」を 5 つの音楽パラメーターに変換します。

対応表

コードのどこを見るか 変わる音のパラメーター 変化のイメージ
ブロック構造の深さ(iffor のネスト) フィルターの明るさ(Cutoff) 深くなるほど音が明るく開く
制御フローの数(if / for / while の合計) 音の揺らぎの速さ(LFO レート) 多いほど揺らぎが速くなる
関数の数(def の数) 音の重なり(ポリフォニー声部数) 多いほど音が重なる(最大 4)
コメントの割合(コメント行 ÷ 全行) 空間の広さ(リバーブの深さ) 多いほど残響が増える
volume= 引数のデフォルト値 音量(Amplitude) 直接指定。0.0〜1.0
eq= / low= / mid= / high= 引数 簡易 3 バンド EQ ループごとの音質補正

実例で見る

フィルターの明るさ(ネストの深さ)

@loop("test", interval=1.0)
def f(volume=0.3):
    # ネスト深さ 1 → フィルター最小(こもった音)
    pass
@loop("test", interval=1.0)
def f(volume=0.3):
    # ネスト深さ 4 → フィルター最大(明るい音)
    for i in range(4):
        for j in range(4):
            if i == j:
                pass

x = 1 + 2 * (3 + 4) のような演算式はネストの深さにカウントされません。iffor などのブロック構造だけを数えます。

揺らぎの速さ(制御フローの数)

@loop("test", interval=1.0)
def f(volume=0.3):
    # 制御フロー 0 個 → 揺らぎ最小(ゆったり)
    pass
@loop("test", interval=1.0)
def f(volume=0.3):
    for i in range(4):   # 1 つ目
        if i > 2:        # 2 つ目
            while False: # 3 つ目
                pass

音の重なり(関数の数)

@loop("test", interval=1.0)
def solo(volume=0.3):
    # 関数 1 個 → 1 声(ソロ)
    pass
@loop("test", interval=1.0)
def f(volume=0.3):
    # 関数 4 個 → 4 声(最大ポリフォニー)
    def voice_a(): pass
    def voice_b(): pass
    def voice_c(): pass
    def voice_d(): pass

空間の広さ(コメント率)

@loop("test", interval=1.0)
def f(volume=0.3):
    # コメントなし → ドライな音
    x = 1
    return x
@loop("test", interval=1.0)
def f(volume=0.3):
    # コメントが多い → 深い残響
    # 余白
    # 余白
    # 余白
    pass

音量(volume 引数)

@loop("kick", interval=1.0)
def my_kick(volume=0.9):   # 大きい
    ...

@loop("shimmer", interval=4.0)
def bg_shimmer(volume=0.05):  # 奥で小さく
    ...

簡易 EQ

eq= でジャンル寄りの EQ プリセットを選べます。必要なら low=, mid=, high= で一部だけ上書きできます。

@loop("bass_reese", interval=0.5)
def bass(volume=0.45, eq="edm"):
    ...

@loop("hat_engine", interval=0.25)
def hats(volume=0.08, eq="edm", low=0.5, high=1.25):
    ...
eq傾向
"flat"補正なし
"rock" / "pop"低音と高音を少し上げ、中域を少し下げる
"edm" / "hiphop"低音を強め、高音も少し上げる
"classic" / "jazz"フラット志向
"acoustic"低音を控えめにして中高域を少し上げる

7. pattern() で音程とリズムを指定する

前章の「コード構造が音を変える」とは別に、明示的にリズムと音程を指定する方法があります。それが pattern() です。

基本

from pycodedj import loop, pattern

@loop("kick", synth="floor_kick", dur=0.25)
def kick_drum():
    pattern("x . x .")

pattern() に渡す文字列に、鳴らすタイミングを書きます。スペースで区切ると 1 ステップです。

トークン意味
xここで音を鳴らす(トリガー)
.休符(無音)
0, 1, 2音を鳴らす + 音程(スケール度数)
[0 3]コード(複数の度数を同時発音)
~タイ(直前の音を 1 ステップ延長)

@loop のパラメーター(pattern 用)

引数説明
synth=使うシンセ名synth="floor_kick"
root=ルートノートroot="A3", root="C4"
scale=スケール名scale="minor", scale="major"
dur=1 ステップの長さ(秒)dur=0.25(16 分音符相当)

トリガーパターン — x と . だけで

音程なしで「リズムだけ」を指定したいときは x. だけ使います。

@loop("kick", synth="floor_kick", dur=0.25)
def kick():
    pattern("x . x .")      # 4 ステップ

@loop("hat", synth="hat_engine", dur=0.25)
def hat():
    pattern("x x x x x x x x")  # 8 ステップ(16 分グリッド)

@loop("snare", synth="clap_snare", dur=0.25)
def snare():
    pattern(". . x . . . x .")   # 2・4 拍に鳴る

音程パターン — 度数(整数)で指定する

音程を指定したいときは整数(0 以上)を使います。数字はスケールの度数(0 から数えるインデックス)です。

@loop("melody", synth="acid_lead", root="A3", scale="minor", dur=0.25)
def melody():
    pattern("0 . 3 . 5 . 7 .")

scale="minor"root="A3" のとき、度数と音程の対応はこうなります。

度数A ナチュラルマイナー
0A3
1B3
2C4
3D4
4E4
5F4
6G4
7A4(1 オクターブ上)

度数が 7 以上になると自動的にオクターブが上がります。70 の 1 オクターブ上、14 は 2 オクターブ上です。

利用可能なスケール(主なもの)

scale=スケール
"major"メジャー(長調)
"minor"ナチュラルマイナー(短調)
"chromatic"クロマチック(半音階)
"dorian"ドリアン
"pentatonicMajor"メジャーペンタトニック
"pentatonicMinor"マイナーペンタトニック

コード — 複数の音を同時に鳴らす

角括弧で複数の度数を囲むと、1 ステップで複数の音を同時に鳴らせます。

@loop("chord", synth="note", root="C3", scale="minor", dur=0.5)
def chord():
    pattern("[0 2 4] . [0 3] .")
    # [0 2 4]→C3+Eb3+G3(短三和音), 休, [0 3]→C3+Eb3, 休

コード内に書けるのは 0 以上の整数のみです。.x~ は書けません。

タイ — 音を伸ばす

~ を使うと、直前の音(またはコード)を次のステップまで伸ばせます。

@loop("bass", synth="note", root="A1", scale="minor", dur=0.25)
def bass():
    pattern("0 . [0 3] ~ 5 . 3 .")
    # 0→A1, 休, [0 3]→和音(2ステップ持続), 5→F2, 休, 3→D2, 休

~ は単音・コードの直後にのみ書けます。先頭・.x の直後は書けません。

実例: キック・ベース・メロディー

from pycodedj import loop, pattern

@loop("kick", synth="floor_kick", dur=0.25)
def kick():
    pattern("x . . . x . . .")

@loop("bass", synth="bass_acid", root="A1", scale="minor", dur=0.25)
def bass():
    pattern("0 . [0 3] ~ 5 . 3 .")
    # 0→A1, 休, [0 3]→和音(2ステップ持続), 5→F2, 休, 3→D2, 休

@loop("melody", synth="acid_lead", root="A3", scale="minor", dur=0.5)
def melody():
    pattern("0 3 5 7")

@loop("pad", interval=4.0)
def pad(volume=0.06):
    # 背景の空気感
    # コード構造で鳴らす
    pass

pattern() と構造マッピングの違い

コード構造マッピング(従来)pattern()
リズムコードの構造から自動生成自分で指定
音程コードの構造から自動生成自分で指定(または任せる)
使いどき構造の変化を楽しみたいリズム・音程を明示したい

どちらも同じファイルの中で自由に混在させられます。


8. 複数のループを同時に動かす

PyCodeDJ の最大の特徴は、複数のループが独立して動き続けることです。1 つのループを変更しても、他のループは止まりません。

基本の使い方

from pycodedj import loop, pattern

@loop("kick", synth="floor_kick", dur=0.25)
def kick():
    pattern("x . x .")

@loop("bass", interval=2.0)
def bass_line(volume=0.4):
    for i in range(8):
        if i % 2 == 0:
            pass

@loop("pad", interval=4.0)
def atmosphere(volume=0.08):
    # 背景の空気
    # 余白
    pass

watch で起動すれば、保存するたびに変更したループだけが更新されます。

pycodedj watch myfile.py

演奏中のコントロール

pycodedj mute bass        # bass を消音(停止はしない)
pycodedj unmute bass      # bass の音量を元に戻す
pycodedj panic            # すべてのループを即時停止
pycodedj status           # ループの状態を確認

ループを削除するには

ファイルからそのブロック(@loop デコレータごと関数)を削除して保存します。watch モードなら保存時に自動的に停止します。

サンプルファイル

ファイル内容
examples/demo.pybass / melody / pad の 3 ループ入門デモ
examples/club_set.pyEDM クラブグルーヴ(キック・ベース・ハット・コード・パッドを含む 8 ループ)
examples/sound_showcase.py全 30 音色 — 1 音ずつ eval して確認できる

9. 音色リファレンス

@loop の第一引数(ループ名)を変えると、SuperCollider 側で使う音色を選べます。全 30 音色を 1 音ずつ確認したい場合は examples/sound_showcase.py を使います。

pycodedj eval examples/sound_showcase.py::bass_acid
pycodedj eval examples/sound_showcase.py::riser_noise
pycodedj eval examples/sound_showcase.py::bell_rave

キック

ループ名
kick_hard硬めでアタックの強いキック
floor_kick太い四つ打ちキック
kick_pulse軽めのパルスキック

ベース

ループ名
bass_rumbleキック由来の低いランブル
bass_reese揺れる Reese 系ベース
sub_bassサブベース
bass_acid303スタイルのアシッドベース(スクウェルチ付き)

パーカッション

ループ名
hat_engineクローズ/オープンのハットグリッド
hat_ride長めのライド/オープンハット
clap_snap鋭いクラップ
clap_snareスネア寄りのクラップ
tom_drumフロアタム(ピッチスイープあり)
snare_rollスネアロール(lfoRate で速度制御)
noise_crashクラッシュシンバル(長いテール)

コード・スタブ

ループ名
chord_rave明るいレイブスタブ
neon_stabネオン系スタブコード
dub_chordダブコード
stab_sawデチューンソーコードスタブ
organ_chordハモンドオルガン風コード
bell_raveインハーモニクスFMレイブベル

リード・メロディー

ループ名
acid_leadアシッド系リード
lead_hooverHoover 風リード
soft_pluckやわらかいプラック
synth_arpアルペジオシンセ
note汎用ノートシンセ(音程パターン向け)

アトモスフィア

ループ名
shimmer_pad深いシマーパッド
warehouse_air倉庫っぽい空気感
vox_ahhフォルマントボーカルパッド

FX

ループ名
fx_impact低いインパクト
riser_noiseノイズライザー(8秒でスイープ上昇)
glitch_ticks細かいグリッチ音

10. 演奏のアイデア

アイデア A: シンプルから複雑へ育てる

最初は空のコードから始めて、少しずつ要素を加えていきます。watch を起動した状態で保存するたびに音が変わっていく様子を楽しめます。

# 段階 1: ほぼ無音(フィルター最小、ポリフォニー 1)
@loop("main", interval=1.0)
def f(volume=0.3):
    pass
# 段階 2: 揺らぎを加える
@loop("main", interval=1.0)
def f(volume=0.3):
    for i in range(4):
        pass
# 段階 3: さらに深く
@loop("main", interval=1.0)
def f(volume=0.3):
    for i in range(4):
        for j in range(2):
            if i > j:
                pass
# 段階 4: 声部を増やしてクライマックス
@loop("main", interval=1.0)
def f(volume=0.5):
    def voice_a():
        for i in range(4):
            for j in range(2):
                if i > j:
                    pass

    def voice_b():
        for k in range(8):
            pass

アイデア B: pattern() でライブシーケンス

pattern() を使って、保存するたびにリズムや音程を変えていきます。

from pycodedj import loop, pattern

@loop("kick", synth="floor_kick", dur=0.25)
def kick():
    pattern("x . x .")     # ← ここを変えて保存するたびにリズムが変わる

@loop("bass", synth="bass_acid", root="A1", scale="minor", dur=0.25)
def bass():
    pattern("0 . 0 . 3 .") # ← 度数を変えて和声を変える

アイデア C: コントラストをつける

2 つのループを使って、にぎやかなパートと静かなパートを対比させます。

@loop("bass", interval=2.0)
def the_bass(volume=0.5):
    def layer_a():
        for i in range(8):
            for j in range(4):
                if i == j:
                    pass

    def layer_b():
        for k in range(8):
            pass
@loop("pad", interval=4.0)
def space(volume=0.08):
    # 静寂
    # もっと静寂
    # ただの余白
    pass

アイデア D: コメントだけで演奏する

関数は 1 つだけ残して、コメントの量だけで演奏します。コメントが増えるほど残響が深くなり、音の空間が変化します。

@loop("ambient", interval=4.0)
def f(volume=0.15):
    # ここからコメントを増やしたり減らしたりするだけ
    pass

アイデア E: 関数名をストーリーとして書く

音は関数の中身の構造で決まります。関数名はどんな名前でも構いません。演奏しながらコードがストーリーになるような書き方もできます。

@loop("narrative", interval=2.0)
def the_city_wakes_up(volume=0.3):
    for hour in range(6):
        if hour > 4:
            pass

@loop("texture", interval=1.0)
def rush_hour(volume=0.2):
    for commuter in range(8):
        for train in range(3):
            if commuter % 2 == 0:
                pass

11. うまくいかないとき

音が鳴らない

まず SuperCollider 単体で音が出るか確認します。SuperCollider IDE で新しい空のドキュメントを開き、次の 1 行を実行します。

{ SinOsc.ar(440, 0, 0.1) ! 2 }.play;

実行は Ctrl+Enter(Mac は Cmd+Enter)です。音を止めるには Ctrl+.(Mac は Cmd+.)を押します。

ここで音が出ない場合は、PyCodeDJ ではなく SuperCollider のサーバー、Mac/PC の音量、出力先を確認してください。

次に SuperCollider のサーバーが起動しているか確認します。

s.boot;

次に sc/synths.scd を再実行します(Ctrl+A → Ctrl+Enter、Mac は Cmd+A → Cmd+Enter)。Post window に次が出るはずです。

PyCodeDJ synths loaded. Ready. OSC port: 57120

OSC port が 57120 か確認するには、SuperCollider で次を実行します。

NetAddr.langPort.postln;

57120 以外が表示された場合は、Python 側でその番号を指定します。

pycodedj eval examples/demo.py::bass --sc-port 表示された番号

SuperCollider 側のシンセが読み込まれているか直接確認するには、SuperCollider で次を実行します。

~startLoop.value("bass", 1);

これで音が出れば、シンセ定義は読み込まれています。音を止めるには Ctrl+.(Mac は Cmd+.)です。

さらに OSC 受信を SuperCollider 内だけで確認するには、次を実行します。

NetAddr("127.0.0.1", NetAddr.langPort).sendMsg("/pycodedj/loop/bass/voice_count", 1);

これで音が出れば、SuperCollider 側の OSC 受信も動いています。

それでも音が鳴らない場合は、接続確認をします。

pycodedj eval examples/demo.py::bass

必要なら SuperCollider 側で OSC の受信ログを出せます。

OSCFunc.trace(true);

ログを止めるには次を実行します。

OSCFunc.trace(false);

[pycodedj] OSC error というエラーが出る

SuperCollider が起動していないか、ポート番号が違います。

  1. SuperCollider IDE が開いていて、サーバーが起動しているか確認する
  2. sc/synths.scd を実行して Ready. メッセージを確認する
  3. ポート番号がデフォルト(57120)から変わっていれば --sc-port で指定する
pycodedj eval demo.py::bass --sc-port 57200

eval を実行したが何も出ない(フィードバックが出ない)

eval に成功すると [pycodedj] ループ名 cutoff=...Hz ... の行が出るはずです。何も出ない場合は stderr を確認してください。構文エラーが出ているかもしれません。

loop 'xxx' not found というエラーが出る

ループ名の綴りが @loop(...) の第一引数と一致していません。:: の後ろの名前を確認してください。

# ファイルの中に @loop("bass", ...) と書いてあれば
pycodedj eval demo.py::bass   # OK
pycodedj eval demo.py::Bass   # NG(大文字小文字が違う)

file not found というエラーが出る

ファイルのパスが正しくありません。カレントディレクトリを確認するか、フルパスで指定します。

pwd
ls

pycodedj eval /home/user/projects/myfile.py::bass

pycodedj watch が watchdog をインストールしろと言う

pip install 'pycodedj[watch]'

最初のインストールで [watch] を付け忘れた場合はこれで追加できます。

構文エラーのあるコードを評価したとき

[pycodedj] syntax error (bass): invalid syntax ...

構文エラーがあったブロックは変化せず、直前の音を維持します。他のループは止まりません。コードの構文を修正してから再度評価してください。


12. コマンドと設定の全リスト

pycodedj eval

指定したループを一度だけ評価して SuperCollider にパラメーターを送ります。eval は evaluate(評価する)の略で、「このループを今すぐ音に反映する」という意味です。

pycodedj eval FILE::LOOP [--sc-host HOST] [--sc-port PORT]
引数・オプション 説明 デフォルト
FILE::LOOP ファイルパスとループ名を :: で区切る
--sc-host SuperCollider のホスト 127.0.0.1
--sc-port SuperCollider の受信ポート番号 57120

FILE::LOOP は、FILE の中にある @loop("LOOP", ...) のブロックを指定します。たとえば examples/demo.py::bass は、@loop("bass", ...) デコレータが付いた関数を評価します。

成功すると stdout にフィードバックが出ます。

[pycodedj] bass  cutoff=418Hz  lfo=1.08Hz  reverb=0.00  voices=1  amp=0.40

評価に失敗した場合(構文エラー / OSC 送信失敗)は stderr にエラーが出て終了コード 1 で終了します。

使用例:

pycodedj eval examples/demo.py::bass
pycodedj eval demo.py::melody --sc-host 192.168.1.10
pycodedj eval demo.py::pad --sc-port 57200

pycodedj watch

ファイルを監視し、起動時と保存のたびに全ループを自動で再評価します。Ctrl+C で停止します。

pycodedj watch FILE [--sc-host HOST] [--sc-port PORT] [--debounce SECS]
引数・オプション 説明 デフォルト
FILE 監視するファイルのパス
--sc-host SuperCollider のホスト 127.0.0.1
--sc-port SuperCollider の受信ポート番号 57120
--debounce 連続保存をまとめる待機時間(秒) 0.3

使用例:

pycodedj watch examples/demo.py
pycodedj watch club_set.py --debounce 0.5
pycodedj watch myfile.py --sc-host 192.168.1.10

pycodedj panic

全アクティブループに即時停止信号を送ります。演奏中に問題が起きたとき、すべての音をすぐ止めたい場合に使います。SuperCollider 側で実行中のシンセをすべて解放し、ループ状態を初期化します。

pycodedj panic [--sc-host HOST] [--sc-port PORT]

使用例:

pycodedj panic

pycodedj mute

ループを消音します(停止はしません)。ループは引き続き管理され、unmute で音量が復元します。

pycodedj mute NAME [--sc-host HOST] [--sc-port PORT]
引数・オプション説明デフォルト
NAMEループ名
--sc-hostSuperCollider のホスト127.0.0.1
--sc-portSuperCollider の受信ポート番号57120

使用例:

pycodedj mute bass

注意: CLI は OSC を直接 SuperCollider に送信します。ループを再評価してもミュート状態を維持したい場合は、watch セッション内で Engine.mute() を呼び出してください。

pycodedj unmute

ミュートしたループの音量を元に戻します。

pycodedj unmute NAME [--sc-host HOST] [--sc-port PORT]

使用例:

pycodedj unmute bass

pycodedj solo

CLI からはサポートされていません。 Solo は watch プロセスの状態へのアクセスが必要です。watch セッション内で Engine.solo() を直接呼び出してください。

pycodedj unsolo

CLI からはサポートされていません。 watch セッション内で Engine.unsolo() を直接呼び出してください。

pycodedj status

アクティブなループの名前・ミュート状態・音量・フィルターカットオフを表示します。

pycodedj status [--sc-host HOST] [--sc-port PORT]

出力形式:

Loop         State    Amp    Cutoff
bass         playing  0.40   1340Hz
pad          muted    0.15   200Hz

注意: statuspycodedj watch とは別プロセスで動作するため、watch プロセスの状態を読み取れません。CLI から単独で実行すると「no active loops」と表示されます。

使用例:

pycodedj status

ループの書き方

from pycodedj import loop

@loop("ループ名", interval=秒)
def 関数名(volume=音量, eq="プリセット"):
    # 関数の中身が音楽パラメーターに変換される
    ...
要素説明
"ループ名" SuperCollider に送られる名前。英数字とアンダースコア。例: bass, kick_hard
interval=秒 ループの更新間隔(秒)。省略時は 1.0
volume=音量 音量。0.0〜1.0 の浮動小数点数。省略時は 0.3
eq="プリセット" 簡易 EQ。省略時は "flat"
low=倍率, mid=倍率, high=倍率 EQ の手動調整。0.0〜2.0。プリセットの一部だけ上書きできる
関数名 自由につけられる。ループ名とは独立している

13. 仕組みをもっと知りたい人へ

マッピングの数値

パラメーター 入力 出力範囲 スケール
Cutoff ブロック深さ 0–10 200–4000 Hz リニア
LFO レート 制御フロー数 0–10 0.1–5.0 Hz リニア
リバーブ コメント率 0.0–1.0 0.0–0.8 リニア
声部数 関数数(クランプ) 1–4 クランプ
音量 volume= 引数 そのまま パススルー
EQ eq= プリセット + low/mid/high 0.0–2.0 プリセット、手動値はクランプ

OSC アドレス

SuperCollider と通信するアドレスの形式です。Hydra などのビジュアルツールを繋ぐときに参照してください。

アドレス
/pycodedj/loop/<name>/params int, float, float, float, float voice_count, cutoff, lfo_rate, reverb, amp の順
/pycodedj/loop/<name>/voice_count int 1–4(互換用)
/pycodedj/loop/<name>/cutoff float 200–4000(互換用)
/pycodedj/loop/<name>/lfo_rate float 0.1–5.0(互換用)
/pycodedj/loop/<name>/reverb float 0.0–0.8(互換用)
/pycodedj/loop/<name>/amp float 0.0–1.0(互換用)

Python から直接使う

CLI を使わずにプログラムから操作することもできます。

from pycodedj.block_parser import parse_blocks
from pycodedj.engine import Engine
from pycodedj.osc_bridge import OscBridge, OscEndpoint

bridge = OscBridge(audio=OscEndpoint("127.0.0.1", 57120))
engine = Engine(bridge=bridge)

source = open("demo.py").read()
blocks = {b.name: b for b in parse_blocks(source).blocks}

params = engine.eval_block(blocks["bass"])
if params is not None:
    print(f"cutoff={params.cutoff:.0f}Hz  amp={params.amp:.2f}")

eval_block は成功すると MusicParams を返します。構文エラーや OSC 送信失敗の場合は None を返します。

モジュール構成

pycodedj/
├── _loop.py          # @loop デコレータ(実行時は no-op)
├── block_parser.py   # @loop デコレータを AST で解析してブロックを分割する
├── analyzer.py       # コードの特徴量(深さ・数・比率)を抽出する
├── mapper.py         # 特徴量を音楽パラメーターに変換する
├── pattern.py        # pattern() 文字列を解析する
├── engine.py         # ブロック評価のパイプライン全体を管理する
├── osc_bridge.py     # SuperCollider へ OSC で送信する
├── watcher.py        # ファイル監視(watchdog ベース)
└── __main__.py       # CLI コマンドのエントリポイント