node-web-audio-api 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.
package/CHANGELOG.md CHANGED
@@ -1,8 +1,25 @@
1
- ## v0.4.0
1
+ ## v0.7.0
2
+
3
+ - Improve readme & doc
4
+ - Fix AudioParam method names
5
+ -
6
+
7
+ ## v0.6.0 - Feb 2023
8
+
9
+ - Basic support for mediaDevices & MediaStreamAudioSourceNode
10
+ - Add bindings to ConvolverNode, AnalyserNode & Panner nodes
11
+ - Update upstream crate to v0.26
12
+
13
+ ## v0.5.0 - Dec 2022
14
+
15
+ - Implement AudioParam#setValueCurveAtTime
16
+ - Offline context constructor
17
+
18
+ ## v0.4.0 - Nov 2022
2
19
 
3
20
  - Implement offline audio context
4
- - Update web-audio-api-rs to v0.24.0
5
- - Implement `audio_node.disconnect()`
21
+ - Update upstream crate to v0.24
22
+ - Implement AudioNode#disconnect
6
23
  - Properly support ESM
7
24
  - Limit number of online contexts to 1 on Linux
8
25
  - Force latencyHint to 'playback' if not manually set on RPi
package/README.md CHANGED
@@ -1,6 +1,13 @@
1
- # `node-web-audio-api`
1
+ # Node Web Audio API
2
2
 
