跨平台实时音频驱动:libsoundio
jopen
9年前
libsoundio 是轻量级抽象的声音驱动程序,是一个跨平台实时音频输入和输出的 C99 库。libsoundio 提供文档完善的 API,适用于实时软件,比如游戏,数字音频工作站,音乐播放器等等实用工具。
libsoundio 非常健壮,可以正确处理内存不足的状态。
特性&限制
-
支持的后端
-
JACK
-
PulseAudio
-
ALSA
-
CoreAudio
-
WASAPI
-
Dummy (silence)
-
支持原始设备和共享设备
-
支持设备 ID 和友好的名字
-
支持优化每个后端的使用
-
C 语言库,仅仅依赖于后端 API 库和 libc
-
支持频道布局
基础正弦波示例
#include <soundio/soundio.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> static const float PI = 3.1415926535f; static float seconds_offset = 0.0f; static void write_callback(struct SoundIoOutStream *outstream, int frame_count_min, int frame_count_max) { const struct SoundIoChannelLayout *layout = &outstream->layout; float float_sample_rate = outstream->sample_rate; float seconds_per_frame = 1.0f / float_sample_rate; struct SoundIoChannelArea *areas; int frames_left = frame_count_max; int err; while (frames_left > 0) { int frame_count = frames_left; if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count))) { fprintf(stderr, "%s\n", soundio_strerror(err)); exit(1); } if (!frame_count) break; float pitch = 440.0f; float radians_per_second = pitch * 2.0f * PI; for (int frame = 0; frame < frame_count; frame += 1) { float sample = sinf((seconds_offset + frame * seconds_per_frame) * radians_per_second); for (int channel = 0; channel < layout->channel_count; channel += 1) { float *ptr = (float*)(areas[channel].ptr + areas[channel].step * frame); *ptr = sample; } } seconds_offset += seconds_per_frame * frame_count; if ((err = soundio_outstream_end_write(outstream))) { fprintf(stderr, "%s\n", soundio_strerror(err)); exit(1); } frames_left -= frame_count; } } int main(int argc, char **argv) { int err; struct SoundIo *soundio = soundio_create(); if (!soundio) { fprintf(stderr, "out of memory\n"); return 1; } if ((err = soundio_connect(soundio))) { fprintf(stderr, "error connecting: %s", soundio_strerror(err)); return 1; } soundio_flush_events(soundio); int default_out_device_index = soundio_default_output_device_index(soundio); if (default_out_device_index < 0) { fprintf(stderr, "no output device found"); return 1; } struct SoundIoDevice *device = soundio_get_output_device(soundio, default_out_device_index); if (!device) { fprintf(stderr, "out of memory"); return 1; } fprintf(stderr, "Output device: %s\n", device->name); struct SoundIoOutStream *outstream = soundio_outstream_create(device); outstream->format = SoundIoFormatFloat32NE; outstream->write_callback = write_callback; if ((err = soundio_outstream_open(outstream))) { fprintf(stderr, "unable to open device: %s", soundio_strerror(err)); return 1; } if (outstream->layout_error) fprintf(stderr, "unable to set channel layout: %s\n", soundio_strerror(outstream->layout_error)); if ((err = soundio_outstream_start(outstream))) { fprintf(stderr, "unable to start device: %s", soundio_strerror(err)); return 1; } for (;;) soundio_wait_events(soundio); soundio_outstream_destroy(outstream); soundio_device_unref(device); soundio_destroy(soundio); return 0; }