| 1 | ;;; emms-volume.el --- Volume functions and a minor mode to adjust volume easily -*- lexical-binding: t; -*- |
| 2 | |
| 3 | ;; Copyright (C) 2006-2023, 2025 Free Software Foundation, Inc. |
| 4 | |
| 5 | ;; Author: Martin Schoenmakers <aiviru@diamond-age.net> |
| 6 | ;; Bruno Félix Rezende Ribeiro <oitofelix@gnu.org> |
| 7 | |
| 8 | ;; This file is part of EMMS. |
| 9 | |
| 10 | ;; EMMS 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, or (at your option) |
| 13 | ;; any later version. |
| 14 | ;; |
| 15 | ;; EMMS 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 EMMS; see the file COPYING. If not, write to the |
| 22 | ;; Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
| 23 | ;; Boston, MA 02110-1301, USA. |
| 24 | |
| 25 | ;;; Commentary: |
| 26 | ;; |
| 27 | ;; This file provides generally two things: |
| 28 | ;; Generic volume setting functions and some appropriate bindings for EMMS |
| 29 | ;; playlist buffers. These can also be bound to global keys,however, the |
| 30 | ;; second part may be more useful for this. This part provides functions |
| 31 | ;; meant to be bound to a global key (the author uses C-c e + and C-c e -), |
| 32 | ;; which then temporarily activates a minor mode allowing you to change the |
| 33 | ;; volume with just + and -. This mode deactivates a short (configurable) |
| 34 | ;; amount of time after the last volume change. This allows for easier volume |
| 35 | ;; adjustment without getting in the way. |
| 36 | |
| 37 | ;;; History: |
| 38 | |
| 39 | ;; May 2006: First stab at writing the minor mode. |
| 40 | ;; |
| 41 | ;; 30 May 2006: Cleanup and restructuring to fit with EMMS. |
| 42 | |
| 43 | ;;; Todo: |
| 44 | |
| 45 | ;; Some of this could benefit from adding customize interfaces. |
| 46 | |
| 47 | ;;; Code: |
| 48 | |
| 49 | |
| 50 | (require 'emms) |
| 51 | (require 'emms-playlist-mode) |
| 52 | (require 'emms-volume-amixer) |
| 53 | (require 'emms-volume-pulse) |
| 54 | (require 'emms-volume-mixerctl) |
| 55 | (require 'emms-volume-sndioctl) |
| 56 | (require 'emms-volume-mpv) |
| 57 | |
| 58 | ;; Customize group |
| 59 | (defgroup emms-volume nil |
| 60 | "Volume setting for EMMS." |
| 61 | :group 'emms) |
| 62 | |
| 63 | (defcustom emms-volume-change-function |
| 64 | (cond |
| 65 | ;; check for sndioctl first to avoid picking up mixerctl or pactl |
| 66 | ;; on OpenBSD. |
| 67 | ((executable-find "sndioctl") #'emms-volume-sndioctl-change) |
| 68 | ((executable-find "amixer") #'emms-volume-amixer-change) |
| 69 | ((executable-find "pactl") #'emms-volume-pulse-change) |
| 70 | ((executable-find "mixerctl") #'emms-volume-mixerctl-change) |
| 71 | (t #'(lambda (_amount) (user-error "%s" "No supported mixer found. Please, define ‘emms-volume-change-function’.")))) |
| 72 | "The function to use to change the volume. |
| 73 | If you have your own functions for changing volume, set this." |
| 74 | :type '(choice (const :tag "Amixer" emms-volume-amixer-change) |
| 75 | (const :tag "MPD" emms-volume-mpd-change) |
| 76 | (const :tag "mpv" emms-volume-mpv-change) |
| 77 | (const :tag "PulseAudio" emms-volume-pulse-change) |
| 78 | (const :tag "Mixerctl" emms-volume-mixerctl-change) |
| 79 | (const :tag "Sndioctl" emms-volume-sndioctl-change) |
| 80 | (function :tag "Lisp function"))) |
| 81 | |
| 82 | (defcustom emms-volume-change-amount 2 |
| 83 | "The amount to use when raising or lowering the volume using the |
| 84 | emms-volume interface. |
| 85 | |
| 86 | This should be a positive integer." |
| 87 | :type 'integer) |
| 88 | |
| 89 | (defun emms-volume-select-get-function () |
| 90 | "Return the corresponding get function." |
| 91 | (cond ((not emms-volume-change-function) |
| 92 | (error "`emms-volume-change-function' is not set")) |
| 93 | ((eq emms-volume-change-function #'emms-volume-amixer-change) |
| 94 | #'emms-volume-amixer-get) |
| 95 | ((eq emms-volume-change-function #'emms-volume-pulse-change) |
| 96 | #'emms-volume-pulse-get) |
| 97 | (t (error "could not find corresponding volume getter function for %s" |
| 98 | emms-volume-change-function)))) |
| 99 | |
| 100 | (defun emms-volume-get () |
| 101 | "Return the volume as an integer in the range [0-100]." |
| 102 | (funcall (emms-volume-select-get-function))) |
| 103 | |
| 104 | ;;;###autoload |
| 105 | (defun emms-volume-raise () |
| 106 | "Raise the volume." |
| 107 | (interactive) |
| 108 | (funcall emms-volume-change-function emms-volume-change-amount)) |
| 109 | |
| 110 | ;;;###autoload |
| 111 | (defun emms-volume-lower () |
| 112 | "Lower the volume." |
| 113 | (interactive) |
| 114 | (funcall emms-volume-change-function (- emms-volume-change-amount))) |
| 115 | |
| 116 | (define-key emms-playlist-mode-map (kbd "+") #'emms-volume-raise) |
| 117 | (define-key emms-playlist-mode-map (kbd "-") #'emms-volume-lower) |
| 118 | |
| 119 | ;; Code specific to the minor mode. |
| 120 | (define-minor-mode emms-volume-minor-mode |
| 121 | "Allows volume setting with + and - after an initial key combo." |
| 122 | :global t |
| 123 | :init-value nil |
| 124 | :lighter " (+/-)" |
| 125 | :keymap '(("+" . emms-volume-mode-plus) |
| 126 | ("-" . emms-volume-mode-minus))) |
| 127 | |
| 128 | (defvar emms-volume-mode-timeout 2 |
| 129 | "*The timeout in amount of seconds used by `emms-volume-minor-mode'.") |
| 130 | |
| 131 | (defvar emms-volume-mode-timer nil |
| 132 | "The timer `emms-volume-minor-mode' uses.") |
| 133 | |
| 134 | ;;;###autoload |
| 135 | (defun emms-volume-mode-plus () |
| 136 | "Raise volume and enable or extend the `emms-volume-minor-mode' timeout." |
| 137 | (interactive) |
| 138 | (emms-volume-raise) |
| 139 | (emms-volume-mode-start-or-extend)) |
| 140 | |
| 141 | ;;;###autoload |
| 142 | (defun emms-volume-mode-minus () |
| 143 | "Lower volume and enable or extend the `emms-volume-minor-mode' timeout." |
| 144 | (interactive) |
| 145 | (emms-volume-lower) |
| 146 | (emms-volume-mode-start-or-extend)) |
| 147 | |
| 148 | (defun emms-volume-mode-disable-timer () |
| 149 | "Disable `emms-volume-minor-mode' timer." |
| 150 | (cancel-timer emms-volume-mode-timer) |
| 151 | (setq emms-volume-mode-timer nil)) |
| 152 | |
| 153 | (defun emms-volume-mode-set-timer () |
| 154 | "Set a new `emms-volume-minor-mode' timer." |
| 155 | (when emms-volume-mode-timer |
| 156 | (emms-volume-mode-disable-timer)) |
| 157 | (setq emms-volume-mode-timer (run-at-time emms-volume-mode-timeout |
| 158 | nil |
| 159 | #'emms-volume-mode-timer-timeout))) |
| 160 | |
| 161 | (defun emms-volume-mode-timer-timeout () |
| 162 | "Function to disable `emms-volume-minor-mode' at timeout." |
| 163 | (setq emms-volume-mode-timer nil) |
| 164 | (emms-volume-minor-mode -1)) |
| 165 | |
| 166 | (defun emms-volume-mode-start-or-extend () |
| 167 | "Start `emms-volume-minor-mode' or extend its running time." |
| 168 | (when (null emms-volume-minor-mode) |
| 169 | (emms-volume-minor-mode 1)) |
| 170 | (emms-volume-mode-set-timer)) |
| 171 | |
| 172 | (provide 'emms-volume) |
| 173 | ;;; emms-volume.el ends here |