I'm working on incorporating voice recognition into skyrim using http://voce.sourceforge.net/ and SKSE. I've made some progress but this is:
1.) my first SKSE plugin.
2.) first time working with VOCE.
3.) I haven't done c++ coding in like 13 years.
I have a parser engine well underway written in papyrus. I call the function from this SKSE plugin passing it a flag when a button is pressed/released. The function returns a string of the speech recognized by VOCE/CMU Sphinx 4.
In the SKSE plugin I check whether the "mic" button is pressed by checking the state of the flag being passed from papyrus. If the mix button is held down then I initialize a virtual machine using the VOCE library. The functionality to initialize the VM is built into VOCE, and depends upon jni.h and jvm.dll. I think I have correctly linked and pointed to appropriate library dirs/libraries; header dirs/headers. There seems to be something wrong with this initialization function because if I exclude the call to init() from my code when I hit the "mic" button TESV.exe hangs with run time error 0: the value of esp was not properly saved across a function call, and it points to line 1396 of jni.h. When I include the call to init() from my code and hit the "mic" button the game crashes to desktop with no error.
I'd be happy for someone to look at my code, or the project perhaps, it's pretty straight forward, or at least tell me how I can enable logging error messages/saving a dump file for this crash, so that I can debug this CTD and continue progressing on the skyrim voice command engine.
SKSE_SpeechRecPlugin.cpp
Spoiler
#include "SKSE_SpeechRecPlugin.h"
#include "voce.h"
#include "string.h"
#include
#include
#include
#include
#ifdef WIN32
#include
#else
#include
#endif
namespace SpeechRecNamespace {
BSFixedString GetTextFromSpeech(StaticFunctionTag *base, float iFlag) {
const char* c_GetSpeech = "";
BSFixedString ReturnState;
ReturnState = "Entered SKSE Function.";
//initialize VOCE Java virtual machine
voce::init("../../../../../../lib/", false, true, "../../../../../../../gram/", "digits.gram");
//voce::init("C:/Users/Anonymous/Desktop/SKSE_SpeechRecPlugin/SpeechRecPlugin/lib/", false, true, "C:/Users/Anonymous/Desktop/SKSE_SpeechRecPlugin/SpeechRecPlugin/lib/gram/", "digits");
//voce::init("C:\Users\Anonymous\Desktop\SKSE_SpeechRecPlugin\SpeechRecPlugin\lib", false, true, "./grammar", "digits");
std::string s_TextFromSpeech = voce::popRecognizedString();
if (iFlag==1.0)
{
ReturnState = "Entered SKSE Function. Entered Listening.";
voce::setRecognizerEnabled(true);
if (voce::isRecognizerEnabled()==true)
{
ReturnState = "Entered SKSE Function. Entered Listening. Recognizer Enabled.";
while (voce::getRecognizerQueueSize() > 0)
{
ReturnState = "Entered SKSE Function. Entered Listening. Recognizer Enabled. Entered Recognizer Queue loop.";
std::string s_TextFromSpeech = voce::popRecognizedString();
const char* c_GetSpeech = s_TextFromSpeech.c_str();
//the current parser engine simulates speech by inputting commands from a text file.
std::fstream myfile("C:/Games/SteamApps/common/Skyrim/Data/SVE_PI.txt", std::fstream::out | std::fstream::app);
if (myfile.is_open()==true)
{
ReturnState = "Entered SKSE Function. Entered Listening. Recognizer Enabled. Entered Recognizer Queue loop. Wrote to File.";
myfile << s_TextFromSpeech;
myfile.close();
}
}
voce::setRecognizerEnabled(false);
voce::destroy();
ReturnState = "Entered SKSE Function. Entered Listening. Recognizer Enabled. Entered Recognizer Queue loop. Wrote to File. Buffer destroyed.";
iFlag = 2.0;
}
}
return ReturnState;
}
bool RegisterFuncs(VMClassRegistry* registry) {
registry->RegisterFunction(
new NativeFunction1("GetTextFromSpeech", "SKSE_SpeechRecPlugin", SpeechRecNamespace::GetTextFromSpeech, registry));
return true;
}
}
SKSE_SpeechRecPluginHeader.h
Spoiler
#include "skse/PapyrusNativeFunctions.h"
namespace SpeechRecNamespace
{
BSFixedString GetTextFromSpeech(StaticFunctionTag *base, float iFlag);
bool RegisterFuncs(VMClassRegistry* registry);
}
main.cpp
Spoiler
#include "skse/PluginAPI.h" // super
#include "skse/skse_version.h" // What version of SKSE is running?
#include// CSIDL_MYCODUMENTS
#include "SKSE_SpeechRecPlugin.h"
static PluginHandle g_pluginHandle = kPluginHandle_Invalid;
static SKSEPapyrusInterface * g_papyrus = NULL;
extern "C" {
bool SKSEPlugin_Query(const SKSEInterface * skse, PluginInfo * info) { // Called by SKSE to learn about this plugin and check that it's safe to load it
gLog.OpenRelative(CSIDL_MYDOCUMENTS, "\\My Games\\Skyrim\\SKSE\\SKSE_SpeechRecPlugin.log");
gLog.SetPrintLevel(IDebugLog::kLevel_Error);
gLog.SetLogLevel(IDebugLog::kLevel_DebugMessage);
_MESSAGE("SKSE_SpeechRecPlugin");
// populate info structure
info->infoVersion = PluginInfo::kInfoVersion;
info->name = "SKSE_SpeechRecPlugin";
info->version = 1;
// store plugin handle so we can identify ourselves later
g_pluginHandle = skse->GetPluginHandle();
if(skse->isEditor)
{
_MESSAGE("loaded in editor, marking as incompatible");
return false;
}
else if(skse->runtimeVersion != RUNTIME_VERSION_1_9_32_0)
{
_MESSAGE("unsupported runtime version %08X", skse->runtimeVersion);
return false;
}
// ### do not do anything else in this callback
// ### only fill out PluginInfo and return true/false
// supported runtime version
return true;
}
bool SKSEPlugin_Load(const SKSEInterface * skse) { // Called by SKSE to load this plugin
_MESSAGE("SKSE_SpeechRecPlugin loaded");
g_papyrus = (SKSEPapyrusInterface *)skse->QueryInterface(kInterface_Papyrus);
//Check if the function registration was a success...
bool btest = g_papyrus->Register(SpeechRecNamespace::RegisterFuncs);
if (btest) {
_MESSAGE("Register Succeeded");
}
return true;
}
};
papyrus function declaration
scriptName SKSE_SpeechRecPlugin Hidden
string Function GetTextFromSpeech(float bFlag) global native
Relevant code from SKSE_ParserEngine
Spoiler
Event OnKeyUp(int keyCode, float holdTime)
;debug.notification("Refreshing script.")
string HelloWorld
float bFlag=2.0
if !(Input.IsKeyPressed(29))
HelloWorld=SKSE_SpeechRecPlugin.GetTextFromSpeech(bFlag)
debug.notification("Calling speech recognizer.")
debug.notification("Speech recognizer returned: " + HelloWorld)
endif
RegisterForSingleUpdate(0.004)
EndEvent
Event OnKeyDown(int keyCode)
float bFlag=1.0
string HelloWorld
if (Input.IsKeyPressed(29))
HelloWorld=SKSE_SpeechRecPlugin.GetTextFromSpeech(bFlag)
debug.notification("Calling speech recognizer.")
debug.notification("Speech recognizer returned: " + HelloWorld)
endif
RegisterForSingleUpdate(0.004)
endEvent
https://www.dropbox.com/s/zawzm11f62ytv3z/SKSE_SpeechRecPlugin.7z?dl=0
I can't really take credit for any of this, it's piece meal between the VOCE libraries, the SKSE example plugin, and some random code i found online, or just wrote.
Any help would be appreciated. If I had to guess I'm not doing something with the project properties correctly, linking libraries, or failing to include the *.jar files, or providing incorrect relative paths, or something.