Skip to content

Commit

Permalink
cleaning up before release
Browse files Browse the repository at this point in the history
  • Loading branch information
windymelt committed Mar 29, 2024
1 parent 2f2e0d8 commit 57012c6
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 95 deletions.
55 changes: 40 additions & 15 deletions src/main/scala/dev/capslock/voicevoxcore4s/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,76 @@ import com.sun.jna.ptr.{PointerByReference, IntByReference, LongByReference}
import java.io.FileOutputStream

object Hello extends App {
/* Extract dictionary files from JAR into real file system */
// Extract dictionary files from JAR into real file system.
// Files will go to temporary directory in OS.
val dictionaryDirectory = Util.extractDictFiles()
Util.extractModels()
Util.extractAndLoadLibraries()

// Load required library
val searchPath = (os.pwd / "lib").toString
com.sun.jna.NativeLibrary.addSearchPath("voicevox_core", searchPath)
com.sun.jna.NativeLibrary.addSearchPath("onnxruntime", searchPath)
System.load((os.pwd / "lib" / "libonnxruntime.so.1.13.1").toString)

// vocevox_core will be loaded automatically.
val core = Core()
println(core.voicevox_get_version())

val initializeOptions = core.voicevox_make_default_initialize_options()
initializeOptions.open_jtalk_dict_dir = dictionaryDirectory
initializeOptions.acceleration_mode =
Core.VoicevoxAccelerationMode.VOICEVOX_ACCELERATION_MODE_CPU.code
println(initializeOptions)

val initialized = core.voicevox_initialize(initializeOptions)
println(s"Hello, voicevoxcore4s! initialized? -> (${initialized})")

if (initialized == Core.VoicevoxResultCode.VOICEVOX_RESULT_OK.code) {
val loadResult = core.voicevox_load_model(2) // metan
val model_shikoku_metan = 2
val loadResult = core.voicevox_load_model(model_shikoku_metan)
println(s"model loaded: $loadResult")
val wl = new IntByReference()
val wav = new PointerByReference()

// Generating voice.
// First, we should have two pointers: result length, result wav buffer.
val bytesLength = new IntByReference()
val wavBuffer = new PointerByReference()

// Second, prepare TTS(talk to speech) options
val ttsOpts = core.voicevox_make_default_tts_options()
ttsOpts.kana = false

// Run TTS.
// VOICEVOX will rewrite memory beyond pointer.
val tts = core.voicevox_tts(
"こんにちは、世界",
2,
model_shikoku_metan,
ttsOpts,
wl,
wav
bytesLength, // this will be modified
wavBuffer // this will be modified
)
if (tts == Core.VoicevoxResultCode.VOICEVOX_RESULT_OK.code) {
println(s"length: ${wl.getValue()}")
val resultPtr = wav.getValue()
println("got pointer")
val resultArray = resultPtr.getByteArray(0, wl.getValue())
println("got array")
// You can acquire data from pointer using getValue()
val length = bytesLength.getValue()
val resultPtr = wavBuffer.getValue()
val resultArray = resultPtr.getByteArray(0, bytesLength.getValue())
println(s"length: $length bytes")

// Write out buffer.
val fs = new FileOutputStream("./result.wav")
fs.write(resultArray)
println("wrote array into file")
fs.close()
println("closed file")

// Release allocated memory.
core.voicevox_wav_free(resultPtr)
println("freed array")
} else {
println(s"tts failed: $tts")
}

// When program exit, bury VOICEVOX instance.
core.voicevox_finalize()

// Delete dictionary directory extracted into temporary directory.
os.remove.all(os.Path(dictionaryDirectory))
}
}
77 changes: 5 additions & 72 deletions src/main/scala/dev/capslock/voicevoxcore4s/Util.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import java.lang.invoke.MethodHandles
import Logger.logger

