More on the Workout mode.

Shuffle and repeat working.
Highlighting the playing track in "now playing" list.
More icons.
Added help dialog.
This commit is contained in:
Daniel Önnerby 2009-08-29 21:20:13 +00:00
parent 13567caf8d
commit 522e3c917b
34 changed files with 745 additions and 270 deletions

View File

@ -3,7 +3,7 @@
package="org.musikcube"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name" android:name="App" android:debuggable="true">
<application android:icon="@drawable/icon" android:label="@string/app_name" android:name="App" android:debuggable="false">
<activity android:name=".main"
android:label="@string/app_name" android:launchMode="singleTask">
<intent-filter>
@ -17,6 +17,8 @@
<activity android:name="Preferences"></activity>
<activity android:name="PlayerControl" android:launchMode="singleTask"></activity>
<activity android:name="NowPlayingList" android:launchMode="singleTask"></activity>
<activity android:name="PlayerBPMControl" android:launchMode="singleTask" android:screenOrientation="portrait"></activity>
<activity android:name="CategorySelect" android:launchMode="singleTask"></activity>
</application>
<uses-sdk android:minSdkVersion="3" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 935 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -7,9 +7,15 @@
android:paddingRight="8dp" android:gravity="center_vertical">
<LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical|center_horizontal">
<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content">
<FrameLayout android:id="@+id/FrameLayout01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="10sp" android:padding="2sp" android:background="#666666">
<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" android:background="#000000"></ImageView>
</FrameLayout>
<LinearLayout android:id="@+id/LinearLayout01" android:layout_height="wrap_content" android:orientation="vertical" android:layout_width="wrap_content" android:layout_gravity="center_vertical">
<ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/MediaRepeat" android:src="@drawable/ic_repeat" android:adjustViewBounds="true" android:padding="10sp"></ImageButton>
<ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:adjustViewBounds="true" android:padding="10sp" android:id="@+id/MediaShuffle" android:src="@drawable/ic_shuffle"></ImageButton>
</LinearLayout>
</LinearLayout>
<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:" 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>

View File

@ -5,8 +5,6 @@
android:layout_height="fill_parent">
<TextView android:id="@+id/text"
android:layout_width="0dip"
android:layout_weight="1.0"
android:layout_height="wrap_content" android:textSize="28sp" android:fadingEdge="horizontal" android:maxLines="1" android:fadingEdgeLength="10sp"/>
android:layout_height="wrap_content" android:textSize="28sp" android:fadingEdge="horizontal" android:maxLines="1" android:fadingEdgeLength="10sp" android:layout_width="wrap_content"/>
</LinearLayout>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="8dp"
android:paddingRight="8dp">
<ListView android:id="@id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:drawSelectorOnTop="false"/>
<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

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<CheckBox android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="28sp" android:maxLines="1"></CheckBox>
</LinearLayout>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/help_main" android:layout_margin="10sp"></TextView>
</LinearLayout>

View File

@ -3,17 +3,17 @@
android:layout_width="fill_parent"
android:layout_height="fill_parent" android:orientation="horizontal">
<ImageView android:id="@+id/PlayingImage" android:layout_height="32sp" android:layout_width="32sp"></ImageView>
<TextView android:id="@+id/track"
android:layout_width="32sp"
android:layout_height="wrap_content" android:textSize="24sp" android:fadingEdge="horizontal" android:maxLines="1" android:fadingEdgeLength="10sp"/>
<LinearLayout
android:layout_height="wrap_content" android:orientation="vertical" android:layout_width="wrap_content">
<TextView android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content" android:textSize="24sp" android:fadingEdge="horizontal" android:maxLines="1" android:fadingEdgeLength="10sp" android:hint="...."/>
android:layout_height="wrap_content" android:textSize="24sp" android:fadingEdge="horizontal" android:maxLines="1" android:fadingEdgeLength="10sp" android:hint="...." android:layout_width="wrap_content"/>
<TextView android:id="@+id/artist"
android:layout_width="fill_parent"
android:layout_height="wrap_content" android:fadingEdge="horizontal" android:maxLines="1" android:fadingEdgeLength="10sp" android:textColor="#999999" android:textSize="16sp"/>
android:layout_height="wrap_content" android:fadingEdge="horizontal" android:maxLines="1" android:fadingEdgeLength="10sp" android:textColor="#999999" android:textSize="16sp" android:layout_width="wrap_content"/>
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="8dp"
android:paddingRight="8dp" android:gravity="center_vertical|center_horizontal">
<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content">
<FrameLayout android:id="@+id/FrameLayout01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="10sp" android:padding="2sp" android:background="#666666">
<ImageView android:layout_marginTop="5sp" android:layout_marginBottom="5sp" android:id="@+id/AlbumCover" android:background="#000000" android:src="@drawable/running" android:layout_height="128sp" android:layout_width="128sp" android:scaleType="fitXY"></ImageView>
</FrameLayout>
</LinearLayout>
<LinearLayout android:id="@+id/LinearLayout01" android:layout_height="wrap_content" android:orientation="vertical" android:gravity="left" android:layout_width="wrap_content" android:layout_gravity="left" android:paddingLeft="20sp">
<TextView android:layout_height="wrap_content" android:textSize="24sp" android:id="@+id/TrackTitle" android:lines="1" android:layout_width="wrap_content" android:text="Title:"></TextView>
<TextView android:layout_height="wrap_content" android:text="Album:" android:id="@+id/TrackAlbum" android:lines="1" android:layout_width="wrap_content"></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"><TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:id="@+id/BPMText" android:textSize="32sp" android:text="Pace: - Bpm"></TextView></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:adjustViewBounds="true" android:id="@+id/MediaPause" android:src="@drawable/ic_media_pause" android:padding="15sp"></ImageButton>
<ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/MediaNext" android:adjustViewBounds="true" android:src="@drawable/ic_media_next" android:padding="15sp"></ImageButton>
</LinearLayout>
<LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="0:00" android:id="@+id/TrackPosition" android:typeface="monospace"></TextView>
<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:id="@+id/TrackProgress" android:progress="0" android:secondaryProgress="0"></SeekBar>
</LinearLayout>

View File

