@effetune/dsp 0.5.0 → 0.7.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.
@@ -64,9 +64,21 @@
64
64
  "6",
65
65
  "7",
66
66
  "8",
67
+ "9",
68
+ "10",
69
+ "11",
70
+ "12",
71
+ "13",
72
+ "14",
73
+ "15",
74
+ "16",
67
75
  "34",
68
76
  "56",
69
- "78"
77
+ "78",
78
+ "910",
79
+ "1112",
80
+ "1314",
81
+ "1516"
70
82
  ],
71
83
  "default": "all"
72
84
  },
@@ -183,6 +195,9 @@
183
195
  {
184
196
  "$ref": "#/$defs/GroupDelayEQ"
185
197
  },
198
+ {
199
+ "$ref": "#/$defs/GroupDelayPEQ"
200
+ },
186
201
  {
187
202
  "$ref": "#/$defs/HiPassFilter"
188
203
  },
@@ -234,6 +249,9 @@
234
249
  {
235
250
  "$ref": "#/$defs/HumGenerator"
236
251
  },
252
+ {
253
+ "$ref": "#/$defs/MDSimulator"
254
+ },
237
255
  {
238
256
  "$ref": "#/$defs/MP3CodecSimulator"
239
257
  },
@@ -799,7 +817,7 @@
799
817
  "matrixRoutes": {
800
818
  "type": "string",
801
819
  "maxLength": 3072,
802
- "pattern": "^(?:p?[0-8][0-8])*$",
820
+ "pattern": "^(?:p?[0-9a-f][0-9a-f])*$",
803
821
  "default": "0011"
804
822
  }
805
823
  }
