如何在SDL2中将Mix_Chunk更改为Mix_Music

问题描述 投票:0回答:2
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 功能正常工作?

sdl-2 sdl-mixer
2个回答
1
投票

unknown wave format
”应该表示
Mix_LoadMUSType_RW
函数
无法将
SDL_RWops
对象
的数据解释为 WAV 文件。
这可能是由于
SDL_RWops
对象是从
Mix_Chunk
对象
创建的方式造成的。

一旦添加了标题,它就可以工作,但是:

Mix_SetMusicPosition
功能不起作用。它说“音乐类型未实现位置”。

这...是预期的,考虑到

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 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 文件加载到内存中两次,这对于大文件来说可能效率低下。


1
投票

我必须添加 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 函数不起作用。它说“音乐类型未实现位置”。

© www.soinside.com 2019 - 2024. All rights reserved.