sample formats: take into account ALSA

This commit is contained in:
Andrew Kelley 2015-07-10 00:46:03 -07:00
parent fe2040da7c
commit 8887a528ef
8 changed files with 148 additions and 49 deletions

View file

@ -79,11 +79,11 @@ int main(int argc, char **argv) {
double latency = 0.1; double latency = 0.1;
struct SoundIoInputDevice *input_device; struct SoundIoInputDevice *input_device;
soundio_input_device_create(in_device, SoundIoSampleFormatFloat, 48000, latency, NULL, soundio_input_device_create(in_device, SoundIoSampleFormatFloat32NE, 48000, latency, NULL,
read_callback, &input_device); read_callback, &input_device);
struct SoundIoOutputDevice *output_device; struct SoundIoOutputDevice *output_device;
soundio_output_device_create(out_device, SoundIoSampleFormatFloat, 48000, latency, NULL, soundio_output_device_create(out_device, SoundIoSampleFormatFloat32NE, 48000, latency, NULL,
write_callback, underrun_callback, &output_device); write_callback, underrun_callback, &output_device);
if ((err = soundio_input_device_start(input_device))) if ((err = soundio_input_device_start(input_device)))

View file

@ -90,7 +90,7 @@ int main(int argc, char **argv) {
soundio_device_description(device)); soundio_device_description(device));
struct SoundIoOutputDevice *output_device; struct SoundIoOutputDevice *output_device;
soundio_output_device_create(device, SoundIoSampleFormatFloat, 48000, soundio_output_device_create(device, SoundIoSampleFormatFloat32NE, 48000,
0.1, NULL, write_callback, underrun_callback, &output_device); 0.1, NULL, write_callback, underrun_callback, &output_device);
if ((err = soundio_output_device_start(output_device))) if ((err = soundio_output_device_start(output_device)))

View file

@ -295,7 +295,7 @@ int soundio_dummy_init(SoundIo *soundio) {
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
device->channel_layout = *soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdMono); device->channel_layout = *soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdMono);
device->default_sample_format = SoundIoSampleFormatFloat; device->default_sample_format = SoundIoSampleFormatFloat32NE;
device->default_latency = 0.01; device->default_latency = 0.01;
device->sample_rate_default = 48000; device->sample_rate_default = 48000;
device->purpose = SoundIoDevicePurposeOutput; device->purpose = SoundIoDevicePurposeOutput;
@ -325,7 +325,7 @@ int soundio_dummy_init(SoundIo *soundio) {
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
device->channel_layout = *soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdMono); device->channel_layout = *soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdMono);
device->default_sample_format = SoundIoSampleFormatFloat; device->default_sample_format = SoundIoSampleFormatFloat32NE;
device->default_latency = 0.01; device->default_latency = 0.01;
device->sample_rate_default = 48000; device->sample_rate_default = 48000;
device->purpose = SoundIoDevicePurposeInput; device->purpose = SoundIoDevicePurposeInput;

View file

@ -11,7 +11,6 @@
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
// safe to call from any thread(s) multiple times, but // safe to call from any thread(s) multiple times, but
// must be called at least once before calling any other os functions // must be called at least once before calling any other os functions
void soundio_os_init(void); void soundio_os_init(void);

View file

