基于lvgl与mplayer音乐播放器

该博客介绍了如何基于lvgl图形库和mplayer音乐播放器,设计并实现一个具备基本播放功能、播放列表显示、进度控制和歌词显示的嵌入式音乐播放器。功能包括列表选歌、播放控制、播放模式设置、音量及进度调节。设计方案涉及多线程、互斥锁、条件变量和信号等技术。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

设计目标:

1 实现基本的音乐播放器功能

2 显示播放列表

3 实现进度条控制音乐

4 歌词显示

功能描述:

列表选歌

播放暂停,快进快退,上下切歌

设置播放模式,播放速度

调节音量、进度条

设计方案:

多线程、互斥锁、条件变量、信号

界面效果:

 

源码

#include "lvgl/examples/lv_examples.h"
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include<time.h>
#include <semaphore.h>

extern pthread_mutex_t mutex_lv;//lvgl线程锁

static char local_music_path[]="/root/player/music";//音乐路径
static char local_pic_path[]="/root/player/picture";//图片路径
static char local_words_path[]="/root/player/words";//歌词路径

static char music_path[100][1024];//音乐路径
static char pic_path[100][1024];//图片路径
static char words_path[100][1024];//歌词路径
static char words_buf[5*1024]={0};  //放歌词的数组

static FILE *fp_mplayer=NULL;   //播放器传回的管道,接收播放进度
static FILE *fp_words=NULL;     //歌词文件
static int fd_mplayer = 0;      //定义管道文件描述符,发送指令给mplayer
static int music_num=0;         //音乐数量
static int music_index=-1;      //当前音乐的下标值,用于寻找上下首

static int percent_pos;         //当前播放百分比
static float time_length;       //歌曲长度
static float time_pos;          //当前播放进度

static bool list_flag=1;    //开关列表
static bool words_flag=1;    //歌词列表
static bool play_flag=0;    //播放音乐开关
static bool start=0;        //启动,线程读mplayer返回信息

static lv_style_t font_style;   //中文
static lv_obj_t *play_mode;     //下拉列表对象,播放模式
static lv_obj_t *speed_obj;     //下拉列表对象,播放速度
static lv_obj_t * music_list;   //列表对象
static lv_obj_t *pic_obj;       //图片对象
static lv_obj_t * volume_slider;  //音量滑条对象
static lv_obj_t * play_slider;  //播放进度条对象

static lv_obj_t *title_label;     //图片信息标签
static lv_obj_t *words_label;     //歌词标签
static lv_obj_t * volume_label; //音量标签
static lv_obj_t *time_length_label; //时长标签
static lv_obj_t *time_pos_label; //当前时间标签
static lv_obj_t *words_list;     //歌词标签   

pthread_cond_t cond;        //条件变量,用于暂停读取mplayer
pthread_cond_t cond1;
pthread_mutex_t mutex;
pthread_mutex_t mutex1;

pthread_t tid_read;         //读mplayer的线程id
pthread_t tid_write;        //写mplayer的线程id


//检索本地歌单
void get_music_path()
{
    //读目录,mp3后缀保存到数组
    DIR *dirp = opendir(local_music_path);
    if(dirp==NULL)
    {
        perror(local_music_path);
        exit(0);
    }
    struct dirent* msg;
    while(1)
    {
        msg = readdir(dirp);
        if(msg == NULL)break;
        if(msg->d_name[0]=='.')continue;
        if(strstr(msg->d_name,".mp3"))
        {
            sprintf(music_path[music_num], "%s/%s", local_music_path, msg->d_name);
            //拼接图片与歌词路径↓
            char name[100]={0};
            strcpy(name,strtok(msg->d_name,"."));
            sprintf(pic_path[music_num], "S:%s/%s.jpg", local_pic_path, name);
            sprintf(words_path[music_num], "%s/%s.lrc", local_words_path, name);
            //拼接图片与歌词路径↑
            music_num++;
            puts(music_path[music_num - 1]);
        }
    }
    printf("检索歌单完成 共%d\n",music_num);
}
//检索本地图片
void get_pic_path()
{
    //读目录,图片后缀保存到数组
    DIR *dirp = opendir(local_pic_path);
    if(dirp==NULL)
    {
        perror(local_pic_path);
        return;
    }
    
    struct dirent* msg;
    int pic_num=0;
    while(1)
    {
        msg = readdir(dirp);
        if(msg == NULL)break;
        if(msg->d_name[0]=='.')continue;
        if(strstr(msg->d_name,".png")||strstr(msg->d_name,".jpg"))
        {
            sprintf(pic_path[pic_num++], "S:%s/%s", local_pic_path, msg->d_name);
            puts(pic_path[pic_num - 1]);
        }
    }
    printf("检索图片完成 共%d\n",pic_num);
}
//检索歌词
void get_words_paht()
{
    //读目录,lrc后缀保存到数组
    DIR *dirp = opendir(local_words_path);
    if(dirp==NULL)
    {
        perror(local_words_path);
        return;
    }
    struct dirent* msg;
    int words_num=0;
    while(1)
    {
        msg = readdir(dirp);
        if(msg == NULL)break;
        if(msg->d_name[0]=='.')continue;
        if(strstr(msg->d_name,".lrc"))
        {
            sprintf(words_path[words_num++], "%s/%s", local_words_path, msg->d_name);
            puts(words_path[words_num - 1]);
        }
    }
    printf("检索歌词完成 共%d\n",words_num);
}

