Java SFXR Port - проблема с записью байта [] в файл WAV - PullRequest
2 голосов
/ 02 апреля 2012

Я использую порт Java генератора звуковых эффектов SFXR, который включает в себя множество загадочного музыкального кода, который я не понимаю, будучи новичком, когда дело касается аудио. Что я знаю, так это то, что код может надежно генерировать и воспроизводить звуки в Java с использованием объекта SourceDataLine.

Данные, которые использует объект SDL, хранятся в байте []. Однако просто записать это в файл не получится (возможно, из-за отсутствия WAV-заголовка, или так я думал).

Однако я скачал этот класс чтения / записи WAV: http://computermusicblog.com/blog/2008/08/29/reading-and-writing-wav-files-in-java/, который добавляет информацию заголовка при записи файла WAV. Предоставление данных байта [] из SFXR по-прежнему приводит к созданию файлов, которые не могут быть воспроизведены ни одним моим музыкальным проигрывателем.

Я полагаю, что я что-то упускаю. Вот соответствующий код при воспроизведении звуковых данных:

public void play(int millis) throws Exception {
    AudioFormat stereoFormat = getStereoAudioFormat();
    SourceDataLine stereoSdl = AudioSystem.getSourceDataLine(stereoFormat);

    if (!stereoSdl.isOpen()) {
        try {
            stereoSdl.open();
        } catch (LineUnavailableException e) {
            e.printStackTrace();
        }
    }
    if (!stereoSdl.isRunning()) {
        stereoSdl.start();
    }

    double seconds = millis / 1000.0;

    int bufferSize = (int) (4 * 41000 * seconds);

    byte[] target = new byte[bufferSize];

    writeBytes(target);
    stereoSdl.write(target, 0, target.length);
}

Это из порта SFXR. Вот файл save () из класса WavIO (в этом классе, конечно, много другого кода, я подумал, что это может стоить опубликовать на тот случай, если кто-то захочет увидеть, как именно обрабатываются данные буфера:

    public boolean save()
{
    try
    {
        DataOutputStream outFile  = new DataOutputStream(new FileOutputStream(myPath));

        // write the wav file per the wav file format
        outFile.writeBytes("RIFF");                 // 00 - RIFF
        outFile.write(intToByteArray((int)myChunkSize), 0, 4);      // 04 - how big is the rest of this file?
        outFile.writeBytes("WAVE");                 // 08 - WAVE
        outFile.writeBytes("fmt ");                 // 12 - fmt 
        outFile.write(intToByteArray((int)mySubChunk1Size), 0, 4);  // 16 - size of this chunk
        outFile.write(shortToByteArray((short)myFormat), 0, 2);     // 20 - what is the audio format? 1 for PCM = Pulse Code Modulation
        outFile.write(shortToByteArray((short)myChannels), 0, 2);   // 22 - mono or stereo? 1 or 2?  (or 5 or ???)
        outFile.write(intToByteArray((int)mySampleRate), 0, 4);     // 24 - samples per second (numbers per second)
        outFile.write(intToByteArray((int)myByteRate), 0, 4);       // 28 - bytes per second
        outFile.write(shortToByteArray((short)myBlockAlign), 0, 2); // 32 - # of bytes in one sample, for all channels
        outFile.write(shortToByteArray((short)myBitsPerSample), 0, 2);  // 34 - how many bits in a sample(number)?  usually 16 or 24
        outFile.writeBytes("data");                 // 36 - data
        outFile.write(intToByteArray((int)myDataSize), 0, 4);       // 40 - how big is this data chunk
        outFile.write(myData);                      // 44 - the actual data itself - just a long string of numbers
    }
    catch(Exception e)
    {
        System.out.println(e.getMessage());
        return false;
    }

    return true;
}

Все, что я знаю, это то, что у меня есть куча данных, и я хочу, чтобы они оказались в каком-то воспроизводимом аудиофайле (в этот момент я бы взял ЛЮБОЙ формат!). Какой лучший способ для меня поместить этот байтовый буфер в воспроизводимый файл? Или этот байт [] не тот, что я думаю?

1 Ответ

4 голосов
/ 10 апреля 2012

У меня мало шансов поиграть со звуковыми возможностями Java, поэтому я использую ваш вопрос в качестве учебного упражнения (надеюсь, вы не против).Статья, на которую вы ссылались о Чтении и записи WAV-файлов на Java , очень старая по отношению к истории Java (1998).Также кое-что о создании WAV-заголовка вручную не совсем подходило мне (это казалось немного подверженным ошибкам).Поскольку Java является достаточно зрелым языком, я ожидал, что библиотека поддержит такого рода вещи.

Я смог создать WAV-файл из байтового массива, разыскивая в Интернете примеры фрагментов кода.Вот код, который я придумал (я думаю, он неоптимален, но, похоже, работает):

// Generate bang noise data
// Sourced from http://www.rgagnon.com/javadetails/java-0632.html
public static byte[] bang() {
    byte[] buf = new byte[8050];
    Random r = new Random();
    boolean silence = true;
    for (int i = 0; i < 8000; i++) {
        while (r.nextInt() % 10 != 0) {
            buf[i] =
                    silence ? 0
                    : (byte) Math.abs(r.nextInt()
                    % (int) (1. + 63. * (1. + Math.cos(((double) i)
                    * Math.PI / 8000.))));
            i++;
        }
        silence = !silence;
    }
    return buf;
}


private static void save(byte[] data, String filename) throws IOException, LineUnavailableException, UnsupportedAudioFileException {
    InputStream byteArray = new ByteArrayInputStream(data);
    AudioInputStream ais = new AudioInputStream(byteArray, getAudioFormat(), (long) data.length);
    AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File(filename));
}

private static AudioFormat getAudioFormat() {
    return new AudioFormat(
            8000f, // sampleRate
            8, // sampleSizeInBits
            1, // channels
            true, // signed
            false);      // bigEndian  
}

public static void main(String[] args) throws Exception {
    byte[] data  = bang();
    save(data, "test.wav");
}

Надеюсь, это поможет.

...