2023-6-15 16:10:32 [显示全部楼层]
46248浏览
查看: 46248|回复: 13

手搓了一个「千千静听」

[复制链接]


手搓了一个「千千静听」图1

这个项目用到了LVGL和SquareLine Studio来设计音乐播放器的界面。

先看看效果:


装机展示:




任何带有屏幕和音频输出的ESP32开发设备都可以。

以下是作者在本教程中开发用到的东西:

https://item.taobao.com/item.htm?id=694922892355

https://www.aliexpress.com/item/1005004267336768.html

https://www.makerfabs.com/esp32-s3-parallel-tft-with-touch-4-inch.html

https://www.aliexpress.com/item/1005004952726089.html

步骤1:什么是LVGL?
LVGL是一个很好的图形库,可以轻松制作漂亮的GUI界面。而SquareLine Studio可以帮助我们减少大量的编码工作。

官方解释:

LVGL (Light and Versatile Graphics Library)是一个开源的嵌入式图形库,用于创建图形用户界面 (GUI)。它被设计为尽可能轻量、灵活和可扩展,适用于各种嵌入式系统。LVGL提供了丰富的图形元素和控件,可以帮助开发者快速创建漂亮和交互性强的用户界面。它具有跨平台的特性,支持多种显示控制器和输入设备。LVGL还提供了易于使用的API和丰富的文档,使开发人员能够高效地构建和定制他们的应用程序界面。

步骤2:项目源文件
所有图像源文件、SquareLine Studio项目和源代码都可以在Github上找到:https://github.com/moononournation/LVGL_Music_Player.git

也可以在文末打包下载。

步骤3:界面设计
当前的开发设备具有不同形状的显示屏,圆形、正方形、长方形都有,所以建议最好先确定使用哪种形状。

然后下一步是确定界面的外观。

步骤4:经典音乐播放器
手搓了一个「千千静听」图2

手搓了一个「千千静听」图3

手搓了一个「千千静听」图4

如果你还没有任何界面设计的想法,那么建议可以模仿一个经典的音乐播放器。

Winamp是一个经典的Windows桌面音乐播放器,上个世纪就问世了,然后有一个名为TTPlayer的类似的界面变体,支持中文字符。这两个应用程序是我(和许多人)的童年记忆,所以我将使用这些界面作为设计模板。

Winamp设计得可以轻松更换"皮肤",皮肤图像资源以BMP格式打包在一个zip文件中。你可以在skins.webamp.org找到大量的Winamp皮肤收藏,很容易可以把你喜欢的Winamp皮肤作为设计的模板。

如何从Winamp皮肤开始设计界面,可以看这个视频:

https://www.bilibili.com/video/BV1ia4y137KM/

步骤5:功能愿望清单
音乐播放器具有各种功能,但我更感兴趣的是在Winamp或TTPlayer中发现的功能。

以下是我的功能愿望清单:
  • 支持从SD卡播放MP3
  • 支持从SD卡列出MP3文件
  • 支持显示Unicode字符
  • 支持基本播放操作(播放、暂停、停止、上一曲和下一曲)
  • 支持音量控制
  • 支持显示MP3的ID3信息
  • 支持显示MP3的封面图片
  • 支持显示MP3歌词
  • 支持播放时同步显示歌词
  • 支持显示音频频谱分析仪

步骤6:从SD卡播放MP3

首先,我们需要一个音频库,可以从SD卡读取MP3文件并将其播放出来。这次我使用的是ESP32-audioI2S。它支持ESP32系列,可以从各种来源读取音频文件并将输出播放到I2S模块。

你可以在Github上找到更多详细信息:https://github.com/schreibfaul1/ESP32-audioI2S.git

步骤7:基本播放操作
手搓了一个「千千静听」图5

ESP32-audioI2S提供了所有基本的播放API,我们只需要为每个操作创建相应的按钮部件。不过,原始的Winamp按钮设计对于用手指触摸屏幕操作来说太小了,所以我稍微放大了按钮,并用透明背景扩大了触摸区域。

对于每个按钮,将按钮部件分配相应的函数。

