@vessel-dsp/runtime 0.7.0 → 0.14.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,45 @@ 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, shape = 1, maxSeconds = Number.POSITIVE_INFINITY) {
1413
+ const depth = Math.min(1, Math.max(0, depth01));
1414
+ return Math.min(
1415
+ maxSeconds,
1416
+ baseSeconds * Math.pow(slowdown, Math.pow(depth, shape))
1417
+ );
1418
+ }
1419
+ function dbxVcaPrimeTarget(inputAmps, refCurrentAmps) {
1420
+ return Math.abs(inputAmps) > refCurrentAmps ? 0 : 1;
1421
+ }
1422
+ function dbxVcaShutdownTarget(peakTargetVolts, edgeThreshVolts, primed01, gainPerVolt) {
1423
+ const excess = peakTargetVolts - edgeThreshVolts;
1424
+ if (!(excess > 0) || !(primed01 > 0)) return 0;
1425
+ const primed = Math.min(1, primed01);
1426
+ return gainPerVolt * excess * excess * primed;
1427
+ }
1428
+ function dbxVcaVictimTc(primed01, fastSeconds, slowSeconds) {
1429
+ const primed = Math.min(1, Math.max(0, primed01));
1430
+ return primed > 0.05 ? slowSeconds : fastSeconds;
1431
+ }
1432
+ function dbxVcaEnvelopeK(tcSeconds, sampleRate2) {
1433
+ const denom = tcSeconds * sampleRate2;
1434
+ if (!(denom > 0)) return 1;
1435
+ return 1 - Math.exp(-1 / denom);
1436
+ }
1398
1437
  var NEWTON_UNPRODUCTIVE_ITERATIONS = 64;
1399
1438
  var NEWTON_UNPRODUCTIVE_PROBATION_SAMPLES = 1024;
1400
1439
  var NEWTON_RELATIVE_TOLERANCE = 1e-3;
@@ -1577,7 +1616,10 @@ var IMPLEMENTED_OPERATORS = {
1577
1616
  "clock-driver": true,
1578
1617
  comparator: true,
1579
1618
  // Linear-control VCA cell. Reads the control node, draws nothing.
1580
- "linear-vca": true
1619
+ "linear-vca": true,
1620
+ // dbx-style VCA cell (uPC1252H2). Bounded sigmoidal gain in the
1621
+ // control voltage. Reads the control node, draws nothing.
1622
+ "dbx-vca": true
1581
1623
  };
