Hamza Zaidi Hamza Zaidi - 6 months ago 31
Java Question

Generate Sine Tone with sweep - Android

I am trying to generate sine tone with sweep. I am using the code below which i got from here. The problem is, i can hear sound that is above 200Hz but i cannot hear tone that is below 200Hz (like 20hz or 50Hz).
Please help me to generate accurate sine tone.

private final int sampleRate = 44100;


public void generateTone(double startFreq, double endFreq, float duration)
{
double dnumSamples = duration * sampleRate;
dnumSamples = Math.ceil(dnumSamples);
numSamples = (int) dnumSamples;
double sample[] = new double[numSamples];

double currentFreq = 0,numerator;

for (int i = 0; i < numSamples; ++i) {
numerator = (double) i / (double) numSamples;
currentFreq = startFreq + (numerator * (endFreq - startFreq))/2;
if ((i % 1000) == 0) {
Log.e("Current Freq:", String.format("Freq is: %f at loop %d of %d", currentFreq, i, numSamples));
}
sample[i] = Math.sin(2 * Math.PI * i / (sampleRate / currentFreq));
}

generatedSnd = new byte[2 * numSamples];
int idx = 0;
for (final double dVal : sample) {
// scale to maximum amplitude
final short val = (short) ((dVal * 32767));
// in 16 bit wav PCM, first byte is the low order byte
generatedSnd[idx++] = (byte) (val & 0x00ff);
generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);

}
}

Answer

Your code will be more robust if you keep track of the current position in the sine wave, and increment it based on the current frequency, instead of calculating the position each sample relative to the starting position.

double currentPos = 0.0;
for (int i = 0; i < numSamples; ++i) {
    numerator = (double) i / (double) numSamples;
    currentFreq = startFreq + (numerator * (endFreq - startFreq))/2;
    if ((i % 1000) == 0) {
        Log.e("Current Freq:", String.format("Freq is:  %f at loop %d of %d", currentFreq, i, numSamples));
    }
    currentPos += 2 * Math.PI * (currentFreq / sampleRate);
    sample[i] = Math.sin(currentPos);
}

This avoids a problem with an decrease in the frequency potentially causing the current position to move backwards.

If you want the tone to fade in over a certain number of samples you can add this code:

int fadeInSamples = 5000;
double fadeIn = (i < fadeInSamples) ? (double)i / (double)fadeInSamples : 1.0;

sample[i] = Math.sin(currentPos) * fadeIn;