Last night I had time to expand the proof of concept. This uses VoxWav to record the "voice print" that gets uploaded to Dropbox.
Findings are:
a) You need pretty long voice recordings and pass phrases for this to work decently.
b) Depending on your Internet connection, the first attempt to recognize the voice print may not work and you'll have to re-try.
Note: If you're not using VoxWav with VC and/or you're not a -- let's say -- "advanced" VC user, this project should probably be avoided. ;-)
[Update: James has now added a standard action that you can use instead of VoxWav if you prefer:
VcAdvanced.SaveRecoWav]
Four commands here:
1. Not really needed, but VoxWav users can use it to record their voice profile data if they want. This is used to create keylemon "models" (user profiles).
2. Use it to create user models. Sample command needs to be adapted to your user names and file paths etc.
3. "Begin User Authorization". See description in the command. This command automatically triggers the voice data processing command.
4. Voice processing command. Currently just tells you whether a voice was identified or not.
<?xml version="1.0" encoding="utf-16"?>
<!--VoxCommando 2.1.4.2-->
<commandGroup open="True" name="keylemon" enabled="True" prefix="" priority="0" requiredProcess="" description="">
<command id="705" name="1 - record voice data for model creation" enabled="true" alwaysOn="False" confirm="False" requiredConfidence="0" loop="False" loopDelay="0" loopMax="0" description="Use with VoxWav to record your voice. Replace with your own file path. After, you can use these to create a speaker model (voice profile for a specific user). Recordings must be good quality and at least 4 or 5 seconds long.">
<action>
<cmdType>TTS.SpeakSync</cmdType>
<params>
<param>Start talking.</param>
</params>
<cmdRepeat>1</cmdRepeat>
</action>
<action>
<cmdType>TcpMic.SaveNext</cmdType>
<params>
<param>local file path to Dropbox folder\{1}.wav</param>
</params>
<cmdRepeat>1</cmdRepeat>
</action>
<phrase>Record voice print for</phrase>
<payloadList>James, Naomi</payloadList>
</command>
<command id="689" name="2 - create model for {1}" enabled="true" alwaysOn="False" confirm="False" requiredConfidence="0" loop="False" loopDelay="0" loopMax="0" description="Creates a speaker model for {1} based on a wav file (or files) uploaded to the web. I used a Dropbox link -- saved to my map as {M:keylemon.dropboxURL}. Separate multiple wav file URLs with commas. I've created a map called keylemon, in which I store my username, api key, and models etc.">
<action>
<cmdType>Scrape.Post</cmdType>
<params>
<param>https://api.keylemon.com/api/speaker/model/?user={M:keylemon.username}&key={M:keylemon.APIkey}</param>
<param>urls={M:keylemon.dropboxURL}/{1}.wav&name={1}</param>
<param />
<param />
<param>application/x-www-form-urlencoded</param>
</params>
<cmdRepeat>1</cmdRepeat>
</action>
<action>
<cmdType>Results.RegExSingle</cmdType>
<params>
<param>"model_id":\s"(.*?)".*?"name":\s"(.*?)"</param>
</params>
<cmdRepeat>1</cmdRepeat>
</action>
<action>
<cmdType>Results.MatchToMap</cmdType>
<params>
<param>keylemon</param>
<param>True</param>
</params>
<cmdRepeat>1</cmdRepeat>
</action>
<phrase>create model for</phrase>
<payloadList>James, Naomi</payloadList>
</command>
<command id="690" name="Begin user authorization" enabled="true" alwaysOn="False" confirm="False" requiredConfidence="0" loop="False" loopDelay="0" loopMax="0" description="Works best if you use a pass phrase that matches one of your model phrases. Recognizer returns a "score" out of 100.">
<action>
<cmdType>TTS.SpeakSync</cmdType>
<params>
<param>Please say your pass phrase now.</param>
</params>
<cmdRepeat>1</cmdRepeat>
</action>
<action>
<cmdType>TcpMic.SaveNext</cmdType>
<params>
<param>LOCAL PATH TO YOUR DROPBOX\Public\keylemon\authUser.wav</param>
</params>
<cmdRepeat>1</cmdRepeat>
</action>
<action>
<cmdType>VC.SetEventTimer</cmdType>
<params>
<param>8s</param>
<param>postvoicedata</param>
</params>
<cmdRepeat>1</cmdRepeat>
</action>
<phrase>Begin user authorization</phrase>
</command>
<command id="703" name="process voice data" enabled="true" alwaysOn="False" confirm="False" requiredConfidence="0" loop="False" loopDelay="0" loopMax="0" description="Compares voice data to my 2 user models (James and Naomi). Recognizer returns a "score" out of 100. Proof of concept. Doesn't do anything useful at the moment.">
<action>
<cmdType>TTS.SpeakSync</cmdType>
<params>
<param>Processing data. Please wait.</param>
</params>
<cmdRepeat>1</cmdRepeat>
</action>
<action>
<cmdType>Scrape.Post</cmdType>
<params>
<param>https://api.keylemon.com/api/speaker/recognize/?user={M:keylemon.username}&key={M:keylemon.APIkey}</param>
<param>urls={M:keylemon.dropboxURL}/authUser.wav&models={M:keylemon.Naomi},{M:keylemon.James}</param>
<param />
<param />
<param>application/x-www-form-urlencoded</param>
</params>
<cmdRepeat>1</cmdRepeat>
</action>
<if ifBlockDisabled="False" ifNot="True">
<ifType>LastActionSuccess</ifType>
<ifParams>&&</ifParams>
<then>
<action>
<cmdType>TTS.Speak</cmdType>
<params>
<param>Voice processing failed.</param>
</params>
<cmdRepeat>1</cmdRepeat>
</action>
<action>
<cmdType>OSD.ShowText</cmdType>
<params>
<param>Processing failed. {CR} If you think your recording was good, say: "Re-try voice authorization"</param>
</params>
<cmdRepeat>1</cmdRepeat>
</action>
<action>
<cmdType>VC.StopMacro</cmdType>
<params />
<cmdRepeat>1</cmdRepeat>
</action>
</then>
<else />
</if>
<action>
<cmdType>Results.RegEx</cmdType>
<params>
<param>"name":\s"(.*?)",\s"score":\s(.*?)\}</param>
<param> - </param>
</params>
<cmdRepeat>1</cmdRepeat>
</action>
<if ifBlockDisabled="False" ifNot="False">
<ifType>(A)<(B)</ifType>
<ifParams>85&&{Match.1.2}</ifParams>
<then>
<action>
<cmdType>TTS.Speak</cmdType>
<params>
<param>Match found. Welcome {Match.1.1}. Switching to profile for {Match.1.1}</param>
</params>
<cmdRepeat>1</cmdRepeat>
</action>
<action>
<cmdType>VC.SetProfile</cmdType>
<params>
<param>{Match.1.1}</param>
</params>
<cmdRepeat>0</cmdRepeat>
</action>
</then>
<else />
</if>
<if ifBlockDisabled="False" ifNot="False">
<ifType>(A)<(B)</ifType>
<ifParams>85&&{Match.2.2}</ifParams>
<then>
<action>
<cmdType>TTS.Speak</cmdType>
<params>
<param>Match found. Welcome {Match.2.1}. </param>
</params>
<cmdRepeat>1</cmdRepeat>
</action>
<action>
<cmdType>VC.SetProfile</cmdType>
<params>
<param>{Match.2.1}</param>
</params>
<cmdRepeat>0</cmdRepeat>
</action>
</then>
<else />
</if>
<action>
<cmdType>OSD.ShowText</cmdType>
<params>
<param>Results:</param>
</params>
<cmdRepeat>1</cmdRepeat>
</action>
<action>
<cmdType>OSD.AddText</cmdType>
<params>
<param>{Match.{i}.1}: {Match.{i}.2}</param>
</params>
<cmdRepeat>{#M}</cmdRepeat>
</action>
<action>
<cmdType>File.Delete</cmdType>
<params>
<param>LOCAL PATH TO YOUR DROPBOX\Public\keylemon\authUser.wav</param>
</params>
<cmdRepeat>1</cmdRepeat>
</action>
<event>postvoicedata</event>
<phrase>Re-try voice authorization</phrase>
</command>
</commandGroup>
Users will need to get their own username and API key from the keylemon website.
POST SCRIPT: Although this will work for those who don't mind an Internet-reliant system, and has a "fun factor" to it, it has no genuine advantage that I can see over simply having a dedicated pass phrase for each user -- without using biometrics (as I described near the beginning of this thread). The simple pass phrase ("Call me Ishmael", "My name is Luka") does not require Internet or waiting for said Internet service or extra levels of potential failure.