@ -14,8 +14,6 @@
<ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/MediaRepeat" android:src="@drawable/ic_repeat" android:adjustViewBounds="true" android:padding="10sp"></ImageButton>
<ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:adjustViewBounds="true" android:padding="10sp" android:id="@+id/MediaShuffle" android:src="@drawable/ic_shuffle"></ImageButton>
</LinearLayout>
</LinearLayout>
<LinearLayout android:id="@+id/LinearLayout01" android:layout_height="wrap_content" android:orientation="vertical" android:gravity="left" android:layout_width="wrap_content" android:layout_gravity="left" android:paddingLeft="20sp">

View File

@ -3,4 +3,5 @@
<item android:title="@string/menu_controls" android:id="@+id/context_controls" android:enabled="true" android:visible="true" android:icon="@drawable/ic_menu_play"></item>
<item android:title="@string/menu_settings" android:id="@+id/context_settings" android:enabled="true" android:visible="true" android:icon="@drawable/ic_menu_preferences"></item>
<item android:id="@+id/context_nowplaying" android:title="@string/menu_nowplaying" android:icon="@drawable/ic_menu_nowplaying"></item>
<item android:id="@+id/context_help" android:title="@string/menu_help" android:icon="@drawable/ic_menu_help"></item>
</menu>

View File

@ -19,4 +19,6 @@
<string name="menu_controls">Player controls</string>
<string name="menu_browse">Browse</string>
<string name="menu_nowplaying">Now playing</string>
<string name="help_main">musikCube is a application that connects to you musikServer that you have installed on your desktop/server computer. Once musikCube is connected you are able to browse and play all your music directly on your phone without having to copy them to you SD card.</string>
</resources>

View File

