The Jupiter Speech System

The Jupiter Speech System, Version 2.0

Contents

Overview

The Jupiter speech system captures console output in a large circular buffer and allows the blind user to read the accumulated text via a voice synthesizer. There are several features that separate this adaptive software from the many excellent packages on the Blinux web site.

  1. Jupiter does not lock the blind user into a screen oriented paradigm. It does have a screen review mode, which reads directly from screen memory, but it can also run in line mode, which captures the accumulated output of the prior commands, exactly as generated.

    Most adaptive systems restrict the user to the text that is currently on the screen. This makes sense for screen oriented applications such as emacs or lynx. However, other applications, such as the standard Unix shell, present a command-response interface. Under these circumstances, an ongoing log of the interactive session is more appropriate. The user can review each line of text, exactly as it was typed (input) or generated (output). Jupiter allows the user to run in linear or screen mode.

  2. Jupiter generates audio feedback via the PC in-built speaker as text is displayed on the screen. The user quickly learns to recognize familiar messages simply by their sounds. Hence there is no need to read them, saving quite a bit of time. The user can also issue several commands and passively monitor the computer's response, while reading through the output of an earlier command. A simple click indicates a "$" prompt -- all is well -- so type the next command -- while your synthesizer continues to read an earlier message.

    This audio feedback isn't much help in screen mode. In fact you might tire of the clicks and chirps as the screen is constantly being refreshed. However, it is a simple matter to turn it off when running in screen mode, and reenable it for line mode.

    Those wishing to incorporate console audio feedback into their own adaptive software can use my clicktty module, which is included in this package. This module generates audio feedback as text is generated, but it assumes some other process, such as Emacsspeak or Brltty, is actually reading the words.

  3. Jupiter allows a great deal of customization, well beyond simple key binding. The atomic speech commands are quite simple: start of line, start of word, back one character, read character, read word, start continuous reading, etc. The user can string these together to make a composite command, and bind this composite to a key. For instance,

            ^N eline for eline for read
    

    will cause control-N to advance to the end of the line, move forward one space (onto the next line), advance to the end of that line, forward one space, and start reading. In other words, ^N skips down two lines and begins reading. In screen mode, composite commands might locate the visual cursor and read the character, word, or line that is indicated by the cursor. In a more contrived, yet not implausible example, suppose you often read the second to last column in a spreadsheet, and you'd like a single keystroke command to do this.

                eline lspc back sword lspc back word
    

    might work, if the entries in your spreadsheet are simple enough. Other composites let you move up and down this all-important column, or switch between this column and the first column (the customer's name). You can usually create whatever commands you need in your work, and bind them to single keystrokes.

  4. Jupiter reads dates, times, street addresses, and so on using natural English words, rather than the cryptic strings of digits and abbreviations that have become the written standard. This eliminates confusion and saves time.

  5. Jupiter is a loadable module; it need not be compiled into the kernel. This package does patch the kernel, but only to support the loadable module. After the patch, the kernel calls functions in the Jupiter module, if that module is present, else it goes about its business. This small kernel patch will support anybody's speech package, not just mine. Thus, if you don't like my adaptive software, just pop in somebody else's module or write your own. Click here for documentation on this modular interface. I hope that this small change to the kernel becomes part of the standard Linux distribution, whence the blind user could grab a module off the internet, run insmod, and hear the results immediately.

  6. Jupiter allows speech functions to be activated from the keyboard or the escape sequences produced by a running program. This can be used in several ways.

    • Simple commands such as /bin/ls can be wrappered or rewritten to "read" the output as soon as it is generated. First issue the escape sequence that places the reading cursor at the end of the buffer, run the Linux command, then initiate reading with another escape sequence. This reads the output of the command without any additional keystrokes.

    • A background job, running in another virtual terminal, can literally tell you when it is done, or give periodic updates on its progress. This will interrupt any reading you are doing in the foreground session, but that's probably what you want. If self-speaking applications are well designed, we almost have a true windowing environment for the blind.

    • One could imagine a comprehensive tutorial that reads itself. After all, how can the blind user learn to run a speech package if he cannot use the speech package to read the user's manual? A good tutorial will be fully interactive, teaching the user how to run the various speech functions, build composite functions, bind them to keys, respell words for improved pronunciation, and so on. An application running under Jupiter could do this, and much more. However, the tutorial that I envision is probably larger than the Jupiter speech system itself, and I don't have time to write it at present.

If you download this package from the internet, and manage to install it yourself, I'd still like to know that you are using it. That way I can keep you informed of bug fixes and new features etc. Please drop me a line.

Back to top

Copyright Notice

The Jupiter Speech Package (software and documentation) is copyright (C) Karl Dahlke, 2000-2001. It may be freely distributed under the terms of the General Public License, as articulated by the Free Software Foundation.

Back to top

Platforms Supported

Although I haven't tested each and every platform, I believe Jupiter can be patched into Linux version 2.2 or higher, and it should run on any hardware supported by Linux. However, the console audio feedback, which is an important part of the overall package, is restricted to boxes with an in-built toggle speaker .

Back to top

Synthesizers Supported

This package works best with the Doubletalk light, Braille N speak, and Dectalk Express synthesizers. It also works with the Dectalk PC card, though the setup procedure is a bit more complicated. Finally, Jupiter will work, at a minimal level, with almost any external synthesizer. In generic mode, Jupiter sends a stream of ASCII words over the serial port, delimited by CR, so the unit will speak them immediately. Most synthesizers support this basic interface. Thus Jupiter will work with most external synthesizers, but if you want high speech quality, low speech latency, and software control over speed, volume, pitch, etc, you should use the Doubletalk, Dectalk, or Braille N speak.

Back to top

Atomic Speech Commands

This section presents the atomic commands currently supported. As mentioned earlier, these can be joined together to make a composite, which is then bound to a single keystroke. Alternatively, a program can generate escape sequences that activate these atomic commands. In theory, several virtual terminals, running their own programs, might vie for the speech synthesizer simultaneously, while the user issues speech commands from the keyboard. Fortunately this doesn't happen very often in practice.

Most of the atomic commands refer to a cursor. This is the reading cursor, which should not be confused with the visual cursor on the screen. The reading cursor roams around the text, and corresponds to the text being spoken by the synthesizer at the time.

In screen review mode, the cursor (i.e. the reading cursor) moves about in screen memory. If you move up one row, the cursor literally moves up one row on the screen. thus each line of text is actually one line on the screen, 80 characters long, followed by a virtual newline character. There are 25 of these "lines" in the buffer, corresponding to the lines on a display screen. That is the text you are allowed to read. Even in screen review mode, the reading cursor and the visual cursor are not the same, although the former can "sync up" with the latter, at your command.

In line mode, the cursor travels through a log of your interactive session. Each line is as you typed it (input), or as it was generated (output). You can review text that has scrolled off the screen long ago. The size of the circular buffer is a compile time constant, and can be increased if you wish. However, a text buffer is allocated for each open virtual terminal, and /etc/inittab opens six just for starters, so watch your memory consumption.

Each command has a short, somewhat cryptic name. The names are presented below, and should be used in the configuration file that builds and binds composites. Although the names are short, they do follow a pattern, and it's better than giving each command a number. 8-)

clbuf
Clear the text buffer. The accumulated text is discarded and the interactive session begins anew. This is meaningless in screen mode.
cursor
Move the reading cursor to the visual cursor. This only makes sense in screen mode.
sbuf
Move the cursor to the start of the buffer. In screen mode, this is the leftmost character on the top line of the screen. In line mode, this could be the first character produced by the first program run after bootup, probably something out of /etc/rc.d/rc.sysinit. Of course this old text will scroll over the horizon eventually, depending on the size of your text buffer and the amount of output your programs produce.
ebuf
Move the cursor to the end of the buffer. In screen mode, the last character is the artificial newline that terminates the last line of text on the screen. The preceding 80 characters form the bottom line of text. In line mode, this is the last character generated by the last program you ran, or the last character you typed (if you are entering text).
lcline
Move to the last complete line. The cursor starts at the end of the buffer and moves back to the first nonblank character that has a newline after it. This bypasses the final prompt, if any, and ignores any intermediate blank lines, leaving the cursor on what is usually the last nontrivial line of output. This is often what you want to hear. In screen mode, the final newline that terminates the last line on the screen is ignored. Thus the reading cursor bypasses the prompt on the bottom line, moves back across the newline boundary, and up to the previous line, which is what you want to hear.
sline
Move to the start of the current line.
eline
Move to the end of the current line. This will always be a newline character, unless you are positioned within the last line, and it is not yet complete.
sword
Move to the start of the current word. A "word" is any contiguous sequence of letters and digits, with at most one apostrophe embedded (such as didn't). If the cursor is on a punctuation mark, such as a hyphen, that character is its own word. Moving to the beginning of that word doesn't change a thing. However, if there are 5 or more hyphens in sequence, that is considered one word, and is read "hyphen length 5". This command moves to the first hyphen in the sequence, and the next command moves to the last hyphen. This holds for any punctuation mark, and is intended to support the lines of dashes and equals and dots etc that often appear in textual output.
eword
Move to the end of the current word.
lspc
If there are spaces at the immediate left of the cursor, move to the leftmost space in this sequence.
rspc
If there are spaces at the immediate right of the cursor, move to the rightmost space in this sequence.
back
Move back one character. If the cursor is at the start of buffer, it cannot go back. This is a boundary error, and is indicated by two high notes in quick succession. Any error in an atomic command aborts the larger composite and leaves the cursor where it started.
for
Move forward one character. If the cursor is at the end of buffer, it cannot go forward. This is a boundary error, as described above.
prow
Move the cursor up to the previous row, within the same column. In other words, if the cursor was on the 7th character in the 18th line, it will be positioned on the 7th character in the 17th line. A boundary error occurs if there is no previous line. If the prior line is too short, we have a "functional" error, indicated by the same beep that accompanies ^G.
nrow
Move the cursor to the next row. If there is no next row, or the next row is too short, we have a boundary or functional error, respectively.
char
Speak the character indicated by the cursor. If sounds are enabled, '\r' produces the same chirp that is heard when return is sent to the screen. Similarly, ^G produces the same beep. If sounds are disabled, these characters are rendered "line" and "bell" respectively. Linefeed is read as "feed", and all other control characters are read as "control letter". Unless cc_buffering mode is enabled, control characters are generally discarded, and will not be present in your text buffer, except for CR and bell, which convey real information. Graphics characters, with the high bit set, are turned into spaces. This is only an issue in screen mode.

The words used to read punctuation marks are under the user's control, as indicated by the configuration file. I recommend short words, such as "dot", rather than "period".

asword
It is often difficult to distinguish between 'm' and 'n'. If you're not sure what the letter was, this command speaks a word that starts with that letter, using the NATO standard phonetic alphabet.

alpha     hotel     oscar     uniform   
bravo     india     papa      victor    
charlie   juliet    quebec    wiskey    
delta     kilo      romeo     x-ray     
echo      lima      sierra    yankee    
foxtrot   mike      tango     zulu      
golf      november  
case
Indicate the case of the current letter. Upper case is indicated by a long high tone, which is often associated with a mode being "active". Lower case produces a short lower tone, which is often associated with a mode being "inactive". If sounds are disabled, Jupiter simply says "upper" or "lower".
colnum
Speak the current column number. The first character in a line is at column 1.
word
Speak the current word. A word is actually a token, as described in sword above. Note that 900 letters or digits in sequence represents one word, albeit pathologically long. If you wait patiently, this command will read the entire word. However, it actually reads the word in pieces, hence it can be interrupted.
read
Start continuous reading. Reading proceeds, controlled by an asynchronous thread, until it is stopped by the next speech command, or we run out of text. If one_line mode is enabled, reading stops at the end of each line. This gives you a chance to digest what you've just heard, before the software barrels on ahead.
shutup
As mentioned above, any speech function will interrupt reading. This one doesn't do anything else. You can hit it when the phone rings, to suspend speech, and then start reading again after you have told the salesman that you really don't need new windows or aluminum siding.
bypass
Send the next character through to the operating system. If you have assigned a speech function to ^C, and you need to send ^C to Linux to generate an interrupt, use the bypass feature.
toggle
Toggle one of Jupiter's binary modes, based on the next character received. The modes are shown below. The character used to toggle the mode is presented first, then the description of the mode.

n:
Noisy mode, generates clicks and chirps as text is displayed.
c:
Stores control characters in the text buffer.
1:
Oneline mode stops reading at the end of each line.
a:
autoread starts reading when the computer displays new text.
i:
interrupt speech when any key is pressed.
o:
Overrides unexpected signals from the synthesizer.
s:
Runs in screen review mode, rather than line mode.
l:
Reads all punctuations literally.
b:
Processes escape left-bracket sequences.
B:
Processes escape left-brace sequences.

For example, to enable/disable console noises, activate the toggle function, then hit 'n'. Jupiter produces the high active tone if the mode is enabled, and the low inactive tone if the mode is disabled. When sounds are disabled, the inactive tone will be the last sound you hear, until you enable audio feedback again. These on-off tones are not generated unless the toggle command is the last in its composite.

clmode
Clear one of the binary modes, based on the next character received. A running program, such as the tutorial, might use this command to put the system into a known state, whereas the user might embed this command inside a larger composite. For instance, to start at the next line and read the rest of the screen/buffer, disable one-line reading mode, move to the next line, and start reading. This is written:

        clmode 1 eline for read

In contrast, if you need to go back one line, you probably don't want to read the rest of the screen. You need to listen to that line carefully, and perhaps the line before. An appropriate composite would set one-line reading mode, back up to the previous line, and start reading. Recall that the mode changes don't generate any sounds when they are part of a larger composite. All you hear is the line you want to hear.

stmode
Set one of the binary modes, based on the next character received.
echo
Echo letters or words as you enter them. Follow echo with a digit from 0 to 4. 0 turns it off - disables the echo feature. 1 echos characters (not whitespace) as you type them. 2 echos words as each space tab or return is entered. 3 and 4 are like 1 and 2, except echoing is supressed if you type quickly. The system figures you know what you are doing, and you don't require feedback. If you don't type for a quarter second it speaks the last character, or the word you are currently typing.
searchd
Starting at the current cursor position and moving down the buffer/screen, search for a particular text fragment. The search is case insensitive. The user types the string immediately after activating this command, and terminates it with the return key. The backspace key erases a character in the entered string, and escape aborts the search. Speech functions will not operate while the string is being entered. You must type ASCII characters, then hit return. If the string is empty, Jupiter uses the last string as its search pattern. Thus you can locate multiple instances of a string simply by hitting "search return". If the string is not found, Jupiter generates a boundary error, as described in the back command. If the string is found, the cursor is positioned at the beginning of that string in the buffer, and Jupiter says "ok". However, if one_line mode is enabled, Jupiter reads the line containing the string. A subsequent search moves to the next line, and will not reread the current line, even if it contains a second instance of the search string.
searchu
Search for an entered string, but move backwards through the buffer (up), rather than forward (down).
volume
Set speech volume according to the next key entered. The key should be a digit from 0 to 9. Jupiter converts these 10 numbers to corresponding volume levels in the attached synthesizer. This is meaningless when the synthesizer has no software volume control.
incvol
Increase volume by one and speak the word "louder". This produces the boundary error if the volume is already at 9.
decvol
Decrease volume by one and speak the word "softer". This produces the boundary error if the volume is already at 0.
speed
Set speech rate according to the next key entered. The key should be a digit from 0 to 9.
incspd
Increase speed by one and speak the word "faster". This produces the boundary error if the speed is already at 9.
decspd
Decrease speed by one and speak the word "slower". This produces the boundary error if the speed is already at 0.
pitch
Set voice pitch according to the next key entered. The key should be a digit from 0 to 9.
incpch
Increase pitch by one and speak the word "higher". This produces the boundary error if the pitch is already at 9.
decpch
Decrease pitch by one and speak the word "lower". This produces the boundary error if the pitch is already at 0.
voice
If the synthesizer supports multiple voices, select one of the voices using the digits 1 through 9. The Doubletalk supports 8 voices, 1 through 8. Voice 3 is the default. The Dectalk supports 9 voices, 1 through 9. Voice 1 is the default.

Due to roundoff errors, the pitch of a predefined voice may not match any of the 10 preset pitch levels used by Jupiter. Thus incrementing and then decrementing the pitch may not return the unit to the exact same frequency. Of course, once you have issued a pitch command, you will remain on Jupiter's 10 pitch levels, until you switch voices again, or reinitialize the unit.

func
Announce the function of the next key entered. The next key should be a meta key -- something that could, theoretically, have a speech function assigned to it. Any other key produces the error bell. If the key is unbound, Jupiter says "no speech function". Otherwise it gives a short description of the last atomic command in the composite bound to that key. It might be preferable to hear all the commands in the composite, but in practice this would be a rather confusing report. In a future version, you will be able to add your own description to each key binding. You might describe a composite as "Read the word just to the left of the visual cursor", and here this description when you invoke this function. For now, you only get my description of the last atomic command.
setpro
Establish the pronunciation of a punctuation mark or a word. Type the punctuation mark or word, followed by a space or tab, then the replacement text. Like the search string, backspace erases a character and escape aborts the command. As an example, many synthesizers pronounce "read" as "red". This is correct about 30% of the time, but more often, it should be rendered "reed". So I activate this command, then type "read reed", followed by the return key. Of course I don't actually do this at the start of each session, since this particular translation is contained in my configuration file -- but you get the idea.

A new definition overwrites the old one, and if there is no replacement text, the old definition disappears. If you add too many replacements to the word replacement table, which is currently 30K, you will hear the boundary error tones.

Jupiter understands simple English suffixes, and the rules for applying them. In the above example, we turned "read" into "reed". This effectively maps "reading" into "reeding", and "reads" into "reeds". Most of the time this is what you want. When it isn't, you can ad special translations for the conjugate forms of the root word.

bind
Bind a composite speech command to a key. Like the previous command, this command expects a follow-on string. type the key designator, follow by the atomic speech commands, separated by whitespace. Use the names presented in this section. The syntax for the key designator is as follows. Upper or lower case letters can be used.

^X  control x
@X  alt x
F7  function key 7
+F7 shift function key 7
^F7 control function key 7
@F7 alt function key 7
#7  numpad key 7, without numlock
+#7 shift numpad key 7
^#7 control numpad key 7
@#7 alt numpad key 7
#.  numpad key .   (following the + ^ @ convention)
#+  numpad key +
#-  numpad key -
#*  numpad key *
#/  numpad key /
up  up arrow  (down left and right are similar)

To illustrate, suppose you want control j to read the previous word. You would type

        ^J sword lspc back word

The configuration file, presented in the next section, contains a wealth of examples.

In this version, composite commands are somewhat limited. If an atomic command speaks, or initiates reading, it must end the composite. You cannot construct one composite that reads the current word and the next word. Also, commands that require follow-on strings, such as this bind command, must appear at the end of a composite. If a command requires a follow-on character, such as toggle, the caracter can be included in the composite, provided it is an alphanumeric. Thus a single keystroke can toggle audio feedback or single-line reading. I have placed both these composites on prominent functions keys, because I constantly toggle these modes in my work.

setmac
Jupiter can bind a text macro to a key. This should not be confused with the previous command, which deals with speech functions. A macro is merely a form of speed-dialing. When you hit ^F7, dump the corresponding text into the input queue, and that's it. Macros can be applied at any time, and they can be configured on the fly by a running program. It is possible to put a wrapper around your favorite text editor or browser, so that it configures all your favorite macros, relative to that program. It is not clear whether dynamic macros will improve productivity, or cause confusion and chaos.

After activating this command, enter the key designator, as described above, followed by the less than character '<'. Then type the replacement text, followed by the return key. You cannot embed the return key or the escape key directly into a macro, as these terminate follow-on input. However, \nnn is translated into its octal equivalent, so that \15 becomes return and \33 becomes escape. In addition, \b \f \t \n and \r are translated as they would be in a C string. Thus it is easy to build a macro that contains control characters, including the all important return key \r.

reset
Sometimes the autoprobe feature doesn't detect the synthesizer, and sometimes the synthesizer is disconnected, or simply turned off. Use this function to establish a connection with your synthesizer. If the follow-on character is a digit from 0 to 3, Jupiter assumes the synthesizer is connected to that serial port, using the /dev/ttyS? convention. If the character is a question mark '?', Jupiter attempts to find the synthesizer by autoprobing the four ports. Thus you do not need to reboot the system, just because you forgot to turn on the synthesizer.
markl
This is used by the cut and paste feature, which is described in a later section.
markr
This is used by the cut and paste feature, which is described in a later section.

Back to top

The Configuration File

At startup, Jupiter binds several critical speech commands to your function keys. Thus, if your configuration file is missing or corrupt, you can still get something done. The first five function keys read the previous, current, next, after next, and last complete line, respectively. F6 toggles modes, and F7 and F8 move the cursor to the top and bottom of the buffer respectively. F9 toggles one line reading mode. F10 is the bind function, which allows you to assign other speech commands to other keys. Finally, +F10 is the all-important reset command, in case you have to reestablish the link to your synthesizer, or designate a particular serial port. Of course this is only used as a fallback -- your configuration file should set everything up for you at startup.

The configuration file, /etc/jupiter.cfg by convention, is line oriented. Lines beginning with a semi colon are ignored. I would have used the # sign, like shell scripts, but the keys on the numeric keypad are denoted #1 through #9, when specifying key bindings, and that implies a leading #. So I decided to use the semi colon, which is a standard comment character in many assemblers.

Each non-comment line establishes a pronunciation, binds a speech command, or defines a macro. The text is written exactly as it would be typed in by the user, after invoking the corresponding atomic command, as documented in the previous section. For instance, a line in the configuration file contains the text "read reed", and this establishes the pronunciation of the word "read". Since examples are the best form of documentation, I'll stop here and let you peruse two sample configuration files. The first arranges the keys in a manner that will be familiar to anyone who has used ASAP (DOS) or Speakup (Linux). You'll know exactly where the reading keys are and what they do. This makes it easy to jump right into Jupiter without a steep learning curve. The second is my config file, which uses more control keys, so that I don't have to move my hands all over the keyboard just to read the current word/line etc. I have swapped the control and caps lock on my system, making it much easier to activate the control keys. This also prevents me from hitting caps lock by mistake.

The last line of the config file is often the "invoke now" line, as indicated by a leading ^^. For instance,
^^ voice 7 pitch 3 speed 8 stmode s
establishes the voice parameters and puts you in screen review mode. This puts Jupiter in a known state for you, so you don't have to write a separate shell script with strange looking echo commands.

The talking Linux kernel does not actually read /etc/jupiter.cfg and configure itself; another utility is involved. The program "talkcfg" reads the configuration file and passes it to the Jupiter module inside the running kernel. This is similar to the loadkeys(8) utility, which passes a keymap to the running kernel. Thus Jupiter can be reconfigured at any time; no need to reload the module. You may want to place the command

        post-install jupiter talkcfg  /etc/jupiter.cfg

in your /etc/modules.conf file. Thus, whenever modprobe loads the jupiter speech module, it runs the talkcfg utility, which configures the system.

The talkcfg utility is startlingly simple. It reads each line in the configuration file, prepends the appropriate escape sequence, and sends the modified string to standard out. That's it! The machinery inside Jupiter spots the escape sequence and activates the corresponding atomic command, which swallows the follow-on string and parses it, as though it had been typed in at the keyboard. That is why the syntax is, and must be, exactly the same as if you had typed it in yourself.

The talkcfg program can be run in test mode, by using the -t option. This verifies the syntax of your configuration file without affecting the running system. If there are syntax errors in your file, and you send it on to the kernel anyways, Jupiter will beep once for every improper line. This is not a serious problem -- just fix the file and run it through again.

Back to top

Cut And Paste

In windows, you can capture a block of text, switch to another window, and copy that text into another running application, as though you had typed it in at the keyboard. This is a very nice feature, which Jupiter attempts to emulate.

The markl and markr commands mark the left and right boundaries of a block of text to be copied. The left boundary must be specified first, then the right. All text between the two markers, inclusive, is captured in an internal buffer. The markers can span multiple lines. Line breaks are stored as linefeed, ascii 10. This is Linux for newline. The running application will think you are hitting return after every line, as though you had typed it in at the keyboard.

There is a limit to the amount of text that can be captured in this way, so don't get carried away. At present the limit is about 200 characters, the size of a tty input queue. If you need to manage large blocks of text from your interactive session, use the /proc/accessibility/jupiter/buf* files, described in a later section.

The captured text is stored as a macro, and bound to one of your alt keys. The markr command requires a follow-on letter, a through z. If you follow up with k, the captured text is reproduced by hitting alt-k. This holds true even if you switch consoles. Cut and paste is truely a global feature.

Let's consider some examples. Suppose you want a single keystroke, f7, to capture the current line of text, at the reading cursor, and make it available as a macro under alt-k. The following composite should do the trick. The back command prevents the final line break from becoming part of your macro.

f7 sline markl eline back markr k

For another example, let's say you are working in screen mode, and you don't want all the trailing spaces at the end of a line on the screen. Also, you are capturing a line that you typed in at the shell, rather than a line of output. Thus you don't want the leading dollar prompt. We skip two spaces over to bypass the prompt.

f7 sline for for markl eline lspc back markr k

When marking text, you may want a key that moves to the beginning of the current word and then sets the left marker. Rarely will you want to copy part of a word, so you may as well move to the start. Thus most people will use "sword markl" for their left mark command. Some will also establish a "sline markl" command to mark the beginning of the current line. It all depends on the type of text you normally cut and paste.

Back to top

Escape Sequences

A running program activates a speech command by sending the string "\33{name" to standard out, where \33 represents the ASCII escape character, and name is one of the atomic commands presented earlier. Thus a C program can initiate reading via printf("\33{read";. This approach works for perl, java, and even shell scripts, provided you remember the -e option on the echo command.

I wrote a general purpose self-talking wrapper, called speaknow, which I can then use to make any shell command self-talking. It moves the reading cursor to the end of the buffer, runs the designated command, and then starts reading. Thus `speaknow echo hello world' will cause the computer to print hello world on the screen, and then read it. You don't have to hit any function keys at all.

#  Self-talking programs
function speaknow() {
	if [ -t 1 ]  # terminal
		then echo -en "\33{ebuf"
	fi
	"$@"
	if [ -t 1 ]  # terminal
		then echo -en  "\33{for\33{read"
	fi
}

#  Check current directory, date, and time -- self-talking.
alias pwd="speaknow /bin/pwd"
alias cdate="speaknow /bin/date +'%B %-d'"
alias ctime="speaknow /bin/date +'%H:%M'"

Note that this speaknow function tests for an interactive terminal. Thus you can redirect pwd into a file, and get only the current directory. Run pwd interactively and you'll also get the escape sequences needed to read the output.

Most screen oriented applications, such as emacs, produce escape sequences of their own, compatible with the VT100 terminal interface. These sequences, which begin with "\33[", rather than "\33{", modify the color and highlighting of text fields, and manage the visual cursor on the screen. Although these escape codes are entrained in the standard output, it doesn't make much sense to dump them into the text buffer. Therefore, Jupiter passes them directly through to the console. This leaves only the text output in the buffer, which the blind user can read, and in some cases, make sense of. Escape codes that specifically reposition the cursor cause a newline to be placed in the buffer. This separates text fields within the buffer; else they would all run together into one big word. All of this is moot if the blind user chooses to access his screen oriented program in screen mode; but if he wants to run it in line mode, or review his interactive session later on, Jupiter tries to "do the right thing".

These two features, escape braces and escape brackets, can be disabled by "clmode b" and "clmode B" respectively. This is generally not done, except for debugging the system.

Back to top

Autoread Mode

The autoread mode deserves at least a paragraph of documentation. By default, Jupiter doesn't say anything unless you ask for it. You hear the chirps and clicks as text is sent to the screen, and if you decide to read it, you hit some function keys. Certain programs, whose output should always be read, are made self-talking, as described in the previous section. But what if you want to read the output of almost everything? You can do this by activating autoread mode. Forget about the self-talking utilities, you don't need them, and they are incompatible with autoread mode in any case. Now Jupiter reads text as it is sent to the tty. There are a few caveats.

  1. This feature does not work in screen mode. If I start reading, and more text is printed, and the screen scrolls, it's hard to keep the reading cursor attached to the scrolling text. I decided not to attempt it. Remember, Jupiter is not a screen reader. It is geared towards text applications with a command line interface.

  2. New text is not read if you are reading something else. This preserves the ability to type ahead, and monitor your commands via the clicks and beeps, while reading something else.

  3. Text that is merely the echo of your typing is not read. Remember, you can activate echo mode if you want Jupiter to confirm your keystrokes.

  4. Only text sent to the foreground console is auto-read. Text sent to any of the other virtual consoles is stored in the buffer as usual.

  5. New text is not read unless there is enough of it to send to the unit. In other words, we expect the first sentence to be complete. If the synthesizer supports index markers, Jupiter normally sents text sentence by sentence, for the highest speech quality. We wouldn't want to jump as soon as characters appear, and send the first word, and then send the rest of the phrase. Unfortunately the criteria for deciding when to start reading will always be imperfect. At present it is coarse -- too coarse. Jupiter starts reading after 100 characters, or after a newline character. Thus it doesn't read your dollar prompt, and maybe you don't want it to. At the same time, it doesn't read "enter your password:", without a newline, and you probably do want to hear this. I'll improve the algorithm in the near future. This is a new feature, and I'm still getting use to it.

  6. If reading stopped because Jupiter came to the end of a line, and one-line mode is set, new text will not be read until you hit a key - any key.

Back to top

Transparent Mode

If you share your computer with sighted colleagues, you can effectively put Jupiter on hold by hitting alt-=. A sighted user would never know that Jupiter was loaded, unless he happened to hit the alt-= key, which restores Jupiter to full functionality. You can also remove the jupiter module (rmmod) and reinstall it later (modprobe).

Back to top

Audio Feedback

Along with the clicks and chirps associated with console output, Jupiter produces several sounds (if sound mode is enabled) that provide valuable information. Using this mechanism, Jupiter effectively implements two separate audio channels, a control channel and a data channel, similar to stream sockets. The synthesized voice usually reads the words on the screen, while sounds convey status or error conditions. Here is a list of the sounds currently employed.

Startup:
Jupiter comes to life when insmod or modprobe successfully installs it, and it detects an open console tty. It allocates resources for each open tty, then generates the startup sound, a quick series of four ascending notes. At this point, Jupiter is gathering all console output for all virtual terminals. Any prior messages will not be stored in Jupiter's internal reading buffer, but recent messages can still be read via screen review, and kernel messages can be recovered using dmesg(8). The only other circumstance that invokes this sound is when leaving transparent mode and returning to Jupiter mode, as discussed in the previous section.

The startup sound tells you that Jupiter is up and running, even if your synthesizer's connection isn't working, and you can't read any words. In fact, you will be amazed how much you can get done without any speech -- acting only on the audio feedback at the console. You know the sounds of the common messages, standard and anomolous, hence you proceed accordingly. You can log-in successfully, issue a few simple commands, run sync (so your file system is safe), and try to reinitialize your synthesizer on its designated serial port (in case autoprobe failed). If this doesn't work, you can always reboot, and ask lilo to launch a backup kernel.

Bad Connection:
If Jupiter tries to connect to the synthesizer, either on a designated port or via autoprobe, and it cannot establish the connection, it issues a low long buzz. The same buzz is issued whenever you try to read words and the connection doesn't look good. It is sometimes helpful to enable the override mode, which tells Jupiter to ignore the DSR and CTS signals from the synthesizer. After all, the cable may not have all its wires in place. Flow control will no longer operate, and speech may run together, especially when reading long blocks of text, but at least you're hearing something. If this works, turn override mode back off, as a test. If you get the buzzer again, there is something wrong with the serial connection, specifically DSR or CTS.
Enable/Disable:
When a mode is cleared, or set, or toggled, a high tone indicates an active status, while a low tone indicates an inactive status. The latter is also produced when a speech command requires additional input, such as the buffer search, which expects a follow-on search string.
Echo Caps:
It's easy to hit the caps lock by mistake, and without visual feedback, you can accidentally type an entire paragraph in caps. Needless to say, this is very frustrating. In an effort to provide timely feedback, Jupiter generates a quick high beep whenever a capital letter is echoed to the screen. All other characters echoed from input, and all characters generated as output, produce simple clickss, as described in the overview. Thus the user always knows whether he is typing small or capital letters.

Since control keys are so important, and the caps lock is so annoying, most users will want to swap them. Thus the control key is just to the left of the a key, a much more convenient location. This can be done by running loadkeys on the following file.

#  Swap caps-lock and control
keymaps 0-2,4-6,8-9,12
keycode  58 = Control       
keycode  29 = Caps_Lock         
keycode  97 = Caps_Lock         
Error Bell:
Control-g produces a tone that is somewhat higher and shorter than the 100-ms 1-khz standard. This beep also accompanies a functional error in a speech command, such as asking whether 8 is upper or lower case, or issuing a key binding command that is syntactically incorrect.
Error Boundary:
If you try to read past the end of the text buffer, two quick ascending notes indicate a boundary error. The same sound is produced if you search for a string that is not present in the buffer. Essentially, the reading cursor has moved to the end of the buffer without finding a match.
Printk:
When the kernel sends a warning or panic message to the console, Jupiter generates a wavy sound, rising and falling quickly in pitch. This tells you to read the screen, if you are in screen mode, or look at the end of the text buffer, if you are in line mode.

Back to top

Speech Latency

Every speech synthesizer, including a human, performs better when reading an entire sentence, as opposed to a series of words in isolation. This is especially true in other languages, such as French, where the pronunciation of one word may depend on the initial letter of the next. For best results, Jupiter should send entire sentences, or at least phrases, to the synthesizer when reading large blocks of text. Unfortunately this exacerbates the problem of speech latency.

Suppose you are reading the Declaration of Independence, and you have just heard the words "We hold these truths to be self-evident." The phone rings, and you hit the shut-up key. Where is the reading cursor? It may be several phrases ahead, perhaps all the way down to "life, liberty, and the pursuit of happiness." Speech latency is the distance, measured in words or in seconds, between the speech you are hearing and the location of the reading cursor. If we send an entire sentence to the synthesizer, and receive no feedback until that sentence is spoken in its entirety, the latency could be large. The better synthesizers provide real-time feedback as each word is spoken, so the reading cursor can follow along. Doubletalk provides this feedback, hence Jupiter can transmit an entire sentence for best pronunciation, and still track the speech with its reading cursor. This is not possible in generic mode.

Back to top

Reading Words And Numbers

This section describes how Jupiter reads words and numbers. See the atomic command char for the rules governing punctuation marks.

Short numbers, four digits or less, are read naturally, rather than digit by digit. Thus 12 becomes twelve, 338 becomes three thirty eight or three hundred thirty eight (depending on context), 1492 becomes fourteen ninety two, 2nd becomes second, and 104th becomes one hundred fourth. This translation is not done if the number begins with a zero. Multi-token numbers such as 12,345 are also translated, up to six digits with literal mode on, and 15 digits with literal mode off. This is one of many tradeoffs between clear English speech and accurate unambiguous information. In the C language, you might encounter an array of initializers {102,305,907,484}. We wouldn't want to read this as a number in the billions. Since C programmers always work with literal mode enabled, they will hear each 3 digit initializer, separated by commas. On the other hand, 1,000 is probably one thousand, even in a C program (perhaps a comment or print statement), so we read it that way. We make statistical choices and hope we are right most of the time.

When a token consists of numbers and letters, Jupiter first separates the token into its components, such that each piece contains either letters or numbers, but not both. Numeric pieces are read as described above. Letter components are then split at case boundaries. This is especially useful for programmers who must deal with runTogetherVariableNames in their work. Once a letter component is isolated, Jupiter compares it to the items in the replacement table, as set by the configuration file. If the user has respelled this word, the new text is sent to the synthesizer. If the word is not found, Jupiter tries to strip off the suffix and respell the root word. This was described in the atomic command setpro. If the replacement text contains spaces or digits, the substitution is not made, because Jupiter isn't sure how to put the original suffix back on. If the word was not respelled by the user, Jupiter asks whether it is an English word, or whether it should be read letter by letter, as in xyz. This software is not trivial, and will not be described in detail. Needless to say, it sometimes makes mistakes, so don't be afraid to establish your own spellings in your configuration file. Words longer than six letters are never read letter by letter. It may not be an English word, but you don't really want to hear all those letters either. A word that looks like a name, with a leading capital letter, is pronounced, unless it contains no vowels.

The Jupiter system includes a sophisticated text preprocessor that reformats words and numbers, as described above. This preprocessor also translates dates, times, units, state abbreviations, and much more. Some of these transformations occur all the time; others are suppressed when literal mode is active. This preprocessor is well encapsulated, and can be linked into any adaptive speech package. It can also be incorporated into a stand-alone speech application such as an email reader. The details of this text -> TTS preprocessor are presented in another document.

Back to top

Saving The Text Buffer

There will be times when you want to save your text buffer to a file for future reference, before it scrolls over the horizon. This is especially true if something has gone wrong, and you need to send the log, complete with error messages, to a friend. Jupiter can do this, whether you are in screen or line mode. As you know, this feature is redundant in screen mode. Under Linux, you can already capture the screen image by running `cp /dev/vcs1 saveMyScreen'. You can even do this from another virtual console if you don't want to disturb the screen by leaving your current application and issuing this command. Jupiter allows you to save your text buffer in a similar manner.

At first you might anticipate a new atomic command (svbuf), which expects a follow-on string (the filename), and then saves the text to that file. A Linux expert could probably implement this, but I cannot. In fact I couldn't even do it in DOS. The problem is, keystroke commands are processed at interrupt level, and there are only certain things an interrupt handler can do, in DOS or in Linux. A handler can write to the serial port (thus talking to the synthesizer), because it "owns" that serial port, but it cannot write to a disk file, while (perhaps) other processes are in the middle of writing to that disk. The race conditions are unmanageable. One might set a flag and let a daemon within the kernel, or a daemon process, write the file a millisecond later, when the kernel is back in system/process mode, but this is just beyond me.

You might anticipate another approach, which Jupiter used when it ran under DOS. We could greate a new ioctl call that returns the text buffer, or at least makes it available to the running program. Since ioctl runs at system level, rather than interrupt level, this does not pose a technical challenge. In fact, Speakup has lots of new ioctl calls. However, this approach poses a serious administrative challenge when there are multiple independent developers. What's to keep me from accidentally reusing the same ioctl numbers as someone else? Nobody could have Speakup and Jupiter on the same machine. Even if there are no collisions, adding new #defines to the system ioctl.h header file forces an entire rebuild of the kernel, and requires extensive documentation. It is not self-evident that ioctl(0, 2739, &mybuf) fetches a copy of the text buffer.

Fortunately Linux has a better, I might even say brilliant, approach, namely the /proc file system. This directory looks like it has files under it, but they are really dynamic aspects of the system. For instance, there's a file for memory layout, another for interrupts, another for dma, another for allocated IO ports, another for each running process, and so on. Furthermore, modules and device drivers often create their own files under /proc, telling the user all about that device or module. Note that these files are plain ASCII, and are (generally) easy to read and understand. They are almost self-evident, requiring little or no documentation. Whenever somebody wants to pass new information back to the user from the kernel, he doesn't have to invent a new system call. Instead, he simply stuffs a new file under the /proc directory, which the user can read, and in some cases write to. This is a natural approach for Jupiter.

If you are on console 1, also known as tty1, and you want to save the buffer into foo, you would type `cp /proc/accessibility/jupiter/buf1 foo'. The other text buffers, corresponding to the other consoles, are in buf2 through buf6. Returns, which act as line breaks in the buffer, are automatically converted into linefeeds, the standard Unix line delimiters.

One thing you don't want to do, if you're on tty1, is type `cat /proc/accessibility/jupiter/buf1'. The beginning of buffer 1 is printed out onto the screen, whence it is appended to the end of buffer one. When cat gets to what was formerly the end of the buffer, there is more stuff to print. The snake chases its tail forever. Hit control c to break out of this loop.

Note that other adaptive modules can put other subdirectories in /proc/accessibility, consistent with my open architecture. Each adapter can do what it likes.

Now for the bad news; the files /proc/accessibility/jupiter/buf* can only be read by root. If they were readable by all, you would have no security or privacy. Someone could read your log and see, in plain text, the password you sent to your ftp server, etc. You will need to switch to a root console to save your session. I often leave console 6 up as root, to do privileged tasks. And I'm never in console 6 unless i have to do something as root. So you might hit alt-f6 to switch to root, run the save command, then hit alt-f1 to return to your work. Alternatively, you can right a setuid root program to save your buffer. (Consult the author if you're not sure how to do this.)

Of course, most blind users own and monopolize their own PC, and are more interested in convenience than security. If you fit this category, you will want to own the files under /proc/accessibility/jupiter, so you can read them any time you want without having to become root. This is accomplished by a module parameter. If your user id is 300, as shown by `id -u', you can pass owner=300 to Jupiter when it is launched, and all the files under /proc/accessibility/jupiter will be yours. Note that this approach still provides good security in a multi-user system, as well as convenience for you. Module parameters will be discussed in a later section.

Back to top

Talking Rescue Floppy Disks

If you want to give Jupiter a try without changing a thing on your current computer, or if you simply want some talking rescue floppy disks on hand, you can download two disk images from my web site: fdboot.img and fdramdisk.img. These disk images must be written directly to floppy disks. This can be done via the rawrite command under Windows, or by the dd command in Linux, as follows.

dd if=fdboot.img of=/dev/fd0 bs=1k
# change floppies - no mounts or unmounts required.
dd if=fdramdisk.img of=/dev/fd0 bs=1k

When you have made the floppies, insert the first one and reboot the computer. You may hear a bell as the machine restarts - it depends on your machine. Then you should hear a double bell at the lilo prompt. I always embed two control g's in my boot message. At this point you must type r and hit return, for rescue floppy. The disk will spin as the kernel loads. When the first disk stops spinning, put in the second and hit return. Once that floppy is read, you must enter your symthesizer, port, and preferred keyboard. This is how the screen looks at this point.


I'm ready to load the Jupiter speech adapter, but I need to know
the synthesizer and port.  Enter synthesizer, port, and keyboard layout,
space separated, on one line.
Synth codes are: dti (DecTalk internal), dte (DecTalk external),
dbe (DoubleTalk external), epc (Echo PC), bns (Braille N speak),
and g (generic).
Port is a number from 0 to 3.
Include this number even if the synth is internal; it selects
an io base address.
Finally, enter k for Karl's keyboard or s for the Speakup layout.
Example:  dbe 0 s    (DoubleTalk external on port 0 with Speakup keyboard)

Enter the codes as described above. If you're using BNS, be sure to put the unit in "block shaking" "line" mode. You have to do this from the keyboard; I can't configure it from my end.

Function keys and control keys should now activate speech. If you weren't sure of the port, you can try another port using the alt-r key. Follow alt-r with 0 through 3, for a different port. This resets the synthesizer on port 0 through 3.

If you're still not hearing words, or you only get one word every few seconds, type alt-o. This overrides the DSR and CTS signals. If the synthesizer is unknown to me, I'm probably not interpreting these signals correctly in any case.

Sorry, but the Dectalk PC cannot be accessed from floppies; there is no room for its firmware. You'll need to use the talking CD. In fact, you may need to boot from the CD in any case, since some computers don't even have floppy drives. Download the compressed CD image (about 30MB), uncompress, burn the image to a writable CD, and boot from that CD. But before you do, read the documentation on the talking CD.

In either the rescue floppy or the CD, there are a number of predefined mount points under /mnt. List the directory and you'll see what I mean. These are pretty self-explanatory. Type `mount /mnt/a1' to mount the first partition of drive 1 on /mnt/a1. Mount /mnt/b2 for the second partition of drive 2, and so on. /mnt/fd is the floppy drive, and /mnt/cd is the CD rom. You don't have to specify the file system type; we figure it out automatically. You can look at Linux files (ext2 or ext3), Windows, or DOS.

You must unmount these file systems when your done, or they may be corrupt. Cat /proc/mounts to see what is mounted.

If you have mounted a working Linux partition, you can chroot into that partition and go to work, as though you had booted straight in. If /mnt/a1 is a working Linux partition, type `chroot /mnt/a1', do your work, then exit, and you'll be return to the rescue CD. Note, you will not be able to mount /proc inside your Linux partition, and lots of programs, like ps, won't work without /proc. If you're going to be working inside a partition for a while, and you want access to all your favorite utilities, you should probably unmount /proc and /dev/pts first, then chroot to your partition, then remount them there. But you have to keep track. You have to unmount these virtual file systems before you exit back to your rescue disk.

When you're done with your rescue session, be sure all file systems are unmounted, then you can turn off your computer, or hit the reset button on the front panel. Make sure all rescue diskcs, or other disks, are removed before you push the button, or the computer will try to boot off your floppy again.

Back to top

Making Jupiter Part Of Your Kernel

This section provides instructions for patching Jupiter into your kernel.

Begin by downloading the package, which is a compressed tar archive. When unpacked, it creates a jupiter directory and populates it with this user's guide, several support files, and two patch files. The first patch, kernel-version.patch, modifies several functions in the keyboard and console device drivers. In this context, version is 2.2.16 or 2.4.4, for 2.2 kernels and 2.4 kernels respectively. select the appropriate one for your 2.2 series or 2.4 series kernel. The modified device drivers call Jupiter routines, which intersept keyboard input and console output. This patch also creates the accessibility directory, next to the sound directory, beneath drivers. I am trying to follow the sound card paradigm. Various sound card drivers are implemented as modules and plugged into one universal sound receptacle in the kernel. Similarly, many adaptive modules, within the accessibility directory, will all plug into the modified kernel. Use kernel-version.patch to "prepare" the kernel for adaptive modules.

The second patch, jupiter-version.patch, places the Jupiter speech system in a jupiter directory beneath the accessibility directory. This holds the source for the Jupiter speech package. Move to /usr/src/linux, apply both patches, rebuild the kernel and the modules, install the kernel, adjust lilo.conf, run lilo, reboot, and activate the Jupiter module. If you unpack Jupiter in your home directory, the following script should build the software. Remember that it must be run as root.

cd /home/your_login
#  We assume the downloaded archive jupiter.tar.gz is here
tar xzf jupiter.tar.gz
rm jupiter.tar.gz  # it's unpacked, don't need the tar file any more
package=/home/your_login/jupiter  # contains all the files
cd $package
cp talkcfg /usr/bin
cp jup_*.cfg /etc
ln -s /etc/jup_kad.cfg /etc/jupiter.cfg
lsrc=/usr/src/linux  # Linux source code
cd $lsrc
patch -b -p0 <$package/kernel-version.patch  # apply patch to the kernel
patch -b -p0 <$package/jupiter-version.patch  # bring in Jupiter speech adapter
make config
#  Say yes when it asks about CONFIG_ACCESSIBILITY
#  and say M for CONFIG_JUPITER
#  You can just hit return for all other questions.
make dep
make bzImage
cp $lsrc/arch/i386/boot/bzImage /boot/jrlinux  # jupiter ready linux
make modules
cp $lsrc/drivers/accessibility/jupiter/jupiter.o /lib/modules/*/misc
depmod -a

If patch cannot update a source file, you should contact the author. The compilations may produce a few warnings, but there should be no fatal errors. If all goes well, you will have a Jupiter-ready kernel in /boot/jrlinux. Edit the file /etc/lilo.conf and add a new block that looks something like this.

image=/boot/jrlinux
	label=jr
	root=/dev/hda1

If you have some other root, such as root=/dev/hda5, you will want to use that. You may also want to edit /boot/message, so that it says something like, "Type Linux or wait 5 seconds for the original kernel; or type jr for the Jupiter-ready kernel." Include a control g bell in this file, so you will "hear" the lilo prompt. Run lilo, and if there are no errors, reboot the computer. Type jr at the lilo prompt to launch the modified kernel. This kernel does not talk; it is simply ready for talking modules. It should do exactly what the old kernel did. You won't notice any difference. At this point you could install Jupiter using insmod, with the parameters (e.g. synthesizer and com port) on the command line, or you could use the modprobe facility.

Back to top

Module Parameters

Whether you run a pre-compiled jupiter.o, or your own compiled Jupiter (modified as you wish), you must define some startup parameters such as the type of synthesizer and the serial port. This is typically done by modprobe as it reads /etc/modules.conf. The following entries are typical.

alias access jupiter
options jupiter synth=double-lt port=0 baud=9600 lang=e owner=300
post-install jupiter talkcfg /etc/jupiter.cfg

The first parameter on the options line is the name of the synthesizer. At present Jupiter recognizes epc (echo pc), dti (Dectalk internal), dte (Dectalk external), dbe(Doubletalk external), bns (Braille N Speak), and g (generic). If the designated synthesizer is not recognized or supported, generic is the default. Keep in mind, generic works with most external synthesizers.

The baud= parameter sets the baud rate for an external synthesizer. The default is 9600. Only the "standard" baud rates are supported.

The port= parameter sets the serial port. Valid ports are 0 through 3, following the /dev/ttyS? convention. Dos users can simply subtract 1 from the com port number. If there is no port parameter, Jupiter will autoprobe for the device. Keep in mind, Jupiter cannot autoprobe for a generic synthesizer. Note that the serial port is always polled, saving that precious IRQ for the sibling serial port.

The owner parameter establishes the owner of the files under /proc/accessibility/jupiter. These files convey the status of the running adapter. Recall that buf1 through buf6 hold the text buffers corresponding to the 6 virtual consoles. You will usually set owner to your user id, so that you can own these files.

The lang=e parameter specifies English. Other languages are not supported at this time, although I am working on a Spanish version, and any help in this area would be greatly appreciated.

Add these fields to the insmod command line, orun `modprobe access', and Jupiter should be installed with your parameters. If you're using modprobe, the post-install directive can also configure Jupiter with your key bindings. The talkcfg program should be in the standard Linux PATH, or you can use an absolute path for this utility.

Back to top

Dectalk PC Card

If your synthesizer is a circuit board inside the computer, rather than an external unit on a serial port, you won't be using the port= parameter above. Instead, you might need to specify io=address, but only if your card is using a nonstandard address space, as set by dip switches on the unit. At present, only the Dectalk pc card is supported, although this is a very popular synthesizer for blind users. Set synth=dec-pc if you have this card. Set io to 0x240, 0x250, 0x340, or 0x350 if you have changed the card's address space via its dip switches. This should not be confused with the Dectalk express, synth=dec-ext, which is an external unit on the serial port.

The dectalk card and its resident software are bundled separately. At bootup, your computer must download the Dectalk software into the card, or it won't say a thing. Once again I use the /proc file system, rather than creating a lot of new ioctl calls. The directory /proc/accessibility/jupiter will contain three card-specific files, in addition to buf1 through buf6. These are write only files, used to transfer the Dectalk software down to the card. The "firmware" file downloads the kernel, "dict" is for dictionaries, and "exe" is for other executables that run on the card. You might be tempted to simply copy the Dectalk files into their /proc counterparts, but it's safer to use the jdtload utility that I provide. A typical Dectalk load command looks like this.

jdtload kernel.sys dtpc.dic lts.exe ph.exe cmd.exe usa.exe go

Somewhere near the beginning of your startup script, /etc/rc.d/rc.sysinit in Redhat, you should install the Jupiter module, load the Dectalk software as above, and run talkcfg to configure your keyboard, in that order. Remember that you cannot run jdtload until /proc has been mounted. Thus the insmod command can be at the top of the file, to capture as much output as possible, but the next two commands will have to wait until /proc has been mounted.

So -- where do you get all those Dectalk firmware files? Well they came with your card, but they are bundled up in a self-extracting Dos program, to the great annoyance of Linux users everywhere. You have to boot up on Dos, if Dos is on your system, or run dosemu under Linux, or ask a friend with a Dos box for help. Somehow, the install program must be run under Dos, to give you the files you need. And this is all suppose to happen before your synthesizer is talking. :-( In opposition to this Dos-centered mindset, I have some Dectalk files you can use, and they are good enough to get you started, but they won't be the latest and greatest. As soon as you can arrange it, you'll want to use the files that came with your card.

This download procedure also throws a monkey wrench into my rescue floppy disks, since there is no room for the Dectalk firmware on these floppies. Not to worry though - the talking CD rom is coming soon.

Back to top

After Installation

This is an optimistic section to be sure. When the patched kernel boots successfully, or the rescue floppy comes up successfully, and the Jupiter module loads successfully, the first thing you will hear is the startup notes, as described in an earlier section. This tells you Jupiter has allocated its buffers and is ready to intersept keyboard input and console output. If you didn't specify any module parameters, you will also hear the long low buzz that indicates a bad connection to the synthesizer. This is because the two defaults, generic synthesizer and autoprobe, are mutually incompatible. Jupiter cannot autoprobe for a generic synthesizer. Alternatively, you may have specified port and/or device, and Jupiter couldn't make the connection to its satisfaction. If you hear this buzz, you'll have to do something about it, but not right away. For the moment, patience is a virtue.

Next you will hear the clicks and chirps of your prompt, or any other output messages that may follow the installation of this module. Cat some files and listen to the audio stream. It sounds like an old paper teletype running at 1,500 baud. In fact I created these sounds because I began my programming career on these teletypes, before synthesized speech became affordable, and I could sometimes accomplish a great deal using only this audio feedback. Once you are use to these sounds, type "sync", to safe your file system. (Thanks to NASA, safe has become a verb.) You never know what will happen when you first ask Jupiter to speak, so caution is in order.

Now hit F9. This is initially bound to a command that toggles single-line reading mode. In other words, we are still cautious -- still not messing with the synthesizer. You should hear a short high tone as the mode is enabled. Hit the key again and note the short low tone of a disabled mode. Repeat this, and gain some confidence; Jupiter is intersepting keyboard input and interpreting it properly.

Finally you are ready to invoke speech. Hit F5 to read the last complete line. If you got a buzz at startup, you'll get another buzz now, because we're not connected to the synthesizer. We need to fix this problem, if possible. Forget autoprobe -- it didn't work. Hit alt-r, followed by a digit from 0 to 3, indicating the serial port. For you DOS folks, ttyS0 is com1, and so on. This does not trigger the verification sequence, as autoprobe does, so silence isn't always golden, but it's a good sign. Another buzzer is definitely a bad sign. Make sure your synthesizer is properly connected and turned on, and make sure you've specified the right serial port.

Let's suppose you've gotten past the nasty buzzers. Hit F5 again, and you should hear the last complete line, which is the sync command that you typed in (since sync produces no output). If you hear this output, hit F5 again and again, in quick succession, so that each interrupts the previous. The synthesizer should interrupt each instance of the word "sync" to read the next. In other words, you are testing the shut-up feature, which varies from one model to another. If Jupiter is assuming a generic synthesizer, it assumes ^X is the shut-up character. If this is not the case for your unit, speech will not be interruptable.

Now test flow control by hitting F7 and F2. This moves to the top of the buffer and starts reading. Make sure you left single-line mode off (when you were playing with F9). If you hear a continuous parade of coherent sentences, you're in good shape. If phrases, words, and even parts of words are omitted, Jupiter is sending text faster than the synthesizer can receive it. In other words, flow control isn't working. The default flow control is CTS, an RS-232 standard. If your unit has any other type of flow control, such as x-on x-off, we need to add support for this in tc_synth.c. It's not hard to do; I just haven't done it yet. All the units I've worked with use CTS.

Even if shut-up and flow control don't work, you can get quite a bit done. If you're hearing words, the aforementioned shortcomings are merely inconveniences. If you haven't gotten any words yet, or you only get one word every few seconds, hit alt-o. This activates override mode, so that Jupiter pays no attention to the DSR or CTS signals. Flow control is guaranteed to fail now, as text is sent to the unit on blind faith. But if your unit is connected, and at the appropriate baud rate (9600 by default), you should definitely hear something now.

Once you hear words and start using the system, you will find that the assigned functions are not right for you. There are no key commands to interrogate individual words or letters, and for you screen-mode users, there is no way to locate the visual cursor on the screen. You need to load a configuration file. If you've made your own, via some other talking system, great. But if not, use one that comes with this package; either the Speakup version or my version. This won't be right for you either, but it's a start. Import the talkcfg utility and the config files, and run "talkcfg jup_??.cfg". Note that post-install does this for you, if you ran modprobe Jupiter. If you load my config file, control keys interrogate letters and words, and shifted function keys perform exotic functions. Review the config files; they are well commented.

As a final test, hit F7 shift-F7 sync <return>. This starts at the top of the buffer and looks for the word sync, which you typed in earlier. Jupiter should find this text fragment without difficulty, and proudly say "sync".

The next thing you will want to do is restructure the config file to suit your needs and working conditions. If you spend a lot of time in screen mode, you will probably want to replace most of my key bindings. I don't have any commands to read the character, word, or line indicated by the visual cursor, but you will want these, and more. If you spend 8 hours a day working on a fixed screen, such as order entry, you can build keystrokes that jump straight to the fifth line, third word. Perhaps this is the customer's name, or his account balance. Jupiter is a system that isn't very good at the start, but it can make you incredibly productive if you work at it. As always, I am ready to answer any questions. Contact me via email at karl@eklhad.net, or by phone at (USA) 248-524-1004 during regular business hours EST.

Back to top