RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1220717
Accepted
bestorone
bestorone
Asked:2021-12-18 23:25:02 +0000 UTC2021-12-18 23:25:02 +0000 UTC 2021-12-18 23:25:02 +0000 UTC

你需要一个兼容C语言的音频库

  • 772

我们需要一个 Linux 的音频库,兼容 C 语言,最好是小而简单(越简单越好)。任务是播放短声音(0.1-1 秒)。我试着这样玩,但由于某种原因,allegro 吃了很多资源。你有什么建议?

求你出一个库的安装、程序的汇编和播放声音的程序代码的答案

linux
  • 4 4 个回答
  • 10 Views

4 个回答

  • Voted
  1. Best Answer
    Arty
    2021-12-21T21:48:30Z2021-12-21T21:48:30Z

    我建议使用跨平台多媒体库SDL,它适用于所有操作系统(Windows、Linux、MacOS、iOS、Android)。它是用 C 编写的,可以在 C 和 C++ 中使用。

    我在下面写了一个小型包装库,这个迷你库的目的是展示一个使用 SDL 播放音频文件的示例,以及提供现成的方便函数,用于通过单个函数调用播放文件。我的库只播放 WAV 声音文件,为简单起见,如有必要,它也可以修改为 MP3 和其他格式。SDL 支持它们。

    库中有 3 个函数 - PlayWavFile - 从由名称指定的文件中播放 WAV 文件,PlayWavMem - 播放位于内存中的 WAV 文件,PlayWavError - 返回错误文本(更准确地说,完整的错误堆栈以及随附的解释性消息) .

    播放声音的主要功能在文件PlayWavRW()内部play_wav.c,这是中心功能,您可以阅读它以了解如何在 SDL 中播放声音。我的库的其余函数和宏只是辅助的(例如,用于汇编和错误输出)。

    为了使我的库正常工作,需要执行以下步骤:

    1. 通过sudo apt install libsdl2-dev.
    2. 通过 . 编译我的示例代码和库gcc -o play_wav_usage_example play_wav_usage_example.c play_wav.c -lSDL2。
    3. 运行./play_wav_usage_example,它需要附近的文件sound.wav才能播放。
    4. 可以在这里在线尝试编译和运行所有文件的示例,虽然服务器不会播放声音,但程序会启动。

    使用play_wav_usage_example.c的示例:

    // play_wav_usage_example.c
    
    #include "play_wav.h"
    #include <stdio.h>
    
    int main() {
        if (PlayWavFile("sound.wav") != 0)
            printf("Error:\n%s\n", PlayWavError(1));
    }
    

    头文件play_wav.h:

    // play_wav.h
    
    #ifndef _PLAY_WAV_H_
    #define _PLAY_WAV_H_
    
    #include <stdint.h>
    // Play WAV from memory-file.
    // Returns 0 on success, and non-0 on error.
    uint32_t PlayWavMem(char const * buf, uint32_t size);
    // Play WAV from file.
    // Returns 0 on success, and non-0 on error.
    uint32_t PlayWavFile(char const * file_name);
    // Returns error stack, clears errors stack if clear_errors != 0.
    char const * PlayWavError(int clear_errors);
    
    #endif // _PLAY_WAV_H_
    

    实现函数play_wav.c的文件:

    // play_wav.c
    
    #include "play_wav.h"
    
    #include <SDL2/SDL.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    #include <stdint.h>
    #include <string.h>
    
    enum PlayWavErrors {
        ERR_PLAY_WAV_SDL_FAILED = 0xC8B30001,
        ERR_PLAY_WAV_PLAY_WAV_RW_FAILED,
    };
    
    #define MEMZERO(obj) memset(&(obj), 0, sizeof(obj))
    
    typedef uint32_t Error; 
    
    struct ErrInfo {
        uint32_t line;
        Error err;
        char const * serr;
        char const * func;
        char const * code;
        char const * file;
        char msg[256];
    };
    
    enum { c_max_errors_cnt = 128 };
    
    static struct ErrInfo g_errors[c_max_errors_cnt];
    static uint32_t g_errors_cnt = 0;
    
    static void ClearErrors() {
        MEMZERO(g_errors);
        g_errors_cnt = 0;
    }
    
    #define ERRIFMSG(cond, err_, msg_) \
        if (cond) { \
            if (g_errors_cnt < c_max_errors_cnt) { \
                g_errors[g_errors_cnt].err = (err_); \
                g_errors[g_errors_cnt].line = __LINE__; \
                g_errors[g_errors_cnt].func = __FUNCTION__; \
                g_errors[g_errors_cnt].file = __FILE__; \
                g_errors[g_errors_cnt].code = #cond; \
                g_errors[g_errors_cnt].serr = #err_; \
                MEMZERO(g_errors[g_errors_cnt].msg); \
                if (msg_) strncpy(g_errors[g_errors_cnt].msg, (msg_), sizeof(g_errors[g_errors_cnt].msg) - 1); \
                ++g_errors_cnt; \
            } \
            return (err_); \
        }
    #define ERRIF(cond, err) ERRIFMSG(cond, err, "")    
    #define SDLERRIF(cond) ERRIFMSG(cond, ERR_PLAY_WAV_SDL_FAILED, SDL_GetError())
    
    static Error PlayWavRW(SDL_RWops * data) {
        // load WAV file
        SDL_AudioSpec wavSpec;
        Uint32 wavLength = 0;
        Uint8 * wavBuffer = 0;
        SDLERRIF(SDL_LoadWAV_RW(data, 0, &wavSpec, &wavBuffer, &wavLength) == 0);
        
        // open audio device
        SDL_AudioDeviceID dev = 0;
        SDLERRIF((dev = SDL_OpenAudioDevice(NULL, 0, &wavSpec, NULL, 0)) == 0);
        
        // clear existing audio in queue
        SDL_ClearQueuedAudio(dev);
        
        // play audio
        SDLERRIF(SDL_QueueAudio(dev, wavBuffer, wavLength) != 0);
        SDL_PauseAudioDevice(dev, 0);
        
        // wait while audio is playing
        while (1) {
            Uint32 queued_size = SDL_GetQueuedAudioSize(dev);
            if (queued_size == 0)
                break;
            SDL_Delay(20);
        }
    
        // stop playing    
        SDL_PauseAudioDevice(dev, 1);
        
        // clean up
        SDL_CloseAudioDevice(dev);
        SDL_FreeWAV(wavBuffer);
         
        return 0;
    }
    
    static bool g_sdl_inited = false;
    
    static void PlayWavInit() {
        if (!g_sdl_inited) {
            SDL_Init(SDL_INIT_AUDIO);
            g_sdl_inited = true;
        }
    }
    
    static void PlayWavQuit() {
        if (g_sdl_inited) {
            SDL_Quit();
            g_sdl_inited = false;
        }
    }
    
    Error PlayWavMem(char const * buf, uint32_t size) {
        PlayWavInit();
        SDL_RWops * data = 0;
        SDLERRIF((data = SDL_RWFromConstMem(buf, size)) == 0);
        ERRIF(PlayWavRW(data) != 0, ERR_PLAY_WAV_PLAY_WAV_RW_FAILED);
        SDL_FreeRW(data);
        return 0;
    }
    
    Error PlayWavFile(char const * file_name) {
        PlayWavInit();
        SDL_RWops * data = 0;
        SDLERRIF((data = SDL_RWFromFile(file_name, "rb")) == 0);
        ERRIF(PlayWavRW(data) != 0, ERR_PLAY_WAV_PLAY_WAV_RW_FAILED);
        SDL_FreeRW(data);
        return 0;
    }
    
    char const * PlayWavError(int clear_errors) {
        static char buf[2048];
        MEMZERO(buf);
        for (uint32_t i = 0; i < g_errors_cnt; ++i)
            snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%d:%s:%d:%s():\"%s\":\"%s\"\n",
                i, g_errors[i].file, g_errors[i].line, g_errors[i].func, /*g_errors[i].serr, g_errors[i].err,*/ g_errors[i].code, g_errors[i].msg);
        if (clear_errors)
            ClearErrors();
        return buf;
    }
    
    • 7
  2. eri
    2021-12-22T19:21:24Z2021-12-22T19:21:24Z

    Gstreamer 并不像看起来那么大,但用途广泛:

    #include <gst/gst.h>
    
    int main(int argc, char *argv[]) {
      GstBus *bus;
      GstMessage *msg;
      GstElement *playbin;
    
      gst_init (&argc, &argv);
      playbin = gst_element_factory_make ("playbin", "playbin");
      g_object_set (playbin, "uri", "file:///usr/share/sounds/freedesktop/stereo/message.oga", NULL);
      gst_element_set_state (playbin, GST_STATE_PLAYING);
      bus = gst_element_get_bus (playbin);
      do { // ждем конца файла
       msg = gst_bus_timed_pop_filtered (bus, 1 * GST_MSECOND, GST_MESSAGE_EOS);
       if (msg != NULL && GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS) {
         break;
       }
      } while ( 1 );
    
      /* Free resources */
      gst_element_set_state (playbin, GST_STATE_NULL);
      gst_object_unref (playbin);
    
      return 0;
    }
    

    在构建环境中安装

    apt install libgstreamer1.0-dev
    

    使用 ogg、vorbis、opus、theora 编解码器在运行时安装(10 兆字节)

    apt install gstreamer1.0-plugins-base
    

    编译

    gcc play.c `pkg-config --cflags --libs gstreamer-1.0`
    

    内存分配 12 兆字节与编解码器和所有库。

    • 7
  3. Daniil Loban
    2021-12-21T04:00:31Z2021-12-21T04:00:31Z

    不知道目的是什么,但是可以使用已经安装好的软件,我觉得从C调用进程是没有问题的

    ffplay <audiofile> -nodisp
    
    -nodisp - флаг для скрытия окна думаю оно в данном случае не нужно.
    

    至于音频库,我曾经尝试过 - https://juce.com/

    JUCE is an open-source cross-platform C++ application framework used for rapidly
    developing high quality desktop and mobile applications, including VST, AU (and AUv3),
    RTAS and AAX audio plug-ins. JUCE can be easily integrated with existing projects or can
    be used as a project generation tool via the Projucer,
    which supports exporting projects for Xcode (macOS and iOS), Visual Studio, Android Studio,
    Code::Blocks, CLion and Linux Makefiles as well as containing a source code editor and
    live-coding engine which can be used for rapid prototyping.
    

    安装也很简单

    Getting started
    
    Download JUCE. Unpack the JUCE folder 
    and place it to some location on your computer. 
    Your user home folder is a convenient place.
    
    Go into the JUCE folder you just installed. 
    Launch the Projucer, which is located there.
    

    在此处输入图像描述

    • 5
  4. Eugene X
    2021-12-21T03:21:37Z2021-12-21T03:21:37Z

    如果问题的价格不麻烦,那么我可以提供 Un4seen 的低音音频。

    https://www.un4seen.com/bass.html

    优点 - 一个极其简单易懂的 API,文档齐全,作为单个 dll/so 文件分发,具有播放任何音频文件、多线程和跨平台的巨大潜力。(我们经常在大型android/ios游戏中使用它)

    缺点 - 昂贵。但她值得。

    关于文档,对于开发人员来说是一个单独的加分点,即使是刚在不到一周的时间内进入项目的初学者也可以自由地开始使用库 API。

    • 4

相关问题

  • 如果 fuser -k number/tcp 没有帮助,如何在 Debian 中释放端口?

  • Ubuntu。startx 不起作用。黑屏

  • --syn 在 iptables 中有什么作用?

  • 为什么需要iso格式?

  • C程序中没有密码的sudo

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何从列表中打印最大元素(str 类型)的长度?

    • 2 个回答
  • Marko Smith

    如何在 PyQT5 中清除 QFrame 的内容

    • 1 个回答
  • Marko Smith

    如何将具有特定字符的字符串拆分为两个不同的列表?

    • 2 个回答
  • Marko Smith

    导航栏活动元素

    • 1 个回答
  • Marko Smith

    是否可以将文本放入数组中?[关闭]

    • 1 个回答
  • Marko Smith

    如何一次用多个分隔符拆分字符串?

    • 1 个回答
  • Marko Smith

    如何通过 ClassPath 创建 InputStream?

    • 2 个回答
  • Marko Smith

    在一个查询中连接多个表

    • 1 个回答
  • Marko Smith

    对列表列表中的所有值求和

    • 3 个回答
  • Marko Smith

    如何对齐 string.Format 中的列?

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5