diff --git a/mpg123-decoder.rkt b/mpg123-decoder.rkt new file mode 100644 index 0000000..869eded --- /dev/null +++ b/mpg123-decoder.rkt @@ -0,0 +1,189 @@ +(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 + + flac-valid? + flac-read + flac-read-meta + flac-stream-state + flac-stop + flac-seek + (all-from-out "flac-definitions.rkt") + kinds + last-buffer last-buf-len + ) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Functions to do the good stuff +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + (define (mp3-valid? mp3-file) + #t) + + (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 (mp3-ffi- + + (define (flac-valid? flac-file*) + #t) + + (define (flac-open flac-file* cb-stream-info cb-audio) + (let ((flac-file (if (path? flac-file*) (path->string flac-file*) flac-file*))) + (if (file-exists? flac-file) + (let ((handler (flac-ffi-decoder-handler))) + (handler 'new) + (handler 'init flac-file) + (let ((h (make-flac-handle handler))) + (set-flac-handle-cb-stream-info! h cb-stream-info) + (set-flac-handle-cb-audio! h cb-audio) + h)) + #f))) + + (define (flac-stream-state handle) + ((flac-handle-ffi-decoder-handler handle) 'state)) + + + (define kinds (make-hash)) + (define last-buffer #f) + (define last-buf-len #f) + + (define (process-frame handle frame buffer) + (let* ((h (flac-ffi-frame-header frame)) + (cb-audio (flac-handle-cb-audio handle)) + (ffi (flac-handle-ffi-decoder-handler handle)) + (type (hash-ref h 'number-type)) + (channels (hash-ref h 'channels)) + (block-size (hash-ref h 'blocksize))) + (hash-set! h 'duration (flac-duration handle)) + (let ((sample (hash-ref h 'number))) + (hash-set! h 'sample sample)) + (set! last-buffer buffer) + (set! last-buf-len block-size) + (hash-set! kinds type #t) + (when (procedure? cb-audio) + (cb-audio h buffer block-size)) + ) + #t + ) + + (define (process-meta handle meta) + (let ((type (FLAC__StreamMetadata-type meta))) + (dbg-sound (format " Got metadata type: ~a\n" type)) + (cond + ([eq? type 'streaminfo] + (let ((mh (flac-ffi-meta meta))) + (let ((si (make-flac-stream-info + (hash-ref mh 'min-blocksize) (hash-ref mh 'max-blocksize) + (hash-ref mh 'min-framesize) (hash-ref mh 'max-framesize) + (hash-ref mh 'sample-rate) + (hash-ref mh 'channels) + (hash-ref mh 'bits-per-sample) + (hash-ref mh 'total-samples)))) + (let ((duration (exact->inexact + (/ (hash-ref mh 'total-samples) + (hash-ref mh 'sample-rate))))) + (hash-set! mh 'duration duration)) + (set-flac-handle-stream-info! handle si) + (let ((cb (flac-handle-cb-stream-info handle))) + (when (procedure? cb) + (cb mh)))))) + ) + ) + ) + + (define (flac-read handle) + (let* ((ffi-handler (flac-handle-ffi-decoder-handler handle)) + (state (ffi-handler 'state))) + (set-flac-handle-stop-reading! handle #f) + (set-flac-handle-reading! handle #t) + (letrec ((reader (lambda (frame-nr) + (if (flac-handle-stop-reading handle) + (begin + (dbg-sound "handling stop at: ~a" (current-milliseconds)) + (set-flac-handle-reading! handle #f) + 'stopped-reading) + (let* ((st (ffi-handler 'state))) + (ffi-handler 'process-single) + (unless (eq? state st) + (set! state st) + (dbg-sound "Now in state ~a (frame-nr = ~a) (int-state = ~a)" + st frame-nr (ffi-handler 'int-state)) + ) + (when (ffi-handler 'has-errno?) + (err-sound "Error in stream: ~a" (ffi-handler 'errno)) + ) + (when (ffi-handler 'has-meta-data?) + (ffi-handler 'process-meta-data + (lambda (meta) (process-meta handle meta))) + ) + (when (ffi-handler 'has-write-data?) + (ffi-handler 'process-write-data + (lambda (frame buffer) + (process-frame handle frame buffer))) + ) + (if (eq? st 'end-of-stream) + (begin + (set-flac-handle-reading! handle #f) + st) + (reader (+ frame-nr 1)))))) + )) + (reader 0) + ; done reading, delete flac encoder + (ffi-handler 'delete) + ) + ) + ) + + (define (flac-read-meta handle) + (let* ((ffi-handler (flac-handle-ffi-decoder-handler handle)) + (state (ffi-handler 'state))) + (while (not (or (eq? state 'read-metadata) + (eq? state 'end-of-stream) + (eq? state 'aborted) + (eq? state 'memory-allocation-error) + (eq? state 'uninitialized))) + (ffi-handler 'process-single) + (set! state (ffi-handler 'state)) + state) + (if (eq? state 'read-metadata) + (begin + (ffi-handler 'process-meta-data + (lambda (meta) (process-meta handle meta))) + (flac-handle-stream-info handle)) + #f))) + + (define (flac-seek handle percentage) + (dbg-sound "seek to percentage ~a" percentage) + (let ((ffi-handler (flac-handle-ffi-decoder-handler handle))) + (let ((total-samples (flac-total-samples handle))) + (unless (eq? total-samples #f) + (let ((sample (inexact->exact (round (* (exact->inexact (/ percentage 100.0)) total-samples))))) + (ffi-handler 'seek-to-sample sample)) + ) + ) + ) + ) + + + (define (flac-stop handle) + (let ((ct (current-milliseconds))) + (dbg-sound "requesting stop at: ~a" ct) + (set-flac-handle-stop-reading! handle #t) + (while (flac-handle-reading handle) + (sleep 0.01)) + (let ((ct* (current-milliseconds))) + (dbg-sound "stop came back at: ~a" ct*) + (dbg-sound "flac-stop took: ~a ms" (- ct* ct))) + ) + ) + + ); end of module