node-web-audio-api 0.6.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 +20 -3
- package/README.md +45 -46
- package/monkey-patch.js +0 -9
- package/node-web-audio-api.darwin-arm64.node +0 -0
- package/node-web-audio-api.darwin-x64.node +0 -0
- package/node-web-audio-api.linux-arm-gnueabihf.node +0 -0
- package/node-web-audio-api.linux-x64-gnu.node +0 -0
- package/node-web-audio-api.win32-arm64-msvc.node +0 -0
- package/node-web-audio-api.win32-x64-msvc.node +0 -0
- package/package.json +4 -2
- package/simple-test.cjs +1 -1
- package/simple-test.mjs +16 -21
- package/tests/audio-buffer.mjs +70 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
|
-
## v0.
|
|
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
|
|
5
|
-
- Implement
|
|
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
|
-
#
|
|
1
|
+
# Node Web Audio API
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](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
|
-
|
|
45
|
+
### Running the Examples
|
|
37
46
|
|
|
38
|
-
|
|
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
|
-
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
|
|
61
|
-
|
|
62
|
+
3. Run the examples from the project's root directory
|
|
63
|
+
```sh
|
|
64
|
+
node examples/granular-scrub.mjs
|
|
62
65
|
```
|
|
63
66
|
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
116
|
+
[BSD-3-Clause](./LICENSE)
|
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
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-web-audio-api",
|
|
3
|
-
"version": "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,13 +33,15 @@
|
|
|
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
39
|
"@ircam/eslint-config": "^1.3.0",
|
|
40
|
+
"@ircam/sc-gettime": "^1.0.0",
|
|
40
41
|
"@sindresorhus/slugify": "^2.1.1",
|
|
41
42
|
"camelcase": "^7.0.1",
|
|
42
43
|
"chalk": "^5.2.0",
|
|
44
|
+
"cli-table": "^0.3.11",
|
|
43
45
|
"dotenv": "^16.0.3",
|
|
44
46
|
"eslint": "^8.32.0",
|
|
45
47
|
"node-ssh": "^13.0.0",
|
package/simple-test.cjs
CHANGED
package/simple-test.mjs
CHANGED
|
@@ -1,25 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
import { AudioContext } from './index.mjs';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
const audioContext = new AudioContext();
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
setInterval(() => {
|
|
6
|
+
const now = audioContext.currentTime;
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
const env = audioContext.createGain();
|
|
9
|
+
env.connect(audioContext.destination);
|
|
10
|
+
env.gain.value = 0;
|
|
11
|
+
env.gain.setValueAtTime(0, now);
|
|
12
|
+
env.gain.linearRampToValueAtTime(0.1, now + 0.02);
|
|
13
|
+
env.gain.exponentialRampToValueAtTime(0.0001, now + 1);
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
import { mediaDevices } from './index.mjs';
|
|
24
|
-
|
|
25
|
-
console.log(mediaDevices);
|
|
15
|
+
const osc = audioContext.createOscillator();
|
|
16
|
+
osc.frequency.value = 200 + Math.random() * 2800;
|
|
17
|
+
osc.connect(env);
|
|
18
|
+
osc.start(now);
|
|
19
|
+
osc.stop(now + 1);
|
|
20
|
+
}, 100);
|
|
@@ -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
|
+
});
|