Нужна аудио библиотека совместимая с языком си
Нужна аудио библиотека на линукс, совместимая с языком си, желательно маленькая и желательно простая(чем проще тем лучше). Задача в проигрывании коротких звуков(0.1-1 сек). Я пытался сделать проигрывание вот так, но почему-то allegro жрет очень много ресурсов. Что можете предложить?
Ответ прошу оформить с установкой библиотеки, сборкой программы и кодом программы проигрывающей звук
Ответы (4 шт):
Если цена вопроса не волнует, то могу предложить Bass Audio от Un4seen.
https://www.un4seen.com/bass.html
Плюсы - крайне простой и понятный API, отлично документирована, распространяется одним dll/so файлом, имеет огромный потенциал в проигрывании любых аудио файлов, многопоточна и кроссплатформенная. (Часто используем её в крупных android/ios играх)
Минусы - Дорого. Но она того стоит.
Про документацию отдельный плюсик разработчикам, даже новички только входящие в проект менее чем за неделю свободно начинают работать с API библиотеки.
Не знаю какая цель, но можно воспользоваться уже установленным софтом, думаю что из Си нет проблем вызвать процесс
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.
Предлагаю использовать кросс-платформенную мультимедийную библиотеку SDL, она есть под все операционные системы (Windows, Linux, MacOS, iOS, Android). Она написана на языке C и может использовать как в C так и C++.
Я написал небольшую библиотеку-обёртку ниже, цель этой мини-библиотеки чтобы показать пример использования SDL для проигрывания аудио файлов, а также предоставить готовые удобные функции для проигрывания файла вызовом одной функции. Моя библиотека проигрывает только WAV звуковые файлы, для простоты, при необходимости можно доработать и для MP3 и других форматов, т.к. SDL их поддерживает.
В библиотеке 3 функции - PlayWavFile - проигрывает WAV файл из файла указанного по имени, PlayWavMem - проигрывает WAV файл расположенный в памяти, PlayWavError - возвращает текст ошибки (точнее полный стэк ошибки с сопутствующими поясняющими сообщениями).
Основная функция проигрывания звука это PlayWavRW() внутри play_wav.c файла, это центральная функция, её можно почитать чтобы понять как проигрывать звук в SDL. Остальные функции и макросы моей библиотеки всего лишь вспомогательные (например для сборки и вывода ошибок).
Для работы моей библиотеки нужны следующие шаги:
- Установить SDL через
sudo apt install libsdl2-dev. - Скомпилировать код моего примера и библиотеки через
gcc -o play_wav_usage_example play_wav_usage_example.c play_wav.c -lSDL2. - Запустить
./play_wav_usage_example, он требует рядом наличия файлаsound.wavдля проигрывания. - Пример компиляции и запуска всех файлов можно попробовать здесь онлайн, правда сервера не проиграют звук, но программа запустится.
Пример использования 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;
}
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 мегабайт с кодеком и со всеми библиотеками.
