Android Open Source - libsoundfinder Sound Finder






From Project

Back to project page libsoundfinder.

License

The source code is released under:

GNU General Public License

If you think the Android project libsoundfinder listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package de.uvwxy.soundfinder;
// w ww  .  jav  a  2s. c  om
import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.location.Location;
import android.media.AudioManager;
import android.media.SoundPool;
import android.media.SoundPool.OnLoadCompleteListener;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
import de.uvwxy.audio.AudioParameters;
import de.uvwxy.sensors.CompassReader;
import de.uvwxy.sensors.SensorReader.SensorResultCallback;
import de.uvwxy.sensors.location.GPSWIFIReader;
import de.uvwxy.sensors.location.LocationReader.LocationResultCallback;
import de.uvwxy.sensors.location.LocationReader.LocationStatusCallback;

@SuppressWarnings("unused")
public class SoundFinder extends Activity {
  private static final String EXTRA_LOCATION_LAT = "EXTRA_LOCATION_LAT";
  private static final String EXTRA_LOCATION_LON = "EXTRA_LOCATION_LON";
  private static final String EXTRA_LOCATION_ALT = "EXTRA_LOCATION_ALT";
  private static final String EXTRA_LOCATION_PRECISION = "EXTRA_LOCATION_PRECISION";
  private static final String EXTRA_LOCATION_MAX_DISTANCE = "EXTRA_LOCATION_MAX_DISTANCE";
  private static final String EXTRA_LOCATION_DESTINATION_RADIUS = "EXTRA_LOCATION_DESTINATION_RADIUS";

  private int origHeight = -1;
  private TextView vBarDistance = null;
  private TextView vBarCorrectRight = null;
  private TextView vBarCorrectLeft = null;
  private TextView vBarErrorLeft = null;
  private TextView vBarErrorRight = null;
  private TextView tvInfo = null;
  private View hBar1 = null;
  private View hBar0 = null;
  private View vBar1 = null;
  private View vBar0 = null;
  private ToggleButton tbtnBearing = null;
  private SeekBar sbTest = null;
  private SeekBar sbDist = null;

  private int tvInfoClickCount = 0;

  private double locationPrecision = 15.0f;
  private double locationMaxDistance = 250.0f;
  private float loactionLastAccuracy = -1f;
  private double locationDestinationZoneRadius = 10f;

  private SoundPool pool = null;
  private AudioParameters noise = new AudioParameters();
  private AudioParameters beep = new AudioParameters();
  private AudioParameters error = new AudioParameters();
  private AudioParameters destinationZone = new AudioParameters();

  boolean isNotAccurateEnough = true;
  boolean useCompass = false;

  private GPSWIFIReader locationReader = null;
  private CompassReader compassReader = null;

  private Location locationLast = new Location("Dummy");
  private Location locationDestination = new Location("Dummy");

  private void initGUI() {
    vBarDistance = (TextView) findViewById(R.id.vBarDistance);
    vBarCorrectRight = (TextView) findViewById(R.id.vBarCorrectRight);
    vBarCorrectLeft = (TextView) findViewById(R.id.vBarCorrectLeft);
    vBarErrorLeft = (TextView) findViewById(R.id.vBarErrorLeft);
    vBarErrorRight = (TextView) findViewById(R.id.vBarErrorRight);
    hBar1 = (View) findViewById(R.id.hBar1);
    vBar1 = (View) findViewById(R.id.vBar1);
    vBar0 = (View) findViewById(R.id.vBar0);
    hBar0 = (View) findViewById(R.id.hBar0);
    tbtnBearing = (ToggleButton) findViewById(R.id.tbtnBearing);
    tvInfo = (TextView) findViewById(R.id.tvInfo);
    sbTest = (SeekBar) findViewById(R.id.sbTest);
    sbTest.setVisibility(View.INVISIBLE);
    sbDist = (SeekBar) findViewById(R.id.sbDist);
    sbDist.setVisibility(View.INVISIBLE);

    // distance bar to red until precision sufficient
    vBarDistance.setBackgroundColor(Color.rgb(0xff, 0x44, 0x44));
  }

  private void initClicks() {

    tbtnBearing.setOnCheckedChangeListener(new OnCheckedChangeListener() {

      @Override
      public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        if (isChecked) {
          useCompass = true;
          Toast.makeText(getApplicationContext(), "Using Compass", Toast.LENGTH_SHORT).show();
        } else {
          useCompass = false;
          Toast.makeText(getApplicationContext(), "Using GPS Bearing", Toast.LENGTH_SHORT).show();
        }
      }
    });

    tvInfo.setOnClickListener(new OnClickListener() {

      @Override
      public void onClick(View v) {
        // TODO Auto-generated method stub
        tvInfoClickCount++;
        if (tvInfoClickCount > 6) {
          sbTest.setVisibility(View.VISIBLE);
          sbDist.setVisibility(View.VISIBLE);
        }
      }
    });

    sbTest.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

