JOrbisAudioStream.java

net.minecraft.client.sounds.JOrbisAudioStream

信息

  • 全限定名:net.minecraft.client.sounds.JOrbisAudioStream
  • 类型:public class
  • 包:net.minecraft.client.sounds
  • 源码路径:src/main/java/net/minecraft/client/sounds/JOrbisAudioStream.java
  • 起始行号:L20
  • 实现:FloatSampleSource
  • 职责:

    TODO

字段/常量

  • BUFSIZE

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L21
    • 说明:

      TODO

  • PAGEOUT_RECAPTURE

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L22
    • 说明:

      TODO

  • PAGEOUT_NEED_MORE_DATA

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L23
    • 说明:

      TODO

  • PAGEOUT_OK

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L24
    • 说明:

      TODO

  • PACKETOUT_ERROR

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L25
    • 说明:

      TODO

  • PACKETOUT_NEED_MORE_DATA

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L26
    • 说明:

      TODO

  • PACKETOUT_OK

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L27
    • 说明:

      TODO

  • syncState

    • 类型: SyncState
    • 修饰符: private final
    • 源码定位: L28
    • 说明:

      TODO

  • page

    • 类型: Page
    • 修饰符: private final
    • 源码定位: L29
    • 说明:

      TODO

  • streamState

    • 类型: StreamState
    • 修饰符: private final
    • 源码定位: L30
    • 说明:

      TODO

  • packet

    • 类型: Packet
    • 修饰符: private final
    • 源码定位: L31
    • 说明:

      TODO

  • info

    • 类型: Info
    • 修饰符: private final
    • 源码定位: L32
    • 说明:

      TODO

  • dspState

    • 类型: DspState
    • 修饰符: private final
    • 源码定位: L33
    • 说明:

      TODO

  • block

    • 类型: Block
    • 修饰符: private final
    • 源码定位: L34
    • 说明:

      TODO

  • audioFormat

    • 类型: AudioFormat
    • 修饰符: private final
    • 源码定位: L35
    • 说明:

      TODO

  • input

    • 类型: InputStream
    • 修饰符: private final
    • 源码定位: L36
    • 说明:

      TODO

  • samplesWritten

    • 类型: long
    • 修饰符: private
    • 源码定位: L37
    • 说明:

      TODO

  • totalSamplesInStream

    • 类型: long
    • 修饰符: private
    • 源码定位: L38
    • 说明:

      TODO

内部类/嵌套类型

构造器

public JOrbisAudioStream(InputStream input) @ L40

  • 构造器名:JOrbisAudioStream
  • 源码定位:L40
  • 修饰符:public

参数:

  • input: InputStream

说明:

TODO

方法

下面的方法块按源码顺序生成。

private static boolean isError(int value) @ L69

  • 方法名:isError
  • 源码定位:L69
  • 返回类型:boolean
  • 修饰符:private static

参数:

  • value: int

说明:

TODO

public AudioFormat getFormat() @ L73

  • 方法名:getFormat
  • 源码定位:L73
  • 返回类型:AudioFormat
  • 修饰符:public

参数:

说明:

TODO

private boolean readToBuffer() @ L78

  • 方法名:readToBuffer
  • 源码定位:L78
  • 返回类型:boolean
  • 修饰符:private

参数:

说明:

TODO

private Page readPage() @ L90

  • 方法名:readPage
  • 源码定位:L90
  • 返回类型:Page
  • 修饰符:private

参数:

说明:

TODO

private Packet readIdentificationPacket(Page firstPage) @ L114

  • 方法名:readIdentificationPacket
  • 源码定位:L114
  • 返回类型:Packet
  • 修饰符:private

参数:

  • firstPage: Page

说明:

TODO

private Packet readPacket() @ L128

  • 方法名:readPacket
  • 源码定位:L128
  • 返回类型:Packet
  • 修饰符:private

参数:

说明:

TODO

private long getSamplesToWrite(int samples) @ L153

  • 方法名:getSamplesToWrite
  • 源码定位:L153
  • 返回类型:long
  • 修饰符:private

参数:

  • samples: int

说明:

TODO

