@opendaw/studio-adapters 0.0.119 → 0.0.120

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.
@@ -12,7 +12,7 @@ export declare namespace RingBuffer {
12
12
  interface Reader {
13
13
  stop(): void;
14
14
  }
15
- const reader: ({ sab, numChunks, numberOfChannels, bufferSize }: Config, append: Procedure<Array<Float32Array>>) => Reader;
15
+ const reader: (config: Config, append: Procedure<Array<Float32Array>>) => Reader;
16
16
  const writer: ({ sab, numChunks, numberOfChannels, bufferSize }: Config) => Writer;
17
17
  }
18
18
  export declare const mergeChunkPlanes: (chunks: ReadonlyArray<ReadonlyArray<Float32Array>>, bufferSize: int, maxFrames?: int) => ReadonlyArray<Float32Array>;
@@ -1 +1 @@
1
- {"version":3,"file":"RingBuffer.d.ts","sourceRoot":"","sources":["../src/RingBuffer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,GAAG,EAAS,SAAS,EAAC,MAAM,kBAAkB,CAAA;AAItE,yBAAiB,UAAU,CAAC;IACxB,UAAiB,MAAM;QACnB,GAAG,EAAE,iBAAiB,CAAA;QACtB,SAAS,EAAE,GAAG,CAAA;QACd,gBAAgB,EAAE,GAAG,CAAA;QACrB,UAAU,EAAE,GAAG,CAAA;KAClB;IAED,UAAiB,MAAM;QAAE,KAAK,CAAC,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,GAAG,IAAI,CAAA;KAAC;IAE5E,UAAiB,MAAM;QAAE,IAAI,IAAI,IAAI,CAAA;KAAC;IAE/B,MAAM,MAAM,GAAI,kDAKG,MAAM,EAAE,QAAQ,SAAS,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,KAAG,MAqC1E,CAAA;IAEM,MAAM,MAAM,GAAI,kDAAgD,MAAM,KAAG,MAqB/E,CAAA;CACJ;AAED,eAAO,MAAM,gBAAgB,GAAI,QAAQ,aAAa,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,EAClD,YAAY,GAAG,EACf,YAAW,GAA6B,KAAG,aAAa,CAAC,YAAY,CAkBrG,CAAA"}
1
+ {"version":3,"file":"RingBuffer.d.ts","sourceRoot":"","sources":["../src/RingBuffer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,GAAG,EAAS,SAAS,EAAC,MAAM,kBAAkB,CAAA;AAEtE,yBAAiB,UAAU,CAAC;IACxB,UAAiB,MAAM;QACnB,GAAG,EAAE,iBAAiB,CAAA;QACtB,SAAS,EAAE,GAAG,CAAA;QACd,gBAAgB,EAAE,GAAG,CAAA;QACrB,UAAU,EAAE,GAAG,CAAA;KAClB;IAED,UAAiB,MAAM;QAAE,KAAK,CAAC,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,GAAG,IAAI,CAAA;KAAC;IAE5E,UAAiB,MAAM;QAAE,IAAI,IAAI,IAAI,CAAA;KAAC;IAM/B,MAAM,MAAM,GAAI,QAAQ,MAAM,EAAE,QAAQ,SAAS,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,KAAG,MA8C/E,CAAA;IAEM,MAAM,MAAM,GAAI,kDAAgD,MAAM,KAAG,MAqB/E,CAAA;CACJ;AAED,eAAO,MAAM,gBAAgB,GAAI,QAAQ,aAAa,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,EAClD,YAAY,GAAG,EACf,YAAW,GAA6B,KAAG,aAAa,CAAC,YAAY,CAkBrG,CAAA"}
@@ -1,48 +1,58 @@
1
1
  import { Arrays, assert, panic } from "@opendaw/lib-std";
2
2
  export var RingBuffer;
3
3
  (function (RingBuffer) {
4
- RingBuffer.reader = ({ sab, numChunks, numberOfChannels, bufferSize }, append) => {
5
- let running = true;
6
- const pointers = new Int32Array(sab, 0, 2);
7
- const audio = new Float32Array(sab, 8);
8
- const planarChunk = new Float32Array(numberOfChannels * bufferSize);
9
- const canBlock = typeof document === "undefined"; // for usage in workers
10
- const step = () => {
11
- if (!running) {
12
- return;
13
- }
14
- let readPtr = Atomics.load(pointers, 1);
15
- let writePtr = Atomics.load(pointers, 0);
16
- if (readPtr === writePtr) {
17
- if (canBlock) {
18
- Atomics.wait(pointers, 0, writePtr);
19
- }
20
- else {
21
- setTimeout(step, 1); // non‑blocking poll fallback
22
- return;
4
+ // The reader drains the ring on a dedicated worker that blocks on `Atomics.wait` (woken by the writer's
5
+ // `Atomics.notify`). This avoids the main-thread `setTimeout` polling that Chrome throttles to ~1s in hidden
6
+ // tabs, which used to overrun the ring (~0.37s) and silently drop recorded audio. Drained chunks are posted
7
+ // back (transferred) so the caller's `append` still runs on the main thread. See issue #290.
8
+ RingBuffer.reader = (config, append) => {
9
+ const code = `
10
+ onmessage = (event) => {
11
+ const {sab, numChunks, numberOfChannels, bufferSize} = event.data
12
+ const pointers = new Int32Array(sab, 0, 2)
13
+ const audio = new Float32Array(sab, 8)
14
+ const chunkFloats = numberOfChannels * bufferSize
15
+ while (true) {
16
+ let readPtr = Atomics.load(pointers, 1)
17
+ let writePtr = Atomics.load(pointers, 0)
18
+ if (readPtr === writePtr) {
19
+ Atomics.wait(pointers, 0, writePtr)
20
+ writePtr = Atomics.load(pointers, 0)
21
+ }
22
+ const batch = []
23
+ const transfer = []
24
+ while (readPtr !== writePtr) {
25
+ const offset = readPtr * chunkFloats
26
+ const channels = []
27
+ for (let channel = 0; channel < numberOfChannels; channel++) {
28
+ const start = offset + channel * bufferSize
29
+ const frames = audio.slice(start, start + bufferSize)
30
+ channels.push(frames)
31
+ transfer.push(frames.buffer)
32
+ }
33
+ readPtr = (readPtr + 1) % numChunks
34
+ Atomics.store(pointers, 1, readPtr)
35
+ batch.push(channels)
36
+ }
37
+ postMessage(batch, transfer)
23
38
  }
24
- writePtr = Atomics.load(pointers, 0);
25
39
  }
26
- while (readPtr !== writePtr) {
27
- const offset = readPtr * numberOfChannels * bufferSize;
28
- planarChunk.set(audio.subarray(offset, offset + numberOfChannels * bufferSize));
29
- const channels = [];
30
- for (let channel = 0; channel < numberOfChannels; channel++) {
31
- const start = channel * bufferSize;
32
- const end = start + bufferSize;
33
- channels.push(planarChunk.slice(start, end));
34
- }
35
- readPtr = (readPtr + 1) % numChunks;
36
- Atomics.store(pointers, 1, readPtr);
37
- if (!running) {
38
- return;
39
- }
40
+ `;
41
+ const url = URL.createObjectURL(new Blob([code], { type: "application/javascript" }));
42
+ const worker = new Worker(url);
43
+ worker.onmessage = (event) => {
44
+ const batch = event.data;
45
+ for (const channels of batch) {
40
46
  append(channels);
41
47
  }
42
- step();
43
48
  };
44
- step();
45
- return { stop: () => running = false };
49
+ worker.postMessage(config);
50
+ return {
51
+ stop: () => {
52
+ worker.terminate();
53
+ URL.revokeObjectURL(url);
54
+ }
55
+ };
46
56
  };
47
57
  RingBuffer.writer = ({ sab, numChunks, numberOfChannels, bufferSize }) => {
48
58
  const pointers = new Int32Array(sab, 0, 2);
@@ -17,8 +17,8 @@ export declare class VocoderDeviceBoxAdapter implements AudioEffectDeviceAdapter
17
17
  readonly carrierMaxFreq: import("../..").AutomatableParameterFieldAdapter<number>;
18
18
  readonly modulatorMinFreq: import("../..").AutomatableParameterFieldAdapter<number>;
19
19
  readonly modulatorMaxFreq: import("../..").AutomatableParameterFieldAdapter<number>;
20
- readonly qMin: import("../..").AutomatableParameterFieldAdapter<number>;
21
- readonly qMax: import("../..").AutomatableParameterFieldAdapter<number>;
20
+ readonly qStart: import("../..").AutomatableParameterFieldAdapter<number>;
21
+ readonly qEnd: import("../..").AutomatableParameterFieldAdapter<number>;
22
22
  readonly envAttack: import("../..").AutomatableParameterFieldAdapter<number>;
23
23
  readonly envRelease: import("../..").AutomatableParameterFieldAdapter<number>;
24
24
  readonly gain: import("../..").AutomatableParameterFieldAdapter<number>;
@@ -59,8 +59,8 @@ _VocoderDeviceBoxAdapter_context = new WeakMap(), _VocoderDeviceBoxAdapter_box =
59
59
  carrierMaxFreq: __classPrivateFieldGet(this, _VocoderDeviceBoxAdapter_parametric, "f").createParameter(box.carrierMaxFreq, freqMap, freqStr, "Carrier Max"),
60
60
  modulatorMinFreq: __classPrivateFieldGet(this, _VocoderDeviceBoxAdapter_parametric, "f").createParameter(box.modulatorMinFreq, freqMap, freqStr, "Mod Min"),
61
61
  modulatorMaxFreq: __classPrivateFieldGet(this, _VocoderDeviceBoxAdapter_parametric, "f").createParameter(box.modulatorMaxFreq, freqMap, freqStr, "Mod Max"),
62
- qMin: __classPrivateFieldGet(this, _VocoderDeviceBoxAdapter_parametric, "f").createParameter(box.qMin, qMap, qStr, "Q Min"),
63
- qMax: __classPrivateFieldGet(this, _VocoderDeviceBoxAdapter_parametric, "f").createParameter(box.qMax, qMap, qStr, "Q Max"),
62
+ qStart: __classPrivateFieldGet(this, _VocoderDeviceBoxAdapter_parametric, "f").createParameter(box.qStart, qMap, qStr, "Q Start"),
63
+ qEnd: __classPrivateFieldGet(this, _VocoderDeviceBoxAdapter_parametric, "f").createParameter(box.qEnd, qMap, qStr, "Q End"),
64
64
  envAttack: __classPrivateFieldGet(this, _VocoderDeviceBoxAdapter_parametric, "f").createParameter(box.envAttack, ValueMapping.exponential(0.1, 100.0), StringMapping.numeric({ unit: "ms", fractionDigits: 1 }), "Attack"),
65
65
  envRelease: __classPrivateFieldGet(this, _VocoderDeviceBoxAdapter_parametric, "f").createParameter(box.envRelease, ValueMapping.exponential(1.0, 1000.0), StringMapping.numeric({ unit: "ms", fractionDigits: 0 }), "Release"),
66
66
  gain: __classPrivateFieldGet(this, _VocoderDeviceBoxAdapter_parametric, "f").createParameter(box.gain, ValueMapping.linear(-20.0, 20.0), StringMapping.decible, "Gain"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opendaw/studio-adapters",
3
- "version": "0.0.119",
3
+ "version": "0.0.120",
4
4
  "license": "LGPL-3.0-or-later",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -25,19 +25,19 @@
25
25
  "pregenerate-all-boxes": "npm run build -w @opendaw/studio-forge-boxes && npm run build -w @opendaw/studio-boxes"
26
26
  },
27
27
  "dependencies": {
28
- "@opendaw/lib-box": "^0.0.88",
29
- "@opendaw/lib-dsp": "^0.0.86",
30
- "@opendaw/lib-fusion": "^0.0.96",
31
- "@opendaw/lib-midi": "^0.0.68",
32
- "@opendaw/lib-runtime": "^0.0.81",
33
- "@opendaw/lib-std": "^0.0.80",
34
- "@opendaw/studio-boxes": "^0.0.96",
35
- "@opendaw/studio-enums": "^0.0.79",
28
+ "@opendaw/lib-box": "^0.0.89",
29
+ "@opendaw/lib-dsp": "^0.0.87",
30
+ "@opendaw/lib-fusion": "^0.0.97",
31
+ "@opendaw/lib-midi": "^0.0.69",
32
+ "@opendaw/lib-runtime": "^0.0.82",
33
+ "@opendaw/lib-std": "^0.0.81",
34
+ "@opendaw/studio-boxes": "^0.0.97",
35
+ "@opendaw/studio-enums": "^0.0.80",
36
36
  "soundfont2": "^0.5.0"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@opendaw/eslint-config": "^0.0.28",
40
40
  "@opendaw/typescript-config": "^0.0.32"
41
41
  },
42
- "gitHead": "39217ab3e0c5e488cb21ca20e1fcd673e6f60142"
42
+ "gitHead": "8b806c880c2642b10f277e8b74c31aeafe7e6bfc"
43
43
  }