221 lines
8.4 KiB
Java
221 lines
8.4 KiB
Java
package com.mojang.blaze3d.audio;
|
|
|
|
import java.util.function.Consumer;
|
|
import net.minecraft.util.Mth;
|
|
import org.lwjgl.BufferUtils;
|
|
import com.google.common.collect.Lists;
|
|
import java.util.List;
|
|
import java.nio.FloatBuffer;
|
|
import org.lwjgl.PointerBuffer;
|
|
import java.nio.Buffer;
|
|
import java.nio.IntBuffer;
|
|
import org.lwjgl.stb.STBVorbisInfo;
|
|
import org.lwjgl.stb.STBVorbisAlloc;
|
|
import org.lwjgl.stb.STBVorbis;
|
|
import java.io.IOException;
|
|
import org.lwjgl.system.MemoryStack;
|
|
import org.lwjgl.system.MemoryUtil;
|
|
import java.nio.ByteBuffer;
|
|
import java.io.InputStream;
|
|
import javax.sound.sampled.AudioFormat;
|
|
import net.minecraft.client.sounds.AudioStream;
|
|
|
|
public class OggAudioStream implements AudioStream {
|
|
private long handle;
|
|
private final AudioFormat audioFormat;
|
|
private final InputStream input;
|
|
private ByteBuffer buffer;
|
|
|
|
public OggAudioStream(final InputStream inputStream) throws IOException {
|
|
this.buffer = MemoryUtil.memAlloc(8192);
|
|
this.input = inputStream;
|
|
this.buffer.limit(0);
|
|
try (final MemoryStack memoryStack3 = MemoryStack.stackPush()) {
|
|
final IntBuffer intBuffer5 = memoryStack3.mallocInt(1);
|
|
final IntBuffer intBuffer6 = memoryStack3.mallocInt(1);
|
|
while (this.handle == 0L) {
|
|
if (!this.refillFromStream()) {
|
|
throw new IOException("Failed to find Ogg header");
|
|
}
|
|
final int integer7 = this.buffer.position();
|
|
this.buffer.position(0);
|
|
this.handle = STBVorbis.stb_vorbis_open_pushdata(this.buffer, intBuffer5, intBuffer6, (STBVorbisAlloc)null);
|
|
this.buffer.position(integer7);
|
|
final int integer8 = intBuffer6.get(0);
|
|
if (integer8 == 1) {
|
|
this.forwardBuffer();
|
|
}
|
|
else {
|
|
if (integer8 != 0) {
|
|
throw new IOException("Failed to read Ogg file " + integer8);
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
this.buffer.position(this.buffer.position() + intBuffer5.get(0));
|
|
final STBVorbisInfo sTBVorbisInfo7 = STBVorbisInfo.mallocStack(memoryStack3);
|
|
STBVorbis.stb_vorbis_get_info(this.handle, sTBVorbisInfo7);
|
|
this.audioFormat = new AudioFormat((float)sTBVorbisInfo7.sample_rate(), 16, sTBVorbisInfo7.channels(), true, false);
|
|
}
|
|
}
|
|
|
|
private boolean refillFromStream() throws IOException {
|
|
final int integer2 = this.buffer.limit();
|
|
final int integer3 = this.buffer.capacity() - integer2;
|
|
if (integer3 == 0) {
|
|
return true;
|
|
}
|
|
final byte[] arr4 = new byte[integer3];
|
|
final int integer4 = this.input.read(arr4);
|
|
if (integer4 == -1) {
|
|
return false;
|
|
}
|
|
final int integer5 = this.buffer.position();
|
|
this.buffer.limit(integer2 + integer4);
|
|
this.buffer.position(integer2);
|
|
this.buffer.put(arr4, 0, integer4);
|
|
this.buffer.position(integer5);
|
|
return true;
|
|
}
|
|
|
|
private void forwardBuffer() {
|
|
final boolean boolean2 = this.buffer.position() == 0;
|
|
final boolean boolean3 = this.buffer.position() == this.buffer.limit();
|
|
if (boolean3 && !boolean2) {
|
|
this.buffer.position(0);
|
|
this.buffer.limit(0);
|
|
}
|
|
else {
|
|
final ByteBuffer byteBuffer4 = MemoryUtil.memAlloc(boolean2 ? (2 * this.buffer.capacity()) : this.buffer.capacity());
|
|
byteBuffer4.put(this.buffer);
|
|
MemoryUtil.memFree((Buffer)this.buffer);
|
|
byteBuffer4.flip();
|
|
this.buffer = byteBuffer4;
|
|
}
|
|
}
|
|
|
|
private boolean readFrame(final OutputConcat a) throws IOException {
|
|
if (this.handle == 0L) {
|
|
return false;
|
|
}
|
|
try (final MemoryStack memoryStack3 = MemoryStack.stackPush()) {
|
|
final PointerBuffer pointerBuffer5 = memoryStack3.mallocPointer(1);
|
|
final IntBuffer intBuffer6 = memoryStack3.mallocInt(1);
|
|
final IntBuffer intBuffer7 = memoryStack3.mallocInt(1);
|
|
while (true) {
|
|
final int integer8 = STBVorbis.stb_vorbis_decode_frame_pushdata(this.handle, this.buffer, intBuffer6, pointerBuffer5, intBuffer7);
|
|
this.buffer.position(this.buffer.position() + integer8);
|
|
final int integer9 = STBVorbis.stb_vorbis_get_error(this.handle);
|
|
if (integer9 == 1) {
|
|
this.forwardBuffer();
|
|
if (!this.refillFromStream()) {
|
|
return false;
|
|
}
|
|
continue;
|
|
}
|
|
else {
|
|
if (integer9 != 0) {
|
|
throw new IOException("Failed to read Ogg file " + integer9);
|
|
}
|
|
final int integer10 = intBuffer7.get(0);
|
|
if (integer10 == 0) {
|
|
continue;
|
|
}
|
|
final int integer11 = intBuffer6.get(0);
|
|
final PointerBuffer pointerBuffer6 = pointerBuffer5.getPointerBuffer(integer11);
|
|
if (integer11 == 1) {
|
|
this.convertMono(pointerBuffer6.getFloatBuffer(0, integer10), a);
|
|
return true;
|
|
}
|
|
if (integer11 == 2) {
|
|
this.convertStereo(pointerBuffer6.getFloatBuffer(0, integer10), pointerBuffer6.getFloatBuffer(1, integer10), a);
|
|
return true;
|
|
}
|
|
throw new IllegalStateException("Invalid number of channels: " + integer11);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void convertMono(final FloatBuffer floatBuffer, final OutputConcat a) {
|
|
while (floatBuffer.hasRemaining()) {
|
|
a.put(floatBuffer.get());
|
|
}
|
|
}
|
|
|
|
private void convertStereo(final FloatBuffer floatBuffer1, final FloatBuffer floatBuffer2, final OutputConcat a) {
|
|
while (floatBuffer1.hasRemaining() && floatBuffer2.hasRemaining()) {
|
|
a.put(floatBuffer1.get());
|
|
a.put(floatBuffer2.get());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void close() throws IOException {
|
|
if (this.handle != 0L) {
|
|
STBVorbis.stb_vorbis_close(this.handle);
|
|
this.handle = 0L;
|
|
}
|
|
MemoryUtil.memFree((Buffer)this.buffer);
|
|
this.input.close();
|
|
}
|
|
|
|
@Override
|
|
public AudioFormat getFormat() {
|
|
return this.audioFormat;
|
|
}
|
|
|
|
@Override
|
|
public ByteBuffer read(final int integer) throws IOException {
|
|
final OutputConcat a3 = new OutputConcat(integer + 8192);
|
|
while (this.readFrame(a3) && a3.byteCount < integer) {}
|
|
return a3.get();
|
|
}
|
|
|
|
public ByteBuffer readAll() throws IOException {
|
|
final OutputConcat a2 = new OutputConcat(16384);
|
|
while (this.readFrame(a2)) {}
|
|
return a2.get();
|
|
}
|
|
|
|
static class OutputConcat {
|
|
private final List<ByteBuffer> buffers;
|
|
private final int bufferSize;
|
|
private int byteCount;
|
|
private ByteBuffer currentBuffer;
|
|
|
|
public OutputConcat(final int integer) {
|
|
this.buffers = Lists.newArrayList();
|
|
this.bufferSize = (integer + 1 & 0xFFFFFFFE);
|
|
this.createNewBuffer();
|
|
}
|
|
|
|
private void createNewBuffer() {
|
|
this.currentBuffer = BufferUtils.createByteBuffer(this.bufferSize);
|
|
}
|
|
|
|
public void put(final float float1) {
|
|
if (this.currentBuffer.remaining() == 0) {
|
|
this.currentBuffer.flip();
|
|
this.buffers.add(this.currentBuffer);
|
|
this.createNewBuffer();
|
|
}
|
|
final int integer3 = Mth.clamp((int)(float1 * 32767.5f - 0.5f), -32768, 32767);
|
|
this.currentBuffer.putShort((short)integer3);
|
|
this.byteCount += 2;
|
|
}
|
|
|
|
public ByteBuffer get() {
|
|
this.currentBuffer.flip();
|
|
if (this.buffers.isEmpty()) {
|
|
return this.currentBuffer;
|
|
}
|
|
final ByteBuffer byteBuffer2 = BufferUtils.createByteBuffer(this.byteCount);
|
|
this.buffers.forEach(byteBuffer2::put);
|
|
byteBuffer2.put(this.currentBuffer);
|
|
byteBuffer2.flip();
|
|
return byteBuffer2;
|
|
}
|
|
}
|
|
}
|