(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