Eclectic Media Git rhapsode / 671fa2a
Improve fallbacks for missing markers. Adrian Cochrane 6 months ago
2 changed file(s) with 39 addition(s) and 13 deletion(s). Raw diff Collapse all Expand all
0 {-# LANGUAGE OverloadedStrings #-}
01 module CExports where
12
23 import Types
45
56 import Render (c_renderDoc)
67 import Links (c_extractLinks)
8 import qualified Text.XML as XML
9 import qualified Data.Text as Txt
10 import qualified Data.Text.Lazy as Txt (fromStrict)
11 import qualified Data.Map as M
712
813 -- Types I can export to C
914 import Foreign.StablePtr
4146 nil <- newCString ""
4247 links <- peekArray0 nil c_links
4348 newArray0 nil (ssml : links)
49
50 -- Since I have XML Conduit here...
51 ssmlHasMark :: Txt.Text -> XML.Element -> Bool
52 ssmlHasMark ident (XML.Element "mark" attrs _) = Just ident == M.lookup "name" attrs
53 ssmlHasMark ident (XML.Element _ _ childs) = or [ssmlHasMark ident el | XML.NodeElement el <- childs]
54
55 foreign export ccall c_ssmlHasMark :: CString -> CString -> IO Bool
56
57 c_ssmlHasMark c_ident c_ssml = do
58 ident <- peekCString c_ident
59 ssml <- peekCString c_ssml
60 case XML.parseText XML.def $ Txt.fromStrict $ Txt.pack ssml of
61 Left _ -> return False
62 Right doc -> return $ ssmlHasMark (Txt.pack ident) $ XML.documentRoot doc
2828 char *c_renderDoc(struct session*, struct page*, _Bool);
2929 char **c_extractLinks(struct page*);
3030 char **c_docLinksAndRendering(struct session*, struct page*, _Bool); // FIXME segfaults.
31 int c_ssmlHasMark(char*, char*);
3132
3233 /* espeak-ng integration. Based on the espeak-ng command source code. */
3334 SNDFILE *fd_wav = NULL;
122123 samplerate = espeak_ng_GetSampleRate();
123124 return 0;
124125 }
125 void speak(char *ssml, char *mark) {
126 void speak(char *ssml, char *mark, char* fallback) {
126127 int flags = espeakCHARS_AUTO | espeakPHONEMES | espeakENDPAUSE | espeakCHARS_UTF8 | espeakSSML;
127 if (mark != NULL) espeak_Synth_Mark(ssml, strlen(ssml)+1, mark, 0, flags, NULL, NULL);
128 espeak_Synth(ssml, strlen(ssml)+1, 0, POS_CHARACTER, 0, flags, NULL, NULL); // FIXME only do so if mark doesn't play.
128 if (mark != NULL && c_ssmlHasMark(mark, ssml))
129 espeak_Synth_Mark(ssml, strlen(ssml)+1, mark, 0, flags, NULL, NULL);
130 else if (fallback != NULL)
131 espeak_Synth_Mark(ssml, strlen(ssml)+1, fallback, 0, flags, NULL, NULL);
132 else espeak_Synth(ssml, strlen(ssml)+1, 0, POS_CHARACTER, 0, flags, NULL, NULL);
129133 }
130134 int read_keyboard = 0;
131135 int speak_finalize(char *ssml) {
133137 char c = getc(stdin);
134138 if (c == '\033') {
135139 char mark[200];
140 char fallback[200];
136141 espeak_Cancel();
137142 c = getc(stdin);
138143 if (c == 0 || c == -1 || c == '\033' || c == 'q') goto close; // skip [
143148 tablerow--;
144149 if (tablerow > 0) {
145150 sprintf(mark, "-rhaps-tablecell%i:%ix%i", tableno, tablerow, tablecol);
146 speak(ssml, mark);
151 speak(ssml, mark, NULL);
147152 break;
148153 } else in_table = 0;
149154 }
150155 section_no--;
151156 sprintf(mark, "-rhaps-section%i", section_no);
152 speak(ssml, section_no > 0 ? mark : NULL);
157 speak(ssml, section_no > 0 ? mark : NULL, NULL);
153158 break;
154159 case 'B':
155160 // 🠗
156161 if (in_table) {
157162 tablerow++;
158163 sprintf(mark, "-rhaps-tablecell%i:%ix%i", tableno, tablerow, tablecol);
159 speak(ssml, mark);
164 sprintf(fallback, "-rhaps-section%i", section_no+1);
165 speak(ssml, mark, fallback);
160166 break; // FIXME What if that mark doesn't exist?
161167 }
162168 section_no++;
163169 sprintf(mark, "-rhaps-section%i", section_no);
164 speak(ssml, section_no > 0 ? mark : NULL);
170 speak(ssml, section_no > 0 ? mark : NULL, NULL);
165171 break;
166172 case 'C':
167173 // ➔
168174 if (in_table) {
169175 tablecol++;
170176 sprintf(mark, "-rhaps-tablecell%i:%ix%i", tableno, tablerow, tablecol);
171 speak(ssml, mark);
177 sprintf(fallback, "-rhaps-paragraph%i", paragraph_no+1);
178 speak(ssml, mark, fallback);
172179 break; // FIXME What if that mark doesn't exist?
173180 }
174181 paragraph_no++;
175182 sprintf(mark, "-rhaps-paragraph%i", paragraph_no);
176 speak(ssml, paragraph_no > 0 ? mark : NULL);
183 speak(ssml, paragraph_no > 0 ? mark : NULL, NULL);
177184 break;
178185 case 'D':
179186 // 🠔
181188 tablecol--;
182189 if (tablecol > 0) {
183190 sprintf(mark, "-rhaps-tablecell%i:%ix%i", tableno, tablerow, tablecol);
184 speak(ssml, mark);
191 speak(ssml, mark, NULL);
185192 break;
186193 } else in_table = 0;
187194 }
188195 paragraph_no--;
189196 sprintf(mark, "-rhaps-paragraph%i", paragraph_no);
190 speak(ssml, paragraph_no > 0 ? mark : NULL);
197 speak(ssml, paragraph_no > 0 ? mark : NULL, NULL);
191198 break;
192199 }
193200 }
302309 if (use_espeak) speak_err = speak_initialize();
303310 char *ssml;
304311 for (int i = optind; i < argc; i++) {
305 if (use_espeak && speak_err == 0) speak(argv[i], NULL);
312 if (use_espeak && speak_err == 0) speak(argv[i], NULL, NULL);
306313 #ifdef WITH_SPEECHD
307314 else if (spd_conn != NULL) spd_say(spd_conn, SPD_MESSAGE, argv[i]);
308315 #endif
314321
315322 if (fd_ssml != NULL) fprintf(fd_ssml, "%s\n", ssml);
316323 if (fd_links != NULL) write_links(fd_links, links);
317 if (use_espeak & speak_err == 0) speak(ssml, "main");
324 if (use_espeak & speak_err == 0) speak(ssml, "main", NULL);
318325 #ifdef WITH_SPEECHD
319326 if (spd_conn != NULL) spd_say(spd_conn, SPD_MESSAGE, ssml);
320327 #endif