生成音调跳过某些频率的功能

时间:2014-12-04 22:47:57

标签: java android audio frequency

以下内容取自Android应用:

    public void genTone(int freq){
        for(int i = 0; i<numSamples; i++){
            samples[i] = Math.pow(-1, (float)(i / (sampleRate/freq)));
        }
        int idx = 0;
        int volume = 32767 * cx/wide;
        for (final double dVal : samples) {
            final short val = (short) ((dVal+1) * volume);

            generatedSnd[idx++] = (byte) (val & 0x00ff);
            generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
            if(isRecording){
                toRec.add((byte)(val & 0x00ff));
                toRec.add((byte)((val & 0xff00) >>> 8));
            }
        }
    }

以上代码是Android应用程序中的Java函数,它生成具有指定频率的方波。频率由整数&#39;音符确定。这是MotionEvent的最后记录位置除以屏幕高度。频率为440 * 2 ^(注意/ 12)。我已经在文本中输出了音符和频率的节目输出,它输出了我想要的内容,但在某些音符中,即使它在文本中输出不同的频率,它听起来完全相同。 8000是一个sampleRate(每秒)太低了吗?这是一个众所周知的错误吗?你有什么可以帮我的吗?

1 个答案:

答案 0 :(得分:1)

主要问题是您需要将句点保留为浮点数,因为8000/789和8000/739否则会舍入到相同的整数:

float period = (float)sampleRate / (float)freq;

for(int i = 0; i<numSamples; i++){
    samples[i] = ((int)(i/period) % 2)==0 ? 0 : 1;
}

作为次要的风格问题,我还建议删除&#34; + 1&#34;从以下行开始,而不是要求cx / wide(你应该真正称之为&#34;获得&#34;)只能在[0,1]范围内:

final short val = (short) ((dVal) * volume);

您的原始代码有效地生成样本为(0,+ 2,0,+ 2,...)因为+1,然后乘以cx/wide,但这会导致您的溢出short val如果cx/wide大于1/2(因为2 * 32767 * 1/2是短片的最大值)。

更常见的做法是将cx/wide指定为(0,1)范围内的增益(其中0 =最小音量和1 =最大音量),并在该函数中强制执行该约束。

第三个问题是您可能只使用输出动态范围的一半。如果输出应该是16位带符号样本(查找它),那么您可以生成原始样本为? -1 : 1而不是0/1。如果输出流接受16位无符号样本,那么您希望将样本保留为0/1,但将volume更改为65535,并使用int而不是{{1} 1}} short