8 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
hans ca9e1878d8 added ffmpeg support on windows 2026-04-28 22:48:14 +02:00
hans 15fb5a8499 enhancements for the rktplayer 2026-04-28 22:20:35 +02:00
33 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.
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.
Binary file not shown.
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.