如何在 C++ 程序中播放或打开 *.mp3 或 *.wav 声音文件?

2021-12-20 00:00:00 audio graphics visual-c++ c++

我是计算机科学专业的学生.我有一个最后一个学期的项目来开发一个带有声音的图形短游戏.

解决方案

首先编写如下代码:

#include #include //这两个头文件已经包含在<Windows.h>标题#pragma 注释(lib,Winmm.lib")

打开*.mp3:

mciSendString("open "*.mp3" type mpegvideo alias mp3", NULL, 0, NULL);

播放*.mp3:

mciSendString("播放mp3", NULL, 0, NULL);

播放并等待 *.mp3 播放完毕:

mciSendString("播放 mp3 等待", NULL, 0, NULL);

要重播(从头开始播放)*.mp3:

mciSendString("从 0 开始播放 mp3", NULL, 0, NULL);

要重播并等待 *.mp3 播放完毕:

mciSendString("从 0 开始播放 mp3 等待", NULL, 0, NULL);

播放 *.mp3 并在每次结束时像循环一样重播:

mciSendString("播放mp3重复", NULL, 0, NULL);

如果你想在*.mp3播放完毕后做点什么,那么你需要通过WNDCLASSEX结构体RegisterClassExCreateWindowEx并在 while 循环中使用 GetMessage、TranslateMessage 和 DispatchMessage 函数处理它的消息并调用:

mciSendString("播放 mp3 通知", NULL, 0, hwnd);//hwnd 是从 CreateWindowEx 返回的窗口句柄.如果这不起作用,则用 MAKELONG(hwnd, 0) 替换 hwnd.

在窗口程序中添加case MM_MCINOTIFY: mp3播放完毕后会执行其中的代码.

但是如果你编写一个控制台应用程序并且你不处理windows,那么你可以CreateThread 通过在 dwCreationFlags 参数中指定 CREATE_SUSPENDED 标志处于挂起状态,并将返回值保存在 static 变量中,并根据需要调用它.例如,我称之为 mp3.这个static变量的类型当然是HANDLE.

这是该线程的lpStartAddressThreadProc:

DWORD WINAPI MP3Proc(_In_ LPVOID lpParameter)//lpParameter 可以是指向存储数据的结构的指针,您无法在此函数之外访问该数据.你可以在 `CreateThread` 之前准备这个结构并在 `lpParameter` 中给出它的地址{数据 *data = (Data*)lpParameter;//如果你称这个结构体为Data,但你可以随意调用它.而(真){mciSendString("从 0 播放 mp3 等待", NULL, 0, NULL);//在这里做你想在mp3播放结束后做的事SuspendThread(GetCurrentThread());//或者你保存在一个静态变量中的这个线程的句柄}}

您现在要做的就是ResumeThread(mp3); 每次您想重播您的 mp3 时都会发生一些事情.

您可以#define play_my_mp3 ResumeThread(mp3);使您的代码更具可读性.

当然你可以删除while (true)SuspendThread和from 0代码,如果你想播放你的mp3文件只一次,结束后随心所欲.

如果您只删除SuspendThread 调用,那么声音将一遍又一遍地播放,并在结束时执行某些操作.这相当于:

mciSendString("播放 mp3 重复通知", NULL, 0, hwnd);//或 MAKELONG(hwnd, 0) 代替

在窗口中.

要在中间暂停 *.mp3:

mciSendString("暂停mp3", NULL, 0, NULL);

并恢复它:

mciSendString("恢复mp3", NULL, 0, NULL);

把它停在中间:

mciSendString("停止mp3", NULL, 0, NULL);

请注意,您无法恢复已停止的声音,而只能继续播放,但您可以通过执行 play 命令重新播放.播放完这个 *.mp3 后,不要忘记:

mciSendString("关闭mp3", NULL, 0, NULL);

所有这些操作也适用于(使用)波形文件,但是对于波形文件,您可以使用waveaudio"而不是mpegvideo".您也可以直接播放它们而无需打开它们:

PlaySound("*.wav", GetModuleHandle(NULL), SND_FILENAME);

如果您不想指定模块的句柄:

sndPlaySound("*.wav", SND_FILENAME);

如果不想等到播放结束:

PlaySound("*.wav", GetModuleHandle(NULL), SND_FILENAME | SND_ASYNC);//或者sndPlaySound("*.wav", SND_FILENAME | SND_ASYNC);

反复播放波形文件:

PlaySound("*.wav", GetModuleHandle(NULL), SND_FILENAME | SND_ASYNC | SND_LOOP);//或者sndPlaySound("*.wav", SND_FILENAME | SND_ASYNC | SND_LOOP);

请注意,您必须同时指定 SND_ASYNCSND_LOOP 标志,因为您永远不会等到重复无数次的声音结束!

您也可以使用 fread 函数fopen 波形文件并将它的所有字节复制到缓冲区(一个巨大/巨大(非常大)的字节数组)和然后:

PlaySound(buffer, GetModuleHandle(NULL), SND_MEMORY);//或者PlaySound(buffer, GetModuleHandle(NULL), SND_MEMORY | SND_ASYNC);//或者PlaySound(buffer, GetModuleHandle(NULL), SND_MEMORY | SND_ASYNC | SND_LOOP);//或者sndPlaySound(缓冲区,SND_MEMORY);//或者sndPlaySound(缓冲区,SND_MEMORY | SND_ASYNC);//或者sndPlaySound(缓冲区,SND_MEMORY | SND_ASYNC | SND_LOOP);

