音调生成器生成第二个音调

时间:2018-06-10 09:27:57

标签: java android javasound android-audiomanager audiotrack

我正在尝试为等时脉动声音制作一个简单的信号发生器。

基本上,“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附近有一个相当大的峰值以及更高的峰值。

enter image description here

代码现在只是使用音高,我删除了节拍Freq:

2 个答案:

答案 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;。