From 8e6bf4e0f767d7339234eb8cce4dcc5178e473dd Mon Sep 17 00:00:00 2001 From: Hans Dijkema Date: Sat, 8 Aug 2026 14:20:46 +0200 Subject: [PATCH] Added capability information --- audio-decoder.rkt | 27 ++++++++++++++++++++- audio-placed-player.rkt | 3 ++- audio-sniffer.rkt | 48 ++++++++++++++++++++++++------------- info.rkt | 1 + main.rkt | 7 ++++++ scrbl/audio-decoder.scrbl | 20 +++++++++++++++- tests/capabilities-test.rkt | 32 +++++++++++++++++++++++++ 7 files changed, 119 insertions(+), 19 deletions(-) create mode 100644 tests/capabilities-test.rkt diff --git a/audio-decoder.rkt b/audio-decoder.rkt index dca41ab..4c424ef 100644 --- a/audio-decoder.rkt +++ b/audio-decoder.rkt @@ -10,6 +10,7 @@ racket/contract racket/string racket/path + racket-mimetypes ) (provide audio-open @@ -24,6 +25,8 @@ make-audio-reader audio-handle? audio-supported-extensions + audio-supported-formats + audio-decoder-for-extension current-opusfile-output-format opusfile-output-format? ) @@ -107,6 +110,20 @@ (define (audio-supported-extensions) known-extensions) + (define/contract (audio-supported-formats) + (-> (listof + (cons/c string? + string?))) + (for/list ((extension + (in-list known-extensions))) + (cons + extension + (mimetype-for-ext + (string-append "audio." + extension) + #:default + "application/octet-stream")))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Register audio reader ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -268,6 +285,14 @@ (cons 'wma 'ffmpeg) (cons 'matroska 'ffmpeg)))) + (define/contract (audio-decoder-for-extension extension) + (-> (or/c string? symbol?) + (or/c #f symbol?)) + (hash-ref + reader-for-kind + (audio-format-for-extension extension) + #f)) + (define (find-reader audio-file) @@ -286,4 +311,4 @@ ) ; end of module - \ No newline at end of file + diff --git a/audio-placed-player.rkt b/audio-placed-player.rkt index e5d4754..f54655e 100644 --- a/audio-placed-player.rkt +++ b/audio-placed-player.rkt @@ -414,7 +414,8 @@ (audio-seek ao-dec percentage))) (define (volume percentage) - (set! req-volume percentage)) + (set! req-volume percentage) + (check-volume)) (define (ao-buf-ms) (ao-playback-buf-ms)) diff --git a/audio-sniffer.rkt b/audio-sniffer.rkt index 589c424..a8f1321 100644 --- a/audio-sniffer.rkt +++ b/audio-sniffer.rkt @@ -10,6 +10,7 @@ audio-sniff-format audio-sniff-format/extension audio-sniff-extension + audio-format-for-extension audio-format-matches? audio-format-known?) @@ -46,6 +47,30 @@ (substring s 1) s))]))) +(define (audio-format-for-extension* extension) + (let* ((text (string-downcase + (format "~a" extension))) + (normalized + (if (string-prefix? text ".") + (substring text 1) + text))) + (case (string->symbol normalized) + [(mp3 mp2 mp1) 'mp3] + [(flac) 'flac] + [(ogg oga) 'ogg] + [(opus) 'opus] + [(wav wave) 'wav] + [(aif aiff aifc) 'aiff] + [(m4a mp4 m4b m4p) 'mp4] + [(aac) 'aac] + [(alac) 'alac] + [(ac3) 'ac3] + [(ape) 'ape] + [(wv wvp wvpk wavpack) 'wavpack] + [(wma asf) 'wma] + [(webm mka mkv) 'matroska] + [else 'unknown]))) + (define (file-readable-status file) (cond [(not (file-exists? file)) 'file-not-found] @@ -294,22 +319,9 @@ fmt] [(not (eq? fmt 'unknown)) fmt] [else - (case (string->symbol (or (audio-sniff-extension* file) "")) - [(mp3 mp2 mp1) 'mp3] - [(flac) 'flac] - [(ogg oga) 'ogg] - [(opus) 'opus] - [(wav wave) 'wav] - [(aif aiff aifc) 'aiff] - [(m4a mp4 m4b m4p) 'mp4] - [(aac) 'aac] - [(alac) 'alac] - [(ac3) 'ac3] - [(ape) 'ape] - [(wv wvp wvpk wavpack) 'wavpack] - [(wma asf) 'wma] - [(webm mka mkv) 'matroska] - [else 'unknown])]))) + (audio-format-for-extension* + (or (audio-sniff-extension* file) + ""))]))) (define (audio-format-known?* fmt) (not (eq? (memq fmt audio-formats) #f))) @@ -321,6 +333,10 @@ (-> path-string? (or/c string? #f)) (audio-sniff-extension* file)) +(define/contract (audio-format-for-extension extension) + (-> (or/c string? symbol?) audio-format?) + (audio-format-for-extension* extension)) + (define/contract (audio-sniff-format file) (-> path-string? audio-format?) (audio-sniff-format* file)) diff --git a/info.rkt b/info.rkt index 29e446d..c799dd6 100644 --- a/info.rkt +++ b/info.rkt @@ -15,6 +15,7 @@ '("racket/gui" "racket/base" "racket" "finalizer" "draw-lib" "net-lib" "simple-log" "simple-ini" "racket-sprintf" + "racket-mimetypes" "early-return" "let-assert" "uni-channel" "port-channel" "rackunit-lib" diff --git a/main.rkt b/main.rkt index 0104ce4..eb9c090 100644 --- a/main.rkt +++ b/main.rkt @@ -3,12 +3,19 @@ (require "taglib.rkt" "audio-sniffer.rkt" "audio-player.rkt" + (only-in "audio-decoder.rkt" + audio-supported-extensions + audio-supported-formats + audio-decoder-for-extension) "opusfile-decoder.rkt" ) (provide (all-from-out "taglib.rkt") (all-from-out "audio-sniffer.rkt") (all-from-out "audio-player.rkt") + audio-supported-extensions + audio-supported-formats + audio-decoder-for-extension current-opusfile-output-format opusfile-output-format? ) diff --git a/scrbl/audio-decoder.scrbl b/scrbl/audio-decoder.scrbl index 2f2394f..6f3653c 100644 --- a/scrbl/audio-decoder.scrbl +++ b/scrbl/audio-decoder.scrbl @@ -105,6 +105,24 @@ Returns the current list of supported filename extensions. This is the same list returned by @racket[audio-known-exts?]. } +@defproc[(audio-supported-formats) + (listof (cons/c string? string?))]{ + +Returns the supported filename extensions together with the MIME type +reported by @racketmodname[racket-mimetypes]. Unknown MIME types use +@racket["application/octet-stream"]. +} + +@defproc[(audio-decoder-for-extension + [extension (or/c string? symbol?)]) + (or/c #f symbol?)]{ + +Returns the decoder selected for audio with @racket[extension], such as +@racket['flac], @racket['opusfile], or @racket['ffmpeg]. The result is +@racket[#f] when the extension is not recognized. Actual playback still +sniffs the file contents before selecting its decoder. +} + @section{Built-in decoder selection} The built-in decoder table contains: @@ -306,4 +324,4 @@ A backend integrated through this interface should provide: Once registered, files with matching extensions can be opened through @racket[audio-open] in the same way as the built-in FLAC, MP3, -Opusfile, and FFmpeg backends. \ No newline at end of file +Opusfile, and FFmpeg backends. diff --git a/tests/capabilities-test.rkt b/tests/capabilities-test.rkt new file mode 100644 index 0000000..6dc8344 --- /dev/null +++ b/tests/capabilities-test.rkt @@ -0,0 +1,32 @@ +#lang racket/base + +(require rackunit + racket-audio) + +(define formats + (audio-supported-formats)) + +(check-not-false + (member "flac" + (audio-supported-extensions))) +(check-equal? + (cdr (assoc "flac" formats)) + "audio/x-flac") +(check-eq? + (audio-decoder-for-extension "flac") + 'flac) +(check-eq? + (audio-decoder-for-extension ".mp3") + 'ffmpeg) +(check-not-false + (member (audio-decoder-for-extension 'opus) + '(opusfile ffmpeg))) +(check-false + (audio-decoder-for-extension "not-audio")) + +(for ((extension + (in-list + (audio-supported-extensions)))) + (check-true + (symbol? + (audio-decoder-for-extension extension))))