diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackFragment.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackFragment.kt
index 5ba6a114b..528b7848e 100644
--- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackFragment.kt
+++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackFragment.kt
@@ -81,7 +81,6 @@ class PlaybackFragment : Fragment() {
setOnMenuItemClickListener { item ->
if (item.itemId == R.id.action_queue) {
findNavController().navigate(MainFragmentDirections.actionShowQueue())
-
true
} else {
false
diff --git a/app/src/main/java/org/oxycblt/auxio/playback/state/LoopMode.kt b/app/src/main/java/org/oxycblt/auxio/playback/state/LoopMode.kt
index 2fbe7777c..dba0a3fa3 100644
--- a/app/src/main/java/org/oxycblt/auxio/playback/state/LoopMode.kt
+++ b/app/src/main/java/org/oxycblt/auxio/playback/state/LoopMode.kt
@@ -42,25 +42,25 @@ enum class LoopMode {
*/
fun toInt(): Int {
return when (this) {
- NONE -> CONST_NONE
- ALL -> CONST_ALL
- TRACK -> CONST_TRACK
+ NONE -> INT_NONE
+ ALL -> INT_ALL
+ TRACK -> INT_TRACK
}
}
companion object {
- private const val CONST_NONE = 0xA100
- private const val CONST_ALL = 0xA101
- private const val CONST_TRACK = 0xA102
+ private const val INT_NONE = 0xA100
+ private const val INT_ALL = 0xA101
+ private const val INT_TRACK = 0xA102
/**
* Convert an int [constant] into a LoopMode, or null if it isnt valid.
*/
fun fromInt(constant: Int): LoopMode? {
return when (constant) {
- CONST_NONE -> NONE
- CONST_ALL -> ALL
- CONST_TRACK -> TRACK
+ INT_NONE -> NONE
+ INT_ALL -> ALL
+ INT_TRACK -> TRACK
else -> null
}
diff --git a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackMode.kt b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackMode.kt
index 512fe598e..48924d241 100644
--- a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackMode.kt
+++ b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackMode.kt
@@ -38,30 +38,30 @@ enum class PlaybackMode {
*/
fun toInt(): Int {
return when (this) {
- ALL_SONGS -> CONST_ALL_SONGS
- IN_ALBUM -> CONST_IN_ALBUM
- IN_ARTIST -> CONST_IN_ARTIST
- IN_GENRE -> CONST_IN_GENRE
+ ALL_SONGS -> INT_ALL_SONGS
+ IN_ALBUM -> INT_IN_ALBUM
+ IN_ARTIST -> INT_IN_ARTIST
+ IN_GENRE -> INT_IN_GENRE
}
}
companion object {
// Kept in reverse order because of backwards compat, do not re-order these
- private const val CONST_ALL_SONGS = 0xA106
- private const val CONST_IN_ALBUM = 0xA105
- private const val CONST_IN_ARTIST = 0xA104
- private const val CONST_IN_GENRE = 0xA103
+ private const val INT_ALL_SONGS = 0xA106
+ private const val INT_IN_ALBUM = 0xA105
+ private const val INT_IN_ARTIST = 0xA104
+ private const val INT_IN_GENRE = 0xA103
/**
* Get a [PlaybackMode] for an int [constant]
- * @return The mode, null if there isnt one for this.
+ * @return The mode, null if there isn't one for this.
*/
fun fromInt(constant: Int): PlaybackMode? {
return when (constant) {
- CONST_ALL_SONGS -> ALL_SONGS
- CONST_IN_ALBUM -> IN_ALBUM
- CONST_IN_ARTIST -> IN_ARTIST
- CONST_IN_GENRE -> IN_GENRE
+ INT_ALL_SONGS -> ALL_SONGS
+ INT_IN_ALBUM -> IN_ALBUM
+ INT_IN_ARTIST -> IN_ARTIST
+ INT_IN_GENRE -> IN_GENRE
else -> null
}
}
diff --git a/app/src/main/java/org/oxycblt/auxio/playback/system/AudioReactor.kt b/app/src/main/java/org/oxycblt/auxio/playback/system/AudioReactor.kt
index de8812a92..981ff54ba 100644
--- a/app/src/main/java/org/oxycblt/auxio/playback/system/AudioReactor.kt
+++ b/app/src/main/java/org/oxycblt/auxio/playback/system/AudioReactor.kt
@@ -37,7 +37,7 @@ import kotlin.math.pow
* Manages the current volume and playback state across ReplayGain and AudioFocus events.
* @author OxygenCobalt
*/
-class AudioReactor(context: Context) : AudioManager.OnAudioFocusChangeListener {
+class AudioReactor(context: Context) : AudioManager.OnAudioFocusChangeListener, SettingsManager.Callback {
private data class Gain(val track: Float, val album: Float)
private val playbackManager = PlaybackStateManager.maybeGetInstance()
@@ -62,13 +62,24 @@ class AudioReactor(context: Context) : AudioManager.OnAudioFocusChangeListener {
get() = field * multiplier
private set
+ init {
+ settingsManager.addCallback(this)
+ }
+
+ /**
+ * Request the android system for audio focus
+ */
+ fun requestFocus() {
+ AudioManagerCompat.requestAudioFocus(audioManager, request)
+ }
+
/**
* Updates the rough volume adjustment for [Metadata] with ReplayGain tags.
* This is based off Vanilla Music's implementation.
*/
fun applyReplayGain(metadata: Metadata?) {
- if (metadata == null) {
- logD("No parsable ReplayGain tags, returning volume to 1.")
+ if (settingsManager.replayGainMode == ReplayGainMode.OFF || metadata == null) {
+ logD("ReplayGain is disabled or cannot be determined for this track, resetting volume.")
volume = 1f
return
}
@@ -76,14 +87,14 @@ class AudioReactor(context: Context) : AudioManager.OnAudioFocusChangeListener {
val gain = parseReplayGain(metadata)
// Currently we consider both the album and the track gain.
- // TODO: Add configuration here
var adjust = 0f
if (gain != null) {
- adjust = if (gain.album != 0f) {
- gain.album
+ // Allow the user to configure a preferred mode for ReplayGain.
+ adjust = if (settingsManager.replayGainMode == ReplayGainMode.TRACK) {
+ if (gain.track != 0f) gain.track else gain.album
} else {
- gain.track
+ if (gain.album != 0f) gain.album else gain.track
}
}
@@ -155,20 +166,16 @@ class AudioReactor(context: Context) : AudioManager.OnAudioFocusChangeListener {
}
}
- /**
- * Request the android system for audio focus
- */
- fun requestFocus() {
- AudioManagerCompat.requestAudioFocus(audioManager, request)
- }
-
/**
* Abandon the current focus request, functionally "Destroying it".
*/
fun release() {
AudioManagerCompat.abandonAudioFocusRequest(audioManager, request)
+ settingsManager.removeCallback(this)
}
+ // --- INTERNAL AUDIO FOCUS ---
+
override fun onAudioFocusChange(focusChange: Int) {
if (!settingsManager.doAudioFocus) {
// Don't do audio focus if its not enabled
@@ -219,6 +226,14 @@ class AudioReactor(context: Context) : AudioManager.OnAudioFocusChangeListener {
logD("Unducked volume, now $volume")
}
+ // --- SETTINGS MANAGEMENT ---
+
+ override fun onAudioFocusUpdate(focus: Boolean) {
+ if (!focus) {
+ onGain()
+ }
+ }
+
companion object {
private const val MULTIPLIER_DUCK = 0.2f
diff --git a/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackService.kt b/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackService.kt
index 8656fd08e..3a18374a0 100644
--- a/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackService.kt
+++ b/app/src/main/java/org/oxycblt/auxio/playback/system/PlaybackService.kt
@@ -353,6 +353,10 @@ class PlaybackService : Service(), Player.Listener, PlaybackStateManager.Callbac
}
}
+ override fun onReplayGainUpdate(mode: ReplayGainMode) {
+ onTracksInfoChanged(player.currentTracksInfo)
+ }
+
// --- OTHER FUNCTIONS ---
/**
diff --git a/app/src/main/java/org/oxycblt/auxio/playback/system/ReplayGainMode.kt b/app/src/main/java/org/oxycblt/auxio/playback/system/ReplayGainMode.kt
new file mode 100644
index 000000000..9c085b080
--- /dev/null
+++ b/app/src/main/java/org/oxycblt/auxio/playback/system/ReplayGainMode.kt
@@ -0,0 +1,30 @@
+package org.oxycblt.auxio.playback.system
+
+enum class ReplayGainMode {
+ OFF,
+ TRACK,
+ ALBUM;
+
+ fun toInt(): Int {
+ return when (this) {
+ OFF -> INT_OFF
+ TRACK -> INT_TRACK
+ ALBUM -> INT_ALBUM
+ }
+ }
+
+ companion object {
+ private const val INT_OFF = 0xA110
+ private const val INT_TRACK = 0xA111
+ private const val INT_ALBUM = 0xA112
+
+ fun fromInt(value: Int): ReplayGainMode? {
+ return when (value) {
+ INT_OFF -> OFF
+ INT_TRACK -> TRACK
+ INT_ALBUM -> ALBUM
+ else -> null
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt b/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt
index b24c9c204..51851e8bf 100644
--- a/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt
+++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt
@@ -25,6 +25,7 @@ import androidx.preference.PreferenceManager
import org.oxycblt.auxio.accent.Accent
import org.oxycblt.auxio.home.tabs.Tab
import org.oxycblt.auxio.playback.state.PlaybackMode
+import org.oxycblt.auxio.playback.system.ReplayGainMode
import org.oxycblt.auxio.ui.DisplayMode
import org.oxycblt.auxio.ui.Sort
@@ -102,6 +103,11 @@ class SettingsManager private constructor(context: Context) :
val doPlugMgt: Boolean
get() = sharedPrefs.getBoolean(KEY_PLUG_MANAGEMENT, true)
+ /** The current ReplayGain configuration */
+ val replayGainMode: ReplayGainMode
+ get() = ReplayGainMode.fromInt(sharedPrefs.getInt(KEY_REPLAY_GAIN, Int.MIN_VALUE))
+ ?: ReplayGainMode.OFF
+
/** What queue to create when a song is selected (ex. From All Songs or Search) */
val songPlaybackMode: PlaybackMode
get() = handleSongPlayModeCompat(sharedPrefs)
@@ -236,6 +242,14 @@ class SettingsManager private constructor(context: Context) :
KEY_LIB_TABS -> callbacks.forEach {
it.onLibTabsUpdate(libTabs)
}
+
+ KEY_AUDIO_FOCUS -> callbacks.forEach {
+ it.onAudioFocusUpdate(doAudioFocus)
+ }
+
+ KEY_REPLAY_GAIN -> callbacks.forEach {
+ it.onReplayGainUpdate(replayGainMode)
+ }
}
}
@@ -250,6 +264,8 @@ class SettingsManager private constructor(context: Context) :
fun onNotifActionUpdate(useAltAction: Boolean) {}
fun onShowCoverUpdate(showCovers: Boolean) {}
fun onQualityCoverUpdate(doQualityCovers: Boolean) {}
+ fun onAudioFocusUpdate(focus: Boolean) {}
+ fun onReplayGainUpdate(mode: ReplayGainMode) {}
}
companion object {
@@ -267,6 +283,7 @@ class SettingsManager private constructor(context: Context) :
const val KEY_AUDIO_FOCUS = "KEY_AUDIO_FOCUS"
const val KEY_PLUG_MANAGEMENT = "KEY_PLUG_MGT"
+ const val KEY_REPLAY_GAIN = "auxio_replay_gain"
const val KEY_SONG_PLAYBACK_MODE = "KEY_SONG_PLAY_MODE2"
const val KEY_KEEP_SHUFFLE = "KEY_KEEP_SHUFFLE"
diff --git a/app/src/main/java/org/oxycblt/auxio/ui/DisplayMode.kt b/app/src/main/java/org/oxycblt/auxio/ui/DisplayMode.kt
index 502a680b2..92ed829c3 100644
--- a/app/src/main/java/org/oxycblt/auxio/ui/DisplayMode.kt
+++ b/app/src/main/java/org/oxycblt/auxio/ui/DisplayMode.kt
@@ -47,11 +47,11 @@ enum class DisplayMode {
}
companion object {
- private const val CONST_NULL = 0xA107
- private const val CONST_SHOW_GENRES = 0xA108
- private const val CONST_SHOW_ARTISTS = 0xA109
- private const val CONST_SHOW_ALBUMS = 0xA10A
- private const val CONST_SHOW_SONGS = 0xA10B
+ private const val INT_NULL = 0xA107
+ private const val INT_SHOW_GENRES = 0xA108
+ private const val INT_SHOW_ARTISTS = 0xA109
+ private const val INT_SHOW_ALBUMS = 0xA10A
+ private const val INT_SHOW_SONGS = 0xA10B
/**
* Convert this enum into an integer for filtering.
@@ -60,11 +60,11 @@ enum class DisplayMode {
*/
fun toFilterInt(value: DisplayMode?): Int {
return when (value) {
- SHOW_SONGS -> CONST_SHOW_SONGS
- SHOW_ALBUMS -> CONST_SHOW_ALBUMS
- SHOW_ARTISTS -> CONST_SHOW_ARTISTS
- SHOW_GENRES -> CONST_SHOW_GENRES
- null -> CONST_NULL
+ SHOW_SONGS -> INT_SHOW_SONGS
+ SHOW_ALBUMS -> INT_SHOW_ALBUMS
+ SHOW_ARTISTS -> INT_SHOW_ARTISTS
+ SHOW_GENRES -> INT_SHOW_GENRES
+ null -> INT_NULL
}
}
@@ -75,10 +75,10 @@ enum class DisplayMode {
*/
fun fromFilterInt(value: Int): DisplayMode? {
return when (value) {
- CONST_SHOW_SONGS -> SHOW_SONGS
- CONST_SHOW_ALBUMS -> SHOW_ALBUMS
- CONST_SHOW_ARTISTS -> SHOW_ARTISTS
- CONST_SHOW_GENRES -> SHOW_GENRES
+ INT_SHOW_SONGS -> SHOW_SONGS
+ INT_SHOW_ALBUMS -> SHOW_ALBUMS
+ INT_SHOW_ARTISTS -> SHOW_ARTISTS
+ INT_SHOW_GENRES -> SHOW_GENRES
else -> null
}
}
diff --git a/app/src/main/java/org/oxycblt/auxio/ui/Sort.kt b/app/src/main/java/org/oxycblt/auxio/ui/Sort.kt
index 5ec294452..a7c378ee9 100644
--- a/app/src/main/java/org/oxycblt/auxio/ui/Sort.kt
+++ b/app/src/main/java/org/oxycblt/auxio/ui/Sort.kt
@@ -163,10 +163,10 @@ sealed class Sort(open val isAscending: Boolean) {
*/
fun toInt(): Int {
return when (this) {
- is ByName -> CONST_NAME
- is ByArtist -> CONST_ARTIST
- is ByAlbum -> CONST_ALBUM
- is ByYear -> CONST_YEAR
+ is ByName -> INT_NAME
+ is ByArtist -> INT_ARTIST
+ is ByAlbum -> INT_ALBUM
+ is ByYear -> INT_YEAR
}.shl(1) or if (isAscending) 1 else 0
}
@@ -202,10 +202,10 @@ sealed class Sort(open val isAscending: Boolean) {
}
companion object {
- private const val CONST_NAME = 0xA10C
- private const val CONST_ARTIST = 0xA10D
- private const val CONST_ALBUM = 0xA10E
- private const val CONST_YEAR = 0xA10F
+ private const val INT_NAME = 0xA10C
+ private const val INT_ARTIST = 0xA10D
+ private const val INT_ALBUM = 0xA10E
+ private const val INT_YEAR = 0xA10F
/**
* Convert a sort's integer representation into a [Sort] instance.
@@ -216,10 +216,10 @@ sealed class Sort(open val isAscending: Boolean) {
val ascending = (value and 1) == 1
return when (value.shr(1)) {
- CONST_NAME -> ByName(ascending)
- CONST_ARTIST -> ByArtist(ascending)
- CONST_ALBUM -> ByAlbum(ascending)
- CONST_YEAR -> ByYear(ascending)
+ INT_NAME -> ByName(ascending)
+ INT_ARTIST -> ByArtist(ascending)
+ INT_ALBUM -> ByAlbum(ascending)
+ INT_YEAR -> ByYear(ascending)
else -> null
}
}
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 97077ff73..335e9556e 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -73,6 +73,10 @@
Pausieren wenn andere Töne abspielt wird [Bsp. Anrufe]
Kopfhörerfokus
Abspielen/Pausieren wenn sich die Kopfhörerverbindung ändert
+ ReplayGain (Nur MP3/FLAC)
+ Aus
+ Titel bevorzugen
+ Album bevorzugen
Verhalten
Wenn ein Lied ausgewählt wird
diff --git a/app/src/main/res/values/settings.xml b/app/src/main/res/values/settings.xml
index c00e52ab8..3da1a79ac 100644
--- a/app/src/main/res/values/settings.xml
+++ b/app/src/main/res/values/settings.xml
@@ -6,7 +6,7 @@
-
+
- @string/set_theme_auto
- @string/set_theme_day
- @string/set_theme_night
@@ -32,6 +32,18 @@
- @integer/play_mode_genre
+
+ - @string/set_replay_gain_off
+ - @string/set_replay_gain_track
+ - @string/set_replay_gain_album
+
+
+
+ - @integer/replay_gain_off
+ - @integer/replay_gain_track
+ - @integer/replay_gain_album
+
+
-1
1
2
@@ -40,4 +52,8 @@
0xA104
0xA105
0xA106
+
+ 0xA110
+ 0xA111
+ 0xA112
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 64424bd60..22449240a 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -85,6 +85,10 @@
Pause when other audio plays [ex. Calls]
Headset focus
Play/Pause when the headset connection changes
+ ReplayGain (MP3/FLAC Only)
+ Off
+ Prefer track
+ Prefer album
Behavior
When a song is selected
diff --git a/app/src/main/res/xml/prefs_main.xml b/app/src/main/res/xml/prefs_main.xml
index 0b2ee933c..cfab281d2 100644
--- a/app/src/main/res/xml/prefs_main.xml
+++ b/app/src/main/res/xml/prefs_main.xml
@@ -7,7 +7,7 @@
+
+