diff --git a/.gitignore b/.gitignore index 7893359..6d257d5 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ compiled/ \#* .\#* libao/c/build +libao/c/ao-play-async/build diff --git a/libao/c/ao-play-async/ao_playasync.c b/libao/c/ao-play-async/ao_playasync.c index 4da7911..64e268e 100644 --- a/libao/c/ao-play-async/ao_playasync.c +++ b/libao/c/ao-play-async/ao_playasync.c @@ -1,10 +1,32 @@ #include "ao_playasync.h" -#include + +#ifdef WIN32 +#include +#define USE_WINDOWS_THREADS +#define sleep_ms(ms) Sleep(ms) +#else +#define USE_PTHREADS +#define sleep_ms(ms) usleep(ms * 1000) +#endif + +#ifdef USE_WINDOWS_THREADS + #define MUTEX_LOCK(m) WaitForSingleObject(m, INFINITE) + #define MUTEX_UNLOCK(m) ReleaseMutex(m) +#endif + +#ifdef USE_PTHREADS + #include + #define MUTEX_LOCK(m) pthread_mutex_lock(&m) + #define MUTEX_UNLOCK(m) pthread_mutex_unlock(&m) +#endif + +#ifndef WIN32 #include +#endif + #include #include #include -//#include #include #include #include @@ -25,12 +47,21 @@ typedef struct _queue_ { struct _queue_ *prev; } Queue_t; +typedef int(*ao_play_func_t)(void *, char *, uint32_t); + typedef struct { Queue_t *play_queue; Queue_t *last_frame; ao_device *ao_device; +#ifdef USE_WINDOWS_THREADS + HANDLE mutex; + HANDLE thread; + DWORD thread_id; +#endif +#ifdef USE_PTHREADS pthread_mutex_t mutex; pthread_t thread; +#endif double at_second; ao_play_func_t ao_play_f; int buf_size; @@ -111,58 +142,48 @@ static void clear(AO_Handle *h) } } +#ifdef USE_PTHREADS static void *run(void *arg) +#endif +#ifdef USE_WINDOWS_THREADS +static DWORD run(LPVOID arg) +#endif { AO_Handle *handle = (AO_Handle *) arg; int go_on = (1 == 1); while(go_on) { - pthread_mutex_lock(&handle->mutex); + MUTEX_LOCK(handle->mutex); int has_frames = (handle->play_queue != NULL); if (has_frames) { Queue_t *q = get(handle); handle->at_second = q->at_second; - pthread_mutex_unlock(&handle->mutex); + MUTEX_UNLOCK(handle->mutex); if (q->command == STOP) { go_on = (1 == 0); } else { + //fprintf(stderr, "playing buf at %lf\n", handle->at_second); handle->ao_play_f(handle->ao_device, q->buf, q->buflen); } del_elem(q); } else { - pthread_mutex_unlock(&handle->mutex); - usleep(5000); // sleep for 5ms + MUTEX_UNLOCK(handle->mutex); + sleep_ms(5); // sleep for 5ms } } +#ifdef USE_PTHREADS return NULL; +#endif +#ifdef USE_WINDOWS_THREADS + return 0; +#endif } -/* -static void get_ao_play(void) -{ - char *lib = "libao.so"; - void *handle = dlopen(lib, RTLD_LAZY); - if (!handle) { - fprintf(stderr, "Cannot open library %s: %s\n", lib, dlerror()); - exit(EXIT_FAILURE); - } - - ao_play = dlsym(handle, "ao_play"); - char *err; - err = dlerror(); - if (err != NULL) { - fprintf(stderr, "Cannot get function ao_play: %s\n", err); - exit(EXIT_FAILURE); - } -} -*/ - - void *ao_create_async(void *ao_device_yeah, void *ao_play_f) { //if (ao_play == NULL) { get_ao_play(); } @@ -173,12 +194,22 @@ void *ao_create_async(void *ao_device_yeah, void *ao_play_f) handle->play_queue = NULL; handle->last_frame = NULL; handle->at_second = -1; - pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; - handle->mutex = m; + handle->ao_play_f = ao_play_f; handle->buf_size = 0; +#ifdef USE_PTHREADS + pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + handle->mutex = m; pthread_create(&handle->thread, NULL, run, handle); +#endif + +#ifdef USE_WINDOWS_THREADS + handle->mutex = CreateMutex(NULL, // default security attributes + FALSE, // initially not owned + NULL); + handle->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) run, handle, 0, &handle->thread_id); +#endif return (void *) handle; } @@ -187,14 +218,21 @@ void ao_stop_async(void *ao_handle) { AO_Handle *h = (AO_Handle *) ao_handle; - pthread_mutex_lock(&h->mutex); + MUTEX_LOCK(h->mutex); clear(h); Queue_t *q = new_elem(STOP, 0.0, 0, NULL); add(h, q); - pthread_mutex_unlock(&h->mutex); + MUTEX_UNLOCK(h->mutex); +#ifdef USE_PTHREADS void *retval; pthread_join(h->thread, &retval); +#endif +#ifdef USE_WINDOWS_THREADS + WaitForSingleObject(h->thread, INFINITE); + CloseHandle(h->thread); + CloseHandle(h->mutex); +#endif free(h); } @@ -202,26 +240,26 @@ void ao_play_async(void *ao_handle, double at_second, int buf_size, void *mem) { AO_Handle *h = (AO_Handle *) ao_handle; Queue_t *q = new_elem(PLAY, at_second, buf_size, mem); - pthread_mutex_lock(&h->mutex); + MUTEX_LOCK(h->mutex); add(h, q); - pthread_mutex_unlock(&h->mutex); + MUTEX_UNLOCK(h->mutex); } double ao_is_at_second_async(void *ao_handle) { AO_Handle *h = (AO_Handle *) ao_handle; - pthread_mutex_lock(&h->mutex); + MUTEX_LOCK(h->mutex); double s = h->at_second; - pthread_mutex_unlock(&h->mutex); + MUTEX_UNLOCK(h->mutex); return s; } int ao_bufsize_async(void *ao_handle) { AO_Handle *h = (AO_Handle *) ao_handle; - pthread_mutex_lock(&h->mutex); + MUTEX_LOCK(h->mutex); int s = h->buf_size; - pthread_mutex_unlock(&h->mutex); + MUTEX_UNLOCK(h->mutex); return s; } diff --git a/libao/c/ao-play-async/ao_playasync.h b/libao/c/ao-play-async/ao_playasync.h index d0c9dfb..3d11f18 100644 --- a/libao/c/ao-play-async/ao_playasync.h +++ b/libao/c/ao-play-async/ao_playasync.h @@ -1,14 +1,20 @@ #ifndef AO_PLAYASYNC_H #define AO_PLAYASYNC_H -#include +#ifdef _WINDOWS +#ifdef AOPLAYASYNC_LIBRARY +#define AOPLAYASYNC_EXPORT __declspec(dllexport) +#else +#define AOPLAYASYNC_EXPORT __declspec(dllimport) +#endif +#else +#define AOPLAYASYNC_EXPORT extern +#endif -typedef int(*ao_play_func_t)(void *, char *, uint32_t); - -extern void *ao_create_async(void *ao_handle, void *ao_play_f); -extern void ao_stop_async(void *handle); -extern void ao_play_async(void *handle, double at_second, int buf_size, void *mem); -extern double ao_is_at_second_async(void *handle); -extern int ao_bufsize_async(void *handle); +AOPLAYASYNC_EXPORT void *ao_create_async(void *ao_handle, void *ao_play_f); +AOPLAYASYNC_EXPORT void ao_stop_async(void *handle); +AOPLAYASYNC_EXPORT void ao_play_async(void *handle, double at_second, int buf_size, void *mem); +AOPLAYASYNC_EXPORT double ao_is_at_second_async(void *handle); +AOPLAYASYNC_EXPORT int ao_bufsize_async(void *handle); #endif // AO_PLAYASYNC_H diff --git a/libao/lib/ao-play-async.dll b/libao/lib/ao-play-async.dll new file mode 100644 index 0000000..aa25038 Binary files /dev/null and b/libao/lib/ao-play-async.dll differ diff --git a/libao/lib/ao-play-async.exp b/libao/lib/ao-play-async.exp new file mode 100644 index 0000000..34f2a35 Binary files /dev/null and b/libao/lib/ao-play-async.exp differ diff --git a/libao/lib/ao-play-async.lib b/libao/lib/ao-play-async.lib new file mode 100644 index 0000000..d9a930c Binary files /dev/null and b/libao/lib/ao-play-async.lib differ diff --git a/libao/libao-async-ffi.rkt b/libao/libao-async-ffi.rkt index bafe099..097597a 100644 --- a/libao/libao-async-ffi.rkt +++ b/libao/libao-async-ffi.rkt @@ -16,10 +16,14 @@ ao_bufsize_async ) -(define-runtime-path libao-async-path "./lib/libao-play-async") +(define-runtime-path libao-async-lib-path "./lib") + +(define lib (if (eq? (system-type 'os) 'windows) + (build-path libao-async-lib-path "ao-play-async") + (build-path libao-async-lib-path "libao-play-async"))) (define-ffi-definer define-libao-async - (ffi-lib libao-async-path '("0" #f) + (ffi-lib lib '("0" #f) #:get-lib-dirs (λ () (let ((sp (cons (build-path ".") (get-lib-search-dirs)))) ;(displayln sp) diff --git a/libao/libao.rkt b/libao/libao.rkt index 8b6314a..7c04a7f 100644 --- a/libao/libao.rkt +++ b/libao/libao.rkt @@ -164,6 +164,11 @@ audio-buf-len audio) ) + ;(let* ((handle-num (ao-handle-handle-num handle)) + ; (ao-device (hash-ref devices handle-num #f))) + ; (if (eq? ao-device #f) + ; (error "No device for this handle") + ; (ao_play ao-device audio audio-buf-len))) ) ) ) diff --git a/play-test.rkt b/play-test.rkt index 9b24c5f..14759c6 100644 --- a/play-test.rkt +++ b/play-test.rkt @@ -4,13 +4,21 @@ data/queue ) +(define test-file3 #f) +(let ((os (system-type 'os))) + (when (eq? os 'unix) + (set! test-file3 "/muziek/Klassiek-Viool/Alina Ibragimova/Paganini_24 Caprices (2021)/24. 24 Caprices, Op 1 - No. 24 in A minor- Tema con variazioni. Quasi presto.flac")) + (when (eq? os 'windows) + (set! test-file3 "C:\\Muziek\\Klassiek-Strijkkwartet\\Quatuor Zaïde\\Franz\\01 Erlkönig, D. 328 (Arr. For String Quartet by Eric Mouret).flac") + ;(set! test-file3 "C:\\Muziek\\Klassiek-Viool\\Janine Jansen\\Janine Jansen - Sibelius en Prokovief 1 (2024)\\02 - Violin Concerto in D Minor, Op. 47 II. Adagio di molto.flac") + ) + ) - -(define test-file3 "/muziek/Klassiek-Viool/Alina Ibragimova/Paganini_24 Caprices (2021)/24. 24 Caprices, Op 1 - No. 24 in A minor- Tema con variazioni. Quasi presto.flac") -(define fmt (ao-mk-format 24 48000 2 'big-endian)) -(define ao-h (ao-open-live #f fmt)) +;(define fmt (ao-mk-format 24 48000 2 'big-endian)) +;(define ao-h (ao-open-live #f fmt)) (define current-seconds 0) +(define ao-h #f) (define (flac-play frame buffer) (let* ((sample (hash-ref frame 'number)) @@ -21,12 +29,17 @@ (channels (hash-ref frame 'channels)) (bytes-per-sample-all-channels (* channels bytes-per-sample)) ) + (when (eq? ao-h #f) + (let ((fmt (ao-mk-format bits-per-sample rate channels 'big-endian))) + (set! ao-h (ao-open-live #f fmt)))) (ao-play ao-h second buffer) (let ((second-printer (λ () (let ((s (inexact->exact (round (ao-at-second ao-h))))) (when (> s current-seconds) (set! current-seconds s) - (displayln (format "At second: ~a" s))))))) + (let ((minutes (quotient s 60)) + (seconds (remainder s 60))) + (displayln (format "At time: ~a:~a" minutes seconds)))))))) (let* ((buf-size (ao-bufsize-async ao-h)) (buf-seconds (exact->inexact (/ buf-size bytes-per-sample-all-channels rate)))) (second-printer)