~alcinnz/rhapsode

671fa2a5eef47996aa8e38076be81793ff4d3a43 — Adrian Cochrane 4 years ago 8a54027
Improve fallbacks for missing markers.
2 files changed, 39 insertions(+), 13 deletions(-)

M src/CExports.hs
M src/main.c
M src/CExports.hs => src/CExports.hs +19 -0
@@ 1,3 1,4 @@
{-# LANGUAGE OverloadedStrings #-}
module CExports where

import Types


@@ 5,6 6,10 @@ import Network.URI.Fetch (Session)

import Render (c_renderDoc)
import Links (c_extractLinks)
import qualified Text.XML as XML
import qualified Data.Text as Txt
import qualified Data.Text.Lazy as Txt (fromStrict)
import qualified Data.Map as M

-- Types I can export to C
import Foreign.StablePtr


@@ 42,3 47,17 @@ c_docLinksAndRendering c_session c_page rewriteUrls = do
    nil <- newCString ""
    links <- peekArray0 nil c_links
    newArray0 nil (ssml : links)

-- Since I have XML Conduit here...
ssmlHasMark :: Txt.Text -> XML.Element -> Bool
ssmlHasMark ident (XML.Element "mark" attrs _) = Just ident == M.lookup "name" attrs
ssmlHasMark ident (XML.Element _ _ childs) = or [ssmlHasMark ident el | XML.NodeElement el <- childs]

foreign export ccall c_ssmlHasMark :: CString -> CString -> IO Bool

c_ssmlHasMark c_ident c_ssml = do
    ident <- peekCString c_ident
    ssml <- peekCString c_ssml
    case XML.parseText XML.def $ Txt.fromStrict $ Txt.pack ssml of
        Left _ -> return False
        Right doc -> return $ ssmlHasMark (Txt.pack ident) $ XML.documentRoot doc

M src/main.c => src/main.c +20 -13
@@ 29,6 29,7 @@ void c_freePage(struct page*);
char *c_renderDoc(struct session*, struct page*, _Bool);
char **c_extractLinks(struct page*);
char **c_docLinksAndRendering(struct session*, struct page*, _Bool); // FIXME segfaults.
int c_ssmlHasMark(char*, char*);

/* espeak-ng integration. Based on the espeak-ng command source code. */
SNDFILE *fd_wav = NULL;


@@ 123,10 124,13 @@ int speak_initialize() {
    samplerate = espeak_ng_GetSampleRate();
    return 0;
}
void speak(char *ssml, char *mark) {
void speak(char *ssml, char *mark, char* fallback) {
    int flags = espeakCHARS_AUTO | espeakPHONEMES | espeakENDPAUSE | espeakCHARS_UTF8 | espeakSSML;
    if (mark != NULL) espeak_Synth_Mark(ssml, strlen(ssml)+1, mark, 0, flags, NULL, NULL);
    espeak_Synth(ssml, strlen(ssml)+1, 0, POS_CHARACTER, 0, flags, NULL, NULL); // FIXME only do so if mark doesn't play.
    if (mark != NULL && c_ssmlHasMark(mark, ssml))
        espeak_Synth_Mark(ssml, strlen(ssml)+1, mark, 0, flags, NULL, NULL);
    else if (fallback != NULL)
        espeak_Synth_Mark(ssml, strlen(ssml)+1, fallback, 0, flags, NULL, NULL);
    else espeak_Synth(ssml, strlen(ssml)+1, 0, POS_CHARACTER, 0, flags, NULL, NULL);
}
int read_keyboard = 0;
int speak_finalize(char *ssml) {


@@ 134,6 138,7 @@ int speak_finalize(char *ssml) {
        char c = getc(stdin);
        if (c == '\033') {
            char mark[200];
            char fallback[200];
            espeak_Cancel();
            c = getc(stdin);
            if (c == 0 || c == -1 || c == '\033' || c == 'q') goto close; // skip [


@@ 144,37 149,39 @@ int speak_finalize(char *ssml) {
                    tablerow--;
                    if (tablerow > 0) {
                        sprintf(mark, "-rhaps-tablecell%i:%ix%i", tableno, tablerow, tablecol);
                        speak(ssml, mark);
                        speak(ssml, mark, NULL);
                        break;
                    } else in_table = 0;
                }
                section_no--;
                sprintf(mark, "-rhaps-section%i", section_no);
                speak(ssml, section_no > 0 ? mark : NULL);
                speak(ssml, section_no > 0 ? mark : NULL, NULL);
                break;
            case 'B':
                // 🠗
                if (in_table) {
                    tablerow++;
                    sprintf(mark, "-rhaps-tablecell%i:%ix%i", tableno, tablerow, tablecol);
                    speak(ssml, mark);
                    sprintf(fallback, "-rhaps-section%i", section_no+1);
                    speak(ssml, mark, fallback);
                    break; // FIXME What if that mark doesn't exist?
                }
                section_no++;
                sprintf(mark, "-rhaps-section%i", section_no);
                speak(ssml, section_no > 0 ? mark : NULL);
                speak(ssml, section_no > 0 ? mark : NULL, NULL);
                break;
            case 'C':
                // ➔
                if (in_table) {
                    tablecol++;
                    sprintf(mark, "-rhaps-tablecell%i:%ix%i", tableno, tablerow, tablecol);
                    speak(ssml, mark);
                    sprintf(fallback, "-rhaps-paragraph%i", paragraph_no+1);
                    speak(ssml, mark, fallback);
                    break; // FIXME What if that mark doesn't exist?
                }
                paragraph_no++;
                sprintf(mark, "-rhaps-paragraph%i", paragraph_no);
                speak(ssml, paragraph_no > 0 ? mark : NULL);
                speak(ssml, paragraph_no > 0 ? mark : NULL, NULL);
                break;
            case 'D':
                // 🠔


@@ 182,13 189,13 @@ int speak_finalize(char *ssml) {
                    tablecol--;
                    if (tablecol > 0) {
                        sprintf(mark, "-rhaps-tablecell%i:%ix%i", tableno, tablerow, tablecol);
                        speak(ssml, mark);
                        speak(ssml, mark, NULL);
                        break;
                    } else in_table = 0;
                }
                paragraph_no--;
                sprintf(mark, "-rhaps-paragraph%i", paragraph_no);
                speak(ssml, paragraph_no > 0 ? mark : NULL);
                speak(ssml, paragraph_no > 0 ? mark : NULL, NULL);
                break;
            }
        }


@@ 303,7 310,7 @@ int main(int argc, char **argv) {
    if (use_espeak) speak_err = speak_initialize();
    char *ssml;
    for (int i = optind; i < argc; i++) {
        if (use_espeak && speak_err == 0) speak(argv[i], NULL);
        if (use_espeak && speak_err == 0) speak(argv[i], NULL, NULL);
        #ifdef WITH_SPEECHD
        else if (spd_conn != NULL) spd_say(spd_conn, SPD_MESSAGE, argv[i]);
        #endif


@@ 315,7 322,7 @@ int main(int argc, char **argv) {

        if (fd_ssml != NULL) fprintf(fd_ssml, "%s\n", ssml);
        if (fd_links != NULL) write_links(fd_links, links);
        if (use_espeak & speak_err == 0) speak(ssml, "main");
        if (use_espeak & speak_err == 0) speak(ssml, "main", NULL);
        #ifdef WITH_SPEECHD
        if (spd_conn != NULL) spd_say(spd_conn, SPD_MESSAGE, ssml);
        #endif