diff --git a/audio_alsa.c b/audio_alsa.c index 3ebe4642..99b70cd3 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -219,6 +219,10 @@ static int init(int argc, char **argv) { config.output_format = SPS_FORMAT_S16; else if (strcasecmp(str, "S24") == 0) config.output_format = SPS_FORMAT_S24; + else if (strcasecmp(str, "S24_3LE") == 0) + config.output_format = SPS_FORMAT_S24_3LE; + else if (strcasecmp(str, "S24_3BE") == 0) + config.output_format = SPS_FORMAT_S24_3BE; else if (strcasecmp(str, "S32") == 0) config.output_format = SPS_FORMAT_S32; else if (strcasecmp(str, "U8") == 0) @@ -226,7 +230,8 @@ static int init(int argc, char **argv) { else if (strcasecmp(str, "S8") == 0) config.output_format = SPS_FORMAT_S8; else - die("Invalid output format \"%s\". It should be \"U8\", \"S8\", \"S16\", \"S24\" or " + die("Invalid output format \"%s\". It should be \"U8\", \"S8\", \"S16\", \"S24\", " + "\"S24_3LE\", \"S24_3BE\" or " "\"S32\"", str); } @@ -417,10 +422,11 @@ int open_alsa_device(void) { // snd_pcm_uframes_t frames = 441 * 10; snd_pcm_uframes_t buffer_size, actual_buffer_length; snd_pcm_access_t access; - - // ensure no calls are made to the alsa device enquiring about the buffer length if synchronisation is disabled. - if (config.no_sync!=0) - audio_alsa.delay = NULL; + + // ensure no calls are made to the alsa device enquiring about the buffer length if + // synchronisation is disabled. + if (config.no_sync != 0) + audio_alsa.delay = NULL; // ensure no calls are made to the alsa device enquiring about the buffer length if // synchronisation is disabled. @@ -479,6 +485,12 @@ int open_alsa_device(void) { case SPS_FORMAT_S24: sf = SND_PCM_FORMAT_S24; break; + case SPS_FORMAT_S24_3LE: + sf = SND_PCM_FORMAT_S24_3LE; + break; + case SPS_FORMAT_S24_3BE: + sf = SND_PCM_FORMAT_S24_3BE; + break; case SPS_FORMAT_S32: sf = SND_PCM_FORMAT_S32; break; diff --git a/common.h b/common.h index 536f24c5..e52f82d2 100644 --- a/common.h +++ b/common.h @@ -64,6 +64,8 @@ enum sps_format_t { SPS_FORMAT_U8, SPS_FORMAT_S16, SPS_FORMAT_S24, + SPS_FORMAT_S24_3LE, + SPS_FORMAT_S24_3BE, SPS_FORMAT_S32, } sps_format_t; diff --git a/player.c b/player.c index b5a8d28d..c09ec67c 100644 --- a/player.c +++ b/player.c @@ -651,6 +651,8 @@ static inline void process_sample(int32_t sample, char **outp, enum sps_format_t dither_mask = (int64_t)1 << (64 + 1 - 32); break; case SPS_FORMAT_S24: + case SPS_FORMAT_S24_3LE: + case SPS_FORMAT_S24_3BE: dither_mask = (int64_t)1 << (64 + 1 - 24); break; case SPS_FORMAT_S16: @@ -682,12 +684,33 @@ static inline void process_sample(int32_t sample, char **outp, enum sps_format_t // move the result to the desired position in the int64_t char *op = *outp; + uint8_t byt; switch (format) { case SPS_FORMAT_S32: hyper_sample >>= (64 - 32); *(int32_t *)op = hyper_sample; result = 4; break; + case SPS_FORMAT_S24_3LE: + hyper_sample >>= (64 - 24); + byt = (uint8_t)hyper_sample; + *op++ = byt; + byt = (uint8_t)(hyper_sample >> 8); + *op++ = byt; + byt = (uint8_t)(hyper_sample >> 16); + *op++ = byt; + result = 3; + break; + case SPS_FORMAT_S24_3BE: + hyper_sample >>= (64 - 24); + byt = (uint8_t)(hyper_sample >> 16); + *op++ = byt; + byt = (uint8_t)(hyper_sample >> 8); + *op++ = byt; + byt = (uint8_t)hyper_sample; + *op++ = byt; + result = 3; + break; case SPS_FORMAT_S24: hyper_sample >>= (64 - 24); *(int32_t *)op = hyper_sample; @@ -1174,7 +1197,7 @@ static inline int32_t mean_32(int32_t a, int32_t b) { // (b) multiplies each sample by the fixedvolume (a 16-bit quantity) // (c) dithers the result to the output size 32/24/16 bits // (d) outputs the result in the approprate format -// formats accepted so far include U8, S8, S16_LE, S24_LE and S32_LE on a little endian machine. +// formats accepted so far include U8, S8, S16, S24, S24_3LE, S24_3BE and S32 // stuff: 1 means add 1; 0 means do nothing; -1 means remove 1 static int stuff_buffer_basic_32(int32_t *inptr, int length, enum sps_format_t l_output_format, @@ -1282,7 +1305,7 @@ static int stuff_buffer_basic(short *inptr, int length, short *outptr, int stuff // (b) multiplies each sample by the fixedvolume (a 16-bit quantity) // (c) dithers the result to the output size 32/24/16 bits // (d) outputs the result in the approprate format -// formats accepted so far include U8, S8, S16_LE, S24_LE and S32_LE on a little endian machine. +// formats accepted so far include U8, S8, S16, S24, S24_3LE, S24_3BE and S32 static int stuff_buffer_soxr_32(int32_t *inptr, int32_t *scratchBuffer, int length, enum sps_format_t l_output_format, char *outptr, int stuff, @@ -1465,6 +1488,10 @@ static void *player_thread_func(void *arg) { output_bytes_per_frame = 4; switch (config.output_format) { + case SPS_FORMAT_S24_3LE: + case SPS_FORMAT_S24_3BE: + output_bytes_per_frame = 6; + break; case SPS_FORMAT_S24: output_bytes_per_frame = 8; break; @@ -1542,6 +1569,8 @@ static void *player_thread_func(void *arg) { output_bit_depth = 16; break; case SPS_FORMAT_S24: + case SPS_FORMAT_S24_3LE: + case SPS_FORMAT_S24_3BE: output_bit_depth = 24; break; case SPS_FORMAT_S32: diff --git a/shairport.c b/shairport.c index 1406de66..fd2cd965 100644 --- a/shairport.c +++ b/shairport.c @@ -1092,7 +1092,8 @@ int main(int argc, char **argv) { debug(1, "disable_synchronization is %d.", config.no_sync); debug(1, "use_mmap_if_available is %d.", config.no_mmap ? 0 : 1); debug(1, "output_rate is %d.", config.output_rate); - debug(1, "output_format is %d (0-unknown, 1-S8, 2-U8, 3-S16, 4-S24, 5-S32).", + debug(1, + "output_format is %d (0-unknown, 1-S8, 2-U8, 3-S16, 4-S24, 5-S24_3LE, 6-S24_3BE, 7-S32).", config.output_format); debug(1, "audio backend desired buffer length is %f seconds.", config.audio_backend_buffer_desired_length);