How do I stop SAPI.SpVoice reading "is." as "island"? - text-to-speech

Can you configure the way SAPI.spVoice reads text?
In my situation I am reading the current clipboard using an AutoHotKey script.
The script makes a COM call to SAPI.spVoice passing the text from the clipboard.
;;;;;;;;;;;;;;;;;;;;TTS;;;;;;;;;;;;;;;;;;;;;;
#^!D:: ; Win + Ctrl + D + Alt
ClipSaved := ClipboardAll
clipboard = ; Start off empty to allow ClipWait to detect when the text has arrived.
Send ^c
ClipWait ; Wait for the clipboard to contain text.
ComObjCreate("SAPI.SpVoice").Speak(clipboard)
Clipboard := ClipSaved
ClipSaved = ; Free the memory
return
The problem is.. that SAPI reads some text incorrectly..
For Example:
"Yes it is. Ours is complex." reads "is." as island,
"Yes it is. This is complex." is read correctly.
You can experiment with this by doing the following:
If you are running windows 7.
Press the windows key and type "Change text to speech settings" and pick the option.
In this dialog enter "Yes it is. Ours is complex." in the "Use the following text to preview the voice:" field.
Press "Preview Voice"
Hear it read the "is." as island.
So... My question is...
Is it possible to change/configure the way "Microsoft Anna" reads text so it doesn't make these mistakes?
Is this a bug in the Anna voice only or all voices?
How can I make it read the text the way I want it read?

This is done by SAPI's text normalization code. Unfortunately, this is quite difficult to modify without building a custom voice, which is likely far more work than you probably want to implement.

"Every problem (except the problem of too many levels of indirection) can be solved with another level of indirection."
The SAPI.spVoice object can be passed text (as I was doing) or SSML.
By taking the text to be spoken, then converting it to SSML you gain control over how words are spoken. You have a chance to pre-process the text and replace miss-read words with the specific pronunciation you wish.
For example: "Yes it is. Ours is complex." becomes "Yes it <sub alias="is">is</sub>. Ours is complex."
sub and say_as seem to work. phoneme seem to be ignored.. but I may have something configured wrongly.
Note: If you want XML read aloud, XML escape the text before converting it to SSML, otherwise it will be assumed to be part of the SSML.
So.. in code:
;;;;;;;;;;;;;;;;;;;;TTS;;;;;;;;;;;;;;;;;;;;;;
#^D:: ; Win + Ctrl + D
ClipSaved := ClipboardAll
Clipboard = ; Start off empty to allow ClipWait to detect when the text has arrived.
Send ^c
ClipWait ; Wait for the clipboard to contain text.
FileDelete , c:\tmp\tmp_ahk_tts_clip.txt
FileAppend , %Clipboard% , c:\tmp\tmp_ahk_tts_clip.txt
RunWait, %comspec% /c ""F:\bin\tools\speakit.rb" c:\tmp\tmp_ahk_tts_clip.txt > c:\tmp\tmp_ahk_clip_tts_out.txt" ,,Hide
FileRead, Clipboard, c:\tmp\tmp_ahk_clip_tts_out.txt
ComObjCreate("SAPI.SpVoice").Speak(Clipboard)
Clipboard := ClipSaved
ClipSaved = ; Free the memory
return
and F:\bin\tools\speakit.rb is sometihng like this:
#!/usr/bin/env ruby
substitutions = [
[/[A-Z][A-Z][A-Z][A-Z]+((?=[^A-Za-z])|(?!.))/, lambda{|x|x.downcase}], #All caps becomes word
[/\.exe(?=[^a-z])/i, " executable "],
[/\.txt(?=[^a-z])/i, " text file "],
[/rebranded/, "re-branded"],
[/App(?=[\s\.])/, " application "],
['GUI' , " gooee "],
[/localhost/, "local host"],
[/(?<word>[A-Z][a-z]*)(?=[A-Z ,\.;:\t\/])/, "'\\k<word>' "], # CamelCaseWords should be split by spaces
['\\', '<sub alias="slash">\\</sub>'],
]
require 'cgi'
puts <<-eos
<?xml version="1.0"?>
<speak xmlns="http://www.w3.org/2001/10/synthesis" version="1.0" xml:lang="en-UK">
<voice xml:lang="en-UK">
#{substitutions.reduce(CGI::escapeHTML(ARGF.read)){|o, (r,s)| s.is_a?(Proc) ? o.gsub(r, &s) : o.gsub(r,s) }}
</voice>
</speak>
eos

