| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
(defvar mw32-mci-notify-callback-alist nil) |
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
(defun mw32-mci-add-notify-callback (device-id callback-func |
|---|
| 10 |
&optional callback-arg) |
|---|
| 11 |
"Add a callback function when a notify event rises." |
|---|
| 12 |
(setq mw32-mci-notify-callback-alist |
|---|
| 13 |
(cons (list device-id callback-func callback-arg) |
|---|
| 14 |
mw32-mci-notify-callback-alist))) |
|---|
| 15 |
|
|---|
| 16 |
|
|---|
| 17 |
(defun mw32-mci-remove-notify-callback (device-id callback-func) |
|---|
| 18 |
"Remove a callback function." |
|---|
| 19 |
(let ((elem (assoc device-id mw32-mci-notify-callback-alist))) |
|---|
| 20 |
(while elem |
|---|
| 21 |
(let ((func (nth 1 elem))) |
|---|
| 22 |
(when (eq func callback-func) |
|---|
| 23 |
(setq mw32-mci-notify-callback-alist |
|---|
| 24 |
(delq elem mw32-mci-notify-callback-alist))) |
|---|
| 25 |
(setq elem (assoc device-id mw32-mci-notify-callback-alist)))))) |
|---|
| 26 |
|
|---|
| 27 |
|
|---|
| 28 |
(defun mw32-mci-notify-event-handler (device-id exit-state) |
|---|
| 29 |
(let ((elem (assoc device-id mw32-mci-notify-callback-alist)) |
|---|
| 30 |
target-alist) |
|---|
| 31 |
(while elem |
|---|
| 32 |
(setq target-alist (cons elem target-alist)) |
|---|
| 33 |
(setq mw32-mci-notify-callback-alist |
|---|
| 34 |
(delq elem mw32-mci-notify-callback-alist)) |
|---|
| 35 |
(setq elem (assoc device-id mw32-mci-notify-callback-alist))) |
|---|
| 36 |
(setq elem (car target-alist)) |
|---|
| 37 |
(while elem |
|---|
| 38 |
(let ((func (nth 1 elem)) |
|---|
| 39 |
(arg (nth 2 elem))) |
|---|
| 40 |
(funcall func device-id exit-state arg) |
|---|
| 41 |
(setq target-alist (cdr target-alist)) |
|---|
| 42 |
(setq elem (car target-alist)))))) |
|---|
| 43 |
|
|---|
| 44 |
|
|---|
| 45 |
(defun mw32-mci-handle-event (event) |
|---|
| 46 |
(interactive "e") |
|---|
| 47 |
(let ((event-type (nth 1 event)) |
|---|
| 48 |
(device-id (nth 2 event)) |
|---|
| 49 |
(event-arg (nth 3 event))) |
|---|
| 50 |
(cond |
|---|
| 51 |
((eq event-type 'mw32-mci-notify) |
|---|
| 52 |
(mw32-mci-notify-event-handler device-id event-arg))))) |
|---|
| 53 |
|
|---|
| 54 |
|
|---|
| 55 |
|
|---|
| 56 |
(define-key special-event-map [mw32-mci] 'mw32-mci-handle-event) |
|---|
| 57 |
|
|---|
| 58 |
|
|---|
| 59 |
(defun mw32-mci-notify-func (device-id exit-state &optional arg) |
|---|
| 60 |
(cond |
|---|
| 61 |
((eq exit-state 'mw32-mci-notify-successful) |
|---|
| 62 |
(let (device-name tmp-file) |
|---|
| 63 |
(cond |
|---|
| 64 |
((stringp arg) |
|---|
| 65 |
(setq device-name arg)) |
|---|
| 66 |
((listp arg) |
|---|
| 67 |
(setq device-name (nth 0 arg)) |
|---|
| 68 |
(setq tmp-file (nth 1 arg)))) |
|---|
| 69 |
(when (stringp device-name) |
|---|
| 70 |
(mw32-mci-send-string (format "close %s" device-name))) |
|---|
| 71 |
(when (and (stringp tmp-file) |
|---|
| 72 |
(file-writable-p tmp-file)) |
|---|
| 73 |
(delete-file tmp-file)))) |
|---|
| 74 |
(t |
|---|
| 75 |
(error "abnormal termination")))) |
|---|
| 76 |
|
|---|
| 77 |
|
|---|
| 78 |
|
|---|
| 79 |
|
|---|
| 80 |
|
|---|
| 81 |
|
|---|
| 82 |
|
|---|
| 83 |
|
|---|
| 84 |
|
|---|
| 85 |
|
|---|
| 86 |
|
|---|
| 87 |
|
|---|
| 88 |
|
|---|
| 89 |
|
|---|
| 90 |
|
|---|
| 91 |
|
|---|
| 92 |
|
|---|
| 93 |
|
|---|
| 94 |
|
|---|
| 95 |
|
|---|
| 96 |
|
|---|
| 97 |
|
|---|
| 98 |
|
|---|
| 99 |
|
|---|
| 100 |
|
|---|
| 101 |
|
|---|
| 102 |
|
|---|
| 103 |
|
|---|
| 104 |
(defun parse-sound (sound) |
|---|
| 105 |
(catch 'invalid |
|---|
| 106 |
(progn |
|---|
| 107 |
|
|---|
| 108 |
(unless (and (consp sound) |
|---|
| 109 |
(eq (car sound) 'sound)) |
|---|
| 110 |
(throw 'invalid nil)) |
|---|
| 111 |
(setq sound (cdr sound)) |
|---|
| 112 |
(let ((file (plist-get sound :file)) |
|---|
| 113 |
(data (plist-get sound :data)) |
|---|
| 114 |
(device (plist-get sound :device)) |
|---|
| 115 |
(volume (plist-get sound :volume))) |
|---|
| 116 |
|
|---|
| 117 |
|
|---|
| 118 |
(unless (or (stringp file) |
|---|
| 119 |
(stringp data)) |
|---|
| 120 |
(throw 'invalid nil)) |
|---|
| 121 |
|
|---|
| 122 |
|
|---|
| 123 |
(when volume |
|---|
| 124 |
(cond |
|---|
| 125 |
((integerp volume) |
|---|
| 126 |
(if (or (< volume 0) |
|---|
| 127 |
(> volume 100)) |
|---|
| 128 |
(throw 'invalid nil))) |
|---|
| 129 |
((floatp volume) |
|---|
| 130 |
(if (or (< volume 0.0) |
|---|
| 131 |
(> volume 1.0)) |
|---|
| 132 |
(throw 'invalid nil))) |
|---|
| 133 |
(t |
|---|
| 134 |
(throw 'invalid nil)))) |
|---|
| 135 |
|
|---|
| 136 |
|
|---|
| 137 |
(when (and device |
|---|
| 138 |
(not (stringp device))) |
|---|
| 139 |
(throw 'invalid nil)))) |
|---|
| 140 |
t)) |
|---|
| 141 |
|
|---|
| 142 |
|
|---|
| 143 |
(defun play-sound (sound) |
|---|
| 144 |
"Play sound SOUND.\n\ |
|---|
| 145 |
SOUND is a list of the form `(sound KEYWORD VALUE...)'.\n\ |
|---|
| 146 |
The following keywords are recognized:\n\ |
|---|
| 147 |
\n\ |
|---|
| 148 |
:file FILE.- read sound data from FILE. If FILE isn't an\n\ |
|---|
| 149 |
absolute file name, it is searched in `data-directory'.\n\ |
|---|
| 150 |
\n\ |
|---|
| 151 |
:data DATA - read sound data from string DATA.\n\ |
|---|
| 152 |
\n\ |
|---|
| 153 |
Exactly one of :file or :data must be present.\n\ |
|---|
| 154 |
\n\ |
|---|
| 155 |
:volume VOL - set volume to VOL. VOL must an integer in the\n\ |
|---|
| 156 |
range 0..100 or a float in the range 0..1.0. If not specified,\n\ |
|---|
| 157 |
don't change the volume setting of the sound device.\n\ |
|---|
| 158 |
\n\ |
|---|
| 159 |
:device DEVICE - play sound on DEVICE. If not specified,\n\ |
|---|
| 160 |
a system-dependent default device name is used." |
|---|
| 161 |
|
|---|
| 162 |
(when (null (parse-sound sound)) |
|---|
| 163 |
(error "Invalid sound specification")) |
|---|
| 164 |
|
|---|
| 165 |
(setq sound (cdr sound)) |
|---|
| 166 |
(let ((file (plist-get sound :file)) |
|---|
| 167 |
(data (plist-get sound :data)) |
|---|
| 168 |
(device (plist-get sound :device)) |
|---|
| 169 |
(volume (plist-get sound :volume)) |
|---|
| 170 |
(device-name (make-temp-name "waveaudio")) |
|---|
| 171 |
tmp-file arg) |
|---|
| 172 |
(if (stringp file) |
|---|
| 173 |
(progn |
|---|
| 174 |
(setq file (expand-file-name file data-directory)) |
|---|
| 175 |
(setq arg device-name)) |
|---|
| 176 |
(setq tmp-file (make-temp-file "waveaudio")) |
|---|
| 177 |
(setq file (concat tmp-file ".wav")) |
|---|
| 178 |
(rename-file tmp-file file) |
|---|
| 179 |
(if (file-writable-p file) |
|---|
| 180 |
(with-temp-buffer |
|---|
| 181 |
(let ((coding-system-for-write 'binary)) |
|---|
| 182 |
(set-buffer-multibyte nil) |
|---|
| 183 |
(princ data (current-buffer)) |
|---|
| 184 |
(write-file file))) |
|---|
| 185 |
(error (format "cannot open %s" file))) |
|---|
| 186 |
(setq arg (list device-name file))) |
|---|
| 187 |
(let (result device-id) |
|---|
| 188 |
(setq result |
|---|
| 189 |
(mw32-mci-send-string (format "open \"%s\" alias %s" |
|---|
| 190 |
file device-name))) |
|---|
| 191 |
(when (numberp result) |
|---|
| 192 |
(error (format "cannot open %s!" file))) |
|---|
| 193 |
(setq device-id (string-to-number result)) |
|---|
| 194 |
(mw32-mci-send-string (format "play %s notify" device-name)) |
|---|
| 195 |
(mw32-mci-add-notify-callback device-id 'mw32-mci-notify-func arg)) |
|---|
| 196 |
|
|---|
| 197 |
) |
|---|
| 198 |
t) |
|---|