我是一名计算机科学专业的学生。我有一个期末项目,需要开发一个带有图形和声音的简短游戏。
我是一名计算机科学专业的学生。我有一个期末项目,需要开发一个带有图形和声音的简短游戏。
首先,编写以下代码:
#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);
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);
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播放完成时执行。
但是,如果您正在编写控制台应用程序并且不涉及 windows,则可以通过在dwCreationFlags
参数中指定CREATE_SUSPENDED
标志来创建处于暂停状态的线程,并将返回值保存在一个静态变量中,例如我称其为mp3。这个static
变量的类型当然是HANDLE
。
这里是此线程的lpStartAddress
的ThreadProc
: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);
,这样它就会在每次结束后自动重复播放。#define play_my_mp3 ResumeThread(mp3);
来使你的代码更易读。while (true)
、SuspendThread
和from 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);
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_ASYNC
和 SND_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);
可以使用OpenFile
或CreateFile
或CreateFile2
函数之一,以及ReadFile
或ReadFileEx
函数之一,代替fopen
和fread
函数。
希望这完美地回答了你的问题。
*.mp3
必须替换为 mp3 文件的完整路径和文件名。 - Paul Ogilviehttp://sfml-dev.org/documentation/2.0/classsf_1_1Music.php
SFML没有mp3支持,正如其他人所建议的那样。我通常使用Audacity将所有音乐转换为ogg格式,并将所有音效保留为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();
如果您想播放*.mp3或*.wav文件,我认为最简单的方法是使用SFML。
尝试在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;
}
我建议你在游戏中使用FMOD。它能够播放几乎所有的声音文件,并且在C++中实现起来非常简单。将FMOD和DirectX一起使用可以发挥强大的作用,而且并不难。如果您熟悉单例类,我建议在您的win main cpp中创建一个声音管理器的单例类,然后可以随时访问它以加载或播放新的音乐或音效。 以下是一个音频管理器示例:
#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
shutdown()
方法中的相同代码放置到析构函数中。这确实是析构函数的目的,释放对象持有的所有资源。我经常看到这种两步销毁的设计,但从未理解其背后的原因。为什么不使用C++提供的默认设施呢?此外,您始终可以使用智能指针,而无需担心显式释放资源。我只是看不到单独的shutdown()
函数的好处。 - jaho