package com.cellbots;
/*
* Robot control console. Copyright (C) 2010 Darrell Taylor & Eric Hokanson
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import java.util.Arrays;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.util.Log;
// TODO: Auto-generated Javadoc
/**
* The Class PulseGenerator.
*/
public class PulseGenerator implements Runnable
{
//
/** The sample rate. 44100hz is native on g1 */
private int sampleRate;
/** The MI n_ puls e_ width. */
public int MIN_PULSE_WIDTH;
/** The MA x_ puls e_ width. */
public int MAX_PULSE_WIDTH;
/** The left channel pulse width. */
private int pulseWidthArray[];
/** The pulse interval. */
private int pulseInterval;
/** The buffer pulses. */
private int bufferPulses = 2;
/** The ammount modulation. */
private int modulation = 200;
/** The max volume */
private int volume = Short.MAX_VALUE;
/** Are we playing sound right now? */
private boolean playing = false;
/** Do we need to update the buffer? */
private boolean bufferChanged = false;
/** The noise audio track. */
private AudioTrack noiseAudioTrack;
/** The bufferlength. */
private int bufferlength; // 4800
/** The audio buffer. */
private short[] audioBuffer;
/** The left channel buffer. */
private short[] leftChannelBuffer;
/** The right channel buffer. */
private short[] rightChannelBuffer;
private static String TAG = "Servo Pulse Generator";
/**
* Instantiates a new pulse generator.
*/
public PulseGenerator()
{
sampleRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
MIN_PULSE_WIDTH = sampleRate / 1200;
MAX_PULSE_WIDTH = sampleRate / 456;
pulseWidthArray = new int[4];
Arrays.fill(pulseWidthArray, ( MIN_PULSE_WIDTH + MAX_PULSE_WIDTH ) / 2);
pulseInterval = sampleRate / 50;
bufferlength = AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT);
noiseAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT, bufferlength, AudioTrack.MODE_STREAM);
sampleRate = noiseAudioTrack.getSampleRate();
Log.i(TAG, "BufferLength = " + Integer.toString(bufferlength));
Log.i(TAG, "Sample Rate = " + Integer.toString(sampleRate));
audioBuffer = new short[bufferlength];
leftChannelBuffer = new short[bufferlength / 2];
rightChannelBuffer = new short[bufferlength / 2];
noiseAudioTrack.play();
}
private void generatePCM(int pulseWidth, int negPulseWidth, int pulseInterval, int volume, int modulation, short buffer[], int bufferLength, int lastChanged)
{
int i = 0;
int j = 0;
while (i < bufferLength)
{
j = 0;
if (lastChanged % 2 == 0)
{
while (j < pulseWidth)// && i < bufferLength)
{
buffer[i] = (short) ( ( volume ) );
i++;
j++;
}
while (j < pulseInterval )// && i < bufferLength)
{
buffer[i] = (short) ( ( -volume ) );
i++;
j++;
}
}
else
{
while (j < negPulseWidth)
{
// we have to modulate the signal a bit because the sound card freaks
// out if it goes dc
buffer[i] = (short) ( ( -volume ) );
i++;
j++;
}
while (j < pulseInterval )// && i < bufferLength)
{
buffer[i] = (short) ( ( volume ) );
i++;
j++;
}
}
}
bufferChanged = true;
}
public void run()
{
generatePCM(pulseWidthArray[0], pulseWidthArray[1], pulseInterval, volume, modulation, leftChannelBuffer, pulseInterval * bufferPulses, 0);
generatePCM(pulseWidthArray[2], pulseWidthArray[3], pulseInterval, volume, modulation, rightChannelBuffer, pulseInterval * bufferPulses, 2);
while (true)
{
int bufferlength = pulseInterval * bufferPulses * 2;
if (playing)
{
for (int i = 0; i < bufferlength && bufferChanged; i += 2)
{
audioBuffer[i] = leftChannelBuffer[i / 2];
audioBuffer[i + 1] = rightChannelBuffer[i / 2];
}
}
else
{
for (int i = 0; i < bufferlength; i++)
{
audioBuffer[i] = (short) ( 0 );
}
}
noiseAudioTrack.write(audioBuffer, 0, bufferlength);
}
}
/**
* Stop.
*/
public void stop()
{
playing = false;
noiseAudioTrack.stop();
noiseAudioTrack.release();
}
/**
* Toggle playback.
*/
public void togglePlayback()
{
playing = !playing;
}
/**
* Checks if is playing.
*
* @return true, if is playing
*/
public boolean isPlaying()
{
return playing;
}
/**
* Sets the left pulse percent.
*
* @param percent
* the new left pulse percent
*/
public void setPulsePercent(int percent, int i)
{
if (i< 0 || i > 4)
{
Log.e(TAG,"Servo index out of bounds, should be between 0 and 3");
return;
}
this.pulseWidthArray[i] = MIN_PULSE_WIDTH + ( ( percent * ( MAX_PULSE_WIDTH - MIN_PULSE_WIDTH ) ) / 100 );
if (i < 2)
{
generatePCM(pulseWidthArray[0], pulseWidthArray[1], pulseInterval, volume, modulation, leftChannelBuffer, pulseInterval * bufferPulses, i);
}
else
{
generatePCM(pulseWidthArray[2], pulseWidthArray[3], pulseInterval, volume, modulation, rightChannelBuffer, pulseInterval * bufferPulses, i);
}
}
/**
* Gets the pulse percent.
*
* @return the pulse percent
*/
public int getPulsePercent(int i)
{
return ( ( pulseWidthArray[i] - MIN_PULSE_WIDTH ) / ( MAX_PULSE_WIDTH - MIN_PULSE_WIDTH ) ) * 100;
}
/**
* Gets the pulse ms.
*
* @return the pulse ms
*/
public float getPulseMs(int i)
{
return ( (float) pulseWidthArray[i] / sampleRate ) * 1000;
}
/**
* Gets the pulse samples.
*
* @return the pulse samples
*/
public int getPulseSamples(int i)
{
return pulseWidthArray[i];
}
}