mirror of
https://github.com/Xinyuan-LilyGO/TTGO_TWatch_Library.git
synced 2026-03-03 14:54:08 +01:00
265 lines
6.8 KiB
C++
265 lines
6.8 KiB
C++
#pragma mark - Depend ESP8266Audio and ESP8266_Spiram libraries
|
|
/*
|
|
cd ~/Arduino/libraries
|
|
git clone https://github.com/earlephilhower/ESP8266Audio
|
|
git clone https://github.com/Gianbacchio/ESP8266_Spiram
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include <WiFi.h>
|
|
#include <HTTPClient.h> //Remove Audio Lib error
|
|
#include "AudioFileSourceSD.h"
|
|
#include "AudioFileSourceID3.h"
|
|
#include "AudioGeneratorMP3.h"
|
|
#include "AudioOutputI2S.h"
|
|
#include <Esp.h>
|
|
|
|
Ticker tk;
|
|
TTGOClass *ttgo;
|
|
AudioGeneratorMP3 *mp3;
|
|
AudioFileSourceSD *file;
|
|
AudioOutputI2S *out;
|
|
AudioFileSourceID3 *id3;
|
|
|
|
static lv_obj_t *list_cont;
|
|
static lv_obj_t *play_cont;
|
|
static lv_obj_t *curr_list;
|
|
static lv_obj_t *label;
|
|
static lv_obj_t *scr;
|
|
static lv_obj_t *list;
|
|
static lv_obj_t *img_btn[3];
|
|
static lv_obj_t *button[3];
|
|
static const void *src_img_btn[4] = {LV_SYMBOL_PREV, LV_SYMBOL_PAUSE, LV_SYMBOL_NEXT, LV_SYMBOL_PLAY};
|
|
static void list_event_handler(lv_obj_t *obj, lv_event_t event);
|
|
static char filename[128];
|
|
uint8_t state = 255;
|
|
LV_IMG_DECLARE(bg1);
|
|
|
|
enum {
|
|
PLAY,
|
|
PAUSE,
|
|
NEXT,
|
|
PREV,
|
|
};
|
|
|
|
void create_gui();
|
|
|
|
void pressed()
|
|
{
|
|
ESP.restart();
|
|
}
|
|
|
|
static void list_event_handler(lv_obj_t *obj, lv_event_t event)
|
|
{
|
|
if (event == LV_EVENT_CLICKED) {
|
|
curr_list = obj;
|
|
const char *txt = lv_list_get_btn_text(obj);
|
|
Serial.printf("Clicked %s\n", txt);
|
|
state = PLAY;
|
|
strcpy(filename, txt);
|
|
create_gui();
|
|
file->open(txt);
|
|
mp3->begin(id3, out);
|
|
}
|
|
}
|
|
|
|
static void event_handler(lv_obj_t *obj, lv_event_t event)
|
|
{
|
|
if (event == LV_EVENT_CLICKED) {
|
|
if (button[0] == obj) {
|
|
if (state != PLAY)return;
|
|
lv_obj_t *prev_btn = lv_list_get_prev_btn(list, curr_list);
|
|
if (prev_btn == NULL) {
|
|
Serial.println("prev is null");
|
|
return;
|
|
}
|
|
curr_list = prev_btn;
|
|
const char *txt = lv_list_get_btn_text(prev_btn);
|
|
lv_label_set_text(label, txt);
|
|
out->stop();
|
|
if (mp3->isRunning())
|
|
mp3->stop();
|
|
file->open(txt);
|
|
mp3->begin(id3, out);
|
|
|
|
|
|
} else if (button[1] == obj) {
|
|
if (state == PAUSE) {
|
|
state = PLAY;
|
|
lv_img_set_src(img_btn[1], LV_SYMBOL_PAUSE);
|
|
out->begin();
|
|
} else {
|
|
state = PAUSE;
|
|
out->stop();
|
|
lv_img_set_src(img_btn[1], LV_SYMBOL_PLAY);
|
|
}
|
|
} else if (button[2] == obj) {
|
|
if (state != PLAY)return;
|
|
lv_obj_t *next_btn = lv_list_get_next_btn(list, curr_list);
|
|
if (next_btn == NULL) {
|
|
Serial.println("next is null");
|
|
return;
|
|
}
|
|
curr_list = next_btn;
|
|
const char *txt = lv_list_get_btn_text(next_btn);
|
|
lv_label_set_text(label, txt);
|
|
out->stop();
|
|
if (mp3->isRunning())
|
|
mp3->stop();
|
|
file->open(txt);
|
|
mp3->begin(id3, out);
|
|
}
|
|
}
|
|
}
|
|
|
|
void create_gui()
|
|
{
|
|
lv_obj_set_hidden(list_cont, true);
|
|
|
|
play_cont = lv_cont_create(scr, NULL);
|
|
lv_obj_set_size(play_cont, 240, 240);
|
|
|
|
lv_obj_t *img = lv_img_create(play_cont, NULL);
|
|
lv_img_set_src(img, &bg1);
|
|
lv_obj_align(img, NULL, LV_ALIGN_CENTER, 0, 0);
|
|
|
|
label = lv_label_create(play_cont, NULL);
|
|
lv_label_set_text(label, filename);
|
|
lv_label_set_long_mode(label, LV_LABEL_LONG_SROLL);
|
|
lv_obj_set_width(label, 80);
|
|
lv_obj_align(label, play_cont, LV_ALIGN_IN_TOP_MID, 0, 50);
|
|
|
|
for (uint8_t i = 0; i < 3; i++) {
|
|
button[i] = lv_btn_create(play_cont, NULL);
|
|
lv_obj_set_size(button[i], 50, 50);
|
|
img_btn[i] = lv_img_create(button[i], NULL);
|
|
lv_img_set_src(img_btn[i], src_img_btn[i]);
|
|
lv_obj_set_event_cb(button[i], event_handler);
|
|
}
|
|
|
|
lv_obj_align(button[0], NULL, LV_ALIGN_IN_LEFT_MID, 40, 40);
|
|
|
|
for (uint8_t i = 1; i < 3; i++) {
|
|
lv_obj_align(button[i], button[i - 1], LV_ALIGN_OUT_RIGHT_MID, 10, 0);
|
|
}
|
|
|
|
}
|
|
|
|
int searchMusic(fs::FS &fs, const char *dirname, uint8_t levels)
|
|
{
|
|
int searchFiles = 0;
|
|
File root = fs.open(dirname);
|
|
if (!root) {
|
|
Serial.println("- failed to open directory");
|
|
return 0;
|
|
}
|
|
if (!root.isDirectory()) {
|
|
Serial.println(" - not a directory");
|
|
return 0;
|
|
}
|
|
File file = root.openNextFile();
|
|
while (file) {
|
|
if (!file.isDirectory()) {
|
|
String name = String(file.name());
|
|
if (name.endsWith(".mp3") || name.endsWith(".MP3")) {
|
|
if (searchFiles++ > 50)return searchFiles;
|
|
lv_obj_t *list_btn = lv_list_add_btn(list, LV_SYMBOL_FILE, file.name());
|
|
lv_obj_set_event_cb(list_btn, list_event_handler);
|
|
}
|
|
}
|
|
file = root.openNextFile();
|
|
}
|
|
return searchFiles;
|
|
}
|
|
|
|
|
|
|
|
void setup()
|
|
{
|
|
WiFi.mode(WIFI_OFF);
|
|
delay(500);
|
|
|
|
Serial.begin(115200);
|
|
ttgo = TTGOClass::getWatch();
|
|
ttgo->begin();
|
|
ttgo->openBL();
|
|
ttgo->tft->fillScreen(TFT_BLACK);
|
|
ttgo->tft->setTextFont(2);
|
|
|
|
ttgo->tft->setCursor(0, 0);
|
|
ttgo->tft->fillScreen(TFT_BLACK);
|
|
ttgo->tft->println("Sample MP3 playback begins");
|
|
|
|
ttgo->button->setPressedHandler(pressed);
|
|
|
|
tk.attach_ms(30, []() {
|
|
ttgo->button->loop();
|
|
});
|
|
|
|
//!Turn on the audio power
|
|
ttgo->enableLDO3();
|
|
|
|
file = new AudioFileSourceSD();
|
|
id3 = new AudioFileSourceID3(file);
|
|
out = new AudioOutputI2S();
|
|
//! External DAC decoding
|
|
out->SetPinout(TWATCH_DAC_IIS_BCK, TWATCH_DAC_IIS_WS, TWATCH_DAC_IIS_DOUT);
|
|
mp3 = new AudioGeneratorMP3();
|
|
|
|
while (1) {
|
|
if (ttgo->sdcard_begin()) {
|
|
Serial.println("sd begin pass");
|
|
break;
|
|
}
|
|
Serial.println("sd begin fail,wait 1 sec");
|
|
delay(1000);
|
|
}
|
|
|
|
ttgo->lvgl_begin();
|
|
|
|
scr = lv_scr_act();
|
|
|
|
list_cont = lv_cont_create(scr, NULL);
|
|
|
|
lv_obj_set_size(list_cont, 240, 240);
|
|
|
|
list = lv_list_create(list_cont, NULL);
|
|
|
|
lv_obj_set_size(list, 240, 240);
|
|
|
|
lv_obj_align(list, list_cont, LV_ALIGN_CENTER, 0, 0);
|
|
|
|
if (searchMusic(SD, "/", 2) == 0) {
|
|
Serial.println("No Search mp3 file");
|
|
while (1) {
|
|
delay(1000);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void loop()
|
|
{
|
|
switch (state) {
|
|
case PLAY:
|
|
if (mp3->isRunning()) {
|
|
if (!mp3->loop()) {
|
|
mp3->stop();
|
|
state = 255;
|
|
}
|
|
}
|
|
break;
|
|
case PAUSE:
|
|
break;
|
|
case NEXT:
|
|
break;
|
|
case PREV:
|
|
break;
|
|
default:
|
|
delay(5);
|
|
break;
|
|
}
|
|
lv_task_handler();
|
|
}
|
|
|