@denaudio/den 0.0.0-stage → 0.1.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 +17 -0
- package/LICENSE-APACHE +202 -0
- package/LICENSE-MIT +21 -0
- package/README.md +102 -2
- package/dist/biquad-eq.d.ts +11 -0
- package/dist/biquad-eq.js +35 -0
- package/dist/catalog-filter-math.d.ts +4 -0
- package/dist/catalog-filter-math.js +30 -0
- package/dist/character-filter.d.ts +13 -0
- package/dist/character-filter.js +53 -0
- package/dist/convolution-spectrum.d.ts +25 -0
- package/dist/convolution-spectrum.js +82 -0
- package/dist/convolution.d.ts +15 -0
- package/dist/convolution.js +81 -0
- package/dist/crossover.d.ts +11 -0
- package/dist/crossover.js +17 -0
- package/dist/curve-shaper.d.ts +26 -0
- package/dist/curve-shaper.js +73 -0
- package/dist/delay-fx.d.ts +37 -0
- package/dist/delay-fx.js +84 -0
- package/dist/delay-readhead.d.ts +19 -0
- package/dist/delay-readhead.js +54 -0
- package/dist/delay-settings.d.ts +55 -0
- package/dist/delay-settings.js +20 -0
- package/dist/drive.d.ts +24 -0
- package/dist/drive.js +116 -0
- package/dist/dual-head-delay.d.ts +28 -0
- package/dist/dual-head-delay.js +77 -0
- package/dist/dynamics.d.ts +61 -0
- package/dist/dynamics.js +130 -0
- package/dist/envelope.d.ts +34 -0
- package/dist/envelope.js +62 -0
- package/dist/filter.d.ts +9 -0
- package/dist/filter.js +34 -0
- package/dist/filterbank-vocoder.d.ts +35 -0
- package/dist/filterbank-vocoder.js +52 -0
- package/dist/formant-bank.d.ts +15 -0
- package/dist/formant-bank.js +28 -0
- package/dist/freeze-reverb.d.ts +35 -0
- package/dist/freeze-reverb.js +61 -0
- package/dist/frequency-shifter.d.ts +24 -0
- package/dist/frequency-shifter.js +57 -0
- package/dist/gate.d.ts +2 -0
- package/dist/gate.js +12 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +12 -0
- package/dist/instrument-example.d.ts +12 -0
- package/dist/instrument-example.js +29 -0
- package/dist/instrument-settings.d.ts +95 -0
- package/dist/instrument-settings.js +36 -0
- package/dist/instrument.d.ts +42 -0
- package/dist/instrument.js +166 -0
- package/dist/lfo.d.ts +19 -0
- package/dist/lfo.js +55 -0
- package/dist/live-buffer.d.ts +39 -0
- package/dist/live-buffer.js +52 -0
- package/dist/live-granular.d.ts +41 -0
- package/dist/live-granular.js +64 -0
- package/dist/lookahead-limiter.d.ts +31 -0
- package/dist/lookahead-limiter.js +67 -0
- package/dist/loop-crossfade.d.ts +28 -0
- package/dist/loop-crossfade.js +72 -0
- package/dist/modulation-fx.d.ts +47 -0
- package/dist/modulation-fx.js +58 -0
- package/dist/modulation.d.ts +132 -0
- package/dist/modulation.js +228 -0
- package/dist/mpe-expression.d.ts +36 -0
- package/dist/mpe-expression.js +73 -0
- package/dist/multiband-dynamics.d.ts +50 -0
- package/dist/multiband-dynamics.js +60 -0
- package/dist/musical-controls.d.ts +76 -0
- package/dist/musical-controls.js +125 -0
- package/dist/musical-examples.d.ts +21 -0
- package/dist/musical-examples.js +142 -0
- package/dist/musical-materials.d.ts +110 -0
- package/dist/musical-materials.js +56 -0
- package/dist/oscillator.d.ts +10 -0
- package/dist/oscillator.js +35 -0
- package/dist/oversampled-drive.d.ts +19 -0
- package/dist/oversampled-drive.js +99 -0
- package/dist/performance.d.ts +61 -0
- package/dist/performance.js +241 -0
- package/dist/pitch-quantizer.d.ts +26 -0
- package/dist/pitch-quantizer.js +88 -0
- package/dist/prepared-convolution.d.ts +22 -0
- package/dist/prepared-convolution.js +99 -0
- package/dist/resident-recorder.d.ts +28 -0
- package/dist/resident-recorder.js +68 -0
- package/dist/resident-time-stretch.d.ts +44 -0
- package/dist/resident-time-stretch.js +135 -0
- package/dist/resonator.d.ts +32 -0
- package/dist/resonator.js +63 -0
- package/dist/reverb.d.ts +27 -0
- package/dist/reverb.js +52 -0
- package/dist/sample.d.ts +113 -0
- package/dist/sample.js +212 -0
- package/dist/source.d.ts +58 -0
- package/dist/source.js +113 -0
- package/dist/spatial-chains.d.ts +48 -0
- package/dist/spatial-chains.js +76 -0
- package/dist/spectral-fft.d.ts +21 -0
- package/dist/spectral-fft.js +74 -0
- package/dist/spectral-freeze.d.ts +22 -0
- package/dist/spectral-freeze.js +74 -0
- package/dist/spectral-gate.d.ts +21 -0
- package/dist/spectral-gate.js +58 -0
- package/dist/spectral-stft.d.ts +13 -0
- package/dist/spectral-stft.js +69 -0
- package/dist/spectral-texture.d.ts +42 -0
- package/dist/spectral-texture.js +141 -0
- package/dist/spectral.d.ts +16 -0
- package/dist/spectral.js +10 -0
- package/dist/state-variable-filter.d.ts +17 -0
- package/dist/state-variable-filter.js +25 -0
- package/dist/stereo-delay.d.ts +45 -0
- package/dist/stereo-delay.js +70 -0
- package/dist/virtual-analog.d.ts +26 -0
- package/dist/virtual-analog.js +66 -0
- package/dist/voice-policy.d.ts +37 -0
- package/dist/voice-policy.js +245 -0
- package/dist/wavetable-bands.d.ts +37 -0
- package/dist/wavetable-bands.js +145 -0
- package/dist/wavetable-read.d.ts +6 -0
- package/dist/wavetable-read.js +11 -0
- package/dist/wavetable.d.ts +29 -0
- package/dist/wavetable.js +49 -0
- package/dist/windowed-pitch-shift.d.ts +34 -0
- package/dist/windowed-pitch-shift.js +51 -0
- package/docs/catalog-audition.md +76 -0
- package/docs/catalog-filters.md +125 -0
- package/docs/catalog-modulation-fx.md +220 -0
- package/docs/catalog-status.md +431 -0
- package/docs/character-filter.md +139 -0
- package/docs/contracts.md +131 -0
- package/docs/control-modulation.md +194 -0
- package/docs/convolution.md +45 -0
- package/docs/curve-shaper.md +117 -0
- package/docs/delay-fx-capture-findings.json +134 -0
- package/docs/delay-fx.md +202 -0
- package/docs/delay-readhead.md +121 -0
- package/docs/delay-settings-candidate.json +333 -0
- package/docs/delay-settings.md +111 -0
- package/docs/dependency-findings.md +61 -0
- package/docs/deployment-status.md +37 -0
- package/docs/drive.md +152 -0
- package/docs/dual-head-delay.md +131 -0
- package/docs/dynamics.md +180 -0
- package/docs/envelope-integer-staging.md +64 -0
- package/docs/filter-materialization-results.json +71 -0
- package/docs/filter-materialization.md +135 -0
- package/docs/filter-oscillator.md +126 -0
- package/docs/filterbank-vocoder-entry.md +58 -0
- package/docs/freeze-reverb.md +179 -0
- package/docs/frequency-shifter.md +133 -0
- package/docs/frontend-audition.md +22 -0
- package/docs/gain-schedule-verification.md +53 -0
- package/docs/initial-acceptance.md +79 -0
- package/docs/instrument-performance.md +191 -0
- package/docs/instrument-settings.md +130 -0
- package/docs/instrument.md +204 -0
- package/docs/integration-candidate.md +114 -0
- package/docs/live-buffer.md +163 -0
- package/docs/live-granular.md +179 -0
- package/docs/lookahead-multiband.md +183 -0
- package/docs/loop-crossfade.md +99 -0
- package/docs/mpe-expression.md +65 -0
- package/docs/musical-clock-seek-boundary.md +31 -0
- package/docs/musical-controls-contract.md +144 -0
- package/docs/musical-examples.md +255 -0
- package/docs/oversampled-drive.md +153 -0
- package/docs/performance.md +53 -0
- package/docs/pitch-quantizer.md +55 -0
- package/docs/prepared-convolution.md +188 -0
- package/docs/realtime-audition.md +63 -0
- package/docs/resident-recorder.md +151 -0
- package/docs/resident-time-stretch.md +190 -0
- package/docs/sample.md +191 -0
- package/docs/sound-audition-headroom.md +103 -0
- package/docs/sources.md +81 -0
- package/docs/spatial-chains-entry.md +250 -0
- package/docs/spectral-freeze-entry.md +130 -0
- package/docs/spectral-gate-entry.md +130 -0
- package/docs/spectral-large-candidate.md +74 -0
- package/docs/spectral-texture-entry.md +174 -0
- package/docs/spectral.md +118 -0
- package/docs/virtual-analog.md +77 -0
- package/docs/voice-policy.md +38 -0
- package/docs/wavetable-bands.md +138 -0
- package/docs/wavetable.md +101 -0
- package/docs/windowed-pitch-shift.md +112 -0
- package/package.json +269 -4
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Entry contract for parallel DSP work
|
|
2
|
+
|
|
3
|
+
This document preserves the original G0 entry proposals and their provisional
|
|
4
|
+
bounds. It is historical design context, not a statement that only the gate exists
|
|
5
|
+
or that later public exports are unavailable. Current module contracts and the
|
|
6
|
+
implemented initial package/site boundary are linked from [the README](../README.md)
|
|
7
|
+
and [the acceptance record](initial-acceptance.md). Later reviewed module-specific
|
|
8
|
+
contracts supersede the provisional choices below.
|
|
9
|
+
|
|
10
|
+
## Authority and provisional choices
|
|
11
|
+
|
|
12
|
+
The approved initial-scope specification says that individual DSP methods and
|
|
13
|
+
numeric upper bounds are not yet determined. GEN-610 asks the entry work to make
|
|
14
|
+
those boundaries concrete for review; it does not approve a particular voice
|
|
15
|
+
count, delay capacity, filter law, or musical behavior.
|
|
16
|
+
|
|
17
|
+
The numbers and engine policies below are **provisional implementation proposals**,
|
|
18
|
+
not user-approved product limits or tested defaults. In particular:
|
|
19
|
+
|
|
20
|
+
- **16 voice slots** is a candidate starting capacity for testing chord overlap,
|
|
21
|
+
release reuse, and deterministic stealing. It is not derived from a measured
|
|
22
|
+
CPU/memory budget. GEN-616 must select/benchmark capacity and expose it as fixed
|
|
23
|
+
construction configuration, rather than assuming 16 is a product-wide ceiling.
|
|
24
|
+
- **Two seconds per delay channel** is a candidate starting allocation for short
|
|
25
|
+
effects and delay fixtures. At 96 kHz, stereo f32 buffers with two guard samples
|
|
26
|
+
use 1,536,016 bytes. This is not a validated product memory budget. A whole note
|
|
27
|
+
at 30 BPM requires eight seconds, so the candidate capacity does not cover all
|
|
28
|
+
rhythmic settings. GEN-615/GEN-620 must jointly choose capacity and explicit
|
|
29
|
+
out-of-capacity behavior; silent tempo-time clamping is not accepted as correct
|
|
30
|
+
rhythmic playback. Keep maximum delay as fixed construction configuration.
|
|
31
|
+
- All other stated ranges, signal shapes, voice priorities, interpolation,
|
|
32
|
+
feedback/mix, and bypass policies have the same provisional status. Later lanes
|
|
33
|
+
must validate or revise them with independent numerical evidence and review.
|
|
34
|
+
Review-approved code decisions still do not imply human sound approval.
|
|
35
|
+
|
|
36
|
+
The gate proves only the public package/subgraph boundary, mono one-sample memory,
|
|
37
|
+
linear gain [0,1], actual parameter edits, and same-schema snapshot continuation.
|
|
38
|
+
It contains no 16-voice allocation or two-second delay implementation. DSP lanes
|
|
39
|
+
can propose revisions without seeking a new product decision for every engineering
|
|
40
|
+
choice, but must coordinate changes that affect shared consumers/contracts.
|
|
41
|
+
|
|
42
|
+
## Composition and state
|
|
43
|
+
|
|
44
|
+
- One ESM package, `@denaudio/den`; current exports are `gateCell` at the root and
|
|
45
|
+
`gate` at `/gate`. Subsequent module exports require integration review.
|
|
46
|
+
- Reusable DSP is an existing `defineSubgraph` declaration. Use required config
|
|
47
|
+
arguments (no default parameter), and `instantiate(unit, config, {name})` with
|
|
48
|
+
stable, unique instance names. Audio-rate inputs/outputs use unworklet
|
|
49
|
+
`Node<'f32'>`; boolean controls use `Node<'bool'>`. No custom graph or routing API.
|
|
50
|
+
- Configuration is immutable per instantiation: sample rate, fixed capacities,
|
|
51
|
+
selected DSP mode. Continuous controls use existing a-rate AudioParams and
|
|
52
|
+
graph inputs. No den parameter registry or preset format.
|
|
53
|
+
- Internal phase, history, and buffers use unworklet state. Persistent slots have
|
|
54
|
+
stable names/types; use existing snapshot profiles, codec, and migration APIs.
|
|
55
|
+
Gate restoration is verified only for the identical processor/schema and rate.
|
|
56
|
+
Never treat same byte width as type compatibility (#79). A schema change needs
|
|
57
|
+
an explicit reviewed migration and its own tests before old snapshots are used.
|
|
58
|
+
- Native transient state is excluded from snapshots, not automatically reset by
|
|
59
|
+
an in-place restore. Fresh-driver offline restore starts from declaration
|
|
60
|
+
defaults; browser `node.restore()` leaves current excluded notes/controllers
|
|
61
|
+
unchanged. A cold live restore requires the composition's explicit reset,
|
|
62
|
+
followed by a rendered quantum before fresh notes. Do not infer live clearing
|
|
63
|
+
from fresh-instance offline evidence.
|
|
64
|
+
- Save after AudioParam edits have actually rendered, while controls are stable
|
|
65
|
+
(#78). A suspended snapshot is not a reliable capture of pending edits in 0.4.1.
|
|
66
|
+
This gate does not solve suspended preset editing or in-flight automation recall.
|
|
67
|
+
- Live `node.restore()` in core 0.4.1 is not an atomic state/AudioParam transaction.
|
|
68
|
+
The worklet copies persistent slots before acknowledging; only then does the
|
|
69
|
+
host restore AudioParam values. A running quantum can use restored history with
|
|
70
|
+
old controls. For the frozen-tail composition, first set every saved control,
|
|
71
|
+
confirm those values have rendered (including completed freeze transition),
|
|
72
|
+
then restore history while controls remain stable. This is a scoped caller
|
|
73
|
+
protocol, not a generic atomic-restore API or a guarantee for arbitrary graphs,
|
|
74
|
+
automation, external inputs or pending events. See [freeze restore](freeze-reverb.md#live-browser-restore-ordering).
|
|
75
|
+
- Worklet compilation is sample-rate-specific. Offline rendering is verified at
|
|
76
|
+
44100, 48000, and 96000 Hz, with 128-frame quanta. The existing 0.4.1 Vite plugin
|
|
77
|
+
compiles at 48000 and exposes no sample-rate option; real browser contexts at
|
|
78
|
+
44100/96000 are verified to reject creation. Browser rendering is proven only
|
|
79
|
+
at 48000. Non-48-kHz browser loading remains an upstream limitation, not a requirement
|
|
80
|
+
of this entry gate and not a blocker for den development. Do not bypass the
|
|
81
|
+
mismatch guard or claim multi-rate browser readiness. The supported browser
|
|
82
|
+
scope is explicitly 48 kHz; offline multi-rate coverage is separate.
|
|
83
|
+
- State allocation is fixed at graph creation. No dynamic audio-thread allocation.
|
|
84
|
+
Reset uses existing node/event control, clears histories/voices/phase immediately
|
|
85
|
+
at its dispatched sample, and may create a discontinuity. Reset is not bypass.
|
|
86
|
+
|
|
87
|
+
## Module boundaries and provisional defaults
|
|
88
|
+
|
|
89
|
+
| Lane | Graph boundary and units | Proposed policy for first integration |
|
|
90
|
+
| --- | --- | --- |
|
|
91
|
+
| Envelope (GEN-611) | Gate/retrigger → normalized unipolar level [0,1] and completion flag. Attack/decay/release seconds [0,30], sustain [0,1]. | One state per voice/use; zero time is instantaneous. Retrigger from current level; note-off releases from current level. Completion only when release reaches zero. Lane selects/documents curve law; no second envelope engine for pitch/filter. |
|
|
92
|
+
| LFO/modulation (GEN-614) | Rate Hz [0,20], phase cycles [0,1), reset → bipolar unit signal [-1,1]. Depth is applied at the destination in its own units. | Rate 0 holds phase. Free-running or explicit phase reset; no implicit note reset. First shape sine; further shapes need lane tests. Pitch depth semitones [-24,24], cutoff depth octaves [-8,8], delay depth seconds [0,0.05]. Clamp the composed destination to its bounds. |
|
|
93
|
+
| Filter (GEN-612) | Mono normalized audio → mono audio; cutoff Hz [20,min(20000,0.45×sampleRate)], resonance Q [0.5,10]. | One low-pass method selected and justified by this lane. Independent state per voice/channel. Reset clears history. No hidden gain normalization; response/peak bounds must be established before integration. |
|
|
94
|
+
| Voice policy (GEN-616) | Existing MIDI events → per-voice note, gate/retrigger, velocity [0,1], release completion. | Candidate default 16 slots, fixed per construction; mono uses one. Mono last-note priority, legato preserves envelopes until an explicit retrigger. Poly reuse free, then oldest releasing, then oldest active voice; deterministic slot-index tie break. Duplicate note-ons allocate separately; note-off releases oldest matching active channel/note. Velocity-zero note-on means note-off. Completion returns a voice to free; reset/all-sound-off clears all. |
|
|
95
|
+
| Oscillator (GEN-613) | Frequency Hz [0,0.45×sampleRate], phase reset → mono signal nominally [-1,1]. | Per-voice phase cycles [0,1); rate 0 holds. MIDI tuning A4=440 Hz, equal temperament. Lane selects one band-limited method and documents alias/level limits. Reset phase 0. No new MIDI receiver. |
|
|
96
|
+
| Delay read-head (GEN-615) | Mono input and delay seconds [1/sampleRate,2] → delayed mono output. Two independent instances form stereo FX. | Candidate allocation ceil(maxDelaySeconds×sampleRate)+2 samples per channel, initially proposing maxDelaySeconds=2; no resizing. Linear fractional interpolation with wrapped adjacent reads. Continuous moving head (Doppler behavior), not dual-head crossfade. Clamp time after modulation; reset clears buffer and pointers. |
|
|
97
|
+
|
|
98
|
+
Methods and exported types for unfinished modules are deliberately not stubbed:
|
|
99
|
+
use each lane's own tested unworklet subgraph with reviewed boundaries, then bring
|
|
100
|
+
public exports through integration review. `tests/consumer/contract.ts` demonstrates
|
|
101
|
+
composition from the packed public entry. The small gate's actual `tick(input,
|
|
102
|
+
gain)` is solely a packaging example, not an imposed interface for every module.
|
|
103
|
+
|
|
104
|
+
## Engine integration targets
|
|
105
|
+
|
|
106
|
+
One instrument: existing MIDI input `midi`, stereo audio output `main`, mono DSP
|
|
107
|
+
per voice feeding equal L/R initially; amp and velocity gains are linear, no
|
|
108
|
+
limiter or automatic loudness normalization. Mono/poly is immutable configuration
|
|
109
|
+
for the first engine. Voice stealing hard-retriggers from current envelope level;
|
|
110
|
+
its click behavior needs numerical and listening evidence before sound approval.
|
|
111
|
+
|
|
112
|
+
One stereo delay: audio input/output `main`; mono callers duplicate L/R explicitly.
|
|
113
|
+
Feedback gain [0,0.95], low-pass tone in the feedback path, dry/wet linear crossfade
|
|
114
|
+
[0,1]. Input stop preserves decay. Bypass emits unity dry only, feeds zero new input
|
|
115
|
+
to delay, and lets internal feedback decay; unbypass can expose a remaining tail.
|
|
116
|
+
Reset clears that tail immediately. BPM [30,300], note durations converted to
|
|
117
|
+
seconds; out-of-capacity behavior remains a joint read-head/tempo decision and
|
|
118
|
+
must not silently alter a requested rhythm. Tempo changes provisionally use the
|
|
119
|
+
same moving-head policy.
|
|
120
|
+
Feedback stability and stereo/tempo details are later integration tasks, not claims
|
|
121
|
+
established by this one-sample gate.
|
|
122
|
+
|
|
123
|
+
## Acceptance each lane must supply
|
|
124
|
+
|
|
125
|
+
Use unworklet offline rendering and existing test helpers after checking their
|
|
126
|
+
behavior. Provide independent formulas/reference oracles, endpoint and modulation
|
|
127
|
+
cases, sample-rate/capacity boundaries, reset tests, and exact input/settings.
|
|
128
|
+
No expected waveform may be copied from the implementation as its correctness
|
|
129
|
+
oracle. Counterexamples must fail. Human hearing can remain pending independently
|
|
130
|
+
of code/numerical work; artifacts stay candidates. Envelope/LFO/filter/oscillator/
|
|
131
|
+
voice/read-head work can proceed in parallel only after this entry contract review.
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# Control modulation candidates
|
|
2
|
+
|
|
3
|
+
Catalog §5, additive `@denaudio/den/modulation` entry. Existing `envelope` and
|
|
4
|
+
`lfo` implementations and contracts are unchanged. These are graph-native fixed
|
|
5
|
+
state modules for instruments and FX, not a transport, routing layer, arbitrary
|
|
6
|
+
scheduler, MIDI framework, approved sound library, or real-time guarantee.
|
|
7
|
+
|
|
8
|
+
## Shared execution contract
|
|
9
|
+
|
|
10
|
+
Instantiate during graph construction, with an integer sample rate from 8,000
|
|
11
|
+
through 192,000 Hz where a rate is required. Call each instance's `tick` exactly
|
|
12
|
+
once per audio sample. All dynamic numeric inputs must be finite. Audio/event
|
|
13
|
+
rates are not silently smoothed or converted to control-block rates. Changing
|
|
14
|
+
sample rate requires reconstruction; same-schema snapshots continue an instance
|
|
15
|
+
at the same sample rate and construction settings. No cross-configuration or
|
|
16
|
+
cross-rate snapshot compatibility is claimed. Give independent instances distinct
|
|
17
|
+
unworklet names.
|
|
18
|
+
|
|
19
|
+
Construction checks reject nonfinite values, unsupported modes, invalid bounds,
|
|
20
|
+
or capacities. Fixed capacities are at most 16 MSEG segments and 64 sequence
|
|
21
|
+
steps. Arrays are copied at construction; no dynamic graph/buffer growth occurs.
|
|
22
|
+
|
|
23
|
+
Scalar histories that can contain tiny f32 controls use exact power-of-two f64
|
|
24
|
+
scaling. This avoids core 0.4.1's tiny scalar-state write flush without introducing
|
|
25
|
+
a control dead zone. Sample-and-hold preserves the entire finite f32 input range,
|
|
26
|
+
including subnormals and values above full scale.
|
|
27
|
+
|
|
28
|
+
## Musical clock
|
|
29
|
+
|
|
30
|
+
`musicalClock({ sampleRate, mode, steps, stepsPerBeat? })` exposes
|
|
31
|
+
`tick({ rate, reset, seek, position }) -> { step, phase, tick }`.
|
|
32
|
+
|
|
33
|
+
- `mode` is `free` or `tempo`; `steps` is a fixed integer 1..64.
|
|
34
|
+
- Free `rate` is steps per second. Tempo `rate` is BPM. Both clamp to [0,1000].
|
|
35
|
+
- Tempo `stepsPerBeat` defaults to 1 and accepts powers of two from 1/64 to 64.
|
|
36
|
+
Free mode requires the default 1. Thus the maximum step rate is below the
|
|
37
|
+
minimum sample rate and at most one boundary can occur per sample.
|
|
38
|
+
- `step` is an integer-valued f32 in [0,steps); `phase` is an f32 fraction in
|
|
39
|
+
[0,1), capped at the largest f32 below 1 to keep the public range exact.
|
|
40
|
+
- Output describes the current sample before integrating its rate. The initial
|
|
41
|
+
sample ticks, even at rate zero. Subsequent zero rate holds the current phase.
|
|
42
|
+
- Rate changes preserve phase. The sample receiving a new rate uses that rate
|
|
43
|
+
for the next sample's phase. A pending boundary tick remains observable if
|
|
44
|
+
the new rate becomes zero on the boundary sample.
|
|
45
|
+
- Held `reset` pins step/phase to zero and suppresses all ticks. The first
|
|
46
|
+
reset-low sample emits the start tick and starts integrating again.
|
|
47
|
+
- `seek` applies only on its rising edge. Held seek does not freeze phase or
|
|
48
|
+
retrigger. `position` is in steps, explicitly clamped to [-1048576,1048576],
|
|
49
|
+
then wrapped to [0,steps). Negative positions wrap backward. A seek emits a
|
|
50
|
+
tick on that sample, including a seek into the middle of a step.
|
|
51
|
+
- Reset wins over seek and consumes the seek level. A seek held across reset
|
|
52
|
+
release needs another low→high edge to take effect.
|
|
53
|
+
|
|
54
|
+
Internal phase uses compensated f64 accumulation in frequency units. It avoids
|
|
55
|
+
rounding a noninteger samples-per-step period and divides only for phase output.
|
|
56
|
+
There is no growing global position counter or global duration limit. This is a
|
|
57
|
+
numerical design, not a proof of perpetual drift-free behavior: the accompanying
|
|
58
|
+
tests compare measured boundary samples against independent schedules at
|
|
59
|
+
44.1/48/96 kHz, with documented observation lengths.
|
|
60
|
+
|
|
61
|
+
## Fixed step sequence
|
|
62
|
+
|
|
63
|
+
`stepSequence({ sampleRate, mode, stepsPerBeat?, steps })` accepts 1..64 fixed
|
|
64
|
+
`{ value, gate }` entries. Values are [-1,1], gate fractions [0,1]. Its `tick`
|
|
65
|
+
uses the clock controls and returns `{ value, gate, step, phase, tick }`.
|
|
66
|
+
|
|
67
|
+
Value changes exactly with step selection. Gate is true while the internal f64
|
|
68
|
+
phase is strictly less than the selected gate fraction: zero never opens and one
|
|
69
|
+
stays open for the whole step. Reset always gates off but exposes step zero's
|
|
70
|
+
value. Release opens the gate according to the first step. Tempo/free zero holds
|
|
71
|
+
a currently open gate; callers wanting a stop must use reset. Adjacent gate-one
|
|
72
|
+
steps can stay continuously high, while `tick` still identifies step starts.
|
|
73
|
+
Gate decisions use f64 phase, not the rounded public f32 phase. No interpolation,
|
|
74
|
+
swing, arbitrary ordering, note allocation, or implicit smoothing is provided.
|
|
75
|
+
|
|
76
|
+
## MSEG
|
|
77
|
+
|
|
78
|
+
`mseg({ sampleRate, initial, segments, loop? })` accepts `initial` and segment
|
|
79
|
+
`target` values in [-1,1], and 1..16 `{ seconds, target, curve }` entries.
|
|
80
|
+
Durations are fixed at construction, in [0,30] seconds, rounded to the nearest
|
|
81
|
+
sample with half-samples rounded up. Curves on normalized segment time t are:
|
|
82
|
+
|
|
83
|
+
- `linear`: t
|
|
84
|
+
- `easeIn`: t²
|
|
85
|
+
- `easeOut`: 2t−t²
|
|
86
|
+
- `smoothstep`: 3t²−2t³
|
|
87
|
+
|
|
88
|
+
`tick({ trigger, reset })` returns `{ value, done, segment }`. A rising trigger
|
|
89
|
+
starts from `initial`, emitting step 1 on that sample. A positive N-sample segment
|
|
90
|
+
reaches its target on step N. A held trigger does not retrigger. A new rising
|
|
91
|
+
trigger restarts from initial even while already running, intentionally permitting
|
|
92
|
+
a jump. Reset wins, consumes the trigger level, emits initial, and sets done.
|
|
93
|
+
Idle segment is zero; active segment is an integer-valued f32 list index.
|
|
94
|
+
|
|
95
|
+
Zero-duration segments collapse at their exact boundary in list order, including
|
|
96
|
+
those after a positive segment's endpoint; the last coincident zero segment wins.
|
|
97
|
+
A nonlooping all-zero MSEG reaches its last target and becomes done on its trigger
|
|
98
|
+
sample. Otherwise done becomes true on the final endpoint sample and the final
|
|
99
|
+
value remains held. No threshold tail detection is used.
|
|
100
|
+
|
|
101
|
+
Whole-envelope looping emits the final endpoint before the next iteration's
|
|
102
|
+
first step. It can jump when the final target differs from initial. There is no
|
|
103
|
+
implicit crossfade or smoothing. An all-zero loop is rejected. This first version
|
|
104
|
+
does not add sustain-point, release-segment, partial-loop, or runtime duration
|
|
105
|
+
editing semantics.
|
|
106
|
+
|
|
107
|
+
## Sample-and-hold and correlated random
|
|
108
|
+
|
|
109
|
+
`sampleAndHold({ initial })` has `tick(input, trigger, reset)`. Initial is bounded
|
|
110
|
+
to [-1,1], but sampled input is any finite f32. Trigger is level-sensitive: each
|
|
111
|
+
high sample stores that sample's input. Low trigger holds finite f32 numeric values; the native scalar-state write
|
|
112
|
+
canonicalizes negative zero to positive zero. All nonzero finite values, including
|
|
113
|
+
subnormals, remain bit-exact. Reset wins, restores initial, and holds it throughout a held reset.
|
|
114
|
+
|
|
115
|
+
`randomModulator({ seed, initial })` has
|
|
116
|
+
`tick({ trigger, reset, correlation })`. Seed is an integer 1..2147483646;
|
|
117
|
+
initial is [-1,1]. On every high trigger it advances the Park–Miller recurrence
|
|
118
|
+
`s = (16807*s) mod 2147483647` using exactly represented f64 integers, maps
|
|
119
|
+
`u = 2*(s−1)/2147483645−1`, then outputs
|
|
120
|
+
`correlation*previous + (1−correlation)*u`. Correlation clamps to [0,1].
|
|
121
|
+
|
|
122
|
+
Zero correlation is seeded uniform S&H. Positive correlation makes a bounded
|
|
123
|
+
first-order correlated sequence. One holds the value but still advances the seed;
|
|
124
|
+
returning to zero therefore resumes at the advanced random position. Reset
|
|
125
|
+
restores both seed and initial, with no PRNG advance even if trigger is high.
|
|
126
|
+
Independent instances do not share random state. No cryptographic suitability,
|
|
127
|
+
Gaussian distribution, variance normalization, target spectral color, or sound
|
|
128
|
+
quality equivalence is claimed.
|
|
129
|
+
|
|
130
|
+
## Evidence and limits
|
|
131
|
+
|
|
132
|
+
`tests/control-modulation.spec.ts` uses independent closed-form curves, exact
|
|
133
|
+
BigInt PRNG arithmetic, sample-index timing schedules, boundary/held-control
|
|
134
|
+
checks, seed isolation, snapshots, and bounds. The packed consumer installs the
|
|
135
|
+
actual tarball using its pinned npm lock, imports only the public entry, typechecks
|
|
136
|
+
strictly, compiles and renders actual DSP at 44.1/48/96 kHz, and checks zero scrub.
|
|
137
|
+
Any emitted evidence is CANDIDATE. No new human-approved golden or browser/hardware
|
|
138
|
+
real-time claim is made.
|
|
139
|
+
|
|
140
|
+
The native MIDI probe in `tests/probes/control-midi-output.mjs` verifies offline
|
|
141
|
+
note-on/off at samples 127/128 when explicit absolute `atSample` is supplied.
|
|
142
|
+
This is only a native emitted-event entry proof. Browser bridge, WebMIDI device,
|
|
143
|
+
and external host delivery are not verified. An output declaration alone is not
|
|
144
|
+
host integration proof. The bounded arp below builds only on the proven native
|
|
145
|
+
emitted-event path.
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
## Fixed-note arpeggiator candidate
|
|
149
|
+
|
|
150
|
+
`fixedArpeggiator({ sampleRate, mode, stepsPerBeat?, channel, notes })` accepts a
|
|
151
|
+
fixed list of 1..64 `{ note, velocity, gate }` entries. Channel is an integer
|
|
152
|
+
0..15, note 0..127, velocity 1..127, gate fraction [0,1]. The list plays in its
|
|
153
|
+
specified order. It does not capture incoming chords, allocate voices, alter
|
|
154
|
+
transport, or add another MIDI queue.
|
|
155
|
+
|
|
156
|
+
`tick(output, { rate, reset, seek, position, atSample })` receives a native
|
|
157
|
+
`MidiOutputHandle` created by `event.midi({ to: 'main', ... })`. It returns
|
|
158
|
+
`{ note, gate, step, phase, tick }` and conditionally emits native note events.
|
|
159
|
+
The clock/reset/seek contracts above apply unchanged.
|
|
160
|
+
|
|
161
|
+
- Gate zero is a rest and never produces a note-on.
|
|
162
|
+
- At each step-start tick, an existing note is turned off before the new note
|
|
163
|
+
is turned on, even for repeated pitches and gate-one adjacent steps.
|
|
164
|
+
- When the selected gate closes, the active note is turned off once.
|
|
165
|
+
- Seeking turns the old note off first; it starts the new note only if the
|
|
166
|
+
seeked phase lies within that step's gate. A held seek does not retrigger.
|
|
167
|
+
- Reset turns the active note off once, suppresses starts while held, and
|
|
168
|
+
starts step zero on reset release if that step is not a rest.
|
|
169
|
+
- Rate zero holds phase and any active note. Send reset and process that sample
|
|
170
|
+
before stopping/disconnecting. This module cannot guarantee a note-off after
|
|
171
|
+
the host abruptly stops calling it, loses queued events, or loses a device.
|
|
172
|
+
- The caller supplies the absolute `atSample` timestamp as a `Node<'i32'>`
|
|
173
|
+
containing native unsigned 32-bit timestamp bits. The native reader interprets
|
|
174
|
+
the bits unsigned: the signed 2^31 boundary is preserved, and 2^32 wraps to 0.
|
|
175
|
+
This is the native format limit, not an indefinitely monotonic timestamp API.
|
|
176
|
+
Caller and host own epoch/transport interpretation. The module does not add
|
|
177
|
+
a global timestamp counter or another transport. No implicit lookahead exists.
|
|
178
|
+
- At most one off plus one on can be emitted by this producer on any sample.
|
|
179
|
+
A dedicated output capacity of at least 256 covers the conservative two-event
|
|
180
|
+
bound for a 128-sample quantum when drained every quantum. Native tests verify
|
|
181
|
+
all 256 slots are usable. This is not a lossless guarantee if the host stops
|
|
182
|
+
draining or additional producers share that ring. Native overflow drops the
|
|
183
|
+
oldest event, which can lose a note-off; host diagnostics and lifecycle matter.
|
|
184
|
+
- Same-schema snapshot continuation is demonstrated only when the external MIDI
|
|
185
|
+
recipient has the matching note state. Restoring a DSP snapshot into an empty
|
|
186
|
+
or different MIDI device state does not reconstruct that device's notes.
|
|
187
|
+
|
|
188
|
+
`tests/control-arpeggiator.spec.ts` checks actual native event payloads/order,
|
|
189
|
+
zero/full gates, reset/seek/tempo changes, stopped-rate hold, reset-before-stop,
|
|
190
|
+
repeated pitches, same-schema continuation, signed timestamp crossing and uint32
|
|
191
|
+
wrap at 44.1/48/96 kHz. A bounded burst test proves 256 usable native ring slots
|
|
192
|
+
and retains an undersized-128 counterexample that loses the first half of the
|
|
193
|
+
burst. These are offline native-event tests; browser bridge, WebMIDI devices,
|
|
194
|
+
external host delivery and human musical approval remain unverified.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Bounded uniform convolution candidate
|
|
2
|
+
|
|
3
|
+
`partitionedConvolution({ blockSize, impulse }).tick(input, reset,
|
|
4
|
+
everyNSamples)` uses the existing stride-1 `forSample` scheduler. This is a small
|
|
5
|
+
uniform-partition frequency-domain convolution, not a direct FIR relabeled as
|
|
6
|
+
FFT processing. It is CANDIDATE and has no human or realtime acceptance.
|
|
7
|
+
The initial B<=32 and IR<=128-sample range is a bounded partitioning/FIR proof,
|
|
8
|
+
not a practical convolution-reverb or complete catalog §10 capability.
|
|
9
|
+
|
|
10
|
+
## Contract
|
|
11
|
+
|
|
12
|
+
- B is a construction-fixed power of two in 4..32; N=2B. The original/fixed IR has
|
|
13
|
+
1..4B taps, each finite in [-1,1], and sum of absolute tap values <=4. Input is
|
|
14
|
+
finite normalized audio [-1,1]; output is not clipped or gain-normalized.
|
|
15
|
+
- The IR is split into at most four B-sample partitions, each zero-padded to N.
|
|
16
|
+
Its complex spectra are calculated from the DFT formula at graph construction.
|
|
17
|
+
Runtime uses the internal radix-2 FFT, frequency-delay line, complex products,
|
|
18
|
+
normalized IFFT and overlap-add. No dependency, loader, alternate runtime,
|
|
19
|
+
dynamic allocation, runtime IR update or new snapshot system is introduced.
|
|
20
|
+
- At sample t=mB, the previous input block [t-B,t) is transformed. For output
|
|
21
|
+
block m the spectral sum is Σ H_p X_(m-p), then its 2B time samples are added
|
|
22
|
+
to [t,t+2B). Algorithmic latency is exactly B samples. The IR's own leading
|
|
23
|
+
zeros/predelay and tail of L-1 samples are additional, separate properties.
|
|
24
|
+
- Reset immediately outputs zero, discards its input sample and pre-reset tail,
|
|
25
|
+
invalidates history and earlier partitions, and preserves native hop phase.
|
|
26
|
+
The partial first block after reset is zero-padded before the reset boundary.
|
|
27
|
+
Held reset remains silent. Flush with B+L-1 zero samples to hear the full tail.
|
|
28
|
+
- Fixed f64 buffers use exact 2^128 scaling for input/history/spectra, avoiding
|
|
29
|
+
0.4.1's 1e-30 buffer-write flush discarding f32 subnormal audio. IR coefficients
|
|
30
|
+
are double constants. No treatment of arbitrary nonfinite inputs is promised.
|
|
31
|
+
- Persistent history, overlap, spectra and indices use native full snapshots.
|
|
32
|
+
FFT/mixed-spectrum scratch is transient and rewritten before use. Same graph
|
|
33
|
+
and rate are required. Changing IR/configuration requires a new graph; no
|
|
34
|
+
migration, IR swap, crossfade, stereo adapter or long-room support is implied.
|
|
35
|
+
|
|
36
|
+
## Required evidence
|
|
37
|
+
|
|
38
|
+
Three-rate direct time-domain FIR comparison covers one tap, partial final
|
|
39
|
+
partitions, all partition counts, taps at partition boundaries, random original
|
|
40
|
+
IRs, impulse/full tail, all reset hop phases, zero IR and linearity. Snapshot
|
|
41
|
+
continuation must be bit-identical, no output scrub is accepted, and instance
|
|
42
|
+
memory must stay fixed. Packed consumer and generated-worklet checks remain
|
|
43
|
+
separate gates. Measured local cold/warm quantum costs are diagnostic only.
|
|
44
|
+
The shared N64 FFT/STFT proof measured a 298-ms cold first quantum locally;
|
|
45
|
+
this is a startup hazard, not a runtime-safe building block certification.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Editable curve shaper
|
|
2
|
+
|
|
3
|
+
Status: **CANDIDATE**.
|
|
4
|
+
|
|
5
|
+
This additive catalog §7 module is a bounded piecewise-linear user curve/LUT.
|
|
6
|
+
It uses only unworklet 0.4.1 graph nodes and native state. No additional parameter,
|
|
7
|
+
asset, snapshot, routing, loader, or test system is introduced.
|
|
8
|
+
|
|
9
|
+
## Public entry
|
|
10
|
+
|
|
11
|
+
`@denaudio/den/curve-shaper` exports `curveShaper`, `CurveShaperConfig`,
|
|
12
|
+
`CurveShaperControls`, and `CurveShaperQuality`.
|
|
13
|
+
|
|
14
|
+
- Config: `sampleRate` finite in [8000,192000] Hz; `pointCount` integer in [2,17];
|
|
15
|
+
immutable `quality: 'direct' | 'adaa'`, default `'adaa'`.
|
|
16
|
+
- `tick(input, controls)` is called once per sample. `input` is f32. Controls are
|
|
17
|
+
`gain`, `mix`, `reset`, and `ordinates: readonly Node<'f32'>[]` with exactly
|
|
18
|
+
`pointCount` entries. Ordinates may be constants, native params, or graph signals.
|
|
19
|
+
- Equally spaced immutable input knots cover [-1,1], including both endpoints.
|
|
20
|
+
Each audio-rate ordinate is clamped to [-1,1]. NaN becomes zero; infinity
|
|
21
|
+
saturates. Values outside the knot domain use the nearest endpoint ordinate.
|
|
22
|
+
- Input clamps to [-8,8], gain to [0,32], mix to [0,1], with NaN becoming zero.
|
|
23
|
+
Gain is a linear multiplier; no automatic loudness compensation is applied.
|
|
24
|
+
- Direct quality evaluates linear interpolation of the current ordinates.
|
|
25
|
+
- ADAA averages the **current sample's curve** over the previous/current driven
|
|
26
|
+
input interval by summing overlap trapezoids. It never differences primitives
|
|
27
|
+
computed under different ordinate values. At almost equal inputs a midpoint
|
|
28
|
+
replacement uses distance <= 1e-6/(pointCount-1). Since each segment has
|
|
29
|
+
slope magnitude <= pointCount-1, the mean-versus-midpoint error is bounded by
|
|
30
|
+
slope*distance/4 <= 2.5e-7, including knot crossings.
|
|
31
|
+
- Gain and ordinate edits are immediate. This antialiases the input interpolation
|
|
32
|
+
for a fixed curve; rapid curve edits can still produce sidebands and aliasing.
|
|
33
|
+
There is no smoothing, edit crossfade, arbitrary-graph oversampling, higher-order
|
|
34
|
+
ADAA, or guarantee of a bandlimited output.
|
|
35
|
+
- Direct dry is immediate. ADAA dry is the same two-sample mean as a linear curve,
|
|
36
|
+
with half-sample group delay and cosine rolloff. Mix zero is not transparent
|
|
37
|
+
bypass in ADAA mode. Arbitrary asymmetric curves can generate DC; no DC blocker
|
|
38
|
+
is built in.
|
|
39
|
+
- Reset clears input and dry histories before the current sample. The first ADAA
|
|
40
|
+
interval therefore begins at zero. Same-schema native snapshots preserve those
|
|
41
|
+
histories. Point-count or quality migration is not promised.
|
|
42
|
+
- Output is bounded by the blend of |dry|≤8 and |wet|≤1. State uses exact binary
|
|
43
|
+
scaling to retain recoverable f32 subnormals through native state-write flush.
|
|
44
|
+
|
|
45
|
+
## Evidence and limits
|
|
46
|
+
|
|
47
|
+
Independent scalar interpolation and knot-segmented quadrature, 44.1/48/96 kHz,
|
|
48
|
+
minimum and maximum point counts, asymmetric and folded user curves, knots and
|
|
49
|
+
endpoint extension, finite/extreme/non-finite controls, gain/mix/ordinate editing,
|
|
50
|
+
reset, same-schema snapshot continuation, independent instances, tiny inputs,
|
|
51
|
+
linear dry alignment and measured fixed-curve folded-alias comparisons.
|
|
52
|
+
|
|
53
|
+
The packed isolated consumer must compile only public declarations, render actual
|
|
54
|
+
WASM, check the independent oracles and record source/package/audio hashes.
|
|
55
|
+
Generated audio is **CANDIDATE**, never an approved golden. Browser deadline,
|
|
56
|
+
listening approval, and oversampling are separate claims.
|
|
57
|
+
|
|
58
|
+
The independent integration owner approved this bounded entry before DSP
|
|
59
|
+
implementation. Existing `/drive`, reduction, and all other DSP remain untouched.
|
|
60
|
+
|
|
61
|
+
## Numerical implementation
|
|
62
|
+
|
|
63
|
+
Internally, t=(pointCount-1)*x makes knot locations exact integers separated by
|
|
64
|
+
2. Sign-changing segments use a barycentric zero-crossing anchor, with explicit
|
|
65
|
+
zero-valued endpoint branches and protected zero-slope division. This avoids
|
|
66
|
+
spurious nonzero output at symmetric zero crossings when the original x spacing
|
|
67
|
+
is not exactly representable in binary. Same-sign segments use ordinary linear
|
|
68
|
+
interpolation. Histories retain the driven x rather than a rounded LUT index.
|
|
69
|
+
|
|
70
|
+
The rejected fractional-knot/root implementation is retained only in a test
|
|
71
|
+
fixture. Its four-point symmetric curve creates about 5.55e-17 of spurious DC
|
|
72
|
+
at exact zero; the silence oracle must continue rejecting it. It is not shipped.
|
|
73
|
+
The corrected implementation is checked for exact silence and signed recoverable
|
|
74
|
+
f32 tiny inputs at every point count from 2 through 17.
|
|
75
|
+
|
|
76
|
+
## Example construction
|
|
77
|
+
|
|
78
|
+
Use three native f32 AudioParams named `negative`, `center`, and `positive`, with
|
|
79
|
+
initial values -1,0,1 and bounds [-1,1]. Use native `instantiate(curveShaper,
|
|
80
|
+
{sampleRate, pointCount:3, quality:'adaa'}, {name:'shaper'})`, then pass their
|
|
81
|
+
`.at(i)` values as `ordinates` inside `forSample`.
|
|
82
|
+
Changing the center ordinate makes the curve asymmetric; editing both endpoints
|
|
83
|
+
alters polarity or folds the transfer without replacing the graph. The point
|
|
84
|
+
count remains fixed. This is an example of graph composition, not a custom
|
|
85
|
+
parameter manager or curve-asset loader.
|
|
86
|
+
|
|
87
|
+
The focused suite has 17 tests. Actual native offline rendering at 44.1,48,96 kHz
|
|
88
|
+
passes the interpolation/quadrature, edit, reset, state, non-finite, tiny-signal,
|
|
89
|
+
and alignment checks above. Two fixed five-point curves, [-1,-1,0,1,1] and
|
|
90
|
+
[-0.5,-0.5,0,1,1], are measured with coherent 8192-frame sines at bins 997 and
|
|
91
|
+
1709, amplitude 3, after one full period of warmup. Projection removes DC and
|
|
92
|
+
only harmonics below Nyquist. The remaining folded RMS decreases by 8.64–9.47 dB
|
|
93
|
+
in ADAA versus direct quality, exceeding the test's fixed 6 dB requirement.
|
|
94
|
+
Fundamental amplitudes are recorded without loudness normalization. These are
|
|
95
|
+
specific fixed-curve fixtures, not guarantees for arbitrary edits or signals.
|
|
96
|
+
|
|
97
|
+
`tests/curve-shaper-packed.test.mjs` installs the actual package tarball into a
|
|
98
|
+
locked isolated consumer, checks public TypeScript, and renders the minimum and
|
|
99
|
+
maximum point counts in both modes at all three rates. Gain, mix and every
|
|
100
|
+
ordinate are written through native a-rate parameter blocks, including edits
|
|
101
|
+
inside a block. An independent scalar interpolation/segmented Simpson reference
|
|
102
|
+
has maximum f32 error below 6e-8 in this fixture; the fixed limit is 8e-7. Reset and
|
|
103
|
+
exact same-schema continuation are checked in the native offline renderer, whose
|
|
104
|
+
whole output must also exactly match the manually driven public WASM instance.
|
|
105
|
+
|
|
106
|
+
The maximum 17-point ADAA graph is about 0.79 MB of serialized graph and 78,938
|
|
107
|
+
bytes of WASM. Each test instance retains fixed 65,536-byte WASM memory. Local
|
|
108
|
+
128-frame process timings include cold execution and host jitter, with observed
|
|
109
|
+
maxima above the quantum budget in some runs. These diagnostics are not a browser
|
|
110
|
+
or real-time capacity approval. Host composition and simultaneous instance count
|
|
111
|
+
need their own measurements; a small LUT can cost substantially less than 17
|
|
112
|
+
points. There is no browser worklet or listening approval in this lane.
|
|
113
|
+
|
|
114
|
+
Oversampling, explicit interpolation/decimation FIRs, integer latency compensation,
|
|
115
|
+
and higher-order AA remain unimplemented. This candidate closes the bounded
|
|
116
|
+
editable-LUT part of catalog §7 only; it does not establish a new oversampling
|
|
117
|
+
quality for existing `/drive` or arbitrary stateful graphs.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
{
|
|
2
|
+
"status": "NUMERICAL_DIAGNOSTIC_NOT_LISTENING_APPROVAL",
|
|
3
|
+
"sourceCommit": "2ada71cfdb785d8940dae2f655abda180ea7eeaa",
|
|
4
|
+
"engineWasmSHA256": "25202e821cecfc39de34a7c6e153d89091ff5b29db893856d22861370c21b6f1",
|
|
5
|
+
"method": "Simultaneous engine-internal fixed-buffer snapshots and downstream ScriptProcessor capture; separate run with internal capture only; separate ten-second native source. No thresholds changed. Recordings compared to independent feedback/biquad reference.",
|
|
6
|
+
"results": [
|
|
7
|
+
{
|
|
8
|
+
"mode": "paired",
|
|
9
|
+
"externalInput": {
|
|
10
|
+
"first": 7201,
|
|
11
|
+
"last": 198559,
|
|
12
|
+
"span": 191358,
|
|
13
|
+
"recurrenceMax": 0.09555476785926614,
|
|
14
|
+
"gaps": [
|
|
15
|
+
73728,
|
|
16
|
+
73729,
|
|
17
|
+
73856,
|
|
18
|
+
73857,
|
|
19
|
+
81920,
|
|
20
|
+
81921,
|
|
21
|
+
131200,
|
|
22
|
+
131201,
|
|
23
|
+
147456,
|
|
24
|
+
147457
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
"internalInput": {
|
|
28
|
+
"first": 7201,
|
|
29
|
+
"last": 199199,
|
|
30
|
+
"span": 191998,
|
|
31
|
+
"recurrenceMax": 1.7585315980131466e-07,
|
|
32
|
+
"gaps": []
|
|
33
|
+
},
|
|
34
|
+
"internalOracle": [
|
|
35
|
+
{
|
|
36
|
+
"ch": 0,
|
|
37
|
+
"max": 7.450580596923828e-09,
|
|
38
|
+
"first": -1
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"ch": 1,
|
|
42
|
+
"max": 0,
|
|
43
|
+
"first": -1
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"externalOracle": [
|
|
47
|
+
{
|
|
48
|
+
"ch": 0,
|
|
49
|
+
"max": 0.0973740704357624,
|
|
50
|
+
"first": 73728
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"ch": 1,
|
|
54
|
+
"max": 0.3697686046361923,
|
|
55
|
+
"first": 73728
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"alignmentOffset": 0,
|
|
59
|
+
"externalVsInternal": [
|
|
60
|
+
{
|
|
61
|
+
"ch": 0,
|
|
62
|
+
"max": 0.09630811214447021,
|
|
63
|
+
"first": 73728
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"ch": 1,
|
|
67
|
+
"max": 0.05186933092772961,
|
|
68
|
+
"first": 73728
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"ch": 2,
|
|
72
|
+
"max": 0.2157386764883995,
|
|
73
|
+
"first": 73728
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"mode": "internal",
|
|
79
|
+
"externalInput": {
|
|
80
|
+
"first": -1,
|
|
81
|
+
"last": -1,
|
|
82
|
+
"span": 0,
|
|
83
|
+
"recurrenceMax": 0,
|
|
84
|
+
"gaps": []
|
|
85
|
+
},
|
|
86
|
+
"internalInput": {
|
|
87
|
+
"first": 7201,
|
|
88
|
+
"last": 199199,
|
|
89
|
+
"span": 191998,
|
|
90
|
+
"recurrenceMax": 1.7585315980131466e-07,
|
|
91
|
+
"gaps": []
|
|
92
|
+
},
|
|
93
|
+
"internalOracle": [
|
|
94
|
+
{
|
|
95
|
+
"ch": 0,
|
|
96
|
+
"max": 7.450580596923828e-09,
|
|
97
|
+
"first": -1
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"ch": 1,
|
|
101
|
+
"max": 0,
|
|
102
|
+
"first": -1
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"mode": "native",
|
|
108
|
+
"externalInput": {
|
|
109
|
+
"first": 7201,
|
|
110
|
+
"last": 487199,
|
|
111
|
+
"span": 479998,
|
|
112
|
+
"recurrenceMax": 1.795446433333625e-07,
|
|
113
|
+
"gaps": []
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
],
|
|
117
|
+
"fileSHA256": {
|
|
118
|
+
"native-external-2.f32le": "c33ce044995ae068c9ec702bf90499a3f0ff0f737415aabef23e324e1487ce2f",
|
|
119
|
+
"native-external-1.f32le": "c33ce044995ae068c9ec702bf90499a3f0ff0f737415aabef23e324e1487ce2f",
|
|
120
|
+
"native-external-0.f32le": "c33ce044995ae068c9ec702bf90499a3f0ff0f737415aabef23e324e1487ce2f",
|
|
121
|
+
"internal-capturedRight.f32le": "da393ab21b1351f79886509730ba257baf90826b3ce3773e66b6b1be26deb2de",
|
|
122
|
+
"internal-capturedLeft.f32le": "9340b04f14ec1b10cf470ced283be59f421bb29218ffae29e10bb1f07d72b0b2",
|
|
123
|
+
"internal-capturedInput.f32le": "041f4c9538b9a1871bfef691105315c168287630ab662daab2c3a1d278d91d45",
|
|
124
|
+
"internal-external-2.f32le": "5647f05ec18958947d32874eeb788fa396a05d0bab7c1b71f112ceb7e9b31eee",
|
|
125
|
+
"internal-external-1.f32le": "5647f05ec18958947d32874eeb788fa396a05d0bab7c1b71f112ceb7e9b31eee",
|
|
126
|
+
"internal-external-0.f32le": "5647f05ec18958947d32874eeb788fa396a05d0bab7c1b71f112ceb7e9b31eee",
|
|
127
|
+
"paired-capturedRight.f32le": "da393ab21b1351f79886509730ba257baf90826b3ce3773e66b6b1be26deb2de",
|
|
128
|
+
"paired-capturedLeft.f32le": "9340b04f14ec1b10cf470ced283be59f421bb29218ffae29e10bb1f07d72b0b2",
|
|
129
|
+
"paired-capturedInput.f32le": "041f4c9538b9a1871bfef691105315c168287630ab662daab2c3a1d278d91d45",
|
|
130
|
+
"paired-external-2.f32le": "f658b8375c49984cf924067a88048d9817a263fe6469612b0169a744e5dff12f",
|
|
131
|
+
"paired-external-1.f32le": "f93c655f9ba42e80bd9b2bf7db1d5aa83ebcd822219b8f80196fa9fd8929492a",
|
|
132
|
+
"paired-external-0.f32le": "9d7567d989e6563813433dd71752d6bd680dc754855d88f6bff02a92927e101c"
|
|
133
|
+
}
|
|
134
|
+
}
|