什么是轻量级跨平台WAV播放库?

14

我正在寻找一种轻量级的方法,使我的C语言程序能够在Windows或Linux上播放音频文件。目前我正在使用Windows本地调用,这基本上只是一个传递文件名的单个调用。我希望能有类似的东西可以在Linux上运行。

音频文件为Microsoft PCM格式,单声道,22Khz。

有什么建议吗?

7个回答

12

由于我也在寻找答案,所以我做了一些研究,但我没有找到任何简单的(简单像调用一个函数)播放音频文件的方式。但是通过几行代码,即使使用已经提到的portaudio和libsndfile(LGPL),也可以以便携的方式实现。

这里是我编写的一个小测试案例,用于测试这两个库:


#include <portaudio.h>
#include <sndfile.h>

static int
output_cb(const void * input, void * output, unsigned long frames_per_buffer,
        const PaStreamCallbackTimeInfo *time_info,
        PaStreamCallbackFlags flags, void * data)
{
    SNDFILE * file = data;

    /* this should not actually be done inside of the stream callback
     * but in an own working thread 
     *
     * Note although I haven't tested it for stereo I think you have
     * to multiply frames_per_buffer with the channel count i.e. 2 for
     * stereo */
    sf_read_short(file, output, frames_per_buffer);
    return paContinue;
}

static void
end_cb(void * data)
{
    printf("end!\n");
}

#define error_check(err) \
    do {\
        if (err) { \
            fprintf(stderr, "line %d ", __LINE__); \
            fprintf(stderr, "error number: %d\n", err); \
            fprintf(stderr, "\n\t%s\n\n", Pa_GetErrorText(err)); \
            return err; \
        } \
    } while (0)

int
main(int argc, char ** argv)
{
    PaStreamParameters out_param;
    PaStream * stream;
    PaError err;
    SNDFILE * file;
    SF_INFO sfinfo;

    if (argc < 2)
    {
        fprintf(stderr, "Usage %s \n", argv[0]);
        return 1;
    }

    file = sf_open(argv[1], SFM_READ, &sfinfo);
    printf("%d frames %d samplerate %d channels\n", (int)sfinfo.frames,
            sfinfo.samplerate, sfinfo.channels);

    /* init portaudio */
    err = Pa_Initialize();
    error_check(err);

    /* we are using the default device */
    out_param.device = Pa_GetDefaultOutputDevice();
    if (out_param.device == paNoDevice)
    {
        fprintf(stderr, "Haven't found an audio device!\n");
        return -1;
    }

    /* stero or mono */
    out_param.channelCount = sfinfo.channels;
    out_param.sampleFormat = paInt16;
    out_param.suggestedLatency = Pa_GetDeviceInfo(out_param.device)->defaultLowOutputLatency;
    out_param.hostApiSpecificStreamInfo = NULL;

    err = Pa_OpenStream(&stream, NULL, &out_param, sfinfo.samplerate,
            paFramesPerBufferUnspecified, paClipOff,
            output_cb, file);
    error_check(err);

    err = Pa_SetStreamFinishedCallback(stream, &end_cb);
    error_check(err);

    err = Pa_StartStream(stream);
    error_check(err);

    printf("Play for 5 seconds.\n");
    Pa_Sleep(5000);

    err = Pa_StopStream(stream);
    error_check(err);

    err = Pa_CloseStream(stream);
    error_check(err);

    sf_close(file);

    Pa_Terminate();

    return 0;
}

一些注意事项。在流回调中加载数据并不是良好的实践,而应在自己的加载线程中完成。如果您需要播放多个音频文件,那就更加困难,因为并非所有portaudio后端都支持一个设备的多个流,例如OSS后端不支持,但ALSA后端支持。我不知道Windows的情况如何。由于所有输入文件都是相同类型的,您可以自己混合它们,这会稍微使代码复杂化,但然后您还将支持OSS。如果您还有不同的采样率或通道数,那将变得非常困难。

因此,如果您不想同时播放多个文件,这可能是一个解决方案,或者至少对您来说是一个开始。


很棒的小程序!有一个问题,我还没有实现从单独线程读取数据的方法,我想知道你是否认为这可能是低音频质量的原因,因为流回调被 SNDFILE * file = data 拖慢了一点。谢谢! - Seth Taddiken

5

SDL_Mixer虽然不是很轻巧,但它具有一个简单的界面来播放WAV文件。我认为,就像SDL一样,SDL_Mixer也是LGPL。

OpenAL是另一个跨平台的音频库,更适用于3D音频。

还有另一个开源音频库,你可能想要检查一下,那就是PortAudio


3

我已经使用OpenAL在空中交通管制系统中播放wav文件作为警报

我发现它的优点是:

  1. 它跨平台
  2. 与C语言兼容(还有其他语言,但你的问题是关于C语言的)
  3. 轻量级
  4. 网上有很好的文档可供参考
  5. 许可证是LGPL,所以您可以使用API而不会涉及许可问题

1
你可以尝试使用这个链接:libao

2
libao 看起来很不错,但不幸的是它是在 GPL 下发布的。 - quinmars

0

你也可以尝试使用Audiere。最后一次发布是在2006年,但它是开源的并且根据LGPL许可证授权。


0

我喜欢FMOD。该许可证适用于个人使用是免费的,对于小型共享软件或商业项目来说非常合理。


0

1
请注意,如果您要在商业产品中使用该软件,您需要支付许可费用(尽管相对较小)。http://www.ambiera.com/irrklang/irrklang_pro.html - Ponkadoodle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接