【SDL游戏编程入门第十八卷】SDL_mixer音乐播放

一、前言

到目前为止,我们只处理视频和输入。大多数制作的游戏都需要某种声音,在这里我们将使用 SDL_mixer 为我们播放音频。

✨官网链接

✨参考文档

下载方式和之前一样

本卷使用资源

🚀点击下载

二、使用 SDL_mixer 播放音乐和音效

// Init
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)

之前忘记提到了初始化时我是直接初始化所有,这个性能损耗现在来看可以忽略,这么写方便很多,之后看实际需求再更改

// --- 播放音乐 -----------------------------------------------------------------
if (Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, 4096) == -1)
    MyError("Failed to Open Audio!");
// 音乐的SDL_mixer数据类型为 Mix_Music,短音的数据类型为 Mix_Chunk。
// 加载音乐(比较长的音乐),一般这个只有一个通道,所以使用这个不能同时播放音乐
Mix_Music* music = Mix_LoadMUS("res/musics/Reynard Silva - The Way I Still Love You.mp3");

// 如果需要同时播放音乐,可以使用下面的函数,一般电脑上通道限制可能是 8 个,每个音乐会占用一个通道
// 音效(短音)一般用这个,虽然函数名后缀是 WAV,不过除了 wav 也能加载其他格式,如 mp3
Mix_Chunk* chunkScratch = Mix_LoadWAV("res/musics/scratch.wav");
Mix_Chunk* chunkHigh = Mix_LoadWAV("res/musics/high.wav");
Mix_Chunk* chunkLow = Mix_LoadWAV("res/musics/low.wav");
Mix_Chunk* chunkMedium = Mix_LoadWAV("res/musics/medium.wav");

要初始化 SDL_mixer 我们需要调用 Mix_OpenAudio。第一个参数设置 声音频率,44100 是适用于大多数系统的标准频率,我这里直接使用默认值。第二个参数确定示例格式,这里我们再次使用默认值。第三个参数是硬件通道的数量,这里我们可以使用 MIX_DEFAULT_CHANNELS2 个通道进行立体声,也可以用其他。最后一个参数是样本大小,它决定了我们使用的块的大小 播放声音时。默认 2048 字节,但您可能需要尝试使用此值以最大程度地减少播放声音时的延迟。这里我使用 4096

如果 SDL_mixer 有任何错误,Mix_GetError 会报告这些错误。

注意:
✨ 加载音频后记得释放资源
✨ 最后也要使用 MIX_Quit() 退出

1. 示例代码

✨ 使用 1234 播放音效,9 键播放 / 暂停音乐,0 键停止所有 音乐/音效 播放

#include <iostream>
#include <SDL.h>
#include <SDL_mixer.h>

#pragma comment(lib, "SDL2.lib")
#pragma comment(lib, "SDL2main.lib")
#pragma comment(lib, "SDL2_mixer.lib")

constexpr int SRC_WIDTH = 640;
constexpr int SRC_HEIGHT = 480;
// 错误处理
#define MyError(ErrorMessage) \
	{\
		std::cout << "[Error]: " << (ErrorMessage) << std::endl;\
		return -1;\
	}

int main(int argc, char* argv[])
{
	// Init
	if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
		MyError("Failed to Initialize SDL!");
	SDL_Window* window = SDL_CreateWindow("HelloSDL", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SRC_WIDTH, SRC_HEIGHT, SDL_WINDOW_SHOWN);
	if (!window)
		MyError("Failed to create window!");
	SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
	if (!renderer)
		MyError("Failed to create window renderer");

	// --- 播放音乐 -----------------------------------------------------------------
	//if (Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, 4096) == -1)
	if (Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, MIX_CHANNELS, 4096) == -1)  // 也可以设置最大通道 MIX_CHANNELS 8
		MyError("Failed to Open Audio!");
	// 音乐的SDL_mixer数据类型为 Mix_Music,短音的数据类型为 Mix_Chunk。
	// 加载音乐(比较长的音乐),一般这个只有一个通道,所以使用这个不能同时播放音乐
	Mix_Music* music = Mix_LoadMUS("res/musics/Reynard Silva - The Way I Still Love You.mp3");

	// 如果需要同时播放音乐,可以使用下面的函数,一般电脑上通道限制可能是 8 个,每个音乐会占用一个通道
	// 音效(短音)一般用这个,虽然函数名后缀是 WAV,不过除了 wav 也能加载其他格式,如 mp3
	Mix_Chunk* chunkScratch = Mix_LoadWAV("res/musics/scratch.wav");
	Mix_Chunk* chunkHigh = Mix_LoadWAV("res/musics/high.wav");
	Mix_Chunk* chunkLow = Mix_LoadWAV("res/musics/low.wav");
	Mix_Chunk* chunkMedium = Mix_LoadWAV("res/musics/medium.wav");

	// SDL_mixer 对音频数据有两个单独的数据结构。一个它称为“块”,这意味着一个完全解码到预先内存中的文件,另一个它称为“音乐”,这是一个旨在按需解码的文件。
	// 最初,像未压缩的WAV文件这样的简单格式是块,压缩的东西,如MP3,应该是音乐,你会为游戏的音乐流式传输一件事,并用块制作重复的声音效果。

	// 【总之,一般 Mix_Music 只有一个,一般用作背景音乐或其他,Mix_Chunk 有多个且可以同时播放】

	// Game Running
	SDL_Event event;
	bool running = true;
	while (running)
	{
		// Event Loop
		while (SDL_PollEvent(&event))
		{
			if (event.type == SDL_QUIT)
				running = false;
			else if (event.type == SDL_KEYDOWN)
			{
				switch (event.key.keysym.sym)
				{
					// 播放音效
				case SDLK_1: Mix_PlayChannel(-1, chunkHigh, 0); break;
				case SDLK_2: Mix_PlayChannel(-1, chunkMedium, 0); break;
				case SDLK_3: Mix_PlayChannel(-1, chunkLow, 0); break;
				case SDLK_4: Mix_PlayChannel(-1, chunkScratch, 0); break;

				case SDLK_9:
					if (Mix_PlayingMusic() == 0)
					{
						Mix_PlayMusic(music, -1);  // 播放音乐
					}
					else if(Mix_PausedMusic() == 1)
					{
						Mix_ResumeMusic();  // 从暂停的位置恢复音频继续播放
					}
					else
					{
						Mix_PauseMusic();  // 暂停音乐
					}
					break;
					// 停止播放音乐流
				case SDLK_0: Mix_HaltMusic(); break;
				}
			}
		}
		// 清屏(黑色)
		SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
		SDL_RenderClear(renderer);

		// 更新屏幕
		SDL_RenderPresent(renderer);
	}
	// Clear up
	// 清理音乐
	Mix_FreeChunk(chunkHigh);
	Mix_FreeChunk(chunkLow);
	Mix_FreeChunk(chunkMedium);
	Mix_FreeChunk(chunkScratch);
	Mix_FreeMusic(music);
	Mix_Quit();  // 退出 Mix

	SDL_DestroyRenderer(renderer);
	SDL_DestroyWindow(window);
	SDL_Quit();
	return 0;
}



本节内容就到这里了,下卷会继续分享 SDL 的基本使用

The End.

posted @ 2022-12-09 17:33  AnnihilateSword  阅读(489)  评论(0编辑  收藏  举报