Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -109,19 +109,25 @@ if(ENABLE_COREAUDIO)
find_path(AUDIOUNIT_INCLUDE_DIR NAMES AudioUnit.h)
find_library(AUDIOUNIT_LIBRARY NAMES AudioUnit)
include_directories(${AUDIOUNIT_INCLUDE_DIR})

find_path(AUDIOTOOLBOX_INCLUDE_DIR NAMES AudioToolbox/AudioFormat.h)
find_library(AUDIOTOOLBOX_LIBRARY NAMES AudioToolbox)
include_directories(${AUDIOTOOLBOX_INCLUDE_DIR})
else()
set(STATUS_COREAUDIO "not found")
set(SOUNDIO_HAVE_COREAUDIO false)
set(COREAUDIO_LIBRARY "")
set(COREFOUNDATION_LIBRARY "")
set(AUDIOUNIT_LIBRARY "")
set(AUDIOTOOLBOX_LIBRARY "")
endif()
else()
set(STATUS_COREAUDIO "disabled")
set(SOUNDIO_HAVE_COREAUDIO false)
set(COREAUDIO_LIBRARY "")
set(COREFOUNDATION_LIBRARY "")
set(AUDIOUNIT_LIBRARY "")
set(AUDIOTOOLBOX_LIBRARY "")
endif()

