(十六)EGE音乐播放

目录

  • 音乐播放
    • winmm.lib 库的链接检查
    • MUSIC类
    • 让音乐播放起来
      • 先把文件扩展名显示设置打开
      • 进入当前目录
      • 把音乐文件放到源文件旁边
      • 播放音乐的程序
        • 测试程序
        • 如果音乐文件名正确,但是还是无法打开音乐文件
    • 音乐播放器控制
        • OpenFile() 打开音乐文件
        • IsOpen() 检测音乐文件是否成功打开
        • GetPlayStatus() 获取播放状态
        • Play() 播放音乐
        • Pause() 暂停播放
        • Seek() 调节播放进度
        • Stop() 停止播放
        • GetLength() 获取音乐时长
        • GetPosition() 获取音乐播放进度
        • SetVolume() 调节音量
        • Close() 关闭音乐文件
    • 音乐播放状态切换示例
    • 注意事项
      • 音乐自动播放完毕
    • 音乐播放示例程序

音乐播放

winmm.lib 库的链接检查

  音乐播放需要使用到 winmm.lib 库,如果你是使用的VC编译器,因为源代码中加了 #pragma 编译指令,会自动链接用到的一些库,所以你使用VC的编译器话,那么就不用手动添加链接库了。
  但是用 #pragma链接库只对VC编译器有效,所以使用CodeBlocksDevC++ 的需要手动添加链接库
  音乐播放相关需要用到 winmm.lib 库, 所以必须加到链接库里,否则会出现链接错误(undefined reference to)
