@hraness/dawg 0.6.0 → 0.7.0
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 +126 -0
- package/DAWG.md +655 -141
- package/README.md +27 -25
- package/core/autotune.ts +1119 -0
- package/core/chords.ts +759 -23
- package/core/clips.ts +499 -0
- package/core/diff.ts +182 -99
- package/core/expression.ts +158 -6
- package/core/fx.ts +354 -32
- package/core/granular.ts +91 -0
- package/core/instruments.ts +180 -0
- package/core/keys.ts +573 -4
- package/core/loop.ts +5 -0
- package/core/lyrics.ts +297 -0
- package/core/master.ts +3 -3
- package/core/resonators.ts +306 -4
- package/core/routing.ts +165 -0
- package/core/score.ts +1181 -16
- package/core/sdk/eval-child.ts +7 -2
- package/core/sdk/eval.ts +35 -6
- package/core/sdk/print.ts +354 -6
- package/core/sdk/sync-lyrics.ts +49 -0
- package/core/sdk/v1.ts +3160 -69
- package/core/sections.ts +298 -24
- package/core/sing.ts +815 -0
- package/core/strings.ts +237 -2
- package/core/style-provenance.ts +80 -0
- package/core/styles/africa-mena-southasia.ts +2893 -0
- package/core/styles/americas.ts +3810 -0
- package/core/styles/art.ts +4993 -0
- package/core/styles/base.ts +123 -0
- package/core/styles/cycles.ts +106 -0
- package/core/styles/electronic.ts +2723 -0
- package/core/styles/europe-asia-pacific.ts +2838 -0
- package/core/styles/excerpt.ts +29 -0
- package/core/styles/gamelan.ts +283 -0
- package/core/styles/generate.ts +2199 -0
- package/core/styles/index.ts +515 -0
- package/core/styles/parts.ts +106 -0
- package/core/styles/pop.ts +3189 -0
- package/core/styles/rock.ts +2993 -0
- package/core/styles/roots.ts +4175 -0
- package/core/styles/schema.ts +429 -0
- package/core/styles/taxonomy.ts +940 -0
- package/core/styles/validate.ts +528 -0
- package/core/tempo.ts +32 -2
- package/core/tuning.ts +19 -3
- package/core/vocoder.ts +524 -0
- package/core/winds.ts +652 -0
- package/guides/agent.md +29 -0
- package/guides/arrange.md +30 -0
- package/guides/audition.md +20 -14
- package/guides/automation.md +12 -6
- package/guides/chords.md +16 -14
- package/guides/effects.md +17 -15
- package/guides/faders.md +20 -16
- package/guides/files.md +13 -9
- package/guides/getting-started.md +15 -11
- package/guides/keys.md +19 -15
- package/guides/media.md +17 -12
- package/guides/mix.md +12 -6
- package/guides/music.md +23 -8
- package/guides/notes.md +15 -9
- package/guides/performance.md +15 -10
- package/guides/play.md +21 -13
- package/guides/project.md +25 -8
- package/guides/providers.md +20 -14
- package/guides/resample.md +32 -0
- package/guides/rhythm.md +17 -13
- package/guides/sessions.md +17 -7
- package/guides/show-me.md +31 -0
- package/guides/sound.md +25 -9
- package/guides/sounds.md +15 -12
- package/guides/styles.md +31 -0
- package/guides/tempo.md +15 -10
- package/guides/tracks.md +15 -10
- package/guides/tuning.md +32 -0
- package/guides/voice.md +31 -0
- package/guides/web-search.md +18 -8
- package/native/prebuilt/darwin-arm64/libdawg_sink.dylib +0 -0
- package/native/prebuilt/darwin-x64/libdawg_sink.dylib +0 -0
- package/native/prebuilt/linux-arm64/libdawg_sink.so +0 -0
- package/native/prebuilt/linux-x64/libdawg_sink.so +0 -0
- package/native/prebuilt/manifest.json +21 -0
- package/package.json +5 -2
- package/src/agent/agent.ts +131 -13
- package/src/agent/calibration-tools.ts +53 -0
- package/src/agent/chord-tools.ts +153 -1
- package/src/agent/clip-tools.ts +453 -0
- package/src/agent/command-agent.ts +369 -0
- package/src/agent/drum-tools.ts +2 -2
- package/src/agent/expression-tools.ts +91 -0
- package/src/agent/gateway.ts +246 -60
- package/src/agent/models.ts +53 -12
- package/src/agent/ops.ts +15 -1
- package/src/agent/pack-tools.ts +1 -1
- package/src/agent/planner.ts +13 -0
- package/src/agent/portable-schema.ts +80 -0
- package/src/agent/preview-tool.ts +5 -1
- package/src/agent/provider.ts +22 -8
- package/src/agent/resample-tool.ts +131 -0
- package/src/agent/rhythm-tools.ts +1 -1
- package/src/agent/section-tools.ts +1 -1
- package/src/agent/show-me.ts +497 -0
- package/src/agent/steer.ts +15 -0
- package/src/agent/style-tools.ts +217 -0
- package/src/agent/tool-error.ts +12 -0
- package/src/agent/tools.ts +307 -37
- package/src/agent/usage.ts +2 -2
- package/src/agent/voice-tools.ts +925 -0
- package/src/agent/xcb-agent.ts +16 -6
- package/src/argv.ts +38 -0
- package/src/audio/analysis.ts +253 -0
- package/src/audio/arrange.ts +58 -3
- package/src/audio/autotune-engine.ts +101 -0
- package/src/audio/autotune.ts +640 -0
- package/src/audio/clips.ts +240 -0
- package/src/audio/doctor.ts +86 -0
- package/src/audio/dsp/bandbank.ts +138 -0
- package/src/audio/dsp/envelope.ts +171 -0
- package/src/audio/dsp/follow.ts +120 -0
- package/src/audio/dsp/formant.ts +427 -0
- package/src/audio/dsp/glottal.ts +243 -0
- package/src/audio/dsp/interp.ts +7 -2
- package/src/audio/dsp/lpc.ts +50 -0
- package/src/audio/dsp/periodicity.ts +59 -0
- package/src/audio/dsp/pitch.ts +995 -0
- package/src/audio/dsp/psola.ts +199 -0
- package/src/audio/dsp/shift.ts +256 -0
- package/src/audio/effects/chain.ts +21 -4
- package/src/audio/effects/common.ts +57 -0
- package/src/audio/effects/convolution.ts +113 -5
- package/src/audio/effects/filter.ts +48 -69
- package/src/audio/effects/formant.ts +263 -0
- package/src/audio/effects/gaze.ts +354 -0
- package/src/audio/engine.ts +206 -33
- package/src/audio/fit.ts +80 -3
- package/src/audio/granular.ts +352 -21
- package/src/audio/instrument-check.ts +67 -47
- package/src/audio/instruments.ts +36 -3
- package/src/audio/keys/calibration.ts +56 -0
- package/src/audio/keys/electric.ts +427 -0
- package/src/audio/keys/engine.ts +156 -20
- package/src/audio/keys/organ.ts +1335 -0
- package/src/audio/keys/piano.ts +72 -8
- package/src/audio/keys/sympathetic.ts +127 -0
- package/src/audio/kits.ts +135 -6
- package/src/audio/live-worker.ts +3 -1
- package/src/audio/live.ts +247 -26
- package/src/audio/native.ts +615 -0
- package/src/audio/preview.ts +45 -3
- package/src/audio/render-worker.ts +2 -0
- package/src/audio/renderer.ts +2 -0
- package/src/audio/resample.ts +286 -0
- package/src/audio/resonators.ts +10 -2
- package/src/audio/sampler.ts +252 -24
- package/src/audio/samples.ts +46 -3
- package/src/audio/sing/analysis.ts +193 -0
- package/src/audio/sing/engine.ts +949 -0
- package/src/audio/strings/body.ts +29 -16
- package/src/audio/strings/bow.ts +699 -0
- package/src/audio/strings/engine.ts +274 -22
- package/src/audio/strings/measure.test-helpers.ts +2 -0
- package/src/audio/synth/oscillators.ts +31 -21
- package/src/audio/synth/voice.ts +34 -1
- package/src/audio/vocoder/bank.ts +314 -0
- package/src/audio/vocoder/carrier.ts +165 -0
- package/src/audio/vocoder/control.ts +68 -0
- package/src/audio/vocoder/detect.ts +50 -0
- package/src/audio/vocoder/index.ts +304 -0
- package/src/audio/vocoder/talkbox.ts +143 -0
- package/src/audio/wav.ts +608 -85
- package/src/audio/winds/engine.ts +306 -0
- package/src/audio/winds/filters.ts +153 -0
- package/src/audio/winds/pitch.ts +104 -0
- package/src/audio/winds/trim.ts +104 -0
- package/src/audio/winds/trims.ts +917 -0
- package/src/audio/winds/trims1.ts +297 -0
- package/src/audio/winds/voice.ts +492 -0
- package/src/auth/cli.ts +38 -36
- package/src/auth/credentials.ts +30 -1
- package/src/auth/login.ts +15 -9
- package/src/auth/tui.ts +19 -10
- package/src/commands/arrange.ts +44 -29
- package/src/commands/autotune.ts +421 -0
- package/src/commands/calibration.ts +74 -0
- package/src/commands/clips.ts +887 -0
- package/src/commands/drums.ts +3 -2
- package/src/commands/edit.ts +11 -4
- package/src/commands/expression.ts +104 -23
- package/src/commands/formant.ts +221 -0
- package/src/commands/fx.ts +105 -33
- package/src/commands/grammar.ts +558 -0
- package/src/commands/granular.ts +7 -2
- package/src/commands/help.ts +652 -339
- package/src/commands/history.ts +18 -0
- package/src/commands/keys.ts +293 -17
- package/src/commands/modal.ts +67 -4
- package/src/commands/music.ts +1 -1
- package/src/commands/nearest.ts +53 -0
- package/src/commands/pack.ts +9 -2
- package/src/commands/param-range.ts +56 -0
- package/src/commands/parses.ts +130 -0
- package/src/commands/progression.ts +170 -0
- package/src/commands/resample.ts +281 -0
- package/src/commands/rhythm.ts +3 -0
- package/src/commands/rig.ts +8 -25
- package/src/commands/sample.ts +49 -2
- package/src/commands/shift.ts +119 -0
- package/src/commands/sing.ts +478 -0
- package/src/commands/string.ts +28 -2
- package/src/commands/strum.ts +485 -0
- package/src/commands/style.ts +415 -0
- package/src/commands/time.ts +6 -3
- package/src/commands/tuning.ts +3 -3
- package/src/commands/vocal-pitch.ts +616 -0
- package/src/commands/vocal.ts +147 -0
- package/src/commands/vocoder.ts +627 -0
- package/src/commands/wind.ts +244 -0
- package/src/fs/durable.ts +50 -0
- package/src/lang/glossary.ts +493 -0
- package/src/launch-args.ts +163 -0
- package/src/main.ts +1521 -255
- package/src/media/cli.ts +20 -3
- package/src/media/import.ts +3 -1
- package/src/project/check.ts +26 -3
- package/src/project/clip-pins.ts +72 -0
- package/src/project/init.ts +23 -8
- package/src/project/sync.ts +418 -86
- package/src/render.ts +36 -1
- package/src/session/daemon.ts +3 -0
- package/src/session/meta.ts +14 -0
- package/src/session/origin.ts +154 -0
- package/src/session/port.ts +22 -4
- package/src/session/presence.ts +50 -7
- package/src/session/protocol.ts +5 -1
- package/src/session/rebase.ts +18 -5
- package/src/session/receipt.ts +258 -0
- package/src/session/store.ts +65 -43
- package/src/tui/arrange-menu.ts +65 -31
- package/src/tui/audition.ts +1 -1
- package/src/tui/euclid.ts +18 -13
- package/src/tui/fader.ts +228 -41
- package/src/tui/granular-menu.ts +2 -4
- package/src/tui/menu-clips.ts +297 -0
- package/src/tui/menu-time.ts +20 -13
- package/src/tui/menu-voice.ts +405 -0
- package/src/tui/menu.ts +1377 -193
- package/src/tui/modal-menu.ts +38 -11
- package/src/tui/performance-menu.ts +46 -1
- package/src/tui/play-chords.ts +108 -5
- package/src/tui/play-mode.ts +16 -1
- package/src/tui/play-session.ts +81 -16
- package/src/tui/sing-menu.ts +278 -0
- package/src/tui/style-menu.ts +104 -0
- package/src/tui/vocoder-menu.ts +244 -0
- package/src/tui/wind-menu.ts +144 -0
- package/src/version.ts +8 -0
- package/src/web/fetch.ts +115 -29
- package/tui/activity.ts +180 -9
- package/tui/app.ts +274 -40
- package/tui/clip-row.ts +132 -0
- package/tui/delight.ts +144 -0
- package/tui/drawer.ts +70 -22
- package/tui/frame-gate.ts +76 -0
- package/tui/grammar.ts +112 -63
- package/tui/guide.ts +42 -4
- package/tui/highway.ts +269 -25
- package/tui/hints.ts +192 -0
- package/tui/input.ts +60 -9
- package/tui/keys.ts +1 -1
- package/tui/play-strip.ts +68 -14
- package/tui/prompt.ts +1 -1
- package/tui/screen.ts +144 -14
- package/tui/theme.ts +27 -0
package/core/fx.ts
CHANGED
|
@@ -12,10 +12,13 @@
|
|
|
12
12
|
* under `track.fx.<name>` with every parameter stored once enabled.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import { MODAL_LANE_PARAMS } from "./resonators.ts";
|
|
15
|
+
import { MODAL_LANE_PARAMS, WIND_LANE_PARAMS } from "./resonators.ts";
|
|
16
|
+
import { VOCODER_LANE_PARAMS } from "./vocoder.ts";
|
|
16
17
|
import { SYNTH_LANE_PARAMS } from "./synth.ts";
|
|
17
18
|
import { STRING_LANE_PARAMS } from "./strings.ts";
|
|
18
19
|
import { KEYS_LANE_PARAMS } from "./keys.ts";
|
|
20
|
+
import { GRANULAR_LANE_PARAMS } from "./granular.ts";
|
|
21
|
+
import { SING_LANE_PARAMS } from "./sing.ts";
|
|
19
22
|
import {
|
|
20
23
|
FxValidationError,
|
|
21
24
|
normalizeParam,
|
|
@@ -48,6 +51,8 @@ export const FX_CHAIN = Object.freeze([
|
|
|
48
51
|
"filter",
|
|
49
52
|
"djf",
|
|
50
53
|
"autofilter",
|
|
54
|
+
// 0.7 formant shift at constant pitch (src/audio/effects/formant.ts).
|
|
55
|
+
"formant",
|
|
51
56
|
"vowel",
|
|
52
57
|
"crush",
|
|
53
58
|
"distort",
|
|
@@ -55,9 +60,16 @@ export const FX_CHAIN = Object.freeze([
|
|
|
55
60
|
"stomp",
|
|
56
61
|
"head",
|
|
57
62
|
"cab",
|
|
63
|
+
// 0.6.1 shoegaze (src/audio/effects/gaze.ts): a held tremolo arm, the
|
|
64
|
+
// dominant note's feedback bloom, a volume swell; double (mono in, stereo
|
|
65
|
+
// out) runs where the chain turns stereo.
|
|
66
|
+
"wobble",
|
|
67
|
+
"bloom",
|
|
68
|
+
"swell",
|
|
58
69
|
"tremolo",
|
|
59
70
|
"compressor",
|
|
60
71
|
"pan",
|
|
72
|
+
"double",
|
|
61
73
|
"phaser",
|
|
62
74
|
"chorus",
|
|
63
75
|
"leslie",
|
|
@@ -102,7 +114,7 @@ const sync = (fallback: number, strudel?: readonly string[]): NumberParam => ({
|
|
|
102
114
|
default: fallback,
|
|
103
115
|
step: 0.25,
|
|
104
116
|
unit: "beats",
|
|
105
|
-
doc: "LFO
|
|
117
|
+
doc: "LFO period in beats (tempo-synced); 0 uses rate in Hz",
|
|
106
118
|
...(strudel ? { strudel } : {}),
|
|
107
119
|
});
|
|
108
120
|
const mix = (fallback: number, strudel?: readonly string[]): NumberParam => ({
|
|
@@ -116,6 +128,25 @@ const mix = (fallback: number, strudel?: readonly string[]): NumberParam => ({
|
|
|
116
128
|
...(strudel ? { strudel } : {}),
|
|
117
129
|
});
|
|
118
130
|
|
|
131
|
+
/** Vowels of the `vowel` effect (src/audio/dsp/formant.ts tables). */
|
|
132
|
+
export const VOWEL_VALUES = Object.freeze([
|
|
133
|
+
"a",
|
|
134
|
+
"e",
|
|
135
|
+
"i",
|
|
136
|
+
"o",
|
|
137
|
+
"u",
|
|
138
|
+
"ae",
|
|
139
|
+
"aa",
|
|
140
|
+
"oe",
|
|
141
|
+
"ue",
|
|
142
|
+
"y",
|
|
143
|
+
"uh",
|
|
144
|
+
"un",
|
|
145
|
+
"en",
|
|
146
|
+
"an",
|
|
147
|
+
"on",
|
|
148
|
+
] as const);
|
|
149
|
+
|
|
119
150
|
/**
|
|
120
151
|
* Effects stored under `track.fx`. Every number is bounded; enabling an
|
|
121
152
|
* effect stores all of its parameters so a document says exactly what plays.
|
|
@@ -123,7 +154,7 @@ const mix = (fallback: number, strudel?: readonly string[]): NumberParam => ({
|
|
|
123
154
|
export const FX_SPECS = Object.freeze({
|
|
124
155
|
autofilter: {
|
|
125
156
|
label: "auto filter",
|
|
126
|
-
doc: "filter whose cutoff an LFO sweeps around a
|
|
157
|
+
doc: "filter whose cutoff an LFO sweeps around a center, optionally opened by the input level",
|
|
127
158
|
simple: ["type", "cutoff", "depth", "sync", "shape"],
|
|
128
159
|
strudel:
|
|
129
160
|
"none built in (Strudel fakes it with lpf(sine.range(..)).seg(n)); names follow lpf/lpq",
|
|
@@ -143,7 +174,7 @@ export const FX_SPECS = Object.freeze({
|
|
|
143
174
|
step: "log",
|
|
144
175
|
unit: "Hz",
|
|
145
176
|
automate: true,
|
|
146
|
-
doc: "
|
|
177
|
+
doc: "center cutoff",
|
|
147
178
|
strudel: ["lpf", "cutoff"],
|
|
148
179
|
},
|
|
149
180
|
resonance: {
|
|
@@ -164,7 +195,7 @@ export const FX_SPECS = Object.freeze({
|
|
|
164
195
|
step: 0.25,
|
|
165
196
|
unit: "oct",
|
|
166
197
|
automate: true,
|
|
167
|
-
doc: "sweep width in octaves around the
|
|
198
|
+
doc: "sweep width in octaves around the center",
|
|
168
199
|
},
|
|
169
200
|
sync: sync(4),
|
|
170
201
|
rate: rate(0.5),
|
|
@@ -208,11 +239,30 @@ export const FX_SPECS = Object.freeze({
|
|
|
208
239
|
default: 0.5,
|
|
209
240
|
step: 0.02,
|
|
210
241
|
automate: true,
|
|
211
|
-
doc: "0 dark … 0.5 open … 1 thin",
|
|
242
|
+
doc: "0 dark (20 Hz low-pass) … 0.5 open … 1 thin (10 kHz high-pass)",
|
|
212
243
|
strudel: ["djf"],
|
|
213
244
|
},
|
|
214
245
|
},
|
|
215
246
|
},
|
|
247
|
+
formant: {
|
|
248
|
+
label: "formant",
|
|
249
|
+
doc: "formant shift at constant pitch: moves the spectral envelope (throat or gender knob), any source",
|
|
250
|
+
simple: ["shift", "mix"],
|
|
251
|
+
strudel: "none (not a Strudel concept)",
|
|
252
|
+
params: {
|
|
253
|
+
shift: {
|
|
254
|
+
kind: "number",
|
|
255
|
+
min: -12,
|
|
256
|
+
max: 12,
|
|
257
|
+
default: 0,
|
|
258
|
+
step: 0.5,
|
|
259
|
+
unit: "st",
|
|
260
|
+
automate: true,
|
|
261
|
+
doc: "semitones the formants move (negative deeper, positive smaller); pitch stays",
|
|
262
|
+
},
|
|
263
|
+
mix: mix(1),
|
|
264
|
+
},
|
|
265
|
+
},
|
|
216
266
|
vowel: {
|
|
217
267
|
label: "vowel",
|
|
218
268
|
doc: "formant filter bank: five band-passes per vowel",
|
|
@@ -221,28 +271,30 @@ export const FX_SPECS = Object.freeze({
|
|
|
221
271
|
params: {
|
|
222
272
|
vowel: {
|
|
223
273
|
kind: "enum",
|
|
224
|
-
values:
|
|
225
|
-
"a",
|
|
226
|
-
"e",
|
|
227
|
-
"i",
|
|
228
|
-
"o",
|
|
229
|
-
"u",
|
|
230
|
-
"ae",
|
|
231
|
-
"aa",
|
|
232
|
-
"oe",
|
|
233
|
-
"ue",
|
|
234
|
-
"y",
|
|
235
|
-
"uh",
|
|
236
|
-
"un",
|
|
237
|
-
"en",
|
|
238
|
-
"an",
|
|
239
|
-
"on",
|
|
240
|
-
],
|
|
274
|
+
values: VOWEL_VALUES,
|
|
241
275
|
default: "a",
|
|
242
276
|
doc: "vowel formants (a e i o u plus the extended set)",
|
|
243
277
|
strudel: ["vowel"],
|
|
244
278
|
},
|
|
245
279
|
mix: mix(1),
|
|
280
|
+
// 0.7: optional morph target; absent keeps the static bank exactly.
|
|
281
|
+
to: {
|
|
282
|
+
kind: "enum",
|
|
283
|
+
values: VOWEL_VALUES,
|
|
284
|
+
default: "a",
|
|
285
|
+
optional: true,
|
|
286
|
+
doc: "vowel to morph toward (absent: no morph)",
|
|
287
|
+
},
|
|
288
|
+
morph: {
|
|
289
|
+
kind: "number",
|
|
290
|
+
min: 0,
|
|
291
|
+
max: 1,
|
|
292
|
+
default: 0,
|
|
293
|
+
step: 0.05,
|
|
294
|
+
optional: true,
|
|
295
|
+
automate: true,
|
|
296
|
+
doc: "position between vowel (0) and to (1), log-frequency formant morph",
|
|
297
|
+
},
|
|
246
298
|
},
|
|
247
299
|
},
|
|
248
300
|
crush: {
|
|
@@ -459,7 +511,7 @@ export const FX_SPECS = Object.freeze({
|
|
|
459
511
|
step: 1,
|
|
460
512
|
unit: "dB",
|
|
461
513
|
optional: true,
|
|
462
|
-
doc: "noise gate threshold before the amp (absent: no gate)",
|
|
514
|
+
doc: "noise gate threshold before the amp (absent: no gate; 0 dB gates all)",
|
|
463
515
|
},
|
|
464
516
|
level: {
|
|
465
517
|
kind: "number",
|
|
@@ -490,11 +542,140 @@ export const FX_SPECS = Object.freeze({
|
|
|
490
542
|
max: 1,
|
|
491
543
|
default: 0.3,
|
|
492
544
|
step: 0.05,
|
|
493
|
-
doc: "microphone position: 0
|
|
545
|
+
doc: "microphone position: 0 center (bright) .. 1 edge (dark)",
|
|
494
546
|
},
|
|
495
547
|
mix: mix(1),
|
|
496
548
|
},
|
|
497
549
|
},
|
|
550
|
+
wobble: {
|
|
551
|
+
label: "wobble",
|
|
552
|
+
doc: "held tremolo arm: slow seeded pitch wow and flutter of the whole track",
|
|
553
|
+
simple: ["depth", "rate", "drift"],
|
|
554
|
+
strudel: "(no Strudel equivalent; dawg shoegaze)",
|
|
555
|
+
params: {
|
|
556
|
+
depth: {
|
|
557
|
+
kind: "number",
|
|
558
|
+
min: 0,
|
|
559
|
+
max: 100,
|
|
560
|
+
default: 20,
|
|
561
|
+
step: 1,
|
|
562
|
+
unit: "c",
|
|
563
|
+
automate: true,
|
|
564
|
+
doc: "peak pitch deviation in cents",
|
|
565
|
+
},
|
|
566
|
+
rate: {
|
|
567
|
+
kind: "number",
|
|
568
|
+
min: 0.05,
|
|
569
|
+
max: 8,
|
|
570
|
+
default: 0.5,
|
|
571
|
+
step: 0.05,
|
|
572
|
+
unit: "Hz",
|
|
573
|
+
doc: "wobble rate",
|
|
574
|
+
},
|
|
575
|
+
drift: {
|
|
576
|
+
kind: "number",
|
|
577
|
+
min: 0,
|
|
578
|
+
max: 1,
|
|
579
|
+
default: 0.3,
|
|
580
|
+
step: 0.05,
|
|
581
|
+
doc: "0 periodic .. 1 wandering (seeded, so every render matches)",
|
|
582
|
+
},
|
|
583
|
+
},
|
|
584
|
+
},
|
|
585
|
+
bloom: {
|
|
586
|
+
label: "bloom",
|
|
587
|
+
doc: "feedback bloom: the top held note grows a singing harmonic",
|
|
588
|
+
simple: ["amount", "harm", "delay"],
|
|
589
|
+
strudel: "(no Strudel equivalent; dawg shoegaze)",
|
|
590
|
+
params: {
|
|
591
|
+
amount: {
|
|
592
|
+
kind: "number",
|
|
593
|
+
min: 0,
|
|
594
|
+
max: 1,
|
|
595
|
+
default: 0.5,
|
|
596
|
+
step: 0.05,
|
|
597
|
+
doc: "level of the feedback partial",
|
|
598
|
+
},
|
|
599
|
+
harm: {
|
|
600
|
+
kind: "number",
|
|
601
|
+
min: 1,
|
|
602
|
+
max: 4,
|
|
603
|
+
default: 2,
|
|
604
|
+
step: 1,
|
|
605
|
+
doc: "harmonic that feeds back: 1 the note, 2 its octave, 3 the fifth above",
|
|
606
|
+
},
|
|
607
|
+
delay: {
|
|
608
|
+
kind: "number",
|
|
609
|
+
min: 0,
|
|
610
|
+
max: 4,
|
|
611
|
+
default: 0.6,
|
|
612
|
+
step: 0.05,
|
|
613
|
+
unit: "s",
|
|
614
|
+
doc: "how long a note is held before it starts to feed back",
|
|
615
|
+
},
|
|
616
|
+
time: {
|
|
617
|
+
kind: "number",
|
|
618
|
+
min: 0.05,
|
|
619
|
+
max: 4,
|
|
620
|
+
default: 1,
|
|
621
|
+
step: 0.05,
|
|
622
|
+
unit: "s",
|
|
623
|
+
doc: "how fast the feedback grows",
|
|
624
|
+
},
|
|
625
|
+
},
|
|
626
|
+
},
|
|
627
|
+
swell: {
|
|
628
|
+
label: "swell",
|
|
629
|
+
doc: "volume swell: each strum fades in, no pick attack",
|
|
630
|
+
simple: ["time", "mix"],
|
|
631
|
+
strudel: "(no Strudel equivalent; dawg shoegaze)",
|
|
632
|
+
params: {
|
|
633
|
+
time: {
|
|
634
|
+
kind: "number",
|
|
635
|
+
min: 0.01,
|
|
636
|
+
max: 4,
|
|
637
|
+
default: 0.4,
|
|
638
|
+
step: 0.01,
|
|
639
|
+
unit: "s",
|
|
640
|
+
doc: "rise time after each onset",
|
|
641
|
+
},
|
|
642
|
+
mix: mix(1),
|
|
643
|
+
},
|
|
644
|
+
},
|
|
645
|
+
double: {
|
|
646
|
+
label: "double",
|
|
647
|
+
doc: "automatic double tracking: a seeded second take, spread left and right",
|
|
648
|
+
simple: ["time", "drift", "width"],
|
|
649
|
+
strudel: "(no Strudel equivalent; dawg shoegaze)",
|
|
650
|
+
params: {
|
|
651
|
+
time: {
|
|
652
|
+
kind: "number",
|
|
653
|
+
min: 5,
|
|
654
|
+
max: 60,
|
|
655
|
+
default: 22,
|
|
656
|
+
step: 1,
|
|
657
|
+
unit: "ms",
|
|
658
|
+
doc: "how late the second take plays",
|
|
659
|
+
},
|
|
660
|
+
drift: {
|
|
661
|
+
kind: "number",
|
|
662
|
+
min: 0,
|
|
663
|
+
max: 10,
|
|
664
|
+
default: 3,
|
|
665
|
+
step: 0.5,
|
|
666
|
+
unit: "ms",
|
|
667
|
+
doc: "how far the second take's timing wanders",
|
|
668
|
+
},
|
|
669
|
+
width: {
|
|
670
|
+
kind: "number",
|
|
671
|
+
min: 0,
|
|
672
|
+
max: 1,
|
|
673
|
+
default: 0.6,
|
|
674
|
+
step: 0.05,
|
|
675
|
+
doc: "0 centered .. 1 the two takes hard left and right",
|
|
676
|
+
},
|
|
677
|
+
},
|
|
678
|
+
},
|
|
498
679
|
tremolo: {
|
|
499
680
|
label: "tremolo",
|
|
500
681
|
doc: "volume modulation",
|
|
@@ -634,7 +815,7 @@ export const FX_SPECS = Object.freeze({
|
|
|
634
815
|
default: 1000,
|
|
635
816
|
step: "log",
|
|
636
817
|
unit: "Hz",
|
|
637
|
-
doc: "sweep
|
|
818
|
+
doc: "sweep center",
|
|
638
819
|
strudel: ["phasercenter", "phc"],
|
|
639
820
|
},
|
|
640
821
|
sweep: {
|
|
@@ -818,7 +999,7 @@ export const TRACK_EFFECT_SPECS = Object.freeze({
|
|
|
818
999
|
step: "log",
|
|
819
1000
|
unit: "Hz",
|
|
820
1001
|
automate: true,
|
|
821
|
-
doc: "cutoff (lpf/hpf) or
|
|
1002
|
+
doc: "cutoff (lpf/hpf) or center (bpf) frequency",
|
|
822
1003
|
strudel: [
|
|
823
1004
|
"lpf",
|
|
824
1005
|
"cutoff",
|
|
@@ -1006,6 +1187,14 @@ export const CORE_EFFECTS: readonly EffectName[] = Object.freeze([
|
|
|
1006
1187
|
"reverb",
|
|
1007
1188
|
] as const);
|
|
1008
1189
|
|
|
1190
|
+
/** The 0.6.1 shoegaze stages (Effects > Shoegaze), in chain order. */
|
|
1191
|
+
export const SHOEGAZE_EFFECTS: readonly EffectName[] = Object.freeze([
|
|
1192
|
+
"wobble",
|
|
1193
|
+
"bloom",
|
|
1194
|
+
"swell",
|
|
1195
|
+
"double",
|
|
1196
|
+
] as const);
|
|
1197
|
+
|
|
1009
1198
|
export function isEffectName(value: unknown): value is EffectName {
|
|
1010
1199
|
return (
|
|
1011
1200
|
typeof value === "string" &&
|
|
@@ -1076,12 +1265,22 @@ export function normalizeFx(input: unknown): TrackFx | undefined {
|
|
|
1076
1265
|
|
|
1077
1266
|
/** Automation lane name of an `fx` parameter, e.g. `distort-drive`. */
|
|
1078
1267
|
export type FxLane =
|
|
1079
|
-
`${FxName | "reverb" | "synth" | "string" | "keys" | "modal"}-${string}`;
|
|
1268
|
+
`${FxName | "reverb" | "synth" | "string" | "keys" | "modal" | "grain" | "wind" | "sing" | "vocoder"}-${string}`;
|
|
1080
1269
|
|
|
1081
1270
|
/** Every automatable `fx` parameter as `{ lane, effect, param, spec }`. */
|
|
1082
1271
|
export const FX_LANES: readonly Readonly<{
|
|
1083
1272
|
lane: FxLane;
|
|
1084
|
-
effect:
|
|
1273
|
+
effect:
|
|
1274
|
+
| FxName
|
|
1275
|
+
| "reverb"
|
|
1276
|
+
| "synth"
|
|
1277
|
+
| "string"
|
|
1278
|
+
| "keys"
|
|
1279
|
+
| "modal"
|
|
1280
|
+
| "grain"
|
|
1281
|
+
| "wind"
|
|
1282
|
+
| "sing"
|
|
1283
|
+
| "vocoder";
|
|
1085
1284
|
param: string;
|
|
1086
1285
|
spec: NumberParam;
|
|
1087
1286
|
}>[] = Object.freeze([
|
|
@@ -1137,6 +1336,43 @@ export const FX_LANES: readonly Readonly<{
|
|
|
1137
1336
|
spec,
|
|
1138
1337
|
}),
|
|
1139
1338
|
),
|
|
1339
|
+
// Granular parameters (core/granular.ts, 0.6.1), read every 32 frames;
|
|
1340
|
+
// grain-scoped ones are latched at each grain's onset.
|
|
1341
|
+
...GRANULAR_LANE_PARAMS.map(({ param, spec }) =>
|
|
1342
|
+
Object.freeze({
|
|
1343
|
+
lane: `grain-${param}` as FxLane,
|
|
1344
|
+
effect: "grain" as const,
|
|
1345
|
+
param,
|
|
1346
|
+
spec,
|
|
1347
|
+
}),
|
|
1348
|
+
),
|
|
1349
|
+
// Wind parameters (core/winds.ts), read every 32-sample control tick.
|
|
1350
|
+
...WIND_LANE_PARAMS.map(({ param, spec }) =>
|
|
1351
|
+
Object.freeze({
|
|
1352
|
+
lane: `wind-${param}` as FxLane,
|
|
1353
|
+
effect: "wind" as const,
|
|
1354
|
+
param,
|
|
1355
|
+
spec,
|
|
1356
|
+
}),
|
|
1357
|
+
),
|
|
1358
|
+
// Sing parameters (core/sing.ts, 0.7), read every 32-sample control tick.
|
|
1359
|
+
...SING_LANE_PARAMS.map(({ param, spec }) =>
|
|
1360
|
+
Object.freeze({
|
|
1361
|
+
lane: `sing-${param}` as FxLane,
|
|
1362
|
+
effect: "sing" as const,
|
|
1363
|
+
param,
|
|
1364
|
+
spec,
|
|
1365
|
+
}),
|
|
1366
|
+
),
|
|
1367
|
+
// Vocoder (core/vocoder.ts, 0.7), read per 32-sample block on the song grid.
|
|
1368
|
+
...VOCODER_LANE_PARAMS.map(({ param, spec }) =>
|
|
1369
|
+
Object.freeze({
|
|
1370
|
+
lane: `vocoder-${param}` as FxLane,
|
|
1371
|
+
effect: "vocoder" as const,
|
|
1372
|
+
param,
|
|
1373
|
+
spec,
|
|
1374
|
+
}),
|
|
1375
|
+
),
|
|
1140
1376
|
]);
|
|
1141
1377
|
|
|
1142
1378
|
/**
|
|
@@ -1183,6 +1419,12 @@ export const FX_PRESETS: Readonly<
|
|
|
1183
1419
|
resonance: 0.6,
|
|
1184
1420
|
},
|
|
1185
1421
|
},
|
|
1422
|
+
formant: {
|
|
1423
|
+
deep: { shift: -4 },
|
|
1424
|
+
giant: { shift: -8 },
|
|
1425
|
+
bright: { shift: 3 },
|
|
1426
|
+
tiny: { shift: 7 },
|
|
1427
|
+
},
|
|
1186
1428
|
vowel: { a: { vowel: "a" }, o: { vowel: "o" }, ee: { vowel: "i" } },
|
|
1187
1429
|
crush: {
|
|
1188
1430
|
"8-bit": { bits: 8, coarse: 1 },
|
|
@@ -1222,6 +1464,24 @@ export const FX_PRESETS: Readonly<
|
|
|
1222
1464
|
"1x15": { type: "1x15" },
|
|
1223
1465
|
di: { type: "di" },
|
|
1224
1466
|
},
|
|
1467
|
+
wobble: {
|
|
1468
|
+
glide: { depth: 35, rate: 0.4, drift: 0.4 },
|
|
1469
|
+
tape: { depth: 12, rate: 0.8, drift: 0.6 },
|
|
1470
|
+
seasick: { depth: 60, rate: 0.25, drift: 0.2 },
|
|
1471
|
+
},
|
|
1472
|
+
bloom: {
|
|
1473
|
+
octave: { amount: 0.5, harm: 2, delay: 0.6, time: 1 },
|
|
1474
|
+
fifth: { amount: 0.4, harm: 3, delay: 0.8, time: 1.2 },
|
|
1475
|
+
ebow: { amount: 0.8, harm: 1, delay: 0.1, time: 0.6 },
|
|
1476
|
+
},
|
|
1477
|
+
swell: {
|
|
1478
|
+
slow: { time: 0.8 },
|
|
1479
|
+
violin: { time: 0.3 },
|
|
1480
|
+
},
|
|
1481
|
+
double: {
|
|
1482
|
+
tight: { time: 12, drift: 1.5, width: 0.5 },
|
|
1483
|
+
wide: { time: 28, drift: 3, width: 0.7 },
|
|
1484
|
+
},
|
|
1225
1485
|
tremolo: {
|
|
1226
1486
|
gentle: { sync: 1, depth: 0.3, shape: "sine" },
|
|
1227
1487
|
"eighth-chop": { sync: 0.5, depth: 0.9, shape: "square" },
|
|
@@ -1390,14 +1650,70 @@ export const RIG_PRESETS: Readonly<
|
|
|
1390
1650
|
head: { type: "chime", gain: 3, treble: 7 },
|
|
1391
1651
|
cab: { type: "2x12", mic: 0.2 },
|
|
1392
1652
|
compressor: { threshold: -20, ratio: 4, attack: 0.01, release: 0.15 },
|
|
1653
|
+
// 0.6.1: the double-tracked jangle of a twelve-string record. A stored
|
|
1654
|
+
// 0.6.0 jangle (no double) keeps rendering as it was; `rig jangle` again
|
|
1655
|
+
// adds it. The SDK's rig("jangle") keeps its 0.6.0 stages (see
|
|
1656
|
+
// RIG_ADDED), so the printer writes this double out explicitly.
|
|
1657
|
+
double: { time: 12, drift: 1.5, width: 0.5 },
|
|
1393
1658
|
},
|
|
1394
1659
|
alt: {
|
|
1395
1660
|
stomp: { type: "rat", gain: 6, tone: 0.4 },
|
|
1396
1661
|
head: { type: "crunch", gain: 4 },
|
|
1397
1662
|
cab: { type: "4x12" },
|
|
1398
1663
|
},
|
|
1664
|
+
// 0.6.1 shoegaze rigs (src/audio/effects/gaze.ts): fuzz into a held
|
|
1665
|
+
// tremolo arm, a feedback bloom, doubled takes and a long wash.
|
|
1666
|
+
shoegaze: {
|
|
1667
|
+
stomp: { type: "fuzz", gain: 7, tone: 0.45 },
|
|
1668
|
+
head: { type: "chime", gain: 4 },
|
|
1669
|
+
cab: { type: "2x12" },
|
|
1670
|
+
wobble: { depth: 25, rate: 0.4, drift: 0.4 },
|
|
1671
|
+
bloom: { amount: 0.4, harm: 2, delay: 0.6, time: 1 },
|
|
1672
|
+
double: { time: 18, drift: 2.5, width: 0.4 },
|
|
1673
|
+
postgain: { gain: 0.86 },
|
|
1674
|
+
reverb: { mix: 0.35, size: 0.9, fade: 4, predelay: 0.02, dim: 6000 },
|
|
1675
|
+
},
|
|
1676
|
+
glide: {
|
|
1677
|
+
stomp: { type: "face", gain: 5, tone: 0.5 },
|
|
1678
|
+
head: { type: "clean", gain: 4, treble: 5 },
|
|
1679
|
+
cab: { type: "2x12" },
|
|
1680
|
+
wobble: { depth: 35, rate: 0.4, drift: 0.4 },
|
|
1681
|
+
postgain: { gain: 0.8 },
|
|
1682
|
+
reverb: { mix: 0.35, size: 0.7, fade: 2.5, predelay: 0.01, dim: 6000 },
|
|
1683
|
+
},
|
|
1684
|
+
dreampop: {
|
|
1685
|
+
head: { type: "clean", gain: 2, treble: 6 },
|
|
1686
|
+
cab: { type: "1x12" },
|
|
1687
|
+
chorus: { rate: 0.6, depth: 0.3, mix: 0.35 },
|
|
1688
|
+
double: { time: 14, drift: 2, width: 0.4 },
|
|
1689
|
+
postgain: { gain: 1.45 },
|
|
1690
|
+
reverb: { mix: 0.4, size: 0.85, fade: 5, predelay: 0.03, dim: 7000 },
|
|
1691
|
+
},
|
|
1692
|
+
swell: {
|
|
1693
|
+
head: { type: "clean", gain: 3, treble: 5 },
|
|
1694
|
+
cab: { type: "1x12" },
|
|
1695
|
+
swell: { time: 0.5 },
|
|
1696
|
+
postgain: { gain: 1.25 },
|
|
1697
|
+
reverb: { mix: 0.45, size: 0.8, fade: 4, predelay: 0.02, dim: 6500 },
|
|
1698
|
+
},
|
|
1699
|
+
ebow: {
|
|
1700
|
+
stomp: { type: "od", gain: 3, tone: 0.5, level: 3 },
|
|
1701
|
+
head: { type: "lead", gain: 5, mid: 6 },
|
|
1702
|
+
cab: { type: "4x12" },
|
|
1703
|
+
swell: { time: 0.25 },
|
|
1704
|
+
bloom: { amount: 0.8, harm: 1, delay: 0.1, time: 0.6 },
|
|
1705
|
+
},
|
|
1399
1706
|
});
|
|
1400
1707
|
|
|
1708
|
+
/**
|
|
1709
|
+
* Effects a rig preset gained after SDK `rig(name)` was fixed. `rig(name)`
|
|
1710
|
+
* leaves them out, so an older song.ts spreading `...rig("jangle")` keeps
|
|
1711
|
+
* its sound; the printer writes them next to the spread, and a stored
|
|
1712
|
+
* track with or without them still reads as that rig.
|
|
1713
|
+
*/
|
|
1714
|
+
export const RIG_ADDED: Readonly<Record<string, readonly FxName[]>> =
|
|
1715
|
+
Object.freeze({ jangle: Object.freeze(["double"] as FxName[]) });
|
|
1716
|
+
|
|
1401
1717
|
export function isRigPreset(name: string): boolean {
|
|
1402
1718
|
return Object.prototype.hasOwnProperty.call(RIG_PRESETS, name);
|
|
1403
1719
|
}
|
|
@@ -1476,8 +1792,11 @@ export function rigReverb(name: string): FxValues | undefined {
|
|
|
1476
1792
|
export function rigPresetOf(fx: TrackFx | undefined): string | undefined {
|
|
1477
1793
|
if (!fx || !RIG_STAGES.some((stage) => fx[stage])) return undefined;
|
|
1478
1794
|
for (const name of Object.keys(RIG_PRESETS)) {
|
|
1479
|
-
const want
|
|
1480
|
-
|
|
1795
|
+
const want: Partial<Record<FxName, FxValues>> = {
|
|
1796
|
+
...(applyRigPreset(undefined, name) ?? {}),
|
|
1797
|
+
};
|
|
1798
|
+
for (const added of RIG_ADDED[name] ?? []) delete want[added];
|
|
1799
|
+
const keys = new Set<string>([...RIG_STAGES, ...Object.keys(want)]);
|
|
1481
1800
|
if (
|
|
1482
1801
|
[...keys].every(
|
|
1483
1802
|
(key) =>
|
|
@@ -1492,7 +1811,10 @@ export function rigPresetOf(fx: TrackFx | undefined): string | undefined {
|
|
|
1492
1811
|
|
|
1493
1812
|
/** The effects of `fx` a printed `...rig(name)` stands for. */
|
|
1494
1813
|
export function rigPresetKeys(name: string): readonly FxName[] {
|
|
1495
|
-
|
|
1814
|
+
const added = RIG_ADDED[name] ?? [];
|
|
1815
|
+
return Object.keys(RIG_PRESETS[name] ?? {}).filter(
|
|
1816
|
+
(key): key is FxName => isFxName(key) && !added.includes(key),
|
|
1817
|
+
);
|
|
1496
1818
|
}
|
|
1497
1819
|
|
|
1498
1820
|
export function effectPresetNames(effect: EffectName): readonly string[] {
|
package/core/granular.ts
CHANGED
|
@@ -77,6 +77,14 @@ export type TrackGranular = Readonly<{
|
|
|
77
77
|
release?: number;
|
|
78
78
|
veltone?: number;
|
|
79
79
|
gain?: number;
|
|
80
|
+
/** Optional (0.6.1): grain rate as a note value on the tempo map. */
|
|
81
|
+
sync?: GrainSync;
|
|
82
|
+
/** Optional (0.6.1): snap grain pitches to the scale or chord. */
|
|
83
|
+
quant?: GrainQuant;
|
|
84
|
+
/** Optional (0.6.1): one voice; legato notes retarget it. */
|
|
85
|
+
mono?: boolean;
|
|
86
|
+
/** Optional (0.6.1): the sustain pedal freezes the head. */
|
|
87
|
+
pedal?: boolean;
|
|
80
88
|
/**
|
|
81
89
|
* The instrument `grain off` returns to (set when granular turns on;
|
|
82
90
|
* absent: a sampler, a wavetable, or the source's synth).
|
|
@@ -102,6 +110,30 @@ const n = (
|
|
|
102
110
|
...extra,
|
|
103
111
|
});
|
|
104
112
|
|
|
113
|
+
export const GRAIN_SYNC_VALUES = Object.freeze([
|
|
114
|
+
"off",
|
|
115
|
+
"1/64",
|
|
116
|
+
"1/32",
|
|
117
|
+
"1/16t",
|
|
118
|
+
"1/16",
|
|
119
|
+
"1/16d",
|
|
120
|
+
"1/8t",
|
|
121
|
+
"1/8",
|
|
122
|
+
"1/8d",
|
|
123
|
+
"1/4t",
|
|
124
|
+
"1/4",
|
|
125
|
+
"1/4d",
|
|
126
|
+
"1/2",
|
|
127
|
+
"1/1",
|
|
128
|
+
] as const);
|
|
129
|
+
export type GrainSync = (typeof GRAIN_SYNC_VALUES)[number];
|
|
130
|
+
export const GRAIN_QUANT_VALUES = Object.freeze([
|
|
131
|
+
"off",
|
|
132
|
+
"scale",
|
|
133
|
+
"chord",
|
|
134
|
+
] as const);
|
|
135
|
+
export type GrainQuant = (typeof GRAIN_QUANT_VALUES)[number];
|
|
136
|
+
|
|
105
137
|
/**
|
|
106
138
|
* The granular parameter table: one row per stored number, enum or flag,
|
|
107
139
|
* in stored key order. It drives validation, the printer, the menu, the
|
|
@@ -223,8 +255,63 @@ export const GRANULAR_PARAMS: Readonly<Record<string, ParamSpec>> =
|
|
|
223
255
|
}),
|
|
224
256
|
veltone: n(0, 1, 0, 0.05, "soft notes are darker"),
|
|
225
257
|
gain: n(0, 4, 1, 0.05, "voice level"),
|
|
258
|
+
// 0.6.1 grainplay (appended; absent keeps 0.6.0 behaviour).
|
|
259
|
+
sync: Object.freeze({
|
|
260
|
+
kind: "enum",
|
|
261
|
+
values: GRAIN_SYNC_VALUES,
|
|
262
|
+
default: "off",
|
|
263
|
+
doc: "grain rate as a note value on the tempo map (off: grain/overlap)",
|
|
264
|
+
}),
|
|
265
|
+
quant: Object.freeze({
|
|
266
|
+
kind: "enum",
|
|
267
|
+
values: GRAIN_QUANT_VALUES,
|
|
268
|
+
default: "off",
|
|
269
|
+
doc: "snap grain pitches to the song scale or the sounding chord",
|
|
270
|
+
}),
|
|
271
|
+
mono: Object.freeze({
|
|
272
|
+
kind: "boolean",
|
|
273
|
+
default: false,
|
|
274
|
+
doc: "one voice: legato notes retarget its pitch, the cloud keeps going",
|
|
275
|
+
}),
|
|
276
|
+
pedal: Object.freeze({
|
|
277
|
+
kind: "boolean",
|
|
278
|
+
default: false,
|
|
279
|
+
doc: "the sustain pedal freezes the head while it is down",
|
|
280
|
+
}),
|
|
226
281
|
});
|
|
227
282
|
|
|
283
|
+
/** Lanes `grain-<param>` (0.6.1): every number row marked `automate`. */
|
|
284
|
+
export const GRANULAR_LANE_PARAMS: readonly Readonly<{
|
|
285
|
+
param: string;
|
|
286
|
+
spec: Extract<ParamSpec, { kind: "number" }>;
|
|
287
|
+
}>[] = Object.freeze(
|
|
288
|
+
Object.entries(GRANULAR_PARAMS)
|
|
289
|
+
.filter(
|
|
290
|
+
(entry): entry is [string, Extract<ParamSpec, { kind: "number" }>] =>
|
|
291
|
+
entry[1].kind === "number" && entry[1].automate === true,
|
|
292
|
+
)
|
|
293
|
+
.map(([param, spec]) => Object.freeze({ param, spec })),
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
/** Note values `sync` takes, with their length in beats. */
|
|
297
|
+
export const GRAIN_SYNC_BEATS: Readonly<Record<string, number>> = Object.freeze(
|
|
298
|
+
{
|
|
299
|
+
"1/64": 1 / 16,
|
|
300
|
+
"1/32": 1 / 8,
|
|
301
|
+
"1/16t": 1 / 6,
|
|
302
|
+
"1/16": 1 / 4,
|
|
303
|
+
"1/16d": 3 / 8,
|
|
304
|
+
"1/8t": 1 / 3,
|
|
305
|
+
"1/8": 1 / 2,
|
|
306
|
+
"1/8d": 3 / 4,
|
|
307
|
+
"1/4t": 2 / 3,
|
|
308
|
+
"1/4": 1,
|
|
309
|
+
"1/4d": 3 / 2,
|
|
310
|
+
"1/2": 2,
|
|
311
|
+
"1/1": 4,
|
|
312
|
+
},
|
|
313
|
+
);
|
|
314
|
+
|
|
228
315
|
export type GranularParamName = keyof typeof GRANULAR_PARAMS & string;
|
|
229
316
|
|
|
230
317
|
/** Resolved settings the voice reads (presets and defaults applied). */
|
|
@@ -256,6 +343,10 @@ export type GranularSettings = Readonly<{
|
|
|
256
343
|
release: number;
|
|
257
344
|
veltone: number;
|
|
258
345
|
gain: number;
|
|
346
|
+
sync: GrainSync;
|
|
347
|
+
quant: GrainQuant;
|
|
348
|
+
mono: boolean;
|
|
349
|
+
pedal: boolean;
|
|
259
350
|
}>;
|
|
260
351
|
|
|
261
352
|
/**
|