Function to generate tone skipping cretain frequencies

The following was taken from an Android app:

    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));
            }
        }
    }

The above code is a Java function in an Android app the generate a square wave with a specified frequency. The frequency is determined by an integer 'note' which is the last recorded position of a MotionEvent divided by the height of the screen. The frequency is 440 * 2^(note/12). I've made the program output in text the note and frequency, and it outputs what I want it to, but at certain notes, even though it outputs a different frequency in text, it sounds exactly the same. Is 8000 too low a sampleRate(per second)? Is this a well-known bug? Anything you can help me with?


The primary issue is that you need to leave the period as a float, because 8000/789 and 8000/739 otherwise round to the same integer:

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

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

As a secondary stylistic issue, I would also suggest removing the "+1" from the following line and instead requiring that cx/wide (which you should really call "gain") be exclusively in the range [0,1]:

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

Your original code was effectively generating samples as (0, +2, 0, +2,...) because of the +1, and then multiplying by cx/wide , but this would cause an overflow in your short val if cx/wide were ever greater than 1/2 (because 2*32767*1/2 is the maximum value of a short).

A more common practice would be to specify cx/wide as a gain in the range of (0,1) (where 0=min volume and 1=max volume) and also to enforce that constraint in the function.

A tertiary issue is that you are probably only using half of the dynamic range of the output. If the output is supposed to be 16-bit signed samples (look it up), then you can generate the original samples as ? -1 : 1 ? -1 : 1 instead of 0/1. If the output stream accepts 16-bit unsigned samples, then you'd want to leave the samples as 0/1, but change volume to 65535, and use an int instead of a short for val .

链接地址: http://www.djcxy.com/p/62146.html

上一篇: 带通FIR滤波器

下一篇: 产生音调跳过cretain频率的功能