(module libmpg123-ffi racket/base (require ffi/unsafe ffi/unsafe/define "private/utils.rkt" ) (provide mpg123-ffi-decoder-handler ) (define lib (get-lib '("libmpg123") '("0" #f))) (define-ffi-definer define-libmpg123 lib #:default-make-fail make-not-available) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Some MPG123 Constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define _size_t _size) (define SEEK_SET 0) (define SEEK_CUR 1) (define SEEK_END 2) (define _Seek_t (_enum '(seek-set = 0 seek-cur = 1 seek-end = 2 ) ) ) (define _MPG123_Result (_enum '(MPG123_DONE = -12 ;/**< Message: Track ended. Stop decoding. */ MPG123_NEW_FORMAT = -11 ;/**< Message: Output format will be different on next call. ; Note that some libmpg123 versions between 1.4.3 and 1.8.0 ; insist on you calling mpg123_getformat() after getting this ; message code. Newer verisons behave like advertised: ; You have the chance to call mpg123_getformat(), but you can ; also just continue decoding and get your data. */ MPG123_NEED_MORE = -10 ;/**< Message: For feed reader: "Feed me more!" (call ; mpg123_feed() or mpg123_decode() with some new input data). */ MPG123_ERR = -1 ;/**< Generic Error */ MPG123_OK = 0 ;/**< Success */ MPG123_BAD_OUTFORMAT ;/**< Unable to set up output format! */ MPG123_BAD_CHANNEL ;/**< Invalid channel number specified. */ MPG123_BAD_RATE ;/**< Invalid sample rate specified. */ MPG123_ERR_16TO8TABLE ;/**< Unable to allocate memory for 16 to 8 converter table! */ MPG123_BAD_PARAM ;/**< Bad parameter id! */ MPG123_BAD_BUFFER ;/**< Bad buffer given -- invalid pointer or too small size. */ MPG123_OUT_OF_MEM ;/**< Out of memory -- some malloc() failed. */ MPG123_NOT_INITIALIZED ;/**< You didn't initialize the library! */ MPG123_BAD_DECODER ;/**< Invalid decoder choice. */ MPG123_BAD_HANDLE ;/**< Invalid mpg123 handle. */ MPG123_NO_BUFFERS ;/**< Unable to initialize frame buffers (out of memory?). */ MPG123_BAD_RVA ;/**< Invalid RVA mode. */ MPG123_NO_GAPLESS ;/**< This build doesn't support gapless decoding. */ MPG123_NO_SPACE ;/**< Not enough buffer space. */ MPG123_BAD_TYPES ;/**< Incompatible numeric data types. */ MPG123_BAD_BAND ;/**< Bad equalizer band. */ MPG123_ERR_NULL ;/**< Null pointer given where valid storage address needed. */ MPG123_ERR_READER ;/**< Error reading the stream. */ MPG123_NO_SEEK_FROM_END ;/**< Cannot seek from end (end is not known). */ MPG123_BAD_WHENCE ;/**< Invalid 'whence' for seek function.*/ MPG123_NO_TIMEOUT ;/**< Build does not support stream timeouts. */ MPG123_BAD_FILE ;/**< File access error. */ MPG123_NO_SEEK ;/**< Seek not supported by stream. */ MPG123_NO_READER ;/**< No stream opened or no reader callback setup. */ MPG123_BAD_PARS ;/**< Bad parameter handle. */ MPG123_BAD_INDEX_PAR ;/**< Bad parameters to MPG123_index() and MPG123_set_index() */ MPG123_OUT_OF_SYNC ;/**< Lost track in bytestream and did not try to resync. */ MPG123_RESYNC_FAIL ;/**< Resync failed to find valid MPEG data. */ MPG123_NO_8BIT ;/**< No 8bit encoding possible. */ MPG123_BAD_ALIGN ;/**< Stack aligmnent error */ MPG123_NULL_BUFFER ;/**< NULL input buffer with non-zero size... */ MPG123_NO_RELSEEK ;/**< Relative seek not possible (screwed up file offset) */ MPG123_NULL_POINTER ;/**< You gave a null pointer somewhere where you shouldn't have. */ MPG123_BAD_KEY ;/**< Bad key value given. */ MPG123_NO_INDEX ;/**< No frame index in this build. */ MPG123_INDEX_FAIL ;/**< Something with frame index went wrong. */ MPG123_BAD_DECODER_SETUP ;/**< Something prevents a proper decoder setup */ MPG123_MISSING_FEATURE ;/**< This feature has not been built into libmpg123. */ MPG123_BAD_VALUE ;/**< A bad value has been given somewhere. */ MPG123_LSEEK_FAILED ;/**< Low-level seek failed. */ MPG123_BAD_CUSTOM_IO ;/**< Custom I/O not prepared. */ MPG123_LFS_OVERFLOW ;/**< Offset value overflow during translation ; of large file API calls -- your client program ; cannot handle that large file. */ MPG123_INT_OVERFLOW ;/**< Some integer overflow. */ MPG123_BAD_FLOAT ;/**< Floating-point computations work not as expected. */ ) _int ) ) (define _mpg123_handle _pointer) ; MPG123_EXPORT int mpg123_init (void) ; Not relevant anymore (define-libmpg123 mpg123_init (_fun -> _MPG123_Result)) ; MPG123_EXPORT mpg123_handle *mpg123_new (const char *decoder, int *error) (define-libmpg123 mpg123_new (_fun _string/utf-8 (err : (_ptr o _int)) -> (h : _mpg123_handle) -> (values h err))) ; MPG123_EXPORT size_t mpg123_outblock ( mpg123_handle * mh ) (define-libmpg123 mpg123_outblock (_fun _mpg123_handle -> _size_t)) ; MPG123_EXPORT int mpg123_open (mpg123_handle *mh, const char *path) (define-libmpg123 mpg123_open (_fun _mpg123_handle _string/utf-8 -> _MPG123_Result)) ; MPG123_EXPORT int mpg123_close (mpg123_handle *mh) (define-libmpg123 mpg123_close (_fun _mpg123_handle -> _MPG123_Result)) ; MPG123_EXPORT int mpg123_getformat (mpg123_handle *mh, long *rate, int *channels, int *encoding) (define-libmpg123 mpg123_getformat (_fun _mpg123_handle (rate : (_ptr o _long)) (channels : (_ptr o _int)) (encoding : (_ptr o _int)) -> (r : _MPG123_Result) -> (values r rate channels encoding))) ; MPG123_EXPORT int mpg123_encsize ( int encoding ) (define-libmpg123 mpg123_encsize (_fun _int -> _int)) ; MPG123_EXPORT int mpg123_read (mpg123_handle *mh, void *outmemory, size_t outmemsize, size_t *done) (define-libmpg123 mpg123_read (_fun _mpg123_handle _pointer _size_t (done : (_ptr o _size_t)) -> (r : _MPG123_Result) -> (values r done))) ; MPG123_EXPORT int64_t mpg123_tell64 ( mpg123_handle * mh ) (define-libmpg123 mpg123_tell64 (_fun _mpg123_handle -> _int64)) ; MPG123_EXPORT int64_t mpg123_seek64(mpg123_handle * mh, int64_t sampleoff, int whence ) (define-libmpg123 mpg123_seek64 (_fun _mpg123_handle _int64 _Seek_t -> _int64)) ; MPG123_EXPORT int mpg123_scan ( mpg123_handle * mh ) (define-libmpg123 mpg123_scan (_fun _mpg123_handle -> _MPG123_Result)) ; MPG123_EXPORT off_t mpg123_length ( mpg123_handle * mh ) (define-libmpg123 mpg123_length64 (_fun _mpg123_handle -> _int64)) ; MPG123_EXPORT void mpg123_delete (mpg123_handle *mh) (define-libmpg123 mpg123_delete (_fun _mpg123_handle -> _void)) ; MPG123_EXPORT void mpg123_exit (void) ; Not relevant anymore (define-libmpg123 mpg123_exit (_fun -> _void)) ; MPG123_EXPORT const char* mpg123_plain_strerror ( int errcode ) (define-libmpg123 mpg123_plain_strerror (_fun _MPG123_Result -> _string*/utf-8)) (define mpg123_int_strerror (get-ffi-obj "mpg123_plain_strerror" lib (_fun _int -> _string*/utf-8))) #| #include #include #define BITS 8 int main(int argc, char *argv[]) { mpg123_handle *mh; unsigned char *buffer; size_t buffer_size; size_t done; int err; int driver; ao_device *dev; ao_sample_format format; int channels, encoding; long rate; if(argc < 2) exit(0); /* initializations */ ao_initialize(); driver = ao_default_driver_id(); mpg123_init(); mh = mpg123_new(NULL, &err); buffer_size = mpg123_outblock(mh); buffer = (unsigned char*) malloc(buffer_size * sizeof(unsigned char)); /* open the file and get the decoding format */ mpg123_open(mh, argv[1]); mpg123_getformat(mh, &rate, &channels, &encoding); /* set the output format and open the output device */ format.bits = mpg123_encsize(encoding) * BITS; format.rate = rate; format.channels = channels; format.byte_format = AO_FMT_NATIVE; format.matrix = 0; dev = ao_open_live(driver, &format, NULL); /* decode and play */ while (mpg123_read(mh, buffer, buffer_size, &done) == MPG123_OK) ao_play(dev, buffer, done); /* clean up */ free(buffer); ao_close(dev); mpg123_close(mh); mpg123_delete(mh); mpg123_exit(); ao_shutdown(); return 0; } |# ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Our interface for decoding to racket ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define BITS 8) (define (mpg123-ffi-decoder-handler) (define mh #f) (define buf-size -1) (define buffer #f) (define rate -1) (define channels -1) (define sample-bits -1) (define sample-bytes -1) (define pcm-length -1) (define encoding -1) (define mp3-file "") (define (new) (if (eq? mh #f) (let-values ([(h err) (mpg123_new #f)]) (when (eq? h #f) (error (format "mpg123_new: ~a" (mpg123_int_strerror err)))) (set! mh h) (set! buf-size (mpg123_outblock mh)) (set! buffer (malloc buf-size 'atomic-interior )) ) (error "mpg123 handle already initialized, delete it first")) #t) (define (delete) (if (eq? mh #f) (error "mpg123 has already been deleted") (begin (mpg123_delete mh) (set! mh #f) (set! buf-size -1) (set! buffer #f) )) #t) (define (info) (info-sound "file : ~a" mp3-file) (info-sound "buf-size : ~a" buf-size) (info-sound "channels : ~a" channels) (info-sound "sample-bits: ~a" sample-bits) (info-sound "rate : ~a" rate) (info-sound "encoding : ~a" encoding) (info-sound "pcm-length : ~a" pcm-length) (info-sound "duration : ~a" (if (= rate -1) 0 (exact->inexact (/ pcm-length rate)))) #t ) (define (init file) (let ((r (mpg123_open mh file))) (unless (eq? r 'MPG123_OK) (error (format "mpg123_open: ~a" (mpg123_plain_strerror r)))) ) (let-values ([(fr rate* channels* encoding*) (mpg123_getformat mh)]) (unless (eq? fr 'MPG123_OK) (error (format "mpg123_format: ~a" (mpg123_plain_strerror fr)))) (set! rate rate*) (set! channels channels*) (set! encoding encoding*) (dbg-sound "mpg123_format: ~a ~a ~a" rate channels encoding) (set! sample-bits (* (mpg123_encsize encoding) BITS)) (set! sample-bytes (/ sample-bits 8))) (let ((sr (mpg123_scan mh))) (unless (eq? sr 'MPG123_OK) (error (format "mpg123_scan: ~a" (mpg123_plain_strerror sr)))) (set! pcm-length (mpg123_length64 mh))) (set! mp3-file (format "~a" file)) #t) (define (mp3-format cb) (cb rate channels sample-bits sample-bytes pcm-length)) (define (close) (let ((r (mpg123_close mh))) (unless (eq? r 'MPG123_OK) (error (format "mpg123_close: ~a" (mpg123_plain_strerror r)))) (set! channels -1) (set! pcm-length -1) (set! rate -1) (set! sample-bits -1) (set! sample-bytes -1) (set! encoding -1) (set! mp3-file "") #t)) (define (read cb) (let-values ([(r done) (mpg123_read mh buffer buf-size)]) (if (eq? r 'MPG123_DONE) (cb 'done -1 buffer done) (if (eq? r 'MPG123_OK) (let ((pcm-pos (mpg123_tell64 mh))) (cb 'data pcm-pos buffer done)) (error (format "mpg123_read: ~a" (mpg123_plain_strerror r))) ) ) ) #t) (define (seek pcm-pos) (let ((r (mpg123_seek64 mh pcm-pos 'seek-set))) (unless (>= r 0) (error (format "mpg123_seek64: ~a" (mpg123_int_strerror r)))) #t)) (define (tell) (mpg123_tell64 mh)) (λ (cmd . args) (cond [(eq? cmd 'new) (new)] [(eq? cmd 'delete) (delete)] [(eq? cmd 'init) (init (car args))] [(eq? cmd 'close) (close)] [(eq? cmd 'format) (mp3-format (car args))] [(eq? cmd 'info) (info)] [(eq? cmd 'read) (read (car args))] [(eq? cmd 'seek) (seek (car args))] [(eq? cmd 'tell) (tell)] [(eq? cmd 'file) mp3-file] [else (error (format "Unknown command: ~a" cmd))] ) ) ) ); end of module