public void TestProcess() { Porcupine p = new Porcupine(Path.Combine(Environment.CurrentDirectory, "porcupine_params.pv"), keywordFilePath: $"{GetAbsRootPath()}resources/keyword_files/porcupine_{GetEnvironmentName()}.ppn", sensitivity: 0.5f); Assert.AreEqual(PicoVoiceStatus.SUCCESS, p.Status, "the status of the creation of the recognition system has failed"); WAVFile file = new WAVFile(); file.Open("porcupine.wav", WAVFile.WAVFileMode.READ); Assert.AreEqual(p.SampleRate() / 1000, file.BitsPerSample, "The samplerate is not equal!!!"); List <short> data = new List <short>(); while (file.NumSamplesRemaining > 0) { data.Add(BitConverter.ToInt16(file.GetNextSample_ByteArray())); } int framecount = (int)Math.Floor((decimal)(data.Count / p.FrameLength())); var results = new List <bool>(); for (int i = 0; i < framecount; i++) { int start = i * p.FrameLength(); int count = p.FrameLength(); List <short> frame = data.GetRange(start, count); p.Process(frame.ToArray(), out bool result); results.Add(result); } var res = results.Count(x => x); Assert.AreEqual(1, res, $"The result is not as expected, expected {1} got {res}"); p.Dispose(); }
public void TestProcess() { Porcupine p = Porcupine.Create(keywords: new List <string> { "porcupine" }); int frameLen = p.FrameLength; string testAudioPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "resources/audio_samples/porcupine.wav"); List <short> data = GetPcmFromFile(testAudioPath, p.SampleRate); int framecount = (int)Math.Floor((float)(data.Count / frameLen)); var results = new List <int>(); for (int i = 0; i < framecount; i++) { int start = i * p.FrameLength; int count = p.FrameLength; List <short> frame = data.GetRange(start, count); int result = p.Process(frame.ToArray()); Assert.IsTrue(result == -1 || result == 0, "Porcupine returned an unexpected result (should return 0 or -1)"); if (result >= 0) { results.Add(result); } } Assert.IsTrue(results.Count == 1 && results[0] == 0, "Expected to find keyword 'porcupine', but no keyword was detected."); p.Dispose(); }
private void RunTestCase(string audioFileName, List <int> expectedResults) { int frameLen = porcupine.FrameLength; string testAudioPath = Path.Combine(_relativeDir, "resources/audio_samples", audioFileName); List <short> data = GetPcmFromFile(testAudioPath, porcupine.SampleRate); int framecount = (int)Math.Floor((float)(data.Count / frameLen)); var results = new List <int>(); for (int i = 0; i < framecount; i++) { int start = i * frameLen; int count = frameLen; List <short> frame = data.GetRange(start, count); int result = porcupine.Process(frame.ToArray()); Assert.IsTrue(result >= -1, "Porcupine returned an unexpected result (<-1)"); if (result >= 0) { results.Add(result); } } Assert.AreEqual(expectedResults.Count, results.Count, $"Should have found {expectedResults.Count} keywords, but {results.Count} were found."); for (int i = 0; i < results.Count; i++) { Assert.AreEqual(expectedResults[i], results[i], $"Expected keyword {expectedResults[i]}, but Porcupine detected keyword {results[i]}."); } porcupine.Dispose(); }
public void TestVersion() { porcupine = Porcupine.FromBuiltInKeywords(ACCESS_KEY, new List <BuiltInKeyword> { BuiltInKeyword.PORCUPINE }); Assert.IsFalse(string.IsNullOrWhiteSpace(porcupine.Version), "Porcupine did not return a valid version number."); porcupine.Dispose(); }
public void TestFrameLength() { porcupine = Porcupine.FromBuiltInKeywords(ACCESS_KEY, new List <BuiltInKeyword> { BuiltInKeyword.PORCUPINE }); Assert.IsTrue(porcupine.FrameLength > 0, "Specified frame length was not a valid number."); porcupine.Dispose(); }
/// <summary> /// Reads through input file and, upon detecting the specified wake word(s), prints the detection timecode and the wake word. /// </summary> /// <param name="inputAudioPath">Required argument. Absolute path to input audio file.</param> /// <param name="modelPath">Absolute path to the file containing model parameters. If not set it will be set to the default location.</param> /// <param name="keywordPaths">Absolute paths to keyword model files. If not set it will be populated from `keywords` argument.</param> /// <param name="sensitivities"> /// Sensitivities for detecting keywords. Each value should be a number within [0, 1]. A higher sensitivity results in fewer /// misses at the cost of increasing the false alarm rate. If not set 0.5 will be used. /// </param> /// <param name="keywords"> /// List of keywords (phrases) for detection. The list of available (default) keywords can be retrieved /// using `Porcupine.KEYWORDS`. If `keyword_paths` is set then this argument will be ignored. /// </param> public static void RunDemo(string inputAudioPath, string modelPath, List <string> keywordPaths, List <string> keywords, List <float> sensitivities) { Porcupine porcupine = null; try { // init porcupine wake word engine porcupine = Porcupine.Create(modelPath, keywordPaths, keywords, sensitivities); // get keyword names for labeling detection results if (keywords == null) { keywords = keywordPaths.Select(k => Path.GetFileNameWithoutExtension(k).Split("_")[0]).ToList(); } using BinaryReader reader = new BinaryReader(File.Open(inputAudioPath, FileMode.Open)); ValidateWavFile(reader, porcupine.SampleRate, 16, out short numChannels); // read audio and send frames to porcupine short[] porcupineFrame = new short[porcupine.FrameLength]; int frameIndex = 0; long totalSamplesRead = 0; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); while (reader.BaseStream.Position != reader.BaseStream.Length) { totalSamplesRead++; porcupineFrame[frameIndex++] = reader.ReadInt16(); if (frameIndex == porcupineFrame.Length) { int result = porcupine.Process(porcupineFrame); if (result >= 0) { Console.WriteLine($"Detected {keywords[result]} at " + $"{Math.Round(totalSamplesRead / (double)porcupine.SampleRate, 2)} sec"); } frameIndex = 0; } // skip right channel if (numChannels == 2) { reader.ReadInt16(); } } stopWatch.Stop(); double audioLen = Math.Round(totalSamplesRead / (double)porcupine.SampleRate, 2); double realtimeFactor = Math.Round(audioLen / stopWatch.Elapsed.TotalSeconds, 2); Console.WriteLine($"Realtime factor: {realtimeFactor}x"); } finally { porcupine?.Dispose(); } }
public void TestVersion() { Porcupine p = Porcupine.Create(keywords: new List <string> { "porcupine" }); Assert.IsFalse(string.IsNullOrWhiteSpace(p.Version), "Porcupine did not return a valid version number."); p.Dispose(); }
public void TestFrameLength() { Porcupine p = Porcupine.Create(keywords: new List <string> { "porcupine" }); Assert.IsTrue(p.FrameLength > 0, "Specified frame length was not a valid number."); p.Dispose(); }
/// <summary> /// Reads through input file and, upon detecting the specified wake word(s), prints the detection timecode and the wake word. /// </summary> /// <param name="inputAudioPath">Required argument. Absolute path to input audio file.</param> /// <param name="modelPath">Absolute path to the file containing model parameters. If not set it will be set to the default location.</param> /// <param name="keywordPaths">Absolute paths to keyword model files. If not set it will be populated from `keywords` argument.</param> /// <param name="sensitivities"> /// Sensitivities for detecting keywords. Each value should be a number within [0, 1]. A higher sensitivity results in fewer /// misses at the cost of increasing the false alarm rate. If not set 0.5 will be used. /// </param> /// <param name="keywords"> /// List of keywords (phrases) for detection. The list of available (default) keywords can be retrieved /// using `Porcupine.KEYWORDS`. If `keyword_paths` is set then this argument will be ignored. /// </param> public static void RunDemo(string inputAudioPath, string modelPath, List <string> keywordPaths, List <string> keywords, List <float> sensitivities) { Porcupine porcupine = null; try { // init porcupine wake word engine porcupine = Porcupine.Create(modelPath, keywordPaths, keywords, sensitivities); using (BinaryReader reader = new BinaryReader(File.Open(inputAudioPath, FileMode.Open))) { short numChannels; ValidateWavFile(reader, porcupine.SampleRate, 16, out numChannels); // read audio and send frames to porcupine short[] porcupineFrame = new short[porcupine.FrameLength]; int frameIndex = 0; long totalSamplesRead = 0; while (reader.BaseStream.Position != reader.BaseStream.Length) { totalSamplesRead++; porcupineFrame[frameIndex++] = reader.ReadInt16(); if (frameIndex == porcupineFrame.Length) { int result = porcupine.Process(porcupineFrame); if (result >= 0) { Console.WriteLine($"Detected {keywords[result]} at " + $"{Math.Round(totalSamplesRead / (double)porcupine.SampleRate, 2)} sec"); } frameIndex = 0; } // skip right channel if (numChannels == 2) { reader.ReadInt16(); } } } } finally { porcupine?.Dispose(); } }
public void MultipleKeywords() { var modelFilePath = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "porcupine_params.pv")); Assert.IsTrue(File.Exists(modelFilePath), $"File.Exists(modelFilePath) --> {modelFilePath}"); paths.ForEach(keywordFilePath => Assert.IsTrue(File.Exists(keywordFilePath), $"File.Exists(keywordFilePath) --> {keywordFilePath}")); Porcupine p = new Porcupine(modelFilePath, keywordFilePaths: paths, sensitivities: senses); Assert.AreEqual(PicoVoiceStatus.SUCCESS, p.Status, "the status of the creation of the recognition system has failed"); WAVFile file = new WAVFile(); file.Open("multiple_keywords.wav", WAVFile.WAVFileMode.READ); Assert.AreEqual(p.SampleRate(), file.AudioFormat.SampleRateHz, "The samplerate is not equal!!!"); List <short> data = new List <short>(); while (file.NumSamplesRemaining > 0) { data.Add(BitConverter.ToInt16(file.GetNextSample_ByteArray())); } int framecount = (int)Math.Floor((decimal)(data.Count / p.FrameLength())); var results = new List <int>(); for (int i = 0; i < framecount; i++) { int start = i * p.FrameLength(); int count = p.FrameLength(); List <short> frame = data.GetRange(start, count); PicoVoiceStatus status = p.ProcessMultipleKeywords(frame.ToArray(), out int result); if (result >= 0) { results.Add(result); } Assert.AreEqual(PicoVoiceStatus.SUCCESS, status, "The status is not as expected"); } var requiredRes = new[] { 8, 0, 1, 2, 3, 4, 5, 7, 8, 9 }; Assert.AreEqual(requiredRes.Length, results.Count, $"expected results length are different expected {requiredRes.Length} got {results.Count}"); for (var i = 0; i < results.Count; i++) { Assert.AreEqual(requiredRes[i], results[i], $"The result is not as expected, expected {requiredRes[i]} got {results[i]}"); } p.Dispose(); }
public void TestProcessMultiple() { List <string> inputKeywords = new List <string> { "alexa", "americano", "blueberry", "bumblebee", "grapefruit", "grasshopper", "picovoice", "porcupine", "terminator" }; List <int> expectedResults = new List <int>() { 7, 0, 1, 2, 3, 4, 5, 6, 7, 8 }; Porcupine p = Porcupine.Create(keywords: inputKeywords); int frameLen = p.FrameLength; string testAudioPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "resources/audio_samples/multiple_keywords.wav"); List <short> data = GetPcmFromFile(testAudioPath, p.SampleRate); int framecount = (int)Math.Floor((float)(data.Count / frameLen)); var results = new List <int>(); for (int i = 0; i < framecount; i++) { int start = i * frameLen; int count = frameLen; List <short> frame = data.GetRange(start, count); int result = p.Process(frame.ToArray()); Assert.IsTrue(result >= -1, "Porcupine returned an unexpected result (<-1)"); if (result >= 0) { results.Add(result); } } Assert.AreEqual(expectedResults.Count, results.Count, $"Should have found {expectedResults.Count} keywords, but {results.Count} were found."); for (int i = 0; i < results.Count; i++) { Assert.AreEqual(expectedResults[i], results[i], $"Expected '{Porcupine.KEYWORDS[expectedResults[i]]}', but '{Porcupine.KEYWORDS[results[i]]}' was detected."); } p.Dispose(); }
public void TestProcess() { var modelFilePath = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "porcupine_params.pv")); Assert.IsTrue(File.Exists(modelFilePath), $"File.Exists(modelFilePath) --> {modelFilePath}"); keywordPaths.ForEach(keywordFilePath => Assert.IsTrue(File.Exists(keywordFilePath), $"File.Exists(keywordFilePath) --> {keywordFilePath}")); Porcupine p = new Porcupine(modelFilePath, keywordPaths: keywordPaths, sensitivities: sensitivities); List <short> data = new List <short>(); using (BinaryReader reader = new BinaryReader(File.Open("multiple_keywords.wav", FileMode.Open))) { reader.ReadBytes(44); while (reader.BaseStream.Position != reader.BaseStream.Length) { data.Add(reader.ReadInt16()); } } int framecount = (int)Math.Floor((decimal)(data.Count / p.FrameLength())); var results = new List <int>(); for (int i = 0; i < framecount; i++) { int start = i * p.FrameLength(); int count = p.FrameLength(); List <short> frame = data.GetRange(start, count); int result = p.Process(frame.ToArray()); if (result >= 0) { results.Add(result); } } var requiredRes = new[] { 6, 0, 1, 2, 3, 4, 5, 6, 7 }; Assert.AreEqual(requiredRes.Length, results.Count, $"expected results length are different expected {requiredRes.Length} got {results.Count}"); for (var i = 0; i < results.Count; i++) { Assert.AreEqual(requiredRes[i], results[i], $"The result is not as expected, expected {requiredRes[i]} got {results[i]}"); } p.Dispose(); }
public void TestProcessMultiple() { Porcupine p = Porcupine.Create(keywords: Porcupine.KEYWORDS); int frameLen = p.FrameLength; string testAudioPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "resources/audio_samples/multiple_keywords.wav"); List <short> data = GetPcmFromFile(testAudioPath, p.SampleRate); int framecount = (int)Math.Floor((float)(data.Count / frameLen)); var results = new List <int>(); for (int i = 0; i < framecount; i++) { int start = i * p.FrameLength; int count = p.FrameLength; List <short> frame = data.GetRange(start, count); int result = p.Process(frame.ToArray()); Assert.IsTrue(result >= -1, "Porcupine returned an unexpected result (<-1)"); if (result >= 0) { results.Add(result); } } var expectedResults = new[] { 6, 0, 1, 2, 3, 4, 5, 6, 7 }; Assert.AreEqual(expectedResults.Length, results.Count, $"Should have found {expectedResults.Length} keywords, but {results.Count} were found."); for (int i = 0; i < results.Count; i++) { Assert.AreEqual(expectedResults[i], results[i], $"Expected '{Porcupine.KEYWORDS[expectedResults[i]]}', but '{Porcupine.KEYWORDS[results[i]]}' was detected."); } p.Dispose(); }
/// <summary> /// Creates an input audio stream, instantiates an instance of Porcupine object, and monitors the audio stream for /// occurrencec of the wake word(s). It prints the time of detection for each occurrence and the wake word. /// </summary> /// <param name="modelPath">Absolute path to the file containing model parameters. If not set it will be set to the default location.</param> /// <param name="keywordPaths">Absolute paths to keyword model files. If not set it will be populated from `keywords` argument.</param> /// <param name="keywordPaths">Absolute paths to keyword model files. If not set it will be populated from `keywords` argument.</param> /// <param name="sensitivities"> /// Sensitivities for detecting keywords. Each value should be a number within [0, 1]. A higher sensitivity results in fewer /// misses at the cost of increasing the false alarm rate. If not set 0.5 will be used. /// </param> /// <param name="keywords"> /// List of keywords (phrases) for detection. The list of available (default) keywords can be retrieved /// using `Porcupine.KEYWORDS`. If `keyword_paths` is set then this argument will be ignored. /// </param> /// <param name="audioDeviceIndex">Optional argument. If provided, audio is recorded from this input device. Otherwise, the default audio input device is used.</param> /// <param name="outputPath">Optional argument. If provided, recorded audio will be stored in this location at the end of the run.</param> public static void RunDemo(string modelPath, List <string> keywordPaths, List <string> keywords, List <float> sensitivities, int?audioDeviceIndex = null, string outputPath = null) { Porcupine porcupine = null; BinaryWriter outputFileWriter = null; int totalSamplesWritten = 0; try { // init porcupine wake word engine porcupine = Porcupine.Create(modelPath, keywordPaths, keywords, sensitivities); // get keyword names for labeling detection results if (keywords == null) { keywords = keywordPaths.Select(k => Path.GetFileNameWithoutExtension(k).Split("_")[0]).ToList(); } // open stream to output file if (!string.IsNullOrWhiteSpace(outputPath)) { outputFileWriter = new BinaryWriter(new FileStream(outputPath, FileMode.OpenOrCreate, FileAccess.Write)); WriteWavHeader(outputFileWriter, 1, 16, 16000, 0); } // choose audio device string deviceName = null; if (audioDeviceIndex != null) { List <string> captureDeviceList = ALC.GetStringList(GetEnumerationStringList.CaptureDeviceSpecifier).ToList(); if (captureDeviceList != null && audioDeviceIndex.Value < captureDeviceList.Count) { deviceName = captureDeviceList[audioDeviceIndex.Value]; } else { throw new ArgumentException("No input device found with the specified index. Use --show_audio_devices to show" + "available inputs", "--audio_device_index"); } } Console.Write("Listening for {"); for (int i = 0; i < keywords.Count; i++) { Console.Write($" {keywords[i]}({sensitivities[i]})"); } Console.Write(" }\n"); // create and start recording short[] recordingBuffer = new short[porcupine.FrameLength]; ALCaptureDevice captureDevice = ALC.CaptureOpenDevice(deviceName, 16000, ALFormat.Mono16, porcupine.FrameLength * 2); { ALC.CaptureStart(captureDevice); while (!Console.KeyAvailable) { int samplesAvailable = ALC.GetAvailableSamples(captureDevice); if (samplesAvailable > porcupine.FrameLength) { ALC.CaptureSamples(captureDevice, ref recordingBuffer[0], porcupine.FrameLength); int result = porcupine.Process(recordingBuffer); if (result >= 0) { Console.WriteLine($"[{DateTime.Now.ToLongTimeString()}] Detected '{keywords[result]}'"); } if (outputFileWriter != null) { foreach (short sample in recordingBuffer) { outputFileWriter.Write(sample); } totalSamplesWritten += recordingBuffer.Length; } } Thread.Yield(); } // stop and clean up resources Console.WriteLine("Stopping..."); ALC.CaptureStop(captureDevice); ALC.CaptureCloseDevice(captureDevice); } } finally { if (outputFileWriter != null) { // write size to header and clean up WriteWavHeader(outputFileWriter, 1, 16, 16000, totalSamplesWritten); outputFileWriter.Flush(); outputFileWriter.Dispose(); } porcupine?.Dispose(); } }
/// <summary> /// Creates an input audio stream, instantiates an instance of Porcupine object, and monitors the audio stream for /// occurrencec of the wake word(s). It prints the time of detection for each occurrence and the wake word. /// </summary> /// <param name="accessKey">AccessKey obtained from Picovoice Console (https://console.picovoice.ai/).</param> /// <param name="modelPath">Absolute path to the file containing model parameters. If not set it will be set to the default location.</param> /// <param name="keywordPaths">Absolute paths to keyword model files. If not set it will be populated from `keywords` argument.</param> /// <param name="sensitivities"> /// Sensitivities for detecting keywords. Each value should be a number within [0, 1]. A higher sensitivity results in fewer /// misses at the cost of increasing the false alarm rate. If not set 0.5 will be used. /// </param> /// <param name="audioDeviceIndex">Optional argument. If provided, audio is recorded from this input device. Otherwise, the default audio input device is used.</param> /// <param name="outputPath">Optional argument. If provided, recorded audio will be stored in this location at the end of the run.</param> public static void RunDemo( string accessKey, string modelPath, List <string> keywordPaths, List <float> sensitivities, int audioDeviceIndex, string outputPath = null) { Porcupine porcupine = null; BinaryWriter outputFileWriter = null; int totalSamplesWritten = 0; // init porcupine wake word engine porcupine = Porcupine.FromKeywordPaths(accessKey, keywordPaths, modelPath, sensitivities); // get keyword names for labeling detection results List <string> keywordNames = keywordPaths.Select(k => Path.GetFileNameWithoutExtension(k).Split("_")[0]).ToList(); // open stream to output file if (!string.IsNullOrWhiteSpace(outputPath)) { outputFileWriter = new BinaryWriter(new FileStream(outputPath, FileMode.OpenOrCreate, FileAccess.Write)); WriteWavHeader(outputFileWriter, 1, 16, 16000, 0); } Console.CancelKeyPress += (s, o) => { Console.WriteLine("Stopping..."); if (outputFileWriter != null) { // write size to header and clean up WriteWavHeader(outputFileWriter, 1, 16, 16000, totalSamplesWritten); outputFileWriter.Flush(); outputFileWriter.Dispose(); } porcupine?.Dispose(); }; // create and start recording using (PvRecorder recorder = PvRecorder.Create(deviceIndex: audioDeviceIndex, frameLength: porcupine.FrameLength)) { Console.WriteLine($"Using device: {recorder.SelectedDevice}"); Console.Write($"Listening for [{string.Join(' ', keywordNames.Select(k => $"'{k}'"))}]...\n"); recorder.Start(); while (true) { short[] pcm = recorder.Read(); int result = porcupine.Process(pcm); if (result >= 0) { Console.WriteLine($"[{DateTime.Now.ToLongTimeString()}] Detected '{keywordNames[result]}'"); } if (outputFileWriter != null) { foreach (short sample in pcm) { outputFileWriter.Write(sample); } totalSamplesWritten += pcm.Length; } Thread.Yield(); } } }