Related

How to write a text prompt in Nim that has readline-style line editing?

readLine() doesn't support line editing and recalling previous commands, eg:
while true:
var name: string = readLine(stdin)
echo "Hi, ", name, "!"
Has no editing. But if I compile that and wrap it in rlwrap:
$ rlwrap read_test
It works as I hope. with editable and recallable lines, provided by the readline library.
readLineFromStdin() almost works, but doesn't support ctrl+d, it returns an empty string on ctrl+d, which is indistinguishable from a newline.
How can I do this in pure Nim? Thanks!
Ctrl+D is an EOF "signal", and thus you can catch the EOF in your input:
while not endOfFile(stdin):
var name: string = readLine(stdin)
echo "Hi, ", name, "!"
The procedure readLineFromStdin (https://github.com/nim-lang/Nim/blob/version-1-2/lib/impure/rdstdin.nim#L54) is not that complex, and you can re-write your own adding the above code to it.
While #xbello's answer is correct, if you want to use a package, we ended up using https://github.com/jangko/nim-noise, which supports C-d handling and loads of other features.

Input hidden, output has excess indentation

As formerly stated here, I am trying to recreate an SSH profile manager in Pascal that I had originally written in Ruby. With the answer provided I have been able to get the shell to stay open and accept input. Now I have the new problem of any and all input is hidden and all output seems to be tiling with several tab characters before each line. The updated relevant code is as follows:
if HasOption('c', 'connect') then begin
TempFile:= GetRecord(GetOptionValue('c', 'connect'));
AProcess:= TProcess.Create(nil);
AProcess.Executable:= '/usr/bin/ssh';
AProcess.Parameters.Add('-p');
AProcess.Parameters.Add(TempFile.Port);
AProcess.Parameters.Add('-tt');
AProcess.Parameters.Add(TempFile.Username + '#' + TempFile.Address);
AProcess.Options:= [];
AProcess.ShowWindow:= swoShow;
AProcess.InheritHandles:= False;
AProcess.Execute;
AProcess.WaitOnExit;
AProcess.Free;
Terminate;
Exit;
end;
The output provide looks like this:
I ran ls, pwd, and exit in that order.
So probably you use crt or some other terminal library that puts the terminal into raw mode, requiring both a cr and lf.
Remove crt from the uses clause, and probably it will go better

golang reading text input over more than one line and stop ctrl+s

How can I read more than one line in golang, console input.
reader := bufio.NewReader(os.Stdin)
fmt.Println("Enter Text:")
text, _ := reader.ReadString('\n')
How I must change ReadString(???) to stop reading if the user hit: ctrl+s
The New Line (\n) must remain a constituent of the input.
Is there some library/framework for that?
Thanks for every help.
Cheers
Here is an answer for Linux (and could work for other *nix platforms)
Ctrl+S is a control character DC3, it means "XOFF, stop sending". If you press Ctrl+S the terminal would freeze.
Ctrl+Q is a control character DC1, it mean "XON, continue sending", it is necessary after Ctrl+S to unfreeze.
To use the Ctrl+S, first disable XON/XOFF with stty -ixon (maybe in in startup script)
After disabling XON/XOFF, the sample code is following (DC3 is HEX:13/DEC:19 in ASCII table);
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Println("Enter Text:")
text, _ := reader.ReadString('\x13')
fmt.Println(text)
}

How to write an xcode user script to surround the string the cursor is inside with NSLocalizedString(<string>, nil)

