@vessel-dsp/compiler 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.
- package/README.md +314 -2
- package/dist/bake.d.ts +38 -0
- package/dist/bake.d.ts.map +1 -0
- package/dist/bake.js +101 -0
- package/dist/bake.js.map +1 -0
- package/dist/bbd-clock.d.ts +171 -0
- package/dist/bbd-clock.d.ts.map +1 -0
- package/dist/bbd-clock.js +1750 -0
- package/dist/bbd-clock.js.map +1 -0
- package/dist/block-row.d.ts +51 -0
- package/dist/block-row.d.ts.map +1 -0
- package/dist/block-row.js +17 -0
- package/dist/block-row.js.map +1 -0
- package/dist/bypass.d.ts +3 -0
- package/dist/bypass.d.ts.map +1 -0
- package/dist/bypass.js +228 -0
- package/dist/bypass.js.map +1 -0
- package/dist/compile.d.ts +24 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +344 -0
- package/dist/compile.js.map +1 -0
- package/dist/converter-scale.d.ts +14 -0
- package/dist/converter-scale.d.ts.map +1 -0
- package/dist/converter-scale.js +133 -0
- package/dist/converter-scale.js.map +1 -0
- package/dist/couple.d.ts +28 -0
- package/dist/couple.d.ts.map +1 -0
- package/dist/couple.js +567 -0
- package/dist/couple.js.map +1 -0
- package/dist/dangling-active-terminal.d.ts +47 -0
- package/dist/dangling-active-terminal.d.ts.map +1 -0
- package/dist/dangling-active-terminal.js +542 -0
- package/dist/dangling-active-terminal.js.map +1 -0
- package/dist/declared-program.d.ts +23 -0
- package/dist/declared-program.d.ts.map +1 -0
- package/dist/declared-program.js +387 -0
- package/dist/declared-program.js.map +1 -0
- package/dist/denomination.d.ts +48 -0
- package/dist/denomination.d.ts.map +1 -0
- package/dist/denomination.js +27 -0
- package/dist/denomination.js.map +1 -0
- package/dist/device-laws.d.ts +237 -0
- package/dist/device-laws.d.ts.map +1 -0
- package/dist/device-laws.js +3497 -0
- package/dist/device-laws.js.map +1 -0
- package/dist/diagnostics.d.ts +13 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +19 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/emit.d.ts +8 -0
- package/dist/emit.d.ts.map +1 -0
- package/dist/emit.js +43 -0
- package/dist/emit.js.map +1 -0
- package/dist/errors.d.ts +22 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +39 -0
- package/dist/errors.js.map +1 -0
- package/dist/firmware-class.d.ts +69 -0
- package/dist/firmware-class.d.ts.map +1 -0
- package/dist/firmware-class.js +20 -0
- package/dist/firmware-class.js.map +1 -0
- package/dist/fixtures/circuits.d.ts +1721 -0
- package/dist/fixtures/circuits.d.ts.map +1 -0
- package/dist/fixtures/circuits.js +13404 -0
- package/dist/fixtures/circuits.js.map +1 -0
- package/dist/fixtures/expected.d.ts +257 -0
- package/dist/fixtures/expected.d.ts.map +1 -0
- package/dist/fixtures/expected.js +311 -0
- package/dist/fixtures/expected.js.map +1 -0
- package/dist/fixtures/index.d.ts +4 -0
- package/dist/fixtures/index.d.ts.map +1 -0
- package/dist/fixtures/index.js +8 -0
- package/dist/fixtures/index.js.map +1 -0
- package/dist/fixtures/registry.d.ts +52 -0
- package/dist/fixtures/registry.d.ts.map +1 -0
- package/dist/fixtures/registry.js +341 -0
- package/dist/fixtures/registry.js.map +1 -0
- package/dist/generic-tube-fit.d.ts +12 -0
- package/dist/generic-tube-fit.d.ts.map +1 -0
- package/dist/generic-tube-fit.js +45 -0
- package/dist/generic-tube-fit.js.map +1 -0
- package/dist/grounded-clock-supply.d.ts +13 -0
- package/dist/grounded-clock-supply.d.ts.map +1 -0
- package/dist/grounded-clock-supply.js +45 -0
- package/dist/grounded-clock-supply.js.map +1 -0
- package/dist/identify.d.ts +50 -0
- package/dist/identify.d.ts.map +1 -0
- package/dist/identify.js +319 -0
- package/dist/identify.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/inert-controls.d.ts +15 -0
- package/dist/inert-controls.d.ts.map +1 -0
- package/dist/inert-controls.js +266 -0
- package/dist/inert-controls.js.map +1 -0
- package/dist/latch-seed.d.ts +53 -0
- package/dist/latch-seed.d.ts.map +1 -0
- package/dist/latch-seed.js +257 -0
- package/dist/latch-seed.js.map +1 -0
- package/dist/link.d.ts +7 -0
- package/dist/link.d.ts.map +1 -0
- package/dist/link.js +270 -0
- package/dist/link.js.map +1 -0
- package/dist/lower.d.ts +79 -0
- package/dist/lower.d.ts.map +1 -0
- package/dist/lower.js +1855 -0
- package/dist/lower.js.map +1 -0
- package/dist/netlist.d.ts +79 -0
- package/dist/netlist.d.ts.map +1 -0
- package/dist/netlist.js +4746 -0
- package/dist/netlist.js.map +1 -0
- package/dist/non-executable-clock-drivers.d.ts +8 -0
- package/dist/non-executable-clock-drivers.d.ts.map +1 -0
- package/dist/non-executable-clock-drivers.js +33 -0
- package/dist/non-executable-clock-drivers.js.map +1 -0
- package/dist/open-category.d.ts +98 -0
- package/dist/open-category.d.ts.map +1 -0
- package/dist/open-category.js +111 -0
- package/dist/open-category.js.map +1 -0
- package/dist/over-driven-node.d.ts +33 -0
- package/dist/over-driven-node.d.ts.map +1 -0
- package/dist/over-driven-node.js +188 -0
- package/dist/over-driven-node.js.map +1 -0
- package/dist/part-catalog.d.ts +7 -0
- package/dist/part-catalog.d.ts.map +1 -0
- package/dist/part-catalog.js +6639 -0
- package/dist/part-catalog.js.map +1 -0
- package/dist/part-number.d.ts +32 -0
- package/dist/part-number.d.ts.map +1 -0
- package/dist/part-number.js +80 -0
- package/dist/part-number.js.map +1 -0
- package/dist/partition.d.ts +7 -0
- package/dist/partition.d.ts.map +1 -0
- package/dist/partition.js +242 -0
- package/dist/partition.js.map +1 -0
- package/dist/port-full-scale.d.ts +70 -0
- package/dist/port-full-scale.d.ts.map +1 -0
- package/dist/port-full-scale.js +235 -0
- package/dist/port-full-scale.js.map +1 -0
- package/dist/pot-orientation.d.ts +114 -0
- package/dist/pot-orientation.d.ts.map +1 -0
- package/dist/pot-orientation.js +551 -0
- package/dist/pot-orientation.js.map +1 -0
- package/dist/power-domain-control.d.ts +40 -0
- package/dist/power-domain-control.d.ts.map +1 -0
- package/dist/power-domain-control.js +142 -0
- package/dist/power-domain-control.js.map +1 -0
- package/dist/proxy-declaration.d.ts +121 -0
- package/dist/proxy-declaration.d.ts.map +1 -0
- package/dist/proxy-declaration.js +50 -0
- package/dist/proxy-declaration.js.map +1 -0
- package/dist/registry.d.ts +323 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +192 -0
- package/dist/registry.js.map +1 -0
- package/dist/sparse-schedule.d.ts +65 -0
- package/dist/sparse-schedule.d.ts.map +1 -0
- package/dist/sparse-schedule.js +421 -0
- package/dist/sparse-schedule.js.map +1 -0
- package/dist/speaker-load.d.ts +38 -0
- package/dist/speaker-load.d.ts.map +1 -0
- package/dist/speaker-load.js +97 -0
- package/dist/speaker-load.js.map +1 -0
- package/dist/stage-coverage.d.ts +21 -0
- package/dist/stage-coverage.d.ts.map +1 -0
- package/dist/stage-coverage.js +124 -0
- package/dist/stage-coverage.js.map +1 -0
- package/dist/stamp-partition.d.ts +314 -0
- package/dist/stamp-partition.d.ts.map +1 -0
- package/dist/stamp-partition.js +472 -0
- package/dist/stamp-partition.js.map +1 -0
- package/dist/supply-reference.d.ts +19 -0
- package/dist/supply-reference.d.ts.map +1 -0
- package/dist/supply-reference.js +66 -0
- package/dist/supply-reference.js.map +1 -0
- package/dist/supply-short.d.ts +32 -0
- package/dist/supply-short.d.ts.map +1 -0
- package/dist/supply-short.js +118 -0
- package/dist/supply-short.js.map +1 -0
- package/dist/supply-stamps.d.ts +51 -0
- package/dist/supply-stamps.d.ts.map +1 -0
- package/dist/supply-stamps.js +363 -0
- package/dist/supply-stamps.js.map +1 -0
- package/dist/terminal-role.d.ts +109 -0
- package/dist/terminal-role.d.ts.map +1 -0
- package/dist/terminal-role.js +46 -0
- package/dist/terminal-role.js.map +1 -0
- package/dist/terminal-roles.d.ts +59 -0
- package/dist/terminal-roles.d.ts.map +1 -0
- package/dist/terminal-roles.js +92 -0
- package/dist/terminal-roles.js.map +1 -0
- package/dist/transformer.d.ts +181 -0
- package/dist/transformer.d.ts.map +1 -0
- package/dist/transformer.js +476 -0
- package/dist/transformer.js.map +1 -0
- package/dist/types.d.ts +3157 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -0
- package/dist/unbounded-operating-point.d.ts +35 -0
- package/dist/unbounded-operating-point.d.ts.map +1 -0
- package/dist/unbounded-operating-point.js +181 -0
- package/dist/unbounded-operating-point.js.map +1 -0
- package/dist/unexecuted-region.d.ts +3 -0
- package/dist/unexecuted-region.d.ts.map +1 -0
- package/dist/unexecuted-region.js +122 -0
- package/dist/unexecuted-region.js.map +1 -0
- package/dist/unimplemented-control-role.d.ts +3 -0
- package/dist/unimplemented-control-role.d.ts.map +1 -0
- package/dist/unimplemented-control-role.js +61 -0
- package/dist/unimplemented-control-role.js.map +1 -0
- package/dist/unreachable-output.d.ts +3 -0
- package/dist/unreachable-output.d.ts.map +1 -0
- package/dist/unreachable-output.js +97 -0
- package/dist/unreachable-output.js.map +1 -0
- package/dist/unreadable-terminal-role.d.ts +67 -0
- package/dist/unreadable-terminal-role.d.ts.map +1 -0
- package/dist/unreadable-terminal-role.js +409 -0
- package/dist/unreadable-terminal-role.js.map +1 -0
- package/dist/unverified-pinout.d.ts +27 -0
- package/dist/unverified-pinout.d.ts.map +1 -0
- package/dist/unverified-pinout.js +121 -0
- package/dist/unverified-pinout.js.map +1 -0
- package/package.json +75 -5
package/README.md
CHANGED
|
@@ -1,3 +1,315 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @vessel-dsp/compiler
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Headless circuit compiler turning `.vdsp` / `CircuitDocument` schematic data into compiled simulation `Program` ROMs for VesselDSP. Pure TypeScript, deterministic, rate independent, headless. It depends on `@vessel-dsp/core` and `js-yaml` only.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
`@vessel-dsp/compiler` 0.1.0 is not yet on npm. Until the release is published, use the package from this repository's workspace rather than an install command that will 404.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# once published:
|
|
11
|
+
bun add @vessel-dsp/compiler
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Minimal example
|
|
15
|
+
|
|
16
|
+
Compile takes `.vdsp` source text and an optional part registry. It returns a result, never a throw, for a document it cannot use.
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { readFileSync } from "node:fs";
|
|
20
|
+
import { compile, pedalPartCatalog } from "@vessel-dsp/compiler";
|
|
21
|
+
|
|
22
|
+
const source = readFileSync("big-muff-pi.vdsp", "utf8");
|
|
23
|
+
const result = compile(source, { registry: pedalPartCatalog });
|
|
24
|
+
|
|
25
|
+
if (result.status === "ok") {
|
|
26
|
+
console.log("Compiled program blocks:", result.program.blocks.length);
|
|
27
|
+
console.log("Warnings:", result.warnings.length);
|
|
28
|
+
} else {
|
|
29
|
+
console.error("Compilation refused:", result.reasons);
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```text
|
|
34
|
+
Compiled program blocks: 1
|
|
35
|
+
Warnings: 0
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Which registry to pass
|
|
39
|
+
|
|
40
|
+
`compile(source, options)` defaults to `emptyRegistry` when no registry is given. The empty registry models only device class laws (resistor, capacitor, plain op-amp stages) and refuses parts that need catalog identity. `pedalPartCatalog` is the corpus facing catalog injected by scripts and tests.
|
|
41
|
+
|
|
42
|
+
Measured over the 121 top level packets in the artifacts corpus (read only, not committed):
|
|
43
|
+
|
|
44
|
+
- `emptyRegistry`: 74 of 121 compile.
|
|
45
|
+
- `pedalPartCatalog`: 119 of 121 compile. The two refusals are `boss-dd-3t.vdsp` and `boss-dd-5.vdsp`.
|
|
46
|
+
|
|
47
|
+
Use `pedalPartCatalog` for real pedal packets. Use `emptyRegistry` only to measure what works with no part knowledge, or for synthetic device class probes.
|
|
48
|
+
|
|
49
|
+
One refusal shape, for `boss-dd-3t.vdsp` with `pedalPartCatalog`:
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
[{ "stage": "device-laws", "device": "U1",
|
|
53
|
+
"reason": "integrated circuit has no model: its part number
|
|
54
|
+
\"undisclosed-roland-boss-dsp\" matched no registry entry, and a declared
|
|
55
|
+
class may not supply a macro for a part whose identity is unresolved" }]
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Result shape
|
|
59
|
+
|
|
60
|
+
`compile` returns `CompileResult`:
|
|
61
|
+
|
|
62
|
+
- `{ status: "ok", program, warnings }`. Warnings never block a program. A pedal with a dead knob is still worth hearing, but it must not be silent about it.
|
|
63
|
+
- `{ status: "unsupported", reasons }`. Each reason is a `CompileRefusal` with `stage` (`netlist`, `device-laws`, `partition`, `lower`, or `link`), `device` (component id or null), and a human readable `reason`. `device-laws` means a part could not be modelled; any other stage means the document itself does not support a program.
|
|
64
|
+
|
|
65
|
+
Only a `StageRefusal` becomes a result. Anything else (a compiler bug) propagates as a throw, because a bug reported as an unsupported pedal would be a wrong answer about someone's circuit.
|
|
66
|
+
|
|
67
|
+
`compileToArtifact(source, options)` runs `compile` and pairs it with `emit`: `{ result, artifact }` where `artifact` is null unless the result is ok. `decode(text)` parses an artifact back into a `Program`.
|
|
68
|
+
|
|
69
|
+
`readNetlist(source, options?)` runs the first stage only: document text to a law free `Netlist` with `inputJack`/`outputJack` overrides and `parseQuantity` for SI values (`10k` to 10000).
|
|
70
|
+
|
|
71
|
+
## The Program
|
|
72
|
+
|
|
73
|
+
A `Program` is rate independent: it carries no sample rate. The runtime supplies the rate at `prepare()`. Top level keys:
|
|
74
|
+
|
|
75
|
+
`formatVersion` (always 1), `requiredOperators`, `requiredModels`, `costPredictors`, `blocks`, `order`, `controls`, `ports`, `supplyReference`, `portReferenceVolts`, `portFullScaleVolts`, `stageCoverage`, `portImpedanceOhms`.
|
|
76
|
+
|
|
77
|
+
`requiredOperators` lists every stamp operator the executed blocks present, sorted, so a runtime can refuse by name at load. `requiredModels` lists every macro DSP model id the same way. `order` is the block execution order. `supplyReference` is `negative-ground`, `positive-ground`, `dual-rail`, or `unpowered`, derived from `dc-source` signs. `stageCoverage` is `instrument`, `preamp`, `speaker-electrical`, or `miked`.
|
|
78
|
+
|
|
79
|
+
`big-muff-pi.vdsp` with `pedalPartCatalog` compiles to 1 block (`order: ["analog:0"]`) with stamp kinds `dc-source` 1, `bjt` 4, `conductance` 22, `capacitor` 13, `controlled-conductance` 6, `diode` 4, `input-source` 1. Controls are `IN`, `OUT`, `SUSTAIN`, `TONE`, `VOLUME`, each 0..1 with default 0.5.
|
|
80
|
+
|
|
81
|
+
Each `mna` block carries `nodeIds` (row to source node map), `auxCount`, `stamps`, `stampPartition`, `sparseSchedule`, `stateCount`, `linear`, `controlFree`, `eliminate`, input/output nodes, and operating point seeds. A `macro` block carries a DSP `modelId` with parameters instead of stamps.
|
|
82
|
+
|
|
83
|
+
## Supply stamps
|
|
84
|
+
|
|
85
|
+
`resolveSupplyStamps(source, program)` joins the document power domains to the compiled `dc-source` stamps. It takes the same source text the program was compiled from and returns `{ supplies, refused }`. Only rails in an external DC domain with `derivation: direct` and `role: main-supply` are candidates; derived rails (divider, regulator, inverter, doubler, isolated) keep their compiled values.
|
|
86
|
+
|
|
87
|
+
Measured over the same 121 packets with `pedalPartCatalog`: 54 packets resolve at least one supply. Refusals by entry: `derived-rail` 60, `no-power-section` 42, `no-stamp-for-rail` 17, `mains-ac-source` 7, `unknown-source-kind` 4, plus 2 packets that do not compile at all. `big-muff-pi` resolves `VPLUS_RAIL` with role `main-supply`.
|
|
88
|
+
|
|
89
|
+
The closed refusal reasons are `no-power-section`, `mains-ac-source`, `unknown-source-kind`, `source-kind-conflict`, `derived-rail`, `rail-not-main-supply`, `no-stamp-for-rail`, `ambiguous-stamp`. Callers switch on `reason`; `detail` is prose for a human report.
|
|
90
|
+
|
|
91
|
+
## Public exports
|
|
92
|
+
|
|
93
|
+
### Compile
|
|
94
|
+
|
|
95
|
+
| Name | What it is |
|
|
96
|
+
| --- | --- |
|
|
97
|
+
| `compile` | Compile, or explain the refusal. Never throws for a document it cannot use. |
|
|
98
|
+
| `compileToArtifact` | `compile` plus `emit`, paired as `{ result, artifact }`. |
|
|
99
|
+
| `CompileOptions` | `{ registry, inputJack, outputJack }`. |
|
|
100
|
+
| `CompileResult` | `CompileSuccess` or `CompileFailure`. |
|
|
101
|
+
| `CompileSuccess` | `{ status: "ok", program, warnings }`. |
|
|
102
|
+
| `CompileFailure` | `{ status: "unsupported", reasons }`. |
|
|
103
|
+
| `CompileRefusal` | `{ stage, device, reason }`. |
|
|
104
|
+
| `CompilerStage` | `netlist`, `partition`, `lower`, or `link`. |
|
|
105
|
+
| `StageRefusal` | Stage error that becomes a result instead of a throw. |
|
|
106
|
+
| `LoweringError` | A device declared with a terminal count lowering cannot stamp. |
|
|
107
|
+
| `NetlistError` | Netlist stage refusal. |
|
|
108
|
+
| `PartitionError` | Partition stage refusal. |
|
|
109
|
+
| `LinkError` | Link stage refusal. |
|
|
110
|
+
|
|
111
|
+
### Artifacts
|
|
112
|
+
|
|
113
|
+
| Name | What it is |
|
|
114
|
+
| --- | --- |
|
|
115
|
+
| `emit` | Render a `Program` to its serializable `Artifact`. |
|
|
116
|
+
| `decode` | Parse an artifact back into a `Program`. |
|
|
117
|
+
| `Artifact` | The serializable form of a compiled program. |
|
|
118
|
+
|
|
119
|
+
### Netlist
|
|
120
|
+
|
|
121
|
+
| Name | What it is |
|
|
122
|
+
| --- | --- |
|
|
123
|
+
| `readNetlist` | First stage only: source text to a law free `Netlist`. |
|
|
124
|
+
| `ReadNetlistOptions` | `{ inputJack, outputJack }` overrides. |
|
|
125
|
+
| `Netlist` | Devices, controls, ports, and port metadata before laws attach. |
|
|
126
|
+
| `Device` | One lowered device with kind, identity, terminals, and parameters. |
|
|
127
|
+
| `DeviceId` | Component id string. |
|
|
128
|
+
| `DeviceKind` | What a device is electrically (resistor through power-amp, plus sources, rails, gates, BBD, compandor). |
|
|
129
|
+
| `DeviceIdentity` | Evidence a part is recognised by, in stage 2 order. |
|
|
130
|
+
| `DeviceLaw` | A lumped constitutive relation the solver can stamp. |
|
|
131
|
+
| `DeviceResolution` | Per device law outcome, including unsupported with reason. |
|
|
132
|
+
| `LawedNetlist` | Netlist plus per device resolutions. |
|
|
133
|
+
| `parseQuantity` | Parse a quantity to SI base units (`10k` to 10000). |
|
|
134
|
+
| `dcConductingKinds` | DC conducting device kinds, for asking whether a node potential is generated. |
|
|
135
|
+
| `deviceCountByNode` | How many devices touch each node. |
|
|
136
|
+
| `DeclaredWinding` | One declared coil: role, name, terminals in coil order. |
|
|
137
|
+
| `DeclaredWindingImpedance` | One rated coil impedance in ohms. |
|
|
138
|
+
|
|
139
|
+
### Registries
|
|
140
|
+
|
|
141
|
+
| Name | What it is |
|
|
142
|
+
| --- | --- |
|
|
143
|
+
| `emptyRegistry` | No part knowledge; measures what device class laws alone cover. |
|
|
144
|
+
| `pedalPartCatalog` | The catalog corpus facing scripts inject. |
|
|
145
|
+
| `PartRegistry` | `{ entries }` consulted by stage 2. |
|
|
146
|
+
| `PartEntry` | One catalog entry binding identity to a model. |
|
|
147
|
+
| `PartModel` | Law, sections, or macro model a part supplies. |
|
|
148
|
+
| `PartSection` | One section of a multi section part with its terminals. |
|
|
149
|
+
| `PartPinout` | Terminal order a sections model indices assume. |
|
|
150
|
+
| `PartIdentity` | A resolved part identity. |
|
|
151
|
+
| `MacroPartModel` | Macro model a registered part supplies. |
|
|
152
|
+
| `MacroPortRoles` | Where a macro ports sit, named by terminal role. |
|
|
153
|
+
| `MacroBarePinPositions` | Physical terminal positions for pin numbered documents. |
|
|
154
|
+
| `registryEntryFor` | Entry lookup for a device. |
|
|
155
|
+
| `registryModelFor` | Model lookup for a device. |
|
|
156
|
+
| `registryLawFor` | The law a registered part supplies for a device. |
|
|
157
|
+
| `terminalWithRole` | Index of the terminal whose role matches, or null. |
|
|
158
|
+
| `pinoutMatches` | Whether a device declares the order an entry was written against. |
|
|
159
|
+
| `foldPartId` | Fold case and separators (`MN-3007` is `mn3007`). |
|
|
160
|
+
| `foldToken` | Fold case and whitespace for typed vocabulary values. |
|
|
161
|
+
| `recordedReads` | What each owner consulted. |
|
|
162
|
+
| `withRecordedReads` | Run a function with registry reads recorded. |
|
|
163
|
+
| `clearRecordedReads` | Forget everything recorded so far. |
|
|
164
|
+
|
|
165
|
+
### Supply stamps
|
|
166
|
+
|
|
167
|
+
| Name | What it is |
|
|
168
|
+
| --- | --- |
|
|
169
|
+
| `resolveSupplyStamps` | Join document power domains to compiled `dc-source` stamps. |
|
|
170
|
+
| `SupplyAddress` | `{ blockIndex, sourceIndex }` naming one `dc-source` stamp. |
|
|
171
|
+
| `ResolvedSupply` | Address plus rail id, role, and nominal volts. |
|
|
172
|
+
| `RefusedSupply` | Unmapped rail with reason and human readable detail. |
|
|
173
|
+
| `SupplyResolution` | `{ supplies, refused }`. |
|
|
174
|
+
| `SupplyRefusalReason` | Closed union of eight refusal reasons. |
|
|
175
|
+
|
|
176
|
+
### Partition, lower, link, couple
|
|
177
|
+
|
|
178
|
+
| Name | What it is |
|
|
179
|
+
| --- | --- |
|
|
180
|
+
| `partition` | Split the lawed netlist into regions. |
|
|
181
|
+
| `Partitioning` | Regions plus dependencies. |
|
|
182
|
+
| `Region` | One coupled subgraph with its kind. |
|
|
183
|
+
| `RegionKind` | `linear`, `nonlinear`, or `macro`. |
|
|
184
|
+
| `lower` | Turn regions into MNA stamp blocks. |
|
|
185
|
+
| `lowerRegion` | Lower one region. |
|
|
186
|
+
| `link` | Order blocks and attach program metadata. |
|
|
187
|
+
| `couple` | Wire coupled and parameter ports after every region exists. |
|
|
188
|
+
| `Coupled` | Coupled seam record. |
|
|
189
|
+
| `blockNodeIndex` | A block row index for a source node id, or null. |
|
|
190
|
+
|
|
191
|
+
### Stamps, blocks, program
|
|
192
|
+
|
|
193
|
+
| Name | What it is |
|
|
194
|
+
| --- | --- |
|
|
195
|
+
| `Program` | The compiled ROM: operators, models, blocks, order, controls, ports, supply reference, scales, coverage. |
|
|
196
|
+
| `Block` | One `mna` solve block or one `macro` DSP block. |
|
|
197
|
+
| `Stamp` | One MNA contribution (conductance through switch families). |
|
|
198
|
+
| `OperatorKind` | A stamp kind a runtime must implement. |
|
|
199
|
+
| `StampPartition` | Compile time linear, control, constant, and dynamic partition. |
|
|
200
|
+
| `SparseSchedule` | Compile time static sparse elimination schedule. |
|
|
201
|
+
| `stampControl` | Control a stamp reads, or null. |
|
|
202
|
+
| `stampNeedsNewton` | Whether a stamp needs the Newton loop. |
|
|
203
|
+
| `stampNodes` | Every node a stamp names. |
|
|
204
|
+
| `stampInSourceNodes` | A stamp read back in document node ids. |
|
|
205
|
+
| `withStamp` | Add a stamp with linear and controlFree re-derived. |
|
|
206
|
+
| `Ports` | Input and output node ids. |
|
|
207
|
+
| `CostPredictors` | Rate independent cost facts for admission. |
|
|
208
|
+
| `OperatingPointSeed` | A nodeset style hint for the DC solve start. |
|
|
209
|
+
| `NodeId` | Electrical node number. |
|
|
210
|
+
| `GROUND` | Node 0. |
|
|
211
|
+
| `ModulationPort` | Solved node read every sample to scale a delay macro. |
|
|
212
|
+
| `ParameterPort` | Scalar another operator derives. |
|
|
213
|
+
| `MacroModel` | A region the compiler does not solve. |
|
|
214
|
+
| `MacroClockControl` | Clock control mapping for a macro block. |
|
|
215
|
+
| `SUPPLY_SOURCE_OHMS` | Default series impedance of a pedal supply in ohms (1). |
|
|
216
|
+
| `STATE_SLOTS_PER_REACTIVE_ELEMENT` | State slots a reactive element companion model needs. |
|
|
217
|
+
| `THERMAL_VOLTAGE` | Room temperature thermal voltage for the diode law. |
|
|
218
|
+
| `SILICON_SATURATION_CURRENT` | Default silicon saturation current. |
|
|
219
|
+
| `SILICON_FORWARD_BETA` | Default silicon forward beta (100). |
|
|
220
|
+
| `SWITCH_ON_OHMS` | Closed switch resistance. |
|
|
221
|
+
| `SWITCH_OFF_OHMS` | Open switch resistance. |
|
|
222
|
+
|
|
223
|
+
### Controls and tapers
|
|
224
|
+
|
|
225
|
+
| Name | What it is |
|
|
226
|
+
| --- | --- |
|
|
227
|
+
| `Control` | Compiled control with id, taper, default position, role, label. |
|
|
228
|
+
| `ControlId` | Control id string. |
|
|
229
|
+
| `TaperKind` | `linear`, `logarithmic`, `reverse-logarithmic`, or `reverse-linear`. |
|
|
230
|
+
|
|
231
|
+
### Clocks, timing, delay lines
|
|
232
|
+
|
|
233
|
+
| Name | What it is |
|
|
234
|
+
| --- | --- |
|
|
235
|
+
| `deriveBbdDelayFromNetlist` | Derive BBD delay from the clock network. |
|
|
236
|
+
| `derivePt2399DelayFromNetlist` | Derive PT2399 delay from the VCO resistor network. |
|
|
237
|
+
| `deriveM50195DelayFromNetlist` | Derive M50195P delay from the oscillator network. |
|
|
238
|
+
| `pt2399DelayFromOhms` | PT2399 delay formula from VCO resistance. |
|
|
239
|
+
| `identifyClockFamily` | Clock driver family for a device. |
|
|
240
|
+
| `ClockDriverFamily` | BBD clock family. |
|
|
241
|
+
| `clockTimingNodes` | Nodes a clock driver timing network hangs on. |
|
|
242
|
+
| `activeTimingDrivers` | Devices actively steering a timing network. |
|
|
243
|
+
| `ACTIVE_TIMING_KINDS` | Device kinds that can drive a timing node. |
|
|
244
|
+
| `findClockDriverDevice` | Locate the clock driver device. |
|
|
245
|
+
| `resolveClockModulationSource` | Node an LFO reaches a modulated BBD clock on. |
|
|
246
|
+
| `ClockModulationSource` | That modulation source. |
|
|
247
|
+
| `BbdClockDerivationOutcome` | BBD clock derivation result. |
|
|
248
|
+
|
|
249
|
+
### Device helpers
|
|
250
|
+
|
|
251
|
+
| Name | What it is |
|
|
252
|
+
| --- | --- |
|
|
253
|
+
| `attachDeviceLaws` | Stage 2: attach laws to every netlist device. |
|
|
254
|
+
| `declaredRegulatorTerminals` | Output and reference terminals of a regulator model. |
|
|
255
|
+
| `isElectricallyIsolated` | Whether every device node is private to itself. |
|
|
256
|
+
| `opampInputDistances` | Op-amp input network distances. |
|
|
257
|
+
| `quietDistances` | Quiet network distances. |
|
|
258
|
+
| `optocouplerBinding` | Which rung decided an optocoupler wiring. |
|
|
259
|
+
| `otaPackageOrderAssumed` | Whether an OTA used DIP-8 package order. |
|
|
260
|
+
| `potTerminals` | Potentiometer terminal roles. |
|
|
261
|
+
| `synthesizeOpampImplicitBias` | Add implicit DC bias where topology leaves it undefined. |
|
|
262
|
+
| `stageCoverage` | Amplification stage coverage read from lowered stamps. |
|
|
263
|
+
|
|
264
|
+
### Diagnostics (warnings and their finders)
|
|
265
|
+
|
|
266
|
+
| Name | What it is |
|
|
267
|
+
| --- | --- |
|
|
268
|
+
| `CompileWarning` | Union of every warning shape. |
|
|
269
|
+
| `findInertControls` | A pot whose wiper touches nothing is a fixed resistor. |
|
|
270
|
+
| `InertControlWarning` | Why a control cannot move the circuit. |
|
|
271
|
+
| `ControlPositionDisagreesWarning` | Panel and component disagree about a control setting. |
|
|
272
|
+
| `findUnboundedOpamps` | Op-amps with no DC feedback path. |
|
|
273
|
+
| `UnboundedOpampWarning` | Op-amp on the signal path with no DC feedback. |
|
|
274
|
+
| `findSupplyShorts` | Diodes forward across a supply. |
|
|
275
|
+
| `SupplyShortWarning` | A diode wired forward across a supply. |
|
|
276
|
+
| `findOverDrivenNodes` | Nodes driven by more than one ideal source. |
|
|
277
|
+
| `OverDrivenNodeWarning` | Over-determined node. |
|
|
278
|
+
| `findDanglingActiveTerminals` | Active terminals on untouched nodes. |
|
|
279
|
+
| `DanglingActiveTerminalWarning` | Active device terminal that cannot conduct. |
|
|
280
|
+
| `findGroundedClockSupplies` | Clock drivers with supply at ground. |
|
|
281
|
+
| `ClockDriverSupplyAtGroundWarning` | Clock driver rendering no clock at all. |
|
|
282
|
+
| `findUnimplementedDeviceLaws` | Devices with no law, told by name. |
|
|
283
|
+
| `UnimplementedDeviceLawWarning` | Device class with no law. |
|
|
284
|
+
| `UnimplementedControlRoleWarning` | Control role with no law: accepted, lowered, ignored. |
|
|
285
|
+
| `findUnreachableOutput` | Outputs reachable by nothing. |
|
|
286
|
+
| `OutputPortUnreachableWarning` | Program executing no blocks. |
|
|
287
|
+
| `OutputPortNotTransformerCoupledWarning` | Output measured before the power stage. |
|
|
288
|
+
| `NoOutputTransformerWarning` | Amp shaped document with no output transformer. |
|
|
289
|
+
| `findUnexecutedRegions` | Regions the program never executes. |
|
|
290
|
+
| `UnexecutedActiveRegionWarning` | Active region never executed. |
|
|
291
|
+
| `findIcsNotExecuted` | Declared ICs the program does not execute. |
|
|
292
|
+
| `IcNotExecutedWarning` | Declared but unexecuted IC. |
|
|
293
|
+
| `findElectricallyIsolatedIcs` | Identification devices with all private nodes. |
|
|
294
|
+
| `ElectricallyIsolatedIcWarning` | Isolated device given an open law. |
|
|
295
|
+
| `OpenIcReason` | Why a device got an open law. |
|
|
296
|
+
| `findPowerDomainControls` | Power hardware exposed as sweepable controls. |
|
|
297
|
+
| `PowerDomainControlWarning` | Power domain hardware outside the audio graph. |
|
|
298
|
+
| `findNonExecutableClockDrivers` | Clock drivers bypassed by the MNA solver. (finder; warning type `NonExecutableClockDriverWarning`) |
|
|
299
|
+
| `NonExecutableClockDriverWarning` | Clock behavior not modelled. |
|
|
300
|
+
| `NonExecutableSupportShellWarning` | Support shell preserved but not executed. |
|
|
301
|
+
| `findGenericTubeFits` | Tubes lowered with device class fits. (finder; types below) |
|
|
302
|
+
| `GenericTubeFitWarning` | Tube lowered without a catalog match. |
|
|
303
|
+
| `GenericSpeakerProfileWarning` | Speaker load with a generic driver profile. |
|
|
304
|
+
| `findUnverifiedPinoutBindings` | Parts wired by declaration order. (finder; type below) |
|
|
305
|
+
| `UnverifiedPinoutBindingWarning` | Terminals placed by order, not assertion. |
|
|
306
|
+
| `UnreadableTerminalRoleWarning` | Terminals wired by order after an unplaceable spelling. |
|
|
307
|
+
| `UnroutableThrowWarning` | Switch throw alone on its node. |
|
|
308
|
+
| `InterfaceOrSourceOnlyWarning` | Interface or source only component. |
|
|
309
|
+
| `UnconnectedBehaviorComponentWarning` | Behavior component with no connection to the audio graph. |
|
|
310
|
+
| `NotPopulatedWarning` | DNP position with nothing fitted. |
|
|
311
|
+
| `NotPopulatedWithoutValueWarning` | DNP component with no value. |
|
|
312
|
+
| `LedgerDivergenceWarning` | Nodes ledger and terminal refs disagree. |
|
|
313
|
+
| `DeclaredDelayWarning` | Delay typed into the source, not derived. |
|
|
314
|
+
| `ModulationNotModelledWarning` | Wired modulation input admission refused. |
|
|
315
|
+
| `TaperNotExecutableWarning` | Taper that renders linear. |
|
package/dist/bake.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Block } from "./types";
|
|
2
|
+
/** Why a block's realisation may not be baked, naming the block and the failing flag. */
|
|
3
|
+
export type BakeRefusal = {
|
|
4
|
+
readonly block: string;
|
|
5
|
+
readonly reason: string;
|
|
6
|
+
};
|
|
7
|
+
export type BakeDecision = {
|
|
8
|
+
readonly outcome: "may-bake";
|
|
9
|
+
} | {
|
|
10
|
+
readonly outcome: "refused";
|
|
11
|
+
readonly refusal: BakeRefusal;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* May this block's realisation be derived once and reused across samples?
|
|
15
|
+
*
|
|
16
|
+
* Only when `linear && controlFree` both hold. Checked in that order because a `linear`
|
|
17
|
+
* failure is the more fundamental one -- a nonlinear block has no fixed realisation to derive
|
|
18
|
+
* at all, `linear && controlFree` or not -- so naming it first is the more useful refusal even
|
|
19
|
+
* though a real block can fail either independently (see `bake.test.ts`'s four-quadrant cases,
|
|
20
|
+
* matching `lower.test.ts`'s own `resistorDivider`/`potDivider`/`switchedDivider`/
|
|
21
|
+
* `diodeClipper` fixtures for `linear`/`controlFree`'s own precedent).
|
|
22
|
+
*/
|
|
23
|
+
export declare function bakeDecisionFor(block: Extract<Block, {
|
|
24
|
+
readonly kind: "mna";
|
|
25
|
+
}>,
|
|
26
|
+
/**
|
|
27
|
+
* Whether every supply this block references holds still across the samples the realisation
|
|
28
|
+
* would be reused over.
|
|
29
|
+
*
|
|
30
|
+
* `true` for every block the compiler builds today — a rail is ground or a node inside this
|
|
31
|
+
* block's own matrix, and sag inside the matrix is already exact in a linear realisation.
|
|
32
|
+
* The reducer must pass `false` the day a rail is driven from outside the block, whichever
|
|
33
|
+
* shape that plumbing takes.
|
|
34
|
+
*/
|
|
35
|
+
supply?: {
|
|
36
|
+
readonly static: boolean;
|
|
37
|
+
}): BakeDecision;
|
|
38
|
+
//# sourceMappingURL=bake.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bake.d.ts","sourceRoot":"","sources":["../src/bake.ts"],"names":[],"mappings":"AAmDA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAErC,yFAAyF;AACzF,MAAM,MAAM,WAAW,GAAG;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,YAAY,GACrB;IAAE,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;CAAE,GAChC;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;CAAE,CAAC;AAElE;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC9B,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC;AAC/C;;;;;;;;GAQG;AACH,MAAM,GAAE;IAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CAAqB,GACrD,YAAY,CA6Bd"}
|
package/dist/bake.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// Spec clause 5: `linear && controlFree`, jointly, as the precondition for baking a
|
|
2
|
+
// realisation -- and NOTHING ELSE. No new field: `Block.linear` and `Block.controlFree`
|
|
3
|
+
// already exist (`src/compiler/types.ts`, computed in `lower.ts` from the exhaustive,
|
|
4
|
+
// `never`-bound `stampNeedsNewton`/`stampControl` classifiers), and this file is the
|
|
5
|
+
// instruction to read them as a conjunction rather than separately, at the one place a
|
|
6
|
+
// reduction may ever be baked and reused across samples.
|
|
7
|
+
//
|
|
8
|
+
// **This gate has no caller today, and that is honest rather than incomplete.** Nothing in
|
|
9
|
+
// this compiler reduces an `mna` block into a state-space realisation -- that is step 5's own
|
|
10
|
+
// future work, and it does not exist yet (build-order steps 4 and 5 are unbuilt; clause 4,
|
|
11
|
+
// declared output nodes, has nothing to govern until something reduces). `bakeDecisionFor`
|
|
12
|
+
// is the precondition function that future stage MUST call before it bakes anything, and it
|
|
13
|
+
// is written, tested and wired into the plan's documentation now rather than left implicit,
|
|
14
|
+
// so the precondition cannot be forgotten the day someone builds the reducer. The insertion
|
|
15
|
+
// point is between `lower`/`couple` and `link` in `compile.ts`'s pipeline -- after a block's
|
|
16
|
+
// stamps are final and its `linear`/`controlFree` flags are settled, before anything is
|
|
17
|
+
// scheduled to run.
|
|
18
|
+
//
|
|
19
|
+
// **Why the conjunction, not either flag alone.** `linear-core-state-space-gate` measured
|
|
20
|
+
// H0 (a linear reduction is exact) fully holding, and H2 ("linear is sufficient on its own")
|
|
21
|
+
// false: its `load-shift` mutation -- a realisation derived at one load, evaluated at
|
|
22
|
+
// another -- errs 80% of the signal (`4.19e-02` against a `5.23e-02` reference), because a
|
|
23
|
+
// pot sits *inside* the matrix a realisation is derived from, so a knob move is exactly the
|
|
24
|
+
// kind of topology change a baked realisation cannot track without re-deriving. `linear`
|
|
25
|
+
// alone would have let that 80% error ship silently -- see `bake.test.ts`'s reproduction of
|
|
26
|
+
// this shape on `potDivider`, and `pipeline.test.ts` for the same shape measured end to end.
|
|
27
|
+
//
|
|
28
|
+
// **The supply gap, closed 2026-09-02 as a third condition rather than a fourth flag.** A block
|
|
29
|
+
// can be `linear && controlFree` and still reference a rail that moves with the audio, because
|
|
30
|
+
// `controlFree` is about controls and says nothing about supply state. This used to be recorded
|
|
31
|
+
// here as an undecided gap waiting on the rail-port design. It is not: the gate can refuse the
|
|
32
|
+
// case without knowing how a moving rail will eventually be *plumbed*, and refusing it is what
|
|
33
|
+
// the reducer needs.
|
|
34
|
+
//
|
|
35
|
+
// **Why the caller supplies the answer instead of the block carrying a flag.** A rail that moves
|
|
36
|
+
// cannot cross a block boundary today -- every supply a block references is either ground or a
|
|
37
|
+
// node inside its own matrix, and a rail sagging *inside* a linear block is already exact in the
|
|
38
|
+
// realisation, because the sag is part of the linear system being derived. So a `supplyStatic`
|
|
39
|
+
// field on `Block` would be a constant `true` with no way to test it, and this repository's
|
|
40
|
+
// evidence rule asks for a check that can fail for the reason claimed. Taking it as an argument
|
|
41
|
+
// makes the future reducer state the answer at the point it bakes, keeps the Program contract
|
|
42
|
+
// (and its C++ mirror) unchanged, and is testable today by passing `false`.
|
|
43
|
+
//
|
|
44
|
+
// **What is still open is the port design, and it is deliberately not decided here.** Whether a
|
|
45
|
+
// dynamic rail becomes a fourth port kind or folds into `coupled` is an architecture question
|
|
46
|
+
// whose evidence does not exist yet -- `thoughts/shared/experiments/power-domain-rail-sag-contract/`
|
|
47
|
+
// was written to produce exactly that evidence (sign convention, multi-rail summing, the DK
|
|
48
|
+
// rail-in/current-out contract) and has never been run. This gate is correct under either answer:
|
|
49
|
+
// whichever one lands sets `supply.static` to `false` for a block whose rail is driven from
|
|
50
|
+
// outside it.
|
|
51
|
+
/**
|
|
52
|
+
* May this block's realisation be derived once and reused across samples?
|
|
53
|
+
*
|
|
54
|
+
* Only when `linear && controlFree` both hold. Checked in that order because a `linear`
|
|
55
|
+
* failure is the more fundamental one -- a nonlinear block has no fixed realisation to derive
|
|
56
|
+
* at all, `linear && controlFree` or not -- so naming it first is the more useful refusal even
|
|
57
|
+
* though a real block can fail either independently (see `bake.test.ts`'s four-quadrant cases,
|
|
58
|
+
* matching `lower.test.ts`'s own `resistorDivider`/`potDivider`/`switchedDivider`/
|
|
59
|
+
* `diodeClipper` fixtures for `linear`/`controlFree`'s own precedent).
|
|
60
|
+
*/
|
|
61
|
+
export function bakeDecisionFor(block,
|
|
62
|
+
/**
|
|
63
|
+
* Whether every supply this block references holds still across the samples the realisation
|
|
64
|
+
* would be reused over.
|
|
65
|
+
*
|
|
66
|
+
* `true` for every block the compiler builds today — a rail is ground or a node inside this
|
|
67
|
+
* block's own matrix, and sag inside the matrix is already exact in a linear realisation.
|
|
68
|
+
* The reducer must pass `false` the day a rail is driven from outside the block, whichever
|
|
69
|
+
* shape that plumbing takes.
|
|
70
|
+
*/
|
|
71
|
+
supply = { static: true }) {
|
|
72
|
+
if (!block.linear) {
|
|
73
|
+
return {
|
|
74
|
+
outcome: "refused",
|
|
75
|
+
refusal: {
|
|
76
|
+
block: block.id,
|
|
77
|
+
reason: `block "${block.id}" is not linear, so it has no fixed realisation to derive at all -- it must keep iterating Newton every sample`,
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
if (!block.controlFree) {
|
|
82
|
+
return {
|
|
83
|
+
outcome: "refused",
|
|
84
|
+
refusal: {
|
|
85
|
+
block: block.id,
|
|
86
|
+
reason: `block "${block.id}" is linear but not control-free, so a realisation baked at one control position would be wrong at another -- linear-core-state-space-gate measured this at 80% of the signal (load-shift). Refuse to bake and keep solving the per-sample stamps until re-derivation on control change or knob-grid tabulation exists`,
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
if (!supply.static) {
|
|
91
|
+
return {
|
|
92
|
+
outcome: "refused",
|
|
93
|
+
refusal: {
|
|
94
|
+
block: block.id,
|
|
95
|
+
reason: `block "${block.id}" is linear and control-free but references a supply that moves with the audio, and a realisation derived at one rail voltage is wrong at another for the same reason a pot position is -- the rail sits inside the matrix the realisation is derived from. Refuse to bake until the rail is an input the realisation can be re-derived against`,
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return { outcome: "may-bake" };
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=bake.js.map
|
package/dist/bake.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bake.js","sourceRoot":"","sources":["../src/bake.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,wFAAwF;AACxF,sFAAsF;AACtF,qFAAqF;AACrF,uFAAuF;AACvF,yDAAyD;AACzD,EAAE;AACF,2FAA2F;AAC3F,8FAA8F;AAC9F,2FAA2F;AAC3F,2FAA2F;AAC3F,4FAA4F;AAC5F,4FAA4F;AAC5F,4FAA4F;AAC5F,6FAA6F;AAC7F,wFAAwF;AACxF,oBAAoB;AACpB,EAAE;AACF,0FAA0F;AAC1F,6FAA6F;AAC7F,sFAAsF;AACtF,2FAA2F;AAC3F,4FAA4F;AAC5F,yFAAyF;AACzF,4FAA4F;AAC5F,6FAA6F;AAC7F,EAAE;AACF,gGAAgG;AAChG,+FAA+F;AAC/F,gGAAgG;AAChG,+FAA+F;AAC/F,+FAA+F;AAC/F,qBAAqB;AACrB,EAAE;AACF,iGAAiG;AACjG,+FAA+F;AAC/F,iGAAiG;AACjG,+FAA+F;AAC/F,4FAA4F;AAC5F,gGAAgG;AAChG,8FAA8F;AAC9F,4EAA4E;AAC5E,EAAE;AACF,gGAAgG;AAChG,8FAA8F;AAC9F,qGAAqG;AACrG,4FAA4F;AAC5F,kGAAkG;AAClG,4FAA4F;AAC5F,cAAc;AAcd;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAC9B,KAA+C;AAC/C;;;;;;;;GAQG;AACH,SAAuC,EAAE,MAAM,EAAE,IAAI,EAAE;IAEvD,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QACnB,OAAO;YACN,OAAO,EAAE,SAAS;YAClB,OAAO,EAAE;gBACR,KAAK,EAAE,KAAK,CAAC,EAAE;gBACf,MAAM,EAAE,UAAU,KAAK,CAAC,EAAE,gHAAgH;aAC1I;SACD,CAAC;IACH,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;QACxB,OAAO;YACN,OAAO,EAAE,SAAS;YAClB,OAAO,EAAE;gBACR,KAAK,EAAE,KAAK,CAAC,EAAE;gBACf,MAAM,EAAE,UAAU,KAAK,CAAC,EAAE,wTAAwT;aAClV;SACD,CAAC;IACH,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACpB,OAAO;YACN,OAAO,EAAE,SAAS;YAClB,OAAO,EAAE;gBACR,KAAK,EAAE,KAAK,CAAC,EAAE;gBACf,MAAM,EAAE,UAAU,KAAK,CAAC,EAAE,iVAAiV;aAC3W;SACD,CAAC;IACH,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import type { ControlId, Device, DeviceKind, Netlist, NodeId, TaperKind } from "./types";
|
|
2
|
+
import type { PartRegistry } from "./registry";
|
|
3
|
+
export type ClockDriverFamily = "CD4047" | "MN3101" | "MN3102" | "unknown";
|
|
4
|
+
export type BbdClockDerivationOutcome = {
|
|
5
|
+
readonly outcome: "derived";
|
|
6
|
+
readonly delaySeconds: number;
|
|
7
|
+
readonly rOhms: number;
|
|
8
|
+
readonly cFarads: number;
|
|
9
|
+
readonly fClockHz: number;
|
|
10
|
+
readonly family: ClockDriverFamily;
|
|
11
|
+
readonly stages: number;
|
|
12
|
+
readonly formulaConstant: number;
|
|
13
|
+
readonly offsetSeconds: number;
|
|
14
|
+
readonly controlId: ControlId | null;
|
|
15
|
+
readonly taper: TaperKind;
|
|
16
|
+
readonly ohmsAtControlMin: number;
|
|
17
|
+
readonly ohmsAtControlMax: number;
|
|
18
|
+
} | {
|
|
19
|
+
readonly outcome: "no-clock-driver";
|
|
20
|
+
} | {
|
|
21
|
+
readonly outcome: "refused";
|
|
22
|
+
readonly reason: string;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Device kinds that can *drive* a timing node rather than merely set it.
|
|
26
|
+
*
|
|
27
|
+
* A resistor, a capacitor and a potentiometer are the timing network — a pot is a knob, which is
|
|
28
|
+
* control-rate and already carried as `controlId`. Anything on this list sitting on the timing
|
|
29
|
+
* network is steering it at signal rate, which is how an LFO reaches a BBD clock.
|
|
30
|
+
*
|
|
31
|
+
* `diode` is deliberately absent: `mxr-carbon-copy` clamps its CD4047 timing node with `D5` to
|
|
32
|
+
* ground, and a clamp is not a modulator. `ic` is absent because the clock driver is itself an
|
|
33
|
+
* `ic` on its own timing pins.
|
|
34
|
+
*/
|
|
35
|
+
export declare const ACTIVE_TIMING_KINDS: ReadonlySet<DeviceKind>;
|
|
36
|
+
/**
|
|
37
|
+
* Devices actively steering this clock driver's timing network, by id.
|
|
38
|
+
*
|
|
39
|
+
* The discrimination this exists for, measured 2026-08-29 across the corpus: `mxr-carbon-copy`
|
|
40
|
+
* and `boss-dm-2` carry only resistors, capacitors and pots on their timing nodes, so their
|
|
41
|
+
* derived delays are a property of the circuit. `boss-ce-5` carries **`Q8`'s emitter directly
|
|
42
|
+
* on oscillator node 42**, so the frequency is set by that transistor's current and the R·C
|
|
43
|
+
* arithmetic reads a resistor that is not what times the oscillator.
|
|
44
|
+
*/
|
|
45
|
+
export declare function activeTimingDrivers(clockDevice: Device, netlist: Netlist, registry: PartRegistry): readonly string[];
|
|
46
|
+
export type ClockModulationSource = {
|
|
47
|
+
readonly outcome: "resolved";
|
|
48
|
+
readonly steeredBy: string;
|
|
49
|
+
readonly node: NodeId;
|
|
50
|
+
} | {
|
|
51
|
+
readonly outcome: "none";
|
|
52
|
+
} | {
|
|
53
|
+
readonly outcome: "refused";
|
|
54
|
+
readonly reason: string;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* The node an LFO reaches a modulated BBD clock on: the steering device's **control** terminal.
|
|
58
|
+
*
|
|
59
|
+
* **Not the timing node.** That is the point of this function. The timing node carries the
|
|
60
|
+
* oscillator's own waveform at the clock rate — for a chorus, ~100 kHz, far above anything a
|
|
61
|
+
* 48 kHz host can sample — so reading it as a modulation source would alias garbage into the
|
|
62
|
+
* delay length. The control terminal carries the LFO and nothing else: on `boss-ce-2` that is
|
|
63
|
+
* `Q5`'s base, which the DEPTH pot reaches through `Q4` and `D1`.
|
|
64
|
+
*
|
|
65
|
+
* Deliberately strict. Exactly one steering device with one resolvable control terminal, and
|
|
66
|
+
* that terminal may not sit on ground or on the timing network itself. Anything else refuses by
|
|
67
|
+
* name and leaves the delay static, because a guess here is a sweep of the wrong thing.
|
|
68
|
+
*/
|
|
69
|
+
export declare function resolveClockModulationSource(bbdDevice: Device, netlist: Netlist, registry: PartRegistry): ClockModulationSource;
|
|
70
|
+
/**
|
|
71
|
+
* The nodes a clock driver's own timing network hangs on, by family.
|
|
72
|
+
*
|
|
73
|
+
* Exported because `scripts/report-bbd-architecture.ts` asks the same question and answered it
|
|
74
|
+
* with a private copy of the role vocabulary, which **under-reported immediately**: an MN3102
|
|
75
|
+
* spelling its pins `oscillatorinput`/`oscillatoroutput`/`clockcontrol` (`boss-bf-2`) matched
|
|
76
|
+
* none of the canonical `ox1`/`ox2`/`ox3` tokens, so a driver the compiler finds read as absent
|
|
77
|
+
* in the report. One enumerator, shared, is the same conclusion `stampNodes` reached.
|
|
78
|
+
*
|
|
79
|
+
* Role tokens are compared as whole values after folding, never by substring, and the MN310x
|
|
80
|
+
* branch admits the registry's own alias spellings through `oscillatorRoleTokens`.
|
|
81
|
+
*/
|
|
82
|
+
export declare function clockTimingNodes(device: Device, registry: PartRegistry): ReadonlySet<NodeId>;
|
|
83
|
+
export declare function identifyClockFamily(device: Device): ClockDriverFamily;
|
|
84
|
+
export declare function findClockDriverDevice(netlist: Netlist): Device | null;
|
|
85
|
+
export declare function deriveBbdDelayFromNetlist(bbdDevice: Device, netlist: Netlist, stages: number, registry: PartRegistry): BbdClockDerivationOutcome;
|
|
86
|
+
/**
|
|
87
|
+
* Open-OX2 clock law (CE-2 first slice, 2026-09-28).
|
|
88
|
+
*
|
|
89
|
+
* The form the MN3101 datasheet never drew: OX2 left open (N.C.) and a single
|
|
90
|
+
* relaxation loop across the OX1→OX3 inverter pair — a timing capacitor
|
|
91
|
+
* between OX3 and OX1 charged through a pull-up on OX1 and discharged by a
|
|
92
|
+
* transistor the OX3 side drives, with the LFO setting the restart level
|
|
93
|
+
* through a diode. `boss-ce-2` v1.25 is the corpus case.
|
|
94
|
+
*
|
|
95
|
+
* Family constants (per-packet R and C come from the netlist):
|
|
96
|
+
* - `OPEN_OX2_VDD_VOLTS`: the driver's supply span, 9 V nominal from the
|
|
97
|
+
* packet's own supply port (the filtered rail measures 8.967 V, 0.4%,
|
|
98
|
+
* disclosed and immaterial beside the threshold sensitivity).
|
|
99
|
+
* - `OPEN_OX2_VTH_VOLTS`: solved 2026-09-28 for 110 kHz at the measured
|
|
100
|
+
* Depth-0 divider level 1.565 V against a scope specimen (DIYstompboxes
|
|
101
|
+
* 2011, one rough forum reading, disclosed), inside the 3.4–5.6 V window
|
|
102
|
+
* the MN3101 p.60 example table allows. Re-solve, never tune: procedure in
|
|
103
|
+
* `docs/todo-archive/2026-09-28-ce2-clock-law-analysis.md`.
|
|
104
|
+
* - `OPEN_OX2_VF_VOLTS`: generic-diode forward drop, disclosed typical.
|
|
105
|
+
* - `OPEN_OX2_FLOOR_VOLTS`: yank-minus-kick bottom under datasheet OX3 drive
|
|
106
|
+
* (R_OH ≈ 667 Ω / R_OL ≈ 500 Ω from the I_OH2/I_OL2 minimums): a ~7 V OX3
|
|
107
|
+
* step kicks ~6.2 V through 47 pF against cited diode maxima, landing near
|
|
108
|
+
* −5.3 V — below the D1 floor at every measured divider level, so the D1
|
|
109
|
+
* branch binds everywhere. Same max() form as the analysis, not a deletion.
|
|
110
|
+
*/
|
|
111
|
+
export declare const OPEN_OX2_VDD_VOLTS = 9;
|
|
112
|
+
export declare const OPEN_OX2_VTH_VOLTS = 4.757;
|
|
113
|
+
export declare const OPEN_OX2_VF_VOLTS = 0.65;
|
|
114
|
+
export declare const OPEN_OX2_FLOOR_VOLTS = -5.35;
|
|
115
|
+
export type OpenOx2ClockLawOutcome = {
|
|
116
|
+
readonly outcome: "recognized";
|
|
117
|
+
readonly slowNode: NodeId;
|
|
118
|
+
readonly steeredBy: string;
|
|
119
|
+
readonly rOhms: number;
|
|
120
|
+
readonly cFarads: number;
|
|
121
|
+
} | {
|
|
122
|
+
readonly outcome: "absent";
|
|
123
|
+
readonly reason: string;
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* Recognise the open-OX2 relaxation form by connectivity, never by names or
|
|
127
|
+
* prose: an MN3101-family driver with OX2 touched by nothing but its own pin,
|
|
128
|
+
* one capacitor bridging OX3 to OX1, one pull-up resistor from OX1 to the
|
|
129
|
+
* driver's own supply pin, one resistor from OX3 into a grounded-emitter
|
|
130
|
+
* transistor's base, that transistor's collector on a pulled-up discharge
|
|
131
|
+
* node back into OX1 through a diode, and one diode from OX1 into a
|
|
132
|
+
* divider-fed slow node.
|
|
133
|
+
*
|
|
134
|
+
* Anything else is `absent` with the failed check named, and the caller falls
|
|
135
|
+
* back to the existing star/gate derivation untouched. In particular the
|
|
136
|
+
* pre-rewire collapse (capacitor on OX1–OX2), a transistor sitting directly
|
|
137
|
+
* on a timing node (the modulated refusal owns that), and the MN3102 two-leg
|
|
138
|
+
* form (a different oscillator; no corpus case) all read absent here.
|
|
139
|
+
*/
|
|
140
|
+
export declare function deriveOpenOx2ClockLaw(netlist: Netlist, registry: PartRegistry): OpenOx2ClockLawOutcome;
|
|
141
|
+
/**
|
|
142
|
+
* Princeton Technology PT2399 delay time from external VCO resistance R (in Ohms).
|
|
143
|
+
*
|
|
144
|
+
* Princeton PT2399 datasheet, TABLE 1: RESISTOR/DELAY TIME VALUES (V1.4, Oct 2005;
|
|
145
|
+
* the same 28-row table is reprinted in V1.1, V1.2 and V1.6; the packet-local V1.9,
|
|
146
|
+
* Mar 2022, drops the table but still says "Please refer to Table 1 for the
|
|
147
|
+
* Resistor/Delay Time values"). Note 1 under the table states R in Ohms, so the
|
|
148
|
+
* last row's "0.5" is 0.5 Ohms (pin 6 effectively grounded, 31.3 ms), not 0.5 kOhms.
|
|
149
|
+
*
|
|
150
|
+
* The table is linear in R: with pin 6 held at 2.5 V, the page
|
|
151
|
+
* https://electrosmash.mas-effects.com/pt2399-analysis gives
|
|
152
|
+
* I_pin6 (mA) = 28.65 / (Delay_ms - 29.70), i.e. Delay_ms = 29.70 + 11.46 * R_kOhms,
|
|
153
|
+
* which reproduces all 28 cited rows within 4 ms (worst row: 27.6 kOhms, 346.0 ms
|
|
154
|
+
* predicted vs 342 ms cited). That linear form is what this returns.
|
|
155
|
+
*
|
|
156
|
+
* Deliberately no clamp and no hard maximum: the cited source states none. Quality
|
|
157
|
+
* degrades past about 350 ms (the table's own THD reaches 1.0% at 342 ms), but the
|
|
158
|
+
* delay keeps growing with R, so this extrapolates the line rather than clipping it.
|
|
159
|
+
*/
|
|
160
|
+
export declare function pt2399DelayFromOhms(rOhms: number): number;
|
|
161
|
+
/**
|
|
162
|
+
* Derives delaySeconds and dynamic control mapping for PT2399 digital delay chips
|
|
163
|
+
* by tracing the series resistor/potentiometer network connected to VCO Pin 6.
|
|
164
|
+
*/
|
|
165
|
+
export declare function derivePt2399DelayFromNetlist(device: Device, netlist: Netlist): BbdClockDerivationOutcome;
|
|
166
|
+
/**
|
|
167
|
+
* Derives delaySeconds and dynamic control mapping for Mitsubishi M50195P digital echo LSI
|
|
168
|
+
* by tracing the inverter oscillator timing network connected to CLK1.
|
|
169
|
+
*/
|
|
170
|
+
export declare function deriveM50195DelayFromNetlist(device: Device, netlist: Netlist): BbdClockDerivationOutcome;
|
|
171
|
+
//# sourceMappingURL=bbd-clock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bbd-clock.d.ts","sourceRoot":"","sources":["../src/bbd-clock.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EACX,SAAS,EACT,MAAM,EACN,UAAU,EACV,OAAO,EACP,MAAM,EACN,SAAS,EACT,MAAM,SAAS,CAAC;AAEjB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE3E,MAAM,MAAM,yBAAyB,GAClC;IACA,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;CACjC,GACD;IACA,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;CACnC,GACD;IACA,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACvB,CAAC;AA0FL;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,EAAE,WAAW,CAAC,UAAU,CAOtD,CAAC;AAEH;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAClC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,YAAY,GACpB,SAAS,MAAM,EAAE,CAkBnB;AAiSD,MAAM,MAAM,qBAAqB,GAC9B;IAAE,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACnF;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC5B;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5D;;;;;;;;;;;;GAYG;AACH,wBAAgB,4BAA4B,CAC3C,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,YAAY,GACpB,qBAAqB,CAiFvB;AAqBD;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC/B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,YAAY,GACpB,WAAW,CAAC,MAAM,CAAC,CA6BrB;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,CAMrE;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAUrE;AAueD,wBAAgB,yBAAyB,CACxC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,YAAY,GACpB,yBAAyB,CAyY3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAC;AACpC,eAAO,MAAM,kBAAkB,QAAQ,CAAC;AACxC,eAAO,MAAM,iBAAiB,OAAO,CAAC;AACtC,eAAO,MAAM,oBAAoB,QAAQ,CAAC;AAE1C,MAAM,MAAM,sBAAsB,GAC/B;IACA,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACxB,GACD;IACA,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACvB,CAAC;AAmDL;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,YAAY,GACpB,sBAAsB,CA2MxB;AACD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAC3C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,GACd,yBAAyB,CA2F3B;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAC3C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,GACd,yBAAyB,CA8E3B"}
|