我一直在尝试手动读取Java中的wav文件,并读取字节数组,然后写入音频缓冲区以供回放。我正在接收回放,但它严重失真。Java声音支持16位采样率,但不支持24位。
我进入Logic9,将一个24位的音频文件导出为16位,然后在我的程序中使用。最初,24位样本会产生白噪声。现在我可以听到我的样本,但非常扭曲,听起来像是被压碎了。
有人能帮我得到清晰的信号吗?
我是一个非常新手的音频编程,但我目前在一个基本的数字音频工作站工作。
import javax.sound.sampled.*;
import javax.sound.sampled.DataLine.Info;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.io.*;
public class AudioData {
private String filepath;
private String filepath1;
private File file;
private byte [] fileContent;
private Mixer mixer;
private Mixer.Info[] mixInfos;
private AudioInputStream input;
private ByteArrayOutputStream byteoutput;
public static void main (String [] args) {
AudioData audiodata = new AudioData();
}
public AudioData () {
filepath = "/Users/ivaannagen/Documents/Samples/Engineering Samples - Obscure Techno Vol 3 (WAV)/ES_OT3_Kit03_Gmin_130bpm/ES_OT3_Kit03_FX_Fast_Snare_Riser_Gmin_130bpm.wav";
filepath1 = "/Users/ivaannagen/Documents/Samples/dawsampletest.wav";
file = new File (filepath1);
readAudio();
}
public void readAudio () {
mixInfos = AudioSystem.getMixerInfo();
mixer = AudioSystem.getMixer(mixInfos[0]);
AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100, 16, 2, 4, 44100, false);
// set up an audio format.
try {
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); // creates data line with class type and audio format.
SourceDataLine source = (SourceDataLine) AudioSystem.getLine(info);
System.out.println("Size of data line buffer: " + source.getBufferSize());
fileContent = new byte [source.getBufferSize() / 50];
byteoutput = new ByteArrayOutputStream();
input = AudioSystem.getAudioInputStream(file);
int readBytes = 0;
while ((readBytes = input.read(fileContent, 0, fileContent.length)) != -1) {
byteoutput.write(fileContent, 0, readBytes);
}
System.out.println("Size of audio buffer: " + fileContent.length);
//byteoutput.write(0);
// byteoutput.write(0);
System.out.println("Size of audio buffer: " + byteoutput.size());
source.open(format, source.getBufferSize()); // line must be open to be recognised by the mixer.
Line[] lines = mixer.getSourceLines();
System.out.println("mixer lines: " + lines.length);
// for(byte bytes: fileContent) {
// System.out.println(bytes);
// }
Thread playback = new Thread () {
public void run () {
// System.out.println((byteoutput.size() +2) % 4);
source.start(); // play (buffer originally empty)
source.write(byteoutput.toByteArray(), 0, byteoutput.size()); // write input bytes to output buffer
} // end run (to do).
}; // end thread action
playback.start(); // start thread
}
catch (LineUnavailableException lue) {
System.out.println(lue.getMessage());
}
catch (FileNotFoundException fnfe) {
System.out.println(fnfe.getMessage());
}
catch(IOException ioe) {
System.out.println(ioe.getMessage());
}
catch(UnsupportedAudioFileException uafe) {
System.out.println(uafe.getMessage());
}
}
}
发布于 2018-06-29 04:23:09
是否可以加载和播放24位文件取决于系统,afaik。
我使用Audacity进行转换。您应该能够将文件导入Audacity,并将其导出为16位、立体声、little-endian、44100 fps格式,然后使用Java的AudioInputStream
加载该导出。
您从Audacity或Java播放时听到的内容应该是完全相同的(根据音量进行调整)。如果没有,最可能的原因可能与代码中的错误或疏忽有关,这很容易做到。
在代码中使用ByteOutputStream
是多余的。从AudioInputStream
读取到固定大小的字节数组(size是缓冲区长度,我建议第一次尝试使用8或16 * 1024字节),然后使用SourceDataLine
写入方法发送该数组。
下面是在我的系统上运行的代码,用于加载一个名为"a3.wav“的"CD质量”wav,它与Java类位于同一目录中。您应该能够交换在您自己的44100,16位,立体声,小端wav文件。
我已经注释掉了加载和播放24位wav文件"spoken8000_24.wav“的尝试。那次尝试给了我一个IllegalArgumentException
:No line matching interface SourceDataLine supporting format PCM_SIGNED 8000.0 Hz, 24 bit, stereo, 6 bytes/frame, little-endian is supported.
我必须承认,我不清楚是我的系统没有提供所需的行,还是我可能编码错误!我的操作系统当然可以播放这个文件。因此,我认为操作系统可以做什么和给定系统上的“混合器”为Java提供了什么是有区别的。
作为权宜之计,我总是把所有东西都转换成"CD质量“格式,因为这似乎是最受支持的格式。
public class TriggerSound_SDL extends JFrame
{
public TriggerSound_SDL()
{
JButton button = new JButton("Play Sound");
button.addActionListener(e -> new Thread(() -> playBuzzer()).start());
getContentPane().add(button);
}
private void playBuzzer()
{
try
{
URL url;
url = getClass().getResource("a3.wav");
// url = getClass().getResource("spoken8000_24.wav");
AudioInputStream ais = AudioSystem.getAudioInputStream(url);
System.out.println(ais.getFormat());
AudioFormat audioFmt;
// "CD Quality" 44100 fps, 16-bit, stereo, little endian
audioFmt = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED,
44100, 16, 2, 4, 44100, false);
// 8000 fps, 32-bit, stereo
// audioFmt = new AudioFormat(
// AudioFormat.Encoding.PCM_SIGNED,
// 8000, 24, 2, 6, 8000, false);
Info info = new DataLine.Info(SourceDataLine.class,
audioFmt);
SourceDataLine sdl = (SourceDataLine)AudioSystem.getLine(info);
int bufferSize = 16 * 1024;
byte[] buffer = new byte[bufferSize];
sdl.open(audioFmt, bufferSize);
sdl.start();
int numBytesRead = 0;
while((numBytesRead = ais.read(buffer)) != -1)
{
sdl.write(buffer, 0, numBytesRead);
}
}
catch (IOException | UnsupportedAudioFileException
| LineUnavailableException ex)
{
ex.printStackTrace();
}
}
private static void createAndShowGUI()
{
JFrame frame = new TriggerSound_SDL();
frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(() -> createAndShowGUI());
}
}
这段代码,经过一些小的调整,应该至少可以让你测试不同的格式。
编辑:我知道你的目标是创建一个DAW!在这种情况下,您需要将字节转换为PCM数据。我可以建议你从AudioCue借一些代码吗?我写它基本上是为了替代剪辑,其中一部分涉及到使PCM数据可用于操作。在它里面可以找到一些混音,不同频率播放,多线程的技术。
发布于 2018-06-30 17:11:51
谢谢你们给我的建议。我将摆脱ByteOutputStream,只使用AudioInputStream,我现在明白我所做的事情是不必要的!!谢谢大家的建议!我确实尝试过使用AudioCue,但对于我想做的事情来说,它的级别还不够低!
还有一件事伙计们。之前,我创建了一个使用Clip类的多轨媒体播放器。为了一起播放所有的音轨,我循环播放剪辑列表并播放它们。然而,这意味着由于循环的处理,所有的曲目可能会彼此播放少量的曲目。另外,Clip类为每个音频创建了一个新线程。我不希望100个线程运行在100首曲目上,我想我的音频输出一个线程。我仍然在试图找出如何在没有循环的情况下同时开始所有的曲目…(我猜AudioCue已经锁定了并发的线索)。
有谁知道在一个输出中播放多个音轨的最佳方法吗?我是否需要将我所有的音轨路由/总线到一个输出,然后以某种方式将音频文件中的所有数据写入到一个输出缓冲区中,然后在线程中播放这个输出?
谢谢!!
https://stackoverflow.com/questions/51067250
复制相似问题