@hraness/dawg 0.5.0 → 0.6.1
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.
- package/CHANGELOG.md +63 -0
- package/DAWG.md +592 -49
- package/README.md +4 -4
- package/core/chords.ts +492 -4
- package/core/diff.ts +9 -0
- package/core/expression.ts +143 -6
- package/core/fx.ts +689 -2
- package/core/granular.ts +619 -0
- package/core/instruments.ts +442 -0
- package/core/keys.ts +955 -0
- package/core/resonators.ts +862 -0
- package/core/score.ts +529 -8
- package/core/sdk/eval-child.ts +2 -0
- package/core/sdk/print.ts +247 -16
- package/core/sdk/sync-instruments.ts +58 -0
- package/core/sdk/v1.ts +2417 -40
- package/core/sections.ts +44 -10
- package/core/strings.ts +1080 -0
- package/core/winds.ts +652 -0
- package/guides/automation.md +1 -0
- package/guides/chords.md +3 -1
- package/guides/effects.md +5 -2
- package/guides/media.md +1 -1
- package/guides/performance.md +3 -0
- package/guides/resample.md +26 -0
- package/guides/sounds.md +7 -2
- package/guides/tempo.md +1 -0
- package/package.json +1 -1
- package/src/agent/agent.ts +13 -0
- package/src/agent/chord-tools.ts +153 -1
- package/src/agent/expression-tools.ts +91 -0
- package/src/agent/granular-tools.ts +138 -0
- package/src/agent/models.ts +4 -4
- package/src/agent/ops.ts +42 -2
- package/src/agent/preview-tool.ts +7 -1
- package/src/agent/resample-tool.ts +131 -0
- package/src/agent/tools.ts +726 -17
- package/src/agent/xcb-agent.ts +13 -0
- package/src/audio/arrange.ts +42 -3
- package/src/audio/dsp/bank.ts +233 -0
- package/src/audio/dsp/envelope.ts +161 -0
- package/src/audio/dsp/fft.ts +6 -0
- package/src/audio/dsp/filters.ts +57 -0
- package/src/audio/dsp/interp.ts +112 -0
- package/src/audio/dsp/modal.ts +684 -0
- package/src/audio/dsp/onset.ts +197 -0
- package/src/audio/dsp/oversample.ts +202 -0
- package/src/audio/dsp/rng.ts +37 -0
- package/src/audio/dsp/shape.ts +81 -0
- package/src/audio/dsp/shift.ts +256 -0
- package/src/audio/dsp/stft.ts +73 -0
- package/src/audio/dsp/window.ts +77 -0
- package/src/audio/effects/chain.ts +23 -3
- package/src/audio/effects/common.ts +14 -0
- package/src/audio/effects/convolution.ts +106 -1
- package/src/audio/effects/gaze.ts +354 -0
- package/src/audio/effects/rig/cab.ts +99 -0
- package/src/audio/effects/rig/filters.ts +152 -0
- package/src/audio/effects/rig/gate.ts +39 -0
- package/src/audio/effects/rig/head.ts +487 -0
- package/src/audio/effects/rig/index.ts +170 -0
- package/src/audio/effects/rig/section.ts +78 -0
- package/src/audio/effects/rig/stomp.ts +238 -0
- package/src/audio/engine.ts +56 -6
- package/src/audio/fit.ts +447 -0
- package/src/audio/granular.ts +995 -0
- package/src/audio/instrument-check.ts +137 -0
- package/src/audio/instruments.ts +140 -0
- package/src/audio/keys/dsp.ts +323 -0
- package/src/audio/keys/electric.ts +420 -0
- package/src/audio/keys/engine.ts +485 -0
- package/src/audio/keys/organ.ts +1335 -0
- package/src/audio/keys/piano.ts +476 -0
- package/src/audio/keys/sympathetic.ts +127 -0
- package/src/audio/live-worker.ts +56 -0
- package/src/audio/live.ts +361 -15
- package/src/audio/loudness.ts +65 -20
- package/src/audio/preview.ts +17 -1
- package/src/audio/resample.ts +285 -0
- package/src/audio/resonators.ts +295 -0
- package/src/audio/sampler.ts +328 -35
- package/src/audio/samples.ts +56 -8
- package/src/audio/strings/body.ts +263 -0
- package/src/audio/strings/bow.ts +656 -0
- package/src/audio/strings/engine.ts +615 -0
- package/src/audio/strings/loop.ts +119 -0
- package/src/audio/strings/measure.test-helpers.ts +200 -0
- package/src/audio/strings/pluck.ts +354 -0
- package/src/audio/warp.ts +61 -0
- package/src/audio/wav.ts +191 -19
- package/src/audio/winds/engine.ts +302 -0
- package/src/audio/winds/filters.ts +153 -0
- package/src/audio/winds/pitch.ts +104 -0
- package/src/audio/winds/trim.ts +80 -0
- package/src/audio/winds/trims.ts +917 -0
- package/src/audio/winds/voice.ts +479 -0
- package/src/commands/expression.ts +111 -23
- package/src/commands/fit.ts +135 -0
- package/src/commands/fx.ts +35 -1
- package/src/commands/granular.ts +432 -0
- package/src/commands/help.ts +159 -5
- package/src/commands/keys.ts +629 -0
- package/src/commands/modal.ts +310 -0
- package/src/commands/resample.ts +281 -0
- package/src/commands/rig.ts +264 -0
- package/src/commands/sample.ts +52 -2
- package/src/commands/shift.ts +119 -0
- package/src/commands/string.ts +201 -0
- package/src/commands/strum.ts +473 -0
- package/src/commands/time.ts +4 -1
- package/src/commands/wind.ts +244 -0
- package/src/main.ts +339 -15
- package/src/project/check.ts +17 -0
- package/src/render.ts +49 -4
- package/src/session/presence.ts +16 -3
- package/src/tui/audition.ts +2 -2
- package/src/tui/granular-menu.ts +278 -0
- package/src/tui/menu.ts +934 -9
- package/src/tui/modal-menu.ts +145 -0
- package/src/tui/performance-menu.ts +42 -0
- package/src/tui/play-chords.ts +104 -3
- package/src/tui/play-mode.ts +1 -0
- package/src/tui/play-session.ts +70 -2
- package/src/tui/wind-menu.ts +144 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-track string bodies and sympathetic strings (0.6 strings prototype,
|
|
3
|
+
* proto/strings/strings.ts). A body is a direct path plus a bank of 0 dB
|
|
4
|
+
* band-pass modes, run once per track over the summed strings; `size`
|
|
5
|
+
* scales the body (mode frequencies x 1/size). Sympathetic strings are
|
|
6
|
+
* one-way coupled loops tuned to the song key, open strings or a drone.
|
|
7
|
+
*/
|
|
8
|
+
import { thiranFor } from "../dsp/interp.ts";
|
|
9
|
+
import { C4 } from "./pluck.ts";
|
|
10
|
+
import { designLoss, onePoleDelay } from "./loop.ts";
|
|
11
|
+
|
|
12
|
+
/** [frequency Hz, Q, gain] */
|
|
13
|
+
export type BodyMode = readonly [number, number, number];
|
|
14
|
+
export type Body = Readonly<{ direct: number; modes: readonly BodyMode[] }>;
|
|
15
|
+
|
|
16
|
+
export const BODIES: Readonly<Record<string, Body>> = Object.freeze({
|
|
17
|
+
none: { direct: 1, modes: [] },
|
|
18
|
+
guitar: {
|
|
19
|
+
direct: 0.55,
|
|
20
|
+
modes: [
|
|
21
|
+
[98, 10, 1.2],
|
|
22
|
+
[204, 14, 0.9],
|
|
23
|
+
[390, 18, 0.5],
|
|
24
|
+
[560, 20, 0.35],
|
|
25
|
+
[960, 12, 0.3],
|
|
26
|
+
[2300, 5, 0.35],
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
steel: {
|
|
30
|
+
direct: 0.6,
|
|
31
|
+
modes: [
|
|
32
|
+
[110, 10, 1.0],
|
|
33
|
+
[220, 14, 0.9],
|
|
34
|
+
[420, 16, 0.6],
|
|
35
|
+
[700, 14, 0.4],
|
|
36
|
+
[1600, 6, 0.4],
|
|
37
|
+
[3200, 4, 0.3],
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
small: {
|
|
41
|
+
direct: 0.6,
|
|
42
|
+
modes: [
|
|
43
|
+
[140, 10, 1.0],
|
|
44
|
+
[270, 14, 0.8],
|
|
45
|
+
[520, 16, 0.5],
|
|
46
|
+
[900, 12, 0.4],
|
|
47
|
+
[2200, 5, 0.35],
|
|
48
|
+
[3600, 4, 0.3],
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
bowl: {
|
|
52
|
+
direct: 0.55,
|
|
53
|
+
modes: [
|
|
54
|
+
[120, 10, 1.0],
|
|
55
|
+
[250, 12, 0.8],
|
|
56
|
+
[480, 14, 0.5],
|
|
57
|
+
[900, 10, 0.35],
|
|
58
|
+
[1800, 6, 0.3],
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
gourd: {
|
|
62
|
+
direct: 0.5,
|
|
63
|
+
modes: [
|
|
64
|
+
[180, 8, 0.9],
|
|
65
|
+
[360, 10, 0.5],
|
|
66
|
+
[720, 8, 0.4],
|
|
67
|
+
[1500, 5, 0.35],
|
|
68
|
+
[3000, 4, 0.3],
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
skin: {
|
|
72
|
+
direct: 0.45,
|
|
73
|
+
modes: [
|
|
74
|
+
[300, 6, 1.2],
|
|
75
|
+
[650, 6, 0.8],
|
|
76
|
+
[1300, 5, 0.6],
|
|
77
|
+
[2600, 4, 0.5],
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
board: {
|
|
81
|
+
direct: 0.6,
|
|
82
|
+
modes: [
|
|
83
|
+
[95, 6, 0.8],
|
|
84
|
+
[180, 8, 0.7],
|
|
85
|
+
[350, 8, 0.6],
|
|
86
|
+
[700, 8, 0.45],
|
|
87
|
+
[1400, 6, 0.35],
|
|
88
|
+
[2800, 5, 0.25],
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
violin: {
|
|
92
|
+
direct: 0.3,
|
|
93
|
+
modes: [
|
|
94
|
+
[275, 14, 1.0],
|
|
95
|
+
[460, 18, 0.9],
|
|
96
|
+
[540, 18, 1.1],
|
|
97
|
+
[700, 12, 0.5],
|
|
98
|
+
[1100, 8, 0.4],
|
|
99
|
+
[2500, 3, 0.9],
|
|
100
|
+
[3400, 4, 0.4],
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* The body for a name and size: modes x 1/size. `bass` is the violin body
|
|
107
|
+
* at 0.3 (a double bass is about 3.3 times the size).
|
|
108
|
+
*/
|
|
109
|
+
export function bodyFor(name: string, size: number): Body {
|
|
110
|
+
const base =
|
|
111
|
+
name === "bass" ? BODIES.violin! : (BODIES[name] ?? BODIES.none!);
|
|
112
|
+
const k = (name === "bass" ? 0.3 : 1) / Math.max(0.05, size);
|
|
113
|
+
if (k === 1) return base;
|
|
114
|
+
return {
|
|
115
|
+
direct: base.direct,
|
|
116
|
+
modes: base.modes.map(([f, q, g]) => [f * k, q, g] as const),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Body over `x` in place: direct + modes, then a 10 Hz DC blocker. */
|
|
121
|
+
export function applyBody(x: Float64Array, body: Body, sr: number): void {
|
|
122
|
+
if (body.modes.length === 0 && body.direct === 1) return;
|
|
123
|
+
// Every mode per sample in one pass, summed in mode order (the same
|
|
124
|
+
// arithmetic as a pass per mode, so the output is bit-identical), with
|
|
125
|
+
// the coefficients in flat arrays: about 7x faster under JSC.
|
|
126
|
+
const live = body.modes.filter(([f]) => f < 0.45 * sr);
|
|
127
|
+
const m = live.length;
|
|
128
|
+
const B0 = new Float64Array(m);
|
|
129
|
+
const A1 = new Float64Array(m);
|
|
130
|
+
const A2 = new Float64Array(m);
|
|
131
|
+
const G = new Float64Array(m);
|
|
132
|
+
const Z1 = new Float64Array(m);
|
|
133
|
+
const Z2 = new Float64Array(m);
|
|
134
|
+
for (let k = 0; k < m; k += 1) {
|
|
135
|
+
const [f, q, g] = live[k]!;
|
|
136
|
+
const w = (2 * Math.PI * f) / sr;
|
|
137
|
+
const alpha = Math.sin(w) / (2 * q);
|
|
138
|
+
const a0 = 1 + alpha;
|
|
139
|
+
B0[k] = alpha / a0;
|
|
140
|
+
A1[k] = (-2 * Math.cos(w)) / a0;
|
|
141
|
+
A2[k] = (1 - alpha) / a0;
|
|
142
|
+
G[k] = g;
|
|
143
|
+
}
|
|
144
|
+
const direct = body.direct;
|
|
145
|
+
for (let i = 0; i < x.length; i += 1) {
|
|
146
|
+
const xi = x[i]!;
|
|
147
|
+
let acc = direct * xi;
|
|
148
|
+
for (let k = 0; k < m; k += 1) {
|
|
149
|
+
const b0 = B0[k]!;
|
|
150
|
+
const y = b0 * xi + Z1[k]!;
|
|
151
|
+
Z1[k] = -A1[k]! * y + Z2[k]!;
|
|
152
|
+
Z2[k] = -b0 * xi - A2[k]! * y;
|
|
153
|
+
acc = acc + G[k]! * y;
|
|
154
|
+
}
|
|
155
|
+
x[i] = acc;
|
|
156
|
+
}
|
|
157
|
+
const R = Math.exp((-2 * Math.PI * 10) / sr);
|
|
158
|
+
let x1 = 0;
|
|
159
|
+
let y1 = 0;
|
|
160
|
+
for (let i = 0; i < x.length; i += 1) {
|
|
161
|
+
const xi = x[i]!;
|
|
162
|
+
const y = xi - x1 + R * y1;
|
|
163
|
+
x1 = xi;
|
|
164
|
+
y1 = y;
|
|
165
|
+
x[i] = y;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export type SymTune = "scale" | "open" | "drone";
|
|
170
|
+
|
|
171
|
+
/** A sympathetic string: a MIDI key plus cents (quarter tones). */
|
|
172
|
+
export interface SymKey {
|
|
173
|
+
key: number;
|
|
174
|
+
cents: number;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Sympathetic string keys per tuning mode. `steps` is the song key's scale
|
|
179
|
+
* in semitones above the tonic (fractional for quarter tones). `scale`
|
|
180
|
+
* tunes up to 13 strings to it; `drone` is Sa-Pa-Sa, or Sa-Ma-Sa (else
|
|
181
|
+
* Sa-Ni-Sa) when the scale has no Pa; `open` is guitar EADGBE.
|
|
182
|
+
*/
|
|
183
|
+
export function symKeys(
|
|
184
|
+
mode: string,
|
|
185
|
+
root: number,
|
|
186
|
+
steps: readonly number[],
|
|
187
|
+
): SymKey[] {
|
|
188
|
+
const at = (step: number): SymKey => {
|
|
189
|
+
const whole = Math.round(step);
|
|
190
|
+
return { key: root + whole, cents: Math.round((step - whole) * 1000) / 10 };
|
|
191
|
+
};
|
|
192
|
+
if (mode === "open")
|
|
193
|
+
return [40, 45, 50, 55, 59, 64].map((key) => ({ key, cents: 0 }));
|
|
194
|
+
if (mode === "drone") {
|
|
195
|
+
const has = (n: number) => steps.some((s) => Math.abs(s - n) < 0.01);
|
|
196
|
+
const second = has(7)
|
|
197
|
+
? at(-5)
|
|
198
|
+
: has(5)
|
|
199
|
+
? at(-7)
|
|
200
|
+
: has(6)
|
|
201
|
+
? at(-6)
|
|
202
|
+
: has(11)
|
|
203
|
+
? at(-1)
|
|
204
|
+
: at(-5);
|
|
205
|
+
return [at(-12), second, at(0)];
|
|
206
|
+
}
|
|
207
|
+
const sorted = [...steps]
|
|
208
|
+
.map((s) => ((s % 12) + 12) % 12)
|
|
209
|
+
.sort((a, b) => a - b);
|
|
210
|
+
const keys: SymKey[] = [];
|
|
211
|
+
for (let octave = 0; octave <= 12 && keys.length < 13; octave += 12)
|
|
212
|
+
for (const step of sorted)
|
|
213
|
+
if (step + octave <= 19 && keys.length < 13) keys.push(at(step + octave));
|
|
214
|
+
return keys;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Sympathetic strings: one-way coupled loops excited by `x`; returns only
|
|
219
|
+
* what they add (the coupled input is subtracted back out).
|
|
220
|
+
*/
|
|
221
|
+
export function sympathetic(
|
|
222
|
+
x: Float64Array,
|
|
223
|
+
hzs: readonly number[],
|
|
224
|
+
couple: number,
|
|
225
|
+
decay: number,
|
|
226
|
+
damp: number,
|
|
227
|
+
sr: number,
|
|
228
|
+
): Float64Array {
|
|
229
|
+
const out = new Float64Array(x.length);
|
|
230
|
+
for (const hz of hzs) {
|
|
231
|
+
if (!(hz > 20) || hz > 0.4 * sr) continue;
|
|
232
|
+
const t0 = decay * (hz / C4) ** -0.3;
|
|
233
|
+
const { g, p } = designLoss(
|
|
234
|
+
hz,
|
|
235
|
+
t0,
|
|
236
|
+
Math.max(3000, 3 * hz),
|
|
237
|
+
t0 / (1 + 99 * damp * damp),
|
|
238
|
+
sr,
|
|
239
|
+
);
|
|
240
|
+
const w0 = (2 * Math.PI * hz) / sr;
|
|
241
|
+
const rest = sr / hz - onePoleDelay(p, w0);
|
|
242
|
+
const N = Math.max(1, Math.floor(rest - 0.5));
|
|
243
|
+
const a = thiranFor(rest - N, w0);
|
|
244
|
+
let size = 16;
|
|
245
|
+
while (size < N + 4) size <<= 1;
|
|
246
|
+
const buf = new Float64Array(size);
|
|
247
|
+
const m = size - 1;
|
|
248
|
+
let tx = 0;
|
|
249
|
+
let ty = 0;
|
|
250
|
+
let ly = 0;
|
|
251
|
+
const lgain = g * (1 - p);
|
|
252
|
+
for (let i = 0; i < x.length; i += 1) {
|
|
253
|
+
const d = buf[(i - N) & m]!;
|
|
254
|
+
const t = a * d + tx - a * ty;
|
|
255
|
+
tx = d;
|
|
256
|
+
ty = t;
|
|
257
|
+
ly = lgain * t + p * ly;
|
|
258
|
+
buf[i & m] = couple * x[i]! + ly;
|
|
259
|
+
out[i] = out[i]! + ly;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return out;
|
|
263
|
+
}
|