【问题标题】:What is the format of the data you can write to a SourceDataLine?您可以写入 SourceDataLine 的数据格式是什么?
【发布时间】:2013-06-18 00:50:34
【问题描述】:

在java中你可以像这样创建一个SourceDataLine:

AudioFormat af = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100.0, 16, 1, 2, 44100.0, false);       
SourceDataLine sdl = AudioSystem.getSourceDataLine(af);

之后你可以打开然后写入数据:

byte[] data = new byte[1024];
fillwithsounds(data);

sdl.open()
sdl.start()
sdl.write(data, 0, 1024);

这一切都适用于单声道数据。

我想做的是能够编写立体数据,但我在网上找不到任何关于如何更改字节数组才能写入立体数据的文档。

似乎我需要在创建 AudioFormat 时增加通道数量 - 使其成为立体声 - 然后我需要将帧速率减半(否则 Java 会抛出 IllegalArgumentException)

我不明白为什么会这样,也不明白我提供给 DataSourceLine 的数据的新格式应该是什么。

也许有人在音频格式方面的经验比我多一点,无法解释这个问题。提前致谢!

【问题讨论】:

  • 我的理论是,而不是由 Mono-Frame、Mono-Frame、Mono-Frame 组成的字节数组。字节数组现在应该由左帧、右帧、左帧、右帧、左帧、右帧组成。我试图实现这一点,但它没有给我任何明智的东西,而是给了我静态。
  • “之后您可以打开然后向其中写入数据:这一切都适用于单声道数据。” 好的,您就快到了。无论您以原始格式为每个 16 字节帧写什么,都写两次。这实际上是“通过两个扬声器单声道”,但如果你有不同的东西要写到另一个频道,那就写吧。
  • “我试图实现它,但是..” 为了尽快获得更好的帮助,请发布SSCCE

标签: java audio javasound


【解决方案1】:

我使用的立体声格式如下:

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

您可能希望将每帧的字节数加倍,而不是将位编码减半。我不确定 8 位编码听起来像什么,但肯定会比 16 位编码更嘈杂!

生成的文件长度是原来的两倍。然后,您可以获取构成 16 位样本的两字节对,并将它们复制到接下来的两个位置,用于“单声道”播放(两个立体声通道相同)。

给定:

frame = F
little end byte = A
big end byte = B
AB = 16-bit little-endian encoding
left channel = L
right channel = R

你原来的单声道:

F1A、F1B、F2A、F2B、F3A、F3B ...

使用上述格式的立体声:

F1AL、F1BL、F1AR、F1BR、F2AL、F2BL、F2AR、F2BR、F3AL、F3BL、F3AR、F3BR ...

我很可能会混淆左右顺序。但我希望你能明白!

【讨论】:

  • 谢谢,我写了这个函数来实现你的理论,但我得到了一个非常奇怪的结果:pastebin.com/L86ZmXrg我正在使用你在答案第一行中提到的 AudioFormat。我将用我对“极其奇怪的结果”的定义写一条新评论
  • 要看到“一个非常奇怪的结果”,比较 home.coolkev.com/BeforeProgram.mp3home.coolkev.com/AfterProgram.mp3
  • Pastebin 功能看起来不错。我将这两个文件带入了 Audacity。它说它们都使用 32 位编码(不是 16 位)并标记为单声道。因此,您的原始文件每帧使用 4 个字节而不是 2 个。您是否将输出格式设置为 2 个通道?为什么结果是 MONO?我不知道如何在 Java 中将 32 位转换为 16 位。我使用 Audacity 进行复杂的转换(除了单声道到立体声,反之亦然)。您可以扩展循环以将 i 增加 4 并在每个中传输 4 个字节(并相应地调整输出格式,为 2 个通道和每帧 8 个字节)并保留 32 位编码。
  • 对不起,那些文件是回放的录音。我不确定如何从 Java 写回文件,但我可以调查一下。
  • 那么,验证以下内容会很有帮助:向我们展示原始 wav 文件的数据格式,向我们展示用于 SDL 的格式。需要仔细检查所有值是否按预期排列!
【解决方案2】:

我刚刚找到了解决方案,并找到了 Andrew Thompson 的评论来准确解释我需要什么。

我认为我必须每帧编写两次,但让我着迷的是 Java 不允许我只使用我的单声道通道的帧大小。 (它抛出了一个 IllegalArgumentException)

所以我把帧率减半来满足Java,但是我不记得修改字节数组了。

我实现的代码采用“每帧 2 个字节,1 个通道”字节[],并将其转换为“每帧 1 个字节,2 个通道”字节[]。

private static final float LEFT   = -1;
private static final float CENTER = 0;
private static final float RIGHT  = 1;

private byte[] monoToStereo(byte[] data, float pan){
    byte[] output = new byte[data.length];
    for (int i = 0; i < (data.length - 2); i+=2){
        int currentvalue = (data[i+1]*256 + data[i])/(256*2);
        if (pan == LEFT || pan == CENTER){
            output[i] = (byte) currentvalue;
        } else {
            output[i] = 0;
        }
        if (pan == RIGHT || pan == CENTER){
            output[i+1] = (byte) currentvalue;
        } else {
            output[i+1] = 0;
        }
    }
    return output;
}

使用它,我可以播放立体声音频(虽然有柔和的静电,但我可以清楚地听到原始音轨)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-08-05
    • 2012-04-08
    • 1970-01-01
    • 2012-08-20
    • 2019-06-16
    • 1970-01-01
    • 2011-07-11
    相关资源
    最近更新 更多