├── .gitignore
├── DemoMedia
├── ScreenRecord.mp4
└── ScreenShoot.png
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── utopiaxc
│ │ └── utopiatts
│ │ └── ExampleInstrumentedTest.java
│ ├── debug
│ ├── ic_launcher-playstore.png
│ └── res
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ └── ic_launcher_background.xml
│ ├── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-playstore.png
│ ├── java
│ │ └── com
│ │ │ └── utopiaxc
│ │ │ └── utopiatts
│ │ │ ├── APP.java
│ │ │ ├── MainActivity.java
│ │ │ ├── engine
│ │ │ ├── CheckVoiceData.java
│ │ │ ├── GetSampleText.java
│ │ │ └── UtopiaTtsService.java
│ │ │ ├── enums
│ │ │ ├── SettingsEnum.java
│ │ │ └── ThemeModeEnum.java
│ │ │ ├── fragments
│ │ │ ├── FragmentAbout.java
│ │ │ ├── FragmentTtsSettings.java
│ │ │ └── FragmentTtsUsage.java
│ │ │ ├── tts
│ │ │ ├── MsTts.java
│ │ │ ├── Tts.java
│ │ │ ├── WsTts.java
│ │ │ ├── enums
│ │ │ │ ├── Actors.java
│ │ │ │ ├── Driver.java
│ │ │ │ ├── OutputFormat.java
│ │ │ │ ├── Regions.java
│ │ │ │ ├── Roles.java
│ │ │ │ └── Styles.java
│ │ │ └── utils
│ │ │ │ ├── ByteArrayMediaDataSource.java
│ │ │ │ ├── CommonTool.java
│ │ │ │ ├── Constants.java
│ │ │ │ ├── Ssml.java
│ │ │ │ └── WebSocketState.java
│ │ │ ├── usage
│ │ │ ├── FragmentUsageDirect.java
│ │ │ ├── FragmentUsageInnerApp.java
│ │ │ └── FragmentUsageSystem.java
│ │ │ ├── utils
│ │ │ └── ThemeUtil.java
│ │ │ └── welcome
│ │ │ ├── FragmentSetAzureToken.kt
│ │ │ ├── FragmentTtsSelect.kt
│ │ │ └── IntroActivity.kt
│ └── res
│ │ ├── drawable-v24
│ │ └── logo.png
│ │ ├── drawable
│ │ ├── ic_baseline_code_24.xml
│ │ ├── ic_baseline_help_outline_24.xml
│ │ ├── ic_baseline_help_outline_24_night.xml
│ │ ├── ic_baseline_settings_accessibility_24.xml
│ │ └── ic_sharp_hearing_24.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── fragment_set_azure_token.xml
│ │ ├── fragment_tts_select.xml
│ │ └── fragment_tts_usage.xml
│ │ ├── menu
│ │ └── bottom_nav_menu.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── navigation
│ │ └── nav_graph.xml
│ │ ├── values-land
│ │ └── dimens.xml
│ │ ├── values-night
│ │ └── themes.xml
│ │ ├── values-w1240dp
│ │ └── dimens.xml
│ │ ├── values-w600dp
│ │ └── dimens.xml
│ │ ├── values-zh
│ │ ├── arrays.xml
│ │ └── strings.xml
│ │ ├── values
│ │ ├── arrays.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ │ └── xml
│ │ ├── backup_rules.xml
│ │ ├── data_extraction_rules.xml
│ │ ├── root_preferences.xml
│ │ └── tts_engine.xml
│ ├── release
│ ├── ic_launcher-playstore.png
│ └── res
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ └── ic_launcher_background.xml
│ └── test
│ └── java
│ └── com
│ └── utopiaxc
│ └── utopiatts
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | /.gradle/
3 | /local.properties
4 | /.idea/
5 | .DS_Store
6 | /build
7 | /captures
8 | .externalNativeBuild
9 | .cxx
10 | local.properties
11 | /app/debug/
12 | /app/release/
13 |
--------------------------------------------------------------------------------
/DemoMedia/ScreenRecord.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/DemoMedia/ScreenRecord.mp4
--------------------------------------------------------------------------------
/DemoMedia/ScreenShoot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/DemoMedia/ScreenShoot.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Utopia TTS (WIP)
2 | This is an Android TTS engine based on Microsoft TTS with personal token.
3 | 这是一个基于微软TTS的安卓文字转语音引擎,使用个人Token。
4 | 正在开发中
5 |
6 | ### 使用教程
7 | 暂无
8 |
9 | ### 鸣谢
10 | 大佬[ag2s20150909](https://github.com/ag2s20150909)的[TTS](https://github.com/ag2s20150909/TTS)项目
11 |
12 | ### 演示
13 | #### 应用截图
14 | 
15 |
16 | #### 演示视频
17 | 视频见[使用演示:medias/ScreenRecord.mp4](DemoMedia/ScreenRecord.mp4)
18 |
19 | ### 开发进程
20 |
21 | 20220929:微软仿佛有什么大病,才写了三天,五十万字的额度就耗尽了,这绝对不可能啊。算了,之后再说吧,躺了。至于官网Demo驱动的,还是去用ag2s写的TTS吧,日
22 |
23 | 20221202:尝试继承了一下ag2s大佬的ws方法,确实能用,等之后优化一下就可以发一版了
24 |
25 | 20230123:进行了一些简单的优化,发布一个[正式测试版](https://github.com/UtopiaXC/UtopiaTTS/releases/tag/0.0.1-beta03)。建议使用Demo WebSocket模式,同时选择东南亚可用区(这个可用区在我这测是网络问题最小的),需要的在[Release](https://github.com/UtopiaXC/UtopiaTTS/releases/tag/0.0.1-beta03)中自取。
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | android {
7 | namespace 'com.utopiaxc.utopiatts'
8 | compileSdk 33
9 |
10 | defaultConfig {
11 | applicationId "com.utopiaxc.utopiatts"
12 | minSdk 23
13 | targetSdk 33
14 | versionCode 3
15 | versionName "0.0.1 Beta03"
16 |
17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | compileOptions {
27 | sourceCompatibility JavaVersion.VERSION_1_8
28 | targetCompatibility JavaVersion.VERSION_1_8
29 | }
30 | buildFeatures {
31 | viewBinding true
32 | }
33 | }
34 |
35 | dependencies {
36 |
37 | implementation 'androidx.appcompat:appcompat:1.6.0'
38 | implementation 'com.google.android.material:material:1.7.0'
39 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
40 | implementation 'androidx.navigation:navigation-fragment:2.5.3'
41 | implementation 'androidx.navigation:navigation-ui:2.5.3'
42 | implementation 'androidx.preference:preference:1.2.0'
43 | testImplementation 'junit:junit:4.13.2'
44 | androidTestImplementation 'androidx.test.ext:junit:1.1.5'
45 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
46 |
47 | //microsoft TTS
48 | implementation 'com.microsoft.cognitiveservices.speech:client-sdk:1.23.0'
49 |
50 | //welcome page
51 | implementation 'com.github.AppIntro:AppIntro:6.2.0'
52 |
53 | //about page
54 | implementation 'com.github.daniel-stoneuk:material-about-library:3.1.2'
55 | implementation "com.mikepenz:iconics-core:3.2.5"
56 | implementation "com.mikepenz:iconics-views:3.2.5"
57 | implementation 'com.mikepenz:google-material-typeface:3.0.1.3.original@aar'
58 | implementation 'com.mikepenz:material-design-iconic-typeface:2.2.0.5@aar'
59 | implementation 'com.mikepenz:fontawesome-typeface:5.3.1.1@aar'
60 | implementation 'com.mikepenz:octicons-typeface:3.2.0.5@aar'
61 | implementation 'com.mikepenz:meteocons-typeface:1.1.0.5@aar'
62 | implementation 'com.mikepenz:community-material-typeface:3.5.95.1@aar'
63 | implementation 'com.mikepenz:weather-icons-typeface:2.0.10.5@aar'
64 | implementation 'com.mikepenz:typeicons-typeface:2.0.7.5@aar'
65 | implementation 'com.mikepenz:entypo-typeface:1.0.0.5@aar'
66 | implementation 'com.mikepenz:devicon-typeface:2.0.0.5@aar'
67 | implementation 'com.mikepenz:foundation-icons-typeface:3.0.0.5@aar'
68 | implementation 'com.mikepenz:ionicons-typeface:2.0.1.5@aar'
69 | implementation 'com.mikepenz:pixeden-7-stroke-typeface:1.2.0.3@aar'
70 |
71 | //PersistentCookieJar
72 | implementation 'com.github.franmontiel:PersistentCookieJar:v1.0.1'
73 |
74 | //OKHTTP
75 | implementation "com.squareup.okhttp3:okhttp:5.0.0-alpha.10"
76 | implementation "com.squareup.okhttp3:okhttp-dnsoverhttps:5.0.0-alpha.10"
77 | implementation "com.squareup.okio:okio:3.2.0"
78 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/utopiaxc/utopiatts/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 | assertEquals("com.utopiaxc.utopiatts", appContext.getPackageName());
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/debug/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/debug/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/debug/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/debug/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/debug/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/debug/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/debug/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/debug/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/debug/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/debug/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/debug/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/debug/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/debug/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/debug/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/debug/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FAFAFA
4 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
24 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
36 |
37 |
38 |
41 |
42 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
56 |
57 |
58 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/APP.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.app.Application;
5 | import android.content.Context;
6 | import android.content.SharedPreferences;
7 | import android.os.Handler;
8 | import android.os.Looper;
9 | import android.util.Log;
10 | import android.widget.Toast;
11 |
12 | import androidx.annotation.NonNull;
13 | import androidx.annotation.Nullable;
14 |
15 | import com.franmontiel.persistentcookiejar.PersistentCookieJar;
16 | import com.franmontiel.persistentcookiejar.cache.SetCookieCache;
17 | import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor;
18 |
19 | import java.io.File;
20 | import java.net.InetAddress;
21 | import java.net.UnknownHostException;
22 | import java.util.Arrays;
23 | import java.util.Set;
24 | import java.util.concurrent.TimeUnit;
25 |
26 | import okhttp3.ConnectionSpec;
27 | import okhttp3.HttpUrl;
28 | import okhttp3.OkHttpClient;
29 | import okhttp3.dnsoverhttps.DnsOverHttps;
30 |
31 | @SuppressWarnings("unused")
32 | public class APP extends Application {
33 | /**
34 | * 全局的android.content.Context
35 | */
36 | @SuppressLint("StaticFieldLeak")
37 | private static Context mContext;
38 |
39 |
40 | /**
41 | * 用于DoH的@see:okhttp3.OkHttpClient
42 | */
43 | private static final OkHttpClient bootClient = new OkHttpClient.Builder()
44 | .connectionSpecs(Arrays.asList(ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS, ConnectionSpec.CLEARTEXT))
45 | .fastFallback(true)
46 | .build();
47 | private static volatile DnsOverHttps dns = null;
48 |
49 | private static DnsOverHttps getDns() {
50 |
51 | if (dns == null) {
52 | synchronized (APP.class) {
53 | if (dns == null) {
54 | OkHttpClient temp = APP.bootClient.newBuilder().cache(getCache("doh", 1024 * 1024 * 100)).build();
55 | dns = new DnsOverHttps.Builder()
56 | .client(temp)
57 | .url(HttpUrl.get("https://dns.alidns.com/dns-query"))
58 | .bootstrapDnsHosts(
59 | getByName("223.5.5.5"),
60 | getByName("223.6.6.6"),
61 | getByName("2400:3200::1"),
62 | getByName("2400:3200:baba::1")
63 | )
64 |
65 | .includeIPv6(true)
66 | .build();
67 | }
68 | }
69 | }
70 | return dns;
71 | }
72 | //private static final DnsOverHttps dns = new DnsOverHttps.Builder().client(
73 |
74 |
75 | private static volatile OkHttpClient okHttpClient = null;
76 |
77 | public static OkHttpClient getOkHttpClient() {
78 | if (okHttpClient == null) {
79 | synchronized (APP.class) {
80 | if (okHttpClient == null) {
81 |
82 | okHttpClient = new OkHttpClient.Builder()
83 | .cookieJar(new PersistentCookieJar(new SetCookieCache(),
84 | new SharedPrefsCookiePersistor(getContext())))
85 | .pingInterval(20, TimeUnit.SECONDS) // 设置 PING 帧发送间隔
86 | .fastFallback(true)
87 | .dns(s -> {
88 | // if("speech.platform.bing.com".equals(s)){
89 | // s="cn.bing.com";
90 | // }
91 | return getDns().lookup(s);
92 | })
93 | .build();
94 | }
95 | }
96 | }
97 | return okHttpClient;
98 | }
99 |
100 |
101 | public static void putString(String key, @Nullable String value) {
102 | SharedPreferences.Editor editor = getSharedPreferences().edit();
103 | editor.putString(key, value);
104 | editor.apply();
105 |
106 | }
107 |
108 |
109 | public static void putStringSet(String key, @Nullable Set values) {
110 | SharedPreferences.Editor editor = getSharedPreferences().edit();
111 | editor.putStringSet(key, values);
112 | editor.apply();
113 |
114 | }
115 |
116 |
117 | public static void putInt(String key, int value) {
118 | SharedPreferences.Editor editor = getSharedPreferences().edit();
119 | editor.putInt(key, value);
120 | editor.apply();
121 |
122 | }
123 |
124 |
125 | public static void putLong(String key, long value) {
126 | SharedPreferences.Editor editor = getSharedPreferences().edit();
127 | editor.putLong(key, value);
128 | editor.apply();
129 | }
130 |
131 |
132 | public static void putFloat(String key, float value) {
133 | SharedPreferences.Editor editor = getSharedPreferences().edit();
134 | editor.putFloat(key, value);
135 | editor.apply();
136 |
137 | }
138 |
139 |
140 | public static void putBoolean(String key, boolean value) {
141 | SharedPreferences.Editor editor = getSharedPreferences().edit();
142 | editor.putBoolean(key, value);
143 | editor.apply();
144 |
145 | }
146 |
147 |
148 | @Nullable
149 | public static String getString(String key, @Nullable String defValue) {
150 | return getSharedPreferences().getString(key, defValue);
151 | }
152 |
153 |
154 | @Nullable
155 | public static Set getStringSet(String key, @Nullable Set defValues) {
156 | return getSharedPreferences().getStringSet(key, defValues);
157 | }
158 |
159 |
160 | public static int getInt(String key, int defValue) {
161 | return getSharedPreferences().getInt(key, defValue);
162 | }
163 |
164 |
165 | public static long getLong(String key, long defValue) {
166 | return getSharedPreferences().getLong(key, defValue);
167 | }
168 |
169 | public static float getFloat(String key, float defValue) {
170 | return getSharedPreferences().getFloat(key, defValue);
171 | }
172 |
173 |
174 | public static boolean getBoolean(String key, boolean defValue) {
175 | return getSharedPreferences().getBoolean(key, defValue);
176 | }
177 |
178 |
179 | private static final class PreferencesHolder {
180 | public static final SharedPreferences preferences = getContext().getSharedPreferences("TTS", Context.MODE_PRIVATE);
181 | }
182 |
183 | public static SharedPreferences getSharedPreferences() {
184 | return PreferencesHolder.preferences;
185 | }
186 |
187 | public static @Nullable
188 | InetAddress getByName(@NonNull String ip) {
189 |
190 | try {
191 | return InetAddress.getByName(ip);
192 | } catch (UnknownHostException e) {
193 | return null;
194 | }
195 | }
196 |
197 |
198 | public static Context getContext() {
199 | if (mContext == null) {
200 | mContext = initAndGetAppCtxWithReflection();
201 | }
202 | return mContext;
203 | }
204 |
205 |
206 | public static okhttp3.Cache getCache(String name, int maxSize) {
207 | File file = new File(getContext().getExternalCacheDir(), name);
208 | if (!file.exists()) {
209 | boolean mkdirs = file.mkdirs();
210 | if (!mkdirs) {
211 | Log.e(APP.class.getSimpleName(), "创建文件夹失败");
212 | }
213 | }
214 | return new okhttp3.Cache(file, maxSize);
215 | }
216 |
217 |
218 | /**
219 | * 反射获取Context
220 | */
221 | @SuppressLint({"DiscouragedPrivateApi", "PrivateApi"})
222 | private static Context initAndGetAppCtxWithReflection() {
223 | // Fallback, should only run once per non default process.
224 | try {
225 | return (Context) Class.forName("android.app.ActivityThread")
226 | .getDeclaredMethod("currentApplication")
227 | .invoke(null);
228 | } catch (Exception e) {
229 | return null;
230 | }
231 |
232 | }
233 |
234 |
235 | @Override
236 | public void onCreate() {
237 | super.onCreate();
238 | //Security.insertProviderAt(Conscrypt.newProvider(), 1);
239 | mContext = this.getApplicationContext();
240 | }
241 |
242 | public static void showToast(String msg) {
243 | if (isMainThread()) {
244 | Toast.makeText(getContext(), msg, Toast.LENGTH_LONG).show();
245 | } else {
246 | new Handler(Looper.getMainLooper()).post(() -> Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show());
247 | }
248 | }
249 |
250 | public static boolean isMainThread() {
251 | return Looper.getMainLooper().getThread().getId() == Thread.currentThread().getId();
252 | }
253 |
254 | @Override
255 | protected void attachBaseContext(Context base) {
256 | super.attachBaseContext(base);
257 | //Security.insertProviderAt(Conscrypt.newProvider(), 1);
258 | mContext = getApplicationContext();
259 | }
260 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts;
2 |
3 | import android.content.Intent;
4 | import android.content.SharedPreferences;
5 | import android.os.Bundle;
6 |
7 | import androidx.appcompat.app.AppCompatActivity;
8 | import androidx.navigation.NavController;
9 | import androidx.navigation.Navigation;
10 | import androidx.navigation.ui.AppBarConfiguration;
11 | import androidx.navigation.ui.NavigationUI;
12 | import androidx.preference.PreferenceManager;
13 |
14 | import com.utopiaxc.utopiatts.databinding.ActivityMainBinding;
15 | import com.utopiaxc.utopiatts.enums.SettingsEnum;
16 | import com.utopiaxc.utopiatts.tts.MsTts;
17 | import com.utopiaxc.utopiatts.tts.WsTts;
18 | import com.utopiaxc.utopiatts.tts.enums.Driver;
19 | import com.utopiaxc.utopiatts.utils.ThemeUtil;
20 | import com.utopiaxc.utopiatts.welcome.IntroActivity;
21 |
22 | public class MainActivity extends AppCompatActivity {
23 | @Override
24 | protected void onCreate(Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | com.utopiaxc.utopiatts.databinding.ActivityMainBinding binding =
27 | ActivityMainBinding.inflate(getLayoutInflater());
28 | setContentView(binding.getRoot());
29 | //Night mode
30 | SharedPreferences sharedPreferences =
31 | PreferenceManager.getDefaultSharedPreferences(this);
32 | ThemeUtil.setThemeMode(sharedPreferences.getString(SettingsEnum.THEME.getKey(),
33 | (String) SettingsEnum.THEME.getDefaultValue()));
34 | //First install check
35 | if (sharedPreferences.getBoolean(SettingsEnum.FIRST_BOOT.getKey(),
36 | (Boolean) SettingsEnum.FIRST_BOOT.getDefaultValue())) {
37 | //Welcome
38 | Intent intent = new Intent(this, IntroActivity.class);
39 | startActivity(intent);
40 | finish();
41 | return;
42 | }
43 |
44 | //Init tts engine
45 | if (sharedPreferences.getString(SettingsEnum.TTS_DRIVER.getKey(), Driver.AZURE_SDK.getId())
46 | .equals(Driver.AZURE_SDK.getId())){
47 | MsTts.getInstance(getApplicationContext());
48 | }else{
49 | WsTts.getInstance(getApplicationContext());
50 | }
51 | AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
52 | R.id.fragment_tts_settings, R.id.fragment_tts_usage, R.id.fragment_about)
53 | .build();
54 | NavController navController =
55 | Navigation.findNavController(this, R.id.nav_host_fragment_activity_main);
56 | NavigationUI
57 | .setupActionBarWithNavController(this, navController, appBarConfiguration);
58 | NavigationUI.setupWithNavController(binding.navView, navController);
59 | }
60 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/engine/CheckVoiceData.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.engine;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.speech.tts.TextToSpeech;
7 | import android.util.Log;
8 |
9 | import java.util.ArrayList;
10 | import java.util.Arrays;
11 |
12 | public class CheckVoiceData extends Activity {
13 | private static final String TAG = CheckVoiceData.class.getSimpleName();
14 |
15 | @Override
16 | protected void onCreate(Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | int result = TextToSpeech.Engine.CHECK_VOICE_DATA_PASS;
19 |
20 | ArrayList unavailable = new ArrayList<>();
21 |
22 | ArrayList available = new ArrayList<>(
23 | Arrays.asList("zho-CHN", "zho-HKG", "zho-TWN"));
24 |
25 |
26 | Intent returnData = new Intent();
27 | Log.i(TAG, available.toString());
28 |
29 | returnData.putStringArrayListExtra(TextToSpeech.Engine.EXTRA_AVAILABLE_VOICES, available);
30 | returnData.putStringArrayListExtra(
31 | TextToSpeech.Engine.EXTRA_UNAVAILABLE_VOICES, unavailable);
32 | setResult(result, returnData);
33 | finish();
34 | }
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/engine/GetSampleText.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.engine;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.speech.tts.TextToSpeech;
7 | import android.util.Log;
8 |
9 | import com.utopiaxc.utopiatts.R;
10 |
11 | import java.util.Locale;
12 |
13 | public class GetSampleText extends Activity {
14 | private static final String TAG = "GetSampleText";
15 |
16 | @Override
17 | protected void onCreate(Bundle savedInstanceState) {
18 | Log.i(TAG, "onCreate");
19 | super.onCreate(savedInstanceState);
20 | int result = TextToSpeech.LANG_AVAILABLE;
21 | Intent returnData = new Intent();
22 |
23 | Intent i = getIntent();
24 | String language = i.getExtras().getString("language");
25 | String country = i.getExtras().getString("country");
26 | String variant = i.getExtras().getString("variant");
27 | Log.i(TAG, language + "_" + country + "_" + variant);
28 | Locale locale = new Locale(language, country);
29 | returnData.putExtra("sampleText", getText(R.string.tts_demo_text));
30 | setResult(result, returnData);
31 | finish();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/engine/UtopiaTtsService.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.engine;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.app.Notification;
5 | import android.app.NotificationChannel;
6 | import android.app.NotificationManager;
7 | import android.app.PendingIntent;
8 | import android.content.Context;
9 | import android.content.Intent;
10 | import android.content.SharedPreferences;
11 | import android.os.Build;
12 | import android.speech.tts.SynthesisCallback;
13 | import android.speech.tts.SynthesisRequest;
14 | import android.speech.tts.TextToSpeech;
15 | import android.speech.tts.TextToSpeechService;
16 | import android.util.Log;
17 |
18 | import androidx.preference.PreferenceManager;
19 |
20 | import com.utopiaxc.utopiatts.enums.SettingsEnum;
21 | import com.utopiaxc.utopiatts.tts.MsTts;
22 | import com.utopiaxc.utopiatts.tts.Tts;
23 | import com.utopiaxc.utopiatts.tts.WsTts;
24 | import com.utopiaxc.utopiatts.tts.enums.Driver;
25 | import com.utopiaxc.utopiatts.tts.enums.OutputFormat;
26 |
27 | import java.util.ArrayList;
28 | import java.util.Arrays;
29 | import java.util.List;
30 | import java.util.Locale;
31 |
32 | public class UtopiaTtsService extends TextToSpeechService {
33 | private static final String TAG = "UtopiaTtsService";
34 | private volatile String[] mCurrentLanguage = null;
35 | NotificationManager notificationManager;
36 | Notification.Builder notificationBuilder;
37 | final String notificationChannelId = UtopiaTtsService.class.getName();
38 | final String notificationName = "Utopia TTS Service Notification";
39 | private static final int NOTIFICATION_ID = 1;
40 | private static final String ACTION_STOP_SERVICE = "action_stop_service";
41 | private Tts mTts;
42 | private Thread mSynthesizeTextThread;
43 |
44 | @Override
45 | public void onCreate() {
46 | Log.i(TAG, "onCreate");
47 | super.onCreate();
48 | if (PreferenceManager.getDefaultSharedPreferences(this)
49 | .getString(SettingsEnum.TTS_DRIVER.getKey(), Driver.AZURE_SDK.getId())
50 | .equals(Driver.AZURE_SDK.getId())) {
51 | mTts = MsTts.getInstance(getApplicationContext());
52 | } else {
53 | mTts = WsTts.getInstance(getApplicationContext());
54 | }
55 | startForegroundService();
56 | }
57 |
58 | @Override
59 | public void onDestroy() {
60 | Log.i(TAG, "onDestroy");
61 | mTts.stopSpeak();
62 | if (mSynthesizeTextThread != null) {
63 | mSynthesizeTextThread.interrupt();
64 | }
65 | super.onDestroy();
66 | }
67 |
68 | @Override
69 | protected int onIsLanguageAvailable(String lang, String country, String variant) {
70 | if ((Locale.SIMPLIFIED_CHINESE.getISO3Language().equals(lang)) ||
71 | (Locale.US.getISO3Language().equals(lang))) {
72 | if ((Locale.SIMPLIFIED_CHINESE.getISO3Country().equals(country)) ||
73 | (Locale.US.getISO3Country().equals(country))) {
74 | return TextToSpeech.LANG_COUNTRY_AVAILABLE;
75 | }
76 | return TextToSpeech.LANG_AVAILABLE;
77 | }
78 | return TextToSpeech.LANG_NOT_SUPPORTED;
79 | }
80 |
81 | @Override
82 | protected String[] onGetLanguage() {
83 | return mCurrentLanguage;
84 | }
85 |
86 | @Override
87 | protected int onLoadLanguage(String lang, String country, String variant) {
88 | lang = lang == null ? "" : lang;
89 | country = country == null ? "" : country;
90 | variant = variant == null ? "" : variant;
91 | int result = onIsLanguageAvailable(lang, country, variant);
92 | if (result == TextToSpeech.LANG_COUNTRY_AVAILABLE ||
93 | TextToSpeech.LANG_AVAILABLE == result ||
94 | result == TextToSpeech.LANG_COUNTRY_VAR_AVAILABLE) {
95 | mCurrentLanguage = new String[]{lang, country, variant};
96 | }
97 | return result;
98 | }
99 |
100 | @Override
101 | protected void onStop() {
102 | Log.i(TAG, "onStop");
103 | mTts.stopSpeak();
104 | if (mSynthesizeTextThread != null) {
105 | mSynthesizeTextThread.interrupt();
106 | }
107 | }
108 |
109 | @SuppressLint("WrongConstant")
110 | @Override
111 | protected void onSynthesizeText(SynthesisRequest synthesisRequest,
112 | SynthesisCallback synthesisCallback) {
113 | Log.i(TAG, "onSynthesizeText");
114 | int load = onLoadLanguage(synthesisRequest.getLanguage(), synthesisRequest.getCountry(),
115 | synthesisRequest.getVariant());
116 | if (load == TextToSpeech.LANG_NOT_SUPPORTED) {
117 | synthesisCallback.error();
118 | Log.i(TAG, "LANG_NOT_SUPPORTED");
119 | return;
120 | }
121 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
122 | OutputFormat outputFormat = OutputFormat.getOutputFormat(
123 | preferences.getString(SettingsEnum.OUTPUT_FORMAT.getKey(),
124 | (String) SettingsEnum.OUTPUT_FORMAT.getDefaultValue()));
125 | synthesisCallback.start(outputFormat.getSoundFrequency(),
126 | outputFormat.getAudioFormat(), 1);
127 | mSynthesizeTextThread = new Thread(new SynthesizeText(synthesisRequest, synthesisCallback));
128 | mSynthesizeTextThread.start();
129 | try {
130 | mSynthesizeTextThread.join();
131 | } catch (InterruptedException e) {
132 | e.printStackTrace();
133 | }
134 | }
135 |
136 | class SynthesizeText implements Runnable {
137 | SynthesisRequest synthesisRequest;
138 | SynthesisCallback synthesisCallback;
139 |
140 | public SynthesizeText(SynthesisRequest synthesisRequest,
141 | SynthesisCallback synthesisCallback) {
142 | this.synthesisRequest = synthesisRequest;
143 | this.synthesisCallback = synthesisCallback;
144 | }
145 |
146 | @Override
147 | public void run() {
148 | String textToSpeech = synthesisRequest.getCharSequenceText().toString();
149 | List text = new ArrayList<>();
150 | StringBuilder textBuilder = new StringBuilder();
151 | for (int i = 0; i < textToSpeech.length(); i++) {
152 | char c = textToSpeech.charAt(i);
153 | if (".。!!??".contains(String.valueOf(c))) {
154 | textBuilder.append(c);
155 | if (textBuilder.length() >= 50) {
156 | text.add(textBuilder.toString());
157 | textBuilder.setLength(0);
158 | }
159 | } else {
160 | textBuilder.append(c);
161 | }
162 | }
163 | text.add(textBuilder.toString());
164 | for (String s : text) {
165 | Log.i(TAG, s);
166 | if (!mTts.doSpeak(s,
167 | synthesisRequest.getPitch(), synthesisRequest.getSpeechRate(),
168 | synthesisCallback)) {
169 | synthesisCallback.error();
170 | return;
171 | }
172 | }
173 | synthesisCallback.done();
174 | }
175 | }
176 |
177 | private void startForegroundService() {
178 | notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
179 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
180 | NotificationChannel notificationChannel = new NotificationChannel(notificationChannelId,
181 | notificationName, NotificationManager.IMPORTANCE_LOW);
182 | notificationManager.createNotificationChannel(notificationChannel);
183 |
184 | }
185 | startForeground(NOTIFICATION_ID, getNotification());
186 | }
187 |
188 | private Notification getNotification() {
189 | Intent stopSelf = new Intent(this, UtopiaTtsService.class);
190 | stopSelf.setAction(ACTION_STOP_SERVICE);
191 | PendingIntent pStopSelf = PendingIntent.getService(this, 0, stopSelf,
192 | PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
193 | notificationBuilder = new Notification.Builder(this)
194 | .setOnlyAlertOnce(true)
195 | .setVibrate(null)
196 | .setSound(null)
197 | .setLights(0, 0, 0)
198 | .setContentTitle("Utopia TTS Service")
199 | .setContentText("UtopiaTTS Service is running...");
200 |
201 | Notification.Action action;
202 | action = new Notification.Action.Builder(null, "stop", pStopSelf).build();
203 | notificationBuilder.addAction(action);
204 |
205 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
206 | notificationBuilder.setChannelId(notificationChannelId);
207 | }
208 | return notificationBuilder.build();
209 | }
210 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/enums/SettingsEnum.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.enums;
2 |
3 | import com.utopiaxc.utopiatts.tts.enums.Driver;
4 | import com.utopiaxc.utopiatts.tts.enums.OutputFormat;
5 |
6 | public enum SettingsEnum {
7 |
8 | THEME("THEME", "theme", "auto"),
9 | FIRST_BOOT("FIRST_BOOT", "first_boot", true),
10 | AZURE_REGION("AZURE_REGION", "azure_region", ""),
11 | AZURE_TOKEN("AZURE_TOKEN", "azure_token", "NULL"),
12 | OUTPUT_FORMAT("OUTPUT_FORMAT", "output_format",
13 | OutputFormat.OGG_48K_HZ_16_BIT_MONO_OPUS.getName()),
14 | ACTOR("ACTOR", "actor", ""),
15 | ROLE("ROLE", "role", ""),
16 | STYLE("STYLE", "style", ""),
17 | STYLE_DEGREE("STYLE_DEGREE", "style_degree", 0),
18 | TTS_DRIVER("TTS_DRIVER", "tts_driver", Driver.AZURE_SDK.getId());
19 | private final String mName;
20 | private final String mKey;
21 | private final Object mDefaultValue;
22 |
23 | SettingsEnum(String name, String key, Object defaultValue) {
24 | mName = name;
25 | mKey = key;
26 | mDefaultValue = defaultValue;
27 | }
28 |
29 | public String getName() {
30 | return mName;
31 | }
32 |
33 | public String getKey() {
34 | return mKey;
35 | }
36 |
37 | public Object getDefaultValue() {
38 | return mDefaultValue;
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/enums/ThemeModeEnum.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.enums;
2 |
3 | public enum ThemeModeEnum {
4 | AUTO_MODE("auto", "Auto Mode"),
5 | DAY_MODE("day", "Day Mode"),
6 | NIGHT_MODE("night", "Night Mode");
7 |
8 | private final String mode;
9 | private final String description;
10 | ThemeModeEnum(String mode, String description) {
11 | this.mode = mode;
12 | this.description = description;
13 | }
14 |
15 | public String getMode() {
16 | return mode;
17 | }
18 | public String getDescription() {
19 | return description;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/fragments/FragmentAbout.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.fragments;
2 |
3 | import android.app.AlertDialog;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.net.Uri;
7 |
8 | import androidx.preference.PreferenceManager;
9 |
10 | import com.danielstone.materialaboutlibrary.ConvenienceBuilder;
11 | import com.danielstone.materialaboutlibrary.MaterialAboutFragment;
12 | import com.danielstone.materialaboutlibrary.items.MaterialAboutActionItem;
13 | import com.danielstone.materialaboutlibrary.items.MaterialAboutTitleItem;
14 | import com.danielstone.materialaboutlibrary.model.MaterialAboutCard;
15 | import com.danielstone.materialaboutlibrary.model.MaterialAboutList;
16 | import com.mikepenz.community_material_typeface_library.CommunityMaterial;
17 | import com.mikepenz.iconics.IconicsDrawable;
18 | import com.utopiaxc.utopiatts.MainActivity;
19 | import com.utopiaxc.utopiatts.R;
20 |
21 | public class FragmentAbout extends MaterialAboutFragment {
22 |
23 | @Override
24 | protected MaterialAboutList getMaterialAboutList(Context activityContext) {
25 | //app cards
26 | MaterialAboutCard.Builder appCardBuilder = new MaterialAboutCard.Builder();
27 |
28 | //copyright card
29 | appCardBuilder.addItem(new MaterialAboutTitleItem.Builder()
30 | .text(R.string.app_name)
31 | .desc(R.string.rights)
32 | .icon(R.mipmap.ic_launcher)
33 | .build());
34 |
35 | //version card
36 | appCardBuilder.addItem(ConvenienceBuilder.createVersionActionItem(activityContext,
37 | new IconicsDrawable(activityContext)
38 | .icon(CommunityMaterial.Icon.cmd_code_array)
39 | .sizeDp(18),
40 | requireActivity().getString(R.string.version),
41 | true));
42 |
43 | //change log card
44 | appCardBuilder.addItem(new MaterialAboutActionItem.Builder()
45 | .text(R.string.change_log)
46 | .icon(new IconicsDrawable(activityContext)
47 | .icon(CommunityMaterial.Icon.cmd_content_paste)
48 | .sizeDp(18))
49 | .setOnClickAction(ConvenienceBuilder.createWebViewDialogOnClickAction(
50 | activityContext,
51 | requireActivity().getString(R.string.change_log_title),
52 | getString(R.string.github_release_link), true, false))
53 | .build());
54 |
55 | //license card
56 | appCardBuilder.addItem(new MaterialAboutActionItem.Builder()
57 | .text(R.string.licenses)
58 | .icon(new IconicsDrawable(activityContext)
59 | .icon(CommunityMaterial.Icon.cmd_code_tags)
60 | .sizeDp(18))
61 | .setOnClickAction(() -> {
62 | //Intent intent = new Intent(activityContext, LicencesActivity.class);
63 | //startActivity(intent);
64 | })
65 | .build());
66 |
67 | //author cards
68 | MaterialAboutCard.Builder authorCardBuilder = new MaterialAboutCard.Builder();
69 | authorCardBuilder.title(R.string.author);
70 |
71 | //author card
72 | authorCardBuilder.addItem(new MaterialAboutActionItem.Builder()
73 | .text(R.string.author_name)
74 | .icon(new IconicsDrawable(activityContext)
75 | .icon(CommunityMaterial.Icon.cmd_account)
76 | .sizeDp(18))
77 | .build());
78 |
79 | //github card
80 | authorCardBuilder.addItem(new MaterialAboutActionItem.Builder()
81 | .text(R.string.follow_on_github)
82 | .icon(new IconicsDrawable(activityContext)
83 | .icon(CommunityMaterial.Icon.cmd_github_circle)
84 | .sizeDp(18))
85 | .setOnClickAction(ConvenienceBuilder.createWebsiteOnClickAction(
86 | activityContext, Uri.parse(getString(R.string.github_link))))
87 | .build());
88 |
89 | //email feedback card
90 | authorCardBuilder.addItem(ConvenienceBuilder.createEmailItem(activityContext,
91 | new IconicsDrawable(activityContext)
92 | .icon(CommunityMaterial.Icon.cmd_email)
93 | .sizeDp(18),
94 | requireActivity().getString(R.string.feedback_by_email),
95 | true,
96 | getString(R.string.user_email),
97 | requireActivity().getString(R.string.feedback_subject)));
98 |
99 | //settings card
100 | MaterialAboutCard.Builder settingsCardBuilder = new MaterialAboutCard.Builder();
101 | settingsCardBuilder.title(R.string.settings);
102 |
103 | //clear profiles
104 | settingsCardBuilder.addItem(new MaterialAboutActionItem.Builder()
105 | .text(R.string.clear_all_profiles)
106 | .icon(new IconicsDrawable(activityContext)
107 | .icon(CommunityMaterial.Icon.cmd_delete)
108 | .sizeDp(18))
109 | .setOnClickAction(() -> new AlertDialog.Builder(getContext())
110 | .setTitle(R.string.warning)
111 | .setMessage(R.string.clear_all_profiles_confirm)
112 | .setPositiveButton(R.string.confirm, (dialog, which) -> {
113 | PreferenceManager.getDefaultSharedPreferences(requireActivity())
114 | .edit().clear().apply();
115 | Intent intent = new Intent(requireContext(), MainActivity.class);
116 | startActivity(intent);
117 | requireActivity().finish();
118 | })
119 | .setNegativeButton(R.string.cancel, null)
120 | .create()
121 | .show())
122 | .build());
123 | return new MaterialAboutList(appCardBuilder.build(),
124 | authorCardBuilder.build(),
125 | settingsCardBuilder.build());
126 | }
127 |
128 | @Override
129 | public void onDestroyView() {
130 | super.onDestroyView();
131 | }
132 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/fragments/FragmentTtsSettings.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.fragments;
2 |
3 | import android.app.AlertDialog;
4 | import android.content.SharedPreferences;
5 | import android.os.Bundle;
6 | import android.text.InputType;
7 | import android.util.Log;
8 |
9 | import androidx.preference.EditTextPreference;
10 | import androidx.preference.ListPreference;
11 | import androidx.preference.PreferenceFragmentCompat;
12 | import androidx.preference.PreferenceManager;
13 |
14 |
15 | import com.utopiaxc.utopiatts.R;
16 | import com.utopiaxc.utopiatts.enums.SettingsEnum;
17 | import com.utopiaxc.utopiatts.tts.MsTts;
18 | import com.utopiaxc.utopiatts.tts.Tts;
19 | import com.utopiaxc.utopiatts.tts.WsTts;
20 | import com.utopiaxc.utopiatts.tts.enums.Actors;
21 | import com.utopiaxc.utopiatts.tts.enums.Driver;
22 | import com.utopiaxc.utopiatts.tts.enums.Regions;
23 |
24 | import java.util.Objects;
25 |
26 | public class FragmentTtsSettings extends PreferenceFragmentCompat {
27 |
28 | @Override
29 | public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
30 | Tts tts;
31 | SharedPreferences sharedPreferences =
32 | PreferenceManager.getDefaultSharedPreferences(requireActivity());
33 | if (sharedPreferences.getString(SettingsEnum.TTS_DRIVER.getKey(), Driver.AZURE_SDK.getId())
34 | .equals(Driver.AZURE_SDK.getId())) {
35 | tts = MsTts.getInstance(requireActivity().getApplicationContext());
36 | } else {
37 | tts = WsTts.getInstance(requireActivity().getApplicationContext());
38 | }
39 | setPreferencesFromResource(R.xml.root_preferences, rootKey);
40 | EditTextPreference azureToken = findPreference(SettingsEnum.AZURE_TOKEN.getKey());
41 | Objects.requireNonNull(azureToken).setOnBindEditTextListener(editText -> editText
42 | .setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD));
43 | azureToken.setSummary(null);
44 | azureToken.setOnPreferenceChangeListener((preference, newValue) -> {
45 | boolean ok = MsTts.testAzureConfig((String) newValue,
46 | Regions.getRegion(PreferenceManager
47 | .getDefaultSharedPreferences(requireActivity())
48 | .getString(SettingsEnum.AZURE_REGION.getKey(),
49 | (String) SettingsEnum.AZURE_REGION.getDefaultValue()))
50 | .getId());
51 | if (ok) {
52 | new AlertDialog.Builder(requireActivity()).setTitle(R.string.success)
53 | .setMessage(R.string.success_azure_token)
54 | .setPositiveButton(R.string.confirm, null)
55 | .create()
56 | .show();
57 | } else {
58 | new AlertDialog.Builder(requireActivity()).setTitle(R.string.error)
59 | .setMessage(R.string.error_azure_token)
60 | .setPositiveButton(R.string.confirm, null)
61 | .create()
62 | .show();
63 | }
64 | tts.initTts();
65 | return ok;
66 | });
67 |
68 | ListPreference listActors = findPreference(SettingsEnum.ACTOR.getKey());
69 | assert listActors != null;
70 | listActors.setOnPreferenceChangeListener((preference, newValue) -> {
71 | if (Actors.getActor((String) newValue).isPre()) {
72 | if (Regions.getRegion(sharedPreferences.getString(SettingsEnum.AZURE_REGION
73 | .getKey(),
74 | String.valueOf(SettingsEnum.AZURE_REGION.getDefaultValue())))
75 | .isNotSupportPre()) {
76 | new AlertDialog.Builder(requireActivity()).setTitle(R.string.error)
77 | .setMessage(R.string.region_not_support_pre)
78 | .setPositiveButton(R.string.confirm, null)
79 | .create()
80 | .show();
81 | return false;
82 | }
83 | }
84 | tts.initTts();
85 | return true;
86 | });
87 |
88 | ListPreference listRegion = findPreference(SettingsEnum.AZURE_REGION.getKey());
89 | assert listRegion != null;
90 | listRegion.setOnPreferenceChangeListener((preference, newValue) -> {
91 | if (Actors.getActor(sharedPreferences.getString(SettingsEnum.ACTOR.getKey(),
92 | (String) SettingsEnum.ACTOR.getDefaultValue())).isPre()) {
93 | if (Regions.getRegion((String) newValue).isNotSupportPre()) {
94 | new AlertDialog.Builder(requireActivity()).setTitle(R.string.error)
95 | .setMessage(R.string.actor_is_pre)
96 | .setPositiveButton(R.string.confirm, null)
97 | .create()
98 | .show();
99 | }
100 | return false;
101 | }
102 | return true;
103 | });
104 |
105 | ListPreference listFormat = findPreference(SettingsEnum.OUTPUT_FORMAT.getKey());
106 | assert listFormat != null;
107 | listFormat.setOnPreferenceChangeListener((preference, newValue) -> {
108 | new AlertDialog.Builder(requireActivity()).setTitle(R.string.warning)
109 | .setMessage(R.string.warning_of_output_format)
110 | .setPositiveButton(R.string.confirm, null)
111 | .create()
112 | .show();
113 | return true;
114 | });
115 |
116 | EditTextPreference editTextPreferenceToken = findPreference(
117 | SettingsEnum.AZURE_TOKEN.getKey());
118 | assert editTextPreferenceToken != null;
119 | editTextPreferenceToken.setEnabled(Driver.AZURE_SDK.getId().equals(
120 | sharedPreferences.getString(SettingsEnum.TTS_DRIVER.getKey(),
121 | String.valueOf(SettingsEnum.TTS_DRIVER.getDefaultValue()))));
122 |
123 | ListPreference listDriver = findPreference(SettingsEnum.TTS_DRIVER.getKey());
124 | assert listDriver != null;
125 | listDriver.setOnPreferenceChangeListener((preference, newValue) -> {
126 | editTextPreferenceToken.setEnabled(Driver.AZURE_SDK.getId().equals(newValue));
127 | return true;
128 | });
129 | }
130 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/fragments/FragmentTtsUsage.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.fragments;
2 |
3 | import android.os.Bundle;
4 |
5 | import androidx.fragment.app.Fragment;
6 |
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import com.utopiaxc.utopiatts.databinding.FragmentTtsUsageBinding;
11 |
12 | import com.utopiaxc.utopiatts.R;
13 |
14 | public class FragmentTtsUsage extends Fragment {
15 | public FragmentTtsUsage() {
16 |
17 | }
18 |
19 | public static FragmentTtsUsage newInstance() {
20 | return new FragmentTtsUsage();
21 | }
22 |
23 | @Override
24 | public void onCreate(Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | }
27 |
28 | @Override
29 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
30 | Bundle savedInstanceState) {
31 | return inflater.inflate(R.layout.fragment_tts_usage, container, false);
32 | }
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/tts/MsTts.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.tts;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.speech.tts.SynthesisCallback;
6 | import android.util.Log;
7 |
8 | import androidx.preference.PreferenceManager;
9 |
10 | import com.microsoft.cognitiveservices.speech.CancellationReason;
11 | import com.microsoft.cognitiveservices.speech.ResultReason;
12 | import com.microsoft.cognitiveservices.speech.SpeechConfig;
13 | import com.microsoft.cognitiveservices.speech.SpeechSynthesisCancellationDetails;
14 | import com.microsoft.cognitiveservices.speech.SpeechSynthesisResult;
15 | import com.microsoft.cognitiveservices.speech.SpeechSynthesizer;
16 | import com.microsoft.cognitiveservices.speech.audio.AudioConfig;
17 | import com.utopiaxc.utopiatts.enums.SettingsEnum;
18 | import com.utopiaxc.utopiatts.tts.enums.Actors;
19 | import com.utopiaxc.utopiatts.tts.enums.OutputFormat;
20 | import com.utopiaxc.utopiatts.tts.enums.Regions;
21 | import com.utopiaxc.utopiatts.tts.enums.Roles;
22 | import com.utopiaxc.utopiatts.tts.enums.Styles;
23 | import com.utopiaxc.utopiatts.tts.utils.Ssml;
24 |
25 | import java.util.concurrent.ExecutionException;
26 |
27 | public class MsTts implements Tts{
28 | private static final String TAG = "MsTts";
29 | private static volatile Tts mInstance;
30 | private SpeechSynthesizer mSpeechSynthesizer;
31 | SharedPreferences mSharedPreferences;
32 |
33 | public MsTts(Context context) {
34 | mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
35 | initTts();
36 | }
37 |
38 | public static Tts getInstance(Context context) {
39 | if (mInstance == null) {
40 | synchronized (MsTts.class) {
41 | if (mInstance == null) {
42 | mInstance = new MsTts(context.getApplicationContext());
43 | }
44 | }
45 | }
46 | return mInstance;
47 | }
48 |
49 | @Override
50 | public boolean doSpeak(String text, int pitch, int rate, SynthesisCallback synthesisCallback) {
51 | Actors actor = Actors.getActor(
52 | mSharedPreferences.getString(SettingsEnum.ACTOR.getKey(),
53 | (String) SettingsEnum.ACTOR.getDefaultValue()));
54 | Roles role = Roles.getRole(
55 | mSharedPreferences.getString(SettingsEnum.ROLE.getKey(),
56 | (String) SettingsEnum.ROLE.getDefaultValue()));
57 | Styles style = Styles.getStyle(
58 | mSharedPreferences.getString(SettingsEnum.STYLE.getKey(),
59 | (String) SettingsEnum.STYLE.getDefaultValue()));
60 | int styleDegree = mSharedPreferences.getInt(SettingsEnum.STYLE_DEGREE.getKey(),
61 | (Integer) SettingsEnum.STYLE_DEGREE.getDefaultValue());
62 | Ssml ssml = new Ssml(text, actor.getId(), pitch,
63 | rate, role.getId(), style.getId(), styleDegree);
64 | try {
65 | SpeechSynthesisResult speechRecognitionResult =
66 | mSpeechSynthesizer.SpeakSsmlAsync(ssml.toString()).get();
67 | if (speechRecognitionResult.getReason() == ResultReason.SynthesizingAudioCompleted) {
68 | Log.d(TAG,"Speech synthesized to speaker for text = " + text);
69 | return true;
70 | } else if (speechRecognitionResult.getReason() == ResultReason.Canceled) {
71 | SpeechSynthesisCancellationDetails cancellation =
72 | SpeechSynthesisCancellationDetails.fromResult(speechRecognitionResult);
73 | if (cancellation.getReason() == CancellationReason.Error) {
74 | Log.e(TAG,"Speech synthesized error");
75 | Log.e(TAG,cancellation.getErrorDetails());
76 | }
77 | }
78 | } catch (ExecutionException | InterruptedException e) {
79 | e.printStackTrace();
80 | }
81 | return false;
82 | }
83 |
84 | @Override
85 | public void stopSpeak() {
86 | if (mSpeechSynthesizer != null) {
87 | mSpeechSynthesizer.StopSpeakingAsync();
88 | }
89 | }
90 |
91 | @Override
92 | public void initTts() {
93 | Log.i(TAG, "initTts");
94 | Regions region = Regions.getRegion(
95 | mSharedPreferences.getString(
96 | SettingsEnum.AZURE_REGION.getKey(),
97 | (String) SettingsEnum.AZURE_REGION.getDefaultValue()));
98 | String token=mSharedPreferences.getString(
99 | SettingsEnum.AZURE_TOKEN.getKey(),
100 | (String) SettingsEnum.AZURE_TOKEN.getDefaultValue());
101 | if ("".equals(token)){
102 | token=(String) SettingsEnum.AZURE_TOKEN.getDefaultValue();
103 | }
104 | SpeechConfig speechConfig = SpeechConfig.fromSubscription(token, region.getId());
105 | OutputFormat outputFormat = OutputFormat.getOutputFormat(
106 | mSharedPreferences.getString(
107 | SettingsEnum.OUTPUT_FORMAT.getKey(),
108 | (String) SettingsEnum.OUTPUT_FORMAT.getDefaultValue()));
109 | speechConfig.setSpeechSynthesisOutputFormat(outputFormat.getSpeechSynthesisOutputFormat());
110 | AudioConfig audioConfig = AudioConfig.fromDefaultSpeakerOutput();
111 | mSpeechSynthesizer = new SpeechSynthesizer(speechConfig, audioConfig);
112 | }
113 |
114 | public static boolean testAzureConfig(String token,String region){
115 | SpeechConfig speechConfig = SpeechConfig.fromSubscription(token, region);
116 | SpeechSynthesizer speechSynthesizer=new SpeechSynthesizer(speechConfig,null);
117 | try {
118 | SpeechSynthesisResult speechRecognitionResult =
119 | speechSynthesizer.SpeakTextAsync("").get();
120 | if (speechRecognitionResult.getReason() == ResultReason.SynthesizingAudioCompleted) {
121 | return true;
122 | }
123 | else if (speechRecognitionResult.getReason() == ResultReason.Canceled) {
124 | SpeechSynthesisCancellationDetails cancellation =
125 | SpeechSynthesisCancellationDetails.fromResult(speechRecognitionResult);
126 | if (cancellation.getReason() == CancellationReason.Error) {
127 | return false;
128 | }
129 | }
130 | } catch (ExecutionException | InterruptedException e) {
131 | e.printStackTrace();
132 | return false;
133 | }
134 | return false;
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/tts/Tts.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.tts;
2 |
3 | import android.speech.tts.SynthesisCallback;
4 |
5 | public interface Tts {
6 | boolean doSpeak(String text, int pitch, int rate, SynthesisCallback synthesisCallback);
7 | void stopSpeak();
8 | void initTts();
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/tts/WsTts.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.tts;
2 |
3 | import static com.utopiaxc.utopiatts.tts.utils.CommonTool.getTime;
4 |
5 | import android.content.Context;
6 | import android.content.SharedPreferences;
7 | import android.media.MediaCodec;
8 | import android.media.MediaExtractor;
9 | import android.media.MediaFormat;
10 | import android.os.SystemClock;
11 | import android.speech.tts.SynthesisCallback;
12 | import android.text.TextUtils;
13 | import android.util.Log;
14 |
15 | import androidx.annotation.NonNull;
16 | import androidx.preference.PreferenceManager;
17 |
18 | import com.utopiaxc.utopiatts.APP;
19 | import com.utopiaxc.utopiatts.enums.SettingsEnum;
20 | import com.utopiaxc.utopiatts.tts.enums.Actors;
21 | import com.utopiaxc.utopiatts.tts.enums.OutputFormat;
22 | import com.utopiaxc.utopiatts.tts.enums.Regions;
23 | import com.utopiaxc.utopiatts.tts.enums.Roles;
24 | import com.utopiaxc.utopiatts.tts.enums.Styles;
25 | import com.utopiaxc.utopiatts.tts.utils.ByteArrayMediaDataSource;
26 | import com.utopiaxc.utopiatts.tts.utils.CommonTool;
27 | import com.utopiaxc.utopiatts.tts.utils.Constants;
28 | import com.utopiaxc.utopiatts.tts.utils.Ssml;
29 | import com.utopiaxc.utopiatts.tts.utils.WebSocketState;
30 |
31 | import org.jetbrains.annotations.NotNull;
32 | import org.jetbrains.annotations.Nullable;
33 |
34 | import java.io.IOException;
35 | import java.nio.ByteBuffer;
36 | import java.nio.charset.StandardCharsets;
37 | import java.util.Date;
38 | import java.util.Objects;
39 |
40 | import okhttp3.OkHttpClient;
41 | import okhttp3.Request;
42 | import okhttp3.Response;
43 | import okhttp3.WebSocket;
44 | import okhttp3.WebSocketListener;
45 | import okio.Buffer;
46 | import okio.ByteString;
47 |
48 | public class WsTts implements Tts {
49 | private static final String TAG = "WsTts";
50 | private static volatile Tts mInstance;
51 | SharedPreferences mSharedPreferences;
52 | private volatile boolean mIsSynthesizing = false;
53 | private OutputFormat mOutputFormat = null;
54 | private Regions mRegions = null;
55 | private WebSocket mWebSocket = null;
56 | private volatile WebSocketState mWebSocketState = WebSocketState.OFFLINE;
57 | private OkHttpClient mClient;
58 | private final Buffer mData = new Buffer();
59 | private MediaCodec mMediaCodec;
60 | private String mOldMime;
61 | private Ssml mSsml;
62 | private SynthesisCallback mCallback;
63 | private final WebSocketListener mWebSocketListener = new WebSocketListener() {
64 | @Override
65 | public void onClosed(@NotNull WebSocket webSocket, int code, @NotNull String reason) {
66 | super.onClosed(webSocket, code, reason);
67 | Log.e(TAG, "onClosed:" + reason);
68 | }
69 |
70 | @Override
71 | public void onClosing(@NotNull WebSocket webSocket, int code, @NotNull String reason) {
72 | super.onClosing(webSocket, code, reason);
73 | Log.e(TAG, "onClosing:" + reason);
74 | mWebSocket = null;
75 | mWebSocketState = WebSocketState.OFFLINE;
76 | if (mIsSynthesizing) {
77 | mWebSocket = getOrCreateWs();
78 | }
79 | }
80 |
81 | @Override
82 | public void onFailure(@NotNull WebSocket webSocket, @NotNull Throwable t, @Nullable Response response) {
83 | super.onFailure(webSocket, t, response);
84 | mWebSocket = null;
85 | mWebSocketState = WebSocketState.OFFLINE;
86 | Log.e(TAG, "onFailure, throwable = \n", t);
87 | try {
88 | getOrCreateWs().send(mSsml.toStringForWs());
89 | } catch (NullPointerException exception) {
90 | exception.printStackTrace();
91 | }
92 | }
93 |
94 | @Override
95 | public void onMessage(@NotNull WebSocket webSocket, @NotNull String text) {
96 | super.onMessage(webSocket, text);
97 | final String endTag = "turn.end";
98 | final String startTag = "turn.start";
99 | int endIndex = text.lastIndexOf(endTag);
100 | int startIndex = text.lastIndexOf(startTag);
101 | if (startIndex != -1) {
102 | mIsSynthesizing = true;
103 | mData.clear();
104 | } else if (endIndex != -1) {
105 | if (mCallback != null && !mCallback.hasFinished() && mIsSynthesizing) {
106 | if (mOutputFormat.needDecode()) {
107 | doDecode(mData.readByteString());
108 | } else {
109 | doUnDecode(mData.readByteString());
110 | }
111 | }
112 | }
113 | }
114 |
115 | @Override
116 | public void onMessage(@NotNull WebSocket webSocket, @NotNull ByteString bytes) {
117 | super.onMessage(webSocket, bytes);
118 | final String audioTag = "Path:audio\r\n";
119 | final String startTag = "Content-Type:";
120 | final String endTag = "\r\nX-StreamId";
121 | int audioIndex = bytes.lastIndexOf(audioTag.getBytes(StandardCharsets.UTF_8)) + audioTag.length();
122 | int startIndex = bytes.lastIndexOf(startTag.getBytes(StandardCharsets.UTF_8)) + startTag.length();
123 | int endIndex = bytes.lastIndexOf(endTag.getBytes(StandardCharsets.UTF_8));
124 | if (audioIndex != -1) {
125 | try {
126 | String temp = bytes.substring(startIndex, endIndex).utf8();
127 | String mCurrentMime;
128 | if (temp.startsWith("audio")) {
129 | mCurrentMime = temp;
130 | } else {
131 | return;
132 | }
133 | if (!mOutputFormat.needDecode()) {
134 | if ("audio/x-wav".equals(mCurrentMime) && bytes.lastIndexOf("RIFF".getBytes(StandardCharsets.UTF_8)) != -1) {
135 | audioIndex += 44;
136 | }
137 | }
138 | mData.write(bytes.substring(audioIndex));
139 | } catch (Exception e) {
140 | mIsSynthesizing = false;
141 | }
142 | }
143 | }
144 |
145 | @Override
146 | public void onOpen(@NotNull WebSocket webSocket, @NotNull Response response) {
147 | super.onOpen(webSocket, response);
148 | Log.e(TAG, "onOpen" + response.headers());
149 | }
150 | };
151 |
152 | public WsTts(Context context) {
153 | mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
154 | initTts();
155 | }
156 |
157 | public static Tts getInstance(Context context) {
158 | if (mInstance == null) {
159 | synchronized (Tts.class) {
160 | if (mInstance == null) {
161 | mInstance = new WsTts(context.getApplicationContext());
162 | }
163 | }
164 | }
165 | return mInstance;
166 | }
167 |
168 | @Override
169 | public boolean doSpeak(String text, int pitch, int rate, SynthesisCallback synthesisCallback) {
170 | mCallback = synthesisCallback;
171 | mIsSynthesizing = true;
172 | if (CommonTool.isNoVoice(text)) {
173 | mIsSynthesizing = false;
174 | return true;
175 | }
176 |
177 | long startTime = SystemClock.elapsedRealtime();
178 | synchronized (WsTts.this) {
179 | mIsSynthesizing = true;
180 | sendText(text, pitch, rate);
181 | while (mIsSynthesizing) {
182 | try {
183 | this.wait(100);
184 | } catch (InterruptedException e) {
185 | e.printStackTrace();
186 | }
187 | long time = SystemClock.elapsedRealtime() - startTime;
188 | if (time > 50000) {
189 | return false;
190 | }
191 | }
192 | }
193 | mIsSynthesizing = false;
194 | return true;
195 | }
196 |
197 | @Override
198 | public void stopSpeak() {
199 | if (mWebSocket != null) {
200 | Objects.requireNonNull(mWebSocket).close(1000, "closed by call onStop");
201 | mWebSocket = null;
202 | }
203 | mIsSynthesizing = false;
204 | mData.clear();
205 | }
206 |
207 | @Override
208 | public void initTts() {
209 | Log.i(TAG, "initTts");
210 | stopSpeak();
211 | if (mCallback != null) {
212 | mCallback.error();
213 | }
214 | mRegions = Regions.getRegion(
215 | mSharedPreferences.getString(
216 | SettingsEnum.AZURE_REGION.getKey(),
217 | (String) SettingsEnum.AZURE_REGION.getDefaultValue()));
218 |
219 | mOutputFormat = OutputFormat.getOutputFormat(
220 | mSharedPreferences.getString(
221 | SettingsEnum.OUTPUT_FORMAT.getKey(),
222 | (String) SettingsEnum.OUTPUT_FORMAT.getDefaultValue()));
223 | mClient = APP.getOkHttpClient();
224 | mWebSocket = getOrCreateWs();
225 | sendConfig(mWebSocket);
226 | }
227 |
228 | public synchronized void sendText(String text, int pitch, int rate) {
229 | Actors actor = Actors.getActor(
230 | mSharedPreferences.getString(SettingsEnum.ACTOR.getKey(),
231 | (String) SettingsEnum.ACTOR.getDefaultValue()));
232 | Roles role = Roles.getRole(
233 | mSharedPreferences.getString(SettingsEnum.ROLE.getKey(),
234 | (String) SettingsEnum.ROLE.getDefaultValue()));
235 | Styles style = Styles.getStyle(
236 | mSharedPreferences.getString(SettingsEnum.STYLE.getKey(),
237 | (String) SettingsEnum.STYLE.getDefaultValue()));
238 | int styleDegree = mSharedPreferences.getInt(SettingsEnum.STYLE_DEGREE.getKey(),
239 | (Integer) SettingsEnum.STYLE_DEGREE.getDefaultValue());
240 |
241 | mSsml = new Ssml(text, actor.getId(), pitch,
242 | rate, role.getId(), style.getId(), styleDegree);
243 |
244 | while (mIsSynthesizing) {
245 | Log.w(TAG, "try sendText");
246 | try {
247 | if (getOrCreateWs().send(mSsml.toStringForWs())) {
248 | break;
249 | }
250 | } catch (Exception e) {
251 | try {
252 | this.wait(500);
253 | } catch (Exception ignored) {
254 | }
255 | Log.w(TAG, "Retry sendText");
256 | }
257 | }
258 | }
259 |
260 | private synchronized void sendConfig(@NonNull WebSocket ws) {
261 | String msg = "X-Timestamp:+" + getTime() + "\r\n" +
262 | "Content-Type:application/json; charset=utf-8\r\n" +
263 | "Path:speech.config\r\n\r\n"
264 | + "{\"context\":" +
265 | "{\"synthesis\":" +
266 | "{\"audio\":" +
267 | "{\"metadataoptions\":" +
268 | "{\"sentenceBoundaryEnabled\":\"true\",\"wordBoundaryEnabled\":\"true\"" +
269 | "},\"outputFormat\":\"" + mOutputFormat.getValue() + "\"}}}}";
270 | ws.send(msg);
271 | }
272 |
273 | public synchronized WebSocket getOrCreateWs() {
274 | if (mWebSocket == null) {
275 | if (mWebSocketState == WebSocketState.CONNECTED) {
276 | mClient.dispatcher().cancelAll();
277 | }
278 | String url;
279 | String origin;
280 | url = Constants.WSS + mRegions.getId() + Constants.MS_API +
281 | CommonTool.getMD5String(new Date().toString());
282 | origin = "https://azure.microsoft.com";
283 | Request request = new Request.Builder()
284 | .url(url)
285 | .header("User-Agent", Constants.EDGE_UA)
286 | .addHeader("Origin", origin)
287 | .build();
288 | mWebSocketState = WebSocketState.CONNECTING;
289 | mWebSocket = mClient.newWebSocket(request, mWebSocketListener);
290 |
291 | mWebSocketState = WebSocketState.CONNECTED;
292 | sendConfig(Objects.requireNonNull(mWebSocket));
293 | }
294 | return mWebSocket;
295 | }
296 |
297 | private synchronized void doDecode(@NonNull ByteString data) {
298 | mIsSynthesizing = true;
299 | try {
300 | MediaExtractor mediaExtractor = new MediaExtractor();
301 | mediaExtractor.setDataSource(new ByteArrayMediaDataSource(data.toByteArray()));
302 | int audioTrackIndex = -1;
303 | String mime = null;
304 | MediaFormat trackFormat = null;
305 | for (int i = 0; i < mediaExtractor.getTrackCount(); i++) {
306 | trackFormat = mediaExtractor.getTrackFormat(i);
307 | mime = trackFormat.getString(MediaFormat.KEY_MIME);
308 | if (!TextUtils.isEmpty(mime) && mime.startsWith("audio")) {
309 | audioTrackIndex = i;
310 | break;
311 | }
312 | }
313 | if (audioTrackIndex == -1) {
314 | Log.e(TAG, "initAudioDecoder: 没有找到音频流");
315 | mIsSynthesizing = false;
316 | return;
317 | }
318 | if ("audio/opus".equals(mime)) {
319 | Buffer buf = new Buffer();
320 | buf.write("OpusHead".getBytes(StandardCharsets.UTF_8));
321 | buf.writeByte(1);
322 | buf.writeByte(1);
323 | buf.writeShortLe(0);
324 | buf.writeIntLe(mOutputFormat.getSoundFrequency());
325 | buf.writeShortLe(0);
326 | buf.writeByte(0);
327 | byte[] csd1bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
328 | byte[] csd2bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
329 | ByteString hd = buf.readByteString();
330 | ByteBuffer csd0 = ByteBuffer.wrap(hd.toByteArray());
331 | trackFormat.setByteBuffer("csd-0", csd0);
332 | ByteBuffer csd1 = ByteBuffer.wrap(csd1bytes);
333 | trackFormat.setByteBuffer("csd-1", csd1);
334 | ByteBuffer csd2 = ByteBuffer.wrap(csd2bytes);
335 | trackFormat.setByteBuffer("csd-2", csd2);
336 | }
337 | mediaExtractor.selectTrack(audioTrackIndex);
338 | MediaCodec mediaCodec = getMediaCodec(mime, trackFormat);
339 | mediaCodec.start();
340 | MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
341 | ByteBuffer inputBuffer;
342 | long TIME_OUT_US = 10000;
343 | while (mIsSynthesizing) {
344 | int inputIndex = mediaCodec.dequeueInputBuffer(TIME_OUT_US);
345 | if (inputIndex < 0) {
346 | break;
347 | }
348 | bufferInfo.presentationTimeUs = mediaExtractor.getSampleTime();
349 | inputBuffer = mediaCodec.getInputBuffer(inputIndex);
350 | if (inputBuffer != null) {
351 | inputBuffer.clear();
352 | } else {
353 | continue;
354 | }
355 | int sampleSize = mediaExtractor.readSampleData(inputBuffer, 0);
356 |
357 | if (sampleSize > 0) {
358 | bufferInfo.size = sampleSize;
359 | mediaCodec.queueInputBuffer(inputIndex, 0, sampleSize, 0, 0);
360 | mediaExtractor.advance();
361 | } else {
362 | break;
363 | }
364 | int outputIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, TIME_OUT_US);
365 | ByteBuffer outputBuffer;
366 | byte[] pcmData;
367 | while (outputIndex >= 0) {
368 | outputBuffer = mediaCodec.getOutputBuffer(outputIndex);
369 | pcmData = new byte[bufferInfo.size];
370 | if (outputBuffer != null) {
371 | outputBuffer.get(pcmData);
372 | outputBuffer.clear();
373 | }
374 | mCallback.audioAvailable(pcmData, 0, bufferInfo.size);
375 | mediaCodec.releaseOutputBuffer(outputIndex, false);
376 | outputIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, TIME_OUT_US);
377 | }
378 | }
379 | mediaCodec.reset();
380 | mIsSynthesizing = false;
381 | } catch (Exception e) {
382 | Log.e(TAG, "doDecode", e);
383 | mIsSynthesizing = false;
384 | }
385 | }
386 |
387 |
388 | private synchronized void doUnDecode(@NonNull ByteString data) {
389 | mIsSynthesizing = true;
390 | int length = data.toByteArray().length;
391 | final int maxBufferSize = mCallback.getMaxBufferSize();
392 | int offset = 0;
393 | while (offset < length && mIsSynthesizing) {
394 | int bytesToWrite = Math.min(maxBufferSize, length - offset);
395 | mCallback.audioAvailable(data.toByteArray(), offset, bytesToWrite);
396 | offset += bytesToWrite;
397 | }
398 | mCallback.done();
399 | mIsSynthesizing = false;
400 | }
401 |
402 | private MediaCodec getMediaCodec(String mime, MediaFormat mediaFormat) {
403 | if (mMediaCodec == null || !mime.equals(mOldMime)) {
404 | if (null != mMediaCodec) {
405 | mMediaCodec.release();
406 | }
407 | try {
408 | mMediaCodec = MediaCodec.createDecoderByType(mime);
409 | mOldMime = mime;
410 | } catch (IOException ioException) {
411 | ioException.printStackTrace();
412 | throw new RuntimeException(ioException);
413 | }
414 | }
415 | mMediaCodec.reset();
416 | mMediaCodec.configure(mediaFormat, null, null, 0);
417 | return mMediaCodec;
418 | }
419 | }
420 |
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/tts/enums/Actors.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.tts.enums;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | public enum Actors {
6 | ZH_CN_XIAOCHEN_NEURAL("ZH_CN_XIAOCHEN_NEURAL", "zh-CN", "zh-CN-XiaochenNeural", 'F',false),
7 | ZH_CN_XIAOHAN_NEURAL("ZH_CN_XIAOHAN_NEURAL", "zh-CN", "zh-CN-XiaohanNeural", 'F',false),
8 | ZH_CN_XIAOMENG_NEURAL("ZH_CN_XIAOMENG_NEURAL", "zh-CN", "zh-CN-XiaomengNeural", 'F',true),
9 | ZH_CN_XIAOMO_NEURAL("ZH_CN_XIAOMO_NEURAL", "zh-CN", "zh-CN-XiaomoNeural", 'F',false),
10 | ZH_CN_XIAOQIU_NEURAL("ZH_CN_XIAOQIU_NEURAL", "zh-CN", "zh-CN-XiaoqiuNeural", 'F',false),
11 | ZH_CN_XIAORUI_NEURAL("ZH_CN_XIAORUI_NEURAL", "zh-CN", "zh-CN-XiaoruiNeural", 'F',false),
12 | ZH_CN_XIAOSHUANG_NEURAL("ZH_CN_XIAOSHUANG_NEURAL", "zh-CN", "zh-CN-XiaoshuangNeural", 'F',false),
13 | ZH_CN_XIAOXIAO_NEURAL("ZH_CN_XIAOXIAO_NEURAL", "zh-CN", "zh-CN-XiaoxiaoNeural", 'F',false),
14 | ZH_CN_XIAOXUAN_NEURAL("ZH_CN_XIAOXUAN_NEURAL", "zh-CN", "zh-CN-XiaoxuanNeural", 'F',false),
15 | ZH_CN_XIAOYAN_NEURAL("ZH_CN_XIAOYAN_NEURAL", "zh-CN", "zh-CN-XiaoyanNeural", 'F',false),
16 | ZH_CN_XIAOYI_NEURAL("ZH_CN_XIAOYI_NEURAL", "zh-CN", "zh-CN-XiaoyiNeural", 'F',true),
17 | ZH_CN_XIAOYOU_NEURAL("ZH_CN_XIAOYOU_NEURAL", "zh-CN", "zh-CN-XiaoyouNeural", 'F',false),
18 | ZH_CN_XIAOZHEN_NEURAL("ZH_CN_XIAOZHEN_NEURAL", "zh-CN", "zh-CN-XiaozhenNeural", 'F',true),
19 | ZH_CN_YUNFENG_NEURAL("ZH_CN_YUNFENG_NEURAL", "zh-CN", "zh-CN-YunfengNeural", 'M',true),
20 | ZH_CN_YUNHAO_NEURAL("ZH_CN_YUNHAO_NEURAL", "zh-CN", "zh-CN-YunhaoNeural", 'M',true),
21 | ZH_CN_YUNJIAN_NEURAL("ZH_CN_YUNJIAN_NEURAL", "zh-CN", "zh-CN-YunjianNeural", 'M',true),
22 | ZH_CN_YUNXIA_NEURAL("ZH_CN_YUNXIA_NEURAL", "zh-CN", "zh-CN-YunxiaNeural", 'M',true),
23 | ZH_CN_YUNXI_NEURAL("ZH_CN_YUNXI_NEURAL", "zh-CN", "zh-CN-YunxiNeural", 'M',false),
24 | ZH_CN_YUNYANG_NEURAL("ZH_CN_YUNYANG_NEURAL", "zh-CN", "zh-CN-YunyangNeural", 'M',false),
25 | ZH_CN_YUNYE_NEURAL("ZH_CN_YUNYE_NEURAL", "zh-CN", "zh-CN-YunyeNeural", 'M',false),
26 | ZH_CN_YUNZE_NEURAL("ZH_CN_YUNZE_NEURAL", "zh-CN", "zh-CN-YunzeNeural", 'M',true),
27 | ZH_CN_HENAN_YUNDENG_NEURAL("ZH_CN_HENAN_YUNDENG_NEURAL", "zh-CN-henan", "zh-CN-henan-YundengNeural", 'M',true),
28 | ZH_CN_LIAONING_XIAOBEI_NEURAL("ZH_CN_LIAONING_XIAOBEI_NEURAL", "zh-CN-liaoning", "zh-CN-liaoning-XiaobeiNeural", 'F',true),
29 | ZH_CN_SHAANXI_XIAONI_NEURAL("ZH_CN_SHAANXI_XIAONI_NEURAL", "zh-CN-shaanxi", "zh-CN-shaanxi-XiaoniNeural", 'F',true),
30 | ZH_CN_SHANDONG_YUNXIANG_NEURAL("ZH_CN_SHANDONG_YUNXIANG_NEURAL", "zh-CN-shandong", "zh-CN-shandong-YunxiangNeural", 'M',true),
31 | ZH_CN_SICHUAN_YUNXI_NEURAL("ZH_CN_SICHUAN_YUNXI_NEURAL", "zh-CN-sichuan", "zh-CN-sichuan-YunxiNeural", 'M',true),
32 | ZH_HK_HIUGAAI_NEURAL("ZH_HK_HIUGAAI_NEURAL", "zh-HK", "zh-HK-HiuGaaiNeural", 'F',false),
33 | ZH_HK_HIUMAAN_NEURAL("ZH_HK_HIUMAAN_NEURAL", "zh-HK", "zh-HK-HiuMaanNeural", 'F',false),
34 | ZH_HK_WANLUNG_NEURAL("ZH_HK_WANLUNG_NEURAL", "zh-HK", "zh-HK-WanLungNeural", 'M',false),
35 | ZH_TW_HSIAOCHEN_NEURAL("ZH_TW_HSIAOCHEN_NEURAL", "zh-TW", "zh-TW-HsiaoChenNeural", 'F',false),
36 | ZH_TW_HSIAOYU_NEURAL("ZH_TW_HSIAOYU_NEURAL", "zh-TW", "zh-TW-HsiaoYuNeural", 'F',false),
37 | ZH_TW_YUNJHE_NEURAL("ZH_TW_YUNJHE_NEURAL", "zh-TW", "zh-TW-YunJheNeural", 'M',false);
38 |
39 | private final String mName;
40 | private final String mRegion;
41 | private final String mId;
42 | private final Character mGender;
43 | private final boolean mIsPre;
44 |
45 | Actors(String name, String region, String id, Character gender, boolean isPre) {
46 | mName = name;
47 | mRegion = region;
48 | mId = id;
49 | mGender = gender;
50 | mIsPre = isPre;
51 | }
52 |
53 | @NonNull
54 | @Override
55 | public String toString() {
56 | return mName;
57 | }
58 |
59 |
60 | public static Actors getActor(String name) {
61 | for (Actors actors : Actors.values()) {
62 | if (actors.getName().equals(name)) {
63 | return actors;
64 | }
65 | }
66 | return ZH_CN_XIAOXIAO_NEURAL;
67 | }
68 |
69 | public String getName() {
70 | return mName;
71 | }
72 |
73 | public String getId() {
74 | return mId;
75 | }
76 |
77 | public String getRegion() {
78 | return mRegion;
79 | }
80 |
81 | public Character getGender() {
82 | return mGender;
83 | }
84 |
85 | public boolean isFemale() {
86 | return mGender == 'F';
87 | }
88 |
89 | public boolean isPre(){
90 | return mIsPre;
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/tts/enums/Driver.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.tts.enums;
2 |
3 | public enum Driver {
4 | AZURE_SDK("AZURE_SDK","azure_sdk"),
5 | WEBSOCKET("WEBSOCKET","websocket");
6 |
7 | private final String mName;
8 | private final String mId;
9 |
10 | Driver(String name, String id){
11 | mName=name;
12 | mId=id;
13 | }
14 |
15 | public String getName() {
16 | return mName;
17 | }
18 |
19 | public String getId() {
20 | return mId;
21 | }
22 |
23 | public static Driver getRole(String name) {
24 | for (Driver role: Driver.values()) {
25 | if (role.getName().equals(name)) {
26 | return role;
27 | }
28 | }
29 | return AZURE_SDK;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/tts/enums/OutputFormat.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.tts.enums;
2 |
3 | import android.media.AudioFormat;
4 |
5 | import androidx.annotation.NonNull;
6 |
7 | import com.microsoft.cognitiveservices.speech.SpeechSynthesisOutputFormat;
8 |
9 | public enum OutputFormat {
10 | AUDIO_16K_HZ_128K_BIT_RATE_MONO_MP3("AUDIO_16K_HZ_128K_BIT_RATE_MONO_MP3",
11 | "audio-16khz-128kbitrate-mono-mp3",
12 | true,
13 | 16000, AudioFormat.ENCODING_PCM_16BIT,
14 | SpeechSynthesisOutputFormat.Audio16Khz128KBitRateMonoMp3),
15 | AUDIO_16K_HZ_16_BIT_32KBPS_MONO_OPUS("AUDIO_16K_HZ_128K_BIT_RATE_MONO_MP3",
16 | "audio-16khz-128kbitrate-mono-mp3",
17 | true,
18 | 16000, AudioFormat.ENCODING_PCM_16BIT,
19 | SpeechSynthesisOutputFormat.Audio16Khz16Bit32KbpsMonoOpus),
20 | AUDIO_16K_HZ_16KBPS_MONO_SIREN("AUDIO_16K_HZ_16KBPS_MONO_SIREN",
21 | "audio-16khz-16kbps-mono-siren",
22 | false,
23 | 16000, AudioFormat.ENCODING_PCM_16BIT,
24 | SpeechSynthesisOutputFormat.Audio16Khz16KbpsMonoSiren),
25 | AUDIO_16K_HZ_32K_BIT_RATE_MONO_MP3("AUDIO_16K_HZ_32K_BIT_RATE_MONO_MP3",
26 | "audio-16khz-32kbitrate-mono-mp3",
27 | true,
28 | 16000, AudioFormat.ENCODING_PCM_16BIT,
29 | SpeechSynthesisOutputFormat.Audio16Khz32KBitRateMonoMp3),
30 | AUDIO_16K_HZ_64K_BIT_RATE_MONO_MP3("AUDIO_16K_HZ_64K_BIT_RATE_MONO_MP3",
31 | "audio-16khz-64kbitrate-mono-mp3",
32 | true,
33 | 16000, AudioFormat.ENCODING_PCM_16BIT,
34 | SpeechSynthesisOutputFormat.Audio16Khz64KBitRateMonoMp3),
35 | AUDIO_24K_HZ_160K_BIT_RATE_MONO_MP3("AUDIO_24K_HZ_160K_BIT_RATE_MONO_MP3",
36 | "audio-24khz-160kbitrate-mono-mp3",
37 | true,
38 | 24000, AudioFormat.ENCODING_PCM_16BIT,
39 | SpeechSynthesisOutputFormat.Audio24Khz160KBitRateMonoMp3),
40 | AUDIO_24K_HZ_16_BIT_24KBPS_MONO_OPUS("AUDIO_24K_HZ_16_BIT_24KBPS_MONO_OPUS",
41 | "audio-24khz-16bit-24kbps-mono-opus",
42 | true,
43 | 24000, AudioFormat.ENCODING_PCM_16BIT,
44 | SpeechSynthesisOutputFormat.Audio24Khz16Bit24KbpsMonoOpus),
45 | AUDIO_24K_HZ_16_BIT_48KBPS_MONO_OPUS("AUDIO_24K_HZ_16_BIT_48KBPS_MONO_OPUS",
46 | "audio-24khz-16bit-48kbps-mono-opus",
47 | true,
48 | 24000, AudioFormat.ENCODING_PCM_16BIT,
49 | SpeechSynthesisOutputFormat.Audio24Khz16Bit48KbpsMonoOpus),
50 | AUDIO_24K_HZ_48K_BIT_RATE_MONO_MP3("AUDIO_24K_HZ_48K_BIT_RATE_MONO_MP3",
51 | "audio-24khz-48kbitrate-mono-mp3",
52 | true,
53 | 24000, AudioFormat.ENCODING_PCM_16BIT,
54 | SpeechSynthesisOutputFormat.Audio24Khz48KBitRateMonoMp3),
55 | AUDIO_24K_HZ_96K_BIT_RATE_MONO_MP3("AUDIO_24K_HZ_96K_BIT_RATE_MONO_MP3",
56 | "audio-24khz-96kbitrate-mono-mp3",
57 | true,
58 | 24000, AudioFormat.ENCODING_PCM_16BIT,
59 | SpeechSynthesisOutputFormat.Audio24Khz96KBitRateMonoMp3),
60 | AUDIO_48K_HZ_192K_BIT_RATE_MONO_MP3("AUDIO_48K_HZ_192K_BIT_RATE_MONO_MP3",
61 | "audio-48khz-192kbitrate-mono-mp3",
62 | true,
63 | 48000, AudioFormat.ENCODING_PCM_16BIT,
64 | SpeechSynthesisOutputFormat.Audio48Khz192KBitRateMonoMp3),
65 | AUDIO_48K_HZ_96K_BIT_RATE_MONO_MP3("AUDIO_48K_HZ_96K_BIT_RATE_MONO_MP3",
66 | "audio-48khz-96kbitrate-mono-mp3",
67 | true,
68 | 48000, AudioFormat.ENCODING_PCM_16BIT,
69 | SpeechSynthesisOutputFormat.Audio48Khz192KBitRateMonoMp3),
70 | OGG_16K_HZ_16_BIT_MONO_OPUS("OGG_16K_HZ_16_BIT_MONO_OPUS",
71 | "ogg-16khz-16bit-mono-opus",
72 | true,
73 | 16000, AudioFormat.ENCODING_PCM_16BIT,
74 | SpeechSynthesisOutputFormat.Ogg16Khz16BitMonoOpus),
75 | OGG_24K_HZ_16_BIT_MONO_OPUS("OGG_24K_HZ_16_BIT_MONO_OPUS",
76 | "ogg-24khz-16bit-mono-opus",
77 | true,
78 | 24000, AudioFormat.ENCODING_PCM_16BIT,
79 | SpeechSynthesisOutputFormat.Ogg24Khz16BitMonoOpus),
80 | OGG_48K_HZ_16_BIT_MONO_OPUS("OGG_48K_HZ_16_BIT_MONO_OPUS",
81 | "ogg-48khz-16bit-mono-opus",
82 | true,
83 | 48000, AudioFormat.ENCODING_PCM_16BIT,
84 | SpeechSynthesisOutputFormat.Ogg48Khz16BitMonoOpus),
85 | RAW_16K_HZ_16_BIT_MONO_PCM("RAW_16K_HZ_16_BIT_MONO_PCM",
86 | "raw-16khz-16bit-mono-pcm",
87 | false,
88 | 16000, AudioFormat.ENCODING_PCM_16BIT,
89 | SpeechSynthesisOutputFormat.Raw16Khz16BitMonoPcm),
90 | RAW_16K_HZ_16_BIT_MONO_TRUE_SILK("RAW_16K_HZ_16_BIT_MONO_TRUE_SILK",
91 | "raw-16khz-16bit-mono-true-silk",
92 | false,
93 | 16000, AudioFormat.ENCODING_PCM_16BIT,
94 | SpeechSynthesisOutputFormat.Raw16Khz16BitMonoTrueSilk),
95 | RAW_22050_HZ_16_BIT_MONO_PCM("RAW_22050_HZ_16_BIT_MONO_PCM",
96 | "raw-22050hz-16bit-mono-pcm",
97 | false,
98 | 22050, AudioFormat.ENCODING_PCM_16BIT,
99 | SpeechSynthesisOutputFormat.Raw22050Hz16BitMonoPcm),
100 | RAW_24K_HZ_16_BIT_MONO_PCM("RAW_24K_HZ_16_BIT_MONO_PCM",
101 | "raw-24khz-16bit-mono-pcm",
102 | false,
103 | 24000, AudioFormat.ENCODING_PCM_16BIT,
104 | SpeechSynthesisOutputFormat.Raw24Khz16BitMonoPcm),
105 | RAW_24K_HZ_16_BIT_MONO_TRUE_SILK("RAW_24K_HZ_16_BIT_MONO_TRUE_SILK",
106 | "raw-24khz-16bit-mono-true-silk",
107 | false,
108 | 24000, AudioFormat.ENCODING_PCM_16BIT,
109 | SpeechSynthesisOutputFormat.Raw24Khz16BitMonoTrueSilk),
110 | RAW_44100_HZ_16_BIT_MONO_PCM("RAW_44100_HZ_16_BIT_MONO_PCM",
111 | "raw-44100hz-16bit-mono-pcm",
112 | false,
113 | 44100, AudioFormat.ENCODING_PCM_16BIT,
114 | SpeechSynthesisOutputFormat.Raw44100Hz16BitMonoPcm),
115 | RAW_48K_HZ_16_BIT_MONO_PCM("RAW_48K_HZ_16_BIT_MONO_PCM",
116 | "raw-48khz-16bit-mono-pcm",
117 | false,
118 | 48000, AudioFormat.ENCODING_PCM_16BIT,
119 | SpeechSynthesisOutputFormat.Raw48Khz16BitMonoPcm),
120 | RAW_8K_HZ_16_BIT_MONO_PCM("RAW_8K_HZ_16_BIT_MONO_PCM",
121 | "raw-8khz-16bit-mono-pcm",
122 | false,
123 | 8000, AudioFormat.ENCODING_PCM_16BIT,
124 | SpeechSynthesisOutputFormat.Raw8Khz16BitMonoPcm),
125 | RAW_8K_HZ_8_BIT_MONO_ALAW("RAW_8K_HZ_8_BIT_MONO_ALAW",
126 | "raw-8khz-8bit-mono-alaw",
127 | false,
128 | 8000, AudioFormat.ENCODING_PCM_8BIT,
129 | SpeechSynthesisOutputFormat.Raw8Khz8BitMonoALaw),
130 | RAW_8K_HZ_8_BIT_MONO_MULAW("RAW_8K_HZ_8_BIT_MONO_MULAW",
131 | "raw-8khz-8bit-mono-mulaw",
132 | false,
133 | 8000, AudioFormat.ENCODING_PCM_8BIT,
134 | SpeechSynthesisOutputFormat.Raw8Khz8BitMonoMULaw),
135 | RIFF_16K_HZ_16_BIT_MONO_PCM("RIFF_16K_HZ_16_BIT_MONO_PCM",
136 | "riff-16khz-16bit-mono-pcm",
137 | false,
138 | 16000, AudioFormat.ENCODING_PCM_16BIT,
139 | SpeechSynthesisOutputFormat.Riff16Khz16BitMonoPcm),
140 | RIFF_16K_HZ_16KBPS_MONO_SIREN("RIFF_16K_HZ_16KBPS_MONO_SIREN",
141 | "riff-16khz-16kbps-mono-siren",
142 | false,
143 | 16000, AudioFormat.ENCODING_PCM_16BIT,
144 | SpeechSynthesisOutputFormat.Riff16Khz16KbpsMonoSiren),
145 | RIFF_22050_HZ_16_BIT_MONO_PCM("RIFF_22050_HZ_16_BIT_MONO_PCM",
146 | "riff-22050hz-16bit-mono-pcm",
147 | false,
148 | 22050, AudioFormat.ENCODING_PCM_16BIT,
149 | SpeechSynthesisOutputFormat.Riff22050Hz16BitMonoPcm),
150 | RIFF_24K_HZ_16_BIT_MONO_PCM("RIFF_24K_HZ_16_BIT_MONO_PCM",
151 | "riff-24khz-16bit-mono-pcm",
152 | false,
153 | 24000, AudioFormat.ENCODING_PCM_16BIT,
154 | SpeechSynthesisOutputFormat.Riff24Khz16BitMonoPcm),
155 | RIFF_44100_HZ_16_BIT_MONO_PCM("RIFF_44100_HZ_16_BIT_MONO_PCM",
156 | "riff-44100hz-16bit-mono-pcm",
157 | false,
158 | 44100, AudioFormat.ENCODING_PCM_16BIT,
159 | SpeechSynthesisOutputFormat.Riff44100Hz16BitMonoPcm),
160 | RIFF_48K_HZ_16_BIT_MONO_PCM("RIFF_48K_HZ_16_BIT_MONO_PCM",
161 | "riff-48khz-16bit-mono-pcm",
162 | false,
163 | 48000, AudioFormat.ENCODING_PCM_16BIT,
164 | SpeechSynthesisOutputFormat.Riff48Khz16BitMonoPcm),
165 | RIFF_8K_HZ_16_BIT_MONO_PCM("RIFF_8K_HZ_16_BIT_MONO_PCM",
166 | "riff-8khz-16bit-mono-pcm",
167 | false,
168 | 8000, AudioFormat.ENCODING_PCM_16BIT,
169 | SpeechSynthesisOutputFormat.Riff8Khz16BitMonoPcm),
170 | RIFF_8K_HZ_8_BIT_MONO_ALAW("RIFF_8K_HZ_8_BIT_MONO_ALAW",
171 | "riff-8khz-8bit-mono-alaw",
172 | false,
173 | 8000, AudioFormat.ENCODING_PCM_8BIT,
174 | SpeechSynthesisOutputFormat.Riff8Khz8BitMonoALaw),
175 | RIFF_8K_HZ_8_BIT_MONO_MULAW("RIFF_8K_HZ_8_BIT_MONO_MULAW",
176 | "riff-8khz-8bit-mono-mulaw",
177 | false,
178 | 8000, AudioFormat.ENCODING_PCM_8BIT,
179 | SpeechSynthesisOutputFormat.Riff8Khz8BitMonoMULaw),
180 | WEBM_16K_HZ_16_BIT_MONO_OPUS("WEBM_16K_HZ_16_BIT_MONO_OPUS",
181 | "webm-16khz-16bit-mono-opus",
182 | true,
183 | 16000, AudioFormat.ENCODING_PCM_16BIT,
184 | SpeechSynthesisOutputFormat.Webm16Khz16BitMonoOpus),
185 | WEBM_24K_HZ_16_BIT_24KBPS_MONO_OPUS("WEBM_24K_HZ_16_BIT_24KBPS_MONO_OPUS",
186 | "webm-24khz-16bit-24kbps-mono-opus",
187 | true,
188 | 24000, AudioFormat.ENCODING_PCM_16BIT,
189 | SpeechSynthesisOutputFormat.Webm24Khz16Bit24KbpsMonoOpus),
190 | WEBM_24K_HZ_16_BIT_MONO_OPUS("WEBM_24K_HZ_16_BIT_MONO_OPUS",
191 | "webm-24khz-16bit-mono-opus",
192 | true,
193 | 24000, AudioFormat.ENCODING_PCM_16BIT,
194 | SpeechSynthesisOutputFormat.Webm24Khz16BitMonoOpus),
195 | ;
196 |
197 | private final String mName;
198 | private final int mSoundFrequency;
199 | private final int mAudioFormat;
200 | private final SpeechSynthesisOutputFormat mSpeechSynthesisOutputFormat;
201 | private final String mValue;
202 | private final boolean mNeedDecode;
203 |
204 | OutputFormat(String name, String value, boolean needDecode, int soundFrequency, int audioFormat,
205 | SpeechSynthesisOutputFormat speechSynthesisOutputFormat) {
206 | mName = name;
207 | mValue = value;
208 | mNeedDecode = needDecode;
209 | mSoundFrequency = soundFrequency;
210 | mAudioFormat = audioFormat;
211 | mSpeechSynthesisOutputFormat = speechSynthesisOutputFormat;
212 | }
213 |
214 | @NonNull
215 | @Override
216 | public String toString() {
217 | return mName;
218 | }
219 |
220 | public String getName() {
221 | return mName;
222 | }
223 |
224 | public String getValue() {
225 | return mValue;
226 | }
227 |
228 | public int getSoundFrequency() {
229 | return mSoundFrequency;
230 | }
231 |
232 | public int getAudioFormat() {
233 | return mAudioFormat;
234 | }
235 |
236 | public SpeechSynthesisOutputFormat getSpeechSynthesisOutputFormat() {
237 | return mSpeechSynthesisOutputFormat;
238 | }
239 |
240 | public boolean needDecode(){
241 | return mNeedDecode;
242 | }
243 |
244 | public static OutputFormat getOutputFormat(String name) {
245 | for (OutputFormat outputFormat : OutputFormat.values()) {
246 | if (outputFormat.getName().equals(name)) {
247 | return outputFormat;
248 | }
249 | }
250 | return OGG_48K_HZ_16_BIT_MONO_OPUS;
251 | }
252 | }
253 |
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/tts/enums/Regions.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.tts.enums;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | public enum Regions {
6 | SOUTH_AFRICA_NORTH("SOUTH_AFRICA_NORTH", "southafricanorth", false),
7 | EAST_ASIA("EAST_ASIA", "eastasia", false),
8 | SOUTH_EAST_ASIA("SOUTH_EAST_ASIA", "southeastasia", true),
9 | AUSTRALIA_EAST("AUSTRALIA_EAST", "australiaeast", false),
10 | CENTRAL_INDIA("CENTRAL_INDIA", "centralindia", false),
11 | JAPAN_EAST("JAPAN_EAST", "japaneast", false),
12 | JAPAN_WEST("JAPAN_WEST", "japanwest", false),
13 | KOREA_CENTRAL("KOREA_CENTRAL", "koreacentral", false),
14 | CANADA_CENTRAL("CANADA_CENTRAL", "canadacentral", false),
15 | NORTH_EUROPE("NORTH_EUROPE", "northeurope", false),
16 | WEST_EUROPE("WEST_EUROPE", "westeurope", true),
17 | FRANCE_CENTRAL("FRANCE_CENTRAL", "francecentral", false),
18 | GERMANY_WEST_CENTRAL("GERMANY_WEST_CENTRAL", "germanywestcentral", false),
19 | NORWAY_EAST("NORWAY_EAST", "norwayeast", false),
20 | SWITZERLAND_NORTH("SWITZERLAND_NORTH", "switzerlandnorth", false),
21 | SWITZERLAND_WEST("SWITZERLAND_WEST", "switzerlandwest", false),
22 | UK_SOUTH("UK_SOUTH", "uksouth", false),
23 | UAE_NORTH("UAE_NORTH", "uaenorth", false),
24 | BRAZIL_SOUTH("BRAZIL_SOUTH", "brazilsouth", false),
25 | CENTRAL_US("CENTRAL_US", "centralus", false),
26 | EAST_US("EAST_US", "eastus", true),
27 | EAST_US2("EAST_US2", "eastus2", true),
28 | NORTH_CENTRAL_US("NORTH_CENTRAL_US", "northcentralus", false),
29 | SOUTH_CENTRAL_US("SOUTH_CENTRAL_US", "southcentralus", false),
30 | WEST_CENTRAL_US("WEST_CENTRAL_US", "westcentralus",false),
31 | WEST_US("WEST_US", "westus", false),
32 | WEST_US2("WEST_US2", "westus2", false),
33 | WEST_US3("WEST_US3", "westus3", false);
34 |
35 | private final String mName;
36 | private final String mId;
37 | private final boolean mIsSupportPre;
38 |
39 | Regions(String name, String id, boolean isSupportPre) {
40 | mName = name;
41 | mId = id;
42 | mIsSupportPre = isSupportPre;
43 | }
44 |
45 | @NonNull
46 | @Override
47 | public String toString() {
48 | return mName;
49 | }
50 |
51 |
52 | public static Regions getRegion(String name) {
53 | for (Regions region : Regions.values()) {
54 | if (region.getName().equals(name)) {
55 | return region;
56 | }
57 | }
58 | return SOUTH_EAST_ASIA;
59 | }
60 |
61 | public String getName() {
62 | return mName;
63 | }
64 |
65 | public String getId() {
66 | return mId;
67 | }
68 |
69 | public boolean isNotSupportPre(){
70 | return !mIsSupportPre;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/tts/enums/Roles.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.tts.enums;
2 |
3 | public enum Roles {
4 | NONE("NONE",""),
5 | YOUNG_ADULT_FEMALE("YOUNG_ADULT_FEMALE","YoungAdultFemale"),
6 | YOUNG_ADULT_MALE("YOUNG_ADULT_MALE","YoungAdultMale"),
7 | OLDER_ADULT_FEMALE("OLDER_ADULT_FEMALE","OlderAdultFemale"),
8 | OLDER_ADULT_MALE("OLDER_ADULT_MALE","OlderAdultMale"),
9 | SENIOR_FEMALE("SENIOR_FEMALE","SeniorFemale"),
10 | SENIOR_MALE("SENIOR_MALE","SeniorMale"),
11 | GIRL("GIRL","Girl"),
12 | BOY("BOY","Boy"),
13 | NARRATOR("NARRATOR","Narrator");
14 |
15 | private final String mName;
16 | private final String mId;
17 |
18 | Roles(String name, String id){
19 | mName=name;
20 | mId=id;
21 | }
22 |
23 | public String getName() {
24 | return mName;
25 | }
26 |
27 | public String getId() {
28 | return mId;
29 | }
30 |
31 | public static Roles getRole(String name) {
32 | for (Roles role: Roles.values()) {
33 | if (role.getName().equals(name)) {
34 | return role;
35 | }
36 | }
37 | return NONE;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/tts/enums/Styles.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.tts.enums;
2 |
3 | public enum Styles {
4 | NONE("NONE",""),
5 | CALM("CALM","calm"),
6 | FEARFUL("FEARFUL","fearful"),
7 | CHEERFUL("CHEERFUL","cheerful"),
8 | DISGRUNTLED("DISGRUNTLED","disgruntled"),
9 | SERIOUS("SERIOUS","serious"),
10 | ANGRY("ANGRY","angry"),
11 | GENTLE("GENTLE","gentle"),
12 | AFFECTIONATE("AFFECTIONATE","affectionate"),
13 | EMBARRASSED("EMBARRASSED","embarrassed"),
14 | DEPRESSED("DEPRESSED","depressed"),
15 | ENVIOUS("ENVIOUS","envious"),
16 | ASSISTANT("ASSISTANT","assistant"),
17 | CUSTOMER_SERVICE("CUSTOMER_SERVICE","customerservice"),
18 | NEWSCAST("NEWSCAST","newscast"),
19 | LYRICAL("LYRICAL","lyrical"),
20 | POETRY_READING("POETRY_READING","poetry-reading"),
21 | ADVERTISEMENT_UPBEAT("ADVERTISEMENT_UPBEAT","Advertisement_upbeat"),
22 | SPORTS_COMMENTARY("SPORTS_COMMENTARY","Sports_commentary"),
23 | SPORTS_COMMENTARY_EXCITED("SPORTS_COMMENTARY_EXCITED","Sports_commentary_excited"),
24 | NARRATION_RELAXED("NARRATION_RELAXED","narration-relaxed"),
25 | DOCUMENTARY_NARRATION("DOCUMENTARY_NARRATION","documentary-narration");
26 |
27 | private final String mName;
28 | private final String mId;
29 |
30 | Styles(String name, String id){
31 | mName=name;
32 | mId=id;
33 | }
34 |
35 | public String getName() {
36 | return mName;
37 | }
38 |
39 | public String getId() {
40 | return mId;
41 | }
42 |
43 | public static Styles getStyle(String name) {
44 | for (Styles style : Styles.values()) {
45 | if (style.getName().equals(name)) {
46 | return style;
47 | }
48 | }
49 | return NONE;
50 | }
51 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/tts/utils/ByteArrayMediaDataSource.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.tts.utils;
2 |
3 | import android.media.MediaDataSource;
4 | import android.os.Build;
5 |
6 | import androidx.annotation.NonNull;
7 | import androidx.annotation.RequiresApi;
8 |
9 | public class ByteArrayMediaDataSource extends MediaDataSource {
10 | private byte[] data;
11 |
12 | public ByteArrayMediaDataSource(@NonNull byte[] data) {
13 | this.data = data;
14 | }
15 |
16 | @Override
17 | public int readAt(long position, byte[] buffer, int offset, int size) {
18 | if (position >= data.length) {
19 | return -1;
20 | }
21 | int endPosition = (int) (position + size);
22 | int size2 = size;
23 | if (endPosition > data.length) {
24 | size2 -= endPosition - data.length;
25 | }
26 | System.arraycopy(data, (int) position, buffer, offset, size2);
27 | return size2;
28 | }
29 |
30 | @Override
31 | public long getSize() {
32 | return data.length;
33 | }
34 |
35 | @Override
36 | public void close() {
37 | data = null;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/tts/utils/CommonTool.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.tts.utils;
2 |
3 | import java.io.PrintWriter;
4 | import java.io.StringWriter;
5 | import java.math.BigDecimal;
6 | import java.math.RoundingMode;
7 | import java.nio.charset.StandardCharsets;
8 | import java.text.SimpleDateFormat;
9 | import java.util.Date;
10 | import java.util.Locale;
11 | import java.util.regex.Pattern;
12 |
13 | import okio.ByteString;
14 |
15 | public class CommonTool {
16 |
17 | static final Pattern NoVoicePattern = Pattern.compile("[\\s\\p{C}\\p{P}\\p{Z}\\p{S}]");
18 | static final SimpleDateFormat sdf = new SimpleDateFormat(
19 | "EEE MMM dd yyyy HH:mm:ss 'GMT'Z", Locale.ENGLISH);
20 |
21 |
22 | public static boolean isNoVoice(CharSequence charSequence) {
23 | return NoVoicePattern.matcher(charSequence).replaceAll("").isEmpty();
24 | }
25 |
26 | @SuppressWarnings("unused")
27 | public static void removeAllBlankSpace(StringBuilder sb) {
28 | int j = 0;
29 | for (int i = 0; i < sb.length(); i++) {
30 | if (!(Character.isWhitespace(sb.charAt(i)) || sb.charAt(i) == ' ')) {
31 | sb.setCharAt(j++, sb.charAt(i));
32 | }
33 | }
34 | sb.delete(j, sb.length());
35 | }
36 |
37 | public static void Trim(StringBuilder sb) {
38 | if (sb == null || sb.length() == 0) return;
39 | int st = 0;
40 | while (Character.isWhitespace(sb.charAt(st)) || sb.charAt(st) == ' ') {
41 | st++;
42 | }
43 | if (st > 0) {
44 | sb.delete(0, st);
45 | }
46 |
47 | int ed = sb.length();
48 | while (Character.isWhitespace(sb.charAt(ed - 1)) || sb.charAt(ed - 1) == ' ') {
49 | ed--;
50 | }
51 | if (ed < sb.length()) {
52 | sb.delete(ed, sb.length());
53 | }
54 |
55 | }
56 |
57 |
58 | public static void replace(StringBuilder builder, String from, String to) {
59 | int index = builder.indexOf(from);
60 | while (index != -1) {
61 | builder.replace(index, index + from.length(), to);
62 | index += to.length(); // Move to the end of the replacement
63 | index = builder.indexOf(from, index);
64 | }
65 | }
66 |
67 | public static String getStackTrace(Throwable throwable) {
68 | StringWriter sw = new StringWriter();
69 |
70 | try (PrintWriter pw = new PrintWriter(sw)) {
71 | throwable.printStackTrace(pw);
72 | return sw.toString();
73 | }
74 | }
75 |
76 | public static String getTime() {
77 | Date date = new Date();
78 | return sdf.format(date);
79 | }
80 |
81 | public static String getTime(long timestamp) {
82 | Date date = new Date(timestamp);
83 | return sdf.format(date);
84 | }
85 |
86 | public static String getMD5String(String str) {
87 | return ByteString.of(str.getBytes(StandardCharsets.UTF_8)).md5().hex();
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/tts/utils/Constants.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.tts.utils;
2 |
3 | public final class Constants {
4 | public static final String EDGE_UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
5 | "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 " +
6 | "Edg/106.0.1370.42";
7 | public static final String WSS = "wss://";
8 |
9 | public static final String MS_API = ".api.speech.microsoft.com/" +
10 | "cognitiveservices/websocket/v1?TrafficType=AzureDemo&Authorization=bearer " +
11 | "undefined&X-ConnectionId=";
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/tts/utils/Ssml.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.tts.utils;
2 |
3 | import android.util.Log;
4 |
5 | import androidx.annotation.NonNull;
6 |
7 | import java.util.List;
8 |
9 | public class Ssml {
10 | private static final String TAG = "Ssml";
11 | private final String mActor;
12 | private final int mPitch;
13 | private final int mRate;
14 | private final String mStyle;
15 | private final int mStyleDegree;
16 | private final StringBuilder mText;
17 | private final String mRole;
18 |
19 | public Ssml(String text, String actor, int pitch, int rate, String role, String style,
20 | int styleDegree) {
21 | mText = new StringBuilder(text);
22 | mActor = actor;
23 | mPitch = (pitch / 4) - 25;
24 | mRate = (rate / 4) - 25;
25 | mRole = role;
26 | mStyle = style;
27 | mStyleDegree = styleDegree;
28 | handleContent();
29 | }
30 |
31 |
32 | @NonNull
33 | @Override
34 | public String toString() {
35 | StringBuilder sb = new StringBuilder();
36 | sb.append("");
40 | sb.append("");
41 | if (!"".equals(mStyle) || !"".equals(mRole)) {
42 | sb.append("");
51 | }
52 | sb.append("");
54 | sb.append(mText);
55 | sb.append("");
56 | if (!"".equals(mStyle)) {
57 | sb.append("");
58 | }
59 | sb.append("");
60 | Log.d(TAG, "toString = " + sb);
61 | return sb.toString();
62 | }
63 |
64 | public String toStringForWs() {
65 | long timestamp = System.currentTimeMillis();
66 | StringBuilder sb = new StringBuilder()
67 | .append("Path:ssml\r\n")
68 | .append("X-RequestId:").append(CommonTool.getMD5String(mText + "" + timestamp))
69 | .append("\r\n")
70 | .append("X-Timestamp:")
71 | .append(CommonTool.getTime(timestamp)).append("Z\r\n")
72 | .append("Content-Type:application/ssml+xml\r\n\r\n");
73 | sb.append("");
77 | sb.append("");
78 | if (!"".equals(mStyle) || !"".equals(mRole)) {
79 | sb.append("");
88 | }
89 | sb.append("");
91 | sb.append(mText);
92 | sb.append("");
93 | if (!"".equals(mStyle)) {
94 | sb.append("");
95 | }
96 | sb.append("");
97 | Log.d(TAG, "toString = " + sb);
98 | return sb.toString();
99 | }
100 |
101 | private void handleContent() {
102 | CommonTool.replace(mText, "\n", " ");
103 | CommonTool.Trim(mText);
104 | CommonTool.replace(mText, "&", "&");
105 | CommonTool.replace(mText, "\"", """);
106 | CommonTool.replace(mText, "'", "'");
107 | CommonTool.replace(mText, ">", "<");
108 | CommonTool.replace(mText, "<", ">");
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/tts/utils/WebSocketState.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.tts.utils;
2 |
3 | public enum WebSocketState {
4 | OFFLINE,//断线
5 | CONNECTED,//已连接
6 | CONNECTING //连接中
7 | }
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/usage/FragmentUsageDirect.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.usage;
2 |
3 | import androidx.fragment.app.Fragment;
4 |
5 | public class FragmentUsageDirect extends Fragment {
6 |
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/usage/FragmentUsageInnerApp.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.usage;
2 |
3 | import androidx.fragment.app.Fragment;
4 |
5 | public class FragmentUsageInnerApp extends Fragment {
6 | }
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/usage/FragmentUsageSystem.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.usage;
2 |
3 | import androidx.fragment.app.Fragment;
4 |
5 | public class FragmentUsageSystem extends Fragment {
6 | }
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/utils/ThemeUtil.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.utils;
2 |
3 | import android.content.Context;
4 | import android.content.res.Configuration;
5 |
6 | import androidx.appcompat.app.AppCompatDelegate;
7 |
8 | import com.utopiaxc.utopiatts.enums.ThemeModeEnum;
9 |
10 | public class ThemeUtil {
11 | public static void setThemeMode(String mode) {
12 | if (mode.equals(ThemeModeEnum.AUTO_MODE.getMode())) {
13 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
14 | } else if (mode.equals(ThemeModeEnum.NIGHT_MODE.getMode())) {
15 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
16 | } else if (mode.equals(ThemeModeEnum.DAY_MODE.getMode())) {
17 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
18 | }
19 | }
20 |
21 | public static boolean isNightMode(Context context){
22 | int mode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
23 | return mode == Configuration.UI_MODE_NIGHT_YES;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/welcome/FragmentSetAzureToken.kt:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.welcome
2 |
3 | import android.app.AlertDialog
4 | import android.content.Context
5 | import android.content.res.Resources.Theme
6 | import android.os.Bundle
7 | import android.os.Handler
8 | import android.os.Looper
9 | import android.os.Message
10 | import android.util.Log
11 | import android.view.LayoutInflater
12 | import android.view.View
13 | import android.view.ViewGroup
14 | import android.view.inputmethod.InputMethodManager
15 | import androidx.fragment.app.Fragment
16 | import androidx.preference.PreferenceManager
17 | import com.github.appintro.SlidePolicy
18 | import com.utopiaxc.utopiatts.R
19 | import com.utopiaxc.utopiatts.databinding.FragmentSetAzureTokenBinding
20 | import com.utopiaxc.utopiatts.enums.SettingsEnum
21 | import com.utopiaxc.utopiatts.tts.MsTts
22 | import com.utopiaxc.utopiatts.tts.enums.Regions
23 | import com.utopiaxc.utopiatts.utils.ThemeUtil
24 |
25 |
26 | class FragmentSetAzureToken(private var mContext: IntroActivity) : Fragment(), SlidePolicy {
27 | private val TAG = "FragmentSetAzureToken"
28 | private lateinit var mBinding: FragmentSetAzureTokenBinding
29 | private var mIsChecked = false
30 | private lateinit var mFragmentSetAzureTokenHandler: FragmentSetAzureTokenHandler
31 |
32 | override fun onCreate(savedInstanceState: Bundle?) {
33 | super.onCreate(savedInstanceState)
34 | mBinding = FragmentSetAzureTokenBinding.inflate(layoutInflater)
35 | mFragmentSetAzureTokenHandler = FragmentSetAzureTokenHandler(mContext.mainLooper)
36 | }
37 |
38 | override fun onCreateView(
39 | inflater: LayoutInflater, container: ViewGroup?,
40 | savedInstanceState: Bundle?
41 | ): View {
42 | Log.d(TAG, "onCreateView")
43 | if (ThemeUtil.isNightMode(mContext)) {
44 | mBinding.root.setBackgroundColor(mContext.getColor(R.color.welcome_bg_night))
45 | } else {
46 | mBinding.root.setBackgroundColor(mContext.getColor(R.color.welcome_bg_day))
47 | }
48 |
49 | mBinding.buttonSetAzureToken.setOnClickListener {
50 | val imm: InputMethodManager = requireView().context
51 | .getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
52 | imm.hideSoftInputFromWindow(requireView().windowToken, 0)
53 | val token = mBinding.editTextAzureToken.text.toString()
54 | if (token == "") {
55 | AlertDialog.Builder(this.activity).setTitle(R.string.warning)
56 | .setMessage(R.string.warning_blank_token)
57 | .setPositiveButton(R.string.confirm, null)
58 | .create()
59 | .show()
60 | return@setOnClickListener
61 | }
62 | val region = Regions.getRegion(
63 | resources.getStringArray(R.array.azure_region_values)
64 | [mBinding.spinnerAzureRegion.selectedItemId.toInt()]
65 | ).id
66 | mBinding.buttonSetAzureToken.isEnabled = false
67 | mBinding.buttonSetAzureToken.text = getString(R.string.checking)
68 | Thread(CheckToken(token, region)).start()
69 | }
70 | mBinding.buttonAzureTokenHelp.setOnClickListener {
71 | AlertDialog.Builder(this.activity).setTitle(R.string.tips)
72 | .setMessage(R.string.tips_azure_token)
73 | .setPositiveButton(R.string.confirm, null)
74 | .setNegativeButton(R.string.tutorials) { _, _ ->
75 | run {
76 | AlertDialog.Builder(this.activity).setTitle(R.string.sorry)
77 | .setMessage(R.string.tutorials_is_not_ready)
78 | .setPositiveButton(R.string.confirm, null)
79 | .create()
80 | .show()
81 | }
82 | }
83 | .create()
84 | .show()
85 | }
86 | return mBinding.root
87 | }
88 |
89 | companion object {
90 | @JvmStatic
91 | fun newInstance(context: IntroActivity): FragmentSetAzureToken {
92 | return FragmentSetAzureToken(context)
93 | }
94 | }
95 |
96 | override val isPolicyRespected: Boolean
97 | get() = mIsChecked
98 |
99 | override fun onUserIllegallyRequestedNextPage() {
100 | AlertDialog.Builder(this.activity).setTitle(R.string.warning)
101 | .setMessage(R.string.warning_azure_token_not_checked)
102 | .setPositiveButton(R.string.confirm, null)
103 | .create()
104 | .show()
105 | }
106 |
107 | private inner class CheckToken(var token: String, var region: String) : Runnable {
108 |
109 | override fun run() {
110 | if (MsTts.testAzureConfig(token, region)) {
111 | val message = Message()
112 | message.what = mFragmentSetAzureTokenHandler.CHECK_TOKEN_SUCCESS
113 | val bundle = Bundle()
114 | bundle.putString(SettingsEnum.AZURE_TOKEN.key, token)
115 | bundle.putString(SettingsEnum.AZURE_REGION.key, Regions.getRegion(region).getName())
116 | message.data = bundle
117 | mFragmentSetAzureTokenHandler.sendMessage(message)
118 | } else {
119 | mFragmentSetAzureTokenHandler.sendEmptyMessage(
120 | mFragmentSetAzureTokenHandler.CHECK_TOKEN_ERROR
121 | )
122 | }
123 | }
124 | }
125 |
126 | private inner class FragmentSetAzureTokenHandler(looper: Looper) : Handler(looper) {
127 | val CHECK_TOKEN_SUCCESS = 0x01
128 | val CHECK_TOKEN_ERROR = 0x02
129 |
130 | override fun handleMessage(msg: Message) {
131 | super.handleMessage(msg)
132 | when (msg.what) {
133 | CHECK_TOKEN_SUCCESS -> {
134 | val bundle = msg.data
135 | mBinding.buttonSetAzureToken.isEnabled = true
136 | mBinding.buttonSetAzureToken.text = getString(R.string.success)
137 | mBinding.buttonSetAzureToken
138 | .setBackgroundColor(resources.getColor(R.color.success))
139 | val editor = PreferenceManager.getDefaultSharedPreferences(mContext).edit()
140 | editor.putString(
141 | SettingsEnum.AZURE_TOKEN.key, bundle
142 | .getString(SettingsEnum.AZURE_TOKEN.key)
143 | )
144 | editor.putString(
145 | SettingsEnum.AZURE_REGION.key, bundle
146 | .getString(SettingsEnum.AZURE_REGION.key)
147 | )
148 | editor.apply()
149 | mIsChecked = true
150 | }
151 | CHECK_TOKEN_ERROR -> {
152 | mBinding.buttonSetAzureToken.isEnabled = true
153 | mBinding.buttonSetAzureToken
154 | .setBackgroundColor(resources.getColor(R.color.warning))
155 | mBinding.buttonSetAzureToken.text = getString(R.string.error)
156 | AlertDialog.Builder(mContext).setTitle(R.string.error)
157 | .setMessage(R.string.error_azure_token)
158 | .setPositiveButton(R.string.confirm, null)
159 | .create()
160 | .show()
161 | }
162 | }
163 | }
164 | }
165 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/welcome/FragmentTtsSelect.kt:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.welcome
2 |
3 | import android.app.AlertDialog
4 | import android.content.Intent
5 | import android.net.Uri
6 | import android.os.Bundle
7 | import android.util.Log
8 | import android.view.LayoutInflater
9 | import android.view.View
10 | import android.view.ViewGroup
11 | import androidx.fragment.app.Fragment
12 | import androidx.preference.PreferenceManager
13 | import com.github.appintro.SlidePolicy
14 | import com.utopiaxc.utopiatts.MainActivity
15 | import com.utopiaxc.utopiatts.R
16 | import com.utopiaxc.utopiatts.databinding.FragmentTtsSelectBinding
17 | import com.utopiaxc.utopiatts.enums.SettingsEnum
18 | import com.utopiaxc.utopiatts.tts.enums.Driver
19 | import com.utopiaxc.utopiatts.utils.ThemeUtil
20 |
21 |
22 | class FragmentTtsSelect(private var mContext: IntroActivity) : Fragment(), SlidePolicy {
23 | private val TAG = "FragmentTtsSelect"
24 | private var mIsChecked = true
25 | private lateinit var mBinding: FragmentTtsSelectBinding
26 |
27 | override fun onCreate(savedInstanceState: Bundle?) {
28 | super.onCreate(savedInstanceState)
29 | mBinding = FragmentTtsSelectBinding.inflate(layoutInflater)
30 |
31 | }
32 |
33 | override fun onCreateView(
34 | inflater: LayoutInflater, container: ViewGroup?,
35 | savedInstanceState: Bundle?
36 | ): View {
37 | val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext)
38 | val editor = sharedPreferences.edit()
39 | editor.putString(
40 | SettingsEnum.TTS_DRIVER.key,
41 | SettingsEnum.TTS_DRIVER.defaultValue as String
42 | )
43 | editor.apply()
44 | if (ThemeUtil.isNightMode(mContext)) {
45 | mBinding.root.setBackgroundColor(mContext.getColor(R.color.welcome_bg_night))
46 | mBinding.buttonTtsFromSelectHelp.setImageResource(R.drawable.ic_baseline_help_outline_24_night)
47 | } else {
48 | mBinding.root.setBackgroundColor(mContext.getColor(R.color.welcome_bg_day))
49 | }
50 | mBinding.buttonTtsFromSelectHelp.setOnClickListener {
51 | AlertDialog.Builder(this.activity).setTitle(R.string.tips)
52 | .setMessage(R.string.tips_tts_driver)
53 | .setPositiveButton(R.string.confirm, null)
54 | .setNeutralButton(R.string.ag2s20150909_tts_title) { _, _ ->
55 | run {
56 | val uri: Uri = Uri.parse(getString(R.string.ag2s20150909_tts))
57 | val intent = Intent(Intent.ACTION_VIEW, uri)
58 | startActivity(intent)
59 | }
60 | }
61 | .create()
62 | .show()
63 | }
64 | mBinding.ttsFromSdk.setOnClickListener {
65 | Log.d(TAG, "ttsFromSdk clicked")
66 | editor.putString(SettingsEnum.TTS_DRIVER.key, Driver.AZURE_SDK.id)
67 | editor.apply()
68 | mIsChecked=true
69 | }
70 | mBinding.ttsFromWebsocket.setOnClickListener {
71 | Log.d(TAG, "ttsFromWebsocket clicked")
72 | editor.putString(SettingsEnum.TTS_DRIVER.key, Driver.WEBSOCKET.id)
73 | editor.apply()
74 | mIsChecked=false
75 | }
76 | return mBinding.root
77 | }
78 |
79 | override val isPolicyRespected: Boolean
80 | get() = mIsChecked
81 |
82 | override fun onUserIllegallyRequestedNextPage() {
83 | val editor = PreferenceManager.getDefaultSharedPreferences(mContext).edit()
84 | editor.putBoolean(SettingsEnum.FIRST_BOOT.key, false)
85 | editor.apply()
86 | mContext.startActivity(Intent(mContext, MainActivity::class.java))
87 | mContext.finish()
88 | }
89 |
90 | companion object {
91 | @JvmStatic
92 | fun newInstance(context: IntroActivity): FragmentTtsSelect {
93 | return FragmentTtsSelect(context)
94 | }
95 | }
96 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/utopiaxc/utopiatts/welcome/IntroActivity.kt:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts.welcome
2 |
3 | import android.content.Intent
4 | import android.os.Bundle
5 | import androidx.fragment.app.Fragment
6 | import androidx.preference.PreferenceManager
7 | import com.github.appintro.AppIntro2
8 | import com.github.appintro.AppIntroFragment
9 | import com.utopiaxc.utopiatts.MainActivity
10 | import com.utopiaxc.utopiatts.R
11 | import com.utopiaxc.utopiatts.enums.SettingsEnum
12 | import com.utopiaxc.utopiatts.utils.ThemeUtil
13 |
14 | class IntroActivity : AppIntro2() {
15 | override fun onCreate(savedInstanceState: Bundle?) {
16 | super.onCreate(savedInstanceState)
17 | isWizardMode = true
18 | supportActionBar?.hide()
19 | setSwipeLock(true)
20 |
21 | val stringColor: Int
22 | val bgColor: Int
23 | if (ThemeUtil.isNightMode(this)) {
24 | stringColor = R.color.welcome_string_night
25 | bgColor = R.color.welcome_bg_night
26 | } else {
27 | stringColor = R.color.welcome_string_day
28 | bgColor = R.color.welcome_bg_day
29 | }
30 |
31 | //First Fragment
32 | addSlide(
33 | AppIntroFragment.createInstance(
34 | getString(R.string.welcome),
35 | getString(R.string.rights),
36 | R.mipmap.ic_launcher,
37 | bgColor,
38 | stringColor,
39 | stringColor,
40 | )
41 | )
42 |
43 | addSlide(FragmentTtsSelect.newInstance(this))
44 |
45 | addSlide(FragmentSetAzureToken.newInstance(this))
46 |
47 | }
48 |
49 | override fun onDonePressed(currentFragment: Fragment?) {
50 | super.onDonePressed(currentFragment)
51 | val editor = PreferenceManager.getDefaultSharedPreferences(this).edit()
52 | editor.putBoolean(SettingsEnum.FIRST_BOOT.key, false)
53 | editor.apply()
54 | startActivity(Intent(this, MainActivity::class.java))
55 | finish()
56 | }
57 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/main/res/drawable-v24/logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_code_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_help_outline_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_help_outline_24_night.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_settings_accessibility_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_sharp_hearing_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
21 |
22 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_set_azure_token.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
32 |
33 |
45 |
46 |
58 |
59 |
69 |
70 |
84 |
85 |
98 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_tts_select.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
21 |
22 |
33 |
34 |
41 |
42 |
49 |
50 |
51 |
65 |
66 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_tts_usage.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/bottom_nav_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/navigation/nav_graph.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
11 |
16 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/values-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 48dp
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w1240dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 200dp
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 48dp
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values-zh/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - 南非北部
5 | - 东亚
6 | - 东南亚 (支持预览)
7 | - 澳大利亚东部
8 | - 印度中部
9 | - 日本东部
10 | - 日本西部
11 | - 韩国中部
12 | - 加拿大中部
13 | - 北欧
14 | - 西欧 (支持预览)
15 | - 法国中部
16 | - 德国中西部
17 | - 挪威东部
18 | - 瑞士北部
19 | - 瑞士西部
20 | - 英国南部
21 | - 阿拉伯联合酋长国北部
22 | - 巴西南部
23 | - 美国中部
24 | - 美国东部 (支持预览)
25 | - 美国东部 2 (支持预览)
26 | - 美国中北部
27 | - 美国中南部
28 | - 美国中西部
29 | - 美国西部
30 | - 美国西部 2
31 | - 美国西部 3
32 |
33 |
34 |
35 | - 中国大陆 中文 晓晨(女)
36 | - 中国大陆 中文 晓涵(女)
37 | - 中国大陆 中文 晓梦(女、预览)
38 | - 中国大陆 中文 晓墨(女)
39 | - 中国大陆 中文 晓秋(女)
40 | - 中国大陆 中文 晓睿(女)
41 | - 中国大陆 中文 晓双(女)
42 | - 中国大陆 中文 晓晓(女)
43 | - 中国大陆 中文 晓萱(女)
44 | - 中国大陆 中文 晓颜(女)
45 | - 中国大陆 中文 晓伊(女、预览)
46 | - 中国大陆 中文 晓悠(女)
47 | - 中国大陆 中文 晓甄(女、预览)
48 | - 中国大陆 中文 云枫(男、预览)
49 | - 中国大陆 中文 云皓(男、预览)
50 | - 中国大陆 中文 云健(男、预览)
51 | - 中国大陆 中文 云夏(男、预览)
52 | - 中国大陆 中文 云希(男)
53 | - 中国大陆 中文 云扬(男)
54 | - 中国大陆 中文 云野(男)
55 | - 中国大陆 中文 云泽(男、预览)
56 | - 中国河南 中文 云登(男、预览)
57 | - 中国辽宁 中文 晓北(女、预览)
58 | - 中国陕西 中文 晓妮(女、预览)
59 | - 中国山东 中文 云飞(男、预览)
60 | - 中国四川 中文 云希(男、预览)
61 | - 中国香港 中文 曉佳(女)
62 | - 中国香港 中文 曉曼(女)
63 | - 中国香港 中文 雲龍(男)
64 | - 中国台湾 中文 曉臻(女)
65 | - 中国台湾 中文 曉雨(女)
66 | - 中国台湾 中文 雲哲(女)
67 |
68 |
69 |
70 | - 无
71 | - 冷静
72 | - 害怕
73 | - 喜悦
74 | - 不满
75 | - 严肃
76 | - 生气
77 | - 绅士
78 | - 亲切
79 | - 尴尬
80 | - 低沉
81 | - 羡慕
82 | - 助理
83 | - 客服
84 | - 新闻
85 | - 抒情
86 | - 朗诵
87 | - 发奋
88 | - 体育解说
89 | - 兴奋地体育解说
90 | - 轻松叙事
91 | - 纪录片解说
92 |
93 |
94 |
95 | - AUDIO_16K_HZ_128K_BIT_RATE_MONO_MP3 *
96 | - AUDIO_16K_HZ_16_BIT_32KBPS_MONO_OPUS *
97 | - AUDIO_16K_HZ_16KBPS_MONO_SIREN
98 | - AUDIO_16K_HZ_32K_BIT_RATE_MONO_MP3 *
99 | - AUDIO_16K_HZ_64K_BIT_RATE_MONO_MP3 *
100 | - AUDIO_24K_HZ_160K_BIT_RATE_MONO_MP3 *
101 | - AUDIO_24K_HZ_16_BIT_24KBPS_MONO_OPUS *
102 | - AUDIO_24K_HZ_16_BIT_48KBPS_MONO_OPUS *
103 | - AUDIO_24K_HZ_48K_BIT_RATE_MONO_MP3 *
104 | - AUDIO_24K_HZ_96K_BIT_RATE_MONO_MP3 *
105 | - AUDIO_48K_HZ_192K_BIT_RATE_MONO_MP3 *
106 | - AUDIO_48K_HZ_96K_BIT_RATE_MONO_MP3 *
107 | - OGG_16K_HZ_16_BIT_MONO_OPUS *
108 | - OGG_24K_HZ_16_BIT_MONO_OPUS *
109 | - OGG_48K_HZ_16_BIT_MONO_OPUS * 默认格式
110 | - RAW_16K_HZ_16_BIT_MONO_PCM
111 | - RAW_16K_HZ_16_BIT_MONO_TRUE_SILK
112 | - RAW_22050_HZ_16_BIT_MONO_PCM
113 | - RAW_24K_HZ_16_BIT_MONO_PCM
114 | - RAW_24K_HZ_16_BIT_MONO_TRUE_SILK
115 | - RAW_44100_HZ_16_BIT_MONO_PCM
116 | - RAW_48K_HZ_16_BIT_MONO_PCM
117 | - RAW_8K_HZ_16_BIT_MONO_PCM
118 | - RAW_8K_HZ_8_BIT_MONO_ALAW
119 | - RAW_8K_HZ_8_BIT_MONO_MULAW
120 | - RIFF_16K_HZ_16_BIT_MONO_PCM
121 | - RIFF_16K_HZ_16KBPS_MONO_SIREN
122 | - RIFF_22050_HZ_16_BIT_MONO_PCM
123 | - RIFF_24K_HZ_16_BIT_MONO_PCM
124 | - RIFF_44100_HZ_16_BIT_MONO_PCM
125 | - RIFF_48K_HZ_16_BIT_MONO_PCM
126 | - RIFF_8K_HZ_16_BIT_MONO_PCM
127 | - RIFF_8K_HZ_8_BIT_MONO_ALAW
128 | - RIFF_8K_HZ_8_BIT_MONO_MULAW
129 | - WEBM_16K_HZ_16_BIT_MONO_OPUS *
130 | - WEBM_24K_HZ_16_BIT_24KBPS_MONO_OPUS *
131 | - WEBM_24K_HZ_16_BIT_MONO_OPUS *
132 |
133 |
134 |
135 | - Azure SDK个人密钥
136 | - 官网Demo WebSocket
137 |
138 |
--------------------------------------------------------------------------------
/app/src/main/res/values-zh/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Utopia TTS
4 | 设置
5 |
6 |
7 | Azure设置
8 | TTS 设置
9 |
10 |
11 | Azure密钥
12 | Azure可用区
13 |
14 | TTS设置
15 | 使用TTS
16 | 关于
17 |
18 | 欢迎使用 Utopia TTS
19 | Copyright © 2022 UtopiaXC All Rights Reserved.
20 |
21 | 提示
22 | Azure SDK方式采用微软官方开发工具包,速度快,连接稳定,但是需要注册Azure账户(有每月50万字免费额度),并输入密钥。\n\nWebSocket方式采用微软TTS官网的网页演示Demo的WebSocket接口实现,不需要注册账户和生成密钥。\n\n\感谢ag2s20150909大佬为本项目的创作提供灵感。
23 | 确认
24 | TTS引擎驱动方式
25 | Azure SDK
26 | Demo WebSocket
27 | 警告
28 | 请输入Azure TTS服务密钥。
29 | 您的Azure信息未经检查,请先点击确认进行检查。
30 | 检查中
31 | 成功
32 | 错误
33 | 您的Azure密钥或可用区错误,请检查其是否正确或余量是否用尽,或检查您的网络是否可以访问微软对应服务器。
34 | 您的Azure密钥验证成功,已设置。
35 | 语音演员
36 | 当前所选地区不支持预览版语音,请先选择支持的区域。目前支持预览版的可用区为:美国东部、西欧和东南亚
37 | 您当前选中的语音演员为预览版,您需要选择支持预览版的地区,或先切换成非预览版的语音演员。
38 | 声音风格
39 | 版本
40 | 更新日志
41 | 开源许可证
42 | 作者
43 | 在GitHub上关注
44 | 通过邮件反馈
45 | UtopiaTTS的反馈
46 | 清空保存的配置
47 | 取消
48 | 确认清空全部保存的配置?
49 | 设置
50 | 更新日志
51 | 教程
52 | 抱歉
53 | 教程还未编写完成。
54 | 此处输入从微软Azure中获取的TTS服务密钥,如果不理解,可以点击教程前往了解。
55 | 音频流格式
56 | "如果您的语音不卡顿,请不要修改本项,因为部分语音在WebSocket模式下存在部分无法解决的问题以加剧卡顿。\n如果需要修改,请首选带'*'的格式,因为它们是需要进行解码的格式,因此可能更加稳定。"
57 | 这是一个由Utopia TTS合成的语音合成范例。
58 |
--------------------------------------------------------------------------------
/app/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | - South Africa North
4 | - East Asia
5 | - South East Asia (Support Preview)
6 | - Australia East
7 | - Central India
8 | - Japan East
9 | - Japan West
10 | - Korea Central
11 | - Canada Central
12 | - North Europe
13 | - West Europe (Support Preview)
14 | - France Central
15 | - Germany West Central
16 | - Norway East
17 | - Switzerland North
18 | - Switzerland West
19 | - UK South
20 | - UAE North
21 | - Brazil South
22 | - Central US
23 | - East US (Support Preview)
24 | - East US 2 (Support Preview)
25 | - North Central US
26 | - South Central US
27 | - West Central US
28 | - West US
29 | - West US 2
30 | - West US 3
31 |
32 |
33 |
34 | - SOUTH_AFRICA_NORTH
35 | - EAST_ASIA
36 | - SOUTH_EAST_ASIA
37 | - AUSTRALIA_EAST
38 | - CENTRAL_INDIA
39 | - JAPAN_EAST
40 | - JAPAN_WEST
41 | - KOREA_CENTRAL
42 | - CANADA_CENTRAL
43 | - NORTH_EUROPE
44 | - WEST_EUROPE
45 | - FRANCE_CENTRAL
46 | - GERMANY_WEST_CENTRAL
47 | - NORWAY_EAST
48 | - SWITZERLAND_NORTH
49 | - SWITZERLAND_WEST
50 | - UK_SOUTH
51 | - UAE_NORTH
52 | - BRAZIL_SOUTH
53 | - CENTRAL_US
54 | - EAST_US
55 | - EAST_US2
56 | - NORTH_CENTRAL_US
57 | - SOUTH_CENTRAL_US
58 | - WEST_CENTRAL_US
59 | - WEST_US
60 | - WEST_US2
61 | - WEST_US3
62 |
63 |
64 |
65 | - China Chinese XiaoChen (Female)
66 | - China Chinese XiaoHan (Female)
67 | - China Chinese XiaoMeng (Female,Preview)
68 | - China Chinese XiaoMo (Female)
69 | - China Chinese XiaoQiu (Female)
70 | - China Chinese XiaoRiu (Female)
71 | - China Chinese XiaoShuang (Female)
72 | - China Chinese XiaoXiao (Female)
73 | - China Chinese XiaoXuan (Female)
74 | - China Chinese XiaoYan (Female)
75 | - China Chinese XiaoYi (Female,Preview)
76 | - China Chinese XiaoYou (Female)
77 | - China Chinese XiaoZhen (Female,Preview)
78 | - China Chinese YunFeng (Male,Preview)
79 | - China Chinese YunHao (Male,Preview)
80 | - China Chinese YunJian (Male,Preview)
81 | - China Chinese YunXia (Male,Preview)
82 | - China Chinese YunXi (Male)
83 | - China Chinese YunYang (Male)
84 | - China Chinese YunYe (Male)
85 | - China Chinese YunZe (Male)
86 | - China Chinese(Henan) YunDeng(Male,Preview)
87 | - China Chinese(Liaoning) XiaoBei(Female,Preview)
88 | - China Chinese(Shaanxi) XiaoNi(Female,Preview)
89 | - China Chinese(Shandong) YunXiang(Male,Preview)
90 | - China Chinese(Sichuan) YunXi(Male,Preview)
91 | - China Chinese(HongKong) HiuGaai(Female)
92 | - China Chinese(HongKong) HiuMaan(Female)
93 | - China Chinese(HongKong) WanLung(Male)
94 | - China Chinese(TaiWan) HsiaoChen(Female)
95 | - China Chinese(TaiWan) HsiaoYu(Female)
96 | - China Chinese(TaiWan) YunJhe(Male)
97 |
98 |
99 |
100 | - ZH_CN_XIAOCHEN_NEURAL
101 | - ZH_CN_XIAOHAN_NEURAL
102 | - ZH_CN_XIAOMENG_NEURAL
103 | - ZH_CN_XIAOMO_NEURAL
104 | - ZH_CN_XIAOQIU_NEURAL
105 | - ZH_CN_XIAORUI_NEURAL
106 | - ZH_CN_XIAOSHUANG_NEURAL
107 | - ZH_CN_XIAOXIAO_NEURAL
108 | - ZH_CN_XIAOXUAN_NEURAL
109 | - ZH_CN_XIAOYAN_NEURAL
110 | - ZH_CN_XIAOYI_NEURAL
111 | - ZH_CN_XIAOYOU_NEURAL
112 | - ZH_CN_XIAOZHEN_NEURAL
113 | - ZH_CN_YUNFENG_NEURAL
114 | - ZH_CN_YUNHAO_NEURAL
115 | - ZH_CN_YUNJIAN_NEURAL
116 | - ZH_CN_YUNXIA_NEURAL
117 | - ZH_CN_YUNXI_NEURAL
118 | - ZH_CN_YUNYANG_NEURAL
119 | - ZH_CN_YUNYE_NEURAL
120 | - ZH_CN_YUNZE_NEURAL
121 | - ZH_CN_HENAN_YUNDENG_NEURAL
122 | - ZH_CN_LIAONING_XIAOBEI_NEURAL
123 | - ZH_CN_SHAANXI_XIAONI_NEURAL
124 | - ZH_CN_SHANDONG_YUNXIANG_NEURAL
125 | - ZH_CN_SICHUAN_YUNXI_NEURAL
126 | - ZH_HK_HIUGAAI_NEURAL
127 | - ZH_HK_HIUMAAN_NEURAL
128 | - ZH_HK_WANLUNG_NEURAL
129 | - ZH_TW_HSIAOCHEN_NEURAL
130 | - ZH_TW_HSIAOYU_NEURAL
131 | - ZH_TW_YUNJHE_NEURAL
132 |
133 |
134 |
135 | - None
136 | - Calm
137 | - Fearful
138 | - Cheerful
139 | - Disgruntled
140 | - Serious
141 | - Angry
142 | - Gentle
143 | - Affectionate
144 | - Embarrassed
145 | - Depressed
146 | - Envious
147 | - Assistant
148 | - Customer Service
149 | - Newscast
150 | - Lyrical
151 | - Poetry Reading
152 | - Advertisement Upbeat
153 | - Sports Commentary
154 | - Sports Commentary Excited
155 | - Narration Relaxed
156 | - Documentary Narration
157 |
158 |
159 |
160 | - NONE
161 | - CALM
162 | - FEARFUL
163 | - CHEERFUL
164 | - DISGRUNTLED
165 | - SERIOUS
166 | - ANGRY
167 | - GENTLE
168 | - AFFECTIONATE
169 | - EMBARRASSED
170 | - DEPRESSED
171 | - ENVIOUS
172 | - ASSISTANT
173 | - CUSTOMER_SERVICE
174 | - NEWSCAST
175 | - LYRICAL
176 | - ADVERTISEMENT_UPBEAT
177 | - SPORTS_COMMENTARY
178 | - SPORTS_COMMENTARY_EXCITED
179 | - NARRATION_RELAXED
180 | - DOCUMENTARY_NARRATION
181 |
182 |
183 |
184 | - AUDIO_16K_HZ_128K_BIT_RATE_MONO_MP3 *
185 | - AUDIO_16K_HZ_16_BIT_32KBPS_MONO_OPUS *
186 | - AUDIO_16K_HZ_16KBPS_MONO_SIREN
187 | - AUDIO_16K_HZ_32K_BIT_RATE_MONO_MP3 *
188 | - AUDIO_16K_HZ_64K_BIT_RATE_MONO_MP3 *
189 | - AUDIO_24K_HZ_160K_BIT_RATE_MONO_MP3 *
190 | - AUDIO_24K_HZ_16_BIT_24KBPS_MONO_OPUS *
191 | - AUDIO_24K_HZ_16_BIT_48KBPS_MONO_OPUS *
192 | - AUDIO_24K_HZ_48K_BIT_RATE_MONO_MP3 *
193 | - AUDIO_24K_HZ_96K_BIT_RATE_MONO_MP3 *
194 | - AUDIO_48K_HZ_192K_BIT_RATE_MONO_MP3 *
195 | - AUDIO_48K_HZ_96K_BIT_RATE_MONO_MP3 *
196 | - OGG_16K_HZ_16_BIT_MONO_OPUS *
197 | - OGG_24K_HZ_16_BIT_MONO_OPUS *
198 | - OGG_48K_HZ_16_BIT_MONO_OPUS * (Default)
199 | - RAW_16K_HZ_16_BIT_MONO_PCM
200 | - RAW_16K_HZ_16_BIT_MONO_TRUE_SILK
201 | - RAW_22050_HZ_16_BIT_MONO_PCM
202 | - RAW_24K_HZ_16_BIT_MONO_PCM
203 | - RAW_24K_HZ_16_BIT_MONO_TRUE_SILK
204 | - RAW_44100_HZ_16_BIT_MONO_PCM
205 | - RAW_48K_HZ_16_BIT_MONO_PCM
206 | - RAW_8K_HZ_16_BIT_MONO_PCM
207 | - RAW_8K_HZ_8_BIT_MONO_ALAW
208 | - RAW_8K_HZ_8_BIT_MONO_MULAW
209 | - RIFF_16K_HZ_16_BIT_MONO_PCM
210 | - RIFF_16K_HZ_16KBPS_MONO_SIREN
211 | - RIFF_22050_HZ_16_BIT_MONO_PCM
212 | - RIFF_24K_HZ_16_BIT_MONO_PCM
213 | - RIFF_44100_HZ_16_BIT_MONO_PCM
214 | - RIFF_48K_HZ_16_BIT_MONO_PCM
215 | - RIFF_8K_HZ_16_BIT_MONO_PCM
216 | - RIFF_8K_HZ_8_BIT_MONO_ALAW
217 | - RIFF_8K_HZ_8_BIT_MONO_MULAW
218 | - WEBM_16K_HZ_16_BIT_MONO_OPUS *
219 | - WEBM_24K_HZ_16_BIT_24KBPS_MONO_OPUS *
220 | - WEBM_24K_HZ_16_BIT_MONO_OPUS *
221 |
222 |
223 |
224 | - AUDIO_16K_HZ_128K_BIT_RATE_MONO_MP3
225 | - AUDIO_16K_HZ_16_BIT_32KBPS_MONO_OPUS
226 | - AUDIO_16K_HZ_16KBPS_MONO_SIREN
227 | - AUDIO_16K_HZ_32K_BIT_RATE_MONO_MP3
228 | - AUDIO_16K_HZ_64K_BIT_RATE_MONO_MP3
229 | - AUDIO_24K_HZ_160K_BIT_RATE_MONO_MP3
230 | - AUDIO_24K_HZ_16_BIT_24KBPS_MONO_OPUS
231 | - AUDIO_24K_HZ_16_BIT_48KBPS_MONO_OPUS
232 | - AUDIO_24K_HZ_48K_BIT_RATE_MONO_MP3
233 | - AUDIO_24K_HZ_96K_BIT_RATE_MONO_MP3
234 | - AUDIO_48K_HZ_192K_BIT_RATE_MONO_MP3
235 | - AUDIO_48K_HZ_96K_BIT_RATE_MONO_MP3
236 | - OGG_16K_HZ_16_BIT_MONO_OPUS
237 | - OGG_24K_HZ_16_BIT_MONO_OPUS
238 | - OGG_48K_HZ_16_BIT_MONO_OPUS
239 | - RAW_16K_HZ_16_BIT_MONO_PCM
240 | - RAW_16K_HZ_16_BIT_MONO_TRUE_SILK
241 | - RAW_22050_HZ_16_BIT_MONO_PCM
242 | - RAW_24K_HZ_16_BIT_MONO_PCM
243 | - RAW_24K_HZ_16_BIT_MONO_TRUE_SILK
244 | - RAW_44100_HZ_16_BIT_MONO_PCM
245 | - RAW_48K_HZ_16_BIT_MONO_PCM
246 | - RAW_8K_HZ_16_BIT_MONO_PCM
247 | - RAW_8K_HZ_8_BIT_MONO_ALAW
248 | - RAW_8K_HZ_8_BIT_MONO_MULAW
249 | - RIFF_16K_HZ_16_BIT_MONO_PCM
250 | - RIFF_16K_HZ_16KBPS_MONO_SIREN
251 | - RIFF_22050_HZ_16_BIT_MONO_PCM
252 | - RIFF_24K_HZ_16_BIT_MONO_PCM
253 | - RIFF_44100_HZ_16_BIT_MONO_PCM
254 | - RIFF_48K_HZ_16_BIT_MONO_PCM
255 | - RIFF_8K_HZ_16_BIT_MONO_PCM
256 | - RIFF_8K_HZ_8_BIT_MONO_ALAW
257 | - RIFF_8K_HZ_8_BIT_MONO_MULAW
258 | - WEBM_16K_HZ_16_BIT_MONO_OPUS
259 | - WEBM_24K_HZ_16_BIT_24KBPS_MONO_OPUS
260 | - WEBM_24K_HZ_16_BIT_MONO_OPUS
261 |
262 |
263 |
264 |
265 |
266 | - Azure SDK Token
267 | - Demo WebSocket
268 |
269 |
270 |
271 | - azure_sdk
272 | - websocket
273 |
274 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 | #FFFFFF
11 | #3E3E3E
12 | #000000
13 | #ECECEC
14 | #F44336
15 | #009688
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 16dp
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FAFAFA
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Utopia TTS
3 | Settings
4 |
5 |
6 | Azure Settings
7 | TTS Settings
8 |
9 | Azure Token
10 | Azure Region
11 |
12 | TTS Settings
13 | TTS Usage
14 | About
15 |
16 | Welcome to Utopia TTS
17 | Copyright © 2022 UtopiaXC All Rights Reserved.
18 |
19 | Tips
20 | The Azure SDK approach uses the official Microsoft development kit, which is fast and stable, but requires an Azure account (with 500,000 free words per month) and a token.\n\nThe WebSocket approach uses the WebSocket interface from the Microsoft TTS website\'s web demo, which is slow, unstable and at risk of not being available at any time, but does not require account registration and key generation, and is highly discouraged.
21 | Confirm
22 |
23 | TTS engine driven approach
24 | Azure SDK
25 | Demo WebSocket
26 | Warning
27 | Please input the token.
28 | Your azure config is not checked. Please tap confirm first.
29 | Checking
30 | Success
31 | Error
32 | Your token or region is wrong, please check that it is correct or that the spare capacity is not exhausted, or maybe your network is not available
33 | Your token is available, set successful.
34 | Voice Actor
35 | The region you set is not support preview actor, please change region first.Now, the support region are East US, West Europe and Southeast Asia
36 | The voice actor you set is preview, you should only select region which is supported preview.
37 | Voice Style
38 | Version
39 | Change Log
40 | License
41 | Author
42 | UtopiaXC
43 | Follow on GitHub
44 | Feedback by email
45 | https://github.com/UtopiaXC/UtopiaTTS
46 | utopiaxc@utopiaxc.com
47 | Feedback for UtopiaTTS
48 | Clear all profiles
49 | Cancel
50 | Confirm to clear all profiles?
51 | Settings
52 | Change log(Please wait for GitHub)
53 | https://github.com/UtopiaXC/UtopiaTTS
54 | https://github.com/ag2s20150909/TTS
55 | ag2s20150909 TTS
56 | Tutorials
57 | Sorry
58 | Tutorials is not ready.
59 | Input the token you get from azure, you can tap tutorials button to learn.
60 | Voice Output Format
61 | "Please don't change it if the voice is not stuttering because some format have problems during websocket request. If you want to change it, please use the format with '*' because they are encoded format witch maybe mach stable."
62 | This is an example of speech synthesis by Utopia TTS.
63 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/root_preferences.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
12 |
13 |
18 |
19 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
37 |
38 |
44 |
45 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/tts_engine.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
--------------------------------------------------------------------------------
/app/src/release/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/release/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/release/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/release/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/release/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/release/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/release/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/release/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/release/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/release/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/release/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/release/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/release/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/release/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/release/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/release/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/release/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/release/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/release/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/release/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/release/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/release/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/release/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/release/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/release/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/release/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/release/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/release/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/release/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/release/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/release/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/release/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/release/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/app/src/release/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/release/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FAFAFA
4 |
--------------------------------------------------------------------------------
/app/src/test/java/com/utopiaxc/utopiatts/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.utopiaxc.utopiatts;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | plugins {
3 | id 'com.android.application' version '7.3.0' apply false
4 | id 'com.android.library' version '7.3.0' apply false
5 | id 'org.jetbrains.kotlin.android' version '1.6.21' apply false
6 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Enables namespacing of each library's R class so that its R class includes only the
19 | # resources declared in the library itself and none from the library's dependencies,
20 | # thereby reducing the size of the R class for that library
21 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UtopiaXC/UtopiaTTS/b609bd98ba9244d11c3e8db13fc0380d3051766a/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Sep 26 21:00:41 CST 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | google()
5 | mavenCentral()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | maven { url "https://jitpack.io" }
14 | }
15 | }
16 | rootProject.name = "Utopia TTS"
17 | include ':app'
18 |
--------------------------------------------------------------------------------