Skip to content
This repository has been archived by the owner on Sep 17, 2024. It is now read-only.

Commit

Permalink
给 Windows 版增加本地 TTS。
Browse files Browse the repository at this point in the history
  • Loading branch information
tangshimin committed Nov 19, 2022
1 parent a935fc9 commit 82c55d9
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 17 deletions.
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ dependencies {
implementation("com.squareup.okhttp3:okhttp:4.10.0")
implementation(files("lib/ebml-reader-0.1.1.jar"))
implementation(files("lib/subtitleConvert-1.0.2.jar"))
implementation(files("lib/jacob-1.20.jar"))
implementation("org.apache.maven:maven-artifact:3.8.6")
implementation("org.burnoutcrew.composereorderable:reorderable:0.9.2")
implementation("com.github.albfernandez:juniversalchardet:2.4.0")
Expand Down
Binary file added lib/jacob-1.20.jar
Binary file not shown.
Binary file added resources/windows/jacob/jacob-1.20-x64.dll
Binary file not shown.
39 changes: 34 additions & 5 deletions src/main/kotlin/player/AudioButton.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import ui.LocalCtrl
import data.Word
import kotlinx.coroutines.launch
import state.AppState
import state.WordState
import state.getAudioDirectory
import tts.MSTTSpeech
import ui.LocalCtrl
import uk.co.caprica.vlcj.player.base.MediaPlayer
import uk.co.caprica.vlcj.player.base.MediaPlayerEventAdapter
import uk.co.caprica.vlcj.player.component.AudioPlayerComponent
Expand Down Expand Up @@ -63,7 +64,11 @@ fun AudioButton(
var isAutoPlay by remember { mutableStateOf(true) }

val playAudio = {
playAudio(audioPath, volume, audioPlayerComponent,
playAudio(
audioPath,
pronunciation = pronunciation,
volume,
audioPlayerComponent,
changePlayerState = { isPlaying = it },
setIsAutoPlay = { isAutoPlay = it })
}
Expand Down Expand Up @@ -156,7 +161,11 @@ fun AudioButton(
addToAudioSet = {state.audioSet.add(it)},
pronunciation = typingState.pronunciation
)
playAudio(audioPath, volume, audioPlayerComponent,
playAudio(
audioPath,
pronunciation = pronunciation,
volume,
audioPlayerComponent,
changePlayerState = { isPlaying = it },
setIsAutoPlay = { })
}
Expand Down Expand Up @@ -220,12 +229,28 @@ fun AudioButton(
}
fun playAudio(
audioPath: String,
pronunciation:String,
volume: Float,
audioPlayerComponent: AudioPlayerComponent,
changePlayerState: (Boolean) -> Unit,
setIsAutoPlay: (Boolean) -> Unit,
) {
if (audioPath.isNotEmpty()) {
// 如果单词发音为 local TTS 或者由于网络问题,没有获取到发音
// 就自动使用本地的 TTS
if (pronunciation == "local TTS" || audioPath.isEmpty()) {
Thread(Runnable {

if (isWindows()) {
val speech = MSTTSpeech()
speech.speak(audioPath)
}


}).start()


}else if (audioPath.isNotEmpty()) {

changePlayerState(true)
setIsAutoPlay(false)
audioPlayerComponent.mediaPlayer().events().addMediaPlayerEventListener(object : MediaPlayerEventAdapter() {
Expand All @@ -250,13 +275,17 @@ fun getAudioPath(
addToAudioSet:(String) -> Unit,
pronunciation: String
): String {
if(pronunciation == "local TTS") return word
val audioDir = getAudioDirectory()
var path = ""
val type: Any = when (pronunciation) {
"us" -> "type=2"
"uk" -> "type=1"
"jp" -> "le=jap"
else -> println(pronunciation)
else -> {
println("未知类型$pronunciation")
""
}
}
val fileName = word + "_" + pronunciation + ".mp3"
// 先查询本地有没有
Expand Down
49 changes: 49 additions & 0 deletions src/main/kotlin/tts/MSTTSpeech.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package tts

import com.jacob.activeX.ActiveXComponent
import com.jacob.com.Dispatch
import com.jacob.com.Variant
import state.getResourcesFile

class MSTTSpeech {

/** 音量 1到100 */
var volume: Int = 100

/** 频率 -10到10 */
var rate: Int = 0

/** 输出设备序号 */
var audio: Int = 0

/** 声音对象 */
var spVoice:Dispatch? = null

var ax: ActiveXComponent? = null

init {
System.setProperty("jacob.dll.path", getResourcesFile("jacob/jacob-1.20-x64.dll").absolutePath ?: "")
ax = ActiveXComponent("Sapi.SpVoice")
spVoice = ax!!.`object`
}


/**
* 播放语言
* @param text 要转换成语言的文本
*/
fun speak(text: String) {
try{
// 设置音量
Dispatch.put(spVoice,"Volume",Variant(this.volume))
// 设置速率
Dispatch.put(spVoice,"Rate",Variant(this.rate))
// 开始朗读
Dispatch.call(spVoice,"Speak",Variant(text))
}catch (exception: Exception) {
println(exception.message)
exception.printStackTrace()
}
}

}
1 change: 1 addition & 0 deletions src/main/kotlin/ui/Search.kt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ fun Search(
)
playAudio(
audioPath = audioPath,
pronunciation = typingWordState.pronunciation,
volume = appState.global.audioVolume,
audioPlayerComponent = audioPlayer,
changePlayerState = { isPlaying -> isPlayingAudio = isPlaying },
Expand Down
1 change: 1 addition & 0 deletions src/main/kotlin/ui/TypingWord.kt
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ fun MainContent(
if (!isPlayingAudio) {
playAudio(
audioPath = audioPath,
pronunciation = typingWord.pronunciation,
volume = appState.global.audioVolume,
audioPlayerComponent = audioPlayerComponent,
changePlayerState = { isPlaying -> isPlayingAudio = isPlaying },
Expand Down
38 changes: 26 additions & 12 deletions src/main/kotlin/ui/TypingWordSidebar.kt
Original file line number Diff line number Diff line change
Expand Up @@ -464,19 +464,20 @@ fun TypingWordSidebar(
modifier = Modifier.fillMaxWidth().padding(start = 16.dp, end = 8.dp)
) {
Text("自动发音", color = MaterialTheme.colors.onBackground)
Spacer(Modifier.width(35.dp))
Spacer(Modifier.width(5.dp))
var expand by remember { mutableStateOf(false) }
val selectedText = when (typingWordState.pronunciation) {
"us" -> "美音"
"uk" -> "英音"
"us" -> "真人美音"
"uk" -> "真人英音"
"jp" -> "日语"
"local TTS" -> "语音合成"
else -> "关闭"
}
Box {
OutlinedButton(
onClick = { expand = true },
modifier = Modifier
.width(87.dp)
.width(120.dp)
.background(Color.Transparent)
.border(1.dp, Color.Transparent)
) {
Expand All @@ -486,8 +487,8 @@ fun TypingWordSidebar(
DropdownMenu(
expanded = expand,
onDismissRequest = { expand = false },
modifier = Modifier.width(87.dp)
.height(140.dp)
modifier = Modifier.width(120.dp)
.height(180.dp)
) {
if (typingWordState.vocabulary.language == "english") {
DropdownMenuItem(
Expand All @@ -498,9 +499,9 @@ fun TypingWordSidebar(
expand = false
}
},
modifier = Modifier.width(87.dp).height(40.dp)
modifier = Modifier.width(120.dp).height(40.dp)
) {
Text("英音")
Text("真人英音")
}
DropdownMenuItem(
onClick = {
Expand All @@ -510,9 +511,9 @@ fun TypingWordSidebar(
expand = false
}
},
modifier = Modifier.width(87.dp).height(40.dp)
modifier = Modifier.width(120.dp).height(40.dp)
) {
Text("美音")
Text("真人美音")
}
}

Expand All @@ -525,12 +526,25 @@ fun TypingWordSidebar(
expand = false
}
},
modifier = Modifier.width(87.dp).height(40.dp)
modifier = Modifier.width(120.dp).height(40.dp)
) {
Text("日语")
}
}

DropdownMenuItem(
onClick = {
scope.launch {
typingWordState.pronunciation = "local TTS"
typingWordState.saveTypingWordState()
expand = false
}
},
modifier = Modifier.width(120.dp).height(40.dp)
) {
Text("语音合成")
}

DropdownMenuItem(
onClick = {
scope.launch {
Expand All @@ -539,7 +553,7 @@ fun TypingWordSidebar(
expand = false
}
},
modifier = Modifier.width(87.dp).height(40.dp)
modifier = Modifier.width(120.dp).height(40.dp)
) {
Text("关闭")
}
Expand Down

0 comments on commit 82c55d9

Please sign in to comment.