Introduction

This software is a library package aimed at developers who wish to produce Java applications that speak. This is old obsolete software that only works on Mac OS 9 and earlier.

Packaging

lib
JAR files containing precompiled versions of the code, plus the Synthesis Callbacks native library
src
The source code, mostly Java but also a little C for the native library
docs
JavaDoc documentation on the code

Using JSAPI

JSAPI for Macintosh is an implementation of Sun Microsystem's documented Java Speech API. Currently javax.speech.synthesis and the minimum amount of javax.speech to support synthesis are implemented. See the release notes below. JSAPI for Macintosh requires that you build JSpeechLib. To build the JSAPI parts build JSAPI Mac Glue.mcp and Pure JSAPI Layer.mcp. Start by looking at the Voice, Central and Synthesiser classes.

Using JSpeechLib

Although most applications would want to use JSAPI for portability, Macintosh specific Java applications can use JSpeechLib directly by accessing the package lordpixel.macspeech. JSpeechLib can be built using the project JSpeechLib.mcp. Start by looking at the SpeechChannel and Voice classes.

Synthesis Callbacks Native Library

A small native library, written in C is required to implement callbacks into Java from the native Mac OS speech synthesiser. i.e. its used to feed events about the progress of the speech back to the listeners in the Java code. SynthesisCallbacksLib is built using SynthesisCallbacks.mcp.

Version History

Release of JSpeechLib 3.0.0 and JSAPI for Macintosh 0.5 marks the first integrated release

  JSAPI for Macintosh 0.2. Brendan's maintainance release. (29 Feb 2000)
Phase 3 work begins JSAPI for Macintosh 0.1. Brendan's first release. (02 Feb 2000)
JSpeechLib 2.0.1 Modified to take account of changes predicted for MRJ 2.1 final and remove some work arounds that are no longer needed.  
First public release. Works with MRJ 2.1ea3 using JDirect 2.  
JSpeechLib 1.X Worked with MRJ 1.5 and 2.0 and JDirect 1. Unreleased.  

New in this release

Support for Mexican Spanish through MacinTalk Español Mexicano in JSAPI for Macintosh. [JSAPI]

Support for Simplified and Traditional Chinese (Mandarin) added to both JSpeechLib and JSAPI for Macintosh. [JSpeechLib and JSAPI]

Overall this means all synthesisers which work with the modern Macintosh SpeechManager are supported: MacinTalk 3, MacinTalk Pro, MacinTalk Español Mexicano, MacinTalk Simplified Chinese and MacinTalk Traditional Chinese. MacinTalk 2 ceased to operate with the release of Mac OS 8, and the original MacinTalk dates back to the System 6 era. Both are obsolete and unsupported.

EngineCentral will return 4 synthesisers, one for each language and script (US English, Mexican Spanish, Simplified Chinese and Traditional Chinese) which limits the Voices that it reports to those that can speak that language. In reality you can assign any Voice to any synthesiser and it should work, because the underlying implementation tries to allow this. However, ordinarily there is no real reason why you would want to do that. [JSAPI]

Interrupt driven Speech Event listeners added to JSpeechLib. These are used to provide interrupt driven speech events in JSAPI for Macintosh and hence have enabled the removal of the event polling in release 0.2. [JSpeechLib and JSAPI]

Javadoc in lordpixel.macspeech.SpeechChannel is up to date [JSpeechLib]

Voice styles are now implemented, so e.g. Trinoids is now classified as Alien/Robot if Voice.getStyle() is invoked. [JSAPI]

Added more descriptive output to speakable event and speech event when printed. [JSAPI]

Bugs fixed

MacintoshSynthesizer.allocate is now checking that its deallocated, ensuring that multiple allocations do nothing, an throwing exceptions when it should - in short its behaving much more like the documented behaviour for JSAPI synthesisers. [JSAPI]

