@pompeii-labs/audio 0.0.1

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/README.md ADDED
@@ -0,0 +1 @@
1
+ # @pompeii-labs/audio
@@ -0,0 +1,15 @@
1
+ type AudioEncoding = 'pcm' | 'mulaw';
2
+ type AudioFormat = {
3
+ sampleRate: number;
4
+ channels: 1;
5
+ encoding: AudioEncoding;
6
+ };
7
+ interface PCMData {
8
+ sampleRate: number;
9
+ channels: number;
10
+ bitsPerSample: number;
11
+ samples: Float32Array;
12
+ duration: number;
13
+ }
14
+
15
+ export type { AudioFormat as A, PCMData as P, AudioEncoding as a };
@@ -0,0 +1,15 @@
1
+ type AudioEncoding = 'pcm' | 'mulaw';
2
+ type AudioFormat = {
3
+ sampleRate: number;
4
+ channels: 1;
5
+ encoding: AudioEncoding;
6
+ };
7
+ interface PCMData {
8
+ sampleRate: number;
9
+ channels: number;
10
+ bitsPerSample: number;
11
+ samples: Float32Array;
12
+ duration: number;
13
+ }
14
+
15
+ export type { AudioFormat as A, PCMData as P, AudioEncoding as a };
@@ -0,0 +1,44 @@
1
+ import { P as PCMData, A as AudioFormat$1 } from './index-o4B-ThOL.mjs';
2
+ export { a as AudioEncoding } from './index-o4B-ThOL.mjs';
3
+
4
+ /**
5
+ * Decodes a WAV audio file from raw bytes into PCM (Pulse-Code Modulation) data.
6
+ * WAV files consist of a header followed by chunks of data. The main chunks are:
7
+ * - 'RIFF' chunk: Contains the file identifier and size
8
+ * - 'fmt ' chunk: Contains format information (sample rate, channels, etc.)
9
+ * - 'data' chunk: Contains the actual audio samples
10
+ *
11
+ * @param bytes - Raw bytes of the WAV file as a Uint8Array
12
+ * @returns PCMData object containing decoded audio data, or null if the file is not a valid WAV
13
+ */
14
+ declare function decodeWAV(bytes: Uint8Array): PCMData | null;
15
+ interface PCMFormat {
16
+ bitDepth: 8 | 16 | 24 | 32;
17
+ signed: boolean;
18
+ littleEndian: boolean;
19
+ float: boolean;
20
+ }
21
+
22
+ declare function mulawToPcm16(mulawData: Buffer): Int16Array;
23
+
24
+ declare function pcm16ToMulaw(pcmData: Int16Array): Uint8Array;
25
+
26
+ declare function bufferToInt16Array(buffer: Buffer): Int16Array;
27
+
28
+ declare function encodePcm(audio: Int16Array, encoding: AudioFormat$1['encoding']): Buffer;
29
+ declare function decodeToPcm(audio: Buffer, encoding: AudioFormat$1['encoding']): Int16Array;
30
+
31
+ interface AudioFormat {
32
+ format: string;
33
+ mimeType: string;
34
+ description: string;
35
+ }
36
+ declare function identifyAudioFormat(bytes: Uint8Array): AudioFormat | null;
37
+
38
+ declare function generateFadeOutSamples(lastSampleValue: number, fadeDurationMs: number, sampleRate: number): Uint8Array;
39
+
40
+ declare function int16ArrayToBuffer(int16Array: Int16Array): Buffer;
41
+
42
+ declare function resamplePcm(pcm: Int16Array, originalSampleRate: number, targetSampleRate: number): Int16Array;
43
+
44
+ export { AudioFormat$1 as AudioFormat, PCMData, type PCMFormat, bufferToInt16Array, decodeToPcm, decodeWAV, encodePcm, generateFadeOutSamples, identifyAudioFormat, int16ArrayToBuffer, mulawToPcm16, pcm16ToMulaw, resamplePcm };
@@ -0,0 +1,44 @@
1
+ import { P as PCMData, A as AudioFormat$1 } from './index-o4B-ThOL.js';
2
+ export { a as AudioEncoding } from './index-o4B-ThOL.js';
3
+
4
+ /**
5
+ * Decodes a WAV audio file from raw bytes into PCM (Pulse-Code Modulation) data.
6
+ * WAV files consist of a header followed by chunks of data. The main chunks are:
7
+ * - 'RIFF' chunk: Contains the file identifier and size
8
+ * - 'fmt ' chunk: Contains format information (sample rate, channels, etc.)
9
+ * - 'data' chunk: Contains the actual audio samples
10
+ *
11
+ * @param bytes - Raw bytes of the WAV file as a Uint8Array
12
+ * @returns PCMData object containing decoded audio data, or null if the file is not a valid WAV
13
+ */
14
+ declare function decodeWAV(bytes: Uint8Array): PCMData | null;
15
+ interface PCMFormat {
16
+ bitDepth: 8 | 16 | 24 | 32;
17
+ signed: boolean;
18
+ littleEndian: boolean;
19
+ float: boolean;
20
+ }
21
+
22
+ declare function mulawToPcm16(mulawData: Buffer): Int16Array;
23
+
24
+ declare function pcm16ToMulaw(pcmData: Int16Array): Uint8Array;
25
+
26
+ declare function bufferToInt16Array(buffer: Buffer): Int16Array;
27
+
28
+ declare function encodePcm(audio: Int16Array, encoding: AudioFormat$1['encoding']): Buffer;
29
+ declare function decodeToPcm(audio: Buffer, encoding: AudioFormat$1['encoding']): Int16Array;
30
+
31
+ interface AudioFormat {
32
+ format: string;
33
+ mimeType: string;
34
+ description: string;
35
+ }
36
+ declare function identifyAudioFormat(bytes: Uint8Array): AudioFormat | null;
37
+
38
+ declare function generateFadeOutSamples(lastSampleValue: number, fadeDurationMs: number, sampleRate: number): Uint8Array;
39
+
40
+ declare function int16ArrayToBuffer(int16Array: Int16Array): Buffer;
41
+
42
+ declare function resamplePcm(pcm: Int16Array, originalSampleRate: number, targetSampleRate: number): Int16Array;
43
+
44
+ export { AudioFormat$1 as AudioFormat, PCMData, type PCMFormat, bufferToInt16Array, decodeToPcm, decodeWAV, encodePcm, generateFadeOutSamples, identifyAudioFormat, int16ArrayToBuffer, mulawToPcm16, pcm16ToMulaw, resamplePcm };
package/dist/index.js ADDED
@@ -0,0 +1,533 @@
1
+ 'use strict';
2
+
3
+ // src/decoders/wav.ts
4
+ function decodeWAV(bytes) {
5
+ const view = new DataView(bytes.buffer);
6
+ if (String.fromCharCode(...bytes.slice(0, 4)) !== "RIFF" || String.fromCharCode(...bytes.slice(8, 12)) !== "WAVE") {
7
+ console.log("Invalid WAV header detected");
8
+ return null;
9
+ }
10
+ let offset = 12;
11
+ let audioFormat = 0;
12
+ let channels = 0;
13
+ let sampleRate = 0;
14
+ let bitsPerSample = 0;
15
+ let dataOffset = 0;
16
+ let dataSize = 0;
17
+ while (offset < bytes.length - 8) {
18
+ const chunkId = String.fromCharCode(...bytes.slice(offset, offset + 4));
19
+ const chunkSize = view.getUint32(offset + 4, true);
20
+ if (chunkId === "fmt ") {
21
+ audioFormat = view.getUint16(offset + 8, true);
22
+ channels = view.getUint16(offset + 10, true);
23
+ sampleRate = view.getUint32(offset + 12, true);
24
+ bitsPerSample = view.getUint16(offset + 22, true);
25
+ } else if (chunkId === "data") {
26
+ dataOffset = offset + 8;
27
+ const availableSize = bytes.length - dataOffset;
28
+ dataSize = Math.min(chunkSize, availableSize);
29
+ break;
30
+ }
31
+ offset += 8 + chunkSize;
32
+ }
33
+ if (audioFormat !== 1) {
34
+ throw new Error(`Unsupported WAV format: ${audioFormat}`);
35
+ }
36
+ const bytesPerSample = bitsPerSample / 8;
37
+ const numSamples = Math.floor(dataSize / bytesPerSample);
38
+ const samples = new Float32Array(numSamples);
39
+ for (let i = 0; i < numSamples; i++) {
40
+ const byteOffset = dataOffset + i * bytesPerSample;
41
+ if (byteOffset + bytesPerSample > bytes.length) {
42
+ console.error("Buffer overflow detected:", {
43
+ byteOffset,
44
+ bytesPerSample,
45
+ bufferLength: bytes.length,
46
+ sampleIndex: i
47
+ });
48
+ throw new Error("Buffer overflow while reading samples");
49
+ }
50
+ let sample = 0;
51
+ if (bitsPerSample === 8) {
52
+ sample = (bytes[byteOffset] - 128) / 128;
53
+ } else if (bitsPerSample === 16) {
54
+ const rawValue = view.getInt16(byteOffset, true);
55
+ sample = rawValue / 32768;
56
+ } else if (bitsPerSample === 24) {
57
+ const byte1 = bytes[byteOffset];
58
+ const byte2 = bytes[byteOffset + 1];
59
+ const byte3 = bytes[byteOffset + 2];
60
+ const value = byte3 << 16 | byte2 << 8 | byte1;
61
+ sample = (value > 8388607 ? value - 16777216 : value) / 8388608;
62
+ } else if (bitsPerSample === 32) {
63
+ sample = view.getFloat32(byteOffset, true);
64
+ }
65
+ samples[i] = Math.max(-1, Math.min(1, sample));
66
+ }
67
+ const result = {
68
+ sampleRate,
69
+ channels,
70
+ bitsPerSample,
71
+ samples,
72
+ duration: numSamples / (sampleRate * channels)
73
+ // Calculate duration in seconds
74
+ };
75
+ return result;
76
+ }
77
+
78
+ // src/decoders/mulaw.ts
79
+ function mulawToPcm16(mulawData) {
80
+ const pcmData = new Int16Array(mulawData.length);
81
+ for (let i = 0; i < mulawData.length; i++) {
82
+ pcmData[i] = mulawToLinear(mulawData[i]);
83
+ }
84
+ return pcmData;
85
+ }
86
+ function mulawToLinear(mulawByte) {
87
+ const inverted = mulawByte ^ 255;
88
+ const sign = inverted & 128;
89
+ const segment = (inverted & 112) >> 4;
90
+ const step = inverted & 15;
91
+ let linear;
92
+ if (segment === 0) {
93
+ linear = (step << 1) + 1;
94
+ } else {
95
+ linear = (step << 1) + 1 + 32 << segment + 2;
96
+ }
97
+ linear -= 33;
98
+ return sign ? -linear : linear;
99
+ }
100
+
101
+ // src/encoders/mulaw.ts
102
+ var BIAS = 132;
103
+ var CLIP = 32635;
104
+ var encodeTable = [
105
+ 0,
106
+ 0,
107
+ 1,
108
+ 1,
109
+ 2,
110
+ 2,
111
+ 2,
112
+ 2,
113
+ 3,
114
+ 3,
115
+ 3,
116
+ 3,
117
+ 3,
118
+ 3,
119
+ 3,
120
+ 3,
121
+ 4,
122
+ 4,
123
+ 4,
124
+ 4,
125
+ 4,
126
+ 4,
127
+ 4,
128
+ 4,
129
+ 4,
130
+ 4,
131
+ 4,
132
+ 4,
133
+ 4,
134
+ 4,
135
+ 4,
136
+ 4,
137
+ 5,
138
+ 5,
139
+ 5,
140
+ 5,
141
+ 5,
142
+ 5,
143
+ 5,
144
+ 5,
145
+ 5,
146
+ 5,
147
+ 5,
148
+ 5,
149
+ 5,
150
+ 5,
151
+ 5,
152
+ 5,
153
+ 5,
154
+ 5,
155
+ 5,
156
+ 5,
157
+ 5,
158
+ 5,
159
+ 5,
160
+ 5,
161
+ 5,
162
+ 5,
163
+ 5,
164
+ 5,
165
+ 5,
166
+ 5,
167
+ 5,
168
+ 5,
169
+ 6,
170
+ 6,
171
+ 6,
172
+ 6,
173
+ 6,
174
+ 6,
175
+ 6,
176
+ 6,
177
+ 6,
178
+ 6,
179
+ 6,
180
+ 6,
181
+ 6,
182
+ 6,
183
+ 6,
184
+ 6,
185
+ 6,
186
+ 6,
187
+ 6,
188
+ 6,
189
+ 6,
190
+ 6,
191
+ 6,
192
+ 6,
193
+ 6,
194
+ 6,
195
+ 6,
196
+ 6,
197
+ 6,
198
+ 6,
199
+ 6,
200
+ 6,
201
+ 6,
202
+ 6,
203
+ 6,
204
+ 6,
205
+ 6,
206
+ 6,
207
+ 6,
208
+ 6,
209
+ 6,
210
+ 6,
211
+ 6,
212
+ 6,
213
+ 6,
214
+ 6,
215
+ 6,
216
+ 6,
217
+ 6,
218
+ 6,
219
+ 6,
220
+ 6,
221
+ 6,
222
+ 6,
223
+ 6,
224
+ 6,
225
+ 6,
226
+ 6,
227
+ 6,
228
+ 6,
229
+ 6,
230
+ 6,
231
+ 6,
232
+ 6,
233
+ 7,
234
+ 7,
235
+ 7,
236
+ 7,
237
+ 7,
238
+ 7,
239
+ 7,
240
+ 7,
241
+ 7,
242
+ 7,
243
+ 7,
244
+ 7,
245
+ 7,
246
+ 7,
247
+ 7,
248
+ 7,
249
+ 7,
250
+ 7,
251
+ 7,
252
+ 7,
253
+ 7,
254
+ 7,
255
+ 7,
256
+ 7,
257
+ 7,
258
+ 7,
259
+ 7,
260
+ 7,
261
+ 7,
262
+ 7,
263
+ 7,
264
+ 7,
265
+ 7,
266
+ 7,
267
+ 7,
268
+ 7,
269
+ 7,
270
+ 7,
271
+ 7,
272
+ 7,
273
+ 7,
274
+ 7,
275
+ 7,
276
+ 7,
277
+ 7,
278
+ 7,
279
+ 7,
280
+ 7,
281
+ 7,
282
+ 7,
283
+ 7,
284
+ 7,
285
+ 7,
286
+ 7,
287
+ 7,
288
+ 7,
289
+ 7,
290
+ 7,
291
+ 7,
292
+ 7,
293
+ 7,
294
+ 7,
295
+ 7,
296
+ 7,
297
+ 7,
298
+ 7,
299
+ 7,
300
+ 7,
301
+ 7,
302
+ 7,
303
+ 7,
304
+ 7,
305
+ 7,
306
+ 7,
307
+ 7,
308
+ 7,
309
+ 7,
310
+ 7,
311
+ 7,
312
+ 7,
313
+ 7,
314
+ 7,
315
+ 7,
316
+ 7,
317
+ 7,
318
+ 7,
319
+ 7,
320
+ 7,
321
+ 7,
322
+ 7,
323
+ 7,
324
+ 7,
325
+ 7,
326
+ 7,
327
+ 7,
328
+ 7,
329
+ 7,
330
+ 7,
331
+ 7,
332
+ 7,
333
+ 7,
334
+ 7,
335
+ 7,
336
+ 7,
337
+ 7,
338
+ 7,
339
+ 7,
340
+ 7,
341
+ 7,
342
+ 7,
343
+ 7,
344
+ 7,
345
+ 7,
346
+ 7,
347
+ 7,
348
+ 7,
349
+ 7,
350
+ 7,
351
+ 7,
352
+ 7,
353
+ 7,
354
+ 7,
355
+ 7,
356
+ 7,
357
+ 7,
358
+ 7,
359
+ 7,
360
+ 7
361
+ ];
362
+ function encodeSample(sample) {
363
+ const sign = sample >> 8 & 128;
364
+ if (sign !== 0) sample = -sample;
365
+ sample = sample + BIAS;
366
+ if (sample > CLIP) sample = CLIP;
367
+ const exponent = encodeTable[sample >> 7 & 255];
368
+ const mantissa = sample >> exponent + 3 & 15;
369
+ return ~(sign | exponent << 4 | mantissa);
370
+ }
371
+ function pcm16ToMulaw(pcmData) {
372
+ const mulawData = new Uint8Array(pcmData.length);
373
+ for (let i = 0; i < pcmData.length; i++) {
374
+ mulawData[i] = encodeSample(pcmData[i]);
375
+ }
376
+ return mulawData;
377
+ }
378
+
379
+ // src/helpers/bufferToInt16Array.ts
380
+ function bufferToInt16Array(buffer) {
381
+ return new Int16Array(buffer.buffer, buffer.byteOffset, buffer.byteLength / 2);
382
+ }
383
+
384
+ // src/helpers/int16ArrayToBuffer.ts
385
+ function int16ArrayToBuffer(int16Array) {
386
+ return Buffer.from(int16Array.buffer, int16Array.byteOffset, int16Array.byteLength);
387
+ }
388
+
389
+ // src/helpers/convertAudioFormat.ts
390
+ function encodePcm(audio, encoding) {
391
+ switch (encoding) {
392
+ case "mulaw":
393
+ return Buffer.from(pcm16ToMulaw(audio));
394
+ case "pcm":
395
+ return int16ArrayToBuffer(audio);
396
+ default:
397
+ throw new Error(`Could not encode audio: Unsupported encoding: ${encoding}`);
398
+ }
399
+ }
400
+ function decodeToPcm(audio, encoding) {
401
+ switch (encoding) {
402
+ case "mulaw":
403
+ return mulawToPcm16(audio);
404
+ case "pcm":
405
+ return bufferToInt16Array(audio);
406
+ default:
407
+ throw new Error(`Could not decode audio: Unsupported encoding: ${encoding}`);
408
+ }
409
+ }
410
+
411
+ // src/helpers/detectFormat.ts
412
+ function identifyAudioFormat(bytes) {
413
+ const checkBytes = (offset, expected) => {
414
+ if (offset + expected.length > bytes.length) return false;
415
+ return expected.every((byte, i) => bytes[offset + i] === byte);
416
+ };
417
+ if (checkBytes(0, [82, 73, 70, 70]) && // "RIFF"
418
+ checkBytes(8, [87, 65, 86, 69])) {
419
+ return {
420
+ format: "WAV",
421
+ mimeType: "audio/wav",
422
+ description: "Waveform Audio File Format"
423
+ };
424
+ }
425
+ if (checkBytes(0, [73, 68, 51]) || // ID3 tag
426
+ checkBytes(0, [255, 251]) || // MP3 frame sync
427
+ checkBytes(0, [255, 243]) || // MP3 frame sync
428
+ checkBytes(0, [255, 242])) {
429
+ return {
430
+ format: "MP3",
431
+ mimeType: "audio/mpeg",
432
+ description: "MPEG Audio Layer III"
433
+ };
434
+ }
435
+ if (checkBytes(0, [102, 76, 97, 67])) {
436
+ return {
437
+ format: "FLAC",
438
+ mimeType: "audio/flac",
439
+ description: "Free Lossless Audio Codec"
440
+ };
441
+ }
442
+ if (checkBytes(0, [79, 103, 103, 83])) {
443
+ return {
444
+ format: "OGG",
445
+ mimeType: "audio/ogg",
446
+ description: "Ogg Vorbis"
447
+ };
448
+ }
449
+ if (checkBytes(4, [102, 116, 121, 112]) && // "ftyp"
450
+ (checkBytes(8, [77, 52, 65, 32]) || // "M4A "
451
+ checkBytes(8, [105, 115, 111, 109]))) {
452
+ return {
453
+ format: "M4A",
454
+ mimeType: "audio/mp4",
455
+ description: "MPEG-4 Audio"
456
+ };
457
+ }
458
+ if (checkBytes(0, [70, 79, 82, 77]) && // "FORM"
459
+ checkBytes(8, [65, 73, 70, 70])) {
460
+ return {
461
+ format: "AIFF",
462
+ mimeType: "audio/aiff",
463
+ description: "Audio Interchange File Format"
464
+ };
465
+ }
466
+ if (checkBytes(
467
+ 0,
468
+ [
469
+ 48,
470
+ 38,
471
+ 178,
472
+ 117,
473
+ 142,
474
+ 102,
475
+ 207,
476
+ 17,
477
+ 166,
478
+ 217,
479
+ 0,
480
+ 170,
481
+ 0,
482
+ 98,
483
+ 206,
484
+ 108
485
+ ]
486
+ )) {
487
+ return {
488
+ format: "WMA",
489
+ mimeType: "audio/x-ms-wma",
490
+ description: "Windows Media Audio"
491
+ };
492
+ }
493
+ return null;
494
+ }
495
+
496
+ // src/helpers/generateFadeOutSamples.ts
497
+ function generateFadeOutSamples(lastSampleValue, fadeDurationMs, sampleRate) {
498
+ const fadeNumSamples = Math.ceil(fadeDurationMs / 1e3 * sampleRate);
499
+ const fadeSamples = new Int16Array(fadeNumSamples);
500
+ for (let i = 0; i < fadeNumSamples; i++) {
501
+ const progress = 1 - i / (fadeNumSamples - 1);
502
+ fadeSamples[i] = Math.round(lastSampleValue * progress);
503
+ }
504
+ return new Uint8Array(fadeSamples.buffer);
505
+ }
506
+
507
+ // src/helpers/resamplePcm.ts
508
+ function resamplePcm(pcm, originalSampleRate, targetSampleRate) {
509
+ const ratio = originalSampleRate / targetSampleRate;
510
+ const newLength = Math.floor(pcm.length / ratio);
511
+ const newSamples = new Int16Array(newLength);
512
+ for (let i = 0; i < newSamples.length; i++) {
513
+ const exactPos = i * ratio;
514
+ const lowerIndex = Math.floor(exactPos);
515
+ const upperIndex = Math.min(lowerIndex + 1, pcm.length - 1);
516
+ const fraction = exactPos - lowerIndex;
517
+ const lowerSample = pcm[lowerIndex];
518
+ const upperSample = pcm[upperIndex];
519
+ newSamples[i] = Math.round(lowerSample + (upperSample - lowerSample) * fraction);
520
+ }
521
+ return newSamples;
522
+ }
523
+
524
+ exports.bufferToInt16Array = bufferToInt16Array;
525
+ exports.decodeToPcm = decodeToPcm;
526
+ exports.decodeWAV = decodeWAV;
527
+ exports.encodePcm = encodePcm;
528
+ exports.generateFadeOutSamples = generateFadeOutSamples;
529
+ exports.identifyAudioFormat = identifyAudioFormat;
530
+ exports.int16ArrayToBuffer = int16ArrayToBuffer;
531
+ exports.mulawToPcm16 = mulawToPcm16;
532
+ exports.pcm16ToMulaw = pcm16ToMulaw;
533
+ exports.resamplePcm = resamplePcm;