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 a7e2854..1fccd67 100644 Binary files a/lib/windows-x86_64/ao-play-async.dll and b/lib/windows-x86_64/ao-play-async.dll differ diff --git a/lib/windows-x86_64/ao-play-async.lib b/lib/windows-x86_64/ao-play-async.lib index 0890b86..4492e35 100644 Binary files a/lib/windows-x86_64/ao-play-async.lib and b/lib/windows-x86_64/ao-play-async.lib differ