CodeBlocks 是加上libwinmm.a, 如下图,倒数第二个(配置时已经添加
CodeBlocks
(十六)EGE音乐播放_第1张图片
DevC++ 是加上 -lwinmm 的编译参数, 如下图(有些教程的配置里没加上,自己检查一下)
64位链接库的编译参数是

-lgraphics64 -luuid -lmsimg32 -lgdi32 -limm32 -lole32 -loleaut32 -lwinmm

32位链接库的编译参数是

-lgraphics -luuid -lmsimg32 -lgdi32 -limm32 -lole32 -loleaut32 -lwinmm

(十六)EGE音乐播放_第2张图片

MUSIC类

  EGE有用于控制音乐播放的 MUSIC类, 是对 windowsAPI的一个封装,调用了 中的函数。
  类定义如下:

typedef unsigned long DWORD;

class MUSIC
{
public:
	MUSIC();
	virtual ~MUSIC();
	operator HWND()const{ return (HWND)m_dwCallBack; }
public:
	int   IsOpen() { return (m_DID != MUSIC_ERROR) ? 1 : 0; }
	DWORD OpenFile(LPCSTR  filepath);
	DWORD OpenFile(LPCWSTR filepath);
	DWORD Play(DWORD dwFrom = MUSIC_ERROR, DWORD dwTo = MUSIC_ERROR);
	DWORD Pause();
	DWORD Seek(DWORD dwTo); //播放位置定位,单位为ms
	DWORD SetVolume(float value);
	DWORD Close();
	DWORD Stop();
	DWORD GetPosition();
	DWORD GetLength();
	// 以下函数GetPlayStatus的返回值为以下之一(意义看后缀):
	// MUSIC_MODE_NOT_OPEN   //没有正确打开
	// MUSIC_MODE_NOT_READY  //设备没准备好 (较少使用)
	// MUSIC_MODE_PAUSE  //暂停中
	// MUSIC_MODE_PLAY   //正在播放
	// MUSIC_MODE_STOP   //成功打开后,或者播放完是这个状态
	// MUSIC_MODE_OPEN   //打开中 (较少使用)
	// MUSIC_MODE_SEEK   //定位中 (较少使用)
	DWORD GetPlayStatus();
private:
	DWORD       m_DID;
	PVOID       m_dwCallBack;
};

让音乐播放起来

先把文件扩展名显示设置打开

打开 文件资源管理器, 勾选上文件扩展名。这样就能看到完整的文件名。
在这里插入图片描述

进入当前目录

  如果你的源文件是新建的,那么就是源文件所在的目录。
  源文件就是你的代码文件, 建项目的时候创建有 .cpp 文件,懂吧?
(十六)EGE音乐播放_第3张图片

把音乐文件放到源文件旁边

  东西比较多,显得凌乱,为了简单方便,就直接把音乐文件放在源文件旁边。
(十六)EGE音乐播放_第4张图片

播放音乐的程序

  • 先定义一个MUSIC类变量
	MUSIC music;
  • 使用music.OpenFile( )打开音乐文件
    还可以使用 music.IsOpen() 检查是否打开了文件,打开成功返回true, 失败则返回false;
music.OpenFile("音乐文件名(带扩展名)");
  • 使用music.Play()播放音乐
music.Play();

所以想要打开音乐播放,使用如下代码便可

MUSIC music;
music.OpenFile("音乐文件名");
music.Play();			//当然,如果没打开成功,是播放不出来的

测试程序

  下面这个是音乐播放测试
  改成自己的音乐文件名, 带扩展名, 比如下面这首,就写成

music.OpenFile("马步谣-双笙.mp3");

(十六)EGE音乐播放_第5张图片

  • 先调节一下电脑的音量大小,以免放不出声音是因为没开声音

(十六)EGE音乐播放_第6张图片
  如果无法播放,请检查一下文件名是否写对,如果文件名写对了还是无法播放,往后看,有解决办法

#include 

int main()
{
	initgraph(640, 480, 0);
	setbkcolor(WHITE);
	setcolor(BLACK);
	setfont(40, 0, "楷体");

	MUSIC music;
	music.OpenFile("音乐名文件名(带扩展名)");
	
	//检查是否打开
	xyprintf(200, 220, "%s\n", music.IsOpen() ? "音乐打开成功" : "音乐打开失败");

	music.Play();
	
	getch();

	music.Close();

	closegraph();

	return 0;
}

如果音乐文件名正确,但是还是无法打开音乐文件

  可能是音乐文件的格式不兼容,所以打不开

解决方案:
  下载一个格式工厂, 新版的有可能不行。将音频文件转换成mp3格式(本来是mp3格式的也要过一遍

3.8版本格式工厂下载 http://down.pcgeshi.com/FormatFactory_3.8.0.0_setup.exe
4.8版本格式工厂下载
http://www.downza.cn/soft/187613.html

音乐播放器控制

MUSIC类使用方法:

OpenFile() 打开音乐文件

  打开音乐文件用的是 OpenFile() 函数, 参数是带扩展名的音乐文件名。
  比如我有个文件名为 musicFile.mp3的文件,在当前工作目录下(当前工作目录,一般是与新建的源文件同一个目录)。或者你直接使用带全路径的文件名
  那么打开文件方法如下:

	music.OpenFile("musicFile.mp3");

IsOpen() 检测音乐文件是否成功打开

  • 成功打开返回 true,否则返回false
if (music.IsOpen()) {
	音乐文件已经成功打开
}

GetPlayStatus() 获取播放状态

  下面可以获取播放状态

DWORD playStatus = music.GetPlayStatus();

  返回值是以下枚举值之一, 可以根据状态来判断。
  比如,播放完毕自动重放,可以检查状态是否为 MUSIC_MODE_STOP, 是的话就 Play(0)

enum music_state_flag {
   MUSIC_MODE_NOT_OPEN = 0x0,			未打开文件
   MUSIC_MODE_NOT_READY = 0x20C,		没准备好
   MUSIC_MODE_PAUSE = 0x211,			暂停播放状态
   MUSIC_MODE_PLAY = 0x20E,				正在播放
   MUSIC_MODE_STOP = 0x20D,				停止播放状态
   MUSIC_MODE_OPEN = 0x212,				已打开文件
   MUSIC_MODE_SEEK = 0x210,				播放进度条调整(未播放)
};

  音乐打开加载完成后,播放状态为 MUSIC_MODE_STOP

Play() 播放音乐

  检测到音乐文件已经成功打开后,便可以播放音乐。
  函数声明如下:
  下面的时间指的是音乐的时间,单位是毫秒

DWORD Play(DWORD dwFrom = MUSIC_ERROR, DWORD dwTo = MUSIC_ERROR);

Play(开始时间, 结束时间)

  • 继续播放使用
music.Play();
  • 从音乐某个时间开始播放至音乐结束
music.Play(开始时间);

  而且 music.Play(开始时间) 还可以调整播放进度,而且是立即播放
  播放时状态是MUSIC_MODE_PLAY

  • 从音乐某个时间开始播放,播放到指定时间停止
music.Play(开始时间, 结束时间);

Pause() 暂停播放

  暂停后状态是 MUSIC_MODE_PAUSE

music.Pause();

Seek() 调节播放进度

  但是我实验了好像Seek() 不能用,可以用 Play(时间) 代替

	music.Seek( 毫秒数);

  换成下面这个

   music.Play(毫秒数);

Stop() 停止播放

停止是调用Stop()
调用后,播放状态是MUSIC_MODE_STOP
调用 Stop(), 仅仅是将播放状态设为MUSIC_MODE_STOP, 并且暂停播放
但是播放进度并没有变,将停留在刚才的进度,你使用Play() 会从刚才停的地方继续播放。所以如果是处于停止状态,应该使用Play(0) , 而不是Play(),否则和暂停没区别

如果想要进度马上调整到开始处,可以使用

   music.Play(0);
   music.Stop();

停止后的播放应该是

if (music.GetPlayStatus() == MUSIC_MODE_STOP) {
	musci.play(0);
}

GetLength() 获取音乐时长

返回音乐的总时长,单位是毫秒。

int musicDuration = music.GetLength();

GetPosition() 获取音乐播放进度

(已播放的时间,单位是毫秒)

int playTime = music.GetPosition();

SetVolume() 调节音量

参数是float 型的,范围是0.0 ~ 1.0, 0表示没有声音,大于1和1无差别
默认是1.0
(这个音量是基于电脑的扬声器大小调节的,不会改变电脑的扬声器大小)

music.SetVolume(volume);

Close() 关闭音乐文件

不使用当前音乐后,可以关闭当前音乐文件,同时音乐播放也就停止了。
如果想要用同一个 MUSIC 对象打开另一个音乐文件,需要先关闭再打开。
MUSIC类对象被销毁时自动调用Close()进行关闭

music.Close();

音乐播放状态切换示例

控制的时候先获取一下播放状态

  • 播放
    第一次播放直接 Play() 就可, 如果是在播放时候切换状态,可以先检测一下,避免多余操作。
    方法: 如果是暂停,那么调用 Play() 继续播放,如果是停止,那么调用 Play(0) 重新播放(如果你停止的时候已经调用Play(0)将进度调整到了开头,那么直接用Play()就行)
DWORD status = music.GetPlayStatus();
if (status == MUSIC_MODE_PAUSE)
	music.Play();
else if (status == MUSIC_MODE_STOP)
	music.Play(0);
  • 暂停
    如果正在播放,那么就暂停
DWORD status = music.GetPlayStatus();
if (status == MUSIC_MODE_PLAY)
	music.Pause();
  • 停止
    如果处于播放或暂停,那么先调用 Play(0) 将进度调至开头,再调用 Stop() 停止(因为单单调用Stop()并不会改变播放进度)
DWORD status = music.GetPlayStatus();
if (status != MUSIC_MODE_STOP) {	
	music.Play(0);
	music.Stop();
}
  • 播放暂停切换
DWORD status = music.GetPlayStatus();
if (status == MUSIC_MODE_PLAY)
	music.Pause();
else if (status == MUSIC_MODE_PAUSE)
	music.Play();
else if (status == MUSIC_MODE_STOP)
	music.Play(0);

  • 调整播放进度
    直接调用Play(播放时间), 单位是毫秒

注意事项

音乐自动播放完毕

音乐自动播放完毕后,状态为 MUSIC_MODE_STOP = 0x20D,此时调用 Play() 是无法继续播放的, 需要使用 Play(0) ,设置播放进度到开始位置。

  • 自动重播
//如果音乐已经播放完毕
if (music.GetPlayStatus() == MUSIC_MODE_STOP ) {
	//从头开始播放
	music.Play(0);
}

音乐播放示例程序

音乐文件名替换成自己的

如果遇到音乐不能播放,音乐文件名写成绝对路径形式试试,再不行就把音乐用格式工厂过一遍,转mp3再试试

#include 
#include 
#include 

class ProgressBar
{
private:
	//进度条样式参数
	int x, y, width, height;	//位置,尺寸
	color_t progressBkcolor;	//进度条背景色
	color_t progressColor;		//进度条进度颜色
	float progress;				//进度

public:
	ProgressBar(int x, int y, int width, int height) : x(x), y(y), width(width), height(height) {
		progressBkcolor = LIGHTGRAY;
		progressColor = LIGHTBLUE;
		progress = 0.0f;
	}

	void setProgress(float progress) {
		this->progress = progress;
		draw();
	}

private:
	void draw() {
		int cur = (int)(x + width * progress);

		setfillcolor(progressColor);
		bar(x, y, cur, y + height);
		setfillcolor(progressBkcolor);
		bar(cur, y, x + width, y + height);
	}
};

int main()
{
	initgraph(640, 480, INIT_RENDERMANUAL);			//初始化窗口
	setcaption("EGE音乐播放");		//设置窗口标题

	setbkcolor(WHITE);
	setcolor(BLACK);
	setfont(16, 0, "楷体");

	xyprintf(20, 20, "按空格键播放/暂停, S 键停止");
	xyprintf(20, 40, "P键增大音量,M键减小音量");
	xyprintf(20, 60, "N键前进,B键后退");
	xyprintf(20, 80, "Q键退出");

	setcolor(LIGHTBLUE);

	//手动渲染模式,先刷新一下窗口,让背景色先出来
	//因为音乐加载需要时间,这段时间窗口是黑色的
	delay_ms(0);

	MUSIC music;
	//音乐文件名,改成自己的音乐
	const char* musicFile = "resource/music/薛之谦 - 花儿和少年.mp3";
	//找歌名位置
	size_t len = strlen(musicFile);
	while (len > 0 && musicFile[len] != '/' && musicFile[len] != '\\') {
		--len;
	}
	const char* musicName = musicFile + len + 1;
	music.OpenFile(musicFile);

	if (music.IsOpen()) {
		ProgressBar progressBar(20, 200, 500, 20);
		progressBar.setProgress(0.0f);

		music.Play(0);

		int playTime = 0;				
		int totalTime = music.GetLength();		//获取音乐总时长(单位:毫秒)
		float volume = 0.8f;					//音量	
		music.SetVolume(volume);

		xyprintf(20, 160, "音乐名:%s", musicName);
		xyprintf(400, 240, "音乐总时长:%02d:%02d",
			totalTime / 1000 / 60, totalTime / 1000 % 60);

		bool exit = false;

		//上次调节进度时间
		double lastAdjustTime = fclock(), curtime = lastAdjustTime;

		//检测键盘,控制音乐播放
		for (; is_run(); delay_fps(20)) {
			if (exit)
				break;

			while (kbmsg()) {
				key_msg keyMsg = getkey();
				if (keyMsg.msg != key_msg_down)
					continue;

				DWORD status = music.GetPlayStatus();
				int key = keyMsg.key;
				switch (key) {
				case 'Q':		//退出
					exit = true;
					break;
				case ' ':		//播放暂停切换
					if (status == MUSIC_MODE_PLAY)
						music.Pause();
					else if (status == MUSIC_MODE_PAUSE)
						music.Play();
					else if (status == MUSIC_MODE_STOP)
						music.Play(0);
					
					break;
				case 'S':		//停止
					if (status != MUSIC_MODE_STOP) {	
						music.Play(0);
						music.Stop();
					}
					break;

				case 'P':		//增加音量
					if ((volume += 0.1f) >= 1)
						volume = 1;
					music.SetVolume(volume);
					break;
				case 'M':		//减小音量
					if ((volume -= 0.1f) < 0)
						volume = 0;
					music.SetVolume(volume);
					break;
				case 'N':		//快进
					//no-break;
				case 'B':		//快退
					curtime= fclock();
					if (curtime- lastAdjustTime < 0.3)
						break;
					lastAdjustTime = curtime;

					if (key == 'N') {
						playTime += 10 * 1000;
						if (playTime > totalTime)
							playTime = totalTime;
					}
					else {
						playTime -= 10 * 1000;
						if (playTime < 0)
							playTime = 0;
					}
					music.Play(playTime);
					break;
				}
			}
			//获取播放时间(毫秒)
			int pos = music.GetPosition();

			//更新进度条
			if (pos != playTime) {
				playTime = pos;
				progressBar.setProgress(playTime * 1.0f / totalTime);
			}
			xyprintf(20, 240, "播放进度%02d:%02d", playTime / 1000 / 60, playTime / 1000 % 60);
			xyprintf(20, 280, "音量%3.0f%%", (volume * 100));
		}

		//关闭音乐
		music.Close();
	}
	else {
		xyprintf(50, 200, "打开音乐失败,请检查音乐文件名");
		getch();
	}

	closegraph();

	return 0;
}

(十六)EGE音乐播放_第7张图片
  播放、暂停、停止,前进后退,显示音乐时长和播放进度,调节音量都已实现。

你可能感兴趣的:(EGE)