blob: 2577af3875050dfc45e538e09024f49c29149744 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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
105
106
107
108
109
110
|
;;; greader.el --- gnamù reader, send buffer contents to a speech engine. -*- lexical-binding: t; -*-
;; FIXME: The above line is not right for this file :-(
;; Copyright (C) 2017-2023 Free Software Foundation, Inc.
;;; Code:
(defgroup greader-mac
nil
"Back-end of mac for greader."
:group 'greader
)
(defcustom greader-mac-voice nil
"Set the desired voice for the tts `say’.
nil means to use the system voice."
:tag "mac tts voice"
:type '(choice (const :tag "system voice" nil)
(string :tag "Specify")))
(defcustom greader-mac-rate 200
"Rate of tts expressed in words per minute."
:tag "Mac tts speech rate"
:type 'integer)
(defcustom greader-mac-executable-name "say"
"Name of the program that actually produces the voice."
:tag "mac tts command"
:type 'string)
(defvar greader-mac-end-of-sentence-regexp "[.?!,][«»\"]?[\n ]"
"A regexp that matches the end of the string to send to the tts.")
(defun greader-mac-set-rate (&optional rate)
"Return a string suitable for setting mac RATE."
(if (not rate)
(concat "-r" (number-to-string greader-mac-rate))
(progn
(setq-local greader-mac-rate rate)
(concat "-r" (number-to-string rate)))))
(defun greader-mac-set-voice (voice)
"Set specified VOICE for `say'.
When called interactively, this function reads a string from the minibuffer
providing completion."
(interactive
(list (read-string "Voice: " nil nil (greader--mac-get-voices))))
(when voice
(setq-local greader-mac-voice
(if (string-equal "system" voice) nil voice)))
(when greader-mac-voice (concat "-v" greader-mac-voice)))
;;;###autoload
(defun greader-mac (command &optional arg &rest _)
"Back-end main function of greader-mac.
COMMAND must be a string suitable for `make-process'."
(pcase command
;; ('get-text
;; (greader-mac-get-sentence))
;; ('next-text
;; (greader-mac-forward-sentence))
('executable
greader-mac-executable-name)
('lang
(greader-mac-set-voice arg))
('set-voice
(call-interactively 'greader-mac-set-voice))
('rate
(cond
((equal arg 'value)
greader-mac-rate)
(t
(greader-mac-set-rate arg))))
('punctuation
nil)
(_
'not-implemented)))
(put 'greader-mac 'greader-backend-name "greader-mac")
(defun greader-mac-get-sentence ()
(let ((sentence-start (point)))
(save-excursion
(greader-mac-forward-sentence)
(if (> (point) sentence-start)
(string-trim (buffer-substring-no-properties sentence-start (point)) "[ \t\n\r]+")
nil))))
(defun greader-mac-forward-sentence ()
(re-search-forward greader-mac-end-of-sentence-regexp nil 'move))
(defun greader--mac-get-voices ()
"Return a list which contains all voices suitable for this backend."
(with-temp-buffer
(call-process "say" nil t nil "-v" "?")
(goto-char (point-min))
(let ((lines (list "system")))
(while (not (eobp))
(let ((mymarker (make-marker)))
(search-forward "_")
(backward-word)
(re-search-backward "[^ ]")
(forward-char)
(set-marker mymarker (point))
(end-of-line)
(delete-region mymarker (point)))
(push (string-chop-newline (thing-at-point 'line)) lines)
(forward-line))
(reverse lines))))
(provide 'greader-mac)
|