【发布时间】:2020-06-03 04:43:56
【问题描述】:
我有一个立体声文件,我只需要读取和播放选定的频道。实现这一目标的最佳方法是什么?
【问题讨论】:
我有一个立体声文件,我只需要读取和播放选定的频道。实现这一目标的最佳方法是什么?
【问题讨论】:
当您通过 AudioInputStream 引入 wav 文件时,使用 AudioFileFormat 信息将字节转换为 PCM。左右的数据交替出现。因此,如果该行是 16 位,则每帧将有 4 个字节。前两个将组装到左通道中,后两个将组装到右通道中。 (或者反之亦然——我很难记住哪个频道是左还是右。)
这是一个很好的教程,其中包含有关如何阅读一行的示例: http://docs.oracle.com/javase/tutorial/sound/converters.html
可能需要跟踪中的一些早期教程来帮助澄清。此外,如果您对将字节转换为 PCM 和返回有疑问,StackOverflow 上已有一些解释可供参考。应该不难找到它们。
【讨论】:
这是一个从多声道直接音频线 (JavaSound) 中提取单声道的简单方法。用我的 Line6(r) Helix(r) 吉他音效板(8 通道)试了一下,效果很好。我猜它适用于任何类型的 DataTargetLine。在这种情况下,我们基于包含 16 位样本的 AudioFormat 处理数据。希望对您有所帮助。
public ArrayList<byte[]> extract16BitsSingleChannels(byte[] audioBuffer, int channels) {
/* Parameters :
*
* audioBuffer : the buffer that has just been produced by
* your targetDataLine.read();
* channels : the number of channels defined in the AudioFormat you
* use with the line
*
* the AudioFormat which I tested :
* float sampleRate = 44100;
* int sampleSizeInBits = 16;
* int channels = 8;
* boolean signed = true;
* boolean bigEndian = true;
*/
/* let's create a container which will receive our "per channel" buffers */
ArrayList<byte[]> channelsData = new ArrayList<byte[]>();
/* take care of adjusting the size of the audioBuffer so that
* audioBuffer % channels == 0 is true ... because :
*/
final int channelLength=audioBuffer.length/channels;
/* let's create one buffer per channel and place them in the
* container
*/
for (int c=0 ; c < channels ; c++)
{
byte[] channel=new byte[channelLength];
channelsData.add(channel);
}
/* then process bytes from audioBuffer and copy each channels byte
* in its dedicated buffer
*/
int byteIndex=0;
for(int i = 0; i < channelLength; i+=2) //i+=2 for 16 bits=2 Bytes samples
{
for (int c=0 ; c < channels ; c++) {
channelsData.get(c)[i]=audioBuffer[byteIndex]; // 1st Byte
byteIndex++;
channelsData.get(c)[i+1]=audioBuffer[byteIndex]; // 2nd Byte
byteIndex++;
}
}
/* Returns each set of bytes from each channel in its buffer you can use to
write on whatever Byte streamer you like. */
return channelsData;
}
【讨论】: