Commit ca3bc651 authored by Sébastien Toque's avatar Sébastien Toque
Browse files

UI: equalizer

parent e16fa987
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<ToggleButton
android:id="@+id/equalizer_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Spinner
android:id="@+id/equalizer_presets"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<SeekBar
android:id="@+id/equalizer_preamp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxHeight="4dip"
android:minHeight="4dip"
android:progressDrawable="@drawable/po_seekbar"
android:thumb="@drawable/ic_seekbar_thumb" />
<HorizontalScrollView
android:id="@+id/equalizer_scroll"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1" >
<LinearLayout
android:id="@+id/equalizer_bands"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal" />
</HorizontalScrollView>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="64dp"
android:layout_height="match_parent"
android:orientation="vertical" >
<org.videolan.vlc.widget.VerticalSeekBar
android:id="@+id/equalizer_seek"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
android:maxHeight="4dip"
android:minHeight="4dip"
android:progressDrawable="@drawable/po_seekbar"
android:thumb="@drawable/ic_seekbar_thumb" />
<TextView
android:id="@+id/equalizer_band"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
android:text="16 kHz"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/equalizer_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="10dp"
android:text="0.0 Db"
tools:ignore="HardcodedText" />
</LinearLayout>
\ No newline at end of file
......@@ -584,11 +584,11 @@ public class LibVLC {
private native void detachEventHandler();
private native float[] getBands();
public native float[] getBands();
private native String[] getPresets();
public native String[] getPresets();
private native float[] getPreset(int index);
public native float[] getPreset(int index);
private native int setNativeEqualizer(float[] bands);
}
......@@ -35,11 +35,14 @@ import java.util.HashSet;
import java.util.Locale;
import java.util.StringTokenizer;
import org.json.JSONArray;
import org.json.JSONException;
import org.videolan.libvlc.LibVLC;
import org.videolan.libvlc.LibVlcException;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Environment;
......@@ -79,6 +82,33 @@ public class Util {
return instance;
}
public static float[] getFloatArray(SharedPreferences pref, String key) {
float[] array = null;
String s = pref.getString(key, null);
if (s != null) {
try {
JSONArray json = new JSONArray(s);
array = new float[json.length()];
for (int i = 0; i < array.length; i++)
array[i] = (float) json.getDouble(i);
} catch (JSONException e) {
e.printStackTrace();
}
}
return array;
}
public static void putFloatArray(Editor editor, String key, float[] array) {
try {
JSONArray json = new JSONArray();
for (float f : array)
json.put(f);
editor.putString("equalizer_values", json.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
public static void updateLibVlcSettings(SharedPreferences pref) {
LibVLC instance = LibVLC.getExistingInstance();
if (instance == null)
......@@ -90,6 +120,9 @@ public class Util {
instance.setChroma(pref.getString("chroma_format", ""));
instance.setVerboseMode(pref.getBoolean("enable_verbose_mode", true));
if (pref.getBoolean("equalizer_enabled", false))
instance.setEqualizer(getFloatArray(pref, "equalizer_values"));
int aout;
try {
aout = Integer.parseInt(pref.getString("aout", "-1"));
......
......@@ -28,6 +28,7 @@ import org.videolan.vlc.R;
import org.videolan.vlc.Util;
import org.videolan.vlc.VLCApplication;
import org.videolan.vlc.gui.audio.AudioBrowserFragment;
import org.videolan.vlc.gui.audio.EqualizerFragment;
import org.videolan.vlc.gui.video.VideoGridFragment;
import android.graphics.drawable.Drawable;
......@@ -70,6 +71,7 @@ public class SidebarAdapter extends BaseAdapter {
new SidebarEntry( "audio", R.string.audio, R.drawable.header_icon_audio ),
new SidebarEntry( "directories", R.string.directories, R.drawable.ic_folder ),
new SidebarEntry( "history", R.string.history, android.R.drawable.ic_menu_recent_history ),
new SidebarEntry( "equalizer", "Equalizer", R.drawable.ic_bookmarks ),
//new SidebarEntry( "bookmarks", R.string.bookmarks, R.drawable.ic_bookmarks ),
//new SidebarEntry( "playlists", R.string.playlists, R.drawable.icon ),
};
......@@ -129,6 +131,8 @@ public class SidebarAdapter extends BaseAdapter {
f = new DirectoryViewFragment();
} else if(id.equals("history")) {
f = new HistoryFragment();
} else if(id.equals("equalizer")) {
f = new EqualizerFragment();
} else { /* TODO */
f = new AboutLicenceFragment();
}
......
/*****************************************************************************
* EqualizerFragment.java
*****************************************************************************
* Copyright © 2013 VLC authors and VideoLAN
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
package org.videolan.vlc.gui.audio;
import org.videolan.libvlc.LibVLC;
import org.videolan.libvlc.LibVlcException;
import org.videolan.vlc.R;
import org.videolan.vlc.Util;
import org.videolan.vlc.VLCApplication;
import org.videolan.vlc.interfaces.OnEqualizerBarChangeListener;
import org.videolan.vlc.widget.EqualizerBar;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.Spinner;
import android.widget.ToggleButton;
public class EqualizerFragment extends Fragment {
public final static String TAG = "VLC/EqualizerFragment";
private ToggleButton button;
private Spinner equalizer_presets;
private SeekBar preamp;
private LinearLayout bands_layout;
LibVLC libVlc = null;
float[] equalizer = null;
/* All subclasses of Fragment must include a public empty constructor. */
public EqualizerFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
super.onCreateView(inflater, container, savedInstanceState);
View v = inflater.inflate(R.layout.equalizer, container, false);
button = (ToggleButton) v.findViewById(R.id.equalizer_button);
equalizer_presets = (Spinner) v.findViewById(R.id.equalizer_presets);
preamp = (SeekBar) v.findViewById(R.id.equalizer_preamp);
bands_layout = (LinearLayout) v.findViewById(R.id.equalizer_bands);
// only allow scroll in the lower 50dp part of the layout (where frequencies are displayed)
HorizontalScrollView scroll = (HorizontalScrollView) v.findViewById(R.id.equalizer_scroll);
final float density = this.getResources().getDisplayMetrics().density;
scroll.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int delta = v.getHeight() - (int) event.getY();
return delta > 50 * density;
}
});
return v;
}
@Override
public void onResume() {
super.onResume();
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(VLCApplication.getAppContext());
float[] bands = null;
String[] presets = null;
try {
libVlc = Util.getLibVlcInstance();
bands = libVlc.getBands();
presets = libVlc.getPresets();
if (equalizer == null)
equalizer = Util.getFloatArray(preferences, "equalizer_values");
if (equalizer == null)
equalizer = new float[bands.length + 1];
} catch (LibVlcException e) {
e.printStackTrace();
}
// on/off
button.setChecked(libVlc.getEqualizer() != null);
button.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (libVlc == null)
return;
libVlc.setEqualizer(isChecked ? equalizer : null);
}
});
// presets
equalizer_presets.setAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_spinner_dropdown_item, presets));
equalizer_presets.setSelection(preferences.getInt("equalizer_preset", 0), false);
// set listener asynchronously to prevent the listener from being fired during spinner init
equalizer_presets.post(new Runnable() {
@Override
public void run() {
equalizer_presets.setOnItemSelectedListener(mPresetListener);
}
});
// preamp
preamp.setMax(40);
preamp.setProgress((int) equalizer[0] + 20);
preamp.setOnSeekBarChangeListener(mPreampListener);
// bands
for (int i = 0; i < bands.length; i++) {
float band = bands[i];
EqualizerBar bar = new EqualizerBar(getActivity(), band);
bar.setValue(equalizer[i + 1]);
bar.setListener(new BandListener(i + 1));
bands_layout.addView(bar);
LayoutParams params = bar.getLayoutParams();
params.height = LayoutParams.MATCH_PARENT;
bar.setLayoutParams(params);
}
}
@Override
public void onPause() {
super.onPause();
button.setOnCheckedChangeListener(null);
equalizer_presets.setOnItemSelectedListener(null);
preamp.setOnSeekBarChangeListener(null);
bands_layout.removeAllViews();
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(VLCApplication.getAppContext());
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("equalizer_enabled", button.isChecked());
Util.putFloatArray(editor, "equalizer_values", equalizer);
editor.putInt("equalizer_preset", equalizer_presets.getSelectedItemPosition());
editor.commit();
}
private final OnItemSelectedListener mPresetListener = new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
if (libVlc == null)
return;
float[] preset = libVlc.getPreset(pos);
if (preset == null)
return;
equalizer = preset;
preamp.setProgress((int) equalizer[0] + 20);
for (int i = 0; i < equalizer.length - 1; ++i) {
EqualizerBar bar = (EqualizerBar) bands_layout.getChildAt(i);
bar.setValue(equalizer[i + 1]);
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
};
private final OnSeekBarChangeListener mPreampListener = new OnSeekBarChangeListener() {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (!fromUser)
return;
equalizer[0] = progress - 20;
if (libVlc != null && button.isChecked())
libVlc.setEqualizer(equalizer);
}
};
private class BandListener implements OnEqualizerBarChangeListener {
private int index;
public BandListener(int index) {
this.index = index;
}
@Override
public void onProgressChanged(float value) {
equalizer[index] = value;
if (libVlc != null && button.isChecked())
libVlc.setEqualizer(equalizer);
}
};
}
\ No newline at end of file
/*****************************************************************************
* OnEqualizerBarChangeListener.java
*****************************************************************************
* Copyright © 2013 VLC authors and VideoLAN
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
package org.videolan.vlc.interfaces;
public interface OnEqualizerBarChangeListener {
public abstract void onProgressChanged(float value);
}
/*****************************************************************************
* EqualizerBar.java
*****************************************************************************
* Copyright © 2013 VLC authors and VideoLAN
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
package org.videolan.vlc.widget;
import org.videolan.vlc.R;
import org.videolan.vlc.interfaces.OnEqualizerBarChangeListener;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
public class EqualizerBar extends LinearLayout {
private static final int PRECISION = 10;
private static final int RANGE = 20 * PRECISION;
private VerticalSeekBar mSeek;
private TextView mBand;
private TextView mValue;
private OnEqualizerBarChangeListener listener;
public EqualizerBar(Context context, float band) {
super(context);
init(context, band);
}
public EqualizerBar(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, 0);
}
private void init(Context context, float band) {
LayoutInflater.from(context).inflate(R.layout.equalizer_bar, this, true);
mSeek = (VerticalSeekBar) findViewById(R.id.equalizer_seek);
mSeek.setMax(2 * RANGE);
mSeek.setProgress(RANGE);
mSeek.setOnSeekBarChangeListener(mSeekListener);
mBand = (TextView) findViewById(R.id.equalizer_band);
mBand.setText(band < 1000
? (int) band + " Hz"
: (int) (band / 1000) + " kHz");
mValue = (TextView) findViewById(R.id.equalizer_value);
}
private final OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
float value = (progress - RANGE) / (float) PRECISION;
mValue.setText(value + " Db");
if (listener != null)
listener.onProgressChanged(value);
}
};
public void setValue(float value) {
mSeek.setProgress((int) (value * PRECISION + RANGE));
}
public void setListener(OnEqualizerBarChangeListener listener) {
this.listener = listener;
}
}
/*****************************************************************************
* VerticalSeekBar.java
*****************************************************************************
* Copyright © 2013 VLC authors and VideoLAN
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
package org.videolan.vlc.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.SeekBar;
public class VerticalSeekBar extends SeekBar {
public VerticalSeekBar(Context context) {
super(context);
}
public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public VerticalSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(h, w, oldh, oldw);
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}
protected void onDraw(Canvas c) {
c.rotate(-90);