home *** CD-ROM | disk | FTP | other *** search
- /*
- HASSoundSpeech.c from Hsoi's App Shell © 1995-1997 John C. Daub. All rights reserved.
-
- This file contains the functions dealing with text-to-speech and any of my own
- sound handling functions and notes (i.e. stuff not in Michael Kamprath's WASTE
- Object Handlers library, a library used by Hsoi's App Shell to handle objects
- like PICTs, snds, HFS objects, etc.).
-
- Do see Michael's library, most notably the WE_snd_Handler.c and .h files for
- more information
- */
-
- /*
- The text-to-speech code in here (both the dialog and the actual code to
- do text to speech) are based upon Tom Bender's Tex-Edit+ 1.6.3 source
- code. I translated to C (from Pascal), made appropriate modifications,
- and any other neccessary adjustments to work in the scope of Hsoi's App Shell.
-
- NOTE: (temporary note) until i get all of Tom's code translated and things
- working right, i'm doing it all just like Tom did it...the ResID's are the
- same, everything is the same (except perhaps some of the strings). i will
- also be having the speech options dialog be a menu item for now, but i do
- want to make it part of the prefs dialogs eventually.
- */
-
- #pragma mark ••• #includes •••
-
- #ifndef _WASTE_
- #include "WASTE.h"
- #endif
-
- #include "HASGlobals.h"
- #include "HASMain.h"
- #include "HASMenus.h"
- #include "HASUtilDialogs.h"
- #include "HASUtilPStrings.h"
- #include "HASUtilities.h"
- #include "HASMovableModal.h"
- #include "HASSoundSpeech.h"
-
- #include "WASTE_Objects.h"
-
- #ifndef __SPEECH__
- #include <Speech.h>
- #endif
-
- #ifndef __TEXTEDIT__
- #include <TextEdit.h>
- #endif
-
-
- #pragma mark -
- #pragma mark ••• Constants •••
-
- enum {
- inSpacers = 1,
- inEnders = 2
- };
-
- const char kSpacers[] = { ' ', '.', '!', '?', '…', 9 /*tab*/, 13 /*cr*/, \
- '3' /*^C*/, 41 /*)*/, 93 /*]*/, 125 /*}*/, 211 /*"*/ };
-
- const char kSentenceEnders[] = { '.', '!', '?', '…', 13 };
-
-
- #pragma mark -
- #pragma mark ••• Globals •••
-
- // these 4 globals are just temporary until i get the prefs implimented with the sound
-
- //Fixed sVoicePitch = 0;
- //Fixed sVoiceRate = 0;
- //Fixed sVoiceMod = 0;
- //Str255 sVoiceStr = "\p";
-
- // shell-wide globals to help determine the state of things
-
- SpeechChannel gSpeechChannel = nil;
- HiliteMethod gHiliteMethod = off;
- Boolean gSpeechOn = false;
- Boolean gHiliting = false;
- Boolean gPaused = false;
-
- // and some local globals to help us keep track of things.
-
- long sCBWordStart;
- long sCBWordEnd;
- long sCBSelStart;
- WindowRef sTalkingWPtr;
- Handle sSpokenTxtHdl; // space to hold text block being read
-
-
- #pragma mark -
- #pragma mark ••• Voice Menu •••
-
- // this function is used to build the popup voice menu the first time the speech
- // options dialog is invoked. the gala (pro) voices are put at the top and the
- // regular voices are put at the bottom. (gala (pro) voices are used by Macintalk Pro)
-
- OSErr HsoiBuildVoiceMenu( void )
- {
- MenuRef voiceMenuHdl;
- VoiceSpec vSpec;
- VoiceDescription vDesc;
- short numVoices;
- short x, galaCt;
- OSErr err;
-
- // get the menu handle
-
- voiceMenuHdl = GetMenu( kPopmenuVoice );
-
- // count the number of available voices
-
- err = CountVoices( &numVoices );
-
- // make sure we need to build a menu
-
- if ( (err == noErr) && (CountMenuItems( voiceMenuHdl ) == 3 ))
- {
- galaCt = 0;
-
- if ( numVoices > kMaxVoiceCount )
- numVoices = kMaxVoiceCount;
-
- // get each voice's name and insert it
-
- for ( x = 1; x <= numVoices; x++ )
- {
- if (err == noErr )
- err = GetIndVoice( x, &vSpec );
-
- if ( err == noErr )
- err = GetVoiceDescription( &vSpec, &vDesc, sizeof( VoiceDescription ) );
-
- if ( err == noErr )
- {
- // insert pro voices at top of menu
-
- if ( vDesc.voice.creator == 'gala' )
- {
- InsertMenuItem( voiceMenuHdl, vDesc.name, 2 );
- galaCt += 1;
- }
- else
- InsertMenuItem( voiceMenuHdl, vDesc.name, 3 + galaCt );
- }
- }
-
- }
-
- return err;
- }
-
-
- // this function returns the name of the voice currently selected in the voice popup
- // menu (cntrlHdl). if the default item is selected (item #1), then the empty string
- // is returned.
-
- void HsoiGetVoiceMenuSelection( Handle cntrlHdl, Str255 voiceStr )
- {
- // Str255 voiceStr = NIL_STRING;
-
- short currentVoiceItem;
- MenuRef voiceMenuHdl;
- register short i;
-
- for ( i=0; i < 255; i++ )
- voiceStr[i] = nil;
-
- currentVoiceItem = GetControlValue( (ControlRef)cntrlHdl );
-
- if ( currentVoiceItem > 2 )
- {
- voiceMenuHdl = GetMenu( kPopmenuVoice );
- GetMenuItemText( voiceMenuHdl, currentVoiceItem, voiceStr );
- }
-
- return;
- }
-
-
- // this procedure selects (checkmarks) the given voice on the menu. it is used
- // when the menu is built
-
- void HsoiSetVoiceMenuSelection( ConstStr255Param selVoiceStr, ControlRef cntrlHdl )
- {
- Str255 voiceStr = NIL_STRING;
- short numItems;
- MenuRef voiceMenuHdl;
- short x = 1, index = 1;
-
- // get the menu handle
-
- voiceMenuHdl = GetMenu( kPopmenuVoice );
-
- // count the number of items on the menu
-
- numItems = CountMenuItems( voiceMenuHdl );
-
- // scan the voice menu -- look for match for selVoiceStr
-
- while ( (index == 1) && ( x <= numItems ) )
- {
- GetMenuItemText( voiceMenuHdl, x, voiceStr );
-
- if ( EqualString ( selVoiceStr, voiceStr, false, false ) )
- index = x;
- else
- x++;
- }
-
- // now checkmark the popup menu
-
- (*cntrlHdl)->contrlValue = index;
-
- return;
- }
-
-
- #pragma mark -
- #pragma mark ••• Speech Options Dialog Utils •••
-
- // draw the comments describing the voice which is currently selected by the popmenu
-
- // ••• DEBUG THIS FUNCTION, STEP THROUGH LINE BY LINE, ESPECIALLY CHECKING THE
- // VALUES OF THE STRINGS AS WE GO ALONG.
-
- pascal void HsoiDrawVoiceDescBox( WindowRef dlg, short itemNo )
- {
- GrafPtr oldPort;
- long oldFont, oldSize;
- Str255 voiceStr = NIL_STRING;
- short theVoicePref;
- Rect r;
- Handle h;
- OSErr err;
- VoiceSpec vSpec;
- VoiceSpec *vSpecPtr;
- VoiceDescription vDesc;
- Str255 theGender, theAge;
- Str255 yearsOldStr, theTextStr = "\p";
-
- // set up the ports
-
- GetPort( &oldPort );
- SetPortWindowPort( dlg );
-
- // save the original font and size settings
-
- oldFont = GetWindowPort(dlg)->txFont;
- oldSize = GetWindowPort(dlg)->txSize;
-
- // get the current voiceSpec and description
-
- h = HsoiGetDialogItemHandle( dlg, kDlgItemVoicePopmenu );
- HsoiGetVoiceMenuSelection( h, voiceStr );
- theVoicePref = HsoiGetVoiceIndex( voiceStr );
-
- // get the voice description of the default/chosen voice
-
- if ( theVoicePref == 0 )
- {
- vSpecPtr = nil;
-
- err = GetVoiceDescription( vSpecPtr, &vDesc, sizeof( VoiceDescription ) );
- }
- else
- {
- err = GetIndVoice( theVoicePref, &vSpec );
- if ( err == noErr )
- err = GetVoiceDescription( &vSpec, &vDesc, sizeof( VoiceDescription) );
- }
-
- // assemble and display a descriptive string
-
- if ( err == noErr )
- {
- // set the font/size for drawing.
-
- TextSize( 9 );
- TextFont( geneva );
-
- // get the gender in a string
-
- if ( vDesc.gender == kMale )
- GetIndString( theGender, kVoiceStringsID, kStrMale );
- else if ( vDesc.gender == kFemale )
- GetIndString( theGender, kVoiceStringsID, kStrFemale );
- else
- GetIndString( theGender, kVoiceStringsID, kStrNeuter );
-
- // get the age in a string
-
- NumToString( (long)vDesc.age, theAge );
- GetIndString( yearsOldStr, kVoiceStringsID, kStrYearsOld );
-
- // and take all the strings and make them into one big string
-
- // add the default voice name if needed
-
- if ( theVoicePref == 0 )
- {
- HsoiConcatString( theTextStr, "\p[" );
- HsoiConcatString( theTextStr, vDesc.name );
- HsoiConcatString( theTextStr, "\p] " );
- }
-
- HsoiConcatString( theTextStr, theAge );
- HsoiConcatString( theTextStr, yearsOldStr );
- HsoiConcatString( theTextStr, theGender );
- HsoiConcatString( theTextStr, "\p-- " );
- HsoiConcatString( theTextStr, vDesc.comment );
-
- // fyi, in the end, this should read something like:
- // "30 year old male.-- I sure love being inside of this computer"
- // and if there is a default voice name, just prepend a "[Fred] 30 year old..."
-
- // draw the voice description
-
- // incidentally, this neat little function, TETextBox is part of TextEdit.
- // you can read more about it in NIM:Text (it's a neat, handy thing). but
- // it'd be really cool if we could create a WASTE equiv of this.
-
- //TETextBox(const void *text, long length, const Rect *box, short just)
-
- HsoiGetDialogItemRect( dlg, itemNo, &r );
- TETextBox( &theTextStr[1], theTextStr[0], &r, teFlushDefault );
- TextFont( oldFont );
- TextSize( oldSize );
-
-
- }
-
- SetPort( oldPort );
-
- return;
- }
-
- #pragma mark -
- #pragma mark ••• Speech Options Dialog •••
-
- // display the speech options dialog box
-
- void HsoiDoSpeechOptionsDialog( void )
- {
- long xx;
- Str255 s;
- Handle h;
- OSErr err= noErr;
- DialogRef dialog;
- UserItemUPP drawVoiceDescBoxUPP = nil;
- ModalFilterUPP filterUPP = nil;
- short item;
-
- // get the dialog
-
- dialog = GetNewDialog( kDialogSpeechOptions, nil, MOVE_TO_FRONT );
-
- if ( dialog == nil )
- {
- SysBeep( 1 ); // lame error handling
- return;
- }
-
- SetGrafPortOfDialog( dialog );
-
- // Tom drew the OK button's outline with his own proc...we'll just use the
- // built-in Dialog Manager routines
-
- SetDialogDefaultItem( dialog, ok );
- SetDialogCancelItem( dialog, cancel );
- SetDialogTracksCursor( dialog, true );
-
- // get the description box's proc set up
-
- drawVoiceDescBoxUPP = NewUserItemProc( HsoiDrawVoiceDescBox );
- HsoiSetDialogItemProc( dialog, kDlgItemVoiceDescription, drawVoiceDescBoxUPP );
-
- // build the voice menu
-
- err = HsoiBuildVoiceMenu();
-
- // set the voice menu to the option stored in the prefs
-
- // NOTE!!!!! when i get the prefs updated, I need to update this line to
- // use the value (Str255) stored in the prefs.
-
- if ( err == noErr )
- HsoiSetVoiceMenuSelection( gMyPrefs.sVoiceStr, (ControlRef)HsoiGetDialogItemHandle( dialog, kDlgItemVoicePopmenu ) );
- else
- { // do some error handling
-
- HsoiDisplaySpeechError( err );
- goto exit;
- }
-
- // set up pitch/rate controls
-
- h = HsoiGetDialogItemHandle( dialog, kDlgItemPitch );
- xx = HiWrd( gMyPrefs.sVoicePitch );
- NumToString( xx, s );
- SetDialogItemText( h ,s );
-
- h = HsoiGetDialogItemHandle( dialog, kDlgItemRate );
- xx = HiWrd( gMyPrefs.sVoiceRate );
- NumToString( xx, s );
- SetDialogItemText( h, s );
-
- h = HsoiGetDialogItemHandle( dialog, kDlgItemMod );
- xx = HiWrd( gMyPrefs.sVoiceMod );
- NumToString( xx, s );
- SetDialogItemText( h, s );
-
- SelectDialogItemText( dialog, kDlgItemPitch, 0, MAXLONG );
-
- SetCursor( &qd.arrow );
-
- ShowWindow( GetDialogWindow( dialog ) );
- SelectWindow( GetDialogWindow( dialog ) );
-
- gInModalState = true;
- HsoiAdjustMenus();
-
- // INSERT MOVABLE MODAL DIALOG HANDLER HERE
-
- filterUPP = NewModalFilterProc( hsoiSpeechOptionsDialogFilter );
-
- do {
- MovableModalDialog( filterUPP, &item );
-
- HsoiHandleSpeechOptionsDialog( item, dialog );
- } while ( (item != ok) && (item != cancel ) );
-
-
-
- exit:
-
- DisposeRoutineDescriptor( filterUPP );
- filterUPP = nil;
- DisposeRoutineDescriptor( drawVoiceDescBoxUPP );
- drawVoiceDescBoxUPP = nil;
-
- DisposeDialog( dialog );
-
- gInModalState = false;
- HsoiAdjustMenus();
-
- return;
- }
-
-
- // the speech options dialog filter. mostly, we just check to make sure we have
- // something in all the edit boxes, and filter out "junk" keys. then we call our
- // usual dialog filter
-
- pascal Boolean hsoiSpeechOptionsDialogFilter( DialogRef theDialog, EventRecord *event, short *item )
- {
- Str255 pitchStr, rateStr, modStr;
- Boolean okIsDimmed;
- char theKey;
- Boolean retval = false;
- GrafPtr oldPort;
-
- GetPort( &oldPort );
- SetGrafPortOfDialog( theDialog );
-
- // see if there is text in the dialog edittext items. if any of these
- // fields are empty, we cannot allow the user to proceed, so we'll dim the OK
- // button and the Sample button
-
- GetDialogItemText( HsoiGetDialogItemHandle( theDialog, kDlgItemPitch ), pitchStr );
- GetDialogItemText( HsoiGetDialogItemHandle( theDialog, kDlgItemRate ), rateStr );
- GetDialogItemText( HsoiGetDialogItemHandle( theDialog, kDlgItemMod ), modStr );
-
- if ( (pitchStr[0] != 0) && (rateStr[0] != 0) && (modStr[0] != 0) )
- {
- // we have text in all three, we can make sure OK is enabled
-
- HiliteControl( (ControlRef)HsoiGetDialogItemHandle( theDialog, ok ), kCtlActive );
-
- // make sure Sample is enabled
-
- HiliteControl( (ControlRef)HsoiGetDialogItemHandle( theDialog, kDlgItemSample ), kCtlActive );
- okIsDimmed = false;
- }
- else
- {
- // something must be empty, dim OK
-
- HiliteControl( (ControlRef)HsoiGetDialogItemHandle( theDialog, ok ), kCtlInactive );
- HiliteControl( (ControlRef)HsoiGetDialogItemHandle( theDialog, kDlgItemSample ), kCtlInactive );
- okIsDimmed = true;
- }
-
- // now we'll check for key related events
-
- if ( (event->what == keyDown) || (event->what == autoKey ) )
- {
- theKey = event->message & charCodeMask;
-
- // if the return or enter key was hit and OK is dimmed, we need to snarf
- // that keypress ourselves
-
- if ( ((theKey == kEnterKey) || (theKey == kReturnKey)) && okIsDimmed )
- {
- retval = true;
- SysBeep( 3 ); // just to give some sort of feedback
- goto exit;
- }
- else
- retval = false;
-
- // and let's snarf some other things....if it's not one of a few certain keys,
- // we'll complain. The user only needs a few certain keys (numbers, return, etc)
- // to deal with this dialog...and by restricting them somewhat, it can make our
- // lives easier in ensuring that they don't enter any invalid stuff
-
- if ( !(theKey > 0x2F && theKey < 0x3A ) && // if it wasn't a number
- ( theKey != kEnterKey ) && // if it wasn't the Enter key
- ( theKey != kReturnKey ) && // if it wasn't the Return key
- ( theKey != kEscKey ) && // if it wasn't Escape
- ( theKey != kBackSpace ) && // if it wasn't backspace
- ( theKey != kDeleteKey ) && // if it wasn't the delete key
- ( theKey != kTabKey ) && // if it wasn't the tab key
- ( theKey != kLeftArrow ) && // and all the arrow keys for easy editing
- ( theKey != kRightArrow ) &&
- ( theKey != kUpArrow ) &&
- ( theKey != kDownArrow ) )
- {
- SysBeep( 5 );
- retval = true; // we've handled it
- }
- else if ( theKey > 0x2F && theKey < 0x3A ) // if it's a number key
- {
- // things are a bit tricky now. we know the key is one of the allowed keys.
- // but! we want to restrict the length of the strings entered by the user.
- // using the up/down arrows, if you've hit the upper or lower limit, it'll
- // just sit there...the value won't increase any more.
-
- // but, this would still allow the user to type in something like: 10000000
-
- // that's not quite a valid value. now, it doesn't really matter if this
- // happens cause HsoiGetDialogItemValue, if it receives a value greater than
- // or less than the upper/lower limits, it'll just pin the return value to
- // the limit. so from a code level, we'll never have values outside of
- // the valid range.
-
- // however, this might confuse the user... "I entered 5 billion, why isn't
- // it speaking with that???"
-
- // so, what we'll do here is limit what the user can enter in terms of
- // text. it's nice that the upper limits of the values (kMaxPitch, kMaxRate
- // and kMaxMod) are all 3 digit numbers. so, what we can do is check to
- // see if we'll be moving beyond that (i.e. limit the text entry to no more
- // than 3 characters).
-
- // in doing this, now not only do we have to check the length of the
- // existing text, but there is also the chance there could be a selection
- // active, and if so, that will replace what we have, so who knows how
- // things could go! this might get hairy....
-
- Str255 s; // the text of the currently active edit line
-
- // now, get the text of the currently active edit line
-
- GetDialogItemText( HsoiGetDialogItemHandle( theDialog, GetDialogKeyboardFocusItem( theDialog )), s );
-
- // see if there is a selection range
-
- if ( HsoiHasSelectionRange( (DialogPeek)theDialog ) )
- {
- // it does...so the limit buffer doesn't really matter. if one charcter
- // is selected, it'll just replace it, no biggie. if more than one
- // character is selected, the total number of characters in the
- // edittext box will drop, so again, no biggie
-
- retval = false; // let the Dialog Manager handle it
- }
- else
- {
- // there isn't a selection range, so we'll just check how big the
- // string currently is. if it's 3 or more, beep, else let it through
- // (remember, we can check for "3" only cause all the pitch/rate/mod
- // max's are 3 digits...a nice and by-chance thing
-
- if ( s[0] >= 3 )
- {
- SysBeep( 3 );
- retval = true; // we handled it
- }
-
- // now, all of that probably seemed really unnecessary...like checking
- // for a selection range. but if you have the ability to paste/copy/cut
- // stuff (mostly paste) into your dialogs, this will have to be
- // checked for (see the big modal dialog's filter for an example)
-
-
- }
- }
- else
- retval = false; // let the dialog manager handle it
- }
-
-
- exit:
- // that's about all we need to handle specially...just call our normal dialog filter
- // (and rememeber that this filter was written to be used with HASMovableModal.c
- // (based upon Marco Piovanelli's MovableModal Libary 2.0). this is important
- // cause we're leaving out stuff like dealing with drags, mouse clicks, etc)
-
- if ( !retval )
- retval = hsoiMyStandardDialogFilter( theDialog, event, item );
-
- SetPort( oldPort );
-
- return retval;
- }
-
-
- // handle action in the speech options dialog
-
- void HsoiHandleSpeechOptionsDialog( short theItem, DialogRef dlg )
- {
- Str255 s;
- VoiceSpec vSpec;
- Fixed thePitchPref = 0, theRatePref = 0, theModPref = 0;
- double xx;
- long x;
- short currVoiceItem; // selected menu item
- short i;
- OSErr err = noErr;
- Boolean legal;
-
- switch( theItem )
- {
- case ok:
- {
- // get pitch/rate/mod and convert to Fixed
-
- HsoiGetDialogItemValue( dlg, kDlgItemPitch, kMinPitch, kMaxPitch, &legal, &xx );
- x = xx;
- //if ( legal )
- gMyPrefs.sVoicePitch = BSL( x, 16 );
-
- HsoiGetDialogItemValue( dlg, kDlgItemRate, kMinRate, kMaxRate, &legal, &xx );
- x = xx;
- //if ( legal )
- gMyPrefs.sVoiceRate = BSL( x, 16 );
-
- HsoiGetDialogItemValue( dlg, kDlgItemMod, kMinMod, kMaxMod, &legal, &xx );
- x = xx;
- //if ( legal )
- gMyPrefs.sVoiceMod = BSL( x, 16 );
-
- // get the chosen voice and remember as globals
-
- HsoiGetVoiceMenuSelection( HsoiGetDialogItemHandle( dlg, kDlgItemVoicePopmenu ), gMyPrefs.sVoiceStr );
-
- if ( err == noErr )
- err = SetSpeechRate( gSpeechChannel, gMyPrefs.sVoiceRate );
- if ( err == noErr )
- err = SetSpeechPitch( gSpeechChannel, gMyPrefs.sVoicePitch );
- if ( err == noErr )
- err = SetSpeechInfo( gSpeechChannel, soPitchMod, &gMyPrefs.sVoiceMod );
-
- // the prefs have changed
-
- gWritePrefs = true;
-
- // hide the dialog
-
- // HideWindow( GetDialogWindow( dlg ) );
- }
- break; // end: case ok
-
- case cancel:
- {
- err = DisposeSpeechChannel( gSpeechChannel );
-
- // restore previous speech channel
-
- i = HsoiGetVoiceIndex( gMyPrefs.sVoiceStr );
-
- if ( i == 0 )
- err = NewSpeechChannel( nil, &gSpeechChannel );
- else
- {
- if ( err == noErr )
- err = GetIndVoice( i, &vSpec );
- if ( err == noErr )
- err = NewSpeechChannel( &vSpec, &gSpeechChannel );
- }
-
- if ( err == noErr )
- err = SetSpeechRate( gSpeechChannel, gMyPrefs.sVoiceRate );
- if ( err == noErr )
- err = SetSpeechPitch( gSpeechChannel, gMyPrefs.sVoicePitch );
- if ( err == noErr )
- err = SetSpeechInfo( gSpeechChannel, soPitchMod, &gMyPrefs.sVoiceMod );
-
- // hide the dialog
-
- // HideWindow( GetDialogWindow( dlg ) );
-
- }
- break; // end: case cancel
-
- case kDlgItemPitchUp:
- HsoiGetDialogItemValue( dlg, kDlgItemPitch, kMinPitch, kMaxPitch, &legal, &xx );
- HsoiDoArrowUpDown( dlg, kDlgItemPitchUp, kDlgItemPitch, kDlgItemPitchArrows, 1, kMinPitch, kMaxPitch, false, &xx );
- break;
-
- case kDlgItemPitchDown:
- HsoiGetDialogItemValue( dlg, kDlgItemPitch, kMinPitch, kMaxPitch, &legal, &xx );
- HsoiDoArrowUpDown( dlg, kDlgItemPitchDown, kDlgItemPitch, kDlgItemPitchArrows, -1, kMinPitch, kMaxPitch, false, &xx );
- break;
-
- case kDlgItemRateUp:
- HsoiGetDialogItemValue( dlg, kDlgItemRate, kMinRate, kMaxRate, &legal, &xx );
- HsoiDoArrowUpDown( dlg, kDlgItemRateUp, kDlgItemRate, kDlgItemRateArrows, 1, kMinRate, kMaxRate, false, &xx );
- break;
-
- case kDlgItemRateDown:
- HsoiGetDialogItemValue( dlg, kDlgItemRate, kMinRate, kMaxRate, &legal, &xx );
- HsoiDoArrowUpDown( dlg, kDlgItemRateDown, kDlgItemRate, kDlgItemRateArrows, -1, kMinRate, kMaxRate, false, &xx );
- break;
-
- case kDlgItemModUp:
- HsoiGetDialogItemValue( dlg, kDlgItemMod, kMinMod, kMaxMod, &legal, &xx );
- HsoiDoArrowUpDown( dlg, kDlgItemModUp, kDlgItemMod, kDlgItemModArrows, 1, kMinMod, kMaxMod, false, &xx );
- break;
-
- case kDlgItemModDown:
- HsoiGetDialogItemValue( dlg, kDlgItemMod, kMinMod, kMaxMod, &legal, &xx );
- HsoiDoArrowUpDown( dlg, kDlgItemModDown, kDlgItemMod, kDlgItemModArrows, -1, kMinMod, kMaxMod, false, &xx );
- break;
-
- case kDlgItemSample:
- {
- Boolean reset;
-
- // get the currently selected speech parameters and voiceSpec
- // if the number in the edit box is greater/less than the max/min for
- // that parameter, change the value in the edit box to the apporpriate
- // min/max
-
- GetDialogItemText( HsoiGetDialogItemHandle( dlg, kDlgItemPitch ), s );
- StringToNum( s, &x );
- if ( x < kMinPitch )
- {
- x = kMinPitch;
- reset = true;
- }
- else if ( x > kMaxPitch )
- {
- x = kMaxPitch;
- reset = true;
- }
- else
- reset = false;
-
- if ( reset )
- {
- NumToString( x, s );
- SetDialogItemText( HsoiGetDialogItemHandle( dlg, kDlgItemPitch ), s );
- }
-
- HsoiGetDialogItemValue( dlg, kDlgItemPitch, kMinPitch, kMaxPitch, &legal, &xx );
- x = xx;
- thePitchPref = BSL( x, 16 );
-
- GetDialogItemText( HsoiGetDialogItemHandle( dlg, kDlgItemRate ), s );
- StringToNum( s, &x );
- if ( x < kMinRate )
- {
- x = kMinRate;
- reset = true;
- }
- else if ( x > kMaxRate )
- {
- x = kMaxRate;
- reset = true;
- }
- else
- reset = false;
-
- if ( reset )
- {
- NumToString( x, s );
- SetDialogItemText( HsoiGetDialogItemHandle( dlg, kDlgItemRate ), s );
- }
-
- HsoiGetDialogItemValue( dlg, kDlgItemRate, kMinRate, kMaxRate, &legal, &xx );
- x = xx;
- theRatePref = BSL( x, 16 );
-
- GetDialogItemText( HsoiGetDialogItemHandle( dlg, kDlgItemMod ), s );
- StringToNum( s, &x );
- if ( x < kMinMod )
- {
- x = kMinMod;
- reset = true;
- }
- else if ( x > kMaxMod )
- {
- x = kMaxMod;
- reset = true;
- }
- else
- reset = false;
-
- if ( reset )
- {
- NumToString( x, s );
- SetDialogItemText( HsoiGetDialogItemHandle( dlg, kDlgItemMod ), s );
- }
-
- HsoiGetDialogItemValue( dlg, kDlgItemMod, kMinMod, kMaxMod, &legal, &xx );
- x = xx;
- theModPref = BSL( x, 16 );
-
- HsoiGetVoiceMenuSelection( HsoiGetDialogItemHandle( dlg, kDlgItemVoicePopmenu ), s );
-
- currVoiceItem = HsoiGetVoiceIndex( s );
-
- if ( currVoiceItem > 0 )
- err = GetIndVoice( currVoiceItem, &vSpec );
-
- // reset the speech channel using the new speech parameters
-
- // REMOVE THIS...USE THE COMMENT STORED IN EACH VOICE
-
- //HsoipStringCopy( "\pThe quick brown fox jumped over the lazy dog", s );
-
- if ( err == noErr )
- err = DisposeSpeechChannel( gSpeechChannel );
-
- if ( err == noErr )
- {
- if ( currVoiceItem > 0 )
- err = NewSpeechChannel( &vSpec, &gSpeechChannel );
- else
- err = NewSpeechChannel( nil, &gSpeechChannel );
- }
-
- if ( err == noErr )
- err = SetSpeechRate( gSpeechChannel, theRatePref );
- if ( err == noErr )
- err = SetSpeechPitch( gSpeechChannel, thePitchPref );
- if ( err == noErr )
- err = SetSpeechInfo( gSpeechChannel, soPitchMod, &theModPref );
-
- if ( err == noErr )
- {
- VoiceDescription vDesc;
- short len;
- VoiceSpec *vSpecPtr;
-
- if ( currVoiceItem > 0 )
- err = GetVoiceDescription( &vSpec, &vDesc, sizeof( VoiceDescription) );
- else
- {
- vSpecPtr = nil;
- err = GetVoiceDescription( vSpecPtr, &vDesc, sizeof( VoiceDescription ) );
- }
- //short len = s[0];
- //err = SpeakText( gSpeechChannel, (char *)&s[1], len );
-
- //HsoipStringCopy( vDesc.comment, s );
- len = vDesc.comment[0];
- err = SpeakText( gSpeechChannel, (char *)&vDesc.comment[1], len );
- while ( SpeechBusy() )
- ; // do nothing, just wait for the sample to finish
- }
-
- HsoiDisplaySpeechError( err );
-
- }
- break; // end: case kDlgItemSample
-
- case kDlgItemVoicePopmenu:
- {
- // get current speech parameters -- reset the speech channel
-
- HsoiGetVoiceMenuSelection( HsoiGetDialogItemHandle( dlg, kDlgItemVoicePopmenu ), s );
- currVoiceItem = HsoiGetVoiceIndex( s );
-
- // if currVoiceItem = 0, then using default voice
-
- if ( currVoiceItem > 0 )
- err = GetIndVoice( currVoiceItem, &vSpec );
- if ( err == noErr )
- err = DisposeSpeechChannel( gSpeechChannel );
- if ( err == noErr )
- {
- if ( currVoiceItem > 0 )
- err = NewSpeechChannel( &vSpec, &gSpeechChannel );
- else
- err = NewSpeechChannel( nil, &gSpeechChannel );
- }
-
- // get default rate/pitch/modulation
-
- if ( err == noErr )
- err = GetSpeechRate( gSpeechChannel, &theRatePref );
- if ( err == noErr )
- err = GetSpeechPitch( gSpeechChannel, &thePitchPref );
- if ( err == noErr )
- err = GetSpeechInfo( gSpeechChannel, soPitchMod, &theModPref );
-
- // show correct default settings
-
- if ( err == noErr )
- {
- xx = HiWrd( thePitchPref );
- NumToString( xx, s );
- SetDialogItemText( HsoiGetDialogItemHandle( dlg, kDlgItemPitch ), s );
-
- xx = HiWrd( theRatePref );
- NumToString( xx, s );
- SetDialogItemText( HsoiGetDialogItemHandle( dlg, kDlgItemRate ), s );
-
- xx = HiWrd( theModPref );
- NumToString( xx, s );
- SetDialogItemText( HsoiGetDialogItemHandle( dlg, kDlgItemMod ), s );
-
- SelectDialogItemText( dlg, kDlgItemPitch, 0, 0 );
-
- // draw new comment box
-
- HsoiDrawVoiceDescBox( dlg, kDlgItemVoiceDescription );
-
-
- }
-
- }
- break; // end: case kDlgItemVoicePopmenu
-
- } // end: switch( theItem )
-
- HsoiDisplaySpeechError( err );
-
- return;
- }
-
-
- #pragma mark -
- #pragma mark •••• Speech Utils •••••
-
- void HsoiDisplaySpeechError( OSErr err )
- {
- Str255 s;
- short result;
-
- if ( err != noErr )
- {
- NumToString( err, s );
- ParamText( s, NIL_STRING, NIL_STRING, NIL_STRING );
- result = Alert( kSpeechErrorAlert, HsoiGetMyStandardDialogFilter() );
- }
-
- return;
- }
-
-
- void HsoiInitSpeechStuff( void )
- {
- qd.randSeed = TickCount(); // seed for rnd#
-
- gSpeechOn = false; // speech on/off
-
- gHiliting = false; // not reading yet
-
- gHiliteMethod = off; // no autohiliting yet
-
- gPaused = false; // not paused yet
-
- gSpeechChannel = nil; // no open speech channel yet
-
- sTalkingWPtr = nil; // which window is talking?
-
- sSpokenTxtHdl = nil;
-
- sCBSelStart = 0; // used by callback to store starting position
-
- return;
- }
-
- // this function returns the voice index number which has the given voice name.
- // a zero is returned if there is no match
-
- short HsoiGetVoiceIndex( Str255 voiceStr )
- {
- VoiceSpec vSpec;
- VoiceDescription vDesc;
- short numVoices;
- short foundVoiceIndex = 0;
- short x = 1;
- OSErr err;
-
- err = CountVoices( &numVoices );
-
- // find a matching voice index
-
- while ( (err == noErr) && (foundVoiceIndex == 0) && ( x <= numVoices ) )
- {
- err = GetIndVoice( x, &vSpec );
-
- if ( err == noErr )
- err = GetVoiceDescription( &vSpec, &vDesc, sizeof( VoiceDescription ) );
-
- // found a match? we're done
-
- if ( ( err == noErr ) && ( EqualString( vDesc.name, voiceStr, false, false ) ) )
- foundVoiceIndex = x;
- else
- x++;
- }
-
- HsoiDisplaySpeechError( err );
-
- return foundVoiceIndex;
- }
-
- // this callback routine updates static variables which keep track of the position of the
- // word being read so it can be hilited
-
- pascal void HsoiMyWordCallback( SpeechChannel chan, long refCon, long wordPos, short wordLen )
- {
- #pragma unused( refCon, chan )
-
- sCBWordStart = sCBSelStart + wordPos;
- sCBWordEnd = sCBSelStart + wordPos + wordLen;
-
- return;
- }
-
- // this proceedure reads aloud the chosen text using the existing speech
- // characterisstics. a handle is created to hold the desired text. it must stay
- // locked until we are finished reading
-
- void HsoiReadTheText( long selStart, long selEnd, WEReference txtHdl )
- {
- Ptr txPtr;
- long selLength;
- long myA5;
- OSErr err;
- SpeechWordUPP speechWordUPP = nil;
-
-
- if ( txtHdl != nil )
- {
- // dispose of block of text being read, if any
-
- if ( sSpokenTxtHdl != nil )
- HsoiForgetHandle( &sSpokenTxtHdl );
- selLength = selEnd - selStart;
- err = HsoiNewHandleTemp( 0, &sSpokenTxtHdl );
-
- // create a new text handle and lock it
-
- if ( err == noErr )
- err = WECopyRange( selStart, selEnd, sSpokenTxtHdl, nil, nil, txtHdl );
-
- if ( err == noErr )
- {
- MoveHHi( sSpokenTxtHdl );
- HLock( sSpokenTxtHdl );
- txPtr = *sSpokenTxtHdl;
-
- // set up the callback routine to hilite words as they are spoken
-
- if ( gHiliting && (gHiliteMethod == word) )
- {
- sCBSelStart = selStart;
- sCBWordStart = selStart;
- sCBWordEnd = selStart;
-
- // allows callback to access my globals
-
- // one interesting thing of note here. this is taken from NIM:Sound (4-21)
-
- /*
-
- Unlike other selectors, the soCurrentA5 and soRefCon selectors do not
- require that you pass a pointer to the information you are specifying
- in the speechInfo parameter. Because an application’s A5 value and a
- speech channel’s reference constant value are always each 4 bytes long
- (the same size as the speechInfo parameter), your application passes
- these values directly, casting them to pointer values
-
- */
-
- // hence why SetSpeechInfo ends with (Ptr)myA5 instead of something
- // like &myA5. same goes for the installation of the word proc.
- // it's already (technically in 68k Macs) a typedef'd void * so we
- // can just pass it "straight".
-
- myA5 = SetCurrentA5();
- err = SetSpeechInfo( gSpeechChannel, soCurrentA5, (Ptr)myA5 );
-
- if ( err == noErr )
- {
- speechWordUPP = NewSpeechWordProc( HsoiMyWordCallback );
- err = SetSpeechInfo( gSpeechChannel, soWordCallBack, speechWordUPP );
- }
- }
-
- // now start talking
-
- err = SpeakText( gSpeechChannel, txPtr, selLength );
- }
-
- // if hiliting, fix the menu bar
-
- if ( gHiliting )
- HsoiAdjustMenus();
-
- if ( err != noErr )
- {
- HsoiDisplaySpeechError( err );
- gHiliting = false;
- }
-
- if ( speechWordUPP != nil )
- DisposeRoutineDescriptor( speechWordUPP );
- } // end: if ( txtHdl != nil )
-
- return;
- }
-
-
- // read the entire document
-
- void HsoiDoReadDoc( WindowRef window )
- {
- WEReference txtHdl;
- long selStart, selEnd;
-
- if ( window != nil )
- {
- // remember which window is being read
-
- sTalkingWPtr = window;
-
- txtHdl = HsoiGetWindowWE( window );
-
- gPaused = false;
-
- switch( gHiliteMethod )
- {
- case off:
- gHiliting = false;
- selStart = 0;
- selEnd = WEGetTextLength( txtHdl );
- HsoiReadTheText( selStart, selEnd, txtHdl );
- break;
-
- case word:
- gHiliting = true;
- selStart = 0;
- selEnd = WEGetTextLength( txtHdl );
- HsoiReadTheText( selStart, selEnd, txtHdl );
- break;
-
- case sentence:
- gHiliting = true;
- WESetSelection( 0, 0, txtHdl );
- break;
- }
-
- }
-
- return;
- }
-
- // read the document starting at the cursor position
-
- void HsoiDoReadFromCursor( WindowRef window )
- {
- WEReference txtHdl;
- long selStart, selEnd;
-
- if ( window != nil )
- {
- // remember which window is being read
-
- sTalkingWPtr = window;
-
- txtHdl = HsoiGetWindowWE( window );
-
- gPaused = false;
-
- WEGetSelection( &selStart, &selEnd, txtHdl );
-
- switch( gHiliteMethod )
- {
- case off:
- gHiliting = false;
- selEnd = WEGetTextLength( txtHdl );
- HsoiReadTheText( selStart, selEnd, txtHdl );
- break;
-
- case word:
- gHiliting = true;
- selEnd = WEGetTextLength( txtHdl );
- HsoiReadTheText( selStart, selEnd, txtHdl );
- break;
-
- case sentence:
- gHiliting = true;
- WESetSelection( selStart, selEnd, txtHdl );
- break;
- }
- }
-
- return;
- }
-
-
- // read the selected text
-
- void HsoiDoReadSelection( WindowRef window )
- {
- WEReference txtHdl;
- long selStart, selEnd;
-
- if ( window != nil )
- {
- gPaused = false;
- gHiliting = false;
-
- txtHdl = HsoiGetWindowWE( window );
-
- WEGetSelection( &selStart, &selEnd, txtHdl );
-
- HsoiReadTheText( selStart, selEnd, txtHdl );
- }
- return;
- }
-
-
- // stop all sound playback and reading
-
- OSErr HsoiDoStop( void )
- {
- OSErr err = noErr;
-
- if ( gHasSpeechManager )
- {
- if ( ( SpeechBusy() > 0 ) || gPaused || gHiliting )
- {
- // stop talking now
-
- err = StopSpeech( gSpeechChannel );
- HsoiDisplaySpeechError( err );
-
- // release the memory
-
- if ( sSpokenTxtHdl != nil )
- HsoiForgetHandle( &sSpokenTxtHdl );
-
- sTalkingWPtr = nil;
- gHiliting = false;
- gPaused = false;
- }
- }
-
- // stop all other sound
-
- if ( SoundIsPlaying() )
- StopCurrentSound();
-
- HsoiAdjustMenus();
-
- return err;
- }
-
-
- // pause/resume talking
-
- void HsoiDoPause( void )
- {
- OSErr err;
-
- if ( gPaused )
- {
- // resume talking
-
- err = ContinueSpeech( gSpeechChannel );
- gPaused = false;
- }
- else
- {
- // pause speech
-
- err = PauseSpeechAt( gSpeechChannel, kImmediate );
- gPaused = true;
- }
-
- HsoiDisplaySpeechError( err );
-
- return;
- }
-
- // handle the "Turn Speech On/Off" menu item
-
- void HsoiDoSpeechOnOff( void )
- {
- VoiceSpec vSpec;
- short voiceIndex;
- OSErr err = noErr;
-
- // turn speech off, release memory
-
- if ( gSpeechOn )
- {
- err = HsoiDoStop();
-
- if ( (err == noErr) && (gSpeechChannel != nil) )
- {
- err = DisposeSpeechChannel( gSpeechChannel );
- gSpeechChannel = nil;
- }
-
- gSpeechOn = false;
- }
- else
- {
- // turn speech on, make sure speech manager is installed
-
- // we should have more informative error handling than this, but the adjust
- // menus code ought to be well enough written that if there is no Speech Manager,
- // the "Turn Speech On" menu item should never be an option (never be hilited/enabled)
-
- if ( !gHasSpeechManager )
- HsoiDisplaySpeechError( -1 );
- else
- {
- voiceIndex = HsoiGetVoiceIndex( gMyPrefs.sVoiceStr );
-
- // use default voice and default settings
-
- if ( voiceIndex == 0 )
- {
- err = NewSpeechChannel( nil, &gSpeechChannel );
- if ( err == noErr )
- err = GetSpeechRate( gSpeechChannel, &gMyPrefs.sVoiceRate );
- if ( err == noErr )
- err = GetSpeechPitch( gSpeechChannel, &gMyPrefs.sVoicePitch );
- if ( err == noErr )
- err = GetSpeechInfo( gSpeechChannel, soPitchMod, &gMyPrefs.sVoiceMod );
- }
- else
- {
- // restsore preferred voice and settings
-
- err = GetIndVoice( voiceIndex, &vSpec );
-
- if ( err == noErr )
- err = NewSpeechChannel( &vSpec, &gSpeechChannel );
- if ( err == noErr )
- err = SetSpeechRate( gSpeechChannel, gMyPrefs.sVoiceRate );
- if ( err == noErr )
- err = SetSpeechPitch( gSpeechChannel, gMyPrefs.sVoicePitch );
- if ( err == noErr )
- err = SetSpeechInfo( gSpeechChannel, soPitchMod, &gMyPrefs.sVoiceMod );
- }
-
- // success!
-
- if ( err == noErr )
- {
- gSpeechOn = true;
- gHiliting = false;
- }
- }
- }
-
- HsoiDisplaySpeechError( err );
-
- return;
- }
-
-
- // this procedure is called by HsoiDoMenuCommand to handle a selection in the AutoHighlight
- // subment. The word or sentence is hilited as it is spoken
-
- void HsoiDoHiliteMenu( short item )
- {
- switch ( item )
- {
- case iHilitingNone:
- gHiliteMethod = off;
- break;
-
- case iHilitingWord:
- gHiliteMethod = word;
- break;
-
- case iHilitingSentence:
- gHiliteMethod = sentence;
- break;
-
- default:
- gHiliteMethod = off;
- }
-
- return;
- }
-
- // this procedure returns the selStart/selEnd of the next legal sentence, for hiliting purposes
-
- void HsoiGetNextSelection( long *selStart, long *selEnd, WEReference txtHdl )
- {
- long textLength;
-
- textLength = WEGetTextLength( txtHdl );
-
- // skip over leading blanks to find the start of the sentence
-
- while( (*selStart < textLength) && HsoiIsSpacer( *selStart, txtHdl, inSpacers ) )
- *selStart += 1;
-
- // now find the end of this sentence
-
- if ( *selStart < textLength )
- *selEnd = *selStart + 1;
- else
- *selEnd = *selStart;
-
- while( (*selEnd < textLength ) && !HsoiIsSpacer( *selEnd, txtHdl, inEnders ) )
- *selEnd += 1;
-
- if ( *selEnd < textLength )
- *selEnd += 1;
-
- return;
- }
-
- // given a handle to the text and an offset, find out if the given char (at that offset in
- // the text) is a spacer (kSpacer) or not
-
- Boolean HsoiIsSpacer( long selStart, WEReference we, short inWhat )
- {
- unsigned char c;
- short x;
-
- c = WEGetChar( selStart, we );
-
- if ( inWhat == inSpacers )
- {
- for ( x = 0; x < sizeof( kSpacers ); x++ )
- {
- if ( c == kSpacers[x] )
- return true;
- }
-
- return false;
- }
-
- else if ( inWhat == inEnders )
- {
- for ( x = 0; x < sizeof( kSentenceEnders ); x++ )
- {
- if ( c == kSentenceEnders[x] )
- return true;
- }
-
- return false;
- }
-
- return false;
- }
-
-
- // main RunHiliter routine. called fromthe main event loop (gHiliting == true) when reading
- // and hiliting the entire document, word by word, or sentence by sentence
-
- void HsoiRunHiliter( EventRecord *event )
- {
- WindowRef window;
- WEReference we;
- long selStart;
- long selEnd;
- OSErr err;
-
- window = FrontWindow();
-
- if ( EventAvail( everyEvent, event) || !HsoiIsDocumentWindow(window) || gPaused ||
- (window != sTalkingWPtr ) )
- return;
-
- we = HsoiGetWindowWE( window );
- WEGetSelection( &selStart, &selEnd, we );
-
- // autohiliting by word
-
- if ( gHiliteMethod == word )
- {
- // done with doc
-
- if ( SpeechBusy() == 0 )
- err = HsoiDoStop();
- else if ( sCBWordEnd != selEnd )
- WESetSelection( sCBWordStart, sCBWordEnd, we ); // don't reselect the same word
- }
- else if ( SpeechBusy() > 0 ) // autohiliting by sentence...not done with current sentence yet
- return;
-
- else if ( selEnd == WEGetTextLength( we ) ) // finished reading doc
- err = HsoiDoStop();
-
- else
- {
- // hilite and read the next sentence
-
- selStart = selEnd;
- HsoiGetNextSelection( &selStart, &selEnd, we );
- WESetSelection( selStart, selEnd, we );
- HsoiReadTheText( selStart, selEnd, we );
- }
-
- return;
- }
-
- // this routine is called by the various HsoiAdjustMenu() functions to make sure the
- // sound menu looks proper.
-
- void HsoiAdjustSoundMenu( WindowRef window )
- {
- MenuRef soundMenu, hilitingMenu;
- short i;
- OSErr isOnlySoundObject;
- WEObjectReference objectRef;
- Str255 onOffStr, pauseResumeStr;
- WEReference we;
- Boolean disableSpeakCursor;
-
-
- soundMenu = GetMenuHandle( mSound );
- hilitingMenu = GetMenuHandle( mHiliting );
-
- // if we don't have a window that can have it's text spoken (i.e not a document
- // window), it's simple enough...just disable it all. the one thing that i would
- // think to have enabled would be to turn speech on or off, but if we did that,
- // the nonverbal cues/feedback given to the user via the GUI would possibly have them
- // think they could speak what's in this "odd" window. so, it's best that if there's
- // no window or it's a non-speakable window, disable the whole schebang.
-
- if ( (window == nil) || ((!HsoiIsDocumentWindow(window)) && (!HsoiIsClipboardWindow(window))) )
- {
- DisableItem( soundMenu, 0 );
- return;
- }
-
- // we know we have a valid window, so enable/disable items as needed
-
- we = HsoiGetWindowWE( window );
-
- // check if the WASTE instance is read-only. if so, and if WASTE_NO_RO_CARET is defined
- // as true, then in a read-only instance there is no cursor to read from (so we'll
- // always disable "Speak from Cursor")
-
- #if WASTE_NO_RO_CARET
-
- // since we have the precompiler directive on, if it's a read-only instance then
- // the caret will be hid
-
- disableSpeakCursor = WEFeatureFlag( weFReadOnly, weBitTest, we );
-
- #else
-
- // now whether it's read only or not, there will be a caret so we can disable/enable
- // the "Speak from Cursor" "normally"
-
- disableSpeakCursor = false;
-
- #endif
-
- // first, enable everything, disable as we go
-
- for ( i = 0; i <= CountMenuItems( soundMenu ); i++ )
- EnableItem( soundMenu, i );
- for ( i = 0; i<= CountMenuItems( hilitingMenu ); i++ )
- EnableItem( hilitingMenu, i );
-
- // get the toggle strings all set up and the menu displaying the correct text
-
- if ( gPaused )
- GetIndString( pauseResumeStr, kVoiceStringsID, kStrResume );
- else
- GetIndString( pauseResumeStr, kVoiceStringsID, kStrPause );
- SetMenuItemText( soundMenu, iPauseSpeaking, pauseResumeStr );
-
- if ( gSpeechOn )
- GetIndString( onOffStr, kVoiceStringsID, kStrTurnOff );
- else
- {
- if ( gHasSpeechManager )
- GetIndString( onOffStr, kVoiceStringsID, kStrTurnOn );
- else
- GetIndString( onOffStr, kVoiceStringsID, kStrNoSpeechMgr );
- }
-
- SetMenuItemText( soundMenu, iTurnSpeechOnOff, onOffStr );
-
- // and go ahead and adjust the "Speak from Cursor" item
-
- if ( disableSpeakCursor )
- DisableItem( GetMenuHandle( mSound ), iSpeakFromCursor );
-
- // now, we do not want the ability to play a sound while text is being spoken, nor
- // do we want to speak text while a sound is being played. so, there are basically
- // 3 "modes" to check for:
-
- // no sound playing nor speech talking
- // a sound playing
- // speech talking
-
- // first, we'll check for a sound playing
-
- if ( SoundIsPlaying() )
- {
- // ok, a sound is playing, most everything gets disabled
-
- // obviously we can't record
-
- DisableItem( soundMenu, iRecordNewSnd );
-
- // enable Play Sound if and only if a sound object is selected, and if the object
- // selected it a 'snd ' object (you'd think we should check to see if a sound
- // is currently playing, but that's not necessary since Kamprath's Object Handlers
- // can play sound async and starting a sound with one playing will stop any currntly
- // playing sound (e.g. play one sound, while playing select another, start playing
- // it cause this first sound is getting boring).
-
- isOnlySoundObject = WEGetSelectedObject( &objectRef, we );
-
- if ((!isOnlySoundObject) && ( WEGetObjectType( objectRef ) == TYPE_SOUND) )
- EnableItem( soundMenu, iPlaySnd );
- else
- DisableItem( soundMenu, iPlaySnd );
-
-
- // of course, we can stop a playing sound
-
- EnableItem( soundMenu, iStopPlayingSnd );
-
- // and then everything dealing with text to speech should be disabled
-
- DisableItem( soundMenu, iSpeakAll );
- DisableItem( soundMenu, iSpeakFromCursor );
- DisableItem( soundMenu, iSpeakSelection );
- DisableItem( soundMenu, iStopSpeaking );
- DisableItem( soundMenu, iPauseSpeaking );
- DisableItem( soundMenu, iTurnSpeechOnOff );
- DisableItem( soundMenu, iAutoHiliting );
- DisableItem( soundMenu, iSpeechOptions );
-
- // and then just return, we're done
-
- return;
- }
-
- if ( !gSpeechOn )
- {
- // we don't even have speech turned on, so this is pretty simple too. we
- // also know by now that there isn't a sound playing (if there was, we should
- // have hit the previous if statement)
-
- // also, this "if" block is the place to catch things if the Speech Manager
- // isn't even installed on the user's machine. if no speech manager, gSpeechOn
- // will always be false and we'll always come into this if statement (unless
- // there is a sound playing, and in that case, we hit the previous if
- // and the text-to-speech stuff is disabled anyways)
-
- // first, deal with the sound items
-
- // can we record?
-
- if ( !gCanRecordSound )
- DisableItem( soundMenu, iRecordNewSnd );
- else
- {
- // there are capabilities to record sound, but do we want to? depends
- // on the front window
-
- if ( HsoiIsClipboardWindow( window ) )
- DisableItem( soundMenu, iRecordNewSnd );
- }
- // can we play a sound?
-
- isOnlySoundObject = WEGetSelectedObject( &objectRef, we );
-
- if ((!isOnlySoundObject) && ( WEGetObjectType( objectRef ) == TYPE_SOUND) )
- EnableItem( soundMenu, iPlaySnd );
- else
- DisableItem( soundMenu, iPlaySnd );
-
- // can we stop a sound? we shouldn't be able to cause there should be no
- // sounds playing
-
- DisableItem( soundMenu, iStopPlayingSnd );
-
- // and since speech isn't turned on, everything but the "Turn On" item
- // can be disabled
-
- DisableItem( soundMenu, iSpeakAll );
- DisableItem( soundMenu, iSpeakFromCursor );
- DisableItem( soundMenu, iSpeakSelection );
- DisableItem( soundMenu, iStopSpeaking );
- DisableItem( soundMenu, iPauseSpeaking );
- DisableItem( soundMenu, iAutoHiliting );
- DisableItem( soundMenu, iSpeechOptions );
-
- if ( !gHasSpeechManager )
- DisableItem( soundMenu, iTurnSpeechOnOff );
-
- // and we can just return
-
- return;
- } // end: if (!gSpeechOn)
-
- // ok, so by now we know a few things: there are no currently playing sounds,
- // and speech must be on.
-
- // ingoring playing sounds for a moment, there are a few cases within gSpeechOn == true
- // that we have to contend with:
-
- // if we are currently speaking
- // if we're not speaking yet
- // if speech is paused
- // if we're hiliting
-
- // so, let's get to it
-
- if ( gSpeechOn )
- {
- // we know speech is on, and there shouldn't be any sounds playing
-
- // now, if we're already speaking, adjust accordingly
-
- if ( (SpeechBusy() > 0) || gHiliting || gPaused )
- {
- DisableItem( soundMenu, iSpeakAll );
- DisableItem( soundMenu, iSpeakFromCursor );
- DisableItem( soundMenu, iSpeakSelection );
- // stop and pause should already be enabled (and the pause item should have the
- // correct menu item text)
- DisableItem( soundMenu, iAutoHiliting );
- DisableItem( soundMenu, iSpeechOptions );
-
- // and since we know we're speaking, we can disable all the sound stuff
-
- DisableItem( soundMenu, iRecordNewSnd );
- DisableItem( soundMenu, iPlaySnd );
- DisableItem( soundMenu, iStopPlayingSnd );
- }
- else
- {
- long selStart, selEnd;
-
- // we're not speaking yet
-
- // Speak all and speak from cursor should already be enabled
-
- // check if we have a selection, and if not, disable Speak Selection
-
- WEGetSelection( &selStart, &selEnd, we );
-
- if ( selStart == selEnd )
- DisableItem( soundMenu, iSpeakSelection );
-
- DisableItem( soundMenu, iStopSpeaking );
- DisableItem( soundMenu, iPauseSpeaking );
-
- // and turn on/off, autohiliting, and speech options should already be
- // enabled
-
- // do the auto-hiliting sub menu
-
- // enable it all
-
- for ( i = 0; i <= CountMenuItems( hilitingMenu ); i++ )
- EnableItem( hilitingMenu, i );
-
- // set the check marks
-
- CheckItem( hilitingMenu, iHilitingNone, (gHiliteMethod == off) );
- CheckItem( hilitingMenu, iHilitingWord, (gHiliteMethod == word) );
- CheckItem( hilitingMenu, iHilitingSentence, (gHiliteMethod == sentence) );
-
- // and do the sound items
-
- // we know there are no currently playing sounds....
-
- if ( !gCanRecordSound )
- DisableItem( soundMenu, iRecordNewSnd );
- else
- {
- if ( HsoiIsClipboardWindow( window ) )
- DisableItem( soundMenu, iRecordNewSnd );
- }
-
- // enable Play Sound if we can
-
- // can we play a sound?
-
- isOnlySoundObject = WEGetSelectedObject( &objectRef, we );
-
- if ((!isOnlySoundObject) && ( WEGetObjectType( objectRef ) == TYPE_SOUND) )
- EnableItem( soundMenu, iPlaySnd );
- else
- DisableItem( soundMenu, iPlaySnd );
-
- // can we stop a sound? we shouldn't be able to cause there should be no
- // sounds playing
-
- DisableItem( soundMenu, iStopPlayingSnd );
- }
-
- // we have to check if spoken text is being hilited. if so, we cannot allow
- // much else to occur. basically, disable everything.
-
- if ( gHiliting )
- {
- DisableItem( GetMenuHandle( mApple ), 0 );
- DisableItem( GetMenuHandle( mFile ), 0 );
- DisableItem( GetMenuHandle( mEdit ), 0 );
- DisableItem( GetMenuHandle( mText ), 0 );
- DisableItem( GetMenuHandle( mDialogs ), 0 );
- DisableItem( GetMenuHandle( mWindows ), 0 );
- }
-
- }// end: if ( gSpeechOn )
-
-
- // and hopefully, that does it all just right!
-
-
- return;
- }