Need help from experienced coder with SKSE plugin.

Post » Wed Nov 30, 2016 6:05 am

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.

User avatar
Dominic Vaughan
 
Posts: 3531
Joined: Mon May 14, 2007 1:47 pm

Return to V - Skyrim