From f882f7cf14c7e6c285c0c6cf14756a0653f0427d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johann=20N=2E=20L=C3=B6fflmann?= Date: Wed, 4 Jan 2023 01:26:18 +0100 Subject: [PATCH] improved error handling, avoiding System.err output in lib --- README.md | 48 +++++++++--------- build.gradle.kts | 2 +- pom.xml | 2 +- .../engines/SpeechEngine.java | 5 +- .../engines/SpeechEngineAbstract.java | 50 +++++++++++-------- .../engines/SpeechEngineNative.java | 11 ++-- .../NotSupportedOperatingSystemException.java | 32 ------------ ...ava => SpeechEngineCreationException.java} | 8 +-- .../engines/linux/SpeechEngineLinux.java | 6 ++- .../engines/macos/SpeechEngineMacOS.java | 7 ++- .../engines/windows/SpeechEngineWindows.java | 7 ++- .../jonelo/jAdapterForNativeTTS/tui/Main.java | 42 +++++++++++----- 12 files changed, 111 insertions(+), 109 deletions(-) delete mode 100644 src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/exceptions/NotSupportedOperatingSystemException.java rename src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/exceptions/{NotEvenOneVoiceAvailableException.java => SpeechEngineCreationException.java} (88%) diff --git a/README.md b/README.md index 72e1adb..d59c7e8 100644 --- a/README.md +++ b/README.md @@ -21,33 +21,31 @@ set the voice of your choice either directly or by providing voice preferences a String text = "The answer to the ultimate question of life, the universe, and everything is 42"; try { SpeechEngine speechEngine = SpeechEngineNative.getInstance(); - List voices = speechEngine.getAvailableVoices(); - if (voices.size() > 0) { - System.out.println("For now the following voices are supported:\n"); - for (Voice voice : voices) { - System.out.printf("%s\n", voice); - } - // We want to find a voice according our preferences - VoicePreferences voicePreferences = new VoicePreferences(); - voicePreferences.setLanguage("en"); // ISO-639-1 - voicePreferences.setCountry("GB"); // ISO 3166-1 Alpha-2 code - voicePreferences.setGender(VoicePreferences.Gender.FEMALE); - - Voice voice = speechEngine.findVoiceByPreferences(voicePreferences); - // simple fallback just in case our preferences didn't match any voice - if (voice == null) { - System.out.printf("Warning: Voice has not been found by the voice preferences %s\n", voicePreferences); - voice = voices.get(0); - System.out.printf("Using \"%s\" instead.\n", voice); - } - speechEngine.setVoice(voice.getName()); - speechEngine.say(text); - } else { - System.out.printf("Error: not even one voice have been found.\n"); + + System.out.println("For now the following voices are supported:\n"); + for (Voice voice : voices) { + System.out.printf("%s%n", voice); } - } catch (NotSupportedOperatingSystemException | IOException e) { + // We want to find a voice according our preferences + VoicePreferences voicePreferences = new VoicePreferences(); + voicePreferences.setLanguage("en"); // ISO-639-1 + voicePreferences.setCountry("GB"); // ISO 3166-1 Alpha-2 code + voicePreferences.setGender(VoicePreferences.Gender.FEMALE); + Voice voice = speechEngine.findVoiceByPreferences(voicePreferences); + + // simple fallback just in case our preferences didn't match any voice + if (voice == null) { + System.out.printf("Warning: Voice has not been found by the voice preferences %s%n", voicePreferences); + voice = voices.get(0); // it is guaranteed that the speechEngine supports at least one voice + System.out.printf("Using \"%s\" instead.%n", voice); + } + + speechEngine.setVoice(voice.getName()); + speechEngine.say(text); + + } catch (SpeechEngineCreationException | IOException e) { System.err.println(e.getMessage()); } ``` @@ -59,7 +57,7 @@ Please stay tuned for an artifact on Maven Central. For demonstration purposes, you can also call the Text User Interface (see also Main.java): ``` -> java -jar jadapter-for-native-tts-0.11.0.jar "The answer to the ultimate question of life, the universe, and everything is 42" +> java -jar jadapter-for-native-tts-0.12.0.jar "The answer to the ultimate question of life, the universe, and everything is 42" 0: name='Microsoft Hedda Desktop', culture='de-DE', gender='Female', age='Adult', description='Microsoft Hedda Desktop (de_DE, Female)' 1: name='Microsoft Hedda', culture='de-DE', gender='Female', age='Adult', description='Microsoft Hedda (de_DE, Female)' 2: name='Microsoft Katja', culture='de-DE', gender='Female', age='Adult', description='Microsoft Katja (de_DE, Female)' diff --git a/build.gradle.kts b/build.gradle.kts index 88f75ab..b4c6c94 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { } group = "io.github.jonelo" -version = "0.11.0" +version = "0.12.0" repositories { mavenCentral() diff --git a/pom.xml b/pom.xml index b2b96fc..fbf62a2 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ io.github.jonelo jadapter-for-native-tts - 0.11.0 + 0.12.0 jar diff --git a/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/SpeechEngine.java b/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/SpeechEngine.java index 265b58a..a0bd521 100644 --- a/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/SpeechEngine.java +++ b/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/SpeechEngine.java @@ -24,7 +24,6 @@ package io.github.jonelo.jAdapterForNativeTTS.engines; -import io.github.jonelo.jAdapterForNativeTTS.engines.exceptions.NotEvenOneVoiceAvailableException; import io.github.jonelo.jAdapterForNativeTTS.engines.exceptions.ParseException; import java.io.IOException; @@ -41,10 +40,12 @@ public interface SpeechEngine { Voice parse(String line) throws ParseException; - void findAvailableVoices() throws IOException, InterruptedException, ParseException, NotEvenOneVoiceAvailableException; + void findAvailableVoices() throws IOException, InterruptedException; List getAvailableVoices(); + List getParseExceptions(); + Voice findVoiceByPreferences(VoicePreferences voicePreferences); void setRate(int rate) throws IllegalArgumentException; diff --git a/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/SpeechEngineAbstract.java b/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/SpeechEngineAbstract.java index 6886e0d..9588433 100644 --- a/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/SpeechEngineAbstract.java +++ b/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/SpeechEngineAbstract.java @@ -24,7 +24,7 @@ package io.github.jonelo.jAdapterForNativeTTS.engines; -import io.github.jonelo.jAdapterForNativeTTS.engines.exceptions.NotEvenOneVoiceAvailableException; +import io.github.jonelo.jAdapterForNativeTTS.engines.exceptions.SpeechEngineCreationException; import io.github.jonelo.jAdapterForNativeTTS.engines.exceptions.ParseException; import io.github.jonelo.jAdapterForNativeTTS.util.os.ProcessHelper; @@ -38,61 +38,72 @@ public abstract class SpeechEngineAbstract implements SpeechEngine { protected Process process; protected List availableVoices; protected int rate; + protected List parseExceptions; public void setVoice(String voice) { this.voice = voice; } - public SpeechEngineAbstract() { + /** + * Creates a SpeechEngine for your platform. + * After construction, it is guaranteed that at least one voice can be provided. + * @throws SpeechEngineCreationException if the SpeechEngine cannot be created or if not even one voice can be found. + */ + public SpeechEngineAbstract() throws SpeechEngineCreationException { + parseExceptions = new ArrayList<>(); try { findAvailableVoices(); - } catch (Exception e) { - System.err.println(e.getMessage()); + } catch (IOException | InterruptedException e) { + throw new SpeechEngineCreationException(e.getMessage()); + } + if (availableVoices.size() == 0) { + throw new SpeechEngineCreationException(String.format("Not even one voice has been found. There were %s parse error(s).%n", getParseExceptions().size())); } this.voice = null; rate = 0; // normal voice speed } - - public SpeechEngineAbstract(String voice) { + public SpeechEngineAbstract(String voice) throws SpeechEngineCreationException { this(); this.voice = voice; } + /** + * Returns all available voices that are supported by this SpeechEngine instance. + * @return all available voices that are supported by this SpeechEngine instance. + */ public List getAvailableVoices() { return availableVoices; } - public void findAvailableVoices() throws IOException, InterruptedException, NotEvenOneVoiceAvailableException, ParseException { + /** + * Returns all ParseExceptions during creation of this SpeechEngine instance. + * @return all ParseExceptions during creation of this SpeechEngine instance. + */ + public List getParseExceptions() { + return parseExceptions; + } + + public void findAvailableVoices() throws IOException, InterruptedException { ArrayList list = ProcessHelper.startApplicationAndGetOutput(getSayExecutable(), getSayOptionsToGetSupportedVoices()); ArrayList voices = new ArrayList<>(); - int parsedLines = 0; - int parseErrors = 0; for (String line : list) { try { - parsedLines++; Voice v = parse(line); if (v != null) { voices.add(v); } } catch (ParseException e) { - parseErrors++; - e.printStackTrace(); + parseExceptions.add(e); } } availableVoices = voices; - if (availableVoices.size() == 0) { - throw new NotEvenOneVoiceAvailableException(String.format("Not even one voice has been found. There were %s parse errors.%n", parseErrors)); - } - if (parseErrors > 0) { - throw new ParseException(String.format("%s voices have been found, but there were %s parse errors.%n", availableVoices.size(), parseErrors)); - } } /** * Find a Voice instance by providing voice preferences. * @param voicePreferences the preferences for a voice - * @return an instance of the voice that matches the voicePreferences + * @return an instance of the voice that matches the voicePreferences, null if voice is not found by the voicePreferences */ public Voice findVoiceByPreferences(VoicePreferences voicePreferences) { for (Voice voice : availableVoices) { @@ -130,5 +141,4 @@ public void setRate(int rate) throws IllegalArgumentException { this.rate = rate; } - } diff --git a/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/SpeechEngineNative.java b/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/SpeechEngineNative.java index 23cba3c..750fdc7 100644 --- a/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/SpeechEngineNative.java +++ b/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/SpeechEngineNative.java @@ -24,11 +24,10 @@ package io.github.jonelo.jAdapterForNativeTTS.engines; -import io.github.jonelo.jAdapterForNativeTTS.engines.exceptions.NotEvenOneVoiceAvailableException; +import io.github.jonelo.jAdapterForNativeTTS.engines.exceptions.SpeechEngineCreationException; import io.github.jonelo.jAdapterForNativeTTS.engines.linux.SpeechEngineLinux; import io.github.jonelo.jAdapterForNativeTTS.engines.macos.SpeechEngineMacOS; import io.github.jonelo.jAdapterForNativeTTS.engines.windows.SpeechEngineWindows; -import io.github.jonelo.jAdapterForNativeTTS.engines.exceptions.NotSupportedOperatingSystemException; import java.util.Locale; @@ -39,7 +38,7 @@ public class SpeechEngineNative { private static SpeechEngine engine = null; - public static SpeechEngine getInstance() throws NotSupportedOperatingSystemException, NotEvenOneVoiceAvailableException { + public static SpeechEngine getInstance() throws SpeechEngineCreationException { if (engine == null) { String osName = System.getProperty("os.name"); String osNameForComparison = osName.replaceAll("\\s", "").toLowerCase(Locale.US); @@ -57,13 +56,9 @@ public static SpeechEngine getInstance() throws NotSupportedOperatingSystemExcep if (osNameForComparison.startsWith("linux")) { engine = new SpeechEngineLinux(); } else { - throw new NotSupportedOperatingSystemException(String.format("Operating System '%s' is not supported.", osName)); - } - if (engine.getAvailableVoices().size() == 0) { - throw new NotEvenOneVoiceAvailableException("Not even one voice has been found."); + throw new SpeechEngineCreationException(String.format("Operating System '%s' is not supported.", osName)); } } - return engine; } } diff --git a/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/exceptions/NotSupportedOperatingSystemException.java b/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/exceptions/NotSupportedOperatingSystemException.java deleted file mode 100644 index f98e135..0000000 --- a/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/exceptions/NotSupportedOperatingSystemException.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2021 Johann N. Löfflmann - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package io.github.jonelo.jAdapterForNativeTTS.engines.exceptions; - -public class NotSupportedOperatingSystemException extends Exception { - - public NotSupportedOperatingSystemException(String string) { - super(string); - } -} diff --git a/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/exceptions/NotEvenOneVoiceAvailableException.java b/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/exceptions/SpeechEngineCreationException.java similarity index 88% rename from src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/exceptions/NotEvenOneVoiceAvailableException.java rename to src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/exceptions/SpeechEngineCreationException.java index aa26b12..54728f9 100644 --- a/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/exceptions/NotEvenOneVoiceAvailableException.java +++ b/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/exceptions/SpeechEngineCreationException.java @@ -24,8 +24,8 @@ package io.github.jonelo.jAdapterForNativeTTS.engines.exceptions; -public class NotEvenOneVoiceAvailableException extends Exception { - public NotEvenOneVoiceAvailableException(String string) { - super(string); +public class SpeechEngineCreationException extends Exception { + public SpeechEngineCreationException(String string) { + super(string); } -} +} \ No newline at end of file diff --git a/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/linux/SpeechEngineLinux.java b/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/linux/SpeechEngineLinux.java index c999889..181a0e0 100644 --- a/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/linux/SpeechEngineLinux.java +++ b/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/linux/SpeechEngineLinux.java @@ -27,9 +27,13 @@ import io.github.jonelo.jAdapterForNativeTTS.engines.SpeechEngineAbstract; import io.github.jonelo.jAdapterForNativeTTS.engines.Voice; import io.github.jonelo.jAdapterForNativeTTS.engines.exceptions.ParseException; +import io.github.jonelo.jAdapterForNativeTTS.engines.exceptions.SpeechEngineCreationException; public class SpeechEngineLinux extends SpeechEngineAbstract { + public SpeechEngineLinux() throws SpeechEngineCreationException { + super(); + } public String getSayExecutable() { return "spd-say"; @@ -48,7 +52,7 @@ public Voice parse(String line) throws ParseException { String[] tokens = line.trim().split(" +"); if (tokens.length != 3) { - throw new ParseException(String.format("This is an unexpected line from %s: %s%n", getSayExecutable(), line)); + throw new ParseException(String.format("Unexpected line from %s: %s", getSayExecutable(), line)); } // we don't want the header of the output diff --git a/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/macos/SpeechEngineMacOS.java b/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/macos/SpeechEngineMacOS.java index ea758e3..a16ea9b 100644 --- a/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/macos/SpeechEngineMacOS.java +++ b/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/macos/SpeechEngineMacOS.java @@ -27,6 +27,7 @@ import io.github.jonelo.jAdapterForNativeTTS.engines.SpeechEngineAbstract; import io.github.jonelo.jAdapterForNativeTTS.engines.Voice; import io.github.jonelo.jAdapterForNativeTTS.engines.exceptions.ParseException; +import io.github.jonelo.jAdapterForNativeTTS.engines.exceptions.SpeechEngineCreationException; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -46,6 +47,10 @@ public class SpeechEngineMacOS extends SpeechEngineAbstract { // female names from say in macOS 10.13, 10.14, 10.15, 11, and 12 "Alva,Agnes,Alice,Allison,Andrea,Angelica,Anna,Amelie,Aurelie,Ava,Catarina,Carmit,Chantal,Claire,Damayanti,Ellen,Ewa,Fiona,Frederica,Ioana,Iveta,Joana,Kanya,Karen,Kate,Kathy,Katja,Klara,Kyoko,Laila,Laura,Lekha,Luciana,Mariska,Milena,Mei-Jia,Melina,Moira,Monica,Nora,Paola,Paulina,Petra,Princess,Samantha,Sara,Satu,Serena,Sin-ji,Soledad,Susan,Tessa,Ting-Ting,Veena,Vicki,Victoria,Yelda,Yuna,Zosia,Zuzana,"; + public SpeechEngineMacOS() throws SpeechEngineCreationException { + super(); + } + public String getSayExecutable() { return "say"; } @@ -97,7 +102,7 @@ public Voice parse(String line) throws ParseException { voice.setDescription(String.format("%s (%s, %s)", name, culture, gender)); return voice; } else { - throw new ParseException(String.format("This is an unexpected line from %s: %s%n", getSayExecutable(), line)); + throw new ParseException(String.format("Unexpected line from %s: %s", getSayExecutable(), line)); } } diff --git a/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/windows/SpeechEngineWindows.java b/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/windows/SpeechEngineWindows.java index 202ff5a..76b48a6 100644 --- a/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/windows/SpeechEngineWindows.java +++ b/src/main/java/io/github/jonelo/jAdapterForNativeTTS/engines/windows/SpeechEngineWindows.java @@ -27,6 +27,7 @@ import io.github.jonelo.jAdapterForNativeTTS.engines.SpeechEngineAbstract; import io.github.jonelo.jAdapterForNativeTTS.engines.Voice; import io.github.jonelo.jAdapterForNativeTTS.engines.exceptions.ParseException; +import io.github.jonelo.jAdapterForNativeTTS.engines.exceptions.SpeechEngineCreationException; public class SpeechEngineWindows extends SpeechEngineAbstract { @@ -53,6 +54,9 @@ public class SpeechEngineWindows extends SpeechEngineAbstract { "ConvertTo-Csv -NoTypeInformation | ", "Select-Object -Skip 1;"); + public SpeechEngineWindows() throws SpeechEngineCreationException { + super(); + } public String getSayExecutable() { return "PowerShell"; @@ -73,7 +77,6 @@ public String[] getSayOptionsToSayText(String text) { return new String[]{"-Command", String.join("", QUOTE, code, QUOTE)}; } - public String[] getSayOptionsToGetSupportedVoices() { return new String[]{"-Command", String.join("", QUOTE, POWER_SHELL_CODE_SUPPORTED_VOICES, QUOTE)}; } @@ -87,7 +90,7 @@ public Voice parse(String csvLine) throws ParseException { //List tokens = CSVParser.parseLine(csvLine); if (tokens.length != 5) { - throw new ParseException("This is an invalid csv line: " + csvLine); + throw new ParseException(String.format("Invalid csv line: %s", csvLine)); } Voice voice = new Voice(); diff --git a/src/main/java/io/github/jonelo/jAdapterForNativeTTS/tui/Main.java b/src/main/java/io/github/jonelo/jAdapterForNativeTTS/tui/Main.java index 59be2d0..1530a89 100644 --- a/src/main/java/io/github/jonelo/jAdapterForNativeTTS/tui/Main.java +++ b/src/main/java/io/github/jonelo/jAdapterForNativeTTS/tui/Main.java @@ -28,9 +28,8 @@ import io.github.jonelo.jAdapterForNativeTTS.engines.SpeechEngineNative; import io.github.jonelo.jAdapterForNativeTTS.engines.Voice; import io.github.jonelo.jAdapterForNativeTTS.engines.VoicePreferences; -import io.github.jonelo.jAdapterForNativeTTS.engines.exceptions.NotEvenOneVoiceAvailableException; -import io.github.jonelo.jAdapterForNativeTTS.engines.exceptions.NotSupportedOperatingSystemException; import io.github.jonelo.jAdapterForNativeTTS.engines.exceptions.ParseException; +import io.github.jonelo.jAdapterForNativeTTS.engines.exceptions.SpeechEngineCreationException; import java.io.IOException; import java.util.List; @@ -42,11 +41,13 @@ */ public class Main { + private SpeechEngine speechEngine; + /** * Prints the usage to the standard output. */ public static void usage() { - System.out.println("java -jar jadapter-for-native-tts-0.11.0.jar [word]..."); + System.out.println("java -jar jadapter-for-native-tts-0.12.0.jar [word]..."); } @@ -113,7 +114,7 @@ private VoicePreferences readVoicePreferences() { * @throws InterruptedException in case of an interrupt * @throws ParseException in case of an parse error */ - private Voice selectVoice(SpeechEngine speechEngine) throws InterruptedException, ParseException, IOException { + private Voice selectVoice(SpeechEngine speechEngine) throws InterruptedException, IOException { List voices = speechEngine.getAvailableVoices(); printVoices(voices); @@ -121,7 +122,7 @@ private Voice selectVoice(SpeechEngine speechEngine) throws InterruptedException int id; // select a voice do { - System.out.printf("Enter the voice id (1-%d) or hit enter to specify voice preferences: ", voices.size() - 1); + System.out.printf("Enter the voice id (0-%d) or hit enter to specify voice preferences: ", voices.size() - 1); Scanner scanner = new Scanner(System.in); String input = scanner.nextLine(); if (input.length() == 0) { @@ -160,18 +161,15 @@ private String concatenateArgs(String[] args) { return text.toString(); } - private void sayText(String text) { + private void sayText(Voice voice, String text) { try { - SpeechEngine speechEngine = SpeechEngineNative.getInstance(); - Voice voice = selectVoice(speechEngine); speechEngine.setVoice(voice.getName()); speechEngine.setRate(readRateFromUser()); - System.out.printf("Playing the following text: \"%s\"\n", text); + System.out.printf("Playing the following text: \"%s\"%n", text); speechEngine.say(text); // Thread.sleep(1000); // speechEngine.stopTalking(); - } catch (NotSupportedOperatingSystemException | NotEvenOneVoiceAvailableException | - IOException | InterruptedException | ParseException | IllegalArgumentException ex) { + } catch (IOException ex) { System.err.printf("Error: %s%n", ex.getMessage()); } } @@ -183,7 +181,27 @@ private void sayText(String text) { */ public Main(String[] args) { if (args.length > 0) { - sayText(concatenateArgs(args)); + try { + speechEngine = SpeechEngineNative.getInstance(); + + // the speechEngine has been created with at least one voice, + // but if there were parsing errors, we should need to know. + // Usually that shouldn't happen if you use the latest and greatest release. + if (speechEngine.getParseExceptions().size() > 0) { + System.err.printf("Warning: the SpeechEngine supports %d voice(s), but there were %d unexpected parsing errors.%n", + speechEngine.getAvailableVoices().size(), speechEngine.getParseExceptions().size()); + int errorId = 0; + for (ParseException parseException : speechEngine.getParseExceptions()) { + System.err.printf(" Parsing Error (%d): %s%n", errorId++, parseException.getMessage()); + } + System.err.printf(" Please report the above errors at https://github.com/jonelo/jAdapterForNativeTTS/issues%n%n"); + } + + Voice voice = selectVoice(speechEngine); + sayText(voice, concatenateArgs(args)); + } catch (SpeechEngineCreationException | IOException | InterruptedException e) { + System.err.printf("Error: %s%n", e.getMessage()); + } } else { usage(); }