Skip to content

Commit

Permalink
Release v3.22 (#178)
Browse files Browse the repository at this point in the history
* Bump up version

* Create core module

* Move files

* Add some JsExport

* Add: Support analysis for lyrics with suffix

* Add functions for TS library (#164)

* Change: Use Array for better typing

* Add: Add generate functions

* Add: Add ability to build minimum core

* Add: Add wrapper

* Add: Add test

* Improve: gradlew test will run deno test

* Add: Add missing keys

* Change: Create documentToUfData / ufDataToDocument

* Fix: Fix name shadowing

* Add: Add 10 tracks test

* Change: Create project data

* Add: add parseFile and toFile

* Add: Add fromAny

* Add: Add convertJapaneseLyrics

* Add: Add ust

* Delete: Delete deno things

* Delete: Delete unused gitignore#

* Change: DocumentContainer -> ProjectContainer

* Change: Use KDoc

* Change: Use internal to hide error

* Change: Rename convertJapaneseLyrics

* Change: Change visibility

* Revert: webpack.config.d was required

* Fix resources resolve

* Use midi-file instead of midi-parser-js (#165)

* Change: Use midi-file

* Fix: Fix importing assets

* Fix: Run kotlinUpgradeYarnLock

* Fix: Fix resolver

* Change: Make ESModule conditional

* Delete: Delete workaround

* Delete: Delete unused dependency

* Revert: Re-add workaround

* Revert: Revert unrelated changes

* Update: Update yarn.lock

* Change: Re-throw error

* Fix: Fix error

* Fix: It throws string, not an Error

* Fix tasks about resources copy

---------

Co-authored-by: colin.weng <[email protected]>

* Export exceptions to JS (#167)

* Update Russian translation (#168)

* Change: Don't remove "っ" by default (#169)

* Change: Don't remove "っ" by default

* Delete: Why is there a new line?

* Allow specifying default lyrics via ImportParams (#170)

* Add: Allow specifying default lyrics via ImportParams

* Code: gradlew ktlintFormat

* Update: Update Format.kt

* Allow specifying ImportParams from JS, and export pitches (#171)

* Add: Support tssln (#172)

* Add: Support importing tssln

* Add: Add basic export

* Code: gradlew ktlintFormat

* Change: Use yarn

* Update: Update texts for tssln (#174)

* Update: Update texts

* Update: kotlinUpgradeYarnLock

* Fix: Fix around esm import

* Code: Format

* Export tssln to JS (#175)

* Add: Export tssln

* Change: Use val

* Fix some issues (#176)

* Fix: Fix some minor issues

* Add: Add comment

* Fix: Fix loading tssln from VST (#177)

* Fix: Fix loading tssln from VST

* Code: gradlew ktlintFormat

---------

Co-authored-by: sevenc-nanashi <[email protected]>
Co-authored-by: colin.weng <[email protected]>
Co-authored-by: Dmitry Kiryanov <[email protected]>
  • Loading branch information
4 people authored Jul 6, 2024
1 parent baee542 commit 724bee6
Show file tree
Hide file tree
Showing 156 changed files with 1,763 additions and 997 deletions.
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@jsr:registry=https://npm.jsr.io
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ and [React](https://github.com/facebook/react).

- Supported importing
formats: `.vsqx(3/4)`, `.vpr`, `.vsq`, `.mid(VOCALOID)`, `.mid(standard)`, `.ust`, `.ustx`, `.ccs`,`.xml(MusicXML)`
, `.musicxml`, `.svp`, `.s5p`, `.dv`, `.ppsf(NT)`, `.ufdata`
, `.musicxml`, `.svp`, `.s5p`, `.dv`, `.ppsf(NT)`, `.tssln`, `.ufdata`
- Supported exporting
formats: `.vsqx(4)`, `.vpr`, `.vsq`, `.mid(VOCALOID)`, `.mid(standard)`, `.ust`, `.ustx`, `.ccs`, `.xml(MusicXML)`
, `.svp`, `.s5p`, `.dv`, `.ufdata`
, `.svp`, `.s5p`, `.dv`, `.tssln`, `.ufdata`
- Keep information including: tracks, notes, tempo labels, time signatures
- Detect and convert Japanese lyrics types
- between CV and VCV
Expand All @@ -37,6 +37,7 @@ and [React](https://github.com/facebook/react).
| SVP ||||
| S5P || ||
| DV ||||
| Tssln || | |

## Open format published (.ufdata)

Expand All @@ -48,7 +49,7 @@ If you are developing OSS projects related to singing voice synthesis, you may f
## Contributors

[sdercolin](https://github.com/sdercolin), [ghosrt](https://github.com/ghosrt), [shine5402](https://github.com/shine5402), [adlez27](https://github.com/adlez27), [
General Nuisance](https://github.com/GeneralNuisance0)
General Nuisance](https://github.com/GeneralNuisance0), [sevenc-nanashi](https://github.com/sevenc-nanashi)

## Localization help

Expand Down
44 changes: 31 additions & 13 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ repositories {
mavenCentral()
}

configure<org.jlleitschuh.gradle.ktlint.KtlintExtension> {
version.set("0.45.2")
enableExperimentalRules.set(true)
allprojects {
apply(plugin = "org.jlleitschuh.gradle.ktlint")
configure<org.jlleitschuh.gradle.ktlint.KtlintExtension> {
version.set("0.45.2")
enableExperimentalRules.set(true)
}
}

fun kotlinw(target: String): String =
Expand All @@ -35,8 +38,7 @@ kotlin {
sourceSets {
val jsMain by getting {
dependencies {
// Model
implementation("com.sdercolin.utaformatix:utaformatix-data:1.0.0")
implementation(project(":core"))

// Kotlin
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-js:1.6.4")
Expand All @@ -61,17 +63,12 @@ kotlin {
implementation(npm("i18next-browser-languagedetector", "6.0.1"))

// Others
implementation(npm("jszip", "3.5.0"))
implementation(npm("stream-browserify", "3.0.0"))
implementation(npm("buffer", "6.0.3"))
implementation(npm("file-saver", "2.0.5"))
implementation(npm("raw-loader", "4.0.2"))
implementation(npm("file-loader", "6.2.0"))
implementation(npm("encoding-japanese", "1.0.30"))
implementation(npm("uuid", "8.3.2"))
implementation(npm("midi-parser-js", "4.0.4"))
implementation(npm("js-cookie", "2.2.1"))
implementation(npm("js-yaml", "4.1.0"))
}
}
val jsTest by getting {
Expand All @@ -82,14 +79,35 @@ kotlin {
}
}

val copyJsResources by tasks.register<Copy>("copyJsResources") {
from("src/jsMain/resources")
val copyCoreResources by tasks.register<Copy>("copyCoreResources") {
from("core/src/main/resources") {
include("**/*.*")
}
into("build/js/packages/utaformatix/kotlin/")
mustRunAfter("jsProductionExecutableCompileSync")
mustRunAfter("jsDevelopmentExecutableCompileSync")
}
tasks.named("jsBrowserProductionWebpack") {
dependsOn(copyCoreResources)
}
tasks.named("jsBrowserDevelopmentRun") {
dependsOn(copyCoreResources)
}

val copyJsResourcesForTests by tasks.register<Copy>("copyJsResourcesForTests") {
from("core/src/main/resources") {
include("**/*.*")
}
from("src/jsMain/resources") {
include("**/*.*")
}
into("build/js/packages/utaformatix-test/kotlin")
mustRunAfter("jsTestTestDevelopmentExecutableCompileSync")
}
tasks.named("jsBrowserTest") {
dependsOn(copyJsResources)
dependsOn(copyJsResourcesForTests)
}

val cleanDistributedResources by tasks.register<Delete>("cleanDistributedResources") {
listOf("format_templates", "images", "texts").forEach {
delete("build/distributions/$it")
Expand Down
1 change: 1 addition & 0 deletions core/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@jsr:registry=https://npm.jsr.io
32 changes: 32 additions & 0 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
plugins {
kotlin("js")
kotlin("plugin.serialization")
}

group = "com.sdercolin.utaformatix"

repositories {
mavenCentral()
}

kotlin {
js(IR) {
binaries.library()
browser()
generateTypeScriptDefinitions()
useEsModules()
dependencies {
implementation("com.sdercolin.utaformatix:utaformatix-data:1.0.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-js:1.6.4")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
implementation(npm("jszip", "3.5.0"))
implementation(npm("encoding-japanese", "1.0.30"))
implementation(npm("uuid", "8.3.2"))
implementation(npm("midi-file", "1.2.4"))
implementation(npm("js-yaml", "4.1.0"))
implementation(
npm("@sevenc-nanashi/valuetree-ts", "npm:@jsr/[email protected]"),
)
}
}
}
218 changes: 218 additions & 0 deletions core/src/main/kotlin/Library.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
@file:OptIn(DelicateCoroutinesApi::class, ExperimentalJsExport::class, ExperimentalSerializationApi::class)

import com.sdercolin.utaformatix.data.Document
import core.io.UfData
import core.model.ConversionParams
import core.model.ExportResult
import core.model.FeatureConfig
import core.model.Format
import core.model.ImportParams
import core.model.JapaneseLyricsType
import core.model.ProjectContainer
import core.process.lyrics.japanese.analyseJapaneseLyricsTypeForProject
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.promise
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import org.w3c.files.File
import kotlin.js.Promise
import core.process.lyrics.japanese.convertJapaneseLyrics as convertJapaneseLyricsBase

@JsExport
fun parseVsqx(file: File, params: ImportParams): Promise<ProjectContainer> = parse(listOf(file), params, Format.Vsqx)

@JsExport
fun parseVpr(file: File, params: ImportParams): Promise<ProjectContainer> = parse(listOf(file), params, Format.Vpr)

@JsExport
fun parseUst(
files: Array<File>,
params: ImportParams,
): Promise<ProjectContainer> = parse(files.toList(), params, Format.Ust)

@JsExport
fun parseUstx(file: File, params: ImportParams): Promise<ProjectContainer> = parse(listOf(file), params, Format.Ustx)

@JsExport
fun parseCcs(file: File, params: ImportParams): Promise<ProjectContainer> = parse(listOf(file), params, Format.Ccs)

@JsExport
fun parseSvp(file: File, params: ImportParams): Promise<ProjectContainer> = parse(listOf(file), params, Format.Svp)

@JsExport
fun parseS5p(file: File, params: ImportParams): Promise<ProjectContainer> = parse(listOf(file), params, Format.S5p)

@JsExport
fun parseMusicXml(file: File, params: ImportParams): Promise<ProjectContainer> =
parse(listOf(file), params, Format.MusicXml)

@JsExport
fun parseDv(file: File, params: ImportParams): Promise<ProjectContainer> = parse(listOf(file), params, Format.Dv)

@JsExport
fun parseVsq(file: File, params: ImportParams): Promise<ProjectContainer> = parse(listOf(file), params, Format.Vsq)

@JsExport
fun parseVocaloidMid(file: File, params: ImportParams): Promise<ProjectContainer> =
parse(listOf(file), params, Format.VocaloidMid)

@JsExport
fun parseStandardMid(file: File, params: ImportParams): Promise<ProjectContainer> =
parse(listOf(file), params, Format.StandardMid)

@JsExport
fun parsePpsf(file: File, params: ImportParams): Promise<ProjectContainer> = parse(listOf(file), params, Format.Ppsf)

@JsExport
fun parseTssln(file: File, params: ImportParams): Promise<ProjectContainer> = parse(listOf(file), params, Format.Tssln)

@JsExport
fun parseUfData(file: File, params: ImportParams): Promise<ProjectContainer> =
parse(listOf(file), params, Format.UfData)

private fun parse(files: List<File>, params: ImportParams, format: Format): Promise<ProjectContainer> =
GlobalScope.promise {
val project = format.parser(files, params)
ProjectContainer(project)
}

@JsExport
fun generateVsqx(project: ProjectContainer, params: ConversionParams): Promise<ExportResult> =
generate(project, params, Format.Vsqx)

@JsExport
fun generateVpr(project: ProjectContainer, params: ConversionParams): Promise<ExportResult> =
generate(project, params, Format.Vpr)

@JsExport
fun generateUstZip(project: ProjectContainer, params: ConversionParams): Promise<ExportResult> =
generate(project, params, Format.Ust)

@JsExport
fun generateUstx(project: ProjectContainer, params: ConversionParams): Promise<ExportResult> =
generate(project, params, Format.Ustx)

@JsExport
fun generateCcs(project: ProjectContainer, params: ConversionParams): Promise<ExportResult> =
generate(project, params, Format.Ccs)

@JsExport
fun generateSvp(project: ProjectContainer, params: ConversionParams): Promise<ExportResult> =
generate(project, params, Format.Svp)

@JsExport
fun generateS5p(project: ProjectContainer, params: ConversionParams): Promise<ExportResult> =
generate(project, params, Format.S5p)

@JsExport
fun generateMusicXmlZip(project: ProjectContainer, params: ConversionParams): Promise<ExportResult> =
generate(project, params, Format.MusicXml)

@JsExport
fun generateDv(project: ProjectContainer, params: ConversionParams): Promise<ExportResult> =
generate(project, params, Format.Dv)

@JsExport
fun generateVsq(project: ProjectContainer, params: ConversionParams): Promise<ExportResult> =
generate(project, params, Format.Vsq)

@JsExport
fun generateVocaloidMid(project: ProjectContainer, params: ConversionParams): Promise<ExportResult> =
generate(project, params, Format.VocaloidMid)

@JsExport
fun generateStandardMid(project: ProjectContainer, params: ConversionParams): Promise<ExportResult> =
generate(project, params, Format.StandardMid)

@JsExport
fun generateTssln(project: ProjectContainer, params: ConversionParams): Promise<ExportResult> =
generate(project, params, Format.Tssln)

@JsExport
fun generateUfData(project: ProjectContainer, params: ConversionParams): Promise<ExportResult> =
generate(project, params, Format.UfData)

private fun generate(project: ProjectContainer, params: ConversionParams, format: Format): Promise<ExportResult> {
val features = mutableListOf<FeatureConfig>()
if (params.convertPitch) {
features.add(FeatureConfig.ConvertPitch)
}

return GlobalScope.promise {
format.generator(
project.project,
features,
)
}
}

@JsExport
fun projectToUfData(project: ProjectContainer): String {
return jsonSerializer.encodeToString(
Document.serializer(),
UfData.generateDocument(
project.project,
listOf(
FeatureConfig.ConvertPitch,
),
),
)
}

@JsExport
fun ufDataToProject(documentJson: String): ProjectContainer {
val document: Document = jsonSerializer.decodeFromString(documentJson)
return ProjectContainer(
UfData.parseDocument(
document,
listOf(),
ImportParams(),
),
)
}

@JsExport
fun convertJapaneseLyrics(
project: ProjectContainer,
fromType: JapaneseLyricsType,
targetType: JapaneseLyricsType,
convertVowelConnections: Boolean,
): ProjectContainer {
val baseProject = project.project
val newProject = core.model.Project(
format = Format.UfData,
inputFiles = listOf(),
name = baseProject.name,
tracks = baseProject.tracks,
timeSignatures = baseProject.timeSignatures,
tempos = baseProject.tempos,
measurePrefix = baseProject.measurePrefix,
importWarnings = baseProject.importWarnings,
japaneseLyricsType = fromType,
)
val converted = convertJapaneseLyricsBase(
newProject,
targetType,
if (convertVowelConnections) {
Format.Ust
} else {
Format.UfData
},
)
return ProjectContainer(converted)
}

@JsExport
fun analyzeJapaneseLyricsType(project: ProjectContainer): JapaneseLyricsType {
return analyseJapaneseLyricsTypeForProject(project.project)
}

@OptIn(ExperimentalSerializationApi::class)
val jsonSerializer = Json {
isLenient = true
ignoreUnknownKeys = true
encodeDefaults = true
explicitNulls = false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package core.exception

@OptIn(ExperimentalJsExport::class)
@JsExport
class CannotReadFileException : Throwable()
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
package exception
package core.exception

@OptIn(ExperimentalJsExport::class)
@JsExport
class EmptyProjectException : Throwable("This format could not take en empty project.")
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package exception
package core.exception

@OptIn(ExperimentalJsExport::class)
@JsExport
sealed class IllegalFileException(message: String) : Throwable(message) {
class UnknownVsqVersion : IllegalFileException("Cannot identify the version of the loaded vsqx file.")
class XmlRootNotFound : IllegalFileException("The root element is not found in the xml file.")
Expand All @@ -15,4 +17,6 @@ sealed class IllegalFileException(message: String) : Throwable(message) {
)

class IllegalMidiFile : IllegalFileException("Cannot parse this file as a MIDI file.")

class IllegalTsslnFile : IllegalFileException("Cannot parse this file as a tssln file.")
}
Loading

0 comments on commit 724bee6

Please sign in to comment.