projects
/
rrq
/
newlisp
/
alsa-dispatcher.git
/ commitdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
| commitdiff |
tree
raw
|
patch
|
inline
| side by side (parent:
34d6d8f
)
some cleanup
author
Ralph Ronnquist
<ralph.ronnquist@gmail.com>
Sat, 29 Apr 2023 02:54:09 +0000
(12:54 +1000)
committer
Ralph Ronnquist
<ralph.ronnquist@gmail.com>
Sat, 29 Apr 2023 02:54:09 +0000
(12:54 +1000)
alsa-dispatcher.lsp
patch
|
blob
|
history
diff --git
a/alsa-dispatcher.lsp
b/alsa-dispatcher.lsp
index deb557cb8b7336ac510831fac5bb35b8a9c3372c..df8863ba06ed028f9cc33bede1f09522072096bb 100755
(executable)
--- a/
alsa-dispatcher.lsp
+++ b/
alsa-dispatcher.lsp
@@
-9,35
+9,35
@@
(signal 2 (fn (x) (exit 0)))
(signal 15 (fn (x) (exit 0)))
(signal 2 (fn (x) (exit 0)))
(signal 15 (fn (x) (exit 0)))
+; Optionally print output to stderr and optionally exit with code
(define (die N)
(when (args) (write-line 2 (join (map string (args)) " ")))
(when (number? N) (exit N)))
(define (die N)
(when (args) (write-line 2 (join (map string (args)) " ")))
(when (number? N) (exit N)))
-(define (enlist X) (if (list? X) X (list X)))
+; Return non-nil for comment line (starts with # or is blank)
+(define (comment? LINE) (regex "^\\s*(#|$)" LINE 0))
-(define (comment? LINE) (and (regex "^\\s*(#|$)" LINE 0) true))
+; Return list of space-separated words on a line
+(define (words LINE)
+ (parse (trim LINE) "\\s+" 0))
-(define (first-word LINE) (and (regex "^\\s*(\\S+)" LINE 0) $1))
-
-(define (prog1 X) X)
-
-(define (read-config-line LINE)
- (map (fn (x) (if (regex "^([^=]+)=(.*)" x) (list $1 $2) x))
- (map trim (find-all "([^, ]+)" LINE $1 0))))
+; Read the configuration file and return it as list of plugs or the default
+(define (read-config FILE)
+ (or
+ (if (read-file FILE) (map words (clean comment? (parse $it "\n"))))
+ '(("plughw")) ; the default priority list
+ ))
;; ############################################################
;; Load Configuration (~/.alsa-dispatcher)
; Format: one-liners for each option, ignoring comment lines starting
; with # and blank lines.
(constant
;; ############################################################
;; Load Configuration (~/.alsa-dispatcher)
; Format: one-liners for each option, ignoring comment lines starting
; with # and blank lines.
(constant
- 'HOME (env "HOME")
- 'CONFIG (format "%s/.alsa-dispatcher" HOME)
- 'CFGLINES (if (read-file CONFIG) (clean comment? (parse $it "\n" ))
- '("bt,latency=1000" "plughw"))
- 'CFGMAP (map read-config-line CFGLINES)
- 'PCM-LIST (map first-word CFGLINES)
+ 'CFGMAP (read-config (format "%s/.alsa-dispatcher" (env "HOME")))
+ 'PCM-LIST (map first CFGMAP)
)
)
+; Return value of configuration setting KEY for plug PCM, or DEFAULT.
(define (cfg-lookup PCM KEY DEFAULT)
(if (if (assoc PCM CFGMAP) (lookup KEY $it)) (read-expr $it) DEFAULT))
(define (cfg-lookup PCM KEY DEFAULT)
(if (if (assoc PCM CFGMAP) (lookup KEY $it)) (read-expr $it) DEFAULT))
@@
-117,25
+117,22
@@
"long" ; snd_pcm_uframes_t size
)
"long" ; snd_pcm_uframes_t size
)
-;; Open a PCM by name
+;; Open a PCM by name
. Returns list of (NAME PCM) or nil.
(define (open-pcm NAME)
(define (open-pcm NAME)
- (snd_pcm_open NAME SND_PCM_STREAM_PLAYBACK SND_PCM_MODE_BLOCK))
+ (if (snd_pcm_open NAME SND_PCM_STREAM_PLAYBACK SND_PCM_MODE_BLOCK)
+ (list NAME $it)))
-;; Setup PCM
+;; Setup PCM. Preset format. access, channels, rate and soft resample.
+;; Configurable latency.
(define (setup-pcm PCM NAME)
(define (setup-pcm PCM NAME)
- (snd_pcm_set_params PCM
- (cfg-lookup NAME "format" SND_PCM_FORMAT_S16_LE)
- SND_PCM_ACCESS_RW_INTERLEAVED
- 2 ; channels
- 48000 ; rate
- 1 ; soft resample (0/1)
- (cfg-lookup NAME "latency" 100000) ; (microseconds)
- ))
+ (let ((LATENCY (cfg-lookup NAME "latency" 100000)))
+ (snd_pcm_set_params PCM SND_PCM_FORMAT_S16_LE SND_PCM_ACCESS_RW_INTERLEAVED
+ 2 48000 1 LATENCY )))
;; ############################################################
; The main program
;; ############################################################
; The main program
-;
; redirect stdout/err to /dev/null
+;
redirect stdout/err to /dev/null (flagged for debugging purposes)
(when true
(let ((REDIR (open "/dev/null" "append")))
(when (< REDIR) (exit 1))
(when true
(let ((REDIR (open "/dev/null" "append")))
(when (< REDIR) (exit 1))
@@
-145,27
+142,29
@@
))
; find the first usable PCM
))
; find the first usable PCM
-(
setf PCM (unless (dolist (N PCM-LIST (open-pcm (setf NAME N)
)))
- (die 1 "No PCM available")))
+(
map set '(NAME PCM) (unless (dolist (N PCM-LIST (open-pcm N
)))
+
(die 1 "No PCM available")))
; configure the PCM
(when (!= (setf E (setup-pcm PCM NAME)))
(snd_pcm_close PCM)
(die 1 "setup pcm" E))
; configure the PCM
(when (!= (setf E (setup-pcm PCM NAME)))
(snd_pcm_close PCM)
(die 1 "setup pcm" E))
-(setf N 0 x 0 E 0 i 0)
-
-
(while (> (or (setf N (read 0 BUFFER 1000000)) 0)
)
- (while (> N)
+; channel stdin audio onto selected pcm
+(while (> (or (setf N (read 0 BUFFER 2000000)) 0))
+
(while (> N
)
+ ; N is in bytes while snd_pcm_writei counts "frames" of 4 bytes
(when (< (setf E (snd_pcm_writei PCM BUFFER (/ N 4))))
(snd_pcm_close PCM)
(when (< (setf E (snd_pcm_writei PCM BUFFER (/ N 4))))
(snd_pcm_close PCM)
- (die 1 "writing
" E N
))
+ (die 1 "writing
failed"
))
(setf E (* E 4))
(setf BUFFER (E BUFFER))
(dec N E)
)
)
(setf E (* E 4))
(setf BUFFER (E BUFFER))
(dec N E)
)
)
+; let the pcm complete its output
(snd_pcm_drain PCM)
(snd_pcm_drain PCM)
+
(snd_pcm_close PCM)
(exit 0)
(snd_pcm_close PCM)
(exit 0)