final linux version

This commit is contained in:
2026-05-11 09:21:12 +02:00
parent fc4b6f8ced
commit 7de84cbf30
3 changed files with 134 additions and 151 deletions
+133 -148
View File
@@ -128,12 +128,21 @@
#include <ao/ao.h>
#include <errno.h>
#ifdef AO_ASYNC_WINDOWS
#else
#include <dlfcn.h>
#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 <dlfcn.h>
#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)
}
+1 -3
View File
@@ -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,