Java Audio SourceDataLine не поддерживает PCM_FLOAT - PullRequest
0 голосов
/ 04 июня 2018

Я пытаюсь воспроизвести аудио-буфер с использованием Java в Linux.

При попытке открыть линию я получаю следующее исключение (не при записи звука в нее) ...

Exception in thread "main" java.lang.IllegalArgumentException: No line matching interface SourceDataLine supporting format PCM_FLOAT 44100.0 Hz, 16 bit, mono, 2 bytes/frame,  is supported.

    public boolean open()
{
    try {

        int smpSizeInBits = bytesPerSmp * 8;
        int frameSize = bytesPerSmp * channels; // just an fyi, frameSize does not always == bytesPerSmp * channels for non PCM encodings
        int frameRate = (int)smpRate; // again this might not be the case for non PCM encodings.
        boolean isBigEndian = false;

        AudioFormat af = new AudioFormat(AudioFormat.Encoding.PCM_FLOAT , smpRate, smpSizeInBits, channels, frameSize, frameRate, isBigEndian);

        DataLine.Info info = new DataLine.Info(SourceDataLine.class, af);
        int bufferSizeInBytes = bufferSizeInFrames * channels * bytesPerSmp;
        line = (SourceDataLine) AudioSystem.getLine(info);
        line.open(af, bufferSizeInBytes);
        open = true;
    }
    catch(LineUnavailableException e) {
        System.out.println("PcmFloatPlayer: Unable to open, line unavailble.");
    }

    return open;
}

Мне интересно, действительно ли мои предположения о кодировке PCM_FLOAT неверны.

У меня есть код, который читает в файле wav.Wavfile - это моно, 16 бит, несжатый формат.Затем я преобразовываю аудио в числа с плавающей запятой в диапазоне от -1,0 до 1,0 для обработки.

Я предположил, что кодировка PCM_FLOAT - это просто необработанные данные PCM, которые были преобразованы в значения с плавающей запятой в диапазоне от -1,0 до 1,0.Правильно ли это?

Затем я предположил, что SourceDataLine преобразует аудио с плавающей точкой в ​​соответствующий формат на основе моей информации о переданном формате (моно, 16 бит, 2 байта / кадр).Опять же, это предположение неверно?

Должен ли я преобразовать звук с плавающей запятой -1.0 в 1.0 обратно в желаемый формат вывода и установить для SourceDataLine значение PCM_SIGNED (при условии, что это мой требуемый формат)?

РЕДАКТИРОВАТЬ:

Кроме того, когда я вызвал AudioSystem.getTargetEncodings (), с PCM_FLOAT, он возвращает три кодировки.Означает ли это, что он примет PCM_FLOAT и сможет конвертировать в возвращенные кодировки, основываясь на том, что поддерживает соответствующая аудиосистема?

        AudioFormat.Encoding[] encodings = AudioSystem.getTargetEncodings(AudioFormat.Encoding.PCM_FLOAT);
    for(AudioFormat.Encoding e : encodings)
        System.out.println(e);

приводит к ...

PCM_SIGNED PCM_UNSIGNED PCM_FLOAT

Ответы [ 2 ]

0 голосов
/ 06 июня 2018
public class Main {    
    public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread2();
        t1.start(); 
        Thread t2 = new thread3();  
        t2.start();
        Thread.sleep(5000);  
    }  
}

import javax.sound.sampled.*;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Thread2 extends Thread implements Runnable {

   @Override 
   public void run() { 
      playWav("C:/Windows/Media/feel_good_x.wav");
    }

   private static void playWav(String soundFilePath) {
      File sFile = new File(soundFilePath); 
      if (!sFile.exists()) {

         String ls = System.lineSeparator();
         System.err.println("немає в директорії»+
               ls + "(" + soundFilePath + ")" + ls);
         return;
      }

      try {
         Clip clip;

         try (AudioInputStream audioInputStream = AudioSystem.

               getAudioInputStream(sFile.getAbsoluteFile())) { 
            clip = AudioSystem.getClip();
            clip.setFramePosition(0);
            clip.open(audioInputStream);
         }
         clip.start();
      }

      catch (UnsupportedAudioFileException | IOException | LineUnavailableException ex) {

         Logger.getLogger("playWav()").log(Level.SEVERE, null, ex);
      }
   }


}
0 голосов
/ 04 июня 2018

Я не знаю, смогу ли я ответить на ваши прямые вопросы.Но, может быть, код, который я могу вам показать, который, как я знаю, работает (в том числе для Linux), поможет вам найти работоспособное решение.У меня есть программы, которые генерируют аудиосигналы через входящие сигналы, но также и по индивидуальному заказу Synths, и я делаю все микширование и эффекты с помощью поплавков PCM в диапазоне от -1 до 1. Для вывода я преобразую поплавки в стандартное качество CDmsgstr "формат, который поддерживает Java.

Вот формат, который я использую для вывода SourceDataLine:

AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100, 16, 2, 4, 44100, false);

Возможно, вы захотите сделать это моно вместо стерео.Но я должен сказать, что мне кажется, что если вы можете прочитать входящий WAV-файл в другом формате, вы должны иметь возможность воспроизвести этот же формат, при условии, что вы измените все шаги, предпринятые для преобразования входящих данных в PCM.

Для стандартного формата "Качество CD", чтобы перейти от числа с плавающей запятой pcm к байту, существует промежуточный шаг накачивания в диапазон короткого знака со знаком (от -32768 до 32767).

public static byte[] fromBufferToAudioBytes(byte[] audioBytes, float[] buffer)
{
    for (int i = 0, n = buffer.length; i < n; i++)
    {
        buffer[i] *= 32767;
        audioBytes[i*2] = (byte) buffer[i];
        audioBytes[i*2 + 1] = (byte)((int)buffer[i] >> 8 );
    }
    return audioBytes;
}

Это взято из библиотеки AudioCue , которую я написал и разместил на github.

Я считаю, что это уменьшает головные боли, чтобы просто справиться с одним AudioFormat, чтобыделать преобразования с Audacity в один формат, а не пытаться предусмотреть несколько форматов.Но это всего лишь личное предпочтение, и я не знаю, сработает ли эта стратегия для вашей ситуации или нет.

Надеюсь, здесь есть что-то, что помогает!

...