diff --git a/CHANGELOG.md b/CHANGELOG.md
index b7f65701a..186558c62 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
# Changelog
+## 3.4.1
+
+#### What's Fixed
+- R128 adjustments are now adjusted to -18 LUFS to be consistent with MP3
+- Fixed double application of opus base gain
+- Fixed playback state not restoring
+
## 3.4.0
#### What's New
diff --git a/README.md b/README.md
index 084ea5a5a..85006d016 100644
--- a/README.md
+++ b/README.md
@@ -2,8 +2,8 @@
Auxio
A simple, rational music player for android.
-
-
+
+
diff --git a/app/build.gradle b/app/build.gradle
index af0bf21bb..d17211886 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -21,8 +21,8 @@ android {
defaultConfig {
applicationId namespace
- versionName "3.4.0"
- versionCode 41
+ versionName "3.4.1"
+ versionCode 42
minSdk 24
targetSdk 34
diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt
index 1d5c5bdde..41a1055a7 100644
--- a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt
+++ b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt
@@ -222,19 +222,17 @@ class HomeFragment :
collect(detailModel.toShow.flow, ::handleShow)
}
- override fun onStart() {
- super.onStart()
+ override fun onResume() {
+ super.onResume()
// Stock bottom sheet overlay won't work with our nested UI setup, have to replicate
// it ourselves.
requireBinding().root.rootView.apply {
- post {
- findViewById(R.id.main_scrim).setOnTouchListener { _, event ->
- handleSpeedDialBoundaryTouch(event)
- }
- findViewById(R.id.sheet_scrim).setOnTouchListener { _, event ->
- handleSpeedDialBoundaryTouch(event)
- }
+ findViewById(R.id.main_scrim).setOnTouchListener { _, event ->
+ handleSpeedDialBoundaryTouch(event)
+ }
+ findViewById(R.id.sheet_scrim).setOnTouchListener { _, event ->
+ handleSpeedDialBoundaryTouch(event)
}
}
}
diff --git a/app/src/main/java/org/oxycblt/auxio/music/cache/CacheDatabase.kt b/app/src/main/java/org/oxycblt/auxio/music/cache/CacheDatabase.kt
index f64345de2..63e4ccf98 100644
--- a/app/src/main/java/org/oxycblt/auxio/music/cache/CacheDatabase.kt
+++ b/app/src/main/java/org/oxycblt/auxio/music/cache/CacheDatabase.kt
@@ -32,7 +32,7 @@ import org.oxycblt.auxio.music.info.Date
import org.oxycblt.auxio.music.metadata.correctWhitespace
import org.oxycblt.auxio.music.metadata.splitEscaped
-@Database(entities = [CachedSong::class], version = 38, exportSchema = false)
+@Database(entities = [CachedSong::class], version = 42, exportSchema = false)
abstract class CacheDatabase : RoomDatabase() {
abstract fun cachedSongsDao(): CachedSongsDao
}
diff --git a/app/src/main/java/org/oxycblt/auxio/music/metadata/TagWorker.kt b/app/src/main/java/org/oxycblt/auxio/music/metadata/TagWorker.kt
index 2167c195d..78669caee 100644
--- a/app/src/main/java/org/oxycblt/auxio/music/metadata/TagWorker.kt
+++ b/app/src/main/java/org/oxycblt/auxio/music/metadata/TagWorker.kt
@@ -20,7 +20,6 @@ package org.oxycblt.auxio.music.metadata
import androidx.core.text.isDigitsOnly
import androidx.media3.common.MediaItem
-import androidx.media3.common.MimeTypes
import androidx.media3.exoplayer.MetadataRetriever
import androidx.media3.exoplayer.source.MediaSource
import androidx.media3.exoplayer.source.TrackGroupArray
@@ -99,22 +98,26 @@ private class TagWorkerImpl(
populateWithId3v2(textTags.id3v2)
populateWithVorbis(textTags.vorbis)
- // If this metadata is of a vorbis file, we actually need to extract it's base gain
- // and divide it by 256 to get the gain in decibels.
- if (format.sampleMimeType == MimeTypes.AUDIO_OPUS &&
- format.initializationData.isNotEmpty() &&
- format.initializationData[0].size >= 18) {
- val header = format.initializationData[0]
- val gain = (((header[16]).toInt() and 0xFF) or ((header[17].toInt() shl 8))) / 256f
- logD("Obtained opus base gain: $gain dB")
- if (gain != 0f) {
- logD("Applying opus base gain")
- rawSong.replayGainTrackAdjustment =
- (rawSong.replayGainTrackAdjustment ?: 0f) + gain
- rawSong.replayGainAlbumAdjustment =
- (rawSong.replayGainAlbumAdjustment ?: 0f) + gain
- }
- }
+ // OPUS base gain interpretation code: This is likely not needed, as the media player
+ // should be using the base gain already. Uncomment if that's not the case.
+ // if (format.sampleMimeType == MimeTypes.AUDIO_OPUS
+ // && format.initializationData.isNotEmpty()
+ // && format.initializationData[0].size >= 18) {
+ // val header = format.initializationData[0]
+ // val gain =
+ // (((header[16]).toInt() and 0xFF) or ((header[17].toInt() shl 8)))
+ // .R128ToLUFS18()
+ // logD("Obtained opus base gain: $gain dB")
+ // if (gain != 0f) {
+ // logD("Applying opus base gain")
+ // rawSong.replayGainTrackAdjustment =
+ // (rawSong.replayGainTrackAdjustment ?: 0f) + gain
+ // rawSong.replayGainAlbumAdjustment =
+ // (rawSong.replayGainAlbumAdjustment ?: 0f) + gain
+ // } else {
+ // logD("Ignoring opus base gain")
+ // }
+ // }
} else {
logD("No metadata could be extracted for ${rawSong.name}")
}
@@ -317,14 +320,24 @@ private class TagWorkerImpl(
// the base adjustment intrinsic to the format to create the normalized adjustment. This is
// normally the only tag used for opus files, but some software still writes replay gain
// tags anyway.
- (comments["r128_track_gain"]?.parseReplayGainAdjustment()?.div(256)
+ (comments["r128_track_gain"]?.parseR128Adjustment()
?: comments["replaygain_track_gain"]?.parseReplayGainAdjustment())
?.let { rawSong.replayGainTrackAdjustment = it }
- (comments["r128_album_gain"]?.parseReplayGainAdjustment()?.div(256)
+ (comments["r128_album_gain"]?.parseR128Adjustment()
?: comments["replaygain_album_gain"]?.parseReplayGainAdjustment())
?.let { rawSong.replayGainAlbumAdjustment = it }
}
+ private fun List.parseR128Adjustment() =
+ first()
+ .replace(REPLAYGAIN_ADJUSTMENT_FILTER_REGEX, "")
+ .toFloatOrNull()
+ ?.nonZeroOrNull()
+ ?.run {
+ // Convert to fixed-point and adjust to LUFS 18 to match the ReplayGain scale
+ this / 256f + 5
+ }
+
/**
* Parse a ReplayGain adjustment into a float value.
*
diff --git a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt
index 0ebaf669f..7498c8e0b 100644
--- a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt
+++ b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt
@@ -418,12 +418,12 @@ class PlaybackStateManagerImpl @Inject constructor() : PlaybackStateManager {
}
this.stateHolder = stateHolder
- if (isInitialized && stateMirror.index > -1) {
+ if (isInitialized && currentSong != null) {
stateHolder.applySavedState(stateMirror.parent, stateMirror.rawQueue, null)
stateHolder.seekTo(stateMirror.progression.calculateElapsedPositionMs())
stateHolder.playing(false)
- pendingDeferredPlayback?.let(stateHolder::handleDeferred)
}
+ pendingDeferredPlayback?.let(stateHolder::handleDeferred)
}
@Synchronized
diff --git a/fastlane/metadata/android/en-US/changelogs/42.txt b/fastlane/metadata/android/en-US/changelogs/42.txt
new file mode 100644
index 000000000..dcea6e4e6
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/42.txt
@@ -0,0 +1,3 @@
+Auxio 3.4.0 adds gapless playback and new widget designs, alongside a variety of fixes.
+This release fixes critical issues with ReplayGain and playback persistence.
+For more information, see https://github.com/OxygenCobalt/Auxio/releases/tag/v3.4.1
\ No newline at end of file