Compare commits

16 Commits
0-1-0 ... main

22 changed files with 582 additions and 78 deletions

15
.gitignore vendored
View File

@@ -12,23 +12,8 @@
*.gch *.gch
*.pch *.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files # Fortran module files
*.mod *.mod
*.smod *.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app

View File

@@ -1,16 +1,26 @@
all: all:
mkdir -p build mkdir -p build
cmake -S ao-play-async -B build cmake -S ao-play-async -B build
(cd build; make) (cd build; make)
install: install: all
mkdir -p ../../lib
SUBDIR=`racket -e "(display (format \"~a-~a\" (system-type 'os*) (system-type 'arch)))"`; \ SUBDIR=`racket -e "(display (format \"~a-~a\" (system-type 'os*) (system-type 'arch)))"`; \
FILES=`ls build/*.so` 2>/dev/null; if [ "$$FILES" != "" ]; then cp $$FILES ../../lib/$$SUBDIR; fi mkdir -p lib/$$SUBDIR
SUBDIR=`racket -e "(display (format \"~a-~a\" (system-type 'os*) (system-type 'arch)))"`; \ SUBDIR=`racket -e "(display (format \"~a-~a\" (system-type 'os*) (system-type 'arch)))"`; \
FILES=`ls build/*.dll` 2>/dev/null; if [ "$$FILES" != "" ]; then cp $$FILES ../../lib/$$SUBDIR; fi FILES=`ls build/*.so` 2>/dev/null; if [ "$$FILES" != "" ]; then cp $$FILES lib/$$SUBDIR; fi
SUBDIR=`racket -e "(display (format \"~a-~a\" (system-type 'os*) (system-type 'arch)))"`; \
FILES=`ls build/*.dll` 2>/dev/null; if [ "$$FILES" != "" ]; then cp $$FILES lib/$$SUBDIR; fi
test: install
cp lib/linux-x86_64/*.so ~/.local/share/racket/racket-sound-lib/linux-x86_64
zip: install
SUBDIR=`racket -e "(display (format \"~a-~a\" (system-type 'os*) (system-type 'arch)))"`; \
(cd lib; zip -y -r -9 $$SUBDIR.zip $$SUBDIR)
SUBDIR=`racket -e "(display (format \"~a-~a\" (system-type 'os*) (system-type 'arch)))"`; \
(cd lib; rm -rf $$SUBDIR)
clean: clean:
rm -rf build rm -rf build

View File

@@ -72,3 +72,4 @@ CMakeLists.txt.user*
*.dll *.dll
*.exe *.exe
build

View File

@@ -10,4 +10,17 @@ add_library(ao-play-async SHARED
ao_playasync.h ao_playasync.h
) )
if(WIN32)
#include_directories(../../libao/include ../../libao/build-windows)
include_directories(windows)
target_link_directories(ao-play-async PRIVATE ../lib/windows-x86_64)
endif()
if(WIN32)
target_link_libraries(ao-play-async PRIVATE libao-1.2.2 winmm.lib ksuser.lib)
else()
target_link_libraries(ao-play-async PRIVATE ao)
endif()
target_compile_definitions(ao-play-async PRIVATE AOPLAYASYNC_LIBRARY) target_compile_definitions(ao-play-async PRIVATE AOPLAYASYNC_LIBRARY)

View File

@@ -12,31 +12,82 @@
#ifdef USE_WINDOWS_THREADS #ifdef USE_WINDOWS_THREADS
#define MUTEX_LOCK(m) WaitForSingleObject(m, INFINITE) #define MUTEX_LOCK(m) WaitForSingleObject(m, INFINITE)
#define MUTEX_UNLOCK(m) ReleaseMutex(m) #define MUTEX_UNLOCK(m) ReleaseMutex(m)
#define SEM_WAIT(sem, ms) (WaitForSingleObject(sem, ms) == WAIT_OBJECT_0)
#define SEM_TRYWAIT(sem) (WaitForSingleObject(sem, 0) == WAIT_OBJECT_0)
#define SEM_POST(sem) ReleaseSemaphore(sem, 1, NULL)
#define YIELD() sleep_ms(5)
#endif #endif
#ifdef USE_PTHREADS #ifdef USE_PTHREADS
#include <pthread.h> #include <pthread.h>
#include <semaphore.h>
#include <sched.h>
#define TIME_NS_IN_MSEC 1000000ULL
static void makeSemTimeoutTime(struct timespec *ts, int ms) {
clock_gettime(CLOCK_REALTIME, ts);
ts->tv_sec += ms / 1000;
ts->tv_nsec += (ms % 1000) * TIME_NS_IN_MSEC;
if (ts->tv_nsec >= 1000000000L) {
ts->tv_sec++;
ts->tv_nsec = ts->tv_nsec - 1000000000L;
}
}
static int _SEM_WAIT(sem_t *sem, int ms)
{
struct timespec ts;
makeSemTimeoutTime(&ts, ms);
int r = sem_timedwait(sem, &ts);
return (r == 0);
}
static int msleep(long msec)
{
struct timespec ts;
int res;
if (msec < 0) {
return -1;
}
ts.tv_sec = msec / 1000;
ts.tv_nsec = (msec % 1000) * 1000000;
res = nanosleep(&ts, &ts);
return res;
}
static void yield()
{
msleep(5);
}
#define MUTEX_LOCK(m) pthread_mutex_lock(&m) #define MUTEX_LOCK(m) pthread_mutex_lock(&m)
#define MUTEX_UNLOCK(m) pthread_mutex_unlock(&m) #define MUTEX_UNLOCK(m) pthread_mutex_unlock(&m)
#define SEM_WAIT(sem, ms) _SEM_WAIT(&sem, ms)
#define SEM_TRYWAIT(sem) (sem_trywait(&sem) == 0)
#define SEM_POST(sem) sem_post(&sem)
#define YIELD() yield()
#endif #endif
#ifndef WIN32 #ifndef WIN32
#include <unistd.h> #include <unistd.h>
#endif #endif
#include <assert.h>
#include <malloc.h> #include <malloc.h>
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h>
#include <ao/ao.h>
typedef enum { typedef enum {
PLAY = 1, PLAY = 1,
STOP = 2 STOP = 2
} Command_t; } Command_t;
typedef void * ao_device;
typedef struct _queue_ { typedef struct _queue_ {
Command_t command; Command_t command;
@@ -44,6 +95,7 @@ typedef struct _queue_ {
int buflen; int buflen;
double at_second; double at_second;
double music_duration; double music_duration;
int music_id;
struct _queue_ *next; struct _queue_ *next;
struct _queue_ *prev; struct _queue_ *prev;
} Queue_t; } Queue_t;
@@ -53,36 +105,45 @@ typedef int(*ao_play_func_t)(void *, char *, uint32_t);
typedef struct { typedef struct {
Queue_t *play_queue; Queue_t *play_queue;
Queue_t *last_frame; Queue_t *last_frame;
int paused;
ao_device *ao_device; ao_device *ao_device;
#ifdef USE_WINDOWS_THREADS #ifdef USE_WINDOWS_THREADS
HANDLE mutex; HANDLE mutex;
HANDLE pause_mutex;
HANDLE clear_mutex;
HANDLE thread; HANDLE thread;
DWORD thread_id; DWORD thread_id;
HANDLE queue_sem;
#endif #endif
#ifdef USE_PTHREADS #ifdef USE_PTHREADS
pthread_mutex_t mutex; pthread_mutex_t mutex;
pthread_mutex_t pause_mutex;
pthread_mutex_t clear_mutex;
pthread_t thread; pthread_t thread;
sem_t queue_sem;
#endif #endif
double at_second; double at_second;
double music_duration; double music_duration;
ao_play_func_t ao_play_f; int at_music_id;
int buf_size; int buf_size;
int paused;
} AO_Handle; } AO_Handle;
//static int(*ao_play)(void *device, char *samples, uint32_t n) = NULL;
static Queue_t *get(AO_Handle *h, int ms_wait)
static Queue_t *front(AO_Handle *h)
{ {
assert(h->play_queue != NULL); Queue_t *q = NULL;
return h->play_queue; int r;
if (ms_wait <= 0) {
r = SEM_TRYWAIT(h->queue_sem);
} else {
r = SEM_WAIT(h->queue_sem, ms_wait);
} }
if (r) {
static Queue_t *get(AO_Handle *h) MUTEX_LOCK(h->mutex);
{ if (h->play_queue != NULL) { // Clear could have cleared the play_queue.
assert(h->play_queue != NULL); q = h->play_queue;
Queue_t *q = h->play_queue;
h->play_queue = h->play_queue->next; h->play_queue = h->play_queue->next;
if (h->play_queue == NULL) { if (h->play_queue == NULL) {
h->last_frame = NULL; h->last_frame = NULL;
@@ -90,11 +151,15 @@ static Queue_t *get(AO_Handle *h)
h->play_queue->prev = NULL; h->play_queue->prev = NULL;
} }
h->buf_size -= q->buflen; h->buf_size -= q->buflen;
}
MUTEX_UNLOCK(h->mutex);
}
return q; return q;
} }
static void add(AO_Handle *h, Queue_t *elem) static void add(AO_Handle *h, Queue_t *elem)
{ {
MUTEX_LOCK(h->mutex);
if (h->last_frame == NULL) { if (h->last_frame == NULL) {
h->play_queue = elem; h->play_queue = elem;
elem->next = NULL; elem->next = NULL;
@@ -107,9 +172,11 @@ static void add(AO_Handle *h, Queue_t *elem)
h->last_frame = elem; h->last_frame = elem;
} }
h->buf_size += elem->buflen; h->buf_size += elem->buflen;
SEM_POST(h->queue_sem);
MUTEX_UNLOCK(h->mutex);
} }
static Queue_t *new_elem(int command, double at_second, double music_duration, int buf_len, void *buf) static Queue_t *new_elem(int command, int music_id, double at_second, double music_duration, int buf_len, void *buf)
{ {
Queue_t *q = (Queue_t *) malloc(sizeof(Queue_t)); Queue_t *q = (Queue_t *) malloc(sizeof(Queue_t));
void *new_buf; void *new_buf;
@@ -120,11 +187,12 @@ static Queue_t *new_elem(int command, double at_second, double music_duration, i
} else { } else {
new_buf = NULL; new_buf = NULL;
} }
q->music_id = music_id;
q->at_second = at_second; q->at_second = at_second;
q->music_duration = music_duration; q->music_duration = music_duration;
q->buf = new_buf; q->buf = new_buf;
q->buflen = buf_len; q->buflen = buf_len;
q->command = command; q->command = (Command_t) command;
q->next = NULL; q->next = NULL;
q->prev = NULL; q->prev = NULL;
return q; return q;
@@ -140,10 +208,18 @@ static void del_elem(Queue_t *q)
static void clear(AO_Handle *h) static void clear(AO_Handle *h)
{ {
while (h->play_queue != NULL) { //fprintf(stderr, "Wait for clear mutex\n");
Queue_t *q = get(h); MUTEX_LOCK(h->clear_mutex);
//fprintf(stderr, "Starting clear\n");
int count = 0;
Queue_t *q = get(h, 0);
while (q != NULL) {
del_elem(q); del_elem(q);
count += 1;
q = get(h, 0);
} }
fprintf(stderr, "%d elements cleared\n", count);
MUTEX_UNLOCK(h->clear_mutex);
} }
#ifdef USE_PTHREADS #ifdef USE_PTHREADS
@@ -154,30 +230,28 @@ static DWORD run(LPVOID arg)
#endif #endif
{ {
AO_Handle *handle = (AO_Handle *) arg; AO_Handle *handle = (AO_Handle *) arg;
int go_on = (1 == 1); int go_on = (1 == 1);
while(go_on) { while(go_on) {
MUTEX_LOCK(handle->mutex); MUTEX_LOCK(handle->pause_mutex);
int has_frames = (!handle->paused) && (handle->play_queue != NULL); MUTEX_UNLOCK(handle->pause_mutex);
MUTEX_LOCK(handle->clear_mutex);
if (has_frames) { Queue_t *q = get(handle, 250);
Queue_t *q = get(handle); MUTEX_UNLOCK(handle->clear_mutex);
if (q != NULL) {
handle->at_second = q->at_second; handle->at_second = q->at_second;
handle->music_duration = q->music_duration; handle->music_duration = q->music_duration;
MUTEX_UNLOCK(handle->mutex); handle->at_music_id = q->music_id;
if (q->command == STOP) { if (q->command == STOP) {
go_on = (1 == 0); go_on = (1 == 0);
} else { } else {
//fprintf(stderr, "playing buf at %lf\n", handle->at_second); ao_play(handle->ao_device, (char *) q->buf, q->buflen);
handle->ao_play_f(handle->ao_device, q->buf, q->buflen);
} }
del_elem(q); del_elem(q);
} else { } else {
MUTEX_UNLOCK(handle->mutex); YIELD();
sleep_ms(5); // sleep for 5ms
} }
} }
@@ -189,24 +263,71 @@ static DWORD run(LPVOID arg)
#endif #endif
} }
void *ao_create_async(void *ao_device_yeah, void *ao_play_f) int ao_async_version()
{ {
//if (ao_play == NULL) { get_ao_play(); } return VERSION;
}
#ifdef _WIN32
#else
#include <dlfcn.h>
#endif
#ifdef _WIN32
static void at_exit_shutdown_ao(void)
#else
static void at_exit_shutdown_ao()
#endif
{
ao_shutdown();
}
static void init_ao()
{
static int init = 0;
if (!init) {
ao_initialize();
atexit(at_exit_shutdown_ao);
}
}
void *ao_create_async(int bits, int rate, int channels, int byte_format)
{
init_ao();
AO_Handle *handle = (AO_Handle *) malloc(sizeof(AO_Handle)); AO_Handle *handle = (AO_Handle *) malloc(sizeof(AO_Handle));
handle->ao_device = (ao_device *) ao_device_yeah; ao_sample_format fmt;
fmt.bits = bits;
fmt.rate = rate;
fmt.byte_format = byte_format;
fmt.channels = channels;
fmt.matrix = NULL;
ao_device *dev = ao_open_live(ao_default_driver_id(), &fmt, NULL);
if (dev == NULL) {
fprintf(stderr, "Cannot open ao-device, error code = %d\n", errno);
return NULL;
}
handle->ao_device = dev;
handle->play_queue = NULL; handle->play_queue = NULL;
handle->last_frame = NULL; handle->last_frame = NULL;
handle->at_second = -1; handle->at_second = -1;
handle->at_music_id = -1;
handle->ao_play_f = ao_play_f;
handle->buf_size = 0; handle->buf_size = 0;
handle->paused = (1 == 0); handle->paused = (1 == 0);
#ifdef USE_PTHREADS #ifdef USE_PTHREADS
pthread_mutex_t p = PTHREAD_MUTEX_INITIALIZER;
handle->pause_mutex = p;
pthread_mutex_t c = PTHREAD_MUTEX_INITIALIZER;
handle->clear_mutex = c;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
handle->mutex = m; handle->mutex = m;
sem_init(&handle->queue_sem, 0, 0);
pthread_create(&handle->thread, NULL, run, handle); pthread_create(&handle->thread, NULL, run, handle);
#endif #endif
@@ -214,21 +335,38 @@ void *ao_create_async(void *ao_device_yeah, void *ao_play_f)
handle->mutex = CreateMutex(NULL, // default security attributes handle->mutex = CreateMutex(NULL, // default security attributes
FALSE, // initially not owned FALSE, // initially not owned
NULL); NULL);
handle->pause_mutex = CreateMutex(NULL, // default security attributes
FALSE, // initially not owned
NULL);
handle->clear_mutex = CreateMutex(NULL,
FALSE,
NULL);
handle->queue_sem = CreateSemaphore(NULL, 0, 1000000, NULL);
handle->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) run, handle, 0, &handle->thread_id); handle->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) run, handle, 0, &handle->thread_id);
#endif #endif
MUTEX_UNLOCK(handle->pause_mutex);
MUTEX_UNLOCK(handle->clear_mutex);
return (void *) handle; return (void *) handle;
} }
void ao_stop_async(void *ao_handle) void ao_stop_async(void *ao_handle)
{ {
AO_Handle *h = (AO_Handle *) ao_handle; AO_Handle *h = (AO_Handle *) ao_handle;
fprintf(stderr, "stopping ao_async, calling clear\n");
MUTEX_LOCK(h->mutex);
clear(h); clear(h);
Queue_t *q = new_elem(STOP, 0.0, 0.0, 0, NULL);
fprintf(stderr, "queue cleared\n");
if (h->paused) {
MUTEX_UNLOCK(h->pause_mutex);
}
Queue_t *q = new_elem(STOP, 0, 0.0, 0.0, 0, NULL);
add(h, q); add(h, q);
MUTEX_UNLOCK(h->mutex);
fprintf(stderr, "stop command queued\n");
#ifdef USE_PTHREADS #ifdef USE_PTHREADS
void *retval; void *retval;
@@ -239,24 +377,148 @@ void ao_stop_async(void *ao_handle)
CloseHandle(h->thread); CloseHandle(h->thread);
CloseHandle(h->mutex); CloseHandle(h->mutex);
#endif #endif
ao_close(h->ao_device);
fprintf(stderr, "device closed\n");
free(h); free(h);
fprintf(stderr, "async handle freed\n");
} }
void ao_play_async(void *ao_handle, double at_second, double music_duration, int buf_size, void *mem) /*
(define (abs x) (if (>= x 0) x (* x -1)))
(define (make-sample-bytes sample bytes-per-sample endianess)
(letrec ((mk (lambda (i d)
(if (< i bytes-per-sample)
(cons (bitwise-and d 255)
(mk (+ i 1) (arithmetic-shift d -8)))
'()))))
(let ((bytes (mk 0 sample)))
(if (eq? endianess 'big-endian)
(reverse bytes)
bytes))))
;(get-sample (lambda (k channel)
; (let ((chan-buf (list-ref buffer channel)))
; (vector-ref chan-buf k))))
)
;(letrec ((i 0)
; (fill (lambda (k channel)
; (if (< k buf-len)
; (if (< channel channels)
; (let* ((sample (get-sample k channel))
; (bytes (make-sample-bytes sample bytes-per-sample endianess))
; )
; (for-each (lambda (byte)
; (ptr-set! audio _byte i byte)
; (set! i (+ i 1)))
; bytes)
; ;; process sample
; (fill k (+ channel 1)))
; (fill (+ k 1) 0))
; 'filled))
; ))
; (fill 0 0)
*/
#define AO_FMT_LITTLE 1
#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])
{
int i;
for (i = 0; i < bytes_per_sample; i++) {
b[i] = sample&0xff;
sample = sample >> 8;
}
if (endianess == AO_FMT_BIG) {
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];
}
}
}
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 store_size = info->channels * bytes * buf_len;
unsigned char *new_mem = (unsigned char *) malloc(store_size);
*audio_size = store_size;
int32_t **buffer = (int32_t **) mem;
int i, k, channel;
i = 0;
for(k = 0; k < buf_len; k++) {
for(channel = 0; channel < info->channels; channel++) {
int32_t *chan = buffer[channel];
int32_t sample = chan[k];
unsigned char b[4];
make_sample_bytes(sample, bytes, endianness, b);
for(int j = 0; j < bytes; j++) {
new_mem[i++] = b[j];
}
}
}
return (void *) new_mem;
}
void ao_play_async(void *ao_handle, int music_id, double at_second, double music_duration, int buf_size, void *mem, BufferInfo_t info)
{ {
AO_Handle *h = (AO_Handle *) ao_handle; AO_Handle *h = (AO_Handle *) ao_handle;
Queue_t *q = new_elem(PLAY, at_second, music_duration, buf_size, mem);
MUTEX_LOCK(h->mutex); Queue_t *q = NULL;
switch(info.type) {
case flac: {
int store_size = 0;
void *store_mem = convertFlac(mem, buf_size, &info, &store_size);
q = new_elem(PLAY, music_id, at_second, music_duration, store_size, store_mem);
free(store_mem);
}
break;
case ao: {
q = new_elem(PLAY, music_id, at_second, music_duration, buf_size, mem);
}
break;
case mpg123: {
static int warned = 0;
if (!warned) {
warned = 1;
fprintf(stderr, "format mpg123 not supported yet\n");
}
return;
}
break;
case ao_ogg: {
static int warned = 0;
if (!warned) {
warned = 1;
fprintf(stderr, "format ao_ogg not supported yet\n");
}
return;
}
break;
}
add(h, q); add(h, q);
MUTEX_UNLOCK(h->mutex);
} }
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;
MUTEX_LOCK(h->mutex);
clear(h); clear(h);
MUTEX_UNLOCK(h->mutex);
} }
double ao_is_at_second_async(void *ao_handle) double ao_is_at_second_async(void *ao_handle)
@@ -268,6 +530,15 @@ double ao_is_at_second_async(void *ao_handle)
return s; return s;
} }
int ao_is_at_music_id_async(void *ao_handle)
{
AO_Handle *h = (AO_Handle *) ao_handle;
MUTEX_LOCK(h->mutex);
int s = h->at_music_id;
MUTEX_UNLOCK(h->mutex);
return s;
}
double ao_music_duration_async(void *ao_handle) double ao_music_duration_async(void *ao_handle)
{ {
AO_Handle *h = (AO_Handle *) ao_handle; AO_Handle *h = (AO_Handle *) ao_handle;
@@ -290,7 +561,19 @@ void ao_pause_async(void *ao_handle, int paused)
{ {
AO_Handle *h = (AO_Handle *) ao_handle; AO_Handle *h = (AO_Handle *) ao_handle;
MUTEX_LOCK(h->mutex); MUTEX_LOCK(h->mutex);
if (h->paused) {
if (!paused) {
h->paused = paused; h->paused = paused;
MUTEX_UNLOCK(h->pause_mutex);
}
} else {
if (paused) {
h->paused = paused;
MUTEX_LOCK(h->pause_mutex);
}
}
MUTEX_UNLOCK(h->mutex); MUTEX_UNLOCK(h->mutex);
} }

View File

@@ -11,12 +11,31 @@
#define AOPLAYASYNC_EXPORT extern #define AOPLAYASYNC_EXPORT extern
#endif #endif
AOPLAYASYNC_EXPORT void *ao_create_async(void *ao_handle, void *ao_play_f); #define VERSION 2
typedef enum {
ao = 1,
flac = 2,
mpg123 = 3,
ao_ogg = 4
} BufferType_t;
typedef struct {
BufferType_t type;
int sample_bits;
int sample_rate;
int channels;
int endiannes;
} BufferInfo_t;
AOPLAYASYNC_EXPORT int ao_async_version(void);
AOPLAYASYNC_EXPORT void *ao_create_async(int bits, int rate, int channels, int byte_format);
AOPLAYASYNC_EXPORT void ao_stop_async(void *handle); AOPLAYASYNC_EXPORT void ao_stop_async(void *handle);
AOPLAYASYNC_EXPORT void ao_play_async(void *handle, double at_second, double music_duration, int buf_size, void *mem); AOPLAYASYNC_EXPORT void ao_play_async(void *handle, int music_id, double at_second, double music_duration, int buf_size, void *mem, BufferInfo_t info);
AOPLAYASYNC_EXPORT void ao_clear_async(void *handle); AOPLAYASYNC_EXPORT void ao_clear_async(void *handle);
AOPLAYASYNC_EXPORT double ao_is_at_second_async(void *handle); AOPLAYASYNC_EXPORT double ao_is_at_second_async(void *handle);
AOPLAYASYNC_EXPORT int ao_is_at_music_id_async(void *handle);
AOPLAYASYNC_EXPORT double ao_music_duration_async(void *handle); AOPLAYASYNC_EXPORT double ao_music_duration_async(void *handle);
AOPLAYASYNC_EXPORT void ao_pause_async(void *ao_handle, int paused); AOPLAYASYNC_EXPORT void ao_pause_async(void *ao_handle, int paused);

View File

@@ -0,0 +1,151 @@
/*
*
* ao.h
*
* Original Copyright (C) Aaron Holtzman - May 1999
* Modifications Copyright (C) Stan Seibert - July 2000, July 2001
* More Modifications Copyright (C) Jack Moffitt - October 2000
*
* This file is part of libao, a cross-platform audio outputlibrary. See
* README for a history of this source code.
*
* libao is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* libao is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef __AO_H__
#define __AO_H__
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "os_types.h"
/* --- Exporting functions ---*/
#ifdef _WIN32
#ifdef AO_BUILDING_LIBAO
#define AO_EXPORT __declspec(dllexport)
#else
#define AO_EXPORT __declspec(dllimport)
#endif
#else
#define AO_EXPORT
#endif
/* --- Constants ---*/
#define AO_TYPE_LIVE 1
#define AO_TYPE_FILE 2
#define AO_ENODRIVER 1
#define AO_ENOTFILE 2
#define AO_ENOTLIVE 3
#define AO_EBADOPTION 4
#define AO_EOPENDEVICE 5
#define AO_EOPENFILE 6
#define AO_EFILEEXISTS 7
#define AO_EBADFORMAT 8
#define AO_EFAIL 100
#define AO_FMT_LITTLE 1
#define AO_FMT_BIG 2
#define AO_FMT_NATIVE 4
/* --- Structures --- */
typedef struct ao_info {
int type; /* live output or file output? */
char *name; /* full name of driver */
char *short_name; /* short name of driver */
char *author; /* driver author */
char *comment; /* driver comment */
int preferred_byte_format;
int priority;
char **options;
int option_count;
} ao_info;
typedef struct ao_functions ao_functions;
typedef struct ao_device ao_device;
typedef struct ao_sample_format {
int bits; /* bits per sample */
int rate; /* samples per second (in a single channel) */
int channels; /* number of audio channels */
int byte_format; /* Byte ordering in sample, see constants below */
char *matrix; /* input channel location/ordering */
} ao_sample_format;
typedef struct ao_option {
char *key;
char *value;
struct ao_option *next;
} ao_option;
#if defined(AO_BUILDING_LIBAO)
#include "ao_private.h"
#endif
/* --- Functions --- */
/* library setup/teardown */
AO_EXPORT void ao_initialize(void);
AO_EXPORT void ao_shutdown(void);
/* device setup/playback/teardown */
AO_EXPORT int ao_append_global_option(const char *key,
const char *value);
AO_EXPORT int ao_append_option(ao_option **options,
const char *key,
const char *value);
AO_EXPORT void ao_free_options(ao_option *options);
AO_EXPORT ao_device* ao_open_live(int driver_id,
ao_sample_format *format,
ao_option *option);
AO_EXPORT ao_device* ao_open_file(int driver_id,
const char *filename,
int overwrite,
ao_sample_format *format,
ao_option *option);
AO_EXPORT int ao_play(ao_device *device,
char *output_samples,
uint_32 num_bytes);
AO_EXPORT int ao_close(ao_device *device);
/* driver information */
AO_EXPORT int ao_driver_id(const char *short_name);
AO_EXPORT int ao_default_driver_id(void);
AO_EXPORT ao_info *ao_driver_info(int driver_id);
AO_EXPORT ao_info **ao_driver_info_list(int *driver_count);
AO_EXPORT const char *ao_file_extension(int driver_id);
/* miscellaneous */
AO_EXPORT int ao_is_big_endian(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __AO_H__ */

View File

@@ -0,0 +1,10 @@
#pragma once
#include <stdint.h>
typedef uint8_t uint_8;
typedef uint16_t uint_16;
typedef uint32_t uint_32;
typedef int8_t sint_8;
typedef int16_t sint_16;
typedef int32_t sint_32;

BIN
lib/linux-x86_64.zip Normal file

Binary file not shown.

BIN
lib/windows-x86_64.zip Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
lib/windows-x86_64/tag.dll Normal file

Binary file not shown.

Binary file not shown.

BIN
lib/windows-x86_64/zlib.dll Normal file

Binary file not shown.

17
src/Building Win32.txt Normal file
View File

@@ -0,0 +1,17 @@
Building for Win32.
Extract the taglib sources.
Add this in CMakeLists.txt:
set(ZLIB_LIBRARY "c:/devel/libraries/nwin64/lib/zlib.lib")
set(ZLIB_INCLUDE_DIR "c:/devel/libraries/nwin64/include")
set(BUILD_TESTING OFF)
set(BUILD_SHARED_LIBS ON)
Or any place you have zlib.lib stored.
Copy the shared libraries to ../lib/windows_<arch>/

15
src/Makefile Normal file
View File

@@ -0,0 +1,15 @@
TAGLIB=taglib-2.2.1
all:
tar xf ${TAGLIB}.tar.gz
SUBDIR=`racket -e "(display (format \"~a-~a\" (system-type 'os*) (system-type 'arch)))"`; \
(cd ${TAGLIB}; cmake -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=../lib/$$SUBDIR -DCMAKE_BUILD_TYPE=Release .)
(cd ${TAGLIB}; make)
(cd ${TAGLIB}; make install)
SUBDIR=`racket -e "(display (format \"~a-~a\" (system-type 'os*) (system-type 'arch)))"`; \
(cd lib/$$SUBDIR/lib; tar cf - *so *.so.*) | (cd ../lib/$$SUBDIR; tar xvf - )
clean:
rm -rf ${TAGLIB}
rm -rf lib

BIN
src/taglib-2.2.1.tar.gz Normal file

Binary file not shown.