Some more on the PaceDetector. Added a BPMQuery.

Added browse by year.
Cleaned up the ProgressBars and some layouts.
Added context menu to TrackList to append tracks to "now playing".
This commit is contained in:
Daniel Önnerby 2009-08-20 21:19:13 +00:00
parent 16dd505de1
commit 44a071b2bb
16 changed files with 353 additions and 140 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -9,9 +9,9 @@
<LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical|center_horizontal">
<ImageView android:src="@drawable/album" android:layout_height="200sp" android:layout_width="200sp" android:scaleType="fitXY" android:layout_marginRight="10sp" android:id="@+id/AlbumCover"></ImageView>
<LinearLayout android:id="@+id/LinearLayout01" android:layout_height="wrap_content" android:orientation="vertical" android:layout_width="wrap_content">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="24sp" android:id="@+id/TrackTitle" android:text="Title:"></TextView>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Album:" android:id="@+id/TrackAlbum"></TextView>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Artists:" android:id="@+id/TrackArtist"></TextView>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="24sp" android:id="@+id/TrackTitle" android:text="Title:" android:lines="1"></TextView>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Album:" android:id="@+id/TrackAlbum" android:lines="1"></TextView>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Artists:" android:id="@+id/TrackArtist" android:lines="1"></TextView>
<LinearLayout android:id="@+id/LinearLayout02" android:layout_weight="0.5" android:layout_width="wrap_content" android:layout_height="wrap_content"></LinearLayout><LinearLayout android:id="@+id/LinearLayout01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal">
<ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/MediaPrev" android:clickable="true" android:src="@drawable/ic_media_previous" android:adjustViewBounds="true" android:padding="15sp"></ImageButton>
<ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:adjustViewBounds="true" android:id="@+id/MediaPause" android:src="@drawable/ic_media_pause" android:padding="15sp"></ImageButton>
@ -28,5 +28,5 @@
<TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="0:00" android:id="@+id/TrackDuration" android:typeface="monospace" android:gravity="right"></TextView>
</LinearLayout>
<SeekBar android:layout_height="wrap_content" android:layout_width="fill_parent" android:max="1000" android:progress="300" android:secondaryProgress="100" android:id="@+id/TrackProgress"></SeekBar>
<SeekBar android:layout_height="wrap_content" android:layout_width="fill_parent" android:max="1000" android:id="@+id/TrackProgress" android:progress="0" android:secondaryProgress="0"></SeekBar>
</LinearLayout>

View File

@ -11,9 +11,13 @@
android:layout_height="fill_parent"
android:layout_weight="1"
android:drawSelectorOnTop="false"/>
<TextView android:id="@id/android:empty"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text=""/>
</LinearLayout>
<LinearLayout android:id="@id/android:empty"
android:orientation="horizontal"
android:paddingLeft="8dp"
android:paddingRight="8dp" android:layout_width="wrap_content" android:layout_gravity="center_vertical|center_horizontal" android:layout_height="fill_parent">
<ProgressBar android:id="@+id/ProgressBar01" android:keepScreenOn="true" android:layout_gravity="center_vertical|center_horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content"></ProgressBar>
<TextView android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:text="Loading..." android:layout_marginLeft="10sp"></TextView>
</LinearLayout>
</LinearLayout>

View File

@ -13,6 +13,7 @@
<TextView android:id="@+id/TextView01" android:layout_height="wrap_content" android:text="Browse by:" android:layout_width="fill_parent" android:background="@color/headlineColor" android:textSize="16sp" android:padding="4sp"></TextView>
<Button android:layout_height="wrap_content" android:layout_width="fill_parent" android:textSize="22sp" android:text="Genre" android:id="@+id/GenresButton"></Button>
<Button android:layout_height="wrap_content" android:layout_width="fill_parent" android:textSize="22sp" android:id="@+id/ArtistsButton" android:text="Artist"></Button>
<Button android:layout_height="wrap_content" android:layout_width="fill_parent" android:textSize="22sp" android:id="@+id/YearButton" android:text="Year"></Button>
<Button android:layout_height="wrap_content" android:layout_width="fill_parent" android:textSize="22sp" android:id="@+id/BPMButton" android:text="Workout mode"></Button>
</LinearLayout>

View File

