trying to overcome gapless problems with mpg123 (very small tick left) and facilitate output to wav

This commit is contained in:
2026-04-23 11:03:47 +02:00
parent 4bbfa43501
commit 3fd5fdbdd5
5 changed files with 120 additions and 77 deletions
+1 -1
View File
@@ -64,7 +64,7 @@
(define-libao-async ao_async_version (_fun -> _int)) (define-libao-async ao_async_version (_fun -> _int))
;extern void *ao_create_async(int bits, int rate, int channel, int byte_format); ;extern void *ao_create_async(int bits, int rate, int channel, int byte_format);
(define-libao-async ao_create_async(_fun _int _int _int _Endian_t -> _libao-async-handle-pointer)) (define-libao-async ao_create_async(_fun _int _int _int _Endian_t _string/utf-8 -> _libao-async-handle-pointer))
;extern void ao_stop_async(void *handle); ;extern void ao_stop_async(void *handle);
(define-libao-async ao_stop_async(_fun _libao-async-handle-pointer -> _void)) (define-libao-async ao_stop_async(_fun _libao-async-handle-pointer -> _void))
+36 -24
View File
@@ -10,6 +10,7 @@
) )
(provide ao-open-live (provide ao-open-live
ao-open-file
ao-play ao-play
ao-close ao-close
ao-at-second ao-at-second
@@ -81,36 +82,47 @@
(rc:define/contract (ao-open-live bits rate channels byte-format) (rc:define/contract (ao-open-live bits rate channels byte-format)
(rc:-> ao-valid-bits? ao-valid-rate? ao-valid-channels? ao-valid-format? ao-handle?) (rc:-> ao-valid-bits? ao-valid-rate? ao-valid-channels? ao-valid-format? ao-handle?)
(let ((handle (make-ao-handle device-number))) (ao-open-file bits rate channels byte-format #f))
(fin:register-finalizer handle (define (valid-file-kind? f)
(lambda (handle) (or (string? f) (path? f) (eq? f #f)))
(ao-close handle)))
(set-ao-handle-bits! handle bits) (rc:define/contract (ao-open-file bits rate channels byte-format filename)
(set-ao-handle-bytes-per-sample! handle (bytes-for-bits bits)) (rc:-> ao-valid-bits? ao-valid-rate? ao-valid-channels? ao-valid-format? valid-file-kind? ao-handle?)
(set-ao-handle-byte-format! handle byte-format) (let* ((handle (make-ao-handle device-number))
(set-ao-handle-channels! handle channels) (file (if (eq? filename #f)
(set-ao-handle-rate! handle rate) #f
(format "~a" filename)))
)
(fin:register-finalizer handle
(lambda (handle)
(ao-close handle)))
(info-sound "ao-open-live ~a ~a ~a ~a" bits rate channels byte-format) (set-ao-handle-bits! handle bits)
(set-ao-handle-bytes-per-sample! handle (bytes-for-bits bits))
(set-ao-handle-byte-format! handle byte-format)
(set-ao-handle-channels! handle channels)
(set-ao-handle-rate! handle rate)
(let ((player (ffi:ao_create_async bits rate channels byte-format))) (info-sound "ao-open-live ~a ~a ~a ~a ~a" bits rate channels byte-format file)
(set-ao-handle-async-player! handle player)
(if (eq? player #f) (let ((player (ffi:ao_create_async bits rate channels byte-format file)))
(begin (set-ao-handle-async-player! handle player)
(err-sound "ao-open-live - cannote create player") (if (eq? player #f)
(set-ao-handle-closed! handle #t) (begin
handle) (err-sound "ao-open-live - cannote create player")
(begin (set-ao-handle-closed! handle #t)
(info-sound "ao-open-live - created player") handle)
(set-ao-handle-closed! handle #f) (begin
handle (info-sound "ao-open-live - created player")
(set-ao-handle-closed! handle #f)
handle
)
)
) )
)
) )
) )
)
(rc:define/contract (ao-close handle) (rc:define/contract (ao-close handle)
(rc:-> ao-handle? void?) (rc:-> ao-handle? void?)
+24 -16
View File
@@ -329,6 +329,7 @@ int main(int argc, char *argv[])
(define pcm-length -1) (define pcm-length -1)
(define encoding -1) (define encoding -1)
(define mp3-file "") (define mp3-file "")
(define current-pcm-pos 0)
(define (new) (define (new)
(if (eq? mh #f) (if (eq? mh #f)
@@ -386,11 +387,8 @@ int main(int argc, char *argv[])
(define (set-param p val) (define (set-param p val)
(mpg123_param2 mh p val (exact->inexact val))) (mpg123_param2 mh p val (exact->inexact val)))
(define (init file) (define (do-format)
(let ((r (mpg123_open mh file))) (dbg-sound "do-format called, got an MPG123_NEW_FORMAT message")
(unless (eq? r 'MPG123_OK)
(error (format "mpg123_open: ~a" (mpg123_plain_strerror r))))
)
(let-values ([(fr rate* channels* encoding*) (mpg123_getformat mh)]) (let-values ([(fr rate* channels* encoding*) (mpg123_getformat mh)])
(unless (eq? fr 'MPG123_OK) (unless (eq? fr 'MPG123_OK)
(error (format "mpg123_format: ~a" (mpg123_plain_strerror fr)))) (error (format "mpg123_format: ~a" (mpg123_plain_strerror fr))))
@@ -404,11 +402,19 @@ int main(int argc, char *argv[])
(unless (eq? sr 'MPG123_OK) (unless (eq? sr 'MPG123_OK)
(error (format "mpg123_scan: ~a" (mpg123_plain_strerror sr)))) (error (format "mpg123_scan: ~a" (mpg123_plain_strerror sr))))
(set! pcm-length (mpg123_length64 mh))) (set! pcm-length (mpg123_length64 mh)))
)
(define (init file)
(let ((r (mpg123_open mh file)))
(unless (eq? r 'MPG123_OK)
(error (format "mpg123_open: ~a" (mpg123_plain_strerror r))))
)
(set! mp3-file (format "~a" file)) (set! mp3-file (format "~a" file))
(set! current-pcm-pos 0)
#t) #t)
(define (mp3-format cb) (define (mp3-format cb)
(cb rate channels sample-bits sample-bytes pcm-length)) (cb current-pcm-pos rate channels sample-bits sample-bytes pcm-length))
(define (close) (define (close)
(let ((r (mpg123_close mh))) (let ((r (mpg123_close mh)))
@@ -423,16 +429,18 @@ int main(int argc, char *argv[])
(set! mp3-file "") (set! mp3-file "")
#t)) #t))
(define (read cb) (define (read cb format-cb)
(let-values ([(r done) (mpg123_read mh buffer buf-size)]) (let-values ([(r done) (mpg123_read mh buffer buf-size)])
(if (eq? r 'MPG123_DONE) (cond
(cb 'done -1 buffer done) ((eq? r 'MPG123_DONE) (cb 'done -1 buffer done))
(if (eq? r 'MPG123_OK) ((eq? r 'MPG123_NEW_FORMAT) (do-format)
(let ((pcm-pos (mpg123_tell64 mh))) (mp3-format format-cb)
(cb 'data pcm-pos buffer done)) (read cb format-cb))
(error (format "mpg123_read: ~a" (mpg123_plain_strerror r))) ((eq? r 'MPG123_OK) (let ((pcm-pos (mpg123_tell64 mh)))
) (set! current-pcm-pos pcm-pos)
) (cb 'data pcm-pos buffer done)))
(else (error (format "mpg123_read: ~a" (mpg123_plain_strerror r))))
)
) )
#t) #t)
@@ -453,7 +461,7 @@ int main(int argc, char *argv[])
[(eq? cmd 'close) (close)] [(eq? cmd 'close) (close)]
[(eq? cmd 'format) (mp3-format (car args))] [(eq? cmd 'format) (mp3-format (car args))]
[(eq? cmd 'info) (info)] [(eq? cmd 'info) (info)]
[(eq? cmd 'read) (read (car args))] [(eq? cmd 'read) (read (car args) (cadr args))]
[(eq? cmd 'seek) (seek (car args))] [(eq? cmd 'seek) (seek (car args))]
[(eq? cmd 'tell) (tell)] [(eq? cmd 'tell) (tell)]
[(eq? cmd 'file) mp3-file] [(eq? cmd 'file) mp3-file]
+48 -32
View File
@@ -28,37 +28,52 @@
;; Functions to do the good stuff ;; Functions to do the good stuff
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define mp3-handles '())
(register-finalizer mp3-handles
(λ (handles)
(for-each (λ (handle)
(handle 'delete)) handles)))
(define (mp3-valid? mp3-file) (define (mp3-valid? mp3-file)
#t) #t)
(define audio-type 'mp3) (define audio-type 'mp3)
(define last-rate 44200) ; An assumption for if we've got nothing
(define last-channels 2) ; An assumption for if we've got nothing
(define last-bits 16) ; An assumption for if we've got nothing
(define (correct-format-hash h)
(let ((rate (hash-ref h 'sample-rate #f)))
(when (eq? rate #f)
(hash-set! h 'sample-rate last-rate)))
(let ((channels (hash-ref h 'channels #f)))
(when (eq? channels #f)
(hash-set! h 'channels last-channels)))
(let ((bits (hash-ref h 'bits-per-sample #f)))
(when (eq? bits #f)
(hash-set! h 'bits-per-sample last-bits)))
(let ((total-samples (hash-ref h 'total-samples #f)))
(when (eq? total-samples #f)
(hash-set! h 'total-samples 0)
(hash-set! h 'duration 0)))
)
(define (report-format handle current-pcm-pos) (define (report-format handle current-pcm-pos)
(dbg-sound "Reporting format at pcm-pos: ~a" current-pcm-pos)
(let ((h (mp3-handle-format handle)))
(set! last-rate (hash-ref h 'sample-rate))
(set! last-channels (hash-ref h 'channels))
(set! last-bits (hash-ref h 'bits-per-sample)))
((mp3-handle-cb-info handle) (mp3-handle-format handle))) ((mp3-handle-cb-info handle) (mp3-handle-format handle)))
(define (give-audio handle info pos buffer size) (define (give-audio handle info pos buffer size)
(let ((h (mp3-handle-format handle))) (let ((h (mp3-handle-format handle)))
(correct-format-hash h)
(hash-set! h 'sample pos) (hash-set! h 'sample pos)
(hash-set! h 'current-time (exact->inexact (/ pos (hash-ref h 'sample-rate)))) (let ((sample-rate (hash-ref h 'sample-rate last-rate)))
(hash-set! h 'current-time (exact->inexact (/ pos sample-rate))))
((mp3-handle-cb-audio handle) h buffer size))) ((mp3-handle-cb-audio handle) h buffer size)))
(define (mp3-open mp3-file* cb-stream-info cb-audio) (define (mp3-open mp3-file* cb-stream-info cb-audio)
(let ((mp3-file (if (path? mp3-file*) (path->string mp3-file*) mp3-file*))) (let ((mp3-file (if (path? mp3-file*) (path->string mp3-file*) mp3-file*)))
(if (file-exists? mp3-file) (if (file-exists? mp3-file)
(let ((handler (if (null? mp3-handles) (let ((handler (mpg123-ffi-decoder-handler)))
(let ((h (mpg123-ffi-decoder-handler))) (handler 'new)
(h 'new)
h)
(let ((h (car mp3-handles)))
(set! mp3-handles (cdr mp3-handles))
h))))
(handler 'init mp3-file) (handler 'init mp3-file)
(let ((h (make-mp3-handle handler (let ((h (make-mp3-handle handler
cb-stream-info cb-stream-info
@@ -66,26 +81,25 @@
#f #f
#f #f
#f #f
#f (make-hash)
))) )))
(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)) h))
#f))) #f)))
(define (handle-format handle pcm-pos 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! handle f)
)
(report-format handle pcm-pos)
)
(define (mp3-read handle) (define (mp3-read handle)
(let* ((ffi-handler (mp3-handle-if handle)) (let* ((ffi-handler (mp3-handle-if handle))
(cb-info (mp3-handle-cb-info handle)) (cb-info (mp3-handle-cb-info handle))
@@ -110,18 +124,20 @@
(set-mp3-handle-stop! handle #t) (set-mp3-handle-stop! handle #t)
(give-audio handle info pos buffer size) (give-audio handle info pos buffer size)
)) ))
(λ (pcm-pos rate channels sample-bits sample-bytes pcm-length)
(handle-format handle pcm-pos rate channels sample-bits sample-bytes pcm-length))
) )
(loop) (loop)
) )
)) ))
(ffi-handler 'close) (ffi-handler 'close)
(set! mp3-handles (cons ffi-handler mp3-handles)) (ffi-handler 'delete)
) )
) )
(define (mp3-seek handle percentage) (define (mp3-seek handle percentage)
(let ((fmt (mp3-handle-format handle))) (let ((fmt (mp3-handle-format handle)))
(let ((total-samples (hash-ref fmt 'total-samples))) (let ((total-samples (hash-ref fmt 'total-samples 0)))
(unless (or (unless (or
(eq? total-samples #f) (eq? total-samples #f)
(= total-samples -1)) (= total-samples -1))
+11 -4
View File
@@ -19,8 +19,10 @@
(set! test-file4 "/tmp/test1.mp3") (set! test-file4 "/tmp/test1.mp3")
) )
(when (eq? os 'windows) (when (eq? os 'windows)
(set! test-file3 "C:\\Muziek\\Klassiek-Strijkkwartet\\Quatuor Zaïde\\Franz\\01 Erlkönig, D. 328 (Arr. For String Quartet by Eric Mouret).flac") ;(set! test-file3 "C:\\Muziek\\Klassiek-Strijkkwartet\\Quatuor Zaïde\\Franz\\01 Erlkönig, D. 328 (Arr. For String Quartet by Eric Mouret).flac")
;(set! test-file3 "C:\\Muziek\\Klassiek-Viool\\Janine Jansen\\Janine Jansen - Sibelius en Prokovief 1 (2024)\\02 - Violin Concerto in D Minor, Op. 47 II. Adagio di molto.flac") ;(set! test-file3 "C:\\Muziek\\Klassiek-Viool\\Janine Jansen\\Janine Jansen - Sibelius en Prokovief 1 (2024)\\02 - Violin Concerto in D Minor, Op. 47 II. Adagio di molto.flac")
(set! test-file3 "c:\\tmp\\test.mp3")
(set! test-file4 "c:\\tmp\\test1.mp3")
) )
) )
@@ -33,6 +35,7 @@
(define current-audio-h #f) (define current-audio-h #f)
(sl-log-to-display) (sl-log-to-display)
(define wav-output-file #f)
(define (audio-play type ao-type handle buf-info buffer buf-len) (define (audio-play type ao-type handle buf-info buffer buf-len)
(let* ((sample (hash-ref buf-info 'sample)) (let* ((sample (hash-ref buf-info 'sample))
@@ -46,7 +49,7 @@
) )
;(displayln buf-info) ;(displayln buf-info)
(when (eq? ao-h #f) (when (eq? ao-h #f)
(set! ao-h (ao-open-live bits-per-sample rate channels 'native-endian))) (set! ao-h (ao-open-file bits-per-sample rate channels 'native-endian wav-output-file)))
;(displayln 'ao-play) ;(displayln 'ao-play)
(ao-play ao-h current-file-id second duration buffer buf-len ao-type) (ao-play ao-h current-file-id second duration buffer buf-len ao-type)
(set! duration (inexact->exact (round duration))) (set! duration (inexact->exact (round duration)))
@@ -71,13 +74,16 @@
(let* ((buf-size (ao-bufsize-async ao-h)) (let* ((buf-size (ao-bufsize-async ao-h))
(buf-seconds (exact->inexact (/ buf-size bytes-per-sample-all-channels rate)))) (buf-seconds (exact->inexact (/ buf-size bytes-per-sample-all-channels rate))))
(second-printer buf-seconds) (second-printer buf-seconds)
(when (> buf-seconds 10) (when (= (round current-seconds) 10)
(when (= current-file-id 3)
(audio-seek current-audio-h 97.0)))
(when (> buf-seconds 5)
(letrec ((waiter (λ () (letrec ((waiter (λ ()
(let ((buf-seconds-left (exact->inexact (let ((buf-seconds-left (exact->inexact
(/ (ao-bufsize-async ao-h) (/ (ao-bufsize-async ao-h)
bytes-per-sample-all-channels bytes-per-sample-all-channels
rate)))) rate))))
(if (< buf-seconds-left 2.0) (if (< buf-seconds-left 3.0)
(info-sound "Seconds in buffer left: ~a" buf-seconds-left) (info-sound "Seconds in buffer left: ~a" buf-seconds-left)
(begin (begin
(sleep 0.5) (sleep 0.5)
@@ -114,6 +120,7 @@
(set! current-audio-h audio-h) (set! current-audio-h audio-h)
(audio-read audio-h) (audio-read audio-h)
) )
(info-sound "Opening next file: ~a" test-file4)
(let ((audio-h (audio-open test-file4 audio-meta audio-play))) (let ((audio-h (audio-open test-file4 audio-meta audio-play)))
(set! current-file-id test-file4-id) (set! current-file-id test-file4-id)
(set! current-audio-h audio-h) (set! current-audio-h audio-h)