diff --git a/README.md b/README.md
index c64f9ce..b77ebfd 100644
--- a/README.md
+++ b/README.md
@@ -12,12 +12,14 @@ An easy-to-use local text to speech library for Java.
It can produce reasonable quality audio using low-specced hardware.
-It provides four main components
+It provides several components
-* Code to retrieve and run the voice models from the [piper](https://github.com/rhasspy/piper) project
+* Code to run the voice models from the [piper](https://github.com/rhasspy/piper) project
* A piper-compatible pure Java phonemizer for English partially ported from [phonemize](https://github.com/hans00/phonemize)
* Compatible phoneme dictionaries for uk and us English
* A multi-lingual phonemizer using the [onnx model](https://huggingface.co/OpenVoiceOS/g2p-mbyt5-12l-ipa-childes-espeak-onnx) from OpenVoiceOs
+* A small number of piper models available as dependencies on maven central
+* Code to download other models not uploaded to central
The models are run using the onnxruntime library, so can utilise both CPU and GPU.
@@ -25,22 +27,28 @@ The models are run using the onnxruntime library, so can utilise both CPU and GP
See [Releases](https://github.com/hcoles/voices/releases)
-## English-Only Usage
+## English-Only Usage With Rules Based Phonemizer
-Using Voices requires three dependencies
+Using Voices requires three code dependencies and one or more models.
```xml
org.pitest.voices
chorus
- 0.0.4
+ 0.0.5
+
+
+
+ org.pitest.voices
+ alba
+ 0.0.5
org.pitest.voices
en_uk
- 0.0.4
+ 0.0.5
@@ -50,7 +58,7 @@ Using Voices requires three dependencies
```
-Technically, Voices can be used without a dictionary, but the quality of the speech would be poor.
+Technically, the rules based phonemizer can be used without a dictionary, but the quality of the speech would be poor.
The `Chorus` class acts as a manager for voice models, handling loading and freeing of resources. Loading is an expensive
operation, so it is recommended to keep a single instance of `Chorus` for the lifetime of your application.
@@ -58,17 +66,33 @@ operation, so it is recommended to keep a single instance of `Chorus` for the li
```java
ChorusConfig config = chorusConfig(EnUkDictionary.en_uk());
try (Chorus chorus = new Chorus(config)) {
- Voice alba = chorus.voice(Models.albaMedium());
- Voice jenny = chorus.voice(Models.jennyDiocoMedium());
-
- Audio audio = alba.say("Hello there, I'm vaguely Scottish");
- audio = audio.append(jenny.say("I'm not."));
- audio = audio.append(alba.withGain(0.5f).say("I am much quieter"));
-
+ Voice alba = chorus.voice(Alba.albaMedium());
+
+ Audio audio = alba.say("Hello there, I'm vaguely Scottish.");
audio.save(some path);
}
```
+The example above uses a model retrieved at build time as a normal maven dependency.
+
+A wider range of models can be retrieved at runtime by adding the model downloader dependency.
+
+```xml
+
+ org.pitest.voices
+ model-downloader
+ 0.0.5
+
+```
+
+Models can be retrieved using the factory methods on the
+
+* org.pitest.voices.download.Models
+* org.pitest.voices.download.UsModels
+* org.pitest.voices.download.NonEnglishModels
+
+Classes.
+
By default, voice models are downloaded to `~/.cache/voices/`, but this can be configured in ChorusConfig.
## Multi-lingual Usage
diff --git a/alba/pom.xml b/alba/pom.xml
new file mode 100644
index 0000000..1e55ec7
--- /dev/null
+++ b/alba/pom.xml
@@ -0,0 +1,67 @@
+
+
+ 4.0.0
+
+
+ org.pitest.voices
+ voices-parent
+ ${revision}
+
+
+ alba
+ alba
+
+ jar
+
+
+
+ Apache 2
+ https://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+
+
+
+
+
+ org.pitest.voices
+ core
+ ${project.parent.version}
+
+
+ org.pitest.voices
+ alba-model
+ ${models.version}
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+
+
+
+
+
+
diff --git a/alba/src/main/java/org/pitest/voices/alba/Alba.java b/alba/src/main/java/org/pitest/voices/alba/Alba.java
new file mode 100644
index 0000000..3ce6bb4
--- /dev/null
+++ b/alba/src/main/java/org/pitest/voices/alba/Alba.java
@@ -0,0 +1,14 @@
+package org.pitest.voices.alba;
+
+import org.pitest.voices.ClassPathModel;
+import org.pitest.voices.Language;
+import org.pitest.voices.Model;
+
+public class Alba {
+
+ public static Model albaMedium() {
+ return new ClassPathModel("/models/vits-piper-en_GB-alba-medium/en_GB-alba-medium.onnx",
+ Language.en_GB,
+ 2.0f);
+ }
+}
diff --git a/alba/src/test/java/org/pitest/voices/alba/AlbaTest.java b/alba/src/test/java/org/pitest/voices/alba/AlbaTest.java
new file mode 100644
index 0000000..1d45663
--- /dev/null
+++ b/alba/src/test/java/org/pitest/voices/alba/AlbaTest.java
@@ -0,0 +1,31 @@
+package org.pitest.voices.alba;
+
+import org.junit.jupiter.api.Test;
+import org.pitest.voices.Language;
+import org.pitest.voices.Model;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class AlbaTest {
+
+ Model underTest = Alba.albaMedium();
+
+ @Test
+ void speaksProperEnglish() {
+ assertThat(underTest.language()).isEqualTo(Language.en_GB);
+ }
+
+
+ @Test
+ void loadsResources() throws IOException {
+ assertThat(underTest.asBytes(unused())).hasSizeGreaterThan(50000);
+ assertThat(underTest.resolveConfig(unused()).sampleRate()).isEqualTo(22050L);
+ }
+
+ private Path unused() {
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/bryce/pom.xml b/bryce/pom.xml
new file mode 100644
index 0000000..e476c09
--- /dev/null
+++ b/bryce/pom.xml
@@ -0,0 +1,67 @@
+
+
+ 4.0.0
+
+
+ org.pitest.voices
+ voices-parent
+ ${revision}
+
+
+ bryce
+ bryce
+
+ jar
+
+
+
+ Apache 2
+ https://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+
+
+
+
+
+ org.pitest.voices
+ core
+ ${project.parent.version}
+
+
+ org.pitest.voices
+ bryce-model
+ ${models.version}
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+
+
+
+
+
+
diff --git a/bryce/src/main/java/org/pitest/voices/bryce/Bryce.java b/bryce/src/main/java/org/pitest/voices/bryce/Bryce.java
new file mode 100644
index 0000000..b327b7b
--- /dev/null
+++ b/bryce/src/main/java/org/pitest/voices/bryce/Bryce.java
@@ -0,0 +1,14 @@
+package org.pitest.voices.bryce;
+
+import org.pitest.voices.ClassPathModel;
+import org.pitest.voices.Language;
+import org.pitest.voices.Model;
+
+public class Bryce {
+
+ public static Model bryceMedium() {
+ return new ClassPathModel("/models/vits-piper-en_US-bryce-medium/en_US-bryce-medium.onnx",
+ Language.en_US,
+ 1.0f);
+ }
+}
diff --git a/bryce/src/test/java/org/pitest/voices/bryce/BryceTest.java b/bryce/src/test/java/org/pitest/voices/bryce/BryceTest.java
new file mode 100644
index 0000000..ea7b9c2
--- /dev/null
+++ b/bryce/src/test/java/org/pitest/voices/bryce/BryceTest.java
@@ -0,0 +1,30 @@
+package org.pitest.voices.bryce;
+
+import org.junit.jupiter.api.Test;
+import org.pitest.voices.Language;
+import org.pitest.voices.Model;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class BryceTest {
+
+ Model underTest = Bryce.bryceMedium();
+
+ @Test
+ void speaksUSEnglish() {
+ assertThat(underTest.language()).isEqualTo(Language.en_US);
+ }
+
+ @Test
+ void loadsResources() throws IOException {
+ assertThat(underTest.asBytes(unused())).hasSizeGreaterThan(50000);
+ assertThat(underTest.resolveConfig(unused()).sampleRate()).isEqualTo(22050L);
+ }
+
+ private Path unused() {
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/chorus/pom.xml b/chorus/pom.xml
index f8a89fc..eb251b4 100644
--- a/chorus/pom.xml
+++ b/chorus/pom.xml
@@ -26,7 +26,7 @@
org.pitest.voices
- g2p
+ core
${project.parent.version}
@@ -36,12 +36,6 @@
2.5.5
-
- com.google.code.gson
- gson
- 2.13.2
-
-
com.microsoft.onnxruntime
onnxruntime
@@ -56,25 +50,19 @@
2.0.16
-
-
- me.tongfei
- progressbar
- 0.10.1
-
-
- org.apache.commons
- commons-compress
- 1.28.0
-
-
-
org.apache.commons
commons-text
1.14.0
test
+
+ org.pitest.voices
+ alba
+ ${project.parent.version}
+ test
+
+
diff --git a/chorus/src/main/java/org/pitest/voices/Chorus.java b/chorus/src/main/java/org/pitest/voices/Chorus.java
index d17b2ef..8310d83 100644
--- a/chorus/src/main/java/org/pitest/voices/Chorus.java
+++ b/chorus/src/main/java/org/pitest/voices/Chorus.java
@@ -3,13 +3,12 @@
import ai.onnxruntime.OrtEnvironment;
import ai.onnxruntime.OrtException;
import ai.onnxruntime.OrtSession;
-import org.pitest.g2p.core.Dictionary;
-import org.pitest.g2p.core.G2PModel;
-import org.pitest.g2p.core.PiperPhonemizer;
+import org.pitest.voices.g2p.core.Dictionary;
+import org.pitest.voices.g2p.core.G2PModel;
+import org.pitest.voices.g2p.core.PiperPhonemizer;
import java.io.IOException;
import java.nio.file.Files;
-import java.nio.file.Path;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -27,6 +26,9 @@ public class Chorus implements AutoCloseable {
// lazily initialised
private G2PModel g2p;
+ // lazily initialised, held only to allow closing
+ private OrtSession.SessionOptions opts;
+
public Chorus(Dictionary dictionary) {
this(new ChorusConfig(dictionary));
}
@@ -43,8 +45,8 @@ public Voice voice(Model model) {
phonemizer,
conf.trace(),
session,
- model.defaultPauses(),
- model.defaultParams(),
+ Pause.defaultPauses(),
+ ModelParameters.defaultParams(),
model.defaultGain());
}
@@ -59,17 +61,17 @@ private G2PModel g2p() {
private VoiceSession loadVoice(Model model) {
try {
Files.createDirectories(conf.base());
- return loadPiperModel(model, model.resolve(conf.base()));
+ return loadPiperModel(model);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
- private VoiceSession loadPiperModel(Model model, Path onnx) {
+ private VoiceSession loadPiperModel(Model model) {
OrtEnvironment env = OrtEnvironment.getEnvironment();
try {
var options = configureSession();
- var session = env.createSession(onnx.toString(), options);
+ var session = env.createSession(model.asBytes(conf.base()), options);
return new VoiceSession(env, model.resolveConfig(conf.base()), session);
} catch (IOException | OrtException e) {
throw new RuntimeException(e);
@@ -77,9 +79,9 @@ private VoiceSession loadPiperModel(Model model, Path onnx) {
}
private OrtSession.SessionOptions configureSession() {
- OrtSession.SessionOptions options = new OrtSession.SessionOptions();
- conf.cudaOptions().accept(options);
- return options;
+ OrtSession.SessionOptions options = new OrtSession.SessionOptions();
+ conf.cudaOptions().accept(options);
+ return options;
}
@Override
@@ -100,6 +102,14 @@ public void close() {
}
}
+ if (opts != null) {
+ try {
+ opts.close();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
}
}
diff --git a/chorus/src/main/java/org/pitest/voices/ChorusConfig.java b/chorus/src/main/java/org/pitest/voices/ChorusConfig.java
index 07a1db7..b74f33a 100644
--- a/chorus/src/main/java/org/pitest/voices/ChorusConfig.java
+++ b/chorus/src/main/java/org/pitest/voices/ChorusConfig.java
@@ -2,12 +2,12 @@
import ai.onnxruntime.OrtException;
import ai.onnxruntime.OrtSession;
-import org.pitest.g2p.core.EnglishModel;
-import org.pitest.g2p.core.Dictionary;
-import org.pitest.g2p.core.Expansion;
-import org.pitest.g2p.core.expansions.NumberExpander;
-import org.pitest.g2p.core.syllables.RulesSyllabiliser;
-import org.pitest.g2p.core.tracing.Trace;
+import org.pitest.voices.g2p.core.EnglishModel;
+import org.pitest.voices.g2p.core.Dictionary;
+import org.pitest.voices.g2p.core.Expansion;
+import org.pitest.voices.g2p.core.expansions.NumberExpander;
+import org.pitest.voices.g2p.core.syllables.RulesSyllabiliser;
+import org.pitest.voices.g2p.core.tracing.Trace;
import java.nio.file.Path;
import java.util.List;
diff --git a/chorus/src/main/java/org/pitest/voices/G2PModelSupplier.java b/chorus/src/main/java/org/pitest/voices/G2PModelSupplier.java
index 5d9d978..be48afb 100644
--- a/chorus/src/main/java/org/pitest/voices/G2PModelSupplier.java
+++ b/chorus/src/main/java/org/pitest/voices/G2PModelSupplier.java
@@ -2,8 +2,8 @@
import ai.onnxruntime.OrtEnvironment;
import ai.onnxruntime.OrtSession;
-import org.pitest.g2p.core.Dictionary;
-import org.pitest.g2p.core.G2PModel;
+import org.pitest.voices.g2p.core.Dictionary;
+import org.pitest.voices.g2p.core.G2PModel;
import java.nio.file.Path;
import java.util.function.Supplier;
diff --git a/chorus/src/main/java/org/pitest/voices/Pause.java b/chorus/src/main/java/org/pitest/voices/Pause.java
index c950edb..7715976 100644
--- a/chorus/src/main/java/org/pitest/voices/Pause.java
+++ b/chorus/src/main/java/org/pitest/voices/Pause.java
@@ -1,9 +1,18 @@
package org.pitest.voices;
+import java.util.List;
+
public record Pause(String symbol, int beats) {
public boolean matches(String symbol) {
return this.symbol.equals(symbol);
}
+ public static List defaultPauses() {
+ return List.of(new Pause("—", 3),
+ new Pause("–", 2),
+ new Pause(":", 2)
+ );
+ }
+
}
diff --git a/chorus/src/main/java/org/pitest/voices/PiperVoice.java b/chorus/src/main/java/org/pitest/voices/PiperVoice.java
index 3f9d90b..d6829ef 100644
--- a/chorus/src/main/java/org/pitest/voices/PiperVoice.java
+++ b/chorus/src/main/java/org/pitest/voices/PiperVoice.java
@@ -2,9 +2,8 @@
import opennlp.tools.sentdetect.SentenceDetectorME;
import opennlp.tools.sentdetect.SentenceModel;
-import org.pitest.g2p.core.PiperPhonemizer;
-import org.pitest.g2p.core.tracing.Trace;
-import org.pitest.g2p.util.Resource;
+import org.pitest.voices.g2p.core.PiperPhonemizer;
+import org.pitest.voices.g2p.core.tracing.Trace;
import org.pitest.voices.audio.Audio;
diff --git a/chorus/src/test/java/org/pitest/voices/ChorusTest.java b/chorus/src/test/java/org/pitest/voices/ChorusTest.java
index 51142f9..242ab77 100644
--- a/chorus/src/test/java/org/pitest/voices/ChorusTest.java
+++ b/chorus/src/test/java/org/pitest/voices/ChorusTest.java
@@ -1,16 +1,11 @@
package org.pitest.voices;
import org.junit.jupiter.api.Test;
-import org.pitest.g2p.core.Dictionary;
-import org.pitest.g2p.core.EnglishModel;
-import org.pitest.g2p.core.PiperPhonemizer;
-import org.pitest.g2p.core.expansions.NumberExpander;
-import org.pitest.g2p.core.tracing.LoggingTrace;
-import org.pitest.g2p.core.tracing.Trace;
+import org.pitest.voices.alba.Alba;
+import org.pitest.voices.g2p.core.Dictionary;
+import org.pitest.voices.g2p.core.tracing.LoggingTrace;
import org.pitest.voices.audio.Audio;
-import java.util.List;
-
import static org.assertj.core.api.Assertions.assertThat;
import static org.pitest.voices.ChorusConfig.chorusConfig;
import static org.pitest.voices.util.Play.play;
@@ -28,7 +23,7 @@ class ChorusTest {
void someWords() {
try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(Models.aru(4));
+ Voice v1 = chorus.voice(Alba.albaMedium());
Audio audio = v1.say("A rainbow is a meteorological phenomenon that is caused by reflection, " +
"refraction and dispersion of light in water droplets resulting in a spectrum of light appearing in the sky.");
@@ -41,7 +36,7 @@ void someWords() {
@Test
void numbers() {
try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(Models.albaMedium());
+ Voice v1 = chorus.voice(Alba.albaMedium());
Audio audio = v1.say("The year is 2025");
@@ -52,7 +47,7 @@ void numbers() {
@Test
void dashes() {
try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(Models.albaMedium());
+ Voice v1 = chorus.voice(Alba.albaMedium());
Audio audio = v1.say("It wasn't meant for visitors like this one---low and insignificant.");
play(audio);
diff --git a/chorus/src/test/java/org/pitest/voices/ModelConfigTest.java b/chorus/src/test/java/org/pitest/voices/ModelConfigTest.java
index 31950ba..45b153e 100644
--- a/chorus/src/test/java/org/pitest/voices/ModelConfigTest.java
+++ b/chorus/src/test/java/org/pitest/voices/ModelConfigTest.java
@@ -1,12 +1,10 @@
package org.pitest.voices;
import org.junit.jupiter.api.Test;
-import org.pitest.g2p.util.Resource;
import java.io.InputStream;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.*;
class ModelConfigTest {
diff --git a/chorus/src/test/java/org/pitest/voices/util/Fetch.java b/chorus/src/test/java/org/pitest/voices/util/Fetch.java
index 458a740..88ae571 100644
--- a/chorus/src/test/java/org/pitest/voices/util/Fetch.java
+++ b/chorus/src/test/java/org/pitest/voices/util/Fetch.java
@@ -1,8 +1,5 @@
package org.pitest.voices.util;
-import me.tongfei.progressbar.ProgressBar;
-import me.tongfei.progressbar.ProgressBarBuilder;
-
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
@@ -29,12 +26,10 @@ public Path fetch(URL url, String name) throws IOException {
URLConnection urlConn = url.openConnection();
long size = urlConn.getContentLengthLong();
- ProgressBarBuilder pbb = new ProgressBarBuilder();
- pbb.setTaskName("Fetching ");
- pbb.setInitialMax(size);
+
ReadableByteChannel readableByteChannel = Channels
- .newChannel(ProgressBar.wrap(urlConn.getInputStream(), pbb));
+ .newChannel(urlConn.getInputStream());
try(FileOutputStream fileOutputStream = new FileOutputStream(archive.toFile())) {
FileChannel fileChannel = fileOutputStream.getChannel();
diff --git a/core/pom.xml b/core/pom.xml
new file mode 100644
index 0000000..69bd50c
--- /dev/null
+++ b/core/pom.xml
@@ -0,0 +1,66 @@
+
+
+ 4.0.0
+
+
+ org.pitest.voices
+ voices-parent
+ ${revision}
+
+
+ core
+ core
+
+ jar
+
+
+
+ Apache 2
+ https://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+
+
+
+
+ org.pitest.voices
+ g2p
+ ${project.parent.version}
+
+
+
+ com.google.code.gson
+ gson
+ 2.13.2
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+
+
+
+
+
+
diff --git a/core/src/main/java/org/pitest/voices/ClassPathModel.java b/core/src/main/java/org/pitest/voices/ClassPathModel.java
new file mode 100644
index 0000000..21513a7
--- /dev/null
+++ b/core/src/main/java/org/pitest/voices/ClassPathModel.java
@@ -0,0 +1,62 @@
+package org.pitest.voices;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+public class ClassPathModel implements Model {
+
+ private final String resource;
+ private final Language lang;
+ private final int sid;
+ private final float gain;
+
+
+ public ClassPathModel(String resource, Language lang, float gain) {
+ this(resource, lang, -1, gain);
+ }
+
+ public ClassPathModel(String resource, Language lang, int sid, float gain) {
+ this.resource = resource;
+ this.lang = lang;
+ this.sid = sid;
+ this.gain = gain;
+ }
+
+ @Override
+ public byte[] asBytes(Path cacheBase) {
+ return Resource.readAsBytes(resource);
+ }
+
+ @Override
+ public ModelConfig resolveConfig(Path cacheBase) throws IOException {
+ try (var is = Resource.readAsStream(resource + ".json")) {
+ return ModelConfig.fromJson(is);
+ }
+ }
+
+ @Override
+ public String id() {
+ return resource;
+ }
+
+ @Override
+ public int sid() {
+ return sid;
+ }
+
+ @Override
+ public Language language() {
+ return lang;
+ }
+
+ @Override
+ public Model withLanguage(Language lang) {
+ return new ClassPathModel(resource, lang, sid, gain);
+ }
+
+ @Override
+ public float defaultGain() {
+ return gain;
+ }
+
+}
diff --git a/core/src/main/java/org/pitest/voices/Model.java b/core/src/main/java/org/pitest/voices/Model.java
new file mode 100644
index 0000000..3ccd03a
--- /dev/null
+++ b/core/src/main/java/org/pitest/voices/Model.java
@@ -0,0 +1,59 @@
+package org.pitest.voices;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+/**
+ * Piper tts model
+ */
+public interface Model {
+
+ /**
+ * Unique id
+ * @return an id
+ */
+ String id();
+
+ /**
+ * Speaker id
+ * @return speaker id or -1 if model doesn't support them
+ */
+ int sid();
+
+ /**
+ * Language model speaks
+ * @return A language instance
+ */
+ Language language();
+
+ /**
+ * Creates a variation of the model with a different language
+ * @param lang Language to use
+ * @return a new model instance
+ */
+ Model withLanguage(Language lang);
+
+ /**
+ * The model in bytes
+ * @param cacheBase Directory currently used by Voices for any caches
+ * @return Model as bytes
+ * @throws IOException in event of error
+ */
+ byte[] asBytes(Path cacheBase) throws IOException;
+
+ /**
+ * The model config
+ * @param cacheBase Directory currently used by Voices for any caches
+ * @return Model config
+ * @throws IOException in event of error
+ */
+ ModelConfig resolveConfig(Path cacheBase) throws IOException;
+
+ /**
+ * Default gain to use with this model. Useful as some models
+ * appear much louder or quieter than others
+ * @return float representing the default gain
+ */
+ float defaultGain();
+
+}
diff --git a/chorus/src/main/java/org/pitest/voices/ModelConfig.java b/core/src/main/java/org/pitest/voices/ModelConfig.java
similarity index 100%
rename from chorus/src/main/java/org/pitest/voices/ModelConfig.java
rename to core/src/main/java/org/pitest/voices/ModelConfig.java
diff --git a/core/src/main/java/org/pitest/voices/Resource.java b/core/src/main/java/org/pitest/voices/Resource.java
new file mode 100644
index 0000000..005b086
--- /dev/null
+++ b/core/src/main/java/org/pitest/voices/Resource.java
@@ -0,0 +1,40 @@
+package org.pitest.voices;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UncheckedIOException;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class Resource {
+
+ public static byte[] readAsBytes(String resource) {
+ try (InputStream is = readAsStream(resource)) {
+ return is.readAllBytes();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public static List read(String resource) {
+ try (InputStream is = readAsStream(resource);
+ InputStreamReader inputStreamReader = new InputStreamReader(is, StandardCharsets.UTF_8);
+ BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
+ return bufferedReader.lines()
+ .collect(Collectors.toList());
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public static InputStream readAsStream(String resource) {
+ var stream = Resource.class.getResourceAsStream(resource);
+ if (stream == null) {
+ throw new IllegalStateException("Could not find resource " + resource);
+ }
+ return stream;
+ }
+}
diff --git a/cori/pom.xml b/cori/pom.xml
new file mode 100644
index 0000000..60a36df
--- /dev/null
+++ b/cori/pom.xml
@@ -0,0 +1,67 @@
+
+
+ 4.0.0
+
+
+ org.pitest.voices
+ voices-parent
+ ${revision}
+
+
+ cori
+ cori
+
+ jar
+
+
+
+ Apache 2
+ https://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+
+
+
+
+
+ org.pitest.voices
+ core
+ ${project.parent.version}
+
+
+ org.pitest.voices
+ cori-model
+ ${models.version}
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+
+
+
+
+
+
diff --git a/cori/src/main/java/org/pitest/voices/cori/Cori.java b/cori/src/main/java/org/pitest/voices/cori/Cori.java
new file mode 100644
index 0000000..038ac92
--- /dev/null
+++ b/cori/src/main/java/org/pitest/voices/cori/Cori.java
@@ -0,0 +1,14 @@
+package org.pitest.voices.cori;
+
+import org.pitest.voices.ClassPathModel;
+import org.pitest.voices.Language;
+import org.pitest.voices.Model;
+
+public class Cori {
+
+ public static Model coriHigh() {
+ return new ClassPathModel("/models/vits-piper-en_GB-cori-high/en_GB-cori-high.onnx",
+ Language.en_GB,
+ 1.0f);
+ }
+}
diff --git a/cori/src/test/java/org/pitest/voices/cori/CoriTest.java b/cori/src/test/java/org/pitest/voices/cori/CoriTest.java
new file mode 100644
index 0000000..d12232c
--- /dev/null
+++ b/cori/src/test/java/org/pitest/voices/cori/CoriTest.java
@@ -0,0 +1,30 @@
+package org.pitest.voices.cori;
+
+import org.junit.jupiter.api.Test;
+import org.pitest.voices.Language;
+import org.pitest.voices.Model;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class CoriTest {
+
+ Model underTest = Cori.coriHigh();
+
+ @Test
+ void speaksProperEnglish() {
+ assertThat(underTest.language()).isEqualTo(Language.en_GB);
+ }
+
+ @Test
+ void loadsResources() throws IOException {
+ assertThat(underTest.asBytes(unused())).hasSizeGreaterThan(50000);
+ assertThat(underTest.resolveConfig(unused()).sampleRate()).isEqualTo(22050L);
+ }
+
+ private Path unused() {
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/en_uk/pom.xml b/en_uk/pom.xml
index 0dbc1e2..76a2ae2 100644
--- a/en_uk/pom.xml
+++ b/en_uk/pom.xml
@@ -29,7 +29,11 @@
g2p
${project.parent.version}
-
+
+ org.pitest.voices
+ core
+ ${project.parent.version}
+
com.microsoft.onnxruntime
@@ -44,6 +48,18 @@
${project.parent.version}
test
+
+ org.pitest.voices
+ alba
+ ${project.parent.version}
+ test
+
+
+ org.pitest.voices
+ cori
+ ${project.parent.version}
+ test
+
org.pitest.voices
chorus
diff --git a/en_uk/src/main/java/org/pitest/voices/uk/EnUkDictionary.java b/en_uk/src/main/java/org/pitest/voices/uk/EnUkDictionary.java
index b72b6f7..f5926d5 100644
--- a/en_uk/src/main/java/org/pitest/voices/uk/EnUkDictionary.java
+++ b/en_uk/src/main/java/org/pitest/voices/uk/EnUkDictionary.java
@@ -1,8 +1,8 @@
package org.pitest.voices.uk;
-import org.pitest.g2p.core.Dictionary;
+import org.pitest.voices.g2p.core.Dictionary;
-import static org.pitest.g2p.util.Resource.read;
+import static org.pitest.voices.Resource.read;
public class EnUkDictionary {
public static Dictionary en_uk() {
diff --git a/en_uk/src/test/java/org/pitest/voices/dictionary/DictionaryGenerator.java b/en_uk/src/test/java/org/pitest/voices/dictionary/DictionaryGenerator.java
index 6b20a98..c27d5a5 100644
--- a/en_uk/src/test/java/org/pitest/voices/dictionary/DictionaryGenerator.java
+++ b/en_uk/src/test/java/org/pitest/voices/dictionary/DictionaryGenerator.java
@@ -1,7 +1,7 @@
package org.pitest.voices.dictionary;
-import org.pitest.g2p.core.Dictionary;
-import org.pitest.g2p.util.Resource;
+import org.pitest.voices.g2p.core.Dictionary;
+import org.pitest.voices.Resource;
import org.pitest.voices.ChorusConfig;
import org.pitest.voices.util.Fetch;
diff --git a/en_uk/src/test/java/org/pitest/voices/dictionary/Homographs.java b/en_uk/src/test/java/org/pitest/voices/dictionary/Homographs.java
index 163fa78..4189289 100644
--- a/en_uk/src/test/java/org/pitest/voices/dictionary/Homographs.java
+++ b/en_uk/src/test/java/org/pitest/voices/dictionary/Homographs.java
@@ -1,11 +1,11 @@
package org.pitest.voices.dictionary;
-import org.pitest.g2p.core.Dictionary;
-import org.pitest.g2p.core.EnglishModel;
-import org.pitest.g2p.core.Language;
-import org.pitest.g2p.core.PiperPhonemizer;
-import org.pitest.g2p.core.pos.Pos;
-import org.pitest.g2p.core.tracing.Trace;
+import org.pitest.voices.Language;
+import org.pitest.voices.g2p.core.Dictionary;
+import org.pitest.voices.g2p.core.EnglishModel;
+import org.pitest.voices.g2p.core.PiperPhonemizer;
+import org.pitest.voices.g2p.core.pos.Pos;
+import org.pitest.voices.g2p.core.tracing.Trace;
import org.pitest.voices.ChorusConfig;
import java.io.IOException;
diff --git a/en_uk/src/test/java/org/pitest/voices/uk/TryItOutTest.java b/en_uk/src/test/java/org/pitest/voices/uk/TryItOutTest.java
index 73a8a43..ae7862a 100644
--- a/en_uk/src/test/java/org/pitest/voices/uk/TryItOutTest.java
+++ b/en_uk/src/test/java/org/pitest/voices/uk/TryItOutTest.java
@@ -1,11 +1,12 @@
package org.pitest.voices.uk;
import org.junit.jupiter.api.Test;
-import org.pitest.g2p.core.tracing.LoggingTrace;
-import org.pitest.g2p.util.Resource;
+import org.pitest.voices.alba.Alba;
+import org.pitest.voices.cori.Cori;
+import org.pitest.voices.g2p.core.tracing.LoggingTrace;
+import org.pitest.voices.Resource;
import org.pitest.voices.Chorus;
import org.pitest.voices.ChorusConfig;
-import org.pitest.voices.Models;
import org.pitest.voices.Pause;
import org.pitest.voices.Voice;
import org.pitest.voices.audio.Audio;
@@ -23,7 +24,7 @@ public class TryItOutTest {
@Test
void orwell() {
try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(Models.albaMedium());
+ Voice v1 = chorus.voice(Alba.albaMedium());
var audio = v1.say("It was a bright cold day in April, and the clocks were striking thirteen.");
play(audio);
}
@@ -32,7 +33,7 @@ void orwell() {
@Test
void mobyDick() {
try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(Models.albaMedium());
+ Voice v1 = chorus.voice(Alba.albaMedium());
String text = String.join("\n", Resource.read("/samples/moby_dick.md"));
Audio audio = v1.say(text);
@@ -40,22 +41,10 @@ void mobyDick() {
}
}
- @Test
- void aWord() {
- try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(Models.albaMedium());
- Voice v2 = chorus.voice(Models.alanMedium());
- Voice v3 = chorus.voice(Models.northernEnglishMale());
- play(v1.say("abbreviated"));
- play(v2.say("abbreviated"));
- play(v3.say("abbreviated"));
- }
- }
-
@Test
void wutheringHeights() {
try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(Models.coriHigh())
+ Voice v1 = chorus.voice(Cori.coriHigh())
.withPauses(List.of(new Pause(",", 6)));
String text = String.join("\n", Resource.read("/samples/wuthering_heights.md"));
Audio audio = v1.say(text);
@@ -66,7 +55,7 @@ void wutheringHeights() {
@Test
void dashes() {
try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(Models.albaMedium());
+ Voice v1 = chorus.voice(Alba.albaMedium());
Audio audio = v1.say("It wasn't meant for visitors like this one---low and insignificant.");
play(audio);
@@ -78,7 +67,7 @@ void dashes() {
void homographs() {
try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(Models.albaMedium());
+ Voice v1 = chorus.voice(Alba.albaMedium());
Audio audio = v1.say(
"invalid response for an invalid. " +
@@ -100,7 +89,7 @@ void homographs() {
@Test
void rainbows() {
try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(Models.albaMedium());
+ Voice v1 = chorus.voice(Alba.albaMedium());
Audio audio = v1.say("A rainbow is a meteorological phenomenon that is caused by reflection, " +
"refraction and dispersion of light in water droplets resulting in a spectrum of light appearing in the sky.");
@@ -112,7 +101,7 @@ void rainbows() {
void hyphens() {
try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(Models.albaMedium());
+ Voice v1 = chorus.voice(Alba.albaMedium());
Audio audio = v1.say("anti-theft---a security term---device");
play(audio);
}
@@ -123,12 +112,12 @@ void hyphens() {
void normalise() {
String text = "This is a sentence";
try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(Models.albaMedium());
+ Voice v1 = chorus.voice(Alba.albaMedium());
Audio reference = v1.say(text);
float max = reference.max();
for (float gain = 0.7f; gain < 5.0f; gain += 0.1f) {
- var v2 = chorus.voice(Models.coriHigh())
+ var v2 = chorus.voice(Cori.coriHigh())
.withGain(gain)
.say(text);
System.out.println("Testing gain " + gain + " for max " + max + " got " + v2.max());
diff --git a/en_us/pom.xml b/en_us/pom.xml
index a64f445..bc3d6ad 100644
--- a/en_us/pom.xml
+++ b/en_us/pom.xml
@@ -43,6 +43,19 @@
${project.parent.version}
test
+
+
+ org.pitest.voices
+ alba
+ ${project.parent.version}
+ test
+
+
+ org.pitest.voices
+ bryce
+ ${project.parent.version}
+ test
+
org.pitest.voices
chorus
diff --git a/en_us/src/main/java/org/pitest/voices/us/EnUsDictionary.java b/en_us/src/main/java/org/pitest/voices/us/EnUsDictionary.java
index 074aa25..38ff0c5 100644
--- a/en_us/src/main/java/org/pitest/voices/us/EnUsDictionary.java
+++ b/en_us/src/main/java/org/pitest/voices/us/EnUsDictionary.java
@@ -1,8 +1,9 @@
package org.pitest.voices.us;
-import org.pitest.g2p.core.Dictionary;
+import org.pitest.voices.g2p.core.Dictionary;
+
+import static org.pitest.voices.g2p.util.Resource.read;
-import static org.pitest.g2p.util.Resource.read;
public class EnUsDictionary {
public static Dictionary en_us() {
diff --git a/en_us/src/test/java/org/pitest/voices/us/ConvertCMU.java b/en_us/src/test/java/org/pitest/voices/us/ConvertCMU.java
index e174342..aeebe18 100644
--- a/en_us/src/test/java/org/pitest/voices/us/ConvertCMU.java
+++ b/en_us/src/test/java/org/pitest/voices/us/ConvertCMU.java
@@ -1,6 +1,6 @@
package org.pitest.voices.us;
-import org.pitest.g2p.core.Dictionary;
+import org.pitest.voices.g2p.core.Dictionary;
import org.pitest.voices.ChorusConfig;
import org.pitest.voices.util.Fetch;
diff --git a/en_us/src/test/java/org/pitest/voices/us/TryItOutTest.java b/en_us/src/test/java/org/pitest/voices/us/TryItOutTest.java
index 6e61719..74e93c1 100644
--- a/en_us/src/test/java/org/pitest/voices/us/TryItOutTest.java
+++ b/en_us/src/test/java/org/pitest/voices/us/TryItOutTest.java
@@ -2,12 +2,12 @@
import org.junit.jupiter.api.Test;
-import org.pitest.g2p.core.tracing.LoggingTrace;
-import org.pitest.g2p.util.Resource;
+import org.pitest.voices.alba.Alba;
+import org.pitest.voices.bryce.Bryce;
+import org.pitest.voices.g2p.core.tracing.LoggingTrace;
+import org.pitest.voices.Resource;
import org.pitest.voices.Chorus;
import org.pitest.voices.ChorusConfig;
-import org.pitest.voices.Models;
-import org.pitest.voices.UsModels;
import org.pitest.voices.Voice;
import org.pitest.voices.audio.Audio;
@@ -22,7 +22,7 @@ public class TryItOutTest {
@Test
void gibson() {
try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(UsModels.bryceMedium()).withLengthScale(0.7f);
+ Voice v1 = chorus.voice(Bryce.bryceMedium()).withLengthScale(0.7f);
var audio = v1.say("The sky above the port was the color of television, tuned to a dead channel.");
play(audio);
}
@@ -31,7 +31,7 @@ void gibson() {
@Test
void huckleberryFinn() {
try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(Models.albaMedium()).withLengthScale(0.5f);
+ Voice v1 = chorus.voice(Alba.albaMedium()).withLengthScale(0.5f);
String text = String.join("\n", Resource.read("/samples/huckleberry_finn.md"));
Audio audio = v1.say(text);
@@ -42,7 +42,7 @@ void huckleberryFinn() {
@Test
void aWord() {
try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(Models.albaMedium());
+ Voice v1 = chorus.voice(Alba.albaMedium());
Audio audio = v1.say("abbreviated");
play(audio);
}
@@ -51,7 +51,7 @@ void aWord() {
@Test
void someWords() {
try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(Models.albaMedium());
+ Voice v1 = chorus.voice(Alba.albaMedium());
Audio audio = v1.say("usurped\n" +
"usurping\n" +
"usurps\n" +
@@ -98,7 +98,7 @@ void someWords() {
void homographs() {
try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(Models.albaMedium());
+ Voice v1 = chorus.voice(Alba.albaMedium());
Audio audio = v1.say(
"invalid response for an invalid. " +
diff --git a/g2p/src/main/java/org/pitest/g2p/core/NoModel.java b/g2p/src/main/java/org/pitest/g2p/core/NoModel.java
deleted file mode 100644
index 64ac4ce..0000000
--- a/g2p/src/main/java/org/pitest/g2p/core/NoModel.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.pitest.g2p.core;
-
-
-import org.pitest.g2p.core.pos.Pos;
-import org.pitest.g2p.core.tracing.Trace;
-
-public class NoModel implements G2PModel {
-
- @Override
- public String predict(Trace trace, Language lang, String word, Pos pos) {
- return null;
- }
-
- @Override
- public void close() throws Exception {
- // no op
- }
-
-}
diff --git a/g2p/src/main/java/org/pitest/g2p/core/Language.java b/g2p/src/main/java/org/pitest/voices/Language.java
similarity index 97%
rename from g2p/src/main/java/org/pitest/g2p/core/Language.java
rename to g2p/src/main/java/org/pitest/voices/Language.java
index e529a85..672e25b 100644
--- a/g2p/src/main/java/org/pitest/g2p/core/Language.java
+++ b/g2p/src/main/java/org/pitest/voices/Language.java
@@ -1,4 +1,4 @@
-package org.pitest.g2p.core;
+package org.pitest.voices;
public enum Language {
ca_ES("Catalan"),
diff --git a/g2p/src/main/java/org/pitest/g2p/core/Dictionary.java b/g2p/src/main/java/org/pitest/voices/g2p/core/Dictionary.java
similarity index 96%
rename from g2p/src/main/java/org/pitest/g2p/core/Dictionary.java
rename to g2p/src/main/java/org/pitest/voices/g2p/core/Dictionary.java
index 06aeee1..74a72c4 100644
--- a/g2p/src/main/java/org/pitest/g2p/core/Dictionary.java
+++ b/g2p/src/main/java/org/pitest/voices/g2p/core/Dictionary.java
@@ -1,6 +1,6 @@
-package org.pitest.g2p.core;
+package org.pitest.voices.g2p.core;
-import org.pitest.g2p.core.pos.Pos;
+import org.pitest.voices.g2p.core.pos.Pos;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@@ -14,7 +14,6 @@
import java.util.Set;
import static java.util.Collections.emptyMap;
-import static org.pitest.g2p.util.Resource.read;
public class Dictionary {
diff --git a/g2p/src/main/java/org/pitest/g2p/core/EnglishModel.java b/g2p/src/main/java/org/pitest/voices/g2p/core/EnglishModel.java
similarity index 99%
rename from g2p/src/main/java/org/pitest/g2p/core/EnglishModel.java
rename to g2p/src/main/java/org/pitest/voices/g2p/core/EnglishModel.java
index 7c63175..38ec6d2 100644
--- a/g2p/src/main/java/org/pitest/g2p/core/EnglishModel.java
+++ b/g2p/src/main/java/org/pitest/voices/g2p/core/EnglishModel.java
@@ -1,8 +1,9 @@
-package org.pitest.g2p.core;
+package org.pitest.voices.g2p.core;
-import org.pitest.g2p.core.pos.Pos;
-import org.pitest.g2p.core.tracing.Trace;
-import org.pitest.g2p.core.syllables.RulesSyllabiliser;
+import org.pitest.voices.Language;
+import org.pitest.voices.g2p.core.pos.Pos;
+import org.pitest.voices.g2p.core.tracing.Trace;
+import org.pitest.voices.g2p.core.syllables.RulesSyllabiliser;
import java.util.ArrayList;
import java.util.Arrays;
@@ -13,8 +14,8 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import static org.pitest.g2p.util.English.CONSONANTS;
-import static org.pitest.g2p.util.English.VOWELS;
+import static org.pitest.voices.g2p.util.English.CONSONANTS;
+import static org.pitest.voices.g2p.util.English.VOWELS;
/**
* Phonemization model for English. Largely uses a dictionary, but falls back to a rules
diff --git a/g2p/src/main/java/org/pitest/g2p/core/Expansion.java b/g2p/src/main/java/org/pitest/voices/g2p/core/Expansion.java
similarity index 64%
rename from g2p/src/main/java/org/pitest/g2p/core/Expansion.java
rename to g2p/src/main/java/org/pitest/voices/g2p/core/Expansion.java
index 4c6b747..d432655 100644
--- a/g2p/src/main/java/org/pitest/g2p/core/Expansion.java
+++ b/g2p/src/main/java/org/pitest/voices/g2p/core/Expansion.java
@@ -1,4 +1,4 @@
-package org.pitest.g2p.core;
+package org.pitest.voices.g2p.core;
public interface Expansion {
String expand(String text);
diff --git a/g2p/src/main/java/org/pitest/g2p/core/G2PModel.java b/g2p/src/main/java/org/pitest/voices/g2p/core/G2PModel.java
similarity index 73%
rename from g2p/src/main/java/org/pitest/g2p/core/G2PModel.java
rename to g2p/src/main/java/org/pitest/voices/g2p/core/G2PModel.java
index 7b6490c..e077f33 100644
--- a/g2p/src/main/java/org/pitest/g2p/core/G2PModel.java
+++ b/g2p/src/main/java/org/pitest/voices/g2p/core/G2PModel.java
@@ -1,7 +1,8 @@
-package org.pitest.g2p.core;
+package org.pitest.voices.g2p.core;
-import org.pitest.g2p.core.pos.Pos;
-import org.pitest.g2p.core.tracing.Trace;
+import org.pitest.voices.Language;
+import org.pitest.voices.g2p.core.pos.Pos;
+import org.pitest.voices.g2p.core.tracing.Trace;
public interface G2PModel extends AutoCloseable {
diff --git a/g2p/src/main/java/org/pitest/g2p/core/PiperPhonemizer.java b/g2p/src/main/java/org/pitest/voices/g2p/core/PiperPhonemizer.java
similarity index 92%
rename from g2p/src/main/java/org/pitest/g2p/core/PiperPhonemizer.java
rename to g2p/src/main/java/org/pitest/voices/g2p/core/PiperPhonemizer.java
index 2bce564..dc8f087 100644
--- a/g2p/src/main/java/org/pitest/g2p/core/PiperPhonemizer.java
+++ b/g2p/src/main/java/org/pitest/voices/g2p/core/PiperPhonemizer.java
@@ -1,10 +1,11 @@
-package org.pitest.g2p.core;
+package org.pitest.voices.g2p.core;
import opennlp.tools.tokenize.SimpleTokenizer;
-import org.pitest.g2p.core.pos.POSToken;
-import org.pitest.g2p.core.pos.Pos;
-import org.pitest.g2p.core.pos.SimplePOSTagger;
-import org.pitest.g2p.core.tracing.Trace;
+import org.pitest.voices.Language;
+import org.pitest.voices.g2p.core.pos.POSToken;
+import org.pitest.voices.g2p.core.pos.Pos;
+import org.pitest.voices.g2p.core.pos.SimplePOSTagger;
+import org.pitest.voices.g2p.core.tracing.Trace;
import java.io.IOException;
import java.util.ArrayList;
@@ -12,7 +13,7 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import static org.pitest.g2p.core.pos.SimplePOSTagger.makeTagger;
+import static org.pitest.voices.g2p.core.pos.SimplePOSTagger.makeTagger;
public class PiperPhonemizer {
diff --git a/g2p/src/main/java/org/pitest/g2p/core/WordToSyllables.java b/g2p/src/main/java/org/pitest/voices/g2p/core/WordToSyllables.java
similarity index 74%
rename from g2p/src/main/java/org/pitest/g2p/core/WordToSyllables.java
rename to g2p/src/main/java/org/pitest/voices/g2p/core/WordToSyllables.java
index 05d064d..242f0a1 100644
--- a/g2p/src/main/java/org/pitest/g2p/core/WordToSyllables.java
+++ b/g2p/src/main/java/org/pitest/voices/g2p/core/WordToSyllables.java
@@ -1,4 +1,4 @@
-package org.pitest.g2p.core;
+package org.pitest.voices.g2p.core;
import java.util.List;
diff --git a/g2p/src/main/java/org/pitest/g2p/core/expansions/NumberExpander.java b/g2p/src/main/java/org/pitest/voices/g2p/core/expansions/NumberExpander.java
similarity index 99%
rename from g2p/src/main/java/org/pitest/g2p/core/expansions/NumberExpander.java
rename to g2p/src/main/java/org/pitest/voices/g2p/core/expansions/NumberExpander.java
index b2e40b7..0581a2b 100644
--- a/g2p/src/main/java/org/pitest/g2p/core/expansions/NumberExpander.java
+++ b/g2p/src/main/java/org/pitest/voices/g2p/core/expansions/NumberExpander.java
@@ -1,6 +1,6 @@
-package org.pitest.g2p.core.expansions;
+package org.pitest.voices.g2p.core.expansions;
-import org.pitest.g2p.core.Expansion;
+import org.pitest.voices.g2p.core.Expansion;
import java.util.HashMap;
import java.util.Map;
diff --git a/g2p/src/main/java/org/pitest/g2p/core/pos/POSToken.java b/g2p/src/main/java/org/pitest/voices/g2p/core/pos/POSToken.java
similarity index 55%
rename from g2p/src/main/java/org/pitest/g2p/core/pos/POSToken.java
rename to g2p/src/main/java/org/pitest/voices/g2p/core/pos/POSToken.java
index c907a9c..04998d2 100644
--- a/g2p/src/main/java/org/pitest/g2p/core/pos/POSToken.java
+++ b/g2p/src/main/java/org/pitest/voices/g2p/core/pos/POSToken.java
@@ -1,4 +1,4 @@
-package org.pitest.g2p.core.pos;
+package org.pitest.voices.g2p.core.pos;
public record POSToken(String word, Pos pos) {
diff --git a/g2p/src/main/java/org/pitest/g2p/core/pos/Pos.java b/g2p/src/main/java/org/pitest/voices/g2p/core/pos/Pos.java
similarity index 98%
rename from g2p/src/main/java/org/pitest/g2p/core/pos/Pos.java
rename to g2p/src/main/java/org/pitest/voices/g2p/core/pos/Pos.java
index 57629c1..254c41a 100644
--- a/g2p/src/main/java/org/pitest/g2p/core/pos/Pos.java
+++ b/g2p/src/main/java/org/pitest/voices/g2p/core/pos/Pos.java
@@ -1,4 +1,4 @@
-package org.pitest.g2p.core.pos;
+package org.pitest.voices.g2p.core.pos;
// Reduced set of part of speech tags, mapped to
diff --git a/g2p/src/main/java/org/pitest/g2p/core/pos/SimplePOSTagger.java b/g2p/src/main/java/org/pitest/voices/g2p/core/pos/SimplePOSTagger.java
similarity index 96%
rename from g2p/src/main/java/org/pitest/g2p/core/pos/SimplePOSTagger.java
rename to g2p/src/main/java/org/pitest/voices/g2p/core/pos/SimplePOSTagger.java
index 9eb52e1..67fc187 100644
--- a/g2p/src/main/java/org/pitest/g2p/core/pos/SimplePOSTagger.java
+++ b/g2p/src/main/java/org/pitest/voices/g2p/core/pos/SimplePOSTagger.java
@@ -1,9 +1,9 @@
-package org.pitest.g2p.core.pos;
+package org.pitest.voices.g2p.core.pos;
import opennlp.tools.postag.POSModel;
import opennlp.tools.postag.POSTagFormat;
import opennlp.tools.postag.POSTaggerME;
-import org.pitest.g2p.util.Resource;
+import org.pitest.voices.g2p.util.Resource;
import java.io.IOException;
import java.io.UncheckedIOException;
diff --git a/g2p/src/main/java/org/pitest/g2p/core/syllables/RulesSyllabiliser.java b/g2p/src/main/java/org/pitest/voices/g2p/core/syllables/RulesSyllabiliser.java
similarity index 96%
rename from g2p/src/main/java/org/pitest/g2p/core/syllables/RulesSyllabiliser.java
rename to g2p/src/main/java/org/pitest/voices/g2p/core/syllables/RulesSyllabiliser.java
index 11fd476..29b74d8 100644
--- a/g2p/src/main/java/org/pitest/g2p/core/syllables/RulesSyllabiliser.java
+++ b/g2p/src/main/java/org/pitest/voices/g2p/core/syllables/RulesSyllabiliser.java
@@ -1,14 +1,14 @@
-package org.pitest.g2p.core.syllables;
+package org.pitest.voices.g2p.core.syllables;
-import org.pitest.g2p.core.WordToSyllables;
+import org.pitest.voices.g2p.core.WordToSyllables;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
-import static org.pitest.g2p.util.English.CONSONANTS;
-import static org.pitest.g2p.util.English.VOWELS;
+import static org.pitest.voices.g2p.util.English.CONSONANTS;
+import static org.pitest.voices.g2p.util.English.VOWELS;
/**
* Converts words to syllables via a set of hard coded rules.
diff --git a/g2p/src/main/java/org/pitest/g2p/core/tracing/LoggingTrace.java b/g2p/src/main/java/org/pitest/voices/g2p/core/tracing/LoggingTrace.java
similarity index 94%
rename from g2p/src/main/java/org/pitest/g2p/core/tracing/LoggingTrace.java
rename to g2p/src/main/java/org/pitest/voices/g2p/core/tracing/LoggingTrace.java
index 9b3fb2e..87d9e36 100644
--- a/g2p/src/main/java/org/pitest/g2p/core/tracing/LoggingTrace.java
+++ b/g2p/src/main/java/org/pitest/voices/g2p/core/tracing/LoggingTrace.java
@@ -1,6 +1,6 @@
-package org.pitest.g2p.core.tracing;
+package org.pitest.voices.g2p.core.tracing;
-import org.pitest.g2p.core.pos.Pos;
+import org.pitest.voices.g2p.core.pos.Pos;
import java.util.ArrayList;
import java.util.List;
diff --git a/g2p/src/main/java/org/pitest/g2p/core/tracing/Trace.java b/g2p/src/main/java/org/pitest/voices/g2p/core/tracing/Trace.java
similarity index 93%
rename from g2p/src/main/java/org/pitest/g2p/core/tracing/Trace.java
rename to g2p/src/main/java/org/pitest/voices/g2p/core/tracing/Trace.java
index a773a81..3a61d44 100644
--- a/g2p/src/main/java/org/pitest/g2p/core/tracing/Trace.java
+++ b/g2p/src/main/java/org/pitest/voices/g2p/core/tracing/Trace.java
@@ -1,6 +1,6 @@
-package org.pitest.g2p.core.tracing;
+package org.pitest.voices.g2p.core.tracing;
-import org.pitest.g2p.core.pos.Pos;
+import org.pitest.voices.g2p.core.pos.Pos;
import java.util.List;
diff --git a/g2p/src/main/java/org/pitest/g2p/util/English.java b/g2p/src/main/java/org/pitest/voices/g2p/util/English.java
similarity index 89%
rename from g2p/src/main/java/org/pitest/g2p/util/English.java
rename to g2p/src/main/java/org/pitest/voices/g2p/util/English.java
index 2166195..7ea90e9 100644
--- a/g2p/src/main/java/org/pitest/g2p/util/English.java
+++ b/g2p/src/main/java/org/pitest/voices/g2p/util/English.java
@@ -1,4 +1,4 @@
-package org.pitest.g2p.util;
+package org.pitest.voices.g2p.util;
import java.util.Set;
diff --git a/g2p/src/main/java/org/pitest/g2p/util/Resource.java b/g2p/src/main/java/org/pitest/voices/g2p/util/Resource.java
similarity index 80%
rename from g2p/src/main/java/org/pitest/g2p/util/Resource.java
rename to g2p/src/main/java/org/pitest/voices/g2p/util/Resource.java
index d0d18ad..6ee8a4e 100644
--- a/g2p/src/main/java/org/pitest/g2p/util/Resource.java
+++ b/g2p/src/main/java/org/pitest/voices/g2p/util/Resource.java
@@ -1,6 +1,4 @@
-package org.pitest.g2p.util;
-
-import org.pitest.g2p.core.Dictionary;
+package org.pitest.voices.g2p.util;
import java.io.BufferedReader;
import java.io.IOException;
@@ -14,7 +12,7 @@
public class Resource {
public static List read(String resource) {
- try (InputStream is = Dictionary.class.getResourceAsStream(resource);
+ try (InputStream is = readAsStream(resource);
InputStreamReader inputStreamReader = new InputStreamReader(is, StandardCharsets.UTF_8);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
return bufferedReader.lines()
@@ -27,7 +25,7 @@ public static List read(String resource) {
public static InputStream readAsStream(String resource) {
var stream = Resource.class.getResourceAsStream(resource);
if (stream == null) {
- throw new RuntimeException("Could not find resource " + resource);
+ throw new IllegalStateException("Could not find resource " + resource);
}
return stream;
}
diff --git a/g2p/src/test/java/org/pitest/g2p/core/EnglishModelRulesTest.java b/g2p/src/test/java/org/pitest/voices/g2p/core/EnglishModelRulesTest.java
similarity index 95%
rename from g2p/src/test/java/org/pitest/g2p/core/EnglishModelRulesTest.java
rename to g2p/src/test/java/org/pitest/voices/g2p/core/EnglishModelRulesTest.java
index f5a2549..48a447a 100644
--- a/g2p/src/test/java/org/pitest/g2p/core/EnglishModelRulesTest.java
+++ b/g2p/src/test/java/org/pitest/voices/g2p/core/EnglishModelRulesTest.java
@@ -1,11 +1,12 @@
-package org.pitest.g2p.core;
+package org.pitest.voices.g2p.core;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
-import org.pitest.g2p.core.pos.Pos;
-import org.pitest.g2p.core.tracing.Trace;
-import org.pitest.g2p.core.syllables.RulesSyllabiliser;
+import org.pitest.voices.Language;
+import org.pitest.voices.g2p.core.pos.Pos;
+import org.pitest.voices.g2p.core.tracing.Trace;
+import org.pitest.voices.g2p.core.syllables.RulesSyllabiliser;
import static org.assertj.core.api.Assertions.assertThat;
diff --git a/g2p/src/test/java/org/pitest/g2p/core/PiperPhonemizerTest.java b/g2p/src/test/java/org/pitest/voices/g2p/core/PiperPhonemizerTest.java
similarity index 95%
rename from g2p/src/test/java/org/pitest/g2p/core/PiperPhonemizerTest.java
rename to g2p/src/test/java/org/pitest/voices/g2p/core/PiperPhonemizerTest.java
index 272321d..df73df8 100644
--- a/g2p/src/test/java/org/pitest/g2p/core/PiperPhonemizerTest.java
+++ b/g2p/src/test/java/org/pitest/voices/g2p/core/PiperPhonemizerTest.java
@@ -1,8 +1,9 @@
-package org.pitest.g2p.core;
+package org.pitest.voices.g2p.core;
import org.junit.jupiter.api.Test;
-import org.pitest.g2p.core.expansions.NumberExpander;
-import org.pitest.g2p.core.tracing.Trace;
+import org.pitest.voices.Language;
+import org.pitest.voices.g2p.core.expansions.NumberExpander;
+import org.pitest.voices.g2p.core.tracing.Trace;
import java.util.List;
import java.util.Map;
diff --git a/g2p/src/test/java/org/pitest/g2p/core/expansions/NumberExpanderTest.java b/g2p/src/test/java/org/pitest/voices/g2p/core/expansions/NumberExpanderTest.java
similarity index 99%
rename from g2p/src/test/java/org/pitest/g2p/core/expansions/NumberExpanderTest.java
rename to g2p/src/test/java/org/pitest/voices/g2p/core/expansions/NumberExpanderTest.java
index 349417c..68de2b7 100644
--- a/g2p/src/test/java/org/pitest/g2p/core/expansions/NumberExpanderTest.java
+++ b/g2p/src/test/java/org/pitest/voices/g2p/core/expansions/NumberExpanderTest.java
@@ -1,4 +1,4 @@
-package org.pitest.g2p.core.expansions;
+package org.pitest.voices.g2p.core.expansions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
diff --git a/g2p/src/test/java/org/pitest/g2p/core/pos/SimplePOSTaggerTest.java b/g2p/src/test/java/org/pitest/voices/g2p/core/pos/SimplePOSTaggerTest.java
similarity index 95%
rename from g2p/src/test/java/org/pitest/g2p/core/pos/SimplePOSTaggerTest.java
rename to g2p/src/test/java/org/pitest/voices/g2p/core/pos/SimplePOSTaggerTest.java
index d551b0d..b099827 100644
--- a/g2p/src/test/java/org/pitest/g2p/core/pos/SimplePOSTaggerTest.java
+++ b/g2p/src/test/java/org/pitest/voices/g2p/core/pos/SimplePOSTaggerTest.java
@@ -1,9 +1,9 @@
-package org.pitest.g2p.core.pos;
+package org.pitest.voices.g2p.core.pos;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.pitest.g2p.core.pos.SimplePOSTagger.makeTagger;
+import static org.pitest.voices.g2p.core.pos.SimplePOSTagger.makeTagger;
class SimplePOSTaggerTest {
diff --git a/g2p/src/test/java/org/pitest/g2p/core/syllables/RulesSyllabiliserTest.java b/g2p/src/test/java/org/pitest/voices/g2p/core/syllables/RulesSyllabiliserTest.java
similarity index 97%
rename from g2p/src/test/java/org/pitest/g2p/core/syllables/RulesSyllabiliserTest.java
rename to g2p/src/test/java/org/pitest/voices/g2p/core/syllables/RulesSyllabiliserTest.java
index 2d1ff71..142dca0 100644
--- a/g2p/src/test/java/org/pitest/g2p/core/syllables/RulesSyllabiliserTest.java
+++ b/g2p/src/test/java/org/pitest/voices/g2p/core/syllables/RulesSyllabiliserTest.java
@@ -1,4 +1,4 @@
-package org.pitest.g2p.core.syllables;
+package org.pitest.voices.g2p.core.syllables;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
diff --git a/model_downloader/pom.xml b/model_downloader/pom.xml
new file mode 100644
index 0000000..5c5d6ce
--- /dev/null
+++ b/model_downloader/pom.xml
@@ -0,0 +1,94 @@
+
+
+ 4.0.0
+
+
+ org.pitest.voices
+ voices-parent
+ ${revision}
+
+
+ model-downloader
+ model-downloader
+
+ jar
+
+
+
+ Apache 2
+ https://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+
+
+
+
+
+ org.pitest.voices
+ core
+ ${project.parent.version}
+
+
+
+ me.tongfei
+ progressbar
+ 0.10.1
+
+
+ org.apache.commons
+ commons-compress
+ 1.28.0
+
+
+
+
+ com.microsoft.onnxruntime
+ onnxruntime
+ 1.22.0
+ test
+
+
+
+ org.pitest.voices
+ chorus
+ ${project.parent.version}
+ test
+
+
+ org.pitest.voices
+ chorus
+ ${project.parent.version}
+ test-jar
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+
+
+
+
+
+
diff --git a/chorus/src/main/java/org/pitest/voices/Model.java b/model_downloader/src/main/java/org/pitest/voices/download/FileModel.java
similarity index 67%
rename from chorus/src/main/java/org/pitest/voices/Model.java
rename to model_downloader/src/main/java/org/pitest/voices/download/FileModel.java
index b3ab25e..4c460d1 100644
--- a/chorus/src/main/java/org/pitest/voices/Model.java
+++ b/model_downloader/src/main/java/org/pitest/voices/download/FileModel.java
@@ -1,14 +1,16 @@
-package org.pitest.voices;
+package org.pitest.voices.download;
-import org.pitest.g2p.core.Language;
+import org.pitest.voices.Language;
+import org.pitest.voices.Model;
+import org.pitest.voices.ModelConfig;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
-import java.util.List;
-public class Model {
+
+public class FileModel implements Model {
private final String name;
private final String location;
@@ -17,49 +19,57 @@ public class Model {
private final ModelFetcher resolver;
- private final List pauses;
private final float gain;
- private final ModelParameters params;
+ public FileModel(String name,
+ String location,
+ Language lang,
+ ModelFetcher resolver,
+ float gain) {
+ this(name, location,lang, -1, resolver, gain);
+ }
- public Model(String name,
+ public FileModel(String name,
String location,
Language lang,
int sid,
ModelFetcher resolver,
- List pauses,
- float gain,
- ModelParameters params) {
+ float gain) {
this.name = name;
this.location = location;
this.lang = lang;
this.sid = sid;
this.resolver = resolver;
- this.pauses = pauses;
this.gain = gain;
- this.params = params;
}
- public String name() {
+ @Override
+ public String id() {
return name;
}
+
+ @Override
public int sid() {
return sid;
}
+ @Override
public Language language() {
return lang;
}
+ @Override
public Model withLanguage(Language lang) {
- return new Model(name, location, lang, sid, resolver, pauses, gain, params);
+ return new FileModel(name, location, lang, sid, resolver, gain);
}
- public Path resolve(Path cacheBase) throws IOException {
- return resolveFiles(cacheBase).resolve(onnx());
+ @Override
+ public byte[] asBytes(Path cacheBase) throws IOException {
+ return Files.readAllBytes(resolveFiles(cacheBase).resolve(onnx()));
}
+ @Override
public ModelConfig resolveConfig(Path cacheBase) throws IOException {
Path json = resolveFiles(cacheBase).resolve(onnx() + ".json");
try(var in = Files.newInputStream(json, StandardOpenOption.READ)) {
@@ -67,29 +77,13 @@ public ModelConfig resolveConfig(Path cacheBase) throws IOException {
}
}
- public Path fetch() throws IOException {
- return resolver.fetch().resolve(location);
- }
-
- public List defaultPauses() {
- return pauses;
- }
-
- String onnx() {
- return name + ".onnx";
- }
-
-
- String id() {
- return name;
- }
-
+ @Override
public float defaultGain() {
return gain;
}
- public ModelParameters defaultParams() {
- return params;
+ String onnx() {
+ return name + ".onnx";
}
private Path resolveFiles(Path cacheBase) throws IOException {
@@ -102,5 +96,7 @@ private Path resolveFiles(Path cacheBase) throws IOException {
return location;
}
-
+ private Path fetch() throws IOException {
+ return resolver.fetch().resolve(location);
+ }
}
diff --git a/chorus/src/main/java/org/pitest/voices/ModelDownloader.java b/model_downloader/src/main/java/org/pitest/voices/download/ModelDownloader.java
similarity index 98%
rename from chorus/src/main/java/org/pitest/voices/ModelDownloader.java
rename to model_downloader/src/main/java/org/pitest/voices/download/ModelDownloader.java
index bdeb12c..7344b20 100644
--- a/chorus/src/main/java/org/pitest/voices/ModelDownloader.java
+++ b/model_downloader/src/main/java/org/pitest/voices/download/ModelDownloader.java
@@ -1,4 +1,4 @@
-package org.pitest.voices;
+package org.pitest.voices.download;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
diff --git a/chorus/src/main/java/org/pitest/voices/ModelFetcher.java b/model_downloader/src/main/java/org/pitest/voices/download/ModelFetcher.java
similarity index 78%
rename from chorus/src/main/java/org/pitest/voices/ModelFetcher.java
rename to model_downloader/src/main/java/org/pitest/voices/download/ModelFetcher.java
index ff2b98b..8cc2bfa 100644
--- a/chorus/src/main/java/org/pitest/voices/ModelFetcher.java
+++ b/model_downloader/src/main/java/org/pitest/voices/download/ModelFetcher.java
@@ -1,4 +1,4 @@
-package org.pitest.voices;
+package org.pitest.voices.download;
import java.io.IOException;
import java.nio.file.Path;
diff --git a/chorus/src/main/java/org/pitest/voices/Models.java b/model_downloader/src/main/java/org/pitest/voices/download/Models.java
similarity index 76%
rename from chorus/src/main/java/org/pitest/voices/Models.java
rename to model_downloader/src/main/java/org/pitest/voices/download/Models.java
index 548b213..16aa6d9 100644
--- a/chorus/src/main/java/org/pitest/voices/Models.java
+++ b/model_downloader/src/main/java/org/pitest/voices/download/Models.java
@@ -1,13 +1,12 @@
-package org.pitest.voices;
+package org.pitest.voices.download;
-import org.pitest.g2p.core.Language;
+import org.pitest.voices.Language;
+import org.pitest.voices.Model;
import java.net.URL;
-import java.util.List;
public class Models {
-
public static Model coriHigh() {
return sherpaModel("en_GB-cori-high", 2.0f);
}
@@ -16,11 +15,10 @@ public static Model albaMedium() {
return sherpaModel("en_GB-alba-medium", 2.0f);
}
- public static Model aru(int sid) {
+ public static Model aruMedium(int sid) {
return sherpaModel("en_GB-aru-medium", sid,2.0f);
}
-
-
+
public static Model alanMedium() {
return sherpaModel("en_GB-alan-medium", 0.8f);
}
@@ -42,20 +40,12 @@ private static Model sherpaModel(String name, float gain) {
}
private static Model sherpaModel(String name, int sid, float gain) {
- return new Model(name,
+ return new FileModel(name,
"vits-piper-" + name,
Language.en_GB,
sid,
new ModelDownloader(url("https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/vits-piper-" + name + ".tar.bz2")),
- defaultPauses(), gain, ModelParameters.defaultParams()
- );
- }
-
- public static List defaultPauses() {
- return List.of(new Pause("—", 3),
- new Pause("–", 2),
- new Pause(":", 2)
- );
+ gain);
}
static URL url(String url) {
diff --git a/chorus/src/main/java/org/pitest/voices/NonEnglishModels.java b/model_downloader/src/main/java/org/pitest/voices/download/NonEnglishModels.java
similarity index 66%
rename from chorus/src/main/java/org/pitest/voices/NonEnglishModels.java
rename to model_downloader/src/main/java/org/pitest/voices/download/NonEnglishModels.java
index eaf4d96..9877312 100644
--- a/chorus/src/main/java/org/pitest/voices/NonEnglishModels.java
+++ b/model_downloader/src/main/java/org/pitest/voices/download/NonEnglishModels.java
@@ -1,9 +1,10 @@
-package org.pitest.voices;
+package org.pitest.voices.download;
-import org.pitest.g2p.core.Language;
+import org.pitest.voices.Language;
+import org.pitest.voices.Model;
+
+import static org.pitest.voices.download.Models.url;
-import static org.pitest.voices.Models.defaultPauses;
-import static org.pitest.voices.Models.url;
public class NonEnglishModels {
@@ -16,12 +17,11 @@ public static Model nlNLRonnie() {
}
private static Model sherpaModel(String name, Language lang, float gain) {
- return new Model(name,
+ return new FileModel(name,
"vits-piper-" + name,
lang,
-1,
- new ModelDownloader(url("https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/vits-piper-" + name + ".tar.bz2")),
- defaultPauses(), gain, ModelParameters.defaultParams()
- );
+ new ModelDownloader(url("https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/vits-piper-" + name + ".tar.bz2"))
+ , gain );
}
}
diff --git a/chorus/src/main/java/org/pitest/voices/URLModelFetcher.java b/model_downloader/src/main/java/org/pitest/voices/download/URLModelFetcher.java
similarity index 97%
rename from chorus/src/main/java/org/pitest/voices/URLModelFetcher.java
rename to model_downloader/src/main/java/org/pitest/voices/download/URLModelFetcher.java
index cc02ec5..f82e865 100644
--- a/chorus/src/main/java/org/pitest/voices/URLModelFetcher.java
+++ b/model_downloader/src/main/java/org/pitest/voices/download/URLModelFetcher.java
@@ -1,4 +1,4 @@
-package org.pitest.voices;
+package org.pitest.voices.download;
import me.tongfei.progressbar.ProgressBar;
import me.tongfei.progressbar.ProgressBarBuilder;
diff --git a/chorus/src/main/java/org/pitest/voices/UsModels.java b/model_downloader/src/main/java/org/pitest/voices/download/UsModels.java
similarity index 78%
rename from chorus/src/main/java/org/pitest/voices/UsModels.java
rename to model_downloader/src/main/java/org/pitest/voices/download/UsModels.java
index d8c2091..80580c9 100644
--- a/chorus/src/main/java/org/pitest/voices/UsModels.java
+++ b/model_downloader/src/main/java/org/pitest/voices/download/UsModels.java
@@ -1,9 +1,10 @@
-package org.pitest.voices;
+package org.pitest.voices.download;
-import org.pitest.g2p.core.Language;
-import static org.pitest.voices.Models.defaultPauses;
-import static org.pitest.voices.Models.url;
+import org.pitest.voices.Language;
+import org.pitest.voices.Model;
+
+import static org.pitest.voices.download.Models.url;
public class UsModels {
@@ -56,16 +57,10 @@ public static Model samMedium() {
}
private static Model sherpaModel(String name, float gain) {
- return sherpaModel(name, -1, gain);
- }
-
- private static Model sherpaModel(String name, int sid, float gain) {
- return new Model(name,
+ return new FileModel(name,
"vits-piper-" + name,
Language.en_US,
- sid,
new ModelDownloader(url("https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/vits-piper-" + name + ".tar.bz2")),
- defaultPauses(), gain, ModelParameters.defaultParams()
- );
+ gain);
}
}
diff --git a/model_downloader/src/test/java/org/pitest/voices/download/ModelsTest.java b/model_downloader/src/test/java/org/pitest/voices/download/ModelsTest.java
new file mode 100644
index 0000000..b286e4d
--- /dev/null
+++ b/model_downloader/src/test/java/org/pitest/voices/download/ModelsTest.java
@@ -0,0 +1,66 @@
+package org.pitest.voices.download;
+
+import org.junit.jupiter.api.Test;
+import org.pitest.voices.ChorusConfig;
+import org.pitest.voices.Language;
+import org.pitest.voices.Model;
+import org.pitest.voices.g2p.core.Dictionary;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class ModelsTest {
+
+ static final int ARBITRARY_SIZE = 1000;
+ Path cache = ChorusConfig.chorusConfig(Dictionary.empty()).base();
+
+ @Test
+ void coriHigh() throws IOException {
+ var model = Models.coriHigh();
+ checkModel(model);
+ }
+
+ @Test
+ void albaMedium() throws IOException {
+ var model = Models.albaMedium();
+ checkModel(model);
+ }
+
+ @Test
+ void aruMedium() throws IOException {
+ var model = Models.aruMedium(1);
+ checkModel(model);
+ }
+
+ @Test
+ void alanMedium() throws IOException {
+ var model = Models.alanMedium();
+ checkModel(model);
+ }
+
+ @Test
+ void jennyDiocoMedium() throws IOException {
+ var model = Models.jennyDiocoMedium();
+ checkModel(model);
+ }
+
+ @Test
+ void sweetbbakAmy() throws IOException {
+ var model = Models.sweetbbakAmy();
+ checkModel(model);
+ }
+
+ @Test
+ void northernEnglishMale() throws IOException {
+ var model = Models.northernEnglishMale();
+ checkModel(model);
+ }
+
+ private void checkModel(Model model) throws IOException {
+ assertThat(model.asBytes(cache)).hasSizeGreaterThan(ARBITRARY_SIZE);
+ assertThat(model.resolveConfig(cache).sampleRate()).isEqualTo(22050L);
+ assertThat(model.language()).isEqualTo(Language.en_GB);
+ }
+}
\ No newline at end of file
diff --git a/model_downloader/src/test/java/org/pitest/voices/download/NonEnglishModelsTest.java b/model_downloader/src/test/java/org/pitest/voices/download/NonEnglishModelsTest.java
new file mode 100644
index 0000000..59da5c6
--- /dev/null
+++ b/model_downloader/src/test/java/org/pitest/voices/download/NonEnglishModelsTest.java
@@ -0,0 +1,37 @@
+package org.pitest.voices.download;
+
+import org.junit.jupiter.api.Test;
+import org.pitest.voices.ChorusConfig;
+import org.pitest.voices.Language;
+import org.pitest.voices.Model;
+import org.pitest.voices.g2p.core.Dictionary;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.pitest.voices.download.ModelsTest.ARBITRARY_SIZE;
+
+class NonEnglishModelsTest {
+
+ Path cache = ChorusConfig.chorusConfig(Dictionary.empty()).base();
+
+ @Test
+ void frFRSiwis() throws IOException {
+ var model = NonEnglishModels.frFRSiwis();
+ checkModel(model);
+ assertThat(model.language()).isEqualTo(Language.fr_FR);
+ }
+
+ @Test
+ void nlNLRonnie() throws IOException {
+ var model = NonEnglishModels.nlNLRonnie();
+ checkModel(model);
+ assertThat(model.language()).isEqualTo(Language.nl_NL);
+ }
+
+ private void checkModel(Model model) throws IOException {
+ assertThat(model.asBytes(cache)).hasSizeGreaterThan(ARBITRARY_SIZE);
+ assertThat(model.resolveConfig(cache).sampleRate()).isEqualTo(22050L);
+ }
+}
\ No newline at end of file
diff --git a/model_downloader/src/test/java/org/pitest/voices/download/UsModelsTest.java b/model_downloader/src/test/java/org/pitest/voices/download/UsModelsTest.java
new file mode 100644
index 0000000..5b5f5a0
--- /dev/null
+++ b/model_downloader/src/test/java/org/pitest/voices/download/UsModelsTest.java
@@ -0,0 +1,95 @@
+package org.pitest.voices.download;
+
+import org.junit.jupiter.api.Test;
+import org.pitest.voices.ChorusConfig;
+import org.pitest.voices.Language;
+import org.pitest.voices.Model;
+import org.pitest.voices.g2p.core.Dictionary;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.pitest.voices.download.ModelsTest.ARBITRARY_SIZE;
+
+class UsModelsTest {
+ Path cache = ChorusConfig.chorusConfig(Dictionary.empty()).base();
+
+ @Test
+ void amyMedium() throws IOException {
+ var model = UsModels.amyMedium();
+ checkModel(model);
+ }
+
+ @Test
+ void bryceMedium() throws IOException {
+ var model = UsModels.bryceMedium();
+ checkModel(model);
+ }
+
+ @Test
+ void hfcFemaleMedium() throws IOException {
+ var model = UsModels.hfcFemaleMedium();
+ checkModel(model);
+ }
+
+ @Test
+ void hfcMaleMedium() throws IOException {
+ var model = UsModels.hfcMaleMedium();
+ checkModel(model);
+ }
+
+ @Test
+ void joeMedium() throws IOException {
+ var model = UsModels.joeMedium();
+ checkModel(model);
+ }
+
+ @Test
+ void johnMedium() throws IOException {
+ var model = UsModels.johnMedium();
+ checkModel(model);
+ }
+
+ @Test
+ void kristinMedium() throws IOException {
+ var model = UsModels.kristinMedium();
+ checkModel(model);
+ }
+
+ @Test
+ void kusalMedium() throws IOException {
+ var model = UsModels.kusalMedium();
+ checkModel(model);
+ }
+
+ @Test
+ void lessacHigh() throws IOException {
+ var model = UsModels.lessacHigh();
+ checkModel(model);
+ }
+
+ @Test
+ void normanMedium() throws IOException {
+ var model = UsModels.normanMedium();
+ checkModel(model);
+ }
+
+ @Test
+ void ryanHigh() throws IOException {
+ var model = UsModels.ryanHigh();
+ checkModel(model);
+ }
+
+ @Test
+ void samMedium() throws IOException {
+ var model = UsModels.samMedium();
+ checkModel(model);
+ }
+
+ private void checkModel(Model model) throws IOException {
+ assertThat(model.asBytes(cache)).hasSizeGreaterThan(ARBITRARY_SIZE);
+ assertThat(model.resolveConfig(cache).sampleRate()).isEqualTo(22050L);
+ assertThat(model.language()).isEqualTo(Language.en_US);
+ }
+}
\ No newline at end of file
diff --git a/openvoice/pom.xml b/openvoice/pom.xml
index df362fe..c6db385 100644
--- a/openvoice/pom.xml
+++ b/openvoice/pom.xml
@@ -26,17 +26,15 @@
org.pitest.voices
- g2p
+ chorus
${project.parent.version}
org.pitest.voices
- chorus
- ${project.parent.version}
+ openvoice-model
+ ${models.version}
-
-
com.microsoft.onnxruntime
onnxruntime
@@ -49,7 +47,12 @@
slf4j-simple
2.0.16
-
+
+ org.pitest.voices
+ alba
+ ${project.parent.version}
+ test
+
org.pitest.voices
chorus
diff --git a/openvoice/src/main/java/org/pitest/voices/openvoice/ONNXModel.java b/openvoice/src/main/java/org/pitest/voices/openvoice/ONNXModel.java
deleted file mode 100644
index cd25aa3..0000000
--- a/openvoice/src/main/java/org/pitest/voices/openvoice/ONNXModel.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package org.pitest.voices.openvoice;
-
-import org.pitest.voices.ModelFetcher;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-
-public class ONNXModel {
-
- private final ModelFetcher remote;
- private final String local;
-
- public ONNXModel(ModelFetcher remote, String local) {
- this.remote = remote;
- this.local = local;
- }
-
- public Path resolve(Path cacheBase) throws IOException {
- Path location = cacheBase.resolve(this.local);
- Path onnx = location.resolve("model.onnx");
- if (!Files.exists(onnx)) {
- Path tempLocation = remote.fetch();
- Files.move(tempLocation.getParent(), location);
- }
- return onnx;
- }
-}
diff --git a/openvoice/src/main/java/org/pitest/voices/openvoice/OpenVoiceModel.java b/openvoice/src/main/java/org/pitest/voices/openvoice/OpenVoiceModel.java
index c5cde0f..6bef4bc 100644
--- a/openvoice/src/main/java/org/pitest/voices/openvoice/OpenVoiceModel.java
+++ b/openvoice/src/main/java/org/pitest/voices/openvoice/OpenVoiceModel.java
@@ -3,11 +3,11 @@
import ai.onnxruntime.OrtEnvironment;
import ai.onnxruntime.OrtException;
import ai.onnxruntime.OrtSession;
-import org.pitest.g2p.core.Dictionary;
-import org.pitest.g2p.core.G2PModel;
-import org.pitest.g2p.core.pos.Pos;
-import org.pitest.g2p.core.tracing.Trace;
-import org.pitest.g2p.core.Language;
+import org.pitest.voices.Language;
+import org.pitest.voices.g2p.core.Dictionary;
+import org.pitest.voices.g2p.core.G2PModel;
+import org.pitest.voices.g2p.core.pos.Pos;
+import org.pitest.voices.g2p.core.tracing.Trace;
public class OpenVoiceModel implements G2PModel {
diff --git a/openvoice/src/main/java/org/pitest/voices/openvoice/OpenVoiceSupplier.java b/openvoice/src/main/java/org/pitest/voices/openvoice/OpenVoiceSupplier.java
index d63a68b..bbfe7e3 100644
--- a/openvoice/src/main/java/org/pitest/voices/openvoice/OpenVoiceSupplier.java
+++ b/openvoice/src/main/java/org/pitest/voices/openvoice/OpenVoiceSupplier.java
@@ -2,31 +2,22 @@
import ai.onnxruntime.OrtEnvironment;
import ai.onnxruntime.OrtSession;
-import org.pitest.g2p.core.Dictionary;
-import org.pitest.g2p.core.G2PModel;
+import org.pitest.voices.g2p.core.Dictionary;
+import org.pitest.voices.g2p.core.G2PModel;
+import org.pitest.voices.Resource;
import org.pitest.voices.G2PModelSupplier;
-import org.pitest.voices.URLModelFetcher;
import java.nio.file.Path;
import java.util.function.Supplier;
public class OpenVoiceSupplier implements G2PModelSupplier {
- private final ONNXModel model;
-
- public OpenVoiceSupplier() {
- this(new ONNXModel(URLModelFetcher.fromString("https://huggingface.co/OpenVoiceOS/g2p-mbyt5-12l-ipa-childes-espeak-onnx/resolve/main/fdemelo_g2p-mbyt5-12l-ipa-childes-espeak.onnx"),
- "fdemelo_g2p-mbyt5-12l-ipa-childes-espeak"));
- }
-
- public OpenVoiceSupplier(ONNXModel model) {
- this.model = model;
- }
@Override
public G2PModel create(Supplier options, Dictionary dictionary, OrtEnvironment env, Path base) {
try {
- Path onnx = model.resolve(base);
- var session = env.createSession(onnx.toString(), options.get());
+ var model = Resource.readAsBytes("/models/fdemelo_g2p-mbyt5-12l-ipa-childes-espeak.onnx");
+ var opts = options.get();
+ var session = env.createSession(model, opts);
return new OpenVoiceModel(dictionary, session, env);
} catch (Exception e) {
throw new RuntimeException(e);
diff --git a/openvoice/src/test/java/org/pitest/voices/openvoice/OpenVoiceModelTest.java b/openvoice/src/test/java/org/pitest/voices/openvoice/OpenVoiceModelTest.java
index d14d064..e6e1c4f 100644
--- a/openvoice/src/test/java/org/pitest/voices/openvoice/OpenVoiceModelTest.java
+++ b/openvoice/src/test/java/org/pitest/voices/openvoice/OpenVoiceModelTest.java
@@ -3,11 +3,11 @@
import ai.onnxruntime.OrtEnvironment;
import ai.onnxruntime.OrtSession;
import org.junit.jupiter.api.Test;
-import org.pitest.g2p.core.Dictionary;
-import org.pitest.g2p.core.G2PModel;
-import org.pitest.g2p.core.Language;
-import org.pitest.g2p.core.pos.Pos;
-import org.pitest.g2p.core.tracing.Trace;
+import org.pitest.voices.Language;
+import org.pitest.voices.g2p.core.Dictionary;
+import org.pitest.voices.g2p.core.G2PModel;
+import org.pitest.voices.g2p.core.pos.Pos;
+import org.pitest.voices.g2p.core.tracing.Trace;
import java.nio.file.Path;
diff --git a/openvoice/src/test/java/org/pitest/voices/openvoice/TryItOutTest.java b/openvoice/src/test/java/org/pitest/voices/openvoice/TryItOutTest.java
index 97ee4aa..db4fabb 100644
--- a/openvoice/src/test/java/org/pitest/voices/openvoice/TryItOutTest.java
+++ b/openvoice/src/test/java/org/pitest/voices/openvoice/TryItOutTest.java
@@ -1,13 +1,12 @@
package org.pitest.voices.openvoice;
import org.junit.jupiter.api.Test;
-import org.pitest.g2p.core.Dictionary;
-import org.pitest.g2p.core.tracing.LoggingTrace;
-import org.pitest.g2p.util.Resource;
+import org.pitest.voices.alba.Alba;
+import org.pitest.voices.g2p.core.Dictionary;
+import org.pitest.voices.g2p.core.tracing.LoggingTrace;
+import org.pitest.voices.Resource;
import org.pitest.voices.Chorus;
import org.pitest.voices.ChorusConfig;
-import org.pitest.voices.Models;
-import org.pitest.voices.NonEnglishModels;
import org.pitest.voices.Voice;
import org.pitest.voices.audio.Audio;
@@ -23,7 +22,7 @@ class TryItOutTest {
@Test
void orwell() {
try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(Models.albaMedium());
+ Voice v1 = chorus.voice(Alba.albaMedium());
var audio = v1.say("It was a bright cold day in April, and the clocks were striking thirteen.");
play(audio);
}
@@ -32,26 +31,8 @@ void orwell() {
@Test
void interruptedSpeech() {
try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(Models.albaMedium());
- var audio = v1.say("\"That's not what I---\"");
- play(audio);
- }
- }
-
- @Test
- void frFR() {
- try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(NonEnglishModels.frFRSiwis());
- var audio = v1.say("Je parle français");
- play(audio);
- }
- }
-
- @Test
- void nlNL() {
- try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(NonEnglishModels.nlNLRonnie());
- var audio = v1.say("Hallo daar");
+ Voice v1 = chorus.voice(Alba.albaMedium());
+ var audio = v1.say("That's not what I---");
play(audio);
}
}
@@ -59,7 +40,7 @@ void nlNL() {
@Test
void mobyDick() {
try (Chorus chorus = new Chorus(config)) {
- Voice v1 = chorus.voice(Models.albaMedium());
+ Voice v1 = chorus.voice(Alba.albaMedium());
String text = String.join("\n", Resource.read("/samples/moby_dick.md"));
Audio audio = v1.say(text);
diff --git a/pom.xml b/pom.xml
index 8c88f35..b46ba6a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,6 +17,8 @@
dev-SNAPSHOT
+
+ 0.0.1
UTF-8
UTF-8
hcoles/voices
@@ -272,10 +274,16 @@
g2p
+ core
+ alba
+ bryce
+ cori
chorus
+ model_downloader
en_uk
en_us
openvoice
+