6 Commits

Author SHA1 Message Date
hans a358a8593d mac os x instructions (brew) 2026-05-06 17:29:53 +02:00
hans f4e2a6aa31 changes for Mac OS X 2026-05-06 17:26:55 +02:00
hans 51a0138877 one extra linefeet 2026-05-04 17:12:30 +02:00
hans 4134cf0549 ffi_version added 2026-05-04 13:11:50 +02:00
hans 9a0ef7d76e version = 3, removed flac support, only ao type is supported from now, i.e. channel interleaved samples 2026-05-04 11:10:03 +02:00
hans 2606634c11 - 2026-04-30 14:40:47 +02:00
21 changed files with 189 additions and 153 deletions
+3
View File
@@ -20,5 +20,8 @@ build
lib/linux-x86_64
build-ffmpeg
.DS_Store
*.user
/ffmpeg-audio/.qtcreator
+4
View File
@@ -10,8 +10,12 @@ all:
install: all
mkdir -p lib/$(SUBDIR)
@echo "copying from src/$(SUBDIR) to lib/$(SUBDIR)"
exit
(cd src/$(SUBDIR);tar cf - . ) | (cd lib/$(SUBDIR); tar xvf - )
FILES=`ls build/*.so build-ffmpeg/*.so` 2>/dev/null; if [ "$$FILES" != "" ]; then cp $$FILES lib/$(SUBDIR); fi
FILES=`ls build/*.dll build-ffmpeg/*.dll` 2>/dev/null; if [ "$$FILES" != "" ]; then cp $$FILES lib/$(SUBDIR); fi
FILES=`ls build/*.dylib build-ffmpeg/*.dylib` 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
+12 -1
View File
@@ -1,3 +1,14 @@
# racket-sound-lib
Binary packages for the racket-sound FFI binding
Binary packages for the racket-sound FFI binding
## Using on Mac OS X
Make sure you have libao, libFLAC, mpg123 and ffmpeg-full installed using brew.
% brew install libao
% brew install flac
% brew install mpg123
% brew install ffmpeg-full
+8
View File
@@ -5,6 +5,8 @@ project(ao-play-async LANGUAGES C)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
add_library(ao-play-async SHARED
ao_playasync.c
ao_playasync.h
@@ -16,6 +18,12 @@ if(WIN32)
target_link_directories(ao-play-async PRIVATE ../lib/windows-x86_64)
endif()
if(APPLE)
set(AO_HOME /opt/homebrew)
include_directories(${AO_HOME}/include)
target_link_directories(ao-play-async PRIVATE ${AO_HOME}/lib)
endif()
if(WIN32)
target_link_libraries(ao-play-async PRIVATE libao-1.2.2 winmm.lib ksuser.lib)
else()
+99 -151
View File
@@ -1,46 +1,23 @@
#include "ao_playasync.h"
#include "../ffi_version.h"
#ifdef WIN32
#include <windows.h>
#define USE_WINDOWS_THREADS
#define sleep_ms(ms) Sleep(ms)
#else
#ifdef __APPLE__
#define USE_DISPATCH
#include <time.h>
#define sleep_ms(ms) msleep(ms)
#else
#define USE_PTHREADS
#include <sched.h>
#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)
#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
#ifdef USE_PTHREADS
#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);
}
#if defined(USE_PTHREADS) || defined(USE_DISPATCH)
static int msleep(long msec)
{
@@ -62,6 +39,63 @@
{
msleep(5);
}
#endif
#ifdef USE_DISPATCH
#include <pthread.h>
#include <dispatch/dispatch.h>
#include <stdint.h>
static inline dispatch_time_t makeDispatchTimeoutTime(int ms)
{
return dispatch_time(DISPATCH_TIME_NOW,
(int64_t)ms * NSEC_PER_MSEC);
}
static int _SEM_WAIT(dispatch_semaphore_t sem, int ms)
{
return dispatch_semaphore_wait(sem, makeDispatchTimeoutTime(ms)) == 0;
}
#define MUTEX_LOCK(m) pthread_mutex_lock(&m)
#define MUTEX_UNLOCK(m) pthread_mutex_unlock(&m)
#define SEM_WAIT(sem, ms) _SEM_WAIT(sem, ms)
#define SEM_TRYWAIT(sem) (dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW) == 0)
#define SEM_POST(sem) dispatch_semaphore_signal(sem)
#define YIELD() sleep_ms(5)
#endif
#ifdef USE_WINDOWS_THREADS
#define MUTEX_LOCK(m) WaitForSingleObject(m, INFINITE)
#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
#ifdef USE_PTHREADS
#include <pthread.h>
#include <semaphore.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);
}
#define MUTEX_LOCK(m) pthread_mutex_lock(&m)
#define MUTEX_UNLOCK(m) pthread_mutex_unlock(&m)
@@ -75,7 +109,9 @@
#include <unistd.h>
#endif
#ifndef __APPLE__
#include <malloc.h>
#endif
#include <string.h>
#include <stdint.h>
#include <stdio.h>
@@ -123,12 +159,17 @@ typedef struct {
DWORD thread_id;
HANDLE queue_sem;
#endif
#ifdef USE_PTHREADS
#if defined(USE_PTHREADS) || defined(USE_DISPATCH)
pthread_mutex_t mutex;
pthread_mutex_t pause_mutex;
pthread_mutex_t clear_mutex;
pthread_t thread;
#ifdef USE_PTHREADS
sem_t queue_sem;
#endif
#ifdef USE_DISPATCH
dispatch_semaphore_t queue_sem;
#endif
#endif
double at_second;
double music_duration;
@@ -278,7 +319,7 @@ static void inline adjustVolume(AO_Handle *handle, char *_buf, int buf_size, int
}
}
#ifdef USE_PTHREADS
#if defined(USE_PTHREADS) || defined(USE_DISPATCH)
static void *run(void *arg)
#endif
#ifdef USE_WINDOWS_THREADS
@@ -316,7 +357,7 @@ static DWORD run(LPVOID arg)
}
}
#ifdef USE_PTHREADS
#if defined(USE_PTHREADS) || defined(USE_DISPATCH)
return NULL;
#endif
#ifdef USE_WINDOWS_THREADS
@@ -326,7 +367,7 @@ static DWORD run(LPVOID arg)
int ao_async_version()
{
return VERSION;
return ffi_version();
}
#ifdef _WIN32
@@ -513,17 +554,23 @@ void *ao_create_async(int bits, int rate, int channels, int byte_format, const c
handle->paused = (1 == 0);
#ifdef USE_PTHREADS
#if defined(USE_PTHREADS) || defined(USE_DISPATCH)
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;
handle->mutex = m;
#ifdef USE_PTHREADS
sem_init(&handle->queue_sem, 0, 0);
#endif
#ifdef USE_DISPATCH
handle->queue_sem = dispatch_semaphore_create(0);
#endif
pthread_create(&handle->thread, NULL, run, handle);
#endif
#ifdef USE_WINDOWS_THREADS
handle->mutex = CreateMutex(NULL, // default security attributes
FALSE, // initially not owned
@@ -561,10 +608,19 @@ void ao_stop_async(void *ao_handle)
fprintf(stderr, "stop command queued\n");
#ifdef USE_PTHREADS
#if defined(USE_PTHREADS) || defined(USE_DISPATCH)
void *retval;
pthread_join(h->thread, &retval);
#ifdef USE_PTHREADS
sem_destroy(&h->queue_sem);
#endif
pthread_mutex_destroy(&h->pause_mutex);
pthread_mutex_destroy(&h->clear_mutex);
pthread_mutex_destroy(&h->mutex);
#endif
#ifdef USE_WINDOWS_THREADS
WaitForSingleObject(h->thread, INFINITE);
CloseHandle(h->thread);
@@ -579,44 +635,6 @@ void ao_stop_async(void *ao_handle)
fprintf(stderr, "async handle freed\n");
}
/*
(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
@@ -640,87 +658,18 @@ static inline void make_sample_bytes(int32_t sample, int bytes_per_sample, int b
}
}
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 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;
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, big_endian, 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;
Queue_t *q = NULL;
switch(info.type) {
case flac: {
int store_size = 0;
void *store_mem = convertFlac(mem, buf_size, &info, &store_size);
int ao_size = 0;
void *ao_mem = convert_req_to_real(ao_handle, mem, buf_size, &info, &ao_size);
int ao_size = 0;
void *ao_mem = convert_req_to_real(ao_handle, store_mem, store_size, &info, &ao_size);
q = new_elem(PLAY, music_id, at_second, music_duration, ao_size, ao_mem);
q = new_elem(PLAY, music_id, at_second, music_duration, ao_size, ao_mem);
free(store_mem);
free(ao_mem);
}
break;
case ao: {
int ao_size = 0;
void *ao_mem = convert_req_to_real(ao_handle, mem, buf_size, &info, &ao_size);
q = new_elem(PLAY, music_id, at_second, music_duration, ao_size, ao_mem);
free(ao_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;
}
free(ao_mem);
add(h, q);
}
@@ -809,11 +758,10 @@ void ao_pause_async(void *ao_handle, int paused)
MUTEX_UNLOCK(h->mutex);
}
int ao_real_output_bits_async(void *handle)
{
AO_Handle *h = (AO_Handle *) handle;
return h->dev_bits_per_sample;
}
+4 -1
View File
@@ -11,7 +11,9 @@
#define AOPLAYASYNC_EXPORT extern
#endif
#define VERSION 2
#define VERSION_MAJOR 1
#define VERSION_MINOR 0
#define VERSION_PATCH 0
typedef enum {
ao = 1,
@@ -46,4 +48,5 @@ AOPLAYASYNC_EXPORT double ao_volume_async(void *ao_handle);
AOPLAYASYNC_EXPORT int ao_bufsize_async(void *handle);
AOPLAYASYNC_EXPORT int ao_real_output_bits_async(void *handle);
#endif // AO_PLAYASYNC_H
+10
View File
@@ -0,0 +1,10 @@
#ifndef __FFI_VERSION__
#define __FFI_VERSION__
#define VERSION_MAJOR 1
#define VERSION_MINOR 0
#define VERSION_PATCH 0
#define ffi_version() ((VERSION_MAJOR << 16) + (VERSION_MINOR << 8) + VERSION_PATCH)
#endif
+6
View File
@@ -8,6 +8,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_library(ffmpeg_audio SHARED
ffmpeg_audio.cpp
ffmpeg_audio.h
../ffi_version.h
)
add_executable(demo_ffmpeg_audio
@@ -21,6 +22,11 @@ if(WIN32)
target_link_directories(ffmpeg_audio PRIVATE ${FFMPEG_LIB})
set(FFMPEG_LIBRARIES avcodec.lib avformat.lib swresample.lib avutil.lib avdevice.lib avfilter.lib swscale.lib)
target_link_directories(demo_ffmpeg_audio PRIVATE ${FFMPEG_LIB})
elseif(APPLE)
target_link_directories(ffmpeg_audio PRIVATE /opt/homebrew/opt/ffmpeg-full/lib)
include_directories(/opt/homebrew/opt/ffmpeg-full/include)
set(FFMPEG_LIBRARIES avcodec avformat swresample avutil avdevice avfilter swscale)
target_link_directories(demo_ffmpeg_audio PRIVATE /opt/homebrew/opt/ffmpeg-full/lib)
else()
set(FFMPEG_LIBRARIES avcodec avformat swresample avutil avdevice avfilter swscale)
endif()
+6
View File
@@ -13,6 +13,7 @@
*/
#include "ffmpeg_audio.h"
#include "../ffi_version.h"
#include <algorithm>
#include <cstdint>
@@ -1021,3 +1022,8 @@ const char *fmpg_int_version2string(int ver)
return version;
}
int fmpg_version()
{
return ffi_version();
}
+1
View File
@@ -150,6 +150,7 @@ FFMPEG_EXTERN int64_t fmpg_sample_position(fmpg_instance *instance);
/* Approximate start time of the current decoded block in seconds. */
FFMPEG_EXTERN double fmpg_timecode(fmpg_instance *instance);
FFMPEG_EXTERN int fmpg_version();
FFMPEG_EXTERN const char *fmpg_ffmpeg_version();
FFMPEG_EXTERN const char *fmpg_int_version2string(int ver);
FFMPEG_EXTERN int fmpg_compatible_ffmpeg();
+17
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
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
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
libtag.so.2
+1
View File
@@ -0,0 +1 @@
libtag.so.2.2.1
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
libtag_c.so.2
+1
View File
@@ -0,0 +1 @@
libtag_c.so.2.2.1
Binary file not shown.