diff --git a/ao-play-async/ao_playasync.c b/ao-play-async/ao_playasync.c index 76845a5..c2f7770 100644 --- a/ao-play-async/ao_playasync.c +++ b/ao-play-async/ao_playasync.c @@ -128,12 +128,21 @@ #include #include +#ifdef AO_ASYNC_WINDOWS +#else +#include +#endif + + +/************************************************************************** + * Internal data structures + **************************************************************************/ + typedef enum { PLAY = 1, STOP = 2 } Command_t; - typedef struct _queue_ { Command_t command; void *buf; @@ -189,6 +198,16 @@ typedef struct { int volume_in_10000; // volume in 10000 steps, i.e. 10000 equals 100% } AO_Handle; +/************************************************************************** + * Forward function declarations + **************************************************************************/ + +static void del_elem(Queue_t *q); + +/************************************************************************** + * Support functions, for internal state, elements and queuing + **************************************************************************/ + static inline int stopped(AO_Handle *h, int lock_mutex) { if (lock_mutex) MUTEX_LOCK(h->mutex); @@ -197,8 +216,6 @@ static inline int stopped(AO_Handle *h, int lock_mutex) return stopped; } -static void del_elem(Queue_t *q); - static Queue_t *get(AO_Handle *h, int ms_wait) { Queue_t *q = NULL; @@ -328,57 +345,26 @@ static void clear(AO_Handle *h, int do_stop) MUTEX_UNLOCK(h->clear_mutex); } +/************************************************************************** + * Calculations on samples + **************************************************************************/ + static int inline littleEndian() { int n = 1; return (*(char *)&n) == 1; } -/* -static void inline adjustVolume(AO_Handle *handle, char *_buf, int buf_size, int volume_in_10000) +static inline int ao_format_little_endian(int endianess) { - int bytes_per_sample = (handle->dev_bits_per_sample >> 3); - register int endianess = handle->dev_endianess; - register unsigned char *buf = (unsigned char *) _buf; + if (endianess == AO_FMT_LITTLE) return TRUE; + if (endianess == AO_FMT_BIG) return FALSE; - register int i; - register long long sample; - register int k; - - int little_endian = (endianess == AO_FMT_LITTLE); - if (!little_endian && endianess == AO_FMT_NATIVE) little_endian = littleEndian(); - - for(i = 0; i < buf_size; i += bytes_per_sample) { - if (little_endian) { - sample = buf[bytes_per_sample + i - 1] > 127 ? -1 : 0; - for(k = bytes_per_sample + i - 1; k >= i; k--) { - sample <<= 8; - sample |= buf[k]; - } - } else { - sample = (buf[i] > 127) ? -1 : 0; - for(k = i; k < (i + bytes_per_sample); k++) { - sample <<= 8; - sample += buf[k]; - } - } - sample *= volume_in_10000; - sample /= 10000; - if (little_endian) { - for(k = i; k < (i + bytes_per_sample); k++) { - buf[k] = sample&0xff; - sample >>= 8; - } - } else { - for(k = i + bytes_per_sample - 1; k >= i; k--) { - buf[k] = sample&0xff; - sample >>= 8; - } - } - } + /* + AO_FMT_NATIVE, or anything treated as native. + */ + return littleEndian(); } -*/ - static inline int32_t read_sample(unsigned char *mem, int req_bytes, int little_endian) { @@ -408,6 +394,17 @@ static inline void store_sample(unsigned char *dst, int32_t in_sample, int out_b } } +/**** Volume adjustment */ + +static inline int32_t limit_sample(int64_t sample, int bits) +{ + int64_t min = -((int64_t)1 << (bits - 1)); + int64_t max = ((int64_t)1 << (bits - 1)) - 1; + + if (sample < min) return (int32_t) min; + if (sample > max) return (int32_t) max; + return (int32_t) sample; +} static inline void adjustVolume(AO_Handle *handle, char *_buf, @@ -427,10 +424,80 @@ static inline void adjustVolume(AO_Handle *handle, for (int i = 0; i + bytes_per_sample <= buf_size; i += bytes_per_sample) { int32_t sample = read_sample(buf + i, bytes_per_sample, little_endian); int64_t scaled = ((int64_t) sample * volume_in_10000) / 10000; - store_sample(buf + i, (int32_t) scaled, bytes_per_sample, little_endian); + int32_t clipped = limit_sample(scaled, handle->dev_bits_per_sample); + store_sample(buf + i, clipped, bytes_per_sample, little_endian); } } +/**** Bit conversion from input samples to device bits */ + +static inline int32_t convert_bits(int32_t sample, int req_bits, int out_bits) +{ + if (req_bits == out_bits) return sample; + + int shift = req_bits > out_bits + ? req_bits - out_bits + : out_bits - req_bits; + + if (req_bits > out_bits) { + return sample / (1 << shift); + } else { + return (int32_t)((int64_t)sample * ((int64_t)1 << shift)); + } +} + +static void *convert_req_to_real(AO_Handle *h, void *mem, int mem_size, BufferInfo_t *info, int *out_size) +{ + if (mem_size <= 0) { + *out_size = 0; + return NULL; + } + + int output_little_endian = ao_format_little_endian(h->dev_endianess); + int input_little_endian = ao_format_little_endian(info->endiannes); + + int requested_bits = info->sample_bits; + int output_bits = h->dev_bits_per_sample; + + int req_bytes = (requested_bits / 8); + int out_bytes = (output_bits / 8); + + int samples = (mem_size / req_bytes); + + unsigned char *buf_out = (unsigned char *) malloc((samples + 1) * out_bytes); + if (buf_out == NULL) { + fprintf(stderr, "Allocation of output buffer of %d samples of %d bits gives NULL", samples, output_bits); + *out_size = 0; + return NULL; + } + + if (requested_bits == output_bits && input_little_endian == output_little_endian) { + *out_size = mem_size; + memcpy(buf_out, mem, mem_size); + } else { + // convert samples. + + int sample; + unsigned char *p_in = (unsigned char *) mem; + unsigned char *p_out = buf_out; + + for(sample = 0; sample < samples; sample++, p_in += req_bytes, p_out += out_bytes) { + register int32_t smpl; + smpl = read_sample(p_in, req_bytes, input_little_endian); + int32_t out_smpl = convert_bits(smpl, requested_bits, output_bits); + store_sample(p_out, out_smpl, out_bytes, output_little_endian); + } + + *out_size = samples * out_bytes; + } + + return buf_out; +} + +/************************************************************************** + * Play thread of queues samples + **************************************************************************/ + #if defined(USE_PTHREADS) || defined(USE_DISPATCH) static void *run(void *arg) #endif @@ -488,15 +555,18 @@ static DWORD run(LPVOID arg) #endif } +/************************************************************************** + * External API + **************************************************************************/ + +/**** ffi version for ao_play_async and ffmpeg_audio */ + int ao_async_version() { return ffi_version(); } -#ifdef AO_ASYNC_WINDOWS -#else -#include -#endif +/**** ao initialization and shutdown */ #ifdef AO_ASYNC_WINDOWS static void at_exit_shutdown_ao(void) @@ -517,6 +587,7 @@ static void init_ao() } } +/**** Opening ao_devices */ static ao_device *try_open_device(int bits, int rate, int channels, int byte_format, const char *wav_file_output, @@ -556,84 +627,6 @@ static ao_device *try_open_device(int bits, int rate, int channels, int byte_for return NULL; } - -/* -static inline int32_t convert_bits(int32_t sample, int req_bits, int out_bits) -{ - if (req_bits > out_bits) { - sample >>= (req_bits - out_bits); - } else if (req_bits < out_bits) { - sample <<= (out_bits - req_bits); - } - return sample; -} -*/ - -static inline int32_t convert_bits(int32_t sample, int req_bits, int out_bits) -{ - if (req_bits == out_bits) return sample; - - int shift = req_bits > out_bits - ? req_bits - out_bits - : out_bits - req_bits; - - if (req_bits > out_bits) { - return sample / (1 << shift); - } else { - return (int32_t)((int64_t)sample * ((int64_t)1 << shift)); - } -} - - -static void *convert_req_to_real(AO_Handle *h, void *mem, int mem_size, BufferInfo_t *info, int *out_size) -{ - if (mem_size <= 0) { - *out_size = 0; - return NULL; - } - - int endianess = h->dev_endianess; - int little_endian = (endianess == AO_FMT_LITTLE); - if (!little_endian && endianess == AO_FMT_NATIVE) little_endian = littleEndian(); - - int requested_bits = info->sample_bits; // h->requested_bits_per_sample; - int output_bits = h->dev_bits_per_sample; - - int req_bytes = (requested_bits / 8); - int out_bytes = (output_bits / 8); - - int samples = (mem_size / req_bytes); - - unsigned char *buf_out = (unsigned char *) malloc((samples + 1) * out_bytes); - if (buf_out == NULL) { - fprintf(stderr, "Allocation of output buffer of %d samples of %d bits gives NULL", samples, output_bits); - *out_size = 0; - return NULL; - } - - if (requested_bits == output_bits) { - *out_size = mem_size; - memcpy(buf_out, mem, mem_size); - } else { - // convert samples. - - int sample; - unsigned char *p_in = (unsigned char *) mem; - unsigned char *p_out = buf_out; - - for(sample = 0; sample < samples; sample++, p_in += req_bytes, p_out += out_bytes) { - register int32_t smpl; - smpl = read_sample(p_in, req_bytes, little_endian); - int32_t out_smpl = convert_bits(smpl, requested_bits, output_bits); - store_sample(p_out, out_smpl, out_bytes, little_endian); - } - - *out_size = samples * out_bytes; - } - - return buf_out; -} - void *ao_create_async(int bits, int rate, int channels, int byte_format, const char *wav_file_output) { init_ao(); @@ -758,27 +751,8 @@ void ao_stop_async(void *ao_handle) fprintf(stderr, "async handle freed\n"); } -/* -static inline void make_sample_bytes(int32_t sample, int bytes_per_sample, int big_endian, unsigned char b[4]) -{ - int i; - - for (i = 0; i < bytes_per_sample; i++) { - b[i] = sample&0xff; - sample >>= 8; - } - if (big_endian) { - unsigned char b1[4] = { 0, 0, 0, 0 }; - for(i = 0; i < bytes_per_sample; i++) { - b1[bytes_per_sample - i - 1] = b[i]; - } - for(i = 0; i < bytes_per_sample; i++) { - b[i] = b1[i]; - } - } -} -*/ +/**** play a sample */ void ao_play_async(void *ao_handle, int music_id, double at_second, double music_duration, int buf_size, void *mem, BufferInfo_t info) { @@ -804,6 +778,8 @@ void ao_play_async(void *ao_handle, int music_id, double at_second, double music } } +/**** clear the sample queue */ + void ao_clear_async(void *ao_handle) { AO_Handle *h = (AO_Handle *) ao_handle; @@ -811,6 +787,8 @@ void ao_clear_async(void *ao_handle) clear(h, FALSE); } +/**** Information on the current samples being played by the player thread */ + double ao_is_at_second_async(void *ao_handle) { AO_Handle *h = (AO_Handle *) ao_handle; @@ -847,6 +825,8 @@ int ao_bufsize_async(void *ao_handle) return s; } +/**** Volume related functions */ + void ao_set_volume_async(void *ao_handle, double percentage) { AO_Handle *h = (AO_Handle *) ao_handle; @@ -869,6 +849,8 @@ double ao_volume_async(void *ao_handle) return volume; } +/**** Pausing playback */ + void ao_pause_async(void *ao_handle, int paused) { AO_Handle *h = (AO_Handle *) ao_handle; @@ -889,6 +871,8 @@ void ao_pause_async(void *ao_handle, int paused) MUTEX_UNLOCK(h->mutex); } +/**** Information about the output device */ + int ao_real_output_bits_async(void *handle) { AO_Handle *h = (AO_Handle *) handle; @@ -896,3 +880,4 @@ int ao_real_output_bits_async(void *handle) } + diff --git a/ao-play-async/ao_playasync.h b/ao-play-async/ao_playasync.h index 6ecf29c..c92ea08 100644 --- a/ao-play-async/ao_playasync.h +++ b/ao-play-async/ao_playasync.h @@ -11,9 +11,7 @@ #define AOPLAYASYNC_EXPORT extern #endif -#define VERSION_MAJOR 1 -#define VERSION_MINOR 0 -#define VERSION_PATCH 0 +#include "../ffi_version.h" typedef enum { ao = 1, diff --git a/lib/linux-x86_64.zip b/lib/linux-x86_64.zip index e9a1064..b449254 100644 Binary files a/lib/linux-x86_64.zip and b/lib/linux-x86_64.zip differ