node-web-audio-api 0.21.5 → 1.0.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/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## v1.0.0 (11/01/2024)
4
+
5
+ - Align version with upsteam crate
6
+ - Refactor CI
7
+
3
8
  ## v0.21.5 (23/12/2024)
4
9
 
5
10
  - Fix: Use module import for `AudioWorklet#addModule`
@@ -5,6 +5,7 @@ const {
5
5
  kOnUpdate,
6
6
  } = require('./lib/symbols.js');
7
7
  const {
8
+ isFunction,
8
9
  kEnumerableProperty,
9
10
  } = require('./lib/utils.js');
10
11
  const {
@@ -70,7 +71,7 @@ class AudioRenderCapacity extends EventTarget {
70
71
  }
71
72
 
72
73
  targetOptions.updateInterval = conversions['double'](options.updateInterval, {
73
- context: `Failed to execute 'start' on 'AudioRenderCapacity': Failed to read the 'updateInterval' property on 'AudioRenderCapacityOptions': The provided value ()`
74
+ context: `Failed to execute 'start' on 'AudioRenderCapacity': Failed to read the 'updateInterval' property on 'AudioRenderCapacityOptions': The provided value ()`,
74
75
  });
75
76
  } else {
76
77
  targetOptions.updateInterval = 1;
@@ -108,7 +109,7 @@ Object.defineProperties(AudioRenderCapacity.prototype, {
108
109
  },
109
110
 
110
111
  onupdate: kEnumerableProperty,
111
- stop: kEnumerableProperty,
112
+ start: kEnumerableProperty,
112
113
  stop: kEnumerableProperty,
113
114
  });
114
115
 
@@ -1,8 +1,9 @@
1
1
  const {
2
- resolveObjectURL
2
+ resolveObjectURL,
3
3
  } = require('node:buffer');
4
- const fs = require('node:fs').promises;
5
- const { existsSync } = require('node:fs');
4
+ const {
5
+ existsSync,
6
+ } = require('node:fs');
6
7
  const path = require('node:path');