@ -8,10 +8,10 @@
<ImageView android:src="@drawable/album" android:layout_marginTop="5sp" android:layout_marginBottom="5sp" android:layout_height="200sp" android:layout_width="200sp" android:scaleType="fitXY" android:id="@+id/AlbumCover"></ImageView><LinearLayout android:id="@+id/LinearLayout01" android:layout_weight="0.5" android:layout_height="wrap_content" android:orientation="vertical" android:gravity="left" android:layout_width="200sp">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="24sp" android:id="@+id/TrackTitle" android:text="Title:"></TextView>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="24sp" android:id="@+id/TrackTitle" android:text="Title:" android:lines="1"></TextView>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Album:" android:id="@+id/TrackAlbum"></TextView>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Artists:" android:id="@+id/TrackArtist"></TextView>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Album:" android:id="@+id/TrackAlbum" android:lines="1"></TextView>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Artists:" android:id="@+id/TrackArtist" android:lines="1"></TextView>
</LinearLayout>
<LinearLayout android:id="@+id/LinearLayout02" android:layout_weight="0.5" android:layout_width="wrap_content" android:layout_height="wrap_content"></LinearLayout><LinearLayout android:id="@+id/LinearLayout01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal">
<ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/MediaPrev" android:src="@drawable/ic_media_previous" android:adjustViewBounds="true" android:padding="15sp"></ImageButton>
@ -27,5 +27,5 @@
<TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="0:00" android:id="@+id/TrackDuration" android:typeface="monospace" android:gravity="right"></TextView>
</LinearLayout>
<SeekBar android:layout_height="wrap_content" android:layout_width="fill_parent" android:max="1000" android:progress="300" android:secondaryProgress="100" android:id="@+id/TrackProgress"></SeekBar>
<SeekBar android:layout_height="wrap_content" android:layout_width="fill_parent" android:max="1000" android:id="@+id/TrackProgress" android:progress="0" android:secondaryProgress="0"></SeekBar>
</LinearLayout>

View File

@ -12,8 +12,12 @@
android:layout_weight="1"
android:drawSelectorOnTop="false"/>
<TextView android:id="@id/android:empty"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="Loading...."/>
<LinearLayout android:id="@id/android:empty"
android:orientation="horizontal"
android:paddingLeft="8dp"
android:paddingRight="8dp" android:layout_width="wrap_content" android:layout_gravity="center_vertical|center_horizontal" android:layout_height="fill_parent">
<ProgressBar android:id="@+id/ProgressBar01" android:keepScreenOn="true" android:layout_gravity="center_vertical|center_horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content"></ProgressBar>
<TextView android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:text="Loading..." android:layout_marginLeft="10sp"></TextView>
</LinearLayout>
</LinearLayout>

View File

@ -36,7 +36,7 @@ public class CategoryList extends ListActivity implements OnQueryResultListener
private ArrayList<String> selectedCategory;
private ArrayList<Integer> selectedCategoryIds;
private ProgressDialog loadingDialog;
// private ProgressDialog loadingDialog;
// Need handler for callbacks to the UI thread
final Handler callbackHandler = new Handler();
@ -60,15 +60,28 @@ public class CategoryList extends ListActivity implements OnQueryResultListener
}
public int getCount() {
return this.query.resultsInts.size();
int size = this.query.resultsInts.size();
if(size==0){
return 0;
}else{
return size+1;
}
}
public Object getItem(int position) {
return this.query.resultsInts.get(position);
if(position==0){
return 0;
}else{
return this.query.resultsInts.get(position-1);
}
}
public long getItemId(int position) {
return this.query.resultsInts.get(position);
if(position==0){
return 0;
}else{
return this.query.resultsInts.get(position-1);
}
}
public View getView(int position, View view, ViewGroup parent) {
@ -76,32 +89,17 @@ public class CategoryList extends ListActivity implements OnQueryResultListener
view = inflator.inflate(R.layout.category_list_item, null);
}
((TextView) view.findViewById(R.id.text)).setText(this.query.resultsStrings.get(position));
//
if(position==0){
((TextView) view.findViewById(R.id.text)).setText("- All -");
}else{
((TextView) view.findViewById(R.id.text)).setText(this.query.resultsStrings.get(position-1));
}
return view;
}
}
/* private class CategoryItemView extends LinearLayout {
public CategoryItemView(Context context, String title) {
super(context);
this.setOrientation(VERTICAL);
mTitle = new TextView(context);
mTitle.setTextSize(22);
mTitle.setText(title);
addView(mTitle, new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
}
public void SetTitle(String title) {
mTitle.setText(title);
}
private TextView mTitle;
}
*/
private ResultAdapter listAdapter;
@Override
@ -151,7 +149,7 @@ public class CategoryList extends ListActivity implements OnQueryResultListener
org.musikcube.core.Library library = org.musikcube.core.Library.GetInstance();
this.loadingDialog = ProgressDialog.show(this, "", "Loading "+this.category+"...", true);
//this.loadingDialog = ProgressDialog.show(this, "", "Loading "+this.category+"...", true);
library.AddQuery(this.query);
}else{
@ -165,10 +163,10 @@ public class CategoryList extends ListActivity implements OnQueryResultListener
public void OnResults(){
//Log.i("CategoryList::OnResults","In right thread "+this.query.resultsStrings.size());
if(this.loadingDialog!=null){
/*if(this.loadingDialog!=null){
this.loadingDialog.dismiss();
this.loadingDialog = null;
}
}*/
this.listAdapter.notifyDataSetChanged();
}
@ -192,8 +190,10 @@ public class CategoryList extends ListActivity implements OnQueryResultListener
ArrayList<String> selectedCategory = (ArrayList<String>)this.selectedCategory.clone();
ArrayList<Integer> selectedCategoryIds = (ArrayList<Integer>)this.selectedCategoryIds.clone();
selectedCategory.add(this.category);
selectedCategoryIds.add((int)id);
if(id!=0){
selectedCategory.add(this.category);
selectedCategoryIds.add((int)id);
}
if(this.nextCategoryList.equals("")){
// List tracks

View File

@ -28,11 +28,13 @@ import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
public class PlayerControl extends Activity implements OnTrackUpdateListener, OnQueryResultListener {
public class PlayerControl extends Activity implements OnTrackUpdateListener {
private Track track = new Track();
private int duration = 0;
private Object lock = new Object();
private boolean enable = false;
private int currentAlbumCoverId = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
@ -74,56 +76,24 @@ public class PlayerControl extends Activity implements OnTrackUpdateListener, On
this.callbackTrackPositionsUpdateHandler.post(this.callbackTrackPositionsUpdateRunnable);
}
public void OnTrackUpdate() {
/*
synchronized(lock){
int newTrackId = Player.GetInstance().GetCurrentTrackId();
if(newTrackId!=this.trackId){
this.trackId = newTrackId;
this.track = new Track();
if(this.trackId!=0){
MetadataQuery query = new MetadataQuery();
query.requestedMetakeys.add("title");
query.requestedMetakeys.add("track");
query.requestedMetakeys.add("visual_artist");
query.requestedMetakeys.add("album");
query.requestedMetakeys.add("year");
query.requestedMetakeys.add("thumbnail_id");
query.requestedMetakeys.add("duration");
query.requestedTracks.add(this.trackId);
query.SetResultListener(this);
Library.GetInstance().AddQuery(query);
}
}
}*/
this.callbackTrackUpdateHandler.post(this.callbackTrackUpdateRunnable);
}
public void OnQueryResults(IQuery query) {
/* MetadataQuery mdQuery = (MetadataQuery)query;
if(!mdQuery.resultTracks.isEmpty()){
synchronized(lock){
Track newTrack = mdQuery.resultTracks.get(0);
if(this.trackId==newTrack.id){
this.track = newTrack;
this.callbackTrackUpdateHandler.post(this.callbackTrackUpdateRunnable);
}
}
}*/
}
@Override
protected void onPause() {
this.enable = false;
Log.v("MC2::PC","OnPause");
Player.GetInstance().SetUpdateListener(null);
super.onPause();
}
@Override
protected void onResume() {
this.enable = true;
Log.v("MC2::PC","OnResume");
Player.GetInstance().SetUpdateListener(this);
super.onResume();
this.OnUpdateTrackPositionsUI();
this.OnUpdateTrackUI();
}
// Need handler for callbacks to the UI thread
@ -189,13 +159,16 @@ public class PlayerControl extends Activity implements OnTrackUpdateListener, On
}
// clear image
ImageView cover = (ImageView)findViewById(R.id.AlbumCover);
cover.setImageResource(R.drawable.album);
if(thumbnailId!=0){
// Load image
Library library = Library.GetInstance();
new DownloadAlbumCoverTask().execute("http://"+library.host+":"+library.httpPort+"/cover/?cover_id="+thumbnailId);
if(this.currentAlbumCoverId!=thumbnailId){
this.currentAlbumCoverId=thumbnailId;
ImageView cover = (ImageView)findViewById(R.id.AlbumCover);
cover.setImageResource(R.drawable.album);
if(thumbnailId!=0){
// Load image
Library library = Library.GetInstance();
new DownloadAlbumCoverTask().execute("http://"+library.host+":"+library.httpPort+"/cover/?cover_id="+thumbnailId);
}
}
}
@ -238,24 +211,26 @@ public class PlayerControl extends Activity implements OnTrackUpdateListener, On
};
public void OnUpdateTrackPositionsUI() {
int msPosition = Player.GetInstance().GetTrackPosition();
int position = msPosition/1000;
int minutes = (int)Math.floor(position/60);
int seconds = position-minutes*60;
String positionText = Integer.toString(minutes)+":";
if(seconds<10){ positionText += "0"; }
positionText += Integer.toString(seconds);
TextView positionView = (TextView)findViewById(R.id.TrackPosition);
positionView.setText(positionText);
SeekBar seekBar = (SeekBar)findViewById(R.id.TrackProgress);
synchronized (this.lock) {
if(this.duration==0){
seekBar.setProgress(0);
}else{
seekBar.setProgress(msPosition/this.duration);
if(this.enable){
int msPosition = Player.GetInstance().GetTrackPosition();
int position = msPosition/1000;
int minutes = (int)Math.floor(position/60);
int seconds = position-minutes*60;
String positionText = Integer.toString(minutes)+":";
if(seconds<10){ positionText += "0"; }
positionText += Integer.toString(seconds);
TextView positionView = (TextView)findViewById(R.id.TrackPosition);
positionView.setText(positionText);
SeekBar seekBar = (SeekBar)findViewById(R.id.TrackProgress);
synchronized (this.lock) {
if(this.duration==0){
seekBar.setProgress(0);
}else{
seekBar.setProgress(msPosition/this.duration);
}
seekBar.setSecondaryProgress(10*Player.GetInstance().GetTrackBuffer());
}
seekBar.setSecondaryProgress(10*Player.GetInstance().GetTrackBuffer());
}
// Next callback in 0.5 seconds

View File

@ -68,6 +68,16 @@ public class Service extends android.app.Service {
Player player = Player.GetInstance();
player.Play(intent.getIntegerArrayListExtra("org.musikcube.Service.tracklist"), intent.getIntExtra("org.musikcube.Service.position", 0));
}
if(action.equals("appendlist")){
Player player = Player.GetInstance();
player.Append(intent.getIntegerArrayListExtra("org.musikcube.Service.tracklist"));
}
if(action.equals("playlist_prepare")){
Player player = Player.GetInstance();
player.PlayWhenPrepared(intent.getIntegerArrayListExtra("org.musikcube.Service.tracklist"), intent.getIntExtra("org.musikcube.Service.position", 0));
}
if(action.equals("next")){
Player player = Player.GetInstance();
player.Next();
@ -90,6 +100,11 @@ public class Service extends android.app.Service {
this.paceDetector.StartSensor(this);
}
}
if(action.equals("bpmstop")){
if(this.paceDetector!=null){
this.paceDetector.StopSensor(this);
}
}
if(action.equals("player_start")){
Track track = Player.GetInstance().GetCurrentTrack();

View File

@ -16,15 +16,18 @@ import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.AdapterContextMenuInfo;
/**
* @author doy
@ -41,6 +44,11 @@ public class TrackList extends ListActivity implements OnQueryResultListener {
private java.lang.Object lock = new java.lang.Object();
final static public int PLAY_THIS_ID = 0;
final static public int ADD_THIS_ID = 1;
final static public int ADD_ALL_ID = 2;
// Need handler for callbacks to the UI thread
final Handler callbackHandler = new Handler();
@ -164,6 +172,8 @@ public class TrackList extends ListActivity implements OnQueryResultListener {
this.query.listTracks = true;
library.AddQuery(this.query);
this.registerForContextMenu(this.getListView());
}
public void OnResults(){
@ -294,5 +304,46 @@ public class TrackList extends ListActivity implements OnQueryResultListener {
return super.onContextItemSelected(item);
}
}
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
java.util.ArrayList<Integer> trackList = new java.util.ArrayList<Integer>();
Intent intent = new Intent(this, org.musikcube.Service.class);
intent.putExtra("org.musikcube.Service.position", 0);
switch (item.getItemId()) {
case PLAY_THIS_ID:
trackList.add((int)info.id);
intent.putExtra("org.musikcube.Service.tracklist", trackList);
intent.putExtra("org.musikcube.Service.action", "playlist");
startService(intent);
Intent intent2 = new Intent(this, PlayerControl.class);
startActivity(intent2);
return true;
case ADD_THIS_ID:
trackList.add((int)info.id);
intent.putExtra("org.musikcube.Service.tracklist", trackList);
intent.putExtra("org.musikcube.Service.action", "appendlist");
startService(intent);
return true;
case ADD_ALL_ID:
trackList.add((int)info.id);
intent.putExtra("org.musikcube.Service.tracklist", this.trackList);
intent.putExtra("org.musikcube.Service.action", "appendlist");
startService(intent);
return true;
default:
return super.onContextItemSelected(item);
}
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.add(0, PLAY_THIS_ID, 0, "Play this track");
menu.add(0, ADD_THIS_ID, 0, "Add this to current playlist");
menu.add(0, ADD_ALL_ID, 0, "Add all to current playlist");
}
}

View File

@ -0,0 +1,47 @@
package org.musikcube.core;
import doep.xml.WriterNode;
public class BPMQuery extends ListQuery {
public float queryForBPM = 0;
public BPMQuery() {
super();
this.type = "BPMQuery";
this.listTracks = true;
}
@Override
public void SendQuery(WriterNode node)
throws Exception
{
WriterNode queryNode = this.SendQueryNode(node);
// List selections
WriterNode selectionsNode = queryNode.ChildNode("selections");
int selectionCount = this.selectionStrings.size();
for(int i=0;i<selectionCount;i++){
WriterNode selectionNode = selectionsNode.ChildNode("selection");
selectionNode.attributes.put("key", this.selectionStrings.get(i));
selectionNode.content = this.selectionInts.get(i).toString();
}
// What category to listen for
WriterNode listenersNode = queryNode.ChildNode("listeners");
listenersNode.content = this.category;
// List tracks?
if(this.listTracks){
WriterNode listtracksNode = queryNode.ChildNode("listtracks");
listtracksNode.content = "true";
}
WriterNode bpmNode = queryNode.ChildNode("bpm");
bpmNode.content = ""+this.queryForBPM;
queryNode.End();
}
}

View File

@ -6,8 +6,8 @@ import doep.xml.WriterNode;
public class ListQuery extends IQuery {
public String category = "";
private java.util.ArrayList<String> selectionStrings = new java.util.ArrayList<String>();
private java.util.ArrayList<Integer> selectionInts = new java.util.ArrayList<Integer>();
protected java.util.ArrayList<String> selectionStrings = new java.util.ArrayList<String>();
protected java.util.ArrayList<Integer> selectionInts = new java.util.ArrayList<Integer>();
public java.util.ArrayList<String> resultsStrings = new java.util.ArrayList<String>();
public java.util.ArrayList<Integer> resultsInts = new java.util.ArrayList<Integer>();
public java.util.ArrayList<Integer> trackList = new java.util.ArrayList<Integer>();

View File

@ -1,6 +1,11 @@
package org.musikcube.core;
import java.util.Collections;
import org.musikcube.core.IQuery.OnQueryResultListener;
import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
@ -8,18 +13,23 @@ import android.hardware.SensorManager;
import android.util.Log;
public class PaceDetector implements Runnable, SensorEventListener {
public class PaceDetector implements Runnable, SensorEventListener, OnQueryResultListener {
static public float MAX_BPM = 165;
static public float MIN_BPM = 80;
static public int WAVE_MEMORY = 12;
static public int WAVE_MIN_CALC = 6;
static public float WAVE_MIN_BPM_DIFF = 80; // This is in miliseconds
static public int WAVE_COMPARE = 3;
static public float MAX_BPM = 85;
static public float MIN_BPM = 40;
static public int WAVE_MEMORY = 20;
static public int WAVE_MIN_CALC = 8;
static public float WAVE_MIN_BPM_DIFF = 120; // This is in miliseconds
static public int WAVE_COMPARE = 4;
static public int MIN_PLAYTIME = 20000; // Play at leased 20 seconds of a track
static public float BPM_THRESHOLD = 10; // if BPM is off by more than 10 bpm, switch track
private float currentBPM = 0;
private float currentAccuracy = 0;
private long currentBPMstart = 0;
private Context context;
private class PaceDimension{
public java.util.ArrayList<Long> beatTimes = new java.util.ArrayList<Long>();
public java.util.ArrayList<Float> amplitude = new java.util.ArrayList<Float>();
@ -59,26 +69,30 @@ public class PaceDetector implements Runnable, SensorEventListener {
// Lets calculate BPM
long bpmSum = 0;
java.util.TreeSet<Long> bpms = new java.util.TreeSet<Long>();
//java.util.TreeSet<Long> bpms = new java.util.TreeSet<Long>();
java.util.ArrayList<Long> bpms = new java.util.ArrayList<Long>();
for(int i=0;i<this.beatTimes.size()-WAVE_COMPARE;i++){
long orgSample = this.beatTimes.get(i);
for(int j=i+1;j<i+WAVE_COMPARE;j++){
//float bpmSample = 60000/(this.beatTimes.get(j)-orgSample);
long bpmSample = this.beatTimes.get(j)-orgSample;
//Log.v("MC2::C","s "+bpmSample);
if(bpmSample>(60000/MAX_BPM) && bpmSample<(60000/MIN_BPM)){
bpms.add(bpmSample);
bpmSum += bpmSample;
}
}
}
Collections.sort(bpms);
//Log.v("MC2::BEAT","B "+(bpms.size()));
// Lets remove the most "off" samples and correct the AVG until we are down to the desired "diff"
boolean qualified = false;
long bpmDiff = 0;
while(!qualified && bpms.size()>=WAVE_MIN_CALC){
Long first = bpms.first();
Long last = bpms.last();
Long first = bpms.get(0);
Long last = bpms.get(bpms.size()-1);
bpmDiff = last-first;
int bpmSize = bpms.size();
@ -92,11 +106,11 @@ public class PaceDetector implements Runnable, SensorEventListener {
if(avg-first>last-avg){
// Remove first
bpmSum -= first;
bpms.remove(first);
bpms.remove(0);
}else{
// Remove last
bpmSum -= last;
bpms.remove(last);
bpms.remove(bpms.size()-1);
}
}
}
@ -110,7 +124,7 @@ public class PaceDetector implements Runnable, SensorEventListener {
amplitude /= this.amplitude.size();
this.currentBPM = (60000*bpms.size())/bpmSum;
this.currentBPM = ((float)60000*bpms.size())/((float)bpmSum);
this.currentAccuracy = (100-bpmDiff)+bpms.size()*13+amplitude*5;
PaceDetector.this.ChangeBPM(this.currentBPM,this.currentAccuracy);
}
@ -134,20 +148,35 @@ public class PaceDetector implements Runnable, SensorEventListener {
this.xAxis.NextValue(values[0]);
this.yAxis.NextValue(values[1]);
this.zAxis.NextValue(values[2]);
// Log.v("MC2::TJOOOO",""+values[0]);
// Log.v("mC2::ACC","x="+values[0]+" y="+values[1]+" z="+values[2]);
}
public void ChangeBPM(float bpm,float accuracy){
if(accuracy>=this.xAxis.currentAccuracy || accuracy>=this.yAxis.currentAccuracy || accuracy>=this.zAxis.currentAccuracy){
this.currentBPM = bpm;
this.currentAccuracy = accuracy;
Log.v("MC2::BPM","bpm="+bpm+" "+accuracy);
bpm *= 2; // BPM should be the double
if(accuracy>=this.xAxis.currentAccuracy && accuracy>=this.yAxis.currentAccuracy && accuracy>=this.zAxis.currentAccuracy && accuracy>150){
// The BPM has changed
long currentTime = android.os.SystemClock.elapsedRealtime();
if(currentTime>this.currentBPMstart+MIN_PLAYTIME){
// We have played more than minimum time
if(bpm>this.currentBPM+BPM_THRESHOLD || bpm<this.currentBPM-BPM_THRESHOLD){
// BPM has changed enough to switch track
this.currentBPM = bpm;
this.currentAccuracy = accuracy;
BPMQuery query = new BPMQuery();
query.queryForBPM = this.currentBPM;
query.SetResultListener(this);
}
}
}
}
public void StartSensor(Context context){
this.context = context;
Log.v("mC2::ACC","Sensor");
SensorManager sensorMgr = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
Sensor accelerometer = sensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
@ -166,4 +195,15 @@ public class PaceDetector implements Runnable, SensorEventListener {
}
public void OnQueryResults(IQuery query) {
BPMQuery bpmQuery = (BPMQuery)query;
if(!bpmQuery.trackList.isEmpty()){
Intent intent = new Intent(this.context, org.musikcube.Service.class);
intent.putExtra("org.musikcube.Service.tracklist", bpmQuery.trackList);
intent.putExtra("org.musikcube.Service.position", 0);
intent.putExtra("org.musikcube.Service.action", "playlist_prepare");
this.context.startService(intent);
}
}
}

View File

@ -19,6 +19,8 @@ public class Player implements TrackPlayer.OnTrackStatusListener, OnQueryResultL
private TrackPlayer nextPlayer;
private Track currentTrack = new Track();
public boolean playWhenPrepared = false;
public android.app.Service service;
public void run() {
@ -42,6 +44,27 @@ public class Player implements TrackPlayer.OnTrackStatusListener, OnQueryResultL
this.Play();
}
public void Append(java.util.ArrayList<Integer> playlist){
synchronized(this.lock){
this.nowPlaying.addAll(playlist);
}
}
public void PlayWhenPrepared(java.util.ArrayList<Integer> playlist,int position){
synchronized(this.lock){
this.nowPlaying = playlist;
this.position = position;
if(this.nextPlayer!=null){
this.nextPlayer.SetListener(null);
this.nextPlayer.Stop();
}
this.playWhenPrepared = true;
this.nextPlayer = this.PrepareTrack(this.position);
this.nextPlayer.SetListener(this);
}
}
private TrackPlayer PrepareTrack(int position){
synchronized(this.lock){
@ -70,7 +93,7 @@ public class Player implements TrackPlayer.OnTrackStatusListener, OnQueryResultL
this.nextPlayer = null;
}else{
// Something wrong here, not the prepared track
this.nextPlayer.listener = null;
this.nextPlayer.SetListener(null);
this.nextPlayer.Stop();
this.nextPlayer = null;
}
@ -80,7 +103,7 @@ public class Player implements TrackPlayer.OnTrackStatusListener, OnQueryResultL
}
this.playingTracks.add(newPlayer);
this.currentPlayer = newPlayer;
newPlayer.listener = this;
newPlayer.SetListener(this);
newPlayer.Play();
if(this.listener!=null){
@ -114,7 +137,9 @@ public class Player implements TrackPlayer.OnTrackStatusListener, OnQueryResultL
public void OnTrackBufferUpdate(int percent);
public void OnTrackPositionUpdate(int secondsPlayed);
}
protected OnTrackUpdateListener listener = null;
public void SetUpdateListener(OnTrackUpdateListener listener){
synchronized(this.lock){
this.listener = listener;
@ -144,7 +169,7 @@ public class Player implements TrackPlayer.OnTrackStatusListener, OnQueryResultL
synchronized(this.lock){
this.StopAllTracks();
if(this.nextPlayer!=null){
this.nextPlayer.listener = null;
this.nextPlayer.SetListener(null);
this.nextPlayer.Stop();
this.nextPlayer = null;
}
@ -157,7 +182,7 @@ public class Player implements TrackPlayer.OnTrackStatusListener, OnQueryResultL
this.currentPlayer = null;
int trackCount = this.playingTracks.size();
for(int i=0;i<trackCount;i++){
this.playingTracks.get(i).listener = null;
this.playingTracks.get(i).SetListener(null);
this.playingTracks.get(i).Stop();
}
this.playingTracks.clear();
@ -264,4 +289,13 @@ public class Player implements TrackPlayer.OnTrackStatusListener, OnQueryResultL
}
}
public void OnTrackPrepared(TrackPlayer trackPlayer) {
synchronized(this.lock){
if(this.playWhenPrepared){
this.playWhenPrepared = false;
this.Play();
}
}
}
}

View File

@ -1,6 +1,7 @@
package org.musikcube.core;
import android.media.MediaPlayer;
import android.util.Log;
public class TrackPlayer implements Runnable, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener,MediaPlayer.OnBufferingUpdateListener {
@ -20,6 +21,7 @@ public class TrackPlayer implements Runnable, MediaPlayer.OnCompletionListener,
public static final int STATUS_EXIT = 10;
public void run() {
Log.v("mC2::TrackPlayer", "Thread started "+this.url);
synchronized(this.lock){
this.mediaPlayer = new MediaPlayer();
}
@ -30,9 +32,15 @@ public class TrackPlayer implements Runnable, MediaPlayer.OnCompletionListener,
this.mediaPlayer.setOnBufferingUpdateListener(this);
this.mediaPlayer.setDataSource(this.url);
Log.v("mC2::TrackPlayer", "Preparing "+this.url);
this.mediaPlayer.prepare();
Log.v("mC2::TrackPlayer", "Prepared "+this.url);
synchronized(this.lock){
if(this.listener!=null){
this.listener.OnTrackPrepared(this);
}
while(this.status==STATUS_PREPARED)
this.lock.wait();
}
@ -42,6 +50,8 @@ public class TrackPlayer implements Runnable, MediaPlayer.OnCompletionListener,
currentStatus = this.status;
}
Log.v("mC2::TrackPlayer", "Start? "+this.url);
if(currentStatus==STATUS_PLAYING)
this.mediaPlayer.start();
@ -54,6 +64,7 @@ public class TrackPlayer implements Runnable, MediaPlayer.OnCompletionListener,
// The track is almost done
this.almostDoneSend = true;
if(this.listener!=null){
Log.v("mC2::TrackPlayer", "OnTrackAlmostDone "+this.url);
this.listener.OnTrackAlmostDone(this);
}
}
@ -62,16 +73,23 @@ public class TrackPlayer implements Runnable, MediaPlayer.OnCompletionListener,
}
}
Log.v("mC2::TrackPlayer", "Stopping "+this.url);
this.mediaPlayer.stop();
this.mediaPlayer.release();
synchronized(this.lock){
this.mediaPlayer = null;
}
} catch (Exception e) {
}
synchronized(this.lock){
this.status = STATUS_EXIT;
}
Log.v("mC2::TrackPlayer", "ExitCallbacks "+this.url);
this.CallListener();
Log.v("mC2::TrackPlayer", "END "+this.url);
}
@ -126,8 +144,10 @@ public class TrackPlayer implements Runnable, MediaPlayer.OnCompletionListener,
}
private void CallListener(){
if(this.listener!=null){
this.listener.OnTrackStatusUpdate(this,this.status);
synchronized(this.lock){
if(this.listener!=null){
this.listener.OnTrackStatusUpdate(this,this.status);
}
}
}
@ -138,11 +158,18 @@ public class TrackPlayer implements Runnable, MediaPlayer.OnCompletionListener,
}
public interface OnTrackStatusListener{
public void OnTrackPrepared(TrackPlayer trackPlayer);
public void OnTrackStatusUpdate(TrackPlayer trackPlayer,int status);
public void OnTrackAlmostDone(TrackPlayer trackPlayer);
}
public OnTrackStatusListener listener = null;
private OnTrackStatusListener listener = null;
public void SetListener(OnTrackStatusListener listener){
synchronized(this.lock){
this.listener = listener;
}
}
public void onCompletion(MediaPlayer mp) {
synchronized(this.lock){

View File

@ -33,6 +33,10 @@ public class main extends Activity implements OnLibraryStatusListener {
artistsButton.setOnClickListener(this.onArtistsClick);
artistsButton.setEnabled(false);
Button yearButton = (Button)findViewById(R.id.YearButton);
yearButton.setOnClickListener(this.onYearClick);
yearButton.setEnabled(false);
Button bpmButton = (Button)findViewById(R.id.BPMButton);
bpmButton.setOnClickListener(this.onBPMClick);
bpmButton.setEnabled(false);
@ -55,6 +59,14 @@ public class main extends Activity implements OnLibraryStatusListener {
}
};
private OnClickListener onYearClick = new OnClickListener() {
public void onClick(View v){
Intent intent = new Intent(main.this, CategoryList.class);
intent.putExtra("org.musikcube.CategoryList.listCategory", "year,artist,album");
startActivity(intent);
}
};
private OnClickListener onBPMClick = new OnClickListener() {
public void onClick(View v){
Intent intent = new Intent(main.this, org.musikcube.Service.class);
@ -121,15 +133,18 @@ public class main extends Activity implements OnLibraryStatusListener {
int status = Library.GetInstance().GetStatus();
Button genreButton = (Button)findViewById(R.id.GenresButton);
Button artistsButton = (Button)findViewById(R.id.ArtistsButton);
Button yearButton = (Button)findViewById(R.id.YearButton);
Button bpmButton = (Button)findViewById(R.id.BPMButton);
if(status==Library.STATUS_CONNECTED){
genreButton.setEnabled(true);
artistsButton.setEnabled(true);
bpmButton.setEnabled(true);
yearButton.setEnabled(true);
// bpmButton.setEnabled(true);
}else{
genreButton.setEnabled(false);
artistsButton.setEnabled(false);
yearButton.setEnabled(false);
bpmButton.setEnabled(false);
}