This commit is contained in:
2026-06-08 08:49:07 +02:00
3 changed files with 134 additions and 151 deletions
+133 -148
View File
@@ -128,12 +128,21 @@
#include <ao/ao.h> #include <ao/ao.h>
#include <errno.h> #include <errno.h>
#ifdef AO_ASYNC_WINDOWS
#else
#include <dlfcn.h>
#endif
/**************************************************************************
* Internal data structures
**************************************************************************/
typedef enum { typedef enum {
PLAY = 1, PLAY = 1,
STOP = 2 STOP = 2
} Command_t; } Command_t;
typedef struct _queue_ { typedef struct _queue_ {
Command_t command; Command_t command;
void *buf; void *buf;
@@ -189,6 +198,16 @@ typedef struct {
int volume_in_10000; // volume in 10000 steps, i.e. 10000 equals 100% int volume_in_10000; // volume in 10000 steps, i.e. 10000 equals 100%
} AO_Handle; } 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) static inline int stopped(AO_Handle *h, int lock_mutex)
{ {
if (lock_mutex) MUTEX_LOCK(h->mutex); if (lock_mutex) MUTEX_LOCK(h->mutex);
@@ -197,8 +216,6 @@ static inline int stopped(AO_Handle *h, int lock_mutex)
return stopped; return stopped;
} }
static void del_elem(Queue_t *q);
static Queue_t *get(AO_Handle *h, int ms_wait) static Queue_t *get(AO_Handle *h, int ms_wait)
{ {
Queue_t *q = NULL; Queue_t *q = NULL;
@@ -328,57 +345,26 @@ static void clear(AO_Handle *h, int do_stop)
MUTEX_UNLOCK(h->clear_mutex); MUTEX_UNLOCK(h->clear_mutex);
} }
/**************************************************************************
* Calculations on samples
**************************************************************************/
static int inline littleEndian() static int inline littleEndian()
{ {
int n = 1; int n = 1;
return (*(char *)&n) == 1; return (*(char *)&n) == 1;
} }
/* static inline int ao_format_little_endian(int endianess)
static void inline adjustVolume(AO_Handle *handle, char *_buf, int buf_size, int volume_in_10000)
{ {
int bytes_per_sample = (handle->dev_bits_per_sample >> 3); if (endianess == AO_FMT_LITTLE) return TRUE;
register int endianess = handle->dev_endianess; if (endianess == AO_FMT_BIG) return FALSE;
register unsigned char *buf = (unsigned char *) _buf;
register int i; /*
register long long sample; AO_FMT_NATIVE, or anything treated as native.
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;
}
}
}
}
*/ */
return littleEndian();
}
static inline int32_t read_sample(unsigned char *mem, int req_bytes, int little_endian) 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, static inline void adjustVolume(AO_Handle *handle,
char *_buf, 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) { 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); int32_t sample = read_sample(buf + i, bytes_per_sample, little_endian);
int64_t scaled = ((int64_t) sample * volume_in_10000) / 10000; 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) #if defined(USE_PTHREADS) || defined(USE_DISPATCH)
static void *run(void *arg) static void *run(void *arg)
#endif #endif
@@ -488,15 +555,18 @@ static DWORD run(LPVOID arg)
#endif #endif
} }
/**************************************************************************
* External API
**************************************************************************/
/**** ffi version for ao_play_async and ffmpeg_audio */
int ao_async_version() int ao_async_version()
{ {
return ffi_version(); return ffi_version();
} }
#ifdef AO_ASYNC_WINDOWS /**** ao initialization and shutdown */
#else
#include <dlfcn.h>
#endif
#ifdef AO_ASYNC_WINDOWS #ifdef AO_ASYNC_WINDOWS
static void at_exit_shutdown_ao(void) 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, static ao_device *try_open_device(int bits, int rate, int channels, int byte_format,
const char *wav_file_output, 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; 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) void *ao_create_async(int bits, int rate, int channels, int byte_format, const char *wav_file_output)
{ {
init_ao(); init_ao();
@@ -758,27 +751,8 @@ void ao_stop_async(void *ao_handle)
fprintf(stderr, "async handle freed\n"); 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) 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) void ao_clear_async(void *ao_handle)
{ {
AO_Handle *h = (AO_Handle *) ao_handle; AO_Handle *h = (AO_Handle *) ao_handle;
@@ -811,6 +787,8 @@ void ao_clear_async(void *ao_handle)
clear(h, FALSE); clear(h, FALSE);
} }
/**** Information on the current samples being played by the player thread */
double ao_is_at_second_async(void *ao_handle) double ao_is_at_second_async(void *ao_handle)
{ {
AO_Handle *h = (AO_Handle *) ao_handle; AO_Handle *h = (AO_Handle *) ao_handle;
@@ -847,6 +825,8 @@ int ao_bufsize_async(void *ao_handle)
return s; return s;
} }
/**** Volume related functions */
void ao_set_volume_async(void *ao_handle, double percentage) void ao_set_volume_async(void *ao_handle, double percentage)
{ {
AO_Handle *h = (AO_Handle *) ao_handle; AO_Handle *h = (AO_Handle *) ao_handle;
@@ -869,6 +849,8 @@ double ao_volume_async(void *ao_handle)
return volume; return volume;
} }
/**** Pausing playback */
void ao_pause_async(void *ao_handle, int paused) void ao_pause_async(void *ao_handle, int paused)
{ {
AO_Handle *h = (AO_Handle *) ao_handle; AO_Handle *h = (AO_Handle *) ao_handle;
@@ -889,6 +871,8 @@ void ao_pause_async(void *ao_handle, int paused)
MUTEX_UNLOCK(h->mutex); MUTEX_UNLOCK(h->mutex);
} }
/**** Information about the output device */
int ao_real_output_bits_async(void *handle) int ao_real_output_bits_async(void *handle)
{ {
AO_Handle *h = (AO_Handle *) handle; AO_Handle *h = (AO_Handle *) handle;
@@ -896,3 +880,4 @@ int ao_real_output_bits_async(void *handle)
} }
+1 -3
View File
@@ -11,9 +11,7 @@
#define AOPLAYASYNC_EXPORT extern #define AOPLAYASYNC_EXPORT extern
#endif #endif
#define VERSION_MAJOR 1 #include "../ffi_version.h"
#define VERSION_MINOR 0
#define VERSION_PATCH 0
typedef enum { typedef enum {
ao = 1, ao = 1,
Binary file not shown.