-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathwaveWorker.js
More file actions
100 lines (84 loc) · 3.64 KB
/
Copy pathwaveWorker.js
File metadata and controls
100 lines (84 loc) · 3.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// https://stackoverflow.com/questions/22560413/html5-web-audio-convert-audio-buffer-into-wav-file
// Author: https://stackoverflow.com/users/993683/joe
self.onmessage = function( e ){
var wavPCM = new WavePCM( e['data']['config'] );
wavPCM.record( e['data']['pcmArrays'] );
wavPCM.requestData();
};
var WavePCM = function( config ){
this.sampleRate = config['sampleRate'] || 48000;
this.bitDepth = config['bitDepth'] || 16;
this.recordedBuffers = [];
this.bytesPerSample = this.bitDepth / 8;
};
WavePCM.prototype.record = function( buffers ){
this.numberOfChannels = this.numberOfChannels || buffers.length;
var bufferLength = buffers[0].length;
var reducedData = new Uint8Array( bufferLength * this.numberOfChannels * this.bytesPerSample );
// Interleave
for ( var i = 0; i < bufferLength; i++ ) {
for ( var channel = 0; channel < this.numberOfChannels; channel++ ) {
var outputIndex = ( i * this.numberOfChannels + channel ) * this.bytesPerSample;
var sample = buffers[ channel ][ i ];
// Check for clipping
if ( sample > 1 ) {
sample = 0.999999999;
}
else if ( sample < -1 ) {
sample = -1;
}
// bit reduce and convert to uInt
switch ( this.bytesPerSample ) {
case 4:
sample = sample * 2147483648;
reducedData[ outputIndex ] = sample;
reducedData[ outputIndex + 1 ] = sample >> 8;
reducedData[ outputIndex + 2 ] = sample >> 16;
reducedData[ outputIndex + 3 ] = sample >> 24;
break;
case 3:
sample = sample * 8388608;
reducedData[ outputIndex ] = sample;
reducedData[ outputIndex + 1 ] = sample >> 8;
reducedData[ outputIndex + 2 ] = sample >> 16;
break;
case 2:
sample = sample * 32768;
reducedData[ outputIndex ] = sample;
reducedData[ outputIndex + 1 ] = sample >> 8;
break;
case 1:
reducedData[ outputIndex ] = ( sample + 1 ) * 128;
break;
default:
throw "Only 8, 16, 24 and 32 bits per sample are supported";
}
}
}
this.recordedBuffers.push( reducedData );
};
WavePCM.prototype.requestData = function(){
var bufferLength = this.recordedBuffers[0].length;
var dataLength = this.recordedBuffers.length * bufferLength;
var headerLength = 44;
var wav = new Uint8Array( headerLength + dataLength );
var view = new DataView( wav.buffer );
view.setUint32( 0, 1380533830, false ); // RIFF identifier 'RIFF'
view.setUint32( 4, 36 + dataLength, true ); // file length minus RIFF identifier length and file description length
view.setUint32( 8, 1463899717, false ); // RIFF type 'WAVE'
view.setUint32( 12, 1718449184, false ); // format chunk identifier 'fmt '
view.setUint32( 16, 16, true ); // format chunk length
view.setUint16( 20, 1, true ); // sample format (raw)
view.setUint16( 22, this.numberOfChannels, true ); // channel count
view.setUint32( 24, this.sampleRate, true ); // sample rate
view.setUint32( 28, this.sampleRate * this.bytesPerSample * this.numberOfChannels, true ); // byte rate (sample rate * block align)
view.setUint16( 32, this.bytesPerSample * this.numberOfChannels, true ); // block align (channel count * bytes per sample)
view.setUint16( 34, this.bitDepth, true ); // bits per sample
view.setUint32( 36, 1684108385, false); // data chunk identifier 'data'
view.setUint32( 40, dataLength, true ); // data chunk length
for (var i = 0; i < this.recordedBuffers.length; i++ ) {
wav.set( this.recordedBuffers[i], i * bufferLength + headerLength );
}
self.postMessage( wav, [wav.buffer] );
self.close();
};