49 lines
2.1 KiB
TypeScript
49 lines
2.1 KiB
TypeScript
// Ref: https://github.com/telegramdesktop/tdesktop/blob/0743e71ab6b928d2ee5bae1aed991849b1e2b291/Telegram/SourceFiles/data/data_document.cpp#L1018
|
|
export function decodeWaveform(encoded5bit: Uint8Array) {
|
|
const bitsCount = encoded5bit.length * 8;
|
|
const valuesCount = Math.floor(bitsCount / 5);
|
|
if (!valuesCount) {
|
|
return [];
|
|
}
|
|
|
|
// Read each 5 bit of encoded5bit as 0-31 unsigned char.
|
|
// We count the index of the byte in which the desired 5-bit sequence starts.
|
|
// And then we read a uint16 starting from that byte to guarantee to get all of those 5 bits.
|
|
//
|
|
// BUT! if it is the last byte we have, we're not allowed to read a uint16 starting with it.
|
|
// Because it will be an overflow (we'll access one byte after the available memory).
|
|
// We see, that only the last 5 bits could start in the last available byte and be problematic.
|
|
// So we read in a general way all the entries in a general way except the last one.
|
|
const result = Array(valuesCount);
|
|
const bitsData = encoded5bit;
|
|
for (let i = 0, l = valuesCount - 1; i !== l; ++i) {
|
|
const byteIndex = Math.floor((i * 5) / 8);
|
|
const bitShift = Math.floor((i * 5) % 8);
|
|
const value = bitsData[byteIndex] + (bitsData[byteIndex + 1] << 8);
|
|
result[i] = ((value >> bitShift) & 0x1F);
|
|
}
|
|
const lastByteIndex = Math.floor(((valuesCount - 1) * 5) / 8);
|
|
const lastBitShift = Math.floor(((valuesCount - 1) * 5) % 8);
|
|
const lastValue = bitsData[lastByteIndex] + (bitsData[lastByteIndex + 1] << 8);
|
|
result[valuesCount - 1] = (lastValue >> lastBitShift) & 0x1F;
|
|
|
|
return result;
|
|
}
|
|
|
|
export function interpolateArray(data: number[], fitCount: number) {
|
|
let peak = 0;
|
|
const newData = new Array(fitCount);
|
|
const springFactor = data.length / fitCount;
|
|
const leftFiller = data[0];
|
|
const rightFiller = data[data.length - 1];
|
|
for (let i = 0; i < fitCount; i++) {
|
|
const idx = Math.floor(i * springFactor);
|
|
const val = ((data[idx - 1] ?? leftFiller) + (data[idx] ?? leftFiller) + (data[idx + 1] ?? rightFiller)) / 3;
|
|
newData[i] = val;
|
|
if (peak < val) {
|
|
peak = val;
|
|
}
|
|
}
|
|
return { data: newData, peak };
|
|
}
|