mirror of
https://github.com/Coloryr/AllMusic.git
synced 2026-11-13 01:57:38 +00:00
309 lines
12 KiB
Java
309 lines
12 KiB
Java
/*
|
|
* FLAC library (Java)
|
|
* Copyright (c) Project Nayuki
|
|
* https://www.nayuki.io/page/flac-library-java
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this program (see COPYING.txt and COPYING.LESSER.txt).
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package com.coloryr.allmusic.server.core.decoder.flac;
|
|
|
|
import java.io.EOFException;
|
|
import java.io.IOException;
|
|
import java.util.Arrays;
|
|
import java.util.Objects;
|
|
|
|
/**
|
|
* A basic implementation of most functionality required by FlacLowLevelInpuut.
|
|
*/
|
|
public abstract class AbstractFlacLowLevelInput implements FlacLowLevelInput {
|
|
|
|
/*---- Fields ----*/
|
|
|
|
private static final int RICE_DECODING_TABLE_BITS = 13; // Configurable, must be positive
|
|
private static final int RICE_DECODING_TABLE_MASK = (1 << RICE_DECODING_TABLE_BITS) - 1;
|
|
private static final byte[][] RICE_DECODING_CONSUMED_TABLES = new byte[31][1 << RICE_DECODING_TABLE_BITS];
|
|
private static final int[][] RICE_DECODING_VALUE_TABLES = new int[31][1 << RICE_DECODING_TABLE_BITS];
|
|
private static final int RICE_DECODING_CHUNK = 4; // Configurable, must be positive, and RICE_DECODING_CHUNK *
|
|
private static byte[] CRC8_TABLE = new byte[256];
|
|
private static char[] CRC16_TABLE = new char[256];
|
|
|
|
static {
|
|
for (int param = 0; param < RICE_DECODING_CONSUMED_TABLES.length; param++) {
|
|
byte[] consumed = RICE_DECODING_CONSUMED_TABLES[param];
|
|
int[] values = RICE_DECODING_VALUE_TABLES[param];
|
|
for (int i = 0; ; i++) {
|
|
int numBits = (i >>> param) + 1 + param;
|
|
if (numBits > RICE_DECODING_TABLE_BITS) break;
|
|
int bits = ((1 << param) | (i & ((1 << param) - 1)));
|
|
int shift = RICE_DECODING_TABLE_BITS - numBits;
|
|
for (int j = 0; j < (1 << shift); j++) {
|
|
consumed[(bits << shift) | j] = (byte) numBits;
|
|
values[(bits << shift) | j] = (i >>> 1) ^ -(i & 1);
|
|
}
|
|
}
|
|
if (consumed[0] != 0) throw new AssertionError();
|
|
}
|
|
}
|
|
|
|
static {
|
|
for (int i = 0; i < CRC8_TABLE.length; i++) {
|
|
int temp8 = i;
|
|
int temp16 = i << 8;
|
|
for (int j = 0; j < 8; j++) {
|
|
temp8 = (temp8 << 1) ^ ((temp8 >>> 7) * 0x107);
|
|
temp16 = (temp16 << 1) ^ ((temp16 >>> 15) * 0x18005);
|
|
}
|
|
CRC8_TABLE[i] = (byte) temp8;
|
|
CRC16_TABLE[i] = (char) temp16;
|
|
}
|
|
}
|
|
|
|
/*---- Constructors ----*/
|
|
|
|
// Data from the underlying stream is first stored into this byte buffer before further processing.
|
|
private long byteBufferStartPos;
|
|
|
|
/*---- Methods ----*/
|
|
|
|
/*-- Stream position --*/
|
|
private byte[] byteBuffer;
|
|
private int byteBufferLen;
|
|
private int byteBufferIndex;
|
|
// The buffer of next bits to return to a reader. Note that byteBufferIndex is incremented when byte
|
|
// values are put into the bit buffer, but they might not have been consumed by the ultimate reader yet.
|
|
private long bitBuffer; // Only the bottom bitBufferLen bits are valid; the top bits are garbage.
|
|
|
|
/*-- Reading bitwise integers --*/
|
|
private int bitBufferLen; // Always in the range [0, 64].
|
|
// Current state of the CRC calculations.
|
|
private int crc8; // Always a uint8 value.
|
|
private int crc16; // Always a uint16 value.
|
|
private int crcStartIndex; // In the range [0, byteBufferLen], unless byteBufferLen = -1.
|
|
|
|
/*-- Reading bytes --*/
|
|
|
|
public AbstractFlacLowLevelInput() {
|
|
byteBuffer = new byte[4096];
|
|
positionChanged(0);
|
|
}
|
|
|
|
public long getPosition() {
|
|
return byteBufferStartPos + byteBufferIndex - (bitBufferLen + 7) / 8;
|
|
}
|
|
|
|
public int getBitPosition() {
|
|
return (-bitBufferLen) & 7;
|
|
}
|
|
|
|
// When a subclass handles seekTo() and didn't throw UnsupportedOperationException,
|
|
// it must call this method to flush the buffers of upcoming data.
|
|
protected void positionChanged(long pos) {
|
|
byteBufferStartPos = pos;
|
|
Arrays.fill(byteBuffer, (byte) 0); // Defensive clearing, should have no visible effect outside of debugging
|
|
byteBufferLen = 0;
|
|
byteBufferIndex = 0;
|
|
bitBuffer = 0; // Defensive clearing, should have no visible effect outside of debugging
|
|
bitBufferLen = 0;
|
|
resetCrcs();
|
|
}
|
|
|
|
/*-- CRC calculations --*/
|
|
|
|
// Either returns silently or throws an exception.
|
|
private void checkByteAligned() {
|
|
if (bitBufferLen % 8 != 0) throw new IllegalStateException("Not at a byte boundary");
|
|
}
|
|
|
|
public int readUint(int n) throws IOException {
|
|
if (n < 0 || n > 32) throw new IllegalArgumentException();
|
|
while (bitBufferLen < n) {
|
|
int b = readUnderlying();
|
|
if (b == -1) throw new EOFException();
|
|
bitBuffer = (bitBuffer << 8) | b;
|
|
bitBufferLen += 8;
|
|
assert 0 <= bitBufferLen && bitBufferLen <= 64;
|
|
}
|
|
int result = (int) (bitBuffer >>> (bitBufferLen - n));
|
|
if (n != 32) {
|
|
result &= (1 << n) - 1;
|
|
assert (result >>> n) == 0;
|
|
}
|
|
bitBufferLen -= n;
|
|
assert 0 <= bitBufferLen && bitBufferLen <= 64;
|
|
return result;
|
|
}
|
|
|
|
public int readSignedInt(int n) throws IOException {
|
|
int shift = 32 - n;
|
|
return (readUint(n) << shift) >> shift;
|
|
}
|
|
|
|
public void readRiceSignedInts(int param, long[] result, int start, int end) throws IOException {
|
|
if (param < 0 || param > 31) throw new IllegalArgumentException();
|
|
long unaryLimit = 1L << (53 - param);
|
|
|
|
byte[] consumeTable = RICE_DECODING_CONSUMED_TABLES[param];
|
|
int[] valueTable = RICE_DECODING_VALUE_TABLES[param];
|
|
while (true) {
|
|
middle:
|
|
while (start <= end - RICE_DECODING_CHUNK) {
|
|
if (bitBufferLen < RICE_DECODING_CHUNK * RICE_DECODING_TABLE_BITS) {
|
|
if (byteBufferIndex <= byteBufferLen - 8) {
|
|
fillBitBuffer();
|
|
} else break;
|
|
}
|
|
for (int i = 0; i < RICE_DECODING_CHUNK; i++, start++) {
|
|
// Fast decoder
|
|
int extractedBits = (int) (bitBuffer >>> (bitBufferLen - RICE_DECODING_TABLE_BITS))
|
|
& RICE_DECODING_TABLE_MASK;
|
|
int consumed = consumeTable[extractedBits];
|
|
if (consumed == 0) break middle;
|
|
bitBufferLen -= consumed;
|
|
result[start] = valueTable[extractedBits];
|
|
}
|
|
}
|
|
|
|
// Slow decoder
|
|
if (start >= end) break;
|
|
long val = 0;
|
|
while (readUint(1) == 0) {
|
|
if (val >= unaryLimit) {
|
|
// At this point, the final decoded value would be so large that the result of the
|
|
// downstream restoreLpc() calculation would not fit in the output sample's bit depth -
|
|
// hence why we stop early and throw an exception. However, this check is conservative
|
|
// and doesn't catch all the cases where the post-LPC result wouldn't fit.
|
|
throw new DataFormatException("Residual value too large");
|
|
}
|
|
val++;
|
|
}
|
|
val = (val << param) | readUint(param); // Note: Long masking unnecessary because param <= 31
|
|
assert (val >>> 53) == 0; // Must fit a uint53 by design due to unaryLimit
|
|
val = (val >>> 1) ^ -(val & 1); // Transform uint53 to int53 according to Rice coding of signed numbers
|
|
assert (val >> 52) == 0 || (val >> 52) == -1; // Must fit a signed int53 by design
|
|
result[start] = val;
|
|
start++;
|
|
}
|
|
}
|
|
|
|
/*-- Miscellaneous --*/
|
|
|
|
// Appends at least 8 bits to the bit buffer, or throws EOFException.
|
|
private void fillBitBuffer() throws IOException {
|
|
int i = byteBufferIndex;
|
|
int n = Math.min((64 - bitBufferLen) >>> 3, byteBufferLen - i);
|
|
byte[] b = byteBuffer;
|
|
if (n > 0) {
|
|
for (int j = 0; j < n; j++, i++) bitBuffer = (bitBuffer << 8) | (b[i] & 0xFF);
|
|
bitBufferLen += n << 3;
|
|
} else if (bitBufferLen <= 56) {
|
|
int temp = readUnderlying();
|
|
if (temp == -1) throw new EOFException();
|
|
bitBuffer = (bitBuffer << 8) | temp;
|
|
bitBufferLen += 8;
|
|
}
|
|
assert 8 <= bitBufferLen && bitBufferLen <= 64;
|
|
byteBufferIndex += n;
|
|
}
|
|
|
|
/*---- Tables of constants ----*/
|
|
|
|
// For Rice decoding
|
|
|
|
public int readByte() throws IOException {
|
|
checkByteAligned();
|
|
if (bitBufferLen >= 8) return readUint(8);
|
|
else {
|
|
assert bitBufferLen == 0;
|
|
return readUnderlying();
|
|
}
|
|
}
|
|
|
|
public void readFully(byte[] b) throws IOException {
|
|
Objects.requireNonNull(b);
|
|
checkByteAligned();
|
|
for (int i = 0; i < b.length; i++) b[i] = (byte) readUint(8);
|
|
}
|
|
|
|
// Reads a byte from the byte buffer (if available) or from the underlying stream, returning either a uint8 or -1.
|
|
private int readUnderlying() throws IOException {
|
|
if (byteBufferIndex >= byteBufferLen) {
|
|
if (byteBufferLen == -1) return -1;
|
|
byteBufferStartPos += byteBufferLen;
|
|
updateCrcs(0);
|
|
byteBufferLen = readUnderlying(byteBuffer, 0, byteBuffer.length);
|
|
crcStartIndex = 0;
|
|
if (byteBufferLen <= 0) return -1;
|
|
byteBufferIndex = 0;
|
|
}
|
|
assert byteBufferIndex < byteBufferLen;
|
|
int temp = byteBuffer[byteBufferIndex] & 0xFF;
|
|
byteBufferIndex++;
|
|
return temp;
|
|
}
|
|
|
|
// Reads up to 'len' bytes from the underlying byte-based input stream into the given array subrange.
|
|
// Returns a value in the range [0, len] for a successful read, or -1 if the end of stream was reached.
|
|
protected abstract int readUnderlying(byte[] buf, int off, int len) throws IOException;
|
|
|
|
public void resetCrcs() {
|
|
checkByteAligned();
|
|
crcStartIndex = byteBufferIndex - bitBufferLen / 8;
|
|
crc8 = 0;
|
|
crc16 = 0;
|
|
}
|
|
// RICE_DECODING_TABLE_BITS <= 64
|
|
|
|
public int getCrc8() {
|
|
checkByteAligned();
|
|
updateCrcs(bitBufferLen / 8);
|
|
if ((crc8 >>> 8) != 0) throw new AssertionError();
|
|
return crc8;
|
|
}
|
|
|
|
// For CRC calculations
|
|
|
|
public int getCrc16() {
|
|
checkByteAligned();
|
|
updateCrcs(bitBufferLen / 8);
|
|
if ((crc16 >>> 16) != 0) throw new AssertionError();
|
|
return crc16;
|
|
}
|
|
|
|
// Updates the two CRC values with data in byteBuffer[crcStartIndex : byteBufferIndex - unusedTrailingBytes].
|
|
private void updateCrcs(int unusedTrailingBytes) {
|
|
int end = byteBufferIndex - unusedTrailingBytes;
|
|
for (int i = crcStartIndex; i < end; i++) {
|
|
int b = byteBuffer[i] & 0xFF;
|
|
crc8 = CRC8_TABLE[crc8 ^ b] & 0xFF;
|
|
crc16 = CRC16_TABLE[(crc16 >>> 8) ^ b] ^ ((crc16 & 0xFF) << 8);
|
|
assert (crc8 >>> 8) == 0;
|
|
assert (crc16 >>> 16) == 0;
|
|
}
|
|
crcStartIndex = end;
|
|
}
|
|
|
|
// Note: This class only uses memory and has no native resources. It's not strictly necessary to
|
|
// call the implementation of AbstractFlacLowLevelInput.close() here, but it's a good habit anyway.
|
|
public void close() throws IOException {
|
|
byteBuffer = null;
|
|
byteBufferLen = -1;
|
|
byteBufferIndex = -1;
|
|
bitBuffer = 0;
|
|
bitBufferLen = -1;
|
|
crc8 = -1;
|
|
crc16 = -1;
|
|
crcStartIndex = -1;
|
|
}
|
|
|
|
}
|