updates to sndfile
This commit is contained in:
parent
3e78806e67
commit
e29c14c260
|
@ -1,15 +1,21 @@
|
||||||
#lang racket/base
|
#lang racket/base
|
||||||
|
|
||||||
(require ffi/unsafe
|
(require ffi/unsafe
|
||||||
#;rackunit
|
ffi/vector
|
||||||
racket/match)
|
racket/match
|
||||||
|
racket/runtime-path)
|
||||||
|
|
||||||
;; the constants in this file are pulled from version 1.0.21 of the libsndfile header file. However,
|
;; the constants in this file are pulled from version 1.0.21 of the libsndfile header file. However,
|
||||||
;; I think it would be a mistake to specify this in the call to ffi-lib; it appears that
|
;; I think it would be a mistake to specify this in the call to ffi-lib; it appears that
|
||||||
;; this version is a conservative extension of the earlier version (1.0.17?), and I
|
;; this version is a conservative extension of the earlier version (1.0.17?), and I
|
||||||
;; think you'll get graceful failures if the version is wrong.
|
;; think you'll get graceful failures if the version is wrong.
|
||||||
|
|
||||||
(define libsndfile (ffi-lib "libsndfile"))
|
(define-runtime-path mac-ffi-path "./lib/libsndfile")
|
||||||
|
(define libsndfile
|
||||||
|
(match (system-type)
|
||||||
|
['unix (ffi-lib "libsndfile" '("1.0.21" "1.0.20" ""))]
|
||||||
|
['macosx (ffi-lib mac-ffi-path '("1.0.21" "1.0.20" ""))]
|
||||||
|
['windows (error 'libsndfile "libsndfile not supported on windows.")]))
|
||||||
|
|
||||||
;; ==================== Types etc ====================
|
;; ==================== Types etc ====================
|
||||||
|
|
||||||
|
@ -205,7 +211,7 @@
|
||||||
-> (if (sndfile-ptr sf)
|
-> (if (sndfile-ptr sf)
|
||||||
(begin (set-sndfile-info! sf info) sf)
|
(begin (set-sndfile-info! sf info) sf)
|
||||||
;; goofy way to get the error code:
|
;; goofy way to get the error code:
|
||||||
(error 'sf-read "~a" (sf-strerror (make-sndfile #f #f)))))
|
(error 'sf-open "~a" (sf-strerror (make-sndfile #f #f)))))
|
||||||
|
|
||||||
(defsndfile sf-format-check : _sf-info-pointer -> _bool)
|
(defsndfile sf-format-check : _sf-info-pointer -> _bool)
|
||||||
|
|
||||||
|
@ -247,9 +253,9 @@
|
||||||
(when found (sf-set-string sndfile st (cadr found))))))
|
(when found (sf-set-string sndfile st (cadr found))))))
|
||||||
|
|
||||||
|
|
||||||
;; read-sound-internal : path-string [bool] -> (values/c (or/c cblock (listof (listof sample))) a-list)
|
;; read-sound-internal : path-string -> (values/c (or/c cblock (listof (listof sample))) a-list)
|
||||||
;; read the data from a file.
|
;; read the data from a file.
|
||||||
(define (read-sound-internal file #:split [split-into-lists? #t])
|
(define (read-sound-internal file)
|
||||||
(let* ([sndfile (sf-open file 'sfm-read)]
|
(let* ([sndfile (sf-open file 'sfm-read)]
|
||||||
[strings (get-meta-strings sndfile)]
|
[strings (get-meta-strings sndfile)]
|
||||||
[info (sndfile-info sndfile)]
|
[info (sndfile-info sndfile)]
|
||||||
|
@ -258,17 +264,14 @@
|
||||||
[stype (case (sample-type)
|
[stype (case (sample-type)
|
||||||
[(short) _int16] [(int) _int] [(float) _double*])]
|
[(short) _int16] [(int) _int] [(float) _double*])]
|
||||||
[readf (sample-type->reader (sample-type))]
|
[readf (sample-type->reader (sample-type))]
|
||||||
[cblock (malloc (* frames channels) stype)]
|
[cblock ((sample-type->vector-maker (sample-type)) (* frames channels))]
|
||||||
[num-read (readf sndfile cblock frames)]
|
[num-read (readf sndfile ((sample-type->cpointer-extractor (sample-type)) cblock) frames)]
|
||||||
[_ (unless (= frames num-read)
|
[_ (unless (= frames num-read)
|
||||||
(error 'read-sound-internal
|
(error 'read-sound-internal
|
||||||
"wanted ~s frames, but got ~s: ~s"
|
"wanted ~s frames, but got ~s: ~s"
|
||||||
frames num-read
|
frames num-read
|
||||||
(sf-strerror sndfile)))]
|
(sf-strerror sndfile)))])
|
||||||
[data (if split-into-lists?
|
(begin0 (values cblock
|
||||||
(split-sound-cblock cblock stype frames channels)
|
|
||||||
cblock)])
|
|
||||||
(begin0 (values data
|
|
||||||
`((frames ,frames)
|
`((frames ,frames)
|
||||||
(samplerate ,(sf-info-samplerate info))
|
(samplerate ,(sf-info-samplerate info))
|
||||||
(channels ,channels)
|
(channels ,channels)
|
||||||
|
@ -280,9 +283,11 @@
|
||||||
"error while closing file: ~s"
|
"error while closing file: ~s"
|
||||||
(sf-strerror sndfile))))))
|
(sf-strerror sndfile))))))
|
||||||
|
|
||||||
|
|
||||||
;; split-sound-cblock : cblock ffi-type nat nat -> (listof frame)
|
;; split-sound-cblock : cblock ffi-type nat nat -> (listof frame)
|
||||||
;; ... where frame is (listof sample-value)
|
;; ... where frame is (listof sample-value)
|
||||||
(define (split-sound-cblock cblock stype frames channels)
|
;; NOT SUPPORTING THE LIST INTERFACE RIGHT NOW (2010-09-24)
|
||||||
|
#;(define (split-sound-cblock cblock stype frames channels)
|
||||||
(let* ([data (cblock->list cblock stype (* frames channels))])
|
(let* ([data (cblock->list cblock stype (* frames channels))])
|
||||||
(n-split data channels)))
|
(n-split data channels)))
|
||||||
|
|
||||||
|
@ -306,11 +311,12 @@
|
||||||
[(pair? d) (loop (car d)) (loop (cdr d))]))
|
[(pair? d) (loop (car d)) (loop (cdr d))]))
|
||||||
cblock)]))
|
cblock)]))
|
||||||
|
|
||||||
|
|
||||||
;; there are some ugly hidden invariants here: what if the sample-type doesn't match
|
;; there are some ugly hidden invariants here: what if the sample-type doesn't match
|
||||||
;; what's specified in the format? This is a question about libsndfile, and I should check it out...
|
;; what's specified in the format? This is a question about libsndfile, and I should check it out...
|
||||||
|
|
||||||
;; write-sound-internal/cblock
|
;; write-sound-internal/s16vector
|
||||||
(define (write-sound-internal/cblock file cblock format samplerate frames channels sample-type meta)
|
(define (write-sound-internal/s16vector file cblock format samplerate frames channels sample-type meta)
|
||||||
(check-filename-format format file)
|
(check-filename-format format file)
|
||||||
(let* ([writef (sample-type->writer sample-type)]
|
(let* ([writef (sample-type->writer sample-type)]
|
||||||
[info (make-sf-info frames samplerate channels format 1 #f)]
|
[info (make-sf-info frames samplerate channels format 1 #f)]
|
||||||
|
@ -318,13 +324,13 @@
|
||||||
(error 'write-sound-internal "bad format: ~s" format))]
|
(error 'write-sound-internal "bad format: ~s" format))]
|
||||||
[sndfile (sf-open file 'sfm-write info)]
|
[sndfile (sf-open file 'sfm-write info)]
|
||||||
[_ (set-meta-strings sndfile meta)]
|
[_ (set-meta-strings sndfile meta)]
|
||||||
[num-write (writef sndfile cblock frames)])
|
[num-write (writef sndfile (s16vector->cpointer cblock) frames)])
|
||||||
(unless (= frames num-write)
|
(unless (= frames num-write)
|
||||||
(error 'write-sound-internal/cblock
|
(error 'write-sound-internal/s16vector
|
||||||
"wanted to write ~s frames, but wrote only ~s. ~s"
|
"wanted to write ~s frames, but wrote only ~s. ~s"
|
||||||
frames num-write (sf-strerror sndfile)))
|
frames num-write (sf-strerror sndfile)))
|
||||||
(unless (= 0 (sf-close sndfile))
|
(unless (= 0 (sf-close sndfile))
|
||||||
(error 'write-sound-internal/cblock "failed to close file: ~s" (sf-strerror sndfile)))
|
(error 'write-sound-internal/s16vector "failed to close file: ~s" (sf-strerror sndfile)))
|
||||||
(void)))
|
(void)))
|
||||||
|
|
||||||
;; write-sound-internal/lists : path-string (listof (listof sample)) (listof (list/c symbol? string?)) -> (void)
|
;; write-sound-internal/lists : path-string (listof (listof sample)) (listof (list/c symbol? string?)) -> (void)
|
||||||
|
@ -341,7 +347,7 @@
|
||||||
[else (guess-format file)])]
|
[else (guess-format file)])]
|
||||||
[samplerate (cond [(assq 'samplerate meta) => cadr]
|
[samplerate (cond [(assq 'samplerate meta) => cadr]
|
||||||
[else (default-samplerate)])])
|
[else (default-samplerate)])])
|
||||||
(write-sound-internal/cblock file cblock format samplerate frames channels (sample-type) meta)))
|
(write-sound-internal/s16vector file cblock format samplerate frames channels (sample-type) meta)))
|
||||||
|
|
||||||
(define file-format-table
|
(define file-format-table
|
||||||
'((#rx"\\.aiff?" (aiff pcm-16 file))
|
'((#rx"\\.aiff?" (aiff pcm-16 file))
|
||||||
|
@ -402,7 +408,6 @@
|
||||||
(match-lambda
|
(match-lambda
|
||||||
['short sf-readf-short]
|
['short sf-readf-short]
|
||||||
['int sf-readf-int]
|
['int sf-readf-int]
|
||||||
['float sf-readf-float]
|
|
||||||
['double sf-readf-double]))
|
['double sf-readf-double]))
|
||||||
|
|
||||||
;; return the writer that corresponds to a given sample-type
|
;; return the writer that corresponds to a given sample-type
|
||||||
|
@ -410,19 +415,33 @@
|
||||||
(match-lambda
|
(match-lambda
|
||||||
['short sf-writef-short]
|
['short sf-writef-short]
|
||||||
['int sf-writef-int]
|
['int sf-writef-int]
|
||||||
['float sf-writef-float]
|
|
||||||
['double sf-writef-double]))
|
['double sf-writef-double]))
|
||||||
|
|
||||||
|
;; return the vector-maker that corresponds to a given sample-type
|
||||||
|
(define sample-type->vector-maker
|
||||||
|
(match-lambda
|
||||||
|
['short make-s16vector]
|
||||||
|
['int make-s32vector]
|
||||||
|
['double make-f64vector]))
|
||||||
|
|
||||||
|
;; return the cpointer-extractor that corresponds to a given sample-type
|
||||||
|
(define sample-type->cpointer-extractor
|
||||||
|
(match-lambda
|
||||||
|
['short s16vector->cpointer]
|
||||||
|
['int s32vector->cpointer]
|
||||||
|
['double flvector->cpointer]))
|
||||||
|
|
||||||
|
|
||||||
;; ==================== Exposed Scheme interface ====================
|
;; ==================== Exposed Scheme interface ====================
|
||||||
|
|
||||||
;; types of samples we handle: 'short, 'int, 'double, or 'float
|
;; types of samples we handle: 'short, 'int, 'double
|
||||||
(provide sample-type)
|
(provide sample-type)
|
||||||
(define sample-type
|
(define sample-type
|
||||||
(make-parameter
|
(make-parameter
|
||||||
'float (lambda (x)
|
'float (lambda (x)
|
||||||
(if (memq x '(short int float double))
|
(if (memq x '(short int double))
|
||||||
x
|
x
|
||||||
(error 'sample-type "bad type: ~s" x)))))
|
(error 'sample-type "bad or unsupported type: ~s" x)))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -465,25 +484,27 @@
|
||||||
;; C data. It's 2-channel 32-bit float only. Also, it discards
|
;; C data. It's 2-channel 32-bit float only. Also, it discards
|
||||||
;; all meta-information except length and sample-rate.
|
;; all meta-information except length and sample-rate.
|
||||||
|
|
||||||
;; read-sound/floatblock : path-string -> (list/c _pointer nat nat)
|
(define global-channels 2)
|
||||||
|
|
||||||
|
;; read-sound/s16vector : path-string -> (list/c _pointer nat nat)
|
||||||
;; read the file into a buffer, return the data, the number of frames,
|
;; read the file into a buffer, return the data, the number of frames,
|
||||||
;; and the sample rate.
|
;; and the sample rate.
|
||||||
(provide read-sound/floatblock)
|
(provide read-sound/s16vector)
|
||||||
(define (read-sound/floatblock file)
|
(define (read-sound/s16vector file)
|
||||||
(parameterize ([sample-type 'float])
|
(parameterize ([sample-type 'short])
|
||||||
(let*-values ([(cblock meta) (read-sound-internal file #:split #f)])
|
(let*-values ([(cblock meta) (read-sound-internal file)])
|
||||||
(list cblock (cadr (assq 'frames meta)) (cadr (assq 'samplerate meta))))))
|
(list cblock (cadr (assq 'frames meta)) (cadr (assq 'samplerate meta))))))
|
||||||
|
|
||||||
;; write-sound/floatblock : _pointer nat nat path-string -> (void)
|
;; write-sound/s16vector : _pointer nat nat path-string -> (void)
|
||||||
;; write the floatblock sound to the given file as a wav.
|
;; write the cblock sound to the given file as a wav.
|
||||||
(provide write-sound/floatblock)
|
(provide write-sound/s16vector)
|
||||||
(define (write-sound/floatblock data frames sample-rate file)
|
(define (write-sound/s16vector data sample-rate file)
|
||||||
(write-sound-internal/cblock file data '(wav float file)
|
(write-sound-internal/s16vector file data '(wav pcm-16 file)
|
||||||
sample-rate
|
sample-rate
|
||||||
frames
|
(/ (s16vector-length data) global-channels)
|
||||||
2
|
2
|
||||||
'float
|
'short
|
||||||
;; for now, no meta-data possible.
|
;; meta-data not supported.
|
||||||
'()))
|
'()))
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user