@denaudio/den 0.0.0-stage → 0.2.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.
Files changed (191) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/LICENSE-APACHE +202 -0
  3. package/LICENSE-MIT +21 -0
  4. package/README.md +107 -2
  5. package/dist/biquad-eq.d.ts +11 -0
  6. package/dist/biquad-eq.js +35 -0
  7. package/dist/catalog-filter-math.d.ts +4 -0
  8. package/dist/catalog-filter-math.js +30 -0
  9. package/dist/character-filter.d.ts +13 -0
  10. package/dist/character-filter.js +53 -0
  11. package/dist/convolution-spectrum.d.ts +25 -0
  12. package/dist/convolution-spectrum.js +82 -0
  13. package/dist/convolution.d.ts +17 -0
  14. package/dist/convolution.js +87 -0
  15. package/dist/crossover.d.ts +11 -0
  16. package/dist/crossover.js +17 -0
  17. package/dist/curve-shaper.d.ts +26 -0
  18. package/dist/curve-shaper.js +73 -0
  19. package/dist/delay-fx.d.ts +37 -0
  20. package/dist/delay-fx.js +84 -0
  21. package/dist/delay-readhead.d.ts +19 -0
  22. package/dist/delay-readhead.js +54 -0
  23. package/dist/delay-settings.d.ts +55 -0
  24. package/dist/delay-settings.js +20 -0
  25. package/dist/drive.d.ts +24 -0
  26. package/dist/drive.js +116 -0
  27. package/dist/dual-head-delay.d.ts +28 -0
  28. package/dist/dual-head-delay.js +77 -0
  29. package/dist/dynamics.d.ts +61 -0
  30. package/dist/dynamics.js +130 -0
  31. package/dist/envelope.d.ts +34 -0
  32. package/dist/envelope.js +62 -0
  33. package/dist/filter.d.ts +9 -0
  34. package/dist/filter.js +34 -0
  35. package/dist/filterbank-vocoder.d.ts +35 -0
  36. package/dist/filterbank-vocoder.js +52 -0
  37. package/dist/formant-bank.d.ts +15 -0
  38. package/dist/formant-bank.js +28 -0
  39. package/dist/freeze-reverb.d.ts +35 -0
  40. package/dist/freeze-reverb.js +61 -0
  41. package/dist/frequency-shifter.d.ts +24 -0
  42. package/dist/frequency-shifter.js +57 -0
  43. package/dist/gate.d.ts +2 -0
  44. package/dist/gate.js +12 -0
  45. package/dist/index.d.ts +7 -0
  46. package/dist/index.js +12 -0
  47. package/dist/instrument-example.d.ts +12 -0
  48. package/dist/instrument-example.js +29 -0
  49. package/dist/instrument-settings.d.ts +95 -0
  50. package/dist/instrument-settings.js +36 -0
  51. package/dist/instrument.d.ts +42 -0
  52. package/dist/instrument.js +166 -0
  53. package/dist/lfo.d.ts +19 -0
  54. package/dist/lfo.js +55 -0
  55. package/dist/live-buffer.d.ts +39 -0
  56. package/dist/live-buffer.js +52 -0
  57. package/dist/live-granular.d.ts +41 -0
  58. package/dist/live-granular.js +64 -0
  59. package/dist/lookahead-limiter.d.ts +31 -0
  60. package/dist/lookahead-limiter.js +67 -0
  61. package/dist/loop-crossfade.d.ts +28 -0
  62. package/dist/loop-crossfade.js +72 -0
  63. package/dist/modulation-fx.d.ts +47 -0
  64. package/dist/modulation-fx.js +58 -0
  65. package/dist/modulation.d.ts +132 -0
  66. package/dist/modulation.js +228 -0
  67. package/dist/mpe-expression.d.ts +36 -0
  68. package/dist/mpe-expression.js +73 -0
  69. package/dist/multiband-dynamics.d.ts +50 -0
  70. package/dist/multiband-dynamics.js +60 -0
  71. package/dist/musical-controls.d.ts +76 -0
  72. package/dist/musical-controls.js +125 -0
  73. package/dist/musical-examples.d.ts +21 -0
  74. package/dist/musical-examples.js +142 -0
  75. package/dist/musical-materials.d.ts +110 -0
  76. package/dist/musical-materials.js +56 -0
  77. package/dist/oscillator.d.ts +10 -0
  78. package/dist/oscillator.js +35 -0
  79. package/dist/oversampled-drive.d.ts +19 -0
  80. package/dist/oversampled-drive.js +99 -0
  81. package/dist/performance.d.ts +61 -0
  82. package/dist/performance.js +241 -0
  83. package/dist/pitch-quantizer.d.ts +26 -0
  84. package/dist/pitch-quantizer.js +88 -0
  85. package/dist/prepared-convolution.d.ts +26 -0
  86. package/dist/prepared-convolution.js +104 -0
  87. package/dist/resident-recorder.d.ts +28 -0
  88. package/dist/resident-recorder.js +68 -0
  89. package/dist/resident-time-stretch.d.ts +46 -0
  90. package/dist/resident-time-stretch.js +136 -0
  91. package/dist/resonator.d.ts +32 -0
  92. package/dist/resonator.js +63 -0
  93. package/dist/reverb.d.ts +27 -0
  94. package/dist/reverb.js +52 -0
  95. package/dist/sample.d.ts +113 -0
  96. package/dist/sample.js +212 -0
  97. package/dist/source.d.ts +58 -0
  98. package/dist/source.js +113 -0
  99. package/dist/spatial-chains.d.ts +50 -0
  100. package/dist/spatial-chains.js +76 -0
  101. package/dist/spectral-fft.d.ts +27 -0
  102. package/dist/spectral-fft.js +84 -0
  103. package/dist/spectral-freeze.d.ts +24 -0
  104. package/dist/spectral-freeze.js +74 -0
  105. package/dist/spectral-gate.d.ts +23 -0
  106. package/dist/spectral-gate.js +58 -0
  107. package/dist/spectral-stft.d.ts +14 -0
  108. package/dist/spectral-stft.js +70 -0
  109. package/dist/spectral-texture.d.ts +46 -0
  110. package/dist/spectral-texture.js +141 -0
  111. package/dist/spectral.d.ts +18 -0
  112. package/dist/spectral.js +10 -0
  113. package/dist/state-variable-filter.d.ts +17 -0
  114. package/dist/state-variable-filter.js +25 -0
  115. package/dist/stereo-delay.d.ts +45 -0
  116. package/dist/stereo-delay.js +70 -0
  117. package/dist/virtual-analog.d.ts +26 -0
  118. package/dist/virtual-analog.js +66 -0
  119. package/dist/voice-policy.d.ts +37 -0
  120. package/dist/voice-policy.js +245 -0
  121. package/dist/wavetable-bands.d.ts +37 -0
  122. package/dist/wavetable-bands.js +145 -0
  123. package/dist/wavetable-read.d.ts +6 -0
  124. package/dist/wavetable-read.js +11 -0
  125. package/dist/wavetable.d.ts +29 -0
  126. package/dist/wavetable.js +49 -0
  127. package/dist/windowed-pitch-shift.d.ts +34 -0
  128. package/dist/windowed-pitch-shift.js +51 -0
  129. package/docs/catalog-audition.md +76 -0
  130. package/docs/catalog-filters.md +125 -0
  131. package/docs/catalog-modulation-fx.md +220 -0
  132. package/docs/catalog-status.md +433 -0
  133. package/docs/character-filter.md +139 -0
  134. package/docs/contracts.md +141 -0
  135. package/docs/control-modulation.md +194 -0
  136. package/docs/convolution.md +50 -0
  137. package/docs/curve-shaper.md +117 -0
  138. package/docs/delay-fx-capture-findings.json +134 -0
  139. package/docs/delay-fx.md +202 -0
  140. package/docs/delay-readhead.md +121 -0
  141. package/docs/delay-settings-candidate.json +333 -0
  142. package/docs/delay-settings.md +111 -0
  143. package/docs/dependency-findings.md +58 -0
  144. package/docs/deployment-status.md +37 -0
  145. package/docs/drive.md +152 -0
  146. package/docs/dual-head-delay.md +131 -0
  147. package/docs/dynamics.md +180 -0
  148. package/docs/envelope-integer-staging.md +64 -0
  149. package/docs/filter-materialization-results.json +71 -0
  150. package/docs/filter-materialization.md +135 -0
  151. package/docs/filter-oscillator.md +126 -0
  152. package/docs/filterbank-vocoder-entry.md +58 -0
  153. package/docs/freeze-reverb.md +179 -0
  154. package/docs/frequency-shifter.md +133 -0
  155. package/docs/frontend-audition.md +22 -0
  156. package/docs/gain-schedule-verification.md +53 -0
  157. package/docs/initial-acceptance.md +79 -0
  158. package/docs/instrument-performance.md +191 -0
  159. package/docs/instrument-settings.md +130 -0
  160. package/docs/instrument.md +204 -0
  161. package/docs/integration-candidate.md +114 -0
  162. package/docs/live-buffer.md +163 -0
  163. package/docs/live-granular.md +179 -0
  164. package/docs/lookahead-multiband.md +183 -0
  165. package/docs/loop-crossfade.md +99 -0
  166. package/docs/mpe-expression.md +65 -0
  167. package/docs/musical-clock-seek-boundary.md +31 -0
  168. package/docs/musical-controls-contract.md +144 -0
  169. package/docs/musical-examples.md +255 -0
  170. package/docs/oversampled-drive.md +153 -0
  171. package/docs/performance.md +53 -0
  172. package/docs/pitch-quantizer.md +55 -0
  173. package/docs/prepared-convolution.md +197 -0
  174. package/docs/realtime-audition.md +63 -0
  175. package/docs/resident-recorder.md +151 -0
  176. package/docs/resident-time-stretch.md +196 -0
  177. package/docs/sample.md +191 -0
  178. package/docs/sound-audition-headroom.md +103 -0
  179. package/docs/sources.md +81 -0
  180. package/docs/spatial-chains-entry.md +251 -0
  181. package/docs/spectral-freeze-entry.md +132 -0
  182. package/docs/spectral-gate-entry.md +134 -0
  183. package/docs/spectral-large-candidate.md +81 -0
  184. package/docs/spectral-texture-entry.md +178 -0
  185. package/docs/spectral.md +127 -0
  186. package/docs/virtual-analog.md +77 -0
  187. package/docs/voice-policy.md +38 -0
  188. package/docs/wavetable-bands.md +138 -0
  189. package/docs/wavetable.md +101 -0
  190. package/docs/windowed-pitch-shift.md +112 -0
  191. package/package.json +269 -4