以播放按钮为例:
lv_obj_add_event_cb(ui_ButtonPlay, playSong, LV_EVENT_CLICKED, NULL);

然后在playSong函数中,调用ESP32-audioI2S API:
void playSong(lv_event_t *e)
{
  if (isPlaying)
  {
    audio.pauseResume();
  }
  else
  {
    play_selected_song();
  }
}

步骤8:从SD卡列出MP3文件
在告诉ESP32-audioI2S播放MP3文件之前,我们需要先从SD卡找到并列出MP3文件。

以下是read_song_list()函数的代码片段,说明了如何使用换行符(\n)拼接歌曲列表字符串:
File root = SD_MMC.open("/");
File file = root.openNextFile();
while (file)
{
  if (file.isDirectory())
  {
    Serial.printf("DIR: %s\n", file.name());
  }
  else
  {
    const char *filename = file.name();

    int8_t len = strlen(filename);
    const char *MP3_EXT = ".mp3";
    if ((filename[0] != '.') && (strcmp(MP3_EXT, &filename[len - 4]) == 0))
    {
      // Serial.printf("Song file: %s, size: %d\n", filename, file.size());
      if (song_count > 0)
      {
        stringSongList += '\n';
      }
      stringSongList += filename;
      song_count++;
    }
  }
  file = root.openNextFile();
}

然后将拼接好的歌曲列表字符串分配给LVGL的滚动组件:
lv_roller_set_options(ui_RollerPlayList, stringSongList.c_str(), LV_ROLLER_MODE_INFINITE);

步骤9:显示Unicode字符
手搓了一个「千千静听」图6

LVGL支持显示Unicode字符,但需要一个Unicode字体文件。我的歌曲列表主要是中文字符,所以我选择了3种字体来显示它:

https://github.com/ACh-K/Cubic-11.git

https://fonts.google.com/noto/specimen/Noto+Sans+HK/glyphs

https://fonts.google.com/noto/specimen/Noto+Serif+HK/glyphs

然后使用SquareLine Studio的字体工具创建C源文件。

步骤10:音量控制
手搓了一个「千千静听」图7

将音量滑块部件分配给一个值更改事件函数:
lv_obj_add_event_cb(ui_ScaleVolume, volumeChanged, LV_EVENT_VALUE_CHANGED, NULL);

然后在事件函数中调用ESP32-audioI2S API:
void volumeChanged(lv_event_t *e)
{
  int16_t volume = lv_slider_get_value(ui_ScaleVolume);
  audio.setVolume(volume);
}

时间进度UI也是一个滑块部件。但是它离按钮和音量控制UI太近了,所以我禁用了触摸输入,避免误触。

步骤11:显示MP3的ID3信息
ESP32-audioI2S公开了一个audio_id3data()回调函数。该函数会在每个MP3文件中找到一个ID3标签时调用。

在回调函数中,简单地将所有数据连接到一个字符串中:
if (playingStr.length() > 0)
{
  playingStr += " ";
}
playingStr += info;

然后将其分配给一个标签以供显示:
lv_label_set_text(ui_LabelPlaying, playingStr.c_str());

步骤12:显示MP3封面图片
ESP32-audioI2S公开了一个audio_id3image()回调函数。如果在MP3的ID3标签中找到封面图片,则调用此函数。图片可以是任何图片格式,目前只支持解码和显示非渐进式JPEG图像文件。

在回调函数中,复制二进制数据:
file.seek(pos);
file.read(coverImgFile, len);

查找JPEG头:
size_t idx = 11;
while ((idx < len) && ((coverImgFile[idx++] != 0xFF) || (coverImgFile[idx] != 0xD8)))
;
--idx;

然后使用JPEGDEC解码:
jpegdec.openRAM(coverImgFile + idx, len - idx, jpegDrawCallback);

步骤13:显示MP3歌词
ESP32-audioI2S公开了一个audio_id3lyrics()回调函数。如果在MP3文件中找到了同步歌词、非同步歌词或文本数据标签,就会调用该函数。

在回调函数中,复制二进制数据:
file.seek(pos);
file.read((uint8_t *)lyricsText, len);

