From 0c0ee9f14d059f1776495e1a1d4c650781a6c639 Mon Sep 17 00:00:00 2001 From: Rafael Rocha Date: Thu, 10 May 2018 03:29:40 -0300 Subject: [PATCH] Fix: assure samples are de-interleaved on fromScratch(). --- CHANGELOG.md | 1 + README.md | 46 +++++---------- dist/wavefile-min.js | 38 ++++++------ docs/WaveFile.html | 36 ++++++------ docs/example/wavefile-min.js | 108 +++++++++++++++++------------------ docs/index.html | 44 +++++--------- docs/index.js.html | 41 +++++++------ index.js | 39 ++++++------- test/interleave.js | 25 ++++++++ 9 files changed, 185 insertions(+), 193 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0100b13..54bd43b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Reading the "junk" chunk. The chunk is kept when changing bit depth, using compression or when re-creating an existing WaveFile object with the fromScratch() or fromBuffer() method. - Fix: all chunkSize fields are calculated when writing the file. - Fix: calling clearHeader_() on fromBuffer(), not just fromScratch(). The method is used to clear data in the file header that might lead to corrupt files, like the "fact" chunk. +- Fix: assure samples are de-interleaved on fromScratch() before using the array. ## version 6.4.1 (2018-05-07) - Using compilationLevel: ADVANCED with Closure Compiler. diff --git a/README.md b/README.md index d737d00..b5df6ca 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Web browsers are typically limited to play wav files with 8, 16, 24 and 32-bit d Playing ADPCM in the browser: ```javascript // Load a wav file that is encoded as 4-bit IMA ADPCM: -let wav = new Wavefile(ADPCMFileBuffer); +let wav = new WaveFile(ADPCMFileBuffer); // Decode the file to 16-bit PCM, supported by most browsers: wav.fromIMAADPCM(); @@ -56,7 +56,7 @@ let dataURI = wav.toDataURI(); Playing a 64-bit wave file in the browser: ```javascript // Load a wav file that has 64-bit audio: -let wav = new Wavefile(buffer); +let wav = new WaveFile(buffer); // Change the bit depth to 16-bit, supported by most browsers: wav.toBitDepth("16"); @@ -82,7 +82,7 @@ Some bit depths may not be supported by your browser, like 32-bit floating point ## Use ```javascript // Load a wav file from disk into a WaveFile object -let wav = new Wavefile(buffer); +let wav = new WaveFile(buffer); // Check some of the file properties console.log(wav.container); @@ -108,7 +108,7 @@ wav.fromBuffer(buffer); This is the same as passing the buffer when creating the WaveFile object: ```javascript -let wav = new Wavefile(buffer); +let wav = new WaveFile(buffer); ``` #### WaveFile.fromScratch() @@ -262,19 +262,18 @@ wav.fromMuLaw("24"); ``` ### Change the bit depth + +You can change the bit depth of the audio with the **toBitDepth(bitDepth)** method. + ```javascript // Load a wav file with 32-bit audio -let wav = new Wavefile(fs.readFileSync("32bit-file.wav")); +let wav = new WaveFile(fs.readFileSync("32bit-file.wav")); // Change the bit depth to 24-bit wav.toBitDepth("24"); // Write the new 24-bit file fs.writeFileSync("24bit-file.wav", wav.toBuffer()); - -// You can use any supported bit depth: -wav.toBitDepth("11"); -fs.writeFileSync("11bit-file.wav", wav.toBuffer()); ``` ### The properties @@ -286,7 +285,7 @@ console.log(wav.data.samples); The other public properties: ```javascript -let wav = new Wavefile(fs.readFileSync("file.wav")); +let wav = new WaveFile(fs.readFileSync("file.wav")); // The container data console.log(wav.container); //"RIFF" or "RIFX" @@ -332,13 +331,13 @@ console.log(wav.cue.chunkId); console.log(wav.cue.chunkSize); // "LIST" -console.log(wav.LISTChunks.length); +console.log(wav.LIST.length); ``` #### BWF data BWF data ("bext" chunk) is stored in the *bext* property. ```javascript -wav.bext = { +WaveFile.bext = { "chunkId": "", "chunkSize": 0, "description": "", // 256 chars @@ -362,7 +361,7 @@ wav.bext = { #### Cue points "cue " chunk data is stored as follows: ```javascript -wav.cue = { +WaveFile.cue = { "chunkId": "", "chunkSize": 0, "dwCuePoints": 0, //DWORD @@ -389,10 +388,10 @@ Items in cue.points are objects with this signature: * An array of the "LIST" chunks present in the file. * @type {Array} */ -wav.LISTChunks = []; +WaveFile.LIST = []; ``` -WaveFile.LISTChunks is an array of objects with this signature: +WaveFile.LIST is an array of objects with this signature: ```javascript { /** @type {!string} */ @@ -405,22 +404,7 @@ WaveFile.LISTChunks is an array of objects with this signature: "subChunks": [] }; ``` -Where "subChunks" contains the subChunks of the "LIST" chunk. They can be "INFO" or "adtl". A single file may have many "LIST" chunks as long as their formats ("INFO", "adtl", etc) are not the same. - -For "LIST" chunks with the "adtl" format, "subChunks" is an array of objects with this signature: -```javascript -{ - /** @type {!string} */ - "chunkId": "" // only 'labl' or 'note' - /** @type {!number} */ - "chunkSize" 0, - /** @type {!number} */ - "dwName": 0, - /** @type {!string} */ - "value": "" -} -``` -Where "value" is the text of the "labl" or "note" chunk, and "dwName" is the cue point to where the note/labl points to. +Where "subChunks" contains the subChunks of the "LIST" chunk. WaveFile supports "LIST" chunks of format "INFO". A single file may have many "LIST" chunks as long as their formats ("INFO", "adtl", etc) are not the same. For "LIST" chunks with the "INFO" format, "subChunks" is an array of objects with this signature: ```javascript diff --git a/dist/wavefile-min.js b/dist/wavefile-min.js index da630fe..632b0a6 100644 --- a/dist/wavefile-min.js +++ b/dist/wavefile-min.js @@ -9,26 +9,26 @@ a,l){for(var e=0;eparseInt(this.bitDepth,10)))throw Error("Invalid bit depth.");};a.prototype.pa=function(){var c=this.fmt.numChannels*this.fmt.bitsPerSample/8;if(1>this.fmt.numChannels||65535this.fmt.sampleRate||4294967295parseInt(this.bitDepth,10)))throw Error("Invalid bit depth.");};a.prototype.pa=function(){var c=this.fmt.numChannels*this.fmt.bitsPerSample/8;if(1>this.fmt.numChannels|| +65535this.fmt.sampleRate||4294967295parseInt(a,10)||"53">>0;return this.f(this.i(b))};h.prototype.write=function(d, a,b){b=void 0===b?0:b;a=this.f(a);d[b++]=a&255;for(var g=2;g<=this.offset;g++)d[b++]=Math.floor(a/Math.pow(2,8*(g-1)))&255;return b};h.prototype.B=function(d,a,b){a=this.f(a);b=this.v(d,a,void 0===b?0:b);for(var g=2;gdeInterle
Source:
@@ -1321,7 +1321,7 @@

