如何将字节拆分/组合成音频?

Posted

技术标签:

【中文标题】如何将字节拆分/组合成音频?【英文标题】:How can I split/combine bytes into audio? 【发布时间】:2014-07-23 21:47:49 【问题描述】:

我正在玩 Java 中的音频。我发现常用的AudioFormat 使用两个字节。但是,我不知道如何将字节放在一个 int 中。所以我试着反过来做:

public class SineWave 

    public static void main(String[] args) throws LineUnavailableException 
        int hz = 440;
        int samplerate = 16384;
        int amplitude = 127;

        AudioFormat format = new AudioFormat((float) samplerate, 16, 1, true, true);
        SourceDataLine sdl = Audiosystem.getSourceDataLine(format);

        sdl.open(format, samplerate * 2);
        sdl.start();

        while (true) 
            byte[] toWrite = new byte[samplerate * 2];
            for (int x = 0; x < samplerate; x++) 
                int y = (int) Math.round(amplitude * Math.sin(2 * Math.PI * x * hz / samplerate));
                byte b1 = (byte) (y & 0xFF);
                byte b2 = (byte) ((y >> 8) & 0xFF);
                toWrite[2 * x] = b1;
                toWrite[2 * x + 1] = b2;
//                System.out.printf("%d %d%n", b1, b2);
            
            sdl.write(toWrite, 0, toWrite.length);
        
    

但是,这只适用于127 的幅度。当System.out.printf未注释时,很明显这个幅度只使用了1个字节。当我上升到128 时,我会得到这样的输出(和丑陋的声音):

0 0
21 0
42 0
62 0
80 0
96 0
109 0
118 0
125 0
-128 0
127 0
123 0
115 0
104 0
90 0
73 0
55 0
35 0
13 0

负值类似,符号不变,第二个字节总是-1

我推断这是因为有符号字节和二进制补码,但我仍然无法弄清楚我可以做些什么来解决这个问题。

Java 是如何编写它的音频的?

【问题讨论】:

【参考方案1】:

您在正确的轨道上,尽管您的字节顺序可能会倒退(尝试在 toWrite 分配中交换 b1 和 b2 以查看这是否会使事情听起来更好)。这可以解释为什么事情听起来很糟糕。此外,127 的幅度非常小,因此您应该尝试将其增加到最大值(32767)。

您打印字节的方式可能会增加混乱。将一个有符号的 16 位数字拆分为 2 个有符号的 8 位数字实际上没有任何意义。考虑当 16 位数为 -1 (0xffff) 时,打印出两个有符号字节,得到 -1 (0xff) 和 -1 (0xff)。您最好将字节打印为十六进制值并处理您脑海中的符号。

【讨论】:

我了解签名数字在计算机中的工作原理。我不担心十六进制,因为它对我来说无关紧要。但我认为你是对的,我把字节放在错误的顺序,因为另一种方式是沉默的。这是我的问题。 我想我遇到的最大问题是 127 是一个非常小的幅度。我没有意识到,所以当我交换字节时,我认为这是错误的,因为声音变小了。

以上是关于如何将字节拆分/组合成音频?的主要内容,如果未能解决你的问题,请参考以下文章

将两个字节组合成有符号值(16 位)

将打包的半字节组合成打包的字节

如何在android中将多个图像组合成一个图像?

在java中将两个字节(一个正数和另一个负数)组合成short

如何生成波形表以加快实时音频合成

详解如何使用代码进行音频合成