-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathwave.js
More file actions
121 lines (103 loc) · 3.94 KB
/
Copy pathwave.js
File metadata and controls
121 lines (103 loc) · 3.94 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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
function WaveBuilder() {
this.builder = new BlobBuilder();
this.numFrames = 0;
this.numChannels = 2;
}
WaveBuilder.prototype = {
appendInterleaved: function (interleavedFrames) {
var buff = new Int16Array(interleavedFrames.length);
for (var i = 0; i < interleavedFrames.length; i ++) {
buff[i] = interleavedFrames[i] * 32767;
}
this.builder.append(buff.buffer);
this.numFrames += interleavedFrames.length / this.numChannels;
},
generateBlob: function () {
var finalBlobBuilder = new BlobBuilder();
finalBlobBuilder.append(buildWaveHeader({numChannels: this.numChannels, numFrames: this.numFrames}));
finalBlobBuilder.append(this.builder.getBlob());
return finalBlobBuilder.getBlob('audio/x-wav');
}
}
// https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
function buildWaveHeader(opts) {
var numFrames = opts.numFrames;
var numChannels = opts.numChannels || 2;
var sampleRate = opts.sampleRate || 44100;
var bytesPerSample = opts.bytesPerSample || 2;
var blockAlign = numChannels * bytesPerSample;
var byteRate = sampleRate * blockAlign;
var dataSize = numFrames * blockAlign;
var buffer = new ArrayBuffer(44);
var dv = new DataView(buffer);
var p = 0;
function writeString(s) {
for (var i = 0; i < s.length; i++) {
dv.setUint8(p + i, s.charCodeAt(i));
}
p += s.length;
}
function writeUint32(d) {
dv.setUint32(p, d, true);
p += 4;
}
function writeUint16(d) {
dv.setUint16(p, d, true);
p += 2;
}
writeString('RIFF'); // ChunkID
writeUint32(dataSize + 36); // ChunkSize
writeString('WAVE'); // Format
writeString('fmt '); // Subchunk1ID
writeUint32(16); // Subchunk1Size
writeUint16(1); // AudioFormat
writeUint16(numChannels); // NumChannels
writeUint32(sampleRate); // SampleRate
writeUint32(byteRate); // ByteRate
writeUint16(blockAlign); // BlockAlign
writeUint16(bytesPerSample * 8); // BitsPerSample
writeString('data'); // Subchunk2ID
writeUint32(dataSize); // Subchunk2Size
return buffer;
}
function WaveReader(blob) {
this.blob = blob;
this.headerReader = new FileReader();
var that = this;
function handleHeader(e) {
that.header = e.target.result;
var headerView = new DataView(that.header);
//that.chunkId = that.header.substr(0, 4);
that.dataSize = headerView.getUint32(4, true) - 36;
//that.riffType = that.header.substr(8, 4);
//that.fmtChunkId = that.header.substr(12, 4);
that.fmtChunkSize = headerView.getUint32(16, true);
that.audioFormat = headerView.getUint16(20, true);
that.numChannels = headerView.getUint16(22, true);
that.sampleRate = headerView.getUint32(24, true);
that.byteRate = headerView.getUint32(28, true);
that.blockAlign = headerView.getUint16(32, true);
that.bitsPerSample = headerView.getUint16(34, true);
//that.dataChunkId = that.header.substr(36, 4);
that.data = blob.slice(44, that.blob.size - 44);
that.onheaders();
}
this.headerReader.onloadend = handleHeader;
this.headerReader.readAsArrayBuffer(blob.slice(0, 44));
}
WaveReader.prototype = {
onheaders: function () {},
fill: function (buffer, offset, callback) {
var reader = new FileReader();
reader.onloadend = function () {
var ints = new Int16Array(reader.result);
for (var i = 0; i < buffer.length; i++) {
buffer[i] = ints[i] / 32767;
}
callback(buffer);
};
// TODO handle 32 bit samples
var blob = this.data.slice(offset * 2, buffer.length * 2);
reader.readAsArrayBuffer(blob);
}
};