@@ -835,12 +853,20 @@
835
853
  "properties": {
836
854
  "mute": {
837
855
  "type": "array",
838
- "minItems": 8,
839
- "maxItems": 8,
856
+ "minItems": 16,
857
+ "maxItems": 16,
840
858
  "items": {
841
859
  "type": "boolean"
842
860
  },
843
861
  "default": [
862
+ false,
863
+ false,
864
+ false,
865
+ false,
866
+ false,
867
+ false,
868
+ false,
869
+ false,
844
870
  false,
845
871
  false,
846
872
  false,
@@ -853,12 +879,20 @@
853
879
  },
854
880
  "solo": {
855
881
  "type": "array",
856
- "minItems": 8,
857
- "maxItems": 8,
882
+ "minItems": 16,
883
+ "maxItems": 16,
858
884
  "items": {
859
885
  "type": "boolean"
860
886
  },
861
887
  "default": [
888
+ false,
889
+ false,
890
+ false,
891
+ false,
892
+ false,
893
+ false,
894
+ false,
895
+ false,
862
896
  false,
863
897
  false,
864
898
  false,
@@ -871,8 +905,8 @@
871
905
  },
872
906
  "volume": {
873
907
  "type": "array",
874
- "minItems": 8,
875
- "maxItems": 8,
908
+ "minItems": 16,
909
+ "maxItems": 16,
876
910
  "items": {
877
911
  "type": "number",
878
912
  "minimum": -20,
@@ -880,6 +914,14 @@
880
914
  "x-effetune-unit": "dB"
881
915
  },
882
916
  "default": [
917
+ 0,
918
+ 0,
919
+ 0,
920
+ 0,
921
+ 0,
922
+ 0,
923
+ 0,
924
+ 0,
883
925
  0,
884
926
  0,
885
927
  0,
@@ -892,8 +934,8 @@
892
934
  },
893
935
  "delay": {
894
936
  "type": "array",
895
- "minItems": 8,
896
- "maxItems": 8,
937
+ "minItems": 16,
938
+ "maxItems": 16,
897
939
  "items": {
898
940
  "type": "number",
899
941
  "minimum": 0,
@@ -901,6 +943,14 @@
901
943
  "x-effetune-unit": "ms"
902
944
  },
903
945
  "default": [
946
+ 0,
947
+ 0,
948
+ 0,
949
+ 0,
950
+ 0,
951
+ 0,
952
+ 0,
953
+ 0,
904
954
  0,
905
955
  0,
906
956
  0,
@@ -913,12 +963,20 @@
913
963
  },
914
964
  "link": {
915
965
  "type": "array",
916
- "minItems": 7,
917
- "maxItems": 7,
966
+ "minItems": 15,
967
+ "maxItems": 15,
918
968
  "items": {
919
969
  "type": "boolean"
920
970
  },
921
971
  "default": [
972
+ false,
973
+ false,
974
+ false,
975
+ false,
976
+ false,
977
+ false,
978
+ false,
979
+ false,
922
980
  false,
923
981
  false,
924
982
  false,
@@ -3163,6 +3221,67 @@
3163
3221
  }
3164
3222
  }
3165
3223
  },
3224
+ "GroupDelayPEQ": {
3225
+ "type": "object",
3226
+ "additionalProperties": false,
3227
+ "required": [
3228
+ "type",
3229
+ "parameters",
3230
+ "assets"
3231
+ ],
3232
+ "properties": {
3233
+ "id": {
3234
+ "type": "string",
3235
+ "minLength": 1,
3236
+ "maxLength": 128
3237
+ },
3238
+ "type": {
3239
+ "const": "GroupDelayPEQ"
3240
+ },
3241
+ "enabled": {
3242
+ "type": "boolean",
3243
+ "default": true
3244
+ },
3245
+ "channel": {
3246
+ "$ref": "#/$defs/channel"
3247
+ },
3248
+ "parameters": {
3249
+ "type": "object",
3250
+ "additionalProperties": false,
3251
+ "properties": {
3252
+ "latencyMode": {
3253
+ "type": "string",
3254
+ "enum": [
3255
+ "0",
3256
+ "128",
3257
+ "256",
3258
+ "512",
3259
+ "1024"
3260
+ ],
3261
+ "default": "128"
3262
+ },
3263
+ "filterDelaySamples": {
3264
+ "type": "integer",
3265
+ "minimum": 0,
3266
+ "maximum": 65536,
3267
+ "default": 8192
3268
+ }
3269
+ }
3270
+ },
3271
+ "assets": {
3272
+ "type": "object",
3273
+ "additionalProperties": false,
3274
+ "required": [
3275
+ "impulseResponse"
3276
+ ],
3277
+ "properties": {
3278
+ "impulseResponse": {
3279
+ "$ref": "#/$defs/assetReference"
3280
+ }
3281
+ }
3282
+ }
3283
+ }
3284
+ },
3166
3285
  "HiPassFilter": {
3167
3286
  "type": "object",
3168
3287
  "additionalProperties": false,
@@ -4524,6 +4643,60 @@
4524
4643
  }
4525
4644
  }
4526
4645
  },
4646
+ "MDSimulator": {
4647
+ "type": "object",
4648
+ "additionalProperties": false,
4649
+ "required": [
4650
+ "type",
4651
+ "parameters"
4652
+ ],
4653
+ "properties": {
4654
+ "id": {
4655
+ "type": "string",
4656
+ "minLength": 1,
4657
+ "maxLength": 128
4658
+ },
4659
+ "type": {
4660
+ "const": "MDSimulator"
4661
+ },
4662
+ "enabled": {
4663
+ "type": "boolean",
4664
+ "default": true
4665
+ },
4666
+ "channel": {
4667
+ "$ref": "#/$defs/channel"
4668
+ },
4669
+ "parameters": {
4670
+ "type": "object",
4671
+ "additionalProperties": false,
4672
+ "properties": {
4673
+ "mode": {
4674
+ "type": "string",
4675
+ "enum": [
4676
+ "SP (292 kbps)",
4677
+ "LP2 (132 kbps)",
4678
+ "LP4 (66 kbps)"
4679
+ ],
4680
+ "default": "SP (292 kbps)"
4681
+ },
4682
+ "outputGain": {
4683
+ "type": "number",
4684
+ "minimum": -24,
4685
+ "maximum": 12,
4686
+ "x-effetune-unit": "dB",
4687
+ "default": 0
4688
+ },
4689
+ "mix": {
4690
+ "type": "number",
4691
+ "minimum": 0,
4692
+ "maximum": 100,
4693
+ "x-effetune-unit": "%",
4694
+ "default": 100
4695
+ }
4696
+ }
4697
+ }
4698
+ }
4699
+ },
4527
4700
  "MP3CodecSimulator": {
4528
4701
  "type": "object",
4529
4702
  "additionalProperties": false,
@@ -5068,7 +5241,7 @@
5068
5241
  "type": "number",
5069
5242
  "minimum": 0,
5070
5243
  "maximum": 10,
5071
- "default": 0
5244
+ "default": 10
5072
5245
  },
5073
5246
  "wear": {
5074
5247
  "type": "integer",
@@ -6309,7 +6482,7 @@
6309
6482
  "minimum": -36,
6310
6483
  "maximum": 36,
6311
6484
  "x-effetune-unit": "dB",
6312
- "default": 30
6485
+ "default": 26
6313
6486
  }
6314
6487
  }
6315
6488
  }
