UNPKG

5.92 kBJavaScriptView Raw
1"use strict";
2
3/* jshint esnext: false */
4
5/**
6 CAUTION!!!!
7 This file is used in WebWorker.
8 So, must write with ES5, not use ES6.
9 You need attention not to be traspiled by babel.
10*/
11
12var self = {};
13
14function decoder() {
15 self.onmessage = function (e) {
16 switch (e.data.type) {
17 case "decode":
18 self.decode(e.data.buffer).then(function (audioData) {
19 self.postMessage({
20 type: "decoded",
21 audioData: audioData
22 }, [audioData.buffers]);
23 })["catch"](function (err) {
24 self.postMessage({
25 type: "error",
26 message: err.message
27 });
28 });
29 break;
30 }
31 };
32
33 var formats = {
34 1: "lpcm",
35 3: "lpcm" };
36
37 self.decode = function (buffer) {
38 return new Promise(function (resolve) {
39 var reader = new BufferReader(buffer);
40
41 if (reader.readString(4) !== "RIFF") {
42 throw new Error("Invalid WAV file");
43 }
44
45 reader.readUint32(); // file length
46
47 if (reader.readString(4) !== "WAVE") {
48 throw new Error("Invalid WAV file");
49 }
50
51 var format = null;
52 var audioData = null;
53
54 do {
55 var chunkType = reader.readString(4);
56 var chunkSize = reader.readUint32();
57 switch (chunkType) {
58 case "fmt ":
59 format = self.decodeFormat(reader, chunkSize);
60 break;
61 case "data":
62 audioData = self.decodeData(reader, chunkSize, format);
63 break;
64 default:
65 reader.skip(chunkSize);
66 break;
67 }
68 } while (audioData === null);
69
70 return resolve(audioData);
71 });
72 };
73
74 self.decodeFormat = function (reader, chunkSize) {
75 var formatId = reader.readUint16();
76
77 if (!formats.hasOwnProperty(formatId)) {
78 throw new Error("Unsupported format in WAV file");
79 }
80
81 var format = {
82 formatId: formatId,
83 floatingPoint: formatId === 3,
84 numberOfChannels: reader.readUint16(),
85 sampleRate: reader.readUint32(),
86 byteRate: reader.readUint32(),
87 blockSize: reader.readUint16(),
88 bitsPerSample: reader.readUint16() };
89 reader.skip(chunkSize - 16);
90
91 return format;
92 };
93
94 self.decodeData = function (reader, chunkSize, format) {
95 var length = Math.floor(chunkSize / format.blockSize);
96 var channelData = new Array(format.numberOfChannels);
97
98 for (var ch = 0; ch < format.numberOfChannels; ch++) {
99 channelData[ch] = new Float32Array(length);
100 }
101
102 reader.readPCM(channelData, length, format);
103
104 var buffers = channelData.map(function (data) {
105 return data.buffer;
106 });
107
108 return {
109 numberOfChannels: format.numberOfChannels,
110 length: length,
111 sampleRate: format.sampleRate,
112 buffers: buffers
113 };
114 };
115
116 function BufferReader(buffer) {
117 this.buffer = buffer;
118 this.view = new DataView(buffer);
119 this.length = buffer.byteLength;
120 this.pos = 0;
121 }
122
123 BufferReader.prototype.skip = function (n) {
124 for (var i = 0; i < n; i++) {
125 this.view.getUint8(this.pos++);
126 }
127 };
128
129 BufferReader.prototype.readUint8 = function () {
130 var data = this.view.getUint8(this.pos);
131 this.pos += 1;
132 return data;
133 };
134
135 BufferReader.prototype.readInt16 = function () {
136 var data = this.view.getInt16(this.pos, true);
137 this.pos += 2;
138 return data;
139 };
140
141 BufferReader.prototype.readUint16 = function () {
142 var data = this.view.getUint16(this.pos, true);
143 this.pos += 2;
144 return data;
145 };
146
147 BufferReader.prototype.readUint32 = function () {
148 var data = this.view.getUint32(this.pos, true);
149 this.pos += 4;
150 return data;
151 };
152
153 BufferReader.prototype.readString = function (len) {
154 var data = "";
155 for (var i = 0; i < len; i++) {
156 data += String.fromCharCode(this.readUint8());
157 }
158 return data;
159 };
160
161 BufferReader.prototype.readPCM = function (channelData, length, format) {
162 var numberOfChannels = format.numberOfChannels;
163 var uint8 = new Uint8Array(this.view.buffer, this.pos);
164 var viewLength = length * numberOfChannels;
165 var bytes = format.bitsPerSample >> 3;
166 var byteOffset = Math.ceil(uint8.byteOffset / bytes) * bytes;
167 var view,
168 dx = 1;
169
170 if (format.floatingPoint) {
171 switch (format.bitsPerSample) {
172 case 32:
173 view = new Float32Array(uint8.buffer, byteOffset, viewLength);
174 break;
175 case 64:
176 view = new Float64Array(uint8.buffer, byteOffset, viewLength);
177 break;
178 }
179 } else {
180 switch (format.bitsPerSample) {
181 case 8:
182 view = new Int8Array(uint8.buffer, byteOffset, viewLength);
183 dx = 128;
184 break;
185 case 16:
186 view = new Int16Array(uint8.buffer, byteOffset, viewLength);
187 dx = 32768;
188 break;
189 case 24:
190 view = convert24to32(uint8, uint8.byteOffset, viewLength * 3);
191 dx = 8388608;
192 break;
193 case 32:
194 view = new Int32Array(uint8.buffer, byteOffset, viewLength);
195 dx = 2147483648;
196 break;
197 }
198 }
199
200 if (!view) {
201 throw new Error("not suppoerted bit depth " + format.bitsPerSample);
202 }
203
204 for (var i = 0; i < length; i++) {
205 for (var ch = 0; ch < numberOfChannels; ch++) {
206 channelData[ch][i] = view[i * numberOfChannels + ch] / dx;
207 }
208 }
209
210 this.pos += length;
211 };
212
213 function convert24to32(int8, byteOffset, viewLength) {
214 var uint8 = new Uint8Array(int8.buffer, byteOffset, viewLength);
215 var int32 = new Int32Array(uint8.length / 3);
216
217 for (var i = 0, imax = int32.length; i < imax; i++) {
218 var x0 = uint8[i * 3 + 0];
219 var x1 = uint8[i * 3 + 1];
220 var x2 = uint8[i * 3 + 2];
221 var xx = x0 + (x1 << 8) + (x2 << 16);
222
223 int32[i] = xx & 8388608 ? xx - 16777216 : xx;
224 }
225
226 return int32;
227 }
228}
229
230decoder.self = decoder.util = self;
231
232module.exports = decoder;
\No newline at end of file