[Announce] node-red-contrib-personal-wake-word

Hello,
I’d like to introduce:

This node brings integration of the awesome node-personal-wakeword module to nodered.
This enables an easy to use key word spotter for use as a personal wake-word in diy voice projects directly in nodered:

  • install node-red-contrib-personal-wake-word (this can take a few minutes as the node needs to build some underlying libraries)
  • connect a microphone to your machine and install a microphone node like node-red-contrib-sox-utils
  • record 3-10 trimmed samples of you saying the wake-word in a quiet environment.
  • add a wakeword configuration pointing to the folder containing your audio or to the audio files
  • connect the mic node in streaming mode to the wake-word node
  • start streaming and the node will start listening for your wakeword and send a msg when detected

For detailed feature and usage information have a look in the nodes help text in the side bar. I build the node so that it would also work as a drop in replacement for the node-red-contrib-voice2json wait-wake node as it’s much easier to quickly get going with this node then with training a custom precise model. Keep in mind that the node will work best for detecting the wake word from the person the samples are from. The keyword spotter is relatively lightweight in template averaging mode which is default. If you want to detect the wake word from multiple persons just run multiple instances in parallel.
This is a first release so it might be a bit rough around the edges. I will update the readme in the next release to also include a bash script to quickly record good wake-word samples and more detailed usage information.

Have fun with it, Johannes

8 Likes

Crashed Node-Red
MaxOS Mojaci v 10.14.6
Node-RED version: v1.2.7
Node.js version: v12.13.0

  1. Created a number of recordings of my wake word
  2. ran a flow inject-> sox-record -> wakeword -> debug
  3. node-red crashes.
29 Jan 07:04:32 - [info] Started modified flows
29 Jan 07:04:32 - [warn] [wake-word:86fa8e09.877658] ignoring .DS_Store as it is not a wav
29 Jan 07:04:47 - [warn] [sox-record:d55d0da6.48c738] support for other platforms than linux is experimental.
29 Jan 07:04:48 - [red] Uncaught Exception:
29 Jan 07:04:48 - TypeError: Cannot read property 'length' of undefined
    at WakewordDetector._normalizeFeatures (/Users/Paul/.node-red/node_modules/node-personal-wakeword/src/detector.js:289:34)
    at ReadStream.<anonymous> (/Users/Paul/.node-red/node_modules/node-personal-wakeword/src/detector.js:128:20)
    at ReadStream.emit (events.js:215:7)
    at endReadableNT (_stream_readable.js:1183:12)
    at processTicksAndRejections (internal/process/task_queues.js:80:21)
Pauls-mini:.node-red Paul$ 

(Note: the .DS_Store is a hidden file that macOS puts in every folder)

Here are the flows I used:

[{"id":"4446bb55.7e2ab4","type":"tab","label":"Flow 2","disabled":false,"info":""},{"id":"b640954b.a3fbe","type":"sox-record","z":"4446bb55.7e2ab4","name":"","buttonStart":"msg","inputs":1,"inputSource":"default","manualSource":"","inputEncoding":"signed-integer","inputChannels":1,"inputRate":16000,"inputBits":16,"byteOrder":"-L","encoding":"signed-integer","channels":1,"rate":16000,"bits":16,"gain":"0","lowpass":8000,"showDuration":true,"durationType":"forever","durationLength":0,"silenceDetection":"nothing","silenceDuration":"2.0","silenceThreshold":"2.0","outputFormat":"file","manualPath":"/Users/Paul/wakeword/wake0","debugOutput":false,"x":310,"y":240,"wires":[["403b3143.4348e8"],["c0261d02.dc95b"]]},{"id":"86fa8e09.877658","type":"wake-word","z":"4446bb55.7e2ab4","wakeword":"f6b41482.228fb8","threshold":0.5,"averaging":true,"inputProp":"payload","outputProp":"payload","controlProp":"control","passthrough":false,"name":"","x":510,"y":500,"wires":[["535c8e54.defe3"],["fe4bc217.b882f"]]},{"id":"e166e4d5.57a8a8","type":"inject","z":"4446bb55.7e2ab4","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"start","payloadType":"str","x":110,"y":200,"wires":[["b640954b.a3fbe"]]},{"id":"487bb105.2f8eb","type":"inject","z":"4446bb55.7e2ab4","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"stop","payloadType":"str","x":110,"y":260,"wires":[["b640954b.a3fbe"]]},{"id":"5c520f91.275fb8","type":"file","z":"4446bb55.7e2ab4","name":"","filename":"/Users/Paul/wakeword/word0.wav","appendNewline":false,"createDir":true,"overwriteFile":"true","encoding":"none","x":600,"y":300,"wires":[["1aaf09e2.c7a0ee","97c38cde.176d8"]]},{"id":"eb361045.0e5ed","type":"debug","z":"4446bb55.7e2ab4","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":870,"y":360,"wires":[]},{"id":"1f232e64.c9e6d2","type":"inject","z":"4446bb55.7e2ab4","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"0","payloadType":"num","x":110,"y":100,"wires":[["c63390cf.64ce"]]},{"id":"c63390cf.64ce","type":"change","z":"4446bb55.7e2ab4","name":"","rules":[{"t":"set","p":"mw_count","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":340,"y":100,"wires":[[]]},{"id":"403b3143.4348e8","type":"change","z":"4446bb55.7e2ab4","name":"","rules":[{"t":"set","p":"mw_count","pt":"msg","to":"mw_count","tot":"flow"},{"t":"set","p":"mw_count","pt":"msg","to":"mw_count+1","tot":"jsonata"},{"t":"set","p":"mw_count","pt":"flow","to":"mw_count","tot":"msg"},{"t":"set","p":"filename","pt":"msg","to":"wakefoo.wav","tot":"str"},{"t":"change","p":"filename","pt":"msg","from":"foo","fromt":"str","to":"mw_count","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":540,"y":240,"wires":[["66bb950b.40fb9c","5c520f91.275fb8"]]},{"id":"66bb950b.40fb9c","type":"debug","z":"4446bb55.7e2ab4","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":770,"y":240,"wires":[]},{"id":"1aaf09e2.c7a0ee","type":"debug","z":"4446bb55.7e2ab4","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":850,"y":300,"wires":[]},{"id":"97c38cde.176d8","type":"fs-ops-move","z":"4446bb55.7e2ab4","name":"Rename the wake0.wav using mw_count","sourcePath":"/Users/Paul/wakeword/","sourcePathType":"str","sourceFilename":"wake0.wav","sourceFilenameType":"str","destPath":"/Users/Paul/wakeword/","destPathType":"str","destFilename":"filename","destFilenameType":"msg","link":false,"x":620,"y":360,"wires":[["eb361045.0e5ed"]]},{"id":"d55d0da6.48c738","type":"sox-record","z":"4446bb55.7e2ab4","name":"","buttonStart":"msg","inputs":1,"inputSource":"default","manualSource":"","inputEncoding":"signed-integer","inputChannels":1,"inputRate":16000,"inputBits":16,"byteOrder":"-L","encoding":"signed-integer","channels":1,"rate":16000,"bits":16,"gain":"0","lowpass":8000,"showDuration":true,"durationType":"forever","durationLength":0,"silenceDetection":"nothing","silenceDuration":"2.0","silenceThreshold":"2.0","outputFormat":"stream","manualPath":"/Users/Paul/wakeword/wake0","debugOutput":false,"x":290,"y":500,"wires":[["86fa8e09.877658"],[]]},{"id":"fe4bc217.b882f","type":"debug","z":"4446bb55.7e2ab4","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":710,"y":520,"wires":[]},{"id":"535c8e54.defe3","type":"debug","z":"4446bb55.7e2ab4","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":710,"y":480,"wires":[]},{"id":"f2d57990.61f71","type":"inject","z":"4446bb55.7e2ab4","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"start","payloadType":"str","x":130,"y":480,"wires":[["d55d0da6.48c738"]]},{"id":"df5c8d4c.88a798","type":"inject","z":"4446bb55.7e2ab4","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"stop","payloadType":"str","x":130,"y":520,"wires":[["d55d0da6.48c738"]]},{"id":"2522f857.efe5c8","type":"comment","z":"4446bb55.7e2ab4","name":"set my word counter to 0","info":"","x":150,"y":60,"wires":[]},{"id":"c0261d02.dc95b","type":"debug","z":"4446bb55.7e2ab4","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":310,"y":300,"wires":[]},{"id":"d90d143d.062f28","type":"comment","z":"4446bb55.7e2ab4","name":"record the wake word and give them unique names","info":"","x":240,"y":160,"wires":[]},{"id":"92a8be8e.922048","type":"comment","z":"4446bb55.7e2ab4","name":"try out the wake word - BUT this crashes Node-RED","info":"","x":250,"y":420,"wires":[]},{"id":"f6b41482.228fb8","type":"wakeword-config","name":"","files":["/Users/Paul/wakeword"]}]

Ok I did some debugging.
I think I found the culprit @zenofmud
Can you please check your recordings? I can reproduce the error when I have an empty wav (0.04kb size - so only the wav headers and no audio frames) file in the folder. This crashes the underlying node-personal-wakeword. I’ll try and add error handling for this.

Edit can you please update and try, I just published 0.2.5 to npm and this now ignores empty wav files and gives you a warning.

  1. yes there was a wake word that was almost empty (30 bytes)
  2. with the update, Node-RED does not crash.

However I don't see anything coming out of wake word, but it is probably because I'm trying to use sox-record and feeding that directly into wake-word

What is the best way/node to use for listening and feeding into this?

Sox record set up to stream raw audio should be fine. I use it that way. Does the status say listening...?
Because that means its initialized fine if there is nothing in the log. Or does it hang at starting?
Your audio samples have to be just the wake word with no silence at the start or end and no other noise.
Have you tried adjusting the threshold? lower means more sensitivity.

I was seeing 'error' under the node so I looked at sox-record and realzed it wasn't sending a straw. I corrected that and now wake-word shows 'Listening' but it doesn't seem to be picking up the word.

I even played one of my recordings and it doesn't pick it up.

This how it should look (you cant see the green keyword detected in this flow because i send a pause command on detection):
image
I strongly suspect its a audio problem with either the wakeword samples or your input stream. When you look at the advanced debug output of sox record can you see what your saying represented in the levels?
Have you listened to your sample recordings?
They should really be like a second max and only the clean wakeword?

Edit:
You can also use a tool like audacity to look at the files and trim them

  1. the recordings sound fine and are only the wake word. To record them (if you look at the flow image above) I'd hit start, say the word and hit stop. all files (6 of them) are btween 15 and 26 KB.

Here is the debug from the log

29 Jan 10:18:51 - [warn] [sox-record:d55d0da6.48c738] support for other platforms than linux is experimental.
29 Jan 10:18:51 - [info] [debug:sox-rec2] 
{ payload: 'starting', _msgid: 'f66fe129.97154' }
29 Jan 10:18:51 - [info] [debug:sox-rec2] 
{
  payload: '\n' +
    "Input File     : 'default' (coreaudio)\n" +
    'Channels       : 2\n' +
    'Sample Rate    : 48000\n' +
    'Precision      : 32-bit\n' +
    'Sample Encoding: 32-bit Signed Integer PCM\n' +
    '\n' +
    '\rIn:0.00% 00:00:00.00 [00:00:00.00] Out:0     [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:51 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:00.09 [00:00:00.00] Out:490   [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:51 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:00.19 [00:00:00.00] Out:2.45k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:51 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:00.30 [00:00:00.00] Out:3.92k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:51 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:00.41 [00:00:00.00] Out:5.87k [   ===|===   ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:51 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:00.51 [00:00:00.00] Out:7.34k [    ==|==    ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:51 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:00.62 [00:00:00.00] Out:9.30k [     =|=     ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:51 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:00.73 [00:00:00.00] Out:10.8k [     -|-     ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:52 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:00.83 [00:00:00.00] Out:12.7k [     =|=     ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:52 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:00.94 [00:00:00.00] Out:14.2k [     =|=     ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:52 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:01.05 [00:00:00.00] Out:16.1k [    ==|==    ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:52 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:01.15 [00:00:00.00] Out:17.6k [    -=|=-    ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:52 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:01.26 [00:00:00.00] Out:19.6k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:52 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:01.37 [00:00:00.00] Out:21.0k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:52 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:01.47 [00:00:00.00] Out:23.0k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:52 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:01.58 [00:00:00.00] Out:24.5k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:52 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:01.69 [00:00:00.00] Out:26.4k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:52 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:01.79 [00:00:00.00] Out:27.9k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:53 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:01.90 [00:00:00.00] Out:29.8k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:53 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:02.01 [00:00:00.00] Out:30.8k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:53 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:02.11 [00:00:00.00] Out:33.3k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:53 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:02.22 [00:00:00.00] Out:34.3k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:53 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:02.33 [00:00:00.00] Out:36.7k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:53 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:02.43 [00:00:00.00] Out:37.7k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:53 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:02.54 [00:00:00.00] Out:40.1k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:53 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:02.65 [00:00:00.00] Out:41.1k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:53 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:02.75 [00:00:00.00] Out:43.1k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:54 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:02.86 [00:00:00.00] Out:44.5k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:54 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:02.97 [00:00:00.00] Out:46.5k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:54 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:03.07 [00:00:00.00] Out:48.0k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:54 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:03.18 [00:00:00.00] Out:49.9k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:54 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:03.29 [00:00:00.00] Out:51.4k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:54 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:03.39 [00:00:00.00] Out:53.3k [      |      ]        Clip:0    ',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:54 - [warn] [sox-record:d55d0da6.48c738] support for other platforms than linux is experimental.
29 Jan 10:18:54 - [info] [debug:sox-rec2] 
{
  payload: '\rIn:0.00% 00:00:03.46 [00:00:00.00] Out:54.8k [      |      ]        Clip:0    \n',
  _msgid: '6ecc0fb5.df077'
}
29 Jan 10:18:54 - [info] [debug:sox-rec2] 
{ payload: 'Aborted.\n', _msgid: '6ecc0fb5.df077' }
29 Jan 10:18:54 - [info] [debug:sox-rec2] 
{ payload: 'complete', _msgid: 'c2edc2f8.ab2f6' }

I have to go out for about 1/2 hour but will try what ever you want when I get back.

I guess you used a short word but that shouldn’t be a problem except it would give you more false positives normally. What threshold do you use and how many samples? Have you tried a different word and just record like 3 samples to use.
The only thing I could think of is to try something like node-red-contrib-mic or try it on a pi to see if it’s a Mac problem.

Edit:
The levels do look quite low, if they are that low on both recording the samples and the stream you should add some gain.

Ok, I amplified all my recordings and cut down the number to just 3.
The threshold was set to 0.5 (the default) and I have my mic right in front of my speaker and I'm playing the recorded wake word.

I get nothing out of the wakeword node. I tried the threshhold at 0 and 1 and still nothing.

I'll try this on one of my Pi's in a bit and let you know how it goes.

Mostly somewhere around 0.5 should be fine. Everything below 0.4 and i get a lot of false positives normally.
Playing it from a speaker to trigger will not always work as the whole pipeline of playing output speaker and back through the microphone will always change the spectrum of the audio.
With a lower threshold like 0.4 it should definitely trigger when you say it with the same settings used to record the samples. If you upload a sample somewhere i could look at it if i see anything obvious.

Let me try it on the Pi and I'll gat back to you.

1 Like

Ok i ve been chatting with Mathieu the node-personal-wakeword developer and here is what he had to say about running it on mac os:

Never run it on MacOS (don’t have one). The MFCC features extraction uses my native binding of an excellent C++ audio library named Gist. I’ve made pre-built binaries for Windows x64, Linux x64 and Linux Arm64 but not MacOS.

In theory it should work anyway if it builds ot alright on installation. On armhf at least that build step works. But it might have something to do with it.

1 Like

Ok, I've tried it on a Pi 4 and the wake words are still not recognized. Here it the flow I'm using

[{"id":"86fa8e09.877658","type":"wake-word","z":"ce1fdce9.e9f468","wakeword":"f6b41482.228fb8","threshold":"0.5","averaging":false,"inputProp":"payload","outputProp":"payload","controlProp":"control","passthrough":true,"name":"","x":510,"y":680,"wires":[["535c8e54.defe3"],["fe4bc217.b882f"]]},{"id":"d55d0da6.48c738","type":"sox-record","z":"ce1fdce9.e9f468","name":"","buttonStart":"msg","inputs":1,"inputSource":"default","manualSource":"","inputEncoding":"signed-integer","inputChannels":1,"inputRate":16000,"inputBits":16,"byteOrder":"-L","encoding":"signed-integer","channels":1,"rate":16000,"bits":16,"gain":"0","lowpass":8000,"showDuration":false,"durationType":"forever","durationLength":0,"silenceDetection":"nothing","silenceDuration":"2.0","silenceThreshold":"2.0","outputFormat":"stream","manualPath":"/Users/Paul/wakeword/wake0","debugOutput":false,"x":290,"y":680,"wires":[["86fa8e09.877658","1cd4b92e.da38b7"],["c9ab1a9e.550208"]]},{"id":"fe4bc217.b882f","type":"debug","z":"ce1fdce9.e9f468","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":710,"y":700,"wires":[]},{"id":"535c8e54.defe3","type":"debug","z":"ce1fdce9.e9f468","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":710,"y":660,"wires":[]},{"id":"f2d57990.61f71","type":"inject","z":"ce1fdce9.e9f468","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"start","payloadType":"str","x":130,"y":660,"wires":[["d55d0da6.48c738"]]},{"id":"df5c8d4c.88a798","type":"inject","z":"ce1fdce9.e9f468","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"stop","payloadType":"str","x":130,"y":700,"wires":[["d55d0da6.48c738"]]},{"id":"92a8be8e.922048","type":"comment","z":"ce1fdce9.e9f468","name":"try out the wake word - BUT nothing recognized","info":"","x":220,"y":580,"wires":[]},{"id":"1cd4b92e.da38b7","type":"debug","z":"ce1fdce9.e9f468","name":"sox-out1","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":520,"y":620,"wires":[]},{"id":"c9ab1a9e.550208","type":"debug","z":"ce1fdce9.e9f468","name":"sox-rec2","active":false,"tosidebar":true,"console":true,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":510,"y":740,"wires":[]},{"id":"f6b41482.228fb8","type":"wakeword-config","name":"","files":["/home/pi/wakewords"]}]

what else can I try?

i just freshly installed it on a pi4 from the palette manager and than recorded ten samples using this bash script:

(Just save it to the folder you want to record the wake-word in and run it. You might have to change the first sox command to use your device if it’s not configured as default.)

#!/bin/bash

declare -i n=$1
declare -i c=1

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

bold=$(tput bold)
normal=$(tput sgr0)

((p=p+1))

printf "\nThis script can record wake word samples for training of a wake word model.
       \nThe recording starts when you press return and ends automatically each time.
       \nOnce you have started a recording by pressing return say the wake word naturally
       like you would in daily use.\nLets start:"

for i in {0..9}
do
    printf "${normal}\n\nPress Enter to record number ${c} of 10 wake word recordings.\n"
    read -s -n 1 key
    if [[ $key = "" ]]; then
        sox -t alsa default -r 16000 -c 1 -b 16 -e signed-integer -L ${DIR}/tmp.wav trim 0 3
        
        sox ${DIR}/tmp.wav ${DIR}/tmp2.wav vad -p 0.1 reverse vad -p 0.1 reverse
        
        sox ${DIR}/tmp2.wav ${DIR}/hotword.${n}.wav fade 0.1 `soxi -D ${DIR}/tmp2.wav` 0.1
    fi
    ((n=n+1))
    ((c=c+1))
    printf "\nRecorded successfully.\n\n"
done

rm ${DIR}/tmp.wav ${DIR}/tmp2.wav

printf "\n\nFinished, thank you.\n"

I then pointed the wake word node with the sox record connected to it at the folder and it works.
All I can imagine is that it’s some kind of problem with your audio as I have set it up on 4 different pi’s with different versions of nodered and it worked on all of them described as above.
Are you sure everything is recorded in the right format?
16000hz, 16bit, mono?
If there is no errors in the log I really don’t know what else to recommend except trying a different mic.

Just did it on another pi 4 in the last 5 minutes.
Took an old ps eye cam which works as a usb mic connected it to another pi 4.
Copied over the above script and recorded 10 samples of me saying donkey:


I than installed the wake node, connected a sox record, choose the camera as input and start with button (nothing else changed from default), pointed the wake config at the donkey folder (changed nothing else) started recording and:
image
That’s all. That’s the fifth pi I did this on (2xpi4,1xpi3b+,2xpi3a and varying versions of os, node, and nodered) and the 3rd different mic.
So I’m really out of options what to recommend except play with the variables left, record a different wake-word, use a different mic, try the script above.

Ahhh,It works!!! I had 'forward audio on detection event' checked on and i don't think I evr saw the actual result.

Got it to work with both my Shure mic and a Logitec Webcam.

Thanks!

2 Likes

If you check forward on detection it will only trigger once and than ignore until you send a msg to listen again.
Im happy its working for you now :+1:t2: