Blob


1 ;;; sndio.el --- Interact with sndio(8) -*- lexical-binding: t; -*-
3 ;; Copyright (C) 2020 Omar Polo
5 ;; Author: Omar Polo <op@omarpolo.com>
6 ;; Version: 1.0
7 ;; Keywords: multimedia
8 ;; URL: https://git.omarpolo.com/sndio.el
10 ;;; Commentary:
12 ;; This package provides the sndio major mode to interact with
13 ;; OpenBSD' sndio(8).
15 ;;; Code:
17 (eval-when-compile (require 'subr-x))
19 (defvar sndio-sndioctl-cmd "sndioctl"
20 "Path to the sndioctl executable.")
22 (defvar sndio-step 0.02
23 "Step for `sndio-increase' and `sndio-decrease'.")
25 (defvar sndio--window nil
26 "The sndio window.")
28 (defvar sndio-mode-map
29 (let ((m (make-sparse-keymap)))
30 (define-key m (kbd "n") #'forward-line)
31 (define-key m (kbd "p") #'previous-line)
32 (define-key m (kbd "i") #'sndio-increase)
33 (define-key m (kbd "d") #'sndio-decrease)
34 (define-key m (kbd "m") #'sndio-mute)
35 (define-key m (kbd "t") #'sndio-toggle)
36 (define-key m (kbd "g") #'sndio-update)
37 (define-key m (kbd "q") #'sndio-quit)
38 m)
39 "Keymap for sndio.")
41 (define-derived-mode sndio-mode special-mode "sndio"
42 "Major mode for sndio interaction."
43 (buffer-disable-undo)
44 (sndio-update))
46 (defun sndio-update ()
47 "Update the current sndio buffer."
48 (interactive)
49 (when (derived-mode-p 'sndio-mode)
50 (let ((inhibit-read-only t))
51 (erase-buffer)
52 (process-file sndio-sndioctl-cmd nil (current-buffer) nil)
53 (goto-char (point-min)))))
55 (defun sndio--run (&rest args)
56 "Run `sndio-sndioctl-cmd' with ARGS yielding its output."
57 (with-temp-buffer
58 (when (zerop (apply #'process-file sndio-sndioctl-cmd nil t nil args))
59 (buffer-string))))
61 (defun sndio--current-io ()
62 "Yield the input/poutput at point as string."
63 (when-let (end (save-excursion
64 (beginning-of-line)
65 (ignore-errors (search-forward "="))))
66 (buffer-substring-no-properties (line-beginning-position)
67 (1- end))))
69 (defun sndio--update-value (x)
70 "Update the value for the input/output at point setting it to X."
71 (save-excursion
72 (beginning-of-line)
73 (search-forward "=")
74 (let ((inhibit-read-only t))
75 (delete-region (point) (line-end-position))
76 (insert (string-trim-right x)))))
78 (defun sndio-increase ()
79 "Increase the volume for the input/output at point."
80 (interactive)
81 (when-let (x (sndio--current-io))
82 (when-let (val (sndio--run "-n" (concat x "=+" (number-to-string sndio-step))))
83 (sndio--update-value val))))
85 (defun sndio-decrease ()
86 "Decrease the volume for the input/output at point."
87 (interactive)
88 (when-let (x (sndio--current-io))
89 (when-let (val (sndio--run "-n" (concat x "=-" (number-to-string sndio-step))))
90 (sndio--update-value val))))
92 (defun sndio-mute ()
93 "Mute the input/output at point."
94 (interactive)
95 (when-let (x (sndio--current-io))
96 (when-let (val (sndio--run "-n" (concat x "=0")))
97 (sndio--update-value val))))
99 (defun sndio-toggle ()
100 "Toggle input/output at point."
101 (interactive)
102 (when-let (x (sndio--current-io))
103 (when-let (val (sndio--run "-n" (concat x "=!")))
104 (sndio--update-value val))))
106 (defun sndio-quit ()
107 "Quits sndio.
108 Call `delete-window' when the sndio popup window is open or
109 `quit-window' otherwise."
110 (interactive)
111 (if (window-live-p sndio--window)
112 (delete-window)
113 (quit-window)))
115 ;;;###autoload
116 (defun sndio ()
117 "Launch sndio."
118 (interactive)
119 (switch-to-buffer "*sndio*")
120 (sndio-mode))
122 (defun sndio-win-open ()
123 "Open an sndio window at the bottom of the frame for quick editing."
124 (interactive)
125 (unless (window-live-p sndio--window)
126 (setq sndio--window
127 (select-window
128 (let ((ignore-window-parameters t))
129 (split-window (frame-root-window)
130 -1
131 'below))
132 'norecord))
133 (switch-to-buffer (get-buffer-create "*sndio-quick*")
134 'norecord)
135 (if (derived-mode-p 'sndio-mode)
136 (sndio-update)
137 (sndio-mode))
138 (hl-line-mode +1)
139 (setq mode-line-format nil
140 header-line-format nil
141 tab-line-format nil)
142 (set-window-hscroll sndio--window 0)
143 (set-window-dedicated-p sndio--window t)
144 (select-window sndio--window 'norecord)
145 (let ((window-resize-pixelwise t)
146 (window-size-fixed))
147 (fit-window-to-buffer sndio--window nil nil 1))))
149 (provide 'sndio)
150 ;;; sndio.el ends here