public boolean readChunk(FloatConsumer consumer) @ L167

  • 方法名:readChunk
  • 源码定位:L167
  • 返回类型:boolean
  • 修饰符:public

参数:

  • consumer: FloatConsumer

说明:

TODO

private static void copyAnyChannels(float[][] samples, int channelCount, int[] offsets, long count, FloatConsumer output) @ L201

  • 方法名:copyAnyChannels
  • 源码定位:L201
  • 返回类型:void
  • 修饰符:private static

参数:

  • samples: float[][]
  • channelCount: int
  • offsets: int[]
  • count: long
  • output: FloatConsumer

说明:

TODO

private static void copyMono(float[] samples, int offset, long count, FloatConsumer output) @ L211

  • 方法名:copyMono
  • 源码定位:L211
  • 返回类型:void
  • 修饰符:private static

参数:

  • samples: float[]
  • offset: int
  • count: long
  • output: FloatConsumer

说明:

TODO

private static void copyStereo(float[] samples1, int offset1, float[] samples2, int offset2, long count, FloatConsumer output) @ L217

  • 方法名:copyStereo
  • 源码定位:L217
  • 返回类型:void
  • 修饰符:private static

参数:

  • samples1: float[]
  • offset1: int
  • samples2: float[]
  • offset2: int
  • count: long
  • output: FloatConsumer

说明:

TODO

