我正在尝试为等时脉动声音制作一个简单的信号发生器。
基本上,“beatFrequency”控制主(音调)频率的幅度变化。
除了对于4-5 K Hz以上的某些音高频率外,它的效果非常好。 它不是适用于所有频率,但对于很多频率我可以肯定地听到第二声。
这可能是什么?某种共鸣?我尝试提高采样率,但它没有改变任何东西,如果我理解正确的话,使用44100应该足够大约20 KHz?
我真的无法自己弄明白,所以感谢所有的帮助!
以下是beatFreequency 1 Hz,Pitch frequency 5000 Hz和samplerate 44100的示例代码。
public void playSound() {
double beatFreq = 1;
double pitch = 5000;
int mSampleRate = 44100;
AudioTrack mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, mSampleRate,
AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT,
256, AudioTrack.MODE_STREAM);
int loopLength = 2 * this.mSampleRate;
while (isPlaying) {
double[] mSound = new double[loopLength];
for (int i = 0; i < loopLength; i = i + 1) {
mSound[i] = beatFreq*Math.sin((1.0*Math.PI * i/(this.mSampleRate/pitch)));
mBuffer[i] = (short) (mSound[i] * Short.MAX_VALUE);
}
mAudioTrack.play();
mAudioTrack.write(mBuffer, 0, loopLength);
}
}
这是(添加)当我播放音调4734Hz时的频率图像。例如,在1100 Hz附近有一个相当大的峰值以及更高的峰值。
代码现在只是使用音高,我删除了节拍Freq:
答案 0 :(得分:0)
在您的代码中,您使用beatFreq*Math.sin((1.0*Math.PI * i/(this.mSampleRate/pitch)));
来确定频率(此处缺少某种分配)
但是,mSampleRate和pitch是int值,导致整数除法而不是双除法。对于音高和采样率的特殊情况,这将导致频率低于预期。对于更大的音高值,效果会变得更糟。
尝试使用double而不是int,这应该可以解决问题。
答案 1 :(得分:0)
在更好地理解问题之后重写答案,OP想要进行调幅。
是的,Java可以进行幅度调制。我做了一个可通过的板球声,例如,采用4.9KHz音调并以66Hz调制音量,并将得到的音调给出AR信封。
在您的代码中,变量beatFreq在整个for循环中保持不变。你不打算随着时间的推移改变它吗?
我认为您应该同时在其自己的函数中计算beatFreq波值(但也使用变化的i),并将该结果(缩放到0到1的范围)与针对更快的音调计算的值相乘。
**编辑
要将冗余计算移出内循环,可能存在以下情况:
将以下内容作为实例变量:
private double incr;
private double incrSum;
private final double TWO_PI = Math.PI * 2;
在构造函数中只进行一次以下计算:
incr = pitch / audioFmt.getSampleRate();
incr *= TWO_PI;
这假定pitch
是Hertz中所述的值,并且`audioFormat&#39;是正在使用的Java AudioFormat。使用Android,我不知道如何存储或访问音频格式采样率。
有了这个,你可以有一个方法,用一些非常简单的代码返回下一个双PCM值:
private double getNextSinePCM()
{
incrSum += incr;
if (incrSum > TWO_PI)
{
incrSum -= TWO_PI;
}
return Math.sin(incrSum);
}
注意:请勿按照评论中的说明将incrSum
重置为零。这可能会引入不连续性。
如果你有第二个音,它将获得自己的增量和运行总和。这两个结果,然后你可以将它们相乘得到幅度调制。
现在,关于如何正确转换返回到Android可以使用的PCM双倍值的问题,我无法给出明确的答案,因为我没有运行Android。
只是评论:在我看来,你对使用声音充满热情,但可能是自学成才或者在基本编程技术方面有所欠缺。在循环外部移动冗余计算是一种基本的。因此,能够制作简单的测试用例来测试假设和故障排除。在你前进的过程中,我想鼓励你花一些时间来发展这些基础知识并追求对声音的兴趣!您可以查看StackOverflow代码读取组作为更多提示的资源。我也是自学成才,并从那里学到了很多东西以及JavaRanch的代码阅读课程,名为&#34; CattleDrive&#34;。