From d7269dd927f4f6fbd651a3b0fc51d145d8406b97 Mon Sep 17 00:00:00 2001 From: Hans Dijkema Date: Tue, 21 Apr 2026 09:57:42 +0200 Subject: [PATCH] adjusting volume and getting current volume. --- ao-play-async/ao_playasync.c | 105 +++++++++++++++++++++++++-- ao-play-async/ao_playasync.h | 3 + lib/windows-x86_64/ao-play-async.dll | Bin 14848 -> 15872 bytes lib/windows-x86_64/ao-play-async.lib | Bin 3834 -> 4266 bytes 4 files changed, 103 insertions(+), 5 deletions(-) diff --git a/ao-play-async/ao_playasync.c b/ao-play-async/ao_playasync.c index 37391cb..f44966a 100644 --- a/ao-play-async/ao_playasync.c +++ b/ao-play-async/ao_playasync.c @@ -109,6 +109,11 @@ typedef struct { int paused; ao_device *ao_device; + int dev_bits_per_sample; + int dev_endianess; + int dev_channels; + int dev_rate; + #ifdef USE_WINDOWS_THREADS HANDLE mutex; HANDLE pause_mutex; @@ -128,6 +133,7 @@ typedef struct { double music_duration; int at_music_id; int buf_size; + int volume_in_10000; // volume in 100000 steps, i.e. 100000 equals 100% } AO_Handle; @@ -222,6 +228,55 @@ static void clear(AO_Handle *h) MUTEX_UNLOCK(h->clear_mutex); } +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) +{ + int bytes_per_sample = (handle->dev_bits_per_sample >> 3); + register int endianess = handle->dev_endianess; + register unsigned char *buf = (unsigned char *) _buf; + + 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; + } + } + } +} + #ifdef USE_PTHREADS static void *run(void *arg) #endif @@ -243,6 +298,11 @@ static DWORD run(LPVOID arg) handle->music_duration = q->music_duration; handle->at_music_id = q->music_id; + if (handle->volume_in_10000 != 10000) { + // adjust volume + adjustVolume(handle, q->buf, q->buflen, handle->volume_in_10000); + } + if (q->command == STOP) { go_on = (1 == 0); } else { @@ -311,6 +371,12 @@ void *ao_create_async(int bits, int rate, int channels, int byte_format) } handle->ao_device = dev; + handle->dev_bits_per_sample = bits; + handle->dev_channels = channels; + handle->dev_rate = rate; + handle->dev_endianess = byte_format; + handle->volume_in_10000 = 10000; + handle->play_queue = NULL; handle->last_frame = NULL; handle->at_second = -1; @@ -428,14 +494,15 @@ void ao_stop_async(void *ao_handle) #define AO_FMT_BIG 2 #define AO_FMT_NATIVE 4 -static inline void make_sample_bytes(int32_t sample, int bytes_per_sample, int endianess, unsigned char b[4]) +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 = sample >> 8; + sample >>= 8; } - if (endianess == AO_FMT_BIG) { + 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]; @@ -451,7 +518,12 @@ void *convertFlac(void *mem, int buf_len, BufferInfo_t *info, int *audio_size) // buf_size equals number of samples of 32bit for all channels. So buf_size for flac = 4 * buf_len * channels int bytes = info->sample_bits / 8; - int endianness = info->endiannes; + int endianess = info->endiannes; + + int little_endian = (endianess == AO_FMT_LITTLE); + if (!little_endian && endianess == AO_FMT_NATIVE) little_endian = littleEndian(); + int big_endian = !little_endian; + int store_size = info->channels * bytes * buf_len; unsigned char *new_mem = (unsigned char *) malloc(store_size); *audio_size = store_size; @@ -464,7 +536,7 @@ void *convertFlac(void *mem, int buf_len, BufferInfo_t *info, int *audio_size) int32_t *chan = buffer[channel]; int32_t sample = chan[k]; unsigned char b[4]; - make_sample_bytes(sample, bytes, endianness, b); + make_sample_bytes(sample, bytes, big_endian, b); for(int j = 0; j < bytes; j++) { new_mem[i++] = b[j]; } @@ -557,6 +629,28 @@ int ao_bufsize_async(void *ao_handle) return s; } +void ao_set_volume_async(void *ao_handle, double percentage) +{ + AO_Handle *h = (AO_Handle *) ao_handle; + MUTEX_LOCK(h->mutex); + int volume_10000 = (int) (percentage * 100.0); + if (volume_10000 >= 9990 && volume_10000 <= 10010) { + volume_10000 = 10000; + } + h->volume_in_10000 = volume_10000; + MUTEX_UNLOCK(h->mutex); +} + + +double ao_volume_async(void *ao_handle) +{ + AO_Handle *h = (AO_Handle *) ao_handle; + MUTEX_LOCK(h->mutex); + double volume = h->volume_in_10000 / 100.0; + MUTEX_UNLOCK(h->mutex); + return volume; +} + void ao_pause_async(void *ao_handle, int paused) { AO_Handle *h = (AO_Handle *) ao_handle; @@ -578,3 +672,4 @@ void ao_pause_async(void *ao_handle, int paused) } + diff --git a/ao-play-async/ao_playasync.h b/ao-play-async/ao_playasync.h index 1bf75f5..9b7c051 100644 --- a/ao-play-async/ao_playasync.h +++ b/ao-play-async/ao_playasync.h @@ -40,6 +40,9 @@ AOPLAYASYNC_EXPORT double ao_music_duration_async(void *handle); AOPLAYASYNC_EXPORT void ao_pause_async(void *ao_handle, int paused); +AOPLAYASYNC_EXPORT void ao_set_volume_async(void *ao_handle, double percentage); +AOPLAYASYNC_EXPORT double ao_volume_async(void *ao_handle); + AOPLAYASYNC_EXPORT int ao_bufsize_async(void *handle); #endif // AO_PLAYASYNC_H diff --git a/lib/windows-x86_64/ao-play-async.dll b/lib/windows-x86_64/ao-play-async.dll index a7e2854afe1fb2d94a4c49bd4fd61167d42aa223..1fccd67e8e9c626e1375a905f399fcd8475e7d22 100644 GIT binary patch delta 7072 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 delta 6305 zcmeHLeRx#WnLjg`n@m3DBMCPd@<9eNA(IcnkOVh@AQPD2i4Gc-3Kf(<&;^Ug%0yv_ zPV6MR47X#EgVuI!b-PO0KD4Ao6sVSHln_agrdFX+O<8m&glYst#LDgOz4s<$efIzT zXYcd8_xFCC_k7&B4(LZN=+ul zy2QVmGEHq_pXoa(u8A-^K{=w-Jjs4B9jp(O0h%Q4Fc+JA;!$&sz0C|oGsps}6gy$K zP8`F#X745QG?U3KJeHg6+%$icDjzCfj4L;}#UqxQO1CP1Pm^zPE6ZVg7=qHnm1Q0u zkG$bt-qSz!41JZzSbx8GFKtS=DKaNK7hTmWU)C!l%GrSOS!;$WuXQ7I%=Q8t=c(OzXKtF;e})J&&fqO68}*WV^!TlyWzp3^Ia5WKX^PNhj?^$)c~|jRee0V z+1fk5S;Z6Gyehicsmkq>v`(uA$T}Yj@xcF3cvbmsP0?31P`}?l&q48hReh?weA05Q zGagiq24hl*6(bnnvH5-q6!3U4M?|YcV=S{5tuRB2F8NgXNqA)8%r*pvJ|8v#w(gHeVS%f{+ZaBSmtscq&cYaX3cby`@F-sp-GijiJ?UA zm~r+v;}TW&h?1m|g`+L6Amt*Poh+2uskRo;5VhraAL`+(PBoN4Dy!4=uVP_0g!m(bdxA5pQo^E*kkheVJISwXrI*CVj zd$xg1c)hV@O&X8B=-C2^M_=)@17EwG5JbLiY*5xXgZRMf1IpKnc+2I0V~+~@sFU&S*ToXR4xUTj~bOv7IvO-JpNlK@7>0g4$ld2 zT(QJOFuBlOANktc$^#g~Ak>Y@G2W>@TEk;I>OO?*C=lOIE}F9iMW9jnVAzTm*{5

~rF?5{a^}CV=d#4k*ui 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