@@ -6395,7 +6568,7 @@
6395
6568
  "minimum": -36,
6396
6569
  "maximum": 36,
6397
6570
  "x-effetune-unit": "dB",
6398
- "default": 30
6571
+ "default": 26
6399
6572
  }
6400
6573
  }
6401
6574
  }
@@ -8081,6 +8254,93 @@
8081
8254
  100,
8082
8255
  100
8083
8256
  ]
8257
+ },
8258
+ "regionSolo": {
8259
+ "type": "array",
8260
+ "minItems": 5,
8261
+ "maxItems": 5,
8262
+ "items": {
8263
+ "type": "boolean"
8264
+ },
8265
+ "default": [
8266
+ false,
8267
+ false,
8268
+ false,
8269
+ false,
8270
+ false
8271
+ ]
8272
+ },
8273
+ "outerBalanceLow": {
8274
+ "type": "array",
8275
+ "minItems": 5,
8276
+ "maxItems": 5,
8277
+ "items": {
8278
+ "type": "number",
8279
+ "minimum": -100,
8280
+ "maximum": 100,
8281
+ "x-effetune-unit": "%"
8282
+ },
8283
+ "default": [
8284
+ -100,
8285
+ -100,
8286
+ -100,
8287
+ -100,
8288
+ -100
8289
+ ]
8290
+ },
8291
+ "coreBalanceLow": {
8292
+ "type": "array",
8293
+ "minItems": 5,
8294
+ "maxItems": 5,
8295
+ "items": {
8296
+ "type": "number",
8297
+ "minimum": -100,
8298
+ "maximum": 100,
8299
+ "x-effetune-unit": "%"
8300
+ },
8301
+ "default": [
8302
+ -100,
8303
+ -100,
8304
+ -100,
8305
+ -100,
8306
+ -100
8307
+ ]
8308
+ },
8309
+ "coreBalanceHigh": {
8310
+ "type": "array",
8311
+ "minItems": 5,
8312
+ "maxItems": 5,
8313
+ "items": {
8314
+ "type": "number",
8315
+ "minimum": -100,
8316
+ "maximum": 100,
8317
+ "x-effetune-unit": "%"
8318
+ },
8319
+ "default": [
8320
+ 100,
8321
+ 100,
8322
+ 100,
8323
+ 100,
8324
+ 100
8325
+ ]
8326
+ },
8327
+ "outerBalanceHigh": {
8328
+ "type": "array",
8329
+ "minItems": 5,
8330
+ "maxItems": 5,
8331
+ "items": {
8332
+ "type": "number",
8333
+ "minimum": -100,
8334
+ "maximum": 100,
8335
+ "x-effetune-unit": "%"
8336
+ },
8337
+ "default": [
8338
+ 100,
8339
+ 100,
8340
+ 100,
8341
+ 100,
8342
+ 100
8343
+ ]
8084
8344
  }
8085
8345
  }
8086
8346
  }
package/dist/semantics.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { DSP_PARAM_PACKERS } from './internal/dsp-params.generated.js';
2
2
  import { getEffectDefinition, getEffectImplementation } from './catalog.js';
