#!/usr/bin/wish -f ##+########################################################################### ## ## SCRIPT: tkSpeakText_with_espeak.tk ## ## PURPOSE: This Tk GUI script provides a Tk text widget in which the user ## can enter many words (on multiple lines). The words are to ## be spoken by the 'espeak' command, when the user clicks on a ## 'Speak' button. ## ## Alternatively, the user can choose to write the audio to ## a '.wav' audio file, when the user clicks on a 'WriteWAVfile' ## button. ## ## Other speech control options may be implemented ## via widgets on the GUI: ## - amplitude of the speech (0 to20, default 10) ## - pitch of the speech (0 to 99, default 50) ## - speed of the speech (default 160 words/min) ## - write phoneme mnemonics to a text file ## - speak the names of punctuation characters ## ######################################################################### ## THE GUI LAYOUT: ## ## The options available to the user are indicated by ## the following 'sketch' of the GUI: ## ## FRAMEnames ## VVVVVVVVVV ## -------------------------------------------------------------------------- ## tkSpeakText --- using 'espeak' ## [window title] ## -------------------------------------------------------------------------- ## ## .fRbuttons {Exit} {Help} {Speak} {WriteWAVfile} {WritePhonemeFile} ## ## .fRcontrols1 Amplitude: <---------O----------------> Pitch: <---------O---------> ## ## .fRcontrols2 Speed (words/min): <---------O--------> X Speak punctuation chars ## ## .fRmsg [ .......... Messages go here .........................................] ## ## .fRtext |------------------------------------------------------------------------A ## | | ## | [This scrollable text area contains the text-to-be-spoken.] | ## | | ## | | ## | | ## | | ## | | ## |<---------------------------------------------------------------------->V ## ## ------------------------------------------------------------------- ## ## In the above sketch of the GUI: ## ## SQUARE BRACKETS indicate a comment (not to be placed on the GUI). ## BRACES indicate a Tk 'button' widget. ## UNDERSCORES indicate a Tk 'entry' widget. ## A COLON indicates that the text before the colon is on a 'label' widget. ## CAPITAL-O indicates a Tk 'radiobutton' widget. ## CAPITAL-X indicates a Tk 'checkbutton' widget (if any). ## Vertical bars (and horizontal hyphens) outline a 'listbox' widget. ## Less-than and greater-than signs indicate the left and right ends of a horizontal 'scrollbar'. ## Capital-V and Capital-A letters indicate the bottom and top ends of a vertical 'scrollbar'. ## ##+############## ## GUI components: ## ## From the GUI 'sketch' above, it is seen that the GUI consists of ## about ## ## - 5 button widgets ## - 4 label widgets ## - 3 scale widgets ## - 1 text widget with scrollbars ## - 1 checkbutton widget ## - 0 radiobutton widgets ## - 0 listbox widgets ## - 0 canvas widgets ## ##+####################################################################### ## 'CANONICAL' STRUCTURE OF THIS CODE: ## ## 0) Set general window and widget parms (win-name, win-position, ## win-color-scheme, fonts, win-min-size, text-array-for-labels-etc). ## 1a) Define ALL frames (and sub-frames, if any). ## 1b) Pack all the frames. ## 2) Define & pack all widgets in the frames, frame by frame. ## ## 3) Define BINDINGS for key and mouse/touchpad/touch-screen 'events', ## if needed. ## 4) Define PROCS, if needed. ## 5) Additional GUI initialization (typically with one or more of ## the procs), if needed. ## ##+################################# ## Some detail of the code structure of this particular script: ## ## 1a) Define ALL frames: ## ## Top-level : ## 'fRbuttons' - to contain several button widgets (Exit,Help,Speak,...). ## 'fRcontrols1' - to contain a couple of scale widgets. ## 'fRcontrols2' - to contain a scale widget and a checkbutton widget. ## 'fRmsg' - to contain a label widget. ## 'fRtext' - to contain a text widget, with scrollbars ## ## Sub-frames: none ## ## 1b) Pack ALL frames. ## ## 2) Define & pack all WIDGETS in the frames -- basically going through ## frames & their interiors in left-to-right and/or top-to-bottom order. ## ## 3) Define BINDINGS: ## ## 4) Define PROCS: ## - 'speak_text' called by 'Speak' button ## - 'write_wav_file' called by 'WriteWAVfile' button ## - 'advise_user' called by various procs ## - 'popup_msgVarWithScroll' called by the 'Help' button ## ## 5) ADDITIONAL GUI INITIALIZATION: Set some variables --- such as DIRout ## to specify directory location of ## output files --- such as /tmp. ## Also set voice-name for the default ## voice. ##+####################################################################### ## DEVELOPED WITH: Tcl-Tk 8.5 on Ubuntu 9.10 (2009-october, 'Karmic Koala') ## ## $ wish ## % puts "$tcl_version $tk_version" ## ## showed ## 8.5 8.5 ## but this script should work in most previous 8.x versions, and probably ## even in some 7.x versions (if font handling is made 'old-style'). ##+####################################################################### ## MAINTENANCE HISTORY: ## Started by: Blaise Montandon 2016jan27 ## Changed by: Blaise Montandon 2016feb04 Add 'after' pauses to procs ## 'speak_text', 'write_wav_file', ## and 'write_phoneme_file'. ##+######################################################################## ##+####################################################################### ## Set WINDOW TITLE and POSITION. ##+####################################################################### wm title . "tkSpeakText --- using 'espeak'" wm iconname . "SpeakText" wm geometry . +15+30 ##+###################################################### ## Set the COLOR SCHEME for the window and its widgets --- ## such as entry field background color. ##+###################################################### tk_setPalette "#e0e0e0" # set entryBKGD "#ffffff" # set listboxBKGD "#ffffff" set chkbuttBKGD "#ffffff" ## CYAN background for the text area. # set textBKGD "#00ffff" ## GREEN background for the text area. set textBKGD "#33ff33" ##+######################################################## ## Set (temp) FONT NAMES. ## ## We use a VARIABLE-WIDTH font for text on LABEL and ## BUTTON widgets. ## ## We use a FIXED-WIDTH font for the text in ENTRY, LISTBOX, ## and TEXT (or MESSAGE) widgets. ##+######################################################## font create fontTEMP_varwidth \ -family {comic sans ms} \ -size -14 \ -weight bold \ -slant roman font create fontTEMP_SMALL_varwidth \ -family {comic sans ms} \ -size -12 \ -weight bold \ -slant roman ## Some other possible (similar) variable width fonts: ## Arial ## Bitstream Vera Sans ## DejaVu Sans ## Droid Sans ## FreeSans ## Liberation Sans ## Nimbus Sans L ## Trebuchet MS ## Verdana font create fontTEMP_fixedwidth \ -family {liberation mono} \ -size -14 \ -weight bold \ -slant roman font create fontTEMP_SMALL_fixedwidth \ -family {liberation mono} \ -size -12 \ -weight bold \ -slant roman ## Some other possible fixed width fonts (esp. on Linux): ## Andale Mono ## Bitstream Vera Sans Mono ## Courier 10 Pitch ## DejaVu Sans Mono ## Droid Sans Mono ## FreeMono ## Nimbus Mono L ## TlwgMono ##+########################################################### ## Set variables for GEOMETRIC attributes of various widgets. ## (e.g. width and height of canvas, and padding for Buttons) ##+########################################################### ## BUTTON widget geom settings: set PADXpx_button 0 set PADYpx_button 0 set BDwidthPx_button 2 ## LABEL widget geom settings: set PADXpx_label 0 set PADYpx_label 0 set BDwidthPx_label 2 set RELIEF_label "ridge" ## SCALE geom parameters: set BDwidthPx_scale 2 # set initScaleLengthPx 100 set scaleThicknessPx 10 set scaleRepeatDelayMillisecs 800 ## CHECKBUTTON widget geom settings: set BDwidthPx_chkbutt 2 set RELIEF_chkbutt "ridge" ## TEXT widget geom settings: set initTextWidthChars 80 set initTextHeightChars 10 # set BDwidthPx_text 2 set BDwidthPx_text 0 ## DE-ACTIVATE THE FOLLOWING WIDGET-GEOM VARS, for now. if {0} { ## ENTRY widget geom settings: # set BDwidthPx_entry 2 # set initEntryWidthChars 20 ## LISTBOX geom settings: # set BDwidthPx_listbox 2 # set initListboxWidthChars 30 # set initListboxHeightChars 8 ## CANVAS widget geom settings: set initCanWidthPx 100 set initCanHeightPx 100 set minCanWidthPx 24 set minCanHeightPx 24 # set BDwidthPx_canvas 2 set BDwidthPx_canvas 0 } ## END OF if {0} section ##+###################################################### ## Set a MIN-SIZE of the window (roughly). ## ## We set approx MIN WIDTH of the window based on a width ## allowance for, at least, several buttons in the ## 'fRbuttons' frame. ## ## We set the approx MIN HEIGHT of the window based on ## allowance for ## 1 char high for the 'fRbuttons' frame ## 1 char high for the 'fRcontrols1' frame ## 1 char high for the 'fRcontrols2' frame ## 1 char high for the 'fRmsg' frame ## 3 chars high for the 'fRtext' frame ##+###################################################### set minWinWidthPx [font measure fontTEMP_fixedwidth \ " Exit Help Speak WriteWAVfile "] ## Add some pixels to account for right-left-size of window-manager ## decoration (about 8 pixels) --- and add some pixels for ## frame/widget borders (about 4 widgets x 4 pixels/widget): set minWinWidthPx [expr {24 + $minWinWidthPx}] ## Get approx min-HEIGHT for the window allowing ## 1 char high for the 'fRbuttons' frame ## 1 char high for the 'fRcontrols1' frame ## 1 char high for the 'fRcontrols2' frame ## 1 char high for the 'fRmsg' frame ## 3 chars high for the 'fRtext' frame ## ## Add about 20 pixels for top-bottom window decoration -- ## and about 5 frames x 4 pixels/frame for frame/widget borders. set charHeightPx [font metrics fontTEMP_fixedwidth -linespace] set minWinHeightPx [expr {( 7 * $charHeightPx ) + 40 }] ## FOR TESTING: # puts "minWinWidthPx = $minWinWidthPx" # puts "minWinHeightPx = $minWinHeightPx" wm minsize . $minWinWidthPx $minWinHeightPx ## We allow the window to be resizable and we pack the canvas with ## '-fill both' so that the canvas can be enlarged by enlarging the ## window. ## If you want to make the window un-resizable, ## you can use the following statement. # wm resizable . 0 0 ##+#################################################################### ## Set a TEXT-ARRAY to hold text for buttons & labels on the GUI. ## NOTE: This can aid INTERNATIONALIZATION. This array can ## be set according to a nation/region parameter. ##+#################################################################### ## if { "$VARlocale" == "en"} ## For frame 'fRbuttons': set aRtext(buttonEXIT) "Exit" set aRtext(buttonHELP) "Help" set aRtext(buttonCLEARTEXT) "ClearText" set aRtext(buttonSPEAK) "Speak" set aRtext(buttonWRITEWAV) "WriteWAVfile" set aRtext(buttonWRITEPHON) "WritePhonemeFile" ## For frame 'fRcontrols1': set aRtext(labelAMPLITUDE) "Amplitude:" set aRtext(labelPITCH) "Pitch:" ## For frame 'fRcontrols2': set aRtext(labelSPEED) "Speed (words/min):" set aRtext(chkbuttSPEAKPUNCT) "Speak punctuation chars?" ## END OF if { "$VARlocale" == "en"} ##+################################################################ ## DEFINE *ALL* THE FRAMES: ## ## Top-level : '.fRbuttons' '.fRcontrols1' '.fRcontrols2' ## '.fRmsg' '.fRtext' ## ## Sub-frames: none ##+################################################################ ## FOR TESTING: (of resizing of frames during window resizing): # set feRELIEF_frame raised # set feBDwidth_frame 2 set RELIEF_frame flat set BDwidth_frame 0 frame .fRbuttons -relief $RELIEF_frame -bd $BDwidth_frame frame .fRcontrols1 -relief $RELIEF_frame -bd $BDwidth_frame frame .fRcontrols2 -relief $RELIEF_frame -bd $BDwidth_frame frame .fRmsg -relief raised -bd 2 frame .fRtext -relief $RELIEF_frame -bd $BDwidth_frame ##+############################## ## PACK ALL the FRAMES. ##+############################## pack .fRbuttons \ -side top \ -anchor nw \ -fill x \ -expand 0 pack .fRcontrols1 \ -side top \ -anchor nw \ -fill x \ -expand 0 pack .fRcontrols2 \ -side top \ -anchor nw \ -fill x \ -expand 0 pack .fRmsg \ -side top \ -anchor nw \ -fill x \ -expand 0 pack .fRtext \ -side top \ -anchor nw \ -fill both \ -expand 1 ##+################################# ## In FRAME '.fRbuttons' - ## DEFINE-and-PACK BUTTON widgets ## --- 'Exit','Help','ShoImg'. ##+################################# button .fRbuttons.buttEXIT \ -text "$aRtext(buttonEXIT)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {exit} button .fRbuttons.buttHELP \ -text "$aRtext(buttonHELP)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {popup_msgVarWithScroll .topHelp "$HELPtext"} button .fRbuttons.buttCLEARTEXT \ -text "$aRtext(buttonCLEARTEXT)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {clear_text} button .fRbuttons.buttSPEAK \ -text "$aRtext(buttonSPEAK)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {speak_text} button .fRbuttons.buttWRITEWAV \ -text "$aRtext(buttonWRITEWAV)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {write_wav_file} button .fRbuttons.buttWRITEPHON \ -text "$aRtext(buttonWRITEPHON)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {write_phoneme_file} ## Pack the widgets of frame 'fRbuttons'. pack .fRbuttons.buttEXIT \ .fRbuttons.buttHELP \ .fRbuttons.buttCLEARTEXT \ .fRbuttons.buttSPEAK \ .fRbuttons.buttWRITEWAV \ .fRbuttons.buttWRITEPHON \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRcontrols1' frame -- ## DEFINE a LABEL and SCALE widget pair and another pair. ## Then PACK them. ##+######################################################## label .fRcontrols1.labelAMPLITUDE \ -text "$aRtext(labelAMPLITUDE)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief $RELIEF_label \ -bd $BDwidthPx_label ## 'VARamplitude' is the var for this scale widget. set VARamplitude 50 scale .fRcontrols1.scaleAMPLITUDE \ -from 0 -to 200 \ -resolution 1 \ -bigincrement 2 \ -repeatdelay $scaleRepeatDelayMillisecs \ -length 200 \ -font fontTEMP_varwidth \ -variable VARamplitude \ -showvalue true \ -orient horizontal \ -bd $BDwidthPx_scale \ -width $scaleThicknessPx label .fRcontrols1.labelPITCH \ -text "$aRtext(labelPITCH)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief $RELIEF_label \ -bd $BDwidthPx_label ## 'VARpitch' is the var for this scale widget. set VARpitch 50 scale .fRcontrols1.scalePITCH \ -from 0 -to 99 \ -resolution 1 \ -bigincrement 10 \ -repeatdelay $scaleRepeatDelayMillisecs \ -length 200 \ -font fontTEMP_varwidth \ -variable VARpitch \ -showvalue true \ -orient horizontal \ -bd $BDwidthPx_scale \ -width $scaleThicknessPx ## PACK the widgets in frame 'fRcontrols1'. pack .fRcontrols1.labelAMPLITUDE \ .fRcontrols1.scaleAMPLITUDE \ .fRcontrols1.labelPITCH \ .fRcontrols1.scalePITCH \ -side left \ -anchor w \ -fill none \ -expand 0 ##+############################################################ ## IN THE '.fRcontrols2' frame -- ## DEFINE a LABEL and SCALE widget pair and a CHECKBUTTON widget. ## Then PACK them. ##+############################################################ label .fRcontrols2.labelSPEED \ -text "$aRtext(labelSPEED)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief $RELIEF_label \ -bd $BDwidthPx_label ## 'VARspeed' is the var for this scale widget. set VARspeed 160 scale .fRcontrols2.scaleSPEED \ -from 10 -to 200 \ -resolution 1 \ -bigincrement 10 \ -repeatdelay $scaleRepeatDelayMillisecs \ -length 200 \ -font fontTEMP_varwidth \ -variable VARspeed \ -showvalue true \ -orient horizontal \ -bd $BDwidthPx_scale \ -width $scaleThicknessPx set speakPunct0or1 0 checkbutton .fRcontrols2.chkbuttSPEAKPUNCT \ -text "$aRtext(chkbuttSPEAKPUNCT)" \ -font fontTEMP_varwidth \ -variable speakPunct0or1 \ -selectcolor "$chkbuttBKGD" \ -relief $RELIEF_chkbutt \ -bd $BDwidthPx_chkbutt ## PACK the widgets in frame 'fRcontrols2'. pack .fRcontrols2.labelSPEED \ .fRcontrols2.scaleSPEED \ .fRcontrols2.chkbuttSPEAKPUNCT \ -side left \ -anchor w \ -fill none \ -expand 0 ##+################################################################## ## In the '.fRmsg' FRAME --- ## DEFINE-and-PACK 1 LABEL widget. ##+################################################################## label .fRmsg.labelINFO \ -text "" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -background "#ff9999" \ -bd $BDwidthPx_button pack .fRmsg.labelINFO \ -side left \ -anchor w \ -fill x \ -expand 1 ##+############################### ## In FRAME '.fRtext' - ## DEFINE-and-PACK a TEXT widget, ## with SCROLLBARS. ##+############################### text .fRtext.text \ -relief raised \ -borderwidth 2 \ -height $initTextHeightChars \ -width $initTextWidthChars \ -wrap none \ -font fontTEMP_fixedwidth \ -bg $textBKGD \ -state normal \ -yscrollcommand ".fRtext.scrbary set" \ -xscrollcommand ".fRtext.scrbarx set" scrollbar .fRtext.scrbary \ -command ".fRtext.text yview" scrollbar .fRtext.scrbarx \ -orient horizontal \ -command ".fRtext.text xview" ## Pack the widgets in frame 'fRtext'. ## (Pack the scrollbars first, so that ## the text widget does not expand into ## the entire space.) pack .fRtext.scrbary \ -side right \ -anchor center \ -fill y \ -expand 0 pack .fRtext.scrbarx \ -side bottom \ -anchor center \ -fill x \ -expand 0 pack .fRtext.text \ -side top \ -anchor n \ -fill both \ -expand 1 ## Make sure the text widget is empty. .fRtext.text insert 1.0 "" ##+################################################## ## END OF DEFINITION of the GUI widgets. ##+################################################## ## Start of BINDINGS, PROCS, Added-GUI-INIT sections. ##+################################################## ##+####################################################################### ##+####################################################################### ## BINDINGS SECTION: none ##+####################################################################### ##+##################################################################### ##+##################################################################### ## DEFINE PROCS SECTION: ## ## - 'speak_text' called by 'Speak' button ## - 'write_wav_file' called by 'WriteWAVfile' button ## - 'write_phoneme_file' called by 'WritePhonemeFile' button ## - 'clear_text' called by 'ClearText' button ## - 'advise_user' called by various procs ## - 'popup_msgVarWithScroll' called by the 'Help' button ## ##+##################################################################### ##+##################################################################### ## proc 'speak_text' ## ## PURPOSE: Calls on 'espeak' to speak the text in the text widget. ## ## CALLED BY: the 'Speak' button. ##+##################################################################### proc speak_text {} { global VARamplitude VARpitch VARspeed VARvoice speakPunct0or1 ## Get text data from the text widget, into a temp variable. set HOLDtext [.fRtext.text get 1.0 end] set HOLDtext [string trim "$HOLDtext"] advise_user \ "Invoking 'espeak' with parameters -a $VARamplitude -p $VARpitch -s $VARspeed -v $VARvoice ** WAIT for ready msg. **" if {$speakPunct0or1 == 1} { exec espeak -a $VARamplitude -p $VARpitch -s $VARspeed -v $VARvoice \ --punct "$HOLDtext" 2> /dev/null } else { exec espeak -a $VARamplitude -p $VARpitch -s $VARspeed -v $VARvoice \ "$HOLDtext" 2> /dev/null } ## Allow some time (about 4 secs) for 'espeak' to 'recover' so that ## a click on the 'Speak' button will work again. after 4000 advise_user "** Ready to (change text and) click 'Speak' again. **" } ## END OF proc 'speak_text' ##+######################################################################## ## proc 'clear_text' ## ## PURPOSE: Clears the text widget. ## ## CALLED BY: the 'ClearText' button ##+######################################################################## proc clear_text {} { .fRtext.text delete 1.0 end } ## END OF proc 'clear_text' ##+######################################################################### ## proc 'write_wav_file' ## ## PURPOSE: To write a '.wav' audio file from the text in the text widget. ## ## CALLED BY: the 'WriteWAVfile' button. ##+######################################################################### proc write_wav_file {} { global VARamplitude VARpitch VARspeed VARvoice \ WAVout PLAYERwav speakPunct0or1 catch {exec rm "$WAVout"} ## Get text data from the text widget, into a temp variable. set HOLDtext [.fRtext.text get 1.0 end] set HOLDtext [string trim "$HOLDtext"] if {$speakPunct0or1 == 1} { exec espeak -a $VARamplitude -p $VARpitch -s $VARspeed -v $VARvoice \ --punct -w "$WAVout" "$HOLDtext" 2> /dev/null } else { exec espeak -a $VARamplitude -p $VARpitch -s $VARspeed -v $VARvoice \ -w "$WAVout" "$HOLDtext" 2> /dev/null } exec "$PLAYERwav" "$WAVout" & advise_user "** WAV file was written to $WAVout **" ## Allow some time (about 8 secs) for 'espeak' to 'recover' so that ## a click on the 'Speak' button will work again. after 8000 } ## END OF proc 'write_wav_file' ##+######################################################################### ## proc 'write_phoneme_file' ## ## PURPOSE: To write a phonemes text file from the text in the text widget. ## ## CALLED BY: the 'WritePhonemeFile' button. ##+######################################################################### proc write_phoneme_file {} { global VARamplitude VARpitch VARspeed VARvoice \ PHONEMEout PLAYERtxt speakPunct0or1 catch {exec rm "$PHONEMEout"} ## Get text data from the text widget, into a temp variable. set HOLDtext [.fRtext.text get 1.0 end] set HOLDtext [string trim "$HOLDtext"] if {$speakPunct0or1 == 1} { exec espeak -a $VARamplitude -p $VARpitch -s $VARspeed -v $VARvoice \ --punct -x "$HOLDtext" 2> /dev/null > "$PHONEMEout" } else { exec espeak -a $VARamplitude -p $VARpitch -s $VARspeed -v $VARvoice \ -x "$HOLDtext" 2> /dev/null > "$PHONEMEout" } exec "$PLAYERtxt" "$PHONEMEout" & advise_user "** Phoneme file was written to $PHONEMEout **" ## Allow some time (about 6 secs) for 'espeak' to 'recover' so that ## a click on the 'Speak' button will work again. after 6000 } ## END OF proc 'write_phoneme_file' ##+##################################################################### ## PROC 'advise_user' ##+##################################################################### ## PURPOSE: Puts a message to the user on the GUI. ## ## CALLED BY: in three 'set_*_color*' procs, ## in some 'bind' statements in the BIND section above, ## and in the additional-GUI-initialization section at ## the bottom of this script. ##+##################################################################### proc advise_user {text} { .fRmsg.labelINFO configure -text "$text" ## Make sure the text is displayed on the GUI. update ## Alternatively, we could put the message in the title-bar ## of the GUI window. (But it is easy for the user to ## fail to see the message there. Besides, we have more ## options in displaying the message by putting it on a ## Tk widget in the GUI.) ## # wm title . "$text" } ## END OF PROC 'advise_user' ##+######################################################################## ## PROC 'popup_msgVarWithScroll' ##+######################################################################## ## PURPOSE: Report help or error conditions to the user. ## ## We do not use focus,grab,tkwait in this proc, ## because we use it to show help when the GUI is idle, ## and we may want the user to be able to keep the Help ## window open while doing some other things with the GUI ## such as putting a filename in the filename entry field ## or clicking on a radiobutton. ## ## For a similar proc with focus-grab-tkwait added, ## see the proc 'popup_msgVarWithScroll_wait' in a ## 3DterrainGeneratorExaminer Tk script. ## ## REFERENCE: page 602 of 'Practical Programming in Tcl and Tk', ## 4th edition, by Welch, Jones, Hobbs. ## ## ARGUMENTS: A toplevel frame name (such as .fRhelp or .fRerrmsg) ## and a variable holding text (many lines, if needed). ## ## CALLED BY: 'help' button ##+######################################################################## ## To have more control over the formatting of the message (esp. ## words per line), we use this 'toplevel-text' method, ## rather than the 'tk_dialog' method -- like on page 574 of the book ## by Hattie Schroeder & Mike Doyel,'Interactive Web Applications ## with Tcl/Tk', Appendix A "ED, the Tcl Code Editor". ##+######################################################################## proc popup_msgVarWithScroll { toplevName VARtext } { ## global fontTEMP_varwidth #; Not needed. 'wish' makes this global. ## global env # bell # bell ################################################# ## Set VARwidth & VARheight from $VARtext. ################################################# ## To get VARheight, ## split at '\n' (newlines) and count 'lines'. ################################################# set VARlist [ split $VARtext "\n" ] ## For testing: # puts "VARlist: $VARlist" set VARheight [ llength $VARlist ] ## For testing: # puts "VARheight: $VARheight" ################################################# ## To get VARwidth, ## loop through the 'lines' getting length ## of each; save max. ################################################# set VARwidth 0 ############################################# ## LOOK AT EACH LINE IN THE LIST. ############################################# foreach line $VARlist { ############################################# ## Get the length of the line. ############################################# set LINEwidth [ string length $line ] if { $LINEwidth > $VARwidth } { set VARwidth $LINEwidth } } ## END OF foreach line $VARlist ## For testing: # puts "VARwidth: $VARwidth" ############################################################### ## NOTE: VARwidth works for a fixed-width font used for the ## text widget ... BUT the programmer may need to be ## careful that the contents of VARtext are all ## countable characters by the 'string length' command. ############################################################### ##################################### ## SETUP 'TOP LEVEL' HELP WINDOW. ##################################### catch {destroy $toplevName} toplevel $toplevName # wm geometry $toplevName 600x400+100+50 wm geometry $toplevName +100+50 wm title $toplevName "Note" # wm title $toplevName "Note to $env(USER)" wm iconname $toplevName "Note" ##################################### ## In the frame '$toplevName' - ## DEFINE THE TEXT WIDGET and ## its two scrollbars --- and ## DEFINE an OK BUTTON widget. ##################################### if {$VARheight > 10} { text $toplevName.text \ -wrap none \ -font fontTEMP_varwidth \ -width $VARwidth \ -height $VARheight \ -bg "#f0f0f0" \ -relief raised \ -bd 2 \ -yscrollcommand "$toplevName.scrolly set" \ -xscrollcommand "$toplevName.scrollx set" scrollbar $toplevName.scrolly \ -orient vertical \ -command "$toplevName.text yview" scrollbar $toplevName.scrollx \ -orient horizontal \ -command "$toplevName.text xview" } else { text $toplevName.text \ -wrap none \ -font fontTEMP_varwidth \ -width $VARwidth \ -height $VARheight \ -bg "#f0f0f0" \ -relief raised \ -bd 2 } button $toplevName.butt \ -text "OK" \ -font fontTEMP_varwidth \ -command "destroy $toplevName" ############################################### ## PACK *ALL* the widgets in frame '$toplevName'. ############################################### ## Pack the bottom button BEFORE the ## bottom x-scrollbar widget, pack $toplevName.butt \ -side bottom \ -anchor center \ -fill none \ -expand 0 if {$VARheight > 10} { ## Pack the scrollbars BEFORE the text widget, ## so that the text does not monopolize the space. pack $toplevName.scrolly \ -side right \ -anchor center \ -fill y \ -expand 0 ## DO NOT USE '-expand 1' HERE on the Y-scrollbar. ## THAT ALLOWS Y-SCROLLBAR TO EXPAND AND PUTS ## BLANK SPACE BETWEEN Y-SCROLLBAR & THE TEXT AREA. pack $toplevName.scrollx \ -side bottom \ -anchor center \ -fill x \ -expand 0 ## DO NOT USE '-expand 1' HERE on the X-scrollbar. ## THAT KEEPS THE TEXT AREA FROM EXPANDING. pack $toplevName.text \ -side top \ -anchor center \ -fill both \ -expand 1 } else { pack $toplevName.text \ -side top \ -anchor center \ -fill both \ -expand 1 } ##################################### ## LOAD MSG INTO TEXT WIDGET. ##################################### ## $toplevName.text delete 1.0 end $toplevName.text insert end $VARtext $toplevName.text configure -state disabled } ## END OF PROC 'popup_msgVarWithScroll' ##+######################## ## END of PROC definitions. ##+######################## ## Set HELPtext variable. ##+######################## set HELPtext "\ *** HELP for this 'tkSpeakText' utility --- using the 'espeak' program *** This Tk GUI script provides a Tk text widget in which the user can enter many words (on multiple lines) in a text area on the GUI. The words are to be spoken by the 'espeak' command, when the user clicks on a 'Speak' button. Alternatively, the user can choose to write the audio to a '.wav' audio file, when the user clicks on a 'WriteWAVfile' button. A second alternative: The user can choose to write a text file containing phonemes (spellings that sound similar to the user-supplied text). Some speech control options are implemented via widgets on the GUI: - amplitude of the speech (0 to 200, default 50) - pitch of the speech (0 to 99, default 50) - speed of the speech (default 160 words/min) - speak the names of punctuation characters. **************************************** PLAYBACK of the '.wav' and phoneme files: When either of these two files are written, they are immediately 'played'. The 'players' are set via two variables in the Tk script: PLAYERwav and PLAYERtxt. The following 'set' statements show some examples of how the two 'players' can be changed. # set PLAYERwav \"/usr/bin/audacity\" # set PLAYERwav \"/usr/bin/ffplay\" set PLAYERwav \"/usr/bin/totem\" # set PLAYERtxt \"/usr/bin/gedit\" # set PLAYERtxt \"/usr/bin/kedit\" set PLAYERtxt \"$env(HOME)/apps/bin/xpg\" This Tk script can be edited to change the players that are used. The 'set' statements are near the bottom of the script. *************** VOICE setting: The 'espeak' command allows for different 'voices' reflecting different languages. The vollowing 'set' statement, near the bottom of the script, sets the voice. set VARvoice \"english-us\" Other voices can be set --- such as czech, german, greek, finnish, french, slovak, spanish, swedish, etc. The command 'espeak --voices' can be used to show the available voices. *********************** 'man' HELP FOR 'espeak': (2007) NAME espeak - A multi-lingual software speech synthesizer. SYNOPSIS espeak \[options\] \[\] DESCRIPTION espeak is a software speech synthesizer for English, and some other languages. OPTIONS -h Show summary of options. -f Text file to speak --stdin Read text input from stdin instead of a file If neither -f nor --stdin, are spoken, or if none then text is spoken from stdin, each line separately. -q Quiet, don't produce any speech (may be useful with -x) -a Amplitude, 0 to 20, default is 10 \[This seems to be in error. The max can be set much larger, such as 200.\] -l Line length. If not zero (which is the default), consider lines less than this length as and-of-clause -p Pitch adjustment, 0 to 99, default is 50 -s Speed in words per minute, default is 160 -v Use voice file of this name from espeak-data/voices -b Input text is 8-bit encoding -m Indicates that the text contains SSML (Speech Synthesis Markup Language) tags or other XML tags. Those SSML tags which are sup- ported are interpreted. Other tags, including HTML, are ignored, except that some HTML tags such as

and
  • ensure a break in the speech. -w Write output to this WAV file, rather than speaking it directly -x Write phoneme mnemonics to stdout -X Write phonemes mnemonics and translation trace to stdout. If rules files have been built with --compile=debug, line numbers will also be displayed. --stdout Write speech output to stdout --compile= Compile the pronunciation rules and dictionary in the current directory. = is optional and specifies which lan- guage --path= Specifies the directory containing the espeak-data directory --phonout= Write output from -x -X commands and mbrola phoneme data to this file --punct=\"\" Speak the names of punctuation characters during speaking. If = is omitted, all punctuation is spoken. -k Indicate capital letters with: 1=sound, 2=the word \"capitals\", higher values = a pitch increase (try -k20). --voices\[=\] Lists the available voices. If = is present then only those voices which are suitable for that language are listed. --compile=voicename Compile the pronunciation rules and dictionary in the current directory. = is optional and specifies which lan- guage --compile=debug Compile the pronunciation rules and dictionary in the current directory as above, but include line numbers, that get shown when -X is used. AUTHOR eSpeak was written by Jonathan Duddington . The webpage for this package can be found at http://espeak.source- forge.net/. This manual page was written by Luke Yelavich , for the Ubuntu project (but may be used by others). " ##+###################################################### ##+###################################################### ## ADDITIONAL GUI INITIALIZATION SECTION: ##+###################################################### ##+###################################################### ##+##################################################### ## Set the name of the output file directory. ##+##################################################### set DIRout "/tmp" ##+##################################################### ## Set the full-name of the possible '.wav' and ## phoneme output files. ##+##################################################### set WAVout "$DIRout/$env(USER)_espeak.wav" set PHONEMEout "$DIRout/$env(USER)_espeak_phonemes.txt" ##+##################################################### ## Set a 'player' for the '.wav' and '.txt' output files. ##+##################################################### # set PLAYERwav "/usr/bin/audacity" # set PLAYERwav "/usr/bin/ffplay" set PLAYERwav "/usr/bin/totem" # set PLAYERtxt "/usr/bin/gedit" set PLAYERtxt "$env(HOME)/apps/bin/xpg" ##+##################################################### ## Set the voice to use. ## Examples from ## $ espeak --voices ## Pty Language Age/Gender VoiceName File Other Langs ## 5 af M afrikaans af ## 5 bs M bosnian bs ## 5 ca M catalan ca ## 5 cs M czech cs ## 5 cy M welsh-test cy ## 5 da M danish-test da ## 5 de M german de ## 5 el M greek el ## 5 en M default default ## 5 en-sc M en-scottish en/en-sc (en 4) ## 2 en-uk M english en/en (en 2) ## 5 en-uk-north M lancashire en/en-n (en-uk 3) ## 5 en-uk-rp M english_rp en/en-rp (en-uk 4) ## 5 en-uk-wmids M english_wmids en/en-wm ## 2 en-us M english-us en/en-us (en-r 5)(en 3) ## 5 en-wi M en-westindies en/en-wi (en-uk 4) ## 5 eo M esperanto eo ## 5 es M spanish es ## 5 es-la M spanish-latin-american es-la (es-mx 6) ## 5 fi M finnish fi ## 5 fr M french fr ## ..... ##+##################################################### # set VARvoice "english" set VARvoice "english-us" # set VARvoice "french" # set VARvoice "spanish" ##+############################################# ## Tell user how to start. ##+############################################# advise_user "** Enter text in scrollable text area below. Click 'Speak'. **" ##+############################################# ## Put an initial words in the text widget. ##+############################################# .fRtext.text insert 1.0 "This is a test."