@vessel-dsp/runtime 0.7.0 → 0.12.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.
Binary file
@@ -1395,6 +1395,42 @@ function ldrTableResistanceOhms(currentsAmps, ohms, currentAmps, minOhms, maxOhm
1395
1395
  const raw = Math.exp(lnR0 + (lnI - lnI0) * slope);
1396
1396
  return Math.min(Math.max(raw, minOhms), maxOhms);
1397
1397
  }
1398
+ function dbxVcaGainLinear(gainDb) {
1399
+ return Math.pow(10, gainDb / 20);
1400
+ }
1401
+ function dbxVcaRestTerms(vControl, sustainGain, sustainRef) {
1402
+ return sustainGain * (vControl - sustainRef);
1403
+ }
1404
+ function dbxVcaEnvelopeTerms(inputAmps, slopeVoltsPerNeper, kneeVolts) {
1405
+ const absIn = Math.abs(inputAmps);
1406
+ if (!(absIn > 0)) return 0;
1407
+ return Math.max(0, slopeVoltsPerNeper * Math.log(absIn * 1e6) + kneeVolts);
1408
+ }
1409
+ function dbxVcaKneeVolts(vControl, kneeBaseVolts, kneeTrack) {
1410
+ return kneeBaseVolts + kneeTrack * (vControl - 4.65);
1411
+ }
1412
+ function dbxVcaReleaseTc(depth01, baseSeconds, slowdown) {
1413
+ const depth = Math.min(1, Math.max(0, depth01));
1414
+ return baseSeconds * Math.pow(slowdown, depth);
1415
+ }
1416
+ function dbxVcaPrimeTarget(inputAmps, refCurrentAmps) {
1417
+ return Math.abs(inputAmps) > refCurrentAmps ? 0 : 1;
1418
+ }
1419
+ function dbxVcaShutdownTarget(peakTargetVolts, edgeThreshVolts, primed01, gainPerVolt) {
1420
+ const excess = peakTargetVolts - edgeThreshVolts;
1421
+ if (!(excess > 0) || !(primed01 > 0)) return 0;
1422
+ const primed = Math.min(1, primed01);
1423
+ return gainPerVolt * excess * excess * primed;
1424
+ }
1425
+ function dbxVcaVictimTc(primed01, fastSeconds, slowSeconds) {
1426
+ const primed = Math.min(1, Math.max(0, primed01));
1427
+ return primed > 0.05 ? slowSeconds : fastSeconds;
1428
+ }
1429
+ function dbxVcaEnvelopeK(tcSeconds, sampleRate2) {
1430
+ const denom = tcSeconds * sampleRate2;
1431
+ if (!(denom > 0)) return 1;
1432
+ return 1 - Math.exp(-1 / denom);
1433
+ }
1398
1434
  var NEWTON_UNPRODUCTIVE_ITERATIONS = 64;
1399
1435
  var NEWTON_UNPRODUCTIVE_PROBATION_SAMPLES = 1024;
1400
1436
  var NEWTON_RELATIVE_TOLERANCE = 1e-3;
@@ -1577,7 +1613,10 @@ var IMPLEMENTED_OPERATORS = {
1577
1613
  "clock-driver": true,
1578
1614
  comparator: true,
1579
1615
  // Linear-control VCA cell. Reads the control node, draws nothing.
1580
- "linear-vca": true
1616
+ "linear-vca": true,
1617
+ // dbx-style VCA cell (uPC1252H2). Bounded sigmoidal gain in the
1618
+ // control voltage. Reads the control node, draws nothing.
1619
+ "dbx-vca": true
1581
1620
  };
