83 lines
3.5 KiB
Racket
83 lines
3.5 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 (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.
|
|
(rate (hash-ref/default h 'target-sample-rate
|
|
(hash-ref/default h 'sample-rate (hash-ref format 'sample-rate))))
|
|
(channels (hash-ref/default h 'target-channels
|
|
(hash-ref/default h 'channels (hash-ref format 'channels))))
|
|
(bits0 (hash-ref/default h 'target-bits-per-sample
|
|
(hash-ref/default h 'bits-per-sample
|
|
(hash-ref/default format 'bits-per-sample 24))))
|
|
(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
|