# Java Sound: WAVE Format17 einlesen.



## HalloWelt_ (17. Jul 2012)

Hallo.
Ich versuche im Moment WAVE Dateien in Java zu dekodieren, welche im Format: 17 (DIALOGIC OKI ADPCM) komprimiert sind einzulesen, da das Java-Sound nicht von sich aus kann. Ich habe nun einen eigenen Decoder geschrieben... Leider klappt der nicht. Das wird wohl daran liegen, dass das anderes ADPCM ist als ich dachte.
Im Internet konnte ich nichts dazu finden, außer fertige Codecs für zum Beispiel. Windows Media-Player...
Gibt es vielleicht eine fertige Java-Library (nicht native), welche das Format unterstützt? Oder hat jemand eine Beschreibung zu diesem Format?

Mein nicht funktionierender Decoder sieht so aus:

```
public class ADPCMInputStream extends FilterInputStream {

    private static final int[] step_table = {
        7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
        19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
        50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
        130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
        337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
        876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
        2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
        5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
        15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
    };
    private static final int index_table[] = {
        -1, -1, -1, -1, 2, 4, 6, 8,
        -1, -1, -1, -1, 2, 4, 6, 8
    };
    private byte buf = 0;
    private int buf_off = 0;

    public ADPCMInputStream(InputStream in) {
        super(in);
    }

    private int getBit() throws IOException {
        if (buf_off >= 8) {
            int r = super.read();
            if (r == -1) {
                throw new EOFException();
            }
            buf = (byte) r;
            buf_off = 0;
        }
        boolean b = (buf & 1 << buf_off) != 0;
        buf_off++;
        return b ? 1 : 0;
    }

    private int clip(int i, int min, int max) {
        if (i < min) {
            return min;
        }
        if (i > max) {
            return max;
        }
        return i;
    }

    private int bits = 1 << 3;      // 4 bits per sample
    private int j = bits - 1;
    private int k = bits >> 1;
    private int index = 0;
    private int predicted = 0;

    @Override
    public int read() {
        throw new UnsupportedOperationException("Can't read a single byte from this stream!");
    }
    
    @Override
    public int read(byte[] buf) throws IOException {
        return read(buf, 0, buf.length);
    }
    
    @Override
    public int read(byte[] buf, int off, int len) throws IOException {
        int avail = in.available();
        if (avail <= 1) {
            return -1;
        }
        int cnt = Math.min(avail * 2, len);
        cnt -= cnt % 2;
        
        for (int i = off; i < off + cnt;) {
            int nib = 0;
            for (int b = 0; b < 4; b++) {
                nib |= (getBit() << b);
            }
            int to = step_table[index];
            int i1 = 0;
            for (int i2 = k; i2 > 0; i2 >>= 1) {
                if ((nib & i2) != 0) {
                    i1 += to;
                }
                to >>= 1;
            }
            i1 += to;

            predicted += ((nib & bits) != 0 ? -i1 : i1);
            short sample = (short) clip(predicted, Short.MIN_VALUE, Short.MAX_VALUE);
            buf[i++] = (byte) (sample & 0xFF);
            buf[i++] = (byte) ((sample >> 8) & 0xFF);
            
            index += index_table[(nib & j)];
            index = clip(index, 0, 88);
        }
        return cnt;
    }
}
```

Danke!


----------



## Flown (18. Jul 2012)

Ich hoffe das dir das weiterhilft:

Specification


----------



## HalloWelt_ (18. Jul 2012)

Danke!
Mein halbwegs funktionierender Decoder ist jetzt fertig.
Das Problem ist nur, dass die Qualität, vor allem wenn man das Sample mit einem Faktor multipliziert, ziemlich schlecht ist.
Wenn ich das Sample nicht multipliziere, und die Lautstärke an der Stereo-Anlage aufdrehe, leidet die Qualität nicht...
Außerdem habe ich habe die Datei mal in einem "echten" Musik-Player abgespielt und der hörte sich irgendwie besser an. :|

```
public class ADPCMInputStream extends FilterInputStream {

    private static int[] stepTable = {
        16, 17, 19, 21, 23, 25, 28, 31,
        34, 37, 41, 45, 50, 55, 60, 66,
        73, 80, 88, 97, 107, 118, 130, 143,
        157, 173, 190, 209, 230, 253, 279, 307,
        337, 371, 408, 449, 494, 544, 598, 658,
        724, 796, 876, 963, 1060, 1166, 1282, 1411,
        1552
    };
    private static int[] adjusts = {
        -1, -1, -1, -1, 2, 4, 6, 8
    };
    // ---------------------------------------------
    private int stepIndex = 0;
    private int last = 0;

    public ADPCMInputStream(InputStream in) {
        super(in);
    }

    @Override
    public int read() {
        throw new UnsupportedOperationException("Can't read a single byte from this stream!");
    }

    @Override
    public int read(byte[] buf) throws IOException {
        return read(buf, 0, buf.length);
    }

    short decodeOKI(int code) {
        int E = (2 * (code & 0x7) + 1) * stepTable[stepIndex] / 8;
        int diff = (code & 0x08) != 0 ? -E : E;
        int samp = last + diff;
        // Clip the values to +/- 2^11 (supposed to be 12 bits)
        if (samp > 2048) {
            samp = 2048;
        }
        if (samp < -2048) {
            samp = -2048;
        }
        last = samp;
        stepIndex += adjusts[code & 0x07];
        if (stepIndex < 0) {
            stepIndex = 0;
        }
        if (stepIndex >= stepTable.length) {
            stepIndex = stepTable.length - 1;
        }
        // * 16 effectively converts 12-bit input to 16-bit output
        return (short) (samp * 16); // that doesn't worked well for me. try a smaller number...
    }

    @Override
    public int read(byte[] buf, int off, int len) throws IOException {
        int avail = in.available() * 4; // needed bytes: (1 input-byte) ~ (2 16-bit samples) ~ (4 output-bytes)
        if (avail < 4) {                // can just read 2-samples at once
            return -1;
        }

        int cnt = Math.min(avail, len);
        cnt -= cnt % 4;
        for (int i = off; i < off + cnt;) {
            int data = in.read();
            short sa = decodeOKI(((data >> 4) & 0x0f));
            short sb = decodeOKI(((data) & 0x0f));
            buf[i++] = (byte) (sa & 0xFF);
            buf[i++] = (byte) ((sa >> 8) & 0xFF);
            buf[i++] = (byte) (sb & 0xFF);
            buf[i++] = (byte) ((sb >> 8) & 0xFF);
        }
        return cnt;
    }
}
```


----------