3
- > Nodejs bindings for [`orottier/web-audio-api-rs`](https://github.com/orottier/web-audio-api-rs/) using [`napi-rs`](https://github.com/napi-rs/napi-rs/)
3
+ [![npm version](https://badge.fury.io/js/node-web-audio-api.svg)](https://badge.fury.io/js/node-web-audio-api)
4
+
5
+ Node.js bindings for the Rust implementation of the Web Audio API Specification
6
+
7
+ - see [`orottier/web-audio-api-rs`](https://github.com/orottier/web-audio-api-rs/) for the "real" audio guts
8
+ - use [`napi-rs`](https://github.com/napi-rs/napi-rs/) for the Node.js bindigs
9
+
10
+ The goal of the library is to provide an implementation that is both efficient and _exactly_ matches the browsers' API.
4
11
 
5
12
  ## Install
6
13
 
@@ -8,10 +15,12 @@
8
15
  npm install [--save] node-web-audio-api
9
16
  ```
10
17
 
11
- ## Example
18
+ ## Example Use
12
19
 
13
20
  ```js
14
21
  import { AudioContext, OscillatorNode, GainNode } from 'node-web-audio-api';
22
+ // or using old fashionned commonjs syntax:
23
+ // const { AudioContext, OscillatorNode, GainNode } = require('node-web-audio-api');
15
24
 
16
25
  const audioContext = new AudioContext();
17
26
 
@@ -33,54 +42,52 @@ setInterval(() => {
33
42
  }, 80);
34
43
  ```
35
44
 
36
- or using with old fashionned commonjs syntax
45
+ ### Running the Examples
37
46
 
38
- ```js
39
- const { AudioContext, OscillatorNode, GainNode } = require('node-web-audio-api');
47
+ To run all examples locally on your machine you will need to:
40
48
 
41
- const audioContext = new AudioContext();
42
- //...
49
+ 1. Install Rust toolchain
50
+ ```sh
51
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
43
52
  ```
44
53
 
45
- ## Caveats
46
-
47
- - Currently the library does not provide any way of chosing the output interface, system default interface will be used. As the spec and web-audio-api evolve evolve, thus should change in the future see [https://github.com/orottier/web-audio-api-rs/issues/216](https://github.com/orottier/web-audio-api-rs/issues/216)
48
- - On Linux systems, the audio backend is Alsa, which limits the number of online
49
- AudioContext to 1. This is subject to change in the future.
50
-
51
- ### Raspberry Pi
52
-
53
- On Raspberry Pi, the default render quantum size (128) is too small and underruns
54
- occurs frequently. To prevent that, if you do not explicitely provide a latency hint
55
- in the AudioContext options, the value is automatically set to 'playback' which uses
56
- a buffer of 1024 samples. While this is not per se spec compliant, it allow usage
57
- of the library in a more user friendly manner. In the future, this might change according
58
- to the support of other audio backend, which is now alsa.
54
+ 2. Clone the repo and build the binary on your machine
55
+ ```sh
56
+ git clone https://github.com/ircam-ismm/node-web-audio-api.git
57
+ cd node-web-audio-api
58
+ npm install
59
+ npm run build
60
+ ```
59
61
 
60
- ```js
61
- const audioContext = new AudioContext({ latencyHint: 'playback' });
62
+ 3. Run the examples from the project's root directory
63
+ ```sh
64
+ node examples/granular-scrub.mjs
62
65
  ```
63
66
 
64
- The 'playback' latency hint, 1024 samples / ~21ms at 48000Hz, has been found
65
- a good value.
67
+ ## Caveats
68
+
69
+ - The async methods are not trully async for now and are just patched on the JS side. This will evolve once the "trully" async version of the methods are implemented in the upstream library.
70
+ - On Linux systems, the audio backend is currently Alsa, which limits the number of online `AudioContext` to 1. This is subject to change in the future.
71
+ - On Raspberry Pi, the default render quantum size (128) is too small and underruns occurs frequently. To prevent that, if you do not explicitely provide a latency hint in the AudioContext options, the value is automatically set to 'playback' which uses a buffer of 1024 samples (~21ms at 48000Hz). While this is not per se spec compliant, it allows usage of the library in a more user friendly manner. In the future, this might change according to the support of other audio backend.
72
+ - On Raspberry Pi, the `Linux arm gnueabihf` binary provided only works on 32bit OS. We will provide a version for the 64 bit OS in the future.
66
73
 
67
74
  ## Supported Platforms
68
75
 
69
- | | binaries | tested |
70
- | ---------------------------| ------ | ------ |
71
- | Windows x64 | ✓ | |
72
- | Windows arm64 | ✓ | |
73
- | macOS x64 | ✓ | ✓ |
74
- | macOS aarch64 | ✓ | |
75
- | Linux x64 gnu | ✓ | |
76
- | Linux arm gnueabihf (RPi) | ✓ | ✓ |
76
+ | | binaries | tested |
77
+ | --------------------------- | ------ | ------ |
78
+ | Windows x64 | ✓ | |
79
+ | Windows arm64 | ✓ | |
80
+ | macOS x64 | ✓ | ✓ |
81
+ | macOS aarch64 | ✓ | |
82
+ | Linux x64 gnu | ✓ | |
83
+ | Linux arm gnueabihf (RPi) | ✓ | ✓ |
77
84
 
78
85
 
79
86
  ### Manual Build
80
87
 
81
88
  If prebuilt binaries are not shippped for your platform, you will need to:
82
89
 
83
- 1. Install rust toolchain
90
+ 1. Install the Rust toolchain
84
91
 
85
92
  ```sh
86
93
  curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
@@ -94,19 +101,11 @@ cd node_modules/node-web-audio-api
94
101
  npm run build
95
102
  ```
96
103
 
97
- The package will then be built on your machine, which might take some time
98
-
99
- ## Known limitation / caveats
100
-
101
- - async function are not trully async but only monkey patched on the JS side, this will
102
- be updated once `web-audio-api-rs` provide async version of the methods.
103
- - see `web-audio-api-rs`
104
+ The package will be built on your machine, which might take some time
104
105
 
105
106
  ## Development notes
106
107
 
107
- The npm script rely on [`cargo-bump`](https://crates.io/crates/cargo-bump) to maintain version synced between
108
- the `package.json` and the `Cargo.toml` files. Therefore, you will need to install
109
- `cargo-bump` on your machine
108
+ The npm `postversion` script rely on [`cargo-bump`](https://crates.io/crates/cargo-bump) to maintain versions synced between the `package.json` and the `Cargo.toml` files. Therefore, you will need to install `cargo-bump` on your machine
110
109
 
111
110
  ```
112
111
  cargo install cargo-bump
@@ -114,4 +113,4 @@ cargo install cargo-bump
114
113
 
115
114
  ## License
116
115
 
117
- This project is licensed under the [BSD-3-Clause license](./LICENSE).
116
+ [BSD-3-Clause](./LICENSE)
package/index.cjs CHANGED
@@ -93,5 +93,23 @@ nativeBinding.AudioContext = patchAudioContext(nativeBinding.AudioContext);
93
93
  nativeBinding.OfflineAudioContext = patchOfflineAudioContext(nativeBinding.OfflineAudioContext);
94
94
  nativeBinding.load = load;
95
95
 
96
+ // ------------------------------------------------------------------
97
+ // monkey patch proto media devices API
98
+ // @todo - review
99
+ // ------------------------------------------------------------------
100
+ class MediaStream extends nativeBinding.Microphone {};
101
+ // const Microphone = nativeBinding.Microphone;
102
+ nativeBinding.Microphone = null;
103
+
104
+ nativeBinding.mediaDevices = {}
105
+ nativeBinding.mediaDevices.getUserMedia = function getUserMedia(options) {
106
+ if (options && options.audio === true) {
107
+ const mic = new MediaStream();
108
+ return Promise.resolve(mic);
109
+ } else {
110
+ throw new NotSupportedError(`Only { audio: true } is currently supported`);
111
+ }
112
+ }
113
+
96
114
  module.exports = nativeBinding;
97
115
 
package/index.mjs CHANGED
@@ -17,21 +17,28 @@ export const {
17
17
  OfflineAudioContext,
18
18
  AudioBuffer,
19
19
  PeriodicWave,
20
+ // manually written nodes
21
+ MediaStreamAudioSourceNode,
20
22
  // generated supported nodes
23
+ AnalyserNode,
21
24
  AudioBufferSourceNode,
22
25
  BiquadFilterNode,
23
26
  ChannelMergerNode,
24
27
  ChannelSplitterNode,
25
28
  ConstantSourceNode,
29
+ ConvolverNode,
26
30
  DelayNode,
27
31
  DynamicsCompressorNode,
28
32
  GainNode,
29
33
  IIRFilterNode,
30
34
  OscillatorNode,
35
+ PannerNode,
31
36
  StereoPannerNode,
32
37
  WaveShaperNode,
38
+
33
39
  // helper methods
34
40
  load,
41
+ mediaDevices,
35
42
  } = nativeModule;
36
43
 
37
44
  export default nativeModule;
package/monkey-patch.js CHANGED
@@ -121,15 +121,6 @@ function patchOfflineAudioContext(NativeOfflineAudioContext) {
121
121
  }
122
122
 
123
123
  super(...args);
124
-
125
- // not sure this is usefull, to be tested
126
- const keepAwakeId = setInterval(() => {}, 10000);
127
- Object.defineProperty(this, '__keepAwakeId', {
128
- value: keepAwakeId,
129
- enumerable: false,
130
- writable: true,
131
- configurable: false,
132
- });
133
124
  }
134
125
 
135
126
  // promisify sync APIs
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-web-audio-api",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "author": "Benjamin Matuszewski",
5
5
  "description": "Node.js bindings for web-audio-api-rs using napi-rs",
6
6
  "exports": {
@@ -33,24 +33,26 @@
33
33
  "generate": "node generator/index.mjs && cargo fmt",
34
34
  "lint": "eslint monkey-patch.js index.cjs index.mjs && eslint examples/*.mjs",
35
35
  "preversion": "yarn install && npm run generate",
36
- "postversion": "cargo bump $npm_package_version && git commit -am \"v$npm_package_version\""
36
+ "postversion": "cargo bump $npm_package_version && git commit -am \"v$npm_package_version\" && node bin/check-changelog.mjs"
37
37
  },
38
38
  "devDependencies": {
39
- "@ircam/eslint-config": "^1.2.0",
40
- "@sindresorhus/slugify": "^2.1.0",
41
- "camelcase": "^6.3.0",
42
- "chalk": "^5.0.1",
43
- "dotenv": "^16.0.2",
44
- "eslint": "^8.27.0",
39
+ "@ircam/eslint-config": "^1.3.0",
40
+ "@ircam/sc-gettime": "^1.0.0",
41
+ "@sindresorhus/slugify": "^2.1.1",
42
+ "camelcase": "^7.0.1",
43
+ "chalk": "^5.2.0",
44
+ "cli-table": "^0.3.11",
45
+ "dotenv": "^16.0.3",
46
+ "eslint": "^8.32.0",
45
47
  "node-ssh": "^13.0.0",
46
- "octokit": "^2.0.7",
48
+ "octokit": "^2.0.11",
47
49
  "ping": "^0.4.2",
48
50
  "template-literal": "^1.0.4",
49
51
  "waves-masters": "^2.3.1",
50
52
  "webidl2": "^24.2.0"
51
53
  },
52
54
  "dependencies": {
53
- "@napi-rs/cli": "^2.10.0",
55
+ "@napi-rs/cli": "^2.14.3",
54
56
  "@node-rs/helper": "^1.3.3"
55
57
  }
56
58
  }
package/simple-test.cjs CHANGED
@@ -1,4 +1,4 @@
1
- const { AudioContext } = require('./index.js');
1
+ const { AudioContext } = require('./index.cjs');
2
2
 
3
3
  const audioContext = new AudioContext();
4
4
  process.audioContext = audioContext;
@@ -0,0 +1,70 @@
1
+ import { after, before, describe, it } from 'node:test';
2
+ import assert from 'node:assert';
3
+
4
+ import { AudioBuffer, AudioContext } from '../index.mjs';
5
+
6
+ describe('AudioBuffer', () => {
7
+ let audioContext;
8
+
9
+ before(() => {
10
+ console.log('before is run')
11
+ audioContext = new AudioContext();
12
+ });
13
+
14
+ after(() => {
15
+ audioContext.close();
16
+ });
17
+
18
+ describe(`audioContext.createBuffer`, () => {
19
+ // it('should properly create audio buffer', () => {
20
+ // const audioBuffer = audioContext.createBuffer(1, 100, audioContext.sampleRate);
21
+
22
+ // assert.equal(audioBuffer.numberOfChannels, 1);
23
+ // assert.equal(audioBuffer.length, 100);
24
+ // assert.equal(audioBuffer.sampleRate, audioContext.sampleRate);
25
+ // });
26
+
27
+ // it('should properly fail if missing argument', () => {
28
+ // assert.throws(() => {
29
+ // const audioBuffer = audioContext.createBuffer(1, 100);
30
+ // }, {
31
+ // name: 'Error', // should be 'NotSupportedError'
32
+ // message: 'AudioBuffer: Invalid options, sampleRate is required',
33
+ // });
34
+ // });
35
+ });
36
+
37
+ describe(`new AudioBuffer(options)`, () => {
38
+ // it('should properly create audio buffer', () => {
39
+ // const audioBuffer = new AudioBuffer({
40
+ // length: 100,
41
+ // sampleRate: audioContext.sampleRate,
42
+ // });
43
+
44
+ // assert.equal(audioBuffer.numberOfChannels, 1);
45
+ // assert.equal(audioBuffer.length, 100);
46
+ // assert.equal(audioBuffer.sampleRate, audioContext.sampleRate);
47
+ // });
48
+
49
+ // it('should properly fail if missing argument', () => {
50
+ // assert.throws(() => {
51
+ // const audioBuffer = new AudioBuffer({
52
+ // length: 100,
53
+ // });
54
+ // }, {
55
+ // name: 'Error', // should be 'NotSupportedError'
56
+ // message: 'AudioBuffer: Invalid options, sampleRate is required',
57
+ // });
58
+ // });
59
+
60
+ it(`should have type error`, () => {
61
+ try {
62
+ new AudioBuffer(Date, 42);
63
+ } catch (err) {
64
+ console.log(err.type)
65
+ console.log(err.name)
66
+ console.log(err.message)
67
+ }
68
+ });
69
+ });
70
+ });
package/dummy.mjs DELETED
@@ -1,19 +0,0 @@
1
- import { AudioContext } from './index.mjs';
2
-
3
- const audioContext = new AudioContext();
4
-
5
- const now = audioContext.currentTime;
6
-
7
- const gain = audioContext.createGain();
8
- gain.gain.setValueAtTime(0, now);
9
- gain.connect(audioContext.destination);
10
-
11
- const src = audioContext.createOscillator();
12
- src.connect(gain);
13
- src.start();
14
-
15
-
16
- gain.gain.setValueCurveAtTime(new Float32Array([0, 1, 0]), now + 1, 2);
17
- // gain.gain.setValueCurveAtTime(new Float32Array([0, 1, 0]), now + 1, 2);
18
-
19
- gain.gain.linear(new Float32Array([0, 1, 0]), now + 1, 2);