SDL2中如何将Mix_Chunk转为Mix_Music并解决加载失败问题
解决SDL2_Mixer中Mix_LoadMUSType_RW加载WAV失败的问题
你当前代码的核心问题是:Mix_LoadWAV返回的Mix_Chunk中的abuf是已解码的原始PCM音频数据,不包含WAV文件的格式头,但Mix_LoadMUSType_RW要求传入的是完整的WAV文件数据(包含文件头+PCM数据),所以直接用这个内存块会被判定为格式错误。而Mix_PlayChannel可以直接播放PCM数据,因此能正常运行。
以下是两种可行的解决方法:
方法一:直接从文件加载Mix_Music(推荐)
如果不需要先将音频加载为Mix_Chunk,直接跳过Mix_LoadWAV,用Mix_LoadMUS直接加载原WAV文件即可,这是最简便的方式:
#include <iostream> #include <SDL2/SDL.h> #include <SDL2/SDL_mixer.h> using namespace std; int main() { if (SDL_Init(SDL_INIT_AUDIO) < 0) return -1; if( Mix_OpenAudio(48000, MIX_DEFAULT_FORMAT, 2, 4096) == -1 ) return -1; // 直接加载为Mix_Music Mix_Music *music = Mix_LoadMUS("a.wav"); if(!music) { cout << "load Mus error " << SDL_GetError() << endl; return -1; } Mix_PlayMusic(music, 2); char c; cin >> c; Mix_FreeMusic(music); Mix_CloseAudio(); return 0; }
方法二:从Mix_Chunk的PCM数据构造完整WAV文件后加载
如果必须从已加载的Mix_Chunk转换为Mix_Music,需要手动构造WAV文件头,将头和PCM数据组合成完整的WAV数据,再通过SDL_RWFromMem加载:
#include <iostream> #include <cstring> #include <SDL2/SDL.h> #include <SDL2/SDL_mixer.h> using namespace std; // WAV文件头结构体 typedef struct { char riff[4]; // "RIFF"标识 int32_t file_size; // 文件总大小 - 8 char wave[4]; // "WAVE"标识 char fmt[4]; // "fmt "子块标识 int32_t fmt_size; // 子块大小,PCM格式固定为16 int16_t audio_format; // 音频格式,PCM为1 int16_t channels; // 声道数 int32_t sample_rate; // 采样率 int32_t byte_rate; // 字节率 = 采样率*声道数*位深/8 int16_t block_align; // 块对齐 = 声道数*位深/8 int16_t bits_per_sample; // 位深 char data[4]; // "data"子块标识 int32_t data_size; // PCM数据大小 } WavHeader; int main() { if (SDL_Init(SDL_INIT_AUDIO) < 0) return -1; if( Mix_OpenAudio(48000, MIX_DEFAULT_FORMAT, 2, 4096) == -1 ) return -1; Mix_Chunk *wave = Mix_LoadWAV("a.wav"); if(!wave) { cout << "load WAV error " << SDL_GetError() << endl; return -1; } // 获取PCM音频参数 SDL_AudioSpec spec; Mix_GetSpec(wave, &spec); // 构造WAV文件头 WavHeader header; memcpy(header.riff, "RIFF", 4); memcpy(header.wave, "WAVE", 4); memcpy(header.fmt, "fmt ", 4); memcpy(header.data, "data", 4); header.fmt_size = 16; header.audio_format = 1; header.channels = spec.channels; header.sample_rate = spec.freq; header.bits_per_sample = SDL_AUDIO_BITSIZE(spec.format); header.byte_rate = spec.freq * spec.channels * (header.bits_per_sample / 8); header.block_align = spec.channels * (header.bits_per_sample / 8); header.data_size = wave->alen; header.file_size = 36 + header.data_size; // 分配内存存储完整WAV数据(头+PCM) size_t total_size = sizeof(WavHeader) + wave->alen; uint8_t *full_wav = new uint8_t[total_size]; memcpy(full_wav, &header, sizeof(WavHeader)); memcpy(full_wav + sizeof(WavHeader), wave->abuf, wave->alen); // 从内存加载为Mix_Music SDL_RWops *p = SDL_RWFromMem(full_wav, total_size); Mix_Music *music = Mix_LoadMUSType_RW(p, MUS_WAV, 0); if(!music) { cout << "load Mus error " << SDL_GetError() << endl; } else { Mix_PlayMusic(music, 2); } char c; cin >> c; // 释放资源 delete[] full_wav; Mix_FreeMusic(music); Mix_FreeChunk(wave); Mix_CloseAudio(); return 0; }
内容的提问来源于stack exchange,提问作者Zeta
相关产品推荐
相关产品推荐

