1

I'm having some trouble with generating a sound with a specific frequency. I've set up my app so you can slide back and forth on a seekbar to select a specific frequency, which the app should then use to generate a tone.

I'm currently getting a tone just fine, but it's a complete different frequency than the one you set it to. (and I know that the problem is not passing the value from the seekbar to the "tone generating process", so it must be the way I generate the tone.)

What's wrong with this code? Thanks

private final int duration = 3; // seconds
 private final int sampleRate = 8000;
 private final int numSamples = duration * sampleRate;
 private final double sample[] = new double[numSamples];
 double dbFreq = 0; // I assign the frequency to this double
 private final byte generatedSnd[] = new byte[2 * numSamples];

 ...


    void genTone(double dbFreq){

        // fill out the array
        for (int i = 0; i < numSamples; ++i) {
            sample[i] = Math.sin(2 * Math.PI * i / (sampleRate/dbFreq));
        }

        // convert to 16 bit pcm sound array
        // assumes the sample buffer is normalised.
        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);
        }
    }

    void playSound(){
        final AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                sampleRate, AudioFormat.CHANNEL_CONFIGURATION_MONO,
                AudioFormat.ENCODING_PCM_16BIT, numSamples,
                AudioTrack.MODE_STATIC);
        audioTrack.write(generatedSnd, 0, generatedSnd.length);
        audioTrack.play();
   }
Jakob Harteg
  • 9,587
  • 15
  • 56
  • 78
  • a completely wild guess here: maybe you need to use "unsigned bytes"? In which case, due to the lack of unsigned bytes in Java, you could use the technique described here: http://stackoverflow.com/questions/11088/what-is-the-best-way-to-work-around-the-fact-that-all-java-bytes-are-signed – DigCamara Mar 22 '13 at 20:18

1 Answers1

2

Your code is actually correct but have a look at the Sampling theorem.

In short: you must set the sampling rate higher than 2*max_frequency. So set sampleRate = 44000 and you should hear even higher frequencies correct.

j.holetzeck
  • 4,048
  • 2
  • 21
  • 29
  • Thanks, that worked! I have one more question if you have the time. I code posted in the question is pretty much a pull from a source code, with just a few changes. Can you tell what to do in order to make the sound continue until a button is clicked? I can't really figure this out, because the duration int is multiplied with a lot of other values. – Jakob Harteg Mar 24 '13 at 18:56