feat(eq): настоящий эквалайзер + улучшайзеры звука (audiofx)

Раньше пресет эквалайзера в настройках был косметикой (лежал в DataStore, к звуку
не подключён). Теперь — реальные системные эффекты на фикс. аудиосессии плеера:
- AudioEffectsController: графический Equalizer (полосы устройства), BassBoost,
  Virtualizer (объём), LoudnessEnhancer (громкость тихих, до +12 дБ). Привязка к
  generateAudioSessionId() в PlayerController, переживает смену станций. Применение
  в реальном времени, сохранение в DataStore (commit на отпускании слайдера).
- Отдельный экран EqualizerScreen (Настройки → ЗВУК → Эквалайзер): тумблер,
  системные пресеты + «Свой», слайдеры полос (±дБ), bass/virtualizer/loudness.
- Эффекты best-effort: при отсутствии поддержки блок недоступен (null), UI скрывает.
- Убран фейковый чип-пресет Flat/Rock/Pop/Jazz/Bass.
This commit is contained in:
nk
2026-06-06 21:14:38 +03:00
parent 0c01eaab2d
commit e736c2393f
9 changed files with 679 additions and 33 deletions

View File

@@ -42,7 +42,8 @@ import javax.inject.Singleton
@Singleton
class PlayerController @Inject constructor(
@ApplicationContext context: Context,
private val sleepSoundPlayer: SleepSoundPlayer
private val sleepSoundPlayer: SleepSoundPlayer,
private val audioEffects: AudioEffectsController
) {
// Анализатор спектра реального звука — для «живого» эквалайзера.
private val spectrumAnalyzer = AudioSpectrumAnalyzer()
@@ -180,6 +181,11 @@ class PlayerController @Inject constructor(
}
}
})
// Фиксированная аудиосессия → эффекты (эквалайзер и т.д.) держатся на ней
// и переживают смену станций. Привязываем их сразу после создания плеера.
val sessionId = audioManager.generateAudioSessionId()
runCatching { setAudioSessionId(sessionId) }
audioEffects.attach(sessionId)
}
val player: Player = object : ForwardingPlayer(exoPlayer) {