UNPKG

echogarden

Version:

An easy-to-use speech toolset. Includes tools for synthesis, recognition, alignment, speech translation, language detection, source separation and more.

248 lines 10.2 kB
import { createDynamicUint8Array } from "../data-structures/DynamicTypedArray.js"; import { logToStderr } from "../utilities/Utilities.js"; //////////////////////////////////////////////////////////////////////////////////////////////////// // Encode unsigned integer //////////////////////////////////////////////////////////////////////////////////////////////////// export function encodeUnsignedInt(value, outEncodedData) { if (value < 0) { throw new Error(`The negative value ${value} can't be encoded as an unsigned LEB128 integer.`); } if (typeof value === 'number') { if (value < (2 ** 31)) { return encodeUnsignedInt31(value, outEncodedData); } else { return encodeUnsignedBigInt(BigInt(value), outEncodedData); } } else { return encodeUnsignedBigInt(value, outEncodedData); } } function encodeUnsignedInt31(value, outEncodedData) { value = value >>> 0; if (value < (2 ** 7)) { outEncodedData.add(value); } else if (value < (2 ** 14)) { outEncodedData.addMany((value & 0b01111111) | 0b10000000, value >>> 7); } else if (value < (2 ** 21)) { outEncodedData.addMany((value & 0b01111111) | 0b10000000, ((value >>> 7) & 0b01111111) | 0b10000000, value >>> 14); } else if (value < (2 ** 28)) { outEncodedData.addMany((value & 0b01111111) | 0b10000000, ((value >>> 7) & 0b01111111) | 0b10000000, ((value >>> 14) & 0b01111111) | 0b10000000, value >>> 21); } else { outEncodedData.addMany((value & 0b01111111) | 0b10000000, ((value >>> 7) & 0b01111111) | 0b10000000, ((value >>> 14) & 0b01111111) | 0b10000000, ((value >>> 21) & 0b01111111) | 0b10000000, value >>> 28); } return outEncodedData; } function encodeUnsignedBigInt(value, outEncodedData) { while (true) { const lowest7Bits = Number(value & 127n); value = value >> 7n; if (value === 0n) { outEncodedData.add(lowest7Bits); return outEncodedData; } else { outEncodedData.add(lowest7Bits | 0b10000000); } } } //////////////////////////////////////////////////////////////////////////////////// // Decode unsigned integer //////////////////////////////////////////////////////////////////////////////////// export function decodeUnsignedInt31Fast(encodedData, readOffset) { const byte0 = encodedData[readOffset++]; if ((byte0 & 0b10000000) === 0) { const decodedValue = byte0; return { decodedValue, readOffset }; } const byte1 = encodedData[readOffset++]; if ((byte1 & 0b10000000) === 0) { const decodedValue = (byte0 & 0b01111111) | (byte1 & 0b01111111) << 7; return { decodedValue, readOffset }; } const byte2 = encodedData[readOffset++]; if ((byte2 & 0b10000000) === 0) { const decodedValue = (byte0 & 0b01111111) | (byte1 & 0b01111111) << 7 | (byte2 & 0b01111111) << 14; return { decodedValue, readOffset }; } const byte3 = encodedData[readOffset++]; if ((byte3 & 0b10000000) === 0) { const decodedValue = (byte0 & 0b01111111) | (byte1 & 0b01111111) << 7 | (byte2 & 0b01111111) << 14 | (byte3 & 0b01111111) << 21; return { decodedValue, readOffset }; } const byte4 = encodedData[readOffset++]; if ((byte4 & 0b10000000) === 0) { const decodedValue = (byte0 & 0b01111111) | (byte1 & 0b01111111) << 7 | (byte2 & 0b01111111) << 14 | (byte3 & 0b01111111) << 21 | (byte4 & 0b01111111) << 28; return { decodedValue, readOffset }; } if (readOffset >= encodedData.length) { throw new Error(`Invalid LEB128 data. Last encoded byte sequence is truncated.`); } else { throw new Error(`LEB128 sequence can't be decoded. Encoded byte sequence represents a value that extends beyond the range of a unsigned 32 bit integer.`); } } //////////////////////////////////////////////////////////////////////////////////// // Encode signed integer //////////////////////////////////////////////////////////////////////////////////// export function encodeSignedInt32(value, outEncodedData) { if (value < -(2 ** 31) || value > (2 ** 31)) { throw new Error('Value must be between -(2^31) and 2^31 - 1'); } while (true) { const lowest7Bits = value & 0b01111111; value >>= 7; if ((value === 0 && (lowest7Bits & 0b01000000) === 0) || (value === -1 && (lowest7Bits & 0b01000000) !== 0)) { outEncodedData.add(lowest7Bits); return outEncodedData; } else { outEncodedData.add(lowest7Bits | 0b10000000); } } } export function encodeSignedInt32Fast(value, outEncodedData) { const absValue = Math.abs(value | 0); if (absValue < (2 ** 6)) { outEncodedData.add((value & 0b01111111)); } else if (absValue < (2 ** 13)) { outEncodedData.addMany((value & 0b01111111) | 0b10000000, (value >> 7) & 0b01111111); } else if (absValue < (2 ** 20)) { outEncodedData.addMany((value & 0b01111111) | 0b10000000, ((value >> 7) & 0b01111111) | 0b10000000, (value >> 14) & 0b01111111); } else if (absValue < (2 ** 27)) { outEncodedData.addMany((value & 0b01111111) | 0b10000000, ((value >> 7) & 0b01111111) | 0b10000000, ((value >> 14) & 0b01111111) | 0b10000000, (value >> 21) & 0b01111111); } else { outEncodedData.addMany((value & 0b01111111) | 0b10000000, ((value >> 7) & 0b01111111) | 0b10000000, ((value >> 14) & 0b01111111) | 0b10000000, ((value >> 21) & 0b01111111) | 0b10000000, (value >> 28) & 0b01111111); } return outEncodedData; } //////////////////////////////////////////////////////////////////////////////////// // Decode signed integer //////////////////////////////////////////////////////////////////////////////////// export function decodeSignedInt32(encodedData, readOffset) { let decodedValue = 0; let shiftAmount = 0; while (true) { const encodedByte = encodedData[readOffset++]; const lowest7Bits = encodedByte & 0b01111111; decodedValue |= lowest7Bits << shiftAmount; // If 8th bit is 0, then this is the last byte in the sequence if ((encodedByte & 0b10000000) === 0) { // If 7th bit is 1, then the value is negative if ((encodedByte & 0b01000000) !== 0) { // If the value should be negative // Ensure that the value is encoded as a negative number by // setting all higher bits to 1 decodedValue |= -1 << Math.min(shiftAmount + 7, 31); } return { decodedValue, readOffset }; } if (readOffset === encodedData.length) { throw new Error(`Invalid LEB128 data. Last encoded byte sequence is truncated.`); } shiftAmount += 7; if (shiftAmount > 31) { throw new Error(`LEB128 sequence can't be decoded. Byte sequence extends beyond the range of a signed 32 bit integer.`); } } } export function decodeSignedInt32Fast(encodedData, readOffset) { const byte0 = encodedData[readOffset++]; if ((byte0 & 0b10000000) === 0) { let decodedValue = byte0; if ((byte0 & 0b01000000) !== 0) { decodedValue |= -1 << 7; } return { decodedValue, readOffset }; } const byte1 = encodedData[readOffset++]; if ((byte1 & 0b10000000) === 0) { let decodedValue = (byte0 & 0b01111111) | (byte1 & 0b01111111) << 7; if ((byte1 & 0b01000000) !== 0) { decodedValue |= -1 << 14; } return { decodedValue, readOffset }; } const byte2 = encodedData[readOffset++]; if ((byte2 & 0b10000000) === 0) { let decodedValue = (byte0 & 0b01111111) | (byte1 & 0b01111111) << 7 | (byte2 & 0b01111111) << 14; if ((byte2 & 0b01000000) !== 0) { decodedValue |= -1 << 21; } return { decodedValue, readOffset }; } const byte3 = encodedData[readOffset++]; if ((byte3 & 0b10000000) === 0) { let decodedValue = (byte0 & 0b01111111) | (byte1 & 0b01111111) << 7 | (byte2 & 0b01111111) << 14 | (byte3 & 0b01111111) << 21; if ((byte3 & 0b01000000) !== 0) { decodedValue |= -1 << 28; } return { decodedValue, readOffset }; } const byte4 = encodedData[readOffset++]; if ((byte4 & 0b10000000) === 0) { let decodedValue = (byte0 & 0b01111111) | (byte1 & 0b01111111) << 7 | (byte2 & 0b01111111) << 14 | (byte3 & 0b01111111) << 21 | (byte4 & 0b01111111) << 28; if ((byte4 & 0b01000000) !== 0) { decodedValue |= -1 << 31; } return { decodedValue, readOffset }; } if (readOffset >= encodedData.length) { throw new Error(`Invalid LEB128 data. Last encoded byte sequence is truncated.`); } else { throw new Error(`LEB128 sequence can't be decoded. Encoded byte sequence represents a value that extends beyond the range of a signed 32 bit integer.`); } } //////////////////////////////////////////////////////////////////////////////////// // Tests //////////////////////////////////////////////////////////////////////////////////// export function testLeb128Signed() { const encodedBytes = createDynamicUint8Array(); function runTest(testValue) { encodedBytes.clear(); encodeSignedInt32Fast(testValue, encodedBytes); const { decodedValue } = decodeSignedInt32Fast(encodedBytes.elements, 0); if (decodedValue !== testValue) { throw new Error(`Expected ${testValue} but got ${decodedValue}`); } } for (let i = -(2 ** 26); i < 2 ** 26; i++) { if (i % 1000000 === 0) { logToStderr(i); } runTest(i); } const x = 1; } //# sourceMappingURL=LEB128.js.map