Search code examples
javaandroidaudioaudiotrackandroid-audiomanager

How create a 50hz square wave on android and play it


I'm currently writing a android app for mobile phones to control 2 servo motors.

Therefore I need to create a square wave at 50hz with a high amplitude. I alread had a look at some example code of the AudioManager and AudioTrack class, but I dont really get the clue on how to achieve a basic square wave at 50hz with a hearable amplitude.

Here's what i got so far:

package com.example.rollerball;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.support.v7.app.ActionBarActivity;

public class ToneGenerator
{   
    Thread t;
    int sr = 44100;
    boolean isRunning = true;

    public void startTone()
    {
        isRunning = true;
        t = new Thread() {
            public void run() {
                // set process priority
                setPriority(Thread.MAX_PRIORITY);
                int buffsize = AudioTrack.getMinBufferSize(sr,
                        AudioFormat.CHANNEL_OUT_MONO,
                        AudioFormat.ENCODING_PCM_16BIT);
                // create an audiotrack object
                AudioTrack audioTrack = new AudioTrack(
                        AudioManager.STREAM_MUSIC, sr,
                        AudioFormat.CHANNEL_OUT_MONO,
                        AudioFormat.ENCODING_PCM_16BIT, buffsize,
                        AudioTrack.MODE_STREAM);

                short samples[] = new short[buffsize];
                int amp = 10000;
                double twopi = 8. * Math.atan(1.);
                double fr = 440.f;
                double ph = 0.0;
                // start audio
                audioTrack.play();

                while (isRunning) {

                    for (int i = 0; i < buffsize; i++) {
                        samples[i] = (short) (amp * Math.sin(ph));
                        ph += twopi * fr / sr;
                    }
                    audioTrack.write(samples, 0, buffsize);
                }
                audioTrack.stop();
                audioTrack.release();
            }
        };
        t.start();
    }

    public void stopTone(){   
           isRunning = false;
           try {
             t.join();
           } catch (InterruptedException e) {
             e.printStackTrace();
           }    
          t = null;
        }
}

Maybe some of you guys out there can help me!

Thanks in Advance!


Solution

  • As it stands your code generates a nice clean sine wave with peak amplitude of ±10000. The maximum sample value that can be represented in 16-bit PCM is ±1^15-1 = ±32767 which is ~-10dB of FSD.

    You want a square-wave. The code below achieves it (not particularly efficiently).

    for (int i = 0; i < buffsize; i++) {
        short s = (amp * Math.sin(ph));
        if (s > 0.0) {
            sample[i] = 32767;
        };
    
        if (s < 0.0) {
            sample[i] = -32767;
        }
        ph += twopi * fr / sr;
    }