我正在开发纯C++中的Asteroid克隆,为此,我需要为不同的事件添加声音,比如何时发射子弹和何时发生爆炸。然而,问题是我没有任何音频库的经验。
我正在使用简单的DirectMedia层(SDL),并编写了一个名为play人声()的函数,用于在发生特定事件时播放声音。然而,问题在于,如果发生事件,将调用play人声(),并停止代码执行,直到声音完全播放完毕或从函数返回(我使用延迟函数延迟返回)。
我想要做的是,声音播放在后台,而不造成任何滞后的其余游戏。我正在Ubuntu16.04上开发,也不能使用PlaySound()调用ASYNC标志。
以下是功能:
void playsound(string path) {
// Initialize SDL.
if (SDL_Init(SDL_INIT_AUDIO) < 0)
return;
// local variables
Uint32 wav_length; // length of our sample
Uint8 *wav_buffer; // buffer containing our audio file
SDL_AudioSpec wav_spec;
if(SDL_LoadWAV(path.c_str(), &wav_spec, &wav_buffer, &wav_length) == NULL){
return;
}
SDL_AudioDeviceID deviceId = SDL_OpenAudioDevice(NULL, 0, &wav_spec, NULL, 0);
SDL_QueueAudio(deviceId, wav_buffer, wav_length);
SDL_PauseAudioDevice(deviceId, 0);
SDL_Delay(50);
SDL_CloseAudioDevice(deviceId);
SDL_FreeWAV(wav_buffer);
SDL_Quit();
}发布于 2018-05-09 13:19:58
您的延迟正在阻止代码执行,50 is的延迟几乎是2帧,每帧33 is或3帧,每帧16 is,在这里有一个帧拖放,可能没有问题,但是您可以看到连续调用几个声音会减缓程序的速度。
这就是我如何在我的引擎中播放声音,使用SDL2_mixer (简短的声音,对于音乐,您有另一种方法称为Mix_PlayMusic),它可能会对您有所帮助。我没有延迟(我的代码中没有使用任何睡眠或延迟)。一旦调用play(),声音应该被完整播放,除非有其他东西暂停您的代码。
#pragma once
#include <string>
#include <memory>
#include <SDL2/SDL_mixer.h>
class sample {
public:
sample(const std::string &path, int volume);
void play();
void play(int times);
void set_volume(int volume);
private:
std::unique_ptr<Mix_Chunk, void (*)(Mix_Chunk *)> chunk;
};和cpp文件
#include <sample.h>
sample::sample(const std::string &path, int volume)
: chunk(Mix_LoadWAV(path.c_str()), Mix_FreeChunk) {
if (!chunk.get()) {
// LOG("Couldn't load audio sample: ", path);
}
Mix_VolumeChunk(chunk.get(), volume);
}
// -1 here means we let SDL_mixer pick the first channel that is free
// If no channel is free it'll return an err code.
void sample::play() {
Mix_PlayChannel(-1, chunk.get(), 0);
}
void sample::play(int times) {
Mix_PlayChannel(-1, chunk.get(), times - 1);
}
void sample::set_volume(int volume) {
Mix_VolumeChunk(chunk.get(), volume);
}请注意,我不需要线程我的模型,每次有东西触发声音播放,程序保持执行。(我猜SDL_Mixer在主SDL线程中起作用)。
要使其工作,在其中插入SDL,您还必须将混频器作为
if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024) < 0) {
// Error message if can't initialize
}
// Amount of channels (Max amount of sounds playing at the same time)
Mix_AllocateChannels(32);一个如何播放声音的例子是
// at some point loaded a sample s with sample(path to wave mp3 or whatever)
s.play();请注意,您不需要使用,但可以使用的代码,虽然它是一个更简单的例子使用SDL2_mixer。
这意味着缺少功能,您可能需要更严格地处理声音,例如,为了停止声音中间播放(出于某种原因),如果您使用Mix_HaltChannel函数在不同的频道中播放声音,那么play()函数可以接收要播放它的频道。
所有这些函数都返回错误值,例如,如果没有可用的无保留通道,Mix_PlayChannel将返回错误代码。
另一件你想要记住的事情是,如果你播放了几次相同的声音,它会开始变得模糊/你不会注意到,如果同样的声音是再次播放。因此,您可以在示例中添加一个整数来计算一个示例可以播放多少次。
如果您真的想要从主SDL线程(仍然只使用SDL)来线程您的混频器/音频,您可以在线程中生成一个新的SDL上下文,并以某种方式发送信号来播放音频。
发布于 2018-05-08 18:57:46
C++中有几种用于异步操作的工具。您可以尝试最简单 std::async
auto handle = std::async(std::launch::async,
playsound, std::string{"/path/to/cute/sound"});
// Some other stuff. Your game logic doesn't blocked here.
handle.get(); // This can actually block.您应该指定标志std::launch::async,这意味着将使用新线程。然后需要执行可调用名称及其参数。不要忘记包括<future>头。
发布于 2018-05-08 19:00:32
您希望在初始化游戏时加载所有必要的资产。然后,当你想玩的时候,它们会被加载到游戏内存中,不会有任何滞后。也可以在一个单独的线程中播放声音,这样就不会阻塞主线程。
https://stackoverflow.com/questions/50240497
复制相似问题