object Util {
val jarPath = os.pwd
val libDir = jarPath / "voicevoxcore4s-libs"

/** Extract dictionary files for VOICEVOX into temporary directory.
*
Expand All @@ -16,8 +14,9 @@ object Util {
* Extracted dictionary directory
*/
def extractDictFiles(): String = {
val tmpdir = os.temp.dir(prefix = "voicevoxcore4s", deleteOnExit = true)
logger.debug(s"extracting dictionary files into $tmpdir...")
val temporalDirectory =
os.temp.dir(prefix = "voicevoxcore4s", deleteOnExit = true)
logger.debug(s"extracting dictionary files into $temporalDirectory...")
val files = Seq(
"char.bin",
// "COPYING", // sbt-assemblyが自動的に名前を変更して不定になるので省略している。COPYING自体はJARに同梱される
Expand All @@ -31,79 +30,13 @@ object Util {
)
for { p <- files } {
val stream = getClass.getResourceAsStream(s"/$p")
val tmpPath = tmpdir / p
if (!os.exists(tmpPath)) {
logger.debug(s"copying $p")
os.write(tmpPath, stream, createFolders = true)
}
}
logger.debug("finished extracting")
tmpdir.toString()
}

/** Extract library files for VOICEVOX into current working directory.
*
* @return
* Library directory path
*/
def extractAndLoadLibraries(): Unit = {
import scala.sys.process._
import scala.collection.JavaConverters._

System.setProperty("jna.tmpdir", libDir.toString())
logger.debug(s"extracting libraries into $libDir...")

logger.debug("extracting libonnx...")
val libonnx =
com.sun.jna.Native.extractFromResourcePath(s"/${BuildInfo.libonnxFile}")
logger.debug(s"extracted onnx runtime: $libonnx")

val targetLibonnx = new File(libonnx.getParentFile(), BuildInfo.libonnxFile)
libonnx.renameTo(targetLibonnx)
logger.debug(s"renamed onnx runtime: -> $targetLibonnx")

logger.debug("loading libonnx...")
System.load(targetLibonnx.getAbsolutePath())
logger.debug("loaded libonnx.")

logger.debug("extracting libcore...")
val libcore =
com.sun.jna.Native.extractFromResourcePath(s"/${BuildInfo.libcoreFile}")
logger.debug(s"extracted libcore: $libcore")

val targetLibcore = new File(libcore.getParentFile(), BuildInfo.libcoreFile)
libcore.renameTo(targetLibcore)
logger.debug(s"renamed libcore: -> $targetLibcore")

logger.debug("loading libcore...")
System.load(targetLibcore.getAbsolutePath())
logger.debug("loaded libcore.")

// val jarFile = new File(this.getClass.getProtectionDomain().getCodeSource().getLocation().getPath())
// val jar = new JarFile(jarFile)
// for {e <- jar.entries().asIterator().asScala} {
// println(e.getName())
// }
// println(jarFile)
}

/** Extract model files included in VOICEVOX Core into current working
* directory.
*/
def extractModels(): Unit = {
// TODO: 自動化したい。modelディレクトリごとresourcesに格納できないだろうか
logger.debug(s"extracting core models into $libDir...")
val binaries =
(0 to 11) flatMap (n => Seq(s"d${n}.bin", s"pd${n}.bin", s"pi${n}.bin"))
val files = binaries ++ Seq("metas.json")
for { p <- files } {
val stream = getClass.getResourceAsStream(s"/$p")
val tmpPath = libDir / "model" / p
val tmpPath = temporalDirectory / p
if (!os.exists(tmpPath)) {
logger.debug(s"copying $p")
os.write(tmpPath, stream, createFolders = true)
}
}
logger.debug("finished extracting")
temporalDirectory.toString()
}
}
8 changes: 0 additions & 8 deletions src/test/scala/dev/capslock/voicevoxcore4s/CoreSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,6 @@ import org.scalatest.matchers.should.Matchers

import com.sun.jna.ptr.{PointerByReference, IntByReference}

/** 確実に一度だけライブラリをロードするためにObjectを使っている
*/
object TestRunner {
val dictionaryDirectory = Util.extractDictFiles()
Util.extractModels()
Util.extractAndLoadLibraries()
}

class CoreSpec extends AnyFlatSpec with Matchers {
// "Core" should "work at voicevox_tts" in {
// val core = Core()
Expand Down

0 comments on commit 57012c6

Please sign in to comment.