简体   繁体   中英

writing double[] as WAV file in Java

I'm trying to save a double[] array as .WAV file using this method:

public static void saveWav(String filename, double[] samples) {

    // assumes 44,100 samples per second
    // use 16-bit audio, 2 channels, signed PCM, little Endian
    AudioFormat format = new AudioFormat(SAMPLE_RATE * 2, 16, 1, true, false);
    byte[] data = new byte[2 * samples.length];
    for (int i = 0; i < samples.length; i++) {
        int temp = (short) (samples[i] * MAX_16_BIT);
        data[2*i + 0] = (byte) temp;
        data[2*i + 1] = (byte) (temp >> 8);
    }

    // now save the file
    try {
        ByteArrayInputStream bais = new ByteArrayInputStream(data);
        AudioInputStream ais = new AudioInputStream(bais, format, samples.length);
        if (filename.endsWith(".wav") || filename.endsWith(".WAV")) {
            AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File(filename));
        }
        else if (filename.endsWith(".au") || filename.endsWith(".AU")) {
            AudioSystem.write(ais, AudioFileFormat.Type.AU, new File(filename));
        }
        else {
            throw new RuntimeException("File format not supported: " + filename);
        }
    }
    catch (IOException e) {
        System.out.println(e);
        System.exit(1);
    }
}

but when I reload the files I saved, for every song[i], the double value is different than the original. I use this method to read WAV files:

public static double[] read(String filename) {
    byte[] data = readByte(filename);
    int N = data.length;
    double[] d = new double[N/2];
    for (int i = 0; i < N/2; i++) {
        d[i] = ((short) (((data[2*i+1] & 0xFF) << 8) + (data[2*i] & 0xFF))) / ((double) MAX_16_BIT);
    }
    return d;
}
private static byte[] readByte(String filename) {
    byte[] data = null;
    AudioInputStream ais = null;
    try {

        // try to read from file
        File file = new File(filename);
        if (file.exists()) {
            ais = AudioSystem.getAudioInputStream(file);
            data = new byte[ais.available()];
            ais.read(data);
        }

        // try to read from URL
        else {
            URL url = StdAudio.class.getResource(filename);
            ais = AudioSystem.getAudioInputStream(url);
            data = new byte[ais.available()];
            ais.read(data);
        }
    }
    catch (IOException e) {
        System.out.println(e.getMessage());
        throw new RuntimeException("Could not read " + filename);
    }

    catch (UnsupportedAudioFileException e) {
        System.out.println(e.getMessage());
        throw new RuntimeException(filename + " in unsupported audio format");
    }

    return data;
}

I need both double[] arrays to have the exact same values, and that's not the case. when I hear the song playing I can't tell the difference, but I still need those original values.

Any help appreciated.

Guy

A double requires 64-bits of storage and has a lot of precision. You can't just throw away 48 bits of data in the round trip and expect to get the exact same value back. It is analogous to starting with a high resolution image, converting it to a thumbnail and then expecting that you can magically recover the original high resolution image. In the real world, the human ear is not going to be able to distinguish between the two. The higher resolution is useful during computation and signal processing routines to reduce the accumulation of computational errors. That being said, if you want to store 64-bit you'll need to use something other than .WAV. The closest you'll get is 32-bit.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM