mpg123 support
This commit is contained in:
@@ -0,0 +1,333 @@
|
||||
(module libflac-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. */
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(define _mpg123_handle _pointer)
|
||||
|
||||
|
||||
; MPG123_EXPORT int mpg123_init (void)
|
||||
(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))
|
||||
|
||||
|
||||
#|
|
||||
#include <ao/ao.h>
|
||||
#include <mpg123.h>
|
||||
|
||||
#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 (mpg123-ffi-decoder-handler)
|
||||
#t
|
||||
#| (define write-data '())
|
||||
(define meta-data '())
|
||||
(define error-no -1)
|
||||
(define fl #f)
|
||||
(define flac-file #f)
|
||||
(define client-data #f)
|
||||
|
||||
(define (write-callback fl frame buffer client-data)
|
||||
(set! write-data (append write-data (list (cons frame buffer))))
|
||||
0)
|
||||
|
||||
(define (meta-callback fl meta client-data)
|
||||
(let ((meta-clone (FLAC__metadata_object_clone meta)))
|
||||
(unless (eq? meta-clone #f)
|
||||
(set! meta-data (append meta-data (list meta-clone))))))
|
||||
|
||||
(define (error-callback fl errno client-data)
|
||||
(set! error-no errno)
|
||||
)
|
||||
|
||||
(define (new)
|
||||
(set! fl (FLAC__stream_decoder_new))
|
||||
fl)
|
||||
|
||||
(define (init file)
|
||||
(let ((r (FLAC__stream_decoder_init_file
|
||||
fl
|
||||
file
|
||||
write-callback
|
||||
meta-callback
|
||||
error-callback
|
||||
client-data)))
|
||||
(set! flac-file file)
|
||||
r))
|
||||
|
||||
(define (process-single)
|
||||
(FLAC__stream_decoder_process_single fl))
|
||||
|
||||
(define (int-state)
|
||||
(FLAC__stream_decoder_get_state fl))
|
||||
|
||||
(define (state)
|
||||
(decoder-state (int-state)))
|
||||
|
||||
(define (process-meta-data cb)
|
||||
(for-each (λ (meta-entry)
|
||||
(cb meta-entry)
|
||||
(FLAC__metadata_object_delete meta-entry))
|
||||
meta-data)
|
||||
(set! meta-data '()))
|
||||
|
||||
(define (process-write-data cb)
|
||||
(for-each (lambda (d)
|
||||
(cb (car d) (cdr d)))
|
||||
write-data)
|
||||
(set! write-data '()))
|
||||
|
||||
(define (buffer->vectorlist buffer channels size)
|
||||
(letrec ((for-channels
|
||||
(lambda (channel)
|
||||
(if (< channel channels)
|
||||
(letrec ((v (make-vector size 0))
|
||||
(p (ptr-ref buffer FLAC__int32-pointer channel))
|
||||
(to-vec (lambda (i)
|
||||
(when (< i size)
|
||||
(vector-set! v i (ptr-ref p _int32 i))
|
||||
(to-vec (+ i 1)))))
|
||||
)
|
||||
(to-vec 0)
|
||||
(cons v (for-channels (+ channel 1))))
|
||||
'())))
|
||||
)
|
||||
(for-channels 0)))
|
||||
|
||||
(define (seek-to-sample sample)
|
||||
(FLAC__stream_decoder_seek_absolute fl sample))
|
||||
|
||||
(lambda (cmd . args)
|
||||
(cond
|
||||
[(eq? cmd 'write-data) write-data]
|
||||
[(eq? cmd 'meta-data) meta-data]
|
||||
|
||||
[(eq? cmd 'new) (new)]
|
||||
[(eq? cmd 'init) (init (car args))]
|
||||
[(eq? cmd 'process-single) (process-single)]
|
||||
[(eq? cmd 'get-buffers) (buffer->vectorlist (car args) (cadr args) (caddr args))]
|
||||
|
||||
[(eq? cmd 'int-state) (int-state)]
|
||||
[(eq? cmd 'state) (state)]
|
||||
|
||||
[(eq? cmd 'has-write-data?) (not (null? write-data))]
|
||||
[(eq? cmd 'has-meta-data?) (not (null? meta-data))]
|
||||
[(eq? cmd 'has-errno?) (not (= error-no -1))]
|
||||
|
||||
[(eq? cmd 'process-meta-data) (process-meta-data (car args))]
|
||||
[(eq? cmd 'process-write-data) (process-write-data (car args))]
|
||||
[(eq? cmd 'errno) error-no]
|
||||
|
||||
[(eq? cmd 'seek-to-sample) (seek-to-sample (car args))]
|
||||
[(eq? cmd 'file) flac-file]
|
||||
|
||||
[else (error (format "unknown command ~a" cmd))]
|
||||
))
|
||||
|#
|
||||
)
|
||||
|
||||
); end of module
|
||||
Reference in New Issue
Block a user