admin 管理员组

文章数量: 887019

本文会尽量让和笔者一样只有一点点可怜的c语言基础的小白看懂,并写出自己的音乐播放器。

笔者使用的编译器是Visual Studio 2019,直接在官网下载就行了。下面是Visual Studio 2019比较详细的下载、安装、配置、使用的教程,熟悉使用的朋友可以直接跳过。

笔者选择的是Community 2019,即社区版。关于下载位置,可以存c盘也可以改存其他位置,在下才疏学浅,不知道有什么区别。

至于下载的工具负荷,这里有两张截图大家可以参考一下

勾选这些选项应该是足够了,可以根据自身需求来勾选其他选项

然后便是新建项目(想了一下还是手把手教吧,别嫌啰嗦,因为第一次用的话确实不会。大佬些可以直接跳过,看后面的mciSendString函数功能及用法)

打开visual studio 2019, 点击创建新项目如下图:

然后选择创建空项目,点击下一步,如下图所示:

项目名称随便起没有任何影响,文件储存位置嫌麻烦就用默认的就行,点击创建,如下图所示:

在界面右侧右键点击源文件=>添加=>新建项,左键点击新建项,如下图所示:

选择c++文件,将名称的后缀改为.c(其实.cpp也行,不过既然是用c语言编写嘛,就用.c),前面名称也是根据需要来取,点击添加,如下图所示:

然后便可以愉快的码代码啦!

但是大家在运行程序时还会出现这样那样的问题,所以需要在项目属性中调一下配置,按照下面的方法配置就好:

好了,准备工作已经全部就绪,接下来正式介绍mciSendString函数,mciSendString函数需要的头文件有:

#include<stdio.h>
#include<Mmsystem.h>
#include<Windows.h>

mciSendString的常用命令有: 

命令解释
open打开设备
close关闭设备
play播放设备
stop停止播放设备
record开始记录
save保存设备内容
pause暂停设备的播放或记录
resume恢复暂停播放或记录的设备
seek改变媒体播放的位置(指时刻)
capacility查询设备能力
info查询设备信息
status查询设备状态信息

这里介绍如何实现开始、暂停/继续、停止、调节音量、快进快退和进度条显示的功能。

1、播放功能

我们先将命名为01.mp3的音乐存入所在项目的文件夹(这应该是我唯一没有展示详细步骤的操作)。 然后尝试使用相对路径打开音乐,使用语句:

mciSendString("open 01.mp3", NULL, 0, NULL);

 然后再播放音乐,使用语句:

mciSendString("play 01.mp3", NULL, 0, NULL);

完整代码为:

#include<stdio.h>
#include <Windows.h>
#include <mmsystem.h>	
#pragma comment(lib,"winmm.lib")

int main() {
	mciSendString("open 01.mp3", NULL, 0, NULL);
	mciSendString("play 01.mp3", NULL, 0, NULL);
	getchar();
    return (0);
}

说明:

(1)其中gerchar()是为了让程序不要直接退出,这里可以使用scanf达到一样的效果。

(2)#pragma comment(lib,"winmm.lib")可加可不加,因为我们之前已经在链接器中添加了附加项winmm.lib。

先将mp3文件放在所在项目的文件夹,上述方法通过相对路径打开并播放音乐,我们也可以使用绝对路径,即音乐存放在电脑中的位置来打开音乐,比如我们将01.mp3文件放在C:\Users\HP\Music\中,则可以通过以下语句打开音乐:

mciSendString("open C:\\Users\\HP\\Music\\01.mp3", NULL, 0, NULL);

通过以下语句播放音乐:

mciSendString("play C:\\Users\\HP\\Music\\01.mp3", NULL, 0, NULL);

完整的代码为:

#include<stdio.h>
#include <Windows.h>
#include <mmsystem.h>	
#pragma comment(lib,"winmm.lib")

int main() {
	mciSendString("open C:\\Users\\HP\\Music\\01.mp3", NULL, 0, NULL);
	mciSendString("play C:\\Users\\HP\\Music\\01.mp3", NULL, 0, NULL);
	getchar();
	return (0);
}

在音乐播放器的项目中,播放功能可以写成一个函数,让主函数来调用。我们首先将歌曲存入一个文件夹,比如存放在C:\Users\HP\Music\中,这个文件夹中有很多首歌,如01.mp3、02.mp3、03.mp3等等,那么怎么让用户选择歌曲来播放呢?提供一下思路:

(1)创建一个储存歌单信息的链表(链表储存歌曲的序号和名称),然后传入储存歌单信息的链表的头指针。

(2)使用一个char型数组存储"open "、一个char型数组存储"C:\\Users\\HP\\Music\\",通过传入的指针得到歌曲名称

