Audio Encoder laag.
This commit is contained in:
+161
@@ -6,6 +6,7 @@
|
||||
)
|
||||
|
||||
(provide flac-ffi-decoder-handler
|
||||
flac-ffi-encoder-handler
|
||||
_FLAC__StreamMetadata
|
||||
FLAC__StreamMetadata-type
|
||||
flac-ffi-meta
|
||||
@@ -371,6 +372,7 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(define _FLAC__StreamDecoder-pointer (_cpointer 'flac-streamdecoder))
|
||||
(define _FLAC__StreamEncoder-pointer (_cpointer 'flac-streamencoder))
|
||||
(define _FLAC__Data-pointer (_cpointer/null 'flac-client-data))
|
||||
;(define _FLAC__StreamMetadata-pointer (_cpointer/null 'flac-stream-metadata))
|
||||
|
||||
@@ -639,5 +641,164 @@
|
||||
))
|
||||
)
|
||||
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Direct FLAC encoder interface
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(define FLAC__StreamEncoderInitStatus-ok 0)
|
||||
|
||||
(define _FLAC__StreamEncoderProgressCallback _pointer)
|
||||
|
||||
(define-libflac FLAC__stream_encoder_new
|
||||
(_fun -> _FLAC__StreamEncoder-pointer))
|
||||
|
||||
(define-libflac FLAC__stream_encoder_delete
|
||||
(_fun _FLAC__StreamEncoder-pointer -> _void))
|
||||
|
||||
(define-libflac FLAC__stream_encoder_finish
|
||||
(_fun _FLAC__StreamEncoder-pointer -> FLAC__bool))
|
||||
|
||||
(define-libflac FLAC__stream_encoder_get_state
|
||||
(_fun _FLAC__StreamEncoder-pointer -> _int))
|
||||
|
||||
(define-libflac FLAC__stream_encoder_set_verify
|
||||
(_fun _FLAC__StreamEncoder-pointer FLAC__bool -> FLAC__bool))
|
||||
|
||||
(define-libflac FLAC__stream_encoder_set_streamable_subset
|
||||
(_fun _FLAC__StreamEncoder-pointer FLAC__bool -> FLAC__bool))
|
||||
|
||||
(define-libflac FLAC__stream_encoder_set_channels
|
||||
(_fun _FLAC__StreamEncoder-pointer _uint32_t -> FLAC__bool))
|
||||
|
||||
(define-libflac FLAC__stream_encoder_set_bits_per_sample
|
||||
(_fun _FLAC__StreamEncoder-pointer _uint32_t -> FLAC__bool))
|
||||
|
||||
(define-libflac FLAC__stream_encoder_set_sample_rate
|
||||
(_fun _FLAC__StreamEncoder-pointer _uint32_t -> FLAC__bool))
|
||||
|
||||
(define-libflac FLAC__stream_encoder_set_compression_level
|
||||
(_fun _FLAC__StreamEncoder-pointer _uint32_t -> FLAC__bool))
|
||||
|
||||
(define-libflac FLAC__stream_encoder_set_blocksize
|
||||
(_fun _FLAC__StreamEncoder-pointer _uint32_t -> FLAC__bool))
|
||||
|
||||
(define-libflac FLAC__stream_encoder_set_total_samples_estimate
|
||||
(_fun _FLAC__StreamEncoder-pointer FLAC__uint64 -> FLAC__bool))
|
||||
|
||||
(define-libflac FLAC__stream_encoder_init_file
|
||||
(_fun _FLAC__StreamEncoder-pointer
|
||||
_string/utf-8
|
||||
_FLAC__StreamEncoderProgressCallback
|
||||
_FLAC__Data-pointer
|
||||
-> _int))
|
||||
|
||||
(define-libflac FLAC__stream_encoder_process_interleaved
|
||||
(_fun _FLAC__StreamEncoder-pointer _pointer _uint32_t -> FLAC__bool))
|
||||
|
||||
(define (hash-ref/default h k default)
|
||||
(if (hash-has-key? h k) (hash-ref h k) default))
|
||||
|
||||
(define (bool->flac-bool v) (if v 1 0))
|
||||
|
||||
(define (native-signed-ref bs start bytes)
|
||||
(integer-bytes->integer bs #t (system-big-endian?) start (+ start bytes)))
|
||||
|
||||
(define (scale-sample sample in-bits out-bits)
|
||||
(cond [(> in-bits out-bits) (arithmetic-shift sample (- out-bits in-bits))]
|
||||
[(< in-bits out-bits) (arithmetic-shift sample (- out-bits in-bits))]
|
||||
[else sample]))
|
||||
|
||||
(define (pcm-bytes->flac-int32-pointer buffer size channels in-bits out-bits)
|
||||
(let* ((in-bytes (quotient in-bits 8))
|
||||
(sample-count (quotient size in-bytes))
|
||||
(frame-count (quotient sample-count channels))
|
||||
(ptr (malloc _int32 sample-count 'atomic-interior)))
|
||||
(for ([i (in-range sample-count)])
|
||||
(let* ((off (* i in-bytes))
|
||||
(sample (native-signed-ref buffer off in-bytes)))
|
||||
(ptr-set! ptr _int32 i (scale-sample sample in-bits out-bits))))
|
||||
(values ptr frame-count)))
|
||||
|
||||
(define (flac-ffi-encoder-handler)
|
||||
(define enc #f)
|
||||
(define flac-file #f)
|
||||
(define settings #f)
|
||||
|
||||
(define (require-encoder who)
|
||||
(when (eq? enc #f) (error who "FLAC encoder is not initialized")))
|
||||
|
||||
(define (new)
|
||||
(if (eq? enc #f)
|
||||
(begin (set! enc (FLAC__stream_encoder_new)) enc)
|
||||
(error 'flac-ffi-encoder-handler "FLAC encoder already initialized")))
|
||||
|
||||
(define (configure h)
|
||||
(require-encoder 'flac-encoder-configure)
|
||||
(set! settings h)
|
||||
(let ((channels (hash-ref h 'channels))
|
||||
(sample-rate (hash-ref h 'sample-rate))
|
||||
(bits (hash-ref h 'bits-per-sample))
|
||||
(compression-level (hash-ref/default h 'compression-level 5))
|
||||
(verify? (hash-ref/default h 'verify? #f))
|
||||
(streamable-subset? (hash-ref/default h 'streamable-subset? (<= (hash-ref h 'bits-per-sample) 24)))
|
||||
(blocksize (hash-ref/default h 'blocksize 0))
|
||||
(total-samples (hash-ref/default h 'total-samples #f)))
|
||||
(unless (FLAC__stream_encoder_set_channels enc channels) (error 'flac-encoder-configure "could not set channels"))
|
||||
(unless (FLAC__stream_encoder_set_sample_rate enc sample-rate) (error 'flac-encoder-configure "could not set sample rate"))
|
||||
(unless (FLAC__stream_encoder_set_bits_per_sample enc bits) (error 'flac-encoder-configure "could not set bits per sample"))
|
||||
(unless (FLAC__stream_encoder_set_compression_level enc compression-level) (error 'flac-encoder-configure "could not set compression level"))
|
||||
(unless (FLAC__stream_encoder_set_verify enc (bool->flac-bool verify?)) (error 'flac-encoder-configure "could not set verify"))
|
||||
(unless (FLAC__stream_encoder_set_streamable_subset enc (bool->flac-bool streamable-subset?)) (error 'flac-encoder-configure "could not set streamable subset"))
|
||||
(when (and (integer? blocksize) (> blocksize 0))
|
||||
(unless (FLAC__stream_encoder_set_blocksize enc blocksize) (error 'flac-encoder-configure "could not set blocksize")))
|
||||
(when (and (integer? total-samples) (>= total-samples 0))
|
||||
(unless (FLAC__stream_encoder_set_total_samples_estimate enc total-samples) (error 'flac-encoder-configure "could not set total samples estimate")))
|
||||
#t))
|
||||
|
||||
(define (init file)
|
||||
(require-encoder 'flac-encoder-init)
|
||||
(let ((r (FLAC__stream_encoder_init_file enc file #f #f)))
|
||||
(set! flac-file file)
|
||||
(unless (= r FLAC__StreamEncoderInitStatus-ok)
|
||||
(error 'flac-encoder-init "FLAC encoder init failed with status ~a" r))
|
||||
#t))
|
||||
|
||||
(define (write buffer size buf-info)
|
||||
(require-encoder 'flac-encoder-write)
|
||||
(let* ((channels (hash-ref settings 'channels))
|
||||
(in-bits (hash-ref/default buf-info 'pcm-bits-per-sample
|
||||
(hash-ref/default buf-info 'bits-per-sample
|
||||
(hash-ref settings 'bits-per-sample))))
|
||||
(out-bits (hash-ref settings 'bits-per-sample)))
|
||||
(let-values (((ptr frames) (pcm-bytes->flac-int32-pointer buffer size channels in-bits out-bits)))
|
||||
(unless (FLAC__stream_encoder_process_interleaved enc ptr frames)
|
||||
(error 'flac-encoder-write "FLAC encoder process_interleaved failed, state ~a" (FLAC__stream_encoder_get_state enc)))
|
||||
frames)))
|
||||
|
||||
(define (finish)
|
||||
(require-encoder 'flac-encoder-finish)
|
||||
(FLAC__stream_encoder_finish enc))
|
||||
|
||||
(define (delete)
|
||||
(unless (eq? enc #f)
|
||||
(FLAC__stream_encoder_delete enc)
|
||||
(set! enc #f))
|
||||
#t)
|
||||
|
||||
(lambda (cmd . args)
|
||||
(cond [(eq? cmd 'new) (new)]
|
||||
[(eq? cmd 'configure) (configure (car args))]
|
||||
[(eq? cmd 'init) (init (car args))]
|
||||
[(eq? cmd 'write) (write (car args) (cadr args) (caddr args))]
|
||||
[(eq? cmd 'finish) (finish)]
|
||||
[(eq? cmd 'delete) (delete)]
|
||||
[(eq? cmd 'state) (and enc (FLAC__stream_encoder_get_state enc))]
|
||||
[(eq? cmd 'file) flac-file]
|
||||
[(eq? cmd 'settings) settings]
|
||||
[else (error (format "unknown FLAC encoder command ~a" cmd))])))
|
||||
|
||||
|
||||
); end of module
|
||||
|
||||
|
||||
Reference in New Issue
Block a user