1582
1624
  function unimplementedOperators(required) {
1583
1625
  return required.filter(
@@ -6146,6 +6188,106 @@ var ReferenceRuntime = class {
6146
6188
  }
6147
6189
  break;
6148
6190
  }
6191
+ case "dbx-vca": {
6192
+ const dbxBaseIdx = stamp.stateIndex;
6193
+ const ctrlKey = `${block.id}_dbxc_${dbxBaseIdx}`;
6194
+ if (this.elapsedSamples !== (this.lastShiftedSample.get(ctrlKey) ?? -1)) {
6195
+ this.lastShiftedSample.set(ctrlKey, this.elapsedSamples);
6196
+ const vCtrlNow = solution[stamp.control] ?? 0;
6197
+ const ctrlPrev = state[dbxBaseIdx] ?? 0;
6198
+ const ctrlTc = vCtrlNow > ctrlPrev ? stamp.attackSeconds : stamp.releaseSeconds;
6199
+ const ctrlK = dbxVcaEnvelopeK(ctrlTc, this.sampleRate);
6200
+ state[dbxBaseIdx] = ctrlPrev + (vCtrlNow - ctrlPrev) * ctrlK;
6201
+ }
6202
+ const vCtrlHeld = state[dbxBaseIdx] ?? 0;
6203
+ const restHeld = dbxVcaRestTerms(
6204
+ vCtrlHeld,
6205
+ stamp.sustainGain,
6206
+ stamp.sustainRef
6207
+ );
6208
+ const kneeHeld = dbxVcaKneeVolts(
6209
+ vCtrlHeld,
6210
+ stamp.kneeBaseVolts,
6211
+ stamp.kneeTrack
6212
+ );
6213
+ const vInInstDbx = (solution[stamp.plus] ?? 0) - (solution[stamp.minus] ?? 0);
6214
+ const iInInstDbx = vInInstDbx * stamp.inputSiemens;
6215
+ const primeKey = `${block.id}_dbxp_${dbxBaseIdx}`;
6216
+ if (this.elapsedSamples !== (this.lastShiftedSample.get(primeKey) ?? -1)) {
6217
+ this.lastShiftedSample.set(primeKey, this.elapsedSamples);
6218
+ const primeTarget = dbxVcaPrimeTarget(
6219
+ iInInstDbx,
6220
+ stamp.primeRefCurrent
6221
+ );
6222
+ const primePrev = state[dbxBaseIdx + 2] ?? 0;
6223
+ const primeTc = primeTarget > primePrev ? stamp.primeRiseSeconds : stamp.primeFallSeconds;
6224
+ const primeK = dbxVcaEnvelopeK(primeTc, this.sampleRate);
6225
+ state[dbxBaseIdx + 2] = primePrev + (primeTarget - primePrev) * primeK;
6226
+ }
6227
+ const primeHeld = state[dbxBaseIdx + 2] ?? 0;
6228
+ const envKey = `${block.id}_dbxe_${dbxBaseIdx}`;
6229
+ if (this.elapsedSamples !== (this.lastShiftedSample.get(envKey) ?? -1)) {
6230
+ this.lastShiftedSample.set(envKey, this.elapsedSamples);
6231
+ const envTarget = dbxVcaEnvelopeTerms(
6232
+ iInInstDbx,
6233
+ stamp.envelopeSlope,
6234
+ kneeHeld
6235
+ );
6236
+ const envPrev = state[dbxBaseIdx + 1] ?? 0;
6237
+ const envDepth = Math.min(1, Math.max(0, envPrev / 0.15));
6238
+ const envTc = envTarget > envPrev ? stamp.attackSeconds : dbxVcaReleaseTc(envDepth, stamp.releaseSeconds, stamp.releaseSlowdown, stamp.releaseShape, stamp.releaseMaxSeconds);
6239
+ const envK = dbxVcaEnvelopeK(envTc, this.sampleRate);
6240
+ state[dbxBaseIdx + 1] = envPrev + (envTarget - envPrev) * envK;
6241
+ }
6242
+ const envHeld = state[dbxBaseIdx + 1] ?? 0;
6243
+ const shutKey = `${block.id}_dbxs_${dbxBaseIdx}`;
6244
+ if (this.elapsedSamples !== (this.lastShiftedSample.get(shutKey) ?? -1)) {
6245
+ this.lastShiftedSample.set(shutKey, this.elapsedSamples);
6246
+ const peakTarget = dbxVcaEnvelopeTerms(
6247
+ iInInstDbx,
6248
+ stamp.envelopeSlope,
6249
+ kneeHeld
6250
+ );
6251
+ const shutTarget = dbxVcaShutdownTarget(
6252
+ peakTarget,
6253
+ stamp.shutdownEdgeVolts,
6254
+ primeHeld,
6255
+ stamp.shutdownGain
6256
+ );
6257
+ const shutPrev = state[dbxBaseIdx + 3] ?? 0;
6258
+ const shutTc = shutTarget > shutPrev ? stamp.shutdownAttackSeconds : dbxVcaVictimTc(
6259
+ primeHeld,
6260
+ stamp.shutdownFastSeconds,
6261
+ stamp.shutdownSlowSeconds
6262
+ );
6263
+ const shutK = dbxVcaEnvelopeK(shutTc, this.sampleRate);
6264
+ state[dbxBaseIdx + 3] = shutPrev + (shutTarget - shutPrev) * shutK;
6265
+ }
6266
+ const shutHeld = state[dbxBaseIdx + 3] ?? 0;
6267
+ const termsHeld = restHeld + envHeld;
6268
+ const rawDb = -termsHeld / 59e-4;
6269
+ const gainDb = Math.min(stamp.maxGainDb, Math.max(stamp.minGainDb, rawDb));
6270
+ const totalDb = Math.max(-100, gainDb - shutHeld / 59e-4);
6271
+ const gain = dbxVcaGainLinear(totalDb);
6272
+ const vPlus = solution[stamp.plus] ?? 0;
6273
+ const vMinus = solution[stamp.minus] ?? 0;
6274
+ const vIn = vPlus - vMinus;
6275
+ const iIn = vIn * stamp.inputSiemens;
6276
+ const iOut = iIn * gain;
6277
+ const gIn = gain * stamp.inputSiemens;
6278
+ const leaving = -iOut;
6279
+ const equivalent = leaving - (-gIn * vPlus + gIn * vMinus);
6280
+ if (stamp.output !== 0) {
6281
+ if (stamp.plus !== 0) {
6282
+ matrix[stamp.output][stamp.plus] += -gIn;
6283
+ }
6284
+ if (stamp.minus !== 0) {
6285
+ matrix[stamp.output][stamp.minus] += gIn;
6286
+ }
6287
+ rhs[stamp.output] = (rhs[stamp.output] ?? 0) - equivalent;
6288
+ }
6289
+ break;
6290
+ }
6149
6291
  case "spring-reverb": {
6150
6292
  const conductance = 1 / Math.max(stamp.inputOhms, MIN_STAMP_OHMS);
6151
6293
  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.14.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.16.0"
62
+ },
63
+ "publishConfig": {
64
+ "access": "public"
65
+ }
66
66
  }