Java Audio SourceDataLine не поддерживает PCM_FLOAT
Я пытаюсь воспроизвести аудио буфер с использованием 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 ответа
Я не знаю, что смогу ответить на ваши прямые вопросы. Но, может быть, код, который я могу вам показать, который, как я знаю, работает (в том числе для Linux), поможет вам найти работоспособное решение. У меня есть программы, которые генерируют аудиосигналы через входящие сигналы, но также и по индивидуальному заказу Synths, и я делаю все микширование и эффекты с помощью поплавков PCM в диапазоне от -1 до 1. Для вывода я преобразовываю поплавки в стандартное качество CD msgstr "формат, который поддерживает 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 в один формат, а не пытаться создавать условия для нескольких форматов. Но это всего лишь личное предпочтение, и я не знаю, подойдет ли эта стратегия для вашей ситуации или нет.
Надеюсь, что-то здесь поможет!
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);
}
}
}