diff --git a/gulpfile.js b/gulpfile.js index b7ecb80..d1b72fb 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -9,7 +9,7 @@ var order = require("gulp-order"); var del = require('del'); var jshint = require('gulp-jshint'); -gulp.task('default', ['css', 'mp3', 'minify'], function() { +gulp.task('default', ['css', 'audio', 'minify'], function() { }); @@ -31,11 +31,16 @@ gulp.task('css', function(){ .pipe(gulp.dest('css')); }); -gulp.task("mp3", function () { - return gulp.src("src/js/mp3/*.js") - .pipe(uglify()) - .pipe(concat("mp3-min.js")) - .pipe(gulp.dest("lib")); +gulp.task("audio", function () { + gulp.src(["src/js/audio/aurora.js", "src/js/audio/mp3.js"]) + .pipe(concat("audio-min.js")) + .pipe(uglify()) + .pipe(gulp.dest("lib")); + + gulp.src(["src/js/audio/ogg.js", "src/js/audio/vorbis.js"]) + .pipe(concat("oggvorbis.js")) + .pipe(uglify()) + .pipe(gulp.dest("lib")); }); gulp.task("minify", function () { @@ -63,7 +68,8 @@ gulp.task('clean', function() { return del([ 'lib/hues-min.js', 'lib/hues-min.map', - 'lib/mp3-min.js', + 'lib/audio-min.js', + 'lib/oggvorbis.js', 'css', 'release']); }); @@ -72,7 +78,8 @@ gulp.task('release', ['default', 'lint'], function() { gulp.src([ 'css/hues-min.css', 'lib/hues-min.js', - 'lib/mp3-min.js', + 'lib/audio-min.js', + 'lib/oggvorbis.js', 'fonts/**/*', 'img/**/*', 'index.html', diff --git a/lib/workers/mp3-worker.js b/lib/workers/audio-worker.js similarity index 62% rename from lib/workers/mp3-worker.js rename to lib/workers/audio-worker.js index 5b4a090..0bbab90 100644 --- a/lib/workers/mp3-worker.js +++ b/lib/workers/audio-worker.js @@ -1,39 +1,53 @@ -// Use mp3.js and aurora.js for dev -// Use mp3-min.js for release -//importScripts('aurora.js'); -//importScripts('mp3.js'); -importScripts('../mp3-min.js'); +importScripts('../audio-min.js'); // Flash value var LAME_DELAY_START = 2258; var LAME_DELAY_END = 0; var deinterleaveAndTrim = function(buffer, asset) { - // because MP3 is bad, we nuke silence var channels = asset.format.channelsPerFrame, - len = buffer.length / channels; + len = buffer.length / channels, + newLen, start; + + // because MP3 is bad, we nuke silence + if(asset.format.formatID == "mp3") { newLen = len - LAME_DELAY_START - LAME_DELAY_END; - result = new Float32Array(newLen * channels); + start = LAME_DELAY_START; + } else { + newLen = len; + start = 0; + } + var result = new Float32Array(newLen * channels); for(var sample = 0; sample < newLen; sample++) { for(var channel = 0; channel < channels; channel++) { - result[channel*newLen + sample] = buffer[(sample+LAME_DELAY_START)*channels + channel]; + result[channel*newLen + sample] = buffer[(sample+start)*channels + channel]; } } return result; } self.addEventListener('message', function(e) { + if(!e.data.ogg) { + importScripts('../oggvorbis.js'); + } + // To see if things are working, we can ping the worker if(e.data.ping) { self.postMessage({ping: true}); return; } - var arrayBuffer = e.data; + var arrayBuffer = e.data.buffer; var asset = AV.Asset.fromBuffer(arrayBuffer); - // Any errors are thrown up the chain to our Promises + + // On error we still want to restore the audio file + asset.on("error", function(error) { + self.postMessage({arrayBuffer : arrayBuffer, + error: error}, + [arrayBuffer]); + }); asset.decodeToBuffer(function(buffer) { var fixedBuffer = deinterleaveAndTrim(buffer, asset); diff --git a/src/js/HuesEditor.js b/src/js/HuesEditor.js index 5e97b12..f046c00 100644 --- a/src/js/HuesEditor.js +++ b/src/js/HuesEditor.js @@ -278,6 +278,15 @@ HuesEditor.prototype.loadAudio = function(editor) { // load audio this.blobToArrayBuffer(file) .then(buffer => { + // Is this buffer even decodable? + let testSong = {test: buffer}; + return this.core.soundManager.loadBuffer(testSong, "test") + // keep the buffer moving through the chain + // remember it's been passed through to a worker, so we update the reference + .then(() => { + return testSong.test; + }); + }).then(buffer => { this.song[editor._sound] = buffer; // Save filename for XML export let noExt = file.name.replace(/\.[^/.]+$/, ""); @@ -827,7 +836,7 @@ HuesEditor.prototype.uiCreateSingleEditor = function(title, soundName, rhythmNam let fileInput = document.createElement("input"); fileInput.type ="file"; - fileInput.accept="audio/mp3"; + fileInput.accept="audio/mp3|audio/wav|audio/ogg"; fileInput.multiple = false; fileInput.onchange = this.loadAudio.bind(this, container); let load = this.createButton("Load " + title.replace(/ /g,""), rightHeader); diff --git a/src/js/HuesSettings.js b/src/js/HuesSettings.js index ec8874e..052e5c8 100644 --- a/src/js/HuesSettings.js +++ b/src/js/HuesSettings.js @@ -27,7 +27,7 @@ - Go to the HTML and edit the `defaults` object instead! */ HuesSettings.prototype.defaultSettings = { - // Location relative to root - where do the mp3/zip workers live + // Location relative to root - where do the audio/zip workers live // This is required because Web Workers need an absolute path workersPath : "lib/workers/", // Debugging var, for loading zips or not diff --git a/src/js/ResourcePack.js b/src/js/ResourcePack.js index 70efcf9..80a61da 100644 --- a/src/js/ResourcePack.js +++ b/src/js/ResourcePack.js @@ -57,7 +57,7 @@ function Respack() { this.loadedFromURL = false; } -Respack.prototype.audioExtensions = new RegExp("\\.(mp3|ogg)$", "i"); +Respack.prototype.audioExtensions = new RegExp("\\.(mp3|ogg|wav)$", "i"); Respack.prototype.imageExtensions = new RegExp("\\.(png|gif|jpg|jpeg)$", "i"); Respack.prototype.animRegex = new RegExp("(.*?)_\\d+$"); @@ -225,6 +225,9 @@ Respack.prototype.parseSong = function(file) { case "ogg": mime = "audio/ogg"; break; + case "wav": + mime = "audio/wav"; + break; default: mime = "application/octet-stream"; } diff --git a/src/js/SoundManager.js b/src/js/SoundManager.js index 8621cd4..2aa5cb0 100644 --- a/src/js/SoundManager.js +++ b/src/js/SoundManager.js @@ -32,6 +32,7 @@ function SoundManager(core) { /* Lower level audio and timing info */ this.context = null; // Audio context, Web Audio API + this.oggSupport = false; this.buildSource = null; this.loopSource = null; this.buildup = null; @@ -68,8 +69,8 @@ SoundManager.prototype.init = function() { window.AudioContext = window.AudioContext || window.webkitAudioContext; this.context = new window.AudioContext(); // These don't always exist - this.context.suspend = this.context.suspend || Promise.resolve(); - this.context.resume = this.context.resume || Promise.resolve(); + this.context.suspend = this.context.suspend || Promise.resolve; + this.context.resume = this.context.resume || Promise.resolve; this.gainNode = this.context.createGain(); this.gainNode.connect(this.context.destination); } catch(e) { @@ -77,28 +78,39 @@ SoundManager.prototype.init = function() { return; } resolve(); - }).then(response => { + }).then(() => { + // check for .ogg support - if not, we'll have to load the ogg decoder + return new Promise((resolve, reject) => { + this.context.decodeAudioData(miniOgg, success => { + this.oggSupport = true; + resolve(); + }, error => { + this.oggSupport = false; + resolve(); + }); + }); + }).then(() => { return new Promise((resolve, reject) => { - // See if our MP3 decoder is working - let mp3Worker; + // See if our audio decoder is working + let audioWorker; try { - mp3Worker = this.createWorker(); + audioWorker = this.createWorker(); } catch(e) { console.log(e); - reject(Error("MP3 Worker cannot be started - correct path set in defaults?")); + reject(Error("Audio Worker cannot be started - correct path set in defaults?")); + return; } let pingListener = event => { - mp3Worker.removeEventListener('message', pingListener); - mp3Worker.terminate(); + audioWorker.terminate(); resolve(); }; - mp3Worker.addEventListener('message', pingListener, false); - mp3Worker.addEventListener('error', () => { - reject(Error("MP3 Worker cannot be started - correct path set in defaults?")); + audioWorker.addEventListener('message', pingListener, false); + audioWorker.addEventListener('error', () => { + reject(Error("Audio Worker cannot be started - correct path set in defaults?")); }, false); - mp3Worker.postMessage({ping:true}); + audioWorker.postMessage({ping:true, ogg:this.oggSupport}); }); - }).then(response => { + }).then(() => { return new Promise((resolve, reject) => { // iOS and other some mobile browsers - unlock the context as // it starts in a suspended state @@ -158,7 +170,10 @@ SoundManager.prototype.playSong = function(song, playBuild, forcePlay) { // To prevent race condition if you press "next" twice fast if(song != this.song) { // Stop processing - silently ignored in the catch below - throw Error("Song not playable - ignoring!"); + throw { + name: "SoundManagerRace", + message: "Song not playable - ignoring!" + }; } this.buildup = buffers.buildup; @@ -179,10 +194,14 @@ SoundManager.prototype.playSong = function(song, playBuild, forcePlay) { }).then(() => { this.playing = true; }).catch(error => { - // Just to ignore it if the song was invalid - // Log it in case it's something weird - console.log(error); - return; + if(error.name == "SoundManagerRace") { + // Just to ignore it if the song was invalid + // Log it in case it's something weird + console.log("SoundManager couldn't play song", error); + return; + } else { + throw error; + } }); return p; }; @@ -313,27 +332,53 @@ SoundManager.prototype.loadSong = function(song) { }; SoundManager.prototype.loadBuffer = function(song, soundName) { - return new Promise((resolve, reject) => { - let mp3Worker = this.createWorker(); - - mp3Worker.addEventListener('error', () => { - reject(Error("MP3 Worker failed to convert track")); - }, false); - - mp3Worker.addEventListener('message', e => { - let decoded = e.data; - mp3Worker.terminate(); + let buffer = song[soundName]; + + // Is this an ogg file? + let view = new Uint8Array(buffer); + // Signature for ogg file: OggS + if(this.oggSupport && view[0] == 0x4F && view[1] == 0x67 && view[2] == 0x67 && view[3] == 0x53) { + // As we don't control decodeAudioData, we cannot do fast transfers and must copy + let backup = buffer.slice(0); + return new Promise((resolve, reject) => { + this.context.decodeAudioData(buffer, result => { + resolve(result); + }, error => { + reject(Error("decodeAudioData failed to load track")); + }); + }).then(result => { + // restore copied buffer + song[soundName] = backup; + return result; + }); + } else { // Use our JS decoder + return new Promise((resolve, reject) => { + let audioWorker = this.createWorker(); - // restore transferred buffer - song[soundName] = decoded.arrayBuffer; - // Convert to real audio buffer - let audio = this.audioBufFromRaw(decoded.rawAudio); - resolve(audio); - }, false); - - // transfer the buffer to save time - mp3Worker.postMessage(song[soundName], [song[soundName]]); - }); + audioWorker.addEventListener('error', () => { + reject(Error("Audio Worker failed to convert track")); + }, false); + + audioWorker.addEventListener('message', e => { + let decoded = e.data; + audioWorker.terminate(); + + // restore transferred buffer + song[soundName] = decoded.arrayBuffer; + if(decoded.error) { + reject(new Error(decoded.error)); + return; + } + // Convert to real audio buffer + let audio = this.audioBufFromRaw(decoded.rawAudio); + resolve(audio); + }, false); + + // transfer the buffer to save time + audioWorker.postMessage({buffer: buffer, ogg: this.oggSupport}, [buffer]); + }); + } + }; // Converts continuous PCM array to Web Audio API friendly format @@ -342,20 +387,16 @@ SoundManager.prototype.audioBufFromRaw = function(raw) { let channels = raw.channels; let samples = buffer.length/channels; let audioBuf = this.context.createBuffer(channels, samples, raw.sampleRate); - //let audioBuf = this.context.createBuffer(1, buffer.length, raw.sampleRate); - //audioBuf.copyToChannel(buffer, 0, 0); for(let i = 0; i < channels; i++) { - //console.log("Making buffer at offset",i*samples,"and length",samples,".Original buffer is",channels,"channels and",buffer.length,"elements"); // Offset is in bytes, length is in elements let channel = new Float32Array(buffer.buffer , i * samples * 4, samples); - //console.log(channel); audioBuf.copyToChannel(channel, i, 0); } return audioBuf; }; SoundManager.prototype.createWorker = function() { - return new Worker(this.core.settings.defaults.workersPath + 'mp3-worker.js'); + return new Worker(this.core.settings.defaults.workersPath + 'audio-worker.js'); }; SoundManager.prototype.initVisualiser = function(bars) { @@ -516,6 +557,95 @@ SoundManager.prototype.fadeOut = function(callback) { setTimeout(callback, 2000); }; +let miniOggRaw = +"T2dnUwACAAAAAAAAAADFYgAAAAAAAMLKRdwBHgF2b3JiaXMAAAAAAUSsAAAA" + +"AAAAgLsAAAAAAAC4AU9nZ1MAAAAAAAAAAAAAxWIAAAEAAACcKCV2Dzv/////" + +"////////////MgN2b3JiaXMrAAAAWGlwaC5PcmcgbGliVm9yYmlzIEkgMjAx" + +"MjAyMDMgKE9tbmlwcmVzZW50KQAAAAABBXZvcmJpcx9CQ1YBAAABABhjVClG" + +"mVLSSokZc5QxRplikkqJpYQWQkidcxRTqTnXnGusubUghBAaU1ApBZlSjlJp" + +"GWOQKQWZUhBLSSV0EjonnWMQW0nB1phri0G2HIQNmlJMKcSUUopCCBlTjCnF" + +"lFJKQgcldA465hxTjkooQbicc6u1lpZji6l0kkrnJGRMQkgphZJKB6VTTkJI" + +"NZbWUikdc1JSakHoIIQQQrYghA2C0JBVAAABAMBAEBqyCgBQAAAQiqEYigKE" + +"hqwCADIAAASgKI7iKI4jOZJjSRYQGrIKAAACABAAAMBwFEmRFMmxJEvSLEvT" + +"RFFVfdU2VVX2dV3XdV3XdSA0ZBUAAAEAQEinmaUaIMIMZBgIDVkFACAAAABG" + +"KMIQA0JDVgEAAAEAAGIoOYgmtOZ8c46DZjloKsXmdHAi1eZJbirm5pxzzjkn" + +"m3PGOOecc4pyZjFoJrTmnHMSg2YpaCa05pxznsTmQWuqtOacc8Y5p4NxRhjn" + +"nHOatOZBajbW5pxzFrSmOWouxeaccyLl5kltLtXmnHPOOeecc84555xzqhen" + +"c3BOOOecc6L25lpuQhfnnHM+Gad7c0I455xzzjnnnHPOOeecc4LQkFUAABAA" + +"AEEYNoZxpyBIn6OBGEWIacikB92jwyRoDHIKqUejo5FS6iCUVMZJKZ0gNGQV" + +"AAAIAAAhhBRSSCGFFFJIIYUUUoghhhhiyCmnnIIKKqmkoooyyiyzzDLLLLPM" + +"Muuws8467DDEEEMMrbQSS0211VhjrbnnnGsO0lpprbXWSimllFJKKQgNWQUA" + +"gAAAEAgZZJBBRiGFFFKIIaaccsopqKACQkNWAQCAAAACAAAAPMlzREd0REd0" + +"REd0REd0RMdzPEeUREmUREm0TMvUTE8VVdWVXVvWZd32bWEXdt33dd/3dePX" + +"hWFZlmVZlmVZlmVZlmVZlmVZgtCQVQAACAAAgBBCCCGFFFJIIaUYY8wx56CT" + +"UEIgNGQVAAAIACAAAADAURzFcSRHciTJkixJkzRLszzN0zxN9ERRFE3TVEVX" + +"dEXdtEXZlE3XdE3ZdFVZtV1Ztm3Z1m1flm3f933f933f933f933f93UdCA1Z" + +"BQBIAADoSI6kSIqkSI7jOJIkAaEhqwAAGQAAAQAoiqM4juNIkiRJlqRJnuVZ" + +"omZqpmd6qqgCoSGrAABAAAABAAAAAAAomuIppuIpouI5oiNKomVaoqZqriib" + +"suu6ruu6ruu6ruu6ruu6ruu6ruu6ruu6ruu6ruu6ruu6ruu6LhAasgoAkAAA" + +"0JEcyZEcSZEUSZEcyQFCQ1YBADIAAAIAcAzHkBTJsSxL0zzN0zxN9ERP9ExP" + +"FV3RBUJDVgEAgAAAAgAAAAAAMCTDUixHczRJlFRLtVRNtVRLFVVPVVVVVVVV" + +"VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVNU3TNE0gNGQlAAAEAMBijcHl" + +"ICElJeXeEMIQk54xJiG1XiEEkZLeMQYVg54yogxy3kLjEIMeCA1ZEQBEAQAA" + +"xiDHEHPIOUepkxI556h0lBrnHKWOUmcpxZhizSiV2FKsjXOOUketo5RiLC12" + +"lFKNqcYCAAACHAAAAiyEQkNWBABRAACEMUgppBRijDmnnEOMKeeYc4Yx5hxz" + +"jjnnoHRSKuecdE5KxBhzjjmnnHNSOieVc05KJ6EAAIAABwCAAAuh0JAVAUCc" + +"AIBBkjxP8jRRlDRPFEVTdF1RNF3X8jzV9ExTVT3RVFVTVW3ZVFVZljzPND3T" + +"VFXPNFXVVFVZNlVVlkVV1W3TdXXbdFXdlm3b911bFnZRVW3dVF3bN1XX9l3Z" + +"9n1Z1nVj8jxV9UzTdT3TdGXVdW1bdV1d90xTlk3XlWXTdW3blWVdd2XZ9zXT" + +"dF3TVWXZdF3ZdmVXt11Z9n3TdYXflWVfV2VZGHZd94Vb15XldF3dV2VXN1ZZ" + +"9n1b14Xh1nVhmTxPVT3TdF3PNF1XdV1fV13X1jXTlGXTdW3ZVF1ZdmXZ911X" + +"1nXPNGXZdF3bNl1Xll1Z9n1XlnXddF1fV2VZ+FVX9nVZ15Xh1m3hN13X91VZ" + +"9oVXlnXh1nVhuXVdGD5V9X1TdoXhdGXf14XfWW5dOJbRdX1hlW3hWGVZOX7h" + +"WJbd95VldF1fWG3ZGFZZFoZf+J3l9n3jeHVdGW7d58y67wzH76T7ytPVbWOZ" + +"fd1ZZl93juEYOr/w46mqr5uuKwynLAu/7evGs/u+soyu6/uqLAu/KtvCseu+" + +"8/y+sCyj7PrCasvCsNq2Mdy+biy/cBzLa+vKMeu+UbZ1fF94CsPzdHVdeWZd" + +"x/Z1dONHOH7KAACAAQcAgAATykChISsCgDgBAI8kiaJkWaIoWZYoiqbouqJo" + +"uq6kaaapaZ5pWppnmqZpqrIpmq4saZppWp5mmpqnmaZomq5rmqasiqYpy6Zq" + +"yrJpmrLsurJtu65s26JpyrJpmrJsmqYsu7Kr267s6rqkWaapeZ5pap5nmqZq" + +"yrJpmq6reZ5qep5oqp4oqqpqqqqtqqosW55nmproqaYniqpqqqatmqoqy6aq" + +"2rJpqrZsqqptu6rs+rJt67ppqrJtqqYtm6pq267s6rIs27ovaZppap5nmprn" + +"maZpmrJsmqorW56nmp4oqqrmiaZqqqosm6aqypbnmaoniqrqiZ5rmqoqy6Zq" + +"2qppmrZsqqotm6Yqy65t+77ryrJuqqpsm6pq66ZqyrJsy77vyqruiqYpy6aq" + +"2rJpqrIt27Lvy7Ks+6JpyrJpqrJtqqouy7JtG7Ns+7pomrJtqqYtm6oq27It" + +"+7os27rvyq5vq6qs67It+7ru+q5w67owvLJs+6qs+ror27pv6zLb9n1E05Rl" + +"UzVt21RVWXZl2fZl2/Z90TRtW1VVWzZN1bZlWfZ9WbZtYTRN2TZVVdZN1bRt" + +"WZZtYbZl4XZl2bdlW/Z115V1X9d949dl3ea6su3Lsq37qqv6tu77wnDrrvAK" + +"AAAYcAAACDChDBQashIAiAIAAIxhjDEIjVLOOQehUco55yBkzkEIIZXMOQgh" + +"lJI5B6GUlDLnIJSSUgihlJRaCyGUlFJrBQAAFDgAAATYoCmxOEChISsBgFQA" + +"AIPjWJbnmaJq2rJjSZ4niqqpqrbtSJbniaJpqqptW54niqapqq7r65rniaJp" + +"qqrr6rpomqapqq7ruroumqKpqqrrurKum6aqqq4ru7Ls66aqqqrryq4s+8Kq" + +"uq4ry7Jt68Kwqq7ryrJs27Zv3Lqu677v+8KRreu6LvzCMQxHAQDgCQ4AQAU2" + +"rI5wUjQWWGjISgAgAwCAMAYhgxBCBiGEkFJKIaWUEgAAMOAAABBgQhkoNGRF" + +"ABAnAAAYQymklFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSCmllFJKKaWU" + +"UkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSqmklFJKKaWU" + +"UkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWU" + +"UkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWU" + +"UkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWU" + +"UkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWU" + +"UkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimVUkoppZRS" + +"SimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRS" + +"SimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFIKAJCKcACQejCh" + +"DBQashIASAUAAIxRSinGnIMQMeYYY9BJKClizDnGHJSSUuUchBBSaS23yjkI" + +"IaTUUm2Zc1JaizHmGDPnpKQUW805h1JSi7HmmmvupLRWa64151paqzXXnHPN" + +"ubQWa64515xzyzHXnHPOOecYc84555xzzgUA4DQ4AIAe2LA6wknRWGChISsB" + +"gFQAAAIZpRhzzjnoEFKMOecchBAihRhzzjkIIVSMOeccdBBCqBhzzDkIIYSQ" + +"OecchBBCCCFzDjroIIQQQgcdhBBCCKGUzkEIIYQQSighhBBCCCGEEDoIIYQQ" + +"QgghhBBCCCGEUkoIIYQQQgmhlFAAAGCBAwBAgA2rI5wUjQUWGrISAAACAIAc" + +"lqBSzoRBjkGPDUHKUTMNQkw50ZliTmozFVOQORCddBIZakHZXjILAACAIAAg" + +"wAQQGCAo+EIIiDEAAEGIzBAJhVWwwKAMGhzmAcADRIREAJCYoEi7uIAuA1zQ" + +"xV0HQghCEIJYHEABCTg44YYn3vCEG5ygU1TqIAAAAAAADADgAQDgoAAiIpqr" + +"sLjAyNDY4OjwCAAAAAAAFgD4AAA4PoCIiOYqLC4wMjQ2ODo8AgAAAAAAAAAA" + +"gICAAAAAAABAAAAAgIBPZ2dTAAQBAAAAAAAAAMViAAACAAAA22A/JwIBAQAK"; + +// write the bytes of the string to an ArrayBuffer +let miniOggBin = atob(miniOggRaw); +let miniOgg = new ArrayBuffer(miniOggBin.length); +let view = new Uint8Array(miniOgg); +for (var i = 0; i < miniOggBin.length; i++) { + view[i] = miniOggBin.charCodeAt(i); +} + window.SoundManager = SoundManager; })(window, document); \ No newline at end of file diff --git a/src/js/mp3/aurora.js b/src/js/audio/aurora.js similarity index 99% rename from src/js/mp3/aurora.js rename to src/js/audio/aurora.js index bcf5780..33c8d78 100644 --- a/src/js/mp3/aurora.js +++ b/src/js/audio/aurora.js @@ -1729,6 +1729,8 @@ Demuxer = (function(_super) { }; formats = []; + + Demuxer.test = function() {return formats}; Demuxer.register = function(demuxer) { return formats.push(demuxer); diff --git a/src/js/mp3/mp3.js b/src/js/audio/mp3.js similarity index 100% rename from src/js/mp3/mp3.js rename to src/js/audio/mp3.js