fordon_greeman / voidfiles

Branch: main
Switch branches/tags
main
theidioticdev add emacs 2079ec5 1d ago
128 lines · 4.4 KB Raw Blame History
1 ;;; emms-volume-pulse.el --- a mode for changing volume using PulseAudio pactl -*- lexical-binding: t; -*-
2
3 ;; Copyright (C) 2015-2023 Free Software Foundation, Inc.
4
5 ;; Author: Rasmus Pank Roulund <emacs@pank.eu>
6
7 ;; This file is part of EMMS.
8
9 ;; EMMS is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 3, or (at your option)
12 ;; any later version.
13 ;;
14 ;; EMMS is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
18 ;;
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with EMMS; see the file COPYING. If not, write to the
21 ;; Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 ;; Boston, MA 02110-1301, USA.
23
24 ;;; Commentary:
25
26 ;; This file defines a few simple functions to raise or lower the volume
27 ;; using pactl. It can be used stand-alone, though it's meant for usage
28 ;; with EMMS, particularly with emms-volume.el.
29 ;;
30 ;; To use add the following to your EMMS configuration
31 ;; (setq emms-volume-change-function 'emms-volume-pulse-change)
32
33 ;;; History:
34
35 ;; Marts 2015: First release. Partly based on emms-volume-amixer.el
36
37 ;;; Todo:
38
39 ;; There probably needs to be more configurability, which may in turn
40 ;; mean adding some more functions.
41 ;; Some of this could benefit from adding customize interfaces.
42
43 ;;; Code:
44
45 (require 'cl-lib)
46 (require 'subr-x)
47
48 ;; TODO: it would be great if custom could have
49 ;; choices based on pactl list short sinks | cut -f1-2
50
51 (defcustom emms-volume-pulse-sink nil
52 "The sink to use for volume adjustment.
53
54 If nil try to use the default sink.
55
56 See full list of devices on your system by running
57 pactl list short sinks"
58 :type '(choice (number :tag "Sink number")
59 (string :tag "Sink symbolic name")
60 (const :tag "Default sink" nil))
61 :group 'emms-volume)
62
63 ;; 'pactl get-sink-volume' was only added recently (version 14.1).
64 ;; When that version is more widespread this function can be
65 ;; simplified
66 (defun emms-volume--pulse-get-volume ()
67 "Return `emms-volume-pulse-sink' volume."
68 (let* ((emms-volume-pulse-sink
69 (if emms-volume-pulse-sink
70 emms-volume-pulse-sink
71 (string-trim
72 (shell-command-to-string
73 "LC_ALL=C pactl info | grep 'Default Sink: ' | cut -d ' ' -f3-"))))
74 (sink-number-p (numberp emms-volume-pulse-sink))
75 (output
76 (shell-command-to-string
77 (concat "LC_ALL=C pactl list sinks" "|"
78 "grep -E -e 'Sink' -e 'Name' -e '^[^a-zA-Z]*Volume'")))
79 (volume-string
80 (car
81 (reverse
82 (funcall
83 (if sink-number-p #'assq #'assoc)
84 emms-volume-pulse-sink
85 (mapcar (if sink-number-p 'identity 'cdr)
86 (cl-loop while
87 (string-match
88 (mapconcat #'identity
89 '(".*Sink[ \t]+\\#\\([0-9]+\\)"
90 ".*Name:[ \t]\\([^\n]+\\)"
91 ".*Volume:.*?\\([0-9]+\\)%.*\n?")
92 "\n")
93 output)
94 collect (list (string-to-number (match-string 1 output))
95 (match-string 2 output)
96 (match-string 3 output))
97 do (setq output (replace-match "" nil nil output)))))))))
98 (if volume-string
99 (string-to-number volume-string)
100 (error "cannot get volume from sink, check `emms-volume-pulse-sink'"))))
101
102 (defun emms-volume-pulse-limit (v)
103 "Limit V to the range [0-100]"
104 (max (min v 100) 0))
105
106 (defun emms-volume-pulse-get ()
107 "Return the pulse volume."
108 (emms-volume-pulse-limit
109 (emms-volume--pulse-get-volume)))
110
111 ;;;###autoload
112 (defun emms-volume-pulse-change (amount)
113 "Change PulseAudio volume by AMOUNT."
114 (message "Volume is %s%%"
115 (let ((pactl (or (executable-find "pactl")
116 (error "pactl is not in PATH")))
117 (next-vol (emms-volume-pulse-limit
118 (+ (emms-volume--pulse-get-volume) amount))))
119 (when (zerop (call-process
120 pactl nil nil nil
121 "set-sink-volume"
122 (or emms-volume-pulse-sink "@DEFAULT_SINK@")
123 (format "%d%%" next-vol)))
124 next-vol))))
125
126 (provide 'emms-volume-pulse)
127
128 ;;; emms-volume-pulse.el ends here