diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/audiofx/EqualizerController.java b/ultrasonic/src/main/java/org/moire/ultrasonic/audiofx/EqualizerController.java
deleted file mode 100644
index 1f844646..00000000
--- a/ultrasonic/src/main/java/org/moire/ultrasonic/audiofx/EqualizerController.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic 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.
-
- Subsonic 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.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see .
-
- Copyright 2011 (C) Sindre Mehus
- */
-package org.moire.ultrasonic.audiofx;
-
-import android.content.Context;
-import android.media.MediaPlayer;
-import android.media.audiofx.Equalizer;
-
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.MutableLiveData;
-
-import timber.log.Timber;
-
-import org.moire.ultrasonic.util.FileUtil;
-
-import java.io.Serializable;
-
-/**
- * Backward-compatible wrapper for {@link Equalizer}, which is API Level 9.
- *
- * @author Sindre Mehus
- * @version $Id$
- */
-public class EqualizerController
-{
- private static Boolean available = null;
- private static final MutableLiveData instance = new MutableLiveData<>();
-
- private Context context;
- public Equalizer equalizer;
- private int audioSessionId;
-
- /**
- * Retrieves the EqualizerController as LiveData
- */
- public static LiveData get()
- {
- return instance;
- }
-
- /**
- * Initializes the EqualizerController instance with a MediaPlayer
- */
- public static void create(Context context, MediaPlayer mediaPlayer)
- {
- if (mediaPlayer == null) return;
- if (!isAvailable()) return;
-
- EqualizerController controller = new EqualizerController();
- controller.context = context;
-
- try
- {
- controller.audioSessionId = mediaPlayer.getAudioSessionId();
- controller.equalizer = new Equalizer(0, controller.audioSessionId);
- controller.loadSettings();
-
- instance.postValue(controller);
- }
- catch (Throwable x)
- {
- Timber.w(x, "Failed to create equalizer.");
- }
- }
-
- /**
- * Releases the EqualizerController instance when the underlying MediaPlayer is no longer available
- */
- public static void release()
- {
- EqualizerController controller = instance.getValue();
- if (controller == null) return;
-
- controller.equalizer.release();
- instance.postValue(null);
- }
-
- /**
- * Checks if the {@link Equalizer} class is available.
- */
- private static boolean isAvailable()
- {
- if (available != null) return available;
- try
- {
- Class.forName("android.media.audiofx.Equalizer");
- available = true;
- }
- catch (Exception ex)
- {
- Timber.i(ex, "CheckAvailable received an exception getting class for the Equalizer");
- available = false;
- }
- return available;
- }
-
- public void saveSettings()
- {
- if (!available) return;
- try
- {
- FileUtil.serialize(context, new EqualizerSettings(equalizer), "equalizer.dat");
- }
- catch (Throwable x)
- {
- Timber.w(x, "Failed to save equalizer settings.");
- }
- }
-
- public void loadSettings()
- {
- if (!available) return;
- try
- {
- EqualizerSettings settings = FileUtil.deserialize(context, "equalizer.dat");
-
- if (settings != null)
- {
- settings.apply(equalizer);
- }
- }
- catch (Throwable x)
- {
- Timber.w(x, "Failed to load equalizer settings.");
- }
- }
-
- private static class EqualizerSettings implements Serializable
- {
- private static final long serialVersionUID = 626565082425206061L;
- private final short[] bandLevels;
- private short preset;
- private final boolean enabled;
-
- public EqualizerSettings(Equalizer equalizer)
- {
- enabled = equalizer.getEnabled();
- bandLevels = new short[equalizer.getNumberOfBands()];
-
- for (short i = 0; i < equalizer.getNumberOfBands(); i++)
- {
- bandLevels[i] = equalizer.getBandLevel(i);
- }
-
- try
- {
- preset = equalizer.getCurrentPreset();
- }
- catch (Exception x)
- {
- preset = -1;
- }
- }
-
- public void apply(Equalizer equalizer)
- {
- for (short i = 0; i < bandLevels.length; i++)
- {
- equalizer.setBandLevel(i, bandLevels[i]);
- }
-
- if (preset >= 0 && preset < equalizer.getNumberOfPresets())
- {
- equalizer.usePreset(preset);
- }
-
- equalizer.setEnabled(enabled);
- }
- }
-}
diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/EqualizerFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/EqualizerFragment.java
deleted file mode 100644
index bdf6bf33..00000000
--- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/EqualizerFragment.java
+++ /dev/null
@@ -1,275 +0,0 @@
-package org.moire.ultrasonic.fragment;
-
-import android.media.audiofx.Equalizer;
-import android.os.Bundle;
-import android.view.ContextMenu;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.LinearLayout;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
-import androidx.lifecycle.Observer;
-
-import org.jetbrains.annotations.NotNull;
-import org.moire.ultrasonic.R;
-import org.moire.ultrasonic.audiofx.EqualizerController;
-import org.moire.ultrasonic.util.Util;
-
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-
-import timber.log.Timber;
-
-/**
- * Displays the Equalizer
- */
-public class EqualizerFragment extends Fragment {
-
- private static final int MENU_GROUP_PRESET = 100;
-
- private final Map bars = new HashMap<>();
- private EqualizerController equalizerController;
- private Equalizer equalizer;
- private LinearLayout equalizerLayout;
- private View presetButton;
- private CheckBox enabledCheckBox;
-
- @Override
- public void onCreate(@Nullable Bundle savedInstanceState) {
- Util.applyTheme(this.getContext());
- super.onCreate(savedInstanceState);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- return inflater.inflate(R.layout.equalizer, container, false);
- }
-
- @Override
- public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
-
- FragmentTitle.Companion.setTitle(this, R.string.equalizer_label);
- equalizerLayout = view.findViewById(R.id.equalizer_layout);
- presetButton = view.findViewById(R.id.equalizer_preset);
- enabledCheckBox = view.findViewById(R.id.equalizer_enabled);
-
- EqualizerController.get().observe(getViewLifecycleOwner(), new Observer() {
- @Override
- public void onChanged(EqualizerController controller) {
- if (controller != null) {
- Timber.d("EqualizerController Observer.onChanged received controller");
- equalizerController = controller;
- equalizer = controller.equalizer;
- setup();
- } else {
- Timber.d("EqualizerController Observer.onChanged has no controller");
- equalizerController = null;
- equalizer = null;
- }
- }
- });
- }
-
- @Override
- public void onPause()
- {
- super.onPause();
- if (equalizerController == null) return;
- equalizerController.saveSettings();
- }
-
- @Override
- public void onCreateContextMenu(@NotNull ContextMenu menu, @NotNull View view, ContextMenu.ContextMenuInfo menuInfo)
- {
- super.onCreateContextMenu(menu, view, menuInfo);
- if (equalizer == null) return;
-
- short currentPreset;
- try
- {
- currentPreset = equalizer.getCurrentPreset();
- }
- catch (Exception x)
- {
- currentPreset = -1;
- }
-
- for (short preset = 0; preset < equalizer.getNumberOfPresets(); preset++)
- {
- MenuItem menuItem = menu.add(MENU_GROUP_PRESET, preset, preset, equalizer.getPresetName(preset));
- if (preset == currentPreset)
- {
- menuItem.setChecked(true);
- }
- }
- menu.setGroupCheckable(MENU_GROUP_PRESET, true, true);
- }
-
- @Override
- public boolean onContextItemSelected(@NotNull MenuItem menuItem)
- {
- if (equalizer == null) return true;
- try
- {
- short preset = (short) menuItem.getItemId();
- equalizer.usePreset(preset);
- updateBars();
- }
- catch (Exception ex)
- {
- //TODO: Show a dialog?
- Timber.i(ex, "An exception has occurred in EqualizerFragment onContextItemSelected");
- }
-
- return true;
- }
-
- private void setup()
- {
- initEqualizer();
-
- registerForContextMenu(presetButton);
- presetButton.setOnClickListener(new View.OnClickListener()
- {
- @Override
- public void onClick(View view)
- {
- presetButton.showContextMenu();
- }
- });
-
- enabledCheckBox.setChecked(equalizer.getEnabled());
- enabledCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
- {
- @Override
- public void onCheckedChanged(CompoundButton compoundButton, boolean b)
- {
- setEqualizerEnabled(b);
- }
- });
- }
-
- private void setEqualizerEnabled(boolean enabled)
- {
- if (equalizer == null) return;
- equalizer.setEnabled(enabled);
- updateBars();
- }
-
- private void updateBars()
- {
- if (equalizer == null) return;
- try
- {
- for (Map.Entry entry : bars.entrySet())
- {
- short band = entry.getKey();
- SeekBar bar = entry.getValue();
- bar.setEnabled(equalizer.getEnabled());
- short minEQLevel = equalizer.getBandLevelRange()[0];
- bar.setProgress(equalizer.getBandLevel(band) - minEQLevel);
- }
- }
- catch (Exception ex)
- {
- //TODO: Show a dialog?
- Timber.i(ex, "An exception has occurred in EqualizerFragment updateBars");
- }
- }
-
- private void initEqualizer()
- {
- if (equalizer == null) return;
-
- try
- {
- short[] bandLevelRange = equalizer.getBandLevelRange();
- short numberOfBands = equalizer.getNumberOfBands();
-
- final short minEQLevel = bandLevelRange[0];
- final short maxEQLevel = bandLevelRange[1];
-
- for (short i = 0; i < numberOfBands; i++)
- {
- final short band = i;
-
- View bandBar = LayoutInflater.from(getContext()).inflate(R.layout.equalizer_bar, equalizerLayout, false);
- TextView freqTextView;
-
- if (bandBar != null)
- {
- freqTextView = (TextView) bandBar.findViewById(R.id.equalizer_frequency);
- final TextView levelTextView = (TextView) bandBar.findViewById(R.id.equalizer_level);
- SeekBar bar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar);
-
- freqTextView.setText(String.format(Locale.getDefault(), "%d Hz", equalizer.getCenterFreq(band) / 1000));
-
- bars.put(band, bar);
- bar.setMax(maxEQLevel - minEQLevel);
- short level = equalizer.getBandLevel(band);
- bar.setProgress(level - minEQLevel);
- bar.setEnabled(equalizer.getEnabled());
- updateLevelText(levelTextView, level);
-
- bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
- {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
- {
- short level = (short) (progress + minEQLevel);
- if (fromUser)
- {
- try
- {
- equalizer.setBandLevel(band, level);
- }
- catch (Exception ex)
- {
- //TODO: Show a dialog?
- Timber.i(ex, "An exception has occurred in Equalizer onProgressChanged");
- }
- }
- updateLevelText(levelTextView, level);
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar)
- {
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar)
- {
- }
- });
-
- equalizerLayout.addView(bandBar);
- }
- }
- }
- catch (Exception ex)
- {
- //TODO: Show a dialog?
- Timber.i(ex, "An exception has occurred while initializing Equalizer");
- }
- }
-
- private static void updateLevelText(TextView levelTextView, short level)
- {
- if (levelTextView != null)
- {
- levelTextView.setText(String.format(Locale.getDefault(), "%s%d dB", level > 0 ? "+" : "", level / 100));
- }
- }
-}
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/audiofx/EqualizerController.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/audiofx/EqualizerController.kt
new file mode 100644
index 00000000..5c9630d5
--- /dev/null
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/audiofx/EqualizerController.kt
@@ -0,0 +1,124 @@
+/*
+ * EqualizerController.kt
+ * Copyright (C) 2009-2022 Ultrasonic developers
+ *
+ * Distributed under terms of the GNU GPLv3 license.
+ */
+package org.moire.ultrasonic.audiofx
+
+import android.media.audiofx.Equalizer
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import java.io.Serializable
+import java.lang.Exception
+import org.moire.ultrasonic.app.UApp
+import org.moire.ultrasonic.util.FileUtil.deserialize
+import org.moire.ultrasonic.util.FileUtil.serialize
+import timber.log.Timber
+
+/**
+ * Wrapper for [Equalizer] with automatic restoration of presets and settings.
+ *
+ * TODO: Maybe store the settings in the DB?
+ */
+class EqualizerController {
+
+ @JvmField
+ var equalizer: Equalizer? = null
+ private var audioSessionId = 0
+
+ fun saveSettings() {
+ if (equalizer == null) return
+ try {
+ serialize(UApp.applicationContext(), EqualizerSettings(equalizer!!), "equalizer.dat")
+ } catch (all: Throwable) {
+ Timber.w(all, "Failed to save equalizer settings.")
+ }
+ }
+
+ fun loadSettings() {
+ if (equalizer == null) return
+ try {
+ val settings = deserialize(
+ UApp.applicationContext(), "equalizer.dat"
+ )
+ settings?.apply(equalizer!!)
+ } catch (all: Throwable) {
+ Timber.w(all, "Failed to load equalizer settings.")
+ }
+ }
+
+ private class EqualizerSettings(equalizer: Equalizer) : Serializable {
+ private val bandLevels: ShortArray
+ private var preset: Short = 0
+ private val enabled: Boolean
+
+ fun apply(equalizer: Equalizer) {
+ for (i in bandLevels.indices) {
+ equalizer.setBandLevel(i.toShort(), bandLevels[i])
+ }
+ if (preset >= 0 && preset < equalizer.numberOfPresets) {
+ equalizer.usePreset(preset)
+ }
+ equalizer.enabled = enabled
+ }
+
+ init {
+ enabled = equalizer.enabled
+ bandLevels = ShortArray(equalizer.numberOfBands.toInt())
+ for (i in 0 until equalizer.numberOfBands) {
+ bandLevels[i] = equalizer.getBandLevel(i.toShort())
+ }
+ preset = try {
+ equalizer.currentPreset
+ } catch (ignored: Exception) {
+ -1
+ }
+ }
+
+ companion object {
+ private const val serialVersionUID = 6269873247206061L
+ }
+ }
+
+ companion object {
+ private val instance = MutableLiveData()
+
+ /**
+ * Retrieves the EqualizerController as LiveData
+ */
+ @JvmStatic
+ fun get(): LiveData {
+ return instance
+ }
+
+ /**
+ * Initializes the EqualizerController instance with a Session
+ *
+ * @param sessionId
+ * @return the new controller
+ */
+ fun create(sessionId: Int): EqualizerController? {
+ val controller = EqualizerController()
+ return try {
+ controller.audioSessionId = sessionId
+ controller.equalizer = Equalizer(0, controller.audioSessionId)
+ controller.loadSettings()
+ instance.postValue(controller)
+ controller
+ } catch (all: Throwable) {
+ Timber.w(all, "Failed to create equalizer.")
+ null
+ }
+ }
+
+ /**
+ * Releases the EqualizerController instance when the underlying MediaPlayer is no longer available
+ */
+ fun release() {
+ val controller = instance.value ?: return
+ controller.equalizer!!.release()
+ instance.postValue(null)
+ }
+ }
+}
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EqualizerFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EqualizerFragment.kt
new file mode 100644
index 00000000..e1d48e79
--- /dev/null
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/EqualizerFragment.kt
@@ -0,0 +1,232 @@
+/*
+ * EqualizerFragment.kt
+ * Copyright (C) 2009-2022 Ultrasonic developers
+ *
+ * Distributed under terms of the GNU GPLv3 license.
+ */
+
+package org.moire.ultrasonic.fragment
+
+import android.media.audiofx.Equalizer
+import android.os.Bundle
+import android.view.ContextMenu
+import android.view.ContextMenu.ContextMenuInfo
+import android.view.LayoutInflater
+import android.view.MenuItem
+import android.view.View
+import android.view.ViewGroup
+import android.widget.CheckBox
+import android.widget.LinearLayout
+import android.widget.SeekBar
+import android.widget.SeekBar.OnSeekBarChangeListener
+import android.widget.TextView
+import androidx.fragment.app.Fragment
+import java.lang.Exception
+import java.util.HashMap
+import java.util.Locale
+import org.moire.ultrasonic.R
+import org.moire.ultrasonic.audiofx.EqualizerController
+import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle
+import org.moire.ultrasonic.util.Util.applyTheme
+import timber.log.Timber
+
+/**
+ * Displays the Equalizer
+ */
+class EqualizerFragment : Fragment() {
+ private val bars: MutableMap = HashMap()
+ private var equalizerController: EqualizerController? = null
+ private var equalizer: Equalizer? = null
+ private var equalizerLayout: LinearLayout? = null
+ private var presetButton: View? = null
+ private var enabledCheckBox: CheckBox? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ applyTheme(this.context)
+ super.onCreate(savedInstanceState)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ return inflater.inflate(R.layout.equalizer, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ setTitle(this, R.string.equalizer_label)
+ equalizerLayout = view.findViewById(R.id.equalizer_layout)
+ presetButton = view.findViewById(R.id.equalizer_preset)
+ enabledCheckBox = view.findViewById(R.id.equalizer_enabled)
+
+ // Subscribe to changes in the active controller
+ EqualizerController.get().observe(viewLifecycleOwner) { controller ->
+ if (controller != null) {
+ Timber.d("EqualizerController Observer.onChanged received controller")
+ equalizerController = controller
+ equalizer = controller.equalizer
+ setup()
+ } else {
+ Timber.d("EqualizerController Observer.onChanged has no controller")
+ equalizerController = null
+ equalizer = null
+ }
+ }
+ }
+
+ override fun onPause() {
+ super.onPause()
+ equalizerController?.saveSettings()
+ }
+
+ override fun onCreateContextMenu(menu: ContextMenu, view: View, menuInfo: ContextMenuInfo?) {
+ super.onCreateContextMenu(menu, view, menuInfo)
+
+ if (equalizer == null) return
+ val currentPreset: Short = try {
+ equalizer!!.currentPreset
+ } catch (ignored: Exception) {
+ -1
+ }
+ for (preset in 0 until equalizer!!.numberOfPresets) {
+ val menuItem = menu.add(
+ MENU_GROUP_PRESET, preset, preset,
+ equalizer!!.getPresetName(
+ preset.toShort()
+ )
+ )
+ if (preset == currentPreset.toInt()) {
+ menuItem.isChecked = true
+ }
+ }
+ menu.setGroupCheckable(MENU_GROUP_PRESET, true, true)
+ }
+
+ override fun onContextItemSelected(menuItem: MenuItem): Boolean {
+ if (equalizer == null) return true
+ try {
+ val preset = menuItem.itemId.toShort()
+ equalizer!!.usePreset(preset)
+ updateBars()
+ } catch (all: Exception) {
+ // TODO: Show a dialog?
+ Timber.i(all, "An exception has occurred in EqualizerFragment onContextItemSelected")
+ }
+ return true
+ }
+
+ private fun setup() {
+ initEqualizer()
+ registerForContextMenu(presetButton!!)
+ presetButton!!.setOnClickListener { presetButton!!.showContextMenu() }
+ enabledCheckBox!!.isChecked = equalizer!!.enabled
+ enabledCheckBox!!.setOnCheckedChangeListener { _, b -> setEqualizerEnabled(b) }
+ }
+
+ private fun setEqualizerEnabled(enabled: Boolean) {
+ equalizer?.enabled = enabled
+ updateBars()
+ }
+
+ private fun updateBars() {
+ if (equalizer == null) return
+ try {
+ for ((band, bar) in bars) {
+ bar.isEnabled = equalizer!!.enabled
+ val minEQLevel = equalizer!!.bandLevelRange[0]
+ bar.progress = equalizer!!.getBandLevel(band) - minEQLevel
+ }
+ } catch (all: Exception) {
+ // TODO: Show a dialog?
+ Timber.i(all, "An exception has occurred in EqualizerFragment updateBars")
+ }
+ }
+
+ private fun initEqualizer() {
+ if (equalizer == null) return
+ try {
+ val bandLevelRange = equalizer!!.bandLevelRange
+ val numberOfBands = equalizer!!.numberOfBands
+
+ val minEQLevel = bandLevelRange[0]
+ val maxEQLevel = bandLevelRange[1]
+
+ for (i in 0 until numberOfBands) {
+ val bandBar = createSeekBarForBand(i, maxEQLevel, minEQLevel)
+ equalizerLayout!!.addView(bandBar)
+ }
+ } catch (all: Exception) {
+ // TODO: Show a dialog?
+ Timber.i(all, "An exception has occurred while initializing Equalizer")
+ }
+ }
+
+ private fun createSeekBarForBand(index: Int, maxEQLevel: Short, minEQLevel: Short): View {
+ val band = index.toShort()
+ val bandBar = LayoutInflater.from(context)
+ .inflate(R.layout.equalizer_bar, equalizerLayout, false)
+
+ val freqTextView: TextView =
+ bandBar.findViewById(R.id.equalizer_frequency) as TextView
+ val levelTextView = bandBar.findViewById(R.id.equalizer_level) as TextView
+ val bar = bandBar.findViewById(R.id.equalizer_bar) as SeekBar
+
+ val range = equalizer!!.getBandFreqRange(band)
+
+ freqTextView.text = String.format(
+ Locale.getDefault(),
+ "%d - %d Hz",
+ range[0] / 1000, range[1] / 1000
+ )
+
+ bars[band] = bar
+ bar.max = maxEQLevel - minEQLevel
+ val bandLevel = equalizer!!.getBandLevel(band)
+ bar.progress = bandLevel - minEQLevel
+ bar.isEnabled = equalizer!!.enabled
+ updateLevelText(levelTextView, bandLevel)
+
+ bar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
+ override fun onProgressChanged(
+ seekBar: SeekBar,
+ progress: Int,
+ fromUser: Boolean
+ ) {
+ val level = (progress + minEQLevel).toShort()
+ if (fromUser) {
+ try {
+ equalizer!!.setBandLevel(band, level)
+ } catch (all: Exception) {
+ // TODO: Show a dialog?
+ Timber.i(
+ all,
+ "An exception has occurred in Equalizer onProgressChanged"
+ )
+ }
+ }
+ updateLevelText(levelTextView, level)
+ }
+
+ override fun onStartTrackingTouch(seekBar: SeekBar) {}
+ override fun onStopTrackingTouch(seekBar: SeekBar) {}
+ })
+
+ return bandBar
+ }
+
+ companion object {
+ private const val MENU_GROUP_PRESET = 100
+ private fun updateLevelText(levelTextView: TextView?, level: Short) {
+ if (levelTextView != null) {
+ levelTextView.text = String.format(
+ Locale.getDefault(),
+ "%s%d dB",
+ if (level > 0) "+" else "",
+ level / 100
+ )
+ }
+ }
+ }
+}
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/playback/PlaybackService.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/playback/PlaybackService.kt
index 0a200060..675bb39e 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/playback/PlaybackService.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/playback/PlaybackService.kt
@@ -25,6 +25,7 @@ import okhttp3.OkHttpClient
import org.koin.core.component.KoinComponent
import org.moire.ultrasonic.activity.NavigationActivity
import org.moire.ultrasonic.app.UApp
+import org.moire.ultrasonic.audiofx.EqualizerController
import org.moire.ultrasonic.data.ActiveServerProvider
import org.moire.ultrasonic.service.MusicServiceFactory.getMusicService
import org.moire.ultrasonic.service.RxBus
@@ -36,6 +37,7 @@ import timber.log.Timber
class PlaybackService : MediaLibraryService(), KoinComponent {
private lateinit var player: ExoPlayer
private lateinit var mediaLibrarySession: MediaLibrarySession
+ private var equalizer: EqualizerController? = null
private lateinit var librarySessionCallback: MediaLibrarySession.Callback
@@ -128,6 +130,8 @@ class PlaybackService : MediaLibraryService(), KoinComponent {
.setSeekForwardIncrementMs(Settings.seekInterval.toLong())
.build()
+ equalizer = EqualizerController.create(player.audioSessionId)
+
// Enable audio offload
if (Settings.useHwOffload)
player.experimentalSetOffloadSchedulingEnabled(true)