C语言实现音乐播放器(Linux madplay)

(一)需求分析

1.扫描指定路径下的音乐,并显示出来
2.实现音乐的播放、暂停、上一首和下一首的功能
3.程序退出释放内存资源

(二)思路

1.扫描出指定路径下的音乐文件(便利指定文件夹,找出音频文件放在数组里面)
2.创建链表存放音乐的信息(音乐名、歌曲路径、歌曲总数等信息)
3.创建新的进程,用来播放音乐
4.调用kill函数实现音乐的切换和暂停播放功能
注意: 如果出现设备繁忙,可以使用ps -aux命令查看是否正在使用madplay,如果有madplay进程kill掉再运行程序就可以了

(三)接口函数

函数原型功能介绍头文件备注
DIR *opendir(const char *name);打开一个目录#include <sys/types.h>
#include <dirent.h>
struct dirent *readdir(DIR *dirp);读取目录的信息放在返回值中#include <dirent.h>
char *getcwd(char *buf, size_t size)获取当前所在路径#include <unistd.h>
pid_t fork(void)创建一个新的进程#include <unistd.h>父进程和子进程
返回值不同
int kill(pid_t pid, int sig);发送一个信号到进程#include <signal.h>
int execlp(const char *file, const char *arg, …0)调用系统程序#include <unistd.h>注意和system区别

(四)功能演示

在使用前先安装madplay音频解码器,在Ubuntu下安装如下:apt install madplay
安装完成后,编译工程(make) 之后运行程序传递参数就可以播放音乐了图一
图二
输入1测试:
图三
剩下的我就不一一测试了,感兴趣的可以自己下载工程测试下

(五)代码实现

这里贴出主要代码,因为我把功能开写的代码有些多:
music.c

/*********************************************************************
*                                                                    *
File        : music.c                                                *
Purpose     : play music                                             *
author      : @Mrming                                                *
Time        : 2020/2                                             *
***************************END-OF-HEADER******************************
*/#include "link.h"
#include "file.h"
#include <unistd.h>
#include <string.h>
#include <signal.h>
char CtrFlag=0;//0从头播放 1播放 2暂停
pid_t pid;//播放音乐进程句柄
extern struct song song_info;//歌曲信息结构体
link_t song_list = { NULL,0,"song_list" };//创建链表,存放歌曲的信息(链表头部,节点个数,链表名字)
node *cur_song= NULL;//当前歌曲节点/*** @brief 实现音乐的控制播放、暂停** @param  None**/
void play()
{char *str=NULL;switch(CtrFlag){case 0:{pid = fork();if(pid==0){str = strcat(cur_song->path,cur_song->name);//printf("\n%s\n",str);close(0);//execlp("madplay","madplay",str,"-r","-q",NULL);//execlp会开辟一个新的线程覆盖掉子线程}CtrFlag = 2;  }break;case 1:kill(pid,18);//对于主进程控制继续播放CtrFlag = 2;  break;case 2:{CtrFlag = 1;if(pid>0) {kill(pid,19);//主进程中暂停子进程}}break;default:printf("play:");}}/*** @brief  获取下一首歌曲并播放** @param  None**/
void next()
{cur_song = next_node(cur_song);if(cur_song == NULL){cur_song = song_list.phead;}kill(pid,9);//杀死当前音乐的进程CtrFlag = 0;//恢复默认值play();//播放当前选中的音乐
}/*** @brief 获取上一首歌曲并播放** @param  None**/
void prev()
{cur_song = prev_node(cur_song);if(cur_song->prev == NULL){cur_song = song_list.phead->next;printf("this song is the first! \n");}kill(pid,9);//杀死当前音乐的进程CtrFlag = 0;//恢复默认值play();//播放当前选中的音乐
}/*** @brief  显示音乐列表** @param  None**/
void show_music_list(void)
{printf("歌曲总数:%d首\n",song_info.song_num);//打印歌曲总数out_list(&song_list);
}/*** @brief 关闭音乐释放链表资源** @param  None**/
void source_recovery(void)
{system("killall madplay");//关闭madplay进程destory_link(&song_list);//退出程序前释放资源
}
//打印当前歌曲的上一首和下一首
void near_curMusic(node *cur_song)
{printf("\n当前歌曲 : %s\n",cur_song->name);if(CtrFlag == 2)printf("播放状态 :播放\n");if(CtrFlag == 1)printf("播放状态 :暂停\n");}/*** @brief 查找音乐文件放在song_list中** @param  argv:路径**/
void search_all_music(char *argv)
{int i = 0;link_init(&song_list);//初始化链表1search_file(argv,".mp3");//指定路径下查找指定文件名,结果放在song_info结构体中for(i=0;i<song_info.song_num;i++)//歌曲信息插入链表{link_insert_tail(&song_list,song_info.song_name[i],song_info.song_path[i]);//尾插数据//printf("%s\t%s\n",song_info.song_name[i],song_info.song_path[i]);}cur_song = song_list.phead->next;
}/*** @brief 功能列表** @param  None**/
int menu()    
{int i;printf("+-------------------------------------------------------------+\n");printf("|                                                             | \n");printf("|                 Welcome to MP3 PLAYER                       | \n");printf("|                                                             | \n");printf("|                      1.Play\\stop                           | \n");printf("|                      2.prev song                            | \n");printf("|                      3.next song                            | \n");printf("|                      4.music list                           | \n");printf("|                      5.quit                                 | \n");printf("|_____________________________________________________________| \n");printf("choose->");scanf("%d",&i);return i;
}/*** @brief 功能选择** @param  None**/
void start_music()
{show_music_list();while(1){near_curMusic(cur_song);switch(menu()){case 1:play();break;case 2:prev();break;case 3:next();break;case 4 :show_music_list();break;case 5 :return;default:printf("重新输入!\n");break;}}
}int main(int argc, char *argv[])
{system("clear");search_all_music(argv[1]);//查找目录下的mp3文件,结果放在song_liststart_music();//播放音乐source_recovery();return 0;
}

file.c

#include "file.h"
/*************************************函数功能: 扫描目录下指定后缀名的文件*输入 : 路径*输出 :  扫描成功输出0,扫描失败输出-1*注释 :  扫描到的文件名放在song_info结构体里面*************************************/
struct song song_info={0,0};int search_file(char* name,char * type)
{DIR *p=NULL;struct dirent *pdir;p=opendir(name);if(p==NULL){perror("open dir error");return -1;}chdir(name);while(pdir=readdir(p)){if(!(strcmp(pdir->d_name,".")==0) && !(strcmp(pdir->d_name,"..")==0)){struct stat st;stat(pdir->d_name,&st);if((st.st_mode &S_IFMT)== S_IFDIR){// printf("this is a content:%s\n",pdir->d_name);//system("pwd");search_file(pdir->d_name,"mp3");}else {char * file_type;file_type = strstr(pdir->d_name,type);if(file_type){getcwd(song_info.song_path[song_info.song_num],sizeof(song_info.song_path[0]));sprintf(song_info.song_name[song_info.song_num++],"/%s",pdir->d_name);}}}}chdir("..");closedir(p);
return 0;
}

link.h

#pragma once
#ifndef _LINK_H_
#define _LINK_H_ #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define name_max  255
typedef struct _node
{char name[name_max];char path[name_max];struct _node * prev;struct _node * next;
}node;typedef struct _link
{node *phead;//链表头部int count;//节点个数char name[name_max];//链表名字
}link_t;int link_init(link_t *link);//链表初始化,成功返回0,失败返回-1
int link_insert_tail(link_t *link, char *dat1,char *dat2);//尾插链表,使用前先执行link_init初始化链表
int destory_link(link_t *link);//删除链表,成功返回0 失败返回-1
node * pos_list(link_t link, int n);//定位到链表任意位置
node * next_node(node * node);//获取当前节点的上一个节点
node * prev_node(node * node);//获取当前节点的下一个节点
void out_list(link_t *head);//遍历链表#endif /* ifndef _MUSIC_H_ */

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/531498.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

虚拟机中安装linux

&#xff08;一&#xff09;前言 就在昨天电脑的固态突然崩掉&#xff0c;无奈重新把系统装在的以前的硬盘上&#xff0c;为了能够继续工作重新配置嵌入式linux系统开发环境&#xff0c;本教程主要记录在虚拟机中安装linux。 &#xff08;二&#xff09;环境准备 虚拟机&…

Ubuntu设置root登录

1.、Ubuntu 管理员用户 root 默认没有密码&#xff0c;在使用前最好添加密码&#xff0c;使用指令&#xff1a; sudo passwd root 注意&#xff1a;命令行输入密码时不显示&#xff0c;输入时需注意密码的准确性&#xff1b; 2、Ubuntu 想要用 root 帐户登录&#xff0c;可在普…

vim配置之spacevim

为了更好的利用vim&#xff0c;我们一般需要自己配置&#xff0c;今天介绍了一下经常用的spacevim &#xff08;一&#xff09;配置环境 Ubuntu16.04vim 7.4版本以上(必须&#xff01;&#xff01;) &#xff08;二&#xff09;安装spacevim 1.检查vim的版本&#xff1a; v…

Ubuntu更换gnome桌面环境后不能root登录

安装完Ubuntu后感觉界面有点丑陋&#xff0c;安装了gnome桌面环境试一下 sudo apt-get install gnome-shell sudo apt-get install ubuntu-gnome-desktop如果选择了lightdm后可以使用sudo dpkg-reconfigure gdm3 重新改回gdm3 sudo apt-get install unity-tweak-tool sudo ap…

Ubuntu下安装tilix终端仿真器

安装环境 Ubuntu 16.04 操作步骤 首先添加这个终端模拟器仓库的公钥。这里我都是以root超级用户权限操作的&#xff0c;如果没有的话&#xff0c;请在命令前面加sudo。 add-apt-repository ppa:webupd8team/terminixapt update安装Tilix。 apt install tilix安装完成测试结…

vim配置之snippets代码块

&#xff08;一&#xff09;目的 我们在编写程序的过程中&#xff0c;经常会敲一些重复的代码&#xff0c;我们可以利用snippets来达到输入简写来敲出完整的代码 &#xff08;二&#xff09;安装步骤 安装使用Vundle,没有vbundle的先执行下面的命令 git clone https://gith…

c语言实现跳动的心

本文章分为两部分&#xff1a;第一部分为实现多彩的心&#xff0c;第二部分是实现心得跳动&#xff0c;两个代码均独立运行 本篇文章转载自公众号&#xff1a; C语言程序设计基础知识 &#xff08;一&#xff09;C语言实现多彩的心 实现过程其实很简单 首先使用for循环绘制心…

Linux下使用消息队实现 ATM 自动取款机功能

文章分五部分&#xff1a;需求分析、项目所需知识点、思路讲解、代码实现、功能演示 本文内容较长&#xff0c;建议是按照我自己的思路给大家讲解的&#xff0c;如果有其他问题&#xff0c;欢迎评论区讨论 文章中的代码是在linux下编译实现的&#xff0c;注意自己的环境。 &…

200行代码实现视频人物实时去除

今天在GitHub上发现了一个好玩的代码&#xff0c;短短几百行代码就实现了从复杂的背景视频中去除人物&#xff0c;不得不说这位大佬比较厉害。 这个项目只需要在网络浏览器中使用JavaScript&#xff0c;用200多行TensorFlow.js代码&#xff0c;就可以实时让视频画面中的人物对…

codeforces C. Vanya and Scales

C. Vanya and ScalesVanya has a scales for weighing loads and weights of masses w0, w1, w2, ..., w100 grams where w is some integer not less than 2(exactly one weight of each nominal value). Vanya wonders whether he can weight an item with mass m using …

菱形继承和虚继承、对象模型和虚基表

1.菱形继承&#xff08;钻石继承&#xff09;&#xff1a;两个子类继承同一父类&#xff0c;而又有子类同时继承这两个子类。例如B,C两个类同时继承A&#xff0c;但是又有一个D类同时继承B,C类。 2.菱形继承的对象模型 class A { public:int _a; };class B :public A { p…

c++虚函数和虚函数表

前言 &#xff08;1&#xff09;虚基表与虚函数表是两个完全不同的概念 虚基表用来解决继承的二义性(虚基类可以解决)。虚函数用来实现泛型编程&#xff0c;运行时多态。 &#xff08;2&#xff09;虚函数是在基类普通函数前加virtual关键字&#xff0c;是实现多态的基础 &a…

VS2017安装配置Qt

这篇文章作为qt的开发环境配置篇&#xff0c;记录如何在vs2017中安装qt的 所需软件下载链接如下&#xff1a; QT下载链接&#xff1a;QT visual studio下载链接&#xff1a;visual studio 这里推荐安装最新的&#xff0c;原因是vs2017不支持一些老版本的makefile文件生成&#…

STM32位带区和位带别名区的浅谈

1.首先谈下为什么要使用位带&#xff1f; 在学习51单片机时就已经使用过位操作&#xff0c;比如使用sbit对单片机IO口的定义&#xff0c;但是STM32中并没有这类关键字&#xff0c;而是通过访问位带别名区来实现&#xff0c;即通过将每个比特位膨胀成一个32位字&#xff0c;当访…

Hibernate的数据查找,添加!

1.首先看一下测试数据库的物理模型 2.测试所需要的Hibernate的jar包 3.数据库的sql /**/ /* DBMS name: MySQL 5.0 */ /* Created on: 2015/7/3 23:17:57 */ /**/drop table if exists books;drop tab…

新手如何在Altium Designer中绘制电路板

好久没用AD画电路板了&#xff0c;这次电子实训让画个PCB板&#xff0c;借着这个机会写了一篇新手教程。 此教程所用的电路图是自动循迹小车&#xff0c;虽然元件比较简单&#xff0c;但是感觉还是很厉害的&#xff0c;一块看一下吧。 此教程仅适用于没有基础的同学 一、概述 …

Qt模仿QQ登录界面(一)

这两天研究qt&#xff0c;练习时做了个仿QQ登录界面&#xff0c;我这次实现的比较简单&#xff0c;先在这里记录一下&#xff0c;以后有空了会继续完善的。 &#xff08;一&#xff09;效果图 这里使用我的qq号测试的如图&#xff1a; &#xff08;二&#xff09;工程文件 &…

回流焊和波峰焊的区别

本文首先分别介绍回流焊和波峰焊的特点&#xff0c;然后对两者进行比较&#xff0c;欢迎评论补充哦~ 最近在实习看到了厂里面的回流焊的波峰焊&#xff0c;有点好奇就查了点资料&#xff0c;分享给同样爱学习的你。 一.回流焊 一般的表面贴装工艺分三步&#xff1a;印刷机施加…

三对角矩阵的压缩

三对角矩阵&#xff0c;从第二行开始选中的元素的个数都为3个。对于a[i,j]将要存储的位置k&#xff0c;首先前(i-1)行元素的个数是(i-2)*3 2(第一行元素的个数为2)&#xff0c;又a[i,j]属于第i行被选中元素的第j-i1个元素&#xff0c;所以k (i-2)*3 2 j-i1 2*ij-3 如果知道了…

LC和RC滤波电路分析

一、概述 整流电路的输出电压并不是纯粹的直流&#xff0c;从示波器观察整流电路的输出&#xff0c;与直流相差很大&#xff0c;波形中含有较大的脉动成分&#xff0c;称为纹波。为了获得比较理想的直流电压&#xff0c;需要利用具有储能作用的电抗性元件(如&#xff1a;电感、…