I am working on a JavaFX application in Eclipse that uses MaryTTS. In Eclipse the application works fine, but if I generate a runnable jar with Mavens shade plugin I get
marytts.exceptions.MaryConfigurationException: Cannot start MARY server
at marytts.LocalMaryInterface.<init>(LocalMaryInterface.java:66)
at de.levin.util.TextToSpeech.<init>(TextToSpeech.java:27)
at de.levin.ctrl.MainCtrl.initialize(MainCtrl.java:1317)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2655)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2548)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2516)
at de.levin.sifuSays.App.start(App.java:124)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:847)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:484)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:456)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)
at java.base/java.lang.Thread.run(Thread.java:1589)
Caused by: java.lang.NullPointerException: Cannot enter synchronized block because the return value of "marytts.config.MaryConfig.getMainConfig()" is null
at marytts.util.MaryRuntimeUtils.ensureMaryStarted(MaryRuntimeUtils.java:70)
at marytts.LocalMaryInterface.<init>(LocalMaryInterface.java:64)
... 15 more
I checked the implementation in https://github.com/marytts/marytts/blob/master/marytts-runtime/src/main/java/marytts/config/MaryConfig.java and I guess the important line is
private static final ServiceLoader<MaryConfig> configLoader = ServiceLoader.load(MaryConfig.class);
The MaryConfig.class does exist in the jar File that the shade plugin created.
Any idea?
Here are my findings / thoughts: When I was trying to find out was is the issue, I found https://youtrack.jetbrains.com/issue/IDEA-240253 which sounds like a potential root cause also in the shade plugin and I recalled the Warning
[WARNING] maven-shade-plugin has detected that some files are
[WARNING] present in two or more JARs. When this happens, only one
[WARNING] single version of the file is copied to the uber jar.
but when reading the https://maven.apache.org/plugins/maven-shade-plugin/examples/includes-excludes.html page, I don't get it - my Maven skills are very limited. So should you agree, that these things belong together, then how do I need to modify my pom.xml?
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.levin</groupId>
<artifactId>sifuSays</artifactId>
<version>1.0.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<repositories>
<repository>
<id>jcenter</id>
<name>jcenter-bintray</name>
<url>https://jcenter.bintray.com</url>
</repository>
</repositories>
<dependencies>
<!-- JavaFX -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>19</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>19</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId>
<version>19</version>
</dependency>
<!-- JAXB API only -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>4.0.3</version>
<scope>runtime</scope>
</dependency>
<!-- Framegrabber to get image from movies -->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>1.5.9</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg-platform</artifactId>
<version>6.0-1.5.9</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>flandmark</artifactId>
<version>1.07-1.5.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/de.dfki.mary/marytts -->
<!-- https://mvnrepository.com/artifact/de.dfki.mary/marytts-common -->
<dependency>
<groupId>de.dfki.mary</groupId>
<artifactId>marytts-common</artifactId>
<version>5.2.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/de.dfki.mary/voice-dfki-pavoque-neutral-hsmm -->
<dependency>
<groupId>de.dfki.mary</groupId>
<artifactId>voice-dfki-prudence-hsmm</artifactId>
<version>5.2</version>
</dependency>
<dependency>
<groupId>de.dfki.mary</groupId>
<artifactId>voice-cmu-slt-hsmm</artifactId>
<version>5.2.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>11</source>
<target>11</target>
<release>11</release>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<executions>
<execution>
<!-- Default configuration for running -->
<!-- Usage: mvn clean javafx:run -->
<id>default-cli</id>
<configuration>
<mainClass>de.levin.sifuSays.App</mainClass>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>de.levin.sifuSays.AppLauncher</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<outputFile>${dir}/${project.artifactId}.jar</outputFile>
<createDependencyReducedPom>false</createDependencyReducedPom>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>de.levin.sifuSays.AppLauncher</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
In order to build the jar, I call: clean package shade:shade from the Eclipse Maven interface
In case you want to try
package de.levin.util;
import java.io.IOException;
import javax.sound.sampled.AudioInputStream;
import marytts.LocalMaryInterface;
import marytts.MaryInterface;
import marytts.exceptions.MaryConfigurationException;
import marytts.exceptions.SynthesisException;
import marytts.util.data.audio.AudioPlayer;
public class TextToSpeech {
private AudioPlayer tts;
private MaryInterface marytts;
/**
* Constructor
*/
public TextToSpeech() {
try {
marytts = new LocalMaryInterface();
marytts.setVoice("dfki-prudence-hsmm");
marytts.setAudioEffects("Rate(durScale:1.5)+Robot(amount:0)");
} catch (MaryConfigurationException ex) {
ex.printStackTrace();
}
}
/**
* Transform text to speech
*
* @param text
*/
public void speak(String text) {
// Stop the previous player
if (tts != null) {
tts.cancel();
}
try (AudioInputStream audio = marytts.generateAudio(text)) {
// Player is a thread(threads can only run one time) so it can be
// used has to be initiated every time
tts = new AudioPlayer();
tts.setAudio(audio);
tts.setDaemon(true);
tts.start();
} catch (SynthesisException | IOException ex) {
ex.printStackTrace();
}
}
}
and I call the methods from another method in another class
TextToSpeech tts = new TextToSpeech();
tts.speak("Take the stretch a little bit deeper");
One last thought: Ialso found this marytts.exceptions.MaryConfigurationException: Cannot start MARY server Not sure whether it relates?!
Thank you in advance!