fromALawSource:
@@ -1708,7 +1708,7 @@

fromIMAAD
Source:
@@ -1849,7 +1849,7 @@

fromMuLawSource:
@@ -2221,7 +2221,7 @@

getLISTB
Source:
@@ -2327,7 +2327,7 @@

getLISTSi
Source:
@@ -2433,7 +2433,7 @@

interleave<
Source:
@@ -2517,7 +2517,7 @@

realBitD
Source:
@@ -2668,7 +2668,7 @@

toALawSource:
@@ -2752,7 +2752,7 @@

toBase64Source:
@@ -2887,7 +2887,7 @@

toBitDepth<
Source:
@@ -3084,7 +3084,7 @@

toBufferSource:
@@ -3219,7 +3219,7 @@

toDataURISource:
@@ -3354,7 +3354,7 @@

toIMAADPCM<
Source:
@@ -3494,7 +3494,7 @@

toMuLawSource:
@@ -3578,7 +3578,7 @@

toRIFFSource:
@@ -3662,7 +3662,7 @@

toRIFXSource:
@@ -3747,7 +3747,7 @@

toRIFX
- Documentation generated by JSDoc 3.5.5 on Thu May 10 2018 02:22:06 GMT-0300 (Hora oficial do Brasil) using the docdash theme. + Documentation generated by JSDoc 3.5.5 on Thu May 10 2018 03:28:54 GMT-0300 (Hora oficial do Brasil) using the docdash theme.
diff --git a/docs/example/wavefile-min.js b/docs/example/wavefile-min.js index f06124d..632b0a6 100644 --- a/docs/example/wavefile-min.js +++ b/docs/example/wavefile-min.js @@ -1,57 +1,55 @@ -/* - wavefile - Read & write wave files with 4, 8, 11, 12, 16, 20, 24, 32 & 64-bit data. - Copyright (c) 2017-2018 Rafael da Silva Rocha. - https://github.com/rochars/wavefile - -*/ var z="function"==typeof Object.defineProperties?Object.defineProperty:function(d,h,g){d!=Array.prototype&&d!=Object.prototype&&(d[h]=g.value)},D="undefined"!=typeof window&&window===this?this:"undefined"!=typeof global&&null!=global?global:this;function E(d,h){if(h){var g=D;d=d.split(".");for(var a=0;a>10;var c=f&1023;return(a?Math.pow(2,a-15)*(1+c/1024):c/1024*.00006103515625)*(f>>15?-1:1)}function m(f, -a){u[0]=r.read(f,a);return y[0]}function c(f,a){u[0]=r.read(f,a);u[1]=r.read(f,a+4);return B[0]}function n(f,a){for(var c="",l=0;l>16&32768;var b=l>>12&2047;l=l>>23&255;103<=l&&(a=(a|l-112<<10|b>>1)+(b&1));f[c++]=a&255;f[c++]=a>>>8&255;return c}function p(f,a,c){y[0]=a;return r.write(f,u[0],c)}function x(f,a,c){B[0]=a;c=r.write(f,u[0],c);return r.write(f,u[1],c)}function f(f, -a,c){for(var l=0;la.bits||a.bits%2)throw Error("Wrong offset for type char.");}else if(1>a.bits||53a.bits?1:Math.ceil(a.bits/8);a["float"]?16==a.bits?v=t:32==a.bits?v=m:64==a.bits&&(v=c):a["char"]?v=n:v=q;a["float"]?16==a.bits?w=e: -32==a.bits?w=p:64==a.bits&&(w=x):a["char"]?w=f:w=k;a["char"]?r.offset=8>a.bits?1:Math.ceil(a.bits/8):r=new F(64==a.bits?32:a.bits,a["float"]?!1:a.signed)}function C(a,f){a.constructor==String&&(a=a.length>=f.offset?a.slice(0,f.offset):"");return a}var A=g(4),F=g(5);h=new Int8Array(8);var u=new Uint32Array(h.buffer),y=new Float32Array(h.buffer),B=new Float64Array(h.buffer),v,w,r={};d.a.ma={bits:8,"char":!0};d.a.va={bits:32,"char":!0};d.a.la={bits:1};d.a.za={bits:2,signed:!0};d.a.Ma={bits:2};d.a.Ea= -{bits:4,signed:!0};d.a.Ra={bits:4};d.a.Ja={bits:8,signed:!0};d.a.Wa={bits:8};d.a.xa={bits:16,signed:!0};d.a.Ka={bits:16};d.a.pa={bits:16,"float":!0};d.a.Aa={bits:24,signed:!0};d.a.Na={bits:24};d.a.Ca={bits:32,signed:!0};d.a.Pa={bits:32};d.a.ra={bits:32,"float":!0};d.a.Fa={bits:40,signed:!0};d.a.Sa={bits:40};d.a.Ha={bits:48,signed:!0};d.a.Ua={bits:48};d.a.ta={bits:64,"float":!0};d.a.ya={bits:16,signed:!0,be:!0};d.a.La={bits:16,be:!0};d.a.qa={bits:16,"float":!0,be:!0};d.a.Ba={bits:24,signed:!0,be:!0}; -d.a.Oa={bits:24,be:!0};d.a.Da={bits:32,signed:!0,be:!0};d.a.Qa={bits:32,be:!0};d.a.sa={bits:32,"float":!0,be:!0};d.a.Ga={bits:40,signed:!0,be:!0};d.a.Ta={bits:40,be:!0};d.a.Ia={bits:48,signed:!0,be:!0};d.a.Va={bits:48,be:!0};d.a.ua={bits:64,"float":!0,be:!0};d.a.b=function(a,f){var c=void 0===c?10:c;l(f);var e=[];if(void 0===a)return e;a=C(a,f);return b([a],f,c)};d.a.c=function(f,c){var b=void 0===b?10:b;l(c);return(f=a(f.slice(0,c.offset),c,b))?f[0]:c["char"]?"":null};d.a.J=function(a,f){var c=void 0=== -c?10:c;l(f);if(f["char"])for(var e=a.length,k=0;kparseInt(this.bitDepth,10)))throw Error("Invalid bit depth.");};a.prototype.ea=function(){var a=this.fmt.numChannels*this.fmt.bitsPerSample/8;if(1>this.fmt.numChannels||65535this.fmt.sampleRate||4294967295< -a)throw Error("Invalid sample rate.");};a.prototype.K=function(){this.fmt.cbSize=0;this.fmt.validBitsPerSample=0;this.fact.chunkId="";this.ds64.chunkId=""};a.prototype.s=function(){this.B();"16"!=this.bitDepth&&this.toBitDepth("16")};a.prototype.B=function(){"8a"==this.bitDepth?this.fromALaw():"8m"==this.bitDepth?this.fromMuLaw():"4"==this.bitDepth&&this.fromIMAADPCM()};a.prototype.o=function(){this.isInterleaved||this.interleave()};a.prototype.m=function(){var a="RIFX"===this.container;k.be=a;return e.be= -a};a.prototype.l=function(a,c){for(var f=0;fparseInt(a,10)||"53">>0;return this.g(this.j(b))};h.prototype.write=function(d,a,b){b=void 0===b?0:b;a=this.g(a);d[b++]=a&255;for(var g=2;g<=this.offset;g++)d[b++]=Math.floor(a/ -Math.pow(2,8*(g-1)))&255;return b};h.prototype.B=function(d,a,b){a=this.g(a);b=this.A(d,a,void 0===b?0:b);for(var g=2;gthis.f?1:Math.ceil(this.h/8);if(this.h!=this.f||8>this.f||32this.max&&(d-=2*this.max+2);return d};h.prototype.g=function(d){d>this.max?d=this.max:dthis.f||64this.f?d[b++]=0>a?a+Math.pow(2,this.f):a:d[b++]=a&255;return b};d.a=h},function(d){function h(a){return 32768>3;b>d&&(a|=4,b-=d,e+=d);d>>=1;b>d&&(a|=2,b-=d,e+=d);d>>=1;b>d&&(a|=1,e+=d);b=a;c=b&8?c-e:c+e;-32768>c?c=-32768:32767n?n=0:88>1);a&1&&(b+=p>>2);b+=p>>3;a&8&&(b=-b);k+=b;32767k&&(k=-32767);e+=t[a];0>e?e=0:88>8&255);c.push(n);c.push(0);for(b=3;bc.length;)c.push(0);return c}function q(b){k=h(b[1]<<8|b[0]);e=b[2];p=m[e];for(var c=[k,h(b[3]<<8|b[2])],d=4;d>4;c.push(a(q<<4^g));c.push(a(q))}return c}var t= -[-1,-1,-1,-1,2,4,6,8,-1,-1,-1,-1,2,4,6,8],m=[7,8,9,10,11,12,13,14,16,17,19,21,23,25,28,31,34,37,41,45,50,55,60,66,73,80,88,97,107,118,130,143,157,173,190,209,230,253,279,307,337,371,408,449,494,544,598,658,724,796,876,963,1060,1166,1282,1411,1552,1707,1878,2066,2272,2499,2749,3024,3327,3660,4026,4428,4871,5358,5894,6484,7132,7845,8630,9493,10442,11487,12635,13899,15289,16818,18500,20350,22385,24623,27086,29794,32767],c=0,n=0,k=0,e=0,p=7;d.a.encode=function(a){for(var c=[],d=[],e=0;e>8&128)||(a*=-1);32635>8&127],a=b<<4|a>>b+3&15):a>>=4;return a^d^85}function g(a){var b=0;a^=85;a&128&&(a&=-129,b=-1);var d=((a&240)>>4)+4;a=4!=d?1< -a){a=132-a;var b=127}else a+=132,b=255;32767>7;g&240&&(g>>=4,d+=4);g&12&&(g>>=2,d+=2);g&2&&(d+=1);g=d;return(g<<4|a>>g+3&15)^b}function g(a){a=~a;var b=((a&15)<<3)+132<<((a&112)>>4);return a&128?132-b:b-132}d.a.ha=h;d.a.ga=g;d.a.encode=function(a){for(var b=[],d=0;da;a++)d["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charCodeAt(a)]= -a;h.encode=function(a){a=new Uint8Array(a);var b,d=a.length,g="";for(b=0;b>2],g+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(a[b]&3)<<4|a[b+1]>>4],g+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(a[b+1]&15)<<2|a[b+2]>>6],g+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[a[b+2]&63];2===d%3?g=g.substring(0,g.length-1)+"\x3d":1===d%3&&(g=g.substring(0,g.length- -2)+"\x3d\x3d");return g};h.decode=function(a){var b=.75*a.length,g=a.length,h=0;"\x3d"===a[a.length-1]&&(b--,"\x3d"===a[a.length-2]&&b--);var c=new ArrayBuffer(b),n=new Uint8Array(c);for(b=0;b>4;n[h++]=(e&15)<<4|p>>2;n[h++]=(p&3)<<6|x&63}return c}})()}]); \ No newline at end of file +(function(d){function h(a){if(g[a])return g[a].b;var b=g[a]={Fa:a,ra:!1,b:{}};d[a].call(b.b,b,b.b,h);b.ra=!0;return b.b}var g={};h.j=d;h.g=g;h.c=function(a,b){h.f(a)||Object.defineProperty(a,"a",{configurable:!1,enumerable:!0,get:b})};h.h=function(a){var b=a&&a.ta?function(){return a["default"]}:function(){return a};h.c(b,b);return b};h.f=function(a){return Object.prototype.hasOwnProperty.call(a,"a")};h.i="";return h(h.m=1)})([function(d,h,g){function a(c,a,l){a.be&&A(c,a.offset);var e=c.length;if(10!= +l)for(var b=0;b>10;var l=c&1023;return(a?Math.pow(2,a-15)*(1+l/1024):l/1024*.00006103515625)*(c>>15?-1:1)}function p(c, +a){u[0]=r.read(c,a);return y[0]}function f(c,a){u[0]=r.read(c,a);u[1]=r.read(c,a+4);return B[0]}function n(c,a){for(var l="",e=0;e>16&32768;var b=e>>12&2047;e=e>>23&255;103<=e&&(a=(a|e-112<<10|b>>1)+(b&1));c[l++]=a&255;c[l++]=a>>>8&255;return l}function m(c,a,l){y[0]=a;return r.write(c,u[0],l)}function v(c,a,l){B[0]=a;l=r.write(c,u[0],l);return r.write(c,u[1],l)}function c(c, +a,l){for(var e=0;ea.bits||a.bits%2)throw Error("Wrong offset for type char.");}else if(1>a.bits||53a.bits?1:Math.ceil(a.bits/8);a["float"]?16==a.bits?w=t:32==a.bits?w=p:64==a.bits&&(w=f):a["char"]?w=n:w=q;a["float"]?16==a.bits?x=e: +32==a.bits?x=m:64==a.bits&&(x=v):a["char"]?x=c:x=k;a["char"]?r.offset=8>a.bits?1:Math.ceil(a.bits/8):r=new F(64==a.bits?32:a.bits,a["float"]?!1:a.signed)}function C(c,a){c.constructor==String&&(c=c.length>=a.offset?c.slice(0,a.offset):"");return c}var A=g(4),F=g(5);h=new Int8Array(8);var u=new Uint32Array(h.buffer),y=new Float32Array(h.buffer),B=new Float64Array(h.buffer),w,x,r={};d.b.va={bits:8,"char":!0};d.b.Ea={bits:32,"char":!0};d.b.ua={bits:1};d.b.Ia={bits:2,signed:!0};d.b.Va={bits:2};d.b.Na= +{bits:4,signed:!0};d.b.$a={bits:4};d.b.Sa={bits:8,signed:!0};d.b.fb={bits:8};d.b.Ga={bits:16,signed:!0};d.b.Ta={bits:16};d.b.ya={bits:16,"float":!0};d.b.Ja={bits:24,signed:!0};d.b.Wa={bits:24};d.b.La={bits:32,signed:!0};d.b.Ya={bits:32};d.b.Aa={bits:32,"float":!0};d.b.Oa={bits:40,signed:!0};d.b.ab={bits:40};d.b.Qa={bits:48,signed:!0};d.b.cb={bits:48};d.b.Ca={bits:64,"float":!0};d.b.Ha={bits:16,signed:!0,be:!0};d.b.Ua={bits:16,be:!0};d.b.za={bits:16,"float":!0,be:!0};d.b.Ka={bits:24,signed:!0,be:!0}; +d.b.Xa={bits:24,be:!0};d.b.Ma={bits:32,signed:!0,be:!0};d.b.Za={bits:32,be:!0};d.b.Ba={bits:32,"float":!0,be:!0};d.b.Pa={bits:40,signed:!0,be:!0};d.b.bb={bits:40,be:!0};d.b.Ra={bits:48,signed:!0,be:!0};d.b.eb={bits:48,be:!0};d.b.Da={bits:64,"float":!0,be:!0};d.b.a=function(c,a){var e=void 0===e?10:e;l(a);var d=[];if(void 0===c)return d;c=C(c,a);return b([c],a,e)};d.b.l=function(c,e){var b=void 0===b?10:b;l(e);return(c=a(c.slice(0,e.offset),e,b))?c[0]:e["char"]?"":null};d.b.M=function(c,a){var e=void 0=== +e?10:e;l(a);if(a["char"])for(var d=c.length,f=0;fparseInt(this.bitDepth,10)))throw Error("Invalid bit depth.");};a.prototype.pa=function(){var c=this.fmt.numChannels*this.fmt.bitsPerSample/8;if(1>this.fmt.numChannels|| +65535this.fmt.sampleRate||4294967295parseInt(a,10)||"53">>0;return this.f(this.i(b))};h.prototype.write=function(d, +a,b){b=void 0===b?0:b;a=this.f(a);d[b++]=a&255;for(var g=2;g<=this.offset;g++)d[b++]=Math.floor(a/Math.pow(2,8*(g-1)))&255;return b};h.prototype.B=function(d,a,b){a=this.f(a);b=this.v(d,a,void 0===b?0:b);for(var g=2;gthis.c?1:Math.ceil(this.g/8);if(this.g!=this.c||8>this.c||32this.max&&(d-=2*this.max+2);return d};h.prototype.f=function(d){d>this.max?d=this.max:dthis.c||64this.c?d[b++]=0>a?a+Math.pow(2,this.c):a:d[b++]=a&255;return b};d.b=h},function(d){function h(a){return 32768>3;c>b&&(a|=4,c-=b,e+=b);b>>=1;c>b&&(a|=2,c-=b,e+=b);b>>=1;c>b&&(a|=1,e+=b);c=a;f=c&8?f-e:f+e;-32768>f?f=-32768:32767n?n= +0:88>1);a&1&&(c+=m>>2);c+=m>>3;a&8&&(c=-c);k+=c;32767k&&(k=-32767);e+=t[a];0>e?e=0:88>8&255);b.push(n);b.push(0);for(c=3;cb.length;)b.push(0);return b}function q(b){k=h(b[1]<<8|b[0]);e=b[2];m=p[e];for(var c=[k,h(b[3]<<8|b[2])],d=4;d> +4;c.push(a(g<<4^f));c.push(a(g))}return c}var t=[-1,-1,-1,-1,2,4,6,8,-1,-1,-1,-1,2,4,6,8],p=[7,8,9,10,11,12,13,14,16,17,19,21,23,25,28,31,34,37,41,45,50,55,60,66,73,80,88,97,107,118,130,143,157,173,190,209,230,253,279,307,337,371,408,449,494,544,598,658,724,796,876,963,1060,1166,1282,1411,1552,1707,1878,2066,2272,2499,2749,3024,3327,3660,4026,4428,4871,5358,5894,6484,7132,7845,8630,9493,10442,11487,12635,13899,15289,16818,18500,20350,22385,24623,27086,29794,32767],f=0,n=0,k=0,e=0,m=7;d.b.encode=function(a){for(var c= +[],e=[],d=0;d>8&128)||(a*=-1);32635>8&127],a=b<<4|a>>b+3&15):a>>=4;return a^d^85}function g(a){var b=0;a^=85;a&128&&(a&=-129,b=-1);var d=((a&240)>>4)+4;a=4!=d?1<a){a=132-a;var b=127}else a+=132,b=255;32767>7;g&240&&(g>>=4,d+=4);g&12&&(g>>=2,d+=2);g&2&&(d+=1);g=d;return(g<<4|a>>g+3&15)^b}function g(a){a=~a;var b=((a&15)<<3)+132<<((a&112)>>4);return a&128?132-b:b-132}d.b.oa=h;d.b.ma=g;d.b.encode=function(a){for(var b=[],d=0;da;a++)d["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charCodeAt(a)]=a;h.encode=function(a){a=new Uint8Array(a);var b,d=a.length,g="";for(b=0;b>2],g+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(a[b]&3)<<4|a[b+1]>>4],g+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(a[b+1]&15)<<2|a[b+2]>>6],g+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[a[b+ +2]&63];2===d%3?g=g.substring(0,g.length-1)+"\x3d":1===d%3&&(g=g.substring(0,g.length-2)+"\x3d\x3d");return g};h.decode=function(a){var b=.75*a.length,g=a.length,h=0;"\x3d"===a[a.length-1]&&(b--,"\x3d"===a[a.length-2]&&b--);var f=new ArrayBuffer(b),n=new Uint8Array(f);for(b=0;b>4;n[h++]=(e&15)<<4|m>>2;n[h++]=(m&3)<<6|v&63}return f}})()}]); \ No newline at end of file diff --git a/docs/index.html b/docs/index.html index 98020f9..3c166a1 100644 --- a/docs/index.html +++ b/docs/index.html @@ -67,7 +67,7 @@

