@yume-chan/pcm-player 0.0.20 → 0.0.22

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.json CHANGED
@@ -1,6 +1,24 @@
1
1
  {
2
2
  "name": "@yume-chan/pcm-player",
3
3
  "entries": [
4
+ {
5
+ "version": "0.0.22",
6
+ "tag": "@yume-chan/pcm-player_v0.0.22",
7
+ "date": "Wed, 13 Dec 2023 05:57:27 GMT",
8
+ "comments": {
9
+ "none": [
10
+ {
11
+ "comment": "Add basic OLA algorithm to speed up playback when buffer is too high"
12
+ }
13
+ ]
14
+ }
15
+ },
16
+ {
17
+ "version": "0.0.21",
18
+ "tag": "@yume-chan/pcm-player_v0.0.21",
19
+ "date": "Fri, 25 Aug 2023 14:05:18 GMT",
20
+ "comments": {}
21
+ },
4
22
  {
5
23
  "version": "0.0.20",
6
24
  "tag": "@yume-chan/pcm-player_v0.0.20",
package/CHANGELOG.md CHANGED
@@ -1,6 +1,18 @@
1
1
  # Change Log - @yume-chan/pcm-player
2
2
 
3
- This log was last generated on Mon, 05 Jun 2023 02:51:41 GMT and should not be manually modified.
3
+ This log was last generated on Wed, 13 Dec 2023 05:57:27 GMT and should not be manually modified.
4
+
5
+ ## 0.0.22
6
+ Wed, 13 Dec 2023 05:57:27 GMT
7
+
8
+ ### Updates
9
+
10
+ - Add basic OLA algorithm to speed up playback when buffer is too high
11
+
12
+ ## 0.0.21
13
+ Fri, 25 Aug 2023 14:05:18 GMT
14
+
15
+ _Version update only_
4
16
 
5
17
  ## 0.0.20
6
18
  Mon, 05 Jun 2023 02:51:41 GMT
package/README.md CHANGED
@@ -2,11 +2,12 @@
2
2
 
3
3
  Play raw audio sample stream using Web Audio API.
4
4
 
5
- Only support stereo audio.
5
+ ## Features
6
6
 
7
- TODO:
8
-
9
- - [ ] resample audio to compensate for audio buffer underrun
7
+ - [x] Arbitrary channel count
8
+ - [x] Arbitrary sample rate
9
+ - [x] Basic OLA (overlap-add) resampler
10
+ - [ ] Adjustable buffer size
10
11
 
11
12
  ## Usage
12
13
 
package/esm/index.d.ts CHANGED
@@ -1,9 +1,7 @@
1
1
  export declare abstract class PcmPlayer<T> {
2
+ #private;
2
3
  protected abstract sourceName: string;
3
- private _context;
4
- private _worklet;
5
- private _buffer;
6
- constructor(sampleRate: number);
4
+ constructor(sampleRate: number, channelCount: number);
7
5
  protected abstract feedCore(worklet: AudioWorkletNode, source: T): void;
8
6
  feed(source: T): void;
9
7
  start(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8BAAsB,SAAS,CAAC,CAAC;IAC7B,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAEtC,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,OAAO,CAAW;gBAEd,UAAU,EAAE,MAAM;IAO9B,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI;IAEhE,IAAI,CAAC,MAAM,EAAE,CAAC;IASR,KAAK;IAkBZ,IAAI;CAMb;AAED,qBAAa,cAAe,SAAQ,SAAS,CAAC,UAAU,CAAC;IACrD,UAAmB,UAAU,SAA4B;cAEtC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,UAAU;CAW5E;AAED,qBAAa,gBAAiB,SAAQ,SAAS,CAAC,YAAY,CAAC;IACzD,UAAmB,UAAU,SAA8B;cAExC,QAAQ,CACvB,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,YAAY;CAY3B;AAED,qBAAa,sBAAuB,SAAQ,SAAS,CAAC,YAAY,EAAE,CAAC;IACjE,UAAmB,UAAU,SAAqC;cAE/C,QAAQ,CACvB,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,YAAY,EAAE;CAa7B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8BAAsB,SAAS,CAAC,CAAC;;IAC7B,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;gBAQ1B,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;IAQpD,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI;IAEvE,IAAI,CAAC,MAAM,EAAE,CAAC;IAaR,KAAK;IAsBL,IAAI;CAWb;AAED,qBAAa,cAAe,SAAQ,SAAS,CAAC,UAAU,CAAC;IACrD,UAAmB,UAAU,SAA4B;cAEtC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,UAAU;CAW5E;AAED,qBAAa,gBAAiB,SAAQ,SAAS,CAAC,YAAY,CAAC;IACzD,UAAmB,UAAU,SAA8B;cAExC,QAAQ,CACvB,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,YAAY;CAY3B;AAED,qBAAa,sBAAuB,SAAQ,SAAS,CAAC,YAAY,EAAE,CAAC;IACjE,UAAmB,UAAU,SAAqC;cAE/C,QAAQ,CACvB,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,YAAY,EAAE;CAa7B"}
package/esm/index.js CHANGED
@@ -1,37 +1,50 @@
1
1
  export class PcmPlayer {
2
- _context;
3
- _worklet;
4
- _buffer = [];
5
- constructor(sampleRate) {
6
- this._context = new AudioContext({
2
+ #context;
3
+ #channelCount;
4
+ #worklet;
5
+ #buffers = [];
6
+ #stopped = false;
7
+ constructor(sampleRate, channelCount) {
8
+ this.#context = new AudioContext({
7
9
  latencyHint: "interactive",
8
10
  sampleRate,
9
11
  });
12
+ this.#channelCount = channelCount;
10
13
  }
11
14
  feed(source) {
12
- if (this._worklet === undefined) {
13
- this._buffer.push(source);
15
+ if (this.#stopped) {
16
+ throw new Error("PcmPlayer is stopped");
17
+ }
18
+ if (this.#worklet === undefined) {
19
+ this.#buffers.push(source);
14
20
  return;
15
21
  }
16
- this.feedCore(this._worklet, source);
22
+ this.feedCore(this.#worklet, source);
17
23
  }
18
24
  async start() {
19
- await this._context.audioWorklet.addModule(new URL("./worker.js", import.meta.url));
20
- this._worklet = new AudioWorkletNode(this._context, this.sourceName, {
25
+ await this.#context.audioWorklet.addModule(new URL("./worker.js", import.meta.url));
26
+ if (this.#stopped) {
27
+ return;
28
+ }
29
+ this.#worklet = new AudioWorkletNode(this.#context, this.sourceName, {
21
30
  numberOfInputs: 0,
22
31
  numberOfOutputs: 1,
23
- outputChannelCount: [2],
32
+ outputChannelCount: [this.#channelCount],
24
33
  });
25
- this._worklet.connect(this._context.destination);
26
- for (const source of this._buffer) {
27
- this.feedCore(this._worklet, source);
34
+ this.#worklet.connect(this.#context.destination);
35
+ for (const source of this.#buffers) {
36
+ this.feedCore(this.#worklet, source);
28
37
  }
29
- this._buffer.length = 0;
38
+ this.#buffers.length = 0;
30
39
  }
31
40
  async stop() {
32
- this._worklet?.disconnect();
33
- this._worklet = undefined;
34
- await this._context.close();
41
+ if (this.#stopped) {
42
+ return;
43
+ }
44
+ this.#stopped = true;
45
+ this.#worklet?.disconnect();
46
+ this.#worklet = undefined;
47
+ await this.#context.close();
35
48
  }
36
49
  }
37
50
  export class Int16PcmPlayer extends PcmPlayer {
package/esm/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/esm/worker.js CHANGED
@@ -1,97 +1,199 @@
1
+ const INPUT_HOP_SIZE = 3000;
2
+ const SCALE = 0.9;
3
+ const OUTPUT_HOP_SIZE = (INPUT_HOP_SIZE * SCALE) | 0;
4
+ const WINDOW_SIZE = 6000;
5
+ const WINDOW_WEIGHT_TABLE = new Float32Array(WINDOW_SIZE);
6
+ for (let i = 0; i < WINDOW_SIZE / 2; i += 1) {
7
+ const value = Math.sin((i / WINDOW_SIZE) * Math.PI);
8
+ WINDOW_WEIGHT_TABLE[i] = value;
9
+ WINDOW_WEIGHT_TABLE[WINDOW_SIZE - i - 1] = value;
10
+ }
1
11
  class SourceProcessor extends AudioWorkletProcessor {
2
- _sources = [];
3
- _sourceSampleCount = 0;
4
- constructor() {
12
+ channelCount;
13
+ #readBuffer;
14
+ #chunks = [];
15
+ #chunkSampleCounts = [];
16
+ #totalSampleCount = 0;
17
+ #starting = true;
18
+ #speedUp = false;
19
+ #readOffset = 0;
20
+ #inputOffset = 0;
21
+ #outputOffset = 0;
22
+ constructor(options) {
5
23
  super();
24
+ this.channelCount = options.outputChannelCount[0];
25
+ this.#readBuffer = new Float32Array(this.channelCount);
6
26
  this.port.onmessage = (event) => {
27
+ while (this.#totalSampleCount > 0.35 * 48000) {
28
+ this.#chunks.shift();
29
+ const count = this.#chunkSampleCounts.shift();
30
+ this.#totalSampleCount -= count;
31
+ }
7
32
  const data = event.data;
8
33
  const [source, length] = this.createSource(data);
9
- this._sources.push(source);
10
- this._sourceSampleCount += length;
34
+ this.#chunks.push(source);
35
+ this.#chunkSampleCounts.push(length);
36
+ this.#totalSampleCount += length;
37
+ if (!this.#speedUp && this.#totalSampleCount > 0.25 * 48000) {
38
+ this.#speedUp = true;
39
+ this.#readOffset = 0;
40
+ this.#inputOffset = 0;
41
+ this.#outputOffset = 0;
42
+ }
11
43
  };
12
44
  }
13
- process(_inputs, outputs) {
14
- const outputLeft = outputs[0][0];
15
- const outputRight = outputs[0][1];
16
- const outputLength = outputLeft.length;
45
+ process(_inputs, [outputs]) {
46
+ if (this.#starting) {
47
+ if (this.#totalSampleCount < 0.1 * 48000) {
48
+ return true;
49
+ }
50
+ else {
51
+ this.#starting = false;
52
+ }
53
+ }
54
+ if (this.#speedUp && this.#totalSampleCount < 0.15 * 48000) {
55
+ this.#speedUp = false;
56
+ this.#starting = true;
57
+ }
58
+ const outputLength = outputs[0].length;
59
+ if (this.#speedUp) {
60
+ for (let i = 0; i < outputLength; i += 1) {
61
+ let totalWeight = 0;
62
+ const firstWindow = Math.max(0, Math.floor((this.#outputOffset - WINDOW_SIZE) / OUTPUT_HOP_SIZE) + 1);
63
+ let inWindowIndex = this.#outputOffset - firstWindow * OUTPUT_HOP_SIZE;
64
+ let inputIndex = firstWindow * INPUT_HOP_SIZE + inWindowIndex;
65
+ while (inputIndex > 0 && inWindowIndex >= 0) {
66
+ this.#read(inputIndex - this.#readOffset);
67
+ const weight = WINDOW_WEIGHT_TABLE[inWindowIndex];
68
+ for (let j = 0; j < this.channelCount; j += 1) {
69
+ outputs[j][i] += this.#readBuffer[j] * weight;
70
+ }
71
+ totalWeight += weight;
72
+ inputIndex += INPUT_HOP_SIZE - OUTPUT_HOP_SIZE;
73
+ inWindowIndex -= OUTPUT_HOP_SIZE;
74
+ }
75
+ if (totalWeight > 0) {
76
+ for (let j = 0; j < this.channelCount; j += 1) {
77
+ outputs[j][i] /= totalWeight;
78
+ }
79
+ }
80
+ this.#outputOffset += 1;
81
+ if (firstWindow > 0) {
82
+ this.#outputOffset -= OUTPUT_HOP_SIZE;
83
+ this.#readOffset -= INPUT_HOP_SIZE;
84
+ this.#inputOffset += (1 - SCALE) * INPUT_HOP_SIZE;
85
+ }
86
+ }
87
+ this.#inputOffset += outputLength;
88
+ const firstChunkSampleCount = this.#chunkSampleCounts[0];
89
+ if (firstChunkSampleCount !== undefined &&
90
+ this.#inputOffset >= firstChunkSampleCount) {
91
+ this.#chunks.shift();
92
+ this.#chunkSampleCounts.shift();
93
+ this.#totalSampleCount -= firstChunkSampleCount;
94
+ this.#readOffset += firstChunkSampleCount;
95
+ this.#inputOffset -= firstChunkSampleCount;
96
+ }
97
+ }
98
+ else {
99
+ this.#copyChunks(outputs);
100
+ }
101
+ return true;
102
+ }
103
+ #copyChunks(outputs) {
17
104
  let outputIndex = 0;
18
- // Resample source catch up with output
19
- // TODO: should we limit the minimum and maximum speed?
20
- // TODO: this simple resample method changes pitch
21
- const sourceIndexStep = this._sourceSampleCount > 48000 ? 1.02 : 1;
22
- let sourceIndex = 0;
23
- while (this._sources.length > 0 && outputIndex < outputLength) {
24
- const beginSourceIndex = sourceIndex | 0;
25
- let source = this._sources[0];
26
- [source, sourceIndex, outputIndex] = this.copyChunk(sourceIndex, sourceIndexStep, source, outputLeft, outputRight, outputLength, outputIndex);
27
- const consumedSampleCount = (sourceIndex | 0) - beginSourceIndex;
28
- this._sourceSampleCount -= consumedSampleCount;
29
- sourceIndex -= consumedSampleCount;
105
+ const outputLength = outputs[0].length;
106
+ while (this.#chunks.length > 0 && outputIndex < outputLength) {
107
+ let source = this.#chunks[0];
108
+ let consumedSampleCount = 0;
109
+ [source, consumedSampleCount, outputIndex] = this.copyChunk(source, outputs, outputLength, outputIndex);
110
+ this.#totalSampleCount -= consumedSampleCount;
30
111
  if (source) {
31
112
  // Output full
32
- this._sources[0] = source;
33
- return true;
113
+ this.#chunks[0] = source;
114
+ this.#chunkSampleCounts[0] -= consumedSampleCount;
115
+ return;
34
116
  }
35
- this._sources.shift();
117
+ this.#chunks.shift();
118
+ this.#chunkSampleCounts.shift();
36
119
  }
37
- if (outputIndex < outputLength) {
38
- console.log(`[Audio] Buffer underflow, inserting silence: ${outputLength - outputIndex} samples`);
120
+ }
121
+ #read(offset) {
122
+ for (let i = 0; i < this.#chunks.length; i += 1) {
123
+ const length = this.#chunkSampleCounts[i];
124
+ if (offset < length) {
125
+ this.read(this.#chunks[i], offset, this.#readBuffer);
126
+ return;
127
+ }
128
+ offset -= length;
39
129
  }
40
- return true;
130
+ this.#readBuffer.fill(0);
41
131
  }
42
132
  }
43
133
  class Int16SourceProcessor extends SourceProcessor {
44
134
  createSource(data) {
45
135
  const source = new Int16Array(data[0]);
46
- return [source, source.length / 2];
136
+ return [source, source.length / this.channelCount];
137
+ }
138
+ read(source, offset, target) {
139
+ const sourceOffset = offset * this.channelCount;
140
+ for (let i = 0; i < this.channelCount; i += 1) {
141
+ target[i] = source[sourceOffset + i] / 0x8000;
142
+ }
47
143
  }
48
- copyChunk(sourceIndex, sourceIndexStep, source, outputLeft, outputRight, outputLength, outputIndex) {
144
+ copyChunk(source, outputs, outputLength, outputIndex) {
49
145
  const sourceLength = source.length;
50
- let sourceSampleIndex = sourceIndex << 1;
51
- while (sourceSampleIndex < sourceLength) {
52
- outputLeft[outputIndex] = source[sourceSampleIndex] / 0x8000;
53
- outputRight[outputIndex] = source[sourceSampleIndex + 1] / 0x8000;
54
- sourceIndex += sourceIndexStep;
55
- sourceSampleIndex = sourceIndex << 1;
146
+ let sourceIndex = 0;
147
+ while (sourceIndex < sourceLength) {
148
+ for (let i = 0; i < this.channelCount; i += 1) {
149
+ outputs[i][outputIndex] = source[sourceIndex] / 0x8000;
150
+ sourceIndex += 1;
151
+ }
56
152
  outputIndex += 1;
57
153
  if (outputIndex === outputLength) {
58
154
  return [
59
- sourceSampleIndex < sourceLength
60
- ? source.subarray(sourceSampleIndex)
155
+ sourceIndex < sourceLength
156
+ ? source.subarray(sourceIndex)
61
157
  : undefined,
62
- sourceIndex,
158
+ sourceIndex / this.channelCount,
63
159
  outputIndex,
64
160
  ];
65
161
  }
66
162
  }
67
- return [undefined, sourceIndex, outputIndex];
163
+ return [undefined, sourceIndex / this.channelCount, outputIndex];
68
164
  }
69
165
  }
70
166
  class Float32SourceProcessor extends SourceProcessor {
71
167
  createSource(data) {
72
168
  const source = new Float32Array(data[0]);
73
- return [source, source.length / 2];
169
+ return [source, source.length / this.channelCount];
170
+ }
171
+ read(source, offset, target) {
172
+ const sourceOffset = offset * this.channelCount;
173
+ for (let i = 0; i < this.channelCount; i += 1) {
174
+ target[i] = source[sourceOffset + i];
175
+ }
74
176
  }
75
- copyChunk(sourceIndex, sourceIndexStep, source, outputLeft, outputRight, outputLength, outputIndex) {
177
+ copyChunk(source, outputs, outputLength, outputIndex) {
76
178
  const sourceLength = source.length;
77
- let sourceSampleIndex = sourceIndex << 1;
78
- while (sourceSampleIndex < sourceLength) {
79
- outputLeft[outputIndex] = source[sourceSampleIndex];
80
- outputRight[outputIndex] = source[sourceSampleIndex + 1];
81
- sourceIndex += sourceIndexStep;
82
- sourceSampleIndex = sourceIndex << 1;
179
+ let sourceIndex = 0;
180
+ while (sourceIndex < sourceLength) {
181
+ for (let i = 0; i < this.channelCount; i += 1) {
182
+ outputs[i][outputIndex] = source[sourceIndex];
183
+ sourceIndex += 1;
184
+ }
83
185
  outputIndex += 1;
84
186
  if (outputIndex === outputLength) {
85
187
  return [
86
- sourceSampleIndex < sourceLength
87
- ? source.subarray(sourceSampleIndex)
188
+ sourceIndex < sourceLength
189
+ ? source.subarray(sourceIndex)
88
190
  : undefined,
89
- sourceIndex,
191
+ sourceIndex / this.channelCount,
90
192
  outputIndex,
91
193
  ];
92
194
  }
93
195
  }
94
- return [undefined, sourceIndex, outputIndex];
196
+ return [undefined, sourceIndex / this.channelCount, outputIndex];
95
197
  }
96
198
  }
97
199
  class Float32PlanerSourceProcessor extends SourceProcessor {
@@ -99,21 +201,24 @@ class Float32PlanerSourceProcessor extends SourceProcessor {
99
201
  const source = data.map((channel) => new Float32Array(channel));
100
202
  return [source, source[0].length];
101
203
  }
102
- copyChunk(sourceIndex, sourceIndexStep, source, outputLeft, outputRight, outputLength, outputIndex) {
103
- const sourceLeft = source[0];
104
- const sourceRight = source[1];
105
- const sourceLength = sourceLeft.length;
106
- let sourceSampleIndex = sourceIndex | 0;
107
- while (sourceSampleIndex < sourceLength) {
108
- outputLeft[outputIndex] = sourceLeft[sourceSampleIndex];
109
- outputRight[outputIndex] = sourceRight[sourceSampleIndex];
110
- sourceIndex += sourceIndexStep;
111
- sourceSampleIndex = sourceIndex | 0;
204
+ read(source, offset, target) {
205
+ for (let i = 0; i < target.length; i += 1) {
206
+ target[i] = source[i][offset];
207
+ }
208
+ }
209
+ copyChunk(source, outputs, outputLength, outputIndex) {
210
+ const sourceLength = source[0].length;
211
+ let sourceIndex = 0;
212
+ while (sourceIndex < sourceLength) {
213
+ for (let i = 0; i < this.channelCount; i += 1) {
214
+ outputs[i][outputIndex] = source[i][sourceIndex];
215
+ }
216
+ sourceIndex += 1;
112
217
  outputIndex += 1;
113
218
  if (outputIndex === outputLength) {
114
219
  return [
115
- sourceSampleIndex < sourceLength
116
- ? source.map((channel) => channel.subarray(sourceSampleIndex))
220
+ sourceIndex < sourceLength
221
+ ? source.map((channel) => channel.subarray(sourceIndex))
117
222
  : undefined,
118
223
  sourceIndex,
119
224
  outputIndex,
package/esm/worker.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"worker.js","sourceRoot":"","sources":["../worker/worker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"worker.js","sourceRoot":"","sources":["../worker/worker.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yume-chan/pcm-player",
3
- "version": "0.0.20",
3
+ "version": "0.0.22",
4
4
  "description": "Play raw audio sample stream using Web Audio API",
5
5
  "keywords": [
6
6
  "audio"
@@ -24,19 +24,19 @@
24
24
  "main": "esm/index.js",
25
25
  "types": "esm/index.d.ts",
26
26
  "dependencies": {
27
- "tslib": "^2.5.2"
27
+ "tslib": "^2.6.2"
28
28
  },
29
29
  "devDependencies": {
30
- "@jest/globals": "^29.5.0",
31
- "@types/audioworklet": "^0.0.46",
30
+ "@jest/globals": "^29.7.0",
31
+ "@types/audioworklet": "^0.0.52",
32
32
  "@yume-chan/eslint-config": "^1.0.0",
33
33
  "@yume-chan/tsconfig": "^1.0.0",
34
34
  "cross-env": "^7.0.3",
35
- "eslint": "^8.41.0",
36
- "jest": "^29.5.0",
37
- "prettier": "^2.8.8",
38
- "ts-jest": "^29.0.4",
39
- "typescript": "^5.0.3"
35
+ "eslint": "^8.55.0",
36
+ "jest": "^29.7.0",
37
+ "prettier": "^3.1.0",
38
+ "ts-jest": "^29.1.1",
39
+ "typescript": "^5.3.2"
40
40
  },
41
41
  "scripts": {
42
42
  "build": "tsc -b tsconfig.dom.json && tsc -b tsconfig.worker.json",
package/src/index.ts CHANGED
@@ -1,51 +1,67 @@
1
1
  export abstract class PcmPlayer<T> {
2
2
  protected abstract sourceName: string;
3
3
 
4
- private _context: AudioContext;
5
- private _worklet: AudioWorkletNode | undefined;
6
- private _buffer: T[] = [];
7
-
8
- constructor(sampleRate: number) {
9
- this._context = new AudioContext({
4
+ #context: AudioContext;
5
+ #channelCount: number;
6
+ #worklet: AudioWorkletNode | undefined;
7
+ #buffers: T[] = [];
8
+ #stopped = false;
9
+
10
+ constructor(sampleRate: number, channelCount: number) {
11
+ this.#context = new AudioContext({
10
12
  latencyHint: "interactive",
11
13
  sampleRate,
12
14
  });
15
+ this.#channelCount = channelCount;
13
16
  }
14
17
 
15
18
  protected abstract feedCore(worklet: AudioWorkletNode, source: T): void;
16
19
 
17
- public feed(source: T) {
18
- if (this._worklet === undefined) {
19
- this._buffer.push(source);
20
+ feed(source: T) {
21
+ if (this.#stopped) {
22
+ throw new Error("PcmPlayer is stopped");
23
+ }
24
+
25
+ if (this.#worklet === undefined) {
26
+ this.#buffers.push(source);
20
27
  return;
21
28
  }
22
29
 
23
- this.feedCore(this._worklet, source);
30
+ this.feedCore(this.#worklet, source);
24
31
  }
25
32
 
26
- public async start() {
27
- await this._context.audioWorklet.addModule(
28
- new URL("./worker.js", import.meta.url)
33
+ async start() {
34
+ await this.#context.audioWorklet.addModule(
35
+ new URL("./worker.js", import.meta.url),
29
36
  );
30
37
 
31
- this._worklet = new AudioWorkletNode(this._context, this.sourceName, {
38
+ if (this.#stopped) {
39
+ return;
40
+ }
41
+
42
+ this.#worklet = new AudioWorkletNode(this.#context, this.sourceName, {
32
43
  numberOfInputs: 0,
33
44
  numberOfOutputs: 1,
34
- outputChannelCount: [2],
45
+ outputChannelCount: [this.#channelCount],
35
46
  });
36
- this._worklet.connect(this._context.destination);
47
+ this.#worklet.connect(this.#context.destination);
37
48
 
38
- for (const source of this._buffer) {
39
- this.feedCore(this._worklet, source);
49
+ for (const source of this.#buffers) {
50
+ this.feedCore(this.#worklet, source);
40
51
  }
41
- this._buffer.length = 0;
52
+ this.#buffers.length = 0;
42
53
  }
43
54
 
44
55
  async stop() {
45
- this._worklet?.disconnect();
46
- this._worklet = undefined;
56
+ if (this.#stopped) {
57
+ return;
58
+ }
59
+ this.#stopped = true;
60
+
61
+ this.#worklet?.disconnect();
62
+ this.#worklet = undefined;
47
63
 
48
- await this._context.close();
64
+ await this.#context.close();
49
65
  }
50
66
  }
51
67
 
@@ -70,7 +86,7 @@ export class Float32PcmPlayer extends PcmPlayer<Float32Array> {
70
86
 
71
87
  protected override feedCore(
72
88
  worklet: AudioWorkletNode,
73
- source: Float32Array
89
+ source: Float32Array,
74
90
  ) {
75
91
  if (
76
92
  source.byteOffset !== 0 ||
@@ -89,7 +105,7 @@ export class Float32PlanerPcmPlayer extends PcmPlayer<Float32Array[]> {
89
105
 
90
106
  protected override feedCore(
91
107
  worklet: AudioWorkletNode,
92
- source: Float32Array[]
108
+ source: Float32Array[],
93
109
  ) {
94
110
  const buffers = source.map((channel) => {
95
111
  if (