commit
5c8b75ee18
@ -0,0 +1,13 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/caches
|
||||
/.idea/libraries
|
||||
/.idea/modules.xml
|
||||
/.idea/workspace.xml
|
||||
/.idea/navEditor.xml
|
||||
/.idea/assetWizardSettings.xml
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
@ -0,0 +1 @@
|
||||
/build
|
@ -0,0 +1,108 @@
|
||||
import java.security.MessageDigest
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
defaultConfig {
|
||||
applicationId "com.baidu.paddle.lite.demo.tts"
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 28
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation 'com.android.support:appcompat-v7:28.0.0'
|
||||
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
|
||||
implementation 'com.android.support:design:28.0.0'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||
implementation files('libs/PaddlePredictor.jar')
|
||||
}
|
||||
|
||||
def paddleLiteLibs = 'https://paddlespeech.bj.bcebos.com/demos/TTSAndroid/paddle_lite_libs_68b66fd3.tar.gz'
|
||||
task downloadAndExtractPaddleLiteLibs(type: DefaultTask) {
|
||||
doFirst {
|
||||
println "Downloading and extracting Paddle Lite libs"
|
||||
}
|
||||
doLast {
|
||||
// Prepare cache folder for libs
|
||||
if (!file("cache").exists()) {
|
||||
mkdir "cache"
|
||||
}
|
||||
// Generate cache name for libs
|
||||
MessageDigest messageDigest = MessageDigest.getInstance('MD5')
|
||||
messageDigest.update(paddleLiteLibs.bytes)
|
||||
String cacheName = new BigInteger(1, messageDigest.digest()).toString(32)
|
||||
// Download libs
|
||||
if (!file("cache/${cacheName}.tar.gz").exists()) {
|
||||
ant.get(src: paddleLiteLibs, dest: file("cache/${cacheName}.tar.gz"))
|
||||
}
|
||||
// Unpack libs
|
||||
if (!file("cache/${cacheName}").exists()) {
|
||||
copy {
|
||||
from tarTree("cache/${cacheName}.tar.gz")
|
||||
into "cache/${cacheName}"
|
||||
}
|
||||
}
|
||||
// Copy PaddlePredictor.jar
|
||||
if (!file("libs/PaddlePredictor.jar").exists()) {
|
||||
copy {
|
||||
from "cache/${cacheName}/java/PaddlePredictor.jar"
|
||||
into "libs"
|
||||
}
|
||||
}
|
||||
if (!file("src/main/jniLibs/arm64-v8a/libpaddle_lite_jni.so").exists()) {
|
||||
copy {
|
||||
from "cache/${cacheName}/java/libs/arm64-v8a/"
|
||||
into "src/main/jniLibs/arm64-v8a"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
preBuild.dependsOn downloadAndExtractPaddleLiteLibs
|
||||
|
||||
def paddleLiteModels = [['src' : 'https://paddlespeech.bj.bcebos.com/demos/TTSAndroid/fs2cnn_mbmelgan_cpu_v1.3.0.tar.gz',
|
||||
'dest': 'src/main/assets/models'],]
|
||||
task downloadAndExtractPaddleLiteModels(type: DefaultTask) {
|
||||
doFirst {
|
||||
println "Downloading and extracting Paddle Lite models"
|
||||
}
|
||||
doLast {
|
||||
// Prepare cache folder for models
|
||||
String cachePath = "cache"
|
||||
if (!file("${cachePath}").exists()) {
|
||||
mkdir "${cachePath}"
|
||||
}
|
||||
paddleLiteModels.eachWithIndex { model, index ->
|
||||
MessageDigest messageDigest = MessageDigest.getInstance('MD5')
|
||||
messageDigest.update(model.src.bytes)
|
||||
String cacheName = new BigInteger(1, messageDigest.digest()).toString(32)
|
||||
// Download the target model if not exists
|
||||
boolean copyFiles = !file("${model.dest}").exists()
|
||||
if (!file("${cachePath}/${cacheName}.tar.gz").exists()) {
|
||||
ant.get(src: model.src, dest: file("${cachePath}/${cacheName}.tar.gz"))
|
||||
copyFiles = true // force to copy files from the latest archive files
|
||||
}
|
||||
// Copy model file
|
||||
if (copyFiles) {
|
||||
copy {
|
||||
from tarTree("${cachePath}/${cacheName}.tar.gz")
|
||||
into "${model.dest}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
preBuild.dependsOn downloadAndExtractPaddleLiteModels
|
@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
@ -0,0 +1,26 @@
|
||||
package com.baidu.paddle.lite.demo.tts;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
assertEquals("com.baidu.paddle.lite.demo", appContext.getPackageName());
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.baidu.paddle.lite.demo.tts">
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/logo"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@drawable/logo"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity android:name="com.baidu.paddle.lite.demo.tts.MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="com.baidu.paddle.lite.demo.tts.SettingsActivity"
|
||||
android:label="Settings"></activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.baidu.paddle.lite.demo.tts;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.support.annotation.LayoutRes;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AppCompatDelegate;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls
|
||||
* to be used with AppCompat.
|
||||
* <p>
|
||||
* This technique can be used with an {@link android.app.Activity} class, not just
|
||||
* {@link android.preference.PreferenceActivity}.
|
||||
*/
|
||||
public abstract class AppCompatPreferenceActivity extends PreferenceActivity {
|
||||
private AppCompatDelegate mDelegate;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
getDelegate().installViewFactory();
|
||||
getDelegate().onCreate(savedInstanceState);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
getDelegate().onPostCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
public ActionBar getSupportActionBar() {
|
||||
return getDelegate().getSupportActionBar();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MenuInflater getMenuInflater() {
|
||||
return getDelegate().getMenuInflater();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(@LayoutRes int layoutResID) {
|
||||
getDelegate().setContentView(layoutResID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view) {
|
||||
getDelegate().setContentView(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view, ViewGroup.LayoutParams params) {
|
||||
getDelegate().setContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addContentView(View view, ViewGroup.LayoutParams params) {
|
||||
getDelegate().addContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostResume() {
|
||||
super.onPostResume();
|
||||
getDelegate().onPostResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTitleChanged(CharSequence title, int color) {
|
||||
super.onTitleChanged(title, color);
|
||||
getDelegate().setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
getDelegate().onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
getDelegate().onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
getDelegate().onDestroy();
|
||||
}
|
||||
|
||||
public void invalidateOptionsMenu() {
|
||||
getDelegate().invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
private AppCompatDelegate getDelegate() {
|
||||
if (mDelegate == null) {
|
||||
mDelegate = AppCompatDelegate.create(this, null);
|
||||
}
|
||||
return mDelegate;
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
package com.baidu.paddle.lite.demo.tts;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.CheckBoxPreference;
|
||||
import android.preference.EditTextPreference;
|
||||
import android.preference.ListPreference;
|
||||
import android.support.v7.app.ActionBar;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SettingsActivity extends AppCompatPreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
ListPreference lpChoosePreInstalledModel = null;
|
||||
CheckBoxPreference cbEnableCustomSettings = null;
|
||||
EditTextPreference etModelPath = null;
|
||||
ListPreference lpCPUThreadNum = null;
|
||||
ListPreference lpCPUPowerMode = null;
|
||||
|
||||
List<String> preInstalledModelPaths = null;
|
||||
List<String> preInstalledCPUThreadNums = null;
|
||||
List<String> preInstalledCPUPowerModes = null;
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
addPreferencesFromResource(R.xml.settings);
|
||||
ActionBar supportActionBar = getSupportActionBar();
|
||||
if (supportActionBar != null) {
|
||||
supportActionBar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
// Initialized pre-installed models
|
||||
preInstalledModelPaths = new ArrayList<String>();
|
||||
preInstalledCPUThreadNums = new ArrayList<String>();
|
||||
preInstalledCPUPowerModes = new ArrayList<String>();
|
||||
preInstalledModelPaths.add(getString(R.string.MODEL_PATH_DEFAULT));
|
||||
preInstalledCPUThreadNums.add(getString(R.string.CPU_THREAD_NUM_DEFAULT));
|
||||
preInstalledCPUPowerModes.add(getString(R.string.CPU_POWER_MODE_DEFAULT));
|
||||
|
||||
|
||||
// Setup UI components
|
||||
lpChoosePreInstalledModel = (ListPreference) findPreference(getString(R.string.CHOOSE_PRE_INSTALLED_MODEL_KEY));
|
||||
String[] preInstalledModelNames = new String[preInstalledModelPaths.size()];
|
||||
for (int i = 0; i < preInstalledModelPaths.size(); i++) {
|
||||
preInstalledModelNames[i] = preInstalledModelPaths.get(i).substring(preInstalledModelPaths.get(i).lastIndexOf("/") + 1);
|
||||
}
|
||||
lpChoosePreInstalledModel.setEntries(preInstalledModelNames);
|
||||
lpChoosePreInstalledModel.setEntryValues(preInstalledModelPaths.toArray(new String[preInstalledModelPaths.size()]));
|
||||
lpCPUThreadNum = (ListPreference) findPreference(getString(R.string.CPU_THREAD_NUM_KEY));
|
||||
lpCPUPowerMode = (ListPreference) findPreference(getString(R.string.CPU_POWER_MODE_KEY));
|
||||
cbEnableCustomSettings = (CheckBoxPreference) findPreference(getString(R.string.ENABLE_CUSTOM_SETTINGS_KEY));
|
||||
etModelPath = (EditTextPreference) findPreference(getString(R.string.MODEL_PATH_KEY));
|
||||
etModelPath.setTitle("Model Path (SDCard: " + Utils.getSDCardDirectory() + ")");
|
||||
}
|
||||
|
||||
private void reloadPreferenceAndUpdateUI() {
|
||||
SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences();
|
||||
boolean enableCustomSettings = sharedPreferences.getBoolean(getString(R.string.ENABLE_CUSTOM_SETTINGS_KEY), false);
|
||||
String modelPath = sharedPreferences.getString(getString(R.string.CHOOSE_PRE_INSTALLED_MODEL_KEY), getString(R.string.MODEL_PATH_DEFAULT));
|
||||
int modelIdx = lpChoosePreInstalledModel.findIndexOfValue(modelPath);
|
||||
if (modelIdx >= 0 && modelIdx < preInstalledModelPaths.size()) {
|
||||
if (!enableCustomSettings) {
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.putString(getString(R.string.MODEL_PATH_KEY), preInstalledModelPaths.get(modelIdx));
|
||||
editor.putString(getString(R.string.CPU_THREAD_NUM_KEY), preInstalledCPUThreadNums.get(modelIdx));
|
||||
editor.putString(getString(R.string.CPU_POWER_MODE_KEY), preInstalledCPUPowerModes.get(modelIdx));
|
||||
editor.commit();
|
||||
}
|
||||
lpChoosePreInstalledModel.setSummary(modelPath);
|
||||
}
|
||||
cbEnableCustomSettings.setChecked(enableCustomSettings);
|
||||
etModelPath.setEnabled(enableCustomSettings);
|
||||
lpCPUThreadNum.setEnabled(enableCustomSettings);
|
||||
lpCPUPowerMode.setEnabled(enableCustomSettings);
|
||||
modelPath = sharedPreferences.getString(getString(R.string.MODEL_PATH_KEY), getString(R.string.MODEL_PATH_DEFAULT));
|
||||
String cpuThreadNum = sharedPreferences.getString(getString(R.string.CPU_THREAD_NUM_KEY), getString(R.string.CPU_THREAD_NUM_DEFAULT));
|
||||
String cpuPowerMode = sharedPreferences.getString(getString(R.string.CPU_POWER_MODE_KEY), getString(R.string.CPU_POWER_MODE_DEFAULT));
|
||||
|
||||
etModelPath.setSummary(modelPath);
|
||||
etModelPath.setText(modelPath);
|
||||
lpCPUThreadNum.setValue(cpuThreadNum);
|
||||
lpCPUThreadNum.setSummary(cpuThreadNum);
|
||||
lpCPUPowerMode.setValue(cpuPowerMode);
|
||||
lpCPUPowerMode.setSummary(cpuPowerMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
|
||||
reloadPreferenceAndUpdateUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
if (key.equals(getString(R.string.CHOOSE_PRE_INSTALLED_MODEL_KEY))) {
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.putBoolean(getString(R.string.ENABLE_CUSTOM_SETTINGS_KEY), false);
|
||||
editor.commit();
|
||||
}
|
||||
reloadPreferenceAndUpdateUI();
|
||||
}
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
package com.baidu.paddle.lite.demo.tts;
|
||||
|
||||
import static java.lang.Math.abs;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class Utils {
|
||||
public static void copyFileFromAssets(Context appCtx, String srcPath, String dstPath) {
|
||||
if (srcPath.isEmpty() || dstPath.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
InputStream is = null;
|
||||
OutputStream os = null;
|
||||
try {
|
||||
is = new BufferedInputStream(appCtx.getAssets().open(srcPath));
|
||||
os = new BufferedOutputStream(new FileOutputStream(new File(dstPath)));
|
||||
byte[] buffer = new byte[1024];
|
||||
int length = 0;
|
||||
while ((length = is.read(buffer)) != -1) {
|
||||
os.write(buffer, 0, length);
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
os.close();
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void copyDirectoryFromAssets(Context appCtx, String srcDir, String dstDir) {
|
||||
if (srcDir.isEmpty() || dstDir.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (!new File(dstDir).exists()) {
|
||||
new File(dstDir).mkdirs();
|
||||
}
|
||||
for (String fileName : appCtx.getAssets().list(srcDir)) {
|
||||
String srcSubPath = srcDir + File.separator + fileName;
|
||||
String dstSubPath = dstDir + File.separator + fileName;
|
||||
if (new File(srcSubPath).isDirectory()) {
|
||||
copyDirectoryFromAssets(appCtx, srcSubPath, dstSubPath);
|
||||
} else {
|
||||
copyFileFromAssets(appCtx, srcSubPath, dstSubPath);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String getSDCardDirectory() {
|
||||
return Environment.getExternalStorageDirectory().getAbsolutePath();
|
||||
}
|
||||
|
||||
public static void rawToWave(String file, float[] data, int samplerate) throws IOException {
|
||||
// creating the empty wav file.
|
||||
File waveFile = new File(file);
|
||||
waveFile.createNewFile();
|
||||
//following block is converting raw to wav.
|
||||
DataOutputStream output = null;
|
||||
try {
|
||||
output = new DataOutputStream(new FileOutputStream(waveFile));
|
||||
// WAVE header
|
||||
// chunk id
|
||||
writeString(output, "RIFF");
|
||||
// chunk size
|
||||
writeInt(output, 36 + data.length * 2);
|
||||
// format
|
||||
writeString(output, "WAVE");
|
||||
// subchunk 1 id
|
||||
writeString(output, "fmt ");
|
||||
// subchunk 1 size
|
||||
writeInt(output, 16);
|
||||
// audio format (1 = PCM)
|
||||
writeShort(output, (short) 1);
|
||||
// number of channels
|
||||
writeShort(output, (short) 1);
|
||||
// sample rate
|
||||
writeInt(output, samplerate);
|
||||
// byte rate
|
||||
writeInt(output, samplerate * 2);
|
||||
// block align
|
||||
writeShort(output, (short) 2);
|
||||
// bits per sample
|
||||
writeShort(output, (short) 16);
|
||||
// subchunk 2 id
|
||||
writeString(output, "data");
|
||||
// subchunk 2 size
|
||||
writeInt(output, data.length * 2);
|
||||
short[] short_data = FloatArray2ShortArray(data);
|
||||
for (int i = 0; i < short_data.length; i++) {
|
||||
writeShort(output, short_data[i]);
|
||||
}
|
||||
} finally {
|
||||
if (output != null) {
|
||||
output.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeInt(final DataOutputStream output, final int value) throws IOException {
|
||||
output.write(value);
|
||||
output.write(value >> 8);
|
||||
output.write(value >> 16);
|
||||
output.write(value >> 24);
|
||||
}
|
||||
|
||||
private static void writeShort(final DataOutputStream output, final short value) throws IOException {
|
||||
output.write(value);
|
||||
output.write(value >> 8);
|
||||
}
|
||||
|
||||
private static void writeString(final DataOutputStream output, final String value) throws IOException {
|
||||
for (int i = 0; i < value.length(); i++) {
|
||||
output.write(value.charAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
public static short[] FloatArray2ShortArray(float[] values) {
|
||||
float mmax = (float) 0.01;
|
||||
short[] ret = new short[values.length];
|
||||
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (abs(values[i]) > mmax) {
|
||||
mmax = abs(values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
values[i] = values[i] * (32767 / mmax);
|
||||
ret[i] = (short) (values[i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="false"><!--没点击按钮的时候-->
|
||||
<shape android:shape="rectangle"><!--按钮形状-->
|
||||
<solid android:color="#008577" /><!--按钮背景填充色-->
|
||||
<corners android:radius="10dp" />
|
||||
<stroke android:width="1dp" android:color="#009688" /><!--按钮边框-->
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<item android:state_pressed="true">
|
||||
<shape android:shape="rectangle"><!--按钮形状-->
|
||||
<solid android:color="#C3009688" /><!--按钮背景填充色-->
|
||||
<corners android:radius="10dp" />
|
||||
<stroke android:width="1dp" android:color="#009688" /><!--按钮边框-->
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
</selector>
|
||||
|
After Width: | Height: | Size: 9.1 KiB |
After Width: | Height: | Size: 35 KiB |
@ -0,0 +1,112 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".MainActivity">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/logo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:src="@drawable/paddlespeech_logo" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/v_input_info"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/logo"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginTop="120dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_input_setting"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginRight="12dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:lineSpacingExtra="4dp"
|
||||
android:maxLines="6"
|
||||
android:scrollbars="vertical"
|
||||
android:singleLine="false"
|
||||
android:text=""
|
||||
android:textColor="#3C3C3C" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:dropDownSelector="#63D81B60"
|
||||
android:spinnerMode="dropdown" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_inference_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/spinner1"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:layout_marginTop="50dp"
|
||||
android:layout_marginRight="12dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:gravity="start"
|
||||
android:lineSpacingExtra="4dp"
|
||||
android:maxLines="6"
|
||||
android:textColor="#3C3C3C" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/btns"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@+id/tv_inference_time"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginTop="30dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_play"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="40dp"
|
||||
android:background="@drawable/button_drawable"
|
||||
android:text="Play"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="#ffffff" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_pause"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginLeft="3dp"
|
||||
android:background="@drawable/button_drawable"
|
||||
android:text="Pause"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="#ffffff" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_stop"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginLeft="3dp"
|
||||
android:background="@drawable/button_drawable"
|
||||
android:text="Stop"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="#ffffff" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
@ -0,0 +1,9 @@
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<group>
|
||||
<item
|
||||
android:id="@+id/settings"
|
||||
android:title="Settings..."
|
||||
app:showAsAction="withText" />
|
||||
</group>
|
||||
</menu>
|
@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string-array name="cpu_thread_num_entries">
|
||||
<item>1 threads</item>
|
||||
<item>2 threads</item>
|
||||
<item>4 threads</item>
|
||||
<item>8 threads</item>
|
||||
</string-array>
|
||||
<string-array name="cpu_thread_num_values">
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>4</item>
|
||||
<item>8</item>
|
||||
</string-array>
|
||||
<string-array name="cpu_power_mode_entries">
|
||||
<item>HIGH(only big cores)</item>
|
||||
<item>LOW(only LITTLE cores)</item>
|
||||
<item>FULL(all cores)</item>
|
||||
<item>NO_BIND(depends on system)</item>
|
||||
<item>RAND_HIGH</item>
|
||||
<item>RAND_LOW</item>
|
||||
</string-array>
|
||||
<string-array name="cpu_power_mode_values">
|
||||
<item>LITE_POWER_HIGH</item>
|
||||
<item>LITE_POWER_LOW</item>
|
||||
<item>LITE_POWER_FULL</item>
|
||||
<item>LITE_POWER_NO_BIND</item>
|
||||
<item>LITE_POWER_RAND_HIGH</item>
|
||||
<item>LITE_POWER_RAND_LOW</item>
|
||||
</string-array>
|
||||
<string-array name="text">
|
||||
<item>Please select a sentence to be synthesized</item>
|
||||
<item>昨日,这名“伤者”与医生全部被警方依法刑事拘留。</item>
|
||||
<item>钱伟长想到上海来办学校是经过深思熟虑的。</item>
|
||||
<item>她见我一进门就骂,吃饭时也骂,骂得我抬不起头。</item>
|
||||
<item>李述德在离开之前,只说了一句“柱驼杀父亲了”。</item>
|
||||
<item>这种车票和保险单捆绑出售属于重复性购买。</item>
|
||||
<item>戴佩妮的男友西米露接唱情歌,让她非常开心。</item>
|
||||
<item>观大势、谋大局、出大策始终是该院的办院方针。</item>
|
||||
<item>他们骑着摩托回家,正好为农忙时的父母帮忙。</item>
|
||||
<item>但是因为还没到退休年龄,只能掰着指头捱日子。</item>
|
||||
<item>这几天雨水不断,人们恨不得待在家里不出门。</item>
|
||||
</string-array>
|
||||
</resources>
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#008577</color>
|
||||
<color name="colorPrimaryDark">#00574B</color>
|
||||
<color name="colorAccent">#D81B60</color>
|
||||
</resources>
|
@ -0,0 +1,12 @@
|
||||
<resources>
|
||||
<string name="app_name">TTS</string>
|
||||
<string name="CHOOSE_PRE_INSTALLED_MODEL_KEY">CHOOSE_PRE_INSTALLED_MODEL_KEY</string>
|
||||
<string name="ENABLE_CUSTOM_SETTINGS_KEY">ENABLE_CUSTOM_SETTINGS_KEY</string>
|
||||
<string name="MODEL_PATH_KEY">MODEL_PATH_KEY</string>
|
||||
<string name="CPU_THREAD_NUM_KEY">CPU_THREAD_NUM_KEY</string>
|
||||
<string name="CPU_POWER_MODE_KEY">CPU_POWER_MODE_KEY</string>
|
||||
<string name="MODEL_PATH_DEFAULT">models/cpu</string>
|
||||
<string name="CPU_THREAD_NUM_DEFAULT">1</string>
|
||||
<string name="CPU_POWER_MODE_DEFAULT">LITE_POWER_HIGH</string>
|
||||
</resources>
|
||||
|
@ -0,0 +1,16 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
<item name="actionOverflowMenuStyle">@style/OverflowMenuStyle</item>
|
||||
</style>
|
||||
|
||||
<style name="OverflowMenuStyle" parent="Widget.AppCompat.Light.PopupMenu.Overflow">
|
||||
<item name="overlapAnchor">false</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<PreferenceCategory android:title="Model Settings">
|
||||
<ListPreference
|
||||
android:defaultValue="@string/MODEL_PATH_DEFAULT"
|
||||
android:key="@string/CHOOSE_PRE_INSTALLED_MODEL_KEY"
|
||||
android:negativeButtonText="@null"
|
||||
android:positiveButtonText="@null"
|
||||
android:title="Choose pre-installed models" />
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/ENABLE_CUSTOM_SETTINGS_KEY"
|
||||
android:summaryOff="Disable"
|
||||
android:summaryOn="Enable"
|
||||
android:title="Enable custom settings" />
|
||||
<EditTextPreference
|
||||
android:defaultValue="@string/MODEL_PATH_DEFAULT"
|
||||
android:key="@string/MODEL_PATH_KEY"
|
||||
android:title="Model Path" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="CPU Settings">
|
||||
<ListPreference
|
||||
android:defaultValue="@string/CPU_THREAD_NUM_DEFAULT"
|
||||
android:entries="@array/cpu_thread_num_entries"
|
||||
android:entryValues="@array/cpu_thread_num_values"
|
||||
android:key="@string/CPU_THREAD_NUM_KEY"
|
||||
android:negativeButtonText="@null"
|
||||
android:positiveButtonText="@null"
|
||||
android:title="CPU Thread Num" />
|
||||
<ListPreference
|
||||
android:defaultValue="@string/CPU_POWER_MODE_DEFAULT"
|
||||
android:entries="@array/cpu_power_mode_entries"
|
||||
android:entryValues="@array/cpu_power_mode_values"
|
||||
android:key="@string/CPU_POWER_MODE_KEY"
|
||||
android:negativeButtonText="@null"
|
||||
android:positiveButtonText="@null"
|
||||
android:title="CPU Power Mode" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
@ -0,0 +1,17 @@
|
||||
package com.baidu.paddle.lite.demo.tts;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.0'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
# Project-wide Gradle settings.
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
||||
|
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
#Wed Jun 16 14:31:28 CST 2021
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip
|
@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
@ -0,0 +1,84 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
@ -0,0 +1 @@
|
||||
include ':app'
|
@ -0,0 +1,74 @@
|
||||
# This example mainly follows the FastSpeech2 with CSMSC
|
||||
This example contains code used to train a rhythm version of [Fastspeech2](https://arxiv.org/abs/2006.04558) model with [Chinese Standard Mandarin Speech Copus](https://www.data-baker.com/open_source.html).
|
||||
|
||||
## Dataset
|
||||
### Download and Extract
|
||||
Download CSMSC from it's [Official Website](https://test.data-baker.com/data/index/TNtts/) and extract it to `~/datasets`. Then the dataset is in the directory `~/datasets/BZNSYP`.
|
||||
|
||||
### Get MFA Result and Extract
|
||||
We use [MFA](https://github.com/MontrealCorpusTools/Montreal-Forced-Aligner) to get durations for fastspeech2.
|
||||
You can directly download the rhythm version of MFA result from here [baker_alignment_tone.zip](https://paddlespeech.bj.bcebos.com/Rhy_e2e/baker_alignment_tone.zip), or train your MFA model reference to [mfa example](https://github.com/PaddlePaddle/PaddleSpeech/tree/develop/examples/other/mfa) of our repo.
|
||||
Remember in our repo, you should add `--rhy-with-duration` flag to obtain the rhythm information.
|
||||
|
||||
## Get Started
|
||||
Assume the path to the dataset is `~/datasets/BZNSYP`.
|
||||
Assume the path to the MFA result of CSMSC is `./baker_alignment_tone`.
|
||||
Run the command below to
|
||||
1. **source path**.
|
||||
2. preprocess the dataset.
|
||||
3. train the model.
|
||||
4. synthesize wavs.
|
||||
- synthesize waveform from `metadata.jsonl`.
|
||||
- synthesize waveform from a text file.
|
||||
5. inference using the static model.
|
||||
```bash
|
||||
./run.sh
|
||||
```
|
||||
You can choose a range of stages you want to run, or set `stage` equal to `stop-stage` to use only one stage, for example, running the following command will only preprocess the dataset.
|
||||
```bash
|
||||
./run.sh --stage 0 --stop-stage 0
|
||||
```
|
||||
### Data Preprocessing
|
||||
```bash
|
||||
./local/preprocess.sh ${conf_path}
|
||||
```
|
||||
When it is done. A `dump` folder is created in the current directory. The structure of the dump folder is listed below.
|
||||
|
||||
```text
|
||||
dump
|
||||
├── dev
|
||||
│ ├── norm
|
||||
│ └── raw
|
||||
├── phone_id_map.txt
|
||||
├── speaker_id_map.txt
|
||||
├── test
|
||||
│ ├── norm
|
||||
│ └── raw
|
||||
└── train
|
||||
├── energy_stats.npy
|
||||
├── norm
|
||||
├── pitch_stats.npy
|
||||
├── raw
|
||||
└── speech_stats.npy
|
||||
```
|
||||
The dataset is split into 3 parts, namely `train`, `dev`, and` test`, each of which contains a `norm` and `raw` subfolder. The raw folder contains speech、pitch and energy features of each utterance, while the norm folder contains normalized ones. The statistics used to normalize features are computed from the training set, which is located in `dump/train/*_stats.npy`.
|
||||
|
||||
Also, there is a `metadata.jsonl` in each subfolder. It is a table-like file that contains phones, text_lengths, speech_lengths, durations, the path of speech features, the path of pitch features, the path of energy features, speaker, and the id of each utterance.
|
||||
|
||||
# For more details, You can refer to [FastSpeech2 with CSMSC](../tts3)
|
||||
|
||||
## Pretrained Model
|
||||
Pretrained FastSpeech2 model for end-to-end rhythm version:
|
||||
- [fastspeech2_rhy_csmsc_ckpt_1.3.0.zip](https://paddlespeech.bj.bcebos.com/Parakeet/released_models/fastspeech2/fastspeech2_rhy_csmsc_ckpt_1.3.0.zip)
|
||||
|
||||
This FastSpeech2 checkpoint contains files listed below.
|
||||
```text
|
||||
fastspeech2_rhy_csmsc_ckpt_1.3.0
|
||||
├── default.yaml # default config used to train fastspeech2
|
||||
├── phone_id_map.txt # phone vocabulary file when training fastspeech2
|
||||
├── snapshot_iter_153000.pdz # model parameters and optimizer states
|
||||
├── durations.txt # the intermediate output of preprocess.sh
|
||||
├── energy_stats.npy
|
||||
├── pitch_stats.npy
|
||||
└── speech_stats.npy # statistics used to normalize spectrogram when training fastspeech2
|
||||
```
|
@ -0,0 +1 @@
|
||||
../../tts3/conf/default.yaml
|
@ -0,0 +1 @@
|
||||
../../tts3/local/preprocess.sh
|
@ -0,0 +1 @@
|
||||
../../tts3/local/synthesize.sh
|
@ -0,0 +1,119 @@
|
||||
#!/bin/bash
|
||||
|
||||
config_path=$1
|
||||
train_output_path=$2
|
||||
ckpt_name=$3
|
||||
|
||||
stage=0
|
||||
stop_stage=0
|
||||
|
||||
# pwgan
|
||||
if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then
|
||||
FLAGS_allocator_strategy=naive_best_fit \
|
||||
FLAGS_fraction_of_gpu_memory_to_use=0.01 \
|
||||
python3 ${BIN_DIR}/../synthesize_e2e.py \
|
||||
--am=fastspeech2_csmsc \
|
||||
--am_config=${config_path} \
|
||||
--am_ckpt=${train_output_path}/checkpoints/${ckpt_name} \
|
||||
--am_stat=dump/train/speech_stats.npy \
|
||||
--voc=pwgan_csmsc \
|
||||
--voc_config=pwg_baker_ckpt_0.4/pwg_default.yaml \
|
||||
--voc_ckpt=pwg_baker_ckpt_0.4/pwg_snapshot_iter_400000.pdz \
|
||||
--voc_stat=pwg_baker_ckpt_0.4/pwg_stats.npy \
|
||||
--lang=zh \
|
||||
--text=${BIN_DIR}/../sentences.txt \
|
||||
--output_dir=${train_output_path}/test_e2e \
|
||||
--phones_dict=dump/phone_id_map.txt \
|
||||
--inference_dir=${train_output_path}/inference \
|
||||
--use_rhy=True
|
||||
fi
|
||||
|
||||
# for more GAN Vocoders
|
||||
# multi band melgan
|
||||
if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then
|
||||
FLAGS_allocator_strategy=naive_best_fit \
|
||||
FLAGS_fraction_of_gpu_memory_to_use=0.01 \
|
||||
python3 ${BIN_DIR}/../synthesize_e2e.py \
|
||||
--am=fastspeech2_csmsc \
|
||||
--am_config=${config_path} \
|
||||
--am_ckpt=${train_output_path}/checkpoints/${ckpt_name} \
|
||||
--am_stat=dump/train/speech_stats.npy \
|
||||
--voc=mb_melgan_csmsc \
|
||||
--voc_config=mb_melgan_csmsc_ckpt_0.1.1/default.yaml \
|
||||
--voc_ckpt=mb_melgan_csmsc_ckpt_0.1.1/snapshot_iter_1000000.pdz\
|
||||
--voc_stat=mb_melgan_csmsc_ckpt_0.1.1/feats_stats.npy \
|
||||
--lang=zh \
|
||||
--text=${BIN_DIR}/../sentences.txt \
|
||||
--output_dir=${train_output_path}/test_e2e \
|
||||
--phones_dict=dump/phone_id_map.txt \
|
||||
--inference_dir=${train_output_path}/inference \
|
||||
--use_rhy=True
|
||||
fi
|
||||
|
||||
# the pretrained models haven't release now
|
||||
# style melgan
|
||||
# style melgan's Dygraph to Static Graph is not ready now
|
||||
if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then
|
||||
FLAGS_allocator_strategy=naive_best_fit \
|
||||
FLAGS_fraction_of_gpu_memory_to_use=0.01 \
|
||||
python3 ${BIN_DIR}/../synthesize_e2e.py \
|
||||
--am=fastspeech2_csmsc \
|
||||
--am_config=${config_path} \
|
||||
--am_ckpt=${train_output_path}/checkpoints/${ckpt_name} \
|
||||
--am_stat=dump/train/speech_stats.npy \
|
||||
--voc=style_melgan_csmsc \
|
||||
--voc_config=style_melgan_csmsc_ckpt_0.1.1/default.yaml \
|
||||
--voc_ckpt=style_melgan_csmsc_ckpt_0.1.1/snapshot_iter_1500000.pdz \
|
||||
--voc_stat=style_melgan_csmsc_ckpt_0.1.1/feats_stats.npy \
|
||||
--lang=zh \
|
||||
--text=${BIN_DIR}/../sentences.txt \
|
||||
--output_dir=${train_output_path}/test_e2e \
|
||||
--phones_dict=dump/phone_id_map.txt \
|
||||
--use_rhy=True
|
||||
# --inference_dir=${train_output_path}/inference
|
||||
fi
|
||||
|
||||
# hifigan
|
||||
if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then
|
||||
echo "in hifigan syn_e2e"
|
||||
FLAGS_allocator_strategy=naive_best_fit \
|
||||
FLAGS_fraction_of_gpu_memory_to_use=0.01 \
|
||||
python3 ${BIN_DIR}/../synthesize_e2e.py \
|
||||
--am=fastspeech2_csmsc \
|
||||
--am_config=${config_path} \
|
||||
--am_ckpt=${train_output_path}/checkpoints/${ckpt_name} \
|
||||
--am_stat=dump/train/speech_stats.npy \
|
||||
--voc=hifigan_csmsc \
|
||||
--voc_config=hifigan_csmsc_ckpt_0.1.1/default.yaml \
|
||||
--voc_ckpt=hifigan_csmsc_ckpt_0.1.1/snapshot_iter_2500000.pdz \
|
||||
--voc_stat=hifigan_csmsc_ckpt_0.1.1/feats_stats.npy \
|
||||
--lang=zh \
|
||||
--text=${BIN_DIR}/../sentences.txt \
|
||||
--output_dir=${train_output_path}/test_e2e \
|
||||
--phones_dict=dump/phone_id_map.txt \
|
||||
--inference_dir=${train_output_path}/inference \
|
||||
--use_rhy=True
|
||||
fi
|
||||
|
||||
|
||||
# wavernn
|
||||
if [ ${stage} -le 4 ] && [ ${stop_stage} -ge 4 ]; then
|
||||
echo "in wavernn syn_e2e"
|
||||
FLAGS_allocator_strategy=naive_best_fit \
|
||||
FLAGS_fraction_of_gpu_memory_to_use=0.01 \
|
||||
python3 ${BIN_DIR}/../synthesize_e2e.py \
|
||||
--am=fastspeech2_csmsc \
|
||||
--am_config=${config_path} \
|
||||
--am_ckpt=${train_output_path}/checkpoints/${ckpt_name} \
|
||||
--am_stat=dump/train/speech_stats.npy \
|
||||
--voc=wavernn_csmsc \
|
||||
--voc_config=wavernn_csmsc_ckpt_0.2.0/default.yaml \
|
||||
--voc_ckpt=wavernn_csmsc_ckpt_0.2.0/snapshot_iter_400000.pdz \
|
||||
--voc_stat=wavernn_csmsc_ckpt_0.2.0/feats_stats.npy \
|
||||
--lang=zh \
|
||||
--text=${BIN_DIR}/../sentences.txt \
|
||||
--output_dir=${train_output_path}/test_e2e \
|
||||
--phones_dict=dump/phone_id_map.txt \
|
||||
--inference_dir=${train_output_path}/inference \
|
||||
--use_rhy=True
|
||||
fi
|
@ -0,0 +1 @@
|
||||
../../tts3/local/train.sh
|
@ -0,0 +1 @@
|
||||
../tts3/path.sh
|
@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
source path.sh
|
||||
|
||||
gpus=0,1
|
||||
stage=0
|
||||
stop_stage=100
|
||||
|
||||
conf_path=conf/default.yaml
|
||||
train_output_path=exp/default
|
||||
ckpt_name=snapshot_iter_153.pdz
|
||||
|
||||
# with the following command, you can choose the stage range you want to run
|
||||
# such as `./run.sh --stage 0 --stop-stage 0`
|
||||
# this can not be mixed use with `$1`, `$2` ...
|
||||
source ${MAIN_ROOT}/utils/parse_options.sh || exit 1
|
||||
|
||||
if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then
|
||||
# prepare data
|
||||
### please place the mfa result of rhythm here
|
||||
./local/preprocess.sh ${conf_path} || exit -1
|
||||
fi
|
||||
|
||||
if [ ${stage} -le 1 ] && [ ${stop_stage} -ge 1 ]; then
|
||||
# train model, all `ckpt` under `train_output_path/checkpoints/` dir
|
||||
CUDA_VISIBLE_DEVICES=${gpus} ./local/train.sh ${conf_path} ${train_output_path} || exit -1
|
||||
fi
|
||||
|
||||
if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then
|
||||
# synthesize, vocoder is pwgan by default
|
||||
CUDA_VISIBLE_DEVICES=${gpus} ./local/synthesize.sh ${conf_path} ${train_output_path} ${ckpt_name} || exit -1
|
||||
fi
|
||||
|
||||
if [ ${stage} -le 3 ] && [ ${stop_stage} -ge 3 ]; then
|
||||
# synthesize_e2e, vocoder is pwgan by default
|
||||
CUDA_VISIBLE_DEVICES=${gpus} ./local/synthesize_e2e.sh ${conf_path} ${train_output_path} ${ckpt_name} || exit -1
|
||||
fi
|
@ -0,0 +1,111 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
import numpy as np
|
||||
from paddlelite.lite import create_paddle_predictor
|
||||
from paddlelite.lite import MobileConfig
|
||||
|
||||
from .syn_utils import run_frontend
|
||||
|
||||
|
||||
# Paddle-Lite
|
||||
def get_lite_predictor(model_dir: Optional[os.PathLike]=None,
|
||||
model_file: Optional[os.PathLike]=None,
|
||||
cpu_threads: int=1):
|
||||
config = MobileConfig()
|
||||
config.set_model_from_file(str(Path(model_dir) / model_file))
|
||||
predictor = create_paddle_predictor(config)
|
||||
return predictor
|
||||
|
||||
|
||||
def get_lite_am_output(
|
||||
input: str,
|
||||
am_predictor,
|
||||
am: str,
|
||||
frontend: object,
|
||||
lang: str='zh',
|
||||
merge_sentences: bool=True,
|
||||
speaker_dict: Optional[os.PathLike]=None,
|
||||
spk_id: int=0, ):
|
||||
am_name = am[:am.rindex('_')]
|
||||
am_dataset = am[am.rindex('_') + 1:]
|
||||
get_spk_id = False
|
||||
get_tone_ids = False
|
||||
if am_name == 'speedyspeech':
|
||||
get_tone_ids = True
|
||||
if am_dataset in {"aishell3", "vctk", "mix"} and speaker_dict:
|
||||
get_spk_id = True
|
||||
spk_id = np.array([spk_id])
|
||||
|
||||
frontend_dict = run_frontend(
|
||||
frontend=frontend,
|
||||
text=input,
|
||||
merge_sentences=merge_sentences,
|
||||
get_tone_ids=get_tone_ids,
|
||||
lang=lang)
|
||||
|
||||
if get_tone_ids:
|
||||
tone_ids = frontend_dict['tone_ids']
|
||||
tones = tone_ids[0].numpy()
|
||||
tones_handle = am_predictor.get_input(1)
|
||||
tones_handle.from_numpy(tones)
|
||||
|
||||
if get_spk_id:
|
||||
spk_id_handle = am_predictor.get_input(1)
|
||||
spk_id_handle.from_numpy(spk_id)
|
||||
phone_ids = frontend_dict['phone_ids']
|
||||
phones = phone_ids[0].numpy()
|
||||
phones_handle = am_predictor.get_input(0)
|
||||
phones_handle.from_numpy(phones)
|
||||
am_predictor.run()
|
||||
am_output_handle = am_predictor.get_output(0)
|
||||
am_output_data = am_output_handle.numpy()
|
||||
return am_output_data
|
||||
|
||||
|
||||
def get_lite_voc_output(voc_predictor, input):
|
||||
mel_handle = voc_predictor.get_input(0)
|
||||
mel_handle.from_numpy(input)
|
||||
voc_predictor.run()
|
||||
voc_output_handle = voc_predictor.get_output(0)
|
||||
wav = voc_output_handle.numpy()
|
||||
return wav
|
||||
|
||||
|
||||
def get_lite_am_sublayer_output(am_sublayer_predictor, input):
|
||||
input_handle = am_sublayer_predictor.get_input(0)
|
||||
input_handle.from_numpy(input)
|
||||
|
||||
am_sublayer_predictor.run()
|
||||
am_sublayer_handle = am_sublayer_predictor.get_output(0)
|
||||
am_sublayer_output = am_sublayer_handle.numpy()
|
||||
return am_sublayer_output
|
||||
|
||||
|
||||
def get_lite_streaming_am_output(input: str,
|
||||
am_encoder_infer_predictor,
|
||||
am_decoder_predictor,
|
||||
am_postnet_predictor,
|
||||
frontend,
|
||||
lang: str='zh',
|
||||
merge_sentences: bool=True):
|
||||
get_tone_ids = False
|
||||
frontend_dict = run_frontend(
|
||||
frontend=frontend,
|
||||
text=input,
|
||||
merge_sentences=merge_sentences,
|
||||
get_tone_ids=get_tone_ids,
|
||||
lang=lang)
|
||||
phone_ids = frontend_dict['phone_ids']
|
||||
phones = phone_ids[0].numpy()
|
||||
am_encoder_infer_output = get_lite_am_sublayer_output(
|
||||
am_encoder_infer_predictor, input=phones)
|
||||
am_decoder_output = get_lite_am_sublayer_output(
|
||||
am_decoder_predictor, input=am_encoder_infer_output)
|
||||
am_postnet_output = get_lite_am_sublayer_output(
|
||||
am_postnet_predictor, input=np.transpose(am_decoder_output, (0, 2, 1)))
|
||||
am_output_data = am_decoder_output + np.transpose(am_postnet_output,
|
||||
(0, 2, 1))
|
||||
normalized_mel = am_output_data[0]
|
||||
return normalized_mel
|
@ -0,0 +1,14 @@
|
||||
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from .rhy_predictor import *
|
@ -0,0 +1,106 @@
|
||||
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import os
|
||||
import re
|
||||
|
||||
import paddle
|
||||
import yaml
|
||||
from paddlenlp.transformers import ErnieTokenizer
|
||||
from yacs.config import CfgNode
|
||||
|
||||
from paddlespeech.cli.utils import download_and_decompress
|
||||
from paddlespeech.resource.pretrained_models import rhy_frontend_models
|
||||
from paddlespeech.text.models.ernie_linear import ErnieLinear
|
||||
from paddlespeech.utils.env import MODEL_HOME
|
||||
|
||||
DefinedClassifier = {
|
||||
'ErnieLinear': ErnieLinear,
|
||||
}
|
||||
|
||||
model_version = '1.0'
|
||||
|
||||
|
||||
class RhyPredictor():
|
||||
def __init__(
|
||||
self,
|
||||
model_dir: os.PathLike=MODEL_HOME, ):
|
||||
uncompress_path = download_and_decompress(
|
||||
rhy_frontend_models['rhy_e2e'][model_version], model_dir)
|
||||
with open(os.path.join(uncompress_path, 'rhy_default.yaml')) as f:
|
||||
config = CfgNode(yaml.safe_load(f))
|
||||
self.punc_list = []
|
||||
with open(os.path.join(uncompress_path, 'rhy_token'), 'r') as f:
|
||||
for line in f:
|
||||
self.punc_list.append(line.strip())
|
||||
self.punc_list = [0] + self.punc_list
|
||||
self.make_rhy_dict()
|
||||
self.model = DefinedClassifier["ErnieLinear"](**config["model"])
|
||||
pretrained_token = config['data_params']['pretrained_token']
|
||||
self.tokenizer = ErnieTokenizer.from_pretrained(pretrained_token)
|
||||
state_dict = paddle.load(
|
||||
os.path.join(uncompress_path, 'snapshot_iter_2600_main_params.pdz'))
|
||||
self.model.set_state_dict(state_dict)
|
||||
self.model.eval()
|
||||
|
||||
def _clean_text(self, text):
|
||||
text = text.lower()
|
||||
text = re.sub('[^A-Za-z0-9\u4e00-\u9fa5]', '', text)
|
||||
text = re.sub(f'[{"".join([p for p in self.punc_list][1:])}]', '', text)
|
||||
return text
|
||||
|
||||
def preprocess(self, text, tokenizer):
|
||||
clean_text = self._clean_text(text)
|
||||
assert len(clean_text) > 0, f'Invalid input string: {text}'
|
||||
tokenized_input = tokenizer(
|
||||
list(clean_text), return_length=True, is_split_into_words=True)
|
||||
_inputs = dict()
|
||||
_inputs['input_ids'] = tokenized_input['input_ids']
|
||||
_inputs['seg_ids'] = tokenized_input['token_type_ids']
|
||||
_inputs['seq_len'] = tokenized_input['seq_len']
|
||||
return _inputs
|
||||
|
||||
def get_prediction(self, raw_text):
|
||||
_inputs = self.preprocess(raw_text, self.tokenizer)
|
||||
seq_len = _inputs['seq_len']
|
||||
input_ids = paddle.to_tensor(_inputs['input_ids']).unsqueeze(0)
|
||||
seg_ids = paddle.to_tensor(_inputs['seg_ids']).unsqueeze(0)
|
||||
logits, _ = self.model(input_ids, seg_ids)
|
||||
preds = paddle.argmax(logits, axis=-1).squeeze(0)
|
||||
tokens = self.tokenizer.convert_ids_to_tokens(
|
||||
_inputs['input_ids'][1:seq_len - 1])
|
||||
labels = preds[1:seq_len - 1].tolist()
|
||||
assert len(tokens) == len(labels)
|
||||
# add 0 for non punc
|
||||
text = ''
|
||||
for t, l in zip(tokens, labels):
|
||||
text += t
|
||||
if l != 0: # Non punc.
|
||||
text += self.punc_list[l]
|
||||
return text
|
||||
|
||||
def make_rhy_dict(self):
|
||||
self.rhy_dict = {}
|
||||
for i, p in enumerate(self.punc_list[1:]):
|
||||
self.rhy_dict[p] = 'sp' + str(i + 1)
|
||||
|
||||
def pinyin_align(self, pinyins, rhy_pre):
|
||||
final_py = []
|
||||
j = 0
|
||||
for i in range(len(rhy_pre)):
|
||||
if rhy_pre[i] in self.rhy_dict:
|
||||
final_py.append(self.rhy_dict[rhy_pre[i]])
|
||||
else:
|
||||
final_py.append(pinyins[j])
|
||||
j += 1
|
||||
return final_py
|
@ -0,0 +1,78 @@
|
||||
# Streaming DeepSpeech2 Server with WebSocket
|
||||
|
||||
This example is about using `websocket` as streaming deepspeech2 server. For deepspeech2 model training please see [here](../../../../examples/aishell/asr0/).
|
||||
|
||||
The websocket protocal is same to [PaddleSpeech Server](../../../../demos/streaming_asr_server/),
|
||||
for detail of implementation please see [here](../../../speechx/protocol/websocket/).
|
||||
|
||||
|
||||
## Source path.sh
|
||||
|
||||
```bash
|
||||
. path.sh
|
||||
```
|
||||
|
||||
SpeechX bins is under `echo $SPEECHX_BUILD`, more info please see `path.sh`.
|
||||
|
||||
|
||||
## Start WebSocket Server
|
||||
|
||||
```bash
|
||||
bash websoket_server.sh
|
||||
```
|
||||
|
||||
The output is like below:
|
||||
|
||||
```text
|
||||
I1130 02:19:32.029882 12856 cmvn_json2kaldi_main.cc:39] cmvn josn path: /workspace/zhanghui/PaddleSpeech/speechx/examples/ds2_ol/websocket/data/model/data/mean_std.json
|
||||
I1130 02:19:32.032230 12856 cmvn_json2kaldi_main.cc:73] nframe: 907497
|
||||
I1130 02:19:32.032564 12856 cmvn_json2kaldi_main.cc:85] cmvn stats have write into: /workspace/zhanghui/PaddleSpeech/speechx/examples/ds2_ol/websocket/data/cmvn.ark
|
||||
I1130 02:19:32.032579 12856 cmvn_json2kaldi_main.cc:86] Binary: 1
|
||||
I1130 02:19:32.798342 12937 feature_pipeline.h:53] cmvn file: /workspace/zhanghui/PaddleSpeech/speechx/examples/ds2_ol/websocket/data/cmvn.ark
|
||||
I1130 02:19:32.798542 12937 feature_pipeline.h:58] dither: 0
|
||||
I1130 02:19:32.798583 12937 feature_pipeline.h:60] frame shift ms: 10
|
||||
I1130 02:19:32.798588 12937 feature_pipeline.h:62] feature type: linear
|
||||
I1130 02:19:32.798596 12937 feature_pipeline.h:80] frame length ms: 20
|
||||
I1130 02:19:32.798601 12937 feature_pipeline.h:88] subsampling rate: 4
|
||||
I1130 02:19:32.798606 12937 feature_pipeline.h:90] nnet receptive filed length: 7
|
||||
I1130 02:19:32.798611 12937 feature_pipeline.h:92] nnet chunk size: 1
|
||||
I1130 02:19:32.798615 12937 feature_pipeline.h:94] frontend fill zeros: 0
|
||||
I1130 02:19:32.798630 12937 nnet_itf.h:52] subsampling rate: 4
|
||||
I1130 02:19:32.798635 12937 nnet_itf.h:54] model path: /workspace/zhanghui/PaddleSpeech/speechx/examples/ds2_ol/websocket/data/model/exp/deepspeech2_online/checkpoints//avg_1.jit.pdmodel
|
||||
I1130 02:19:32.798640 12937 nnet_itf.h:57] param path: /workspace/zhanghui/PaddleSpeech/speechx/examples/ds2_ol/websocket/data/model/exp/deepspeech2_online/checkpoints//avg_1.jit.pdiparams
|
||||
I1130 02:19:32.798643 12937 nnet_itf.h:59] DS2 param:
|
||||
I1130 02:19:32.798647 12937 nnet_itf.h:61] cache names: chunk_state_h_box,chunk_state_c_box
|
||||
I1130 02:19:32.798652 12937 nnet_itf.h:63] cache shape: 5-1-1024,5-1-1024
|
||||
I1130 02:19:32.798656 12937 nnet_itf.h:65] input names: audio_chunk,audio_chunk_lens,chunk_state_h_box,chunk_state_c_box
|
||||
I1130 02:19:32.798660 12937 nnet_itf.h:67] output names: softmax_0.tmp_0,tmp_5,concat_0.tmp_0,concat_1.tmp_0
|
||||
I1130 02:19:32.798664 12937 ctc_tlg_decoder.h:41] fst path: /workspace/zhanghui/PaddleSpeech/speechx/examples/ds2_ol/websocket/data/wfst//TLG.fst
|
||||
I1130 02:19:32.798669 12937 ctc_tlg_decoder.h:42] fst symbole table: /workspace/zhanghui/PaddleSpeech/speechx/examples/ds2_ol/websocket/data/wfst//words.txt
|
||||
I1130 02:19:32.798673 12937 ctc_tlg_decoder.h:47] LatticeFasterDecoder max active: 7500
|
||||
I1130 02:19:32.798677 12937 ctc_tlg_decoder.h:49] LatticeFasterDecoder beam: 15
|
||||
I1130 02:19:32.798681 12937 ctc_tlg_decoder.h:50] LatticeFasterDecoder lattice_beam: 7.5
|
||||
I1130 02:19:32.798708 12937 websocket_server_main.cc:37] Listening at port 8082
|
||||
```
|
||||
|
||||
## Start WebSocket Client
|
||||
|
||||
```bash
|
||||
bash websocket_client.sh
|
||||
```
|
||||
|
||||
This script using AISHELL-1 test data to call websocket server.
|
||||
|
||||
The input is specific by `--wav_rspecifier=scp:$data/$aishell_wav_scp`.
|
||||
|
||||
The `scp` file which look like this:
|
||||
```text
|
||||
# head data/split1/1/aishell_test.scp
|
||||
BAC009S0764W0121 /workspace/PaddleSpeech/speechx/examples/u2pp_ol/wenetspeech/data/test/S0764/BAC009S0764W0121.wav
|
||||
BAC009S0764W0122 /workspace/PaddleSpeech/speechx/examples/u2pp_ol/wenetspeech/data/test/S0764/BAC009S0764W0122.wav
|
||||
...
|
||||
BAC009S0764W0125 /workspace/PaddleSpeech/speechx/examples/u2pp_ol/wenetspeech/data/test/S0764/BAC009S0764W0125.wav
|
||||
```
|
||||
|
||||
If you want to recognize one wav, you can make `scp` file like this:
|
||||
```text
|
||||
key path/to/wav/file
|
||||
```
|
Loading…
Reference in new issue