@@ -0,0 +1,141 @@
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
+ The current package uses unworklet **0.6.0**. Its entry gate renders in real
11
+ Chromium at 44.1/48/96 kHz, and snapshots include current AudioParam values even
12
+ before rendering or while suspended. The 0.4.1 rate restriction and suspended-edit
13
+ workaround below are historical. Incompatible slot types are now skipped instead
14
+ of reinterpreted; live restore applies saved AudioParams before persistent state.
15
+ See [dependency findings](dependency-findings.md) for the checked regressions and
16
+ remaining constraints. Snapshots still require the same processor/schema, sample
17
+ rate and render quantum; this upgrade does not imply general automation rollback,
18
+ cross-target migration, transient-state clearing or human audio approval.
19
+
20
+ ## Authority and provisional choices
21
+
22
+ The approved initial-scope specification says that individual DSP methods and
23
+ numeric upper bounds are not yet determined. GEN-610 asks the entry work to make
24
+ those boundaries concrete for review; it does not approve a particular voice
25
+ count, delay capacity, filter law, or musical behavior.
26
+
27
+ The numbers and engine policies below are **provisional implementation proposals**,
28
+ not user-approved product limits or tested defaults. In particular:
29
+
30
+ - **16 voice slots** is a candidate starting capacity for testing chord overlap,
31
+ release reuse, and deterministic stealing. It is not derived from a measured
32
+ CPU/memory budget. GEN-616 must select/benchmark capacity and expose it as fixed
33
+ construction configuration, rather than assuming 16 is a product-wide ceiling.
34
+ - **Two seconds per delay channel** is a candidate starting allocation for short
35
+ effects and delay fixtures. At 96 kHz, stereo f32 buffers with two guard samples
36
+ use 1,536,016 bytes. This is not a validated product memory budget. A whole note
37
+ at 30 BPM requires eight seconds, so the candidate capacity does not cover all
38
+ rhythmic settings. GEN-615/GEN-620 must jointly choose capacity and explicit
39
+ out-of-capacity behavior; silent tempo-time clamping is not accepted as correct
40
+ rhythmic playback. Keep maximum delay as fixed construction configuration.
41
+ - All other stated ranges, signal shapes, voice priorities, interpolation,
42
+ feedback/mix, and bypass policies have the same provisional status. Later lanes
43
+ must validate or revise them with independent numerical evidence and review.
44
+ Review-approved code decisions still do not imply human sound approval.
45
+
46
+ The gate proves only the public package/subgraph boundary, mono one-sample memory,
47
+ linear gain [0,1], actual parameter edits, and same-schema snapshot continuation.
48
+ It contains no 16-voice allocation or two-second delay implementation. DSP lanes
49
+ can propose revisions without seeking a new product decision for every engineering
50
+ choice, but must coordinate changes that affect shared consumers/contracts.
51
+
52
+ ## Composition and state
53
+
54
+ - One ESM package, `@denaudio/den`; current exports are `gateCell` at the root and
55
+ `gate` at `/gate`. Subsequent module exports require integration review.
56
+ - Reusable DSP is an existing `defineSubgraph` declaration. Use required config
57
+ arguments (no default parameter), and `instantiate(unit, config, {name})` with
58
+ stable, unique instance names. Audio-rate inputs/outputs use unworklet
59
+ `Node<'f32'>`; boolean controls use `Node<'bool'>`. No custom graph or routing API.
60
+ - Configuration is immutable per instantiation: sample rate, fixed capacities,
61
+ selected DSP mode. Continuous controls use existing a-rate AudioParams and
62
+ graph inputs. No den parameter registry or preset format.
63
+ - Internal phase, history, and buffers use unworklet state. Persistent slots have
64
+ stable names/types; use existing snapshot profiles, codec, and migration APIs.
65
+ Gate restoration is verified only for the identical processor/schema and rate.
66
+ Never treat same byte width as type compatibility (#79). A schema change needs
67
+ an explicit reviewed migration and its own tests before old snapshots are used.
68
+ - Native transient state is excluded from snapshots, not automatically reset by
69
+ an in-place restore. Fresh-driver offline restore starts from declaration
70
+ defaults; browser `node.restore()` leaves current excluded notes/controllers
71
+ unchanged. A cold live restore requires the composition's explicit reset,
72
+ followed by a rendered quantum before fresh notes. Do not infer live clearing
73
+ from fresh-instance offline evidence.
74
+ - Save after AudioParam edits have actually rendered, while controls are stable
75
+ (#78). A suspended snapshot is not a reliable capture of pending edits in 0.4.1.
76
+ This gate does not solve suspended preset editing or in-flight automation recall.
77
+ - Live `node.restore()` in core 0.4.1 is not an atomic state/AudioParam transaction.
78
+ The worklet copies persistent slots before acknowledging; only then does the
79
+ host restore AudioParam values. A running quantum can use restored history with
80
+ old controls. For the frozen-tail composition, first set every saved control,
81
+ confirm those values have rendered (including completed freeze transition),
82
+ then restore history while controls remain stable. This is a scoped caller
83
+ protocol, not a generic atomic-restore API or a guarantee for arbitrary graphs,
84
+ automation, external inputs or pending events. See [freeze restore](freeze-reverb.md#live-browser-restore-ordering).
85
+ - Worklet compilation is sample-rate-specific. Offline rendering is verified at
86
+ 44100, 48000, and 96000 Hz, with 128-frame quanta. The existing 0.4.1 Vite plugin
87
+ compiles at 48000 and exposes no sample-rate option; real browser contexts at
88
+ 44100/96000 are verified to reject creation. Browser rendering is proven only
89
+ at 48000. Non-48-kHz browser loading remains an upstream limitation, not a requirement
90
+ of this entry gate and not a blocker for den development. Do not bypass the
91
+ mismatch guard or claim multi-rate browser readiness. The supported browser
92
+ scope is explicitly 48 kHz; offline multi-rate coverage is separate.
93
+ - State allocation is fixed at graph creation. No dynamic audio-thread allocation.
94
+ Reset uses existing node/event control, clears histories/voices/phase immediately
95
+ at its dispatched sample, and may create a discontinuity. Reset is not bypass.
96
+
97
+ ## Module boundaries and provisional defaults
98
+
99
+ | Lane | Graph boundary and units | Proposed policy for first integration |
100
+ | --- | --- | --- |
101
+ | 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. |
102
+ | 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. |
103
+ | 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. |
104
+ | 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. |
105
+ | 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. |
106
+ | 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. |
107
+
108
+ Methods and exported types for unfinished modules are deliberately not stubbed:
109
+ use each lane's own tested unworklet subgraph with reviewed boundaries, then bring
110
+ public exports through integration review. `tests/consumer/contract.ts` demonstrates
111
+ composition from the packed public entry. The small gate's actual `tick(input,
112
+ gain)` is solely a packaging example, not an imposed interface for every module.
113
+
114
+ ## Engine integration targets
115
+
116
+ One instrument: existing MIDI input `midi`, stereo audio output `main`, mono DSP
117
+ per voice feeding equal L/R initially; amp and velocity gains are linear, no
118
+ limiter or automatic loudness normalization. Mono/poly is immutable configuration
119
+ for the first engine. Voice stealing hard-retriggers from current envelope level;
120
+ its click behavior needs numerical and listening evidence before sound approval.
121
+
122
+ One stereo delay: audio input/output `main`; mono callers duplicate L/R explicitly.
123
+ Feedback gain [0,0.95], low-pass tone in the feedback path, dry/wet linear crossfade
124
+ [0,1]. Input stop preserves decay. Bypass emits unity dry only, feeds zero new input
125
+ to delay, and lets internal feedback decay; unbypass can expose a remaining tail.
126
+ Reset clears that tail immediately. BPM [30,300], note durations converted to
127
+ seconds; out-of-capacity behavior remains a joint read-head/tempo decision and
128
+ must not silently alter a requested rhythm. Tempo changes provisionally use the
129
+ same moving-head policy.
130
+ Feedback stability and stereo/tempo details are later integration tasks, not claims
131
+ established by this one-sample gate.
132
+
133
+ ## Acceptance each lane must supply
134
+
135
+ Use unworklet offline rendering and existing test helpers after checking their
136
+ behavior. Provide independent formulas/reference oracles, endpoint and modulation
137
+ cases, sample-rate/capacity boundaries, reset tests, and exact input/settings.
138
+ No expected waveform may be copied from the implementation as its correctness
139
+ oracle. Counterexamples must fail. Human hearing can remain pending independently
140
+ of code/numerical work; artifacts stay candidates. Envelope/LFO/filter/oscillator/
141
+ 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,50 @@
1
+ # Bounded uniform convolution candidate
2
+
3
+ `partitionedConvolution({ blockSize, impulse, renderQuantumSize: ctx.renderQuantumSize }).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
+ - Pass `ctx.renderQuantumSize` from the enclosing processor. Dispatch runs every
13
+ `gcd(B, renderQuantumSize)` samples, and the persistent cursor commits only at
14
+ true B-sample boundaries. This preserves block-atomic snapshot phase even when
15
+ the quantum does not divide B. Off-phase work is eager; small or coprime
16
+ quanta increase cost and do not gain realtime clearance.
17
+ - B is a construction-fixed power of two in 4..32; N=2B. The original/fixed IR has
18
+ 1..4B taps, each finite in [-1,1], and sum of absolute tap values <=4. Input is
19
+ finite normalized audio [-1,1]; output is not clipped or gain-normalized.
20
+ - The IR is split into at most four B-sample partitions, each zero-padded to N.
21
+ Its complex spectra are calculated from the DFT formula at graph construction.
22
+ Runtime uses the internal radix-2 FFT, frequency-delay line, complex products,
23
+ normalized IFFT and overlap-add. No dependency, loader, alternate runtime,
24
+ dynamic allocation, runtime IR update or new snapshot system is introduced.
25
+ - At sample t=mB, the previous input block [t-B,t) is transformed. For output
26
+ block m the spectral sum is Σ H_p X_(m-p), then its 2B time samples are added
27
+ to [t,t+2B). Algorithmic latency is exactly B samples. The IR's own leading
28
+ zeros/predelay and tail of L-1 samples are additional, separate properties.
29
+ - Reset immediately outputs zero, discards its input sample and pre-reset tail,
30
+ invalidates history and earlier partitions, and preserves native hop phase.
31
+ The partial first block after reset is zero-padded before the reset boundary.
32
+ Held reset remains silent. Flush with B+L-1 zero samples to hear the full tail.
33
+ - Fixed f64 buffers use exact 2^128 scaling for input/history/spectra, avoiding
34
+ 0.4.1's 1e-30 buffer-write flush discarding f32 subnormal audio. IR coefficients
35
+ are double constants. No treatment of arbitrary nonfinite inputs is promised.
36
+ - Persistent history, overlap, spectra and indices use native full snapshots.
37
+ FFT/mixed-spectrum scratch is transient and rewritten before use. Same graph
38
+ and rate/quantum are required. Changing IR/configuration requires a new graph; no
39
+ migration, IR swap, crossfade, stereo adapter or long-room support is implied.
40
+
41
+ ## Required evidence
42
+
43
+ Three-rate direct time-domain FIR comparison covers one tap, partial final
44
+ partitions, all partition counts, taps at partition boundaries, random original
45
+ IRs, impulse/full tail, all reset hop phases, zero IR and linearity. Snapshot
46
+ continuation must be bit-identical, no output scrub is accepted, and instance
47
+ memory must stay fixed. Packed consumer and generated-worklet checks remain
48
+ separate gates. Measured local cold/warm quantum costs are diagnostic only.
49
+ The shared N64 FFT/STFT proof measured a 298-ms cold first quantum locally;
50
+ 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
+ }