How To Make EQ Android App for Your True Wireless Earbuds

You just purchased no name true wireless earbuds and their sound isn’t good. If you want to play around a bit with the sound – you can download EQ app on Android or create a EQ app yourself.

  • Creating Android App requires basic knowledge about Java and Android studio.
  • Google is in favor of Kotlin over Java for Android app
  • As attaching an Equalizer or BassBoost to the global audio output mix by use of session 0 is deprecated. That means you have to attach the affect on specific tracks – it’s more complicated if your phone plays music on Spotify, Apple Music – it’s impossible to get the ID sessions from those apps.
  • Sound effect just increases the ohm of certain ranges – it doesn’t necessarily improve the sound, such as details, separation of instruments’ sound and richness. We just adjust the sound output from the devices – your phones not earbud’s sound itself.

Setting up Bluetooth connection on the App (you can skip this step since you can do pairing on Bluetooth setting).

Personally I think iOS does a better job for Bluetooth and Android needs to do a lot more.

Step 1

On Android Studio – Create a new project with Navigation Drawer Activity.

Name your Application

In AndroidManifest.xml copy and paste this code:

<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

This will allows the app to manage the Bluetooth related matters – discovery, pairing and more.

When you turn on your earbuds for the first time – it will automatically pairs with your phones.

app > java > appName_fragment2 > Right Click to create a new blank fragment and then give it a name. Mine is BassBooster

Implements

View.OnClickListener,
CompoundButton.OnCheckedChangeListener,
SeekBar.OnSeekBarChangeListener

in BassBooster.java the fragment you just created for interactions with button, seekbar.

Go to res > layout > fragment_bass_booster.xml (this is user interface that Android Studio automatically creates when we create a new fragment) add the following:

<RelativeLayout
        android:id="@+id/relativeLayout1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1">

        <Switch
            android:id="@+id/switch"
            android:layout_width="79dp"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_alignParentLeft="true" />

        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginRight="@dimen/default_gap"
            android:layout_marginTop="@dimen/default_gap"
            android:text="FLAT"
            android:layout_alignParentRight="true"
            android:layout_marginEnd="@dimen/default_gap" />

    </RelativeLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="501dp"
        android:layout_weight="1"
        android:orientation="vertical">

        <SeekBar
            android:id="@+id/seekBar1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <SeekBar
            android:id="@+id/seekBar2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <SeekBar
            android:id="@+id/seekBar3"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <SeekBar
            android:id="@+id/seekBar4"
            android:layout_width="match_parent"
            android:layout_height="18dp" />

        <SeekBar
            android:id="@+id/seekBar5"
            android:layout_width="match_parent"
            android:layout_height="18dp" />

        <SeekBar
            android:id="@+id/seekBar6"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <SeekBar
            android:id="@+id/seekBar7"
            android:layout_width="match_parent"
            android:layout_height="12dp" />

        <SeekBar
            android:id="@+id/seekBar8"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom = "true"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btnConStatus"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="@color/design_default_color_primary"
            android:text=""
            app:layout_constraintBottom_toBottomOf="parent" />
    </LinearLayout>

</LinearLayout>

Then go back to BassBooster.java

// Equalizer interface
Switch mSwitch;
Equalizer mEqualizer;
TextView bassLevel;
static final int MAX_SLIDERS = 8;
SeekBar mSlider[] = new SeekBar[MAX_SLIDERS];
int num_sliders = 0;

int min_level = 0;
int max_level = 100;

Button mFlat;
Button btnSimpleSnackbar;

We need to track buttons, seekBar in fragment_bass_booster.xml

A button (R.id.button) to FLAT the sound effect (R.id.button)

A switch to switch on/off sound effect (R.id.switch)

Most phones will display 5 bands of different frequency ranges. Here we include the possible sliders – up to 8 sliders.

mSwitch = view.findViewById(R.id.switch);
mSwitch.setOnCheckedChangeListener(this);

mFlat = view.findViewById(R.id.button);
mFlat.setOnClickListener(this);

btnSimpleSnackbar = view.findViewById(R.id.btnConStatus);

mSlider[0] = view.findViewById(R.id.seekBar1);
mSlider[1] = view.findViewById(R.id.seekBar2);
mSlider[2] = view.findViewById(R.id.seekBar3);
mSlider[3] = view.findViewById(R.id.seekBar4);
mSlider[4] = view.findViewById(R.id.seekBar5);
mSlider[5] = view.findViewById(R.id.seekBar6);
mSlider[6] = view.findViewById(R.id.seekBar7);
mSlider[7] = view.findViewById(R.id.seekBar8);

Back to BassBooster.java, since we can’t get the sessionID, let’s set it by default – zero.

I also pre-set the first band with an increase in level of 4.

mEqualizer = new Equalizer(0, 0);
if (mEqualizer != null) {
    mEqualizer.setEnabled(true);
    int num_bands = mEqualizer.getNumberOfBands();
    num_sliders = num_bands;
    short r[] = mEqualizer.getBandLevelRange();
    min_level = r[0];
    max_level = r[1];
    mEqualizer.setBandLevel((short)4, (short)1);
    for (int i = 0; i < num_sliders && i < MAX_SLIDERS; i++)
    {
        mSlider[i].setOnSeekBarChangeListener(this);
    }

To display the bands

for (int i = num_sliders ; i < MAX_SLIDERS; i++)
{
mSlider[i].setVisibility(View.GONE);
}

We also need to update the equalizer with

UpdateUI();

That’s we’ll create

private void UpdateUI() {
    updateSliders();
    mSwitch.setChecked(mEqualizer.getEnabled());
}
private void updateSliders() {
    for (int i = 0; i < num_sliders; i++)
    {
        int level;
        if (mEqualizer != null)
            level = mEqualizer.getBandLevel ((short)i);
        else
            level = 0;
        int pos = 100 * level / (max_level - min_level) + 50;
        mSlider[i].setProgress (pos);
    }
}

And other methods (set all band to zero and switch on/off sound effect)

When users touch on FLAT button – all bands are set to Zero effect.

public void onClick(View v) {
    if (v == mFlat){
        setFlat();
    }
}
private void setFlat() {
    if (mEqualizer != null)
    {
        for (int i = 0; i < num_sliders; i++)
        {
            mEqualizer.setBandLevel ((short)i, (short)0);
        }
    }

    UpdateUI();
}

To switch on/off sound effect

public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (buttonView == mSwitch ){
mEqualizer.setEnabled (isChecked);
}

}

How to manage Bluetooth connection, pairing name of Bluetooth earbuds. We’ll create a service called BlueService.java (it’s up to you to name the service)

file > new > service > service to create BlueService.java

in public int onStartCommand(Intent intent, int flags, int startId) section, add the following, this will listen the Bluetooth connection when a device is connected and disconnected.

IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
registerReceiver(mBroadcastReceiver, filter); //unregister after use

In this service we set up a method to send Bluetooth status, device name to other activities.

private void sendMessageToActivity(String name, String blueStatus) {
    Intent intent = new Intent("bluetoothHandset");
    intent.putExtra(name, blueStatus);
    LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}

Possible scenarios

The L- earbud is primary but it runs out of battery, and you want to use the R – earbud to listen to music.

You connect your phone with with the R.

The L is charged for a while and ready to use, you switch it on and it’s also paired with your phones. Now your phone connects with both L and R earbuds, but this is when the problem arises they are not synced to each other.

You need to write a function for your app that can detect this matter and “forget” the R earbud.

If earbuds’ Bluetooth chip supports hear-through tech – the mic can pick the surrounding sound and users can hear the outside world we can build this feature in the App.

To be continued…

Please check back for update!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.