mp3 support, based on mpg123
This commit is contained in:
+139
-95
@@ -43,7 +43,7 @@
|
||||
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_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. */
|
||||
@@ -91,6 +91,7 @@
|
||||
MPG123_INT_OVERFLOW ;/**< Some integer overflow. */
|
||||
MPG123_BAD_FLOAT ;/**< Floating-point computations work not as expected. */
|
||||
)
|
||||
_int
|
||||
)
|
||||
)
|
||||
|
||||
@@ -98,6 +99,7 @@
|
||||
|
||||
|
||||
; MPG123_EXPORT int mpg123_init (void)
|
||||
; Not relevant anymore
|
||||
(define-libmpg123 mpg123_init
|
||||
(_fun -> _MPG123_Result))
|
||||
|
||||
@@ -157,7 +159,26 @@
|
||||
(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 <ao/ao.h>
|
||||
#include <mpg123.h>
|
||||
@@ -222,112 +243,135 @@ int main(int argc, char *argv[])
|
||||
;; 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 BITS 8)
|
||||
|
||||
(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 (mpg123-ffi-decoder-handler)
|
||||
|
||||
(define (error-callback fl errno client-data)
|
||||
(set! error-no errno)
|
||||
)
|
||||
(define mh #f)
|
||||
|
||||
(define (new)
|
||||
(set! fl (FLAC__stream_decoder_new))
|
||||
fl)
|
||||
(define buf-size -1)
|
||||
(define buffer #f)
|
||||
|
||||
(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 rate -1)
|
||||
(define channels -1)
|
||||
(define sample-bits -1)
|
||||
(define sample-bytes -1)
|
||||
(define pcm-length -1)
|
||||
(define encoding -1)
|
||||
(define mp3-file "")
|
||||
|
||||
(define (process-single)
|
||||
(FLAC__stream_decoder_process_single fl))
|
||||
(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 (int-state)
|
||||
(FLAC__stream_decoder_get_state fl))
|
||||
|
||||
(define (state)
|
||||
(decoder-state (int-state)))
|
||||
(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 (process-meta-data cb)
|
||||
(for-each (λ (meta-entry)
|
||||
(cb meta-entry)
|
||||
(FLAC__metadata_object_delete meta-entry))
|
||||
meta-data)
|
||||
(set! meta-data '()))
|
||||
(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 (process-write-data cb)
|
||||
(for-each (lambda (d)
|
||||
(cb (car d) (cdr d)))
|
||||
write-data)
|
||||
(set! write-data '()))
|
||||
(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 (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 (mp3-format cb)
|
||||
(cb rate channels sample-bits sample-bytes pcm-length))
|
||||
|
||||
(define (seek-to-sample sample)
|
||||
(FLAC__stream_decoder_seek_absolute fl sample))
|
||||
(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))
|
||||
|
||||
(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]
|
||||
(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)
|
||||
|
||||
[(eq? cmd 'seek-to-sample) (seek-to-sample (car args))]
|
||||
[(eq? cmd 'file) flac-file]
|
||||
|
||||
[else (error (format "unknown command ~a" cmd))]
|
||||
))
|
||||
|#
|
||||
(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
|
||||
Reference in New Issue
Block a user