|
|
@ -32,6 +32,7 @@ function SoundManager(core) { |
|
|
|
|
|
|
|
|
|
|
|
/* Lower level audio and timing info */ |
|
|
|
/* Lower level audio and timing info */ |
|
|
|
this.context = null; // Audio context, Web Audio API
|
|
|
|
this.context = null; // Audio context, Web Audio API
|
|
|
|
|
|
|
|
this.oggSupport = false; |
|
|
|
this.buildSource = null; |
|
|
|
this.buildSource = null; |
|
|
|
this.loopSource = null; |
|
|
|
this.loopSource = null; |
|
|
|
this.buildup = null; |
|
|
|
this.buildup = null; |
|
|
@ -68,8 +69,8 @@ SoundManager.prototype.init = function() { |
|
|
|
window.AudioContext = window.AudioContext || window.webkitAudioContext; |
|
|
|
window.AudioContext = window.AudioContext || window.webkitAudioContext; |
|
|
|
this.context = new window.AudioContext(); |
|
|
|
this.context = new window.AudioContext(); |
|
|
|
// These don't always exist
|
|
|
|
// These don't always exist
|
|
|
|
this.context.suspend = this.context.suspend || Promise.resolve(); |
|
|
|
this.context.suspend = this.context.suspend || Promise.resolve; |
|
|
|
this.context.resume = this.context.resume || Promise.resolve(); |
|
|
|
this.context.resume = this.context.resume || Promise.resolve; |
|
|
|
this.gainNode = this.context.createGain(); |
|
|
|
this.gainNode = this.context.createGain(); |
|
|
|
this.gainNode.connect(this.context.destination); |
|
|
|
this.gainNode.connect(this.context.destination); |
|
|
|
} catch(e) { |
|
|
|
} catch(e) { |
|
|
@ -77,28 +78,39 @@ SoundManager.prototype.init = function() { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
resolve(); |
|
|
|
resolve(); |
|
|
|
}).then(response => { |
|
|
|
}).then(() => { |
|
|
|
|
|
|
|
// check for .ogg support - if not, we'll have to load the ogg decoder
|
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
// See if our MP3 decoder is working
|
|
|
|
this.context.decodeAudioData(miniOgg, success => { |
|
|
|
let mp3Worker; |
|
|
|
this.oggSupport = true; |
|
|
|
|
|
|
|
resolve(); |
|
|
|
|
|
|
|
}, error => { |
|
|
|
|
|
|
|
this.oggSupport = false; |
|
|
|
|
|
|
|
resolve(); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}).then(() => { |
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
|
|
|
// See if our audio decoder is working
|
|
|
|
|
|
|
|
let audioWorker; |
|
|
|
try { |
|
|
|
try { |
|
|
|
mp3Worker = this.createWorker(); |
|
|
|
audioWorker = this.createWorker(); |
|
|
|
} catch(e) { |
|
|
|
} catch(e) { |
|
|
|
console.log(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 => { |
|
|
|
let pingListener = event => { |
|
|
|
mp3Worker.removeEventListener('message', pingListener); |
|
|
|
audioWorker.terminate(); |
|
|
|
mp3Worker.terminate(); |
|
|
|
|
|
|
|
resolve(); |
|
|
|
resolve(); |
|
|
|
}; |
|
|
|
}; |
|
|
|
mp3Worker.addEventListener('message', pingListener, false); |
|
|
|
audioWorker.addEventListener('message', pingListener, false); |
|
|
|
mp3Worker.addEventListener('error', () => { |
|
|
|
audioWorker.addEventListener('error', () => { |
|
|
|
reject(Error("MP3 Worker cannot be started - correct path set in defaults?")); |
|
|
|
reject(Error("Audio Worker cannot be started - correct path set in defaults?")); |
|
|
|
}, false); |
|
|
|
}, false); |
|
|
|
mp3Worker.postMessage({ping:true}); |
|
|
|
audioWorker.postMessage({ping:true, ogg:this.oggSupport}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}).then(response => { |
|
|
|
}).then(() => { |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
// iOS and other some mobile browsers - unlock the context as
|
|
|
|
// iOS and other some mobile browsers - unlock the context as
|
|
|
|
// it starts in a suspended state
|
|
|
|
// 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
|
|
|
|
// To prevent race condition if you press "next" twice fast
|
|
|
|
if(song != this.song) { |
|
|
|
if(song != this.song) { |
|
|
|
// Stop processing - silently ignored in the catch below
|
|
|
|
// 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; |
|
|
|
this.buildup = buffers.buildup; |
|
|
@ -179,10 +194,14 @@ SoundManager.prototype.playSong = function(song, playBuild, forcePlay) { |
|
|
|
}).then(() => { |
|
|
|
}).then(() => { |
|
|
|
this.playing = true; |
|
|
|
this.playing = true; |
|
|
|
}).catch(error => { |
|
|
|
}).catch(error => { |
|
|
|
// Just to ignore it if the song was invalid
|
|
|
|
if(error.name == "SoundManagerRace") { |
|
|
|
// Log it in case it's something weird
|
|
|
|
// Just to ignore it if the song was invalid
|
|
|
|
console.log(error); |
|
|
|
// Log it in case it's something weird
|
|
|
|
return; |
|
|
|
console.log("SoundManager couldn't play song", error); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
throw error; |
|
|
|
|
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
return p; |
|
|
|
return p; |
|
|
|
}; |
|
|
|
}; |
|
|
@ -313,27 +332,53 @@ SoundManager.prototype.loadSong = function(song) { |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
SoundManager.prototype.loadBuffer = function(song, soundName) { |
|
|
|
SoundManager.prototype.loadBuffer = function(song, soundName) { |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
let buffer = song[soundName]; |
|
|
|
let mp3Worker = this.createWorker(); |
|
|
|
|
|
|
|
|
|
|
|
// Is this an ogg file?
|
|
|
|
mp3Worker.addEventListener('error', () => { |
|
|
|
let view = new Uint8Array(buffer); |
|
|
|
reject(Error("MP3 Worker failed to convert track")); |
|
|
|
// Signature for ogg file: OggS
|
|
|
|
}, false); |
|
|
|
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
|
|
|
|
mp3Worker.addEventListener('message', e => { |
|
|
|
let backup = buffer.slice(0); |
|
|
|
let decoded = e.data; |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
mp3Worker.terminate(); |
|
|
|
this.context.decodeAudioData(buffer, result => { |
|
|
|
|
|
|
|
resolve(result); |
|
|
|
// restore transferred buffer
|
|
|
|
}, error => { |
|
|
|
song[soundName] = decoded.arrayBuffer; |
|
|
|
reject(Error("decodeAudioData failed to load track")); |
|
|
|
// Convert to real audio buffer
|
|
|
|
}); |
|
|
|
let audio = this.audioBufFromRaw(decoded.rawAudio); |
|
|
|
}).then(result => { |
|
|
|
resolve(audio); |
|
|
|
// restore copied buffer
|
|
|
|
}, false); |
|
|
|
song[soundName] = backup; |
|
|
|
|
|
|
|
return result; |
|
|
|
// transfer the buffer to save time
|
|
|
|
}); |
|
|
|
mp3Worker.postMessage(song[soundName], [song[soundName]]); |
|
|
|
} else { // Use our JS decoder
|
|
|
|
}); |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
|
|
|
|
let audioWorker = this.createWorker(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
// Converts continuous PCM array to Web Audio API friendly format
|
|
|
@ -342,20 +387,16 @@ SoundManager.prototype.audioBufFromRaw = function(raw) { |
|
|
|
let channels = raw.channels; |
|
|
|
let channels = raw.channels; |
|
|
|
let samples = buffer.length/channels; |
|
|
|
let samples = buffer.length/channels; |
|
|
|
let audioBuf = this.context.createBuffer(channels, samples, raw.sampleRate); |
|
|
|
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++) { |
|
|
|
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
|
|
|
|
// Offset is in bytes, length is in elements
|
|
|
|
let channel = new Float32Array(buffer.buffer , i * samples * 4, samples); |
|
|
|
let channel = new Float32Array(buffer.buffer , i * samples * 4, samples); |
|
|
|
//console.log(channel);
|
|
|
|
|
|
|
|
audioBuf.copyToChannel(channel, i, 0); |
|
|
|
audioBuf.copyToChannel(channel, i, 0); |
|
|
|
} |
|
|
|
} |
|
|
|
return audioBuf; |
|
|
|
return audioBuf; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
SoundManager.prototype.createWorker = function() { |
|
|
|
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) { |
|
|
|
SoundManager.prototype.initVisualiser = function(bars) { |
|
|
@ -516,6 +557,95 @@ SoundManager.prototype.fadeOut = function(callback) { |
|
|
|
setTimeout(callback, 2000); |
|
|
|
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.SoundManager = SoundManager; |
|
|
|
|
|
|
|
|
|
|
|
})(window, document); |
|
|
|
})(window, document); |