@basmilius/apple-audio-source 0.6.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-present Bas Milius
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,4 @@
1
+ export declare const DEFAULT_BYTES_PER_CHANNEL = 2;
2
+ export declare const DEFAULT_CHANNELS = 2;
3
+ export declare const DEFAULT_SAMPLE_RATE = 44100;
4
+ export declare const FFMPEG_FRAMES_PER_PACKET = 352;
@@ -0,0 +1,3 @@
1
+ export declare function isMp3(buffer: Buffer): boolean;
2
+ export declare function isOgg(buffer: Buffer): boolean;
3
+ export declare function isWav(buffer: Buffer): boolean;
@@ -0,0 +1 @@
1
+ export default function(buffer: Buffer): Promise<Buffer>;
@@ -0,0 +1,3 @@
1
+ export { isMp3, isOgg, isWav } from "./codec";
2
+ export { default as decode } from "./decode";
3
+ export * from "./pcm";
@@ -0,0 +1,8 @@
1
+ export declare function convertPcm(input: Buffer, options: ConvertPcmOptions): Buffer;
2
+ type ConvertPcmOptions = {
3
+ readonly inputChannels: number;
4
+ readonly inputSampleRate: number;
5
+ readonly inputBitsPerSample: number;
6
+ readonly inputEndian: "little" | "big";
7
+ };
8
+ export {};
@@ -0,0 +1,10 @@
1
+ import type { AudioSource } from "@basmilius/apple-common";
2
+ export default class Ffmpeg implements AudioSource {
3
+ #private;
4
+ readonly duration: number;
5
+ constructor(filePath: string, duration: number, sampleRate?: number, channels?: number, bytesPerChannel?: number);
6
+ start(): Promise<void>;
7
+ reset(): Promise<void>;
8
+ stop(): Promise<void>;
9
+ readFrames(count: number): Promise<Buffer | null>;
10
+ }
@@ -0,0 +1,7 @@
1
+ export { default as Ffmpeg } from "./ffmpeg";
2
+ export { default as Mp3 } from "./mp3";
3
+ export { default as Ogg } from "./ogg";
4
+ export { default as Pcm } from "./pcm";
5
+ export { default as SineWave } from "./sineWave";
6
+ export { default as Url } from "./url";
7
+ export { default as Wav } from "./wav";
package/dist/index.js ADDED
@@ -0,0 +1,436 @@
1
+ // src/ffmpeg.ts
2
+ import { spawn } from "node:child_process";
3
+
4
+ // src/const.ts
5
+ var DEFAULT_BYTES_PER_CHANNEL = 2;
6
+ var DEFAULT_CHANNELS = 2;
7
+ var DEFAULT_SAMPLE_RATE = 44100;
8
+ var FFMPEG_FRAMES_PER_PACKET = 352;
9
+
10
+ // src/ffmpeg.ts
11
+ class Ffmpeg {
12
+ duration;
13
+ #frameSize;
14
+ #filePath;
15
+ #sampleRate;
16
+ #channels;
17
+ #ffmpeg = null;
18
+ #buffer = Buffer.alloc(0);
19
+ #ended = false;
20
+ #resolveQueue = [];
21
+ constructor(filePath, duration, sampleRate = DEFAULT_SAMPLE_RATE, channels = DEFAULT_CHANNELS, bytesPerChannel = DEFAULT_BYTES_PER_CHANNEL) {
22
+ this.#filePath = filePath;
23
+ this.duration = duration;
24
+ this.#sampleRate = sampleRate;
25
+ this.#channels = channels;
26
+ this.#frameSize = channels * bytesPerChannel;
27
+ }
28
+ async start() {
29
+ this.#ffmpeg = spawn("ffmpeg", [
30
+ "-i",
31
+ this.#filePath,
32
+ "-f",
33
+ "s16be",
34
+ "-acodec",
35
+ "pcm_s16be",
36
+ "-ar",
37
+ String(this.#sampleRate),
38
+ "-ac",
39
+ String(this.#channels),
40
+ "-"
41
+ ], {
42
+ stdio: ["ignore", "pipe", "ignore"]
43
+ });
44
+ this.#ffmpeg.stdout.on("data", (chunk) => {
45
+ this.#buffer = Buffer.concat([this.#buffer, chunk]);
46
+ this.#processQueue();
47
+ });
48
+ this.#ffmpeg.stdout.on("end", () => {
49
+ this.#ended = true;
50
+ this.#processQueue();
51
+ });
52
+ this.#ffmpeg.on("error", (err) => {
53
+ console.error("ffmpeg error:", err);
54
+ this.#ended = true;
55
+ this.#processQueue();
56
+ });
57
+ }
58
+ async reset() {}
59
+ async stop() {
60
+ if (!this.#ffmpeg) {
61
+ return;
62
+ }
63
+ while (this.#resolveQueue.length > 0) {
64
+ this.#resolveQueue.shift()(null);
65
+ }
66
+ this.#ffmpeg.stdout?.removeAllListeners();
67
+ this.#ffmpeg.removeAllListeners();
68
+ this.#ffmpeg.kill();
69
+ this.#ffmpeg = null;
70
+ }
71
+ async readFrames(count) {
72
+ const bytesNeeded = count * this.#frameSize;
73
+ if (this.#buffer.length >= bytesNeeded) {
74
+ const chunk = this.#buffer.subarray(0, bytesNeeded);
75
+ this.#buffer = this.#buffer.subarray(bytesNeeded);
76
+ return chunk;
77
+ }
78
+ if (this.#ended) {
79
+ if (this.#buffer.length > 0) {
80
+ const chunk = this.#buffer;
81
+ this.#buffer = Buffer.alloc(0);
82
+ return chunk;
83
+ }
84
+ return null;
85
+ }
86
+ return new Promise((resolve) => {
87
+ this.#resolveQueue.push(resolve);
88
+ });
89
+ }
90
+ #processQueue() {
91
+ while (this.#resolveQueue.length > 0) {
92
+ const bytesNeeded = FFMPEG_FRAMES_PER_PACKET * this.#frameSize;
93
+ if (this.#buffer.length >= bytesNeeded) {
94
+ const chunk = this.#buffer.subarray(0, bytesNeeded);
95
+ this.#buffer = this.#buffer.subarray(bytesNeeded);
96
+ this.#resolveQueue.shift()(chunk);
97
+ } else if (this.#ended) {
98
+ if (this.#buffer.length > 0) {
99
+ const chunk = this.#buffer;
100
+ this.#buffer = Buffer.alloc(0);
101
+ this.#resolveQueue.shift()(chunk);
102
+ } else {
103
+ this.#resolveQueue.shift()(null);
104
+ }
105
+ } else {
106
+ break;
107
+ }
108
+ }
109
+ }
110
+ }
111
+ // src/decoder/codec.ts
112
+ function isMp3(buffer) {
113
+ return buffer[0] === 73 && buffer[1] === 68 && buffer[2] === 51 || buffer[0] === 255 && (buffer[1] & 224) === 224;
114
+ }
115
+ function isOgg(buffer) {
116
+ return buffer.length > 4 && buffer.toString("ascii", 0, 4) === "OggS";
117
+ }
118
+ function isWav(buffer) {
119
+ return buffer.length > 12 && buffer.toString("ascii", 0, 4) === "RIFF" && buffer.toString("ascii", 8, 12) === "WAVE";
120
+ }
121
+ // src/decoder/pcm.ts
122
+ function convertPcm(input, options) {
123
+ const { inputChannels, inputSampleRate, inputBitsPerSample, inputEndian } = options;
124
+ const bytesPerSample = inputBitsPerSample / 8;
125
+ const inputFrameSize = inputChannels * bytesPerSample;
126
+ const inputFrames = Math.floor(input.length / inputFrameSize);
127
+ const outputFrames = Math.floor(inputFrames * DEFAULT_SAMPLE_RATE / inputSampleRate);
128
+ const output = Buffer.alloc(outputFrames * DEFAULT_CHANNELS * DEFAULT_BYTES_PER_CHANNEL);
129
+ for (let i = 0;i < outputFrames; i++) {
130
+ const srcPos = i * inputSampleRate / DEFAULT_SAMPLE_RATE;
131
+ const srcIndex = Math.floor(srcPos);
132
+ const srcFrac = srcPos - srcIndex;
133
+ for (let ch = 0;ch < DEFAULT_CHANNELS; ch++) {
134
+ const inputCh = Math.min(ch, inputChannels - 1);
135
+ const sample1 = readSample(input, srcIndex, inputCh, inputFrameSize, bytesPerSample, inputBitsPerSample, inputEndian);
136
+ const sample2 = srcIndex + 1 < inputFrames ? readSample(input, srcIndex + 1, inputCh, inputFrameSize, bytesPerSample, inputBitsPerSample, inputEndian) : sample1;
137
+ const sample = sample1 + (sample2 - sample1) * srcFrac;
138
+ const outputOffset = (i * DEFAULT_CHANNELS + ch) * DEFAULT_BYTES_PER_CHANNEL;
139
+ output.writeInt16BE(Math.round(Math.max(-32768, Math.min(32767, sample))), outputOffset);
140
+ }
141
+ }
142
+ return output;
143
+ }
144
+ function readSample(buffer, frame, channel, frameSize, bytesPerSample, bitsPerSample, endian) {
145
+ const offset = frame * frameSize + channel * bytesPerSample;
146
+ if (offset + bytesPerSample > buffer.length)
147
+ return 0;
148
+ if (bitsPerSample === 16) {
149
+ return endian === "little" ? buffer.readInt16LE(offset) : buffer.readInt16BE(offset);
150
+ }
151
+ if (bitsPerSample === 8) {
152
+ return (buffer[offset] - 128) * 256;
153
+ }
154
+ if (bitsPerSample === 24) {
155
+ let value;
156
+ if (endian === "little") {
157
+ value = buffer[offset] | buffer[offset + 1] << 8 | buffer[offset + 2] << 16;
158
+ } else {
159
+ value = buffer[offset] << 16 | buffer[offset + 1] << 8 | buffer[offset + 2];
160
+ }
161
+ if (value & 8388608) {
162
+ value |= ~16777215;
163
+ }
164
+ return value / 256;
165
+ }
166
+ if (bitsPerSample === 32) {
167
+ const value = endian === "little" ? buffer.readInt32LE(offset) : buffer.readInt32BE(offset);
168
+ return value / 65536;
169
+ }
170
+ return 0;
171
+ }
172
+
173
+ // src/decoder/decode.ts
174
+ import audioDecode from "audio-decode";
175
+ async function decode_default(buffer) {
176
+ const audioBuffer = await audioDecode(buffer);
177
+ const numChannels = audioBuffer.numberOfChannels;
178
+ const numFrames = audioBuffer.length;
179
+ const sampleRate = audioBuffer.sampleRate;
180
+ const tempBuffer = Buffer.alloc(numFrames * DEFAULT_CHANNELS * DEFAULT_BYTES_PER_CHANNEL);
181
+ for (let i = 0;i < numFrames; i++) {
182
+ for (let ch = 0;ch < DEFAULT_CHANNELS; ch++) {
183
+ const inputCh = Math.min(ch, numChannels - 1);
184
+ const channelData = audioBuffer.getChannelData(inputCh);
185
+ const sample = Math.round(channelData[i] * 32767);
186
+ const clampedSample = Math.max(-32768, Math.min(32767, sample));
187
+ tempBuffer.writeInt16BE(clampedSample, (i * DEFAULT_CHANNELS + ch) * DEFAULT_BYTES_PER_CHANNEL);
188
+ }
189
+ }
190
+ if (sampleRate !== DEFAULT_SAMPLE_RATE) {
191
+ return convertPcm(tempBuffer, {
192
+ inputChannels: DEFAULT_CHANNELS,
193
+ inputSampleRate: sampleRate,
194
+ inputBitsPerSample: 16,
195
+ inputEndian: "big"
196
+ });
197
+ }
198
+ return tempBuffer;
199
+ }
200
+ // src/mp3.ts
201
+ class Mp3 {
202
+ duration;
203
+ #buffer;
204
+ #frameSize;
205
+ #offset = 0;
206
+ constructor(buffer, duration) {
207
+ this.#buffer = buffer;
208
+ this.#frameSize = DEFAULT_CHANNELS * DEFAULT_BYTES_PER_CHANNEL;
209
+ this.duration = duration;
210
+ }
211
+ async readFrames(count) {
212
+ if (this.#offset >= this.#buffer.length) {
213
+ return null;
214
+ }
215
+ const bytesToRead = count * this.#frameSize;
216
+ const chunk = this.#buffer.subarray(this.#offset, this.#offset + bytesToRead);
217
+ this.#offset += bytesToRead;
218
+ return chunk.length > 0 ? chunk : null;
219
+ }
220
+ async reset() {
221
+ this.#offset = 0;
222
+ }
223
+ async start() {}
224
+ async stop() {}
225
+ static async fromBuffer(mp3Buffer) {
226
+ if (!isMp3(mp3Buffer)) {
227
+ throw new Error("Invalid MP3 file");
228
+ }
229
+ const pcmBuffer = await decode_default(mp3Buffer);
230
+ const duration = pcmBuffer.length / (DEFAULT_CHANNELS * DEFAULT_BYTES_PER_CHANNEL) / DEFAULT_SAMPLE_RATE;
231
+ return new Mp3(pcmBuffer, duration);
232
+ }
233
+ static async fromUrl(url) {
234
+ const response = await fetch(url);
235
+ const arrayBuffer = await response.arrayBuffer();
236
+ return Mp3.fromBuffer(Buffer.from(arrayBuffer));
237
+ }
238
+ }
239
+ // src/ogg.ts
240
+ class Ogg {
241
+ duration;
242
+ #buffer;
243
+ #frameSize;
244
+ #offset = 0;
245
+ constructor(buffer, duration) {
246
+ this.#buffer = buffer;
247
+ this.#frameSize = DEFAULT_CHANNELS * DEFAULT_BYTES_PER_CHANNEL;
248
+ this.duration = duration;
249
+ }
250
+ async readFrames(count) {
251
+ if (this.#offset >= this.#buffer.length) {
252
+ return null;
253
+ }
254
+ const bytesToRead = count * this.#frameSize;
255
+ const chunk = this.#buffer.subarray(this.#offset, this.#offset + bytesToRead);
256
+ this.#offset += bytesToRead;
257
+ return chunk.length > 0 ? chunk : null;
258
+ }
259
+ async reset() {
260
+ this.#offset = 0;
261
+ }
262
+ async start() {}
263
+ async stop() {}
264
+ static async fromBuffer(oggBuffer) {
265
+ if (!isOgg(oggBuffer)) {
266
+ throw new Error("Invalid OGG file");
267
+ }
268
+ const pcmBuffer = await decode_default(oggBuffer);
269
+ const duration = pcmBuffer.length / (DEFAULT_CHANNELS * DEFAULT_BYTES_PER_CHANNEL) / DEFAULT_SAMPLE_RATE;
270
+ return new Ogg(pcmBuffer, duration);
271
+ }
272
+ static async fromUrl(url) {
273
+ const response = await fetch(url);
274
+ const arrayBuffer = await response.arrayBuffer();
275
+ return Ogg.fromBuffer(Buffer.from(arrayBuffer));
276
+ }
277
+ }
278
+ // src/pcm.ts
279
+ class Pcm {
280
+ duration;
281
+ #buffer;
282
+ #frameSize;
283
+ #offset = 0;
284
+ constructor(pcmBuffer, sampleRate = DEFAULT_SAMPLE_RATE) {
285
+ this.#buffer = pcmBuffer;
286
+ this.#frameSize = DEFAULT_CHANNELS * DEFAULT_BYTES_PER_CHANNEL;
287
+ this.duration = pcmBuffer.length / this.#frameSize / sampleRate;
288
+ }
289
+ async readFrames(count) {
290
+ if (this.#offset >= this.#buffer.length) {
291
+ return null;
292
+ }
293
+ const bytesToRead = count * this.#frameSize;
294
+ const chunk = this.#buffer.subarray(this.#offset, this.#offset + bytesToRead);
295
+ this.#offset += bytesToRead;
296
+ return chunk.length > 0 ? chunk : null;
297
+ }
298
+ async reset() {
299
+ this.#offset = 0;
300
+ }
301
+ async start() {}
302
+ async stop() {}
303
+ }
304
+ // src/sineWave.ts
305
+ class SineWave {
306
+ duration;
307
+ #buffer;
308
+ #frameSize;
309
+ #offset = 0;
310
+ constructor(durationSeconds, frequency = 440, sampleRate = DEFAULT_SAMPLE_RATE, channels = DEFAULT_CHANNELS, bytesPerChannel = DEFAULT_BYTES_PER_CHANNEL) {
311
+ this.duration = durationSeconds;
312
+ this.#frameSize = channels * bytesPerChannel;
313
+ this.#buffer = this.#generateSineWave(sampleRate, channels, bytesPerChannel, durationSeconds, frequency);
314
+ }
315
+ #generateSineWave(sampleRate, channels, bytesPerChannel, durationSeconds, frequency) {
316
+ const totalSamples = sampleRate * durationSeconds;
317
+ const buffer = Buffer.alloc(totalSamples * channels * bytesPerChannel);
318
+ const fadeSamples = Math.floor(sampleRate * 0.05);
319
+ for (let i = 0;i < totalSamples; i++) {
320
+ const sample = Math.sin(2 * Math.PI * frequency * i / sampleRate);
321
+ let envelope = 1;
322
+ if (i < fadeSamples) {
323
+ envelope = i / fadeSamples;
324
+ } else if (i >= totalSamples - fadeSamples) {
325
+ envelope = (totalSamples - i) / fadeSamples;
326
+ }
327
+ const value = Math.round(sample * envelope * 32767);
328
+ for (let ch = 0;ch < channels; ch++) {
329
+ const offset = (i * channels + ch) * bytesPerChannel;
330
+ buffer.writeInt16BE(value, offset);
331
+ }
332
+ }
333
+ return buffer;
334
+ }
335
+ async readFrames(count) {
336
+ if (this.#offset >= this.#buffer.length) {
337
+ return null;
338
+ }
339
+ const bytesToRead = count * this.#frameSize;
340
+ const chunk = this.#buffer.subarray(this.#offset, this.#offset + bytesToRead);
341
+ this.#offset += bytesToRead;
342
+ return chunk.length > 0 ? chunk : null;
343
+ }
344
+ async reset() {
345
+ this.#offset = 0;
346
+ }
347
+ async start() {}
348
+ async stop() {}
349
+ }
350
+ // src/url.ts
351
+ class Url {
352
+ duration;
353
+ #buffer;
354
+ #frameSize;
355
+ #offset = 0;
356
+ constructor(buffer, duration) {
357
+ this.#buffer = buffer;
358
+ this.#frameSize = DEFAULT_CHANNELS * DEFAULT_BYTES_PER_CHANNEL;
359
+ this.duration = duration;
360
+ }
361
+ async readFrames(count) {
362
+ if (this.#offset >= this.#buffer.length) {
363
+ return null;
364
+ }
365
+ const bytesToRead = count * this.#frameSize;
366
+ const chunk = this.#buffer.subarray(this.#offset, this.#offset + bytesToRead);
367
+ this.#offset += bytesToRead;
368
+ return chunk.length > 0 ? chunk : null;
369
+ }
370
+ async reset() {
371
+ this.#offset = 0;
372
+ }
373
+ async start() {}
374
+ async stop() {}
375
+ static async fromUrl(url) {
376
+ const response = await fetch(url);
377
+ const arrayBuffer = await response.arrayBuffer();
378
+ const buffer = Buffer.from(arrayBuffer);
379
+ let pcmBuffer;
380
+ if (isMp3(buffer) || isOgg(buffer) || isWav(buffer)) {
381
+ pcmBuffer = await decode_default(buffer);
382
+ } else {
383
+ throw new Error("Unsupported audio format. Please use WAV or MP3.");
384
+ }
385
+ const duration = pcmBuffer.length / (DEFAULT_CHANNELS * DEFAULT_BYTES_PER_CHANNEL) / DEFAULT_SAMPLE_RATE;
386
+ return new Url(pcmBuffer, duration);
387
+ }
388
+ }
389
+ // src/wav.ts
390
+ class Wav {
391
+ duration;
392
+ #buffer;
393
+ #frameSize;
394
+ #offset = 0;
395
+ constructor(buffer, duration) {
396
+ this.#buffer = buffer;
397
+ this.#frameSize = DEFAULT_CHANNELS * DEFAULT_BYTES_PER_CHANNEL;
398
+ this.duration = duration;
399
+ }
400
+ async readFrames(count) {
401
+ if (this.#offset >= this.#buffer.length) {
402
+ return null;
403
+ }
404
+ const bytesToRead = count * this.#frameSize;
405
+ const chunk = this.#buffer.subarray(this.#offset, this.#offset + bytesToRead);
406
+ this.#offset += bytesToRead;
407
+ return chunk.length > 0 ? chunk : null;
408
+ }
409
+ async reset() {
410
+ this.#offset = 0;
411
+ }
412
+ async start() {}
413
+ async stop() {}
414
+ static async fromBuffer(wavBuffer) {
415
+ if (!isWav(wavBuffer)) {
416
+ throw new Error("Invalid WAV file");
417
+ }
418
+ const pcmBuffer = await decode_default(wavBuffer);
419
+ const duration = pcmBuffer.length / (DEFAULT_CHANNELS * DEFAULT_BYTES_PER_CHANNEL) / DEFAULT_SAMPLE_RATE;
420
+ return new Wav(pcmBuffer, duration);
421
+ }
422
+ static async fromUrl(url) {
423
+ const response = await fetch(url);
424
+ const arrayBuffer = await response.arrayBuffer();
425
+ return Wav.fromBuffer(Buffer.from(arrayBuffer));
426
+ }
427
+ }
428
+ export {
429
+ Wav,
430
+ Url,
431
+ SineWave,
432
+ Pcm,
433
+ Ogg,
434
+ Mp3,
435
+ Ffmpeg
436
+ };
package/dist/mp3.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ import type { AudioSource } from "@basmilius/apple-common";
2
+ export default class Mp3 implements AudioSource {
3
+ #private;
4
+ readonly duration: number;
5
+ constructor(buffer: Buffer, duration: number);
6
+ readFrames(count: number): Promise<Buffer | null>;
7
+ reset(): Promise<void>;
8
+ start(): Promise<void>;
9
+ stop(): Promise<void>;
10
+ static fromBuffer(mp3Buffer: Buffer): Promise<Mp3>;
11
+ static fromUrl(url: string): Promise<Mp3>;
12
+ }
package/dist/ogg.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ import type { AudioSource } from "@basmilius/apple-common";
2
+ export default class Ogg implements AudioSource {
3
+ #private;
4
+ readonly duration: number;
5
+ constructor(buffer: Buffer, duration: number);
6
+ readFrames(count: number): Promise<Buffer | null>;
7
+ reset(): Promise<void>;
8
+ start(): Promise<void>;
9
+ stop(): Promise<void>;
10
+ static fromBuffer(oggBuffer: Buffer): Promise<Ogg>;
11
+ static fromUrl(url: string): Promise<Ogg>;
12
+ }
package/dist/pcm.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ import type { AudioSource } from "@basmilius/apple-common";
2
+ export default class Pcm implements AudioSource {
3
+ #private;
4
+ readonly duration: number;
5
+ constructor(pcmBuffer: Buffer, sampleRate?: number);
6
+ readFrames(count: number): Promise<Buffer | null>;
7
+ reset(): Promise<void>;
8
+ start(): Promise<void>;
9
+ stop(): Promise<void>;
10
+ }
@@ -0,0 +1,10 @@
1
+ import type { AudioSource } from "@basmilius/apple-common";
2
+ export default class SineWave implements AudioSource {
3
+ #private;
4
+ readonly duration: number;
5
+ constructor(durationSeconds: number, frequency?: number, sampleRate?: number, channels?: number, bytesPerChannel?: number);
6
+ readFrames(count: number): Promise<Buffer | null>;
7
+ reset(): Promise<void>;
8
+ start(): Promise<void>;
9
+ stop(): Promise<void>;
10
+ }
package/dist/url.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ import type { AudioSource } from "@basmilius/apple-common";
2
+ export default class Url implements AudioSource {
3
+ #private;
4
+ readonly duration: number;
5
+ constructor(buffer: Buffer, duration: number);
6
+ readFrames(count: number): Promise<Buffer | null>;
7
+ reset(): Promise<void>;
8
+ start(): Promise<void>;
9
+ stop(): Promise<void>;
10
+ static fromUrl(url: string): Promise<Url>;
11
+ }
package/dist/wav.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ import type { AudioSource } from "@basmilius/apple-common";
2
+ export default class Wav implements AudioSource {
3
+ #private;
4
+ readonly duration: number;
5
+ constructor(buffer: Buffer, duration: number);
6
+ readFrames(count: number): Promise<Buffer | null>;
7
+ reset(): Promise<void>;
8
+ start(): Promise<void>;
9
+ stop(): Promise<void>;
10
+ static fromBuffer(wavBuffer: Buffer): Promise<Wav>;
11
+ static fromUrl(url: string): Promise<Wav>;
12
+ }
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@basmilius/apple-audio-source",
3
+ "description": "Different audio sources for use in Apple Streaming Protocols.",
4
+ "version": "0.6.0",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": {
8
+ "name": "Bas Milius",
9
+ "email": "bas@mili.us",
10
+ "url": "https://bas.dev"
11
+ },
12
+ "keywords": [],
13
+ "files": [
14
+ "dist",
15
+ "LICENSE"
16
+ ],
17
+ "publishConfig": {
18
+ "access": "public",
19
+ "provenance": true
20
+ },
21
+ "scripts": {
22
+ "build": "tsc && bun -b build.ts"
23
+ },
24
+ "main": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "typings": "./dist/index.d.ts",
27
+ "sideEffects": false,
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "default": "./dist/index.js"
32
+ }
33
+ },
34
+ "dependencies": {
35
+ "@basmilius/apple-common": "0.6.0",
36
+ "audio-decode": "^2.2.3"
37
+ },
38
+ "devDependencies": {
39
+ "@basmilius/tools": "^2.23.0",
40
+ "@types/bun": "^1.3.8"
41
+ }
42
+ }