I'm a visually impaired user of MUSHClient, and while the available plugins for Text-To-Speech (TTS) work, they rely on fairly antiquated VBScript. Sadly, I don't possess the prowess to convert or recreate these plugins in LUA. I therefore am wondering if anyone's done a conversion of the TTS plugin(s) (particularly the TTS_JFW plugin) from VBS to LUA, or knows of such an endeavour.
Text to Speech with LUA
Posted by Wraithian on Mon 30 Aug 2010 09:08 AM — 13 posts, 62,071 views.
Before I start working on that, most installations of Windows come with VBscript. I'm not saying I like it, just that it exists. Is there a reason you don't want to use the existing plugins?
Nick Gammon said:
Before I start working on that, most installations of Windows come with VBscript. I'm not saying I like it, just that it exists. Is there a reason you don't want to use the existing plugins?
Before I start working on that, most installations of Windows come with VBscript. I'm not saying I like it, just that it exists. Is there a reason you don't want to use the existing plugins?
I'm working on it, just getting really annoyed with an unknown issue with loading luacom.dll. (It's practically the only thing left to do.)
[EDIT] The plugin described here is the one we're talking about, right? http://randylaptop.com/software/mushclient/2/
[EDIT] Fixed, see the next post down.
Alright, I give up for now. Here's what I have so far; all that's really needed is to fix the DLL issue (it says it can't be found.) It's all untested, though. (I don't use screenreaders myself, and the DLL issue is blocking me anwyays.)
<link removed, see below>
Alright, I give up for now. Here's what I have so far; all that's really needed is to fix the DLL issue (it says it can't be found.) It's all untested, though. (I don't use screenreaders myself, and the DLL issue is blocking me anwyays.)
<link removed, see below>
Oh, there we go. It's loading now. Give it a try and let me know if it works?
http://dl.dropbox.com/u/10356966/TTS_JFW.plugin.zip
You need to unzip it into your plugins folder. The actual "plugin file" you need to add in MUSHclient is called plugin.xml, and it'll be inside the new TTS_JFW.plugin folder after you've unzipped.
http://dl.dropbox.com/u/10356966/TTS_JFW.plugin.zip
You need to unzip it into your plugins folder. The actual "plugin file" you need to add in MUSHclient is called plugin.xml, and it'll be inside the new TTS_JFW.plugin folder after you've unzipped.
Nick: I mostly wanted the conversion to LUA to avoid any future issues with how Windows 7 implements VBScript (I've already noticed some Windows 7 users having issues with Monkey Term, an old client heavily dependent on VBScript). As it is, even on Windows XP, I've had to download several DLL packages after all the .net updates just to retain compatibility.
Twisol: Thank you for that conversion! It seems to be working fine so far. Much obliged.
Twisol: Thank you for that conversion! It seems to be working fine so far. Much obliged.
Wraithian said:
Twisol: Thank you for that conversion! It seems to be working fine so far. Much obliged.
Twisol: Thank you for that conversion! It seems to be working fine so far. Much obliged.
Awesome, I'm glad I could help. :)
I'm going to take down the plugin within the next day or so, so if anyone wants it, please grab it now. I may or may not post it along with the rest of my plugins, but I really don't want to have to support it because I know next to nothing about screenreaders.
Then just say you don't support it, and leave it up? No point deleting it, since someone obviously was helped by it.
Otherwise one of us might have to reinvent the wheel at some point.
Otherwise one of us might have to reinvent the wheel at some point.
Right then, here is my Lua version.
To use this you need to download luacom.dll from inside this zip file:
http://www.gammon.com.au/files/mushclient/lua5.1_extras/luacom.zip
Unzip and put luacom.dll into the same directory as MUSHclient.exe. This lets Lua call COM components (like the SAPI speaker).
This particular one uses SAPI which is, I believe, built into normal Windows XP onwards.
You may need to disable the Lua sandbox, and check "Allow DLLs to be loaded" as described here:
http://www.gammon.com.au/security
To summarize:
It should now read out text from the MUD.
Optional things you can do:
To save and install the Sapi_speaker plugin do this:
- Copy the code below (in the code box) to the Clipboard
- Open a text editor (such as Notepad) and paste the plugin code into it
- Save to disk on your PC, preferably in your plugins directory, as
Sapi_speaker.xml- The "plugins" directory is usually under the "worlds" directory inside where you installed MUSHclient.
- Go to the MUSHclient File menu -> Plugins
- Click "Add"
- Choose the file
Sapi_speaker.xml(which you just saved in step 3) as a plugin - Click "Close"
- Save your world file, so that the plugin loads next time you open it.
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<muclient>
<plugin
name="Sapi_speaker"
author="Nick Gammon"
id="463242566069ebfd1b379ec1"
language="Lua"
purpose="Speaks incoming text using SAPI."
date_written="2010-09-01"
requires="3.45"
version="1.0"
>
<description trim="y">
Type:
sapi on --> turn on speaking (the default)
sapi off --> turn off speaking of MUD output
sapi skip --> skips one sentence in output stream
Other scripts can speak stuff by doing:
CallPlugin ("463242566069ebfd1b379ec1", "say", "What to say")
</description>
</plugin>
<!-- Triggers -->
<aliases>
<alias
match="sapi on"
enabled="n"
omit_from_command_history="y"
omit_from_log="y"
omit_from_output="y"
script="speak_on"
sequence="100"
group="speech"
>
</alias>
<alias
match="sapi off"
enabled="n"
omit_from_command_history="y"
omit_from_log="y"
omit_from_output="y"
script="speak_off"
sequence="100"
group="speech"
>
</alias>
<alias
match="sapi skip"
enabled="n"
omit_from_log="y"
omit_from_output="y"
script="speak_skip"
sequence="100"
group="speech"
>
</alias>
</aliases>
<triggers>
</triggers>
<!-- Script -->
<script>
<![CDATA[
-- turn on speaking
function speak_on (name, line, wildcards)
speak = true
talk:Speak ("Sapi auto speak now on.", 1)
end -- function speak_on
-- turn off speaking
function speak_off (name, line, wildcards)
speak = false
talk:Speak ("Sapi auto speak now off.",1)
end -- function speak_off
-- skip a sentence
function speak_skip (name, line, wildcards)
talk:Skip ("Sentence", 1)
end -- function speak_skip
-- installation
function OnPluginInstall ()
-- load Lua COM
assert (package.loadlib ("luacom.dll", "luacom_open")) ()
-- Instantiate a SAPI voice obejct
talk = assert (luacom.CreateObject ("SAPI.SpVoice"), "cannot open SAPI")
-- Method call
talk:Speak ("SAPI Plugin installed and is ready.", 1)
speak = true
EnableGroup ("speech", true)
end -- function OnPluginInstall
-- here to draw the screen
function OnPluginScreendraw (t, log, line)
-- check loaded
if not talk then
return
end -- if not installed
if (t == 0 or t == 1) and speak then
talk:Speak (line, 1)
end -- if
end -- function
-- Speak from other scripts
-- eg. CallPlugin ("463242566069ebfd1b379ec1", "say", "What to say")
function say (what)
-- check loaded
if not talk then
return false -- failure
end -- if not installed
talk:Speak (what, 1)
return true -- OK
end -- function say
]]>
</script>
</muclient>
To use this you need to download luacom.dll from inside this zip file:
http://www.gammon.com.au/files/mushclient/lua5.1_extras/luacom.zip
Unzip and put luacom.dll into the same directory as MUSHclient.exe. This lets Lua call COM components (like the SAPI speaker).
This particular one uses SAPI which is, I believe, built into normal Windows XP onwards.
You may need to disable the Lua sandbox, and check "Allow DLLs to be loaded" as described here:
http://www.gammon.com.au/security
To summarize:
- Download LuaCOM from http://www.gammon.com.au/files/mushclient/lua5.1_extras/luacom.zip (90 Kb)
- Unzip and put luacom.dll into your MUSHclient install directory.
- Go to MUSHclient's File menu -> Global Preferences -> Lua and check that "Allow DLLs to be loaded" is checked, and that the sandbox is either disabled as described in http://www.gammon.com.au/security or that all worlds and all plugins are trusted.
- Download the plugin above as described in the box above it.
- Install the plugin
- You should hear it say "SAPI plugin is installed and ready" (it sounds to me like he says "pluge-in").
It should now read out text from the MUD.
Optional things you can do:
- Type "sapi off" to stop it reading out text
- Type "sapi on" to resume reading out text
- Type "sapi skip" to skip the current sentence. Use this to skip over a lengthy room description. Note that it thinks that a newline is the end of a sentence, so it may resume speaking at surprising places.
- Other scripts (eg. triggers) can speak stuff by doing this (in send-to-script):
CallPlugin ("463242566069ebfd1b379ec1", "say", "What to say")
- I would personally use the world configuration "Macros" section to make function keys do the common stuff. For example, you might make F10 do "sapi skip" so whenever you want to skip something you just reach over and hit F10.
Nick Gammon said:
*Download LuaCOM from http://www.gammon.com.au/files/mushclient/lua5.1_extras/luacom.zip (90 Kb)
*Unzip and put luacom.dll into your MUSHclient install directory.
*Download LuaCOM from http://www.gammon.com.au/files/mushclient/lua5.1_extras/luacom.zip (90 Kb)
*Unzip and put luacom.dll into your MUSHclient install directory.
The great thing about structured plugins is that you can skip this step, and I'm really sad that nobody does this besides me. If you have any comments or criticism about it I'd be happy to hear them. :S
Nick Gammon said:
*You should hear it say "SAPI plugin is installed and ready" (it sounds to me like he says "pluge-in").
*You should hear it say "SAPI plugin is installed and ready" (it sounds to me like he says "pluge-in").
I suspect it's breaking it down as "plu" and "gin"; maybe try spelling it in the string as "plug-in"?
Twisol said:
The great thing about structured plugins is that you can skip this step, and I'm really sad that nobody does this besides me. If you have any comments or criticism about it I'd be happy to hear them. :S
The great thing about structured plugins is that you can skip this step, and I'm really sad that nobody does this besides me. If you have any comments or criticism about it I'd be happy to hear them. :S
Well you have a .zip file, which to someone suspicious is immediately a red flag, and then inside you have four files and two directories, to achieve what I have done in a forum posting. Now admittedly you supply the luacom.dll, but if you have 10 plugins that need LuaCom, then you supply it ten times. This seems to me to break the idea of centralizing stuff you only need once.
Just personally I find the structure you use confusing. You start with a generic plugin.xml file (and so in the plugin list you see lots of plugin.xml files, so I wonder which is which), but that has an alias in it and then loads in plugger.xml. Then inside plugger.xml (which is inside another folder) I open that and find it does some fairly complex stuff with paths and things, but I guess it eventually finds main.lua in yet another folder.
Finally in main.lua is the "meat" of the plugin which actually does the text-to-speech stuff.
Now I have had to open three files, in different folders, to even find how you implemented the text-to-speech. And they have generic names (plugger.xml, plugin.xml, main.lua).
Imagine for a moment how confusing the MUSHclient source would be if every file was called main.cpp, and the "real" meaning of the file was in the name of the directory two levels up.
On this site I try to teach how to do things, and in my example plugin above you see, in one place, the whole thing. The alias, the plugin script, everything. And it is, after all, only 145 lines long.
Your structure breaks everything up, so I have to mentally reassemble it. One file has aliases, another has the script, another loads the first two. It's just confusing to me. Maybe other people love it, I'm just answering your query about having comments.
Nick Gammon said:
Maybe other people love it, I'm just answering your query about having comments.
Maybe other people love it, I'm just answering your query about having comments.
Thanks!
Nick Gammon said:
Well you have a .zip file, which to someone suspicious is immediately a red flag
Well you have a .zip file, which to someone suspicious is immediately a red flag
Can you clarify? I see .zip files all the time; even WoW addons are distributed as .zip archives.
Nick Gammon said:
and then inside you have four files and two directories, to achieve what I have done in a forum posting.
and then inside you have four files and two directories, to achieve what I have done in a forum posting.
Brevity is a good point. The extra scaffolding is to keep things grouped together, but if you can fit the whole plugin in one file, it might not be worth it.
Nick Gammon said:
Now admittedly you supply the luacom.dll, but if you have 10 plugins that need LuaCom, then you supply it ten times. This seems to me to break the idea of centralizing stuff you only need once.
Now admittedly you supply the luacom.dll, but if you have 10 plugins that need LuaCom, then you supply it ten times. This seems to me to break the idea of centralizing stuff you only need once.
That's another good point. Maybe it would be a good idea to have a shared_libs folder within the .zip file, outside the plugin folder itself. Then when it's unzipped in the plugins folder, if there's already an existing shared_libs folder it would be merged. It just looks uglier, it's easier for things to clash, and the plugin folders aren't single units anymore. Pros and cons...
Nick Gammon said:
Just personally I find the structure you use confusing. You start with a generic plugin.xml file (and so in the plugin list you see lots of plugin.xml files, so I wonder which is which), but that has an alias in it and then loads in plugger.xml.
Just personally I find the structure you use confusing. You start with a generic plugin.xml file (and so in the plugin list you see lots of plugin.xml files, so I wonder which is which), but that has an alias in it and then loads in plugger.xml.
Usually I put aliases/triggers/other XML objects in the reflexes/ directory, and include them from the plugin.xml (which I call the manifest). It's true that maybe it should be named after the plugin instead, but I opted for something generic originally.
Nick Gammon said:
Then inside plugger.xml (which is inside another folder) I open that and find it does some fairly complex stuff with paths and things, but I guess it eventually finds main.lua in yet another folder.
Then inside plugger.xml (which is inside another folder) I open that and find it does some fairly complex stuff with paths and things, but I guess it eventually finds main.lua in yet another folder.
Plugger just sets things up to adjust to the folder structure. There's a require("scripts.main") at the end which uses the adjusted paths to load and run main.lua.
Nick Gammon said:
Finally in main.lua is the "meat" of the plugin which actually does the text-to-speech stuff.
Finally in main.lua is the "meat" of the plugin which actually does the text-to-speech stuff.
I basically just copied from the original plugin's <script> tag and moved it into main.lua, converted it to XML, and put it into a skeleton plugin structure.
Nick Gammon said:
Now I have had to open three files, in different folders, to even find how you implemented the text-to-speech. And they have generic names (plugger.xml, plugin.xml, main.lua).
Imagine for a moment how confusing the MUSHclient source would be if every file was called main.cpp, and the "real" meaning of the file was in the name of the directory two levels up.
Now I have had to open three files, in different folders, to even find how you implemented the text-to-speech. And they have generic names (plugger.xml, plugin.xml, main.lua).
Imagine for a moment how confusing the MUSHclient source would be if every file was called main.cpp, and the "real" meaning of the file was in the name of the directory two levels up.
I feel that way at times with CMUSHclientDoc, but that's beside the point. :) I agree that maybe the plugin XML should be named after the plugin itself, but 'main' is a rather common/standard entry point name. If you know that main.lua is where the plugin effectively "begins", you don't have to look for anything else.
Nick Gammon said:
On this site I try to teach how to do things, and in my example plugin above you see, in one place, the whole thing. The alias, the plugin script, everything. And it is, after all, only 145 lines long.
Your structure breaks everything up, so I have to mentally reassemble it. One file has aliases, another has the script, another loads the first two. It's just confusing to me.
On this site I try to teach how to do things, and in my example plugin above you see, in one place, the whole thing. The alias, the plugin script, everything. And it is, after all, only 145 lines long.
Your structure breaks everything up, so I have to mentally reassemble it. One file has aliases, another has the script, another loads the first two. It's just confusing to me.
Excellent point. Generally though, you never have to concern yourself with Plugger, it's more of a mini-framework. The plugin.xml file, in my mind, shouldn't even have any actual aliases or code or anything, so I really should have put that in reflexes/aliases.xml or something and <include>d it. Plugin.xml is by and large just for metadata, and as I said before, I consider it the "manifest".
scripts/main.lua is where the work actually begins, and if all you want to do is figure out how something works, that's generally where you want to go first.
As an aside, I usually have a readme.txt at the same level as plugin.xml with directions, troubleshooting, and requirements. I just threw this one together, which is why it's so sloppy.