public void close() @ L224

  • 方法名:close
  • 源码定位:L224
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public class JOrbisAudioStream implements FloatSampleSource {
    private static final int BUFSIZE = 8192;
    private static final int PAGEOUT_RECAPTURE = -1;
    private static final int PAGEOUT_NEED_MORE_DATA = 0;
    private static final int PAGEOUT_OK = 1;
    private static final int PACKETOUT_ERROR = -1;
    private static final int PACKETOUT_NEED_MORE_DATA = 0;
    private static final int PACKETOUT_OK = 1;
    private final SyncState syncState = new SyncState();
    private final Page page = new Page();
    private final StreamState streamState = new StreamState();
    private final Packet packet = new Packet();
    private final Info info = new Info();
    private final DspState dspState = new DspState();
    private final Block block = new Block(this.dspState);
    private final AudioFormat audioFormat;
    private final InputStream input;
    private long samplesWritten;
    private long totalSamplesInStream = Long.MAX_VALUE;
 
    public JOrbisAudioStream(InputStream input) throws IOException {
        this.input = input;
        Comment comment = new Comment();
        Page firstPage = this.readPage();
        if (firstPage == null) {
            throw new IOException("Invalid Ogg file - can't find first page");
        } else {
            Packet firstPacket = this.readIdentificationPacket(firstPage);
            if (isError(this.info.synthesis_headerin(comment, firstPacket))) {
                throw new IOException("Invalid Ogg identification packet");
            } else {
                for (int headerPacketCount = 0; headerPacketCount < 2; headerPacketCount++) {
                    firstPacket = this.readPacket();
                    if (firstPacket == null) {
                        throw new IOException("Unexpected end of Ogg stream");
                    }
 
                    if (isError(this.info.synthesis_headerin(comment, firstPacket))) {
                        throw new IOException("Invalid Ogg header packet " + headerPacketCount);
                    }
                }
 
                this.dspState.synthesis_init(this.info);
                this.block.init(this.dspState);
                this.audioFormat = new AudioFormat(this.info.rate, 16, this.info.channels, true, false);
            }
        }
    }
 
    private static boolean isError(int value) {
        return value < 0;
    }
 
    @Override
    public AudioFormat getFormat() {
        return this.audioFormat;
    }
 
    private boolean readToBuffer() throws IOException {
        int offset = this.syncState.buffer(8192);
        byte[] buffer = this.syncState.data;
        int bytes = this.input.read(buffer, offset, 8192);
        if (bytes == -1) {
            return false;
        } else {
            this.syncState.wrote(bytes);
            return true;
        }
    }
 
    private @Nullable Page readPage() throws IOException {
        while (true) {
            int pageOutResult = this.syncState.pageout(this.page);
            switch (pageOutResult) {
                case -1:
                    throw new IOException("Corrupt or missing data in bitstream");
                case 0:
                    if (this.readToBuffer()) {
                        break;
                    }
 
                    return null;
                case 1:
                    if (this.page.eos() != 0) {
                        this.totalSamplesInStream = this.page.granulepos();
                    }
 
                    return this.page;
                default:
                    throw new IllegalStateException("Unknown page decode result: " + pageOutResult);
            }
        }
    }
 
    private Packet readIdentificationPacket(Page firstPage) throws IOException {
        this.streamState.init(firstPage.serialno());
        if (isError(this.streamState.pagein(firstPage))) {
            throw new IOException("Failed to parse page");
        } else {
            int result = this.streamState.packetout(this.packet);
            if (result != 1) {
                throw new IOException("Failed to read identification packet: " + result);
            } else {
                return this.packet;
            }
        }
    }
 
    private @Nullable Packet readPacket() throws IOException {
        while (true) {
            int packetOutResult = this.streamState.packetout(this.packet);
            switch (packetOutResult) {
                case -1:
                    throw new IOException("Failed to parse packet");
                case 0:
                    Page page = this.readPage();
                    if (page == null) {
                        return null;
                    }
 
                    if (!isError(this.streamState.pagein(page))) {
                        break;
                    }
 
                    throw new IOException("Failed to parse page");
                case 1:
                    return this.packet;
                default:
                    throw new IllegalStateException("Unknown packet decode result: " + packetOutResult);
            }
        }
    }
 
    private long getSamplesToWrite(int samples) {
        long samplesAfterWrite = this.samplesWritten + samples;
        long samplesToWrite;
        if (samplesAfterWrite > this.totalSamplesInStream) {
            samplesToWrite = this.totalSamplesInStream - this.samplesWritten;
            this.samplesWritten = this.totalSamplesInStream;
        } else {
            this.samplesWritten = samplesAfterWrite;
            samplesToWrite = samples;
        }
 
        return samplesToWrite;
    }
 
    @Override
    public boolean readChunk(FloatConsumer consumer) throws IOException {
        float[][][] pcmSampleOutput = new float[1][][];
        int[] pcmOffsetOutput = new int[this.info.channels];
        Packet packet = this.readPacket();
        if (packet == null) {
            return false;
        } else if (isError(this.block.synthesis(packet))) {
            throw new IOException("Can't decode audio packet");
        } else {
            this.dspState.synthesis_blockin(this.block);
 
            int samples;
            while ((samples = this.dspState.synthesis_pcmout(pcmSampleOutput, pcmOffsetOutput)) > 0) {
                float[][] channelSamples = pcmSampleOutput[0];
                long samplesToWrite = this.getSamplesToWrite(samples);
                switch (this.info.channels) {
                    case 1:
                        copyMono(channelSamples[0], pcmOffsetOutput[0], samplesToWrite, consumer);
                        break;
                    case 2:
                        copyStereo(channelSamples[0], pcmOffsetOutput[0], channelSamples[1], pcmOffsetOutput[1], samplesToWrite, consumer);
                        break;
                    default:
                        copyAnyChannels(channelSamples, this.info.channels, pcmOffsetOutput, samplesToWrite, consumer);
                }
 
                this.dspState.synthesis_read(samples);
            }
 
            return true;
        }
    }
 
    private static void copyAnyChannels(float[][] samples, int channelCount, int[] offsets, long count, FloatConsumer output) {
        for (int j = 0; j < count; j++) {
            for (int channel = 0; channel < channelCount; channel++) {
                int offset = offsets[channel];
                float val = samples[channel][offset + j];
                output.accept(val);
            }
        }
    }
 
    private static void copyMono(float[] samples, int offset, long count, FloatConsumer output) {
        for (int i = offset; i < offset + count; i++) {
            output.accept(samples[i]);
        }
    }
 
    private static void copyStereo(float[] samples1, int offset1, float[] samples2, int offset2, long count, FloatConsumer output) {
        for (int i = 0; i < count; i++) {
            output.accept(samples1[offset1 + i]);
            output.accept(samples2[offset2 + i]);
        }
    }
 
    @Override
    public void close() throws IOException {
        this.input.close();
    }
}

引用的其他类