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

时间:2014-03-07 14:40:13

标签: c++ audio visual-c++ graphics

我是计算机科学专业的学生。我有一个最后的学期项目,用于开发图形和声音的短游戏。

6 个答案:

答案 0 :(得分:35)

首先,编写以下代码:

#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播放完毕后执行某些操作,则需要RegisterClassEx WNDCLASSEX结构CreateWindowEx处理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). 循环中的 GetMessage TranslateMessage DispatchMessage 函数并致电:

case MM_MCINOTIFY:

在窗口过程中,添加CreateThread当mp3播放完毕后,将执行代码。

如果你编写一个控制台应用程序并且你没有处理 windows ,那么你可以CREATE_SUSPENDED处于挂起状态,方法是在dwCreationFlags参数中指定static标志,并将返回值保存在static变量中并随意调用它。例如,我称之为mp3。这个HANDLE变量的类型当然是ThreadProc

以下是此主题lpStartAddress的{​​{1}}:

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);使您的代码更具可读性。

当然,如果你只想播放你的mp3文件一次,你可以删除while (true)SuspendThread从0 代码结束时做你想做的事。

如果您删除SuspendThread来电,那么声音会一遍又一遍地播放,并在结束时执行某些操作。这相当于:

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

暂停中间的* .mp3:

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

并恢复它:

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

要在中间阻止它:

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

请注意,您无法恢复已停止但仅暂停的声音,但您可以通过执行播放命令重播该声音。 当你完成播放* .mp3时,请不要忘记:

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

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

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 wave文件并使用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);

可以使用OpenFileCreateFileCreateFile2以及ReadFileReadFileEx个函数代替fopen和{{1}函数。

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

答案 1 :(得分:4)

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

答案 2 :(得分: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();

答案 3 :(得分:2)

使用库来(a)读取声音文件和(b)播放它们。 (我建议你在业余时间尝试自己,但是......)

也许(* nix):

Windows:DirectX。

答案 4 :(得分:2)

我会使用FMOD为你的游戏做这件事。它能够播放任何主要用于声音的文件,并且在C ++中实现起来非常简单。一起使用FMOD和Dir3ect X可以是强大而不是那么困难。如果您熟悉Singleton类,我会在您的win main 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

答案 5 :(得分: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;
}