当我运行以下代码时,我在后台遇到轻微的失真(听起来像是嗡嗡声)。由于其微妙的性质,它使得相信存在字节转换的某种混叠。
AudioFormat = PCM_SIGNED 44100.0 Hz,16位,立体声,4字节/帧,big-endian
注意:代码假定(目前)数据是大端的。
public static void playFreq(AudioFormat audioFormat, double frequency, SourceDataLine sourceDataLine)
{
System.out.println(audioFormat);
double sampleRate = audioFormat.getSampleRate();
int sampleSizeInBytes = audioFormat.getSampleSizeInBits() / 8;
int channels = audioFormat.getChannels();
byte audioBuffer[] = new byte[(int)Math.pow(2.0, 19.0) * channels * sampleSizeInBytes];
for ( int i = 0; i < audioBuffer.length; i+=sampleSizeInBytes*channels )
{
int wave = (int) (127.0 * Math.sin( 2.0 * Math.PI * frequency * i / (sampleRate * sampleSizeInBytes * channels) ) );
//wave = (wave > 0 ? 127 : -127);
if ( channels == 1 )
{
if ( sampleSizeInBytes == 1 )
{
audioBuffer[i] = (byte) (wave);
}
else if ( sampleSizeInBytes == 2 )
{
audioBuffer[i] = (byte) (wave);
audioBuffer[i+1] = (byte)(wave >>> 8);
}
}
else if ( channels == 2 )
{
if ( sampleSizeInBytes == 1 )
{
audioBuffer[i] = (byte) (wave);
audioBuffer[i+1] = (byte) (wave);
}
else if ( sampleSizeInBytes == 2 )
{
audioBuffer[i] = (byte) (wave);
audioBuffer[i+1] = (byte)(wave >>> 8);
audioBuffer[i+2] = (byte) (wave);
audioBuffer[i+3] = (byte)(wave >>> 8);
}
}
}
sourceDataLine.write(audioBuffer, 0, audioBuffer.length);
}
答案 0 :(得分:7)
您的评论说该代码假定为big-endian。
从技术上讲,你实际上是以小端输出然而它似乎并不重要,因为通过一个幸运的怪癖,你最重要的字节总是为0。
编辑:进一步解释 - 当你的值达到最大值127时,你应该写(0x00,0x7f),但你的代码的实际输出是(0x7f,0x00),这是32512.这发生了接近正确的 16位最大值32767,但最后8位全为零。最好始终使用32767作为最大值,然后根据需要丢弃底部的8位。
这意味着即使您输出的是16位数据,有效分辨率也只有8位。这似乎是缺乏音质的原因。
我已经制作了一个代码版本,它只是将原始数据转储到一个文件中,并且看不到任何错误的位移本身。符号或丢失位没有意外更改,但有一个与8位样本质量一致的嗡嗡声。
此外,如果您根据样本计数计算波动方程式,然后分别担心字节偏移,那么您的数学运算会更容易:
int samples = 2 << 19;
byte audioBuffer[] = new byte[samples * channels * sampleSizeInBytes];
for ( int i = 0, j = 0; i < samples; ++i )
{
int wave = (int)(32767.0 * Math.sin(2.0 * Math.PI * frequency * i / sampleRate));
byte msb = (byte)(wave >>> 8);
byte lsb = (byte) wave;
for (int c = 0; c < channels; ++c) {
audioBuffer[j++] = msb;
if (sampleSizeInBytes > 1) {
audioBuffer[j++] = lsb;
}
}
}
答案 1 :(得分:2)
我假设您重复调用此代码以播放长音。
你所产生的波是否有可能在写入之前没有完成一段时间?
如果波在完成一个完整的周期之前被“截止”,然后下一个波被写入输出,你肯定会听到一些奇怪的东西,我认为这可能是导致嗡嗡声的原因。
例如:
/-------\ /-------\ /-------\
-----/ \ -----/ \ -----/ \
\ \ \
\----- \----- \-----
注意此波形部分之间的断开连接。这可能会导致嗡嗡声。