added gitingore
This commit is contained in:
9
android/ConductorsPhone/.gitignore
vendored
Normal file
9
android/ConductorsPhone/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
*.iml
|
||||||
|
.gradle
|
||||||
|
/local.properties
|
||||||
|
/.idea/workspace.xml
|
||||||
|
/.idea/libraries
|
||||||
|
.DS_Store
|
||||||
|
/build
|
||||||
|
/captures
|
||||||
|
.externalNativeBuild
|
||||||
@@ -28,12 +28,16 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
targetCompatibility 1.8
|
||||||
|
sourceCompatibility 1.8
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
implementation 'com.google.android.support:wearable:2.1.0'
|
implementation 'com.google.android.support:wearable:2.1.0'
|
||||||
implementation 'com.google.android.gms:play-services-wearable:11.6.0'
|
implementation 'com.google.android.gms:play-services-wearable:11.8.0'
|
||||||
implementation 'com.android.support:percent:26.1.0'
|
implementation 'com.android.support:percent:26.1.0'
|
||||||
implementation 'com.android.support:animated-vector-drawable:26.1.0'
|
implementation 'com.android.support:animated-vector-drawable:26.1.0'
|
||||||
implementation 'com.android.support:appcompat-v7:26.1.0'
|
implementation 'com.android.support:appcompat-v7:26.1.0'
|
||||||
|
|||||||
@@ -19,10 +19,13 @@
|
|||||||
<!--
|
<!--
|
||||||
Set to true if your app is Standalone, that is, it does not require the handheld
|
Set to true if your app is Standalone, that is, it does not require the handheld
|
||||||
app to run.
|
app to run.
|
||||||
-->
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.google.android.wearable.standalone"
|
android:name="com.google.android.wearable.standalone"
|
||||||
android:value="true" />
|
android:value="true" />
|
||||||
|
-->
|
||||||
|
|
||||||
|
<meta-data android:name="com.google.android.gms.version"
|
||||||
|
android:value="@integer/google_play_services_version" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
|
|||||||
@@ -399,7 +399,7 @@ public class Croller extends View {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onTouchEvent(MotionEvent e) {
|
public boolean onTouchEvent(MotionEvent e) {
|
||||||
|
|
||||||
float distancePointToMiddle = Utils.getDistance(e.getX(), e.getY(), midx, midy);
|
double distancePointToMiddle = Utils.getDistance(e.getX(), e.getY(), midx, midy);
|
||||||
if ((distancePointToMiddle > touchCircleRadiusMax || distancePointToMiddle < touchCircleRadiusMin)) {
|
if ((distancePointToMiddle > touchCircleRadiusMax || distancePointToMiddle < touchCircleRadiusMin)) {
|
||||||
if (startEventSent && mCrollerChangeListener != null) {
|
if (startEventSent && mCrollerChangeListener != null) {
|
||||||
mCrollerChangeListener.onStopTrackingTouch(this);
|
mCrollerChangeListener.onStopTrackingTouch(this);
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ import android.os.Handler;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
|
import de.tonifetzer.conductorswatch.bpmEstimation.AccelerometerData;
|
||||||
|
import de.tonifetzer.conductorswatch.bpmEstimation.AccelerometerWindowBuffer;
|
||||||
|
import de.tonifetzer.conductorswatch.bpmEstimation.BpmEstimator;
|
||||||
import de.tonifetzer.conductorswatch.utilities.Utils;
|
import de.tonifetzer.conductorswatch.utilities.Utils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,7 +24,8 @@ public class Estimator implements SensorEventListener {
|
|||||||
private SensorManager mSensorManager;
|
private SensorManager mSensorManager;
|
||||||
private Sensor mAccelerometer;
|
private Sensor mAccelerometer;
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private Utils.AccelerometerWindowBuffer mAccelerometerWindowBuffer;
|
private AccelerometerWindowBuffer mAccelerometerWindowBuffer;
|
||||||
|
private BpmEstimator mBpmEstimator;
|
||||||
|
|
||||||
private Handler mHandler;
|
private Handler mHandler;
|
||||||
private int mUpdaterate_ms = 100;
|
private int mUpdaterate_ms = 100;
|
||||||
@@ -34,13 +38,10 @@ public class Estimator implements SensorEventListener {
|
|||||||
|
|
||||||
if(mAccelerometerWindowBuffer.isNextWindowReady()){
|
if(mAccelerometerWindowBuffer.isNextWindowReady()){
|
||||||
|
|
||||||
//TODO: calculate average samplerate using the window - interpolation of sensordata would be better i think
|
double bpm = mBpmEstimator.estimate();
|
||||||
|
|
||||||
//int randomNum = ThreadLocalRandom.current().nextInt(0, 240 + 1);
|
|
||||||
long diff = mAccelerometerWindowBuffer.getYongest().ts - mAccelerometerWindowBuffer.getOldest().ts;
|
|
||||||
|
|
||||||
for (OnBpmEstimatorListener listener:listeners) {
|
for (OnBpmEstimatorListener listener:listeners) {
|
||||||
listener.onNewDataAvailable((float) diff);
|
listener.onNewDataAvailable(bpm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +62,8 @@ public class Estimator implements SensorEventListener {
|
|||||||
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
|
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
|
||||||
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_FASTEST);
|
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_FASTEST);
|
||||||
|
|
||||||
mAccelerometerWindowBuffer = new Utils.AccelerometerWindowBuffer(4096, 256);
|
mAccelerometerWindowBuffer = new AccelerometerWindowBuffer(1024, 256);
|
||||||
|
mBpmEstimator = new BpmEstimator(mAccelerometerWindowBuffer, 0, 5000);
|
||||||
|
|
||||||
mHandler = new Handler();
|
mHandler = new Handler();
|
||||||
mHandler.post(mProcessSensors); //start runnable
|
mHandler.post(mProcessSensors); //start runnable
|
||||||
@@ -81,7 +83,7 @@ public class Estimator implements SensorEventListener {
|
|||||||
|
|
||||||
//ca 200hz, every 5 to 6 ms we have an update
|
//ca 200hz, every 5 to 6 ms we have an update
|
||||||
if (se.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION) {
|
if (se.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION) {
|
||||||
mAccelerometerWindowBuffer.add(new Utils.AccelerometerData(System.currentTimeMillis(), se.values[0], se.values[1], se.values[2]));
|
mAccelerometerWindowBuffer.add(new AccelerometerData(System.currentTimeMillis(), se.values[0], se.values[1], se.values[2]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// mSensorUpdateFlag = false;
|
// mSensorUpdateFlag = false;
|
||||||
@@ -98,7 +100,7 @@ public class Estimator implements SensorEventListener {
|
|||||||
* Interface for callback calculated bpm
|
* Interface for callback calculated bpm
|
||||||
*/
|
*/
|
||||||
public interface OnBpmEstimatorListener {
|
public interface OnBpmEstimatorListener {
|
||||||
void onNewDataAvailable(float bpm);
|
void onNewDataAvailable(double bpm);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<OnBpmEstimatorListener> listeners = new CopyOnWriteArrayList<OnBpmEstimatorListener>();
|
private List<OnBpmEstimatorListener> listeners = new CopyOnWriteArrayList<OnBpmEstimatorListener>();
|
||||||
|
|||||||
@@ -7,18 +7,31 @@ import android.graphics.Point;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Vibrator;
|
import android.os.Vibrator;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.wearable.activity.WearableActivity;
|
import android.support.wearable.activity.WearableActivity;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.GestureDetector;
|
import android.view.GestureDetector;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.google.android.gms.common.ConnectionResult;
|
||||||
|
import com.google.android.gms.common.api.GoogleApiClient;
|
||||||
|
import com.google.android.gms.common.api.ResultCallback;
|
||||||
|
import com.google.android.gms.wearable.MessageApi;
|
||||||
|
import com.google.android.gms.wearable.Node;
|
||||||
|
import com.google.android.gms.wearable.NodeApi;
|
||||||
|
import com.google.android.gms.wearable.Wearable;
|
||||||
|
|
||||||
import java.sql.Time;
|
import java.sql.Time;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import de.tonifetzer.conductorswatch.utilities.Utils;
|
import de.tonifetzer.conductorswatch.utilities.Utils;
|
||||||
|
|
||||||
public class MainActivity extends WearableActivity implements WorkerFragment.OnFragmentInteractionListener, TapBpm.OnTapBpmListener{
|
public class MainActivity extends WearableActivity implements WorkerFragment.OnFragmentInteractionListener, TapBpm.OnTapBpmListener, GoogleApiClient.ConnectionCallbacks,
|
||||||
|
GoogleApiClient.OnConnectionFailedListener{
|
||||||
|
|
||||||
// member
|
// member
|
||||||
private TextView mTextView;
|
private TextView mTextView;
|
||||||
@@ -26,6 +39,13 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF
|
|||||||
private GestureDetector mDetector;
|
private GestureDetector mDetector;
|
||||||
private boolean mModeRecord;
|
private boolean mModeRecord;
|
||||||
|
|
||||||
|
// connection to phone stuff
|
||||||
|
private static final String START_ACTIVITY_PATH = "/start-activity";
|
||||||
|
public static final String TAG = "DataLayerListenerService";
|
||||||
|
private GoogleApiClient mGoogleApiClient;
|
||||||
|
private Node mNode;
|
||||||
|
private boolean mResolvingError = false;
|
||||||
|
|
||||||
// display center
|
// display center
|
||||||
private int mDisplayWidth;
|
private int mDisplayWidth;
|
||||||
private int mDisplayHeight;
|
private int mDisplayHeight;
|
||||||
@@ -47,6 +67,7 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF
|
|||||||
private int mLongPressDelay = 1200; // in Milliseconds
|
private int mLongPressDelay = 1200; // in Milliseconds
|
||||||
private boolean mLongPressHandlerActivated = false;
|
private boolean mLongPressHandlerActivated = false;
|
||||||
private final Handler mHandler = new Handler();
|
private final Handler mHandler = new Handler();
|
||||||
|
|
||||||
private Runnable mLongPressed = new Runnable() {
|
private Runnable mLongPressed = new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
|
Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
|
||||||
@@ -91,7 +112,7 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF
|
|||||||
Point currentPoint = new Point((int)ev.getX(), (int)ev.getY());
|
Point currentPoint = new Point((int)ev.getX(), (int)ev.getY());
|
||||||
|
|
||||||
//make sure the longPress only works within the maincircle of the scroller
|
//make sure the longPress only works within the maincircle of the scroller
|
||||||
float distancePointToMiddle = Utils.getDistance(currentPoint.x, currentPoint.y, (float) (mDisplayWidth / 2.0f), (float) (mDisplayHeight / 2.0f));
|
double distancePointToMiddle = Utils.getDistance(currentPoint.x, currentPoint.y, (mDisplayWidth / 2.0f), (mDisplayHeight / 2.0f));
|
||||||
if ((distancePointToMiddle > mCroller.getMainCircleRadius())){
|
if ((distancePointToMiddle > mCroller.getMainCircleRadius())){
|
||||||
mHandler.removeCallbacks(mLongPressed);
|
mHandler.removeCallbacks(mLongPressed);
|
||||||
return false;
|
return false;
|
||||||
@@ -134,7 +155,7 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF
|
|||||||
Point currentPoint = new Point((int)ev.getX(), (int)ev.getY());
|
Point currentPoint = new Point((int)ev.getX(), (int)ev.getY());
|
||||||
|
|
||||||
//only works within the maincircle of the scroller
|
//only works within the maincircle of the scroller
|
||||||
float distancePointToMiddle = Utils.getDistance(currentPoint.x, currentPoint.y, mDisplayCenter.x, mDisplayCenter.y);
|
double distancePointToMiddle = Utils.getDistance(currentPoint.x, currentPoint.y, mDisplayCenter.x, mDisplayCenter.y);
|
||||||
if ((distancePointToMiddle > mCroller.getMainCircleRadius())){
|
if ((distancePointToMiddle > mCroller.getMainCircleRadius())){
|
||||||
|
|
||||||
//if we are outside the area of interest and the animation is already running, we need to reset
|
//if we are outside the area of interest and the animation is already running, we need to reset
|
||||||
@@ -170,7 +191,7 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF
|
|||||||
Point currentPoint = new Point((int)ev.getX(), (int)ev.getY());
|
Point currentPoint = new Point((int)ev.getX(), (int)ev.getY());
|
||||||
|
|
||||||
//only works within the maincircle of the scroller
|
//only works within the maincircle of the scroller
|
||||||
float distancePointToMiddle = Utils.getDistance(currentPoint.x, currentPoint.y, mDisplayCenter.x, mDisplayCenter.y);
|
double distancePointToMiddle = Utils.getDistance(currentPoint.x, currentPoint.y, mDisplayCenter.x, mDisplayCenter.y);
|
||||||
if ((distancePointToMiddle > mCroller.getMainCircleRadius())){
|
if ((distancePointToMiddle > mCroller.getMainCircleRadius())){
|
||||||
|
|
||||||
mCroller.setProgress(mCroller.getProgress());
|
mCroller.setProgress(mCroller.getProgress());
|
||||||
@@ -204,6 +225,14 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
|
|
||||||
|
//init GoogleApiClient and get nodeid (phone)
|
||||||
|
mGoogleApiClient = new GoogleApiClient.Builder(this)
|
||||||
|
.addApi(Wearable.API)
|
||||||
|
.addConnectionCallbacks(this)
|
||||||
|
.addOnConnectionFailedListener(this)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
//get display infos
|
||||||
mDisplayWidth= this.getResources().getDisplayMetrics().widthPixels;
|
mDisplayWidth= this.getResources().getDisplayMetrics().widthPixels;
|
||||||
mDisplayHeight= this.getResources().getDisplayMetrics().heightPixels;
|
mDisplayHeight= this.getResources().getDisplayMetrics().heightPixels;
|
||||||
mDisplayCenter = new Point((mDisplayWidth / 2), (mDisplayHeight / 2));
|
mDisplayCenter = new Point((mDisplayWidth / 2), (mDisplayHeight / 2));
|
||||||
@@ -224,6 +253,7 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF
|
|||||||
public void onProgressChanged(int progress) {
|
public void onProgressChanged(int progress) {
|
||||||
// use the progress
|
// use the progress
|
||||||
mTextView.setText(String.valueOf(progress));
|
mTextView.setText(String.valueOf(progress));
|
||||||
|
sendMessage(Integer.toString(progress));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -242,6 +272,29 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF
|
|||||||
setAmbientEnabled();
|
setAmbientEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void sendMessage(String Key) {
|
||||||
|
|
||||||
|
if (mNode != null && mGoogleApiClient!= null && mGoogleApiClient.isConnected()) {
|
||||||
|
Log.d(TAG, "-- " + mGoogleApiClient.isConnected());
|
||||||
|
Wearable.MessageApi.sendMessage(
|
||||||
|
mGoogleApiClient, mNode.getId(), Key, new byte[0]).setResultCallback(
|
||||||
|
|
||||||
|
new ResultCallback<MessageApi.SendMessageResult>() {
|
||||||
|
@Override
|
||||||
|
public void onResult(MessageApi.SendMessageResult sendMessageResult) {
|
||||||
|
|
||||||
|
Log.d(TAG, "--- " + sendMessageResult.getStatus().getStatusCode());
|
||||||
|
if (!sendMessageResult.getStatus().isSuccess()) {
|
||||||
|
Log.e(TAG, "Failed to send message with status code: "
|
||||||
|
+ sendMessageResult.getStatus().getStatusCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||||
|
|
||||||
@@ -265,14 +318,33 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFragmentStopped(Vector<Float> bpmList) {
|
public void onFragmentStopped(Vector<Double> bpmList) {
|
||||||
|
|
||||||
//TODO: save the bpmList into a file
|
//TODO: save the bpmList into a file
|
||||||
|
|
||||||
|
//TODO: send bpmList and all other data to phone
|
||||||
|
|
||||||
Log.d("FragmentListener", "Received bpmList");
|
Log.d("FragmentListener", "Received bpmList");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
if (!mResolvingError) {
|
||||||
|
mGoogleApiClient.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//start app on phone
|
||||||
|
//TODO: bissle cleverer machen. starten und auf antwort warten. falls er sagt "bin schon an" nicht mehr senden
|
||||||
|
// ansonsten nochmal versuchen.bzw. auch von anderen stellen (bei click etc) aufrufen.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//TODO: disconnect or own class for this stuff
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNewEstimation(int bpm) {
|
public void onNewEstimation(int bpm) {
|
||||||
mTapBpmEstimation = bpm;
|
mTapBpmEstimation = bpm;
|
||||||
@@ -310,4 +382,45 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnected(@Nullable Bundle bundle) {
|
||||||
|
resolveNode();
|
||||||
|
|
||||||
|
|
||||||
|
new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
|
||||||
|
while(mNode == null){
|
||||||
|
|
||||||
|
}
|
||||||
|
sendMessage(START_ACTIVITY_PATH);
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnectionSuspended(int i) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resolveNode() {
|
||||||
|
|
||||||
|
Wearable.NodeApi.getConnectedNodes(mGoogleApiClient)
|
||||||
|
.setResultCallback(new ResultCallback<NodeApi.GetConnectedNodesResult>() {
|
||||||
|
@Override
|
||||||
|
public void onResult(NodeApi.GetConnectedNodesResult nodes) {
|
||||||
|
for (Node node : nodes.getNodes()) {
|
||||||
|
mNode = node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import java.util.Vector;
|
|||||||
public class WorkerFragment extends Fragment implements Metronome.OnMetronomeListener, Estimator.OnBpmEstimatorListener{
|
public class WorkerFragment extends Fragment implements Metronome.OnMetronomeListener, Estimator.OnBpmEstimatorListener{
|
||||||
|
|
||||||
private OnFragmentInteractionListener mListener;
|
private OnFragmentInteractionListener mListener;
|
||||||
private Vector<Float> mBpmList; //TODO save to file.
|
private Vector<Double> mBpmList; //TODO save to file.
|
||||||
|
|
||||||
private Estimator mEstimator;
|
private Estimator mEstimator;
|
||||||
private Metronome mMetronome;
|
private Metronome mMetronome;
|
||||||
@@ -59,7 +59,7 @@ public class WorkerFragment extends Fragment implements Metronome.OnMetronomeLis
|
|||||||
mEstimator = new Estimator(getContext());
|
mEstimator = new Estimator(getContext());
|
||||||
mEstimator.add(this);
|
mEstimator.add(this);
|
||||||
//mBpmThread = new Thread(mEstimator, "estThread");
|
//mBpmThread = new Thread(mEstimator, "estThread");
|
||||||
mBpmList = new Vector<Float>();
|
mBpmList = new Vector<Double>();
|
||||||
|
|
||||||
|
|
||||||
// init metronome and listener
|
// init metronome and listener
|
||||||
@@ -138,17 +138,22 @@ public class WorkerFragment extends Fragment implements Metronome.OnMetronomeLis
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onNewClick() {
|
public void onNewClick() {
|
||||||
mVibrator.vibrate(10);
|
//mVibrator.vibrate(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback function for Bpm estimation update
|
* Callback function for Bpm estimation update
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onNewDataAvailable(float bpm) {
|
public void onNewDataAvailable(double bpm) {
|
||||||
|
|
||||||
//TODO: what if multiple threads access mBpmList? put into synchronized? @frank fragen :D
|
//TODO: what if multiple threads access mBpmList? put into synchronized? @frank fragen :D
|
||||||
//TODO: send this to smartphone
|
//TODO: send this to smartphone
|
||||||
|
|
||||||
|
if(bpm == -1){
|
||||||
|
//to stuff with UI. Write Text or make XX or something like that
|
||||||
|
}
|
||||||
|
|
||||||
mBpmList.add(bpm);
|
mBpmList.add(bpm);
|
||||||
|
|
||||||
// we need this here, since ui elements can only be changed within activity thread and
|
// we need this here, since ui elements can only be changed within activity thread and
|
||||||
@@ -160,7 +165,7 @@ public class WorkerFragment extends Fragment implements Metronome.OnMetronomeLis
|
|||||||
public void run() {
|
public void run() {
|
||||||
|
|
||||||
mTextView.setText(String.valueOf(mBpmList.lastElement()));
|
mTextView.setText(String.valueOf(mBpmList.lastElement()));
|
||||||
mCroller.setProgress((Math.round(mBpmList.lastElement())));
|
mCroller.setProgress((int)(Math.round(mBpmList.lastElement())));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -170,7 +175,7 @@ public class WorkerFragment extends Fragment implements Metronome.OnMetronomeLis
|
|||||||
* Interface for connecting to WorkerFragment
|
* Interface for connecting to WorkerFragment
|
||||||
*/
|
*/
|
||||||
public interface OnFragmentInteractionListener {
|
public interface OnFragmentInteractionListener {
|
||||||
void onFragmentStopped(Vector<Float> bpmList);
|
void onFragmentStopped(Vector<Double> bpmList);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,162 @@ package de.tonifetzer.conductorswatch.utilities;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import org.jtransforms.fft.FloatFFT_1D;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
//TODO: change from double to generic type
|
||||||
public class Utils {
|
public class Utils {
|
||||||
public static float getDistance(float x1, float y1, float x2, float y2) {
|
public static double getDistance(double x1, double y1, double x2, double y2) {
|
||||||
return (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
|
return (double) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double sqr(double x) {
|
||||||
|
return x * x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int nextPow2(int a){
|
||||||
|
return a == 0 ? 0 : 32 - Integer.numberOfLeadingZeros(a - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double sum(double[] data){
|
||||||
|
double sum = 0;
|
||||||
|
for (int i = 0; i < data.length; i++) {
|
||||||
|
sum += data[i];
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long sum(long[] data){
|
||||||
|
long sum = 0;
|
||||||
|
for (int i = 0; i < data.length; i++) {
|
||||||
|
sum += data[i];
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double sum (LinkedList<Double> data){
|
||||||
|
double sum = 0;
|
||||||
|
for (int i = 0; i < data.size(); i++) {
|
||||||
|
sum += data.get(i).doubleValue();
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Could be slow.. faster method?
|
||||||
|
public static double rms(double[] nums) {
|
||||||
|
double sum = 0.0f;
|
||||||
|
for (double num : nums)
|
||||||
|
sum += num * num;
|
||||||
|
return Math.sqrt(sum / nums.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double[] diff(double[] data){
|
||||||
|
double[] diff = new double[data.length - 1];
|
||||||
|
int i=0;
|
||||||
|
for(int j = 1; j < data.length; ++j){
|
||||||
|
diff[i] = data[j] - data[i];
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long[] diff(long[] data){
|
||||||
|
long[] diff = new long[data.length - 1];
|
||||||
|
int i=0;
|
||||||
|
for(int j = 1; j < data.length; ++j){
|
||||||
|
diff[i] = data[j] - data[i];
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double mean(double[] data){
|
||||||
|
return sum(data) / data.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double mean(long[] data){
|
||||||
|
return (double) sum(data) / (double) data.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double mean(LinkedList<Double> data){
|
||||||
|
return sum(data) / data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double median(LinkedList<Double> data){
|
||||||
|
data.sort(Comparator.naturalOrder());
|
||||||
|
|
||||||
|
double median;
|
||||||
|
if (data.size() % 2 == 0)
|
||||||
|
median = (data.get(data.size()/2) + data.get(data.size()/2 - 1))/2;
|
||||||
|
else
|
||||||
|
median = data.get(data.size()/2);
|
||||||
|
|
||||||
|
return median;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Could be slow.. faster method?
|
||||||
|
public static double geometricMean(double[] data) {
|
||||||
|
double sum = data[0];
|
||||||
|
for (int i = 1; i < data.length; i++) {
|
||||||
|
sum *= data[i];
|
||||||
|
}
|
||||||
|
return Math.pow(sum, 1.0 / data.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int intersectionNumber(double[] signal, double border){
|
||||||
|
int cnt = 0;
|
||||||
|
boolean isSmallerValue = false;
|
||||||
|
boolean isBiggerValue = false;
|
||||||
|
|
||||||
|
for(double value : signal){
|
||||||
|
if(value < border){
|
||||||
|
if(isBiggerValue){
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
isSmallerValue = true;
|
||||||
|
isBiggerValue = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(isSmallerValue){
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
isSmallerValue = false;
|
||||||
|
isBiggerValue = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double[] removeZero(double[] array){
|
||||||
|
int j = 0;
|
||||||
|
for( int i=0; i<array.length; i++ )
|
||||||
|
{
|
||||||
|
if (array[i] != 0){
|
||||||
|
array[j++] = array[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
double[] newArray = new double[j];
|
||||||
|
System.arraycopy( array, 0, newArray, 0, j );
|
||||||
|
|
||||||
|
return newArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double[] greaterZero(double[] array){
|
||||||
|
int j = 0;
|
||||||
|
for( int i=0; i < array.length; i++ )
|
||||||
|
{
|
||||||
|
if (array[i] > 0){
|
||||||
|
array[j++] = array[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
double[] newArray = new double[j];
|
||||||
|
System.arraycopy( array, 0, newArray, 0, j );
|
||||||
|
|
||||||
|
return newArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float convertDpToPixel(float dp, Context context) {
|
public static float convertDpToPixel(float dp, Context context) {
|
||||||
@@ -25,174 +173,4 @@ public class Utils {
|
|||||||
return px / ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
|
return px / ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class AccelerometerData {
|
|
||||||
|
|
||||||
public float x,y,z;
|
|
||||||
public long ts;
|
|
||||||
|
|
||||||
public AccelerometerData(long ts, float x, float y, float z){
|
|
||||||
this.ts = ts;
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.z = z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class AccelerometerWindowBuffer extends ArrayList<AccelerometerData> {
|
|
||||||
|
|
||||||
private int mWindowSize;
|
|
||||||
private int mOverlapSize;
|
|
||||||
private int mOverlapCounter;
|
|
||||||
private float[] mX;
|
|
||||||
private float[] mY;
|
|
||||||
private float[] mZ;
|
|
||||||
private long[] mTs;
|
|
||||||
|
|
||||||
public AccelerometerWindowBuffer(int windowSize, int overlap){
|
|
||||||
this.mWindowSize = windowSize;
|
|
||||||
this.mOverlapSize = overlap;
|
|
||||||
mOverlapCounter = 1;
|
|
||||||
|
|
||||||
mX = new float[this.mWindowSize];
|
|
||||||
mY = new float[this.mWindowSize];
|
|
||||||
mZ = new float[this.mWindowSize];
|
|
||||||
mTs = new long[this.mWindowSize];
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean add(AccelerometerData ad){
|
|
||||||
boolean r = super.add(ad);
|
|
||||||
if (size() > mWindowSize){
|
|
||||||
removeRange(0, size() - mWindowSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
//update the double arrays.
|
|
||||||
for (int i = 0; i < size(); ++i) {
|
|
||||||
mX[i] = get(i).x;
|
|
||||||
mY[i] = get(i).y;
|
|
||||||
mZ[i] = get(i).z;
|
|
||||||
mTs[i] = get(i).ts;
|
|
||||||
}
|
|
||||||
|
|
||||||
++mOverlapCounter;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isNextWindowReady(){
|
|
||||||
if(size() == mWindowSize && mOverlapCounter > mOverlapSize){
|
|
||||||
mOverlapCounter = 1;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AccelerometerData getYongest() {
|
|
||||||
return get(size() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AccelerometerData getOldest() {
|
|
||||||
return get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public float[] getX(){
|
|
||||||
return mX;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float[] getY(){
|
|
||||||
return mY;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float[] getZ(){
|
|
||||||
return mZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long[] getTs(){
|
|
||||||
return mTs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static float sqr(float x) {
|
|
||||||
return x * x;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int nextPow2(int a){
|
|
||||||
return a == 0 ? 0 : 32 - Integer.numberOfLeadingZeros(a - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float mean(float[] data){
|
|
||||||
float sum = 0;
|
|
||||||
for (int i = 0; i < data.length; i++) {
|
|
||||||
sum += data[i];
|
|
||||||
}
|
|
||||||
return sum / data.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float[] removeZero(float[] array){
|
|
||||||
int j = 0;
|
|
||||||
for( int i=0; i<array.length; i++ )
|
|
||||||
{
|
|
||||||
if (array[i] != 0)
|
|
||||||
array[j++] = array[i];
|
|
||||||
}
|
|
||||||
float[] newArray = new float[j];
|
|
||||||
System.arraycopy( array, 0, newArray, 0, j );
|
|
||||||
|
|
||||||
return newArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: errorhandling maxLag = 0;
|
|
||||||
//TODO: größeren Testcase schreiben
|
|
||||||
public static float[] fftAutoCorrelation(float[] data, int maxLag) {
|
|
||||||
|
|
||||||
int n = data.length;
|
|
||||||
float[] x = Arrays.copyOf(data, n);
|
|
||||||
int mxl = Math.min(maxLag, n - 1);
|
|
||||||
int ceilLog2 = nextPow2(2*n -1);
|
|
||||||
int n2 = (int) Math.pow(2,ceilLog2);
|
|
||||||
|
|
||||||
// x - mean(x) (pointwise)
|
|
||||||
float x_mean = mean(x);
|
|
||||||
for(int i = 0; i < x.length; ++i){
|
|
||||||
x[i] -= x_mean;
|
|
||||||
}
|
|
||||||
|
|
||||||
// double the size of x and fill up with zeros. if x is not even, add additional 0
|
|
||||||
float[] x2 = new float[n2 * 2]; //need double the size for fft.realForwardFull (look into method description)
|
|
||||||
Arrays.fill(x2, 0);
|
|
||||||
System.arraycopy(x,0, x2, 0, x.length);
|
|
||||||
|
|
||||||
// x_fft calculate fft 1D
|
|
||||||
FloatFFT_1D fft = new FloatFFT_1D(n2);
|
|
||||||
fft.realForwardFull(x2);
|
|
||||||
|
|
||||||
// Cr = abs(x_fft).^2 (absolute with complex numbers is (r^2) + (i^2)
|
|
||||||
float[] Cr = new float[n2 * 2];
|
|
||||||
int j = 0;
|
|
||||||
for(int i = 0; i < x2.length; ++i){
|
|
||||||
Cr[j++] = sqr(x2[i]) + sqr(x2[i+1]);
|
|
||||||
++i; //skip the complex part
|
|
||||||
}
|
|
||||||
|
|
||||||
// ifft(Cr,[],1)
|
|
||||||
FloatFFT_1D ifft = new FloatFFT_1D(n2);
|
|
||||||
ifft.realInverseFull(Cr, true);
|
|
||||||
|
|
||||||
// remove complex part and scale/normalize
|
|
||||||
float[] c1 = new float[n2];
|
|
||||||
j = 0;
|
|
||||||
for(int i = 0; i < Cr.length; ++i){
|
|
||||||
c1[j++] = Cr[i] / Cr[0];
|
|
||||||
++i; //skip the complex part
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep only the lags we want and move negative lags before positive lags.
|
|
||||||
float[] c = new float[(mxl * 2) + 1];
|
|
||||||
System.arraycopy(c1, 0, c, mxl, mxl + 1); // +1 to place the 1.0 in the middle of correlation
|
|
||||||
System.arraycopy(c1, n2 - mxl, c, 0, mxl);
|
|
||||||
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: findPeaks
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,3 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Conductor\'s Watch</string>
|
<string name="app_name">Conductor\'s Watch</string>
|
||||||
<!--
|
|
||||||
This string is used for square devices and overridden by hello_world in
|
|
||||||
values-round/strings.xml for round devices.
|
|
||||||
-->
|
|
||||||
<string name="hello_world">Hello Square World!</string>
|
|
||||||
|
|
||||||
<!-- TODO: Remove or change this placeholder text -->
|
|
||||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import java.io.BufferedReader;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,19 +18,19 @@ public class Main {
|
|||||||
public static void main(String [ ] args) {
|
public static void main(String [ ] args) {
|
||||||
File folder = new File("/home/toni/Documents/programme/dirigent/measurements/wearR");
|
File folder = new File("/home/toni/Documents/programme/dirigent/measurements/wearR");
|
||||||
File[] listOfFiles = folder.listFiles();
|
File[] listOfFiles = folder.listFiles();
|
||||||
/*
|
|
||||||
Utils.ShowPNG windowRaw = new Utils.ShowPNG();
|
Utils.ShowPNG windowRaw = new Utils.ShowPNG();
|
||||||
Utils.ShowPNG windowAuto = new Utils.ShowPNG();
|
Utils.ShowPNG windowAuto = new Utils.ShowPNG();
|
||||||
Utils.ShowPNG windowPeaksX = new Utils.ShowPNG();
|
Utils.ShowPNG windowPeaksX = new Utils.ShowPNG();
|
||||||
Utils.ShowPNG windowPeaksY = new Utils.ShowPNG();
|
Utils.ShowPNG windowPeaksY = new Utils.ShowPNG();
|
||||||
Utils.ShowPNG windowPeaksZ = new Utils.ShowPNG();
|
Utils.ShowPNG windowPeaksZ = new Utils.ShowPNG();
|
||||||
*/
|
|
||||||
|
|
||||||
// iterate trough files in measurements folder
|
// iterate trough files in measurements folder
|
||||||
for (File file : listOfFiles) {
|
for (File file : listOfFiles) {
|
||||||
if (file.isFile() && file.getName().contains(".csv")) {
|
if (file.isFile() && file.getName().contains(".csv")) {
|
||||||
|
|
||||||
AccelerometerWindowBuffer accWindowBuffer = new AccelerometerWindowBuffer(4096, 256);
|
AccelerometerWindowBuffer accWindowBuffer = new AccelerometerWindowBuffer(1024, 256);
|
||||||
BpmEstimator bpmEstimator = new BpmEstimator(accWindowBuffer, 0, 5000);
|
BpmEstimator bpmEstimator = new BpmEstimator(accWindowBuffer, 0, 5000);
|
||||||
|
|
||||||
//read the file line by line
|
//read the file line by line
|
||||||
@@ -51,9 +53,9 @@ public class Main {
|
|||||||
|
|
||||||
double curBpm = bpmEstimator.estimate();
|
double curBpm = bpmEstimator.estimate();
|
||||||
//System.out.println("BPM: " + curBpm);
|
//System.out.println("BPM: " + curBpm);
|
||||||
/*
|
|
||||||
|
|
||||||
AccelerometerInterpolator acInterp = new AccelerometerInterpolator(accWindowBuffer, bpmEstimator.getSampleRate_ms());
|
|
||||||
|
AccelerometerInterpolator acInterp = new AccelerometerInterpolator(accWindowBuffer, 5);
|
||||||
|
|
||||||
//print raw x,y,z
|
//print raw x,y,z
|
||||||
double[] dTs = IntStream.range(0, accWindowBuffer.getTs().length).mapToDouble(i -> accWindowBuffer.getTs()[i]).toArray();
|
double[] dTs = IntStream.range(0, accWindowBuffer.getTs().length).mapToDouble(i -> accWindowBuffer.getTs()[i]).toArray();
|
||||||
@@ -68,9 +70,9 @@ public class Main {
|
|||||||
windowRaw.set(plotRaw.draw());
|
windowRaw.set(plotRaw.draw());
|
||||||
|
|
||||||
//auto corr
|
//auto corr
|
||||||
double[] xAutoCorr = new AutoCorrelation(acInterp.getX(), 1024).getCorr();
|
double[] xAutoCorr = new AutoCorrelation(acInterp.getX(), 512).getCorr();
|
||||||
double[] yAutoCorr = new AutoCorrelation(acInterp.getY(), 1024).getCorr();
|
double[] yAutoCorr = new AutoCorrelation(acInterp.getY(), 512).getCorr();
|
||||||
double[] zAutoCorr = new AutoCorrelation(acInterp.getZ(), 1024).getCorr();
|
double[] zAutoCorr = new AutoCorrelation(acInterp.getZ(), 512).getCorr();
|
||||||
|
|
||||||
//print autocorr
|
//print autocorr
|
||||||
int[] tmp = IntStream.rangeClosed(-((xAutoCorr.length - 1)/2), ((xAutoCorr.length - 1)/2)).toArray();
|
int[] tmp = IntStream.rangeClosed(-((xAutoCorr.length - 1)/2), ((xAutoCorr.length - 1)/2)).toArray();
|
||||||
@@ -87,7 +89,7 @@ public class Main {
|
|||||||
Peaks pX = new Peaks(xAutoCorr, 50, 0.1f, 0, false);
|
Peaks pX = new Peaks(xAutoCorr, 50, 0.1f, 0, false);
|
||||||
LinkedList<Integer> peaksX = pX.getPeaksIdx();
|
LinkedList<Integer> peaksX = pX.getPeaksIdx();
|
||||||
|
|
||||||
double[] dPeaksXX = IntStream.range(0, peaksX.size()).mapToDouble(i -> (peaksX.get(i) - 1024)).toArray();//peaks.stream().mapToDouble(i->i).toArray();
|
double[] dPeaksXX = IntStream.range(0, peaksX.size()).mapToDouble(i -> (peaksX.get(i) - 512)).toArray();//peaks.stream().mapToDouble(i->i).toArray();
|
||||||
double[] dPeaksXY = IntStream.range(0, peaksX.size()).mapToDouble(i -> (xAutoCorr[peaksX.get(i)])).toArray();
|
double[] dPeaksXY = IntStream.range(0, peaksX.size()).mapToDouble(i -> (xAutoCorr[peaksX.get(i)])).toArray();
|
||||||
Plot plotPeaksX = Plot.plot(Plot.plotOpts().
|
Plot plotPeaksX = Plot.plot(Plot.plotOpts().
|
||||||
title("Peak Detection on X").
|
title("Peak Detection on X").
|
||||||
@@ -101,7 +103,7 @@ public class Main {
|
|||||||
Peaks pY = new Peaks(yAutoCorr, 50, 0.1f, 0, false);
|
Peaks pY = new Peaks(yAutoCorr, 50, 0.1f, 0, false);
|
||||||
LinkedList<Integer> peaksY = pY.getPeaksIdx();
|
LinkedList<Integer> peaksY = pY.getPeaksIdx();
|
||||||
|
|
||||||
double[] dPeaksYX = IntStream.range(0, peaksY.size()).mapToDouble(i -> (peaksY.get(i) - 1024)).toArray();//peaks.stream().mapToDouble(i->i).toArray();
|
double[] dPeaksYX = IntStream.range(0, peaksY.size()).mapToDouble(i -> (peaksY.get(i) - 512)).toArray();//peaks.stream().mapToDouble(i->i).toArray();
|
||||||
double[] dPeaksYY = IntStream.range(0, peaksY.size()).mapToDouble(i -> (yAutoCorr[peaksY.get(i)])).toArray();
|
double[] dPeaksYY = IntStream.range(0, peaksY.size()).mapToDouble(i -> (yAutoCorr[peaksY.get(i)])).toArray();
|
||||||
Plot plotPeaksY = Plot.plot(Plot.plotOpts().
|
Plot plotPeaksY = Plot.plot(Plot.plotOpts().
|
||||||
title("Peak Detection on Y").
|
title("Peak Detection on Y").
|
||||||
@@ -115,7 +117,7 @@ public class Main {
|
|||||||
Peaks pZ = new Peaks(zAutoCorr, 50, 0.1f, 0, false);
|
Peaks pZ = new Peaks(zAutoCorr, 50, 0.1f, 0, false);
|
||||||
LinkedList<Integer> peaksZ = pZ.getPeaksIdx();
|
LinkedList<Integer> peaksZ = pZ.getPeaksIdx();
|
||||||
|
|
||||||
double[] dPeaksZX = IntStream.range(0, peaksZ.size()).mapToDouble(i -> (peaksZ.get(i) - 1024)).toArray();//peaks.stream().mapToDouble(i->i).toArray();
|
double[] dPeaksZX = IntStream.range(0, peaksZ.size()).mapToDouble(i -> (peaksZ.get(i) - 512)).toArray();//peaks.stream().mapToDouble(i->i).toArray();
|
||||||
double[] dPeaksZY = IntStream.range(0, peaksZ.size()).mapToDouble(i -> (zAutoCorr[peaksZ.get(i)])).toArray();
|
double[] dPeaksZY = IntStream.range(0, peaksZ.size()).mapToDouble(i -> (zAutoCorr[peaksZ.get(i)])).toArray();
|
||||||
Plot plotPeaksZ = Plot.plot(Plot.plotOpts().
|
Plot plotPeaksZ = Plot.plot(Plot.plotOpts().
|
||||||
title("Peak Detection on Z").
|
title("Peak Detection on Z").
|
||||||
@@ -134,7 +136,7 @@ public class Main {
|
|||||||
//System.out.println("BPM-Z: " + pZ.getBPM(bpmEstimator.getSampleRate_ms()));
|
//System.out.println("BPM-Z: " + pZ.getBPM(bpmEstimator.getSampleRate_ms()));
|
||||||
|
|
||||||
//todo: kleiner fenstergrößen testen. so ist doch etwas langsam auf der Uhr.
|
//todo: kleiner fenstergrößen testen. so ist doch etwas langsam auf der Uhr.
|
||||||
*/
|
|
||||||
int dummyForBreakpoint = 0;
|
int dummyForBreakpoint = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public class AccelerometerWindowBuffer extends ArrayList<AccelerometerData> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNextWindowReady(){
|
public boolean isNextWindowReady(){
|
||||||
if((size() == mWindowSize || size() == mWindowSize / 2 || size() == mWindowSize / 4) && mOverlapCounter > mOverlapSize){
|
if((size() > mWindowSize / 2) && mOverlapCounter > mOverlapSize){
|
||||||
mOverlapCounter = 1;
|
mOverlapCounter = 1;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ public class BpmEstimator {
|
|||||||
//kalman filter (lohnt dann, wenn wir konstantes tempo haben, mit startangabe!)
|
//kalman filter (lohnt dann, wenn wir konstantes tempo haben, mit startangabe!)
|
||||||
|
|
||||||
mBpmHistory.add(estimatedBPM);
|
mBpmHistory.add(estimatedBPM);
|
||||||
|
mResetCounter = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int resetAfter = (int) Math.round(mResetLimit_ms / (mBuffer.getOverlapSize() * sampleRate));
|
int resetAfter = (int) Math.round(mResetLimit_ms / (mBuffer.getOverlapSize() * sampleRate));
|
||||||
@@ -102,9 +103,9 @@ public class BpmEstimator {
|
|||||||
private double getBestBpmEstimation(Peaks peaksX, Peaks peaksY, Peaks peaksZ) throws IllegalArgumentException {
|
private double getBestBpmEstimation(Peaks peaksX, Peaks peaksY, Peaks peaksZ) throws IllegalArgumentException {
|
||||||
|
|
||||||
int cntNumAxis = 0;
|
int cntNumAxis = 0;
|
||||||
double sumCorr = 1; //to prevent division by zero
|
double sumCorr = 0; //to prevent division by zero
|
||||||
double sumRms = 1;
|
double sumRms = 0;
|
||||||
double sumNumInter = 1;
|
double sumNumInter = 0;
|
||||||
|
|
||||||
double corrMeanX = 0, corrRmsX = 0;
|
double corrMeanX = 0, corrRmsX = 0;
|
||||||
int corrNumInterX = 0;
|
int corrNumInterX = 0;
|
||||||
@@ -167,7 +168,7 @@ public class BpmEstimator {
|
|||||||
|
|
||||||
//values to low, reject
|
//values to low, reject
|
||||||
//TODO: this is a pretty simple assumption. first shot!
|
//TODO: this is a pretty simple assumption. first shot!
|
||||||
if(corrRmsX < 0.2 && corrRmsY < 0.2 && corrRmsZ < 0.2){
|
if(corrRmsX < 0.25 && corrRmsY < 0.25 && corrRmsZ < 0.25){
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user