2014-03-07 113 views
6

我是计算机科学专业的学生。我有一个最后一个学期的项目,开发一个带有声音的图形短小游戏。如何在C++程序中播放或打开* .mp3或* .wav声音文件?

+1

[WAV信息(https://ccrma.stanford.edu/courses/422/projects/WaveFormat/) – Michael

+3

为了得到一个有价值的和有益的反应,而不是在网上搜索评论,您需要表明你已经尝试过。也就是说,显示一些试图加载.mp3文件的示例代码。你绑定使用任何现有的库(但失败)。这些更有帮助。 – wmorrison365

+3

p.s.你可以看看这些库如何做到这一点:http://en.cppreference.com/w/cpp/links/libs – wmorrison365

回答

5

如果你想播放* .mp3或* .wav文件,我认为最简单的方法是使用SFML

+4

请记住,由于授权问题,SFML不支持MP3格式。不过,你也可以使用鲜为人知的但同样好的OGG格式。 – Lukas

2

我会使用FMOD为您的游戏做到这一点。它能够播放任何主要用于声音的文件,并且在C++中实现起来非常简单。一起使用FMOD和Dir3ect X可以很强大并且不那么困难。如果你对Singleton类很熟悉,我会在你的win cpp中创建一个声音管理器的Singleton类,然后每当加载或播放新的音乐或声音效果时都可以访问它。 这里是一个音频管理器例如

#pragma once 

#ifndef H_AUDIOMANAGER 
#define H_AUDIOMANAGER 

#include <string> 
#include <Windows.h> 
#include "fmod.h" 
#include "fmod.hpp" 
#include "fmod_codec.h" 
#include "fmod_dsp.h" 
#include "fmod_errors.h" 
#include "fmod_memoryinfo.h" 
#include "fmod_output.h" 

class AudioManager 
{ 
public: 
    // Destructor 
    ~AudioManager(void); 

    void Initialize(void); // Initialize sound components 
    void Shutdown(void); // Shutdown sound components 

    // Singleton instance manip methods 
    static AudioManager* GetInstance(void); 
    static void DestroyInstance(void); 

    // Accessors 
    FMOD::System* GetSystem(void) 
     {return soundSystem;} 

    // Sound playing 
    void Play(FMOD::Sound* sound); // Play a sound/music with default channel 
    void PlaySFX(FMOD::Sound* sound); // Play a sound effect with custom channel 
    void PlayBGM(FMOD::Sound* sound); // Play background music with custom channel 

    // Volume adjustment methods 
    void SetBGMVolume(float volume); 
    void SetSFXVolume(float volume); 

private: 
    static AudioManager* instance; // Singleton instance 
    AudioManager(void); // Constructor 

    FMOD::System* soundSystem; // Sound system object 
    FMOD_RESULT result; 
    FMOD::Channel* bgmChannel; // Channel for background music 
    static const int numSfxChannels = 4; 
    FMOD::Channel* sfxChannels[numSfxChannels]; // Channel for sound effects 
}; 

#endif 
+1

这不是真的与op的问题有关,但你能解释为什么你有单独的关闭方法,而不是依靠析构函数? – jaho

+1

,因为使用尽可能多的组件作为音响系统应该可以处理声音系统的所有对象,而不是在析构函数中,因为析构函数会摧毁声音管理器,但没有声音类创建的对象,只有它自己的班级。 – Josh

+1

那么你可以把你放入'shutdown()'方法的代码放入析构函数中。这就是析构函数的目的,释放一个对象所拥有的所有资源。我经常看到这种两步破坏式的设计,但永远无法理解它背后的推理。为什么不使用C++提供的默认设施?除此之外,您始终可以使用智能指针,而不必担心显式释放资源。我只是看不到单独的shutdown()函数的好处。 – jaho

4

http://sfml-dev.org/documentation/2.0/classsf_1_1Music.php

SFML没有支持MP3别人已经建议。我一直在做的是使用Audacity,并将我所有的音乐变成ogg,并将所有音效保留为wav。

加载和播放一个WAV是简单的(原油为例):

http://www.sfml-dev.org/tutorials/2.0/audio-sounds.php

#include <SFML/Audio.hpp> 
... 
sf::SoundBuffer buffer; 
if (!buffer.loadFromFile("sound.wav")){ 
    return -1; 
} 
sf::Sound sound; 
sound.setBuffer(buffer); 
sound.play(); 

流的OGG音乐文件也很简单:

#include <SFML/Audio.hpp> 
... 
sf::Music music; 
if (!music.openFromFile("music.ogg")) 
    return -1; // error 
music.play(); 
+0

通过使用预编译的二进制文件为我工作 –

22

首先,写以下代码:

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

要打开* .MP3:

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

播放* .MP3:

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

播放,等待* .MP3播放完毕:

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

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

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

要重播,等待* .MP3播放完毕:

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

要播放*。MP3和每次结束就像一个循环时间重播:

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

如果你想要做的事时,* .MP3播放完毕,那么由WNDCLASSEX结构,CreateWindowEx和处理它与消息需要RegisterClassEx的GetMessage的TranslateMessage在DispatchMessage在while功能和呼叫:

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). 

在窗口过程中,添加case MM_MCINOTIFY:当MP3播放完成时,将会执行那里的代码。

如果要编制控制台应用程序,你不窗户应对,那么你就可以在CreateThread通过在dwCreationFlags参数指定CREATE_SUSPENDED标志暂停状态,并保持返回值的static变量并随意调用它。例如,我把它叫做mp3。这个static变量的类型当然是HANDLE

这里是ThreadProc该线程的lpStartAddress

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 
    } 
} 

所有你现在要做的就是ResumeThread(mp3);要重播的MP3和事情会发生在每次完成时间每一次。

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

当然你也可以去掉while (true)SuspendThread从0代码,如果你想播放MP3文件只一次,做任何你想要的,当它结束了。

如果你只有只有删除SuspendThread电话,然后声音会一遍又一遍地播放,并做任何事情,当它结束。这相当于:

​​

在windows中。

要暂停* .MP3在中间:

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

,并恢复它:

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

请注意,您无法恢复:

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

要在中间停止一个已经停止但只能暂停的声音,但您可以通过执行播放命令。 当你玩完这个*。MP3,不要忘了:

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

所有这些行为也适用于(有工作)波形文件太多,但与波形文件,你可以使用“waveaudio”,而不是“mpegvideo”。 您也可以只直接播放它们,而无需打开他们:

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

如果你不想指定一个句柄模块:

sndPlaySound("*.wav", SND_FILENAME); 

如果你不想等到播放结束后:

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

要一遍又一遍播放波形文件:

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

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

您也可以fopen波形文件,它的所有字节复制到缓冲区中(巨大/庞大(非常大)的字节数组)与fread功能,然后:

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); 

无论OpenFileCreateFileCreateFile2ReadFileReadFileEx函数可以用来代替fopenfread函数。

希望这完全回答你的问题。

+6

哇,我不能相信这个答案到目前为止还没有被注意到!对于像我这样想要在C++代码中实现简单的.mp3声音实现的人来说,这是一个很好且详细的资源! – Sossenbinder

2

尝试用VC++中的简单C++代码。

#include <windows.h> 
#include <iostream> 
#pragma comment(lib, "winmm.lib") 

int main(int argc, char* argv[]) 
{ 
std::cout<<"Sound playing... enjoy....!!!"; 
PlaySound("C:\\temp\\sound_test.wav", NULL, SND_FILENAME); //SND_FILENAME or SND_LOOP 
return 0; 
} 
相关问题