comparison WAVE.js @ 1088:3705f68a38b7

The version I use and works, addresses issues #1622, #1616, partially #1620
author Giulio Moro <giuliomoro@yahoo.it>
date Mon, 22 Feb 2016 04:17:19 +0000
parents
children a4ad9e55b5b8
comparison
equal deleted inserted replaced
-1:000000000000 1088:3705f68a38b7
1 // Decode and perform WAVE file byte level manipulation
2
3 find_subarray = function(arr,subarr) {
4 var arr_length = arr.length;
5 var subarr_length = subarr.length;
6 var last_check_index = arr_length - subarr_length;
7
8 positionLoop:
9 for (var i=0; i <= last_check_index; i++)
10 {
11 for (var j=0; j< subarr_length; j++)
12 {
13 if (arr[i + j] !== subarr[j]) {
14 continue positionLoop;
15 }
16 }
17 return i;
18 }
19 return -1;
20 };
21
22 function convertToInteger(arr) {
23 var value = 0;
24 for (var i=0; i<arr.length; i++)
25 {
26 value += arr[i]<<(i*8);
27 }
28 return value;
29 }
30 function convertToString(arr) {
31 var str = "";
32 for (var i=0; i<arr.length; i++)
33 {
34 str = str.concat(String.fromCharCode(arr[i]));
35 }
36 return str;
37 }
38
39 function WAVE()
40 {
41 // The WAVE file object
42 this.status == 'WAVE_DECLARED'
43
44 this.decoded_data = null;
45
46 this.RIFF = String(); //ChunkID
47 this.size; //ChunkSize
48 this.FT_Header; //Format
49 this.fmt_marker; //Subchunk1ID
50 this.formatDataLength; //Subchunk1Size
51 this.type; //AudioFormat
52 this.num_channels; //NumChannels
53 this.sample_rate; //SampleRate
54 this.byte_rate; //ByteRate
55 this.block_align; //BlockAlign
56 this.bits_per_sample; //BitsPerSample
57 this.data_header; //Subchunk2ID
58 this.data_size; //Subchunk2Size
59 this.num_samples;
60
61 this.open = function(IOArrayBuffer)
62 {
63 var IOView8 = new Uint8Array(IOArrayBuffer);
64 this.RIFF = convertToString(IOView8.subarray(0,4));
65 if (this.RIFF != 'RIFF')
66 {
67 console.log('WAVE ERR - Not a RIFF file');
68 return 1;
69 }
70 this.size = convertToInteger(IOView8.subarray(4,8));
71 this.FT_Header = convertToString(IOView8.subarray(8,12));
72 this.fmt_marker = convertToString(IOView8.subarray(12,16));
73 this.formatDataLength = convertToInteger(IOView8.subarray(16,20));
74 this.type = convertToInteger(IOView8.subarray(20,22));
75 this.num_channels = convertToInteger(IOView8.subarray(22,24));
76 this.sample_rate = convertToInteger(IOView8.subarray(24,28));
77 this.byte_rate = convertToInteger(IOView8.subarray(28,32));
78 this.block_align = convertToInteger(IOView8.subarray(32,34));
79 this.bits_per_sample = convertToInteger(IOView8.subarray(34,36));
80
81 // Find the data header first
82 var data_start = find_subarray(IOView8,[100, 97, 116, 97]);
83
84 this.data_header = convertToString(IOView8.subarray(data_start,data_start+4));
85 this.data_size = convertToInteger(IOView8.subarray(data_start+4,data_start+8));
86
87 this.num_samples = this.data_size / this.block_align;
88
89 this.decoded_data = [];
90 if (this.type != 1 && this.type != 3) {
91 console.log("Neither PCM nor IEEE float, cannot decode");
92 return 1;
93 }
94 for (var c=0; c<this.num_channels; c++)
95 {
96 this.decoded_data.push(new Float32Array(this.num_samples));
97 }
98 var sampleDataOffset = data_start+8;
99
100 // Now need to decode the data from sampleDataOffset
101 // Data is always interleved
102 var data_view;
103 if (this.type == 3)
104 {
105 // Already in float
106 if (this.bits_per_sample == 32) {
107 data_view = new Float32Array(IOArrayBuffer.slice(sampleDataOffset,sampleDataOffset+this.data_size));
108 } else if (this.bits_per_sample == 64) {
109 data_view = new Float64Array(IOArrayBuffer.slice(sampleDataOffset,sampleDataOffset+this.data_size));
110 }
111 } else if (this.type == 1)
112 {
113 data_view = new Float32Array(this.num_samples*this.num_channels);
114 integerConvert(new Uint8Array(IOArrayBuffer.slice(sampleDataOffset,sampleDataOffset+this.data_size)),data_view,this.bits_per_sample/8);
115 }
116 deInterlace(data_view,this.decoded_data);
117 return 0;
118 };
119 }
120
121 function deInterlace(src_array, dst_array)
122 {
123 var number = src_array.length;
124 var channels = dst_array.length;
125 var channel_index = 0;
126 var dst_index = 0;
127 for (var n=0; n<number; n++)
128 {
129 dst_array[channel_index][dst_index] = src_array[n];
130 channel_index++;
131 if (channel_index >= channels) {
132 channel_index = 0;
133 dst_index++;
134 }
135 }
136 }
137
138 function integerConvert(srcView,dstView,srcBytes)
139 {
140 //Convert integers of a Uint8Array of certain byte length into a Float32Array
141 var number = dstView.length;
142 var outBits = srcBytes*8;
143 var endShift = 32 - outBits;
144 if (srcView.length != dstView.length*srcBytes)
145 {
146 return -1;
147 }
148 for (var n=0; n<number; n++)
149 {
150 var srcIndex = n*srcBytes;
151 var intData = convertToInteger(srcView.subarray(srcIndex,srcIndex+srcBytes));
152 intData = (intData << (endShift));
153 dstView[n] = intData / 2147483648;
154 }
155 }