blob: 30e2bdfe47cc0dddf1762341f421152839155581 (
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
|
;;; wasp-audio --- On-stream audio input and output -*- lexical-binding: t; -*-
;;; Commentary:
;;; Code:
(require 'wasp-utils)
(require 'wasp-ai)
(defcustom w/audio-play-process "wasp-audio-play"
"Name of process for playing audio with mpv."
:type '(string)
:group 'wasp)
(defcustom w/audio-record-process "wasp-audio-record"
"Name of process for transcribing speech using the Whisper API."
:type '(string)
:group 'wasp)
(defvar w/audio-record-process-current nil)
(defvar w/audio-keep-recording t)
(defvar w/audio-voice-commands nil)
(defvar w/last-stream-transcription "we're going down the rabbit hole")
(defun w/tts (msg)
"Use TTS to say MSG."
(start-process "wasp-tts" nil "say" (w/tempfile "wasp-tts" msg)))
(defun w/audio-play (clip &optional k volume)
"Play CLIP using mpv.
Call K when done.
If VOLUME is specified, use it to adjust the volume (100 is default)."
(make-process
:name w/audio-play-process
:buffer nil
:command
(list
"mpv" "--ao=alsa" "--no-video"
(format "--volume=%s" (or volume 100))
clip)
:sentinel
(lambda (_ _)
(when k
(funcall k)))))
(defun w/stop-all-audio ()
"Stop all audio by killing mpv processes."
(interactive)
(setq w/audio-muzak-queue nil)
(start-process "pkill" nil "pkill" "mpv")
(start-process "pkill" nil "pkill" "muzak"))
(defun w/recorded-chatter-name? (user)
"Return non-nil if we've recorded USER's name."
(f-exists?
(w/asset (s-concat "rats/users/" user ".wav"))))
(defun w/say-chatter-name (user &optional volume k)
"Pronounce USER's name in using mpv.
Call K when done.
If VOLUME is specified, use it :)."
(w/audio-play (w/asset (s-concat "rats/users/" user ".wav")) k volume))
(defun w/multipart-audio-helper (user rest &optional uservol clipvol)
"Player all of the files in REST intercalated with saying USER's name.
Adjust volumes by USERVOL and CLIPVOL."
(when (car rest)
(w/audio-play
(car rest)
(when (cdr rest)
(lambda ()
(w/say-chatter-name
user uservol
(lambda () (w/multipart-audio-helper user (cdr rest) uservol clipvol)))))
clipvol)))
(defun w/audio-rats-rats-we-are-the-rats (user)
"Rats rats we are the rats.
Celebrating yet another birthday bash.
USER it's your birthday today."
(let ((parts (--map (w/asset (format "rats/rats/rats%d.ogg" (+ it 1))) (-iota 3))))
(w/multipart-audio-helper user parts 120 100)))
(defun w/audio-rambling-sub-thanks (user)
"Say the thing about USER."
(let ((parts (--map (w/asset (format "rats/new/part%d.wav" it)) (-iota 5))))
(w/multipart-audio-helper user parts 120 150)))
(defun w/thank-sub (user)
"Thank USER for their subscription user a randomized thanking technique."
(let* ((thankers-named
'(w/audio-rats-rats-we-are-the-rats
w/audio-rambling-sub-thanks))
(thankers-unnamed
'((lambda (_) (w/audio-play (w/asset "rats/sam.wav") nil 90))
(lambda (_) (w/audio-play (w/asset "rats/tyumici.mp3") nil 150))
(lambda (_) (w/audio-play (w/asset "rats/abuffseagull.flac") nil 150))
(lambda (_) (w/audio-play (w/asset "rats/unrecorded.wav") nil 150))
))
(thanker
(w/pick-random
(-concat
(when (w/recorded-chatter-name? user)
thankers-named)
thankers-unnamed))))
(funcall thanker user)))
(defun w/audio-record-start ()
"Start recording audio to transcribe."
(let ((tmp (s-concat (make-temp-name "/tmp/wasp-record-audio") ".wav")))
(unless w/audio-record-process-current
(setq
w/audio-record-process-current
(make-process
:name w/audio-record-process
:buffer nil
:command (list "parecord" tmp)
:sentinel
(lambda (_ _)
(setq w/audio-record-process-current nil)
(w/ai-transcribe
tmp
(lambda (msg)
(w/daily-log (format "[VOICE]: %s" msg))
(setq w/last-stream-transcription msg)
(--each w/audio-voice-commands
(when (s-contains? (car it) (s-downcase msg))
(funcall (cdr it))))))
(when w/audio-keep-recording
(w/audio-record-start))))))))
(defun w/audio-record-end ()
"Stop recording audio to transcribe."
(when w/audio-record-process-current
(start-process "pkill" nil "pkill" "parecord")))
(defvar w/audio-record-end-timer nil)
(defun w/run-audio-record-end-timer ()
"Run the audio recording timer."
(when w/audio-record-end-timer
(cancel-timer w/audio-record-end-timer))
(w/audio-record-end)
(setq
w/audio-record-end-timer
(run-with-timer 10 nil #'w/run-audio-record-end-timer)))
(defun w/start-audio-record ()
"Start recording audio."
(interactive)
(setq w/audio-keep-recording t)
(w/audio-record-start))
(defun w/stop-audio-record ()
"Stop recording audio."
(interactive)
(setq w/audio-keep-recording nil)
(w/audio-record-end))
(defconst w/audio-muzak-path "/home/llll/src/muzak-rs/target/release/muzak")
(defvar w/audio-muzak-now-playing nil)
(defvar w/audio-muzak-queue nil)
(defun w/audio-muzak (user song)
"Play SONG by USER using muzak-rs courtesy The0x539."
(setq w/audio-muzak-now-playing (cons user song))
(w/pub '(avatar overlay muzak) (list (w/encode-string user)))
(let ((proc
(make-process
:name "wasp-muzak"
:connection-type '(pipe . pty)
:buffer " *wasp-muzak-log*"
:command (list w/audio-muzak-path "play")
:sentinel
(lambda (_ _)
(w/pub '(avatar overlay muzak clear) (list))
(setq w/audio-muzak-now-playing nil)))))
(process-send-string proc song)
(process-send-eof proc)))
(defun w/audio-muzak-enqueue (user song)
"Enqueue a play for SONG by USER."
(setq w/audio-muzak-queue (-concat w/audio-muzak-queue (list (cons user song)))))
(defun w/audio-muzak-update ()
"Keep playing songs from the queue if they exist."
(unless w/audio-muzak-now-playing
(when-let* ((entry (pop w/audio-muzak-queue)))
(w/audio-muzak (car entry) (cdr entry)))))
(defvar w/audio-muzak-timer nil)
(defun w/run-audio-muzak-timer ()
"Run the muzak timer."
(when w/audio-muzak-timer
(cancel-timer w/audio-muzak-timer))
(w/audio-muzak-update)
(setq
w/audio-muzak-timer
(run-with-timer 1 nil #'w/run-audio-muzak-timer)))
(w/run-audio-muzak-timer)
(provide 'wasp-audio)
;;; wasp-audio.el ends here
|