OpenFileCreateFileCreateFile2 以及 ReadFileReadFileEx 函数可以用来代替 fopenfread 函数.

希望这能完美回答您的问题.

I'm a student of Computer Science. I have a final semester Project to develop a short game in graphics along with the sound.

解决方案

First of all, write the following code:

#include <Mmsystem.h>
#include <mciapi.h>
//these two headers are already included in the <Windows.h> header
#pragma comment(lib, "Winmm.lib")

To open *.mp3:

mciSendString("open "*.mp3" type mpegvideo alias mp3", NULL, 0, NULL);

To play *.mp3:

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

To play and wait until the *.mp3 has finished playing:

mciSendString("play mp3 wait", NULL, 0, NULL);

To replay (play again from start) the *.mp3:

mciSendString("play mp3 from 0", NULL, 0, NULL);

To replay and wait until the *.mp3 has finished playing:

mciSendString("play mp3 from 0 wait", NULL, 0, NULL);

To play the *.mp3 and replay it every time it ends like a loop:

mciSendString("play mp3 repeat", NULL, 0, NULL);

If you want to do something when the *.mp3 has finished playing, then you need to RegisterClassEx by the WNDCLASSEX structure, CreateWindowEx and process it's messages with the GetMessage, TranslateMessage and DispatchMessage functions in a while loop and call:

mciSendString("play mp3 notify", NULL, 0, hwnd); //hwnd is an handle to the window returned from CreateWindowEx. If this doesn't work, then replace the hwnd with MAKELONG(hwnd, 0).

In the window procedure, add the case MM_MCINOTIFY: The code in there will be executed when the mp3 has finished playing.

But if you program a Console Application and you don't deal with windows, then you can CreateThread in suspend state by specifying the CREATE_SUSPENDED flag in the dwCreationFlags parameter and keep the return value in a static variable and call it whatever you want. For instance, I call it mp3. The type of this static variable is HANDLE of course.

Here is the ThreadProc for the lpStartAddress of this thread:

DWORD WINAPI MP3Proc(_In_ LPVOID lpParameter) //lpParameter can be a pointer to a structure that store data that you cannot access outside of this function. You can prepare this structure before `CreateThread` and give it's address in the `lpParameter`
{
    Data *data = (Data*)lpParameter; //If you call this structure Data, but you can call it whatever you want.
    while (true)
    {
        mciSendString("play mp3 from 0 wait", NULL, 0, NULL);
        //Do here what you want to do when the mp3 playback is over
        SuspendThread(GetCurrentThread()); //or the handle of this thread that you keep in a static variable instead
    }
}

All what you have to do now is to ResumeThread(mp3); every time you want to replay your mp3 and something will happen every time it finishes.

You can #define play_my_mp3 ResumeThread(mp3); to make your code more readable.

Of course you can remove the while (true), SuspendThread and the from 0 codes, if you want to play your mp3 file only once and do whatever you want when it is over.

If you only remove the SuspendThread call, then the sound will play over and over again and do something whenever it is over. This is equivalent to:

mciSendString("play mp3 repeat notify", NULL, 0, hwnd); //or MAKELONG(hwnd, 0) instead

in windows.

To pause the *.mp3 in middle:

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

and to resume it:

mciSendString("resume mp3", NULL, 0, NULL);

To stop it in middle:

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

Note that you cannot resume a sound that has been stopped, but only paused, but you can replay it by carrying out the play command. When you're done playing this *.mp3, don't forget to:

mciSendString("close mp3", NULL, 0, NULL);

All these actions also apply to (work with) wave files too, but with wave files, you can use "waveaudio" instead of "mpegvideo". Also you can just play them directly without opening them:

PlaySound("*.wav", GetModuleHandle(NULL), SND_FILENAME);

If you don't want to specify an handle to a module:

sndPlaySound("*.wav", SND_FILENAME);

If you don't want to wait until the playback is over:

PlaySound("*.wav", GetModuleHandle(NULL), SND_FILENAME | SND_ASYNC);
//or
sndPlaySound("*.wav", SND_FILENAME | SND_ASYNC);

To play the wave file over and over again:

PlaySound("*.wav", GetModuleHandle(NULL), SND_FILENAME | SND_ASYNC | SND_LOOP);
//or
sndPlaySound("*.wav", SND_FILENAME | SND_ASYNC | SND_LOOP);

Note that you must specify both the SND_ASYNC and SND_LOOP flags, because you never going to wait until a sound, that repeats itself countless times, is over!

Also you can fopen the wave file and copy all it's bytes to a buffer (an enormous/huge (very big) array of bytes) with the fread function and then:

PlaySound(buffer, GetModuleHandle(NULL), SND_MEMORY);
//or
PlaySound(buffer, GetModuleHandle(NULL), SND_MEMORY | SND_ASYNC);
//or
PlaySound(buffer, GetModuleHandle(NULL), SND_MEMORY | SND_ASYNC | SND_LOOP);
//or
sndPlaySound(buffer, SND_MEMORY);
//or
sndPlaySound(buffer, SND_MEMORY | SND_ASYNC);
//or
sndPlaySound(buffer, SND_MEMORY | SND_ASYNC | SND_LOOP);

Either OpenFile or CreateFile or CreateFile2 and either ReadFile or ReadFileEx functions can be used instead of fopen and fread functions.

Hope this fully answers perfectly your question.

相关文章