scratch-sb1-converter
Version:
Scratch 1 (.sb) to Scratch 2 (.sb2) conversion library for Scratch 3.0
115 lines (91 loc) • 3.65 kB
JavaScript
import {assert} from '../util/assert';
import {Uint8} from './byte-primitives';
import {ByteStream} from './byte-stream';
const SQUEAK_SOUND_STEP_SIZE_TABLE = [
7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41,
45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209,
230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876,
963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749,
3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630,
9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623,
27086, 29794, 32767
];
const SQUEAK_SOUND_INDEX_TABLES = {
2: [-1, 2, -1, 2],
3: [-1, -1, 2, 4, -1, -1, 2, 4],
4: [-1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8],
5: [
-1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16,
-1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16
]
};
class SqueakSound {
constructor (bitsPerSample) {
this.bitsPerSample = bitsPerSample;
this.indexTable = SQUEAK_SOUND_INDEX_TABLES[bitsPerSample];
this.signMask = 1 << (bitsPerSample - 1);
this.valueMask = this.signMask - 1;
this.valueHighBit = this.signMask >> 1;
this.bitPosition = 0;
this.currentByte = 0;
this.stream = null;
this.end = 0;
}
decode (data) {
// Reset position information.
this.bitPosition = 0;
this.currentByte = 0;
this.stream = new ByteStream(data.buffer, data.byteOffset);
this.end = data.byteOffset + data.length;
const size = Math.floor(data.length * 8 / this.bitsPerSample);
const result = new Int16Array(size);
let sample = 0;
let index = 0;
for (let i = 0; i < size; i++) {
const code = this.nextCode();
assert(code >= 0, 'Ran out of bits in Squeak Sound');
let step = SQUEAK_SOUND_STEP_SIZE_TABLE[index];
let delta = 0;
for (let bit = this.valueHighBit; bit > 0; bit = bit >> 1) {
if ((code & bit) !== 0) {
delta += step;
}
step = step >> 1;
}
delta += step;
sample += ((code & this.signMask) === 0) ? delta : -delta;
index += this.indexTable[code];
if (index < 0) index = 0;
if (index > 88) index = 88;
if (sample > 32767) sample = 32767;
if (sample < -32768) sample = -32768;
result[i] = sample;
}
return result;
}
nextCode () {
let remaining = this.bitsPerSample;
let shift = remaining - this.bitPosition;
let result = (shift < 0) ? (this.currentByte >> -shift) : (this.currentByte << shift);
while (shift > 0) {
remaining -= this.bitPosition;
if (this.end - this.stream.position > 0) {
this.currentByte = this.stream.read(Uint8);
this.bitPosition = 8;
} else {
this.currentByte = 0;
this.bitPosition = 0;
return -1;
}
shift = remaining - this.bitPosition;
result += (shift < 0) ? (this.currentByte >> -shift) : (this.currentByte << shift);
}
this.bitPosition -= remaining;
this.currentByte = this.currentByte & (0xff >> (8 - this.bitPosition));
return result;
}
static samples (bitsPerSample, data) {
return data.length * 8 / bitsPerSample;
}
}
export {SqueakSound};