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
.
上一篇: 带通FIR滤波器
下一篇: 产生音调跳过cretain频率的功能