@ -6,10 +6,10 @@ import java.io.InputStream;
import java.lang.Exception;
public class Reader extends ReaderNode {
private InputStream stream;
private org.xmlpull.v1.XmlPullParser parser;
private java.util.LinkedList<ReaderNode> nodeLevels = new java.util.LinkedList<ReaderNode>();
public final class Reader extends ReaderNode {
private final InputStream stream;
private final org.xmlpull.v1.XmlPullParser parser;
private final java.util.LinkedList<ReaderNode> nodeLevels = new java.util.LinkedList<ReaderNode>();
public ReaderNode currentNode;
private boolean firstParse = true;
@ -33,7 +33,7 @@ public class Reader extends ReaderNode {
}
public void Parse()
public final void Parse()
throws Exception
{
int eventType = 0;

View File

@ -3,10 +3,10 @@ import doep.xml.Reader;
public class ReaderNode {
public String name = "";
public final String name;
public boolean ended = false;
public String content = "";
public ReaderNode parent;
public final ReaderNode parent;
public Reader reader;
public int level = 1;
@ -25,7 +25,7 @@ public class ReaderNode {
* @param attribute
* @return String or null
*/
public String Attribute(String attribute){
public final String Attribute(String attribute){
return this.attributes.get(attribute);
}
@ -34,7 +34,7 @@ public class ReaderNode {
* @param name Name of node to be found
* @return ReaderNode if found, or null if this goes out of scope
*/
public ReaderNode ChildNode(String name)
public final ReaderNode ChildNode(String name)
throws Exception
{
//Log.v("doep::ReaderNode::ChildNode","Node: "+name+" ended: "+this.ended);
@ -59,7 +59,7 @@ public class ReaderNode {
return null;
}
public void End()
public final void End()
throws Exception
{
while(!this.ended){
@ -73,7 +73,7 @@ public class ReaderNode {
* Wait for a childnode
* @return ReaderNode if found, or null if this goes out of scope
*/
public ReaderNode ChildNode()
public final ReaderNode ChildNode()
throws Exception
{
while(!this.ended){

View File

@ -1,10 +1,10 @@
package doep.xml;
public class Writer extends WriterNode {
public final class Writer extends WriterNode {
public String buffer;
private java.io.OutputStream stream;
private final java.io.OutputStream stream;
public Writer(java.io.OutputStream stream){
super("",null);
@ -14,7 +14,7 @@ public class Writer extends WriterNode {
this.state = 1;
}
public void Write(String content)
public final void Write(String content)
throws java.io.IOException
{
//Log.v("doep.xml.Writer","Write "+content);
@ -22,13 +22,13 @@ public class Writer extends WriterNode {
// this.buffer += content;
}
public void Flush()
public final void Flush()
throws java.io.IOException
{
this.Flush(false);
}
public void Flush(boolean writeNull)
public final void Flush(boolean writeNull)
throws java.io.IOException
{
//Log.v("doep.xml.Writer","Flush "+writeNull);

View File

@ -4,12 +4,12 @@ import java.util.ListIterator;
import java.util.Map;
public class WriterNode {
public String name = "";
public final String name;
public String content = "";
protected WriterNode parent;
protected Writer writer;
private java.util.List<WriterNode> children = new java.util.LinkedList<WriterNode>();
public java.util.SortedMap<String,String> attributes = new java.util.TreeMap<String,String>();
private final java.util.List<WriterNode> children = new java.util.LinkedList<WriterNode>();
public final java.util.SortedMap<String,String> attributes = new java.util.TreeMap<String,String>();
protected int state = 0;
@ -27,7 +27,7 @@ public class WriterNode {
return newNode;
}
public void End()
public final void End()
throws java.io.IOException
{
if(this.parent.state==0){
@ -61,7 +61,7 @@ public class WriterNode {
}
}
protected void WriteStartTag()
protected final void WriteStartTag()
throws java.io.IOException
{
if(this.state==0){

View File

@ -5,6 +5,7 @@ package org.musikcube;
import java.util.ArrayList;
import org.musikcube.TrackListBase.TrackViewHolder;
import org.musikcube.core.IQuery;
import org.musikcube.core.ListQuery;
import org.musikcube.core.IQuery.OnQueryResultListener;
@ -20,6 +21,7 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
@ -46,6 +48,10 @@ public class CategoryList extends ListActivity implements OnQueryResultListener
OnResults();
}
};
static class CategoryViewHolder{
TextView title;
}
public class ResultAdapter extends BaseAdapter{
@ -84,15 +90,21 @@ public class CategoryList extends ListActivity implements OnQueryResultListener
}
public View getView(int position, View view, ViewGroup parent) {
final CategoryViewHolder holder;
if(view==null){
view = inflator.inflate(R.layout.category_list_item, null);
holder = new CategoryViewHolder();
holder.title = (TextView) view.findViewById(R.id.text);
view.setTag(holder);
}else{
holder = (CategoryViewHolder)view.getTag();
}
//
if(position==0){
((TextView) view.findViewById(R.id.text)).setText("- All -");
holder.title.setText("- All -");
}else{
((TextView) view.findViewById(R.id.text)).setText(this.query.resultsStrings.get(position-1));
holder.title.setText(this.query.resultsStrings.get(position-1));
}
return view;
}
@ -230,22 +242,10 @@ public class CategoryList extends ListActivity implements OnQueryResultListener
}
public boolean onOptionsItemSelected(MenuItem item) {
//Log.i("MC2.onContextItemSelected","item "+item.getItemId()+" "+R.id.context_settings);
switch (item.getItemId()) {
case R.id.context_settings:
startActivity(new Intent(this, org.musikcube.Preferences.class));
return true;
case R.id.context_browse:
startActivity(new Intent(this, org.musikcube.main.class));
return true;
case R.id.context_controls:
startActivity(new Intent(this, org.musikcube.PlayerControl.class));
return true;
case R.id.context_nowplaying:
startActivity(new Intent(this, org.musikcube.NowPlayingList.class));
return true;
default:
return super.onContextItemSelected(item);
}
if(Helper.DefaultOptionsItemSelected(item,this)){
return true;
}else{
return super.onContextItemSelected(item);
}
}
}

View File

@ -0,0 +1,252 @@
/**
*
*/
package org.musikcube;
import java.util.ArrayList;
import org.musikcube.TrackListBase.TrackViewHolder;
import org.musikcube.core.IQuery;
import org.musikcube.core.ListQuery;
import org.musikcube.core.IQuery.OnQueryResultListener;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
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.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
/**
* @author doy
*
*/
public class CategorySelect extends ListActivity implements OnQueryResultListener {
private String category = null;
private String nextCategoryList = "";
private ListQuery query = new ListQuery();
private ArrayList<String> selectedCategory;
private ArrayList<Integer> selectedCategoryIds;
// private ProgressDialog loadingDialog;
// Need handler for callbacks to the UI thread
final Handler callbackHandler = new Handler();
// Create runnable for posting
final Runnable callbackRunnable = new Runnable() {
public void run() {
OnResults();
}
};
static class CategoryViewHolder{
CheckBox title;
}
public class ResultAdapter extends BaseAdapter{
protected ListQuery query;
protected ListActivity context;
private LayoutInflater inflator;
public ResultAdapter(ListActivity context){
this.context = context;
this.inflator = context.getLayoutInflater();
}
public int getCount() {
int size = this.query.resultsInts.size();
if(size==0){
return 0;
}else{
return size+1;
}
}
public Object getItem(int position) {
if(position==0){
return 0;
}else{
return this.query.resultsInts.get(position-1);
}
}
public long getItemId(int position) {
if(position==0){
return 0;
}else{
return this.query.resultsInts.get(position-1);
}
}
public View getView(int position, View view, ViewGroup parent) {
final CategoryViewHolder holder;
if(view==null){
view = inflator.inflate(R.layout.category_select_item, null);
holder = new CategoryViewHolder();
holder.title = (CheckBox) view.findViewById(R.id.text);
view.setTag(holder);
}else{
holder = (CategoryViewHolder)view.getTag();
}
//
if(position==0){
holder.title.setText("- All -");
}else{
holder.title.setText(this.query.resultsStrings.get(position-1));
}
return view;
}
}
private ResultAdapter listAdapter;
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//Log.v("musikcube.CategoryList", "start");
this.setContentView(R.layout.category_select);
Intent intent = this.getIntent();
this.query.SetResultListener(this);
this.listAdapter = new ResultAdapter(this);
this.listAdapter.query = this.query;
setListAdapter(this.listAdapter);
// Extract the category order
String categoryString = intent.getStringExtra("org.musikcube.CategorySelect.listCategory");
String[] categories = categoryString.split(",");
this.category = categories[0];
// Save the next category lists
for(int i=1;i<categories.length;i++){
if(i>1){
this.nextCategoryList += ",";
}
this.nextCategoryList += categories[i];
}
this.setTitle("musikCube: "+this.category);
if(this.category!=null){
//Log.v("musikcube.CategoryList", "category="+this.category);
// Query for data
this.query.category = this.category;
// check for selection
this.selectedCategory = intent.getStringArrayListExtra("org.musikcube.CategoryList.selectedCategory");
this.selectedCategoryIds = intent.getIntegerArrayListExtra("org.musikcube.CategoryList.selectedCategoryId");
if(this.selectedCategory!=null){
for(int i=0;i<this.selectedCategory.size();i++){
this.query.SelectData(this.selectedCategory.get(i), this.selectedCategoryIds.get(i));
}
}
org.musikcube.core.Library library = org.musikcube.core.Library.GetInstance();
//this.loadingDialog = ProgressDialog.show(this, "", "Loading "+this.category+"...", true);
library.AddQuery(this.query);
}else{
//Log.v("musikcube.CategoryList", "category=null");
}
//Log.v("musikcube.CategoryList", "onCreate end");
}
public void OnResults(){
//Log.i("CategoryList::OnResults","In right thread "+this.query.resultsStrings.size());
/*if(this.loadingDialog!=null){
this.loadingDialog.dismiss();
this.loadingDialog = null;
}*/
this.listAdapter.notifyDataSetChanged();
}
public void OnQueryResults(IQuery query) {
// Call in right thread
this.callbackHandler.post(this.callbackRunnable);
}
@SuppressWarnings("unchecked")
@Override
protected void onListItemClick(ListView l, View v, int position, long id){
//Log.i("CategoryList::onListItemClick","clicked on "+position+" "+id);
// List category
if(this.selectedCategory==null){
this.selectedCategory = new ArrayList<String>();
}
if(this.selectedCategoryIds==null){
this.selectedCategoryIds = new ArrayList<Integer>();
}
ArrayList<String> selectedCategory = (ArrayList<String>)this.selectedCategory.clone();
ArrayList<Integer> selectedCategoryIds = (ArrayList<Integer>)this.selectedCategoryIds.clone();
if(id!=0){
selectedCategory.add(this.category);
selectedCategoryIds.add((int)id);
}
if(this.nextCategoryList.equals("")){
// List tracks
Intent intent = new Intent(this, TrackList.class);
intent.putExtra("org.musikcube.CategoryList.listCategory", this.nextCategoryList);
intent.putExtra("org.musikcube.CategoryList.selectedCategory", selectedCategory);
intent.putExtra("org.musikcube.CategoryList.selectedCategoryId", selectedCategoryIds);
startActivity(intent);
}else{
Intent intent = new Intent(this, CategoryList.class);
intent.putExtra("org.musikcube.CategoryList.listCategory", this.nextCategoryList);
intent.putExtra("org.musikcube.CategoryList.selectedCategory", selectedCategory);
intent.putExtra("org.musikcube.CategoryList.selectedCategoryId", selectedCategoryIds);
startActivity(intent);
}
}
@Override
protected void onPause() {
super.onPause();
org.musikcube.core.Library.GetInstance().RemovePointer();
}
@Override
protected void onResume() {
super.onResume();
startService(new Intent(this, org.musikcube.Service.class));
org.musikcube.core.Library.GetInstance().AddPointer();
}
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.default_menu, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
if(Helper.DefaultOptionsItemSelected(item,this)){
return true;
}else{
return super.onContextItemSelected(item);
}
}
}

View File

@ -0,0 +1,44 @@
package org.musikcube;
import org.musikcube.core.Player;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.view.MenuItem;
public class Helper {
public static boolean DefaultOptionsItemSelected(MenuItem item,Context context) {
//Log.i("MC2.onContextItemSelected","item "+item.getItemId()+" "+R.id.context_settings);
switch (item.getItemId()) {
case R.id.context_settings:
context.startActivity(new Intent(context, org.musikcube.Preferences.class));
return true;
case R.id.context_browse:
context.startActivity(new Intent(context, org.musikcube.main.class));
return true;
case R.id.context_controls:
if(Player.GetInstance().GetBPMMode()){
context.startActivity(new Intent(context, org.musikcube.PlayerBPMControl.class));
}else{
context.startActivity(new Intent(context, org.musikcube.PlayerControl.class));
}
return true;
case R.id.context_nowplaying:
context.startActivity(new Intent(context, org.musikcube.NowPlayingList.class));
return true;
case R.id.context_help:
Dialog dialog = new Dialog(context);
dialog.setContentView(R.layout.help);
dialog.setTitle("Help");
dialog.show();
return true;
default:
return false;
}
}
}

View File

@ -28,11 +28,11 @@ public class NowPlayingList extends TrackListBase implements OnTrackListUpdateLi
final static public int ADD_ALL_ID = 2;
final static public int REMOVE_ID = 3;
public int position = 0;
@Override
protected void onCreate(Bundle savedInstanceState){
this.markPosition = true;
this.trackListViewId = R.layout.now_playing_list;
this.trackListItemViewId = R.layout.now_playing_list_item;
@ -74,6 +74,11 @@ public class NowPlayingList extends TrackListBase implements OnTrackListUpdateLi
intent.putExtra("org.musikcube.Service.action", "appendlist");
startService(intent);
return true;
case REMOVE_ID:
intent.putExtra("org.musikcube.Service.action", "remove_from_list");
intent.putExtra("org.musikcube.Service.position", info.position);
startService(intent);
return true;
default:
return super.onContextItemSelected(item);
}
@ -86,6 +91,7 @@ public class NowPlayingList extends TrackListBase implements OnTrackListUpdateLi
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");
menu.add(0, REMOVE_ID, 0, "Remove from playlist");
}
public void OnTrackListPositionUpdate() {
@ -106,7 +112,6 @@ public class NowPlayingList extends TrackListBase implements OnTrackListUpdateLi
}
@Override
protected void onPause() {
super.onPause();
@ -117,6 +122,8 @@ public class NowPlayingList extends TrackListBase implements OnTrackListUpdateLi
protected void onResume() {
super.onResume();
Player.GetInstance().SetListUpdateListener(this);
this.position = Player.GetInstance().GetPosition();
this.setSelection(this.position);
}

View File

@ -19,71 +19,79 @@ import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
public class BPMControl extends Activity implements OnTrackUpdateListener {
public class PlayerBPMControl 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) {
Log.v("MC2::PC","OnCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.play_control);
/*
setContentView(R.layout.play_bpm_control);
ImageButton nextButton = (ImageButton)findViewById(R.id.MediaNext);
nextButton.setOnClickListener(this.onNextClick);
ImageButton pauseButton = (ImageButton)findViewById(R.id.MediaPause);
pauseButton.setOnClickListener(this.onPauseClick);
*/
this.callbackTrackPositionsUpdateHandler.postDelayed(callbackTrackPositionsUpdateRunnable,500);
Intent intent = new Intent(PlayerBPMControl.this, org.musikcube.Service.class);
intent.putExtra("org.musikcube.Service.action", "bpmstart");
startService(intent);
}
/*
private OnClickListener onNextClick = new OnClickListener() {
public void onClick(View v){
Intent intent = new Intent(PlayerControl.this, org.musikcube.Service.class);
Intent intent = new Intent(PlayerBPMControl.this, org.musikcube.Service.class);
intent.putExtra("org.musikcube.Service.action", "next");
startService(intent);
}
};
private OnClickListener onPauseClick = new OnClickListener() {
public void onClick(View v){
Intent intent = new Intent(PlayerControl.this, org.musikcube.Service.class);
Intent intent = new Intent(PlayerBPMControl.this, org.musikcube.Service.class);
intent.putExtra("org.musikcube.Service.action", "stop");
startService(intent);
}
};
*/
public void OnTrackBufferUpdate(int percent) {
synchronized(lock){
}
this.callbackTrackPositionsUpdateHandler.post(this.callbackTrackPositionsUpdateRunnable);
}
public void OnTrackPositionUpdate(int secondsPlayed) {
synchronized(lock){
}
this.callbackTrackPositionsUpdateHandler.post(this.callbackTrackPositionsUpdateRunnable);
}
public void OnTrackUpdate() {
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
@ -149,13 +157,16 @@ public class BPMControl extends Activity implements OnTrackUpdateListener {
}
// 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);
}
}
}
@ -198,24 +209,26 @@ public class BPMControl extends Activity implements OnTrackUpdateListener {
};
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
@ -230,20 +243,11 @@ public class BPMControl extends Activity implements OnTrackUpdateListener {
}
public boolean onOptionsItemSelected(MenuItem item) {
//Log.i("MC2.onContextItemSelected","item "+item.getItemId()+" "+R.id.context_settings);
switch (item.getItemId()) {
case R.id.context_settings:
startActivity(new Intent(this, org.musikcube.Preferences.class));
return true;
case R.id.context_browse:
startActivity(new Intent(this, org.musikcube.main.class));
return true;
case R.id.context_controls:
startActivity(new Intent(this, org.musikcube.PlayerControl.class));
return true;
default:
return super.onContextItemSelected(item);
}
if(Helper.DefaultOptionsItemSelected(item,this)){
return true;
}else{
return super.onContextItemSelected(item);
}
}
}

View File

@ -287,23 +287,11 @@ public class PlayerControl extends Activity implements OnTrackUpdateListener {
}
public boolean onOptionsItemSelected(MenuItem item) {
//Log.i("MC2.onContextItemSelected","item "+item.getItemId()+" "+R.id.context_settings);
switch (item.getItemId()) {
case R.id.context_settings:
startActivity(new Intent(this, org.musikcube.Preferences.class));
return true;
case R.id.context_browse:
startActivity(new Intent(this, org.musikcube.main.class));
return true;
case R.id.context_controls:
startActivity(new Intent(this, org.musikcube.PlayerControl.class));
return true;
case R.id.context_nowplaying:
startActivity(new Intent(this, org.musikcube.NowPlayingList.class));
return true;
default:
return super.onContextItemSelected(item);
}
if(Helper.DefaultOptionsItemSelected(item,this)){
return true;
}else{
return super.onContextItemSelected(item);
}
}
}

View File

@ -92,6 +92,10 @@ public class Service extends android.app.Service {
Player player = Player.GetInstance();
player.Append(intent.getIntegerArrayListExtra("org.musikcube.Service.tracklist"));
}
if(action.equals("remove_from_list")){
Player player = Player.GetInstance();
player.RemoveFromList(intent.getIntExtra("org.musikcube.Service.position", -1));
}
if(action.equals("playlist_prepare")){
Player player = Player.GetInstance();
@ -109,6 +113,9 @@ public class Service extends android.app.Service {
if(action.equals("stop")){
Player player = Player.GetInstance();
player.Stop();
if(this.paceDetector!=null){
this.paceDetector.StopSensor(this);
}
}
if(action.equals("play")){
Player player = Player.GetInstance();
@ -119,6 +126,7 @@ public class Service extends android.app.Service {
this.stopSelf();
}
if(action.equals("bpmstart")){
Player.GetInstance().SetBPMMode(true);
if(this.paceDetector==null){
this.paceDetector = new PaceDetector();
this.paceDetector.StartSensor(this);
@ -157,7 +165,7 @@ public class Service extends android.app.Service {
contentText += trackArtist;
}
}
Intent notificationIntent = new Intent(this, PlayerControl.class);
Intent notificationIntent = new Intent(this, Player.GetInstance().GetBPMMode()?PlayerBPMControl.class:PlayerControl.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.flags |= Notification.FLAG_ONGOING_EVENT|Notification.FLAG_NO_CLEAR;

View File

@ -20,6 +20,7 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
@ -39,6 +40,9 @@ public class TrackListBase extends ListActivity implements OnQueryResultListener
protected java.lang.Object lock = new java.lang.Object();
protected int position = -1;
protected boolean markPosition = false;
// Need handler for callbacks to the UI thread
final Handler callbackHandler = new Handler();
@ -53,6 +57,7 @@ public class TrackListBase extends ListActivity implements OnQueryResultListener
TextView track;
TextView title;
TextView artist;
ImageView marker;
}
public class ResultAdapter extends BaseAdapter{
@ -82,18 +87,29 @@ public class TrackListBase extends ListActivity implements OnQueryResultListener
public View getView(int position, View view, ViewGroup parent) {
TrackViewHolder holder;
if(view==null){
view = inflator.inflate(R.layout.track_list_item, null);
view = inflator.inflate(TrackListBase.this.trackListItemViewId, null);
holder = new TrackViewHolder();
holder.title = (TextView) view.findViewById(R.id.title);
holder.track = (TextView) view.findViewById(R.id.track);
holder.artist = (TextView) view.findViewById(R.id.artist);
if(TrackListBase.this.markPosition){
holder.marker = (ImageView) view.findViewById(R.id.PlayingImage);
}
view.setTag(holder);
}else{
holder = (TrackViewHolder)view.getTag();
}
if(holder.marker!=null){
if(position==this.trackList.position){
holder.marker.setImageResource(R.drawable.ic_playing);
}else{
holder.marker.setImageBitmap(null);
}
}
Track track = this.trackList.GetTrack(position);
if(track==null){
holder.track.setText("");
@ -248,23 +264,11 @@ public class TrackListBase extends ListActivity implements OnQueryResultListener
}
public boolean onOptionsItemSelected(MenuItem item) {
//Log.i("MC2.onContextItemSelected","item "+item.getItemId()+" "+R.id.context_settings);
switch (item.getItemId()) {
case R.id.context_settings:
startActivity(new Intent(this, org.musikcube.Preferences.class));
return true;
case R.id.context_browse:
startActivity(new Intent(this, org.musikcube.main.class));
return true;
case R.id.context_controls:
startActivity(new Intent(this, org.musikcube.PlayerControl.class));
return true;
case R.id.context_nowplaying:
startActivity(new Intent(this, org.musikcube.NowPlayingList.class));
return true;
default:
return super.onContextItemSelected(item);
}
if(Helper.DefaultOptionsItemSelected(item,this)){
return true;
}else{
return super.onContextItemSelected(item);
}
}
}

View File

@ -24,7 +24,7 @@ public class IQuery extends Object{
protected WriterNode SendQueryNode(WriterNode parentNode)
{
WriterNode queryNode = parentNode.ChildNode("query");
final WriterNode queryNode = parentNode.ChildNode("query");
queryNode.attributes.put("id",Integer.toString(this.id));
queryNode.attributes.put("uid",Integer.toString(this.uid));
queryNode.attributes.put("type",this.type);

View File

@ -18,7 +18,7 @@ import org.musikcube.core.IQuery;
* @author doy
*
*/
public class Library implements Runnable{
public final class Library implements Runnable{
// private String username;
// private String password;
@ -67,7 +67,7 @@ public class Library implements Runnable{
public void OnLibraryStatusChange(int status);
}
public void SetStatusListener(OnLibraryStatusListener statusListener){
public final void SetStatusListener(OnLibraryStatusListener statusListener){
synchronized(this.status){
this.statusListener = statusListener;
if(this.statusListener!=null){
@ -76,7 +76,7 @@ public class Library implements Runnable{
}
}
private void SetStatus(int status){
private final void SetStatus(int status){
synchronized(this.status){
//Log.v("mC2::Lib","STATUS "+this.status);
this.status = status;
@ -86,19 +86,19 @@ public class Library implements Runnable{
}
}
public int GetStatus(){
public final int GetStatus(){
synchronized(this.status){
return this.status.intValue();
}
}
public String GetHost(){
public final String GetHost(){
synchronized(this.notifier){
return this.host;
}
}
public void AddPointer(){
public final void AddPointer(){
synchronized(this.notifier){
this.connections++;
@ -114,7 +114,7 @@ public class Library implements Runnable{
this.notifier.notifyAll();
}
}
public void RemovePointer(){
public final void RemovePointer(){
synchronized(this.notifier){
this.connections--;
if(this.connections==0){
@ -127,7 +127,7 @@ public class Library implements Runnable{
}
public void Startup(Context context){
public final void Startup(Context context){
this.context = context;
// Startup thread when the application sends the context for the first time
@ -136,7 +136,7 @@ public class Library implements Runnable{
this.thread.start();
}
public void Restart(){
public final void Restart(){
synchronized(this.notifier){
this.running = false;
this.restart = true;
@ -152,7 +152,7 @@ public class Library implements Runnable{
}
}
public boolean Running(){
public final boolean Running(){
synchronized(this.notifier){
if(this.running==true){
return true;
@ -161,7 +161,7 @@ public class Library implements Runnable{
return false;
}
private class WriterThreadHelper implements Runnable{
private final class WriterThreadHelper implements Runnable{
private Thread thread;
private Library library;
public WriterThreadHelper(Library library){
@ -169,7 +169,7 @@ public class Library implements Runnable{
this.thread = new Thread(this);
}
public void Start(){
public final void Start(){
this.thread.start();
}
@ -183,7 +183,7 @@ public class Library implements Runnable{
protected Library(){
}
public void WaitForAuthroization(){
public final void WaitForAuthroization(){
// Log.v("Library::WaitForAuthroization","start");
synchronized (notifier) {
if(this.authorization.equals("")){
@ -340,7 +340,7 @@ public class Library implements Runnable{
}
}
public void WriteThread(WriterThreadHelper thread){
public final void WriteThread(WriterThreadHelper thread){
//Log.v("Library::WriteThread","Started");
this.SetStatus(STATUS_AUTHENTICATING);
@ -426,7 +426,7 @@ public class Library implements Runnable{
//Log.v("Library::WriteThread","Ended");
}
public void Exit(){
public final void Exit(){
synchronized(this.notifier){
this.exit = true;
this.running = false;
@ -451,14 +451,14 @@ public class Library implements Runnable{
}
}
public void AddQuery(IQuery query){
public final void AddQuery(IQuery query){
synchronized(this.sendQueryQueue){
this.sendQueryQueue.addLast(query);
this.sendQueryQueue.notifyAll();
}
}
public String GetTrackURL(int trackId){
public final String GetTrackURL(int trackId){
synchronized (notifier) {
if(this.status==STATUS_CONNECTED){
String trackURL = "http://"+this.host+":"+this.httpPort+"/track/?track_id="+trackId+"&auth_key="+this.authorization;

View File

@ -23,7 +23,7 @@ public class ListQuery extends IQuery {
public void SendQuery(WriterNode node)
throws Exception
{
WriterNode queryNode = this.SendQueryNode(node);
final WriterNode queryNode = this.SendQueryNode(node);
// List selections
WriterNode selectionsNode = queryNode.ChildNode("selections");
@ -60,8 +60,11 @@ public class ListQuery extends IQuery {
ReaderNode mdNode = null;
while( (mdNode=childNode.ChildNode("md"))!=null ){
mdNode.End();
this.resultsInts.add(Integer.parseInt(mdNode.attributes.get("id")));
this.resultsStrings.add(mdNode.content);
int resultId = Integer.parseInt(mdNode.attributes.get("id"));
if(resultId!=0){
this.resultsInts.add(resultId);
this.resultsStrings.add(mdNode.content);
}
}
}
}else if(childNode.name.equals("tracklist")){
@ -85,7 +88,7 @@ public class ListQuery extends IQuery {
}
}
public void SelectData(String category,int selection){
public final void SelectData(String category,int selection){
this.selectionStrings.add(category);
this.selectionInts.add(selection);
}

View File

@ -5,9 +5,9 @@ import doep.xml.WriterNode;
public class MetadataQuery extends IQuery {
public java.util.ArrayList<Integer> requestedTracks = new java.util.ArrayList<Integer>();
public java.util.ArrayList<String> requestedMetakeys = new java.util.ArrayList<String>();
public java.util.ArrayList<Track> resultTracks = new java.util.ArrayList<Track>();
public final java.util.ArrayList<Integer> requestedTracks = new java.util.ArrayList<Integer>();
public final java.util.ArrayList<String> requestedMetakeys = new java.util.ArrayList<String>();
public final java.util.ArrayList<Track> resultTracks = new java.util.ArrayList<Track>();
public MetadataQuery() {
super();

View File

@ -18,7 +18,7 @@ public class PaceDetector implements Runnable, SensorEventListener, OnQueryResul
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 int WAVE_MIN_CALC = 10;
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
@ -53,80 +53,88 @@ public class PaceDetector implements Runnable, SensorEventListener, OnQueryResul
}
if(this.lastDiff>=0 && diff<0){
// this is a top on the curve
this.beatTimes.add(android.os.SystemClock.elapsedRealtime());
this.amplitude.add(this.currentMax-this.currentMin);
// Reset the amplitude
this.currentMin = value;
this.currentMax = value;
// only keep the last 10 waves
while(this.beatTimes.size()>WAVE_MEMORY){
this.beatTimes.remove(0);
this.amplitude.remove(0);
}
// Lets calculate BPM
long bpmSum = 0;
//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;
// Amplitude must be at leased 5
if(this.currentMax-this.currentMin<7){
this.currentMin = value;
this.currentMax = value;
// Log.v("APM","-- "+(this.currentMax-this.currentMin));
}else{
// Log.v("APM","B "+(this.currentMax-this.currentMin));
// this is a top on the curve
this.beatTimes.add(android.os.SystemClock.elapsedRealtime());
this.amplitude.add(this.currentMax-this.currentMin);
// Reset the amplitude
this.currentMin = value;
this.currentMax = value;
// only keep the last 10 waves
while(this.beatTimes.size()>WAVE_MEMORY){
this.beatTimes.remove(0);
this.amplitude.remove(0);
}
// Lets calculate BPM
long bpmSum = 0;
//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.get(0);
Long last = bpms.get(bpms.size()-1);
bpmDiff = last-first;
int bpmSize = bpms.size();
// Log.v("MC2::DIFF","diff "+bpmSize+" "+first+"-"+last+" diff="+bpmDiff);
Collections.sort(bpms);
//Log.v("MC2::BEAT","B "+(bpms.size()));
if(bpmDiff<WAVE_MIN_BPM_DIFF){
qualified = true;
}else{
// Remove the element that is most far away from the average
long avg = bpmSum/bpmSize;
if(avg-first>last-avg){
// Remove first
bpmSum -= first;
bpms.remove(0);
// 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.get(0);
Long last = bpms.get(bpms.size()-1);
bpmDiff = last-first;
int bpmSize = bpms.size();
// Log.v("MC2::DIFF","diff "+bpmSize+" "+first+"-"+last+" diff="+bpmDiff);
if(bpmDiff<WAVE_MIN_BPM_DIFF){
qualified = true;
}else{
// Remove last
bpmSum -= last;
bpms.remove(bpms.size()-1);
// Remove the element that is most far away from the average
long avg = bpmSum/bpmSize;
if(avg-first>last-avg){
// Remove first
bpmSum -= first;
bpms.remove(0);
}else{
// Remove last
bpmSum -= last;
bpms.remove(bpms.size()-1);
}
}
}
}
if(qualified){
// Get avg amplitude
float amplitude = this.amplitude.get(0);
for(int i=1;i<this.amplitude.size();i++){
amplitude+=this.amplitude.get(i);
if(qualified){
// Get avg amplitude
float amplitude = this.amplitude.get(0);
for(int i=1;i<this.amplitude.size();i++){
amplitude+=this.amplitude.get(i);
}
amplitude /= this.amplitude.size();
this.currentBPM = ((float)60000*bpms.size())/((float)bpmSum);
this.currentAccuracy = (100-bpmDiff)+bpms.size()*13+amplitude*5;
PaceDetector.this.ChangeBPM(this.currentBPM,this.currentAccuracy);
}
amplitude /= this.amplitude.size();
this.currentBPM = ((float)60000*bpms.size())/((float)bpmSum);
this.currentAccuracy = (100-bpmDiff)+bpms.size()*13+amplitude*5;
PaceDetector.this.ChangeBPM(this.currentBPM,this.currentAccuracy);
}
}
this.lastDiff = diff;
@ -158,10 +166,13 @@ public class PaceDetector implements Runnable, SensorEventListener, OnQueryResul
long currentTime = android.os.SystemClock.elapsedRealtime();
if(currentTime>this.currentBPMstart+MIN_PLAYTIME){
//Log.v("BPM","3 "+bpm);
// We have played more than minimum time
if(bpm>this.currentBPM+BPM_THRESHOLD || bpm<this.currentBPM-BPM_THRESHOLD){
Log.v("BPM","4 "+bpm);
// BPM has changed enough to switch track
this.currentBPMstart = currentTime;
this.currentBPM = bpm;
this.currentAccuracy = accuracy;
@ -169,6 +180,8 @@ public class PaceDetector implements Runnable, SensorEventListener, OnQueryResul
BPMQuery query = new BPMQuery();
query.queryForBPM = this.currentBPM;
query.SetResultListener(this);
Library.GetInstance().AddQuery(query);
}
}
@ -197,6 +210,7 @@ public class PaceDetector implements Runnable, SensorEventListener, OnQueryResul
public void OnQueryResults(IQuery query) {
BPMQuery bpmQuery = (BPMQuery)query;
Log.v("mC2::PaceDetector","Change tracks "+bpmQuery.trackList.size());
if(!bpmQuery.trackList.isEmpty()){
Intent intent = new Intent(this.context, org.musikcube.Service.class);
intent.putExtra("org.musikcube.Service.tracklist", bpmQuery.trackList);

View File

@ -1,18 +1,21 @@
package org.musikcube.core;
import java.util.ArrayList;
import java.util.Random;
import org.musikcube.core.IQuery.OnQueryResultListener;
import org.musikcube.core.TrackPlayer.OnTrackPrepareListener;
import android.content.Intent;
public class Player implements TrackPlayer.OnTrackStatusListener, OnQueryResultListener{
public final class Player implements TrackPlayer.OnTrackStatusListener, OnQueryResultListener, OnTrackPrepareListener{
private ArrayList<Integer> nowPlaying = new ArrayList<Integer>();
private int position = 0;
private boolean repeat = false;
private boolean shuffle = false;
private int nextShufflePosition = -1;
private Library library;
@ -27,6 +30,8 @@ public class Player implements TrackPlayer.OnTrackStatusListener, OnQueryResultL
public android.app.Service service;
private boolean bpmMode = false;
public void run() {
}
@ -44,6 +49,9 @@ public class Player implements TrackPlayer.OnTrackStatusListener, OnQueryResultL
synchronized(this.lock){
this.nowPlaying = playlist;
this.position = position;
if(this.listListener!=null){
this.listListener.OnTrackListUpdate();
}
}
this.Play();
@ -64,12 +72,13 @@ public class Player implements TrackPlayer.OnTrackStatusListener, OnQueryResultL
this.nowPlaying = playlist;
this.position = position;
if(this.nextPlayer!=null){
this.nextPlayer.SetPrepareListener(null);
this.nextPlayer.SetListener(null);
this.nextPlayer.Stop();
}
this.playWhenPrepared = true;
this.nextPlayer = this.PrepareTrack(this.position);
this.nextPlayer.SetListener(this);
this.nextPlayer.SetPrepareListener(this);
if(this.listListener!=null){
this.listListener.OnTrackListUpdate();
@ -182,7 +191,18 @@ public class Player implements TrackPlayer.OnTrackStatusListener, OnQueryResultL
public void Next(){
synchronized(this.lock){
this.currentTrack = new Track();
this.position++;
if(this.shuffle){
if(this.nextShufflePosition==-1){
Random rand = new Random();
this.position = rand.nextInt(this.nowPlaying.size());
}else{
this.position = this.nextShufflePosition;
this.nextShufflePosition = -1;
}
}else{
this.position++;
}
if(this.position>=this.nowPlaying.size()){
if(this.repeat){
@ -205,8 +225,20 @@ public class Player implements TrackPlayer.OnTrackStatusListener, OnQueryResultL
public void Prev(){
synchronized(this.lock){
this.currentTrack = new Track();
this.position--;
this.currentTrack = new Track();
if(this.shuffle){
if(this.nextShufflePosition==-1){
Random rand = new Random();
this.position = rand.nextInt(this.nowPlaying.size());
}else{
this.position = this.nextShufflePosition;
this.nextShufflePosition = -1;
}
}else{
this.position--;
}
if(this.position<0){
this.position = 0;
}
@ -322,7 +354,17 @@ public class Player implements TrackPlayer.OnTrackStatusListener, OnQueryResultL
public void OnTrackAlmostDone(TrackPlayer trackPlayer) {
synchronized(this.lock){
if(this.nextPlayer==null){
this.nextPlayer = this.PrepareTrack(this.position+1);
if(this.shuffle){
if(this.nextShufflePosition==-1){
Random rand = new Random();
this.nextShufflePosition = rand.nextInt(this.nowPlaying.size());
this.nextPlayer = this.PrepareTrack(this.nextShufflePosition);
}else{
this.nextPlayer = this.PrepareTrack(this.nextShufflePosition);
}
}else{
this.nextPlayer = this.PrepareTrack(this.position+1);
}
}
}
}
@ -390,4 +432,25 @@ public class Player implements TrackPlayer.OnTrackStatusListener, OnQueryResultL
}
}
public void SetBPMMode(boolean bpmMode){
synchronized(this.lock){
this.bpmMode = bpmMode;
}
}
public boolean GetBPMMode(){
synchronized(this.lock){
return this.bpmMode;
}
}
public void RemoveFromList(int position){
synchronized(this.lock){
this.nowPlaying.remove(position);
if(this.listListener!=null){
this.listListener.OnTrackListUpdate();
}
}
}
}

View File

@ -31,12 +31,12 @@ public class TrackPlayer implements Runnable, MediaPlayer.OnCompletionListener,
this.mediaPlayer.setOnBufferingUpdateListener(this);
String url = Library.GetInstance().GetTrackURL(this.trackId);
while(url==null && (this.status==STATUS_PREPARED || this.status==STATUS_PLAYING)){
Log.v("mC2::TrackPlayer","Retrying "+this.trackId);
synchronized(this.lock){
synchronized(this.lock){
while(url==null && (this.status==STATUS_PREPARED || this.status==STATUS_PLAYING)){
Log.v("mC2::TrackPlayer","Retrying "+this.trackId);
this.lock.wait(250);
url = Library.GetInstance().GetTrackURL(this.trackId);
}
url = Library.GetInstance().GetTrackURL(this.trackId);
}
if(url==null){
@ -49,8 +49,8 @@ public class TrackPlayer implements Runnable, MediaPlayer.OnCompletionListener,
}
synchronized(this.lock){
if(this.listener!=null){
this.listener.OnTrackPrepared(this);
if(this.listenerPrepare!=null){
this.listenerPrepare.OnTrackPrepared(this);
}
while(this.status==STATUS_PREPARED)
@ -157,18 +157,25 @@ 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 interface OnTrackPrepareListener{
public void OnTrackPrepared(TrackPlayer trackPlayer);
}
private OnTrackStatusListener listener = null;
public void SetListener(OnTrackStatusListener listener){
synchronized(this.lock){
this.listener = listener;
}
}
private OnTrackPrepareListener listenerPrepare = null;
public void SetPrepareListener(OnTrackPrepareListener listener){
synchronized(this.lock){
this.listenerPrepare = listener;
}
}
public void onCompletion(MediaPlayer mp) {
synchronized(this.lock){

View File

@ -70,12 +70,13 @@ public class main extends Activity implements OnLibraryStatusListener {
private OnClickListener onBPMClick = new OnClickListener() {
public void onClick(View v){
Intent intent = new Intent(main.this, org.musikcube.Service.class);
intent.putExtra("org.musikcube.Service.action", "bpmstart");
startService(intent);
Intent intent2 = new Intent(main.this, PlayerControl.class);
/* Log.v("mC2::main","onBPMClick 1");
Intent intent2 = new Intent(main.this, PlayerBPMControl.class);
startActivity(intent2);
Log.v("mC2::main","onBPMClick 2");*/
Intent intent = new Intent(main.this, CategorySelect.class);
intent.putExtra("org.musikcube.CategorySelect.listCategory", "genre");
startActivity(intent);
}
};
@ -86,23 +87,11 @@ public class main extends Activity implements OnLibraryStatusListener {
}
public boolean onOptionsItemSelected(MenuItem item) {
//Log.i("MC2.onContextItemSelected","item "+item.getItemId()+" "+R.id.context_settings);
switch (item.getItemId()) {
case R.id.context_settings:
startActivity(new Intent(this, org.musikcube.Preferences.class));
return true;
case R.id.context_browse:
startActivity(new Intent(this, org.musikcube.main.class));
return true;
case R.id.context_controls:
startActivity(new Intent(this, org.musikcube.PlayerControl.class));
return true;
case R.id.context_nowplaying:
startActivity(new Intent(this, org.musikcube.NowPlayingList.class));
return true;
default:
return super.onContextItemSelected(item);
}
if(Helper.DefaultOptionsItemSelected(item,this)){
return true;
}else{
return super.onContextItemSelected(item);
}
}
@Override
@ -146,7 +135,7 @@ public class main extends Activity implements OnLibraryStatusListener {
genreButton.setEnabled(true);
artistsButton.setEnabled(true);
yearButton.setEnabled(true);
// bpmButton.setEnabled(true);
bpmButton.setEnabled(false);
}else{
genreButton.setEnabled(false);
artistsButton.setEnabled(false);