(module soxr-ffi racket/base (require ffi/unsafe ffi/unsafe/define "private/utils.rkt") (provide soxr-available? soxr-version soxr-create soxr-process soxr-delay soxr-clear soxr-delete soxr-error soxr-engine soxr-io-spec soxr-quality-spec soxr-runtime-spec soxr-error-ptr->string soxr-datatype-size _soxr_t _soxr_io_spec _soxr_io_spec-pointer soxr_io_spec? soxr_io_spec-itype soxr_io_spec-otype soxr_io_spec-scale soxr_io_spec-flags set-soxr_io_spec-scale! set-soxr_io_spec-flags! _soxr_quality_spec _soxr_quality_spec-pointer soxr_quality_spec? soxr_quality_spec-precision soxr_quality_spec-phase_response soxr_quality_spec-passband_end soxr_quality_spec-stopband_begin soxr_quality_spec-flags set-soxr_quality_spec-precision! set-soxr_quality_spec-phase_response! set-soxr_quality_spec-passband_end! set-soxr_quality_spec-stopband_begin! set-soxr_quality_spec-flags! _soxr_runtime_spec _soxr_runtime_spec-pointer soxr_runtime_spec? soxr_runtime_spec-log2_min_dft_size soxr_runtime_spec-log2_large_dft_size soxr_runtime_spec-coef_size_kbytes soxr_runtime_spec-num_threads soxr_runtime_spec-flags set-soxr_runtime_spec-num_threads! set-soxr_runtime_spec-flags! SOXR_FLOAT32 SOXR_FLOAT64 SOXR_INT32 SOXR_INT16 SOXR_SPLIT SOXR_FLOAT32_I SOXR_FLOAT64_I SOXR_INT32_I SOXR_INT16_I SOXR_FLOAT32_S SOXR_FLOAT64_S SOXR_INT32_S SOXR_INT16_S SOXR_TPDF SOXR_NO_DITHER SOXR_QQ SOXR_LQ SOXR_MQ SOXR_HQ SOXR_VHQ SOXR_16_BITQ SOXR_20_BITQ SOXR_24_BITQ SOXR_28_BITQ SOXR_32_BITQ SOXR_LINEAR_PHASE SOXR_INTERMEDIATE_PHASE SOXR_MINIMUM_PHASE SOXR_STEEP_FILTER SOXR_ROLLOFF_SMALL SOXR_ROLLOFF_MEDIUM SOXR_ROLLOFF_NONE SOXR_HI_PREC_CLOCK SOXR_DOUBLE_PRECISION SOXR_VR SOXR_COEF_INTERP_AUTO SOXR_COEF_INTERP_LOW SOXR_COEF_INTERP_HIGH) ;; libsoxr is normally libsoxr.so.0 on Linux and libsoxr.dylib on macOS. ;; The Windows build supplied with racket-audio may be either soxr.dll or ;; libsoxr.dll, so both stems are tried through the existing get-lib helper. (define libsoxr (get-lib (case (system-type 'os) [(windows) '("soxr" "libsoxr")] [else '("soxr" "libsoxr")]) (case (system-type 'os*) [(linux) '("0" #f)] [else '(#f)]))) (define-ffi-definer def-soxr libsoxr #:default-make-fail make-not-available) (define _soxr_t (_cpointer/null 'soxr)) ;; soxr.h structs. These are passed by pointer to soxr_create, while the ;; constructor functions in the C API return initialized structs by value. (define-cstruct _soxr_io_spec ([itype _int] [otype _int] [scale _double] [e _pointer] [flags _ulong])) (define-cstruct _soxr_quality_spec ([precision _double] [phase_response _double] [passband_end _double] [stopband_begin _double] [e _pointer] [flags _ulong])) (define-cstruct _soxr_runtime_spec ([log2_min_dft_size _uint] [log2_large_dft_size _uint] [coef_size_kbytes _uint] [num_threads _uint] [e _pointer] [flags _ulong])) ;; Datatypes supported by libsoxr. The *_I values are channel-interleaved; ;; those are what resampler.rkt uses for normal PCM byte strings. (define SOXR_FLOAT32 0) (define SOXR_FLOAT64 1) (define SOXR_INT32 2) (define SOXR_INT16 3) (define SOXR_SPLIT 4) (define SOXR_FLOAT32_I SOXR_FLOAT32) (define SOXR_FLOAT64_I SOXR_FLOAT64) (define SOXR_INT32_I SOXR_INT32) (define SOXR_INT16_I SOXR_INT16) (define SOXR_FLOAT32_S SOXR_SPLIT) (define SOXR_FLOAT64_S 5) (define SOXR_INT32_S 6) (define SOXR_INT16_S 7) (define SOXR_TPDF 0) (define SOXR_NO_DITHER 8) (define SOXR_QQ 0) (define SOXR_LQ 1) (define SOXR_MQ 2) (define SOXR_16_BITQ 3) (define SOXR_20_BITQ 4) (define SOXR_24_BITQ 5) (define SOXR_28_BITQ 6) (define SOXR_32_BITQ 7) (define SOXR_HQ SOXR_20_BITQ) (define SOXR_VHQ SOXR_28_BITQ) (define SOXR_LINEAR_PHASE #x00) (define SOXR_INTERMEDIATE_PHASE #x10) (define SOXR_MINIMUM_PHASE #x30) (define SOXR_STEEP_FILTER #x40) (define SOXR_ROLLOFF_SMALL 0) (define SOXR_ROLLOFF_MEDIUM 1) (define SOXR_ROLLOFF_NONE 2) (define SOXR_HI_PREC_CLOCK 8) (define SOXR_DOUBLE_PRECISION 16) (define SOXR_VR 32) (define SOXR_COEF_INTERP_AUTO 0) (define SOXR_COEF_INTERP_LOW 2) (define SOXR_COEF_INTERP_HIGH 3) (define (soxr-datatype-size t) (case (bitwise-and t 3) [(0) 4] [(1) 8] [(2) 4] [(3) 2] [else (error 'soxr-datatype-size "invalid datatype ~a" t)])) (define (soxr-error-ptr->string p) (and p (cast p _pointer _string/utf-8))) (def-soxr soxr_version/raw (_fun -> _string/utf-8) #:c-id soxr_version) (def-soxr soxr_io_spec/raw (_fun _int _int -> _soxr_io_spec) #:c-id soxr_io_spec) (def-soxr soxr_quality_spec/raw (_fun _ulong _ulong -> _soxr_quality_spec) #:c-id soxr_quality_spec) (def-soxr soxr_runtime_spec/raw (_fun _uint -> _soxr_runtime_spec) #:c-id soxr_runtime_spec) (def-soxr soxr_create/raw (_fun _double _double _uint (errp : (_ptr o _pointer)) _soxr_io_spec-pointer/null _soxr_quality_spec-pointer/null _soxr_runtime_spec-pointer/null -> (ctx : _soxr_t) -> (values ctx errp)) #:c-id soxr_create) (def-soxr soxr_process/raw (_fun _soxr_t _pointer _size (idone : (_ptr o _size)) _pointer _size (odone : (_ptr o _size)) -> (err : _pointer) -> (values err idone odone)) #:c-id soxr_process) (def-soxr soxr-delay (_fun _soxr_t -> _double) #:c-id soxr_delay) (def-soxr soxr-clear (_fun _soxr_t -> (err : _pointer) -> (soxr-error-ptr->string err)) #:c-id soxr_clear) (def-soxr soxr-error (_fun _soxr_t -> (err : _pointer) -> (soxr-error-ptr->string err)) #:c-id soxr_error) (def-soxr soxr-engine (_fun _soxr_t -> _string/utf-8) #:c-id soxr_engine) (def-soxr soxr-delete (_fun _soxr_t -> _void) #:c-id soxr_delete) (define (soxr-available?) (and libsoxr #t)) (define (soxr-version) (soxr_version/raw)) (define (soxr-io-spec itype otype #:scale [scale 1.0] #:flags [flags 0]) (let ((s (soxr_io_spec/raw itype otype))) (set-soxr_io_spec-scale! s scale) (set-soxr_io_spec-flags! s flags) s)) (define (soxr-quality-spec recipe #:flags [flags 0]) (soxr_quality_spec/raw recipe flags)) (define (soxr-runtime-spec #:num-threads [num-threads 1]) (soxr_runtime_spec/raw num-threads)) (define (soxr-create input-rate output-rate channels #:io-spec [io-spec #f] #:quality-spec [quality-spec #f] #:runtime-spec [runtime-spec #f]) (let-values (((ctx err) (soxr_create/raw (exact->inexact input-rate) (exact->inexact output-rate) channels io-spec quality-spec runtime-spec))) (values ctx (soxr-error-ptr->string err)))) (define (soxr-process ctx in ilen out olen) (let-values (((err idone odone) (soxr_process/raw ctx in ilen out olen))) (values (soxr-error-ptr->string err) idone odone))) ) ; end of module