      @Override
      public void onStopTrackingTouch(SeekBar seekBar) {
        // TODO Auto-generated method stub

      }

      @Override
      public void onStartTrackingTouch(SeekBar seekBar) {
        // TODO Auto-generated method stub

      }

      @Override
      public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        if (fromUser) {
          applyBearingDiffToAudio(progress - 180);
        }
      }
    });
    sbDist.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

      @Override
      public void onStopTrackingTouch(SeekBar seekBar) {
        // TODO Auto-generated method stub

      }

      @Override
      public void onStartTrackingTouch(SeekBar seekBar) {
        // TODO Auto-generated method stub

      }

      @Override
      public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        if (fromUser) {
          locationLast.setAccuracy(1);
          handleLocation(progress);
        }
      }
    });
  }

  LocationStatusCallback cbStatus = new LocationStatusCallback() {

    @Override
    public void status(Location l) {
      // TODO Auto-generated method stub

    }
  };

  LocationResultCallback cbResult = new LocationResultCallback() {

    @Override
    public void result(Location l) {
      if (l == null) {
        return;
      }

      double distance = l.distanceTo(locationDestination);

      loactionLastAccuracy = l.getAccuracy();
      locationLast = l;
      
      handleLocation(distance);
    }
  };

  private SensorResultCallback compassCallback = new SensorResultCallback() {
    @Override
    public void result(float[] f) {
      if (f == null || f.length < 3) {
        return;
      }

      float azimuth = lowPass(f, null)[0];

      if (loactionLastAccuracy <= locationPrecision && useCompass) {
        applyBearingDiffToAudio(azimuth);
      }
    }
  };

  private void handleLocation(double distance) {
    double factor = distance / locationMaxDistance;

    factor = factor > 1f ? 1f : factor;
    factor = factor < 0f ? 0f : factor;

    setHeight(vBarDistance, (int) (factor * origHeight));
    vBarDistance.setText("" + (int) distance + "m");

    if (loactionLastAccuracy > locationPrecision) {
      error.volumeLeft = 1.f;
      error.volumeRight = 1.f;
      error.setVolumeOn(pool);
      beep.muteOn(pool);
      noise.muteOn(pool);
      vBarDistance.setBackgroundColor(Color.rgb(0xff, 0x44, 0x44));
      tvInfo.setText("Location error to high:\n" + loactionLastAccuracy + " > " + locationPrecision);

    } else {
      error.muteOn(pool);
      if (!useCompass) {
        applyBearingDiffToAudio(locationLast.getBearing());
      }

      vBarDistance.setBackgroundColor(Color.rgb(0x33, 0xb5, 0xe5));

    }

    if (distance <= locationDestinationZoneRadius) {
      beep.muteOn(pool);
      noise.muteOn(pool);
      error.muteOn(pool);

      destinationZone.volumeLeft = 1f;
      destinationZone.volumeRight = 1f;
      destinationZone.setVolumeOn(pool);

    } else {
      destinationZone.muteOn(pool);
    }

    if (distance > 250) {
      beep.speed = 1f;
    } else {
      beep.speed = (float) (1f + (1f - (distance / locationMaxDistance))); // 1f - 2f when getting close
    }
    pool.setRate(beep.streamId, beep.speed);
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_soundfinder);

    // -1 = loop
    // -1 = no accuracy waiting/limit
    locationReader = new GPSWIFIReader(this, -1, -1, cbStatus, cbResult, true, true);
    compassReader = new CompassReader(this, -1, compassCallback);
    initAudioStreams();

    Intent config = getIntent();
    locationDestination.setLatitude(config.getDoubleExtra(EXTRA_LOCATION_LAT, 0));
    locationDestination.setLongitude(config.getDoubleExtra(EXTRA_LOCATION_LON, 0));
    locationDestination.setAltitude(config.getDoubleExtra(EXTRA_LOCATION_ALT, 0));
    locationPrecision = config.getDoubleExtra(EXTRA_LOCATION_PRECISION, 10.0f);
    locationMaxDistance = config.getDoubleExtra(EXTRA_LOCATION_MAX_DISTANCE, 100.0f);
    locationDestinationZoneRadius = config.getDoubleExtra(EXTRA_LOCATION_DESTINATION_RADIUS, 10f);

    initGUI();
  }

  @Override
  protected void onResume() {
    super.onResume();
    if (locationReader != null) {
      locationReader.startReading();
    }
    if (compassReader != null) {
      compassReader.startReading();
    }

    initClicks();
  }

  @Override
  protected void onPause() {
    super.onPause();

  }

  @Override
  protected void onDestroy() {
    super.onDestroy();
    if (pool != null) {
      pool.stop(noise.streamId);
      pool.stop(beep.streamId);
      pool.unload(noise.soundId);
      pool.unload(beep.soundId);
      //      pool.stop(error.streamId);
      pool.release();
    }

    if (locationReader != null) {
      locationReader.stopReading();
    }
    if (compassReader != null) {
      compassReader.stopReading();
    }
  }

  private void initAudioStreams() {
    pool = new SoundPool(4, AudioManager.STREAM_MUSIC, 0);
    beep.soundId = pool.load(this, R.raw.sound_beep, 1);
    noise.soundId = pool.load(this, R.raw.sound_noise_static, 1);
    error.soundId = pool.load(this, R.raw.sound_error, 1);
    destinationZone.soundId = pool.load(this, R.raw.sound_destination, 1);

    beep.speed = 1f;
    error.speed = 0.6f;
    pool.setOnLoadCompleteListener(onLoadCompleteListener);
  }

  private OnLoadCompleteListener onLoadCompleteListener = new OnLoadCompleteListener() {

    @Override
    public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {

      if (sampleId == noise.soundId) {
        noise.playOn(pool);
        noise.muteOn(pool);
      }
      if (sampleId == beep.soundId) {
        beep.playOn(pool);
        beep.muteOn(pool);
      }
      if (sampleId == error.soundId) {
        error.playOn(pool);
      }
      if (sampleId == destinationZone.soundId) {
        destinationZone.playOn(pool);
        destinationZone.muteOn(pool);
      }
    }
  };

  private void applyBearingDiffToAudio(float bearing) {
    float targetBearing = locationLast.bearingTo(locationDestination);
    float diff = bearing - targetBearing;
    diff = diff < -180 ? 360f + diff : diff;
    diff = diff > 180 ? diff - 360f : diff;

    //TODO: fix diff 0-360 // REMOVE?
//    float delta = diff;
//    delta /= 180f;
    //    Log.d(TAG, "delta = " + delta);
    origHeight = vBar0.getHeight();
//    float posDelta = Math.abs(delta);

    beep.volumeLeft = angleToVolumeLeft(diff);
    beep.volumeRight = angleToVolumeRight(diff);
    setHeight(vBarCorrectRight, (int) (origHeight * beep.volumeRight));
    setHeight(vBarCorrectLeft, (int) (origHeight * beep.volumeLeft));

    noise.volumeLeft = angleToVolumeErrorLeft(diff);
    noise.volumeRight = angleToVolumeErrorRight(diff);
    setHeight(vBarErrorRight, (int) (origHeight * noise.volumeRight));
    setHeight(vBarErrorLeft, (int) (origHeight * noise.volumeLeft));

    noise.setVolumeOn(pool);
    beep.setVolumeOn(pool);
    error.muteOn(pool);

    tvInfo.setText("Difference: " + (int) diff + "\nBearing: " + bearing + "\n Target Bearing: " + targetBearing + "\nAccuracy: " + loactionLastAccuracy);
  }

  private void setHeight(TextView t, int h) {
    RelativeLayout.LayoutParams params = (LayoutParams) t.getLayoutParams();
    params.height = h;
    t.setLayoutParams(params);
  }

  private float angleToVolumeErrorLeft(float a) {
    a += 180f;
    a = a < -180 ? 360f + a : a;
    a = a > 180 ? a - 360f : a;
    return angleToVolumeLeft(a);
  }

  private float angleToVolumeErrorRight(float a) {
    a += 180f;
    a = a < -180 ? 360f + a : a;
    a = a > 180 ? a - 360f : a;
    return angleToVolumeRight(a);
  }

  private float angleToVolumeRight(float angle) {
    return angleToVolumeLeft(angle * -1.0f);
  }

  private float angleToVolumeLeft(float angle) {
    if (angle > 180.0f) {
      return 0f;
    } else if (angle < -90.0f) {
      return 0f;
    } else if (angle >= 0) {
      return 1.0f - (angle / 180.0f);
    } else if (angle < 0) {
      return 1.0f - (angle / -90.0f);
    }

    return 0.0f;
  }

  static final float ALPHA = 0.15f;

  /**
   * @see http 
   *      ://en.wikipedia.org/wiki/Low-pass_filter#Algorithmic_implementation
   * @see http 
   *      ://developer.android.com/reference/android/hardware/SensorEvent.html
   *      #values
   */
  protected float[] lowPass(float[] input, float[] output) {
    if (output == null)
      return input;

    for (int i = 0; i < input.length; i++) {
      output[i] = output[i] + ALPHA * (input[i] - output[i]);
    }
    return output;
  }

  public static void findNode(Activity act, double lat, double lon, double alt, double precision, double zoneRadius, double maxDistance) {
    Intent intent = new Intent(act, SoundFinder.class);
    intent.putExtra(EXTRA_LOCATION_LAT, lat);
    intent.putExtra(EXTRA_LOCATION_LON, lon);
    intent.putExtra(EXTRA_LOCATION_ALT, alt);
    intent.putExtra(EXTRA_LOCATION_PRECISION, precision);
    intent.putExtra(EXTRA_LOCATION_DESTINATION_RADIUS, zoneRadius);
    intent.putExtra(EXTRA_LOCATION_MAX_DISTANCE, maxDistance);
    try {
      act.startActivity(intent);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}




Java Source Code List

de.uvwxy.soundfinder.SoundFinder.java