Components Of The Macintosh PlainTalk Speech Recognition System
Installation Of Speech Recognition On The Macintosh
Implementing The HyperCard Side Of Our Speech Recognition Idea
Implementing The AppleScript Side Of Our Speech Recognition Idea
Complications With Our Voice Commands
Preparing For Our Presentation
In this project, we used the Macintosh PlainTalk Voice Recognition System, and the AppleScript scripting language to add voice navigation to an already existing HyperCard game that is written in HyperTalk. Originally, we were told that this could not be done because a Software Developer Kit that interacted with the PlainTalk system on the Macintosh was not yet available. However, careful research and experimentation proved differently.
Before proceeding, it is important to define speech recognition, and describe the three available types of speech recognition. According to The Free On-line Dictionary of Computing speech recognition is defined as follows:
The identification of spoken words by a machine. The spoken words are digitised (turned into sequence of numbers) and matched against coded dictionaries in order to identify the words.
There are actually three types of speech recognition systems that we can refer to as fully trained, partially trained, and speaker-independent. These are also described in The Free On-Line Dictionary of Computing as follows:
Most systems must be "trained," requiring samples of all the actual words that will be spoken by the user of the system. The sample words are digitised, stored in the computer and used to match against future words. More sophisticated systems require voice samples, but not of every word. The system uses the voice samples in conjunction with dictionaries of larger vocabularies to match the incoming words. Yet other systems aim to be "speaker-independent", i.e. they will recognise words in their vocabulary from any speaker without training.
Before speech recognition can be installed on the Macintosh, it is necessary to install "English-Text-To-Speech". This was described in our last presentation on Speech Synthesis, so we offer a link to it here.
The Macintosh English Speech Recognition System consists of three parts as described by the About PlainTalk 1.4.1 file that is available on the Apple Support And Information Web Site:
With Speakable Items, if you say the name of any item that is stored in the Speakable Items folder (that is stored in the Apple Menu Items folder), the computer acts as if you double-clicked the item. This feature can be turned on and off through the Speech control panel.
The Speech control panel can be used to set various preferences which concern how the Macintosh speaks and responds to spoken commands. For example, the Macintosh can be set to listen only when you are holding down a special key. Further, the Macintosh can be told to respond only to commands that are prefixed with the computers name (which, by default, is "Computer"). For our game, we suggest selecting the option where-by after saying "Computer", if you wish to perform other voice commands, you need not repeat "Computer" for 15 seconds after the last time you have said it.
The latest version of the PlainTalk speech recognition software is version 1.4.1. This version requires the following:
As can be seen, if we wish to use this software on the Centris 660 AV machines in our lab, it is necessary to use the older PlainTalk version, 1.3. To see the PlainTalk 1.3 README file, click here.
Installation of the speech recognition software on the Macintosh was a fairly straightforward task. First, we had to obtain the PlainTalk software from the Apple Support And Information Web Site. Next, we ran the installer which created the appropriate files on the system. However, we got tired of reinstalling the system each day since Assimilator deletes these files each time the machine is booted. We added the files to the Assimilator client distribution folder on the server. This itself was not a trivial task because the installer would not allow us to select a location for installation - the installer installed the files into the first "System Folder" that it saw. This made it difficult to select the appropriate pieces to install into the Assimilator client distribution folder. Nevertheless, now all of the Macintosh Centris 660 AV's in the lab had the speech recognition software installed.
The latest version of the speech recognition software that we were able to install on the 660 AV's was PlainTalk version 1.3. Later versions are only usable on the Power Macintosh as was indicated in the last section. We were not at all impressed with the speech recognition on the 660 AV's - the machines consistently misinterpreted what we were saying. We decided to try the PlainTalk version for the Power Macintosh on the Power Mac in our Media Lab. For this, we had the CD-ROM that came with the machine to get the software from. We installed PlainTalk version 1.4 into the Power Macintosh's Assimilator client distribution folder on the server, facing the similar problem from before - the installer installed the files into the first "System Folder" that it saw on the machine which is not what we wanted.
An update to PlainTalk 1.4, PlainTalk 1.4.1, is available from Apple. However, the update does not contain any new features that would be especially helpful to us, so we did not get it. Our results using PlainTalk 1.4 were better, however, not anywhere near perfect, which just goes to show that this is an evolving multimedia technology. We used Plaintalk 1.4 on the Power Macintosh for the remainder of the project.
Since the idea in our project was to add voice navigation to a HyperCard game, our next task was finding the game that we would be using. After a lot of searching on the Web and experimenting with a multitude of games, we found a Video Poker stack that would have been perfect for our project. The stack was freeware, however, it was extremely protected. We tried to crack the stack with various utilities that we found on the net. The stack password was removed, however there was internal protection used on many of its scripts. Handlers would automatically set the user level down to 1, and hide the menu bar on a regular basis. In desperation, we even tried copying and pasting cards from the original stack into a new stack, one at a time, to see if we could pinpoint the protection and get rid of it. This was done with no success as the stack used various XCMDs and XFCNs that made things more difficult. It was after one and a half weeks of experimenting with Video Poker that we sadly decided to move on and find a new game. This was when we came across HyperBattleship.
HyperBattleship is a simple implementation of the old battleship game that is written in HyperCard. HyperBattleship is written by Claris Corporation. The interesting thing about this game is that the players play the game through the network. We tried the game out, and enjoyed it. We immediately began looking at its HyperTalk scripts and thinking of ways that we could add voice recognition to it. However, before we could move on, we needed to learn about AppleScript - the scripting language that would provide the interface for the implementation of our design.
According to The Free On-line Dictionary of Computing AppleScript is defined as follows:
An object-oriented shell language for the Macintosh, approximately a superset of HyperTalk.
This definition certainly does not provide much information. We received more information about AppleScript from Apple's Developer Services section on Apple's Web Page. Some of the things that Apple's Developer Services say about AppleScript are as follows:
AppleScript® is a powerful and versatile tool that makes it easy to integrate the functionality of scriptable applications into a single, seamless, custom solution. Working with AppleScript is easy and intuitive. The AppleScript language features a natural syntax, making even complex scripts easy to build, understand and maintain. And with the included FaceSpaninterface builder, you can easily create applications with a professional look and feel. Whether you're an in-house developer, a systems integrator, a consultant, or simply a user who wants to get the most out of your Macintosh, AppleScript provides a breakthrough in computing flexibility and functionality.
AppleScript requires only 4 MB of memory, and System 7 or later. Installing it on our systems in the Media Lab was not necessary as it was already installed. HyperCard is a scriptable application which means that we can interact with it through AppleScript commands.
We tried to find documentation on AppleScript on the Web, but unfortunately, almost every link we clicked on seemed to be unavailable. Nevertheless, we list a couple of interesting AppleScript Web sites in the "References" section of the report. We checked the Yorkline catalog and only found a single video on AppleScript. We found an AppleScript help utility that came with HyperCard that provided enough information to introduce us to the notion of AppleScript.
If we wish the Macintosh to be able to recognize voice commands and execute a file based on the voice command, we place the commands in the "Speakable Items" folder (that is in the Apple Menu Items folder). If we could construct AppleScript scripts that would perform certain actions in the open HyperCard application, we could place these scripts in the "Speakable Items" folder. To be able to do this, we would need to learn the basics of how to interact with HyperCard through AppleScript. The standard battleship game board contains 10 rows labelled 1 through 10, and 10 columns labelled 'A' through 'J'. Our original idea was to have the user speak a letter followed by a number. After the letter was spoken, the AppleScript script for that letter would send the letter to the HyperCard stack. Similarly, after the number was spoken, the AppleScript script for that number would send the number to the stack. A certain voice command would cause the system to take the entered letter and number as the current users move.
We would need to add the following HyperCard functions to the HyperBattleship stack:
The original HyperBattleship HyperCard stack internally supported a letter and number scheme for naming positions. However, it was not necessary to name the actual positions on the game board since the user would be clicking on a position to make their move. We needed to uncover this hidden board representation as our voice recognition users would need this information to be able to select their moves. We added these labels to the stack, but had to rearrange the stack card size because the labels would not fit. Of course, after we rearranged the card size, many components in the stack did not work correctly, and we had to change hard-coded card size values in numerous places in the stack. It took quite a while to figure out how to do this as the background script in the stack kept resizing the card to its old size.
Now, we were ready to implement the HyperCard functions described in the last section. Our HyperCard takeLetter() function is defined as follows:
function takeLetter newLetter
global currentLetter
global currentNumber
put empty into currentLetter
put newLetter into currentLetter
put empty into currentNumber
put "Recognized " & currentLetter & "." into background field Recognized
end takeLetter
This function takes the letter that is sent to the stack, and stores it in a global variable. If a letter and number combination has been already been spoken, and a new letter is spoken, the voice command is reset. This provides a mechanism for the user to make a correction to his voice command in the event that he changes his mind, or the system misinterprets his command. For example, if the user speaks "A" then "5", and the user decides it is really B5 that he wants, he can correct the error by saying "B", and the voice command A5 will be reset to B. If a letter has already been spoken, and another letter is spoken, the voice command is also reset. Finally, the current recognized combination is placed in a field that is visible to the user so that he can see what has been recognized.
Our HyperCard takeNumber() function is as follows:
function takeNumber newNumber
global currentLetter
global currentNumber
if currentLetter is empty then
put "Error - No Letter!" into background field Recognized
else
put empty into currentNumber
put newNumber into currentNumber
put "Recognized " & currentLetter & currentNumber & "." into background field Recognized
end if
end takeNumber
This function takes the number that is sent to the stack, and stores it in a global variable. If a number has already been spoken, and a new number is spoken, the number in the voice command is changed without changing the letter. For example, if the user speaks "C" then "3", and the user decides that it is really C4 that he wants, he can say "4", and the voice command changes to C4. If no letter has been spoken, an error is output in the recognized box - "Error - No Letter!". Finally, the current recognized combination is placed in a field that is visible to the user so that he can see what has been recognized.
Our HyperCard doVoiceMove() function is as follows:
function doVoiceMove x
global currentLetter
global currentNumber
global voiceActivated
if currentLetter is empty then
put "Error - No Letter!" into background field Recognized
put empty into currentNumber
else if currentNumber is empty then
put "Error - No Number!" into background field Recognized
put empty into currentLetter
else
put true into voiceActivated
send "mouseup" to background field "Enemy"
end if
end doVoiceMove
If a valid letter and number have already been recognized, this function simply sets the global variable that determines if the current command is a voice command or not to true (voiceActivated), and then sends a mouseUp event to the game board. The event handler in the game board finds that this is a voice command, and grabs the letter and number appropriately. If a letter has not yet been recognized, an error is output in the recognized box - "Error - No Letter!". Similarly, if a number has not yet been recognized, an error is output in the recognized box - "Error - No Number!".
on mouseUp
global currentLetter
global currentNumber
global voiceActivated
put hbsStatus() into curStatus
if curStatus is "Ready" then
if voiceActivated is true then
put currentLetter & currentNumber into gridClick
else
put gridItem(the clickLoc,rect of me) into gridClick
end if
...
end mouseUp
This is a portion of the code that we added to the Enemy playing field. Before our additions to the game, when a user would click on a location in this field, the system would figure out what location was clicked, and would send a bomb message across the network. The code has been slightly modified to look at the "voiceActivated" variable to determine if a voice command is activating the move. Other minor changes later in this function reset the voiceActivated variable to false, and clear the recognized box and the global variables that store the chosen letter and number.
In addition to these small coding changes, we added the recognized box to the game board that indicates what the current voice move will be. We also made many minor adjustments to card sizes throughout the stack.
After we had the HyperCard side of our idea implemented, it was time to implement the AppleScript side. Up until this point, we had been able to use the HyperCard message box to simulate the voice commands. We did this because we wanted to be sure that everything was working alright in HyperCard before moving on to AppleScript. Our AppleScript implementation would require us creating 21 AppleScript scripts. The first 10 would be the letter scripts. These scripts would send the appropriate letter to the stack. The next 10 would be the number scripts. These scripts would send the appropriate number to the stack. Finally, the 21st script would send a "doVoiceCommand()" call to the HyperCard stack. The user would copy these 21 scripts into the Speakable Items folder prior to playing the HyperBattleship game, and take them out aferwards.
We only needed to learn a few AppleScript commands to make things work. A tell block was used to tell HyperCard a sequence of commands. For example:
tell application "HyperCard"
<Put what you want to tell HyperCard
here.>
end tell
A do script command allows us to send a HyperTalk command to HyperCard through the AppleScript script. For example, to call the function myfunc() in the current HyperCard stack, the following AppleScript script could be used:
tell application "HyperCard"
do script "myfunc()"
end tell
For many of HyperCard's built in commands, you do not need to specify do script, as these commands are built into HyperCard. For example, to tell HyperCard to go to card 1 of the current stack, the following AppleScript script could be used:
tell application "HyperCard"
go card 1
end tell
Here's a sample of our 'A' letter script:
tell application "HyperCard"
go card "Game" of stack "HyperBattleship!"
do script "takeLetter(A)"
end tell
Here, we tell HyperCard to go to the appropriate card of the BattleShip stack, and call our takeLetter() function. Unfortunately, the first line will tell HyperCard to load the stack and go to the appropriate card, even if the stack is not already loaded.
Here's a sample of our '1' number script:
tell application "HyperCard"
go card "Game" of stack "HyperBattleship!"
do script "takeNumber(1)"
end tell
Similar to the previous script, we tell HyperCard to go to the appropriate card of the BattleShip stack, and call our takeNumber() function.
Here's the "fire" script:
tell application "HyperCard"
go card "Game" of stack "HyperBattleship!"
do script "doVoiceMove()"
end tell
Similar to the previous scripts, we tell HyperCard to go to the appropriate card of the BattleShip stack, and call our doVoiceMove() function.
We wanted our scripts to be as robust as possible, however, things were more difficult than we had ever expected. By default, the commands spoken would go to the current active stack, which might not be HyperBattleship. It took quite a while before we figured that we could send a command directly to the HyperBattleship stack with the "go card" commands used above. However, now the name of the stack is hard-coded in the AppleScript scripts. If the user changes the name of the stack, the voice commands will no longer work. The HyperCard name is also hard-coded. This means that if you want to run the BattleShip game using the HyperCard Player that you need to change its name to HyperCard.
Now, we had the pieces that we needed to make the game work. We turned on Speakable Items from the Speech control panel, and were ready to give our game a test.
Our speech recognition concept seemed utterly simple, and we saw no reason why it would not work. Unfortunately, there were problems that we did not foresee.
First, the speech recognition software gave us a great deal of trouble dealing with single letters and numbers. For example, with the scripts A through J and 1 through 10 in the Speakable Items folder, speaking A a number of times in a row would execute various voice commands, but most often, not the A command. The numeric commands gave the same difficulty. In fact, no matter what we tried, the machine would not recognize the number 1 at all. We tried renaming the scripts - "A" became "AYE" and "B" became "BEE". We renamed the numeric scripts - "1" became "one", "2" became "two", etc. Though this produced slightly better results, more than 70% of the time the machine misinterpreted what we were trying to say. It was at this time that we realized that we would not be able to have sole letters and numbers for our rows and columns.
All hope was not lost as we thought of a way that the computer with not confuse words with each other. We immediately went and got a copy of the phonetic alphabet. We thought that this would certainly work without any difficulties since all of the words are phonetically different. Unfortunately, things got only slightly better, and we were still receiving an enormous amount of inaccuracy. There was no way that any user would be putting up with this sort of inaccuracy in playing our game.
Finally, we had had it. We started to give the scripts peoples names - the game board columns received male names while the game board rows received female names. After each modification, we would test out the entire set of names as we found that if all of the names were working, and we added a name, the new name might make a group of the other names not work.
The game board columns were now:
Alex, Blake, Cheeko, Dennis, Ennio, Farley, Gipper, Harold, Izik, and Jason
The game board rows were now:
Kathy, Linda, Melissa, Nadine, Orca, Pretty, Quality, Rachel, Sima, and Teresa
The voice recognition system had a terrible time trying to recognize words that began with a "Q", so we renamed this name appears as "kwality" in the Speakable Items folder.
It took several days of working on these names to finally come up with a voice recognition accuracy level that we believe most game players would put up with. However, the system is still not anywhere near perfect.
If these problems were not enough, the speech recognition system would sometimes crash unexpectedly. Every once in a while, when the system was trying to recognize our voices, a "System Error -10" would appear with the infamous Apple bomb beside it. We were given the option to "Restart", however, each time that we would select this option, the Macintosh would crash, and we would have no choice but to shut it off and reboot it.
After we had found names that could be recognized by the PlainTalk system, we needed to modify the stack once again. Previously, we had needed to rearrange the stack because we needed to add letter and number labels. Once again, we had to rearrange things as we added the longer names to the stack, though we left the letters and numbers for the current users game board since the user would not need to use voice commands on his own board. Unfortunately, these changes required us to raise the card size yet again, and then go back and modify the stack in various places where the card size was hard-coded.
During the course of our project, we faced a number of difficulties as you have read about above. There were yet another three difficulties that we had - a virus in our stack, HyperCard Power PC compatibility problems, and speed problems.
Just as we thought our problems could not get any worse, we found a virus in our HyperBattleship stack. We originally thought that we had found a bug in HyperCard, as our stack code that we had entered at the end of the stack script was no longer at the end any more. Further investigation showed a keyword "merryxmas" at various places in the stack script - we had obtained the Merry XMas virus - a virus which contaminates the HyperCard home stack, and then any stack that is loaded thereafter. It took us a while to find a cure for it. Some programs that we found would add an antidote to the stack. The virus would remain in the stack, but code would be added that would ensure that the virus would never run. However, we were not comfortable with this. Finally, we came across a program called "Virus Warning" that removed the virus from our stack, and the Home stack on our machine. We checked the file server for the virus, and it could not be found.
Next, we were faced with what we believe to be Power PC compatibility problems. During the course of the project, we found that the Power PC gave us some problems with HyperCard. For example, we would go to select the "paint tool", and we would be told that there wasn't enough memory. We would check the memory remaining, and there would be plenty. We even tried with virtual memory on and off. We ended up making modifications to our stack on the 660 AV's, but running the stack on the Power PC. This was quite annoying, but was necessary because we needed the voice recognition of the Power PC. Nevertheless, after we changed the size of the cards on the Centris 660 AV machines so that we could add the names to the stack, we found that the stack would not size correctly on the Power PC. We experimented, and found that though HyperCard 2.2 did not display our stack correctly on the Power PC, the HyperCard Player (version 2.3) that is in the Apple Extras folder on the Power PC played our stack just fine. Unfortunately, though, our AppleScript scripts tell "HyperCard" and not "HyperCard Player" commands, so we had to copy the "HyperCard Player" and rename it to "HyperCard" to make our stack work on the Power PC.
The final problem that we dealt with was a problem of speed. After our additions to the game were completed, we realized that the speed between the time when a voice command is issued and the system executes the AppleScript scripts that we had created was actually too large. Though the system would allow you to speak both names, and a fire command quickly, it would take some time for the system to send the data to HyperCard. We tried a number of things to speed this time up that you can read about in the next section.
We came to the conclusion that the speed problem with our game was due to the speed of the hard disk, so we tried a number of hopeful solutions to the problem. First, we created a RAM Disk that contained 1.5 MB. We then copied our scripts to the RAM disk. We then created aliases from the Speakable Items folder to the RAM disk. Our hope was that because the speed of the RAM disk is much higher than the hard drive that this would alleviate our problem with load time of the scripts. However, we saw little difference in execution time. We later realized that this was due to the fact that the hard disk still had to be accessed to follow the alias to the RAM disk.
Next, we tried copying the entire Speakable Items folder to the RAM disk, and aliasing the Speakable Items folder from the System Folder. Unfortunately, the Speech Recognition system loaded, but immediately quit as it did not see any of the Speakable Items.
Next, we considered whether we would be able to copy the entire System Folder to the RAM disk by making it slightly larger. However, the System Folder on our systems takes up 37 MB in total, and is thus larger than our entire system memory. Further, since many of the files would already be in use in the System Folder, the system would not let us copy them to another location.
Next, we increased the Disk Cache size in the Memory Control Panel. Our script files are small, and we assumed that once they were all loaded for the first time, they would not have to be reloaded each time they were called thereafter. If this was the case, our system could load all the scripts initially in the beginning once, and later speed improvement could be had when the scripts were accessed thereafter. Unfortunately, this did not create any noticeable difference in speed.
Our next attempt at increasing the speed of the scripts running was an experiment at the AppleScript level. It has two parts. Our AppleScript scripts are compiled in the script editor so that they can run faster. The scripts are saved as "Application" files. However, one of the compile options asks whether you want the script to remain in memory. We normally ensure that the script file does not remain loaded in memory to save memory. However, the files are small, so one of our ideas was to keep the script files loaded. Unfortunately, because the scripts are over after the end tell statement, keeping the scripts open does little help since as each script is called, it has no code left to execute. A similar idea that we had was to surround the tell and end tell statements with a repeat and end repeat loop as follows:
repeat
tell application "HyperCard"
...
end tell
tell application "Finder"
activate
end tell
end repeat
Now, after a script was loaded for the first time, it could execute normally. However, after execution, the Finder would be made the active application. By doing this, we would stop the script from running any further. However, the repeat loop would ensure that the next time the script was called, the command would once again be sent to the HyperBattleship stack. Our idea sounded very promising, however, when we tried it, we found that the script would stop executing when the Finder was activated, but would continue to execute when HyperCard became the active application. This meant that as more scripts were loaded, all of the scripts would execute at the same time when HyperCard became the active application, creating a lot of confusion - definately not what we had wanted. Also, since we were making the Finder the active application to stop the scripts from running continually, this also meant that HyperCard could never be the active application for long, which would have the side effect of not allowing the user to use the mouse to play the game.
Next, we had an interesting idea. We made a copy of the "Speakable Items" extension in the extensions folder, and then proceeded to load ResEdit, and view the resources. We figured that if we could find a path that indicated where the Speakable Items folder existed, we could easily change that path point to the location of a RAM disk on our system. Using ResEdit, we did find the actual name of the Speakable Items folder. We changed this to "Speakable Items1", and rebooted the computer. Sure enough, Speakable Items would not begin until we renamed the Speakable Items folder to Speakable Items1. However, next, we used ResEdit to specify a full path to the RAM disk. This did not work. It appears that part of the path is hard-coded - probably the part that finds the System Folder on the current machine. We experimented with this for a while, but it appeared that our idea would not work.
As a final attempt to make our scripts load faster, we took a look at the Macintosh OS Software Developer Kit provided by the professor. In this, we found a file called "Scripting the Finder". Here, we read about a technique in using a scripting property and a library to ensure that subsequent executions of a particular script are loaded from memory, and not disk. However, using this technique would require a lot more work and due to the vast amount of time that we had already put into the project, we did not have the time to look at this. However, we believe that this is an area for further investigation.
As you can see, we tried various ideas to ensure that our voice commands would activate a bit faster. However, in the end, we were not able to speed things up at all. If more time had been available, we might have been able to find a solution to this problem.
One of the nice features of the HyperBattleship game is that it is a two player game that can be played over a network. We wanted to be able to demonstrate this during our presentation, however, the lecture hall that our class is in has only a single network connection. We found some network cables, and through experimentation, we were able to set up a small AppleTalk network. Rather than using EtherTalk, we used LocalTalk. LocalTalk is slower, but did not effect our presentation since we do not need the data transmission to be very fast.
In this project, we did what we set out to do - namely, we used the Macintosh PlainTalk Voice Recognition System, and the AppleScript scripting language to add voice navigation to an already existing HyperCard game. The method that we used for our implementation could be used to add voice commands to other HyperCard games or even other applications that are scriptable with AppleScript. In the end, we found another two resources that could have been studied in more detail, had more time been available. First, Apple's Speech Sprocket for developing applications using speech recognition on the Macintosh is now available. Also, Digital Dreams has introduced a HyperCard XFCN for speech recognition through HyperCard. However, this product was only available in trial version that would expire on April 1, and it was already past that date when we found it. From our surfing the net, it seems as if speech recognition is really catching on. Even Apple has the start of a Speech Recognition page on the net. Speech recognition is an emerging multimedia technology that we can only see expanding in the near future as we get faster computers with more memory, and faster disks. Speech recognition is here to stay.
Aizic, Steven and Jason Keltz. Speech Synthesis.
Apple Computer, Inc. About PlainTalk 1.4.1.
Apple Computer, Inc. Apple Speech Recognition and Synthesis.
Apple Computer, Inc. Apple's Speech Sprocket.
Apple Computer, Inc. Developer Services Search.
Apple Computer, Inc. HyperCard AppleScript Reference, 1993.
Apple Computer, Inc. Mac OS Software Developer Kit, 1994.
Apple Computer, Inc. PlainTalk 1.3 README file.
Apple Computer, Inc. Support And Information Web Site.
Bernier, Marc and Elisa Green. XCMD/XFCN.
Claris Corporation. HyperBattleship.
DAscenzo, RM. Mac Speech.
Hunt, Andrew. comp.speech Frequently Asked Questions Web Page.
Lapin, Jonathan. Macintosh Speech Recognition.
Noon, Bill. ListenUp! Speech Recognition Plug-In For Netscape 2.0.
Phillips, Stephen. Morse Code and the Phonetic Alphabets.
Soghoian, Sal. Sal's AppleScript Snippets.
The Free On-Line Dictionary of Computing
The Internet Access Company, Inc. Every Known Scripting Link.
Wang, James. Macintosh AV General FAQ.