Mercurial > hg > webaudioevaluationtool
view js/WAVE.js @ 2376:c41caaa96633
Some fixes for #90. Also a failsafe loop if the server never responds with meaningul information from saves (for instance, running only on apache or basic http servers). More changes to pythonServer for python 3.5. Please check if still valid on 2.7
author | Nicholas Jillings <nicholas.jillings@mail.bcu.ac.uk> |
---|---|
date | Thu, 19 May 2016 10:44:19 +0100 |
parents | 760719986df3 |
children | 464c6c6692d6 |
line wrap: on
line source
// Decode and perform WAVE file byte level manipulation find_subarray = function(arr,subarr) { var arr_length = arr.length; var subarr_length = subarr.length; var last_check_index = arr_length - subarr_length; positionLoop: for (var i=0; i <= last_check_index; i++) { for (var j=0; j< subarr_length; j++) { if (arr[i + j] !== subarr[j]) { continue positionLoop; } } return i; } return -1; }; function convertToInteger(arr) { var value = 0; for (var i=0; i<arr.length; i++) { value += arr[i]<<(i*8); } return value; } function convertToString(arr) { var str = ""; for (var i=0; i<arr.length; i++) { str = str.concat(String.fromCharCode(arr[i])); } return str; } function WAVE() { // The WAVE file object this.status == 'WAVE_DECLARED' this.decoded_data = null; this.RIFF = String(); //ChunkID this.size; //ChunkSize this.FT_Header; //Format this.fmt_marker; //Subchunk1ID this.formatDataLength; //Subchunk1Size this.type; //AudioFormat this.num_channels; //NumChannels this.sample_rate; //SampleRate this.byte_rate; //ByteRate this.block_align; //BlockAlign this.bits_per_sample; //BitsPerSample this.data_header; //Subchunk2ID this.data_size; //Subchunk2Size this.num_samples; this.open = function(IOArrayBuffer) { var IOView8 = new Uint8Array(IOArrayBuffer); this.RIFF = convertToString(IOView8.subarray(0,4)); if (this.RIFF != 'RIFF') { console.log('WAVE ERR - Not a RIFF file'); return 1; } this.size = convertToInteger(IOView8.subarray(4,8)); this.FT_Header = convertToString(IOView8.subarray(8,12)); this.fmt_marker = convertToString(IOView8.subarray(12,16)); this.formatDataLength = convertToInteger(IOView8.subarray(16,20)); this.type = convertToInteger(IOView8.subarray(20,22)); this.num_channels = convertToInteger(IOView8.subarray(22,24)); this.sample_rate = convertToInteger(IOView8.subarray(24,28)); this.byte_rate = convertToInteger(IOView8.subarray(28,32)); this.block_align = convertToInteger(IOView8.subarray(32,34)); this.bits_per_sample = convertToInteger(IOView8.subarray(34,36)); // Find the data header first var data_start = find_subarray(IOView8,[100, 97, 116, 97]); this.data_header = convertToString(IOView8.subarray(data_start,data_start+4)); this.data_size = convertToInteger(IOView8.subarray(data_start+4,data_start+8)); this.num_samples = this.data_size / this.block_align; this.decoded_data = []; if (this.type != 1 && this.type != 3) { console.log("Neither PCM nor IEEE float, cannot decode"); return 1; } for (var c=0; c<this.num_channels; c++) { this.decoded_data.push(new Float32Array(this.num_samples)); } var sampleDataOffset = data_start+8; // Now need to decode the data from sampleDataOffset // Data is always interleved var data_view; if (this.type == 3) { // Already in float if (this.bits_per_sample == 32) { data_view = new Float32Array(IOArrayBuffer.slice(sampleDataOffset,sampleDataOffset+this.data_size)); } else if (this.bits_per_sample == 64) { data_view = new Float64Array(IOArrayBuffer.slice(sampleDataOffset,sampleDataOffset+this.data_size)); } } else if (this.type == 1) { data_view = new Float32Array(this.num_samples*this.num_channels); integerConvert(new Uint8Array(IOArrayBuffer.slice(sampleDataOffset,sampleDataOffset+this.data_size)),data_view,this.bits_per_sample/8); } deInterlace(data_view,this.decoded_data); return 0; }; } function deInterlace(src_array, dst_array) { var number = src_array.length; var channels = dst_array.length; var channel_index = 0; var dst_index = 0; for (var n=0; n<number; n++) { dst_array[channel_index][dst_index] = src_array[n]; channel_index++; if (channel_index >= channels) { channel_index = 0; dst_index++; } } } function integerConvert(srcView,dstView,srcBytes) { //Convert integers of a Uint8Array of certain byte length into a Float32Array var number = dstView.length; var outBits = srcBytes*8; var endShift = 32 - outBits; if (srcView.length != dstView.length*srcBytes) { return -1; } for (var n=0; n<number; n++) { var srcIndex = n*srcBytes; var intData = convertToInteger(srcView.subarray(srcIndex,srcIndex+srcBytes)); intData = (intData << (endShift)); dstView[n] = intData / 2147483648; } }