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

时间:2022-05-18 02:06:06

I'm looking for a lightweight way to make my program (written in C) be able to play audio files on either windows or linux. I am currently using windows native calls, which is essentially just a single call that is passed a filename. I would like something similar that works on linux.

我正在寻找一种轻量级的方法来让我的程序(用C语言编写)能够在windows或linux上播放音频文件。我目前正在使用windows本机调用,它本质上只是通过文件名进行的单个调用。我想要在linux上使用类似的东西。

The audio files are Microsoft PCM, Single channel, 22Khz

音频文件为微软PCM,单通道,22Khz

Any Suggestions?

有什么建议吗?

7 个解决方案

#1


10  

Since I'm also looking for an answer for question I did a bit of research, and I haven't find any simple (simple like calling one function) way to play an audio file. But with some lines of code, it is possible even in a portable way using the already mentioned portaudio and libsndfile (LGPL).

因为我也在寻找一个问题的答案,我做了一些研究,我没有发现任何简单的(简单的调用一个函数)的方法来播放音频文件。但是,如果使用一些代码行,甚至可以使用已经提到的portaudio和libsndfile (LGPL)进行移植。

Here is a small test case I've written to test both libs:

我写了一个小测试用例来测试这两个libs:


#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;
}

Some notes to the example. It is not good practice to do the data loading inside of the stream callback, but inside an own loading thread. If you need to play several audio files it becomes even more difficult, because not all portaudio backends support multiple streams for one device, for example the OSS backend doesn't, but the ALSA backend does. I don't know how the situation is on windows. Since all your input files are of the same type you could mix them on you own, which complicates the code a bit more, but then you'd have also support for OSS. If you would have also different sample rates or number of channels, it'd become very difficult.

一些例子的注释。在流回调内部进行数据加载不是很好的做法,而是在自己的加载线程内部进行。如果需要播放几个音频文件,就会变得更加困难,因为不是所有的portaudio后端都支持一个设备的多个流,例如OSS后端不支持,但是ALSA后端支持。我不知道windows上的情况如何。由于您的所有输入文件都是相同的类型,您可以自己混合它们,这将使代码更加复杂,但是您还将支持OSS。如果你有不同的采样率或通道数,这将变得非常困难。

So If you don't want to play multiple files at the same time, this could be a solution or at least a start for you.

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

#2


4  

SDL_Mixer, although not very lightweight, does have a simple interface to play WAV files. I believe, like SDL, SDL_Mixer is also LGPL.

SDL_Mixer虽然不是很轻量级,但它有一个简单的接口来播放WAV文件。我认为,与SDL一样,SDL_Mixer也是LGPL。

OpenAL is another cross platform audio library that is more geared towards 3D audio.

OpenAL是另一个面向3D音频的跨平台音频库。

Yet another open source audio library that you might want to check it out is PortAudio

另一个开放源码的音频库是PortAudio

#3


2  

I've used OpenAL to play wav files as alerts/warnings in an Air Traffic Control system

我使用OpenAL在空中交通控制系统中作为警报/警告播放wav文件

The advantages I've found are

我发现的优点是

  1. it is cross platform
  2. 它是跨平台的
  3. works with C (and others but your question is about C)
  4. 与C一起工作(和其他人,但是你的问题是关于C)
  5. light weight
  6. 重量轻
  7. good documentation available on the web
  8. 在web上有很好的文档
  9. the license is LGPL so you call the API with no license problems
  10. 许可证是LGPL,所以您调用API时没有许可证问题

#4


1  

You can try with this one: libao

你可以试试这个:libao。

#5


0  

I like FMOD. The license is free for personal use, and very reasonable for small shareware or commercial projects

我喜欢你。许可证是免费的个人使用,并且非常合理的小型共享软件或商业项目。

#6


0  

You could also try Audiere. The last release is dated 2006, but it is open-source and licensed under the LGPL.

你也可以试试Audiere。上一个版本的发布日期是2006年,但它是开源的,并在LGPL下获得许可。

