Compare commits
12 Commits
0-1-0
...
a9151fdb86
| Author | SHA1 | Date | |
|---|---|---|---|
| a9151fdb86 | |||
| 298cde0779 | |||
| 373da4aa18 | |||
| d33bdb3482 | |||
| d5957c86bd | |||
| 6bcb2702a9 | |||
| be4f0ff9dd | |||
| 09955bebdc | |||
| 2879e3f606 | |||
| 424128975d | |||
| a3119a2444 | |||
| 18803c36f1 |
-15
@@ -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
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -72,3 +72,4 @@ CMakeLists.txt.user*
|
|||||||
*.dll
|
*.dll
|
||||||
*.exe
|
*.exe
|
||||||
|
|
||||||
|
build
|
||||||
@@ -10,4 +10,6 @@ add_library(ao-play-async SHARED
|
|||||||
ao_playasync.h
|
ao_playasync.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
target_link_libraries(ao-play-async PRIVATE ao)
|
||||||
target_compile_definitions(ao-play-async PRIVATE AOPLAYASYNC_LIBRARY)
|
target_compile_definitions(ao-play-async PRIVATE AOPLAYASYNC_LIBRARY)
|
||||||
|
|||||||
+313
-43
@@ -16,27 +16,74 @@
|
|||||||
|
|
||||||
#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 +91,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 +101,43 @@ 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 thread;
|
HANDLE thread;
|
||||||
DWORD thread_id;
|
DWORD thread_id;
|
||||||
#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);
|
||||||
static Queue_t *get(AO_Handle *h)
|
} else {
|
||||||
{
|
r = SEM_WAIT(h->queue_sem, ms_wait);
|
||||||
assert(h->play_queue != NULL);
|
}
|
||||||
Queue_t *q = h->play_queue;
|
if (r) {
|
||||||
|
MUTEX_LOCK(h->mutex);
|
||||||
|
if (h->play_queue != NULL) { // Clear could have cleared the play_queue.
|
||||||
|
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 +145,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 +166,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 +181,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 +202,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 +224,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 +257,67 @@ 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
|
||||||
|
|
||||||
|
static void at_exit_shutdown_ao()
|
||||||
|
{
|
||||||
|
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 +325,35 @@ 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->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);
|
||||||
|
// TODO Windows Semaphores!
|
||||||
#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 +364,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 +517,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 +548,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
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.
Binary file not shown.
@@ -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>/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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
|
||||||
Binary file not shown.
Reference in New Issue
Block a user