A Beginner’s Guide to Using Android’s Inbuilt Equalizer + Sliders
Music sounds different to every ear. Some people love deep bass, others prefer clear vocals, while many enjoy a balanced mix of both. Android gives you a simple way to shape your sound through its inbuilt Equalizer. You don’t need to be an audio engineer to use it—just a little curiosity and a few taps.
What is an Equalizer?
An equalizer (often shortened to EQ) is a tool that lets you adjust different parts of the sound spectrum.
- Bass → The low, rumbling sounds (like drums or deep beats).
- Mid → The middle range, usually where voices and guitars sit.
- Treble → The higher, sharper sounds (like cymbals, strings, or “s” sounds in vocals).
By raising or lowering these ranges, you can make music sound warmer, brighter, punchier, or smoother.
Android’s Inbuilt Equalizer
Most Android devices ship with a simple system equalizer built into the operating system. It usually comes with:
- Five frequency bands (Bass → Low Mid → Mid → High Mid → Treble).
- Presets like “Rock,” “Jazz,” “Pop,” or “Classical” for quick adjustments.
- A Bass Boost slider for extra low-end power.
- A Virtualizer to add a sense of 3D space.
The exact look and features can vary depending on your phone brand (Samsung, Xiaomi, OnePlus, etc.), but the core idea remains the same.
How to Access It
Here’s a common way to open the equalizer on Android:
- Play a song in your favorite music player (Spotify, YouTube Music, local MP3 player).
- Open the Now Playing screen and look for the sound settings icon or the equalizer option in the app’s settings.
- If the app supports it, it will open Android’s default equalizer panel.
- Adjust the sliders or choose a preset to hear instant changes.
👉 Note: Some apps (like Spotify) include their own equalizer, but they often link to the Android system EQ underneath.
Tips for Beginners
Start with Presets
If you’re new, try presets like “Rock” or “Pop.” They give a quick taste of how EQ changes the sound.
Small Moves, Big Difference
Move sliders gently. A little boost (+2 or +3 dB) can make music more enjoyable without distorting it.
Balance Over Boosting
Instead of pushing frequencies too high, try lowering others to create space. This avoids making the sound harsh.
Tailor to Your Environment
- In a noisy bus? Boost mids and treble for clearer vocals.
- At home with good speakers? Add bass for warmth.
Limitations of the Inbuilt Equalizer + Sliders
- It usually works only with media playback, not phone calls.
- Some apps may bypass the equalizer completely.
- Sound quality improvements are noticeable, but not as detailed as professional EQ apps or hardware.
Still, for most users, the inbuilt EQ is more than enough to make music sound personalized and fun.
Why Use It?
Because music is personal. The same song can sound too heavy, too thin, or just right depending on your taste, headphones, or speakers. The equalizer gives you the freedom to sculpt the sound so it matches your style.
🎛️ Equalizer UI with Sliders + Presets
This example shows:
- Five frequency sliders (Bass → Treble).
- Preset buttons styled like modern chips.
- A clean card layout with rounded corners, shadows, and spacing.
@Composable
fun EqualizerScreen() {
val frequencyLabels = listOf("60Hz", "230Hz", "910Hz", "3.6kHz", "14kHz")
val sliderValues = remember { mutableStateListOf(0f, 0f, 0f, 0f, 0f) }
val presets = listOf("Normal", "Rock", "Pop", "Jazz", "Classical")
var selectedPreset by remember { mutableStateOf("Normal") }
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
// Preset Section
Text("Presets", style = MaterialTheme.typography.titleMedium)
Spacer(Modifier.height(8.dp))
FlowRow(
mainAxisSpacing = 8.dp,
crossAxisSpacing = 8.dp
) {
presets.forEach { preset ->
FilterChip(
selected = preset == selectedPreset,
onClick = { selectedPreset = preset },
label = { Text(preset) }
)
}
}
Spacer(Modifier.height(24.dp))
// Sliders Section
Text("Custom Equalizer", style = MaterialTheme.typography.titleMedium)
Spacer(Modifier.height(12.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
frequencyLabels.forEachIndexed { index, label ->
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.weight(1f)
) {
// Vertical Slider
Slider(
value = sliderValues[index],
onValueChange = { sliderValues[index] = it },
valueRange = -10f..10f,
modifier = Modifier
.height(200.dp)
.rotate(-90f) // make vertical
)
Spacer(Modifier.height(8.dp))
Text(label, style = MaterialTheme.typography.labelSmall)
}
}
}
Spacer(Modifier.height(16.dp))
// Reset Button
Button(
onClick = {
sliderValues.indices.forEach { sliderValues[it] = 0f }
selectedPreset = "Normal"
},
modifier = Modifier.align(Alignment.CenterHorizontally),
shape = RoundedCornerShape(50)
) {
Text("Reset")
}
}
}
✨ Features of this UI
- Presets as Chips → quick, modern, and tappable.
- Vertical Sliders → more natural for equalizer controls.
- Rounded card style + shadows (can be wrapped in Card { . }).
- Reset button to bring everything back to normal.
🔹 EqualizerPlayerScreen
@Composable
fun EqualizerPlayerScreen() {
👉 Declares a Composable function. This will show the entire Equalizer screen UI.
val context = LocalContext.current
👉 Gets the current Android Context (needed to access assets, MediaPlayer, etc.).
var mediaPlayer by remember { mutableStateOf(null) }
var equalizer by remember { mutableStateOf(null) }
👉 Two states:
- mediaPlayer → Plays audio
- equalizer → Controls sound bands/presets.
var isPlaying by remember { mutableStateOf(false) }
var presetNames by remember { mutableStateOf(listOf()) }
var selectedPreset by remember { mutableIntStateOf(-1) }
var bandStates by remember { mutableStateOf(listOf>()) }
👉 UI states:- isPlaying → true if music is playing.
- presetNames → list of Equalizer preset names (e.g., "Rock", "Jazz").
- selectedPreset → index of current preset.
- bandStates → list of (centerFrequency, normalizedLevel) for each EQ band.
🎵 Setup when screen opens
LaunchedEffect(Unit) {
👉 Runs once when Composable first appears.
try {
val mp = MediaPlayer()
👉 Create a new MediaPlayer.
val afd = context.assets.openFd("sample.mp3")
mp.setDataSource(afd.fileDescriptor, afd.startOffset, afd.length)
afd.close()
👉 Load sample.mp3 from assets and set it as the MediaPlayer source.
mp.isLooping = true
mp.prepare()
mediaPlayer = mp
👉 Loop song forever, prepare it, and store in mediaPlayer.
val eq = Equalizer(0, mp.audioSessionId)
eq.enabled = true
equalizer = eq
👉 Create Equalizer linked to MediaPlayer’s session.
Enable it and save in state. val names = mutableListOf()
for (i in 0 until eq.numberOfPresets) names += eq.getPresetName(i.toShort())
presetNames = names
if (names.isNotEmpty()) selectedPreset = 0
👉 Get all preset names from Equalizer (Rock, Pop, etc.)
Store in presetNames. If list not empty → select first preset.
val range = eq.bandLevelRange
val min = range[0].toInt()
val max = range[1].toInt()
👉 Each EQ band has min & max level in millibels (mB). We need them to normalize values to 0–1 for sliders.
val bands = (0 until eq.numberOfBands).map { b ->
val center = eq.getCenterFreq(b.toShort()).toInt()
val level = eq.getBandLevel(b.toShort()).toInt()
val normalized = (level - min).toFloat() / (max - min).toFloat()
center to normalized
}
bandStates = bands
👉 For each EQ band: - Get center frequency (e.g., 60 Hz, 1kHz).
- Get current level.
- Normalize between 0–1 for slider UI.
- Store (frequency, normalizedLevel) in bandStates.
} catch (e: Exception) {
Log.e("EQ", "Init failed: ${e.message}")
}
}
👉 Catch any errors during setup (like file not found).🔹 Release resources
DisposableEffect(Unit) {
onDispose {
equalizer?.release()
mediaPlayer?.release()
}
}
👉 When Composable leaves screen → release MediaPlayer & Equalizer to free memory.
UI Layout
Column(
Modifier
.fillMaxSize()
.padding(20.dp)
.verticalScroll(rememberScrollState())
) {
👉 Whole screen is a scrollable Column with padding.Header
Text(
"🎵 Equalizer Player",
fontSize = 26.sp,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.primary
)
👉 Title at top.Player Controls
Card(
Modifier
.fillMaxWidth()
.padding(bottom = 16.dp),
shape = RoundedCornerShape(24.dp),
elevation = CardDefaults.cardElevation(8.dp),
colors = CardDefaults.cardColors(MaterialTheme.colorScheme.surfaceVariant)
) {
👉 Music control section inside a card with rounded corners. IconButton(
onClick = {
mediaPlayer?.let {
if (isPlaying) {
it.pause(); isPlaying = false
} else {
it.start(); isPlaying = true
}
}
},
👉 Play/Pause button toggles MediaPlayer. Updates isPlaying.
Icon(painter = painterResource(if (isPlaying)R.drawable.pause else R.drawable.play),
contentDescription = "Play/Pause", tint = MaterialTheme.colorScheme.onPrimaryContainer,
modifier = Modifier.size(50.dp))
👉 Shows Pause icon if playing, else Play icon.Presets
LazyColumn {
items(presetNames.chunked(3)) { rowItems ->
👉 List of presets, shown in rows of 3 chips. AssistChip(
onClick = {
equalizer?.usePreset(index.toShort())
selectedPreset = index
👉 When chip clicked → Apply preset to Equalizer. Update selectedPreset.
bandStates = (0 until eq.numberOfBands).map { b -> ... }
👉 Refresh band sliders to show preset’s band levels.Bands
Row(
Modifier
.fillMaxWidth()
.height(220.dp),
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.Bottom
) {
👉 Show bands in a Row (side-by-side vertical sliders).
EqualizerBar(
value = normalized,
onValueChange = { newValue ->
bandStates = bandStates.toMutableList().also { list ->
list[index] = center to newValue
}
equalizer?.let { eq ->
val range = eq.bandLevelRange
val min = range[0].toInt()
val max = range[1].toInt()
val level = (min + (max - min) * newValue).toInt().toShort()
eq.setBandLevel(index.toShort(), level)
}
},
👉 Custom slider EqualizerBar:UI value updated in bandStates.
Equalizer band updated with new level (converted back from 0–1 scale → real mB value).
Text(
"${center / 1000} Hz",
fontSize = 12.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
👉 Show frequency label (e.g., "60 Hz").🔹 EqualizerBar (Custom Vertical Slider)
@Composable
fun EqualizerBar(
value: Float, // 0f → min, 1f → max
onValueChange: (Float) -> Unit,
modifier: Modifier = Modifier,
color: Color = MaterialTheme.colorScheme.primary
) {
👉 A custom bar representing one EQ band.
var dragPosition by remember { mutableStateOf(value) }
👉 Current slider value, stored in state.
Box(
modifier
.pointerInput(Unit) {
detectVerticalDragGestures { change, dragAmount ->
change.consume()
dragPosition = (dragPosition - dragAmount / size.height)
.coerceIn(0f, 1f) // clamp 0–1
onValueChange(dragPosition)
}
}
) {
👉 Detect vertical drag. - When dragged → adjust dragPosition.
- Clamp between 0f and 1f.
- Send updated value back to parent.
Canvas(modifier = Modifier.fillMaxSize()) {
// background track
drawRoundRect(
color = Color.Gray.copy(alpha = 0.3f),
cornerRadius = CornerRadius(12f, 12f)
)
👉 Draw background rectangle (slider track).
val filledHeight = size.height * dragPosition
drawRoundRect(
color = color,
topLeft = Offset(0f, size.height - filledHeight),
size = Size(size.width, filledHeight),
cornerRadius = CornerRadius(12f, 12f)
)
}
}
}
👉 Draw filled rectangle (active level).
It grows upwards as dragPosition increases.
@Composable
fun EqualizerPlayerScreen() {
val context = LocalContext.current
var mediaPlayer by remember { mutableStateOf(null) }
var equalizer by remember { mutableStateOf(null) }
var isPlaying by remember { mutableStateOf(false) }
var presetNames by remember { mutableStateOf(listOf()) }
var selectedPreset by remember { mutableIntStateOf(-1) }
var bandStates by remember { mutableStateOf(listOf>()) } // (centerFreq, normalized)
// setup
LaunchedEffect(Unit) {
try {
val mp = MediaPlayer()
val afd = context.assets.openFd("sample.mp3")
mp.setDataSource(afd.fileDescriptor, afd.startOffset, afd.length)
afd.close()
mp.isLooping = true
mp.prepare()
mediaPlayer = mp
val eq = Equalizer(0, mp.audioSessionId)
eq.enabled = true
equalizer = eq
// presets
val names = mutableListOf()
for (i in 0 until eq.numberOfPresets) names += eq.getPresetName(i.toShort())
presetNames = names
if (names.isNotEmpty()) selectedPreset = 0
// bands
val range = eq.bandLevelRange
val min = range[0].toInt()
val max = range[1].toInt()
val bands = (0 until eq.numberOfBands).map { b ->
val center = eq.getCenterFreq(b.toShort()).toInt()
val level = eq.getBandLevel(b.toShort()).toInt()
val normalized = (level - min).toFloat() / (max - min).toFloat()
center to normalized
}
bandStates = bands
} catch (e: Exception) {
Log.e("EQ", "Init failed: ${e.message}")
}
}
DisposableEffect(Unit) {
onDispose {
equalizer?.release()
mediaPlayer?.release()
}
}
Column(
Modifier
.fillMaxSize()
.padding(20.dp)
.systemBarsPadding()
.verticalScroll(rememberScrollState())
) {
// Header
Text(
"🎵 Equalizer Player",
fontSize = 26.sp,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.primary
)
Spacer(Modifier.height(12.dp))
// Player Controls
Card(
Modifier
.fillMaxWidth()
.padding(bottom = 16.dp),
shape = RoundedCornerShape(24.dp),
elevation = CardDefaults.cardElevation(8.dp),
colors = CardDefaults.cardColors(MaterialTheme.colorScheme.surfaceVariant)
) {
Row(
Modifier.fillMaxWidth().padding(16.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(32.dp)
) {
IconButton(
onClick = {
mediaPlayer?.let {
if (isPlaying) {
it.pause(); isPlaying = false
} else {
it.start(); isPlaying = true
}
}
},
modifier = Modifier
.size(60.dp)
.background(
MaterialTheme.colorScheme.primaryContainer,
CircleShape
)
) {
Icon(
painter = painterResource(if (isPlaying) R.drawable.pause else R.drawable.play),
contentDescription = "Play/Pause",
tint = MaterialTheme.colorScheme.onPrimaryContainer,
modifier = Modifier.size(50.dp),
)
}
Text(
if (isPlaying) "Now Playing..." else "Paused",
fontSize = 16.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
// Presets
Text("🎚 Presets", fontSize = 18.sp, fontWeight = FontWeight.Medium)
LazyVerticalGrid(
columns = GridCells.Adaptive(minSize = 90.dp),
modifier = Modifier
.fillMaxWidth()
.height(280.dp)
) {
items(presetNames.size) { i ->
TextButton(
onClick = {
equalizer?.usePreset(i.toShort())
selectedPreset = i
equalizer?.let { eq ->
val range = eq.bandLevelRange
val min = range[0].toInt()
val max = range[1].toInt()
bandStates = (0 until eq.numberOfBands).map { b ->
val center = eq.getCenterFreq(b.toShort()).toInt()
val level = eq.getBandLevel(b.toShort()).toInt()
val normalized =
(level - min).toFloat() / (max - min).toFloat()
center to normalized
}
}
},
modifier = Modifier
.padding(8.dp)
.clip(RoundedCornerShape(12.dp))
.background(
if (i == selectedPreset)
MaterialTheme.colorScheme.primaryContainer
else
MaterialTheme.colorScheme.surfaceVariant
)
) {
Text(
presetNames[i],
fontSize = 14.sp,
color = if (i == selectedPreset)
MaterialTheme.colorScheme.onPrimaryContainer
else
MaterialTheme.colorScheme.onSurface
)
}
}
}
// Bands
Text("🎼 Bands", fontSize = 18.sp, fontWeight = FontWeight.Medium)
Spacer(Modifier.height(8.dp))
Row(
Modifier
.fillMaxWidth()
.height(200.dp),
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.Bottom
) {
bandStates.forEachIndexed { index, (center, normalized) ->
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Bottom
) {
Text(
"${center / 1000} Hz",
fontSize = 12.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
EqualizerBar(
value = normalized,
onValueChange = { newValue ->
bandStates = bandStates.toMutableList().also { list ->
list[index] = center to newValue
}
equalizer?.let { eq ->
val range = eq.bandLevelRange
val min = range[0].toInt()
val max = range[1].toInt()
val level = (min + (max - min) * newValue).toInt().toShort()
eq.setBandLevel(index.toShort(), level)
}
},
modifier = Modifier
.width(20.dp)
.fillMaxHeight()
)
}
}
}
}
}
@Composable
fun EqualizerBar(
value: Float, // 0f → min, 1f → max
onValueChange: (Float) -> Unit,
modifier: Modifier = Modifier,
color: Color = MaterialTheme.colorScheme.primary
) {
var targetValue by remember { mutableFloatStateOf(value) }
// Whenever parent updates (preset change), update target
LaunchedEffect(value) {
targetValue = value
}
// Always animate towards targetValue (drag OR preset)
val animatedValue by animateFloatAsState(
targetValue = targetValue,
animationSpec = tween(durationMillis = 200, easing = LinearEasing) // fast & smooth for drag
)
Box(
modifier
.pointerInput(Unit) {
detectVerticalDragGestures { change, dragAmount ->
change.consume()
val newValue = (targetValue - dragAmount / size.height)
.coerceIn(0f, 1f)
targetValue = newValue
onValueChange(newValue)
}
}
) {
Canvas(modifier = Modifier.fillMaxSize()) {
// background track
drawRoundRect(
color = Color.Gray.copy(alpha = 0.3f),
cornerRadius = CornerRadius(12f, 12f)
)
// active level
val filledHeight = size.height * animatedValue
drawRoundRect(
color = color,
topLeft = Offset(0f, size.height - filledHeight),
size = Size(size.width, filledHeight),
cornerRadius = CornerRadius(12f, 12f)
)
}
}
}
OUTPUT:
Our Thoughts
Android’s inbuilt equalizer is like a secret sound control panel hiding in your phone. It’s simple, free, and surprisingly powerful once you know how to use it. Experiment with presets, play with sliders, and trust your ears. You might rediscover your favorite songs in a brand-new way.