I'm trying to figure out the best way to automatically add NSLocalizedString() around a string in xcode.
Ideally I'd like a way that I could position the cursor within #"foo", press a key binding, and it'd be turned into NSLocalizedString(#"foo", nil).
I've had a look at the documentation for user scripts and can't see an obvious way to get the current cursor position.
Did I miss something, or is there another way to achieve the same result?
Thanks!
You can use %%%{PBXSelectionStart}%%%
From the apple documentation:
Getting Text from the Active Window
These variables are replaced by text in the active window:
%%%{PBXSelectedText}%%% is replaced by the selected text in the active text object.
%%%{PBXAllText}%%% is replaced by the entire text in the active text object.
Getting Information on the Contents of the Active Window
These variables are replaced by information on the text in the active window:
%%%{PBXTextLength}%%% is replaced by the number of characters in the active text object.
%%%{PBXSelectionStart}%%% is replaced by the index of the first character in the selection in the active text object.
%%%{PBXSelectionEnd}%%% is replaced by the index of the first character after the selection in the active text object.
%%%{PBXSelectionLength}%%% is replaced by the number of characters in the current selection in the active text object.
Procrastination brought you this script.
It works and does what it should. But it is very basic, and there are bugs, and this is probably not the best way to do it.
Don't use # and " in the strings you want to replace. If I were you, I wouldn't use it anyway. ^^
Script Input is Selection, Output is Replace Document Contents
#!/bin/sh
if [ %%%{PBXSelectionLength}%%% -gt 0 ]
then
echo "This does not work if you select text. Put your cursor inside a String." >&2
exit
fi
Source=`cat "%%%{PBXFilePath}%%%"`
SelectionStart="%%%{PBXSelectionStart}%%%"
SelectionEnd="%%%{PBXSelectionEnd}%%%"
BOOL=1
StringStart=$SelectionStart
StringStop=$SelectionEnd
while [ $BOOL -eq 1 ]
do
tmpText=`echo "${Source:${StringStart}:1}"`
if [ "$tmpText" = "#" ]
then BOOL=0
else StringStart=$(($StringStart - 1))
fi
done
BOOL=1
while [ $BOOL -eq 1 ]
do
tmpText=`echo "${Source:${StringStop}:1}"`
if [ "$tmpText" = "\"" ]
then BOOL=0
fi
StringStop=$(($StringStop + 1))
done
StringToReplace=`echo ${Source:${StringStart}:$(($StringStop - $StringStart))}`
ReplacementString="NSLocalizedString($StringToReplace,nil)"
echo -n "${Source:0:${StringStart}}"
echo -n "$ReplacementString"
echo -n "${Source:${StringStop}}"
#!/bin/sh
echo -n 'NSLocalizedString(%%%{PBXSelectedText}%%%, nil)'
Make sure script input is "Selection" and output is "Repalce Selection"
Select string and run script.
This is not exactly you want, but I can't google this method, let it be here :)

Best AutoHotKey macros? [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
I use AutoHotKey for Windows macros. Most commonly I use it to define hotkeys that start/focus particular apps, and one to send an instant email message into my ToDo list. I also have an emergency one that kills all of my big memory-hogging apps (Outlook, Firefox, etc).
So, does anyone have any good AHK macros to share?
Very simple and useful snippet:
SetTitleMatchMode RegEx ;
; Stuff to do when Windows Explorer is open
;
#IfWinActive ahk_class ExploreWClass|CabinetWClass
; create new folder
;
^!n::Send !fwf
; create new text file
;
^!t::Send !fwt
; open 'cmd' in the current directory
;
^!c::
OpenCmdInCurrent()
return
#IfWinActive
; Opens the command shell 'cmd' in the directory browsed in Explorer.
; Note: expecting to be run when the active window is Explorer.
;
OpenCmdInCurrent()
{
WinGetText, full_path, A ; This is required to get the full path of the file from the address bar
; Split on newline (`n)
StringSplit, word_array, full_path, `n
full_path = %word_array1% ; Take the first element from the array
; Just in case - remove all carriage returns (`r)
StringReplace, full_path, full_path, `r, , all
full_path := RegExReplace(full_path, "^Address: ", "") ;
IfInString full_path, \
{
Run, cmd /K cd /D "%full_path%"
}
else
{
Run, cmd /K cd /D "C:\ "
}
}
Here is so simple but useful script:
^SPACE:: Winset, Alwaysontop, , A
Use CTRL + Space to set any window always on top.
Add surrounding quotes on selected text/word
Useful when writing emails or during coding...
Doubleclick word, hit Win+X, have quotes around
; Win + X
#x:: ; Attention: Strips formatting from the clipboard too!
Send ^c
clipboard = "%clipboard%"
; Remove space introduced by WORD
StringReplace, clipboard, clipboard,%A_SPACE%",", All
Send ^v
return
; I have this in my start menu so that I won't ruin my ears when I put on my headphones after rebooting my computer
sleep, 5000
SoundSet, 1.5 ; really low volume
I create new Outlook objects with AutoHotKey
; Win+Shift+M = new email
#+m:: Run "mailto:"
; Outlook
#^M:: Run "%ProgramFiles%\Microsoft Office\Office12\OUTLOOK.EXE" /recycle
; Win+Shift+A = create new calendar appointment
#+A:: Run "%ProgramFiles%\Microsoft Office\Office12\OUTLOOK.EXE"/c ipm.appointment
; Win+Shift+T = create new Task
; Win+Shift+K = New task
#+T:: Run "%ProgramFiles%\Microsoft Office\Office12\OUTLOOK.EXE"/c ipm.task
#+K:: Run "%ProgramFiles%\Microsoft Office\Office12\OUTLOOK.EXE"/c ipm.task
Here's a dead-simple snippet to quickly close the current window using a mouse button.
It's one of the actions you perform most often in Windows, and you'll be surprised at how much time you save by no longer having to shoot for that little X. With a 5-button mouse, I find this a very useful reassignment of the "Forward" button.
#IfWinActive ;Close active window when mouse button 5 is pressed
XButton2::
SendInput {Alt Down}{F4}{Alt Up}
Return
#IfWinActive
To take into account programs that use tabbed documents (like web browsers), here's a more comprehensive version:
;-----------------------------------------------------------------------------
; Bind Mouse Button 5 to Close Tab / Close Window command
;-----------------------------------------------------------------------------
; Create a group to hold windows which will use Ctrl+F4 instead of Alt+F4
GroupAdd, CtrlCloseGroup, ahk_class IEFrame ; Internet Explorer
GroupAdd, CtrlCloseGroup, ahk_class Chrome_WidgetWin_0 ; Google Chrome
; (Add more programs that use tabbed documents here)
Return
; For windows in above group, bind mouse button to Ctrl+F4
#IfWinActive, ahk_group CtrlCloseGroup
XButton2::
SendInput {Ctrl Down}{F4}{Ctrl Up}
Return
#IfWinActive
; For everything else, bind mouse button to Alt+F4
#IfWinActive
XButton2::
SendInput {Alt Down}{F4}{Alt Up}
Return
#IfWinActive
; In FireFox, bind to Ctrl+W instead, so that the close command also works
; on the Downloads window.
#IfWinActive, ahk_class MozillaUIWindowClass
XButton2::
SendInput {Ctrl Down}w{Ctrl Up}
Return
#IfWinActive
Visual Studio 2010 can't easily be added to the CtrlCloseGroup above, as it's window class / title aren't easily predictable (I think). Here's the snippet I use to handle it, including a couple additional helpful bindings:
SetTitleMatchMode, 2 ; Move this line to the top of your script
;-----------------------------------------------------------------------------
; Visual Studio 2010
;-----------------------------------------------------------------------------
#IfWinActive, Microsoft Visual Studio
; Make the middle mouse button jump to the definition of any token
MButton::
Click Left ; put the cursor where you clicked
Send {Shift Down}{F2}{Shift Up}
Return
; Make the Back button on the mouse jump you back to the previous area
; of code you were working on.
XButton1::
Send {Ctrl Down}{Shift Down}{F2}{Shift Up}{Ctrl Up}
Return
; Bind the Forward button to close the current tab
XButton2::
SendInput {Ctrl Down}{F4}{Ctrl Up}
Return
#IfWinActive
I also find it useful in Outlook to map ALT+1, ALT+2, etc. to macros I wrote which move the currently selected message(s) to specific folders (eg. "Personal Filed", "Work Filed", etc) but that's a bit more complicated.
There are tons of good ones in the AutoHotKey Forum:
http://www.autohotkey.com/forum/forum-2.html&sid=8149586e9d533532ea76e71e8c9e5b7b
How good? really depends on what you want/need.
I use this one all the time, usually for quick access to the MySQL command line.
http://lifehacker.com/software/featured-windows-download/make-a-quake+style-command-prompt-with-autohotkey-297607.php
Fix an issue when copying file to FTP server when the "Copying" dialog appears on top of the "Confirm File Replace" dialog (very annoying):
SetTimer, FocusOnWindow, 500
return
FocusOnWindow:
IfWinExist, Confirm File Replace
WinActivate
return
One to deactivate the useless Caps-lock key:
Capslock::
return
CTRL + shift + c will copy colour below cursor to the clipboard (in hexadecimal)
^+c::
MouseGetPos,x,y
PixelGetColor,rgb,x,y,RGB
StringTrimLeft,rgb,rgb,2
Clipboard=%rgb%
Return
Write your email address in the active field (Win key + m)
#m::
Send, my#email.com{LWINUP}
Sleep, 100
Send, {TAB}
return