Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .phrasey/schema.toml
Original file line number Diff line number Diff line change
Expand Up @@ -762,3 +762,40 @@ name = "KeepScreenAwakeOnLyrics"

[[keys]]
name = "MinSongDurationFilter"

#[[keys]]
#name = "ReplayGain"

#[[keys]]
#name = "UseReplayGain"

#[[keys]]
#name = "ReplayGainDesc"

#[[keys]]
#name = "ReplayGainMode"

#[[keys]]
#name = "ReplayGainModeAutomatic"

#[[keys]]
#name = "ReplayGainModeAutomaticDesc"

#[[keys]]
#name = "ReplayGainModeAlbum"

#[[keys]]
#name = "ReplayGainModeAlbumDesc"

#[[keys]]
#name = "ReplayGainModeTrack"

#[[keys]]
#name = "ReplayGainModeTrackDesc"

#[[keys]]
#name = "XDb"
#parameters = ["x"]

#[[keys]]
#name = "ReplayGainPreAmp"
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
{
"formatVersion": 1,
"database": {
"version": 3,
"identityHash": "ad501bfa3954da440fc658d7e23c0c4c",
"entities": [
{
"tableName": "songs",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `title` TEXT NOT NULL, `album` TEXT, `artists` TEXT NOT NULL, `composers` TEXT NOT NULL, `albumArtists` TEXT NOT NULL, `genres` TEXT NOT NULL, `trackNumber` INTEGER, `trackTotal` INTEGER, `discNumber` INTEGER, `discTotal` INTEGER, `date` TEXT, `year` INTEGER, `duration` INTEGER NOT NULL, `bitrate` INTEGER, `samplingRate` INTEGER, `channels` INTEGER, `encoder` TEXT, `dateModified` INTEGER NOT NULL, `size` INTEGER NOT NULL, `coverFile` TEXT, `uri` TEXT NOT NULL, `path` TEXT NOT NULL, `trackGain` REAL, `albumGain` REAL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "album",
"columnName": "album",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "artists",
"columnName": "artists",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "composers",
"columnName": "composers",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "albumArtists",
"columnName": "albumArtists",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "genres",
"columnName": "genres",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "trackNumber",
"columnName": "trackNumber",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "trackTotal",
"columnName": "trackTotal",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "discNumber",
"columnName": "discNumber",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "discTotal",
"columnName": "discTotal",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "date",
"columnName": "date",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "year",
"columnName": "year",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "duration",
"columnName": "duration",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "bitrate",
"columnName": "bitrate",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "samplingRate",
"columnName": "samplingRate",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "channels",
"columnName": "channels",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "encoder",
"columnName": "encoder",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "dateModified",
"columnName": "dateModified",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "size",
"columnName": "size",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "coverFile",
"columnName": "coverFile",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uri",
"columnName": "uri",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "path",
"columnName": "path",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "replayGain.trackGain",
"columnName": "trackGain",
"affinity": "REAL",
"notNull": false
},
{
"fieldPath": "replayGain.albumGain",
"columnName": "albumGain",
"affinity": "REAL",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ad501bfa3954da440fc658d7e23c0c4c')"
]
}
}
2 changes: 2 additions & 0 deletions app/src/main/java/io/github/zyrouge/symphony/Symphony.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import io.github.zyrouge.symphony.services.database.Database
import io.github.zyrouge.symphony.services.groove.Groove
import io.github.zyrouge.symphony.services.i18n.Translator
import io.github.zyrouge.symphony.services.radio.Radio
import io.github.zyrouge.symphony.services.replayGain.ReplayGain
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
Expand All @@ -33,6 +34,7 @@ class Symphony(application: Application) : AndroidViewModel(application), Sympho
val groove = Groove(this)
val radio = Radio(this)
val translator = Translator(this)
val replayGain = ReplayGain(this)

var t by mutableStateOf(translator.getCurrentTranslation())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import io.github.zyrouge.symphony.services.groove.repositories.GenreRepository
import io.github.zyrouge.symphony.services.groove.repositories.PlaylistRepository
import io.github.zyrouge.symphony.services.groove.repositories.SongRepository
import io.github.zyrouge.symphony.services.radio.RadioQueue
import io.github.zyrouge.symphony.services.replayGain.ReplayGainNormalizationMode
import io.github.zyrouge.symphony.ui.components.ResponsiveGridColumns
import io.github.zyrouge.symphony.ui.theme.ThemeMode
import io.github.zyrouge.symphony.ui.view.HomePage
Expand Down Expand Up @@ -330,6 +331,10 @@ class Settings(private val symphony: Symphony) {
val caseSensitiveSorting = BooleanEntry("case_sensitive_sorting", false)
val lyricsKeepScreenAwake = BooleanEntry("lyrics_keep_screen_awake", true)

val replayGainEnabled = BooleanEntry("replay_gain_enabled", true)
val replayGainPreAmp = FloatEntry("replay_gain_pre_amp", 0.0F)
val replayGainNormalizationMode = EnumEntry("replay_gain_normalization_mode", enumEntries<ReplayGainNormalizationMode>(), ReplayGainNormalizationMode.AUTOMATIC)

private fun getSharedPreferences() = symphony.applicationContext
.getSharedPreferences("settings", Context.MODE_PRIVATE)
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import io.github.zyrouge.symphony.utils.RoomConvertors

@Database(
entities = [Song::class],
version = 2,
autoMigrations = [AutoMigration(1, 2, CacheDatabase.Migration1To2::class)]
version = 3,
autoMigrations = [AutoMigration(1, 2, CacheDatabase.Migration1To2::class), AutoMigration(2, 3)]
)
@TypeConverters(RoomConvertors::class)
abstract class CacheDatabase : RoomDatabase() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.media.MediaMetadataRetriever
import android.net.Uri
import android.os.Build
import androidx.compose.runtime.Immutable
import androidx.room.Embedded
import androidx.room.Entity
import androidx.room.PrimaryKey
import io.github.zyrouge.symphony.Symphony
Expand Down Expand Up @@ -46,7 +47,14 @@ data class Song(
val coverFile: String?,
val uri: Uri,
val path: String,
@Embedded
val replayGain: ReplayGain,
) {
data class ReplayGain(
val trackGain: Float? = null,
val albumGain: Float? = null,
)

data class ParseOptions(
val symphony: Symphony,
val artistSeparatorRegex: Regex,
Expand Down Expand Up @@ -178,6 +186,10 @@ data class Song(
coverFile = coverFile,
uri = file.uri,
path = path.pathString,
replayGain = ReplayGain(
metadata.songGain,
metadata.albumGain,
)
)
}

Expand Down Expand Up @@ -254,6 +266,7 @@ data class Song(
coverFile = coverFile,
uri = file.uri,
path = path.pathString,
replayGain = ReplayGain(),
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ class RadioPlayer(val symphony: Symphony, val id: String, val uri: Uri) {
var pitch = DEFAULT_PITCH
private set

var replayGainReference: Any? = null

val usable get() = state == State.Prepared
val fadePlayback get() = symphony.settings.fadePlayback.value
val audioSessionId get() = mediaPlayer?.audioSessionId
Expand All @@ -74,6 +76,9 @@ class RadioPlayer(val symphony: Symphony, val id: String, val uri: Uri) {
state = State.Prepared
ump.playbackParams.setAudioFallbackMode(PlaybackParams.AUDIO_FALLBACK_MODE_DEFAULT)
createDurationTimer()

replayGainReference = symphony.replayGain.applyReplayGain(id, ump.audioSessionId)

onPrepared?.invoke()
}
ump.setOnCompletionListener {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,19 @@ class RadioQueue(private val symphony: Symphony) {
symphony.radio.onUpdate.dispatch(Radio.Events.QueueOption.LoopModeChanged)
}

/**
* When in replay gain automatic mode, songs from this album will be played with Album Gain.
*/
var owningAlbum: String? = null

val currentSongId: String?
get() = getSongIdAt(currentSongIndex)

fun hasSongAt(index: Int) = index > -1 && index < currentQueue.size
fun getSongIdAt(index: Int) = if (hasSongAt(index)) currentQueue[index] else null

fun reset() {
owningAlbum = null
originalQueue.clear()
currentQueue.clear()
currentSongIndex = -1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class RadioShorty(private val symphony: Symphony) {
songIds: List<String>,
options: Radio.PlayOptions = Radio.PlayOptions(),
shuffle: Boolean = false,
owningAlbum: String? = null,
) {
symphony.radio.stop(ended = false)
if (songIds.isEmpty()) {
Expand All @@ -69,6 +70,7 @@ class RadioShorty(private val symphony: Symphony) {
copy(index = if (shuffle) Random.nextInt(songIds.size) else options.index)
}
)
symphony.radio.queue.owningAlbum = owningAlbum
symphony.radio.queue.setShuffleMode(shuffle)
}

Expand Down
Loading