123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- #!@GUILE@
- !#
- ;;; sound.scm --- Display OSD with sound volume
- ;; Copyright © 2016 Alex Kost <alezost@gmail.com>
- ;; This program is free software; you can redistribute it and/or modify
- ;; it under the terms of the GNU General Public License as published by
- ;; the Free Software Foundation, either version 3 of the License, or
- ;; (at your option) any later version.
- ;;
- ;; This program is distributed in the hope that it will be useful,
- ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ;; GNU General Public License for more details.
- ;;
- ;; You should have received a copy of the GNU General Public License
- ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
- ;;; Commentary:
- ;; This is a simple example showing how Guile-XOSD can be used to
- ;; display sound volume by getting info from 'amixer' output.
- ;;
- ;; This script passes all its arguments to 'amixer' and parses its
- ;; output by searching a line like this:
- ;;
- ;; ... Playback 39118 [60%] [on]
- ;;
- ;; or this:
- ;;
- ;; ... Playback 32 [50%] [-32.00dB] [off]
- ;;
- ;; Examples of using:
- ;;
- ;; sound.scm sget Master
- ;; sound.scm sset Master toggle
- ;; sound.scm sset Master 40%
- ;;
- ;; See 'man amixer' for more info. Note: 'amixer' is a program from
- ;; 'alsa-utils' package (or whatever it is called by your distribution):
- ;; <http://www.alsa-project.org/>.
- ;; Actually, this is not a real world example. It has 2 downsides:
- ;;
- ;; 1. At first, well, it's not a compiled C program, it's just a Guile
- ;; script, so it is not super-fast :-)
- ;;
- ;; 2. This script exits only after the sound OSD disappears (the timeout
- ;; is set to 3 seconds), so, for example, if you bind "sound.scm sset
- ;; Master 3%+" to some key in your window manager, you'll not be very
- ;; happy if you quickly press this key several times: the sound will be
- ;; increased properly (by 3% each time) but you'll see several OSDs
- ;; laying on each other, as another "sound.scm" script will be called
- ;; when the previous one(s) is(are) still alive.
- ;;
- ;; In practice I use the following solution, that allows me to overcome
- ;; both downsides: I start Guile-Daemon with the config that sets all
- ;; this "sound OSD" stuff, and then I just send small Guile expressions
- ;; to the Daemon for evaluating. As you can see, I'm still using Guile
- ;; to set the sound and to display OSD, but it is *very fast* and it's
- ;; the same OSD object every time!
- ;;
- ;; Guile-Daemon: <https://github.com/alezost/guile-daemon>
- ;; My config for Guile-Daemon: <https://github.com/alezost/guile-daemon-config>
- ;;; Code:
- (use-modules
- (ice-9 format)
- (ice-9 match)
- (ice-9 popen)
- (ice-9 rdelim)
- (ice-9 regex)
- (srfi srfi-11)
- (xosd))
- (define %color-muted "#E74F35")
- (define %color-unmuted "#23B13E")
- (define %color-error "orange")
- (define %osd
- (make-osd #:lines 2
- #:timeout 3
- #:position 'bottom
- #:align 'center
- #:font "-*-dejavu sans-bold-r-normal-*-*-300-*-*-p-*-*-1"
- #:shadow-offset 2))
- (define* (display-sound osd #:key volume mute?)
- (set-osd-color! osd (if mute? %color-muted %color-unmuted))
- (display-string-in-osd osd (format #f "Volume: ~d%" volume))
- (display-percentage-in-osd osd volume 1))
- (define (display-error osd)
- (set-osd-color! osd %color-error)
- (display-string-in-osd osd "")
- (display-string-in-osd osd "Oops, can't parse amixer output :-)" 1))
- (define (call-amixer . args)
- "Call 'amixer' with ARGS and return its output."
- (let* ((port (apply open-pipe* OPEN_READ "amixer" args))
- (out (read-string port)))
- (close-pipe port)
- out))
- (define (parse-amixer-output output)
- "Parse 'amixer' OUTPUT and return 2 values: sound volume (a number
- from 0 to 100) and a boolean value showing if the sound is
- muted/unmuted. Volume is #f if OUTPUT cannot be parsed."
- (let* ((rx (make-regexp
- "Playback [0-9]+ \\[([0-9]+)%\\].* \\[(on|off)\\]"))
- (res (regexp-exec rx output)))
- (if res
- (values (string->number (match:substring res 1))
- (string=? "off" (match:substring res 2)))
- (values #f #f))))
- (define (show-help)
- (format #t "Usage: ~a AMIXER-ARGS ...
- Run 'amixer AMIXER-ARGS ...', parse its output, and display OSD with the
- current sound volume.\n"
- (car (command-line))))
- (define (main args)
- (match (cdr args)
- (((or "-h" "--help" "help") _ ...)
- (show-help))
- ((amixer-args ...)
- (let-values (((volume mute?)
- (parse-amixer-output
- (apply call-amixer amixer-args))))
- (if volume
- (display-sound %osd #:volume volume #:mute? mute?)
- (display-error %osd))
- (wait-while-osd-displayed %osd)))
- (_ (show-help))))
- (when (batch-mode?)
- (main (command-line)))
- ;;; sound.scm ends here
|