Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android AudioTrack does not play all samples

I'm using AudioTrack to play a sequence of sine waves, but when I run it on my HTC M9, it plays only part of the samples, and how long it will play is random. e. g. I have 20 tones to play, but it only plays like 2 to 17.5 tones of them. And yes it even will stop in middle of a tone.

Here is my code, from another answer:

    ArrayList<double[]> samples = new ArrayList<>();
    int numSamples = 0;
    for (final ToneSegment seg : sequence) {
        int num =  seg.getDuration() * sampleRate / 1000;
        double[] sample = new double[num];
        for (int i = 0; i < num; ++i) {
            sample[i] = Math.sin(2 * Math.PI * i * seg.getPitch() / sampleRate);
        }
        samples.add(sample);
        numSamples += num;
    }

    byte generatedSnd[] = new byte[2 * numSamples];
    int idx = 0;
    for (double[] sample : samples) {
        for (final double dVal : sample) {
            final short val = (short) ((dVal * 32767));
            generatedSnd[idx++] = (byte) (val & 0x00ff);
            generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
        }
    }

    audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
            sampleRate, AudioFormat.CHANNEL_OUT_MONO,
            AudioFormat.ENCODING_PCM_16BIT, generatedSnd.length,
            AudioTrack.MODE_STATIC);
    audioTrack.write(generatedSnd, 0, generatedSnd.length);
    audioTrack.play();

Does anyone have any idea? Thanks!

like image 518
Romulus Urakagi Ts'ai Avatar asked Jan 19 '16 10:01

Romulus Urakagi Ts'ai


People also ask

Can Android audiotrack handle linear PCM audio?

However, most low-level audio APIs including Android’s AudioTrack can only accept linear PCM. That’s why if we can’t keep the entire sample in memory, we have to deal with streaming, circular buffers and other clever ways to feed audio to the API.

Why play WAV audio on an audiotrack?

There may be various reasons why you want to play WAV audio on an AudioTrack. Sometimes the size limitations of SoundPool or the latency and high resource usage of MediaPlayer will make you consider going that way. Sometimes you need to modify the audio or mix it on the fly.

What is the problem with audiotrack?

However, the problem now is getting that data from a source. Many applications that need to use AudioTrack do not generate PCM audio from scratch (an example of an app that does that would be Ethereal Dialpad and other similar apps).

Why is there a click when downsampling an audio track?

When changing sample rates after an audio track is created, differences of around 5 to 10 percent from the original rate may trigger a filter recomputation when downsampling (to properly suppress aliasing). This can consume computing resources and may cause an audible click if the filter is replaced in real time.


1 Answers

You are using AudioTrack.MODE_STATIC that is meant for short sounds and low-latency requirements while you should use AudioTrack.MODE_STREAM. AudioTrack.MODE_STREAM is meant for longer streams, but I do not know how long your samples are. So you can try and change AudioTrack:

audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
        sampleRate, AudioFormat.CHANNEL_OUT_MONO,
        AudioFormat.ENCODING_PCM_16BIT, generatedSnd.length,
        AudioTrack.MODE_STREAM);

Also The AudioTrack requires the buffer size in bytes, a short needs to be multiplied by two to calculate the correct amount of required bytes. You could hack it in like this :

audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
        sampleRate, AudioFormat.CHANNEL_OUT_MONO,
        AudioFormat.ENCODING_PCM_16BIT, generatedSnd.length*2,
        AudioTrack.MODE_STREAM);
like image 65
jobbert Avatar answered Oct 30 '22 02:10

jobbert