if(ENABLE_WASAPI)
Expand Down Expand Up @@ -194,6 +200,7 @@ set(LIBSOUNDIO_LIBS
${COREAUDIO_LIBRARY}
${COREFOUNDATION_LIBRARY}
${AUDIOUNIT_LIBRARY}
${AUDIOTOOLBOX_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
)

Expand Down
1 change: 1 addition & 0 deletions example/sio_microphone.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ static enum SoundIoFormat prioritized_formats[] = {
SoundIoFormatS32FE,
SoundIoFormatS24NE,
SoundIoFormatS24FE,
SoundIoFormatS24PLE,
SoundIoFormatS16NE,
SoundIoFormatS16FE,
SoundIoFormatFloat64NE,
Expand Down
1 change: 1 addition & 0 deletions example/sio_record.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ static enum SoundIoFormat prioritized_formats[] = {
SoundIoFormatS32NE,
SoundIoFormatS32FE,
SoundIoFormatS24NE,
SoundIoFormatS24PLE,
SoundIoFormatS24FE,
SoundIoFormatS16NE,
SoundIoFormatS16FE,
Expand Down
52 changes: 51 additions & 1 deletion example/sio_sine.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#include <math.h>

static int usage(char *exe) {
Expand All @@ -33,6 +34,49 @@ static void write_sample_s16ne(char *ptr, double sample) {
*buf = val;
}

/**
* Construct a signed 24 bit integer from three bytes into a int32_t.
*/
static int32_t construct_s24(uint8_t low, uint8_t mid, uint8_t high)
{
return (int32_t)low | ((int32_t)mid << 8) | ((int32_t)high << 16) |
/* extend the sign bit */
(high & 0x80 ? ~(int32_t)0xffffff : 0);
}

/**
* Read a packed signed native-endian 24 bit integer.
*/
static int32_t read_s24(const uint8_t *src)
{
#if defined(SOUNDIO_OS_BIG_ENDIAN)
return construct_s24(src[2], src[1], src[0]);
#elif defined(SOUNDIO_OS_LITTLE_ENDIAN)
return construct_s24(src[0], src[1], src[2]);
#endif
}

static void write_sample_s24ne(char *ptr, double sample) {
const double range = (double)0xFFFFFF;
const double val = sample * range / 2.0;
const int32_t src0 = val;
const int32_t src = read_s24((const uint8_t *)&src0);
int32_t *dest = (int32_t *)ptr;
*dest = src;
}

static void write_sample_s24ple(char *ptr, double sample) {
const double range = 0xFFFFFF;
const double val = sample * range / 2.0;
const int32_t src0 = val;
const uint8_t *src = (const uint8_t *)&src0;
uint8_t *dest = (uint8_t *)ptr;

*dest++ = *src++;
*dest++ = *src++;
*dest++ = *src++;
}

static void write_sample_s32ne(char *ptr, double sample) {
int32_t *buf = (int32_t *)ptr;
double range = (double)INT32_MAX - (double)INT32_MIN;
Expand Down Expand Up @@ -232,7 +276,13 @@ int main(int argc, char **argv) {
} else if (soundio_device_supports_format(device, SoundIoFormatS16NE)) {
outstream->format = SoundIoFormatS16NE;
write_sample = write_sample_s16ne;
} else {
} else if (soundio_device_supports_format(device, SoundIoFormatS24NE)) {
outstream->format = SoundIoFormatS24NE;
write_sample = write_sample_s24ne;
} else if (soundio_device_supports_format(device, SoundIoFormatS24PLE)) {
outstream->format = SoundIoFormatS24PLE;
write_sample = write_sample_s24ple;
}else {
fprintf(stderr, "No suitable device format available.\n");
return 1;
}
Expand Down
13 changes: 12 additions & 1 deletion soundio/soundio.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ enum SoundIoFormat {
SoundIoFormatU16BE, ///< Unsigned 16 bit Big Endian
SoundIoFormatS24LE, ///< Signed 24 bit Little Endian using low three bytes in 32-bit word
SoundIoFormatS24BE, ///< Signed 24 bit Big Endian using low three bytes in 32-bit word
SoundIoFormatS24PLE, ///< Signed 24 bit Little Endian packed into 3 bytes
SoundIoFormatU24LE, ///< Unsigned 24 bit Little Endian using low three bytes in 32-bit word
SoundIoFormatU24BE, ///< Unsigned 24 bit Big Endian using low three bytes in 32-bit word
SoundIoFormatS32LE, ///< Signed 32 bit Little Endian
Expand Down Expand Up @@ -422,7 +423,9 @@ struct SoundIoDevice {
/// provided by a software mixing service such as dmix or PulseAudio (see
/// SoundIoDevice::is_raw). If it is a raw device,
/// current_format is meaningless;
/// the device has no current format until you open it. On the other hand,
/// the device has no current format until you open it (with the
/// exclusion of Core Audio on macOS where the device will always
/// be set to a valid format). On the other hand,
/// if it is a virtual device, current_format describes the
/// destination sample format that your audio will be converted to. Or,
/// if you're the lucky first application to open the device, you might
Expand Down Expand Up @@ -584,6 +587,14 @@ struct SoundIoOutStream {
/// stream. Defaults to `false`.
bool non_terminal_hint;

/// On macOS, even in raw mode the hardware format may not always match the
/// virtual format that the device accepts IO in. If the virtual and physical
/// formats for this stream match (usually only true for integer formats)
/// this flag will be true. Otherwise the output is typically 32 bit float
/// converted to integer by the kernel device driver (NOT Core Audio). Integer
/// virtual formats (required for "bit-perfect" playback) are typically only supported
/// by external USB DACs.
bool physical_format_match;

/// computed automatically when you call ::soundio_outstream_open
int bytes_per_frame;
Expand Down
5 changes: 4 additions & 1 deletion src/alsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ static snd_pcm_format_t to_alsa_fmt(enum SoundIoFormat fmt) {
case SoundIoFormatS24BE: return SND_PCM_FORMAT_S24_BE;
case SoundIoFormatU24LE: return SND_PCM_FORMAT_U24_LE;
case SoundIoFormatU24BE: return SND_PCM_FORMAT_U24_BE;
case SoundIoFormatS24PLE: return SND_PCM_FORMAT_S24_3LE;
case SoundIoFormatS32LE: return SND_PCM_FORMAT_S32_LE;
case SoundIoFormatS32BE: return SND_PCM_FORMAT_S32_BE;
case SoundIoFormatU32LE: return SND_PCM_FORMAT_U32_LE;
Expand Down Expand Up @@ -350,6 +351,7 @@ static int probe_open_device(struct SoundIoDevice *device, snd_pcm_t *handle, in
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_S24_BE);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_U24_LE);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_U24_BE);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_S24_3LE);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_S32_LE);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_S32_BE);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_U32_LE);
Expand All @@ -364,7 +366,7 @@ static int probe_open_device(struct SoundIoDevice *device, snd_pcm_t *handle, in

if (!device->formats) {
snd_pcm_hw_params_get_format_mask(hwparams, fmt_mask);
device->formats = ALLOCATE(enum SoundIoFormat, 18);
device->formats = ALLOCATE(enum SoundIoFormat, 19);
if (!device->formats)
return SoundIoErrorNoMem;

Expand All @@ -379,6 +381,7 @@ static int probe_open_device(struct SoundIoDevice *device, snd_pcm_t *handle, in
test_fmt_mask(device, fmt_mask, SoundIoFormatS24BE);
test_fmt_mask(device, fmt_mask, SoundIoFormatU24LE);
test_fmt_mask(device, fmt_mask, SoundIoFormatU24BE);
test_fmt_mask(device, fmt_mask, SoundIoFormatS24PLE);
test_fmt_mask(device, fmt_mask, SoundIoFormatS32LE);
test_fmt_mask(device, fmt_mask, SoundIoFormatS32BE);
test_fmt_mask(device, fmt_mask, SoundIoFormatU32LE);
Expand Down
Loading