/******************************************************************************* * 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.gaggle; import java.util.Observable; import java.util.Observer; import android.content.Context; import android.content.SharedPreferences; import android.os.Handler; import android.os.Looper; import android.preference.PreferenceManager; import android.util.Log; import com.geeksville.android.PreferenceUtil; import com.geeksville.android.TonePlayer; import com.geeksville.location.BarometerClient; import com.geeksville.location.IBarometerClient; public class AudioVario implements Observer, Runnable, SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = "AudioVario"; private TonePlayer liftTone; private TonePlayer sinkTone; private TonePlayer curTone; private IBarometerClient baro; Handler handler; /** Or <0 for disabled */ long beepDelayMsec = -1; boolean isPlaying = false; float minSinkThreshold = 2.0f; float maxSinkThreshold = 4.0f; float minSinkHz = 1f, maxSinkHz = 10f; float minLiftThreshold = 0.5f; float maxLiftThreshold = 4.0f; float minLiftHz = 1f, maxLiftHz = 10f; private Context context; /** * @see com.geeksville.info.InfoField#onCreate(android.app.Activity) */ public void onCreate(Context context, Looper looper) { this.context = context; if (context != null) { handler = new Handler(looper); PreferenceManager.getDefaultSharedPreferences(context) .registerOnSharedPreferenceChangeListener(this); createFromPreferences(); } } private void createFromPreferences() { onDestroy(); // Tear down old devices if (PreferenceUtil.getBoolean(context, "use_audible_vario", true)) { liftTone = new TonePlayer(PreferenceUtil.getFloat(context, "liftTone2", 1100f)); sinkTone = new TonePlayer(PreferenceUtil.getFloat(context, "sinkTone", 220f)); minSinkThreshold = PreferenceUtil.getFloat(context, "minSinkThreshold", 2.0f); maxSinkThreshold = PreferenceUtil.getFloat(context, "maxSinkThreshold", 4.0f); minSinkHz = PreferenceUtil.getFloat(context, "minSinkHz", 1f); maxSinkHz = PreferenceUtil.getFloat(context, "maxSinkHz", 10f); minLiftThreshold = PreferenceUtil.getFloat(context, "minLiftThreshold", 0.5f); maxLiftThreshold = PreferenceUtil.getFloat(context, "maxLiftThreshold", 4.0f); minLiftHz = PreferenceUtil.getFloat(context, "minLiftHz", 1f); maxLiftHz = PreferenceUtil.getFloat(context, "maxLiftHz", 10f); baro = BarometerClient.create(context); if (baro != null) baro.addObserver(this); // testTones(); } } /** * @see com.geeksville.info.InfoField#onHidden() */ public void onDestroy() { if (baro != null) baro.deleteObserver(this); if (liftTone != null) liftTone.close(); if (sinkTone != null) sinkTone.close(); } @Override public void update(Observable observable, Object data) { updateTone(baro.getVerticalSpeed()); } public void testTones() { Thread t = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub for (float f = -maxSinkThreshold; f <= maxLiftThreshold; f += 0.2f) { updateTone(f); try { Thread.sleep(2 * 1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }, "TestTones"); t.start(); } private static float interpolate(float x0, float x1, float y0, float y1, float x) { return y0 + ((x - x0) * y1 - (x - x0) * y0) / (x1 - x0); } private void updateTone(float vs) { float beepHz; if (vs >= minLiftThreshold) { if (vs > maxLiftThreshold) vs = maxLiftThreshold; // clamp beepHz = interpolate(minLiftThreshold, maxLiftThreshold, minLiftHz, maxLiftHz, vs); curTone = liftTone; } else if (vs <= -minSinkThreshold) { if (vs < -maxSinkThreshold) vs = maxSinkThreshold; // clamp beepHz = interpolate(minSinkThreshold, maxSinkThreshold, minSinkHz, maxSinkHz, -vs); curTone = sinkTone; } else beepHz = -1f; // Turn tone off beepDelayMsec = (int) (1000 / beepHz); Log.d(TAG, "vs=" + vs + " -> hz=" + beepHz + " delay=" + beepDelayMsec); startTone(); } private synchronized void startTone() { if (beepDelayMsec > 0) { // Prime the pump if necessary if (!isPlaying) { isPlaying = true; curTone.play(); // Start the new delay handler.postDelayed(this, beepDelayMsec); } } } /** Called when our timer fires */ @Override public synchronized void run() { // Queue up the next event isPlaying = false; startTone(); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { createFromPreferences(); } }