diff --git a/include/ao/ao.h b/include/ao/ao.h index c1042b466d59c1d434927f5585bde638b759a019..87d71029c04e7baf17534a4f6ba318f4acfa7dc9 100644 --- a/include/ao/ao.h +++ b/include/ao/ao.h @@ -1,6 +1,6 @@ /* * - * ao.h + * audio_out.h * * Original Copyright (C) Aaron Holtzman - May 1999 * Modifications Copyright (C) Stan Seibert - July 2000 @@ -24,13 +24,10 @@ * */ -#ifndef __AO_H__ -#define __AO_H__ - #include <stdlib.h> -/* Type sizes */ -#include <ao/os_types.h> +// Type sizes +#include "config.h" /* --- Structures --- */ @@ -90,6 +87,7 @@ typedef struct ao_device_s /* Total number of drivers */ #define AO_DRIVERS 12 + /* --- Functions --- */ int ao_get_driver_id (const char *short_name); @@ -108,4 +106,4 @@ int ao_append_option (ao_option_t **options, const char* op_str); void ao_free_options (ao_option_t* options); -#endif /* __AO_H__ */ +int ao_is_big_endian(); diff --git a/src/ao_alsa.c b/src/ao_alsa.c index 2caa05dd4b397e93fdceca5e46513494940719c7..20ef05a63bddfa4a50cc4e4f0f956ceedad2d071 100644 --- a/src/ao_alsa.c +++ b/src/ao_alsa.c @@ -31,7 +31,7 @@ #include <string.h> #include <sys/asoundlib.h> -#include <ao/ao.h> +#include "audio_out.h" #define AO_ALSA_BUF_SIZE 32768 @@ -91,7 +91,8 @@ ao_alsa_open (uint_32 bits, uint_32 rate, uint_32 channels, ao_option_t *options { case 8 : param.format.format = SND_PCM_SFMT_S8; break; - case 16 : param.format.format = SND_PCM_SFMT_S16_LE; + case 16 : param.format.format = ao_is_big_endian() ? + SND_PCM_SFMT_S16_BE : SND_PCM_SFMT_S16_LE; break; default : return NULL; } diff --git a/src/ao_oss.c b/src/ao_oss.c index d5d5a7eb8192ce2b55156b67dc30c8771e7bad8b..395f5b38632b967923c9e90c5b217f8b3437b197 100644 --- a/src/ao_oss.c +++ b/src/ao_oss.c @@ -39,7 +39,7 @@ #endif #include <sys/ioctl.h> -#include <ao/ao.h> +#include "audio_out.h" static ao_info_t ao_oss_info = { @@ -120,8 +120,8 @@ ao_oss_open(uint_32 bits, uint_32 rate, uint_32 channels, ao_option_t *options) { case 8: tmp = AFMT_S8; break; - case 16: tmp = AFMT_S16_LE; - break; + case 16: tmp = ao_is_big_endian() ? AFMT_S16_BE : AFMT_S16_LE; + break; default:fprintf(stderr,"libao - Unsupported number of bits: %d.", bits); goto ERR; diff --git a/src/ao_wav.c b/src/ao_wav.c index b529823c21f77019bf252fde9e8c43dfe5621e69..0c542e2a496f93099beb14eddb950cbd007b94d4 100644 --- a/src/ao_wav.c +++ b/src/ao_wav.c @@ -32,7 +32,7 @@ #include <fcntl.h> #include <signal.h> -#include <ao/ao.h> +#include "audio_out.h" #define WAVE_FORMAT_PCM 0x0001 #define FORMAT_MULAW 0x0101 @@ -49,6 +49,8 @@ #define WRITE_U16(buf, x) *(buf) = (unsigned char)(x&0xff);\ *((buf)+1) = (unsigned char)((x>>8)&0xff); +#define DEFAULT_SWAP_BUFFER_SIZE 2048 + struct riff_struct { unsigned char id[4]; /* RIFF */ @@ -94,6 +96,9 @@ typedef struct ao_wav_internal_s { char *output_file; int fd; + int byte_swap; + char *swap_buffer; + int buffer_size; struct wave_header wave; } ao_wav_internal_t; @@ -147,7 +152,19 @@ ao_wav_open(uint_32 bits, uint_32 rate, uint_32 channels, ao_option_t *options) // Grab options here ao_wav_parse_options(state, options); - + state->byte_swap = (bits == 16) && (ao_is_big_endian()); + if (state->byte_swap) + { + state->buffer_size = DEFAULT_SWAP_BUFFER_SIZE; + state->swap_buffer = calloc(sizeof(char), state->buffer_size); + + if (state->swap_buffer == NULL) + { + fprintf(stderr, "ao_wav: Could not allocate byte-swapping buffer.\n"); + goto ERR; + } + } + state->fd=open(state->output_file,O_WRONLY | O_TRUNC | O_CREAT, 0644); if(state->fd < 0) @@ -201,7 +218,36 @@ ERR: static void ao_wav_play(ao_internal_t *state, void *output_samples, uint_32 num_bytes) { - write( ((ao_wav_internal_t *) state)->fd, output_samples, num_bytes ); + int i; + ao_wav_internal_t *s = (ao_wav_internal_t *) state; + + /* Swap all of the bytes if things are not little_endian */ + if (s->byte_swap) + { + /* Resize buffer larger if needed */ + if (num_bytes > s->buffer_size) + { + s->swap_buffer = realloc(s->swap_buffer, sizeof(char)*num_bytes); + if (s->swap_buffer == NULL) { + fprintf(stderr, "ao_wav: Could not resize swap buffer.\n"); + return; + } + else + s->buffer_size = num_bytes; + } + + /* Swap the bytes into the swap buffer (so we don't + mess up the output_samples buffer) */ + for(i = 0; i < num_bytes/2; i+=2) + { + s->swap_buffer[i] = ((char *) output_samples)[i+1]; + s->swap_buffer[i+1] = ((char *) output_samples)[i]; + } + + write(s->fd, s->swap_buffer, num_bytes ); + } + else /* Otherwise just write the output buffer directly */ + write(s->fd, output_samples, num_bytes ); } diff --git a/src/audio_out.c b/src/audio_out.c index b94d667405d90ea18689d92ced076c39b6264619..59fb7392fd20c8ff45750a077b2dc1dd48922896 100644 --- a/src/audio_out.c +++ b/src/audio_out.c @@ -27,7 +27,8 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> -#include <ao/ao.h> +#include <assert.h> +#include "audio_out.h" /* --- Function Tables --- */ @@ -268,3 +269,13 @@ void ao_free_options (ao_option_t* options) options = rest; } } + +/* Helper function lifted from lib/vorbisfile.c */ +int ao_is_big_endian() { + uint_16 pattern = 0xbabe; + unsigned char *bytewise = (unsigned char *)&pattern; + if (bytewise[0] == 0xba) return 1; + + assert(bytewise[0] == 0xbe); + return 0; +}