英文:
How to change Mix_Chunk to Mix_Music in SDL2
问题
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();
英文:
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();
I want to manipulate some wave data and store it in Mix_Music format with SDL2_Mixer.
Above code gives me "load Mus error unknown wave format" error.
commented Mix_PlayChannel function works fine.
How can I change this code to make Mix_PlayMusic function work?
答案1
得分: 1
"unknown wave format" 表示 Mix_LoadMUSType_RW
函数 在解释 SDL_RWops
对象 中的数据为 WAV 文件时出现问题。这可能是由于从 Mix_Chunk
对象 创建的 SDL_RWops
对象的方式引起的。
添加了头部之后,它可以正常工作,但是:
Mix_SetMusicPosition
函数 不起作用。它显示 "Position not implemented for Music type"。
这是预期的,因为 Mix_SetMusicPosition
主要用于具有流中位置概念的音乐格式,例如 MP3 或 OGG。
但是,WAV 格式通常不用于流式传输,可能不受 Mix_SetMusicPosition
支持。
如果您想继续使用 WAV 文件,并且需要类似于 Mix_SetMusicPosition
的功能(不支持 WAV 文件),您可以通过手动计算在音频缓冲区内开始播放的位置来实现此目标。
WAV 文件 通常包含原始 PCM 音频数据,音频流中的位置通常由样本数决定。采样率(例如 44.1 kHz)告诉您每秒音频中有多少样本。
要从 WAV 文件的特定位置开始播放:
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDL_mixer.h>
// ... WavHeader 结构与您的代码中的相同 ...
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;
// 计算要从哪个字节位置开始播放
int secondsToSkip = 3;
int bytesPerSample = h.bitpsample / 8;
int position = secondsToSkip * h.sample * h.channel * bytesPerSample;
// 使用位置偏移创建新的 SDL_RWops
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;
// 从计算的位置开始播放音乐
Mix_PlayMusic(musicFromPosition, 1);
char c;
std::cin >> c;
// 清理
Mix_FreeMusic(musicFromPosition);
Mix_FreeMusic(music);
Mix_FreeChunk(wave);
Mix_CloseAudio();
free(wd);
return 0;
}
这意味着您需要计算 WAV 数据中希望开始播放的字节位置。然后,从该位置创建一个新的 SDL_RWops
并将其加载为 Mix_Music
。这应该会从所需位置开始播放 WAV 文件。请注意,此方法涉及将 WAV 文件加载到内存两次,对于大文件可能效率低下。
英文:
"unknown wave format
" should mean the Mix_LoadMUSType_RW
function is having trouble interpreting the data from the SDL_RWops
object as a WAV file.
This could be due to the way the SDL_RWops
object is created from the Mix_Chunk
object.
Once you have added the header, it works, but:
> Mix_SetMusicPosition
function does not work. It says "Position not implemented for Music type".
Which... is expected, considering Mix_SetMusicPosition
is primarily intended for music formats that have a notion of position within the stream, such as MP3 or OGG.
However, the WAV format is not typically used for streaming and might not be supported by Mix_SetMusicPosition
.
If you would like to continue using WAV files, and you need functionality similar to Mix_SetMusicPosition
(which is not supported for WAV files), you can achieve this by manually calculating the position to start playing within the audio buffer.
WAV files usually contain raw PCM audio data, and the position within the audio stream is typically determined by the number of samples. The sample rate (e.g. 44.1 kHz) tells you how many samples are in one second of audio.
To start playing from a specific position within the WAV file:
#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;
}
Meaning: you would need to calculate the byte position within the WAV data where you want to start playing.
Then, create a new SDL_RWops
from that position and load it as Mix_Music
. This should start playing the WAV file from the desired position. Please note that this approach involves loading the WAV file into memory twice, which could be inefficient for large files.
答案2
得分: 1
我不需要翻译的代码部分:
I had to add Wav header to make it work properly.
I did this manually, but, there might be a better way.
But there is another problem, Mix_SetMusicPosition function does not work. It says "Position not implemented for Music type".
英文:
I had to add Wav header to make it work properly.
I did this manually, but, there might be a better way.
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;
}
But there is another problem, Mix_SetMusicPosition function does not work. It says "Position not implemented for Music type".
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论