See it in action

Using wavefile to extend the browser audio playing

Web browsers are typically limited to play wav files with 8, 16, 24 and 32-bit data. With wavefile you can extended this by changing the bit depth of wav files on the fly before loading them into the player:

Playing ADPCM in the browser:

// Load a wav file that is encoded as 4-bit IMA ADPCM:
-let wav = new Wavefile(ADPCMFileBuffer);
+let wav = new WaveFile(ADPCMFileBuffer);
 
 // Decode the file to 16-bit PCM, supported by most browsers:
 wav.fromIMAADPCM();
@@ -78,7 +78,7 @@ 

See it in action

Using wavefile to extend the browser audio playing // Load your new wav file into your player // ...

Playing a 64-bit wave file in the browser:

// Load a wav file that has 64-bit audio:
-let wav = new Wavefile(buffer);
+let wav = new WaveFile(buffer);
 
 // Change the bit depth to 16-bit, supported by most browsers:
 wav.toBitDepth("16");
@@ -91,7 +91,7 @@ 

Creating wave files in the browser:

https://tr2099.github.io/

This website uses wavefile to create the files. The effects are provided by other libraries.

Some bit depths may not be supported by your browser, like 32-bit floating point or 64-bit floating point (WaveFile is used just to create the files, not to play them).

