├── .gitignore ├── images ├── up.png ├── down.png ├── equal.png ├── logo.png ├── mhd.png ├── ofm.png ├── pause.png ├── play.png ├── github.png ├── header.png ├── nopicture.png └── github-banner.png ├── tests └── node │ ├── out.raw │ ├── pcm.png │ ├── sample.png │ ├── one_second_beep.mp3 │ ├── one_second_of_silence.mp3 │ ├── plot-pcm.gnuplot │ ├── plot-sample.gnuplot │ ├── typed-array.js │ ├── check.rb │ ├── fastdsct.js │ ├── huffdecode.js │ ├── dct.js │ ├── output.js │ ├── imdct.js │ ├── aliasreduce.js │ └── sample.svg ├── experiments ├── images │ └── noise.png ├── experiment.js ├── index.html └── application.css ├── .gitmodules ├── scripts ├── madcat.sh ├── uglify └── sink.min.js ├── src ├── imdct_s.js ├── binarystring │ ├── stringstream.js │ ├── substream.js │ ├── filestream.js │ ├── bytestream.js │ └── ajaxstream.js ├── mp3file.js ├── arraybuffer │ ├── arraystream.js │ ├── substream.js │ ├── filestream.js │ ├── bytestream.js │ └── ajaxstream.js ├── bit.js ├── stream.js ├── player.js ├── mad.js ├── id3v22stream.js ├── binaryajax.js ├── frame.js └── id3v23stream.js ├── css └── style.css ├── README.md ├── index.html ├── mhd.js └── officialfm.js /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .*.swp 3 | -------------------------------------------------------------------------------- /images/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiocogs/jsmad/HEAD/images/up.png -------------------------------------------------------------------------------- /images/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiocogs/jsmad/HEAD/images/down.png -------------------------------------------------------------------------------- /images/equal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiocogs/jsmad/HEAD/images/equal.png -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiocogs/jsmad/HEAD/images/logo.png -------------------------------------------------------------------------------- /images/mhd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiocogs/jsmad/HEAD/images/mhd.png -------------------------------------------------------------------------------- /images/ofm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiocogs/jsmad/HEAD/images/ofm.png -------------------------------------------------------------------------------- /images/pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiocogs/jsmad/HEAD/images/pause.png -------------------------------------------------------------------------------- /images/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiocogs/jsmad/HEAD/images/play.png -------------------------------------------------------------------------------- /images/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiocogs/jsmad/HEAD/images/github.png -------------------------------------------------------------------------------- /images/header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiocogs/jsmad/HEAD/images/header.png -------------------------------------------------------------------------------- /tests/node/out.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiocogs/jsmad/HEAD/tests/node/out.raw -------------------------------------------------------------------------------- /tests/node/pcm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiocogs/jsmad/HEAD/tests/node/pcm.png -------------------------------------------------------------------------------- /images/nopicture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiocogs/jsmad/HEAD/images/nopicture.png -------------------------------------------------------------------------------- /tests/node/sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiocogs/jsmad/HEAD/tests/node/sample.png -------------------------------------------------------------------------------- /images/github-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiocogs/jsmad/HEAD/images/github-banner.png -------------------------------------------------------------------------------- /experiments/images/noise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiocogs/jsmad/HEAD/experiments/images/noise.png -------------------------------------------------------------------------------- /tests/node/one_second_beep.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiocogs/jsmad/HEAD/tests/node/one_second_beep.mp3 -------------------------------------------------------------------------------- /tests/node/one_second_of_silence.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audiocogs/jsmad/HEAD/tests/node/one_second_of_silence.mp3 -------------------------------------------------------------------------------- /tests/node/plot-pcm.gnuplot: -------------------------------------------------------------------------------- 1 | set terminal png 2 | set output 'pcm.png' 3 | plot "pcm-js.txt" title 'jsmad' with lines, "pcm.txt" title 'libmad' with lines 4 | -------------------------------------------------------------------------------- /tests/node/plot-sample.gnuplot: -------------------------------------------------------------------------------- 1 | set terminal png 2 | set output 'sample.png' 3 | plot "sample-js.txt" title 'jsmad' with lines, "sample.txt" title 'libmad' with lines 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "audiolib.js"] 2 | path = audiolib.js 3 | url = git://github.com/jussi-kalliokoski/audiolib.js.git 4 | [submodule "sink.js"] 5 | path = sink.js 6 | url = https://github.com/jussi-kalliokoski/sink.js.git 7 | -------------------------------------------------------------------------------- /tests/node/typed-array.js: -------------------------------------------------------------------------------- 1 | 2 | ArrayBuffer = function(size) { 3 | var array = new Array(size / 4); 4 | 5 | for (var i = 0; i < array.length; i++) { 6 | array[i] = 0; 7 | } 8 | 9 | return array; 10 | }; 11 | 12 | Int32Array = function(buffer) { 13 | return buffer; 14 | }; 15 | 16 | Float32Array = function(buffer) { 17 | return buffer; 18 | }; 19 | 20 | Float64Array = function(buffer) { 21 | return buffer; 22 | }; 23 | -------------------------------------------------------------------------------- /tests/node/check.rb: -------------------------------------------------------------------------------- 1 | # Dir.chdir("../../../libmad") do 2 | # system("make minimad && ./minimad < one_second_beep.mp3 > ../jsmad/experiments/node/libmad.txt") 3 | # end 4 | 5 | # system("node test.js > jsmad.txt") 6 | 7 | libmad = File.readlines(ARGV[0]) 8 | jsmad = File.readlines(ARGV[1]) 9 | 10 | diffs = [] 11 | 12 | libmad.zip(jsmad) do |a, b| 13 | a.split("\t").zip(b.split("\t")) do |x, y| 14 | diffs << (x.to_f - y.to_f).abs 15 | end 16 | end 17 | 18 | puts diffs.max 19 | -------------------------------------------------------------------------------- /scripts/madcat.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Concatenates all the JSMad sources into a single .js file 4 | 5 | cat src/mad.js src/rq_table.js src/imdct_s.js src/huffman.js src/bit.js src/stream.js src/layer3.js src/frame.js src/synth.js src/arraybuffer/bytestream.js src/arraybuffer/filestream.js src/arraybuffer/substream.js src/arraybuffer/arraystream.js src/arraybuffer/ajaxstream.js src/binarystring/bytestream.js src/binarystring/filestream.js src/binarystring/substream.js src/binarystring/stringstream.js src/binarystring/ajaxstream.js src/id3v22stream.js src/id3v23stream.js src/mp3file.js src/player.js 6 | -------------------------------------------------------------------------------- /tests/node/fastdsct.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var sys = require('sys'); 3 | 4 | require('./typed-array.js'); 5 | require('../../mad.js'); 6 | require('../../id3.js'); 7 | require('../../layer3.js'); 8 | var x = [ 9 | -0.00188436,-0.00002753,0.00420964,0.00203913,-0.00782420,-0.00490182,0.01520704,0.01104762,-0.03868370,-0.04013703,0.37942966,-0.46913085,-0.27882083,-0.02320458,0.01611372,0.00400412,-0.00274224,-0.00063538]; 10 | var X = [ 11 | -0.43594157,0.53499295,0.26976736,-0.95755410,0.85856501,0.13600542,-1.19115227,1.15186305,0.17104355,-1.59530227,1.05767249,0.86786658,-1.50597779,0.15820546,1.25546645,-0.87142866,-0.66177376,1.18015846]; 12 | 13 | var _X = []; 14 | 15 | sdctII(x, _X); 16 | 17 | for (var i = 0; i < 18; i++) { 18 | console.log(Math.abs(_X[i] - X[i])); 19 | } 20 | -------------------------------------------------------------------------------- /tests/node/huffdecode.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var sys = require('sys'); 3 | 4 | require('./typed-array.js'); 5 | require('../../mad.js'); 6 | require('../../id3.js'); 7 | require('../../layer3.js'); 8 | require('../../synth.js'); 9 | require("../../mad.js"); 10 | require("../../rq_table.js"); 11 | require("../../imdct_s.js"); 12 | require("../../huffman.js"); 13 | require("../../bit.js"); 14 | require("../../stream.js"); 15 | require("../../id3.js"); 16 | require("../../layer3.js"); 17 | require("../../frame.js"); 18 | require("../../synth.js"); 19 | 20 | var data = fs.readFileSync("one_second_of_silence.mp3", "binary"); 21 | // var data = fs.readFileSync("soul-2.mp3", "binary"); 22 | 23 | console.log("Reading a " + Math.round(data.length / 1024) + "KB file"); 24 | 25 | var stream = new Mad.Stream(data); 26 | 27 | ID3_skipHeader(stream); 28 | 29 | var STEPS_COUNT = 0; 30 | 31 | var frame = null; 32 | 33 | frame = Mad.Frame.decode(stream); // apparently first frame has nothing to decode 34 | frame = Mad.Frame.decode(stream); 35 | 36 | console.log("error code: " + stream.error); 37 | -------------------------------------------------------------------------------- /experiments/experiment.js: -------------------------------------------------------------------------------- 1 | var domReady = function () 2 | { 3 | var fileChooser = document.forms['uploadData']['fileChooser']; 4 | fileChooser.onchange = function(ev) { 5 | readFile() 6 | } 7 | 8 | function readFile() { 9 | var file = fileChooser.files[0]; 10 | console.log("Reading file " + file.name); 11 | 12 | new Mad.FileStream(file, function(stream) { 13 | var mp3 = new Mad.MP3File(stream); 14 | console.log("File loaded"); 15 | var mpeg = mp3.getMpegStream(); 16 | 17 | var howmuch = 10000; 18 | var ss1 = Date.now(); 19 | console.log("Decoding first " + howmuch + " frames"); 20 | var frame = new Mad.Frame(); 21 | 22 | for(var i = 0; i < howmuch; i += 1) { 23 | frame = Mad.Frame.decode(frame, mpeg); 24 | } 25 | var ss2 = Date.now(); 26 | console.log("Done in " + (ss2 - ss1) + "ms"); 27 | }); 28 | } 29 | }; 30 | document.addEventListener("DOMContentLoaded", domReady, false); 31 | -------------------------------------------------------------------------------- /src/imdct_s.js: -------------------------------------------------------------------------------- 1 | Mad.imdct_s = [ 2 | /* 0 */ [ 0.608761429, 3 | -0.923879533, 4 | -0.130526192, 5 | 0.991444861, 6 | -0.382683432, 7 | -0.793353340 ], 8 | 9 | /* 6 */ [ -0.793353340, 10 | 0.382683432, 11 | 0.991444861, 12 | 0.130526192, 13 | -0.923879533, 14 | -0.608761429 ], 15 | 16 | /* 1 */ [ 0.382683432, 17 | -0.923879533, 18 | 0.923879533, 19 | -0.382683432, 20 | -0.382683432, 21 | 0.923879533 ], 22 | 23 | /* 7 */ [ -0.923879533, 24 | -0.382683432, 25 | 0.382683432, 26 | 0.923879533, 27 | 0.923879533, 28 | 0.382683432 ], 29 | 30 | /* 2 */ [ 0.130526192, 31 | -0.382683432, 32 | 0.608761429, 33 | -0.793353340, 34 | 0.923879533, 35 | -0.991444861 ], 36 | 37 | /* 8 */ [ -0.991444861, 38 | -0.923879533, 39 | -0.793353340, 40 | -0.608761429, 41 | -0.382683432, 42 | -0.130526192 ] 43 | ] 44 | -------------------------------------------------------------------------------- /src/binarystring/stringstream.js: -------------------------------------------------------------------------------- 1 | Mad.BinaryStrings.StringStream = function(string) { 2 | this.offset = 0; 3 | this.buffer = string; 4 | this.amountRead = string.length; 5 | this.length = string.length; 6 | } 7 | 8 | Mad.BinaryStrings.StringStream.prototype = new Mad.BinaryStrings.ByteStream(); 9 | 10 | Mad.BinaryStrings.StringStream.prototype.absoluteAvailable = function(n, updated) { 11 | return n < this['amountRead']; 12 | } 13 | 14 | Mad.BinaryStrings.StringStream.prototype.seek = function(n) { 15 | this['offset'] += n; 16 | } 17 | 18 | Mad.BinaryStrings.StringStream.prototype.read = function(n) { 19 | var result = this.peek(n); 20 | 21 | this.seek(n); 22 | 23 | return result; 24 | } 25 | 26 | Mad.BinaryStrings.StringStream.prototype.peek = function(n) { 27 | if (this.available(n)) { 28 | var offset = this['offset']; 29 | 30 | var result = this.get(offset, n); 31 | 32 | return result; 33 | } else { 34 | throw 'TODO: THROW PEEK ERROR!'; 35 | } 36 | } 37 | 38 | Mad.BinaryStrings.StringStream.prototype.get = function(offset, length) { 39 | if (this.absoluteAvailable(offset + length)) { 40 | return this['buffer'].slice(offset, offset + length); 41 | } else { 42 | throw 'TODO: THROW GET ERROR!'; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tests/node/dct.js: -------------------------------------------------------------------------------- 1 | require('./typed-array.js'); 2 | require('../../mad.js'); 3 | require('../../synth.js'); 4 | 5 | var _in = [-24885929,47196,16460,331490,-41214,-9529,22626,8736,-7265,-6506,12615,-7664,11799,-5896,-5173,-4064,5503,-2814,8527,-8558,-2798,-11028,-11343,-4432,6220,2036,-1558,5120,0,0,0,0]; 6 | var lo = [-17429241,-16475780,-15459112,-14484372,-13536059,-12581038,-11687286,-10701390,-9665573,-8622052,-7557596,-6432024,-5223547,-3996414,-2651606,-1281770]; 7 | var hi = [-18405790,-19328854,-20162190,-20939601,-21600256,-22213828,-22816256,-23239559,-23583918,-23939478,-24126106,-24292333,-24437136,-24456072,-24497924,-24537443]; 8 | 9 | function fixToFloat(x) { 10 | return x / (1 << 28); 11 | } 12 | 13 | function floatArray(list) { 14 | var result = []; 15 | for (var i = 0; i < list.length; i++) { 16 | result[i] = fixToFloat(list[i]); 17 | } 18 | return result; 19 | } 20 | 21 | lo = floatArray(lo); 22 | hi = floatArray(hi); 23 | 24 | var _lo = []; 25 | var _hi = []; 26 | 27 | for (var i = 0; i < 16; i++) { 28 | _lo[i] = []; 29 | _hi[i] = []; 30 | } 31 | 32 | Mad.Synth.dct32(floatArray(_in), 0, _lo, _hi); 33 | 34 | for (var i = 0; i < 16; i++) { 35 | console.log(Math.abs(_lo[i][0] - lo[i])); 36 | } 37 | 38 | for (var i = 0; i < 16; i++) { 39 | console.log(Math.abs(_hi[i][0] - hi[i])); 40 | } -------------------------------------------------------------------------------- /src/mp3file.js: -------------------------------------------------------------------------------- 1 | Mad.MP3File = function(stream) { 2 | this.stream = stream; 3 | } 4 | 5 | Mad.MP3File.prototype.getID3v2Header = function() { 6 | if (this.stream.strEquals(0, "ID3")) { 7 | var headerStream = this.stream.substream(0, 10); 8 | 9 | headerStream.seek(3); // 'ID3' 10 | 11 | var major = headerStream.readU8(); 12 | var minor = headerStream.readU8(); 13 | 14 | var flags = headerStream.readU8(); 15 | 16 | var length = headerStream.readSyncInteger(); 17 | 18 | return { version: '2.' + major + '.' + minor, major: major, minor: minor, flags: flags, length: length }; 19 | } else { 20 | return null; 21 | } 22 | } 23 | 24 | Mad.MP3File.prototype.getID3v2Stream = function() { 25 | var header = this.getID3v2Header(); 26 | 27 | if (header) { 28 | if (header.major > 2) { 29 | return new Mad.ID3v23Stream(header, this.stream.substream(10, header.length)); 30 | } else { 31 | return new Mad.ID3v22Stream(header, this.stream.substream(10, header.length)); 32 | } 33 | } else { 34 | return null; 35 | } 36 | } 37 | 38 | Mad.MP3File.prototype.getMpegStream = function() { 39 | var id3header = this.getID3v2Header(); 40 | 41 | if (id3header) { 42 | var offset = 10 + id3header.length; 43 | } else { 44 | var offset = 0; 45 | } 46 | 47 | var length = this.stream.length - offset; 48 | 49 | return new Mad.Stream(this.stream.substream(offset), length); 50 | } 51 | -------------------------------------------------------------------------------- /src/arraybuffer/arraystream.js: -------------------------------------------------------------------------------- 1 | 2 | Mad.ArrayBuffers.ArrayStream = Mad.ArrayBuffers.ByteStream.extend({ 3 | init: function (buffer) { 4 | this.offset = 0; 5 | this.buffer = buffer; 6 | this.amountRead = this.buffer.length; 7 | this.contentLength = this.buffer.length; 8 | this.length = this.amountRead; 9 | }, 10 | 11 | substream: function (offset, length) { 12 | return new Mad.ArrayBuffers.SubStream(this, offset, length); 13 | }, 14 | 15 | absoluteAvailable: function(n, updated) { 16 | return n < this.amountRead; 17 | }, 18 | 19 | getU8: function(offset, bigEndian) { 20 | return this.buffer[offset]; 21 | }, 22 | 23 | seek: function(n) { 24 | this.offset += n; 25 | }, 26 | 27 | read: function(n) { 28 | var result = this.peek(n); 29 | 30 | this.seek(n); 31 | 32 | return result; 33 | }, 34 | 35 | peek: function(n) { 36 | if (this.available(n)) { 37 | var offset = this.offset; 38 | 39 | var result = this.get(offset, n); 40 | 41 | return result; 42 | } else { 43 | throw 'TODO: THROW PEEK ERROR!'; 44 | } 45 | }, 46 | 47 | get: function(offset, length) { 48 | if (offset + length < this.contentLength) { 49 | var subarr = this.buffer.subarray(offset, offset + length); 50 | return subarr; 51 | } else { 52 | throw 'TODO: THROW GET ERROR!'; 53 | } 54 | } 55 | }); 56 | -------------------------------------------------------------------------------- /src/binarystring/substream.js: -------------------------------------------------------------------------------- 1 | 2 | Mad.BinaryStrings.SubStream = function(stream, offset, length) { 3 | this.offset = 0; 4 | this.start = offset; 5 | this.parentStream = stream; 6 | this.length = length; 7 | } 8 | 9 | Mad.BinaryStrings.SubStream.prototype = new Mad.BinaryStrings.ByteStream; 10 | 11 | Mad.BinaryStrings.SubStream.prototype.substream = function (offset, length) { 12 | return new Mad.BinaryStrings.SubStream(this.parentStream, this.start + offset, length); 13 | } 14 | 15 | 16 | Mad.BinaryStrings.SubStream.prototype.absoluteAvailable = function(n) { 17 | return this.parentStream.absoluteAvailable(this.start + n); 18 | } 19 | 20 | Mad.BinaryStrings.SubStream.prototype.seek = function(n) { 21 | this.offset += n; 22 | } 23 | 24 | Mad.BinaryStrings.SubStream.prototype.read = function(n) { 25 | var result = this.peek(n); 26 | 27 | this.seek(n); 28 | 29 | return result; 30 | } 31 | 32 | Mad.BinaryStrings.SubStream.prototype.peek = function(n) { 33 | return this.get(this.offset, n); 34 | } 35 | 36 | Mad.BinaryStrings.SubStream.prototype.get = function(offset, length) { 37 | return this.parentStream.get(this.start + offset, length); 38 | } 39 | 40 | Mad.BinaryStrings.SubStream.prototype.slice = function(start, end) { 41 | return this.parentStream.get(this.start + start, end - start); 42 | } 43 | 44 | Mad.BinaryStrings.SubStream.prototype.requestAbsolute = function(n, callback) { 45 | this.parentStream.requestAbsolute(this.start + n) 46 | } 47 | 48 | Mad.BinaryStrings.SubStream.prototype.request = function(n, callback) { 49 | this.parentStream.requestAbsolute(this.start + this.offset + n) 50 | } 51 | -------------------------------------------------------------------------------- /src/arraybuffer/substream.js: -------------------------------------------------------------------------------- 1 | 2 | Mad.ArrayBuffers.SubStream = Mad.ArrayBuffers.ByteStream.extend({ 3 | init: function(stream, offset, length) { 4 | this.offset = 0; 5 | this.start = offset; 6 | this.parentStream = stream; 7 | this.length = length; 8 | }, 9 | 10 | substream: function (offset, length) { 11 | return new Mad.SubStream(this.parentStream, this.start + offset, length); 12 | }, 13 | 14 | getU8: function(offset, bigEndian) { 15 | return this.parentStream.getU8(this.start + offset, bigEndian); 16 | }, 17 | 18 | getU16: function(offset, bigEndian) { 19 | return this.parentStream.getU16(this.start + offset, bigEndian); 20 | }, 21 | 22 | getU32: function(offset, bigEndian) { 23 | return this.parentStream.getU32(this.start + offset, bigEndian); 24 | }, 25 | 26 | absoluteAvailable: function(n) { 27 | return this.parentStream.absoluteAvailable(this.start + n); 28 | }, 29 | 30 | seek: function(n) { 31 | this.offset += n; 32 | }, 33 | 34 | read: function(n) { 35 | var result = this.peek(n); 36 | this.seek(n); 37 | return result; 38 | }, 39 | 40 | peek: function(n) { 41 | return this.get(this.offset, n); 42 | }, 43 | 44 | get: function(offset, length) { 45 | return this.parentStream.get(this.start + offset, length); 46 | }, 47 | 48 | slice: function(start, end) { 49 | return this.parentStream.get(this.start + start, end - start); 50 | }, 51 | 52 | requestAbsolute: function(n, callback) { 53 | this.parentStream.requestAbsolute(this.start + n) 54 | }, 55 | 56 | request: function(n, callback) { 57 | this.parentStream.requestAbsolute(this.start + this.offset + n) 58 | } 59 | }); 60 | -------------------------------------------------------------------------------- /tests/node/output.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var sys = require('sys'); 3 | 4 | require('./typed-array.js'); 5 | require('../../mad.js'); 6 | require('../../id3.js'); 7 | require('../../layer3.js'); 8 | require('../../synth.js'); 9 | require("../../mad.js"); 10 | require("../../rq_table.js"); 11 | require("../../imdct_s.js"); 12 | require("../../huffman.js"); 13 | require("../../bit.js"); 14 | require("../../stream.js"); 15 | require("../../id3.js"); 16 | require("../../layer3.js"); 17 | require("../../frame.js"); 18 | require("../../synth.js"); 19 | 20 | // var data = fs.readFileSync("one_second_of_silence.mp3", "binary"); 21 | // var data = fs.readFileSync("one_second_beep.mp3", "binary"); 22 | var data = fs.readFileSync("output.mp3", "binary"); 23 | // var data = fs.readFileSync("soul-2.mp3", "binary"); 24 | 25 | console.log("Reading a " + Math.round(data.length / 1024) + "KB file"); 26 | 27 | var stream = new Mad.Stream(data); 28 | 29 | ID3_skipHeader(stream); 30 | 31 | var STEPS_COUNT = 0; 32 | 33 | var frame = null; 34 | 35 | var allmin = 0; 36 | var allmax = 0; 37 | 38 | while (frame = Mad.Frame.decode(stream)) { 39 | var synth = new Mad.Synth(); 40 | synth.frame(frame); 41 | 42 | var samples = synth.pcm.samples[0]; 43 | 44 | var min = 0.0; 45 | var max = 0.0; 46 | var mean = 0.0; 47 | 48 | for (var i = 0; i < samples.length; i++) { 49 | var sample = samples[i]; 50 | mean += (sample / samples.length); 51 | if(min > sample) min = sample; 52 | if(max < sample) max = sample; 53 | } 54 | 55 | console.log("min = " + min + ", max = " + max + ", mean = " + mean); 56 | if(allmin > min) allmin = min; 57 | if(allmax < max) allmax = max; 58 | } 59 | 60 | console.log("allmin = " + allmin + ", allmax = " + allmax); 61 | 62 | console.log("error code: " + stream.error); 63 | -------------------------------------------------------------------------------- /src/binarystring/filestream.js: -------------------------------------------------------------------------------- 1 | Mad.BinaryStrings.FileStream = function(file, callback) { 2 | this.offset = 0; 3 | var self = this, reader = new FileReader(); 4 | 5 | reader.onload = function () { 6 | self['buffer'] = reader.result; 7 | self['amountRead'] = self['buffer'].length; 8 | self['contentLength'] = self['buffer'].length; 9 | 10 | self.length = self['amountRead']; 11 | 12 | callback(self); 13 | } 14 | 15 | reader.onerror = function () { 16 | console.log("Error!"); 17 | } 18 | 19 | reader.readAsBinaryString(file); 20 | } 21 | 22 | Mad.BinaryStrings.FileStream.prototype = new Mad.BinaryStrings.ByteStream(); 23 | 24 | Mad.BinaryStrings.FileStream.prototype.absoluteAvailable = function(n, updated) { 25 | return n < this['amountRead']; 26 | } 27 | 28 | Mad.BinaryStrings.FileStream.prototype.substream = function (offset, length) { 29 | return new Mad.BinaryStrings.SubStream(this, offset, length); 30 | } 31 | 32 | Mad.BinaryStrings.FileStream.prototype.seek = function(n) { 33 | this['offset'] += n; 34 | } 35 | 36 | Mad.BinaryStrings.FileStream.prototype.read = function(n) { 37 | var result = this.peek(n); 38 | 39 | this.seek(n); 40 | 41 | return result; 42 | } 43 | 44 | Mad.BinaryStrings.FileStream.prototype.peek = function(n) { 45 | if (this.available(n)) { 46 | var offset = this['offset']; 47 | 48 | var result = this.get(offset, n); 49 | 50 | return result; 51 | } else { 52 | throw 'TODO: THROW PEEK ERROR!'; 53 | } 54 | } 55 | 56 | Mad.BinaryStrings.FileStream.prototype.get = function(offset, length) { 57 | if (this.absoluteAvailable(offset + length)) { 58 | return this['buffer'].slice(offset, offset + length); 59 | } else { 60 | throw 'TODO: THROW GET ERROR!'; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /scripts/uglify: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var sys = require( 'sys' ), 4 | path = require( 'path' ), 5 | fs = require( 'fs' ), 6 | uglify = require( 'uglify-js' ); 7 | 8 | var root = path.dirname( __dirname ) + '/', 9 | files = [ 10 | 'src/mad.js', 11 | 'src/rq_table.js', 12 | 'src/imdct_s.js', 13 | 'src/huffman.js', 14 | 'src/bit.js', 15 | 'src/stream.js', 16 | 'src/layer3.js', 17 | 'src/frame.js', 18 | 'src/synth.js', 19 | 'src/bytestream.js', 20 | 'src/filestream.js', 21 | 'src/substream.js', 22 | 'src/id3v22stream.js', 23 | 'src/id3v23stream.js', 24 | 'src/mp3file.js', 25 | 'src/ajaxstream.js', 26 | 'src/stringstream.js', 27 | 'src/player.js' 28 | ], 29 | i, 30 | file, 31 | code = ''; 32 | 33 | for( i = 0; i < files.length; i++ ) { 34 | 35 | console.log( 'Reading ' + files[ i ] + '...' ); 36 | 37 | file = root + files[ i ]; 38 | code += '\n/* File: ' + files[ i ] + ' */\n'; 39 | code += fs.readFileSync( file, 'utf-8' ); 40 | } 41 | 42 | try { 43 | 44 | console.log( 'UglifyJS: Parsing the source code...' ); 45 | var ast = uglify.parser.parse( code ); 46 | 47 | console.log( 'UglifyJS: Mangling the code...' ); 48 | ast = uglify.uglify.ast_mangle( ast ); // get a new AST with mangled names 49 | 50 | console.log( 'UglifyJS: Squeezing the code...' ); 51 | ast = uglify.uglify.ast_squeeze( ast ); // get an AST with compression optimizations 52 | 53 | console.log( 'UglifyJS: Generating the code...' ); 54 | var finalCode = uglify.uglify.gen_code( ast ); // compressed code here 55 | 56 | console.log( 'Writing the code into src/jsmad.min.js...' ); 57 | fs.writeFileSync( root + 'src/jsmad.min.js', finalCode, 'utf-8' ); 58 | 59 | console.log( 'Success! The uglified source code has been stored into src/jsmad.min.js.' ); 60 | 61 | } catch( e ) 62 | { 63 | console.error( 'Error: something went wrong.' ); 64 | console.error( e.toString() ); 65 | } 66 | -------------------------------------------------------------------------------- /experiments/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |