mirror of
https://github.com/clangen/musikcube.git
synced 2025-02-11 09:40:26 +00:00
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:
parent
16dd505de1
commit
44a071b2bb
Binary file not shown.
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 34 KiB |
@ -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>
|
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
@ -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>
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
47
src/android/src/org/musikcube/core/BPMQuery.java
Normal file
47
src/android/src/org/musikcube/core/BPMQuery.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
@ -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>();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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){
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user