/* Smalltalk from Squeak4.5 with VMMaker 4.13.6 translated as JS source on 3 November 2014 1:52:20 pm */ /* Automatically generated by JSPluginCodeGenerator VMMakerJS-bf.15 uuid: fd4e10f2-3773-4e80-8bb5-c4b471a014e5 from ADPCMCodecPlugin VMMaker-bf.353 uuid: 8ae25e7e-8d2c-451e-8277-598b30e9c002 */ (function ADPCMCodecPlugin() { "use strict"; var VM_PROXY_MAJOR = 1; var VM_PROXY_MINOR = 11; /*** Functions ***/ function CLASSOF(obj) { return typeof obj === "number" ? interpreterProxy.classSmallInteger() : obj.sqClass } function SIZEOF(obj) { return obj.pointers ? obj.pointers.length : obj.words ? obj.words.length : obj.bytes ? obj.bytes.length : 0 } function BYTESIZEOF(obj) { return obj.bytes ? obj.bytes.length : obj.words ? obj.words.length * 4 : 0 } function DIV(a, b) { return Math.floor(a / b) | 0; } // integer division function MOD(a, b) { return a - DIV(a, b) * b | 0; } // signed modulus function SHL(a, b) { return b > 31 ? 0 : a << b; } // fix JS shift function SHR(a, b) { return b > 31 ? 0 : a >>> b; } // fix JS shift function SHIFT(a, b) { return b < 0 ? (b < -31 ? 0 : a >>> (0-b) ) : (b > 31 ? 0 : a << b); } /*** Variables ***/ var bitPosition = 0; var byteIndex = 0; var currentByte = 0; var encodedBytes = null; var interpreterProxy = null; var moduleName = "ADPCMCodecPlugin 3 November 2014 (e)"; var stepSizeTable = null; /* Note: This is coded so that plugins can be run from Squeak. */ function getInterpreter() { return interpreterProxy; } /* Note: This is hardcoded so it can be run from Squeak. The module name is used for validating a module *after* it is loaded to check if it does really contain the module we're thinking it contains. This is important! */ function getModuleName() { return moduleName; } function halt() { ; } /* Answer the best index to use for the difference between the given samples. */ /* Details: Scan stepSizeTable for the first entry >= the absolute value of the difference between sample values. Since indexes are zero-based, the index used during decoding will be the one in the following stepSizeTable entry. Since the index field of a Flash frame header is only six bits, the maximum index value is 63. */ /* Note: Since there does not appear to be any documentation of how Flash actually computes the indices used in its frame headers, this algorithm was guessed by reverse-engineering the Flash ADPCM decoder. */ function indexForDeltaFromto(thisSample, nextSample) { var bestIndex; var diff; var j; diff = nextSample - thisSample; if (diff < 0) { diff = 0 - diff; } bestIndex = 63; for (j = 1; j <= 62; j++) { if (bestIndex === 63) { if (stepSizeTable[j - 1] >= diff) { bestIndex = j; } } } return bestIndex; } function msg(s) { console.log(moduleName + ": " + s); } /* Answer the next n bits of my bit stream as an unsigned integer. */ function nextBits(n) { var remaining; var result; var shift; result = 0; remaining = n; while(true) { shift = remaining - bitPosition; if (shift > 0) { /* consumed currentByte buffer; fetch next byte */ result += SHL(currentByte, shift); remaining -= bitPosition; currentByte = encodedBytes[((++byteIndex)) - 1]; bitPosition = 8; } else { /* still some bits left in currentByte buffer */ result += SHR(currentByte, (0 - shift)); /* mask out the consumed bits: */ bitPosition -= remaining; currentByte = currentByte & (SHR(255, (8 - bitPosition))); return result; } } } /* Write the next n bits to my bit stream. */ function nextBitsput(n, anInteger) { var bitsAvailable; var buf; var bufBits; var shift; buf = anInteger; bufBits = n; while(true) { bitsAvailable = 8 - bitPosition; /* either left or right shift */ /* append high bits of buf to end of currentByte: */ shift = bitsAvailable - bufBits; if (shift < 0) { /* currentByte buffer filled; output it */ currentByte += SHR(buf, (0 - shift)); encodedBytes[((++byteIndex)) - 1] = currentByte; bitPosition = 0; /* clear saved high bits of buf: */ currentByte = 0; buf = buf & ((SHL(1, (0 - shift))) - 1); bufBits -= bitsAvailable; } else { /* still some bits available in currentByte buffer */ currentByte += SHL(buf, shift); bitPosition += bufBits; return self; } } } function primitiveDecodeMono() { var rcvr; var count; var bit; var delta; var i; var predictedDelta; var step; var bitsPerSample; var deltaSignMask; var deltaValueHighBit; var deltaValueMask; var frameSizeMask; var index; var indexTable; var predicted; var sampleIndex; var samples; rcvr = interpreterProxy.stackValue(1); count = interpreterProxy.stackIntegerValue(0); predicted = interpreterProxy.fetchIntegerofObject(0, rcvr); index = interpreterProxy.fetchIntegerofObject(1, rcvr); deltaSignMask = interpreterProxy.fetchIntegerofObject(2, rcvr); deltaValueMask = interpreterProxy.fetchIntegerofObject(3, rcvr); deltaValueHighBit = interpreterProxy.fetchIntegerofObject(4, rcvr); frameSizeMask = interpreterProxy.fetchIntegerofObject(5, rcvr); currentByte = interpreterProxy.fetchIntegerofObject(6, rcvr); bitPosition = interpreterProxy.fetchIntegerofObject(7, rcvr); byteIndex = interpreterProxy.fetchIntegerofObject(8, rcvr); encodedBytes = interpreterProxy.fetchBytesofObject(9, rcvr); samples = interpreterProxy.fetchInt16ArrayofObject(10, rcvr); sampleIndex = interpreterProxy.fetchIntegerofObject(12, rcvr); bitsPerSample = interpreterProxy.fetchIntegerofObject(13, rcvr); stepSizeTable = interpreterProxy.fetchInt16ArrayofObject(14, rcvr); indexTable = interpreterProxy.fetchInt16ArrayofObject(15, rcvr); if (interpreterProxy.failed()) { return null; } for (i = 1; i <= count; i++) { if ((i & frameSizeMask) === 1) { /* start of frame; read frame header */ predicted = nextBits(16); if (predicted > 32767) { predicted -= 65536; } index = nextBits(6); samples[((++sampleIndex)) - 1] = predicted; } else { delta = nextBits(bitsPerSample); step = stepSizeTable[index]; predictedDelta = 0; bit = deltaValueHighBit; while (bit > 0) { if ((delta & bit) > 0) { predictedDelta += step; } step = step >>> 1; bit = bit >>> 1; } predictedDelta += step; if ((delta & deltaSignMask) > 0) { predicted -= predictedDelta; } else { predicted += predictedDelta; } if (predicted > 32767) { predicted = 32767; } else { if (predicted < -32768) { predicted = -32768; } } index += indexTable[delta & deltaValueMask]; if (index < 0) { index = 0; } else { if (index > 88) { index = 88; } } samples[((++sampleIndex)) - 1] = predicted; } } if (interpreterProxy.failed()) { return null; } interpreterProxy.storeIntegerofObjectwithValue(0, rcvr, predicted); interpreterProxy.storeIntegerofObjectwithValue(1, rcvr, index); interpreterProxy.storeIntegerofObjectwithValue(6, rcvr, currentByte); interpreterProxy.storeIntegerofObjectwithValue(7, rcvr, bitPosition); interpreterProxy.storeIntegerofObjectwithValue(8, rcvr, byteIndex); interpreterProxy.storeIntegerofObjectwithValue(12, rcvr, sampleIndex); interpreterProxy.pop(1); } function primitiveDecodeStereo() { var rcvr; var count; var bit; var deltaLeft; var deltaRight; var i; var indexLeft; var indexRight; var predictedDeltaLeft; var predictedDeltaRight; var predictedLeft; var predictedRight; var stepLeft; var stepRight; var bitsPerSample; var deltaSignMask; var deltaValueHighBit; var deltaValueMask; var frameSizeMask; var index; var indexTable; var predicted; var rightSamples; var sampleIndex; var samples; /* make local copies of decoder state variables */ rcvr = interpreterProxy.stackValue(1); count = interpreterProxy.stackIntegerValue(0); predicted = interpreterProxy.fetchInt16ArrayofObject(0, rcvr); index = interpreterProxy.fetchInt16ArrayofObject(1, rcvr); deltaSignMask = interpreterProxy.fetchIntegerofObject(2, rcvr); deltaValueMask = interpreterProxy.fetchIntegerofObject(3, rcvr); deltaValueHighBit = interpreterProxy.fetchIntegerofObject(4, rcvr); frameSizeMask = interpreterProxy.fetchIntegerofObject(5, rcvr); currentByte = interpreterProxy.fetchIntegerofObject(6, rcvr); bitPosition = interpreterProxy.fetchIntegerofObject(7, rcvr); byteIndex = interpreterProxy.fetchIntegerofObject(8, rcvr); encodedBytes = interpreterProxy.fetchBytesofObject(9, rcvr); samples = interpreterProxy.fetchInt16ArrayofObject(10, rcvr); rightSamples = interpreterProxy.fetchInt16ArrayofObject(11, rcvr); sampleIndex = interpreterProxy.fetchIntegerofObject(12, rcvr); bitsPerSample = interpreterProxy.fetchIntegerofObject(13, rcvr); stepSizeTable = interpreterProxy.fetchInt16ArrayofObject(14, rcvr); indexTable = interpreterProxy.fetchInt16ArrayofObject(15, rcvr); if (interpreterProxy.failed()) { return null; } predictedLeft = predicted[1 - 1]; predictedRight = predicted[2 - 1]; indexLeft = index[1 - 1]; indexRight = index[2 - 1]; for (i = 1; i <= count; i++) { if ((i & frameSizeMask) === 1) { /* start of frame; read frame header */ predictedLeft = nextBits(16); indexLeft = nextBits(6); predictedRight = nextBits(16); indexRight = nextBits(6); if (predictedLeft > 32767) { predictedLeft -= 65536; } if (predictedRight > 32767) { predictedRight -= 65536; } samples[((++sampleIndex)) - 1] = predictedLeft; rightSamples[sampleIndex - 1] = predictedRight; } else { deltaLeft = nextBits(bitsPerSample); deltaRight = nextBits(bitsPerSample); stepLeft = stepSizeTable[indexLeft]; stepRight = stepSizeTable[indexRight]; predictedDeltaLeft = (predictedDeltaRight = 0); bit = deltaValueHighBit; while (bit > 0) { if ((deltaLeft & bit) > 0) { predictedDeltaLeft += stepLeft; } if ((deltaRight & bit) > 0) { predictedDeltaRight += stepRight; } stepLeft = stepLeft >>> 1; stepRight = stepRight >>> 1; bit = bit >>> 1; } predictedDeltaLeft += stepLeft; predictedDeltaRight += stepRight; if ((deltaLeft & deltaSignMask) > 0) { predictedLeft -= predictedDeltaLeft; } else { predictedLeft += predictedDeltaLeft; } if ((deltaRight & deltaSignMask) > 0) { predictedRight -= predictedDeltaRight; } else { predictedRight += predictedDeltaRight; } if (predictedLeft > 32767) { predictedLeft = 32767; } else { if (predictedLeft < -32768) { predictedLeft = -32768; } } if (predictedRight > 32767) { predictedRight = 32767; } else { if (predictedRight < -32768) { predictedRight = -32768; } } indexLeft += indexTable[deltaLeft & deltaValueMask]; if (indexLeft < 0) { indexLeft = 0; } else { if (indexLeft > 88) { indexLeft = 88; } } indexRight += indexTable[deltaRight & deltaValueMask]; if (indexRight < 0) { indexRight = 0; } else { if (indexRight > 88) { indexRight = 88; } } samples[((++sampleIndex)) - 1] = predictedLeft; rightSamples[sampleIndex - 1] = predictedRight; } } predicted[1 - 1] = predictedLeft; predicted[2 - 1] = predictedRight; index[1 - 1] = indexLeft; index[2 - 1] = indexRight; if (interpreterProxy.failed()) { return null; } interpreterProxy.storeIntegerofObjectwithValue(6, rcvr, currentByte); interpreterProxy.storeIntegerofObjectwithValue(7, rcvr, bitPosition); interpreterProxy.storeIntegerofObjectwithValue(8, rcvr, byteIndex); interpreterProxy.storeIntegerofObjectwithValue(12, rcvr, sampleIndex); interpreterProxy.pop(1); } function primitiveEncodeMono() { var rcvr; var count; var bit; var delta; var diff; var i; var p; var predictedDelta; var sign; var step; var bitsPerSample; var deltaSignMask; var deltaValueHighBit; var frameSizeMask; var index; var indexTable; var predicted; var sampleIndex; var samples; rcvr = interpreterProxy.stackValue(1); count = interpreterProxy.stackIntegerValue(0); predicted = interpreterProxy.fetchIntegerofObject(0, rcvr); index = interpreterProxy.fetchIntegerofObject(1, rcvr); deltaSignMask = interpreterProxy.fetchIntegerofObject(2, rcvr); deltaValueHighBit = interpreterProxy.fetchIntegerofObject(4, rcvr); frameSizeMask = interpreterProxy.fetchIntegerofObject(5, rcvr); currentByte = interpreterProxy.fetchIntegerofObject(6, rcvr); bitPosition = interpreterProxy.fetchIntegerofObject(7, rcvr); byteIndex = interpreterProxy.fetchIntegerofObject(8, rcvr); encodedBytes = interpreterProxy.fetchBytesofObject(9, rcvr); samples = interpreterProxy.fetchInt16ArrayofObject(10, rcvr); sampleIndex = interpreterProxy.fetchIntegerofObject(12, rcvr); bitsPerSample = interpreterProxy.fetchIntegerofObject(13, rcvr); stepSizeTable = interpreterProxy.fetchInt16ArrayofObject(14, rcvr); indexTable = interpreterProxy.fetchInt16ArrayofObject(15, rcvr); if (interpreterProxy.failed()) { return null; } step = stepSizeTable[1 - 1]; for (i = 1; i <= count; i++) { if ((i & frameSizeMask) === 1) { predicted = samples[((++sampleIndex)) - 1]; if (((p = predicted)) < 0) { p += 65536; } nextBitsput(16, p); if (i < count) { index = indexForDeltaFromto(predicted, samples[sampleIndex]); } nextBitsput(6, index); } else { /* compute sign and magnitude of difference from the predicted sample */ sign = 0; diff = samples[((++sampleIndex)) - 1] - predicted; if (diff < 0) { sign = deltaSignMask; diff = 0 - diff; } delta = 0; predictedDelta = 0; bit = deltaValueHighBit; while (bit > 0) { if (diff >= step) { delta += bit; predictedDelta += step; diff -= step; } step = step >>> 1; bit = bit >>> 1; } /* compute and clamp new prediction */ predictedDelta += step; if (sign > 0) { predicted -= predictedDelta; } else { predicted += predictedDelta; } if (predicted > 32767) { predicted = 32767; } else { if (predicted < -32768) { predicted = -32768; } } index += indexTable[delta]; if (index < 0) { index = 0; } else { if (index > 88) { index = 88; } } /* output encoded, signed delta */ step = stepSizeTable[index]; nextBitsput(bitsPerSample, sign | delta); } } if (bitPosition > 0) { /* flush the last output byte, if necessary */ encodedBytes[((++byteIndex)) - 1] = currentByte; } if (interpreterProxy.failed()) { return null; } interpreterProxy.storeIntegerofObjectwithValue(0, rcvr, predicted); interpreterProxy.storeIntegerofObjectwithValue(1, rcvr, index); interpreterProxy.storeIntegerofObjectwithValue(6, rcvr, currentByte); interpreterProxy.storeIntegerofObjectwithValue(7, rcvr, bitPosition); interpreterProxy.storeIntegerofObjectwithValue(8, rcvr, byteIndex); interpreterProxy.storeIntegerofObjectwithValue(12, rcvr, sampleIndex); interpreterProxy.pop(1); } /* not yet implemented */ function primitiveEncodeStereo() { var rcvr; var count; rcvr = interpreterProxy.stackValue(1); count = interpreterProxy.stackIntegerValue(0); currentByte = interpreterProxy.fetchIntegerofObject(6, rcvr); bitPosition = interpreterProxy.fetchIntegerofObject(7, rcvr); byteIndex = interpreterProxy.fetchIntegerofObject(8, rcvr); encodedBytes = interpreterProxy.fetchIntegerofObject(9, rcvr); stepSizeTable = interpreterProxy.fetchIntegerofObject(14, rcvr); if (interpreterProxy.failed()) { return null; } success(false); if (interpreterProxy.failed()) { return null; } interpreterProxy.storeIntegerofObjectwithValue(6, rcvr, currentByte); interpreterProxy.storeIntegerofObjectwithValue(7, rcvr, bitPosition); interpreterProxy.storeIntegerofObjectwithValue(8, rcvr, byteIndex); interpreterProxy.pop(1); } /* Note: This is coded so that is can be run from Squeak. */ function setInterpreter(anInterpreter) { var ok; interpreterProxy = anInterpreter; ok = interpreterProxy.majorVersion() == VM_PROXY_MAJOR; if (ok === false) { return false; } ok = interpreterProxy.minorVersion() >= VM_PROXY_MINOR; return ok; } function registerPlugin() { if (typeof Squeak === "object" && Squeak.registerExternalModule) { Squeak.registerExternalModule("ADPCMCodecPlugin", { primitiveDecodeStereo: primitiveDecodeStereo, primitiveEncodeStereo: primitiveEncodeStereo, setInterpreter: setInterpreter, primitiveEncodeMono: primitiveEncodeMono, primitiveDecodeMono: primitiveDecodeMono, getModuleName: getModuleName, }); } else self.setTimeout(registerPlugin, 100); } registerPlugin(); })(); // Register module/plugin