Native<->Java Pitch calculation was wrong, had twelthroot2^((pitch-60 * 261.625) should be twelthroot26^(pitch-60) * 261.625. set/get speechRange need a similar fix. [JSAPI]

MacintoshEngineCentral does a Gestalt check to ensure the SpeechManager is installed, and checks that Mexican Spanish, US English and Chinese voices exist before giving out Synthesisers for those languages. [JSAPI]

Finalize in MacintoshSynthesizer was public, made protected so that it will work as intended. [JSAPI]

Lots of cleanup to semantics, e.g. making sure all DEALLOCATED etc states have no sub states. Also re-did deallocate() to take into account exiting state of synthesiser and throw appropriate exceptions like allocate(). Also handled cancelling whole speech queue. [JSAPI]

Implemented synchronisation of speech event queue with the with AWT event Q as defined in SpeechEvent. This means speech related events are delivered on the AWT Event Q thread as the documentation recommends. [JSAPI]

Added exception to method signature of javax.speech.Engine.allocate as required by API specification. [JSAPI]

EngineCentral objects are loaded and created by reading a properties file, rather than being hard coded into a static initialiser as they were. [JSAPI]

Caching last created engine (synthesiser), as described in JavaDoc. [JSAPI]

Known Limitations

Speech Recognition javax.speech.recognition is not implemented. [JSpeechLib and JSAPI]

There is no support of any sort for the SecurityManager though unsigned applets probably cannot use this library as they cannot access JDirect. Absolutely no assertions warranties or promised are made about security. However its worth noting that since there is no Recogniser implementation in this release, there is little to worry about other than your Mac making annoying sounds. [JSAPI and JSpeechLib]

Speech Phoneme events do not work. Your Mac is likely to hang and crash if you try to use Phoneme events. I believe this may be a bug in the SpeechManager, I reported this issue to Apple; they appear to have no plans to fix it before Mac OS X. [JSpeechLib]

JavaDoc is not complete, apart from in JSpeechLib. [JSAPI]

Calling speakString() does not cause events (e.g. wordDone) to be fired. This cannot be fixed as this is how the underlying synthesiser works. See speakText() instead. [JSpeechLib]

Word Started events are actually delivered when a word is complete (done). This is due to the way the underlying synthesisers report word events. Code requiring very accurate synchronisation will have to track positions in the output string and report the next word that will be spoken as "started" as appropriate.

The Mexican Spanish voices Carlos and Catalina, and their High Quality counterparts, report inaccurate information for their Language and Region codes. The simplest way to get a Spanish voice is to ask for it by name, i.e. "Carlos", "Catalina", "Carlos, high quality" or "Catalina, high quality". [JSpeechLib and JSAPI]

setPitch() and setPitchRange() behave a little oddly. Mac OS channels use a baseline pitch which has a range above and below the baseline. In JSAPI the pitch range is above the baseline. Therefore when you set the pitch range the synthesiser adds half of the desired range to the baseline shifting it up. Then it applies the range, which Mac OS will interpret as being a range above and below, centred on this shifted pitch. The net effect is that the upper and lower bounds of the range are as specified by JSAPI, but the baseline is altered.

Problems with JSML Parsing – Sayas tag:
phon attribute expects Apple's phoneme representation rather than the IPA.
class attribute only supports "literal" as a class. [JSAPI – from Brendan's 0.2 Release Note]

Phonemes currently use the American Phoneme Representation that is internal to the Macintosh Speech Manager rather than the International Phonetic Alphabet referenced by the JSAPI. [JSAPI – from Brendan's 0.2 Release Note]

Technical Notes

Changes to state handling mechanism so all changes go through setState() – that way the wait()/notify() mechanism can be used to implement waitForState() [JSAPI]

Fragments of text presented for output which does not contain JSML is considered to be a complete sentence and ending prosody will be applied. Use JSML for explicit control over prosody. [JSAPI and JSpeechLib]

Reworked fireXXXEvent methods to clone() the listener list before proceeding, as recommended in the O'Reilly Java Beans book. Collapsed (engine)Listeners and synthesiserListerners into one queue of listeners and filter events using instanceof rather than having 2 vectors and 2 for loops. This was mainly so I didn't have to clone 2 lists of Listeners, but its also how Willie Walker suggested implementing it on javaspeech-interest a while back... [JSAPI]

Setting up XML for JSML

You need to setup an XML parser to enable the library to parse JSML content. We have successfully used both Xerces-J and Project X parsers with the library; any parser that implements both SAX and JAXP should work.

If you intend to use JSML then you must inform the library of the name of the XML parser you wish to use by setting a Java System Property. This is achieved using either the properties file for MRJAppBuilder, or the properties pane in JBindery. Its analogous to using the -D option in the Unix and Windows JDK.

For ProjectX
Set javax.xml.parsers.SAXParser=com.sun.xml.parser.Parser
For Xerces-J
Set javax.xml.parsers.SAXParser=org.apache.xerces.parsers.SAXParser

Setting up Synthesis Callbacks

The SynthesisCallbacks native library must be available for JSpeechLib and JSAPI to operate. This is loaded by the Code Fragment Manager, and thus may be located either in the same folder as your application or nested one level down in a sub folder of the folder which contains your application.

You must also read the resource management guide: How the library uses memory and threads.

Copyright and License

The Java™ Speech API was developed by Sun Microsystems

The original JSAPI for Macintosh implementation is Copyright ©2000 Brendan Burns, except changes made to produce version 0.5 which are Copyright ©2000 Andrew Thompson.

JSpeechLib and associated documentation is Copyright ©1997-2000 Andrew Thompson

You rights with respect to this library, both binary and source code and are defined by the GNU Lesser General Public License. A copy has also been included with this distribution. You should read the license carefully as it governs your rights with respect to this library.