Use

// Load a wav file from disk into a WaveFile object
-let wav = new Wavefile(buffer);
+let wav = new WaveFile(buffer);
 
 // Check some of the file properties
 console.log(wav.container);
@@ -106,7 +106,7 @@ 

Use

// Load a wav
 // DataURI to load the file a web browser:
 wavDataURI = wav.toDataURI();

Main methods:

WaveFile.fromBuffer()

Load a .wav file from a byte buffer into a WaveFile object:

wav.fromBuffer(buffer);

This is the same as passing the buffer when creating the WaveFile object:

-
let wav = new Wavefile(buffer);

WaveFile.fromScratch()

Create a WaveFile object with the arguments you pass:

+
let wav = new WaveFile(buffer);

WaveFile.fromScratch()

Create a WaveFile object with the arguments you pass:

// A mono, 44.1 kHz, 32-bit .wav file with just 4 samples:
 wav.fromScratch(1, 44100, '32', [0, -2147483648, 2147483647, 4]);

WaveFile.toBuffer()

Return a Uint8Array with the WaveFile object data. The buffer is a .wav file and can be written to disk:

buffer = wav.toBuffer();

WaveFile.toDataURI()

Return a DataURI string with the WaveFile object data. The DataURI is a .wav file and can be played in browsers:

@@ -160,21 +160,18 @@

Interleave and de-interleave stereo samples

Samples in WaveFile objec

// Decode 8-bit mu-Law as 16-bit:
 wav.fromMuLaw();

Decoding always result in 16-bit audio. To decode to another bit depth:

// Decode 8-bit mu-Law as 24-bit:
-wav.fromMuLaw("24");

Change the bit depth

// Load a wav file with 32-bit audio
-let wav = new Wavefile(fs.readFileSync("32bit-file.wav"));
+wav.fromMuLaw("24");

Change the bit depth

You can change the bit depth of the audio with the toBitDepth(bitDepth) method.

+
// Load a wav file with 32-bit audio
+let wav = new WaveFile(fs.readFileSync("32bit-file.wav"));
 
 // Change the bit depth to 24-bit
 wav.toBitDepth("24");
 
 // Write the new 24-bit file
-fs.writeFileSync("24bit-file.wav", wav.toBuffer());
-
-// You can use any supported bit depth:
-wav.toBitDepth("11");
-fs.writeFileSync("11bit-file.wav", wav.toBuffer());

The properties

Since version 6.0.0 (2018-05-02) the samples are stored in data.samples.

+fs.writeFileSync("24bit-file.wav", wav.toBuffer());

The properties

Since version 6.0.0 (2018-05-02) the samples are stored in data.samples.

