/******************************************************************************* * Gaggle is Copyright 2010 by Geeksville Industries LLC, a California limited liability corporation. * * Gaggle is distributed under a dual license. We've chosen this approach because within Gaggle we've used a number * of components that Geeksville Industries LLC might reuse for commercial products. Gaggle can be distributed under * either of the two licenses listed below. * * 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 General Public License for more details. * * Commercial Distribution License * If you would like to distribute Gaggle (or portions thereof) under a license other than * the "GNU General Public License, version 2", contact Geeksville Industries. Geeksville Industries reserves * the right to release Gaggle source code under a commercial license of its choice. * * GNU Public License, version 2 * All other distribution of Gaggle must conform to the terms of the GNU Public License, version 2. The full * text of this license is included in the Gaggle source, see assets/manual/gpl-2.0.txt. ******************************************************************************/ package com.geeksville.android; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioTrack; public class TonePlayer { // originally from // http://marblemice.blogspot.com/2010/04/generate-and-play-tone-in-android.html // and modified by Steve Pomeroy <steve@staticfree.info> private final float duration = 0.05f; // seconds private final int sampleRate = 8000; private final int numSamples = (int) (duration * sampleRate); private final byte toneSound[] = new byte[2 * numSamples]; // private final byte generatedSound[] = new byte[2 * numSamples]; private AudioTrack audioTrack; public TonePlayer(float freqHz) { setFrequency(freqHz); // setDutyCycle(0.3f); createNative(); } public void close() { if (audioTrack.getState() == AudioTrack.PLAYSTATE_PLAYING) audioTrack.stop(); audioTrack.release(); } /* * // / What percentage of time is the tone on void setDutyCycle(float onTime) * { // We copy some number of the tone bytes followed by 1-onTime of zero // * bytes int splitPoint = 2 * (int) (numSamples * onTime); * * for (int i = 0; i < splitPoint; i++) generatedSound[i] = toneSound[i]; * * for (int j = splitPoint; j < 2 * numSamples; j++) generatedSound[j] = 0; } */ // / @param freqOfTone in Hz void setFrequency(float freqOfTone) { // fill out the array int idx = 0; for (int i = 0; i < numSamples; ++i) { double dVal = Math.sin(2 * Math.PI * i / (sampleRate / freqOfTone)); // convert to 16 bit pcm sound array // assumes the sample buffer is normalised. // scale to maximum amplitude final short val = (short) ((dVal * 32767)); // in 16 bit wav PCM, first byte is the low order byte toneSound[idx++] = (byte) (val & 0x00ff); toneSound[idx++] = (byte) ((val & 0xff00) >>> 8); } } private void createNative() { audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, numSamples, AudioTrack.MODE_STATIC); // audioTrack.write(generatedSound, 0, generatedSound.length); audioTrack.write(toneSound, 0, toneSound.length); audioTrack.setStereoVolume(audioTrack.getMaxVolume(), audioTrack.getMaxVolume()); audioTrack.setNotificationMarkerPosition(numSamples - 1); } public void play() { audioTrack.stop(); audioTrack.reloadStaticData(); audioTrack.play(); } }