Blob


1 ;;; sndio.el --- Interact with sndio(8) -*- lexical-binding: t; -*-
3 ;; Copyright (C) 2020, 2021 Omar Polo
5 ;; Author: Omar Polo <op@omarpolo.com>
6 ;; Version: 1.0
7 ;; Keywords: multimedia
8 ;; URL: https://git.omarpolo.com/sndio.el
9 ;; Package-Requires: ((emacs "25.1"))
11 ;; This program is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation, either version 3 of the License, or
14 ;; (at your option) any later version.
16 ;; This program is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with this program. If not, see <https://www.gnu.org/licenses/>.
24 ;;; Commentary:
26 ;; This package provides the sndio major mode to interact with
27 ;; OpenBSD' sndio(8).
29 ;;; Code:
31 (eval-when-compile (require 'subr-x))
33 (defvar sndio-sndioctl-cmd "sndioctl"
34 "Path to the sndioctl executable.")
36 (defvar sndio-step 0.02
37 "Step for `sndio-increase' and `sndio-decrease'.")
39 (defvar sndio--window nil
40 "The sndio window.")
42 (defvar sndio-mode-map
43 (let ((m (make-sparse-keymap)))
44 (define-key m (kbd "n") #'forward-line)
45 (define-key m (kbd "p") #'previous-line)
46 (define-key m (kbd "i") #'sndio-increase)
47 (define-key m (kbd "d") #'sndio-decrease)
48 (define-key m (kbd "m") #'sndio-mute)
49 (define-key m (kbd "t") #'sndio-toggle)
50 (define-key m (kbd "g") #'sndio-update)
51 (define-key m (kbd "q") #'sndio-quit)
52 m)
53 "Keymap for sndio.")
55 (define-derived-mode sndio-mode special-mode "sndio"
56 "Major mode for sndio interaction."
57 (buffer-disable-undo)
58 (sndio-update))
60 (defun sndio-update ()
61 "Update the current sndio buffer."
62 (interactive)
63 (when (derived-mode-p 'sndio-mode)
64 (let ((inhibit-read-only t))
65 (erase-buffer)
66 (process-file sndio-sndioctl-cmd nil (current-buffer) nil)
67 (goto-char (point-min)))))
69 (defun sndio--run (&rest args)
70 "Run `sndio-sndioctl-cmd' with ARGS yielding its output."
71 (with-temp-buffer
72 (when (zerop (apply #'process-file sndio-sndioctl-cmd nil t nil args))
73 (buffer-string))))
75 (defun sndio--current-io ()
76 "Yield the input/poutput at point as string."
77 (when-let (end (save-excursion
78 (beginning-of-line)
79 (ignore-errors (search-forward "="))))
80 (buffer-substring-no-properties (line-beginning-position)
81 (1- end))))
83 (defun sndio--update-value (x)
84 "Update the value for the input/output at point setting it to X."
85 (save-excursion
86 (beginning-of-line)
87 (search-forward "=")
88 (let ((inhibit-read-only t))
89 (delete-region (point) (line-end-position))
90 (insert (string-trim-right x)))))
92 (defun sndio-increase ()
93 "Increase the volume for the input/output at point."
94 (interactive)
95 (when-let (x (sndio--current-io))
96 (when-let (val (sndio--run "-n" (concat x "=+" (number-to-string sndio-step))))
97 (sndio--update-value val))))
99 (defun sndio-decrease ()
100 "Decrease the volume for the input/output at point."
101 (interactive)
102 (when-let (x (sndio--current-io))
103 (when-let (val (sndio--run "-n" (concat x "=-" (number-to-string sndio-step))))
104 (sndio--update-value val))))
106 (defun sndio-mute ()
107 "Mute the input/output at point."
108 (interactive)
109 (when-let (x (sndio--current-io))
110 (when-let (val (sndio--run "-n" (concat x "=0")))
111 (sndio--update-value val))))
113 (defun sndio-toggle ()
114 "Toggle input/output at point."
115 (interactive)
116 (when-let (x (sndio--current-io))
117 (when-let (val (sndio--run "-n" (concat x "=!")))
118 (sndio--update-value val))))
120 (defun sndio-quit ()
121 "Quits sndio.
122 Call `delete-window' when the sndio popup window is open or
123 `quit-window' otherwise."
124 (interactive)
125 (if (window-live-p sndio--window)
126 (delete-window)
127 (quit-window)))
129 ;;;###autoload
130 (defun sndio ()
131 "Launch sndio."
132 (interactive)
133 (switch-to-buffer "*sndio*")
134 (sndio-mode))
136 ;;;###autoload
137 (defun sndio-win-open ()
138 "Open an sndio window at the bottom of the frame for quick editing."
139 (interactive)
140 (unless (window-live-p sndio--window)
141 (setq sndio--window
142 (select-window
143 (let ((ignore-window-parameters t))
144 (split-window (frame-root-window)
145 -1
146 'below))
147 'norecord))
148 (switch-to-buffer (get-buffer-create "*sndio-quick*")
149 'norecord)
150 (if (derived-mode-p 'sndio-mode)
151 (sndio-update)
152 (sndio-mode))
153 (hl-line-mode +1)
154 (setq mode-line-format nil
155 header-line-format nil
156 tab-line-format nil)
157 (set-window-hscroll sndio--window 0)
158 (set-window-dedicated-p sndio--window t)
159 (select-window sndio--window 'norecord)
160 (let ((window-resize-pixelwise t)
161 (window-size-fixed))
162 (fit-window-to-buffer sndio--window nil nil 1))))
164 (provide 'sndio)
165 ;;; sndio.el ends here