//初始化字体风格
void init_font_style()
{
    /*创建字体*/
    static lv_ft_info_t info;
    info.name = "/font/simhei.ttf";//字体位置
    info.weight = 18;//大小
    info.style = FT_FONT_STYLE_NORMAL;//风格
    info.mem = NULL;
    if(!lv_ft_font_init(&info)) {
        LV_LOG_ERROR("create failed.");
    }

    /*给字体设置样式*/
    
    lv_style_init(&font_style);
    lv_style_set_text_font(&font_style, info.font);
    lv_style_set_text_align(&font_style, LV_TEXT_ALIGN_CENTER);

    //lv_obj_add_style(label, &style, 0);
}
//初始化图片的父对象,即图片都在这个对象中显示
void init_pic_parent_obj()
{
    //在屏幕中创建一个对象
    lv_obj_t * img = lv_obj_create(lv_scr_act());
    //取消滚动
    lv_obj_clear_flag(img, LV_OBJ_FLAG_SCROLLABLE);
    lv_obj_set_size(img, 200, 200);
    lv_obj_align(img, LV_ALIGN_CENTER, 0, -60);
    // lv_obj_set_style_pad_all
    //图片对象
    pic_obj = lv_img_create(img);
    lv_obj_center(pic_obj);  
}
//初始化歌曲信息的父对象
void init_title_obj()
{
    //在屏幕中创建一个对象
    lv_obj_t * title = lv_obj_create(lv_scr_act());
    lv_obj_clear_flag(title, LV_OBJ_FLAG_SCROLLABLE);//禁用滚动
    lv_obj_set_size(title, 200, 50);
    lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 20);
    
    //标题标签
    title_label = lv_label_create(title);

    //添加字体
    lv_obj_add_style(title_label, &font_style, 0);
    lv_obj_center(title_label);
    lv_label_set_text(title_label, "开启音乐之旅");
    //歌词标签
    words_label = lv_label_create(lv_scr_act());
    lv_obj_add_style(words_label, &font_style, 0);
    lv_obj_align(words_label,LV_ALIGN_CENTER,0,70);
    lv_label_set_text(words_label,"歌词");
}

//信号任务
void signal_10_task(int arg)
{
    if (arg == 10)
    {
        printf("收到信号 %d 线程任务(读取mplayer)暂停\n", arg);
        pthread_kill(tid_write,12); //停止写
LVGL(Light and Versatile Graphics Library)是一个用于嵌入式系统的图形库,它本身并不直接提供音乐播放功能。但是,在基于LVGL开发的应用程序中集成一个音乐播放器是完全可行的。 为了创建一个LVGL驱动的音乐播放器界面,你可以按照以下步骤操作: 1. **设计UI布局**:利用LVGL提供的控件如按钮、标签、滑块等构建用户交互元素。例如,可以添加“上一首”、“下一首”、“暂停/播放”的图标按钮以及进度条来显示当前歌曲播放位置。 2. **音频处理模块的选择整合**:选择合适的第三方库或硬件平台自带的支持MP3或其他格式解码的功能,并将其链接到你的项目里。常见的有Mad MP3 Decoder for C/C++ 或者FatFs + VS1053这样的组合方案适用于大多数微控制器系统。 3. **事件响应机制**:当用户点击了界面上的相关组件时触发相应动作,比如切换曲目、调整音量大小等等。这需要编写回调函数监听这些输入事件并调用底层API控制实际的声音输出设备。 4. **状态同步更新**:随着后台正在运行着的实际媒体流变化而动态改变前端展示内容,保持两者之间的协调一致非常重要。也就是说,如果现在正在播放某一段音频,则应该及时刷新时间戳信息;当按下停止键之后也要马上反映出这种改动。 最终结果将取决于具体的实施细节和技术选型,上述只是一个大致框架性的描述。如果你对某个特定部分感兴趣或者遇到了困难,请随时告诉我!
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值