(module mp3-decoder racket/base (require ffi/unsafe "libmpg123-ffi.rkt" "private/utils.rkt") (provide mp3-open mp3-valid? mp3-read mp3-stop mp3-seek ) (define-struct mp3-handle (if cb-info cb-audio (stop #:mutable) (seek #:mutable) (reading #:mutable) (format #:mutable) ) #:transparent ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Functions to do the good stuff ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (mp3-valid? mp3-file) #t) (define audio-type 'mp3) (define (report-format handle current-pcm-pos) ((mp3-handle-cb-info handle) (mp3-handle-format handle))) (define (give-audio handle info pos buffer size) (let ((h (mp3-handle-format handle))) (hash-set! h 'sample pos) (hash-set! h 'current-time (exact->inexact (/ pos (hash-ref h 'sample-rate)))) ((mp3-handle-cb-audio handle) h buffer size))) (define (mp3-open mp3-file* cb-stream-info cb-audio) (let ((mp3-file (if (path? mp3-file*) (path->string mp3-file*) mp3-file*))) (if (file-exists? mp3-file) (let ((handler (mpg123-ffi-decoder-handler))) (handler 'new) (handler 'init mp3-file) (let ((h (make-mp3-handle handler cb-stream-info cb-audio #f #f #f #f ))) (handler 'format (λ (rate channels sample-bits sample-bytes pcm-length) (let ((f (make-hash))) (hash-set! f 'duration (exact->inexact (/ pcm-length rate))) (hash-set! f 'sample-rate rate) (hash-set! f 'channels channels) (hash-set! f 'bits-per-sample sample-bits) (hash-set! f 'bytes-per-sample sample-bytes) (hash-set! f 'total-samples pcm-length) (set-mp3-handle-format! h f) ) ) ) (report-format h 0) h)) #f))) (define (mp3-read handle) (let* ((ffi-handler (mp3-handle-if handle)) (cb-info (mp3-handle-cb-info handle)) (cb-audio (mp3-handle-cb-audio handle)) ) (set-mp3-handle-reading! handle #t) (let loop () (if (eq? (mp3-handle-stop handle) #t) (begin (newline) (dbg-sound "Stopping mp3 decoding") (set-mp3-handle-reading! handle #f) 'stopped-reading ) (begin (unless (eq? (mp3-handle-seek handle) #f) (dbg-sound "Seeking to ~a" (mp3-handle-seek handle)) (ffi-handler 'seek (mp3-handle-seek handle)) (set-mp3-handle-seek! handle #f)) (ffi-handler 'read (λ (info pos buffer size) (if (eq? info 'done) (set-mp3-handle-stop! handle #t) (give-audio handle info pos buffer size) )) ) (loop) ) )) (ffi-handler 'close) (ffi-handler 'delete) ) ) (define (mp3-seek handle percentage) (let ((fmt (mp3-handle-format handle))) (let ((total-samples (hash-ref fmt 'total-samples))) (unless (or (eq? total-samples #f) (= total-samples -1)) (let ((sample (inexact->exact (round (* (exact->inexact (/ percentage 100.0)) total-samples))))) (set-mp3-handle-seek! handle sample)) ) ) ) ) (define (mp3-stop handle) (set-mp3-handle-stop! handle #t) (while (mp3-handle-reading handle) (sleep 0.01)) ) ); end of module