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");
auto *p = SDL_RWFromMem(wave->abuf, wave->alen);
if(!p || !wave) return -1;
Mix_Music *music = Mix_LoadMUSType_RW(p, MUS_WAV, 0);
if(!music) cout <<"load Mus error " << SDL_GetError() << endl;
Mix_PlayMusic(music, 2);
//Mix_PlayChannel(-1, wave, 1);
char c;
cin >> c;
Mix_FreeMusic(music);
Mix_FreeChunk(wave);
Mix_CloseAudio();
我想用SDL2_Mixer操作一些波形数据并将其存储为Mix_Music格式。 上面的代码给了我“加载 Mus 错误未知波形格式”错误。
注释的 Mix_PlayChannel 函数工作正常。
如何更改此代码以使 Mix_PlayMusic 功能正常工作?
“
unknown wave format
”应该表示 Mix_LoadMUSType_RW
函数 无法将 SDL_RWops
对象 的数据解释为 WAV 文件。SDL_RWops
对象是从 Mix_Chunk
对象 创建的方式造成的。
一旦添加了标题,它就可以工作,但是:
功能不起作用。它说“音乐类型未实现位置”。Mix_SetMusicPosition
这...是预期的,考虑到
Mix_SetMusicPosition
主要用于在流中具有位置概念的音乐格式,例如 MP3 或 OGG。Mix_SetMusicPosition
支持。
如果您想继续使用 WAV 文件,并且需要类似于
Mix_SetMusicPosition
的功能(WAV 文件不支持),您可以通过手动计算音频缓冲区内开始播放的位置来实现此目的。
WAV 文件 通常包含原始 PCM 音频数据,音频流中的位置通常由样本数量确定。采样率(例如 44.1 kHz)告诉您一秒音频中有多少个样本。
要从 WAV 文件中的特定位置开始播放:
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDL_mixer.h>
// ... WavHeader structure as in your code ...
int main(int argc, char* argv[])
{
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");
WavHeader h{wave->alen};
void *wd = malloc(wave->alen + 44);
memcpy(wd, &h, 44);
memcpy((char *)wd + 44, wave->abuf, wave->alen);
if (!wave) std::cout << SDL_GetError() << std::endl;
auto *p = SDL_RWFromMem(wd, wave->alen + 44);
if (!p) std::cout << SDL_GetError() << std::endl;
Mix_Music *music = Mix_LoadMUSType_RW(p, MUS_WAV, 1);
if (!music) std::cout << " loadMus error " << SDL_GetError() << std::endl;
// Calculate the byte position to start playing from
int secondsToSkip = 3;
int bytesPerSample = h.bitpsample / 8;
int position = secondsToSkip * h.sample * h.channel * bytesPerSample;
// Create new SDL_RWops with the position offset
SDL_RWops *rw = SDL_RWFromMem((char *)wd + 44 + position, wave->alen - position);
Mix_Music *musicFromPosition = Mix_LoadMUSType_RW(rw, MUS_WAV, 1);
if (!musicFromPosition) std::cout << " loadMus error " << SDL_GetError() << std::endl;
// Play the music from the calculated position
Mix_PlayMusic(musicFromPosition, 1);
char c;
std::cin >> c;
// Clean up
Mix_FreeMusic(musicFromPosition);
Mix_FreeMusic(music);
Mix_FreeChunk(wave);
Mix_CloseAudio();
free(wd);
return 0;
}
含义:您需要计算 WAV 数据中要开始播放的字节位置。
然后,从该位置创建一个新的
SDL_RWops
并将其加载为 Mix_Music
。这应该从所需位置开始播放 WAV 文件。请注意,此方法涉及将 WAV 文件加载到内存中两次,这对于大文件来说可能效率低下。
我必须添加 Wav 标头才能使其正常工作。
我手动完成了此操作,但是,可能有更好的方法。
struct WavHeader
{
char riff[4] = {'R', 'I', 'F', 'F'};
uint32_t size = 0;
char type[4] = {'W', 'A', 'V', 'E'};
char fmt[4] = {'f', 'm', 't', ' '};
uint32_t len = 16;
uint16_t pcm = 1;
uint16_t channel = 2;
uint32_t sample = 48000;
uint32_t sam = 48000 * 16 * 2 / 8;
uint16_t bitstereo = 4;
uint16_t bitpsample = 16;
char data[4] = {'d', 'a', 't', 'a'};
uint32_t datasize = 0;
WavHeader(int sz) {
datasize = sz;
size = sz + 44;
}
};
int main(int argc, char* argv[])
{
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(WAV_PATH);
WavHeader h{wave->alen};
void *wd = malloc(wave->alen + 44);
memcpy(wd, &h, 44);
memcpy(wd + 44, wave->abuf, wave->alen);
if(!wave) cout << SDL_GetError() << endl;
auto *p = SDL_RWFromMem(wd, wave->alen + 44);
if(!p) cout << SDL_GetError() << endl;
Mix_Music *music = Mix_LoadMUSType_RW(p, MUS_WAV, 0);
if(!music) cout <<" loasMus error " << SDL_GetError() << endl;
Mix_PlayMusic(music, 2);
//Mix_PlayChannel(-1, wave, 1);
if(Mix_SetMusicPosition(3) == -1) cout << SDL_GetError() << endl;;
char c;
cin >> c;
Mix_FreeMusic(music);
Mix_FreeChunk(wave);
Mix_CloseAudio();
free(wd);
return 0;
}
但是还有一个问题,Mix_SetMusicPosition 函数不起作用。它说“音乐类型未实现位置”。