Added ability to set Playback speed and pitch

This commit is contained in:
Prathamesh More 2022-01-05 14:26:36 +05:30
parent 3a6645ab35
commit 943de60f23
12 changed files with 229 additions and 18 deletions

View file

@ -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"

View file

@ -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()
}
}
}

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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();
}
}
}
}

View file

@ -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);

View file

@ -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