pycodedj 0.1.4__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pycodedj-0.1.4 → pycodedj-0.2.0}/CHANGELOG.md +25 -0
- {pycodedj-0.1.4 → pycodedj-0.2.0}/PKG-INFO +38 -27
- {pycodedj-0.1.4 → pycodedj-0.2.0}/README.ja.md +37 -26
- {pycodedj-0.1.4 → pycodedj-0.2.0}/README.md +37 -26
- {pycodedj-0.1.4 → pycodedj-0.2.0}/docs/index.html +58 -46
- {pycodedj-0.1.4 → pycodedj-0.2.0}/docs/manual.ja.md +349 -179
- {pycodedj-0.1.4 → pycodedj-0.2.0}/docs/manual.md +350 -174
- pycodedj-0.2.0/examples/club_set.py +218 -0
- {pycodedj-0.1.4 → pycodedj-0.2.0}/examples/demo.py +14 -9
- {pycodedj-0.1.4 → pycodedj-0.2.0}/examples/hello_sc.py +1 -1
- {pycodedj-0.1.4 → pycodedj-0.2.0}/pyproject.toml +1 -1
- pycodedj-0.2.0/sc/synths.scd +494 -0
- {pycodedj-0.1.4 → pycodedj-0.2.0}/src/pycodedj/__init__.py +3 -0
- pycodedj-0.2.0/src/pycodedj/_loop.py +9 -0
- pycodedj-0.2.0/src/pycodedj/block_parser.py +72 -0
- {pycodedj-0.1.4 → pycodedj-0.2.0}/src/pycodedj/engine.py +1 -1
- {pycodedj-0.1.4 → pycodedj-0.2.0}/src/pycodedj/mapper.py +5 -1
- {pycodedj-0.1.4 → pycodedj-0.2.0}/src/pycodedj/osc_bridge.py +17 -9
- {pycodedj-0.1.4 → pycodedj-0.2.0}/src/pycodedj/watcher.py +5 -0
- pycodedj-0.2.0/tests/test_block_parser.py +116 -0
- {pycodedj-0.1.4 → pycodedj-0.2.0}/tests/test_mapper.py +10 -0
- {pycodedj-0.1.4 → pycodedj-0.2.0}/tests/test_osc_bridge.py +5 -9
- {pycodedj-0.1.4 → pycodedj-0.2.0}/tests/test_watcher.py +28 -16
- pycodedj-0.1.4/examples/club_set.py +0 -71
- pycodedj-0.1.4/sc/synths.scd +0 -154
- pycodedj-0.1.4/src/pycodedj/block_parser.py +0 -45
- pycodedj-0.1.4/tests/test_block_parser.py +0 -66
- {pycodedj-0.1.4 → pycodedj-0.2.0}/.github/workflows/workflow.yml +0 -0
- {pycodedj-0.1.4 → pycodedj-0.2.0}/.gitignore +0 -0
- {pycodedj-0.1.4 → pycodedj-0.2.0}/LICENSE +0 -0
- {pycodedj-0.1.4 → pycodedj-0.2.0}/docs/CNAME +0 -0
- {pycodedj-0.1.4 → pycodedj-0.2.0}/src/pycodedj/__main__.py +0 -0
- {pycodedj-0.1.4 → pycodedj-0.2.0}/src/pycodedj/analyzer.py +0 -0
- {pycodedj-0.1.4 → pycodedj-0.2.0}/tests/__init__.py +0 -0
- {pycodedj-0.1.4 → pycodedj-0.2.0}/tests/test_analyzer.py +0 -0
- {pycodedj-0.1.4 → pycodedj-0.2.0}/tests/test_engine.py +0 -0
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.0] - 2026-05-08
|
|
4
|
+
|
|
5
|
+
### Breaking
|
|
6
|
+
|
|
7
|
+
- `# @loop <name> interval=<sec>` コメント構文を廃止。`@loop("name", interval=sec)` デコレータ構文に移行
|
|
8
|
+
- 既存のライブコーディングファイルはデコレータ構文への書き換えが必要
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
- `@loop("name", interval=sec)` デコレータ — ファイルをそのまま `python` で実行できる no-op デコレータとして `from pycodedj import loop` で提供
|
|
13
|
+
- `volume=` 引数 — ループ関数のデフォルト引数として音量を直接指定できる(例: `def my_loop(volume=0.4):`)
|
|
14
|
+
- Amplitude パラメーター(`amp`)を OSC で SuperCollider に送出。`/pycodedj/loop/<name>/params` は `voice_count, cutoff, lfo_rate, reverb, amp` の 5 値に拡張
|
|
15
|
+
|
|
16
|
+
### Improvements
|
|
17
|
+
|
|
18
|
+
- `sc/synths.scd` — `amp` パラメーターをすべての SynthDef と OSC ハンドラーに追加
|
|
19
|
+
- `examples/club_set.py` — 6 層 14 ループ構成のクラブセットに刷新(foundation / movement / body / harmonic / space / texture)
|
|
20
|
+
- `examples/demo.py` — 新デコレータ構文に更新
|
|
21
|
+
|
|
22
|
+
### Docs
|
|
23
|
+
|
|
24
|
+
- README.md / README.ja.md — 新デコレータ構文・`volume=` 引数・`amp` OSC パラメーターに全面更新
|
|
25
|
+
- `docs/manual.md` / `docs/manual.ja.md` — 同上
|
|
26
|
+
- `docs/index.html` — ライブデモアニメーションとコード例を新構文に更新
|
|
27
|
+
|
|
3
28
|
## [0.1.4] - 2026-05-07
|
|
4
29
|
|
|
5
30
|
### Fixes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pycodedj
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
License: MIT License with Commons Clause
|
|
5
5
|
|
|
6
6
|
"Commons Clause" License Condition v1.0
|
|
@@ -107,6 +107,7 @@ BPM clock is held by SuperCollider's `TempoClock`. Python only sends parameter u
|
|
|
107
107
|
| Control-flow count (if/for/while) | LFO rate (0.1–5.0 Hz) | More branches = faster modulation |
|
|
108
108
|
| Function definition count | Polyphony voice count (1–4) | Functions = independent voices |
|
|
109
109
|
| Comment ratio | Reverb depth (0.0–0.8) | More whitespace = more space |
|
|
110
|
+
| `volume=` argument | Amplitude (0.0–1.0) | Direct performer control over loudness |
|
|
110
111
|
|
|
111
112
|
Tempo (BPM) and root pitch are controlled explicitly by the performer, to prevent the foundation of the piece from shifting on every save.
|
|
112
113
|
|
|
@@ -144,20 +145,22 @@ Open `sc/synths.scd` in the SuperCollider IDE and evaluate it.
|
|
|
144
145
|
**2. Write a live-coding file**
|
|
145
146
|
|
|
146
147
|
```python
|
|
147
|
-
|
|
148
|
-
|
|
148
|
+
from pycodedj import loop
|
|
149
|
+
|
|
150
|
+
@loop("bass", interval=2.0)
|
|
151
|
+
def bass(volume=0.4):
|
|
149
152
|
for i in range(8):
|
|
150
153
|
if i % 2 == 0:
|
|
151
154
|
pass
|
|
152
155
|
|
|
153
|
-
|
|
154
|
-
def melody():
|
|
156
|
+
@loop("melody", interval=0.5)
|
|
157
|
+
def melody(volume=0.3):
|
|
155
158
|
x = 1
|
|
156
159
|
y = 2
|
|
157
160
|
return x + y
|
|
158
161
|
|
|
159
|
-
|
|
160
|
-
def pad():
|
|
162
|
+
@loop("pad", interval=4.0)
|
|
163
|
+
def pad(volume=0.15):
|
|
161
164
|
# make space
|
|
162
165
|
# a little more
|
|
163
166
|
pass
|
|
@@ -172,7 +175,7 @@ pycodedj eval demo.py::bass
|
|
|
172
175
|
On success, feedback is printed immediately:
|
|
173
176
|
|
|
174
177
|
```
|
|
175
|
-
[pycodedj] bass cutoff=418Hz lfo=1.08Hz reverb=0.00 voices=1
|
|
178
|
+
[pycodedj] bass cutoff=418Hz lfo=1.08Hz reverb=0.00 voices=1 amp=0.40
|
|
176
179
|
```
|
|
177
180
|
|
|
178
181
|
Other loops keep playing without interruption.
|
|
@@ -187,8 +190,6 @@ pycodedj watch demo.py
|
|
|
187
190
|
|
|
188
191
|
From here, just write code and save.
|
|
189
192
|
|
|
190
|
-
> **Note on `interval` (current MVP):** Values like `interval=2.0` are parsed and stored, but are not yet sent over OSC. Loop repeat timing is managed by SuperCollider's `TempoClock`. A mechanism to pass interval to SC is planned for a future release.
|
|
191
|
-
|
|
192
193
|
---
|
|
193
194
|
|
|
194
195
|
## Example Files
|
|
@@ -196,7 +197,7 @@ From here, just write code and save.
|
|
|
196
197
|
| File | Contents |
|
|
197
198
|
| :--- | :--- |
|
|
198
199
|
| `examples/demo.py` | Intro demo with bass / melody / pad |
|
|
199
|
-
| `examples/club_set.py` |
|
|
200
|
+
| `examples/club_set.py` | Layered club groove using kick_hard / bass_rumble / bass_reese and more |
|
|
200
201
|
|
|
201
202
|
---
|
|
202
203
|
|
|
@@ -205,8 +206,10 @@ From here, just write code and save.
|
|
|
205
206
|
### Deeper nesting opens the filter
|
|
206
207
|
|
|
207
208
|
```python
|
|
208
|
-
|
|
209
|
-
|
|
209
|
+
from pycodedj import loop
|
|
210
|
+
|
|
211
|
+
@loop("bass", interval=2.0)
|
|
212
|
+
def bass(volume=0.4):
|
|
210
213
|
for i in range(4): # control flow +1
|
|
211
214
|
for j in range(4): # depth +1, control flow +1
|
|
212
215
|
if i == j: # depth +1, control flow +1
|
|
@@ -216,21 +219,27 @@ def bass():
|
|
|
216
219
|
### More functions = more polyphony
|
|
217
220
|
|
|
218
221
|
```python
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
def
|
|
223
|
-
def
|
|
222
|
+
from pycodedj import loop
|
|
223
|
+
|
|
224
|
+
@loop("chord", interval=1.0)
|
|
225
|
+
def chord(volume=0.2):
|
|
226
|
+
def voice_a(): pass
|
|
227
|
+
def voice_b(): pass
|
|
228
|
+
def voice_c(): pass
|
|
229
|
+
def voice_d(): pass
|
|
224
230
|
```
|
|
225
231
|
|
|
226
232
|
### More comments = more space (reverb)
|
|
227
233
|
|
|
228
234
|
```python
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
235
|
+
from pycodedj import loop
|
|
236
|
+
|
|
237
|
+
@loop("pad", interval=4.0)
|
|
238
|
+
def pad(volume=0.15):
|
|
239
|
+
# leave space here
|
|
240
|
+
# a little more
|
|
241
|
+
# silence is music
|
|
242
|
+
pass
|
|
234
243
|
```
|
|
235
244
|
|
|
236
245
|
---
|
|
@@ -241,10 +250,12 @@ Addresses used to communicate with SuperCollider.
|
|
|
241
250
|
|
|
242
251
|
| Address | Type | Range | Parameter |
|
|
243
252
|
| :--- | :--- | :--- | :--- |
|
|
244
|
-
| `/pycodedj/loop/<name>/
|
|
245
|
-
| `/pycodedj/loop/<name>/
|
|
246
|
-
| `/pycodedj/loop/<name>/
|
|
247
|
-
| `/pycodedj/loop/<name>/
|
|
253
|
+
| `/pycodedj/loop/<name>/params` | int, float, float, float, float | see parameter order | `voice_count`, `cutoff`, `lfo_rate`, `reverb`, `amp` |
|
|
254
|
+
| `/pycodedj/loop/<name>/cutoff` | float | 200–4000 Hz | Filter Cutoff (compatibility) |
|
|
255
|
+
| `/pycodedj/loop/<name>/lfo_rate` | float | 0.1–5.0 Hz | LFO rate (compatibility) |
|
|
256
|
+
| `/pycodedj/loop/<name>/reverb` | float | 0.0–0.8 | Reverb depth (compatibility) |
|
|
257
|
+
| `/pycodedj/loop/<name>/voice_count` | int | 1–4 | Polyphony voice count (compatibility) |
|
|
258
|
+
| `/pycodedj/loop/<name>/amp` | float | 0.0–1.0 | Amplitude (compatibility) |
|
|
248
259
|
|
|
249
260
|
`<name>` is the loop name (e.g. `bass`, `melody`). Each loop has its own address namespace, so multiple loops never overwrite each other's parameters.
|
|
250
261
|
|
|
@@ -45,6 +45,7 @@ BPMクロックは SuperCollider 側の `TempoClock` が保持します。Python
|
|
|
45
45
|
| 制御フロー数(if/for/while) | LFO レート (0.1–5.0 Hz) | 分岐の多さ=揺らぎの速さ |
|
|
46
46
|
| 関数定義数 | ポリフォニー声部数 (1–4) | 関数=独立した声部 |
|
|
47
47
|
| コメント率 | リバーブ Depth (0.0–0.8) | 余白の多さ=空間の広さ |
|
|
48
|
+
| `volume=` 引数 | Amplitude (0.0–1.0) | 演奏者が直接音量を制御する |
|
|
48
49
|
|
|
49
50
|
テンポ(BPM)と基音(Pitch)は演奏者が明示的に制御します。保存のたびに楽曲全体の土台が変わることを防ぐためです。
|
|
50
51
|
|
|
@@ -82,20 +83,22 @@ SuperCollider IDE で `sc/synths.scd` を開いて実行します。
|
|
|
82
83
|
**2. ライブコーディングファイルを用意する**
|
|
83
84
|
|
|
84
85
|
```python
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
from pycodedj import loop
|
|
87
|
+
|
|
88
|
+
@loop("bass", interval=2.0)
|
|
89
|
+
def bass(volume=0.4):
|
|
87
90
|
for i in range(8):
|
|
88
91
|
if i % 2 == 0:
|
|
89
92
|
pass
|
|
90
93
|
|
|
91
|
-
|
|
92
|
-
def melody():
|
|
94
|
+
@loop("melody", interval=0.5)
|
|
95
|
+
def melody(volume=0.3):
|
|
93
96
|
x = 1
|
|
94
97
|
y = 2
|
|
95
98
|
return x + y
|
|
96
99
|
|
|
97
|
-
|
|
98
|
-
def pad():
|
|
100
|
+
@loop("pad", interval=4.0)
|
|
101
|
+
def pad(volume=0.15):
|
|
99
102
|
# 空間を作る
|
|
100
103
|
# もう少し余白
|
|
101
104
|
pass
|
|
@@ -110,7 +113,7 @@ pycodedj eval demo.py::bass
|
|
|
110
113
|
成功すると次のフィードバックが表示されます。
|
|
111
114
|
|
|
112
115
|
```
|
|
113
|
-
[pycodedj] bass cutoff=418Hz lfo=1.08Hz reverb=0.00 voices=1
|
|
116
|
+
[pycodedj] bass cutoff=418Hz lfo=1.08Hz reverb=0.00 voices=1 amp=0.40
|
|
114
117
|
```
|
|
115
118
|
|
|
116
119
|
他のループはそのまま鳴り続けます。
|
|
@@ -125,8 +128,6 @@ pycodedj watch demo.py
|
|
|
125
128
|
|
|
126
129
|
あとはエディタでコードを書いて保存するだけです。
|
|
127
130
|
|
|
128
|
-
> **`interval` について(現在の MVP):** `interval=2.0` のような値はパーサーが読み取りますが、現時点では OSC では送信されません。ループの繰り返し周期は SuperCollider 側の `TempoClock` で管理します。将来的に SC 側に interval を渡す仕組みを追加する予定です。
|
|
129
|
-
|
|
130
131
|
---
|
|
131
132
|
|
|
132
133
|
## サンプルファイル
|
|
@@ -134,7 +135,7 @@ pycodedj watch demo.py
|
|
|
134
135
|
| ファイル | 内容 |
|
|
135
136
|
| :--- | :--- |
|
|
136
137
|
| `examples/demo.py` | bass / melody / pad の 3 ループ入門デモ |
|
|
137
|
-
| `examples/club_set.py` |
|
|
138
|
+
| `examples/club_set.py` | kick_hard / bass_rumble / bass_reese などを重ねた多層クラブグルーヴ |
|
|
138
139
|
|
|
139
140
|
---
|
|
140
141
|
|
|
@@ -143,8 +144,10 @@ pycodedj watch demo.py
|
|
|
143
144
|
### ネストを深くするとフィルターが開く
|
|
144
145
|
|
|
145
146
|
```python
|
|
146
|
-
|
|
147
|
-
|
|
147
|
+
from pycodedj import loop
|
|
148
|
+
|
|
149
|
+
@loop("bass", interval=2.0)
|
|
150
|
+
def bass(volume=0.4):
|
|
148
151
|
for i in range(4): # 制御フロー +1
|
|
149
152
|
for j in range(4): # ネスト深さ +1、制御フロー +1
|
|
150
153
|
if i == j: # ネスト深さ +1、制御フロー +1
|
|
@@ -154,21 +157,27 @@ def bass():
|
|
|
154
157
|
### 関数を増やすとポリフォニーが広がる
|
|
155
158
|
|
|
156
159
|
```python
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
def
|
|
161
|
-
def
|
|
160
|
+
from pycodedj import loop
|
|
161
|
+
|
|
162
|
+
@loop("chord", interval=1.0)
|
|
163
|
+
def chord(volume=0.2):
|
|
164
|
+
def voice_a(): pass
|
|
165
|
+
def voice_b(): pass
|
|
166
|
+
def voice_c(): pass
|
|
167
|
+
def voice_d(): pass
|
|
162
168
|
```
|
|
163
169
|
|
|
164
170
|
### コメントを増やすと空間(リバーブ)が広がる
|
|
165
171
|
|
|
166
172
|
```python
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
173
|
+
from pycodedj import loop
|
|
174
|
+
|
|
175
|
+
@loop("pad", interval=4.0)
|
|
176
|
+
def pad(volume=0.15):
|
|
177
|
+
# ここに余白を置く
|
|
178
|
+
# もう少し置く
|
|
179
|
+
# 静寂も音楽
|
|
180
|
+
pass
|
|
172
181
|
```
|
|
173
182
|
|
|
174
183
|
---
|
|
@@ -179,10 +188,12 @@ SuperCollider との通信に使うアドレスです。
|
|
|
179
188
|
|
|
180
189
|
| アドレス | 型 | 値域 | 対応パラメーター |
|
|
181
190
|
| :--- | :--- | :--- | :--- |
|
|
182
|
-
| `/pycodedj/loop/<name>/
|
|
183
|
-
| `/pycodedj/loop/<name>/
|
|
184
|
-
| `/pycodedj/loop/<name>/
|
|
185
|
-
| `/pycodedj/loop/<name>/
|
|
191
|
+
| `/pycodedj/loop/<name>/params` | int, float, float, float, float | パラメーター順を参照 | `voice_count`, `cutoff`, `lfo_rate`, `reverb`, `amp` |
|
|
192
|
+
| `/pycodedj/loop/<name>/cutoff` | float | 200–4000 Hz | フィルター Cutoff(互換用) |
|
|
193
|
+
| `/pycodedj/loop/<name>/lfo_rate` | float | 0.1–5.0 Hz | LFO レート(互換用) |
|
|
194
|
+
| `/pycodedj/loop/<name>/reverb` | float | 0.0–0.8 | リバーブ Depth(互換用) |
|
|
195
|
+
| `/pycodedj/loop/<name>/voice_count` | int | 1–4 | ポリフォニー声部数(互換用) |
|
|
196
|
+
| `/pycodedj/loop/<name>/amp` | float | 0.0–1.0 | Amplitude(互換用) |
|
|
186
197
|
|
|
187
198
|
`<name>` はブロック名(`bass`、`melody` など)です。ループごとに独立したアドレスを持つため、複数ループが同じパラメーターを上書きしません。
|
|
188
199
|
|
|
@@ -45,6 +45,7 @@ BPM clock is held by SuperCollider's `TempoClock`. Python only sends parameter u
|
|
|
45
45
|
| Control-flow count (if/for/while) | LFO rate (0.1–5.0 Hz) | More branches = faster modulation |
|
|
46
46
|
| Function definition count | Polyphony voice count (1–4) | Functions = independent voices |
|
|
47
47
|
| Comment ratio | Reverb depth (0.0–0.8) | More whitespace = more space |
|
|
48
|
+
| `volume=` argument | Amplitude (0.0–1.0) | Direct performer control over loudness |
|
|
48
49
|
|
|
49
50
|
Tempo (BPM) and root pitch are controlled explicitly by the performer, to prevent the foundation of the piece from shifting on every save.
|
|
50
51
|
|
|
@@ -82,20 +83,22 @@ Open `sc/synths.scd` in the SuperCollider IDE and evaluate it.
|
|
|
82
83
|
**2. Write a live-coding file**
|
|
83
84
|
|
|
84
85
|
```python
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
from pycodedj import loop
|
|
87
|
+
|
|
88
|
+
@loop("bass", interval=2.0)
|
|
89
|
+
def bass(volume=0.4):
|
|
87
90
|
for i in range(8):
|
|
88
91
|
if i % 2 == 0:
|
|
89
92
|
pass
|
|
90
93
|
|
|
91
|
-
|
|
92
|
-
def melody():
|
|
94
|
+
@loop("melody", interval=0.5)
|
|
95
|
+
def melody(volume=0.3):
|
|
93
96
|
x = 1
|
|
94
97
|
y = 2
|
|
95
98
|
return x + y
|
|
96
99
|
|
|
97
|
-
|
|
98
|
-
def pad():
|
|
100
|
+
@loop("pad", interval=4.0)
|
|
101
|
+
def pad(volume=0.15):
|
|
99
102
|
# make space
|
|
100
103
|
# a little more
|
|
101
104
|
pass
|
|
@@ -110,7 +113,7 @@ pycodedj eval demo.py::bass
|
|
|
110
113
|
On success, feedback is printed immediately:
|
|
111
114
|
|
|
112
115
|
```
|
|
113
|
-
[pycodedj] bass cutoff=418Hz lfo=1.08Hz reverb=0.00 voices=1
|
|
116
|
+
[pycodedj] bass cutoff=418Hz lfo=1.08Hz reverb=0.00 voices=1 amp=0.40
|
|
114
117
|
```
|
|
115
118
|
|
|
116
119
|
Other loops keep playing without interruption.
|
|
@@ -125,8 +128,6 @@ pycodedj watch demo.py
|
|
|
125
128
|
|
|
126
129
|
From here, just write code and save.
|
|
127
130
|
|
|
128
|
-
> **Note on `interval` (current MVP):** Values like `interval=2.0` are parsed and stored, but are not yet sent over OSC. Loop repeat timing is managed by SuperCollider's `TempoClock`. A mechanism to pass interval to SC is planned for a future release.
|
|
129
|
-
|
|
130
131
|
---
|
|
131
132
|
|
|
132
133
|
## Example Files
|
|
@@ -134,7 +135,7 @@ From here, just write code and save.
|
|
|
134
135
|
| File | Contents |
|
|
135
136
|
| :--- | :--- |
|
|
136
137
|
| `examples/demo.py` | Intro demo with bass / melody / pad |
|
|
137
|
-
| `examples/club_set.py` |
|
|
138
|
+
| `examples/club_set.py` | Layered club groove using kick_hard / bass_rumble / bass_reese and more |
|
|
138
139
|
|
|
139
140
|
---
|
|
140
141
|
|
|
@@ -143,8 +144,10 @@ From here, just write code and save.
|
|
|
143
144
|
### Deeper nesting opens the filter
|
|
144
145
|
|
|
145
146
|
```python
|
|
146
|
-
|
|
147
|
-
|
|
147
|
+
from pycodedj import loop
|
|
148
|
+
|
|
149
|
+
@loop("bass", interval=2.0)
|
|
150
|
+
def bass(volume=0.4):
|
|
148
151
|
for i in range(4): # control flow +1
|
|
149
152
|
for j in range(4): # depth +1, control flow +1
|
|
150
153
|
if i == j: # depth +1, control flow +1
|
|
@@ -154,21 +157,27 @@ def bass():
|
|
|
154
157
|
### More functions = more polyphony
|
|
155
158
|
|
|
156
159
|
```python
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
def
|
|
161
|
-
def
|
|
160
|
+
from pycodedj import loop
|
|
161
|
+
|
|
162
|
+
@loop("chord", interval=1.0)
|
|
163
|
+
def chord(volume=0.2):
|
|
164
|
+
def voice_a(): pass
|
|
165
|
+
def voice_b(): pass
|
|
166
|
+
def voice_c(): pass
|
|
167
|
+
def voice_d(): pass
|
|
162
168
|
```
|
|
163
169
|
|
|
164
170
|
### More comments = more space (reverb)
|
|
165
171
|
|
|
166
172
|
```python
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
173
|
+
from pycodedj import loop
|
|
174
|
+
|
|
175
|
+
@loop("pad", interval=4.0)
|
|
176
|
+
def pad(volume=0.15):
|
|
177
|
+
# leave space here
|
|
178
|
+
# a little more
|
|
179
|
+
# silence is music
|
|
180
|
+
pass
|
|
172
181
|
```
|
|
173
182
|
|
|
174
183
|
---
|
|
@@ -179,10 +188,12 @@ Addresses used to communicate with SuperCollider.
|
|
|
179
188
|
|
|
180
189
|
| Address | Type | Range | Parameter |
|
|
181
190
|
| :--- | :--- | :--- | :--- |
|
|
182
|
-
| `/pycodedj/loop/<name>/
|
|
183
|
-
| `/pycodedj/loop/<name>/
|
|
184
|
-
| `/pycodedj/loop/<name>/
|
|
185
|
-
| `/pycodedj/loop/<name>/
|
|
191
|
+
| `/pycodedj/loop/<name>/params` | int, float, float, float, float | see parameter order | `voice_count`, `cutoff`, `lfo_rate`, `reverb`, `amp` |
|
|
192
|
+
| `/pycodedj/loop/<name>/cutoff` | float | 200–4000 Hz | Filter Cutoff (compatibility) |
|
|
193
|
+
| `/pycodedj/loop/<name>/lfo_rate` | float | 0.1–5.0 Hz | LFO rate (compatibility) |
|
|
194
|
+
| `/pycodedj/loop/<name>/reverb` | float | 0.0–0.8 | Reverb depth (compatibility) |
|
|
195
|
+
| `/pycodedj/loop/<name>/voice_count` | int | 1–4 | Polyphony voice count (compatibility) |
|
|
196
|
+
| `/pycodedj/loop/<name>/amp` | float | 0.0–1.0 | Amplitude (compatibility) |
|
|
186
197
|
|
|
187
198
|
`<name>` is the loop name (e.g. `bass`, `melody`). Each loop has its own address namespace, so multiple loops never overwrite each other's parameters.
|
|
188
199
|
|
|
@@ -198,12 +198,14 @@
|
|
|
198
198
|
min-height: 200px;
|
|
199
199
|
white-space: pre-wrap;
|
|
200
200
|
}
|
|
201
|
-
.c-comment
|
|
202
|
-
.c-keyword
|
|
203
|
-
.c-fn
|
|
204
|
-
.c-string
|
|
205
|
-
.c-
|
|
206
|
-
.c-
|
|
201
|
+
.c-comment { color: #585b70; font-style: italic; }
|
|
202
|
+
.c-keyword { color: var(--mauve); }
|
|
203
|
+
.c-fn { color: var(--blue); }
|
|
204
|
+
.c-string { color: var(--green); }
|
|
205
|
+
.c-str { color: var(--green); }
|
|
206
|
+
.c-num { color: var(--yellow); }
|
|
207
|
+
.c-op { color: var(--muted); }
|
|
208
|
+
.c-decorator { color: var(--pink); }
|
|
207
209
|
|
|
208
210
|
.demo-params {
|
|
209
211
|
padding: 1.25rem;
|
|
@@ -719,8 +721,10 @@
|
|
|
719
721
|
<span class="example-tag"># bright + fast</span>
|
|
720
722
|
<span class="example-effect">cutoff ↑ lfo ↑</span>
|
|
721
723
|
</div>
|
|
722
|
-
<pre><span class="c-
|
|
723
|
-
|
|
724
|
+
<pre><span class="c-keyword">from</span> pycodedj <span class="c-keyword">import</span> loop
|
|
725
|
+
|
|
726
|
+
<span class="c-decorator">@loop</span>(<span class="c-str">"bass"</span>, interval=<span class="c-num">2.0</span>)
|
|
727
|
+
<span class="c-keyword">def</span> <span class="c-fn">bass</span>(volume=<span class="c-num">0.4</span>):
|
|
724
728
|
<span class="c-keyword">for</span> i <span class="c-keyword">in</span> <span class="c-fn">range</span>(<span class="c-num">8</span>):
|
|
725
729
|
<span class="c-keyword">for</span> j <span class="c-keyword">in</span> <span class="c-fn">range</span>(<span class="c-num">4</span>):
|
|
726
730
|
<span class="c-keyword">if</span> i <span class="c-op">==</span> j:
|
|
@@ -731,23 +735,29 @@
|
|
|
731
735
|
<span class="example-tag"># 4-voice chord</span>
|
|
732
736
|
<span class="example-effect">voices = 4</span>
|
|
733
737
|
</div>
|
|
734
|
-
<pre><span class="c-
|
|
735
|
-
|
|
736
|
-
<span class="c-
|
|
737
|
-
<span class="c-keyword">def</span> <span class="c-fn">
|
|
738
|
-
<span class="c-keyword">def</span> <span class="c-fn">
|
|
738
|
+
<pre><span class="c-keyword">from</span> pycodedj <span class="c-keyword">import</span> loop
|
|
739
|
+
|
|
740
|
+
<span class="c-decorator">@loop</span>(<span class="c-str">"chord"</span>, interval=<span class="c-num">1.0</span>)
|
|
741
|
+
<span class="c-keyword">def</span> <span class="c-fn">chord</span>(volume=<span class="c-num">0.2</span>):
|
|
742
|
+
<span class="c-keyword">def</span> <span class="c-fn">voice_a</span>(): <span class="c-keyword">pass</span>
|
|
743
|
+
<span class="c-keyword">def</span> <span class="c-fn">voice_b</span>(): <span class="c-keyword">pass</span>
|
|
744
|
+
<span class="c-keyword">def</span> <span class="c-fn">voice_c</span>(): <span class="c-keyword">pass</span>
|
|
745
|
+
<span class="c-keyword">def</span> <span class="c-fn">voice_d</span>(): <span class="c-keyword">pass</span></pre>
|
|
739
746
|
</div>
|
|
740
747
|
<div class="example-card">
|
|
741
748
|
<div class="example-card-header">
|
|
742
749
|
<span class="example-tag"># deep space</span>
|
|
743
750
|
<span class="example-effect">reverb ↑↑</span>
|
|
744
751
|
</div>
|
|
745
|
-
<pre><span class="c-
|
|
746
|
-
|
|
747
|
-
<span class="c-
|
|
748
|
-
<span class="c-
|
|
749
|
-
<span class="c-comment">#
|
|
750
|
-
<span class="c-
|
|
752
|
+
<pre><span class="c-keyword">from</span> pycodedj <span class="c-keyword">import</span> loop
|
|
753
|
+
|
|
754
|
+
<span class="c-decorator">@loop</span>(<span class="c-str">"pad"</span>, interval=<span class="c-num">4.0</span>)
|
|
755
|
+
<span class="c-keyword">def</span> <span class="c-fn">pad</span>(volume=<span class="c-num">0.15</span>):
|
|
756
|
+
<span class="c-comment"># smoke above the kick</span>
|
|
757
|
+
<span class="c-comment"># late reflections</span>
|
|
758
|
+
<span class="c-comment"># concrete room tail</span>
|
|
759
|
+
<span class="c-comment"># crowd heat</span>
|
|
760
|
+
<span class="c-keyword">pass</span></pre>
|
|
751
761
|
</div>
|
|
752
762
|
</div>
|
|
753
763
|
</div>
|
|
@@ -777,72 +787,74 @@
|
|
|
777
787
|
const frames = [
|
|
778
788
|
{
|
|
779
789
|
code: [
|
|
780
|
-
'<span class="c-
|
|
781
|
-
'<span class="c-keyword">def</span> <span class="c-fn">bass</span>():',
|
|
790
|
+
'<span class="c-decorator">@loop</span>(<span class="c-str">"bass"</span>, interval=<span class="c-num">2.0</span>)',
|
|
791
|
+
'<span class="c-keyword">def</span> <span class="c-fn">bass</span>(volume=<span class="c-num">0.4</span>):',
|
|
782
792
|
' <span class="c-keyword">pass</span>',
|
|
783
793
|
],
|
|
784
|
-
// depth=1 cf=0 fns=1 comment_ratio=0.
|
|
794
|
+
// depth=1 cf=0 fns=1 comment_ratio=0.00
|
|
785
795
|
cutoff: { pct: 10, val: '580 Hz' },
|
|
786
796
|
lfo: { pct: 0, val: '0.10 Hz' },
|
|
787
|
-
reverb: { pct:
|
|
797
|
+
reverb: { pct: 0, val: '0.00' },
|
|
788
798
|
voices: { pct: 25, val: '1 voice' },
|
|
789
799
|
},
|
|
790
800
|
{
|
|
791
801
|
code: [
|
|
792
|
-
'<span class="c-
|
|
793
|
-
'<span class="c-keyword">def</span> <span class="c-fn">bass</span>():',
|
|
802
|
+
'<span class="c-decorator">@loop</span>(<span class="c-str">"bass"</span>, interval=<span class="c-num">2.0</span>)',
|
|
803
|
+
'<span class="c-keyword">def</span> <span class="c-fn">bass</span>(volume=<span class="c-num">0.4</span>):',
|
|
794
804
|
' <span class="c-keyword">for</span> i <span class="c-keyword">in</span> <span class="c-fn">range</span>(<span class="c-num">8</span>):',
|
|
795
805
|
' <span class="c-keyword">if</span> i <span class="c-op">%</span> <span class="c-num">2</span> <span class="c-op">==</span> <span class="c-num">0</span>:',
|
|
796
806
|
' <span class="c-keyword">pass</span>',
|
|
797
807
|
],
|
|
798
|
-
// depth=3 cf=2 fns=1 comment_ratio=0.
|
|
808
|
+
// depth=3 cf=2 fns=1 comment_ratio=0.00
|
|
799
809
|
cutoff: { pct: 30, val: '1340 Hz' },
|
|
800
810
|
lfo: { pct: 20, val: '1.08 Hz' },
|
|
801
|
-
reverb: { pct:
|
|
811
|
+
reverb: { pct: 0, val: '0.00' },
|
|
802
812
|
voices: { pct: 25, val: '1 voice' },
|
|
803
813
|
},
|
|
804
814
|
{
|
|
805
815
|
code: [
|
|
806
|
-
'<span class="c-
|
|
807
|
-
'<span class="c-keyword">def</span> <span class="c-fn">bass</span>():',
|
|
816
|
+
'<span class="c-decorator">@loop</span>(<span class="c-str">"bass"</span>, interval=<span class="c-num">2.0</span>)',
|
|
817
|
+
'<span class="c-keyword">def</span> <span class="c-fn">bass</span>(volume=<span class="c-num">0.4</span>):',
|
|
808
818
|
' <span class="c-keyword">for</span> i <span class="c-keyword">in</span> <span class="c-fn">range</span>(<span class="c-num">8</span>):',
|
|
809
819
|
' <span class="c-keyword">for</span> j <span class="c-keyword">in</span> <span class="c-fn">range</span>(<span class="c-num">4</span>):',
|
|
810
820
|
' <span class="c-keyword">if</span> i <span class="c-op">==</span> j:',
|
|
811
821
|
' <span class="c-keyword">pass</span>',
|
|
812
822
|
],
|
|
813
|
-
// depth=4 cf=3 fns=1 comment_ratio=0.
|
|
823
|
+
// depth=4 cf=3 fns=1 comment_ratio=0.00
|
|
814
824
|
cutoff: { pct: 40, val: '1720 Hz' },
|
|
815
825
|
lfo: { pct: 30, val: '1.57 Hz' },
|
|
816
|
-
reverb: { pct:
|
|
826
|
+
reverb: { pct: 0, val: '0.00' },
|
|
817
827
|
voices: { pct: 25, val: '1 voice' },
|
|
818
828
|
},
|
|
819
829
|
{
|
|
820
830
|
code: [
|
|
821
|
-
'<span class="c-
|
|
822
|
-
'<span class="c-keyword">def</span> <span class="c-fn">
|
|
823
|
-
'<span class="c-keyword">def</span> <span class="c-fn">
|
|
824
|
-
'<span class="c-keyword">def</span> <span class="c-fn">
|
|
825
|
-
'<span class="c-keyword">def</span> <span class="c-fn">
|
|
831
|
+
'<span class="c-decorator">@loop</span>(<span class="c-str">"chord"</span>, interval=<span class="c-num">1.0</span>)',
|
|
832
|
+
'<span class="c-keyword">def</span> <span class="c-fn">chord</span>(volume=<span class="c-num">0.2</span>):',
|
|
833
|
+
' <span class="c-keyword">def</span> <span class="c-fn">voice_a</span>(): <span class="c-keyword">pass</span>',
|
|
834
|
+
' <span class="c-keyword">def</span> <span class="c-fn">voice_b</span>(): <span class="c-keyword">pass</span>',
|
|
835
|
+
' <span class="c-keyword">def</span> <span class="c-fn">voice_c</span>(): <span class="c-keyword">pass</span>',
|
|
836
|
+
' <span class="c-keyword">def</span> <span class="c-fn">voice_d</span>(): <span class="c-keyword">pass</span>',
|
|
826
837
|
],
|
|
827
|
-
// depth=1 cf=0 fns=4 comment_ratio=0.
|
|
838
|
+
// depth=1 cf=0 fns=4 comment_ratio=0.00
|
|
828
839
|
cutoff: { pct: 10, val: '580 Hz' },
|
|
829
840
|
lfo: { pct: 0, val: '0.10 Hz' },
|
|
830
|
-
reverb: { pct:
|
|
841
|
+
reverb: { pct: 0, val: '0.00' },
|
|
831
842
|
voices: { pct: 100, val: '4 voices' },
|
|
832
843
|
},
|
|
833
844
|
{
|
|
834
845
|
code: [
|
|
835
|
-
'<span class="c-
|
|
836
|
-
'<span class="c-
|
|
837
|
-
'<span class="c-comment">#
|
|
838
|
-
'<span class="c-comment">#
|
|
839
|
-
'<span class="c-comment">#
|
|
840
|
-
'<span class="c-
|
|
846
|
+
'<span class="c-decorator">@loop</span>(<span class="c-str">"pad"</span>, interval=<span class="c-num">4.0</span>)',
|
|
847
|
+
'<span class="c-keyword">def</span> <span class="c-fn">pad</span>(volume=<span class="c-num">0.15</span>):',
|
|
848
|
+
' <span class="c-comment"># smoke above the kick</span>',
|
|
849
|
+
' <span class="c-comment"># late reflections</span>',
|
|
850
|
+
' <span class="c-comment"># concrete room tail</span>',
|
|
851
|
+
' <span class="c-comment"># crowd heat</span>',
|
|
852
|
+
' <span class="c-keyword">pass</span>',
|
|
841
853
|
],
|
|
842
|
-
// depth=1 cf=0 fns=1 comment_ratio=0.
|
|
854
|
+
// depth=1 cf=0 fns=1 comment_ratio=0.67
|
|
843
855
|
cutoff: { pct: 10, val: '580 Hz' },
|
|
844
856
|
lfo: { pct: 0, val: '0.10 Hz' },
|
|
845
|
-
reverb: { pct:
|
|
857
|
+
reverb: { pct: 71, val: '0.57' },
|
|
846
858
|
voices: { pct: 25, val: '1 voice' },
|
|
847
859
|
},
|
|
848
860
|
];
|