[rustpotterks] Upgrade to version 3 (#15556)

* Upgrade to version 3
* Use ThreadPoolManager and add sleep
* Remove pool prefix, already added by thread pool manager

Signed-off-by: Miguel Álvarez <miguelwork92@gmail.com>
This commit is contained in:
GiviMAD 2023-10-01 21:15:24 +02:00 committed by GitHub
parent 5a39985420
commit 1abb8f267e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 337 additions and 179 deletions

View File

@ -3,12 +3,15 @@
This voice service allows you to use the open source library Rustpotter as your keyword spotter in openHAB.
[Rustpotter](https://github.com/GiviMAD/rustpotter) is a free and open-source keywords spotter written in rust.
Rustpotter provides personal on-device wake word detection. You need to generate a model for your keyword using audio samples.
Rustpotter provides personal on-device wake word detection.
You need to generate a file for your keyword using audio samples.
You can test library in your browser using these web pages:
You can test the library in your browser using these web pages:
- [The spot demo](https://givimad.github.io/rustpotter-worklet-demo/), which include some example wakewords (but it's recommended to use your own).
- [The model creation demo](https://givimad.github.io/rustpotter-create-model-demo/), it allows you to record compatible wav files and generate a wakeword file that you can test on the previous page.
- [The wakeword reference creation demo](https://givimad.github.io/rustpotter-create-model-demo/), it allows you to record compatible wav files and generate a wakeword reference files that you can test on the previous page.
There is also this [command line utility](https://github.com/GiviMAD/rustpotter-cli) that allows taking records and testing the library.
Important: No voice data listened by this service will be uploaded to the Cloud.
The voice data is processed offline, locally on your openHAB server by Rustpotter.
@ -17,12 +20,14 @@ The voice data is processed offline, locally on your openHAB server by Rustpotte
After installing, you will be able to access the service options through the openHAB configuration page in UI (**Settings / Other Services - Rustpotter Keyword Spotter**) to edit them:
- **Threshold** - Configures the detector threshold, is the min score (in range 0. to 1.) that some wake word template should obtain to trigger a detection. Defaults to 0.5.
- **Averaged Threshold** - Configures the detector averaged threshold, is the min score (in range 0. to 1.) that the audio should obtain against a combination of the wake word templates, the detection will be aborted if this is not the case. This way it can prevent to run the comparison of the current frame against each of the wake word templates which saves cpu. If set to 0 this functionality is disabled.
- **Score Mode** - Indicates how to calculate the final score.
- **Min Scores** - Minimum number of positive scores to consider a partial detection as a detection.
- **Comparator Ref** - Configures the reference for the comparator used to match the samples.
- **Comparator Band Size** - Configures the band-size for the comparator used to match the samples.
- **Threshold** - Configures the detector threshold, is the min score (in range 0. to 1.) to trigger the detection. Defaults to 0.5.
- **Averaged Threshold** - Configures the detector averaged threshold. If set to 0 this functionality is disabled.
- **Score Mode** - Indicates how to calculate the final score. (Only applies to wakeword references)
- **Min Scores** - Minimum number of positive scores required to not discard the detection.
- **Eager** - Emit detection on min partial scores.
- **VAD Mode** - Enables a basic vad detector to discard some execution.
- **Score Ref** - Configures the reference for the comparator used to match the samples.
- **Band Size** - Configures the band-size for the comparator used to match the samples. (Only applies to wakeword references)
- **Gain Normalizer** - Enables an audio filter that intent to approximate the volume of the stream to a reference level.
- **Min Gain** - Min gain applied by the gain normalizer filter.
- **Max Gain** - Max gain applied by the gain normalizer filter.
@ -40,26 +45,23 @@ org.openhab.voice.rustpotterks:threshold=0.5
org.openhab.voice.rustpotterks:averagedthreshold=0.2
org.openhab.voice.rustpotterks:scoreMode=max
org.openhab.voice.rustpotterks:minScores=5
org.openhab.voice.rustpotterks:comparatorRef=0.22
org.openhab.voice.rustpotterks:comparatorBandSize=5
org.openhab.voice.rustpotterks:scoreRef=0.22
org.openhab.voice.rustpotterks:bandSize=5
org.openhab.voice.rustpotterks:gainNormalizer=true
org.openhab.voice.rustpotterks:minGain=0.5
org.openhab.voice.rustpotterks:maxGain=1
org.openhab.voice.rustpotterks:gainRef=
org.openhab.voice.rustpotterks:bandPass=true
org.openhab.voice.rustpotterks:lowCutoff=80
org.openhab.voice.rustpotterks:highCutoff=400
org.openhab.voice.rustpotterks:gainRef=0.004
```
## Magic Word Configuration
The magic word to spot is gathered from your 'Voice' configuration.
You can generate your own wakeword files using the [Rustpotter CLI](https://github.com/GiviMAD/rustpotter-cli).
You can generate your own wakeword files using the [command line utility](https://github.com/GiviMAD/rustpotter-cli).
You can also download the models used as examples on the [rustpotter web demo](https://givimad.github.io/rustpotter-worklet-demo/) from [this folder](https://github.com/GiviMAD/rustpotter-worklet-demo/tree/main/static).
You can also download the wakeword used as examples on the [rustpotter web demo](https://givimad.github.io/rustpotter-worklet-demo/) from [this folder](https://github.com/GiviMAD/rustpotter-worklet-demo/tree/main/static).
To use a wake word model, you should place the file under '\<openHAB userdata\>/rustpotter' and configure your magic word to match the file name replacing spaces with '_' and adding the extension '.rpw'.
To use a wake word wakeword, you should place the file under '\<openHAB userdata\>/rustpotter' and configure your magic word to match the file name replacing spaces with '_' and adding the extension '.rpw'.
As an example, the file generated for the keyword "ok openhab" will be named 'ok_openhab.rpw'.
The service will only work if it's able to find the correct rpw for your magic word configuration.

View File

@ -18,7 +18,7 @@
<dependency>
<groupId>io.github.givimad</groupId>
<artifactId>rustpotter-java</artifactId>
<version>2.0.1</version>
<version>3.0.1</version>
</dependency>
</dependencies>
</project>

View File

@ -23,35 +23,46 @@ import org.eclipse.jdt.annotation.Nullable;
@NonNullByDefault
public class RustpotterKSConfiguration {
/**
* Configures the detector threshold, is the min score (in range 0. to 1.) that some wake word template should
* obtain to trigger a detection. Defaults to 0.5.
* Configures the detector threshold, is the min score (in range 0. to 1.) to trigger the detection.
* Defaults to 0.5.
*/
public float threshold = 0.5f;
/**
* Configures the detector averaged threshold, is the min score (in range 0. to 1.) that the audio should obtain
* against a
* combination of the wake word templates, the detection will be aborted if this is not the case. This way it can
* prevent to
* run the comparison of the current frame against each of the wake word templates which saves cpu.
* Configures the detector averaged threshold.
* If set to 0 this functionality is disabled.
*/
public float averagedThreshold = 0.2f;
public float averagedThreshold = 0f;
/**
* Indicates how to calculate the final score.
* Only applies to not trained wakewords.
*/
public String scoreMode = "max";
/**
* Minimum number of positive scores to consider a partial detection as a detection.
* Enables a basic vad detector to discard some execution.
*/
public String vadMode = "";
/**
* Minimum number of positive scores required to not discard the detection.
*/
public int minScores = 5;
/**
* Emit detection on min partial scores.
*/
public boolean eager = false;
/**
* Configures the reference for the comparator used to match the samples.
*/
public float comparatorRef = 0.22f;
public float scoreRef = 0.22f;
/**
* Configures the band-size for the comparator used to match the samples.
* Only applies to wakeword references.
*/
public int comparatorBandSize = 5;
public int bandSize = 5;
/**
* Create wav record on the first partial detections and any other one that surpasses its score.
*
*/
public boolean record = false;
/**
* Enables an audio filter that intent to approximate the volume of the stream to a reference level (RMS of the
* samples is used as volume measure).

View File

@ -14,14 +14,16 @@ package org.openhab.voice.rustpotterks.internal;
import static org.openhab.voice.rustpotterks.internal.RustpotterKSConstants.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.jdt.annotation.NonNullByDefault;
@ -47,9 +49,11 @@ import org.slf4j.LoggerFactory;
import io.github.givimad.rustpotter_java.Endianness;
import io.github.givimad.rustpotter_java.Rustpotter;
import io.github.givimad.rustpotter_java.RustpotterBuilder;
import io.github.givimad.rustpotter_java.RustpotterConfig;
import io.github.givimad.rustpotter_java.RustpotterDetection;
import io.github.givimad.rustpotter_java.SampleFormat;
import io.github.givimad.rustpotter_java.ScoreMode;
import io.github.givimad.rustpotter_java.VADMode;
/**
* The {@link RustpotterKSService} is a keyword spotting implementation based on rustpotter.
@ -61,28 +65,30 @@ import io.github.givimad.rustpotter_java.ScoreMode;
@ConfigurableService(category = SERVICE_CATEGORY, label = SERVICE_NAME
+ " Keyword Spotter", description_uri = SERVICE_CATEGORY + ":" + SERVICE_ID)
public class RustpotterKSService implements KSService {
private static final String RUSTPOTTER_FOLDER = Path.of(OpenHAB.getUserDataFolder(), "rustpotter").toString();
private static final Path RUSTPOTTER_FOLDER = Path.of(OpenHAB.getUserDataFolder(), "rustpotter");
private static final Path RUSTPOTTER_RECORDS_FOLDER = RUSTPOTTER_FOLDER.resolve("records");
private final Logger logger = LoggerFactory.getLogger(RustpotterKSService.class);
private final ScheduledExecutorService executor = ThreadPoolManager.getScheduledPool("OH-voice-rustpotterks");
private final ExecutorService executor = ThreadPoolManager.getPool("voice-rustpotterks");
private RustpotterKSConfiguration config = new RustpotterKSConfiguration();
static {
Logger logger = LoggerFactory.getLogger(RustpotterKSService.class);
File directory = new File(RUSTPOTTER_FOLDER);
if (!directory.exists()) {
if (directory.mkdir()) {
logger.info("rustpotter dir created {}", RUSTPOTTER_FOLDER);
}
}
}
private final List<RustpotterMutex> runningInstances = new ArrayList<>();
@Activate
protected void activate(Map<String, Object> config) {
logger.debug("Loading library");
tryCreateDir(RUSTPOTTER_FOLDER);
tryCreateDir(RUSTPOTTER_RECORDS_FOLDER);
try {
Rustpotter.loadLibrary();
} catch (IOException e) {
logger.warn("Unable to load rustpotter native library: {}", e.getMessage());
}
modified(config);
}
@Modified
protected void modified(Map<String, Object> config) {
this.config = new Configuration(config).as(RustpotterKSConfiguration.class);
asyncUpdateActiveInstances();
}
@Override
@ -102,19 +108,15 @@ public class RustpotterKSService implements KSService {
@Override
public Set<AudioFormat> getSupportedFormats() {
return Set
.of(new AudioFormat(AudioFormat.CONTAINER_WAVE, AudioFormat.CODEC_PCM_SIGNED, null, null, null, null));
return Set.of(
new AudioFormat(AudioFormat.CONTAINER_WAVE, AudioFormat.CODEC_PCM_SIGNED, false, 16, null, 16000L),
new AudioFormat(AudioFormat.CONTAINER_WAVE, AudioFormat.CODEC_PCM_SIGNED, null, 16, null, null),
new AudioFormat(AudioFormat.CONTAINER_WAVE, AudioFormat.CODEC_PCM_SIGNED, null, 32, null, null));
}
@Override
public KSServiceHandle spot(KSListener ksListener, AudioStream audioStream, Locale locale, String keyword)
throws KSException {
logger.debug("Loading library");
try {
Rustpotter.loadLibrary();
} catch (IOException e) {
throw new KSException("Unable to load rustpotter lib: " + e.getMessage());
}
var audioFormat = audioStream.getFormat();
var frequency = audioFormat.getFrequency();
var bitDepth = audioFormat.getBitDepth();
@ -125,27 +127,35 @@ public class RustpotterKSService implements KSService {
"Missing stream metadata: frequency, bit depth, channels and endianness must be defined.");
}
var endianness = isBigEndian ? Endianness.BIG : Endianness.LITTLE;
logger.debug("Audio wav spec: frequency '{}', bit depth '{}', channels '{}', '{}'", frequency, bitDepth,
channels, isBigEndian ? "big-endian" : "little-endian");
logger.debug("Audio wav spec: sample rate {}, {} bits, {} channels, {}", frequency, bitDepth, channels,
isBigEndian ? "big-endian" : "little-endian");
var wakewordName = keyword.replaceAll("\\s", "_") + ".rpw";
var wakewordPath = RUSTPOTTER_FOLDER.resolve(wakewordName);
if (!Files.exists(wakewordPath)) {
throw new KSException("Missing wakeword file: " + wakewordPath);
}
Rustpotter rustpotter;
try {
rustpotter = initRustpotter(frequency, bitDepth, channels, endianness);
} catch (Exception e) {
throw new KSException("Unable to configure rustpotter: " + e.getMessage(), e);
}
var modelName = keyword.replaceAll("\\s", "_") + ".rpw";
var modelPath = Path.of(RUSTPOTTER_FOLDER, modelName);
if (!modelPath.toFile().exists()) {
throw new KSException("Missing model " + modelName);
throw new KSException("Unable to start rustpotter: " + e.getMessage(), e);
}
try {
rustpotter.addWakewordModelFile(modelPath.toString());
rustpotter.addWakewordFile("w", wakewordPath.toString());
} catch (Exception e) {
throw new KSException("Unable to load wake word model: " + e.getMessage());
throw new KSException("Unable to load wakeword file: " + e.getMessage());
}
logger.debug("Model '{}' loaded", modelPath);
logger.debug("Wakeword '{}' loaded", wakewordPath);
AtomicBoolean aborted = new AtomicBoolean(false);
executor.submit(() -> processAudioStream(rustpotter, ksListener, audioStream, aborted));
int bufferSize = (int) rustpotter.getBytesPerFrame();
long bytesPerMs = frequency / 1000 * (long) bitDepth;
RustpotterMutex rustpotterMutex = new RustpotterMutex(rustpotter);
synchronized (this.runningInstances) {
this.runningInstances.add(rustpotterMutex);
}
executor.submit(
() -> processAudioStream(rustpotterMutex, bufferSize, bytesPerMs, ksListener, audioStream, aborted));
return () -> {
logger.debug("Stopping service");
aborted.set(true);
@ -154,40 +164,48 @@ public class RustpotterKSService implements KSService {
private Rustpotter initRustpotter(long frequency, int bitDepth, int channels, Endianness endianness)
throws Exception {
var rustpotterBuilder = new RustpotterBuilder();
// audio configs
rustpotterBuilder.setBitsPerSample(bitDepth);
rustpotterBuilder.setSampleRate(frequency);
rustpotterBuilder.setChannels(channels);
rustpotterBuilder.setSampleFormat(SampleFormat.INT);
rustpotterBuilder.setEndianness(endianness);
// detector configs
rustpotterBuilder.setThreshold(config.threshold);
rustpotterBuilder.setAveragedThreshold(config.averagedThreshold);
rustpotterBuilder.setScoreMode(getScoreMode(config.scoreMode));
rustpotterBuilder.setMinScores(config.minScores);
rustpotterBuilder.setComparatorRef(config.comparatorRef);
rustpotterBuilder.setComparatorBandSize(config.comparatorBandSize);
// filter configs
rustpotterBuilder.setGainNormalizerEnabled(config.gainNormalizer);
rustpotterBuilder.setMinGain(config.minGain);
rustpotterBuilder.setMaxGain(config.maxGain);
rustpotterBuilder.setGainRef(config.gainRef);
rustpotterBuilder.setBandPassFilterEnabled(config.bandPass);
rustpotterBuilder.setBandPassLowCutoff(config.lowCutoff);
rustpotterBuilder.setBandPassHighCutoff(config.highCutoff);
var rustpotterConfig = initRustpotterConfig();
// audio format config just need to be set for initializing the instance, is ignored on config updates
rustpotterConfig.setSampleFormat(getIntSampleFormat(bitDepth));
rustpotterConfig.setSampleRate(frequency);
rustpotterConfig.setChannels(channels);
rustpotterConfig.setEndianness(endianness);
// init the detector
var rustpotter = rustpotterBuilder.build();
rustpotterBuilder.delete();
var rustpotter = new Rustpotter(rustpotterConfig);
rustpotterConfig.delete();
return rustpotter;
}
private void processAudioStream(Rustpotter rustpotter, KSListener ksListener, AudioStream audioStream,
AtomicBoolean aborted) {
private RustpotterConfig initRustpotterConfig() {
var rustpotterConfig = new RustpotterConfig();
// detector configs
rustpotterConfig.setThreshold(config.threshold);
rustpotterConfig.setAveragedThreshold(config.averagedThreshold);
rustpotterConfig.setScoreMode(getScoreMode(config.scoreMode));
rustpotterConfig.setMinScores(config.minScores);
rustpotterConfig.setEager(config.eager);
rustpotterConfig.setScoreRef(config.scoreRef);
rustpotterConfig.setBandSize(config.bandSize);
rustpotterConfig.setVADMode(getVADMode(config.vadMode));
rustpotterConfig.setRecordPath(config.record ? RUSTPOTTER_RECORDS_FOLDER.toString() : null);
// filter configs
rustpotterConfig.setGainNormalizerEnabled(config.gainNormalizer);
rustpotterConfig.setMinGain(config.minGain);
rustpotterConfig.setMaxGain(config.maxGain);
rustpotterConfig.setGainRef(config.gainRef);
rustpotterConfig.setBandPassFilterEnabled(config.bandPass);
rustpotterConfig.setBandPassLowCutoff(config.lowCutoff);
rustpotterConfig.setBandPassHighCutoff(config.highCutoff);
return rustpotterConfig;
}
private void processAudioStream(RustpotterMutex rustpotter, int bufferSize, long bytesPerMs, KSListener ksListener,
AudioStream audioStream, AtomicBoolean aborted) {
int numBytesRead;
var bufferSize = (int) rustpotter.getBytesPerFrame();
byte[] audioBuffer = new byte[bufferSize];
int remaining = bufferSize;
boolean hasFailed = false;
while (!aborted.get()) {
try {
numBytesRead = audioStream.read(audioBuffer, bufferSize - remaining, remaining);
@ -196,10 +214,20 @@ public class RustpotterKSService implements KSService {
}
if (numBytesRead != remaining) {
remaining = remaining - numBytesRead;
try {
Thread.sleep(remaining / bytesPerMs);
} catch (InterruptedException ignored) {
logger.warn("Thread interrupted while waiting for audio, aborting execution");
aborted.set(true);
}
if (aborted.get()) {
break;
}
continue;
}
remaining = bufferSize;
var result = rustpotter.processBytes(audioBuffer);
hasFailed = false;
if (result.isPresent()) {
var detection = result.get();
if (logger.isDebugEnabled()) {
@ -219,33 +247,102 @@ public class RustpotterKSService implements KSService {
} catch (IOException e) {
String errorMessage = e.getMessage();
ksListener.ksEventReceived(new KSErrorEvent(errorMessage != null ? errorMessage : "Unexpected error"));
if (hasFailed) {
logger.warn("Multiple consecutive errors, stopping service");
break;
}
hasFailed = true;
}
}
synchronized (this.runningInstances) {
this.runningInstances.remove(rustpotter);
}
rustpotter.delete();
logger.debug("rustpotter stopped");
logger.debug("Rustpotter stopped");
}
private void asyncUpdateActiveInstances() {
int nInstances;
synchronized (this.runningInstances) {
nInstances = this.runningInstances.size();
}
if (nInstances == 0) {
return;
}
var rustpotterConfig = initRustpotterConfig();
executor.submit(() -> {
logger.debug("Updating running instances");
synchronized (this.runningInstances) {
for (RustpotterMutex rustpotter : this.runningInstances) {
rustpotter.updateConfig(rustpotterConfig);
}
logger.debug("{} running instances updated", this.runningInstances.size());
}
rustpotterConfig.delete();
});
}
private static SampleFormat getIntSampleFormat(int bitDepth) throws IOException {
return switch (bitDepth) {
case 8 -> SampleFormat.I8;
case 16 -> SampleFormat.I16;
case 32 -> SampleFormat.I32;
default -> throw new IOException("Unsupported audio bit depth: " + bitDepth);
};
}
private ScoreMode getScoreMode(String mode) {
switch (mode) {
case "average":
return ScoreMode.AVG;
case "median":
return ScoreMode.MEDIAN;
case "p25":
return ScoreMode.P25;
case "p50":
return ScoreMode.P50;
case "p75":
return ScoreMode.P75;
case "p80":
return ScoreMode.P80;
case "p90":
return ScoreMode.P90;
case "p95":
return ScoreMode.P95;
case "max":
default:
return ScoreMode.MAX;
return switch (mode) {
case "average" -> ScoreMode.AVG;
case "median" -> ScoreMode.MEDIAN;
case "p25" -> ScoreMode.P25;
case "p50" -> ScoreMode.P50;
case "p75" -> ScoreMode.P75;
case "p80" -> ScoreMode.P80;
case "p90" -> ScoreMode.P90;
case "p95" -> ScoreMode.P95;
default -> ScoreMode.MAX;
};
}
private @Nullable VADMode getVADMode(String mode) {
return switch (mode) {
case "easy" -> VADMode.EASY;
case "medium" -> VADMode.MEDIUM;
case "hard" -> VADMode.HARD;
default -> null;
};
}
private void tryCreateDir(Path rustpotterFolder) {
if (!Files.exists(rustpotterFolder) || !Files.isDirectory(rustpotterFolder)) {
try {
Files.createDirectory(rustpotterFolder);
logger.info("Folder {} created", rustpotterFolder);
} catch (IOException e) {
logger.warn("Unable to create folder {}", rustpotterFolder);
}
}
}
private record RustpotterMutex(Rustpotter rustpotter) {
public Optional<RustpotterDetection> processBytes(byte[] bytes) {
synchronized (this.rustpotter) {
return this.rustpotter.processBytes(bytes);
}
}
public void updateConfig(RustpotterConfig config) {
synchronized (this.rustpotter) {
this.rustpotter.updateConfig(config);
}
}
public void delete() {
synchronized (this.rustpotter) {
this.rustpotter.delete();
}
}
}
}

View File

@ -5,8 +5,7 @@
<type>voice</type>
<name>Rustpotter Keyword Spotter</name>
<description>This voice service allows you to use the open source library Rustpotter as your keyword spotter in
openHAB.</description>
<description>This voice service allows using the open source project Rustpotter as your keyword spotter in openHAB.</description>
<connection>none</connection>
<service-id>org.openhab.voice.rustpotterks</service-id>

View File

@ -13,24 +13,22 @@
<label>Audio Filters</label>
<description>Optional audio filter options.</description>
</parameter-group>
<parameter name="threshold" type="decimal" min="0" max="1" groupName="wakewordDetector">
<parameter name="threshold" type="decimal" min="0" max="1" step="0.001" groupName="wakewordDetector">
<label>Threshold</label>
<description>Configures the detector threshold, is the min score (in range 0. to 1.) that some of the wakeword
templates should obtain to trigger a detection. Model defined value takes prevalence if present.</description>
<description>Configures the detector threshold, is the min score (in range 0. to 1.) to trigger the detection.</description>
<default>0.5</default>
</parameter>
<parameter name="averagedThreshold" type="decimal" min="0" max="1" groupName="wakewordDetector">
<parameter name="averagedThreshold" type="decimal" min="0" max="1" step="0.001" groupName="wakewordDetector">
<label>Averaged Threshold</label>
<description>Configures the detector averaged threshold, is the min score (in range 0. to 1.) that the audio should
obtain against a combination of the wake word templates, the detection will be aborted if this is not the case. This
way it can prevent to run the comparison of the current frame against each of the wake word templates which saves
cpu. If set to 0 this functionality is disabled.</description>
<default>0.2</default>
<description>Configures the detector averaged threshold. If set to 0 this functionality is disabled.</description>
<default>0</default>
<advanced>true</advanced>
</parameter>
<parameter name="scoreMode" type="text" groupName="wakewordDetector">
<label>Score Mode</label>
<description>Indicates how to calculate the final score.</description>
<description>Indicates how to calculate the final score. Not affect to wakeword models.</description>
<default>max</default>
<advanced>true</advanced>
<options>
<option value="average">Average</option>
<option value="max">Max</option>
@ -43,23 +41,47 @@
<option value="p95">P95</option>
</options>
</parameter>
<parameter name="vadMode" type="text" groupName="wakewordDetector">
<label>VAD Mode</label>
<description>Enables a basic vad detector to discard some execution.</description>
<advanced>true</advanced>
<options>
<option value="off">Off</option>
<option value="easy">Easy</option>
<option value="medium">Medium</option>
<option value="hard">Hard</option>
</options>
<default>off</default>
</parameter>
<parameter name="minScores" type="integer" groupName="wakewordDetector">
<label>Min Scores</label>
<description>Minimum number of positive scores to consider a partial detection as a detection.</description>
<default>5</default>
</parameter>
<parameter name="comparatorRef" type="decimal" min="0" max="1" groupName="wakewordDetector">
<label>Comparator Ref</label>
<description>Configures the reference for the comparator used to match the samples.</description>
<parameter name="eager" type="boolean" groupName="wakewordDetector">
<label>Eager</label>
<description>Emit detection on min partial scores.</description>
<default>false</default>
</parameter>
<parameter name="scoreRef" type="decimal" min="0" max="1" groupName="wakewordDetector">
<label>Score Ref</label>
<description>Value used to calculate the score as a percent in range 0 - 1.</description>
<default>0.22</default>
<advanced>true</advanced>
</parameter>
<parameter name="comparatorBandSize" type="integer" groupName="wakewordDetector">
<label>Comparator Band Size</label>
<description>Configures the band-size for the comparator used to match the samples.</description>
<parameter name="bandSize" type="integer" groupName="wakewordDetector">
<label>Band Size</label>
<description>Configures the band-size for the comparator used to match the wakeword refs. Not affect to wakeword
models.</description>
<default>5</default>
<advanced>true</advanced>
</parameter>
<parameter name="record" type="boolean" groupName="wakewordDetector">
<label>Record on Partial Detections</label>
<description>Create wav record on the first partial detections and any other one that surpasses its score.</description>
<default>false</default>
<advanced>true</advanced>
</parameter>
<parameter name="gainNormalizer" type="boolean" groupName="filters">
<label>Gain Normalizer</label>
<description> Enables an audio filter that intent to approximate the volume of the stream to a reference level (RMS
@ -76,7 +98,7 @@
<description>Max gain applied by the gain normalizer filter.</description>
<default>1</default>
</parameter>
<parameter name="gainRef" type="decimal" min="0" max="1" step="0.001" groupName="filters">
<parameter name="gainRef" type="decimal" min="0" max="1" step="0.0001" groupName="filters">
<label>Gain Ref</label>
<description>Set the RMS reference used by the gain-normalizer to calculate the gain applied. If unset an estimation
of the wakeword level is used.</description>
@ -85,16 +107,19 @@
<label>Band Pass</label>
<description>Enables an audio filter that attenuates frequencies outside the low cutoff and high cutoff range.</description>
<default>false</default>
<advanced>true</advanced>
</parameter>
<parameter name="lowCutoff" type="decimal" min="0" groupName="filters">
<label>Low Cutoff</label>
<description>Low cutoff for the band-pass filter.</description>
<default>80</default>
<advanced>true</advanced>
</parameter>
<parameter name="highCutoff" type="decimal" min="0" groupName="filters">
<label>High Cutoff</label>
<description>High cutoff for the band-pass filter.</description>
<default>400</default>
<advanced>true</advanced>
</parameter>
</config-description>
</config-description:config-descriptions>

View File

@ -1,11 +1,11 @@
voice.config.rustpotterks.averagedThreshold.label = Averaged Threshold
voice.config.rustpotterks.averagedThreshold.description = Configures the detector averaged threshold, is the min score (in range 0. to 1.) that the audio should obtain against a combination of the wake word templates, the detection will be aborted if this is not the case. This way it can prevent to run the comparison of the current frame against each of the wake word templates which saves cpu. If set to 0 this functionality is disabled.
voice.config.rustpotterks.averagedThreshold.description = Configures the detector averaged threshold. If set to 0 this functionality is disabled.
voice.config.rustpotterks.bandPass.label = Band Pass
voice.config.rustpotterks.bandPass.description = Enables an audio filter that attenuates frequencies outside the low cutoff and high cutoff range.
voice.config.rustpotterks.comparatorBandSize.label = Comparator Band Size
voice.config.rustpotterks.comparatorBandSize.description = Configures the band-size for the comparator used to match the samples.
voice.config.rustpotterks.comparatorRef.label = Comparator Ref
voice.config.rustpotterks.comparatorRef.description = Configures the reference for the comparator used to match the samples.
voice.config.rustpotterks.bandSize.label = Band Size
voice.config.rustpotterks.bandSize.description = Configures the band-size for the comparator used to match the wakeword refs. Not affect to wakeword models.
voice.config.rustpotterks.eager.label = Eager
voice.config.rustpotterks.eager.description = Emit detection on min partial scores.
voice.config.rustpotterks.gainNormalizer.label = Gain Normalizer
voice.config.rustpotterks.gainNormalizer.description = Enables an audio filter that intent to approximate the volume of the stream to a reference level (RMS of the samples is used as volume measure).
voice.config.rustpotterks.gainRef.label = Gain Ref
@ -24,8 +24,10 @@ voice.config.rustpotterks.minGain.label = Min Gain
voice.config.rustpotterks.minGain.description = Min gain applied by the gain normalizer filter.
voice.config.rustpotterks.minScores.label = Min Scores
voice.config.rustpotterks.minScores.description = Minimum number of positive scores to consider a partial detection as a detection.
voice.config.rustpotterks.record.label = Record on Partial Detections
voice.config.rustpotterks.record.description = Create wav record on the first partial detections and any other one that surpasses its score.
voice.config.rustpotterks.scoreMode.label = Score Mode
voice.config.rustpotterks.scoreMode.description = Indicates how to calculate the final score.
voice.config.rustpotterks.scoreMode.description = Indicates how to calculate the final score. Not affect to wakeword models.
voice.config.rustpotterks.scoreMode.option.average = Average
voice.config.rustpotterks.scoreMode.option.max = Max
voice.config.rustpotterks.scoreMode.option.median = Median
@ -35,9 +37,18 @@ voice.config.rustpotterks.scoreMode.option.p75 = P75
voice.config.rustpotterks.scoreMode.option.p80 = P80
voice.config.rustpotterks.scoreMode.option.p90 = P90
voice.config.rustpotterks.scoreMode.option.p95 = P95
voice.config.rustpotterks.scoreRef.label = Score Ref
voice.config.rustpotterks.scoreRef.description = Value used to calculate the score as a percent in range 0 - 1.
voice.config.rustpotterks.threshold.label = Threshold
voice.config.rustpotterks.threshold.description = Configures the detector threshold, is the min score (in range 0. to 1.) that some of the wakeword templates should obtain to trigger a detection. Model defined value takes prevalence if present.
voice.config.rustpotterks.threshold.description = Configures the detector threshold, is the min score (in range 0. to 1.) that some of the wakeword templates should obtain to trigger a detection.
voice.config.rustpotterks.vadMode.label = VAD Mode
voice.config.rustpotterks.vadMode.description = Enables a basic vad detector to discard some execution.
voice.config.rustpotterks.vadMode.option.off = Off
voice.config.rustpotterks.vadMode.option.easy = Easy
voice.config.rustpotterks.vadMode.option.medium = Medium
voice.config.rustpotterks.vadMode.option.hard = Hard
# service
# add-on
service.voice.rustpotterks.label = Rustpotter Keyword Spotter
addon.rustpotterks.name = Rustpotter Keyword Spotter
addon.rustpotterks.description = This voice service allows using the open source project Rustpotter as your keyword spotter in openHAB.

View File

@ -1,41 +1,54 @@
voice.config.rustpotterks.averagedThreshold.label = Soglia Media
voice.config.rustpotterks.averagedThreshold.description = Configura la soglia media del rilevatore, è il punteggio minimo (in intervallo da 0. a 1.) che l'audio dovrebbe avere rispetto a una combinazione dei modelli di parole di wake up, il rilevamento verrà interrotto se non avviene. In questo modo può impedire di eseguire il confronto del frame corrente con ciascuno dei modelli di parole di wake up che permettono di salvare cpu. Se impostato a 0 questa funzionalità è disabilitata.
voice.config.rustpotterks.comparatorBandSize.label = Dimensione Banda Di Comparazione
voice.config.rustpotterks.comparatorBandSize.description = Configura la dimensione della banda per il comparatore usato per abbinare i campioni.
voice.config.rustpotterks.comparatorRef.label = Rif. Comparatore
voice.config.rustpotterks.comparatorRef.description = Configura il riferimento per il comparatore utilizzato per abbinare i campioni.
voice.config.rustpotterks.eagerMode.label = Modalità Eager
voice.config.rustpotterks.eagerMode.description = Abilita la modalità eager. Termina il rilevamento non appena un risultato è sopra il punteggio, invece di aspettare di vedere se il quadro successivo ha un punteggio più alto.
voice.config.rustpotterks.group.noiseDetector.label = Rilevatore Rumore
voice.config.rustpotterks.group.noiseDetector.description = Opzioni aggiuntive di rilevamento del rumore.
voice.config.rustpotterks.group.vadDetector.label = Rilevatore VAD
voice.config.rustpotterks.group.vadDetector.description = Opzioni aggiuntive del rilevatore di attività vocale.
voice.config.rustpotterks.group.wakewordDetector.label = Rivelatore Wakeword
voice.config.rustpotterks.group.wakewordDetector.description = Opzioni di rilevamento Wakeword.
voice.config.rustpotterks.noiseDetectionMode.label = Modalità Rilevamento Rumore
voice.config.rustpotterks.noiseDetectionMode.description = Utilizzare un rilevatore di rumore per ridurre il calcolo in assenza di suono. Configura la difficoltà di considerare un fotogramma come rumore (il livello di rumore richiesto).
voice.config.rustpotterks.noiseDetectionMode.option.disabled = Disabilitato
voice.config.rustpotterks.noiseDetectionMode.option.easiest = Più Semplice
voice.config.rustpotterks.noiseDetectionMode.option.easy = Facile
voice.config.rustpotterks.noiseDetectionMode.option.normal = Normale
voice.config.rustpotterks.noiseDetectionMode.option.hard = Difficile
voice.config.rustpotterks.noiseDetectionMode.option.hardest = Molto Difficile
voice.config.rustpotterks.noiseSensitivity.label = Sensibilità Al Rumore
voice.config.rustpotterks.noiseSensitivity.description = Il rapporto rumore/silenzio nell'ultimo secondo per considerare la voce come rilevata.
voice.config.rustpotterks.threshold.label = Soglia
voice.config.rustpotterks.threshold.description = Configura la soglia del rilevatore, è il punteggio minimo (in intervallo da 0. a 1.) che alcuni modelli di wakeword dovrebbero ottenere per attivare un rilevamento. Il valore definito modello prende la prevalenza se presente.
voice.config.rustpotterks.vadDelay.label = Ritardo VAD
voice.config.rustpotterks.vadDelay.description = Secondi per disabilitare il rivelatore vad dopo che la voce è stata rilevata.
voice.config.rustpotterks.vadMode.label = Modalità VAD
voice.config.rustpotterks.vadMode.description = Utilizzare un rivelatore vad per ridurre il calcolo in assenza di suono vocale.
voice.config.rustpotterks.vadMode.option.disabled = Disabilitato
voice.config.rustpotterks.vadMode.option.low-bitrate = Basso Bitrate
voice.config.rustpotterks.vadMode.option.quality = Qualità
voice.config.rustpotterks.vadMode.option.aggressive = Aggressivo
voice.config.rustpotterks.vadMode.option.very-aggressive = Molto aggressivo
voice.config.rustpotterks.vadSensitivity.label = Sensibilità VAD
voice.config.rustpotterks.vadSensitivity.description = Il rapporto voce/silenzio nell'ultimo secondo per considerare la voce come rilevata.
voice.config.rustpotterks.averagedThreshold.label = Averaged Threshold
voice.config.rustpotterks.averagedThreshold.description = Configures the detector averaged threshold. If set to 0 this functionality is disabled.
voice.config.rustpotterks.bandPass.label = Band Pass
voice.config.rustpotterks.bandPass.description = Enables an audio filter that attenuates frequencies outside the low cutoff and high cutoff range.
voice.config.rustpotterks.bandSize.label = Band Size
voice.config.rustpotterks.bandSize.description = Configures the band-size for the comparator used to match the wakeword refs. Not affect to wakeword models.
voice.config.rustpotterks.eager.label = Eager
voice.config.rustpotterks.eager.description = Emit detection on min partial scores.
voice.config.rustpotterks.gainNormalizer.label = Gain Normalizer
voice.config.rustpotterks.gainNormalizer.description = Enables an audio filter that intent to approximate the volume of the stream to a reference level (RMS of the samples is used as volume measure).
voice.config.rustpotterks.gainRef.label = Gain Ref
voice.config.rustpotterks.gainRef.description = Set the RMS reference used by the gain-normalizer to calculate the gain applied. If unset an estimation of the wakeword level is used.
voice.config.rustpotterks.group.filters.label = Audio Filters
voice.config.rustpotterks.group.filters.description = Optional audio filter options.
voice.config.rustpotterks.group.wakewordDetector.label = Wakeword Detector
voice.config.rustpotterks.group.wakewordDetector.description = Wakeword detection options.
voice.config.rustpotterks.highCutoff.label = High Cutoff
voice.config.rustpotterks.highCutoff.description = High cutoff for the band-pass filter.
voice.config.rustpotterks.lowCutoff.label = Low Cutoff
voice.config.rustpotterks.lowCutoff.description = Low cutoff for the band-pass filter.
voice.config.rustpotterks.maxGain.label = Max Gain
voice.config.rustpotterks.maxGain.description = Max gain applied by the gain normalizer filter.
voice.config.rustpotterks.minGain.label = Min Gain
voice.config.rustpotterks.minGain.description = Min gain applied by the gain normalizer filter.
voice.config.rustpotterks.minScores.label = Min Scores
voice.config.rustpotterks.minScores.description = Minimum number of positive scores to consider a partial detection as a detection.
voice.config.rustpotterks.record.label = Record on Partial Detections
voice.config.rustpotterks.record.description = Create wav record on the first partial detections and any other one that surpasses its score.
voice.config.rustpotterks.scoreMode.label = Score Mode
voice.config.rustpotterks.scoreMode.description = Indicates how to calculate the final score. Not affect to wakeword models.
voice.config.rustpotterks.scoreMode.option.average = Average
voice.config.rustpotterks.scoreMode.option.max = Max
voice.config.rustpotterks.scoreMode.option.median = Median
voice.config.rustpotterks.scoreMode.option.p25 = P25
voice.config.rustpotterks.scoreMode.option.p50 = P50
voice.config.rustpotterks.scoreMode.option.p75 = P75
voice.config.rustpotterks.scoreMode.option.p80 = P80
voice.config.rustpotterks.scoreMode.option.p90 = P90
voice.config.rustpotterks.scoreMode.option.p95 = P95
voice.config.rustpotterks.scoreRef.label = Score Ref
voice.config.rustpotterks.scoreRef.description = Value used to calculate the score as a percent in range 0 - 1.
voice.config.rustpotterks.threshold.label = Threshold
voice.config.rustpotterks.threshold.description = Configures the detector threshold, is the min score (in range 0. to 1.) that some of the wakeword templates should obtain to trigger a detection.
voice.config.rustpotterks.vadMode.label = VAD Mode
voice.config.rustpotterks.vadMode.description = Enables a basic vad detector to discard some execution.
voice.config.rustpotterks.vadMode.option.off = Off
voice.config.rustpotterks.vadMode.option.easy = Easy
voice.config.rustpotterks.vadMode.option.medium = Medium
voice.config.rustpotterks.vadMode.option.hard = Hard
# service
# add-on
service.voice.rustpotterks.label = Parola Chiave Spotter per Rustpotter
addon.rustpotterks.name = Rustpotter Keyword Spotter
addon.rustpotterks.description = This voice service allows using the open source project Rustpotter as your keyword spotter in openHAB.