2

I'm trying to generate and play a square wave. I'm generating the signal and then using

track = new AudioTrack(AudioManager.STREAM_MUSIC,
                sampleRate, AudioFormat.CHANNEL_CONFIGURATION_MONO,
                AudioFormat.ENCODING_PCM_16BIT, minSize,
                AudioTrack.MODE_STREAM);    
track.write(signal, 0, signal.length);

and then calling track.play(). The problem is it only plays once. It looks like there is a method to set the loop points, but I don't know what to put in for the frames.

I have also tried calling track.write() and then track.play() in a while loop, but there is a short lag, and I don't think this is the correct way anyway.

What IS the correct way to have a seamless loop?

Matt
  • 2,650
  • 4
  • 36
  • 46

4 Answers4

6

There's a very similar question: https://stackoverflow.com/questions/4241724/androidaudiotrack-setlooppoint-issue

If I read the Android docs correctly, you are using 16-bit samples, so the signal.length/2 is the number of samples. I'd try:

track.setLoopPoints(0, signal.length/2, -1);
Community
  • 1
  • 1
Femi
  • 64,273
  • 8
  • 118
  • 148
  • Still no luck... I've tried setting the size of the buffer up to 10x the minimum. Am I calling the setLoopPoints from the wrong place? I have it just after write and before play. It always seems to return -3 no matter what I put into it. – Matt Apr 27 '11 at 01:34
  • Invalid operation.....yeaaah...I think you need to use MODE_STATIC, I don't believe the system knows what to do with a loop on MODE_STREAM. – Femi Apr 27 '11 at 01:40
  • That was it! It's looping now. There is still a little pause between the loops though, is there a way to get rid of this? – Matt Apr 27 '11 at 01:45
  • Try track.setLoopPoints(0, signal.length/2-1, -1); ? You'll lose a little bit of the audio, but if you really care then (carefully) splice the beginning of your track onto the end (so the track data is longer) and then keep the loop frame length. – Femi Apr 27 '11 at 01:51
  • It's still there, it almost sounds like a tapping noise. I checked my buffer and the first value was a 0. I removed that, but the noise is still there... Hmmm. The signal is just a square wave, so there shouldn't be any extra values in there besides the min/max ones. – Matt Apr 27 '11 at 02:07
1

To loop in MODE_STREAM, wait until your write loop is finished. Then set loop points, then call play again. Nothing I have done with looping, or even non-looping AudioTrack, has cured the click on start.

R Earle Harris
  • 985
  • 9
  • 17
0

To loop the audio file infinite times set loop to -1. To remove a delay while looping an audio file use the SoundPool class instead of MediaPlayer.

Ben
  • 51,770
  • 36
  • 127
  • 149
0

I faced the same problem now and seems loop doesn't work well for me, there is always a little "break" between loop, then I try to continue generate sound and feed the audiotrack, it works for me:

class ToneGenerator {
    int sampleRate = 8000;
    double sample[] = null;
    byte generatedSnd[] = null;
    int m_ifreq = 400;
    Thread m_PlayThread = null;
    boolean m_bStop = false;
    AudioTrack m_audioTrack = null;
    int m_play_length = 1000;//in seconds

    static public void PlayTone(int freq, int play_length) {
        ToneGenerator player = new ToneGenerator();
        player.m_ifreq = freq;
        player.m_play_length = play_length;
        player.play();
    }

    synchronized void stop() {
        m_bStop = true;
        if (m_PlayThread != null) {
            try {
                m_PlayThread.interrupt();
                m_PlayThread.join();
                m_PlayThread = null;
            } catch (Exception e) {

            }
        }
        if (m_audioTrack != null) {
            m_audioTrack.stop();
            m_audioTrack.release();
            m_audioTrack = null;
        }
    }

    synchronized void play() {
        m_bStop = false;
        m_PlayThread = new Thread() {
            public void run() {
                try {
                    int iToneStep = 0;

                    m_audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                            sampleRate, AudioFormat.CHANNEL_OUT_MONO,
                            AudioFormat.ENCODING_PCM_16BIT, 2 * sampleRate,
                            AudioTrack.MODE_STREAM);

                    while (!m_bStop && m_play_length-- > 0) {
                        genTone(iToneStep++);

                        m_audioTrack.write(generatedSnd, 0, generatedSnd.length);
                        if (iToneStep == 1) {
                            m_audioTrack.play();
                        }
                    }
                } catch (Exception e) {
                    Log.e("Tone", e.toString());
                } catch (OutOfMemoryError e) {
                    Log.e("Tone", e.toString());
                }

            }
        };
        m_PlayThread.start();
    }

    //Generate tone data for 1 seconds
    synchronized void genTone(int iStep) {
        sample = new double[sampleRate];

        for (int i = 0; i < sampleRate; ++i) {
            sample[i] = Math.sin(2 * Math.PI * (i + iStep * sampleRate) / (sampleRate / m_ifreq));
        }

        // convert to 16 bit pcm sound array
        // assumes the sample buffer is normalised.
        generatedSnd = new byte[2 * sampleRate];
        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);
        }
    }

}
Gerry
  • 86
  • 2
  • 13