diff --git a/crates/voicevox_core_java_api/README.md b/crates/voicevox_core_java_api/README.md index d1bc31938..ab5ef5064 100644 --- a/crates/voicevox_core_java_api/README.md +++ b/crates/voicevox_core_java_api/README.md @@ -44,25 +44,31 @@ Java プロジェクトを動かすには、 - `lib/src/main/resources/dll/[target]/libvoicevox_core_java_api.so` を作成する(`libvoicevox_core_java_api.so`はプラットフォームによって異なります、詳細は後述)。 必要があります。 +また、ハードウェアアクセラレーションを有効にする時は`DEVICE`環境変数を`cuda`または`directml`にし、Android 版をビルドする時は`OS`環境変数を`android`にしてください。 ```console ❯ cargo build -❯ LD_LIBRARY_PATH=$(realpath ../../target/debug) ./gradlew build +❯ LD_LIBRARY_PATH=$(realpath ../../target/debug) ./gradlew test # または ❯ cp ../../target/debug/libvoicevox_core_java_api.so lib/src/main/resources/dll/[target]/libvoicevox_core_java_api.so -❯ ./gradlew build +❯ ./gradlew test +❯ DEVICE=cuda ./gradlew test +❯ OS=android ./gradlew test ``` ## ビルド(リリース) `cargo build --release` で Rust 側を、`./gradlew build` で Java 側をビルドできます。 パッケージ化する時は lib/src/main/resources/dll 内に dll をコピーしてください。 +`DEVICE`、`OS`環境変数は開発時と同様です。 ```console ❯ cargo build --release ❯ cp ../../target/release/libvoicevox_core_java_api.so lib/src/main/resources/dll/[target]/libvoicevox_core_java_api.so ❯ ./gradlew build +❯ DEVICE=cuda ./gradlew build +❯ OS=android ./gradlew build ``` ## テスト diff --git a/crates/voicevox_core_java_api/lib/build-android.gradle b/crates/voicevox_core_java_api/lib/build-android.gradle new file mode 100644 index 000000000..f369c663c --- /dev/null +++ b/crates/voicevox_core_java_api/lib/build-android.gradle @@ -0,0 +1,56 @@ +plugins { + id 'com.android.library' version '8.1.1' + id 'org.jetbrains.kotlin.android' version '1.9.10' +} + +version = gradle.ext.version + +repositories { + google() + mavenCentral() +} + +dependencies { + // Use JUnit Jupiter for testing. + testImplementation 'org.junit.jupiter:junit-jupiter:5.9.2' + + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + + // https://mvnrepository.com/artifact/com.google.code.gson/gson + implementation group: 'com.google.code.gson', name: 'gson', version: gradle.ext.gsonVersion + + // https://mvnrepository.com/artifact/jakarta.validation/jakarta.validation-api + implementation group: 'jakarta.validation', name: 'jakarta.validation-api', version: gradle.ext.jakartaValidationVersion + + // https://mvnrepository.com/artifact/jakarta.annotation/jakarta.annotation-api + implementation group: 'jakarta.annotation', name: 'jakarta.annotation-api', version: gradle.ext.jakartaAnnotationVersion + + implementation group: 'com.microsoft.onnxruntime', name: 'onnxruntime-android', version: gradle.ext.onnxruntimeVersion +} + +// Apply a specific Java toolchain to ease working on different environments. +java { + toolchain { + languageVersion = JavaLanguageVersion.of(8) + } +} + +android { + compileSdkVersion 26 + + defaultConfig { + minSdkVersion 26 + targetSdkVersion 26 + } + namespace "jp.hiroshiba.voicevoxcore" + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + sourceSets { + main { + jniLibs.srcDirs = ["./src/main/resources/jniLibs"] + } + } +} diff --git a/crates/voicevox_core_java_api/lib/build.gradle b/crates/voicevox_core_java_api/lib/build.gradle index 3e87cceff..f1eb5b106 100644 --- a/crates/voicevox_core_java_api/lib/build.gradle +++ b/crates/voicevox_core_java_api/lib/build.gradle @@ -11,7 +11,9 @@ plugins { id "com.diffplug.spotless" version "6.20.0" } -version = '0.0.0' +def boolean isGpu = ['cuda', 'directml'].contains(gradle.ext.targetDevice) + +version = gradle.ext.version repositories { // Use Maven Central for resolving dependencies. @@ -24,28 +26,28 @@ dependencies { testRuntimeOnly 'org.junit.platform:junit-platform-launcher' - // This dependency is exported to consumers, that is to say found on their compile classpath. - api 'org.apache.commons:commons-math3:3.6.1' - - // This dependency is used internally, and not exposed to consumers on their own compile classpath. - implementation 'com.google.guava:guava:31.1-jre' - // https://mvnrepository.com/artifact/com.google.code.gson/gson - implementation group: 'com.google.code.gson', name: 'gson', version: '2.10.1' + implementation group: 'com.google.code.gson', name: 'gson', version: gradle.ext.gsonVersion // https://mvnrepository.com/artifact/jakarta.validation/jakarta.validation-api - implementation group: 'jakarta.validation', name: 'jakarta.validation-api', version: '3.0.2' + implementation group: 'jakarta.validation', name: 'jakarta.validation-api', version: gradle.ext.jakartaValidationVersion - implementation group: 'com.microsoft.onnxruntime', name: 'onnxruntime', version: '1.14.0' + // https://mvnrepository.com/artifact/jakarta.annotation/jakarta.annotation-api + implementation group: 'jakarta.annotation', name: 'jakarta.annotation-api', version: gradle.ext.jakartaAnnotationVersion + + if (isGpu) { + implementation group: 'com.microsoft.onnxruntime', name: 'onnxruntime_gpu', version: gradle.ext.onnxruntimeVersion + } else { + implementation group: 'com.microsoft.onnxruntime', name: 'onnxruntime', version: gradle.ext.onnxruntimeVersion + } } // Apply a specific Java toolchain to ease working on different environments. java { toolchain { - languageVersion = JavaLanguageVersion.of(11) + languageVersion = JavaLanguageVersion.of(8) } } - tasks.named('test') { // Use JUnit Platform for unit tests. useJUnitPlatform() diff --git a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/AccentPhrase.java b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/AccentPhrase.java index 8c64c9d11..61e8b5d28 100644 --- a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/AccentPhrase.java +++ b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/AccentPhrase.java @@ -2,10 +2,10 @@ import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; import java.util.ArrayList; import java.util.List; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; /** AccentPhrase (アクセント句ごとの情報)。 */ public class AccentPhrase { diff --git a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/AudioQuery.java b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/AudioQuery.java index 4a23be3f7..c03accf2f 100644 --- a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/AudioQuery.java +++ b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/AudioQuery.java @@ -2,10 +2,10 @@ import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; import java.util.ArrayList; import java.util.List; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; /** AudioQuery(音声合成用のクエリ)。 */ public class AudioQuery { diff --git a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/Mora.java b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/Mora.java index 61dbaf233..f03874323 100644 --- a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/Mora.java +++ b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/Mora.java @@ -2,8 +2,8 @@ import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; /** モーラ(子音+母音)ごとの情報。 */ public class Mora { diff --git a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/OpenJtalk.java b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/OpenJtalk.java index 3228b8d51..c9ad2f963 100644 --- a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/OpenJtalk.java +++ b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/OpenJtalk.java @@ -1,11 +1,7 @@ package jp.hiroshiba.voicevoxcore; -import java.lang.ref.Cleaner; - -/** テキスト解析器としてのOpen JTalk。 */ public class OpenJtalk extends Dll { private long handle; - private static final Cleaner cleaner = Cleaner.create(); /** * Open JTalkの辞書ディレクトリ。 @@ -14,8 +10,11 @@ public class OpenJtalk extends Dll { */ public OpenJtalk(String openJtalkDictDir) { rsNewWithInitialize(openJtalkDictDir); + } - cleaner.register(this, () -> rsDrop()); + protected void finalize() throws Throwable { + rsDrop(); + super.finalize(); } /** diff --git a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/Synthesizer.java b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/Synthesizer.java index 98bf9f403..5739b14f7 100644 --- a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/Synthesizer.java +++ b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/Synthesizer.java @@ -1,11 +1,10 @@ package jp.hiroshiba.voicevoxcore; import com.google.gson.Gson; -import java.lang.ref.Cleaner; +import jakarta.annotation.Nonnull; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import javax.annotation.Nonnull; /** * 音声シンセサイザ。 @@ -14,11 +13,14 @@ */ public class Synthesizer extends Dll { private long handle; - private static final Cleaner cleaner = Cleaner.create(); private Synthesizer(OpenJtalk openJtalk, Builder builder) { rsNewWithInitialize(openJtalk, builder); - cleaner.register(this, () -> rsDrop()); + } + + protected void finalize() throws Throwable { + rsDrop(); + super.finalize(); } /** diff --git a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/UserDict.java b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/UserDict.java index d75924feb..b0b8921a2 100644 --- a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/UserDict.java +++ b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/UserDict.java @@ -4,22 +4,23 @@ import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; import com.google.gson.internal.LinkedTreeMap; +import jakarta.annotation.Nonnull; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; -import java.lang.ref.Cleaner; import java.util.HashMap; -import javax.annotation.Nonnull; /** ユーザー辞書。 */ public class UserDict extends Dll { private long handle; - private static final Cleaner cleaner = Cleaner.create(); /** ユーザー辞書を作成する。 */ public UserDict() { rsNew(); + } - cleaner.register(this, () -> rsDrop()); + protected void finalize() throws Throwable { + rsDrop(); + super.finalize(); } /** diff --git a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/VoiceModel.java b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/VoiceModel.java index 518f1de31..05c1a11b2 100644 --- a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/VoiceModel.java +++ b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/VoiceModel.java @@ -3,13 +3,11 @@ import com.google.gson.Gson; import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; -import java.lang.ref.Cleaner; -import javax.annotation.Nonnull; +import jakarta.annotation.Nonnull; /** 音声モデル。 */ public class VoiceModel extends Dll { private long handle; - private static final Cleaner cleaner = Cleaner.create(); /** ID。 */ @Nonnull public final String id; @@ -27,8 +25,11 @@ public VoiceModel(String modelPath) { throw new RuntimeException("Failed to parse metasJson"); } metas = rawMetas; + } - cleaner.register(this, () -> rsDrop()); + protected void finalize() throws Throwable { + rsDrop(); + super.finalize(); } private native void rsFromPath(String modelPath); diff --git a/crates/voicevox_core_java_api/lib/src/main/resources/jniLibs/README.md b/crates/voicevox_core_java_api/lib/src/main/resources/jniLibs/README.md new file mode 100644 index 000000000..9073988ec --- /dev/null +++ b/crates/voicevox_core_java_api/lib/src/main/resources/jniLibs/README.md @@ -0,0 +1,5 @@ +このディレクトリに Android での JNI 用に読み込まれる DLL を配置します。 +ディレクトリ名は以下のうちのいずれかになります。 + +- `arm64-v8a` +- `x86_64` diff --git a/crates/voicevox_core_java_api/lib/src/main/resources/jniLibs/arm64-x8a/.gitkeep b/crates/voicevox_core_java_api/lib/src/main/resources/jniLibs/arm64-x8a/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/crates/voicevox_core_java_api/lib/src/main/resources/jniLibs/x86_64/.gitkeep b/crates/voicevox_core_java_api/lib/src/main/resources/jniLibs/x86_64/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/crates/voicevox_core_java_api/settings.gradle b/crates/voicevox_core_java_api/settings.gradle index 7d07347eb..20a5e2c6a 100644 --- a/crates/voicevox_core_java_api/settings.gradle +++ b/crates/voicevox_core_java_api/settings.gradle @@ -1,7 +1,44 @@ +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } + + resolutionStrategy { + eachPlugin { + if(requested.id.namespace == "com.android") { + useModule("com.android.tools.build:gradle:${requested.version}") + } + } + } +} plugins { // Apply the foojay-resolver plugin to allow automatic download of JDKs id 'org.gradle.toolchains.foojay-resolver-convention' version '0.4.0' } rootProject.name = 'jp.hiroshiba.voicevoxcore' +def String targetOs = System.getenv('OS')?.toLowerCase() ?: "desktop" +def boolean isAndroid = targetOs == 'android' include('lib') +if (isAndroid) { + project(':lib').buildFileName = 'build-android.gradle' +} else { + project(':lib').buildFileName = 'build.gradle' +} + +def String cargoToml = file('../../Cargo.toml').text +def String cargoTomlVersion = (cargoToml =~ /(?m)^version = "(\S+)"$/)[0][1] + +gradle.ext { + version = cargoTomlVersion + + targetOs = targetOs + targetDevice = System.getenv('DEVICE') ?: 'cpu' + + gsonVersion = '2.10.1' + jakartaValidationVersion = '3.0.2' + jakartaAnnotationVersion = '2.1.1' + onnxruntimeVersion = '1.14.0' +}