3
- import { Effect, validateChannel, validateParameterValue } from './effect.js';
3
+ import {
4
+ Effect, canonicalizeProcessingParameters, validateChannel, validateParameterValue
5
+ } from './effect.js';
4
6
  import {
5
7
  AssetError,
6
8
  EffeTuneError,
@@ -15,6 +17,7 @@ const STREAM_RECONFIGURATION_PARAMETERS = new Map([
15
17
  ['FIRCrossover', new Set(['bandCount', 'latencyMode', 'filterDelaySamples'])],
16
18
  ['FiveBandFIRPEQ', new Set(['latencyMode', 'filterDelaySamples'])],
17
19
  ['GroupDelayEQ', new Set(['latencyMode', 'filterDelaySamples'])],
20
+ ['GroupDelayPEQ', new Set(['latencyMode', 'filterDelaySamples'])],
18
21
  ['IRReverb', new Set(['channelMode', 'latency', 'convolutionRate'])],
19
22
  ['RoomEQ', new Set(['latencyMode', 'filterDelaySamples'])]
20
23
  ]);
@@ -230,6 +233,7 @@ function toInternalValue(transform, value) {
230
233
  }
231
234
 
232
235
  export function packEffect(effect) {
236
+ const parameters = canonicalizeProcessingParameters(effect.type, effect.parameters);
233
237
  const implementation = getEffectImplementation(effect.type);
234
238
  const packer = DSP_PARAM_PACKERS.get(implementation.internalType);
235
239
  if (!packer || (packer.hash >>> 0) !== (implementation.layoutHash >>> 0)) {
@@ -237,7 +241,7 @@ export function packEffect(effect) {
237
241
  }
238
242
  const internal = {};
239
243
  for (const mapping of implementation.packedParameters) {
240
- const value = effect.parameters[mapping.publicName];
244
+ const value = parameters[mapping.publicName];
241
245
  if (mapping.count === 1) {
242
246
  internal[mapping.keys[0]] = toInternalValue(mapping.transform, value);
243
247
  } else {
@@ -248,7 +252,7 @@ export function packEffect(effect) {
248
252
  }
249
253
  const structured = implementation.structuredParameter;
250
254
  if (structured) {
251
- internal[structured.key] = effect.parameters[structured.publicName];
255
+ internal[structured.key] = parameters[structured.publicName];
252
256
  }
253
257
  // The generated packer reports capacity limits with plain JavaScript errors.
254
258
  // Translating them here keeps every public entry point (process, stream, setParam)
@@ -301,18 +305,7 @@ export function setEffectParameter(effect, parameterName, value) {
301
305
 
302
306
  export function canonicalizeEffectForProcessing(effect) {
303
307
  const canonical = cloneEffect(effect);
304
- const parameters = canonical.parameters;
305
- if (effect.type === 'AutoFilter' &&
306
- parameters.minimumFrequency > parameters.maximumFrequency) {
307
- [parameters.minimumFrequency, parameters.maximumFrequency] =
308
- [parameters.maximumFrequency, parameters.minimumFrequency];
309
- } else if (effect.type === 'Chorus' && parameters.depth > parameters.delay) {
310
- parameters.depth = parameters.delay;
311
- } else if (effect.type === 'FrequencyShifter' &&
312
- parameters.minimumShift > parameters.maximumShift) {
313
- [parameters.minimumShift, parameters.maximumShift] =
314
- [parameters.maximumShift, parameters.minimumShift];
315
- }
308
+ canonical.parameters = canonicalizeProcessingParameters(effect.type, canonical.parameters);
316
309
  return canonical;
317
310
  }
318
311
 
@@ -327,8 +320,8 @@ export function validateStreamParameterUpdate(effect, parameterName) {
327
320
 
328
321
  export function channelRange(channel, channelCount) {
329
322
  validateChannel(channel);
330
- if (!Number.isInteger(channelCount) || channelCount < 1 || channelCount > 8) {
331
- throw new ValidationError('Audio must contain between 1 and 8 channels.');
323
+ if (!Number.isInteger(channelCount) || channelCount < 1 || channelCount > 16) {
324
+ throw new ValidationError('Audio must contain between 1 and 16 channels.');
332
325
  }
333
326
  if (channel === 'all') return { start: 0, count: channelCount };
334
327
  if (channel === 'stereo') return { start: 0, count: channelCount >= 2 ? 2 : 1 };
@@ -337,8 +330,9 @@ export function channelRange(channel, channelCount) {
337
330
  if (channelCount < 2) throw new ValidationError('The right channel is unavailable in mono audio.');
338
331
  return { start: 1, count: 1 };
339
332
  }
340
- if (channel === '34' || channel === '56' || channel === '78') {
341
- const start = Number(channel[0]) - 1;
333
+ const pairStart = { '34': 2, '56': 4, '78': 6, '910': 8, '1112': 10, '1314': 12, '1516': 14 }[channel];
334
+ if (pairStart !== undefined) {
335
+ const start = pairStart;
342
336
  if (channelCount < start + 2) {
343
337
  throw new ValidationError(`Channel pair ${channel} is unavailable in ${channelCount}-channel audio.`);
344
338
  }
package/dist/telemetry.js CHANGED
@@ -34,7 +34,7 @@ function common(node, kind, sequence, dropped) {
34
34
  function decodeLevel(payload, node, sequence, dropped) {
35
35
  if (payload.byteLength < 16) return null;
36
36
  const channelCount = payload.getUint32(0, true);
37
- if (channelCount < 1 || channelCount > 8 || payload.byteLength !== 8 + channelCount * 8) {
37
+ if (channelCount < 1 || channelCount > 16 || payload.byteLength !== 8 + channelCount * 8) {
38
38
  return null;
39
39
  }
40
40
  const clipFlags = payload.getUint32(4 + channelCount * 8, true);
package/dist/worklet.js CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  } from './errors.js';
9
9
  import {
10
10
  normalizeChainDocument,
11
+ canonicalizeEffectForProcessing,
11
12
  channelRange,
12
13
  packEffect,
13
14
  setEffectParameter,
@@ -42,8 +43,8 @@ function cloneDocument(document) {
42
43
  }
43
44
 
44
45
  function validateChannels(channels) {
45
- if (!Number.isInteger(channels) || channels < 1 || channels > 8) {
46
- throw new ValidationError('channels must be an integer from 1 to 8.');
46
+ if (!Number.isInteger(channels) || channels < 1 || channels > 16) {
47
+ throw new ValidationError('channels must be an integer from 1 to 16.');
47
48
  }
48
49
  return channels;
49
50
  }
@@ -124,7 +125,11 @@ export class EffeTuneNode extends AudioWorkletNodeBase {
124
125
  })()
125
126
  : input;
126
127
  const { chain, manifest } = splitBundle(source);
127
- const document = normalizeChainDocument(chain);
128
+ const normalized = normalizeChainDocument(chain);
129
+ const document = {
130
+ version: 1,
131
+ chain: normalized.chain.map(canonicalizeEffectForProcessing)
132
+ };
128
133
  const resolvedAssets = await resolveChainAssets(document, {
129
134
  assetResolver: options.assetResolver,
130
135
  manifest
@@ -359,7 +364,9 @@ export class EffeTuneNode extends AudioWorkletNodeBase {
359
364
  if (index < 0) throw new ValidationError(`Unknown effect id: ${effectId}`);
360
365
  const effects = [...this._document.chain];
361
366
  validateStreamParameterUpdate(effects[index], parameterName);
362
- effects[index] = setEffectParameter(effects[index], parameterName, value);
367
+ effects[index] = canonicalizeEffectForProcessing(
368
+ setEffectParameter(effects[index], parameterName, value)
369
+ );
363
370
  if (effects[index].enabled) {
364
371
  const packed = packEffect(effects[index]);
365
372
  await this._command({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effetune/dsp",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "EffeTune's deterministic WebAssembly audio effects for JavaScript and AudioWorklet",
5
5
  "type": "module",
6
6
  "license": "MIT",