Java 函数用于生成音调跳过确认频率

Java 函数用于生成音调跳过确认频率,java,android,audio,frequency,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; fo

以下内容摘自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));
            }
        }
    }
public void genTone(int-freq){
对于(int i=0;i>>8);
如果(isRecording){
toRec.add((字节)(val&0x00ff));
toRec.add((字节)((val&0xff00)>>>8));
}
}
}

上面的代码是Android应用程序中的一个Java函数,用于生成具有指定频率的方波。频率由整数“note”确定,该整数是MotionEvent最后记录的位置除以屏幕高度。频率为440*2^(注/12)。我已经让程序在文本中输出了音符和频率,它输出了我想要的,但在某些音符中,即使它在文本中输出了不同的频率,它听起来也完全一样。采样率8000太低(每秒)?这是一个众所周知的错误吗?您能帮我做点什么吗?

主要问题是您需要将期间保留为浮点数,因为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;
}
由于+1,您的原始代码有效地将样本生成为(0,+2,0,+2,…),然后乘以
cx/wide
,但如果
cx/wide
大于1/2(因为2*32767*1/2是short的最大值),这将导致
short val
溢出

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


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

sampleRate是int还是float?@jaket int:8000,这有区别吗?令人钦佩的是,idk如何精确地进行舍入。在每种情况下,cx、wide、numSamples和freq是什么,您希望它们有所不同,但哪些听起来相同?闻起来像是整数溢出。8千赫不是问题,除非你产生一些高频音调。@Scott Dudley numSamples是持续时间(1)*采样器(8000),所以是8000。Wide是屏幕的宽度,cx是motionevent的最后一个x位置。Wide和cx仅用于控制音量,我认为这是正确的。例如,freq=739和freq=783听起来完全相同,尽管它们应该是一个半音。但是cx和wide究竟是什么呢?这可能很重要。您的建议是编码\u PCM\u 16位,这将是无符号的。它不是已经产生了介于1和-1之间的结果吗?等等,编码是否接受无符号?您原始的
samples[]
应该是-1,1,-1,-1,但您的
dVal+1
将其转换为0,2,0,2。它应该是无符号的。如果有疑问,可以尝试生成0x7fff、0x8000、0x7fff、0x8000的样本。如果它听起来像一个响亮的4KHz音调,它是有符号的。如果你什么都听不到,那就是无符号的。我修改了我的代码,生成了-1和1之间的方波,然后乘以32767*cx/wide(顺便说一句,音量和增益之间的区别是什么?它们不都是振幅吗?),声音非常清晰。实际上,切换类型转换解决了这个问题。非常感谢。
final short val = (short) ((dVal) * volume);