7
8
  const {
8
9
  Worker,
@@ -23,7 +24,7 @@ const {
23
24
 
24
25
  const caller = require('caller');
25
26
  // cf. https://www.npmjs.com/package/node-fetch#commonjs
26
- const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
27
+ const fetch = (...args) => import('node-fetch').then(({ default: fetch }) => fetch(...args));
27
28
 
28
29
  /**
29
30
  * Retrieve code with different module resolution strategies
@@ -47,11 +48,11 @@ const resolveModule = async (moduleUrl) => {
47
48
  }
48
49
  } else if (moduleUrl.startsWith('http')) {
49
50
  try {
50
- const res = await fetch(moduleUrl);
51
- code = await res.text();
52
- } catch (err) {
53
- throw new DOMException(`Failed to execute 'addModule' on 'AudioWorklet': ${err.message}`, 'AbortError');
54
- }
51
+ const res = await fetch(moduleUrl);
52
+ code = await res.text();
53
+ } catch (err) {
54
+ throw new DOMException(`Failed to execute 'addModule' on 'AudioWorklet': ${err.message}`, 'AbortError');
55
+ }
55
56
  } else if (moduleUrl.startsWith('blob:')) {
56
57
  try {
57
58
  const blob = resolveObjectURL(moduleUrl);
@@ -63,16 +64,8 @@ const resolveModule = async (moduleUrl) => {
63
64
  const callerSite = caller(2);
64
65
 
65
66
  if (callerSite.startsWith('http')) { // this branch exists for wpt where caller site is an url
66
- let url;
67
- // handle origin relative and caller path relative URLs
68
- if (moduleUrl.startsWith('/')) {
69
- const origin = new URL(baseUrl).origin;
70
- url = origin + moduleUrl;
71
- } else {
72
- // we know separators are '/'
73
- const baseUrl = callerSite.substr(0, callerSite.lastIndexOf('/'));
74
- url = baseUrl + '/' + moduleUrl;
75
- }
67
+ const baseUrl = callerSite.substring(0, callerSite.lastIndexOf('/'));
68
+ const url = baseUrl + '/' + moduleUrl;
76
69
 
77
70
  try {
78
71
  const res = await fetch(url);
@@ -92,7 +85,7 @@ const resolveModule = async (moduleUrl) => {
92
85
  try {
93
86
  // try resolve according to process.cwd()
94
87
  absPathname = require.resolve(moduleUrl, { paths: [process.cwd()] });
95
- } catch (err) {
88
+ } catch {
96
89
  throw new DOMException(`Failed to execute 'addModule' on 'AudioWorklet': Cannot resolve module ${moduleUrl}`, 'AbortError');
97
90
  }
98
91
  }
@@ -100,7 +93,7 @@ const resolveModule = async (moduleUrl) => {
100
93
  }
101
94
 
102
95
  return { absPathname, code };
103
- }
96
+ };
104
97
 
105
98
  class AudioWorklet {
106
99
  #workletId = null;
@@ -200,6 +193,7 @@ class AudioWorklet {
200
193
  // For OfflineAudioContext only, check that all processors have been properly
201
194
  // created before actual `startRendering`
202
195
  async [kCheckProcessorsCreated]() {
196
+ // eslint-disable-next-line no-async-promise-executor
203
197
  return new Promise(async resolve => {
204
198
  while (this.#pendingCreateProcessors.size !== 0) {
205
199
  // we need a microtask to ensure message can be received
@@ -87,7 +87,7 @@ globalThis[kWorkletRecycleBuffer1] = buffer => pool1.recycle(buffer);
87
87
  globalThis[kWorkletMarkAsUntransferable] = obj => {
88
88
  markAsUntransferable(obj);
89
89
  return obj;
90
- }
90
+ };
91
91
 
92
92
  function isIterable(obj) {
93
93
  // checks for null and undefined
@@ -101,7 +101,7 @@ function isIterable(obj) {
101
101
  function isConstructor(f) {
102
102
  try {
103
103
  Reflect.construct(String, [], f);
104
- } catch (e) {
104
+ } catch {
105
105
  return false;
106
106
  }
107
107
  return true;
@@ -114,7 +114,7 @@ function runLoop() {
114
114
  runLoopImmediateId = setImmediate(runLoop);
115
115
  }
116
116
 
117
- globalThis.currentTime = 0
117
+ globalThis.currentTime = 0;
118
118
  globalThis.currentFrame = 0;
119
119
  globalThis.sampleRate = sampleRate;
120
120
  // @todo - implement in upstream crate
@@ -153,7 +153,7 @@ globalThis.AudioWorkletProcessor = class AudioWorkletProcessor {
153
153
  this[kWorkletParamsCache][desc.name] = [
154
154
  pool128.get(), // should be globalThis.renderQuantumSize
155
155
  pool1.get(),
156
- ]
156
+ ];
157
157
  });
158
158
 
159
159
  this.#port = port;
@@ -170,7 +170,7 @@ globalThis.AudioWorkletProcessor = class AudioWorkletProcessor {
170
170
  [kWorkletQueueTask](cmd, err) {
171
171
  this.#port.postMessage({ cmd, err });
172
172
  }
173
- }
173
+ };
174
174
 
175
175
  // follow algorithm from:
176
176
  // https://webaudio.github.io/web-audio-api/#dom-audioworkletglobalscope-registerprocessor
@@ -300,10 +300,6 @@ globalThis.registerProcessor = function registerProcessor(name, processorCtor) {
300
300
 
301
301
  parentPort.on('message', async event => {
302
302
  switch (event.cmd) {
303
- case 'node-web-audio-api:worklet:init': {
304
- const { workletId, processors, promiseId } = event;
305
- break;
306
- }
307
303
  case 'node-web-audio-api:worklet:exit': {
308
304
  clearImmediate(runLoopImmediateId);
309
305
  // properly exit audio worklet on rust side
@@ -1,4 +1,3 @@
1
- /* eslint-disable no-unused-vars */
2
1
  const conversions = require('webidl-conversions');
3
2
  const {
4
3
  toSanitizedSequence,
@@ -23,8 +22,6 @@ const {
23
22
  ErrorEvent,
24
23
  } = require('./Events.js');
25
24
 
26
- /* eslint-enable no-unused-vars */
27
-
28
25
  const AudioNode = require('./AudioNode.js');
29
26
  const AudioParamMap = require('./AudioParamMap.js');
30
27
  const IMPLEMENTATION_MAX_NUMBER_OF_CHANNELS = 32;
@@ -156,7 +153,7 @@ module.exports = (jsExport, nativeBinding) => {
156
153
  // if we delegate this check to Rust, this can poison a Mutex
157
154
  // (probably the `audio_param_descriptor_channel` one)
158
155
  if (parsedOptions.channelCount <= 0 || parsedOptions.channelCount > IMPLEMENTATION_MAX_NUMBER_OF_CHANNELS) {
159
- throw new DOMException(`Failed to construct 'AudioWorkletNode': Invalid 'channelCount' property: Number of channels: ${parsedOptions.channelCount} is outside range [1, 32]`, 'NotSupportedError')
156
+ throw new DOMException(`Failed to construct 'AudioWorkletNode': Invalid 'channelCount' property: Number of channels: ${parsedOptions.channelCount} is outside range [1, 32]`, 'NotSupportedError');
160
157
  }
161
158
  }
162
159
 
@@ -138,10 +138,12 @@ module.exports = function patchOfflineAudioContext(jsExport, nativeBinding) {
138
138
  // ensure all AudioWorkletProcessor have finished their instanciation
139
139
  await this.audioWorklet[kCheckProcessorsCreated]();
140
140
 
141
- let nativeAudioBuffer;
141
+ // keep this to highlight the workaround w/ the oncomplete event
142
+ let _nativeAudioBuffer;
142
143
 
143
144
  try {
144
- nativeAudioBuffer = await this[kNapiObj].startRendering();
145
+ // eslint-disable-next-line no-unused-vars
146
+ _nativeAudioBuffer = await this[kNapiObj].startRendering();
145
147
  } catch (err) {
146
148
  throwSanitizedError(err);
147
149
  }
package/load-native.cjs CHANGED
@@ -1,3 +1,4 @@
1
+ const fs = require('node:fs');
1
2
  const { platform, arch } = process;
2
3
 
3
4
  let nativeBinding = null;
@@ -21,7 +22,7 @@ switch (platform) {
21
22
  }
22
23
  break;
23
24
  default:
24
- throw new Error(`Unsupported architecture on Windows: ${arch}`);
25
+ loadError = new Error(`Unsupported architecture on Windows: ${arch}`);
25
26
  }
26
27
  break;
27
28
  case 'darwin':
@@ -41,11 +42,15 @@ switch (platform) {
41
42
  }
42
43
  break;
43
44
  default:
44
- throw new Error(`Unsupported architecture on macOS: ${arch}`);
45
+ loadError = new Error(`Unsupported architecture on macOS: ${arch}`);
45
46
  }
46
47
  break;
48
+ // case 'freebsd': x64 only
47
49
  case 'linux':
48
50
  switch (arch) {
51
+ // @todo
52
+ // - support riscv64 arch
53
+ // - support musl C lib
49
54
  case 'x64':
50
55
  try {
51
56
  nativeBinding = require('./node-web-audio-api.linux-x64-gnu.node');
@@ -68,11 +73,20 @@ switch (platform) {
68
73
  }
69
74
  break;
70
75
  default:
71
- throw new Error(`Unsupported architecture on Linux: ${arch}`);
76
+ loadError = new Error(`Unsupported architecture on Linux: ${arch}`);
72
77
  }
73
78
  break;
74
79
  default:
75
- throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`);
80
+ loadError = new Error(`Unsupported OS: ${platform}, architecture: ${arch}`);
81
+ }
82
+
83
+ // use local build if exists
84
+ if (fs.existsSync('node-web-audio-api.build-release.node')) {
85
+ nativeBinding = require('./node-web-audio-api.build-release.node');
86
+ }
87
+
88
+ if (fs.existsSync('node-web-audio-api.build-debug.node')) {
89
+ nativeBinding = require('./node-web-audio-api.build-debug.node');
76
90
  }
77
91
 
78
92
  if (!nativeBinding) {
Binary file
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "node-web-audio-api",
3
- "version": "0.21.5",
3
+ "version": "1.0.0",
4
4
  "author": "Benjamin Matuszewski",
5
- "description": "Node.js bindings for web-audio-api-rs using napi-rs",
5
+ "description": "Web Audio API implementation for Node.js",
6
6
  "exports": {
7
7
  "import": "./index.mjs",
8
8
  "require": "./index.cjs",
@@ -21,7 +21,7 @@
21
21
  "music",
22
22
  "dsp",
23
23
  "rust",
24
- "n-api"
24
+ "node-api"
25
25
  ],
26
26
  "engines": {
27
27
  "node": ">= 14"
@@ -35,46 +35,41 @@
35
35
  "access": "public"
36
36
  },
37
37
  "scripts": {
38
- "artifacts": "napi artifacts",
39
- "build": "npm run generate && napi build --platform --release",
40
- "build:jack": "npm run generate && napi build --platform --features jack --release",
41
- "build:debug": "npm run generate && napi build --platform",
42
- "build:only": "napi build --platform --release",
38
+ "build": "npm run generate && cargo build --release && node ./.scripts/move-artifact.mjs --release",
39
+ "build:jack": "npm run generate && cargo build --features jack --release && node ./.scripts/move-artifact.mjs --release",
40
+ "build:debug": "npm run generate && cargo build && node ./.scripts/move-artifact.mjs",
41
+ "build:only": "cargo build --release && node ./.scripts/move-artifact.mjs --release",
43
42
  "check": "cargo fmt && cargo clippy",
44
43
  "generate": "node generator/index.mjs && cargo fmt",
45
- "lint": "npx eslint index.cjs index.mjs && npx eslint js/*.js && npx eslint examples/*.mjs",
46
- "preversion": "yarn install && npm run generate",
44
+ "lint": "npx eslint index.cjs index.mjs && npx eslint js/*.js && npx eslint examples/*.js",
45
+ "preversion": "npm install && npm run generate",
47
46
  "postversion": "cargo bump $npm_package_version && git commit -am \"v$npm_package_version\" && node .scripts/check-changelog.mjs",
48
47
  "test": "mocha tests/*.spec.mjs",
48
+ "test:ci": "mocha tests/*.spec.mjs -- --ci",
49
49
  "test:only": "mocha",
50
50
  "wpt": "npm run build && node ./.scripts/wpt-harness.mjs",
51
51
  "wpt:only": "node ./.scripts/wpt-harness.mjs"
52
52
  },
53
53
  "devDependencies": {
54
- "@ircam/eslint-config": "^1.3.0",
55
- "@ircam/sc-gettime": "^1.0.0",
56
- "@ircam/sc-scheduling": "^0.1.7",
57
- "@ircam/sc-utils": "^1.3.3",
54
+ "@ircam/eslint-config": "^2.0.0",
55
+ "@ircam/sc-scheduling": "^1.0.0",
56
+ "@ircam/sc-utils": "^1.9.0",
58
57
  "@sindresorhus/slugify": "^2.1.1",
59
- "camelcase": "^7.0.1",
60
- "chai": "^4.3.7",
58
+ "camelcase": "^8.0.0",
59
+ "chai": "^5.1.2",
61
60
  "chalk": "^5.3.0",
62
61
  "cli-table": "^0.3.11",
63
- "commander": "^11.1.0",
62
+ "commander": "^13.0.0",
64
63
  "dotenv": "^16.0.3",
65
- "eslint": "^8.57.0",
64
+ "eslint": "^9.18.0",
66
65
  "js-beautify": "^1.15.1",
67
- "mocha": "^10.2.0",
68
- "node-ssh": "^13.0.0",
69
- "octokit": "^2.0.11",
70
- "ping": "^0.4.2",
66
+ "mocha": "^11.0.1",
67
+ "octokit": "^4.1.0",
71
68
  "template-literal": "^1.0.4",
72
69
  "webidl2": "^24.2.0",
73
70
  "wpt-runner": "^5.0.0"
74
71
  },
75
72
  "dependencies": {
76
- "@napi-rs/cli": "^2.14.3",
77
- "@node-rs/helper": "^1.3.3",
78
73
  "caller": "^1.1.0",
79
74
  "node-fetch": "^3.3.2",
80
75
  "webidl-conversions": "^7.0.0"
package/.eslintrc DELETED
@@ -1,3 +0,0 @@
1
- {
2
- "extends": "@ircam"
3
- }
package/all-checks.sh DELETED
@@ -1,18 +0,0 @@
1
- #!/bin/bash
2
-
3
-
4
- echo "-----------------------------------------------"
5
- echo "> cargo fmt -- --check --color always"
6
- echo "-----------------------------------------------"
7
- cargo fmt -- --check --color always
8
-
9
- echo "-----------------------------------------------"
10
- echo "> cargo clippy --all-targets --features cpal -- -D warnings"
11
- echo "-----------------------------------------------"
12
- cargo clippy --all-targets --features cpal -- -D warnings
13
-
14
- echo "-----------------------------------------------"
15
- echo "> Run js tests"
16
- echo "-----------------------------------------------"
17
- npm run test
18
-
package/run-wpt.sh DELETED
@@ -1,5 +0,0 @@
1
- #!/bin/bash
2
- echo $1
3
- echo ~~~~~~~~~~~~~~~~~
4
- node ./.scripts/wpt-harness.mjs --filter "$1" 2>&1 | grep -A 3 RESULTS
5
- echo