Reputation: 2680
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?
Upvotes: 2
Views: 5375
Reputation: 86
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);
}
}
}
Upvotes: 0
Reputation: 983
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.
Upvotes: 1
Reputation: 129
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
.
Upvotes: 0
Reputation: 64700
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);
Upvotes: 6