added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
27
bundles/org.openhab.voice.picotts/.classpath
Normal file
27
bundles/org.openhab.voice.picotts/.classpath
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="test" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
23
bundles/org.openhab.voice.picotts/.project
Normal file
23
bundles/org.openhab.voice.picotts/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.openhab.voice.picotts</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
13
bundles/org.openhab.voice.picotts/NOTICE
Normal file
13
bundles/org.openhab.voice.picotts/NOTICE
Normal file
@@ -0,0 +1,13 @@
|
||||
This content is produced and maintained by the openHAB project.
|
||||
|
||||
* Project home: https://www.openhab.org
|
||||
|
||||
== Declared Project Licenses
|
||||
|
||||
This program and the accompanying materials are made available under the terms
|
||||
of the Eclipse Public License 2.0 which is available at
|
||||
https://www.eclipse.org/legal/epl-2.0/.
|
||||
|
||||
== Source Code
|
||||
|
||||
https://github.com/openhab/openhab-addons
|
||||
33
bundles/org.openhab.voice.picotts/README.md
Normal file
33
bundles/org.openhab.voice.picotts/README.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Pico Text-to-Speech
|
||||
|
||||
## Overview
|
||||
|
||||
The Pico Text-to-Speech (TTS) service uses the TTS binary from SVOX for producing spoken text.
|
||||
|
||||
You manually need to install the pico2wave binary in order for this service to work correctly. You can,
|
||||
e.g., install it with apt-get on an Ubuntu system:
|
||||
|
||||
```
|
||||
sudo apt-get install libttspico-utils
|
||||
```
|
||||
|
||||
In Arch Linux the pico2wave binaries are available in an Arch User repository (AUR) under
|
||||
https://aur.archlinux.org/packages/svox-pico-bin/
|
||||
|
||||
## Voices
|
||||
|
||||
The following list are the only supported languages (as these are the languages supported by
|
||||
pico2wave, see also [the documentation of the Debian package](https://packages.debian.org/de/wheezy/libttspico-utils)):
|
||||
|
||||
```
|
||||
German (de-DE)
|
||||
English, US (en-US)
|
||||
English, GB (en-GB)
|
||||
Spanish (es-ES)
|
||||
French (fr-FR)
|
||||
Italian (it-IT)
|
||||
```
|
||||
|
||||
## Supported Audio Formats
|
||||
|
||||
The Pico service produces audio streams using WAV containers and PCM (signed) codec with 16bit depth.
|
||||
17
bundles/org.openhab.voice.picotts/pom.xml
Normal file
17
bundles/org.openhab.voice.picotts/pom.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
|
||||
<version>3.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.voice.picotts</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: Voice :: Pico Text-to-Speech</name>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.voice.picotts-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
|
||||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
|
||||
|
||||
<feature name="openhab-voice-picotts" description="Pico Text-to-Speech" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.voice.picotts/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.voice.picotts.internal;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.openhab.core.audio.AudioException;
|
||||
import org.openhab.core.audio.AudioFormat;
|
||||
import org.openhab.core.audio.AudioStream;
|
||||
import org.openhab.core.audio.FixedLengthAudioStream;
|
||||
import org.openhab.core.voice.Voice;
|
||||
|
||||
/**
|
||||
* Implementation of {@link AudioStream} for {@link PicoTTSService}
|
||||
*
|
||||
* @author Florian Schmidt - Initial Contribution
|
||||
*/
|
||||
class PicoTTSAudioStream extends FixedLengthAudioStream {
|
||||
private final Voice voice;
|
||||
private final String text;
|
||||
private final AudioFormat audioFormat;
|
||||
private final InputStream inputStream;
|
||||
|
||||
private long length;
|
||||
private File file;
|
||||
|
||||
public PicoTTSAudioStream(String text, Voice voice, AudioFormat audioFormat) throws AudioException {
|
||||
this.text = text;
|
||||
this.voice = voice;
|
||||
this.audioFormat = audioFormat;
|
||||
this.inputStream = createInputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AudioFormat getFormat() {
|
||||
return audioFormat;
|
||||
}
|
||||
|
||||
private InputStream createInputStream() throws AudioException {
|
||||
String outputFile = generateOutputFilename();
|
||||
String[] command = getCommand(outputFile);
|
||||
|
||||
try {
|
||||
Process process = Runtime.getRuntime().exec(command);
|
||||
process.waitFor();
|
||||
file = new File(outputFile);
|
||||
this.length = file.length();
|
||||
return getFileInputStream(file);
|
||||
} catch (IOException e) {
|
||||
throw new AudioException("Error while executing '" + command + "'", e);
|
||||
} catch (InterruptedException e) {
|
||||
throw new AudioException("The '" + command + "' has been interrupted", e);
|
||||
}
|
||||
}
|
||||
|
||||
private InputStream getFileInputStream(File file) throws AudioException {
|
||||
if (file == null) {
|
||||
throw new IllegalArgumentException("file must not be null");
|
||||
}
|
||||
if (file.exists()) {
|
||||
try {
|
||||
return new FileInputStream(file);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new AudioException("Cannot open temporary audio file '" + file.getName() + ".");
|
||||
}
|
||||
} else {
|
||||
throw new AudioException("Temporary file '" + file.getName() + "' not found!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a unique, absolute output filename
|
||||
*
|
||||
* @return Unique, absolute output filename
|
||||
*/
|
||||
private String generateOutputFilename() throws AudioException {
|
||||
try {
|
||||
File tempFile = File.createTempFile(Integer.toString(text.hashCode()), ".wav");
|
||||
tempFile.deleteOnExit();
|
||||
return tempFile.getAbsolutePath();
|
||||
} catch (IOException e) {
|
||||
throw new AudioException("Unable to create temp file.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the command used to generate an audio file {@code outputFile}
|
||||
*
|
||||
* @param outputFile The absolute filename of the command's output
|
||||
* @return The command used to generate the audio file {@code outputFile}
|
||||
*/
|
||||
private String[] getCommand(String outputFile) {
|
||||
return new String[] { "pico2wave", "-l=" + this.voice.getLabel(), "-w=" + outputFile, this.text };
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return inputStream.read();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long length() {
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getClonedStream() throws AudioException {
|
||||
if (file != null) {
|
||||
return getFileInputStream(file);
|
||||
} else {
|
||||
throw new AudioException("No temporary audio file available.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.voice.picotts.internal;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.openhab.core.audio.AudioException;
|
||||
import org.openhab.core.audio.AudioFormat;
|
||||
import org.openhab.core.audio.AudioStream;
|
||||
import org.openhab.core.voice.TTSException;
|
||||
import org.openhab.core.voice.TTSService;
|
||||
import org.openhab.core.voice.Voice;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
|
||||
/**
|
||||
* @author Florian Schmidt - Initial Contribution
|
||||
*/
|
||||
@Component
|
||||
public class PicoTTSService implements TTSService {
|
||||
private final Set<Voice> voices = Stream
|
||||
.of(new PicoTTSVoice("de-DE"), new PicoTTSVoice("en-US"), new PicoTTSVoice("en-GB"),
|
||||
new PicoTTSVoice("es-ES"), new PicoTTSVoice("fr-FR"), new PicoTTSVoice("it-IT"))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
private final Set<AudioFormat> audioFormats = Collections.singleton(
|
||||
new AudioFormat(AudioFormat.CONTAINER_WAVE, AudioFormat.CODEC_PCM_SIGNED, false, 16, null, 16000L));
|
||||
|
||||
@Override
|
||||
public Set<Voice> getAvailableVoices() {
|
||||
return this.voices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<AudioFormat> getSupportedFormats() {
|
||||
return this.audioFormats;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AudioStream synthesize(String text, Voice voice, AudioFormat requestedFormat) throws TTSException {
|
||||
if (text == null || text.isEmpty()) {
|
||||
throw new TTSException("The passed text can not be null or empty");
|
||||
}
|
||||
|
||||
if (!this.voices.contains(voice)) {
|
||||
throw new TTSException("The passed voice is unsupported");
|
||||
}
|
||||
|
||||
boolean isAudioFormatSupported = this.audioFormats.stream().anyMatch(audioFormat -> {
|
||||
return audioFormat.isCompatible(requestedFormat);
|
||||
});
|
||||
|
||||
if (!isAudioFormatSupported) {
|
||||
throw new TTSException("The passed AudioFormat is unsupported");
|
||||
}
|
||||
|
||||
try {
|
||||
return new PicoTTSAudioStream(text, voice, requestedFormat);
|
||||
} catch (AudioException e) {
|
||||
throw new TTSException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "picotts";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel(Locale locale) {
|
||||
return "PicoTTS";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.voice.picotts.internal;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.openhab.core.voice.Voice;
|
||||
|
||||
/**
|
||||
* Implementation of the Voice interface for PicoTTS
|
||||
*
|
||||
* @author Florian Schmidt - Initial Contribution
|
||||
*/
|
||||
public class PicoTTSVoice implements Voice {
|
||||
private final String languageTag;
|
||||
|
||||
public PicoTTSVoice(String languageTag) {
|
||||
this.languageTag = languageTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUID() {
|
||||
return "picotts:" + languageTag.replaceAll("[^a-zA-Z0-9_]", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return languageTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return Locale.forLanguageTag(languageTag);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user