Skip to content

Commit

Permalink
普通模式不再支持风格调整
Browse files Browse the repository at this point in the history
  • Loading branch information
ag2s20150909 committed Jun 16, 2022
1 parent ddf12a5 commit 7665284
Show file tree
Hide file tree
Showing 14 changed files with 160 additions and 81 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
2022/05/26
2022/08/16

添加预览版语音,需要打开预览语音开关,当选择预览版语音时,如果卡住了,杀掉应用重进!!!
普通模式不再支持风格调整
17 changes: 16 additions & 1 deletion app/src/main/java/me/ag2s/tts/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,12 @@ protected void onCreate(Bundle savedInstanceState) {
binding.switchUseDict.setChecked(APP.getBoolean(Constants.USE_DICT, false));
binding.switchUseDict.setOnCheckedChangeListener((buttonView, isChecked) -> APP.putBoolean(Constants.USE_DICT, isChecked));

showStyleView(APP.getBoolean(Constants.USE_PREVIEW, false));
binding.switchUsePreview.setChecked(APP.getBoolean(Constants.USE_PREVIEW, false));
binding.switchUsePreview.setOnCheckedChangeListener(((buttonView, isChecked) -> APP.putBoolean(USE_PREVIEW, isChecked)));
binding.switchUsePreview.setOnCheckedChangeListener(((buttonView, isChecked) -> {
showStyleView(isChecked);
APP.putBoolean(USE_PREVIEW, isChecked);
}));


TtsActorAdapter actorAdapter = new TtsActorAdapter(TtsActorManger.getInstance().getActors());
Expand Down Expand Up @@ -186,6 +190,17 @@ private void connectToText2Speech() {
}


private void showStyleView(boolean show) {
if (show) {
binding.rvVoiceStyles.setVisibility(View.VISIBLE);
binding.ttsStyleDegreeParent.setVisibility(View.VISIBLE);
} else {
binding.rvVoiceStyles.setVisibility(View.GONE);
binding.ttsStyleDegreeParent.setVisibility(View.GONE);
}
}


@SuppressLint("SetTextI18n")
private void updateView() {
APP.putInt(Constants.VOICE_STYLE_DEGREE, styleDegree);
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/me/ag2s/tts/services/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public final class Constants {


public static final String EDGE_ORIGIN = "chrome-extension://jdiccldimpdaibmpdkjnbmckianbfold";
public static final String EDGE_UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.47";
public static final String EDGE_UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.124 Safari/537.36 Edg/102.0.1245.41";
public static final String EDGE_URL = "https://speech.platform.bing.com/consumer/speech/synthesize/readaloud/edge/v1?TrustedClientToken=6A5AA1D4EAFF4E9FB37E23D68491D6F4";

}
70 changes: 49 additions & 21 deletions app/src/main/java/me/ag2s/tts/services/SSML.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,16 @@ public class SSML {
private short pitch;
private short rate;
private boolean useDict;
//是否使用预览版
private boolean usePre;

private static SSML instance;


private SSML(SynthesisRequest request, String name, TtsStyle ttsStyle, boolean useDict) {
private SSML(SynthesisRequest request, String name, TtsStyle ttsStyle, boolean useDict, boolean usePre) {
this.content = new StringBuilder(request.getCharSequenceText());
this.useDict = useDict;
this.usePre = usePre;
this.name = name;
this.style = new WeakReference<>(ttsStyle);
this.time = CommonTool.getTime();
Expand All @@ -97,19 +100,19 @@ private SSML(SynthesisRequest request, String name, TtsStyle ttsStyle, boolean u

}

public static SSML getInstance(SynthesisRequest request, String name, TtsStyle ttsStyle, boolean useDict) {
public static SSML getInstance(SynthesisRequest request, String name, TtsStyle ttsStyle, boolean useDict, boolean usePre) {
if (instance == null) {
instance = new SSML(request, name, ttsStyle, useDict);
instance = new SSML(request, name, ttsStyle, useDict, usePre);
} else {
instance.content=new StringBuilder(request.getCharSequenceText());
instance.content = new StringBuilder(request.getCharSequenceText());
instance.useDict = useDict;
instance.usePre = usePre;
instance.name = name;
instance.style = new WeakReference<>(ttsStyle);
instance.time = CommonTool.getTime();
instance.pitch = (short) (request.getPitch() - 100);
instance.rate = (short) (request.getSpeechRate());
instance.id = CommonTool.getMD5String(request.getCharSequenceText() + "" + System.currentTimeMillis());
instance.useDict = useDict;
instance.handleContent();
}
return instance;
Expand All @@ -128,7 +131,7 @@ private void handleContent() {
CommonTool.replace(content, ">", "&lt;");
CommonTool.replace(content, "<", "&gt;");
//是否分段
if (APP.getBoolean(Constants.SPLIT_SENTENCE, false)) {
if (APP.getBoolean(Constants.SPLIT_SENTENCE, false) && usePre) {
String temp = content.toString();
temp = p0.matcher(temp).replaceAll("$1");//把常用的影响分句的重复符号合并
temp = p1.matcher(temp).replaceAll("$1</p><p>$2");//单字符断句符,排除后面有引号的情况
Expand All @@ -155,20 +158,45 @@ private void handleContent() {
@NonNull
@Override
public String toString() {
String rateString =rate/100+"."+rate%100;
String pitchString = pitch >= 0 ? "+" + pitch + "Hz" : pitch + "Hz";
return "X-RequestId:" + id + "\r\n" +
"Content-Type:application/ssml+xml\r\n" +
"X-Timestamp:" + time + "Z\r\n" +

"Path:ssml\r\n\r\n" +
"<speak version=\"1.0\" xmlns=\"http://www.w3.org/2001/10/synthesis\" xmlns:mstts=\"https://www.w3.org/2001/mstts\" xml:lang=\"" + lang + "\">" +
"<voice name=\"" + name + "\">" +
"<lang xml:lang=\"" + lang + "\">" +
"<prosody pitch=\"" + pitchString + "\" " +
"rate =\"" + rateString + "\" " +
"volume=\"" + style.get().getVolume() + "\">" +
"<mstts:express-as style=\"" + style.get().value + "\" styledegree=\"" + style.get().getStyleDegree() + "\" ><p>" + content.toString() + "</p></mstts:express-as>" +
"</prosody></lang></voice></speak>";
String rateString = rate / 100 + "." + rate % 100;
// if (!usePre) {
// return "Path: ssml" + "\r\n" +
// "X-RequestId: " + id + "\r\n" +
// "X-Timestamp: " + time + "Z" + "\r\n" +
// "Content-Type: application/ssml+xml" + "\r\n\r\n" +
// "<speak xmlns=\"http://www.w3.org/2001/10/synthesis\" xmlns:mstts=\"http://www.w3.org/2001/mstts\" xmlns:emo=\"http://www.w3.org/2009/10/emotionml\" version=\"1.0\" xml:lang=\"en-US\"><voice name=\"" + name + "\"><prosody rate=\"" + rateString + "%\" pitch=\"" + pitch + "%\">" + content.toString() + "\r\n" +
// "</prosody></voice></speak>";
// }
//String pitchString = pitch >= 0 ? "+" + pitch + "Hz" : pitch + "Hz";
StringBuilder sb = new StringBuilder()
.append("Path:ssml\r\n")
.append("X-RequestId:").append(id).append("\r\n")
.append("X-Timestamp:").append(time).append("Z\r\n")
.append("Content-Type:application/ssml+xml\r\n\r\n");


sb.append("<speak version=\"1.0\" xmlns=\"http://www.w3.org/2001/10/synthesis\" xmlns:emo=\"http://www.w3.org/2009/10/emotionml\" xmlns:mstts=\"https://www.w3.org/2001/mstts\" xml:lang=\"").append(lang).append("\">");
sb.append("<voice name=\"").append(name).append("\">");
if (usePre) {
sb.append("<lang xml:lang=\"").append(lang).append("\">");
}
sb.append("<prosody pitch=\"").append(pitch).append("%\" ").append("rate=\"").append(rateString).append("\" ").append("volume=\"").append(style.get().getVolume()).append("\">");

if (usePre) {
sb.append("<mstts:express-as style=\"").append(style.get().value).append("\" styledegree=\"").append(style.get().getStyleDegree()).append("\" ><p>").append(content.toString()).append("</p></mstts:express-as>");
} else {
sb.append("").append(content.toString()).append("");

}


sb.append("</prosody>");
if (usePre) {
sb.append("</lang>");
}

sb.append("</voice></speak>");

return sb.toString();
}
}
27 changes: 20 additions & 7 deletions app/src/main/java/me/ag2s/tts/services/TTSService.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public class TTSService extends TextToSpeechService {
private final OkHttpClient client;
@Nullable
private volatile WebSocket webSocket;
private volatile boolean isPreview = false;
private volatile boolean isSynthesizing = false;
//当前的生成格式
private volatile TtsOutputFormat currentFormat;
Expand Down Expand Up @@ -564,18 +565,29 @@ public WebSocket getOrCreateWs() {
synchronized (TTSService.class) {
if (this.webSocket == null) {

while (TokenHolder.token == null) {
try {
this.wait(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

String url;
String origin = Constants.EDGE_ORIGIN;
String origin;
if (TokenHolder.token != null && APP.getBoolean(Constants.USE_PREVIEW, false)) {
url = "wss://eastus.tts.speech.microsoft.com/cognitiveservices/websocket/v1?Authorization=bearer " + TokenHolder.token + "&X-ConnectionId=" + CommonTool.getMD5String(new Date().toString());
origin = "https://azure.microsoft.com";
isPreview = true;
} else {
url = Constants.EDGE_URL + "&ConnectionId=" + CommonTool.getMD5String(new Date().toString());
url = Constants.EDGE_URL;
isPreview = false;
origin = Constants.EDGE_ORIGIN;
}
Request request = new Request.Builder()
.url(url)
.header("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6")
.header("Accept-Encoding", "gzip, deflate")
//.header("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6")
//.header("Accept-Encoding", "gzip, deflate")
.header("User-Agent", Constants.EDGE_UA)
.addHeader("Origin", origin)
.build();
Expand All @@ -595,7 +607,7 @@ public WebSocket getOrCreateWs() {
* 发送合成语音配置,更改格式需要重新发送
*/
private synchronized void sendConfig(WebSocket ws, TtsConfig ttsConfig) {
String msg = "X-Timestamp:+" + getTime() + "Z\r\n" +
String msg = "X-Timestamp:+" + getTime() + "\r\n" +
"Content-Type:application/json; charset=utf-8\r\n" +
"Path:speech.config\r\n\r\n"
+ ttsConfig.toString();
Expand Down Expand Up @@ -637,14 +649,15 @@ public synchronized void sendText(SynthesisRequest request, SynthesisCallback ca
ttsStyle.setStyleDegree(APP.getInt(Constants.VOICE_STYLE_DEGREE, 100));
ttsStyle.setVolume(APP.getInt(Constants.VOICE_VOLUME, 100));
boolean useDict = APP.getBoolean(Constants.USE_DICT, false);
SSML ssml = SSML.getInstance(request, name, ttsStyle, useDict);
Log.e(TAG, ssml.toString());


//webSocket = webSocket == null ? getOrCreateWs() : webSocket;
if (oldFormatIndex != index) {
sendConfig(getOrCreateWs(), ttsConfig);
oldFormatIndex = index;
}
SSML ssml = SSML.getInstance(request, name, ttsStyle, useDict, isPreview);
Log.e(TAG, ssml.toString());
//在Google Play图书之类应用会闪退,应该及时调用该方法
callback.start(currentFormat.HZ,
currentFormat.BitRate, 1 /* Number of channels. */);
Expand Down
11 changes: 10 additions & 1 deletion app/src/main/java/me/ag2s/tts/services/TtsActor.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class TtsActor {
*/
@Nullable
private String note;
private Locale tempLocate;

public TtsActor(@NonNull String name, @NonNull String shortName, @NonNull String locate, boolean gender, @Nullable String note) {
this.name = name;
Expand All @@ -53,10 +54,11 @@ public TtsActor(String shortName, boolean gender, @Nullable String note) {
}
//String[] temp = locale.split(tag);

this.name = shortName.substring(shortName.lastIndexOf(tag) + 1).replace("Neural","");
this.name = shortName.substring(shortName.lastIndexOf(tag) + 1).replace("Neural", "");
this.locale = shortName.substring(0, shortName.lastIndexOf(tag));

}

@SuppressWarnings("unused")
public TtsActor(String name, String shortName, String locate, boolean gender) {
this(name, shortName, locate, gender, "");
Expand Down Expand Up @@ -92,6 +94,11 @@ public void setGender(boolean gender) {
}

public Locale getLocale() {
if (tempLocate != null) {
return tempLocate;
}


String tag = "-";
if (locale.contains("-")) {
tag = "-";
Expand All @@ -118,3 +125,5 @@ public void setNote(@Nullable String note) {
this.note = note;
}
}


78 changes: 41 additions & 37 deletions app/src/main/java/me/ag2s/tts/services/TtsActorManger.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package me.ag2s.tts.services;

import android.os.Build;
import android.util.Log;

import androidx.annotation.NonNull;
Expand Down Expand Up @@ -508,48 +509,50 @@ private TtsActorManger() {
}

public List<TtsActor> sortByLocale(List<TtsActor> list, Locale locale) {
Collections.sort(list, (o1, o2) -> {
Locale loc1 = o1.getLocale();
Locale loc2 = o2.getLocale();
boolean b11 = loc1.getISO3Language().equals(locale.getISO3Language());
boolean b12 = loc1.getISO3Country().equals(locale.getISO3Country());
boolean b13 = loc1.getDisplayVariant(Locale.US).equals(locale.getDisplayVariant(Locale.US));
boolean b21 = loc2.getISO3Language().equals(locale.getISO3Language());
boolean b22 = loc2.getISO3Country().equals(locale.getISO3Country());
boolean b23 = loc2.getDisplayVariant(Locale.US).equals(locale.getDisplayVariant(Locale.US));
//语言不同
if ((!b11) && (!b21)) {
return 0;
}
//两个都相同
if (b11 && b12 && b13 == b21 && b22 && b23) {
return 0;
}
if (b11 && b12 && b13) {
return -1;
}
if (b21 && b22 && b23) {
return 1;
}

if ((b11 && b12 == b21 && b22)) {
if (b13 == b23) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Collections.sort(list, (o1, o2) -> {
Locale loc1 = o1.getLocale();
Locale loc2 = o2.getLocale();
boolean b11 = loc1.getISO3Language().equals(locale.getISO3Language());
boolean b12 = loc1.getISO3Country().equals(locale.getISO3Country());
boolean b13 = loc1.getDisplayVariant(Locale.US).equals(locale.getDisplayVariant(Locale.US));
boolean b21 = loc2.getISO3Language().equals(locale.getISO3Language());
boolean b22 = loc2.getISO3Country().equals(locale.getISO3Country());
boolean b23 = loc2.getDisplayVariant(Locale.US).equals(locale.getDisplayVariant(Locale.US));
//语言都不同
if ((!b11) && (!b21)) {
return 0;
}
//两个都相同
if (b11 && b12 && b13 == b21 && b22 && b23) {
return 0;
}
if (b13) {
if (b11 && b12 && b13) {
return -1;
} else {
}
if (b21 && b22 && b23) {
return 1;
}
}
if (b11 && b12) {
return -1;
}
if (b21 && b22) {
return 1;
}
return 0;
});

if ((b11 && b12 == b21 && b22)) {
if (b13 == b23) {
return 0;
}
if (b13) {
return -1;
} else {
return 1;
}
}
if (b11 && b12) {
return -1;
}
if (b21 && b22) {
return 1;
}
return 0;
});
}
return list;
}

Expand All @@ -571,6 +574,7 @@ public TtsActor getByName(@NonNull String name) {
*/
@SuppressWarnings("unused")
public synchronized List<TtsActor> getActors() {

return sortByLocale(this.actors, Locale.getDefault());
//return this.actors;
}
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/java/me/ag2s/tts/services/TtsConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ public TtsOutputFormat getFormat() {
@NotNull
@Override
public String toString() {
//X-Timestamp:Thu Jun 16 2022 19:13:55 GMT+0800 (中国标准时间)
//Content-Type:application/json; charset=utf-8
//Path:speech.config
//
//{"context":{"synthesis":{"audio":{"metadataoptions":{"sentenceBoundaryEnabled":"false","wordBoundaryEnabled":"true"},"outputFormat":"webm-24khz-16bit-mono-opus"}}}}

String msg = "{\"context\":{\"synthesis\":{\"audio\":{\"metadataoptions\":{\"sentenceBoundaryEnabled\":\"%s\",\"wordBoundaryEnabled\":\"%s\"},\"outputFormat\":\"%s\"}}}}";
msg = String.format(msg, sentenceBoundaryEnabled ? "true" : "false", "true", TtsFormatManger.getInstance().getFormat(index).value);
Log.d(TTSService.class.getSimpleName(), msg);
Expand Down
Loading

0 comments on commit 7665284

Please sign in to comment.