penguin/loopdeck

A simple player that support A-B looping for FiiO M11S

app/src/main/java/net/astropenguin/loopdeck/PcmPrebuffer.java

raw ยท 1492 bytes

package net.astropenguin.loopdeck;

import java.io.IOException;
import java.util.function.BooleanSupplier;

/** A bounded stereo prefix. After preparation, ownership passes to playback. */
final class PcmPrebuffer {
    interface Reader { int read(float[] buffer,int frames) throws IOException; }
    private final Reader reader;
    private final long limit;
    private final float[] prefix;
    private int filled, offset;
    private long consumed;
    PcmPrebuffer(Reader reader,int frames,long limit) {
        this.reader=reader; this.limit=limit; prefix=new float[Math.multiplyExact(frames,2)];
    }
    void prepare(BooleanSupplier cancelled) throws IOException {
        float[] scratch=new float[4096];
        while (filled<prefix.length && !cancelled.getAsBoolean()) {
            int requested=(int)Math.min(Math.min(scratch.length/2,(prefix.length-filled)/2),limit-filled/2);
            if (requested<=0) break;
            int n=reader.read(scratch,requested);
            if (n==0) break;
            System.arraycopy(scratch,0,prefix,filled,n*2); filled+=n*2;
        }
    }
    int read(float[] output,int frames) throws IOException {
        frames=(int)Math.min(frames,limit-consumed);
        if (frames<=0) return 0;
        int n;
        if (offset<filled) {
            n=Math.min(frames,(filled-offset)/2);
            System.arraycopy(prefix,offset,output,0,n*2); offset+=n*2;
        } else n=reader.read(output,frames);
        consumed+=n; return n;
    }
}