Added ability to set Playback speed and pitch
This commit is contained in:
parent
3a6645ab35
commit
943de60f23
12 changed files with 229 additions and 18 deletions
|
@ -155,3 +155,5 @@ const val WHITELIST_MUSIC = "whitelist_music"
|
|||
const val MATERIAL_YOU = "material_you"
|
||||
const val SNOWFALL = "snowfall"
|
||||
const val LYRICS_TYPE = "lyrics_type"
|
||||
const val PLAYBACK_SPEED = "playback_speed"
|
||||
const val PLAYBACK_PITCH = "playback_pitch"
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
package code.name.monkey.retromusic.dialogs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.databinding.DialogPlaybackSpeedBinding
|
||||
import code.name.monkey.retromusic.extensions.accent
|
||||
import code.name.monkey.retromusic.extensions.colorButtons
|
||||
import code.name.monkey.retromusic.extensions.materialDialog
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import com.google.android.material.slider.Slider
|
||||
|
||||
class PlaybackSpeedDialog : DialogFragment() {
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val binding = DialogPlaybackSpeedBinding.inflate(layoutInflater)
|
||||
binding.playbackSpeedSlider.accent()
|
||||
binding.playbackPitchSlider.accent()
|
||||
binding.playbackSpeedSlider.addOnChangeListener(Slider.OnChangeListener { _, value, _ ->
|
||||
binding.speedValue.text = "$value"
|
||||
})
|
||||
binding.playbackPitchSlider.addOnChangeListener(Slider.OnChangeListener { _, value, _ ->
|
||||
binding.pitchValue.text = "$value"
|
||||
})
|
||||
binding.playbackSpeedSlider.value = PreferenceUtil.playbackSpeed
|
||||
binding.playbackPitchSlider.value = PreferenceUtil.playbackPitch
|
||||
|
||||
return materialDialog(R.string.playback_settings)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(R.string.save) { _, _ ->
|
||||
updatePlaybackAndPitch(
|
||||
binding.playbackSpeedSlider.value,
|
||||
binding.playbackPitchSlider.value
|
||||
)
|
||||
}
|
||||
.setView(binding.root)
|
||||
.create()
|
||||
.colorButtons()
|
||||
}
|
||||
|
||||
private fun updatePlaybackAndPitch(speed: Float, pitch: Float) {
|
||||
PreferenceUtil.playbackSpeed = speed
|
||||
PreferenceUtil.playbackPitch = pitch
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newInstance(): PlaybackSpeedDialog {
|
||||
return PlaybackSpeedDialog()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,6 +43,7 @@ import com.google.android.material.button.MaterialButton
|
|||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
import com.google.android.material.slider.Slider
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
|
||||
fun Int.ripAlpha(): Int {
|
||||
|
@ -112,6 +113,12 @@ fun SeekBar.addAccentColor() {
|
|||
thumbTintList = colorState
|
||||
}
|
||||
|
||||
fun Slider.accent() {
|
||||
if (materialYou) return
|
||||
trackActiveTintList = context.accentColor().colorStateList
|
||||
trackInactiveTintList = context.accentColorVariant().colorStateList
|
||||
}
|
||||
|
||||
fun Button.accentTextColor() {
|
||||
if (materialYou) return
|
||||
setTextColor(ThemeStore.accentColor(App.getContext()))
|
||||
|
@ -269,6 +276,15 @@ fun Context.darkAccentColorVariant(): Int {
|
|||
)
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
fun Context.accentColorVariant(): Int {
|
||||
return if (surfaceColor().isColorLight) {
|
||||
accentColor().darkerColor
|
||||
} else {
|
||||
accentColor().lighterColor
|
||||
}
|
||||
}
|
||||
|
||||
inline val @receiver:ColorInt Int.isColorLight
|
||||
get() = ColorUtil.isColorLight(this)
|
||||
|
||||
|
@ -276,4 +292,7 @@ inline val @receiver:ColorInt Int.lighterColor
|
|||
get() = ColorUtil.lightenColor(this)
|
||||
|
||||
inline val @receiver:ColorInt Int.darkerColor
|
||||
get() = ColorUtil.darkenColor(this)
|
||||
get() = ColorUtil.darkenColor(this)
|
||||
|
||||
inline val Int.colorStateList : ColorStateList
|
||||
get() = ColorStateList.valueOf(this)
|
|
@ -42,6 +42,7 @@ import androidx.viewpager.widget.ViewPager
|
|||
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
|
||||
import code.name.monkey.retromusic.EXTRA_ARTIST_ID
|
||||
import code.name.monkey.retromusic.PLAYBACK_SPEED
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.activities.MainActivity
|
||||
import code.name.monkey.retromusic.activities.tageditor.AbsTagEditorActivity
|
||||
|
@ -79,6 +80,10 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
|
|||
): Boolean {
|
||||
val song = MusicPlayerRemote.currentSong
|
||||
when (item.itemId) {
|
||||
R.id.action_playback_speed -> {
|
||||
PlaybackSpeedDialog.newInstance().show(childFragmentManager, "PLAYBACK_SETTINGS")
|
||||
return true
|
||||
}
|
||||
R.id.action_toggle_lyrics -> {
|
||||
PreferenceUtil.showLyrics = !item.isChecked
|
||||
item.isChecked = !item.isChecked
|
||||
|
|
|
@ -1,17 +1,3 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software 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.
|
||||
*/
|
||||
|
||||
package code.name.monkey.retromusic.preferences
|
||||
|
||||
import android.app.Dialog
|
||||
|
|
|
@ -16,8 +16,10 @@ package code.name.monkey.retromusic.service;
|
|||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaPlayer;
|
||||
import android.media.PlaybackParams;
|
||||
import android.media.audiofx.AudioEffect;
|
||||
import android.net.Uri;
|
||||
import android.os.PowerManager;
|
||||
|
@ -26,7 +28,10 @@ import android.widget.Toast;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import code.name.monkey.appthemehelper.util.VersionUtils;
|
||||
import code.name.monkey.retromusic.ConstantsKt;
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.service.playback.Playback;
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
||||
|
@ -35,7 +40,7 @@ import code.name.monkey.retromusic.util.PreferenceUtil;
|
|||
* @author Andrew Neal, Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
public class MultiPlayer
|
||||
implements Playback, MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener {
|
||||
implements Playback, MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener, SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
public static final String TAG = MultiPlayer.class.getSimpleName();
|
||||
|
||||
private MediaPlayer mCurrentMediaPlayer = new MediaPlayer();
|
||||
|
@ -53,6 +58,7 @@ public class MultiPlayer
|
|||
MultiPlayer(final Context context) {
|
||||
this.context = context;
|
||||
mCurrentMediaPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK);
|
||||
PreferenceManager.getDefaultSharedPreferences(context).registerOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -86,6 +92,7 @@ public class MultiPlayer
|
|||
} else {
|
||||
player.setDataSource(path);
|
||||
}
|
||||
setPlaybackSpeedPitch(player);
|
||||
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
|
||||
player.prepare();
|
||||
} catch (Exception e) {
|
||||
|
@ -199,6 +206,7 @@ public class MultiPlayer
|
|||
if (mNextMediaPlayer != null) {
|
||||
mNextMediaPlayer.release();
|
||||
}
|
||||
PreferenceManager.getDefaultSharedPreferences(context).unregisterOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -346,4 +354,23 @@ public class MultiPlayer
|
|||
@Override
|
||||
public void setCrossFadeDuration(int duration) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
if (key.equals(ConstantsKt.PLAYBACK_SPEED) || key.equals(ConstantsKt.PLAYBACK_PITCH)) {
|
||||
setPlaybackSpeedPitch(mCurrentMediaPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPlaybackSpeedPitch(MediaPlayer mp) {
|
||||
if (VersionUtils.INSTANCE.hasMarshmallow()) {
|
||||
boolean wasPlaying = mp.isPlaying();
|
||||
mp.setPlaybackParams(new PlaybackParams()
|
||||
.setSpeed(PreferenceUtil.INSTANCE.getPlaybackSpeed())
|
||||
.setPitch(PreferenceUtil.INSTANCE.getPlaybackPitch()));
|
||||
if (!wasPlaying) {
|
||||
if (mp.isPlaying()) mp.pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@ import static code.name.monkey.retromusic.ConstantsKt.BLURRED_ALBUM_ART;
|
|||
import static code.name.monkey.retromusic.ConstantsKt.CLASSIC_NOTIFICATION;
|
||||
import static code.name.monkey.retromusic.ConstantsKt.COLORED_NOTIFICATION;
|
||||
import static code.name.monkey.retromusic.ConstantsKt.CROSS_FADE_DURATION;
|
||||
import static code.name.monkey.retromusic.ConstantsKt.PLAYBACK_SPEED;
|
||||
import static code.name.monkey.retromusic.ConstantsKt.TOGGLE_HEADSET;
|
||||
import static code.name.monkey.retromusic.service.AudioFader.startFadeAnimator;
|
||||
|
||||
|
@ -940,6 +941,9 @@ public class MusicService extends MediaBrowserServiceCompat
|
|||
playingNotification.setPlaying(isPlaying());
|
||||
playingNotification.updateMetadata(getCurrentSong(), this::startForegroundOrNotify);
|
||||
break;
|
||||
case PLAYBACK_SPEED:
|
||||
updateMediaSessionPlaybackState();
|
||||
break;
|
||||
case TOGGLE_HEADSET:
|
||||
registerHeadsetEvents();
|
||||
break;
|
||||
|
@ -1334,7 +1338,7 @@ public class MusicService extends MediaBrowserServiceCompat
|
|||
.setState(
|
||||
isPlaying() ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED,
|
||||
getSongProgressMillis(),
|
||||
1);
|
||||
PreferenceUtil.INSTANCE.getPlaybackSpeed());
|
||||
|
||||
setCustomAction(stateBuilder);
|
||||
|
||||
|
|
|
@ -674,6 +674,16 @@ object PreferenceUtil {
|
|||
} else {
|
||||
LyricsType.OVER_LYRICS
|
||||
}
|
||||
|
||||
var playbackSpeed
|
||||
get() = sharedPreferences
|
||||
.getFloat(PLAYBACK_SPEED, 1F)
|
||||
set(value) = sharedPreferences.edit { putFloat(PLAYBACK_SPEED, value) }
|
||||
|
||||
var playbackPitch
|
||||
get() = sharedPreferences
|
||||
.getFloat(PLAYBACK_PITCH, 1F)
|
||||
set(value) = sharedPreferences.edit { putFloat(PLAYBACK_PITCH, value) }
|
||||
}
|
||||
enum class LyricsType {
|
||||
REPLACE_LYRICS, OVER_LYRICS
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue