#!/usr/bin/tclsh # Keywords: Emacspeak, Software Dectalk , TCL # {{{ LCD Entry: # LCD Archive Entry: # emacspeak| T. V. Raman |raman@cs.cornell.edu # A speech interface to Emacs | #$Id$ #Incorporating fixes from by Tim Cross for DTk 5.0 # Date: 2004/05/01 01:16:25 | # Location undetermined # # }}} # {{{ Copyright: #Copyright (C) 1995 -- 2001, T. V. Raman #All Rights Reserved # # This file is not part of GNU Emacs, but the same permissions apply. # # GNU Emacs is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # GNU Emacs is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Emacs; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. # }}} # {{{source common code package require Tclx set wd [file dirname $argv0] source $wd/tts-lib.tcl set tts(old_rate) 0 # }}} # {{{ procedures proc tts_set_punctuations {mode} { global tts set tts(punctuations) $mode return "" } proc tts_set_speech_rate {rate} { global tts set factor $tts(char_factor) set tts(speech_rate) $rate set tts(say_rate) [round [expr $rate * $factor ]] return "" } proc tts_set_character_scale {factor} { global tts set tts(say_rate) [round [expr $tts(speech_rate) * $factor ]] set tts(char_factor) $factor return "" } proc tts_say {text} { global tts # synth "\[:sa w]$text\013" synth "\[:sa w]$text " return "" } #formerly called tts_letter proc l {text} { global tts set r $tts(speech_rate) set f $tts(say_rate) #synth "\[:say letter]$text\[:say clause]" synth "$text " return "" } #formerly called tts_speak proc d {} { speech_task } proc tts_resume {} { resume return "" } proc tts_repeat {} { global tts queue_rewind if {[queue_empty?]} { synth "No speech to repeat. " set tts(not_stopped) 1 } else { speech_task } return "" } proc tts_pause {} { pause return "" } #formerly called tts_stop proc s {} { stop queue_clear } #formerly called tts_tone proc t {{pitch 440} {duration 50}} { global tts queue set tone "\[:to $pitch $duration\]" set queue($tts(q_tail)) [list t $tone] incr tts(q_tail) return "" } proc sh {{duration 50}} { global tts queue set silence "\[_] " #set queue($tts(q_tail)) [list t $silence] #incr tts(q_tail) return "" } proc tts_split_caps {flag} { global tts set tts(split_caps) $flag return "" } proc tts_capitalize {flag} { global tts set tts(capitalize) $flag return "" } proc tts_allcaps_beep {flag} { global tts set tts(allcaps_beep) $flag return "" } proc tts_reset {} { global tts synth -reset queue_clear synth {[:phoneme arpabet speak on][:pu s][:sa c]} synth "Via Software DecTalk, This, is Eamakspeak! " } proc r {rate} { global queue tts set queue($tts(q_tail)) [list s "\[:rate $rate] "] incr tts(q_tail) return "" } # }}} # {{{ speech task proc speech_task {} { global queue tts set mode $tts(punctuations) set r $tts(speech_rate) set length [queue_length] # say "\[_]\[:sa c]\[:np]\[]\[:pu $mode]" say "\[:sa c]\[:np]\[:pu $mode]" if {$tts(old_rate) != $r } { say "\[:ra $r]" set tts(old_rate) $r } loop index 0 $length { set event [queue_remove] set event_type [lindex $event 0] switch -exact -- $event_type { s { set text [clean [lindex $event 1]] say "\[:i r 1]$text " } c { set text [lindex $event 1] say "\[:i r 1]$text " } a { set sound [lindex $event 1] say "\[:play $sound]" } } } synth " " return "" } # }}} # {{{clean #preprocess element before sending it out: proc clean {element} { global queue tts set element [string trim $element] if {[string match all $tts(punctuations)] } { regsub -all {\#} $element \ { pound } element regsub -all {\*} $element \ { star } element regsub -all {[%&;()$+=/]} $element { \0 } element regsub -all {\.,} $element \ { dot comma [_,] } element regsub -all {\.\.\.} $element \ { dot dot dot } element regsub -all {\.\.} $element \ { dot dot } element regsub -all {([a-zA-Z])\.([a-zA-Z])} $element \ {\1 dot \2} element regsub -all {[0-9]+} $element { & } element } else { # regsub -all {\.,} $element {[_,]} element regsub -all {([0-9a-zA-Z])([\"!;/:()=])+([0-9a-zA-z])} $element \ {\1 \2 \3} element regsub -all {([a-zA-Z])(,)+([a-zA-z])} $element \ {\1 \2 \3} element # regsub -all {([a-zA-Z])(\.)([a-zA-z])} $element {\1[*]dot[*]\3} element regsub -all {([a-zA-Z])(\.)([a-zA-z])} $element {\1 dot \3} element regsub -all {``} $element {[_<1>/]} element regsub -all {''} $element {[_<1>\\]} element # regsub -all { '} $element {[_']} element # regsub -all {' } $element {[_']} element # regsub -all -- {--} $element { [_,]} element regsub -all -- {-} $element { } element } if {$tts(capitalize) } { regsub -all {[A-Z]} $element {[_ :to 440 10]&} element } if {$tts(split_caps) } { if {$tts(allcaps_beep)} { set tone {[_:to 660 10]} set abbrev_tone ":to 660 10" } else { set tone "" set abbrev_tone "" } set allcaps [regexp {[^a-zA-Z0-9]?([A-Z][A-Z0-9]+)[^a-zA-Z0-9]} $element full match ] while {$allcaps } { if {[string length $match] <=3} { # set abbrev "\[_ $abbrev_tone\]$match" set abbrev $match # regsub -all {[A-Z]} $abbrev {&[*]} abbrev regsub -all {[A-Z]} $abbrev {& } abbrev regsub -all A $abbrev {[ey]} abbrev if {[string length $abbrev_tone]} { set abbrev "\[_ $abbrev_tone\]$abbrev" } regsub $match $element $abbrev element } else { regsub $match $element "$tone[string tolower $match]" element } set allcaps [regexp {[^a-zA-Z0-9]([A-Z][A-Z0-9]+)[^a-zA-Z0-9]} $element full match ] } # regsub -all {[A-Z]} $element {[_<5>]&} element regsub -all {[A-Z]} $element { &} element # regsub -all {([^ -_A-Z])([A-Z][a-zA-Z]* )} $element {\1[_<1>]\2[,] } element regsub -all {([^ -_A-Z])([A-Z][a-zA-Z]* )} $element {\1 \2 } element # regsub -all {([^ -_A-Z])([A-Z])} $element {\1[_<1>]\2} element regsub -all {([^ -_A-Z])([A-Z])} $element {\1 \2} element } return "$element " } # }}} # {{{ Initialize and set state. #do not die if you see a control-c signal ignore {sigint} #initialize Dectalk tts_initialize set tts(speech_rate) 225 set tts(say_rate) [round \ [expr $tts(speech_rate) * $tts(char_factor)]] set tclTTS $env(EMACSPEAK_DIR)/servers/software-dtk if [file exists /usr/lib/libaoss.so] { set env(LD_PRELOAD) /usr/lib/libaoss.so } load $tclTTS/tcldtk.so synth {[:phoneme arpabet speak on ] [:pu s ] [:sa c] [:np] Via Software DecTalk, This, is Eamakspeak! } #Start the main command loop: commandloop # }}} # {{{ Emacs local variables ### Local variables: ### major-mode: tcl-mode ### voice-lock-mode: t ### folded-file: t ### End: # }}} commandloop