@hraness/dawg 0.6.1 → 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 +92 -0
- package/DAWG.md +343 -116
- package/README.md +27 -25
- package/core/autotune.ts +1119 -0
- package/core/chords.ts +271 -23
- package/core/clips.ts +499 -0
- package/core/diff.ts +182 -104
- package/core/expression.ts +15 -0
- package/core/fx.ts +99 -29
- package/core/instruments.ts +19 -0
- package/core/keys.ts +3 -3
- package/core/loop.ts +5 -0
- package/core/lyrics.ts +297 -0
- package/core/master.ts +3 -3
- package/core/resonators.ts +16 -2
- package/core/routing.ts +165 -0
- package/core/score.ts +832 -13
- package/core/sdk/eval-child.ts +7 -2
- package/core/sdk/eval.ts +35 -6
- package/core/sdk/print.ts +276 -3
- package/core/sdk/sync-lyrics.ts +49 -0
- package/core/sdk/v1.ts +1849 -42
- package/core/sections.ts +292 -26
- package/core/sing.ts +815 -0
- 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/guides/agent.md +29 -0
- package/guides/arrange.md +30 -0
- package/guides/audition.md +20 -14
- package/guides/automation.md +12 -7
- package/guides/chords.md +15 -15
- package/guides/effects.md +17 -16
- 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 -13
- package/guides/play.md +21 -13
- package/guides/project.md +25 -8
- package/guides/providers.md +20 -14
- package/guides/resample.md +15 -9
- 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 -13
- 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 +126 -14
- package/src/agent/calibration-tools.ts +53 -0
- 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 +1 -1
- package/src/agent/gateway.ts +246 -60
- package/src/agent/models.ts +53 -12
- package/src/agent/ops.ts +12 -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 +4 -1
- package/src/agent/provider.ts +22 -8
- 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 +108 -23
- package/src/agent/usage.ts +2 -2
- package/src/agent/voice-tools.ts +925 -0
- package/src/agent/xcb-agent.ts +11 -7
- package/src/argv.ts +38 -0
- package/src/audio/analysis.ts +253 -0
- package/src/audio/arrange.ts +37 -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 +10 -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/effects/chain.ts +3 -1
- package/src/audio/effects/common.ts +43 -0
- package/src/audio/effects/convolution.ts +7 -4
- package/src/audio/effects/filter.ts +48 -69
- package/src/audio/effects/formant.ts +263 -0
- package/src/audio/engine.ts +160 -28
- package/src/audio/fit.ts +35 -3
- package/src/audio/instrument-check.ts +59 -43
- package/src/audio/instruments.ts +4 -0
- package/src/audio/keys/calibration.ts +56 -0
- package/src/audio/keys/electric.ts +8 -1
- package/src/audio/keys/engine.ts +13 -1
- package/src/audio/keys/piano.ts +22 -2
- package/src/audio/kits.ts +135 -6
- package/src/audio/live.ts +114 -20
- package/src/audio/native.ts +615 -0
- package/src/audio/preview.ts +30 -2
- package/src/audio/render-worker.ts +2 -0
- package/src/audio/renderer.ts +2 -0
- package/src/audio/resample.ts +2 -1
- package/src/audio/sampler.ts +85 -4
- package/src/audio/samples.ts +20 -2
- package/src/audio/sing/analysis.ts +193 -0
- package/src/audio/sing/engine.ts +949 -0
- package/src/audio/strings/bow.ts +48 -5
- package/src/audio/strings/engine.ts +8 -2
- 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 +500 -77
- package/src/audio/winds/engine.ts +5 -1
- package/src/audio/winds/trim.ts +28 -4
- package/src/audio/winds/trims1.ts +297 -0
- package/src/audio/winds/voice.ts +15 -2
- 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 +1 -1
- package/src/commands/formant.ts +221 -0
- package/src/commands/fx.ts +101 -32
- package/src/commands/grammar.ts +558 -0
- package/src/commands/help.ts +610 -380
- package/src/commands/history.ts +18 -0
- package/src/commands/keys.ts +8 -8
- package/src/commands/modal.ts +1 -1
- 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/rhythm.ts +3 -0
- package/src/commands/rig.ts +3 -24
- package/src/commands/sing.ts +478 -0
- package/src/commands/strum.ts +13 -1
- 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 +2 -2
- 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 +1397 -253
- package/src/media/cli.ts +20 -3
- package/src/media/import.ts +3 -1
- package/src/project/check.ts +21 -2
- 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 +20 -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 +34 -4
- 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 +759 -177
- package/src/tui/modal-menu.ts +6 -6
- package/src/tui/performance-menu.ts +5 -2
- package/src/tui/play-chords.ts +4 -2
- package/src/tui/play-mode.ts +15 -1
- package/src/tui/play-session.ts +47 -7
- 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 +3 -3
- 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/src/audio/live.ts
CHANGED
|
@@ -28,6 +28,9 @@ import { isOrganFamily } from "../../core/keys.ts";
|
|
|
28
28
|
import type { LiveFullReply, LiveFullRequest } from "./live-worker.ts";
|
|
29
29
|
import { isBowed, liveStringTrack } from "./strings/engine.ts";
|
|
30
30
|
import { resolveString } from "../../core/strings.ts";
|
|
31
|
+
import { singTrack } from "../../core/sing.ts";
|
|
32
|
+
import { warmGlottal } from "./dsp/glottal.ts";
|
|
33
|
+
import { withSingHorizon } from "./sing/engine.ts";
|
|
31
34
|
|
|
32
35
|
/** A rendered live note: interleaved stereo 16-bit PCM. */
|
|
33
36
|
export type LiveNotePcm = Readonly<{
|
|
@@ -99,7 +102,18 @@ export class LiveSynth {
|
|
|
99
102
|
/** f061-organ: the live organ clock's origin (performance.now ms). */
|
|
100
103
|
private readonly organEpoch = performance.now();
|
|
101
104
|
|
|
102
|
-
|
|
105
|
+
/**
|
|
106
|
+
* `fastTail: false` always renders the whole tail window (tests compare
|
|
107
|
+
* the release-sized buffer against it).
|
|
108
|
+
*/
|
|
109
|
+
public constructor(
|
|
110
|
+
private readonly sampleRate: number,
|
|
111
|
+
private readonly options: Readonly<{
|
|
112
|
+
fastTail?: boolean;
|
|
113
|
+
/** Called with each one-note render's buffer length, in frames. */
|
|
114
|
+
onRender?: (frames: number) => void;
|
|
115
|
+
}> = {},
|
|
116
|
+
) {}
|
|
103
117
|
|
|
104
118
|
public get rate(): number {
|
|
105
119
|
return this.sampleRate;
|
|
@@ -237,7 +251,11 @@ export class LiveSynth {
|
|
|
237
251
|
// Organs too: wheels, rotors and drive cost 4-8 ms per note-second.
|
|
238
252
|
const windowed =
|
|
239
253
|
request.full !== true &&
|
|
240
|
-
(hasRig(track) ||
|
|
254
|
+
(hasRig(track) ||
|
|
255
|
+
organTick !== undefined ||
|
|
256
|
+
bowedTrack(track) ||
|
|
257
|
+
hasFormant(track) ||
|
|
258
|
+
singTrack(track)) &&
|
|
241
259
|
seconds > LIVE_RIG_WINDOW_SECONDS &&
|
|
242
260
|
!this.cache.has(key);
|
|
243
261
|
if (windowed) {
|
|
@@ -282,24 +300,8 @@ export class LiveSynth {
|
|
|
282
300
|
: 0;
|
|
283
301
|
// Fitted sample windows over 8 s fit in the background (silent until
|
|
284
302
|
// ready, never at the wrong pitch); shorter ones fit synchronously.
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
sampleRate: this.sampleRate,
|
|
288
|
-
// The renderer's shortest one-shot is 1 s; the window is cut below.
|
|
289
|
-
maxSeconds: windowed
|
|
290
|
-
? 1
|
|
291
|
-
: Math.max(MAX_LIVE_NOTE_SECONDS + 4, seconds + tail),
|
|
292
|
-
...(request.samples ? { samples: request.samples } : {}),
|
|
293
|
-
...(organTick ? { seedTick: organTick } : {}),
|
|
294
|
-
...(quantChord ? { quantChord } : {}),
|
|
295
|
-
}),
|
|
296
|
-
);
|
|
297
|
-
const frames = windowed
|
|
298
|
-
? Math.min(
|
|
299
|
-
audibleFrames(audio.pcm),
|
|
300
|
-
Math.round(LIVE_RIG_WINDOW_SECONDS * this.sampleRate),
|
|
301
|
-
)
|
|
302
|
-
: audibleFrames(audio.pcm);
|
|
303
|
+
const windowFrames = Math.round(LIVE_RIG_WINDOW_SECONDS * this.sampleRate);
|
|
304
|
+
const horizon = windowed ? windowFrames : Infinity;
|
|
303
305
|
const release = liveEngine?.releaseSeconds
|
|
304
306
|
? liveEngine.releaseSeconds(
|
|
305
307
|
track,
|
|
@@ -311,6 +313,44 @@ export class LiveSynth {
|
|
|
311
313
|
),
|
|
312
314
|
)
|
|
313
315
|
: tail;
|
|
316
|
+
const renderFor = (maxSeconds: number) => {
|
|
317
|
+
const out = withLiveFit(() =>
|
|
318
|
+
withSingHorizon(horizon, () =>
|
|
319
|
+
renderScorePcm(single, {
|
|
320
|
+
sampleRate: this.sampleRate,
|
|
321
|
+
maxSeconds,
|
|
322
|
+
...(request.samples ? { samples: request.samples } : {}),
|
|
323
|
+
...(organTick ? { seedTick: organTick } : {}),
|
|
324
|
+
...(quantChord ? { quantChord } : {}),
|
|
325
|
+
}),
|
|
326
|
+
),
|
|
327
|
+
);
|
|
328
|
+
this.options.onRender?.(out.frames);
|
|
329
|
+
return out;
|
|
330
|
+
};
|
|
331
|
+
const fullSeconds = Math.max(MAX_LIVE_NOTE_SECONDS + 4, seconds + tail);
|
|
332
|
+
// A damped key decays 60 dB per 4.6 x its release (a linear fade of the
|
|
333
|
+
// same energy), so 12 x release is past -150 dB: silent in 16 bits. The
|
|
334
|
+
// renderer is causal, so the short buffer is the full one's prefix; a
|
|
335
|
+
// note still sounding at its end falls back to the full window.
|
|
336
|
+
const shortSeconds =
|
|
337
|
+
!windowed &&
|
|
338
|
+
this.options.fastTail !== false &&
|
|
339
|
+
liveFastTail(track, liveEngine !== undefined)
|
|
340
|
+
? seconds + Math.min(tail, LIVE_TAIL_RELEASES * release) + 0.1
|
|
341
|
+
: Infinity;
|
|
342
|
+
let audio =
|
|
343
|
+
// The renderer's shortest one-shot is 1 s; the window is cut below.
|
|
344
|
+
windowed ? renderFor(1) : renderFor(Math.min(fullSeconds, shortSeconds));
|
|
345
|
+
if (
|
|
346
|
+
shortSeconds < fullSeconds &&
|
|
347
|
+
audibleFrames(audio.pcm) >
|
|
348
|
+
audio.frames - Math.round(LIVE_TAIL_GUARD_SECONDS * this.sampleRate)
|
|
349
|
+
)
|
|
350
|
+
audio = renderFor(fullSeconds);
|
|
351
|
+
const frames = windowed
|
|
352
|
+
? Math.min(audibleFrames(audio.pcm), windowFrames)
|
|
353
|
+
: audibleFrames(audio.pcm);
|
|
314
354
|
const ringOut = !windowed && liveEngine?.ringOut?.(track) === true;
|
|
315
355
|
const pcm = audio.pcm.subarray(0, frames * RENDER_CHANNELS);
|
|
316
356
|
if (ringOut) fadeCutTail(pcm, frames, this.sampleRate);
|
|
@@ -346,6 +386,30 @@ export class LiveSynth {
|
|
|
346
386
|
}
|
|
347
387
|
}
|
|
348
388
|
|
|
389
|
+
/**
|
|
390
|
+
* Pays a voice's one-off costs before a key can sound (formant.md 4.5): the
|
|
391
|
+
* sing engine builds its LF glottal tables (about 50 ms) on first use and
|
|
392
|
+
* its inner loops need a pass to compile, so the first sing key of a session
|
|
393
|
+
* would miss the 15 ms first-window budget by 4x. Every other voice has the
|
|
394
|
+
* same shape at a smaller scale: a cold first press of a grand, a bowed
|
|
395
|
+
* cello, a granular swarm or a track with effects costs 2-4x a warm one
|
|
396
|
+
* (docs/perf.md, `live.*`). Play mode calls this when it opens on a track,
|
|
397
|
+
* so the first key costs what later keys do. The warm render goes
|
|
398
|
+
* through a throwaway synth, so no cache entry or state is left behind.
|
|
399
|
+
*/
|
|
400
|
+
export function warmLive(
|
|
401
|
+
score: TrackScore,
|
|
402
|
+
trackId: string,
|
|
403
|
+
sampleRate: number,
|
|
404
|
+
): void {
|
|
405
|
+
const track = score.tracks.find((candidate) => candidate.id === trackId);
|
|
406
|
+
if (!track) return;
|
|
407
|
+
if (singTrack(track)) warmGlottal();
|
|
408
|
+
const synth = new LiveSynth(sampleRate);
|
|
409
|
+
for (const pitch of [48, 60])
|
|
410
|
+
synth.render({ score, trackId, pitch, velocity: 0.8, seconds: 0.3 });
|
|
411
|
+
}
|
|
412
|
+
|
|
349
413
|
/**
|
|
350
414
|
* The track as it sounds live: audible regardless of mute and solo, and
|
|
351
415
|
* without track `time`, so a key sounds once, as played, not re-placed.
|
|
@@ -379,6 +443,15 @@ function bowedTrack(track: Track): boolean {
|
|
|
379
443
|
);
|
|
380
444
|
}
|
|
381
445
|
|
|
446
|
+
/**
|
|
447
|
+
* Whether the track plays through the 0.7 formant fx. It is not causal (one
|
|
448
|
+
* STFT frame of lookahead), but the window renders a 1 s source, well past
|
|
449
|
+
* the 0.75 s window plus one frame, so the window is an exact prefix.
|
|
450
|
+
*/
|
|
451
|
+
function hasFormant(track: Track): boolean {
|
|
452
|
+
return Boolean(track.fx?.formant);
|
|
453
|
+
}
|
|
454
|
+
|
|
382
455
|
/** Whether the track plays through a guitar rig stage. */
|
|
383
456
|
function hasRig(track: Track): boolean {
|
|
384
457
|
return Boolean(track.fx?.stomp || track.fx?.head || track.fx?.cab);
|
|
@@ -425,6 +498,27 @@ export function fadeCutTail(
|
|
|
425
498
|
}
|
|
426
499
|
}
|
|
427
500
|
|
|
501
|
+
/** A short live render ends at 12 x the engine's release past the note. */
|
|
502
|
+
const LIVE_TAIL_RELEASES = 12;
|
|
503
|
+
/** Audio within this much of a short render's end means it was cut. */
|
|
504
|
+
const LIVE_TAIL_GUARD_SECONDS = 0.05;
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Whether a live note may render a buffer sized by its engine's release
|
|
508
|
+
* rather than the whole tail window: only a 0.6 engine's dry track (echoes
|
|
509
|
+
* and reverb tails are not bounded by the key's release).
|
|
510
|
+
*/
|
|
511
|
+
function liveFastTail(track: Track, engine: boolean): boolean {
|
|
512
|
+
return (
|
|
513
|
+
engine &&
|
|
514
|
+
track.delay === undefined &&
|
|
515
|
+
track.reverb === undefined &&
|
|
516
|
+
(track.fx === undefined || Object.keys(track.fx).length === 0) &&
|
|
517
|
+
(track.fxAutomation === undefined ||
|
|
518
|
+
Object.keys(track.fxAutomation).length === 0)
|
|
519
|
+
);
|
|
520
|
+
}
|
|
521
|
+
|
|
428
522
|
function audibleFrames(pcm: Int16Array): number {
|
|
429
523
|
let last = pcm.length - 1;
|
|
430
524
|
while (last >= 0 && pcm[last] === 0) last -= 1;
|