将二进制解码为UTF8文本:
audio.unicode2utf8(lyricsText, len);

如果文本中有时间标记,将时间索引存储到syncTimeLyricsSec[]和syncTimeLyricsLineIdx[]数组中。

然后将歌词文本设置为滚轮部件:
lv_roller_set_options(ui_RollerLyrics, lyricsText, LV_ROLLER_MODE_NORMAL);

步骤14:播放时同步显示歌词
如果找到了同步歌词标记,播放时滚动歌词部件:
for (int i = 0; i < syncTimeLyricsCount; ++i)
{
  if (syncTimeLyricsSec == currentTime)
  {
    lv_roller_set_selected(ui_RollerLyrics, syncTimeLyricsLineIdx, LV_ANIM_ON);
    break;
  }
}

步骤15:显示音频频谱
ESP32-audioI2S还公开了一个audio_process_i2s()回调函数,用于处理音频输出。我们可以利用这个函数收集音频数据,以可视化音频频谱。

在回调函数中,收集音频数据:
raw_data[raw_data_idx++] = *sample;

如果数据已满,使用FFT类进行处理:
if (raw_data_idx >= WAVE_SIZE)
{
  fft.exec((int16_t *)raw_data);
  draw_fft_level_meter(canvasFFT_gfx);
  lv_obj_invalidate(ui_CanvasFFT);
  raw_data_idx = 0;
}

注意:

可视化是绘制到一个分开的画布canvasFFT_gfx上的。画布与LVGL的部件ui_CanvasFFT相关联。

步骤16:设计外壳(可选)




为开发设备设计一个漂亮的外壳,让它更像一个音乐播放器。

你可以在Thingiverse上找到WT32-SC01 PLUS桌面外壳:

https://www.thingiverse.com/thing:6030590

步骤17:搞定!
是时候享受音乐了!

更多内容可以关注B站:陳亮手痕定律

链接:https://space.bilibili.com/1167567228

手搓了一个「千千静听」图8

骤18:待更新迭代
以下是我们可以进一步实现的功能愿望清单:
  • 随机播放列表顺序
  • LVGL滚轮无法处理大型列表,最好能够按文件夹列出歌曲
  • MP3时间轴寻找
  • 支持更多的封面图片格式
  • 连接到互联网?目前暂时还没有任何想法



附件下载:千千静听

原文作者:陳亮

原文链接:https://www.instructables.com/Design-Music-Player-UI-With-LVGL/

译文首发于公众号:DF创客社区

转载请注明来源信息


dbc0301  高级技匠

发表于 2023-6-26 21:53:07

技术真是太强了
回复

使用道具 举报

花生编程  中级技匠

发表于 2023-6-27 11:37:09

厉害!!
回复

使用道具 举报

花生编程  中级技匠

发表于 2023-6-27 11:38:31

赞赞赞赞赞
回复

使用道具 举报

Amos Young  中级技师

发表于 2023-6-27 15:43:48

看着真棒,技术太厉害了
回复

使用道具 举报

鳄鱼  中级技师

发表于 2023-6-27 21:07:32

这个不错呀
回复

使用道具 举报

腿毛利小五郎  初级技匠

发表于 2023-6-30 17:22:54

帅气啊,学习了
回复

使用道具 举报

JVUm7ppJGaRK  高级技师

发表于 2023-7-4 18:29:34

要是薄一点就更好了,最好加个支架
回复

使用道具 举报

三春牛-创客  初级技神

发表于 2023-7-10 21:41:48

厉害厉害
回复

使用道具 举报

三春牛-创客  初级技神

发表于 2023-7-10 21:42:50

赞!!!!
回复

使用道具 举报

快看擎天猪  中级技师 来自手机

发表于 2023-7-29 14:56:14

666
回复

使用道具 举报

派大星ym  初级技匠

发表于 2023-8-20 11:20:06

酷                    
回复

使用道具 举报

派大星ym  初级技匠

发表于 2023-8-20 11:22:35

厉害厉害厉害
回复

使用道具 举报

Amos Young  中级技师

发表于 2023-8-22 15:35:16


好技术,厉害。做的很棒
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail