Как сохранить воспроизведение аудио в формате WAV на Java - PullRequest
1 голос
/ 09 июня 2019

Я использую алгоритм Sonic, разработанный waywardgeek , чтобы ускорить и замедлить мои аудиофайлы. Работает нормально. Но мне нужно сохранить это воспроизводимое аудио в файл wav. Я пытался сохранить, используя ByteArrayInputStream и TargetDataLink. Но я не смог этого сделать. Кто-нибудь может помочь мне сохранить этот воспроизводимый звук в файл wav? А также я новичок в Java Audio.

Вот код,

Main.java

import java.io.File;
import java.io.IOException;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;

public class Main {

    private static void runSonic(
            AudioInputStream audioStream,
            SourceDataLine line,
            float speed,
            float pitch,
            float rate,
            float volume,
            boolean emulateChordPitch,
            int quality,
            int sampleRate,
            int numChannels) throws IOException {
        Sonic sonic = new Sonic(sampleRate, numChannels);
        int bufferSize = line.getBufferSize();
        byte inBuffer[] = new byte[bufferSize];
        byte outBuffer[] = new byte[bufferSize];
        int numRead, numWritten;

        sonic.setSpeed(speed);
        sonic.setPitch(pitch);
        sonic.setRate(rate);
        sonic.setVolume(volume);
        sonic.setChordPitch(emulateChordPitch);
        sonic.setQuality(quality);
        do {
            numRead = audioStream.read(inBuffer, 0, bufferSize);
            if (numRead <= 0) {
                sonic.flushStream();
            } else {
                sonic.writeBytesToStream(inBuffer, numRead);
            }
            do {
                numWritten = sonic.readBytesFromStream(outBuffer, bufferSize);
                if (numWritten > 0) {
                    line.write(outBuffer, 0, numWritten);
                }
            } while (numWritten > 0);
        } while (numRead > 0);
    }

    public static void main(String[] argv) throws UnsupportedAudioFileException, IOException, LineUnavailableException {
        float speed = 1.0f;
        float pitch = 1.0f;
        float rate = 1.5f;
        float volume = 1.0f;
        boolean emulateChordPitch = false;
        int quality = 0;

        AudioInputStream stream = AudioSystem.getAudioInputStream(new File("C:\\audio1.wav"));
        AudioFormat format = stream.getFormat();
        int sampleRate = (int) format.getSampleRate();
        int numChannels = format.getChannels();
        SourceDataLine.Info info = new DataLine.Info(SourceDataLine.class, format,
                ((int) stream.getFrameLength() * format.getFrameSize()));
        SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info);
        line.open(stream.getFormat());
        line.start();
        runSonic(stream, line, speed, pitch, rate, volume, emulateChordPitch, quality,
                sampleRate, numChannels);
        line.drain();
        line.stop();
    }
}

Я попытался использовать следующий код, и он сохранился в файл wav, но при воспроизведении он содержит звук из одного слова. А также с TargetDataLink ничего не работает.

byteArrayOutputStream = new ByteArrayInputStream(outBuffer);
audioStreams = new AudioInputStream(byteArrayOutputStream, line.getFormat(), bufferSize);
AudioSystem.write(audioStreams, AudioFileFormat.Type.WAVE, new File("C:\\audio2.wav"));

Sonic.java

Невозможно опубликовать полный код здесь из-за ограниченного числа символов. Код здесь .

PS: Код разработан Bill Cox . Спасибо Билл Кокс за этот замечательный код.

Ответы [ 2 ]

1 голос
/ 12 июня 2019

Я почти уверен, что оба вопроса, как изменить скорость воспроизведения и как сохранить wavs, были рассмотрены в предыдущих вопросах.Например, Java - настройка скорости воспроизведения файла WAV См. Ответ о линейной интерполяции.Это не так сложно реализовать.Выбранный ответ подходит, если вы хотите только удвоить скорость, но алгоритм интерполяции позволяет назначать многие другие скорости.

Что касается сохранения в wav, я рекомендую начать с учебника Oracle Sound.https://docs.oracle.com/javase/tutorial/sound/converters.html

Для того, чтобы сделать это потоком, а не хранить полные файлы в памяти, требуется немного управления, но это довольно распространенная задача, и она должна быть в трюке любого программиста.При вводе и обработке данных вы сохраняете их в массив выходного буфера и отслеживаете ход выполнения в выходном буфере.Записывать в выходной поток можно только тогда, когда этот буфер готов.

Обзор шагов: чтение байтов, преобразование в PCM, сдвиг основного тона, если полный буфер готов к выводу: преобразование PCM обратно в байты, записьбайт.

1 голос
/ 10 июня 2019

Я попытался, и теперь я нашел решение, используя ByteArrayInputStream и ByteArrayOutputStream.Сначала я пишу outBuffer, используя ByteArrayOutputStream так же, как SourceDataLine line.write().А затем преобразовать его в byteArray и сохранить его, используя AudioInputStream.Это руководство от java2s помогло мне сделать это.Это работает, но я не знаю, является ли это лучшим решением.Так что любые предложения приветствуются.Спасибо.

import java.io.File;
import java.io.IOException;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;

public class Main {

    private static void runSonic(
            AudioInputStream audioStream,
            SourceDataLine line,
            float speed,
            float pitch,
            float rate,
            float volume,
            boolean emulateChordPitch,
            int quality,
            int sampleRate,
            int numChannels) throws IOException {
        Sonic sonic = new Sonic(sampleRate, numChannels);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        int bufferSize = line.getBufferSize();
        byte inBuffer[] = new byte[bufferSize];
        byte outBuffer[] = new byte[bufferSize];
        int numRead, numWritten;

        sonic.setSpeed(speed);
        sonic.setPitch(pitch);
        sonic.setRate(rate);
        sonic.setVolume(volume);
        sonic.setChordPitch(emulateChordPitch);
        sonic.setQuality(quality);
        do {
            numRead = audioStream.read(inBuffer, 0, bufferSize);
            if (numRead <= 0) {
                sonic.flushStream();
            } else {
                sonic.writeBytesToStream(inBuffer, numRead);
            }
            do {
                numWritten = sonic.readBytesFromStream(outBuffer, bufferSize);
                if (numWritten > 0) {
                    line.write(outBuffer, 0, numWritten);
                    byteArrayOutputStream.write(outBuffer, 0, numWritten);
                }
            } while (numWritten > 0);
        } while (numRead > 0);
        byte audioBytes[] = byteArrayOutputStream.toByteArray();
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(audioBytes);
        AudioFormat format = line.getFormat();

        AudioInputStream audioInputStream = new AudioInputStream(byteArrayInputStream, format, audioBytes.length / format.getFrameSize());
        AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, new File("C:\\audio2.wav"));

    }

    public static void main(String[] argv) throws UnsupportedAudioFileException, IOException, LineUnavailableException {
        float speed = 1.0f;
        float pitch = 1.0f;
        float rate = 1.5f;
        float volume = 1.0f;
        boolean emulateChordPitch = false;
        int quality = 0;

        AudioInputStream stream = AudioSystem.getAudioInputStream(new File("C:\\audio1.wav"));
        AudioFormat format = stream.getFormat();
        int sampleRate = (int) format.getSampleRate();
        int numChannels = format.getChannels();
        SourceDataLine.Info info = new DataLine.Info(SourceDataLine.class, format,
                ((int) stream.getFrameLength() * format.getFrameSize()));
        SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info);
        line.open(stream.getFormat());
        line.start();
        runSonic(stream, line, speed, pitch, rate, volume, emulateChordPitch, quality,
                sampleRate, numChannels);
        line.drain();
        line.stop();
    }
}
...