@ -138,14 +138,28 @@ static double usec_to_sec(pa_usec_t usec) {
return (double)usec / (double)PA_USEC_PER_SEC; return (double)usec / (double)PA_USEC_PER_SEC;
} }
static SoundIoSampleFormat sample_format_from_pulseaudio(pa_sample_spec sample_spec) { static SoundIoSampleFormat sample_format_from_pulseaudio(pa_sample_spec sample_spec) {
switch (sample_spec.format) { switch (sample_spec.format) {
case PA_SAMPLE_U8: return SoundIoSampleFormatUInt8; case PA_SAMPLE_U8: return SoundIoSampleFormatU8;
case PA_SAMPLE_S16NE: return SoundIoSampleFormatInt16; case PA_SAMPLE_S16LE: return SoundIoSampleFormatS16LE;
case PA_SAMPLE_S32NE: return SoundIoSampleFormatInt32; case PA_SAMPLE_S16BE: return SoundIoSampleFormatS16BE;
case PA_SAMPLE_FLOAT32NE: return SoundIoSampleFormatFloat; case PA_SAMPLE_FLOAT32LE: return SoundIoSampleFormatFloat32LE;
default: return SoundIoSampleFormatInvalid; case PA_SAMPLE_FLOAT32BE: return SoundIoSampleFormatFloat32BE;
case PA_SAMPLE_S32LE: return SoundIoSampleFormatS32LE;
case PA_SAMPLE_S32BE: return SoundIoSampleFormatS32BE;
case PA_SAMPLE_S24_32LE: return SoundIoSampleFormatS24LE;
case PA_SAMPLE_S24_32BE: return SoundIoSampleFormatS24BE;
case PA_SAMPLE_MAX:
case PA_SAMPLE_INVALID:
case PA_SAMPLE_ALAW:
case PA_SAMPLE_ULAW:
case PA_SAMPLE_S24LE:
case PA_SAMPLE_S24BE:
return SoundIoSampleFormatInvalid;
} }
return SoundIoSampleFormatInvalid;
} }
static int sample_rate_from_pulseaudio(pa_sample_spec sample_spec) { static int sample_rate_from_pulseaudio(pa_sample_spec sample_spec) {
@ -425,22 +439,29 @@ static void wakeup(SoundIo *soundio) {
static pa_sample_format_t to_pulseaudio_sample_format(SoundIoSampleFormat sample_format) { static pa_sample_format_t to_pulseaudio_sample_format(SoundIoSampleFormat sample_format) {
switch (sample_format) { switch (sample_format) {
case SoundIoSampleFormatUInt8: case SoundIoSampleFormatU8: return PA_SAMPLE_U8;
return PA_SAMPLE_U8; case SoundIoSampleFormatS16LE: return PA_SAMPLE_S16LE;
case SoundIoSampleFormatInt16: case SoundIoSampleFormatS16BE: return PA_SAMPLE_S16BE;
return PA_SAMPLE_S16NE; case SoundIoSampleFormatS24LE: return PA_SAMPLE_S24_32LE;
case SoundIoSampleFormatInt24: case SoundIoSampleFormatS24BE: return PA_SAMPLE_S24_32BE;
return PA_SAMPLE_S24NE; case SoundIoSampleFormatS32LE: return PA_SAMPLE_S32LE;
case SoundIoSampleFormatInt32: case SoundIoSampleFormatS32BE: return PA_SAMPLE_S32BE;
return PA_SAMPLE_S32NE; case SoundIoSampleFormatFloat32LE: return PA_SAMPLE_FLOAT32LE;
case SoundIoSampleFormatFloat: case SoundIoSampleFormatFloat32BE: return PA_SAMPLE_FLOAT32BE;
return PA_SAMPLE_FLOAT32NE;
case SoundIoSampleFormatDouble:
soundio_panic("cannot use double sample format with pulseaudio");
case SoundIoSampleFormatInvalid: case SoundIoSampleFormatInvalid:
soundio_panic("invalid sample format"); case SoundIoSampleFormatS8:
case SoundIoSampleFormatU16LE:
case SoundIoSampleFormatU16BE:
case SoundIoSampleFormatU24LE:
case SoundIoSampleFormatU24BE:
case SoundIoSampleFormatU32LE:
case SoundIoSampleFormatU32BE:
case SoundIoSampleFormatFloat64LE:
case SoundIoSampleFormatFloat64BE:
return PA_SAMPLE_INVALID;
} }
soundio_panic("invalid sample format"); return PA_SAMPLE_INVALID;
} }
static pa_channel_position_t to_pulseaudio_channel_pos(SoundIoChannelId channel_id) { static pa_channel_position_t to_pulseaudio_channel_pos(SoundIoChannelId channel_id) {

View file

@ -35,32 +35,55 @@ const char *soundio_error_string(int error) {
int soundio_get_bytes_per_sample(enum SoundIoSampleFormat sample_format) { int soundio_get_bytes_per_sample(enum SoundIoSampleFormat sample_format) {
switch (sample_format) { switch (sample_format) {
case SoundIoSampleFormatUInt8: return 1; case SoundIoSampleFormatInvalid: soundio_panic("invalid sample format");
case SoundIoSampleFormatInt16: return 2; case SoundIoSampleFormatU8: return 1;
case SoundIoSampleFormatInt24: return 3; case SoundIoSampleFormatS8: return 1;
case SoundIoSampleFormatInt32: return 4; case SoundIoSampleFormatS16LE: return 2;
case SoundIoSampleFormatFloat: return 4; case SoundIoSampleFormatS16BE: return 2;
case SoundIoSampleFormatDouble: return 8; case SoundIoSampleFormatU16LE: return 2;
case SoundIoSampleFormatInvalid: soundio_panic("invalid sample format"); case SoundIoSampleFormatU16BE: return 2;
case SoundIoSampleFormatS24LE: return 4;
case SoundIoSampleFormatS24BE: return 4;
case SoundIoSampleFormatU24LE: return 4;
case SoundIoSampleFormatU24BE: return 4;
case SoundIoSampleFormatS32LE: return 4;
case SoundIoSampleFormatS32BE: return 4;
case SoundIoSampleFormatU32LE: return 4;
case SoundIoSampleFormatU32BE: return 4;
case SoundIoSampleFormatFloat32LE: return 4;
case SoundIoSampleFormatFloat32BE: return 4;
case SoundIoSampleFormatFloat64LE: return 8;
case SoundIoSampleFormatFloat64BE: return 8;
} }
soundio_panic("invalid sample format"); soundio_panic("invalid sample format");
} }
const char * soundio_sample_format_string(enum SoundIoSampleFormat sample_format) { const char * soundio_sample_format_string(enum SoundIoSampleFormat sample_format) {
switch (sample_format) { switch (sample_format) {
case SoundIoSampleFormatUInt8: return "unsigned 8-bit integer"; case SoundIoSampleFormatInvalid: return "(invalid sample format)";
case SoundIoSampleFormatInt16: return "signed 16-bit integer"; case SoundIoSampleFormatU8: return "signed 8-bit";
case SoundIoSampleFormatInt24: return "signed 24-bit integer"; case SoundIoSampleFormatS8: return "unsigned 8-bit";
case SoundIoSampleFormatInt32: return "signed 32-bit integer"; case SoundIoSampleFormatS16LE: return "signed 16-bit LE";
case SoundIoSampleFormatFloat: return "32-bit float"; case SoundIoSampleFormatS16BE: return "signed 16-bit BE";
case SoundIoSampleFormatDouble: return "64-bit float"; case SoundIoSampleFormatU16LE: return "unsigned 16-bit LE";
case SoundIoSampleFormatInvalid: return "invalid sample format"; case SoundIoSampleFormatU16BE: return "unsigned 16-bit LE";
case SoundIoSampleFormatS24LE: return "signed 24-bit LE";
case SoundIoSampleFormatS24BE: return "signed 24-bit BE";
case SoundIoSampleFormatU24LE: return "unsigned 24-bit LE";
case SoundIoSampleFormatU24BE: return "unsigned 24-bit BE";
case SoundIoSampleFormatS32LE: return "signed 32-bit LE";
case SoundIoSampleFormatS32BE: return "signed 32-bit BE";
case SoundIoSampleFormatU32LE: return "unsigned 32-bit LE";
case SoundIoSampleFormatU32BE: return "unsigned 32-bit BE";
case SoundIoSampleFormatFloat32LE: return "float 32-bit LE";
case SoundIoSampleFormatFloat32BE: return "float 32-bit BE";
case SoundIoSampleFormatFloat64LE: return "float 64-bit LE";
case SoundIoSampleFormatFloat64BE: return "float 64-bit BE";
} }
soundio_panic("invalid sample format"); return "(invalid sample format)";
} }
const char *soundio_backend_name(enum SoundIoBackend backend) { const char *soundio_backend_name(enum SoundIoBackend backend) {
switch (backend) { switch (backend) {
case SoundIoBackendNone: return "(none)"; case SoundIoBackendNone: return "(none)";

View file

@ -11,6 +11,30 @@
#include "config.h" #include "config.h"
#include <stdbool.h> #include <stdbool.h>
#if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \
defined(__BIG_ENDIAN__) || \
defined(__ARMEB__) || \
defined(__THUMBEB__) || \
defined(__AARCH64EB__) || \
defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__)
#define SOUNDIO_OS_BIG_ENDIAN
#elif (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \
defined(__LITTLE_ENDIAN__) || \
defined(__ARMEL__) || \
defined(__THUMBEL__) || \
defined(__AARCH64EL__) || \
defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || \
defined(_WIN32)
#define SOUNDIO_OS_LITTLE_ENDIAN
#else
#error unknown byte order
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
{ {
@ -116,17 +140,48 @@ enum SoundIoDevicePurpose {
SoundIoDevicePurposeOutput, SoundIoDevicePurposeOutput,
}; };
// always native-endian
enum SoundIoSampleFormat { enum SoundIoSampleFormat {
SoundIoSampleFormatUInt8,
SoundIoSampleFormatInt16,
SoundIoSampleFormatInt24,
SoundIoSampleFormatInt32,
SoundIoSampleFormatFloat,
SoundIoSampleFormatDouble,
SoundIoSampleFormatInvalid, SoundIoSampleFormatInvalid,
SoundIoSampleFormatU8, // Signed 8 bit
SoundIoSampleFormatS8, // Unsigned 8 bit
SoundIoSampleFormatS16LE, // Signed 16 bit Little Endian
SoundIoSampleFormatS16BE, // Signed 16 bit Big Endian
SoundIoSampleFormatU16LE, // Unsigned 16 bit Little Endian
SoundIoSampleFormatU16BE, // Unsigned 16 bit Little Endian
SoundIoSampleFormatS24LE, // Signed 24 bit Little Endian using low three bytes in 32-bit word
SoundIoSampleFormatS24BE, // Signed 24 bit Big Endian using low three bytes in 32-bit word
SoundIoSampleFormatU24LE, // Unsigned 24 bit Little Endian using low three bytes in 32-bit word
SoundIoSampleFormatU24BE, // Unsigned 24 bit Big Endian using low three bytes in 32-bit word
SoundIoSampleFormatS32LE, // Signed 32 bit Little Endian
SoundIoSampleFormatS32BE, // Signed 32 bit Big Endian
SoundIoSampleFormatU32LE, // Unsigned 32 bit Little Endian
SoundIoSampleFormatU32BE, // Unsigned 32 bit Big Endian
SoundIoSampleFormatFloat32LE, // Float 32 bit Little Endian, Range -1.0 to 1.0
SoundIoSampleFormatFloat32BE, // Float 32 bit Big Endian, Range -1.0 to 1.0
SoundIoSampleFormatFloat64LE, // Float 64 bit Little Endian, Range -1.0 to 1.0
SoundIoSampleFormatFloat64BE, // Float 64 bit Big Endian, Range -1.0 to 1.0
}; };
#if defined(SOUNDIO_OS_BIG_ENDIAN)
#define SoundIoSampleFormatS16NE SoundIoSampleFormatS16BE
#define SoundIoSampleFormatU16NE SoundIoSampleFormatU16BE
#define SoundIoSampleFormatS24NE SoundIoSampleFormatS24BE
#define SoundIoSampleFormatU24NE SoundIoSampleFormatU24BE
#define SoundIoSampleFormatS32NE SoundIoSampleFormatS32BE
#define SoundIoSampleFormatU32NE SoundIoSampleFormatU32BE
#define SoundIoSampleFormatFloat32NE SoundIoSampleFormatFloat32BE
#define SoundIoSampleFormatFloat64NE SoundIoSampleFormatFloat64BE
#elif defined(SOUNDIO_OS_LITTLE_ENDIAN)
#define SoundIoSampleFormatS16NE SoundIoSampleFormatS16LE
#define SoundIoSampleFormatU16NE SoundIoSampleFormatU16LE
#define SoundIoSampleFormatS24NE SoundIoSampleFormatS24LE
#define SoundIoSampleFormatU24NE SoundIoSampleFormatU24LE
#define SoundIoSampleFormatS32NE SoundIoSampleFormatS32LE
#define SoundIoSampleFormatU32NE SoundIoSampleFormatU32LE
#define SoundIoSampleFormatFloat32NE SoundIoSampleFormatFloat32LE
#define SoundIoSampleFormatFloat64NE SoundIoSampleFormatFloat64LE
#endif
struct SoundIoDevice { struct SoundIoDevice {
struct SoundIo *soundio; struct SoundIo *soundio;
char *name; char *name;
@ -276,6 +331,7 @@ const char * soundio_sample_format_string(enum SoundIoSampleFormat sample_format
// Devices // Devices
// returns -1 on error // returns -1 on error

View file

@ -37,7 +37,7 @@ static void test_create_output_device(void) {
soundio_device_name(device); soundio_device_name(device);
soundio_device_description(device); soundio_device_description(device);
struct SoundIoOutputDevice *output_device; struct SoundIoOutputDevice *output_device;
soundio_output_device_create(device, SoundIoSampleFormatFloat, 48000, 0.1, NULL, soundio_output_device_create(device, SoundIoSampleFormatFloat32NE, 48000, 0.1, NULL,
write_callback, underrun_callback, &output_device); write_callback, underrun_callback, &output_device);
soundio_output_device_destroy(output_device); soundio_output_device_destroy(output_device);
soundio_device_unref(device); soundio_device_unref(device);