I need to make an audio system for my go-kart with an esp32
I got the Bluetooth part sorted out, but the EQ, Menu, and Rotary Encoder are not done yet.
I'm working on the rotary encoder first since it's not as hard as the other two I have to work on.
I tried making code for controlling the volume of the kit but it isn't super responsive.
I need help making it more responsive since it is too slow
Here's the code:
#include <Pushbutton.h>
#include <RotaryEncoder.h>
#define USE_A2DP
#include "AudioTools.h"
#include "AudioLibs/AudioKit.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
BluetoothA2DPSink a2dp_sink;
AudioKitStream kit;
String songName;
String songArtist;
//Millis
unsigned long currentMillis;
unsigned long previousMillis = 0;
unsigned long previousMillis1 = 0;
//rotary encoder
RotaryEncoder encoder(18, 23, RotaryEncoder::LatchMode::FOUR3);
#define ROTARYSTEPS 5
#define ROTARYMIN 0
#define ROTARYMAX 100
int lastPos = -1;
bool usingApsoluteVolume = false;
Pushbutton rnButton(5);
//lcd
LiquidCrystal_I2C lcd(0x27, 16, 2);
byte zero[] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000
};
byte one[] = {
B10000,
B10000,
B10000,
B10000,
B10000,
B10000,
B10000,
B10000
};
byte two[] = {
B11000,
B11000,
B11000,
B11000,
B11000,
B11000,
B11000,
B11000
};
byte three[] = {
B11100,
B11100,
B11100,
B11100,
B11100,
B11100,
B11100,
B11100
};
byte four[] = {
B11110,
B11110,
B11110,
B11110,
B11110,
B11110,
B11110,
B11110
};
byte five[] = {
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111
};
bool volumeOnScreen = false;
bool backlight = true;
// Connected States
bool connectedState;
bool lastConnectedState;
//volume
int volume;
//Menus
/*Main Menu*/
bool mainMenuShown = false;
int mainMenuSelected = 0;
// Write data to AudioKit in callback
void read_data_stream(const uint8_t *data, uint32_t length) {
kit.write(data, length);
}
void avrc_metadata_callback(uint8_t id, const uint8_t *text) {
//Serial.printf(">id 0x%x, %s\n", id, text);
switch (id) {
case 0x1:
songName = (char *)text;
break;
case 0x2:
songArtist = (char *)text;
break;
}
if (!mainMenuShown) {
lcd.clear();
lcd.home();
lcd.print(songName);
lcd.setCursor(0, 1);
lcd.print(songArtist);
}
}
void startDisplay() {
lcd.init(21, 22);
lcd.backlight();
lcd.createChar(0, zero);
lcd.createChar(1, one);
lcd.createChar(2, two);
lcd.createChar(3, three);
lcd.createChar(4, four);
lcd.createChar(5, five);
}
void updateProgressBar(unsigned long count, unsigned long totalCount, int lineToPrintOn)
{
double factor = totalCount / 80.0;
int percent = (count + 1) / factor;
int number = percent / 5;
int remainder = percent % 5;
if (number > 0)
{
for (int j = 0; j < number; j++)
{
lcd.setCursor(j, lineToPrintOn);
lcd.write(5);
}
}
lcd.setCursor(number, lineToPrintOn);
lcd.write(remainder);
if (number < 16)
{
for (int j = number + 1; j <= 16; j++)
{
lcd.setCursor(j, lineToPrintOn);
lcd.write(0);
}
}
}
void setup() {
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Warning);
// setup output
auto cfg = kit.defaultConfig(TX_MODE);
cfg.bits_per_sample = AUDIO_HAL_BIT_LENGTH_32BITS;
cfg.sample_rate = AUDIO_HAL_44K_SAMPLES;
kit.begin(cfg);
kit.setVolume(0);
startDisplay();
// register callback
a2dp_sink.set_stream_reader(read_data_stream, false);
a2dp_sink.set_avrc_metadata_attribute_mask(ESP_AVRC_MD_ATTR_TITLE | ESP_AVRC_MD_ATTR_ARTIST);
a2dp_sink.set_avrc_metadata_callback(avrc_metadata_callback);
a2dp_sink.set_bits_per_sample(32);
a2dp_sink.start("TrixoleKart Go-Kart");
a2dp_sink.set_auto_reconnect(true, false, 1000);
}
void volumeChange(int c_volume) {
previousMillis = currentMillis;
if (usingApsoluteVolume) {
volume = map(c_volume, 0, 127, 0, 100);
} else {
volume = c_volume;
}
char buffer[40];
sprintf(buffer, ">volume: %d", volume);
//Serial.println(buffer);
lcd.setCursor(0, 0);
lcd.print(" Volume ");
updateProgressBar(volume, 100, 1);
volumeOnScreen = true;
}
void loop() {
currentMillis = millis();
kit.processActions();
clearAndReturn(2);
SendToMega();
ReceiveFromMega();
rotaryEncoderVolume();
mainMenu();
//connect states
vTaskDelay(5);
connectedState = a2dp_sink.is_connected();
if (connectedState == true && lastConnectedState != true) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Connected to:");
lcd.setCursor(0, 1);
lcd.print(a2dp_sink.get_connected_source_name());
Serial.println(">Bluetooth: Connected to ");
Serial.print(a2dp_sink.get_connected_source_name());
delay(1000);
a2dp_sink.set_volume(127);
lastConnectedState = connectedState;
}
if (connectedState == false && lastConnectedState != false) {
lcd.clear();
lcd.setCursor(2, 0);
lcd.print("Disconnected");
Serial.println(">Bluetooth: Disconnected");
songName = "";
songArtist = "";
delay(1000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("No Device");
lcd.setCursor(0, 1);
lcd.print("Connected!");
lastConnectedState = connectedState;
}
}
void clearAndReturn(int interval) {
if (volumeOnScreen == true) {
if (currentMillis - previousMillis >= interval * 1000) {
previousMillis = currentMillis;
lcd.clear();
lcd.home();
lcd.print(songName);
lcd.setCursor(0, 1);
lcd.print(songArtist);
volumeOnScreen = false;
}
}
}
void SendToMega() {
if (currentMillis - previousMillis1 >= 500) {
previousMillis1 = currentMillis;
String data = songName + "," + songArtist + "," + String(a2dp_sink.get_connected_source_name()) + ", ";
Serial.print(data);
}
}
void ReceiveFromMega() {
char iC = Serial.read();
switch (iC) {
case 'D':
backlight = !backlight;
if (backlight) {
lcd.backlight();
} else {
lcd.noBacklight();
}
break;
case 'N':
a2dp_sink.next();
break;
case 'P':
a2dp_sink.previous();
break;
}
}
void rotaryEncoderVolume() {
if (usingApsoluteVolume)
{
switch (encoder.getDirection()) {
case RotaryEncoder::Direction::CLOCKWISE:
if (a2dp_sink.get_volume() < 127) {
a2dp_sink.set_volume(a2dp_sink.get_volume() + 1);
volumeChange(kit.volume());
}
break;
case RotaryEncoder::Direction::COUNTERCLOCKWISE:
if (a2dp_sink.get_volume() > 0) {
a2dp_sink.set_volume(a2dp_sink.get_volume() - 1);
volumeChange(kit.volume());
}
break;
}
} else {
encoder.tick();
switch (encoder.getDirection()) {
case RotaryEncoder::Direction::CLOCKWISE:
if (kit.volume() < 100) {
int Volume = kit.volume() + ROTARYSTEPS + 2;
kit.setVolume(Volume);
volumeChange(kit.volume());
}
break;
case RotaryEncoder::Direction::COUNTERCLOCKWISE:
if (kit.volume() > 0) {
int Volume = kit.volume() - ROTARYSTEPS;
kit.setVolume(Volume);
volumeChange(kit.volume());
}
break;
}
if (kit.volume() > 100) {
kit.setVolume(100);
}
if (kit.volume() < 0) {
kit.setVolume(0);
}
if (a2dp_sink.get_volume() > 127) {
a2dp_sink.set_volume(127);
}
if (a2dp_sink.get_volume() < 0) {
a2dp_sink.set_volume(0);
}
}
}
void mainMenu() {
if (rnButton.getSingleDebouncedPress() && !mainMenuShown) {
mainMenuShown = true;
mainMenuSelected = 0;
}
if (mainMenuShown) {
encoder.tick();
int newPos = encoder.getPosition();
if (newPos < 0) {
encoder.setPosition(0);
newPos = 0;
} else if (newPos > 5) {
encoder.setPosition(5);
newPos = 5;
}
if (lastPos != newPos) {
mainMenuSelected = newPos;
lcd.clear();
switch (mainMenuSelected) {
case 0:
lcd.setCursor(0, 0);
lcd.print("~");
lcd.setCursor(1, 0);
lcd.print("Play");
lcd.setCursor(1, 1);
lcd.print("Pause");
break;
case 1:
lcd.setCursor(0, 0);
lcd.print("~");
lcd.setCursor(1, 0);
lcd.print("Pause");
lcd.setCursor(1, 1);
lcd.print("Next");
break;
case 2:
lcd.setCursor(0, 0);
lcd.print("~");
lcd.setCursor(1, 0);
lcd.print("Next");
lcd.setCursor(1, 1);
lcd.print("Previous");
break;
case 3:
lcd.setCursor(0, 0);
lcd.print("~");
lcd.setCursor(1, 0);
lcd.print("Previous");
lcd.setCursor(1, 1);
lcd.print("Settings");
break;
case 4:
lcd.setCursor(0, 0);
lcd.print("~");
lcd.setCursor(1, 0);
lcd.print("Settings (N/A)");
lcd.setCursor(1, 1);
lcd.print("Back");
break;
case 5:
lcd.setCursor(0, 0);
lcd.print("~");
lcd.setCursor(1, 0);
lcd.print("Back");
break;
default:
mainMenuSelected = 0;
break;
}
lastPos = newPos;
}
if (rnButton.getSingleDebouncedPress()) {
switch (mainMenuSelected) {
case 0:
a2dp_sink.play();
mainMenuShown = false;
break;
case 1:
a2dp_sink.pause();
mainMenuShown = false;
break;
case 2:
a2dp_sink.next();
mainMenuShown = false;
break;
case 3:
a2dp_sink.previous();
mainMenuShown = false;
break;
case 4:
break;
case 5:
mainMenuShown = false;
lcd.clear();
lcd.home();
lcd.print(songName);
lcd.setCursor(0, 1);
lcd.print(songArtist);
break;
}
}
}
}
Here are some pictures if you need them: