Minor string check to prevent unknown alsa card errors
[clfswm.git] / contrib / amixer.lisp
blob53d4aee272d9b111ee089121d949317b15f8fc7a
1 ;;; --------------------------------------------------------------------------
2 ;;; CLFSWM - FullScreen Window Manager
3 ;;;
4 ;;; --------------------------------------------------------------------------
5 ;;; Documentation: Volume mode
6 ;;; --------------------------------------------------------------------------
7 ;;;
8 ;;; (C) 2012 Desmond O. Chang <dochang@gmail.com>
9 ;;;
10 ;;; This program is free software; you can redistribute it and/or modify
11 ;;; it under the terms of the GNU General Public License as published by
12 ;;; the Free Software Foundation; either version 3 of the License, or
13 ;;; (at your option) any later version.
14 ;;;
15 ;;; This program is distributed in the hope that it will be useful,
16 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;;; GNU General Public License for more details.
19 ;;;
20 ;;; You should have received a copy of the GNU General Public License
21 ;;; along with this program; if not, write to the Free Software
22 ;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 ;;;
24 ;;; Documentation: A volume mode.
25 ;;; If you want to use this file, just add this line in
26 ;;; your configuration file:
27 ;;;
28 ;;; (load-contrib "volume-mode.lisp")
29 ;;; And with the alsa mixer:
30 ;;; (load-contrib "amixer.lisp")
31 ;;;
32 ;;; This mode is inspired by the emms volume package. When you change the
33 ;;; volume in main mode or second mode, clfswm will enter volume mode and
34 ;;; set a timer to leave this mode. Changing volume in volume mode will
35 ;;; reset the timer. You can also leave volume mode manually by return,
36 ;;; escape or control-g.
37 ;;;
38 ;;; Special variable *VOLUME-MODE-TIMEOUT* controls the timeout in
39 ;;; seconds. If it's positive, volume mode will exit when timeout occurs;
40 ;;; if it's 0, volume mode will exit right now; if it's negative, volume
41 ;;; will not exit even if timeout occurs. Default timeout is 3 seconds.
42 ;;;
43 ;;; Volume mode uses three special variables to control the mixer:
44 ;;; *VOLUME-MUTE-FUNCTION*, *VOLUME-LOWER-FUNCTION* and
45 ;;; *VOLUME-RAISE-FUNCTION*. Their values are functions which must accept
46 ;;; no arguments and return two values indicating the mixer state. The
47 ;;; first value is the volume ratio whose type must be (real 0 1). If the
48 ;;; mixer is mute, the second value should be true, otherwise it should be
49 ;;; false. If volume controller cannot get the mixer state, it must
50 ;;; return NIL.
51 ;;;
52 ;;; Volume mode shows a mute sign, a percentage and a ratio bar on the
53 ;;; screen. A plus sign '+' means it's unmute and a minus sign '-' means
54 ;;; it's mute now. If volume mode doesn't know the mixer state, a message
55 ;;; "unknown" will be shown.
56 ;;;
57 ;;; contrib/amixer.lisp shows how to use volume mode with alsa.
58 ;;;
59 ;;; --------------------------------------------------------------------------
61 (in-package :clfswm)
63 (format t "Loading amixer code... ")
65 (defvar *amixer-scontrol* "Master"
66 "Default control for amixer commands.")
68 (defun amixer-cmd (cmd scontrol &rest parameters)
69 (let* ((sed "sed 's/^.*\\[\\([[:digit:]]\\+\\)%\\].*\\[\\(on\\|off\\)\\].*$/\\1%\\2/'")
70 (fmt "amixer ~A ~A~{ ~A~} 2>/dev/null | tail -1 | ~A")
71 (shell (format nil fmt cmd scontrol parameters sed))
72 (line (read-line (do-shell shell) nil t)))
73 (when (stringp line)
74 (let* ((ratio (parse-integer line :junk-allowed t))
75 (%-pos (position #\% line)))
76 (values (and ratio (/ ratio 100))
77 (equal "off" (and %-pos (subseq line (1+ %-pos)))))))))
79 (defun amixer-sset (&rest parameters)
80 (apply 'amixer-cmd "sset" *amixer-scontrol* parameters))
82 (defparameter *volume-mute-function*
83 (lambda () (amixer-sset "toggle")))
85 (defparameter *volume-lower-function*
86 (lambda () (amixer-sset "5%-")))
88 (defparameter *volume-raise-function*
89 (lambda () (amixer-sset "5%+")))
91 (defun amixer-lower-1% ()
92 "Lower 1% volume."
93 (volume-set (lambda () (amixer-sset "1%-"))))
95 (defun amixer-raise-1% ()
96 "Raise 1% volume."
97 (volume-set (lambda () (amixer-sset "1%+"))))
99 (defun amixer-volume-bind ()
100 (define-volume-key ("less") 'amixer-lower-1%)
101 (define-volume-key ("greater") 'amixer-raise-1%)
102 (define-second-key ("less") 'amixer-lower-1%)
103 (define-second-key ("greater") 'amixer-raise-1%))
105 (add-hook *binding-hook* 'amixer-volume-bind)
107 (format t "done~%")