mp3 support, based on mpg123

This commit is contained in:
2026-04-22 13:28:37 +02:00
parent bba44733ab
commit 4c22dd54cc
7 changed files with 575 additions and 116 deletions
+139 -95
View File
@@ -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