1582
1621
  function unimplementedOperators(required) {
1583
1622
  return required.filter(
@@ -6146,6 +6185,106 @@ var ReferenceRuntime = class {
6146
6185
  }
6147
6186
  break;
6148
6187
  }
6188
+ case "dbx-vca": {
6189
+ const dbxBaseIdx = stamp.stateIndex;
6190
+ const ctrlKey = `${block.id}_dbxc_${dbxBaseIdx}`;
6191
+ if (this.elapsedSamples !== (this.lastShiftedSample.get(ctrlKey) ?? -1)) {
6192
+ this.lastShiftedSample.set(ctrlKey, this.elapsedSamples);
6193
+ const vCtrlNow = solution[stamp.control] ?? 0;
6194
+ const ctrlPrev = state[dbxBaseIdx] ?? 0;
6195
+ const ctrlTc = vCtrlNow > ctrlPrev ? stamp.attackSeconds : stamp.releaseSeconds;
6196
+ const ctrlK = dbxVcaEnvelopeK(ctrlTc, this.sampleRate);
6197
+ state[dbxBaseIdx] = ctrlPrev + (vCtrlNow - ctrlPrev) * ctrlK;
6198
+ }
6199
+ const vCtrlHeld = state[dbxBaseIdx] ?? 0;
6200
+ const restHeld = dbxVcaRestTerms(
6201
+ vCtrlHeld,
6202
+ stamp.sustainGain,
6203
+ stamp.sustainRef
6204
+ );
6205
+ const kneeHeld = dbxVcaKneeVolts(
6206
+ vCtrlHeld,
6207
+ stamp.kneeBaseVolts,
6208
+ stamp.kneeTrack
6209
+ );
6210
+ const vInInstDbx = (solution[stamp.plus] ?? 0) - (solution[stamp.minus] ?? 0);
6211
+ const iInInstDbx = vInInstDbx * stamp.inputSiemens;
6212
+ const primeKey = `${block.id}_dbxp_${dbxBaseIdx}`;
6213
+ if (this.elapsedSamples !== (this.lastShiftedSample.get(primeKey) ?? -1)) {
6214
+ this.lastShiftedSample.set(primeKey, this.elapsedSamples);
6215
+ const primeTarget = dbxVcaPrimeTarget(
6216
+ iInInstDbx,
6217
+ stamp.primeRefCurrent
6218
+ );
6219
+ const primePrev = state[dbxBaseIdx + 2] ?? 0;
6220
+ const primeTc = primeTarget > primePrev ? stamp.primeRiseSeconds : stamp.primeFallSeconds;
6221
+ const primeK = dbxVcaEnvelopeK(primeTc, this.sampleRate);
6222
+ state[dbxBaseIdx + 2] = primePrev + (primeTarget - primePrev) * primeK;
6223
+ }
6224
+ const primeHeld = state[dbxBaseIdx + 2] ?? 0;
6225
+ const envKey = `${block.id}_dbxe_${dbxBaseIdx}`;
6226
+ if (this.elapsedSamples !== (this.lastShiftedSample.get(envKey) ?? -1)) {
6227
+ this.lastShiftedSample.set(envKey, this.elapsedSamples);
6228
+ const envTarget = dbxVcaEnvelopeTerms(
6229
+ iInInstDbx,
6230
+ stamp.envelopeSlope,
6231
+ kneeHeld
6232
+ );
6233
+ const envPrev = state[dbxBaseIdx + 1] ?? 0;
6234
+ const envDepth = Math.min(1, Math.max(0, envPrev / 0.15));
6235
+ const envTc = envTarget > envPrev ? stamp.attackSeconds : dbxVcaReleaseTc(envDepth, stamp.releaseSeconds, stamp.releaseSlowdown);
6236
+ const envK = dbxVcaEnvelopeK(envTc, this.sampleRate);
6237
+ state[dbxBaseIdx + 1] = envPrev + (envTarget - envPrev) * envK;
6238
+ }
6239
+ const envHeld = state[dbxBaseIdx + 1] ?? 0;
6240
+ const shutKey = `${block.id}_dbxs_${dbxBaseIdx}`;
6241
+ if (this.elapsedSamples !== (this.lastShiftedSample.get(shutKey) ?? -1)) {
6242
+ this.lastShiftedSample.set(shutKey, this.elapsedSamples);
6243
+ const peakTarget = dbxVcaEnvelopeTerms(
6244
+ iInInstDbx,
6245
+ stamp.envelopeSlope,
6246
+ kneeHeld
6247
+ );
6248
+ const shutTarget = dbxVcaShutdownTarget(
6249
+ peakTarget,
6250
+ stamp.shutdownEdgeVolts,
6251
+ primeHeld,
6252
+ stamp.shutdownGain
6253
+ );
6254
+ const shutPrev = state[dbxBaseIdx + 3] ?? 0;
6255
+ const shutTc = shutTarget > shutPrev ? stamp.shutdownAttackSeconds : dbxVcaVictimTc(
6256
+ primeHeld,
6257
+ stamp.shutdownFastSeconds,
6258
+ stamp.shutdownSlowSeconds
6259
+ );
6260
+ const shutK = dbxVcaEnvelopeK(shutTc, this.sampleRate);
6261
+ state[dbxBaseIdx + 3] = shutPrev + (shutTarget - shutPrev) * shutK;
6262
+ }
6263
+ const shutHeld = state[dbxBaseIdx + 3] ?? 0;
6264
+ const termsHeld = restHeld + envHeld;
6265
+ const rawDb = -termsHeld / 59e-4;
6266
+ const gainDb = Math.min(stamp.maxGainDb, Math.max(stamp.minGainDb, rawDb));
6267
+ const totalDb = Math.max(-100, gainDb - shutHeld / 59e-4);
6268
+ const gain = dbxVcaGainLinear(totalDb);
6269
+ const vPlus = solution[stamp.plus] ?? 0;
6270
+ const vMinus = solution[stamp.minus] ?? 0;
6271
+ const vIn = vPlus - vMinus;
6272
+ const iIn = vIn * stamp.inputSiemens;
6273
+ const iOut = iIn * gain;
6274
+ const gIn = gain * stamp.inputSiemens;
6275
+ const leaving = -iOut;
6276
+ const equivalent = leaving - (-gIn * vPlus + gIn * vMinus);
6277
+ if (stamp.output !== 0) {
6278
+ if (stamp.plus !== 0) {
6279
+ matrix[stamp.output][stamp.plus] += -gIn;
6280
+ }
6281
+ if (stamp.minus !== 0) {
6282
+ matrix[stamp.output][stamp.minus] += gIn;
6283
+ }
6284
+ rhs[stamp.output] = (rhs[stamp.output] ?? 0) - equivalent;
6285
+ }
6286
+ break;
6287
+ }
6149
6288
  case "spring-reverb": {
6150
6289
  const conductance = 1 / Math.max(stamp.inputOhms, MIN_STAMP_OHMS);
6151
6290
  matrix[stamp.inputPlus][stamp.inputPlus] += conductance;
package/package.json CHANGED
@@ -1,66 +1,66 @@
1
1
  {
2
- "name": "@vessel-dsp/runtime",
3
- "version": "0.7.0",
4
- "description": "Real-time MNA simulation runtime and solver console for VesselDSP Program ROMs.",
5
- "keywords": [
6
- "guitar-pedal",
7
- "electronics",
8
- "simulation",
9
- "dsp",
10
- "runtime",
11
- "solver",
12
- "mna"
13
- ],
14
- "homepage": "https://vessel-dsp.github.io/core/",
15
- "bugs": {
16
- "url": "https://github.com/vessel-dsp/core/issues"
17
- },
18
- "repository": {
19
- "type": "git",
20
- "url": "git+https://github.com/vessel-dsp/core.git"
21
- },
22
- "license": "MIT",
23
- "sideEffects": false,
24
- "type": "module",
25
- "exports": {
26
- ".": {
27
- "types": "./dist/index.d.ts",
28
- "bun": "./dist/index.js",
29
- "import": "./dist/index.js"
30
- },
31
- "./package.json": {
32
- "default": "./package.json"
33
- },
34
- "./wasm/*": {
35
- "default": "./dist/wasm/*"
36
- },
37
- "./worklet.js": {
38
- "default": "./dist/worklet/v2-audio-worklet.js"
39
- }
40
- },
41
- "main": "./dist/index.js",
42
- "module": "./dist/index.js",
43
- "types": "./dist/index.d.ts",
44
- "files": [
45
- "dist",
46
- "README.md",
47
- "LICENSE.md"
48
- ],
49
- "scripts": {
50
- "build": "tsc -p tsconfig.build.json && bun run ../../scripts/fix-dist-imports.ts dist && rm -rf dist/wasm && cp -r src/wasm dist/wasm && bun scripts/build-worklet.ts",
51
- "clean": "rm -rf dist",
52
- "prepack": "bun run --cwd ../core build && bun run --cwd ../compiler build && bun run build:wasm && bun run build",
53
- "pack:dry-run": "npm pack --dry-run",
54
- "typecheck": "tsc --noEmit -p tsconfig.json",
55
- "build:wasm": "bash scripts/build-wasm.sh",
56
- "build:worklet": "bun scripts/build-worklet.ts",
57
- "test": "bun test tests",
58
- "generate-kernels": "bun scripts/generate-kernels.ts"
59
- },
60
- "dependencies": {
61
- "@vessel-dsp/compiler": "0.9.0"
62
- },
63
- "publishConfig": {
64
- "access": "public"
65
- }
2
+ "name": "@vessel-dsp/runtime",
3
+ "version": "0.12.0",
4
+ "description": "Real-time MNA simulation runtime and solver console for VesselDSP Program ROMs.",
5
+ "keywords": [
6
+ "guitar-pedal",
7
+ "electronics",
8
+ "simulation",
9
+ "dsp",
10
+ "runtime",
11
+ "solver",
12
+ "mna"
13
+ ],
14
+ "homepage": "https://vessel-dsp.github.io/core/",
15
+ "bugs": {
16
+ "url": "https://github.com/vessel-dsp/core/issues"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/vessel-dsp/core.git"
21
+ },
22
+ "license": "MIT",
23
+ "sideEffects": false,
24
+ "type": "module",
25
+ "exports": {
26
+ ".": {
27
+ "types": "./dist/index.d.ts",
28
+ "bun": "./dist/index.js",
29
+ "import": "./dist/index.js"
30
+ },
31
+ "./package.json": {
32
+ "default": "./package.json"
33
+ },
34
+ "./wasm/*": {
35
+ "default": "./dist/wasm/*"
36
+ },
37
+ "./worklet.js": {
38
+ "default": "./dist/worklet/v2-audio-worklet.js"
39
+ }
40
+ },
41
+ "main": "./dist/index.js",
42
+ "module": "./dist/index.js",
43
+ "types": "./dist/index.d.ts",
44
+ "files": [
45
+ "dist",
46
+ "README.md",
47
+ "LICENSE.md"
48
+ ],
49
+ "scripts": {
50
+ "build": "tsc -p tsconfig.build.json && bun run ../../scripts/fix-dist-imports.ts dist && rm -rf dist/wasm && cp -r src/wasm dist/wasm && bun scripts/build-worklet.ts",
51
+ "clean": "rm -rf dist",
52
+ "prepack": "bun run --cwd ../core build && bun run --cwd ../compiler build && bun run build:wasm && bun run build",
53
+ "pack:dry-run": "npm pack --dry-run",
54
+ "typecheck": "tsc --noEmit -p tsconfig.json",
55
+ "build:wasm": "bash scripts/build-wasm.sh",
56
+ "build:worklet": "bun scripts/build-worklet.ts",
57
+ "test": "bun test tests",
58
+ "generate-kernels": "bun scripts/generate-kernels.ts"
59
+ },
60
+ "dependencies": {
61
+ "@vessel-dsp/compiler": "0.14.0"
62
+ },
63
+ "publishConfig": {
64
+ "access": "public"
65
+ }
66
66
  }