Извлечь амплитудный массив из wav файла с помощью JAVA

Я пытаюсь извлечь массив амплитуд из аудиофайла (WAV файл). Я буду использовать этот массив амплитуд для построения графика амплитуды vs времени для данного wav файла. Я могу сам построить график, но не знаю, как извлечь амплитуду из данного аудио (wav) файла в java?

Ответы

Ответ 1

Вот вспомогательный класс, который вы можете использовать. Метод getSampleInt() - это то, что вам нужно для получения амплитуды:

File file = ...;
WavFile wav = new WavFile(file);

int amplitudeExample = wav.getSampleInt(140); // 140th amplitude value.

for (int i = 0; i < wav.getFramesCount(); i++) {
    int amplitude = wav.getSampleInt(i);
    // Plot.
}

Он также может воспроизводить файлы, чтобы вы могли его протестировать, но только 8-битные или 16-битные файлы. В других случаях их можно прочитать только.

Кроме того, просмотрите эти диаграммы, чтобы увидеть, какие WAV файлы состоят и лучше понять, что делает этот класс.

public class WaveFile {
    public final int NOT_SPECIFIED = AudioSystem.NOT_SPECIFIED; // -1
    public final int INT_SIZE = 4;

    private int sampleSize = NOT_SPECIFIED;
    private long framesCount = NOT_SPECIFIED;
    private int sampleRate = NOT_SPECIFIED;
    private int channelsNum;
    private byte[] data;      // wav bytes
    private AudioInputStream ais;
    private AudioFormat af;

    private Clip clip;
    private boolean canPlay;

    public WaveFile(File file) throws UnsupportedAudioFileException, IOException {
        if (!file.exists()) {
            throw new FileNotFoundException(file.getAbsolutePath());
        }

        ais = AudioSystem.getAudioInputStream(file);

        af = ais.getFormat();

        framesCount = ais.getFrameLength();

        sampleRate = (int) af.getSampleRate();

        sampleSize = af.getSampleSizeInBits() / 8;

        channelsNum = af.getChannels();

        long dataLength = framesCount * af.getSampleSizeInBits() * af.getChannels() / 8;

        data = new byte[(int) dataLength];
        ais.read(data);

        AudioInputStream aisForPlay = AudioSystem.getAudioInputStream(file);
        try {
            clip = AudioSystem.getClip();
            clip.open(aisForPlay);
            clip.setFramePosition(0);
            canPlay = true;
        } catch (LineUnavailableException e) {
            canPlay = false;
            System.out.println("I can play only 8bit and 16bit music.");
        }
    }

    public boolean isCanPlay() {
        return canPlay;
    }

    public void play() {
        clip.start();
    }

    public void stop() {
        clip.stop();
    }

    public AudioFormat getAudioFormat() {
        return af;
    }

    public int getSampleSize() {
        return sampleSize;
    }

    public double getDurationTime() {
        return getFramesCount() / getAudioFormat().getFrameRate();
    }

    public long getFramesCount() {
        return framesCount;
    }


    /**
     * Returns sample (amplitude value). Note that in case of stereo samples
     * go one after another. I.e. 0 - first sample of left channel, 1 - first
     * sample of the right channel, 2 - second sample of the left channel, 3 -
     * second sample of the rigth channel, etc.
     */
    public int getSampleInt(int sampleNumber) {

        if (sampleNumber < 0 || sampleNumber >= data.length / sampleSize) {
            throw new IllegalArgumentException(
                    "sample number can't be < 0 or >= data.length/"
                            + sampleSize);
        }

        byte[] sampleBytes = new byte[4]; //4byte = int

        for (int i = 0; i < sampleSize; i++) {
            sampleBytes[i] = data[sampleNumber * sampleSize * channelsNum + i];
        }

        int sample = ByteBuffer.wrap(sampleBytes)
                .order(ByteOrder.LITTLE_ENDIAN).getInt();
        return sample;
    }

    public int getSampleRate() {
        return sampleRate;
    }

    public Clip getClip() {
        return clip;
    }
}

Ответ 2

Я пробовал ваш код и с несколькими незначительными изменениями создал результат. Что не так с данными, которые выдает код?

I Изменили следующие строки:

// create file input stream
      DataInputStream fis = new DataInputStream(new FileInputStream(wavFile));
      // create byte array from file
      arrFile = new byte[(int) wavFile.length()];
      fis.readFully(arrFile); // make sure you always read the full file, you did not check its return value, so you might be missing some data

Второе, что я изменил, было:

System.out.println(Arrays.toString(s.extractAmplitudeFromFile(f)));

В вашем основном методе, поскольку вы только распечатываете адрес арари. После этих изменений код вывел массив, который имел значения, которые, казалось, коррелировали с желаемыми данными.

что вам не хватает, или что вы ожидаете от данных? Не могли бы вы прояснить вопрос немного больше?