Skip to content

Commit

Permalink
Merge pull request #15 from umjammer/0.0.14
Browse files Browse the repository at this point in the history
0.0.14
  • Loading branch information
umjammer authored Mar 14, 2024
2 parents 1376acd + 7eeda8b commit 354c429
Show file tree
Hide file tree
Showing 42 changed files with 1,194 additions and 533 deletions.
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

# vavi-speech2

<img alt="yukkuries" src="https://github.com/umjammer/vavi-speech2/assets/493908/5ccc63da-5dc8-40ac-b6f6-d8dce89b7cf7" width="300" />

Text to Speech and Speech to Text (JSAPI2) engines for Java

| **Type** | **Description** | **Sythesizer** | **Recognizer** | **Quality** | **Comment** |
Expand Down Expand Up @@ -35,21 +37,24 @@ Text to Speech and Speech to Text (JSAPI2) engines for Java
* [get token as json](https://cloud.google.com/text-to-speech/docs/quickstart-client-libraries)
* set environment variable `"GOOGLE_APPLICATION_CREDENTIALS"` `your_json_path`

### Rococoa

* locate `librococoa.dylib` into one of class paths
* if you use maven it's already done, you can find it at `target/test-classes`.

### Open JTalk

* make `libjtalk.dylib` from `https://github.com/rosmarinus/jtalkdll`
* locate `libjtalk.dylib` into `DYLD_LIBRARY_PATH`
* make `libjtalk.dylib` from https://github.com/rosmarinus/jtalkdll
* locate `libjtalk.dylib` into java classpath or `jna.library.path` system property

### VOICEVOX

* [download](https://voicevox.hiroshiba.jp/) the application
* run the application before using this library

## Usage

### user

* [zundamod](https://github.com/umjammer/zundamod)
* [w/ chatGPT](https://github.com/umjammer/vavi-speech-sandbox/)
* [RPC](https://github.com/umjammer/vavi-speech-rpc/)

## Reference

* [jsr113](https://github.com/JVoiceXML/jsapi)
Expand Down
11 changes: 7 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<groupId>vavi</groupId>
<artifactId>vavi-speech2</artifactId>
<version>0.0.13</version>
<version>0.0.14</version>

<name>vavi-speech2</name>
<description/>
Expand All @@ -21,8 +21,8 @@
</issueManagement>

<properties>
<jsapi2.groupId>com.github.umjammer.jsapi</jsapi2.groupId> <!-- org.jvoicexml / com.github.umjammer.jsapi -->
<jsapi2.version>0.6.6</jsapi2.version>
<jsapi2.groupId>com.github.umjammer.jsapi2</jsapi2.groupId> <!-- org.jvoicexml / com.github.umjammer.jsapi2 -->
<jsapi2.version>0.6.9</jsapi2.version>

<jersey.version>3.1.5</jersey.version>
</properties>
Expand Down Expand Up @@ -106,7 +106,10 @@
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<argLine>-Djava.util.logging.config.file=${project.build.testOutputDirectory}/logging.properties</argLine>
<argLine>
-Djava.util.logging.config.file=${project.build.testOutputDirectory}/logging.properties
-Dvavi.util.logging.VaviFormatter.extraClassMethod=sun\.util\.logging\.internal\.LoggingProviderImpl\$JULWrapper#log
</argLine>
<reuseForks>false</reuseForks>
<trimStackTrace>false</trimStackTrace>
<includes>
Expand Down
187 changes: 187 additions & 0 deletions src/main/java/vavi/speech/BaseEnginFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/*
* Copyright (c) 2024 by Naohide Sano, All rights reserved.
*
* Programmed by Naohide Sano
*/

package vavi.speech;

import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import javax.speech.EngineList;
import javax.speech.EngineMode;
import javax.speech.synthesis.SynthesizerMode;

import static java.lang.System.getLogger;


/**
* BaseEnginFactory.
*
* @author <a href="mailto:umjammer@gmail.com">Naohide Sano</a> (nsano)
* @version 0.00 2024-03-14 nsano initial version <br>
*/
public abstract class BaseEnginFactory<V> {

private static final Logger logger = getLogger(BaseEnginFactory.class.getName());

/**
* Used to be able to generate a list of voices based on unique
* combinations of domain/locale pairs.
*/
protected static class DomainLocale<V> {

/** The domain. */
private final String domain;

/** The locale. */
private final Locale locale;

/** Voices for the current domain and locale. */
private final List<WrappedVoice<V>> voices;

/**
* Constructs a new object.
*
* @param domain the domain to use
* @param locale the locale to use
*/
public DomainLocale(String domain, Locale locale) {
this.domain = domain;
this.locale = locale;
this.voices = new ArrayList<>();
}

/**
* See if two DomainLocale objects are equal.
* The voices are NOT compared.
*
* @param o, the object to compare to
* @return true if the domain and locale are both equal, else
* false
*/
public boolean equals(Object o) {
if (!(o instanceof DomainLocale)) {
return false;
}
return (domain.equals(((DomainLocale<?>) o).getDomain())
&& locale.equals(((DomainLocale<?>) o).getLocale()));
}

/**
* Gets the domain.
*
* @return the domain
*/
public String getDomain() {
return domain;
}

/**
* Gets the locale.
*
* @return the locale
*/
public Locale getLocale() {
return locale;
}

/**
* Adds a voice to this instance.
*
* @param voice the voice to add
*/
public void addVoice(WrappedVoice<V> voice) {
voices.add(voice);
}

/**
* Gets the voices of this instance.
*
* @return all of the voices that have been added to this
* instance.
*/
public List<WrappedVoice<V>> getVoices() {
return voices;
}
}

/** Retrieves all voices. */
protected abstract List<WrappedVoice<V>> geAlltVoices();

/** */
protected abstract SynthesizerMode createSynthesizerMode(DomainLocale<V> domainLocale, List<WrappedVoice<V>> voices);

/** */
protected EngineList createEngineListForSynthesizer(EngineMode require) {
// Must be a synthesizer.
if (require != null && !(require instanceof SynthesizerMode)) {
return null;
}
logger.log(Level.TRACE, getClass().getSimpleName() + " --------");

// get all voices available
List<WrappedVoice<V>> voices = geAlltVoices();
logger.log(Level.TRACE, "voices: " + voices.size());

// We want to get all combinations of domains and locales
List<DomainLocale<V>> domainLocaleList = new ArrayList<>();
for (WrappedVoice<V> voice : voices) {
DomainLocale<V> dl = new DomainLocale<>(voice.getDomain(), voice.getLocale());
// If we find the domain locale in the set, add the existing one
// otherwise add the template
DomainLocale<V> dlentry = getItem(domainLocaleList, dl);
if (dlentry == null) {
domainLocaleList.add(dl);
dlentry = dl;
}
dlentry.addVoice(voice);
}

// SynthesizerModes that will be created from combining domain/locale
// with voice names
List<SynthesizerMode> synthesizerModes = new ArrayList<>();

// build list of SynthesizerModeDesc's for each domain/locale
// combination
for (DomainLocale<V> domainLocale : domainLocaleList) {

// iterate through the voices in a different order
voices = domainLocale.getVoices();

SynthesizerMode mode = createSynthesizerMode(domainLocale, voices);

if (require == null || mode.match(require)) {
synthesizerModes.add(mode);
logger.log(Level.TRACE, "MODE: " + mode + ", voices: " + voices.size());
}
}

EngineList el;
if (synthesizerModes.isEmpty()) {
el = null;
} else {
logger.log(Level.DEBUG, "-------- " + getClass().getSimpleName() + " MODES: " + synthesizerModes.size() + ", voices: " + synthesizerModes.stream().mapToInt(m -> m.getVoices().length).sum());
el = new EngineList(synthesizerModes.toArray(EngineMode[]::new));
}
return el;
}

/**
* Gets an item out of a vector.
*
* @param vector the vector to search
* @param o the object to look for using vector.get(i).equals(o)
* @return the item if it exists in the vector, else null
*/
private DomainLocale<V> getItem(List<DomainLocale<V>> vector, DomainLocale<V> o) {
int index = vector.indexOf(o);
if (index < 0) {
return null;
}
return vector.get(index);
}
}
53 changes: 53 additions & 0 deletions src/main/java/vavi/speech/WrappedVoice.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2024 by Naohide Sano, All rights reserved.
*
* Programmed by Naohide Sano
*/

package vavi.speech;

import java.util.List;
import java.util.Locale;
import javax.speech.SpeechLocale;
import javax.speech.synthesis.Voice;


/**
* WrappedVoice.
*
* @author <a href="mailto:umjammer@gmail.com">Naohide Sano</a> (nsano)
* @version 0.00 2024-03-14 nsano initial version <br>
*/
public abstract class WrappedVoice<V> extends Voice {

/** */
protected V nativeVoice;

/** */
protected WrappedVoice(V nativeVoice) {
this.nativeVoice = nativeVoice;
}

/** */
protected WrappedVoice(SpeechLocale locale, String name, int gender, int age, int variant, V nativeVoice) {
super(locale, name, gender, age, variant);
this.nativeVoice = nativeVoice;
}

/** */
public V getNativeVoice() {
return nativeVoice;
}

/** */
public abstract List<V> getAllNativeVoices();

/** */
public abstract List<WrappedVoice<V>> getAllVoices();

/** */
public abstract String getDomain();

/** */
public abstract Locale getLocale();
}
Loading

0 comments on commit 354c429

Please sign in to comment.