(3)使用strcat、strcpy、sprintf等函数(需要引用头文件#include<stdlib.h>)将这些字符串拼接起来。

播放函数的代码如下(只展示了播放功能)所示:


char filepath[100] = "C:\\Users\\HP\\Music\\";//储存MP3文件的目录,用于向mciSendString函数传递指令
void play(struct media* p0)
{
	char cmd[100];
	char file[100] = "open ";
	char play[100] = "play ";
	sprintf(cmd, "%s%s", filepath, p0->name);
	printf("%s", cmd);
	strcat(file, cmd);
	strcat(play, cmd);
	mciSendString(file, NULL, 0, NULL);
	mciSendString(play, NULL, 0, NULL);
}

 2、暂停/继续功能

思路是先播放、按键后暂停、按键后再播放。我们先使用相对路径实现该功能。

暂停播放的语句为:

mciSendString("pause 01.mp3", NULL, 0, NULL);

那么完整的代码就来了:

#include<stdio.h>
#include <Windows.h>
#include <mmsystem.h>	
#pragma comment(lib,"winmm.lib")

int main() {
	int a;
	mciSendString("open 01.mp3", NULL, 0, NULL);
	mciSendString("play 01.mp3", NULL, 0, NULL);
	scanf("%d", &a);
	mciSendString("pause 01.mp3", NULL, 0, NULL);
	scanf("%d", &a);
	mciSendString("resume 01.mp3", NULL, 0, NULL); //这里也可以使用play
	scanf("%d", &a);
	return (0);
}

至于,如何用绝对路径打开,如何写成函数,上面已经提供了思路,便不再赘述。

3、停止播放

不想啰嗦,懂的都懂。

mciSendString("stop 01.mp3", NULL, 0, NULL);

4、调节音量

调节音量我们要用到两次mciSendString函数,先读取媒体的音量(第一次用到mciSendString),我们把获取的音量增加或减少,再把增加或减少后的音量赋值给媒体(第二次用到mciSendString)。

(1)读取音量的语句:

char res[260];

mciSendString("status 01.mp3 volume", res, 260, NULL);

定义一个长度为260的char型数组(为什么是260呢,我也不知道,用就是了),读取音量的语句就会把媒体音量以字符串的形式读取到res中,中间的参数表示res的长度。

(2)将res中表示音量的字符串转化为数字再进行加减(引入头文件#include<stdlib.h>)

int volume = 0; 

volume = atoi(res); // 转化语句

volume += 200;   // 音量加200,也可以设定减少

(3)将整形的音量再转化为字符串存入数组(引入头文件#include<stdlib.h>)

char vo[20];

itoa(volume, vo, 10); //转化语句

(4)将vo中的音量设定为媒体音量

这里出现了一个问题,先展示一下设定音量的语句(设为800):

mciSendString("setaudio 01.mp3 volume to 800", NULL, 0, NULL);

我们不能这样写:

mciSendString("setaudio 01.mp3 volume to vo", NULL, 0, NULL);

因为在双引号里面vo是字符串而不是变量,那么如何解决这个问题呢?

char file1[100] = "setaudio 01.mp3 volume to "; // to后面一定要有空格,不然会报错

strcat(file1,vo); // 将vo接在file1后面

mciSendString(file1, NULL, 0, NULL); // 设定成功

完整代码如下所示:

char vo[20];
char res[260];
char file1[100] = "setaudio 01.mp3 volume to "; // to后面一定要有空格,不然会报错
mciSendString("status 01.mp3 volume", res, 260, NULL);
int volume = 0;
volume = atoi(res); // 转化语句
volume += 200;
itoa(volume, vo, 10); //转化语句
strcat(file1, vo); // 将vo接在file1后面
mciSendString(file1, NULL, 0, NULL); // 设定成功

当然,如果要用绝对路径打开音乐的话,就具体问题具体分析了,主要工作就是用strcat把字符串连起来,注意空格不能省略。

5、快进、快退

实现快进快退功能的方法和音量调节很相似,我们要先使用mci函数获取音乐播放位置的功能,再使用其跳到某一位置的功能。

(1)获取音乐位置(单位是毫秒)

(2)对这个位置加减15000(15秒)

(3)跳到加减15秒后的位置

单独解释一下:

char st[100];

mciSendString("status 01.mp3 position", st, 100, NULL);

// 音乐播放到第几毫秒就存储在st里面,100是st的长度

mciSendString("seek 01.mp3 to 60000", NULL, 0, NULL);

// 这句话是让音乐跳到第60000毫秒/60秒/1分钟的位置

那么完整的代码来了:

int position;
char st[100];
char file1[100] = "seek 01.mp3 to ";
char file2[100];
mciSendString("status 01.mp3 position", st, 100, 0);
position = atoi(st);
position += 15000;
itoa(position, file2, 10);
strcat(file1, file2);
mciSendString(file1, st, 100, 0);

6、进度条显示

显示进度条的思路是,我们用=打印进度条,因为进度条的总长度不会因为歌曲的长度不同而不同,所以我们假定进度条的总长度为30个=。如下图:

==============================

可以通过mci函数获取一首歌的总长度,转化为整形后,将其30等分,每过一个30等分的时间,printf一个=,即可实现进度条的显示。还有一个问题是,进度条旁边一般会有这样的数字01:23/03:36,左边表示歌曲播放的位置,右边表示歌曲的总时长。

先看总时长如何表示:我们读取到的歌曲时长单位是毫秒,把它转化为分:秒并单独打印每一个数字不难吧。(length是歌曲的总毫秒数,下面会讲,可以用mci得到)

	int MinTens_total = 0, MinOnes_total = 0, SecTens_total = 0, SecOnes_total = 0;
    MinTens_total = length / 600000;
	MinOnes_total = (length / 60000) % 10;
	SecTens_total = ((length / 1000) % 60) / 10;
	SecOnes_total = ((length / 1000) % 60) % 10;

当前时刻则同理:

int MinTens_cur = 0, MinOnes_cur = 0, SecTens_cur = 0, SecOnes_cur = 0;
current = atoi(st2);
MinTens_cur = current / 600000;
MinOnes_cur = (current / 60000) % 10;
SecTens_cur = ((current / 1000) % 60) / 10;
SecOnes_cur = ((current / 1000) % 60) % 10;

获取总时长的函数为:

char st[100];

mciSendString("status 01.mp3 length", st, 100, NULL);

获取当前时刻的函数为:

char st[100];

mciSendString("status 01.mp3 position", st, 100, NULL);

函数如何实现功能,我会在最后展示

以上便是mci能够实现的一些基本功能的具体做法,mci还有很多功能,也值得大家慢慢探索。一个音乐播放器除了能实现这些基本功能外,还要能实现切换上一首/下一首,用户登陆注册的功能。执行这些功能(包括详细介绍的6种功能)就要用到一个工具——链表。

关于链表的相关知识就不在这里过多的解释了。可以参考下面这个代码创建最简单的链表。

#include <stdio.h>
#include <stdlib.h>
#include<string.h>
struct media {
	int num;//编号
	char name[100];//名称
	struct media* next;//存储下一曲地址
};
int main() {
	struct media* head, * p, * q;
	head = (struct media*)malloc(sizeof(struct media));
	p = (struct media*)malloc(sizeof(struct media));
	head->next = p;
	strcpy_s(p->name,6, "1.mp3");
	p->num = 1;
	q = p;
	p = (struct media*)malloc(sizeof(struct media));
	strcpy_s(p->name,6,"2.mp3");
	q->num = 2;
	q->next = p;
	p->next = NULL;
	struct media* m = head->next;
	while (m != NULL) {
		printf("歌曲名称:%s\n", m->name);
		m = m->next;
	}
	getchar();
	return 0;
}

还需要文件读取的操作。

大家可以搜索一下kbhit,键盘监听功能用来解决你以为无解的死循环。

还有Sleep函数来实现对时间间隔的控制。

SetConsoleTextAttribute函数实现对printf打印出的字体的颜色控制。

system("CLS");实现清屏的功能。大家还可以思考如何使用双缓存技术消除闪屏现象。

学习创建链表是一个比较麻烦的过程,如果有机会也想出一篇讲解音乐播放器中创建链表的文章。

由于笔者才疏学浅,以上若有很多不严谨的地方和错误的地方,还请留言指出,想问的问题也可以提出来,我会尽我所能帮你解决。

下面是实现了基本功能的音乐播放器(前提是在C:\Users\HP\Music\中存放有歌曲)

1、face.c的源代码

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<string.h>
#include"play.h"
#include"user.h"
#include"list.h"

extern char filepath2[100] = "C:\\Users\\HP\\Music\\";

int face_user();
int face_play();

int face_user() {
	system("CLS");
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED);
	printf("\n\n\n");
	printf("\t\t\t\t╔═══════════════════════════════════════════════════════════╗\n");
	printf("\t\t\t\t║         __  _______ _____                                 ║\n");
	printf("\t\t\t\t║        /  |/  / __ \\   /                                  ║\n");
	printf("\t\t\t\t║       / /|_/ / /_/ //_ <                                  ║\n");
	printf("\t\t\t\t║      / /  / / ____/__/ /                                  ║\n");
	printf("\t\t\t\t║     /_/__/_/_/    /___/ ____________                      ║\n");
	printf("\t\t\t\t║     / __ \\/ /   /   \\ \\/ / ____/ __ \\                     ║\n");
	printf("\t\t\t\t║    / /_/ / /   / /| |\\  / __/ / /_/ /                     ║\n");
	printf("\t\t\t\t║   / ____/ /___/ ___ |/ / /___/ _, _/                      ║\n");
	printf("\t\t\t\t║  /_/   /_____/_/  |_/_/_____/_/ |_|     1.0  Ver          ║\n");
	printf("\t\t\t\t║                                                           ║\n");
	printf("\t\t\t\t╚═══════════════════════════════════════════════════════════╝\n\n\n\n");
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY |
		FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
	int a;
	printf("\t\t\t\t╔═══════════════════════════════════════════════════════════╗\n");
	printf("\t\t\t\t║                                                           ║\n");
	printf("\t\t\t\t║              *1.登录           *2.注册                    ║\n");
	printf("\t\t\t\t║                                                           ║\n");
	printf("\t\t\t\t║              *0.退出                                      ║\n");
	printf("\t\t\t\t║                                                           ║\n");
	printf("\t\t\t\t╚═══════════════════════════════════════════════════════════╝\n");
	printf("\t\t\t\t ");
	scanf("%d", &a);
	return a;
}

//包含进度条
int face_play(struct media* p0) {
	
	system("CLS");
	struct media* p = p0;
	int a;

	int LENGTH = 50;//进度条长度
	int MinTens_cur = 0, MinOnes_cur = 0, SecTens_cur = 0, SecOnes_cur = 0;
	int MinTens_total = 0, MinOnes_total = 0, SecTens_total = 0, SecOnes_total = 0;

	char st1[50];
	char st2[50];
	char file1[50] = "status ";
	char file2[50] = " length";
	char text1[50] = "status ";
	char text2[50] = " position";
	char cmd[100];

	int length = 0;//存储歌曲时长
	int current = 0;//存储歌曲当前播放位置

	sprintf(cmd, "%s%s", filepath2, p->name);
	strcat(file1, cmd);
	strcat(file1, file2);

	mciSendString(file1, st1, 50, 0);

	length = atoi(st1);

	MinTens_total = length / 600000;
	MinOnes_total = (length / 60000) % 10;
	SecTens_total = ((length / 1000) % 60) / 10;
	SecOnes_total = ((length / 1000) % 60) % 10;

	strcat(text1, cmd);
	strcat(text1, text2);
	mciSendString(text1, st2, 50, 0);
	current = atoi(st2);

	while (!(kbhit())) {
		mciSendString(text1, st2, 50, 0);
		current = atoi(st2);
		MinTens_cur = current / 600000;
		MinOnes_cur = (current / 60000) % 10;
		SecTens_cur = ((current / 1000) % 60) / 10;
		SecOnes_cur = ((current / 1000) % 60) % 10;

		printf("\t\t\t\t╔═════════════════════════════════════════════════════════════════╗\n");
		printf("\t\t\t\t║                                                                 ║\n");
		printf("\t\t\t\t║     *1.暂停/继续              *2.选曲播放                       ║\n");
		printf("\t\t\t\t║                                                                 ║\n");
		printf("\t\t\t\t║     *3.上一曲                 *4.下一曲                         ║\n");
		printf("\t\t\t\t║                                                                 ║\n");
		printf("\t\t\t\t║     *5.音量-                  *6.音量+                          ║\n");
		printf("\t\t\t\t║                                                                 ║\n");
		printf("\t\t\t\t║     *7.快进                   *8.快退                           ║\n");
		printf("\t\t\t\t║                                                                 ║\n");
		printf("\t\t\t\t║     *9.展示歌单               *0.返回上一级                     ║\n");
		printf("\t\t\t\t║                                                                 ║\n");
		printf("\t\t\t\t╚═════════════════════════════════════════════════════════════════╝\n");
		printf("\n\n\t\t\t\t %d%d:%d%d/%d%d:%d%d  ",
			MinTens_cur, MinOnes_cur, SecTens_cur, SecOnes_cur,
			MinTens_total, MinOnes_total, SecTens_total, SecOnes_total);
		for (int j = 0; j <= LENGTH * current / length; j++) {
			printf("═");
		}
		
		Sleep(1000);
		system("CLS");
	}
	return getch() - 48;

}

void face_fileFailure() {
	system("CLS");
	printf("\t\t\t\t╔═══════════════════════════════════════════════╗\n");
	printf("\t\t\t\t║                 文件打开失败!                ║\n");
	printf("\t\t\t\t╚═══════════════════════════════════════════════╝\n");
	return;
}

void face_userNotFound() {
	printf("\t\t\t\t╔═══════════════════════════════════════════════╗\n");
	printf("\t\t\t\t║                 找不到该用户!                ║\n");
	printf("\t\t\t\t╚═══════════════════════════════════════════════╝\n");
	Sleep(3000);
	return;
}

void face_passwordWrong() {
	printf("\t\t\t\t╔═══════════════════════════════════════════════╗\n");
	printf("\t\t\t\t║                    密码错误!                 ║\n");
	printf("\t\t\t\t╚═══════════════════════════════════════════════╝\n");
	Sleep(3000);
}

void face_welcome(struct user* p) {
	system("CLS");
	printf("\t\t\t\t╔═══════════════════════════════════════════════╗\n");
	printf("\t\t\t\t║                   欢迎%-5s!                 ║\n", p->account);
	printf("\t\t\t\t╚═══════════════════════════════════════════════╝\n");
}

char* input_AC() {
	char account[100];
	system("CLS");
	printf("\t\t\t\t╔═══════════════════════════════════════════════╗\n");
	printf("\t\t\t\t║                请输入您的用户名:             ║\n");
	printf("\t\t\t\t╚═══════════════════════════════════════════════╝\n");
	printf("\t\t\t\t ");
	scanf("%s", account);
	return account;
}

char* input_re_AC() {
	char account[100];
	printf("\t\t\t\t╔═══════════════════════════════════════════════╗\n");
	printf("\t\t\t\t║      用户名已存在,请重新输入您的用户名:     ║\n");
	printf("\t\t\t\t╚═══════════════════════════════════════════════╝\n");
	printf("\t\t\t\t ");
	scanf("%s", account);
	return account;
}

char* input_PW() {
	char password[100];
	printf("\t\t\t\t╔═══════════════════════════════════════════════╗\n");
	printf("\t\t\t\t║                 请输入您的密码:              ║\n");
	printf("\t\t\t\t╚═══════════════════════════════════════════════╝\n");
	printf("\t\t\t\t ");
	scanf("%s", password);
	return password;
}

void face_newACsuc() {
	printf("\t\t\t\t╔═══════════════════════════════════════════════╗\n");
	printf("\t\t\t\t║                   注册成功!                  ║\n");
	printf("\t\t\t\t╚═══════════════════════════════════════════════╝\n");
	Sleep(3000);
	return;
}

void listMedia(struct media* head) {
	struct media* p = head->next;
	printf("\t\t\t\t╔═══════════════════════════════════════════════╗\n");
	printf("\t\t\t\t║                                               ║\n");
	while (p != NULL)
	{
		printf("\t\t\t\t║   \t*输入%1d,将播放曲目%-10s\t    \t║\n", p->num, p->name);
		p = p->next;
	}//输出链表中的全部信息
	printf("\t\t\t\t║                                               ║\n");
	printf("\t\t\t\t╚═══════════════════════════════════════════════╝\n");

}

void listSongList(struct list* head) {
	struct list* p = head->next;
	printf("\t\t\t\t╔═══════════════════════════════════════════════╗\n");
	printf("\t\t\t\t║                                               ║\n");
	while (p != NULL)
	{
		printf("\t\t\t\t║   \t*输入%1d,将展示歌单%-10s\t    \t║\n", p->num, p->name);
		p = p->next;
	}//输出链表中的全部信息
	printf("\t\t\t\t║                                               ║\n");
	printf("\t\t\t\t╚═══════════════════════════════════════════════╝\n");

}

 2、list.c的源代码

#include<stdio.h>
#include<stdlib.h>
#include <Windows.h>
#include <mmsystem.h>
#include <io.h>
#include"play.h"
#include"list.h"

char path_list[150] = "mediaList.txt";

//读取指定文件中的用户信息,并把相关信息储存到链表
struct list* pre_list() {
	FILE* fp;

	fp = fopen(path_list, "r");  //打开文件 
	if (fp == NULL)
	{
		face_fileFailure();//输出文件打开失败!\n
		return NULL;
	}

	struct list* head, * p, * q;
	int number = 1;//记录歌单个数

	head = (struct list*)malloc(sizeof(struct list));
	head->next = NULL;
	p = (struct list*)malloc(sizeof(struct list));

	fscanf(fp, "%s", p->name);
	p->num = number;
	head->next = p;

	while (!feof(fp)) {

		number++;
		q = (struct list*)malloc(sizeof(struct list));
		fscanf(fp, "%s", q->name);
		q->num = number;
		q->next = NULL;
		p->next = q;
		p = q;
	}

	p = head->next;

	fclose(fp);

	return head;

}

//输入歌单编号,返回指向对应歌单信息的指针
struct list* getChoice_list(struct list* head)//输入歌曲编号,返回指向对应歌曲信息的指针
{
	int choice_list;
	int flag_list = 0;//1表示成功输入了歌曲编号
	struct list* p = head->next;

	printf("\t\t\t\t请输入歌单编号");
	scanf("%d", &choice_list);
	while (p != NULL) {
		if (p->num == choice_list) {
			flag_list = 1;
			break;
		}
		p = p->next;
	}

	while (flag_list == 0) {
		p = head->next;
		printf("\t\t\t\t不存在!请重新输入");
		scanf("%d", &choice_list);
		while (p != NULL) {
			if (p->num == choice_list) {
				flag_list = 1;
				break;
			}
			p = p->next;
		}
	}
	return p;
}

//将指定歌单中的歌曲信息存入链表中,并返回链表的头节点
struct media* loadMedia(struct list* p0) {

	FILE* fp;
	char path[150];

	strcpy(path, p0->name);

	fp = fopen(path, "r");  //打开文件 
	if (fp == NULL)
	{
		face_fileFailure();//输出文件打开失败!\n
		return NULL;
	}

	struct list* head, * p, * q;
	int number = 1;//记录歌曲个数

	head = (struct media*)malloc(sizeof(struct media));
	head->next = NULL;
	p = (struct media*)malloc(sizeof(struct media));

	fscanf(fp, "%s", p->name);
	p->num = number;
	head->next = p;

	while (!feof(fp)) {

		number++;
		q = (struct list*)malloc(sizeof(struct list));
		fscanf(fp, "%s", q->name);
		q->num = number;
		q->next = NULL;
		p->next = q;
		p = q;
	}

	p = head->next;

	fclose(fp);

	return head;
}

3、main.c的源代码

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<string.h>
#include"user.h"
#include"face.h"
#include"play.h"
#include"list.h"

int main() {

	struct media* HEAD_MEDIA = NULL; //歌曲信息以链表形式存储,HEAD_MEDIA为链表头
	struct user* HEAD_USER = pre_user();//用户信息以链表形式存储,HEAD_USER为链表头
	struct list* HEAD_LIST = pre_list();//歌单信息以链表形式存储,HEAD_LIST为链表头
	struct user* p_user = NULL;//指针,指向当前用户的节点
	struct media* p_media = NULL;//指针,指向当前播放的歌曲的节点
	struct list* p_list = NULL;

	int choice;//储存选择的登录、注册或退出的选项
	int flag_logIn = 0;//记录登录状态,1表示已登录
	int choice_play = 0;//储存选择的播放功能的选项
	int choice_song = 0;//储存选择的播放曲目的序号
	int flag_play = 1;//记录播放状态,0表示退出播放

	while (flag_logIn == 0) {

		choice = face_user();//输出列表——1.登录,2.注册,3.输入;返回代表选项的int值

		switch (choice)
		{
		case 1://登录并播放歌曲
			HEAD_MEDIA = pre_media();
			p_user = logIn(HEAD_USER);
			if (p_user != NULL) {
				flag_logIn = 1;
				listMedia(HEAD_MEDIA);//显示歌曲列表
				p_media = getChoice_media(HEAD_MEDIA);//输入歌曲编号,返回指向对应歌曲信息的指针
				play(p_media);
				flag_play = 1;
				while (flag_play == 1) {
					choice_play = face_play(p_media);

					switch (choice_play)
					{
					case 1://暂停or继续
						switchPlay(p_media);
						break;
					case 2://选曲播放
						stop(p_media);
						listMedia(HEAD_MEDIA);
						p_media = getChoice_media(HEAD_MEDIA);
						play(p_media);
						break;
					case 3://上一首
						stop(p_media);
						p_media = getLast(p_media, HEAD_MEDIA);
						play(p_media);
						break;
					case 4://下一首
						stop(p_media);
						p_media = getNext(p_media, HEAD_MEDIA);
						play(p_media);
						break;
					case 5://音量-
						volumeDown(p_media);
						break;
					case 6://音量+
						volumeUp(p_media);
						break;
					case 7://快进15秒
						goAhead15(p_media);
						break;
					case 8://快退15秒
						drawBack15(p_media);
						break;
					case 9://展示歌单
						stop(p_media);
						p_list = HEAD_LIST->next;
						listSongList(HEAD_LIST);
						p_list = getChoice_list(HEAD_LIST);
						printf("\n\t\t\t\t %s\n", p_list->name);
						HEAD_MEDIA = loadMedia(p_list);
						listMedia(HEAD_MEDIA);//显示歌曲列表
						p_media = getChoice_media(HEAD_MEDIA);//输入歌曲编号,返回指向对应歌曲信息的指针
						play(p_media);
						break;
					case 0://退出播放
						stop(p_media);
						flag_play = 0;
						flag_logIn = 0;
						break;
					}
				}
			}
			break;
		case 2://注册账号
			createAC(HEAD_USER);
			break;
		case 0://退出程序
			return 0;
		}
	}
}

4、play.c的源代码(本文主要讲解该部分内容) 

#include<stdio.h>
#include<stdlib.h>
#include <Windows.h>
#include <mmsystem.h>
#include <io.h>
#include"play.h"

char filepath[100] = "C:\\Users\\HP\\Music\\";//储存MP3文件的目录,用于向mciSendString函数传递指令
char catalog[150] = "C://Users//HP//Music";  //储存MP3文件的目录,用于读取指定文件夹中的文件
char type[20] = "mp3";//文件类型

//播放
void play(struct media* p0)
{
	char cmd[100];
	char file[100] = "open ";
	char play[100] = "play ";
	sprintf(cmd, "%s%s", filepath, p0->name);
	printf("%s", cmd);
	strcat(file, cmd);
	strcat(play, cmd);
	mciSendString(file, NULL, 0, NULL);
	mciSendString(play, NULL, 0, NULL);
}

//获取下一首歌的指针
struct media* getNext(struct media* p0, struct media* head)
{
	struct media* p = NULL;
	if (p0->next == NULL) {
		p = head->next;
	}
	else {
		p = p0->next;
	}
	return p;
}

//获取上一首歌的指针
struct media* getLast(struct media* p0, struct media* head) 
{
	struct media* p = head->next;
	while (p != NULL) {
		if (p->next == p0) {
			return p;
		}
		p = p->next;
	}
	if (p == NULL) {
		p = head;
		while (p->next != NULL) {
			p = p->next;
		}
		return p;
	}
}

//暂停播放
void pause(struct media* p0)
{
	char cmd[100];
	char file[100] = "pause ";
	sprintf(cmd, "%s%s", filepath, p0->name);
	strcat(file, cmd);
	mciSendString(file, NULL, 0, NULL);
}

//继续播放
void continue_play(struct media* p0)
{
	char cmd[100];
	char file[100] = "resume ";
	sprintf(cmd, "%s%s", filepath, p0->name);
	strcat(file, cmd);
	mciSendString(file, NULL, 0, NULL);
}

//获取歌曲的播放状态
char* getState (struct media* p0)
{
	char state[20];
	char cmd[100] = "status ";
	strcat(cmd, filepath);
	strcat(cmd, p0->name);
	strcat(cmd," mode");
	mciSendString(cmd, state, 20, 0);
	return state;
}

//播放或暂停
void switchPlay(struct media* p0)
{
	struct media* p = p0;
	struct media* p2 = p0;
	int a;
	char state[20];
	strcpy(state, getState(p));
	if (strcmp(state, "playing") == 0) {
		pause(p);
	}
	else if (strcmp(state, "paused") == 0) {
		continue_play(p);
	}
	else if (strcmp(state, "stopped") == 0) {
		stop(p);
		play(p);
	}
	else {
		printf("ERROR!\n");
	}
}

//停止播放
void stop(struct media* p0)
{
	char cmd[100];
	char file[100] = "close ";
	sprintf(cmd, "%s%s", filepath, p0->name);
	strcat(file, cmd);
	mciSendString(file, NULL, 0, NULL);
}

//调低音量
void volumeDown(struct media* p0)
{
	char res[260];
	char cmd[100];
	char file1[100] = "status ";
	char file2[100] = " volume";
	char text1[100] = "setaudio ";
	char text2[100] = " volume to ";
	char vo[20];
	int a;
	sprintf(cmd, "%s%s", filepath, p0->name);
	strcat(file1, cmd);
	strcat(file1, file2);
	mciSendString(file1, res, 260, NULL);
	int  volume = 0;
	volume = atoi(res);
	volume -= 200;
	itoa(volume, vo, 10);
	strcat(text1, cmd);
	strcat(text1, text2);
	strcat(text1, vo);
	mciSendString(text1, NULL, 0, NULL);
}

//调高音量
void volumeUp(struct media* p0)
{
	char res[260];
	char cmd[100];
	char file1[100] = "status ";
	char file2[100] = " volume";
	char text1[100] = "setaudio ";
	char text2[100] = " volume to ";
	char vo[20];
	int a;
	sprintf(cmd, "%s%s", filepath, p0->name);
	strcat(file1, cmd);
	strcat(file1, file2);
	mciSendString(file1, res, 260, NULL);
	int  volume = 0;
	volume = atoi(res);
	volume += 200;
	itoa(volume, vo, 10);
	strcat(text1, cmd);
	strcat(text1, text2);
	strcat(text1, vo);
	mciSendString(text1, NULL, 0, NULL);
}

//读取指定文件夹中的MP3文件,并把歌曲相关信息储存到链表
struct media* pre_media()
{
	struct media* head, * p, * q;
	int number = 1;//记录MP3文件个数

	head = (struct media*)malloc(sizeof(struct media));
	head->next = NULL;
	p = (struct media*)malloc(sizeof(struct media));

	long handle;    //句柄
	struct _finddata_t fileinfo;   //文件信息结构体

	char search[150];  //欲查找的文件,支持通配符
	strcpy(search, catalog);
	strcat(search, "\\\\*.");
	strcat(search, type);  // search = C:/Users/吹峰机/Music/*.mp3

	handle = _findfirst(search, &fileinfo);    //第一次查找
	if (-1 == handle)
	{
		printf("未找到所需文件。\n");
		return head;
	}

	strcpy(p->name, fileinfo.name);
	p->num = number;
	head->next = p;
	while (!_findnext(handle, &fileinfo)) //循环查找其他符合的文件,直到找不到其他的为止
	{
		number++;
		q = (struct media*)malloc(sizeof(struct media));
		strcpy(q->name, fileinfo.name);
		q->num = number;
		q->next = NULL;
		p->next = q;
		p = q;
	}//在链表中添加当前查找到的MP3文件
	_findclose(handle); //关闭句柄

	return head;
}

//输入歌曲编号,返回指向对应歌曲信息的指针
struct media* getChoice_media(struct media* head)
{
	int choice_media;
	int flag_media = 0;//1表示成功输入了歌曲编号
	struct media* p = head->next;

	printf("\t\t\t\t请输入歌曲编号");
	scanf("%d", &choice_media);
	while (p != NULL){
		if (p->num == choice_media) {
			flag_media = 1;
			break;
		}
		p = p->next;
	}
	
	while (flag_media == 0){
		p = head->next;
		printf("\t\t\t\t不存在!请重新输入");
		scanf("%d", &choice_media);
		while (p != NULL) {
			if (p->num == choice_media) {
				flag_media = 1;
				break;
			}
			p = p->next;
		}
	}
	return p;
}

//快进15秒
void goAhead15(struct media* p0)
{
	int position;
	char cmd[100];
	char file1[100] = "seek ";
	char file2[100] = " to ";
	char file3[100];
	char text1[100] = "status ";
	char text2[100] = " position";
	char st[100];
	char word1[100] = "play ";

	sprintf(cmd, "%s%s", filepath, p0->name);

	strcat(file1, cmd);
	strcat(file1, file2);

	strcat(text1, cmd);
	strcat(text1, text2);
	mciSendString(text1, st, 100, 0);

	position = atoi(st);
	position += 15000;
	itoa(position, file3, 10);
	strcat(file1, file3);
	mciSendString(file1, NULL, 0, NULL);

	strcat(word1, cmd);
	mciSendString(word1, NULL, 0, NULL);
}

//快退15秒
void drawBack15(struct media* p0) 
{
	int position;
	char cmd[100];
	char file1[100] = "seek ";
	char file2[100] = " to ";
	char file3[100];
	char text1[100] = "status ";
	char text2[100] = " position";
	char st[100];
	char word1[100] = "play ";

	sprintf(cmd, "%s%s", filepath, p0->name);

	strcat(file1, cmd);
	strcat(file1, file2);

	strcat(text1, cmd);
	strcat(text1, text2);
	mciSendString(text1, st, 100, 0);

	position = atoi(st);
	position -= 15000;
	itoa(position, file3, 10);
	strcat(file1, file3);
	mciSendString(file1, NULL, 0, NULL);

	strcat(word1, cmd);
	mciSendString(word1, NULL, 0, NULL);
}

5、user.c的源代码

#include<stdio.h>
#include <io.h>
#include<string.h>
#include"face.h"

struct user {
	int num;
	char account[100];
	char password[100];
	struct user* next;
};

char path_user[150] = "userInfo.txt";  //储存用户信息的文件

//读取指定文件中的用户信息,并把相关信息储存到链表
struct user* pre_user()
{

	FILE* fp;

	fp = fopen(path_user, "r");  //打开文件 
	if (fp == NULL)
	{
		face_fileFailure();//输出文件打开失败!\n
		return NULL;
	}

	struct user* head, * p, * q;
	int number = 1;//记录用户个数

	head = (struct user*)malloc(sizeof(struct user));
	head->next = NULL;
	p = (struct user*)malloc(sizeof(struct user));

	fscanf(fp, "%s", p->account);
	fscanf(fp, "%s", p->password);
	p->num = number;
	head->next = p;

	while (!feof(fp)) {
		
		number++;
		q = (struct user*)malloc(sizeof(struct user));
		fscanf(fp, "%s", q->account);
		fscanf(fp, "%s", q->password);
		q->num = number;
		q->next = NULL;
		p->next = q;
		p = q;
	}

	p = head->next;

	fclose(fp);
	return head;
}

//用户登录
struct user* logIn(struct user* head) 
{
	char account[100];
	char password[100];
	struct user* p = head->next;
	
	strcpy(account, input_AC());

	while (p != NULL && strcmp(p->account, account) != 0) {
		p = p->next;
	}
	if (p == NULL) {
		face_userNotFound();//输出"找不到该用户"
		return NULL;
	}

	strcpy(password, input_PW());

	if (strcmp(p->password, password) != 0) {
		face_passwordWrong();//输出 "密码错误";
		return NULL;
	}
	if (strcmp(p->password, password) == 0) {
		face_welcome(p);//printf"欢迎p->account";
		return p;
	}
}

//用户注册
void createAC(struct user* head)
{
	
	FILE* fp;
	fp = fopen(path_user, "a");
	if (fp == NULL) {
		face_fileFailure();
	}
	else {
		char account[100];
		char password[100];
		struct user* p = NULL;
		int flag_repe = 0;//0表示该用户名没有和别个的account重复,1表示重复了
		struct user* q = (struct user*)malloc(sizeof(struct user));

		strcpy(account, input_AC());

		p = head->next;
		while (p != NULL) {
			if (strcmp(p->account, account) == 0) {
				flag_repe = 1;
			}
			p = p->next;
		}
		while (flag_repe == 1){
			p = head->next;
			flag_repe = 0;
			strcpy(account, input_re_AC());
			while (p != NULL) {
				if (strcmp(p->account, account) == 0) {
					flag_repe = 1;
				}
				p = p->next;
			}
		}

		strcpy(password, input_PW());

		p = head;
		while (p->next != NULL) {
			p = p->next;
		}
		strcpy(q->account, account);
		strcpy(q->password, password);
		q->next = NULL;
		p->next = q;

		fprintf(fp, "\n%s\n%s", account, password);
		fclose(fp);

		face_newACsuc();
	}
}

6、face.h

#include<stdio.h>

int face_user();
int face_play();
int face_play2();




void face_fileFailure();
void face_userNotFound();
void face_passwordWrong();
void face_welcome(struct user* p);
char* input_AC();
char* input_re_AC();
char* input_PW();
void face_newACsuc();
void listMedia(struct media* head);
void listSongList(struct list* head);


 7、list.h的源代码

#include<stdio.h>
#include<stdlib.h>
#include <Windows.h>
#include <mmsystem.h>
#include <io.h>

struct list {
	int num;
	char name[100];//歌单名称
	struct list* next;
};

struct list* pre_list();
struct list* getChoice_list(struct list* head);
struct media* loadMedia(struct list* p);

8、play.h的源代码

#include <stdio.h>
#include <io.h>

struct media {
	int num; // 编号
	char name[100]; //歌曲名称
	struct media* next; // 存储下一曲的地址
};

struct media* pre_media();
struct media* getChoice_media(struct media* head);
void play(struct media* p0);//播放
void pause(struct media* p0);//暂停播放
void continue_play(struct media* p0);//继续播放
void stop(struct media* p0);//停止播放
void volumeDown(struct media* p0);//音量减小
void volumeUp(struct media* p0);//音量增大
struct media* getNext(struct media* p0, struct media* head);
struct media* getLast(struct media* p0, struct media* head);
void volumeDown(struct media* p0);
void volumeUp(struct media* p0);
void switchPlay(struct media* p0);
char* getState(struct media* p0);
void goAhead15(struct media* p0);
void drawBack15(struct media* p0);

9、user.h的源代码

#include<stdio.h>
#include <io.h>
#include<string.h>

struct user {
	int num;
	char account[100];
	char password[100];
	struct user* next;
};

struct user* logIn(struct user* head);
void createAC(struct user* head);
struct user* pre_user();

本文标签: 播放器 使用方法 函数 步骤 完整