Play a sine wave over the default output device.Supports specifying device and backend to use.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <math.h>
static int usage(char *exe) {
fprintf(stderr, "Usage: %s [options]\n"
"Options:\n"
" [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi]\n"
" [--device id]\n"
" [--raw]\n"
" [--name stream_name]\n"
" [--latency seconds]\n"
" [--sample-rate hz]\n"
, exe);
return 1;
}
static void write_sample_s16ne(char *ptr, double sample) {
int16_t *buf = (int16_t *)ptr;
double range = (double)INT16_MAX - (double)INT16_MIN;
double val = sample * range / 2.0;
*buf = val;
}
static void write_sample_s32ne(char *ptr, double sample) {
int32_t *buf = (int32_t *)ptr;
double range = (double)INT32_MAX - (double)INT32_MIN;
double val = sample * range / 2.0;
*buf = val;
}
static void write_sample_float32ne(char *ptr, double sample) {
float *buf = (float *)ptr;
*buf = sample;
}
static void write_sample_float64ne(char *ptr, double sample) {
double *buf = (double *)ptr;
*buf = sample;
}
static void (*write_sample)(char *ptr, double sample);
static const double PI = 3.14159265358979323846264338328;
static double seconds_offset = 0.0;
static volatile bool want_pause = false;
static void write_callback(
struct SoundIoOutStream *outstream,
int frame_count_min,
int frame_count_max) {
double seconds_per_frame = 1.0 / float_sample_rate;
int err;
int frames_left = frame_count_max;
for (;;) {
int frame_count = frames_left;
exit(1);
}
if (!frame_count)
break;
double pitch = 440.0;
double radians_per_second = pitch * 2.0 * PI;
for (int frame = 0; frame < frame_count; frame += 1) {
double sample = sin((seconds_offset + frame * seconds_per_frame) * radians_per_second);
for (
int channel = 0; channel < layout->
channel_count; channel += 1) {
write_sample(areas[channel].ptr, sample);
areas[channel].
ptr += areas[channel].
step;
}
}
seconds_offset = fmod(seconds_offset + seconds_per_frame * frame_count, 1.0);
return;
exit(1);
}
frames_left -= frame_count;
if (frames_left <= 0)
break;
}
}
static int count = 0;
fprintf(stderr, "underflow %d\n", count++);
}
int main(int argc, char **argv) {
char *exe = argv[0];
char *device_id = NULL;
bool raw = false;
char *stream_name = NULL;
double latency = 0.0;
int sample_rate = 0;
for (int i = 1; i < argc; i += 1) {
char *arg = argv[i];
if (arg[0] == '-' && arg[1] == '-') {
if (strcmp(arg, "--raw") == 0) {
raw = true;
} else {
i += 1;
if (i >= argc) {
return usage(exe);
} else if (strcmp(arg, "--backend") == 0) {
if (strcmp(argv[i], "dummy") == 0) {
} else if (strcmp(argv[i], "alsa") == 0) {
} else if (strcmp(argv[i], "pulseaudio") == 0) {
} else if (strcmp(argv[i], "jack") == 0) {
} else if (strcmp(argv[i], "coreaudio") == 0) {
} else if (strcmp(argv[i], "wasapi") == 0) {
} else {
fprintf(stderr, "Invalid backend: %s\n", argv[i]);
return 1;
}
} else if (strcmp(arg, "--device") == 0) {
device_id = argv[i];
} else if (strcmp(arg, "--name") == 0) {
stream_name = argv[i];
} else if (strcmp(arg, "--latency") == 0) {
latency = atof(argv[i]);
} else if (strcmp(arg, "--sample-rate") == 0) {
sample_rate = atoi(argv[i]);
} else {
return usage(exe);
}
}
} else {
return usage(exe);
}
}
if (!soundio) {
fprintf(stderr, "out of memory\n");
return 1;
}
if (err) {
return 1;
}
int selected_device_index = -1;
if (device_id) {
for (int i = 0; i < device_count; i += 1) {
bool select_this_one = strcmp(device->
id, device_id) == 0 && device->
is_raw == raw;
if (select_this_one) {
selected_device_index = i;
break;
}
}
} else {
}
if (selected_device_index < 0) {
fprintf(stderr, "Output device not found\n");
return 1;
}
if (!device) {
fprintf(stderr, "out of memory\n");
return 1;
}
fprintf(stderr,
"Output device: %s\n", device->
name);
return 1;
}
if (!outstream) {
fprintf(stderr, "out of memory\n");
return 1;
}
outstream->
name = stream_name;
write_sample = write_sample_float32ne;
write_sample = write_sample_float64ne;
write_sample = write_sample_s32ne;
write_sample = write_sample_s16ne;
} else {
fprintf(stderr, "No suitable device format available.\n");
return 1;
}
return 1;
}
fprintf(stderr,
"'p\\n' - pause\n"
"'u\\n' - unpause\n"
"'P\\n' - pause from within callback\n"
"'c\\n' - clear buffer\n"
"'q\\n' - quit\n");
return 1;
}
for (;;) {
int c = getc(stdin);
if (c == 'p') {
fprintf(stderr, "pausing result: %s\n",
} else if (c == 'P') {
want_pause = true;
} else if (c == 'u') {
want_pause = false;
fprintf(stderr, "unpausing result: %s\n",
} else if (c == 'c') {
fprintf(stderr, "clear buffer result: %s\n",
} else if (c == 'q') {
break;
} else if (c == '\r' || c == '\n') {
} else {
fprintf(stderr, "Unrecognized command: %c\n", c);
}
}
return 0;
}
#define SoundIoFormatFloat32NE
Definition: soundio.h:288
struct SoundIo * soundio_create(void)
Create a SoundIo context.
#define SoundIoFormatS32NE
Definition: soundio.h:286
#define SoundIoFormatFloat64NE
Definition: soundio.h:289
int soundio_outstream_begin_write(struct SoundIoOutStream *outstream, struct SoundIoChannelArea **areas, int *frame_count)
Call this function when you are ready to begin writing to the device buffer.
#define SoundIoFormatS16NE
Note that we build the documentation in Little Endian mode, so all the "NE" macros in the docs point ...
Definition: soundio.h:282
SoundIoBackend
Definition: soundio.h:218
@ SoundIoBackendNone
Definition: soundio.h:219
@ SoundIoBackendPulseAudio
Definition: soundio.h:221
@ SoundIoBackendCoreAudio
Definition: soundio.h:223
@ SoundIoBackendWasapi
Definition: soundio.h:224
@ SoundIoBackendJack
Definition: soundio.h:220
@ SoundIoBackendDummy
Definition: soundio.h:225
@ SoundIoBackendAlsa
Definition: soundio.h:222
const char * soundio_backend_name(enum SoundIoBackend backend)
Get a string representation of a SoundIoBackend.
int soundio_output_device_count(struct SoundIo *soundio)
Get the number of output devices.
void soundio_device_unref(struct SoundIoDevice *device)
Remove 1 to the reference count of device.
void soundio_destroy(struct SoundIo *soundio)
bool soundio_device_supports_format(struct SoundIoDevice *device, enum SoundIoFormat format)
Convenience function.
struct SoundIoDevice * soundio_get_output_device(struct SoundIo *soundio, int index)
Always returns a device.
int soundio_outstream_open(struct SoundIoOutStream *outstream)
After you call this function, SoundIoOutStream::software_latency is set to the correct value.
struct SoundIoOutStream * soundio_outstream_create(struct SoundIoDevice *device)
Allocates memory and sets defaults.
void soundio_flush_events(struct SoundIo *soundio)
Atomically update information for all connected devices.
void soundio_outstream_destroy(struct SoundIoOutStream *outstream)
You may not call this function from the SoundIoOutStream::write_callback thread context.
const char * soundio_strerror(int error)
Get a string representation of a SoundIoError.
int soundio_default_output_device_index(struct SoundIo *soundio)
returns the index of the default output device returns -1 if there are no devices or if you never cal...
@ SoundIoErrorUnderflow
Buffer underrun occurred.
Definition: soundio.h:100
int soundio_outstream_start(struct SoundIoOutStream *outstream)
After you call this function, SoundIoOutStream::write_callback will be called.
int soundio_connect_backend(struct SoundIo *soundio, enum SoundIoBackend backend)
Instead of calling soundio_connect you may call this function to try a specific backend.
int soundio_outstream_pause(struct SoundIoOutStream *outstream, bool pause)
If the underlying backend and device support pausing, this pauses the stream.
int soundio_connect(struct SoundIo *soundio)
Tries soundio_connect_backend on all available backends in order.
int soundio_outstream_end_write(struct SoundIoOutStream *outstream)
Commits the write that you began with soundio_outstream_begin_write.
int soundio_outstream_clear_buffer(struct SoundIoOutStream *outstream)
Clears the output stream buffer.
The size of this struct is OK to use.
Definition: soundio.h:319
char * ptr
Base address of buffer.
Definition: soundio.h:321
int step
How many bytes it takes to get from the beginning of one sample to the beginning of the next sample.
Definition: soundio.h:324
The size of this struct is OK to use.
Definition: soundio.h:306
int channel_count
Definition: soundio.h:308
The size of this struct is not part of the API or ABI.
Definition: soundio.h:387
int probe_error
This is set to a SoundIoError representing the result of the device probe.
Definition: soundio.h:493
char * name
User-friendly UTF-8 encoded text to describe the device.
Definition: soundio.h:401
char * id
A string of bytes that uniquely identifies this device.
Definition: soundio.h:399
struct SoundIo * soundio
Read-only. Set automatically.
Definition: soundio.h:389
bool is_raw
Raw means that you are directly opening the hardware device and not going through a proxy such as dmi...
Definition: soundio.h:478
The size of this struct is not part of the API or ABI.
Definition: soundio.h:497
enum SoundIoFormat format
Defaults to SoundIoFormatFloat32NE, followed by the first one supported.
Definition: soundio.h:503
int layout_error
If setting the channel layout fails for some reason, this field is set to an error code.
Definition: soundio.h:596
double software_latency
Ignoring hardware latency, this is the number of seconds it takes for the last sample in a full buffe...
Definition: soundio.h:538
struct SoundIoDevice * device
Populated automatically when you call soundio_outstream_create.
Definition: soundio.h:499
struct SoundIoChannelLayout layout
Defaults to Stereo, if available, followed by the first layout supported.
Definition: soundio.h:511
const char * name
Optional: Name of the stream.
Definition: soundio.h:580
void(* underflow_callback)(struct SoundIoOutStream *)
This optional callback happens when the sound device runs out of buffered audio data to play.
Definition: soundio.h:565
int sample_rate
Sample rate is the number of frames per second.
Definition: soundio.h:507
void(* write_callback)(struct SoundIoOutStream *, int frame_count_min, int frame_count_max)
In this callback, you call soundio_outstream_begin_write and soundio_outstream_end_write as many time...
Definition: soundio.h:559
The size of this struct is not part of the API or ABI.
Definition: soundio.h:328
enum SoundIoBackend current_backend
Read-only.
Definition: soundio.h:358