#7


0  

I used irrKlang !

我用irrKlang !

"irrKlang is a cross platform sound library for C++, C# and all .NET languages"

“irrKlang是一个跨平台的声音库,用于c++、c#和所有的。net语言。”

http://www.ambiera.com/irrklang/

http://www.ambiera.com/irrklang/

#1


10  

Since I'm also looking for an answer for question I did a bit of research, and I haven't find any simple (simple like calling one function) way to play an audio file. But with some lines of code, it is possible even in a portable way using the already mentioned portaudio and libsndfile (LGPL).

因为我也在寻找一个问题的答案,我做了一些研究,我没有发现任何简单的(简单的调用一个函数)的方法来播放音频文件。但是,如果使用一些代码行,甚至可以使用已经提到的portaudio和libsndfile (LGPL)进行移植。

Here is a small test case I've written to test both libs:

我写了一个小测试用例来测试这两个libs:


#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;
}

Some notes to the example. It is not good practice to do the data loading inside of the stream callback, but inside an own loading thread. If you need to play several audio files it becomes even more difficult, because not all portaudio backends support multiple streams for one device, for example the OSS backend doesn't, but the ALSA backend does. I don't know how the situation is on windows. Since all your input files are of the same type you could mix them on you own, which complicates the code a bit more, but then you'd have also support for OSS. If you would have also different sample rates or number of channels, it'd become very difficult.

一些例子的注释。在流回调内部进行数据加载不是很好的做法,而是在自己的加载线程内部进行。如果需要播放几个音频文件,就会变得更加困难,因为不是所有的portaudio后端都支持一个设备的多个流,例如OSS后端不支持,但是ALSA后端支持。我不知道windows上的情况如何。由于您的所有输入文件都是相同的类型,您可以自己混合它们,这将使代码更加复杂,但是您还将支持OSS。如果你有不同的采样率或通道数,这将变得非常困难。

So If you don't want to play multiple files at the same time, this could be a solution or at least a start for you.

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

#2


4  

SDL_Mixer, although not very lightweight, does have a simple interface to play WAV files. I believe, like SDL, SDL_Mixer is also LGPL.

SDL_Mixer虽然不是很轻量级,但它有一个简单的接口来播放WAV文件。我认为,与SDL一样,SDL_Mixer也是LGPL。

OpenAL is another cross platform audio library that is more geared towards 3D audio.

OpenAL是另一个面向3D音频的跨平台音频库。

Yet another open source audio library that you might want to check it out is PortAudio

另一个开放源码的音频库是PortAudio

#3


2  

I've used OpenAL to play wav files as alerts/warnings in an Air Traffic Control system

我使用OpenAL在空中交通控制系统中作为警报/警告播放wav文件

The advantages I've found are

我发现的优点是

  1. it is cross platform
  2. 它是跨平台的
  3. works with C (and others but your question is about C)
  4. 与C一起工作(和其他人,但是你的问题是关于C)
  5. light weight
  6. 重量轻
  7. good documentation available on the web
  8. 在web上有很好的文档
  9. the license is LGPL so you call the API with no license problems
  10. 许可证是LGPL,所以您调用API时没有许可证问题

#4


1  

You can try with this one: libao

你可以试试这个:libao。

#5


0  

I like FMOD. The license is free for personal use, and very reasonable for small shareware or commercial projects

我喜欢你。许可证是免费的个人使用,并且非常合理的小型共享软件或商业项目。

#6


0  

You could also try Audiere. The last release is dated 2006, but it is open-source and licensed under the LGPL.

你也可以试试Audiere。上一个版本的发布日期是2006年,但它是开源的,并在LGPL下获得许可。

#7


0  

I used irrKlang !

我用irrKlang !

"irrKlang is a cross platform sound library for C++, C# and all .NET languages"

“irrKlang是一个跨平台的声音库,用于c++、c#和所有的。net语言。”

http://www.ambiera.com/irrklang/

http://www.ambiera.com/irrklang/