libsoundio is a lightweight abstraction over various sound drivers. It provides a well-documented API that operates consistently regardless of the sound driver it connects to. It performs no buffering or processing on your behalf; instead exposing the raw power of the underlying backend.
libsoundio is appropriate for games, music players, digital audio workstations, and various utilities.
libsoundio is serious about robustness. It even handles out of memory conditions correctly.
#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 = sin((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 = fmod(seconds_offset + seconds_per_frame * frame_count, 1.0);
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\n", 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\n");
return 1;
}
struct SoundIoDevice *device = soundio_get_output_device(soundio, default_out_device_index);
if (!device) {
fprintf(stderr, "out of memory\n");
return 1;
}
fprintf(stderr, "Output device: %s\n", device->name);
struct SoundIoOutStream *outstream = soundio_outstream_create(device);
if (!outstream) {
fprintf(stderr, "out of memory\n");
return 1;
}
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\n", soundio_strerror(err));
return 1;
}
for (;;)
soundio_wait_events(soundio);
soundio_outstream_destroy(outstream);
soundio_device_unref(device);
soundio_destroy(soundio);
return 0;
}
Not yet available on libsound.io
Not yet available on libsound.io
release notes not yet available on libsound.io
soundio_outstream_pause
or soundio_instream_pause
during the
write_callback
or read_callback
would cause a deadlock. Now, attempting
to pause always results in SoundIoErrorBackendIncompatible
.software_latency
.soundio_version_string
, soundio_version_major
,
soundio_version_minor
, soundio_version_patch
.write_callback
.soundio_instream_pause
.soundio_outstream_pause
triggering assertion when called
from within write_callback
.soundio_device_nearest_sample_rate
.write_callback
with
frame_count_max
equal to 0.read_callback
and write_callback
must be real time safe.read_callback
.The primary developer of libsoundio is Andrew Kelley, who can be found on GitHub. Consider donating $1 per month.