ffmpeg support
This commit is contained in:
+60
-11
@@ -2,6 +2,9 @@
|
||||
|
||||
(require "flac-decoder.rkt"
|
||||
"mp3-decoder.rkt"
|
||||
"ffmpeg-decoder.rkt"
|
||||
"audio-sniffer.rkt"
|
||||
"private/utils.rkt"
|
||||
racket/contract
|
||||
racket/string
|
||||
racket/path
|
||||
@@ -52,12 +55,38 @@
|
||||
mp3-stop
|
||||
'ao))
|
||||
|
||||
;; FFmpeg decodere
|
||||
(hash-set! audio-readers
|
||||
'ffmpeg
|
||||
(make-audio-reader '("ogg" "oga" "opus"
|
||||
"m4a" "mp4" "m4b"
|
||||
"aac"
|
||||
"wav"
|
||||
"aiff" "aif" "aifc"
|
||||
"wma"
|
||||
"webm" "mkv" "mka")
|
||||
ffmpeg-valid?
|
||||
ffmpeg-open
|
||||
ffmpeg-read
|
||||
ffmpeg-seek
|
||||
ffmpeg-stop
|
||||
'ao))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Known extensions
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(define known-extensions
|
||||
'("flac" "mp3"))
|
||||
'("flac" ; FLAC decoder
|
||||
"mp3" ; mp3 decoder
|
||||
"ogg" "oga" "opus"
|
||||
"m4a" "mp4" "m4b"
|
||||
"aac"
|
||||
"wav"
|
||||
"aiff" "aif" "aifc"
|
||||
"wma"
|
||||
"webm" "mkv" "mka" ; FFMPEG decoder
|
||||
))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Register audio reader
|
||||
@@ -92,7 +121,11 @@
|
||||
(set! ext (format "~a" ext))
|
||||
(when (string-prefix? ext ".")
|
||||
(set! ext (substring ext 1)))
|
||||
(not (null? (filter (λ (e) (string-ci=? ext e)) known-extensions)))
|
||||
(if (not (null? (filter (λ (e) (string-ci=? ext e)) known-extensions)))
|
||||
#t
|
||||
(begin
|
||||
(warn-sound "extension '~a' not in known-extensions '~a'" ext known-extensions)
|
||||
#f))
|
||||
)
|
||||
|
||||
(define/contract (audio-file-valid? file)
|
||||
@@ -189,17 +222,33 @@
|
||||
(define (right-reader? reader ext)
|
||||
(not (null? (filter (λ (e) (string-ci=? ext e)) (audio-reader-exts reader)))))
|
||||
|
||||
(define reader-for-kind
|
||||
(make-hash '((mp3 . ffmpeg) ; ffmpeg does a better job on gapless playback...
|
||||
(flac . flac)
|
||||
(ogg . ffmpeg)
|
||||
(vorbis . ffmpeg)
|
||||
(opus . ffmpeg)
|
||||
(wav . ffmpeg)
|
||||
(aiff . ffmpeg)
|
||||
(mp4 . ffmpeg)
|
||||
(aac . ffmpeg)
|
||||
(alac . ffmpeg)
|
||||
(ac3 . ffmpeg)
|
||||
(ape . ffmpeg)
|
||||
(wavpack . ffmpeg)
|
||||
(wma . ffmpeg)
|
||||
(matroska . ffmpeg))))
|
||||
|
||||
|
||||
(define (find-reader audio-file)
|
||||
(let* ((f (build-path audio-file))
|
||||
(ext (substring (format "~a" (path-get-extension audio-file)) 1)))
|
||||
(letrec ((f (λ (keys)
|
||||
(if (null? keys)
|
||||
; First try to sniff the format
|
||||
(let ((format (audio-sniff-format/extension audio-file)))
|
||||
(let ((reader-kind (hash-ref reader-for-kind format #f)))
|
||||
(if (eq? reader-kind #f)
|
||||
#f
|
||||
(let ((reader (hash-ref audio-readers (car keys))))
|
||||
(if (right-reader? reader ext)
|
||||
(list (car keys) reader)
|
||||
(f (cdr keys))))))))
|
||||
(f (hash-keys audio-readers))
|
||||
(let ((reader (hash-ref audio-readers reader-kind)))
|
||||
(list reader-kind reader))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
+23
-1
@@ -2,7 +2,9 @@
|
||||
|
||||
(require racket/contract
|
||||
racket/path
|
||||
racket/string)
|
||||
racket/string
|
||||
racket/runtime-path
|
||||
)
|
||||
|
||||
(provide audio-format?
|
||||
audio-sniff-format
|
||||
@@ -334,3 +336,23 @@
|
||||
(define/contract (audio-format-matches? file formats)
|
||||
(-> path-string? (listof symbol?) boolean?)
|
||||
(audio-format-matches?* file formats))
|
||||
|
||||
(define-runtime-path audio-tests "tests")
|
||||
|
||||
(define (sniff-test)
|
||||
(for-each (λ (ext)
|
||||
(let* ((dir (build-path audio-tests))
|
||||
(ext* (format ".~a" ext))
|
||||
(files (map (λ (f)
|
||||
(build-path audio-tests f))
|
||||
(filter (λ (f)
|
||||
(string-suffix? (format "~a" f) ext*))
|
||||
(directory-list dir))))
|
||||
)
|
||||
(for-each (λ (f)
|
||||
(displayln (format "~a: ~a" f (audio-sniff-format/extension f))))
|
||||
files)
|
||||
)
|
||||
)
|
||||
'(aac adts flac mp3 ogg ts ac3 aiff m4a mp4 ogx wav wv mp2))
|
||||
)
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
(module ffmpeg_decoder racket/base
|
||||
|
||||
(require ffi/unsafe
|
||||
"ffmpeg_ffi.rkt"
|
||||
"ffmpeg-ffi.rkt"
|
||||
"private/utils.rkt"
|
||||
(prefix-in fin: finalizer)
|
||||
)
|
||||
|
||||
@@ -118,6 +118,16 @@
|
||||
(define-ffmpeg-audio fmpg_timecode
|
||||
(_fun _fmpg_instance -> _double))
|
||||
|
||||
(define-ffmpeg-audio fmpg_ffmpeg_version
|
||||
(_fun -> _string*/utf-8))
|
||||
|
||||
(define-ffmpeg-audio fmpg_int_version2string
|
||||
(_fun _int -> _string*/utf-8))
|
||||
|
||||
(define-ffmpeg-audio fmpg_compatible_ffmpeg
|
||||
(_fun -> _int))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Our interface for decoding to racket
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
)
|
||||
|
||||
(provide ao_create_async
|
||||
ao_real_output_bits_async
|
||||
ao_stop_async
|
||||
ao_play_async
|
||||
ao_is_at_music_id_async
|
||||
@@ -66,6 +67,10 @@
|
||||
;extern void *ao_create_async(int bits, int rate, int channel, int byte_format);
|
||||
(define-libao-async ao_create_async(_fun _int _int _int _Endian_t _string/utf-8 -> _libao-async-handle-pointer))
|
||||
|
||||
;extern int ao_real_output_bits(void *handle)
|
||||
(define-libao-async ao_real_output_bits_async
|
||||
(_fun _libao-async-handle-pointer -> _int))
|
||||
|
||||
;extern void ao_stop_async(void *handle);
|
||||
(define-libao-async ao_stop_async(_fun _libao-async-handle-pointer -> _void))
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
)
|
||||
|
||||
(provide ao-open-live
|
||||
ao-device-bits
|
||||
ao-open-file
|
||||
ao-play
|
||||
ao-close
|
||||
@@ -35,6 +36,8 @@
|
||||
(define-struct ao-handle (handle-num
|
||||
[bits #:auto #:mutable]
|
||||
[bytes-per-sample #:auto #:mutable]
|
||||
[dev-bits #:auto #:mutable]
|
||||
[dev-bytes-per-sample #:auto #:mutable]
|
||||
[byte-format #:auto #:mutable]
|
||||
[channels #:auto #:mutable]
|
||||
[rate #:auto #:mutable]
|
||||
@@ -113,8 +116,10 @@
|
||||
(err-sound "ao-open-live - cannote create player")
|
||||
(set-ao-handle-closed! handle #t)
|
||||
handle)
|
||||
(begin
|
||||
(info-sound "ao-open-live - created player")
|
||||
(let ((out-bits (ffi:ao_real_output_bits_async player)))
|
||||
(info-sound "ao-open-live - created player at ~a bits" out-bits)
|
||||
(set-ao-handle-dev-bits! handle out-bits)
|
||||
(set-ao-handle-dev-bytes-per-sample! handle (/ out-bits 8))
|
||||
(set-ao-handle-closed! handle #f)
|
||||
handle
|
||||
)
|
||||
@@ -143,6 +148,10 @@
|
||||
(define (any? x)
|
||||
#t)
|
||||
|
||||
(rc:define/contract (ao-device-bits handle)
|
||||
(rc:-> ao-handle? integer?)
|
||||
(ao-handle-dev-bits handle))
|
||||
|
||||
(rc:define/contract (ao-play handle music-id at-time-in-s music-duration-s buffer buf-len buf-type)
|
||||
(rc:-> ao-handle? integer? number? number? any? integer? ao-supported-music-format? void?)
|
||||
(let* ((bytes-per-sample (ao-handle-bytes-per-sample handle))
|
||||
|
||||
+43
-4
@@ -4,10 +4,13 @@
|
||||
simple-log
|
||||
"private/utils.rkt"
|
||||
racket-sprintf
|
||||
racket/runtime-path
|
||||
;data/queue
|
||||
;racket-sound
|
||||
)
|
||||
|
||||
(define-runtime-path tests "tests")
|
||||
|
||||
(define test-file3 #f)
|
||||
(define test-file4 #f)
|
||||
(define test-file3-id 3)
|
||||
@@ -15,8 +18,9 @@
|
||||
(let ((os (system-type 'os)))
|
||||
(when (eq? os 'unix)
|
||||
;(set! test-file3 "/muziek/Klassiek-Viool/Alina Ibragimova/Paganini_24 Caprices (2021)/24. 24 Caprices, Op 1 - No. 24 in A minor- Tema con variazioni. Quasi presto.flac")
|
||||
(set! test-file3 "/tmp/test.mp3")
|
||||
(set! test-file4 "/tmp/test1.mp3")
|
||||
;(set! test-file3 "/tmp/test.mp3")
|
||||
(set! test-file3 (build-path tests "mahler-1.mp3"))
|
||||
(set! test-file4 (build-path tests "mahler-2.mp3"))
|
||||
)
|
||||
(when (eq? os 'windows)
|
||||
;(set! test-file3 "C:\\Muziek\\Klassiek-Strijkkwartet\\Quatuor Zaïde\\Franz\\01 Erlkönig, D. 328 (Arr. For String Quartet by Eric Mouret).flac")
|
||||
@@ -34,6 +38,10 @@
|
||||
(define current-file-id -1)
|
||||
(define current-audio-h #f)
|
||||
|
||||
(define current-bits -1)
|
||||
(define current-rate -1)
|
||||
(define current-channels -1)
|
||||
|
||||
(sl-log-to-display)
|
||||
(define wav-output-file #f)
|
||||
(define seeked #f)
|
||||
@@ -51,12 +59,43 @@
|
||||
(when (= (round current-seconds) 10)
|
||||
(when (and (= current-file-id 3) (not seeked))
|
||||
(set! seeked #t)
|
||||
(audio-seek current-audio-h 97.0)))))
|
||||
(let ((perc (exact->inexact (* (/ (- duration 15) duration) 100.0))))
|
||||
(info-sound "Seeking to ~a%" perc)
|
||||
(audio-seek current-audio-h perc))))))
|
||||
)
|
||||
|
||||
(when (not (eq? ao-h #f))
|
||||
(when (not (and
|
||||
(= current-bits bits-per-sample)
|
||||
(= current-rate rate)
|
||||
(= current-channels channels)))
|
||||
(ao-close ao-h)
|
||||
(set! ao-h #f)))
|
||||
|
||||
;(displayln buf-info)
|
||||
(when (eq? ao-h #f)
|
||||
(set! ao-h (ao-open-file bits-per-sample rate channels 'native-endian wav-output-file)))
|
||||
|
||||
(info-sound "Opening ao handle")
|
||||
(info-sound "bits-per-sample: ~a" bits-per-sample)
|
||||
(info-sound "rate : ~a" rate)
|
||||
(info-sound "channels : ~a" channels)
|
||||
(info-sound "endian : ~a" 'native-endian)
|
||||
(info-sound "(optional) file: ~a" wav-output-file)
|
||||
(sync-log-sound)
|
||||
|
||||
(set! ao-h (ao-open-file bits-per-sample rate channels 'native-endian wav-output-file))
|
||||
|
||||
(set! current-bits bits-per-sample)
|
||||
(set! current-rate rate)
|
||||
(set! current-channels channels)
|
||||
(info-sound "ao bits per sample: ~a" (ao-device-bits ao-h))
|
||||
(sync-log-sound)
|
||||
)
|
||||
|
||||
;(displayln 'ao-play)
|
||||
;(dbg-sound "Playing audio at ~a" second)
|
||||
;(sync-log-sound)
|
||||
|
||||
(ao-play ao-h current-file-id second duration buffer buf-len ao-type)
|
||||
(set! duration (inexact->exact (round duration)))
|
||||
;(displayln 'done)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
err-sound
|
||||
warn-sound
|
||||
fatal-sound
|
||||
sync-log-sound
|
||||
)
|
||||
|
||||
(sl-def-log racket-sound sound)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user