Spaces:
Running
Running
/* 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() { | |
; | |
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 | |