Files
gemigreerd-racket-audio/flac-encoder.rkt
T
2026-06-08 12:14:32 +02:00

91 lines
3.8 KiB
Racket

(module flac-encoder racket/base
(require "libflac-ffi.rkt"
"flac-definitions.rkt")
(provide flac-encoder-available?
flac-encoder-default-settings
flac-encoder-prepare-settings
flac-encoder-open
flac-encoder-write
flac-encoder-finish)
(define (flac-encoder-available?) #t)
(define (copy-hash h)
(let ((out (make-hash)))
(for-each (lambda (k) (hash-set! out k (hash-ref h k))) (hash-keys h))
out))
(define (hash-ref/default h k default)
(if (hash-has-key? h k) (hash-ref h k) default))
(define (hash-merge base override)
(let ((out (copy-hash base)))
(when (hash? override)
(for-each (lambda (k) (hash-set! out k (hash-ref override k))) (hash-keys override)))
out))
(define (flac-encoder-default-settings)
(make-hash '((compression-level . 5)
(verify? . #f)
(blocksize . 0))))
(define (source-value v source)
(if (eq? v 'source) source v))
(define (safe-flac-bits bits)
(cond [(and (integer? bits) (or (= bits 8) (= bits 12) (= bits 16) (= bits 20) (= bits 24))) bits]
[(and (integer? bits) (< bits 16)) 16]
[else 24]))
(define (flac-encoder-prepare-settings settings format)
(let* ((base (flac-encoder-default-settings))
(h (hash-merge base settings))
;; In encoder settings, 'sample-rate means the requested output rate.
;; 'target-sample-rate is accepted as an explicit alias for readability.
(source-rate (hash-ref format 'sample-rate))
(source-channels (hash-ref format 'channels))
(source-bits (hash-ref/default format 'bits-per-sample 24))
(rate (source-value (hash-ref/default h 'target-sample-rate
(hash-ref/default h 'sample-rate source-rate))
source-rate))
(channels (source-value (hash-ref/default h 'target-channels
(hash-ref/default h 'channels source-channels))
source-channels))
(bits0 (source-value (hash-ref/default h 'target-bits-per-sample
(hash-ref/default h 'bits-per-sample source-bits))
source-bits))
(bits (safe-flac-bits bits0))
(total (hash-ref/default h 'total-samples (hash-ref/default format 'total-samples #f))))
(hash-set! h 'sample-rate rate)
(hash-set! h 'channels channels)
(hash-set! h 'bits-per-sample bits)
(when (hash-has-key? h 'target-sample-rate) (hash-remove! h 'target-sample-rate))
(when (hash-has-key? h 'target-channels) (hash-remove! h 'target-channels))
(when (hash-has-key? h 'target-bits-per-sample) (hash-remove! h 'target-bits-per-sample))
(when (and total (integer? total) (>= total 0)) (hash-set! h 'total-samples total))
(unless (hash-has-key? h 'streamable-subset?) (hash-set! h 'streamable-subset? (<= bits 24)))
h))
(define (flac-encoder-open output-file settings format)
(let* ((file (if (path? output-file) (path->string output-file) output-file))
(resolved (flac-encoder-prepare-settings settings format))
(handler (flac-ffi-encoder-handler)))
(handler 'new)
(handler 'configure resolved)
(handler 'init file)
(make-flac-encoder-handle handler resolved format file)))
(define (flac-encoder-write handle buf-info buffer buf-len)
((flac-encoder-handle-ffi-encoder-handler handle) 'write buffer buf-len buf-info))
(define (flac-encoder-finish handle)
(let ((handler (flac-encoder-handle-ffi-encoder-handler handle)))
(dynamic-wind
void
(lambda () (handler 'finish))
(lambda () (handler 'delete)))))
) ; end of module