Nop0x Nop0x - 1 month ago 18
Android Question

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!

Answer

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;
}