/* ADPCMSoundLoader loads wav files that have been compressed with the ADPCM format based on code from Scratch-Flash: https://github.com/LLK/scratch-flash/blob/master/src/sound/WAVFile.as */ var ArrayBufferStream = require('./ArrayBufferStream'); var Tone = require('tone'); var log = require('./log'); function ADPCMSoundLoader (url) { var request = new XMLHttpRequest(); request.open('GET', url, true); request.responseType = 'arraybuffer'; request.onload = function () { var audioData = request.response; var stream = new ArrayBufferStream(audioData); var riffStr = stream.readUint8String(4); if (riffStr != 'RIFF') { log.warn('incorrect adpcm wav header'); } var lengthInHeader = stream.readInt32(); if ((lengthInHeader + 8) != audioData.byteLength) { log.warn('adpcm wav length in header: ' + length + 'is incorrect'); } var wavStr = stream.readUint8String(4); if (wavStr != 'WAVE') { log.warn('incorrect adpcm wav header'); } var formatChunk = this.extractChunk('fmt ', stream); this.encoding = formatChunk.readUint16(); this.channels = formatChunk.readUint16(); this.samplesPerSecond = formatChunk.readUint32(); this.bytesPerSecond = formatChunk.readUint32(); this.blockAlignment = formatChunk.readUint16(); this.bitsPerSample = formatChunk.readUint16(); formatChunk.position += 2; // skip extra header byte count this.samplesPerBlock = formatChunk.readUint16(); this.adpcmBlockSize = ((this.samplesPerBlock - 1) / 2) + 4; // block size in bytes var samples = this.imaDecompress(this.extractChunk('data', stream), this.adpcmBlockSize); var buffer = Tone.context.createBuffer(1, samples.length, this.samplesPerSecond); // todo: optimize this? for (var i=0; i 88) index = 88; out.push(sample); } else { // read 4-bit code and compute delta from previous sample if (lastByte < 0) { if (compressedData.getBytesAvailable() == 0) break; lastByte = compressedData.readUint8(); code = lastByte & 0xF; } else { code = (lastByte >> 4) & 0xF; lastByte = -1; } step = this.stepTable[index]; delta = 0; if (code & 4) delta += step; if (code & 2) delta += step >> 1; if (code & 1) delta += step >> 2; delta += step >> 3; // compute next index index += this.indexTable[code]; if (index > 88) index = 88; if (index < 0) index = 0; // compute and output sample sample += (code & 8) ? -delta : delta; if (sample > 32767) sample = 32767; if (sample < -32768) sample = -32768; out.push(sample); } } var samples = Int16Array.from(out); return samples; }; module.exports = ADPCMSoundLoader;