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

时间:2014-07-23 21:47:50

标签: java audio

我正在玩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 个答案:

答案 0 :(得分:1)

你是在正确的轨道上,虽然你可能会向后排序你的字节(尝试在toWrite分配中交换b1和b2,看看是否能让事情听起来更好)。这可以解释为什么事情听起来不好。此外,127的幅度非常小,因此您应该尝试将其增加到最大值(32767)。

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