console.log(wav.data.samples);
 // Output an array of numbers

The other public properties:

-
let wav = new Wavefile(fs.readFileSync("file.wav"));
+
let wav = new WaveFile(fs.readFileSync("file.wav"));
 
 // The container data
 console.log(wav.container); //"RIFF" or "RIFX"
@@ -220,8 +217,8 @@ 

Interleave and de-interleave stereo samples

Samples in WaveFile objec console.log(wav.cue.chunkSize); // "LIST" -console.log(wav.LISTChunks.length);

BWF data

BWF data ("bext" chunk) is stored in the bext property.

-
wav.bext = {
+console.log(wav.LIST.length);

BWF data

BWF data ("bext" chunk) is stored in the bext property.

+
WaveFile.bext = {
     "chunkId": "",
     "chunkSize": 0,
     "description": "", // 256 chars
@@ -240,7 +237,7 @@ 

Interleave and de-interleave stereo samples

Samples in WaveFile objec "reserved": "", // 180 chars "codingHistory": "" // string, unlimited size };

Cue points

"cue " chunk data is stored as follows:

-
wav.cue = {
+
WaveFile.cue = {
     "chunkId": "",
     "chunkSize": 0,
     "dwCuePoints": 0, //DWORD
@@ -258,7 +255,7 @@ 

Interleave and de-interleave stereo samples

Samples in WaveFile objec * An array of the "LIST" chunks present in the file. * @type {Array<Object>} */ -wav.LISTChunks = [];

WaveFile.LISTChunks is an array of objects with this signature:

+WaveFile.LIST = [];

WaveFile.LIST is an array of objects with this signature:

{
     /** @type {!string} */
     "chunkId": "", // always 'LIST'
@@ -268,18 +265,7 @@ 

Interleave and de-interleave stereo samples

Samples in WaveFile objec "format": "", // 'adtl' or 'INFO' /** @type {!Array<Object>} */ "subChunks": [] -};

Where "subChunks" contains the subChunks of the "LIST" chunk. They can be "INFO" or "adtl". A single file may have many "LIST" chunks as long as their formats ("INFO", "adtl", etc) are not the same.

-

For "LIST" chunks with the "adtl" format, "subChunks" is an array of objects with this signature:

-
{
-    /** @type {!string} */
-    "chunkId": "" // only 'labl' or 'note'
-    /** @type {!number} */
-    "chunkSize" 0,
-    /** @type {!number} */
-    "dwName": 0,
-    /** @type {!string} */
-    "value": ""
-}

Where "value" is the text of the "labl" or "note" chunk, and "dwName" is the cue point to where the note/labl points to.

+};

Where "subChunks" contains the subChunks of the "LIST" chunk. WaveFile supports "LIST" chunks of format "INFO". A single file may have many "LIST" chunks as long as their formats ("INFO", "adtl", etc) are not the same.

For "LIST" chunks with the "INFO" format, "subChunks" is an array of objects with this signature:

{
     /** @type {!string} */
@@ -344,7 +330,7 @@ 

LICENSE

Copyright (c) 2017-2018 Rafael da Silva Rocha.


- Documentation generated by JSDoc 3.5.5 on Thu May 10 2018 02:22:06 GMT-0300 (Hora oficial do Brasil) using the docdash theme. + Documentation generated by JSDoc 3.5.5 on Thu May 10 2018 03:28:54 GMT-0300 (Hora oficial do Brasil) using the docdash theme.
diff --git a/docs/index.js.html b/docs/index.js.html index ccf0dde..4401bd6 100644 --- a/docs/index.js.html +++ b/docs/index.js.html @@ -345,9 +345,17 @@

index.js

let numBytes = (((parseInt(bitDepth, 10) - 1) | 7) + 1) / 8; this.clearHeader_(); this.bitDepth = bitDepth; + // interleave the samples if they were passed de-interleaved + this.data.samples = samples; + if (samples.length > 0) { + if (samples[0].constructor === Array) { + this.isInterleaved = false; + this.interleave(); + } + } // Normal PCM file header this.container = options["container"]; - this.chunkSize = 36 + samples.length * numBytes; + this.chunkSize = 36 + this.data.samples.length * numBytes; this.format = "WAVE"; this.fmt.chunkId = "fmt "; this.fmt.chunkSize = 16; @@ -361,18 +369,10 @@

index.js

this.fmt.cbSize = 0; this.fmt.validBitsPerSample = 0; this.data.chunkId = "data"; - this.data.samples = samples; - // interleave the samples if they were passed de-interleaved - if (samples.length > 0) { - if (samples[0].constructor === Array) { - this.isInterleaved = false; - this.interleave(); - } - } - this.data.chunkSize = samples.length * numBytes; + this.data.chunkSize = this.data.samples.length * numBytes; // IMA ADPCM header if (bitDepth == "4") { - this.chunkSize = 40 + samples.length; + this.chunkSize = 40 + this.data.samples.length; this.fmt.chunkSize = 20; this.fmt.byteRate = 4055; this.fmt.blockAlign = 256; @@ -381,22 +381,22 @@

index.js

this.fmt.validBitsPerSample = 505; this.fact.chunkId = "fact"; this.fact.chunkSize = 4; - this.fact.dwSampleLength = samples.length * 2; - this.data.chunkSize = samples.length; + this.fact.dwSampleLength = this.data.samples.length * 2; + this.data.chunkSize = this.data.samples.length; } // A-Law and mu-Law header if (bitDepth == "8a" || bitDepth == "8m") { - this.chunkSize = 40 + samples.length; + this.chunkSize = 40 + this.data.samples.length; this.fmt.chunkSize = 20; this.fmt.cbSize = 2; this.fmt.validBitsPerSample = 8; this.fact.chunkId = "fact"; this.fact.chunkSize = 4; - this.fact.dwSampleLength = samples.length; + this.fact.dwSampleLength = this.data.samples.length; } // WAVE_FORMAT_EXTENSIBLE if (this.fmt.audioFormat == 65534) { - this.chunkSize = 36 + 24 + samples.length * numBytes; + this.chunkSize = 36 + 24 + this.data.samples.length * numBytes; this.fmt.chunkSize = 40; this.fmt.bitsPerSample = ((parseInt(bitDepth, 10) - 1) | 7) + 1; this.fmt.cbSize = 22; @@ -422,7 +422,6 @@

index.js

fromBuffer(bytes) { this.clearHeader_(); this.readRIFFChunk_(bytes); - let bigEndian = this.container == "RIFX"; let chunk = riffChunks_.read(bytes); this.readDs64Chunk_(chunk["subChunks"]); this.readFmtChunk_(chunk["subChunks"]); @@ -545,7 +544,7 @@

index.js

} } this.data.samples = finalSamples; - this.isInterleaved = true; + this.isInterleaved = true; } } @@ -1043,7 +1042,7 @@

index.js

*/ readLISTChunk_(chunks) { let listChunks = this.findChunk_(chunks, "LIST", true); - if (listChunks == null) { + if (listChunks === null) { return; } for (let j=0; j<listChunks.length; j++) { @@ -1121,7 +1120,7 @@

index.js

readZSTR_(bytes) { let str = ""; for (let i=0; i<bytes.length; i++) { - if (bytes[i] == 0) { + if (bytes[i] === 0) { break; } str += byteData_.unpack([bytes[i]], chr_); @@ -1594,7 +1593,7 @@

index.js


- Documentation generated by JSDoc 3.5.5 on Thu May 10 2018 02:22:06 GMT-0300 (Hora oficial do Brasil) using the docdash theme. + Documentation generated by JSDoc 3.5.5 on Thu May 10 2018 03:28:54 GMT-0300 (Hora oficial do Brasil) using the docdash theme.
diff --git a/index.js b/index.js index 30da346..ba82259 100644 --- a/index.js +++ b/index.js @@ -306,9 +306,17 @@ class WaveFile { let numBytes = (((parseInt(bitDepth, 10) - 1) | 7) + 1) / 8; this.clearHeader_(); this.bitDepth = bitDepth; + // interleave the samples if they were passed de-interleaved + this.data.samples = samples; + if (samples.length > 0) { + if (samples[0].constructor === Array) { + this.isInterleaved = false; + this.interleave(); + } + } // Normal PCM file header this.container = options["container"]; - this.chunkSize = 36 + samples.length * numBytes; + this.chunkSize = 36 + this.data.samples.length * numBytes; this.format = "WAVE"; this.fmt.chunkId = "fmt "; this.fmt.chunkSize = 16; @@ -322,18 +330,10 @@ class WaveFile { this.fmt.cbSize = 0; this.fmt.validBitsPerSample = 0; this.data.chunkId = "data"; - this.data.samples = samples; - // interleave the samples if they were passed de-interleaved - if (samples.length > 0) { - if (samples[0].constructor === Array) { - this.isInterleaved = false; - this.interleave(); - } - } - this.data.chunkSize = samples.length * numBytes; + this.data.chunkSize = this.data.samples.length * numBytes; // IMA ADPCM header if (bitDepth == "4") { - this.chunkSize = 40 + samples.length; + this.chunkSize = 40 + this.data.samples.length; this.fmt.chunkSize = 20; this.fmt.byteRate = 4055; this.fmt.blockAlign = 256; @@ -342,22 +342,22 @@ class WaveFile { this.fmt.validBitsPerSample = 505; this.fact.chunkId = "fact"; this.fact.chunkSize = 4; - this.fact.dwSampleLength = samples.length * 2; - this.data.chunkSize = samples.length; + this.fact.dwSampleLength = this.data.samples.length * 2; + this.data.chunkSize = this.data.samples.length; } // A-Law and mu-Law header if (bitDepth == "8a" || bitDepth == "8m") { - this.chunkSize = 40 + samples.length; + this.chunkSize = 40 + this.data.samples.length; this.fmt.chunkSize = 20; this.fmt.cbSize = 2; this.fmt.validBitsPerSample = 8; this.fact.chunkId = "fact"; this.fact.chunkSize = 4; - this.fact.dwSampleLength = samples.length; + this.fact.dwSampleLength = this.data.samples.length; } // WAVE_FORMAT_EXTENSIBLE if (this.fmt.audioFormat == 65534) { - this.chunkSize = 36 + 24 + samples.length * numBytes; + this.chunkSize = 36 + 24 + this.data.samples.length * numBytes; this.fmt.chunkSize = 40; this.fmt.bitsPerSample = ((parseInt(bitDepth, 10) - 1) | 7) + 1; this.fmt.cbSize = 22; @@ -383,7 +383,6 @@ class WaveFile { fromBuffer(bytes) { this.clearHeader_(); this.readRIFFChunk_(bytes); - let bigEndian = this.container == "RIFX"; let chunk = riffChunks_.read(bytes); this.readDs64Chunk_(chunk["subChunks"]); this.readFmtChunk_(chunk["subChunks"]); @@ -506,7 +505,7 @@ class WaveFile { } } this.data.samples = finalSamples; - this.isInterleaved = true; + this.isInterleaved = true; } } @@ -1004,7 +1003,7 @@ class WaveFile { */ readLISTChunk_(chunks) { let listChunks = this.findChunk_(chunks, "LIST", true); - if (listChunks == null) { + if (listChunks === null) { return; } for (let j=0; j