annotate js/WAVE.js @ 3141:335bc77627e0 tip

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