commit 684cec7c6e821b411ea89ef7e50adc18485b26e8 Author: lqdev Date: Fri Nov 18 18:13:03 2022 +0100 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..758a9a3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# gradle + +.gradle/ +build/ +out/ +classes/ + +# eclipse + +*.launch + +# idea + +.idea/ +*.iml +*.ipr +*.iws + +# vscode + +.settings/ +.vscode/ +bin/ +.classpath +.project + +# macos + +*.DS_Store + +# fabric + +run/ + +# Rust + +target/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..6bb1b20 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# dawd³ + +dawd³ (dawd cubed) - Minecraft audio experiments. diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..49717f2 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,81 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + id("fabric-loom") + kotlin("jvm").version(System.getProperty("kotlin_version")) + id("fr.stardustenterprises.rust.wrapper") version "3.2.5" apply false + id("fr.stardustenterprises.rust.importer") version "3.2.5" +} + +base { archivesName.set(project.extra["archives_base_name"] as String) } +version = project.extra["mod_version"] as String +group = project.extra["maven_group"] as String + +repositories {} + +dependencies { + minecraft("com.mojang", "minecraft", project.extra["minecraft_version"] as String) + mappings("net.fabricmc", "yarn", project.extra["yarn_mappings"] as String, null, "v2") + modImplementation("net.fabricmc", "fabric-loader", project.extra["loader_version"] as String) + modImplementation("net.fabricmc.fabric-api", "fabric-api", project.extra["fabric_version"] as String) + modImplementation( + "net.fabricmc", + "fabric-language-kotlin", + project.extra["fabric_language_kotlin_version"] as String + ) + rust(project(":d3r")) +} + +subprojects { + group = "net.liquidev.d3r" + version = "0.1.0" +} + +rustImport { + baseDir.set("/d3r") + layout.set("flat") +} + +tasks { + val javaVersion = JavaVersion.toVersion((project.extra["java_version"] as String).toInt()) + + withType { + options.encoding = "UTF-8" + sourceCompatibility = javaVersion.toString() + targetCompatibility = javaVersion.toString() + options.release.set(javaVersion.toString().toInt()) + } + + withType { + kotlinOptions { + jvmTarget = javaVersion.toString() + } + } + + jar { + from("LICENSE") { rename { "${it}_${base.archivesName}" } } + } + + processResources { + filesMatching("fabric.mod.json") { + expand( + mutableMapOf( + "version" to project.extra["mod_version"] as String, + "fabricloader" to project.extra["loader_version"] as String, + "fabric_api" to project.extra["fabric_version"] as String, + "fabric_language_kotlin" to project.extra["fabric_language_kotlin_version"] as String, + "minecraft" to project.extra["minecraft_version"] as String, + "java" to project.extra["java_version"] as String + ) + ) + } + filesMatching("*.mixins.json") { expand(mutableMapOf("java" to project.extra["java_version"] as String)) } + } + + java { + toolchain { languageVersion.set(JavaLanguageVersion.of(javaVersion.toString())) } + sourceCompatibility = javaVersion + targetCompatibility = javaVersion + withSourcesJar() + } +} diff --git a/d3r/Cargo.lock b/d3r/Cargo.lock new file mode 100644 index 0000000..e3f902d --- /dev/null +++ b/d3r/Cargo.lock @@ -0,0 +1,1106 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" +dependencies = [ + "memchr", +] + +[[package]] +name = "alsa" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5915f52fe2cf65e83924d037b6c5290b7cee097c6b5c8700746e6168a343fd6b" +dependencies = [ + "alsa-sys", + "bitflags", + "libc", + "nix 0.23.1", +] + +[[package]] +name = "alsa-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base-x" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + +[[package]] +name = "bindgen" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a022e58a142a46fea340d68012b9201c094e93ec3d033a944a24f8fd4a4f09a" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "bumpalo" +version = "3.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" + +[[package]] +name = "bytes" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" + +[[package]] +name = "cc" +version = "1.0.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clang-sys" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "coreaudio-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11894b20ebfe1ff903cbdc52259693389eea03b94918a2def2c30c3bf227ad88" +dependencies = [ + "bitflags", + "coreaudio-sys", +] + +[[package]] +name = "coreaudio-sys" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a9444b94b8024feecc29e01a9706c69c1e26bfee480221c90764200cfd778fb" +dependencies = [ + "bindgen", +] + +[[package]] +name = "cpal" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e73413ddcb69c398125f5529714492e070c64c6a090ad5b01d8c082b320a0809" +dependencies = [ + "alsa", + "core-foundation-sys", + "coreaudio-rs", + "jni 0.19.0", + "js-sys", + "libc", + "mach", + "ndk 0.7.0", + "ndk-context", + "nix 0.25.0", + "oboe", + "once_cell", + "parking_lot", + "stdweb", + "thiserror", + "web-sys", + "windows", +] + +[[package]] +name = "cty" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" + +[[package]] +name = "d3r" +version = "0.1.0" +dependencies = [ + "bitvec", + "cpal", + "env_logger", + "jni 0.20.0", + "log", +] + +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "itoa" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "ndk" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys 0.3.0", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys 0.4.0", + "num_enum", + "raw-window-handle", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "ndk-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21d83ec9c63ec5bf950200a8e508bdad6659972187b625469f58ef8c08e29046" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "nix" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", + "memoffset", +] + +[[package]] +name = "nix" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb" +dependencies = [ + "autocfg", + "bitflags", + "cfg-if", + "libc", + "memoffset", + "pin-utils", +] + +[[package]] +name = "nom" +version = "7.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "oboe" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f63c358b4fa0fbcfefd7c8be5cfc39c08ce2389f5325687e7762a48d30a5c1" +dependencies = [ + "jni 0.19.0", + "ndk 0.6.0", + "ndk-context", + "num-derive", + "num-traits", + "oboe-sys", +] + +[[package]] +name = "oboe-sys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3370abb7372ed744232c12954d920d1a40f1c4686de9e79e800021ef492294bd" +dependencies = [ + "cc", +] + +[[package]] +name = "once_cell" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + +[[package]] +name = "proc-macro-crate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" +dependencies = [ + "once_cell", + "thiserror", + "toml", +] + +[[package]] +name = "proc-macro2" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "raw-window-handle" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed7e3d950b66e19e0c372f3fa3fbbcf85b1746b571f74e0c2af6042a5c93420a" +dependencies = [ + "cty", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" + +[[package]] +name = "serde_derive" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + +[[package]] +name = "shlex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_derive", + "syn", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "sha1", + "syn", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + +[[package]] +name = "syn" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + +[[package]] +name = "web-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647" +dependencies = [ + "windows_aarch64_msvc 0.37.0", + "windows_i686_gnu 0.37.0", + "windows_i686_msvc 0.37.0", + "windows_x86_64_gnu 0.37.0", + "windows_x86_64_msvc 0.37.0", +] + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.0", + "windows_i686_gnu 0.42.0", + "windows_i686_msvc 0.42.0", + "windows_x86_64_gnu 0.42.0", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" + +[[package]] +name = "windows_i686_gnu" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" + +[[package]] +name = "windows_i686_msvc" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] diff --git a/d3r/Cargo.toml b/d3r/Cargo.toml new file mode 100644 index 0000000..f1efdf0 --- /dev/null +++ b/d3r/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "d3r" +description = "dawd³ audio runtime" +version = "0.1.0" +edition = "2021" + +[lib] +name = "dawd3_d3r" +crate-type = ["cdylib"] + +[dependencies] +bitvec = "1.0.1" +cpal = "0.14.1" +env_logger = "0.9.3" +jni = "0.20.0" +log = "0.4.17" diff --git a/d3r/README.md b/d3r/README.md new file mode 100644 index 0000000..c866111 --- /dev/null +++ b/d3r/README.md @@ -0,0 +1,8 @@ +# d3r + +**d3r** is a low-level realtime sound output library for Java, developed as the audio backend of dawd³. +The Java sources can be found [here](../src/main/java/net/liquidev/d3r). + +d3r exposes the API of [CPAL] to Java through the use of JNI. + + [CPAL]: https://lib.rs/crates/cpal diff --git a/d3r/build.gradle.kts b/d3r/build.gradle.kts new file mode 100644 index 0000000..1e76c1d --- /dev/null +++ b/d3r/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { + id("fr.stardustenterprises.rust.wrapper") +} + +rust { + command.set("cargo") + cargoInstallTargets.set(true) + + release.set(true) + +// targets += target("x86_64-pc-windows-gnu", "dawd3_d3r.dll") + targets += target("x86_64-unknown-linux-gnu", "libdawd3_d3r.so") +} diff --git a/d3r/src/lib.rs b/d3r/src/lib.rs new file mode 100644 index 0000000..013f8c1 --- /dev/null +++ b/d3r/src/lib.rs @@ -0,0 +1,214 @@ +use std::cell::RefCell; +use std::fmt::Display; + +use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; +use cpal::{BufferSize, Device, Host, SampleRate, Stream, StreamConfig}; +use jni::objects::{JClass, JMethodID, JObject}; +use jni::signature::ReturnType; +use jni::sys::jvalue; +use jni::JNIEnv; +use log::{error, info, warn, LevelFilter}; + +use crate::registry::Registry; + +mod registry; + +struct GlobalState { + host: Option, + devices: Registry, + streams: Registry, +} + +thread_local! { + static STATE: RefCell = RefCell::new(GlobalState { + host: None, + devices: Registry::new(), + streams: Registry::new(), + }); +} + +fn with_global_state(f: impl FnOnce(&mut GlobalState) -> T) -> T { + STATE.with(|state| { + let mut state = state.borrow_mut(); + f(&mut state) + }) +} + +fn try_with_global_state(env: JNIEnv, f: impl FnOnce(&mut GlobalState) -> Result) -> T +where + T: Default, + E: Display, +{ + let result = with_global_state(|state| f(state)); + match result { + Ok(value) => value, + Err(error) => { + let _ = env.throw_new("net/liquidev/d3r/D3rException", error.to_string()); + T::default() + } + } +} + +#[no_mangle] +pub extern "system" fn Java_net_liquidev_d3r_D3r_initialize(_env: JNIEnv, _: JClass) { + env_logger::builder() + .filter(Some("dawd3_d3r"), LevelFilter::Trace) + .format_timestamp(None) + .init(); + info!("d3r initialized successfully") +} + +#[no_mangle] +pub extern "system" fn Java_net_liquidev_d3r_D3r_openDefaultHost(env: JNIEnv, _: JClass) { + try_with_global_state(env, |state| { + if state.host.is_some() { + Err("Audio host already open") + } else { + let host = cpal::default_host(); + info!("using host: {:?}", host.id()); + state.host = Some(host); + Ok(()) + } + }) +} + +#[no_mangle] +pub extern "system" fn Java_net_liquidev_d3r_D3r_openDefaultOutputDevice( + env: JNIEnv, + _: JClass, +) -> u32 { + try_with_global_state(env, |state| { + let Some(host) = &state.host else { return Err("Host is not open"); }; + let Some(device) = host.default_output_device() else { return Err("No default output device found"); }; + if let Ok(name) = device.name() { + info!("default output device opened successfully: {name}"); + } else { + warn!("default output device opened successfully, but could not obtain its name"); + } + Ok(state.devices.add(device)) + }) +} + +fn generate_audio( + output: &mut [f32], + config: &StreamConfig, + env: JNIEnv, + generator: JObject, + method: JMethodID, +) -> Result<(), String> { + let buffer = env + .call_method_unchecked( + generator, + method, + ReturnType::Array, + &[ + jvalue { + i: output.len() as i32, + }, + jvalue { + i: config.channels as i32, + }, + ], + ) + .map_err(|e| format!("error while calling into the audio generator: {e}"))?; + let buffer = buffer.l().expect("buffer must be an object"); + let len = env + .get_array_length(buffer.into_raw()) + .expect("buffer must be a float[]"); + if (len as usize) < output.len() { + return Err(format!( + "audio buffer length is too short (expected {}, but generator returned {len})", + output.len() + )); + } + env.get_float_array_region(buffer.into_raw(), 0, output) + .expect("buffer must be a float[]"); + + Ok(()) +} + +#[no_mangle] +pub extern "system" fn Java_net_liquidev_d3r_D3r_openOutputStream( + env: JNIEnv, + _: JClass, + output_device_id: u32, + sample_rate: u32, + channel_count: u16, + buffer_size: u32, + generator: JObject, +) -> u32 { + try_with_global_state(env, |state| { + let Some(device) = state.devices.get(output_device_id) else { return Err("Invalid output device ID".to_string()); }; + let config = StreamConfig { + channels: channel_count, + sample_rate: SampleRate(sample_rate), + buffer_size: if buffer_size == 0 { + BufferSize::Default + } else { + BufferSize::Fixed(buffer_size) + }, + }; + + let class = env.get_object_class(generator).map_err(|e| e.to_string())?; + let generate_method = env + .get_method_id(class, "getOutputBuffer", "(II)[F") + .map_err(|e| e.to_string())?; + + let generator_ref = env.new_global_ref(generator).map_err(|e| e.to_string())?; + let jvm = env.get_java_vm().map_err(|e| e.to_string())?; + let mut initialized = false; + let stream = device + .build_output_stream( + &config.clone(), + move |data: &mut [f32], _| { + if !initialized { + if let Err(error) = jvm.attach_current_thread_permanently() { + error!("cannot attach JVM to audio thread: {error}"); + // TODO: propagate the error? + return; + } + initialized = true; + } + let env = jvm + .get_env() + .expect("thread should be attached at this point"); + let generator = generator_ref.as_obj(); + if let Err(error) = + generate_audio(data, &config, env, generator, generate_method) + { + error!("{error}"); + } + }, + |error| { + error!("{error}"); // lol + }, + ) + .map_err(|e| e.to_string())?; + Ok(state.streams.add(stream)) + }) +} + +#[no_mangle] +pub extern "system" fn Java_net_liquidev_d3r_D3r_closeOutputStream( + env: JNIEnv, + _: JClass, + output_stream_id: u32, +) { + try_with_global_state(env, |state| { + let Some(stream) = state.devices.remove(output_stream_id) else { return Err("Invalid output stream ID"); }; + drop(stream); + Ok(()) + }); +} + +#[no_mangle] +pub extern "system" fn Java_net_liquidev_d3r_D3r_startPlayback( + env: JNIEnv, + _: JClass, + output_stream_id: u32, +) { + try_with_global_state(env, |state| { + let Some(stream) = state.streams.get(output_stream_id) else { return Err("Invalid output stream ID".to_string()); }; + stream.play().map_err(|e| e.to_string()) + }); +} diff --git a/d3r/src/registry.rs b/d3r/src/registry.rs new file mode 100644 index 0000000..6bebefc --- /dev/null +++ b/d3r/src/registry.rs @@ -0,0 +1,62 @@ +//! Registry that attaches names to objects. + +use std::mem::MaybeUninit; +use bitvec::vec::BitVec; + +pub struct Registry { + next_free: u32, + free_list: Vec, + valid: BitVec, + store: Vec>, +} + +impl Registry { + pub fn new() -> Self { + Self { + next_free: 0, + free_list: vec![], + valid: BitVec::new(), + store: vec![] + } + } + + pub fn add(&mut self, item: T) -> u32 { + if let Some(id) = self.free_list.pop() { + self.valid.set(id as usize, true); + self.store[id as usize].write(item); + id + } else { + let free = self.next_free; + self.next_free += 1; + self.valid.push(true); + self.store.push(MaybeUninit::new(item)); + free + } + } + + pub fn remove(&mut self, index: u32) -> Option { + if self.valid[index as usize] { + self.valid.set(index as usize, false); + let item = std::mem::replace(&mut self.store[index as usize], MaybeUninit::uninit()); + Some(unsafe { item.assume_init() }) + } else { + None + } + } + + pub fn get(&self, index: u32) -> Option<&T> { + if self.valid[index as usize] { + Some(unsafe { self.store[index as usize].assume_init_ref() }) + } else { + None + } + } + + pub fn get_mut(&mut self, index: u32) -> Option<&mut T> { + if self.valid[index as usize] { + Some(unsafe { self.store[index as usize].assume_init_mut() }) + } else { + None + } + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..ece606c --- /dev/null +++ b/gradle.properties @@ -0,0 +1,25 @@ +########################################################################## +# Standard Properties +kotlin.code.style = official +org.gradle.jvmargs = -Xmx1G +org.gradle.warning.mode = all +########################################################################## +# Standard Fabric Dependencies +# Check these on https://fabricmc.net/develop/ +minecraft_version = 1.19.2 +yarn_mappings = 1.19.2+build.28 +loader_version = 0.14.10 +# Fabric API +fabric_version = 0.66.0+1.19.2 +loom_version = 1.0-SNAPSHOT +java_version = 17 +########################################################################## +# Mod Properties +mod_version = 0.1.0 +maven_group = net.liquidev.dawd3 +archives_base_name = dawd3 +########################################################################## +# Kotlin Dependencies +systemProp.kotlin_version = 1.7.20 +fabric_language_kotlin_version = 1.8.5+kotlin.1.7.20 +########################################################################## diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..deedc7f Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..ff75c23 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..1b6c787 --- /dev/null +++ b/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..477c896 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega \ No newline at end of file diff --git a/proj/block/module_generic.ase b/proj/block/module_generic.ase new file mode 100644 index 0000000..69f032a Binary files /dev/null and b/proj/block/module_generic.ase differ diff --git a/proj/block/speaker_front.ase b/proj/block/speaker_front.ase new file mode 100644 index 0000000..a09f132 Binary files /dev/null and b/proj/block/speaker_front.ase differ diff --git a/proj/icon.ase b/proj/icon.ase new file mode 100644 index 0000000..8628181 Binary files /dev/null and b/proj/icon.ase differ diff --git a/proj/item/dawd3.ase b/proj/item/dawd3.ase new file mode 100644 index 0000000..22cf9d8 Binary files /dev/null and b/proj/item/dawd3.ase differ diff --git a/proj/item/patch_cable.ase b/proj/item/patch_cable.ase new file mode 100644 index 0000000..de10a2d Binary files /dev/null and b/proj/item/patch_cable.ase differ diff --git a/proj/tilde.ase b/proj/tilde.ase new file mode 100644 index 0000000..39cecf6 Binary files /dev/null and b/proj/tilde.ase differ diff --git a/proj/tilde.png b/proj/tilde.png new file mode 100644 index 0000000..49f35cd Binary files /dev/null and b/proj/tilde.png differ diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..ea27eaa --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,13 @@ +pluginManagement { + repositories { + maven("https://maven.fabricmc.net") { name = "Fabric" } + mavenCentral() + gradlePluginPortal() + } + plugins { + id("fabric-loom").version(settings.extra["loom_version"] as String) + kotlin("jvm").version(System.getProperty("kotlin_version")) + } +} + +include("d3r") \ No newline at end of file diff --git a/src/main/java/net/liquidev/d3r/AudioOutputStream.java b/src/main/java/net/liquidev/d3r/AudioOutputStream.java new file mode 100644 index 0000000..2dfe1ee --- /dev/null +++ b/src/main/java/net/liquidev/d3r/AudioOutputStream.java @@ -0,0 +1,7 @@ +package net.liquidev.d3r; + +public interface AudioOutputStream { + float[] getOutputBuffer(int sampleCount, int channels); + + void error(String message); +} diff --git a/src/main/java/net/liquidev/d3r/D3r.java b/src/main/java/net/liquidev/d3r/D3r.java new file mode 100644 index 0000000..050fb87 --- /dev/null +++ b/src/main/java/net/liquidev/d3r/D3r.java @@ -0,0 +1,88 @@ +package net.liquidev.d3r; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; + +public class D3r { + private static final Logger LOGGER = LoggerFactory.getLogger("dawd³/d3r"); + private static Path tempDir = null; + + public static void load() throws D3rException, IOException { + LOGGER.info("unpacking native library"); + + var dynlibName = System.mapLibraryName("dawd3_d3r"); + var dynlibClassPath = "/d3r/" + dynlibName; + LOGGER.debug("class path: " + dynlibClassPath); + try (var resourceStream = D3r.class.getResourceAsStream(dynlibClassPath)) { + if (resourceStream == null) { + throw new D3rException("dawd3 cannot find an appropriate version of the d3r audio library for your system"); + } + + var bytes = resourceStream.readAllBytes(); + + tempDir = Files.createTempDirectory("d3r_native_libs"); + var libFile = tempDir.resolve(dynlibName); + + if (Files.deleteIfExists(libFile)) { + LOGGER.debug("deleted old unpacked library file"); + } + try (var outputStream = Files.newOutputStream(libFile)) { + outputStream.write(bytes); + outputStream.flush(); + } + + LOGGER.info("loading library"); + System.load(libFile.toString()); + } + + LOGGER.info("initializing"); + initialize(); + LOGGER.info("loaded successfully"); + } + + public static void unload() { + if (tempDir != null) { + LOGGER.info("removing native library directory"); + try (var walker = Files.walk(tempDir)) { + walker + .sorted(Comparator.reverseOrder()) + .forEach(p -> { + try { + Files.delete(p); + } catch (IOException e) { + e.printStackTrace(); + } + }); + } catch (IOException e) { + e.printStackTrace(); + } + } else { + LOGGER.warn("unload() called twice or without calling load() first"); + } + } + + private static native void initialize(); + + // Host + + public static native void openDefaultHost(); + + // Output device + + public static native int openDefaultOutputDevice(); + + public static native void closeOutputDevice(int outputDeviceId); + + // Output stream + + public static native int openOutputStream(int outputDeviceId, int sampleRate, short channelCount, int bufferSize, AudioOutputStream generator); + + public static native void closeOutputStream(int outputStreamId); + + public static native void startPlayback(int outputStreamId); +} diff --git a/src/main/java/net/liquidev/d3r/D3rException.java b/src/main/java/net/liquidev/d3r/D3rException.java new file mode 100644 index 0000000..f8e60da --- /dev/null +++ b/src/main/java/net/liquidev/d3r/D3rException.java @@ -0,0 +1,7 @@ +package net.liquidev.d3r; + +public class D3rException extends Exception { + D3rException(String what) { + super(what); + } +} diff --git a/src/main/kotlin/net/liquidev/dawd3/D3Registry.kt b/src/main/kotlin/net/liquidev/dawd3/D3Registry.kt new file mode 100644 index 0000000..7f568c7 --- /dev/null +++ b/src/main/kotlin/net/liquidev/dawd3/D3Registry.kt @@ -0,0 +1,23 @@ +package net.liquidev.dawd3 + +import net.minecraft.util.Identifier + +abstract class D3Registry { + abstract fun doRegister(identifier: Identifier, item: T) + + var registered = arrayListOf>() + + fun add(id: String, item: T): Registered { + val entry = Registered(Identifier(Mod.id, id), item) + registered.add(entry) + return entry + } + + fun registerAll() { + registered.forEach { reg -> + doRegister(reg.identifier, reg.item) + } + } + + data class Registered(val identifier: Identifier, val item: T) +} \ No newline at end of file diff --git a/src/main/kotlin/net/liquidev/dawd3/Mod.kt b/src/main/kotlin/net/liquidev/dawd3/Mod.kt new file mode 100644 index 0000000..ed95be5 --- /dev/null +++ b/src/main/kotlin/net/liquidev/dawd3/Mod.kt @@ -0,0 +1,36 @@ +package net.liquidev.dawd3 + +import net.fabricmc.api.ClientModInitializer +import net.fabricmc.api.ModInitializer +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents +import net.liquidev.d3r.D3r +import net.liquidev.dawd3.block.Blocks +import net.liquidev.dawd3.item.Items +import net.liquidev.dawd3.sound.Sound +import org.slf4j.LoggerFactory + +@Suppress("UNUSED") +object Mod : ModInitializer, ClientModInitializer { + const val id = "dawd3" + + private val logger = LoggerFactory.getLogger("dawd³") + + override fun onInitialize() { + logger.info("hello, sound traveler! welcome to the dawd³ experience") + + Blocks.blockRegistry.registerAll() + Items.registry.registerAll() + } + + override fun onInitializeClient() { + logger.info("booting up sound engine") + D3r.load() + Sound.forceInitializationNow() + + ClientLifecycleEvents.CLIENT_STOPPING.register { + logger.info("shutting down sound engine") + Sound.deinitialize() + D3r.unload() + } + } +} diff --git a/src/main/kotlin/net/liquidev/dawd3/block/Blocks.kt b/src/main/kotlin/net/liquidev/dawd3/block/Blocks.kt new file mode 100644 index 0000000..73bd3e5 --- /dev/null +++ b/src/main/kotlin/net/liquidev/dawd3/block/Blocks.kt @@ -0,0 +1,38 @@ +package net.liquidev.dawd3.block + +import net.fabricmc.fabric.api.item.v1.FabricItemSettings +import net.fabricmc.fabric.api.`object`.builder.v1.block.FabricBlockSettings +import net.fabricmc.fabric.api.`object`.builder.v1.block.entity.FabricBlockEntityTypeBuilder +import net.liquidev.dawd3.D3Registry +import net.liquidev.dawd3.Mod +import net.liquidev.dawd3.item.Items +import net.minecraft.block.Block +import net.minecraft.block.Material +import net.minecraft.item.BlockItem +import net.minecraft.util.Identifier +import net.minecraft.util.registry.Registry + +object Blocks { + var blockRegistry = object : D3Registry() { + override fun doRegister(identifier: Identifier, item: Block) { + Registry.register(Registry.BLOCK, identifier, item) + } + } + + val speaker = add("speaker", SpeakerBlock(moduleBlockSettings())) + val speakerEntity = Registry.register( + Registry.BLOCK_ENTITY_TYPE, + Identifier(Mod.id, "speaker"), + FabricBlockEntityTypeBuilder.create(::SpeakerBlockEntity, speaker.item).build(), + ) + + private fun moduleBlockSettings() = FabricBlockSettings + .of(Material.METAL) + .hardness(5.0f) + .resistance(6.0f) + + private fun add(name: String, block: Block): D3Registry.Registered { + Items.addItem(name, BlockItem(block, FabricItemSettings().group(Items.creativeTab))) + return blockRegistry.add(name, block) + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/liquidev/dawd3/block/SpeakerBlock.kt b/src/main/kotlin/net/liquidev/dawd3/block/SpeakerBlock.kt new file mode 100644 index 0000000..7a02619 --- /dev/null +++ b/src/main/kotlin/net/liquidev/dawd3/block/SpeakerBlock.kt @@ -0,0 +1,46 @@ +package net.liquidev.dawd3.block + +import net.minecraft.block.* +import net.minecraft.block.entity.BlockEntity +import net.minecraft.entity.LivingEntity +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.item.ItemPlacementContext +import net.minecraft.item.ItemStack +import net.minecraft.state.StateManager +import net.minecraft.state.property.Properties +import net.minecraft.util.math.BlockPos +import net.minecraft.world.World + +class SpeakerBlock(settings: Settings) : BlockWithEntity(settings), BlockEntityProvider { + override fun appendProperties(builder: StateManager.Builder) { + builder.add(Properties.HORIZONTAL_FACING) + } + + override fun getPlacementState(ctx: ItemPlacementContext): BlockState { + return defaultState.with(Properties.HORIZONTAL_FACING, ctx.playerFacing.opposite) + } + + override fun createBlockEntity(pos: BlockPos, state: BlockState): BlockEntity { + return SpeakerBlockEntity(pos, state) + } + + override fun getRenderType(state: BlockState): BlockRenderType { + return BlockRenderType.MODEL + } + + override fun onPlaced( + world: World, + pos: BlockPos, + state: BlockState, + placer: LivingEntity?, + itemStack: ItemStack, + ) { + println("Speaker placed") + } + + override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity) { + println("Speaker broken, deinitializing block entity") + val blockEntity = world.getBlockEntity(pos) as SpeakerBlockEntity + blockEntity.deinit() + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/liquidev/dawd3/block/SpeakerBlockEntity.kt b/src/main/kotlin/net/liquidev/dawd3/block/SpeakerBlockEntity.kt new file mode 100644 index 0000000..19e1d7c --- /dev/null +++ b/src/main/kotlin/net/liquidev/dawd3/block/SpeakerBlockEntity.kt @@ -0,0 +1,20 @@ +package net.liquidev.dawd3.block + +import net.minecraft.block.BlockState +import net.minecraft.block.entity.BlockEntity +import net.minecraft.util.math.BlockPos + +class SpeakerBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Blocks.speakerEntity, pos, state) { + init { + println("Speaker block entity created") + + } + + fun deinit() { + println("Speaker block entity deinitialized") + } + + private fun finalize() { + deinit() + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/liquidev/dawd3/item/Items.kt b/src/main/kotlin/net/liquidev/dawd3/item/Items.kt new file mode 100644 index 0000000..2b1b18e --- /dev/null +++ b/src/main/kotlin/net/liquidev/dawd3/item/Items.kt @@ -0,0 +1,52 @@ +package net.liquidev.dawd3.item + +import net.fabricmc.fabric.api.client.itemgroup.FabricItemGroupBuilder +import net.fabricmc.fabric.api.item.v1.FabricItemSettings +import net.liquidev.dawd3.D3Registry +import net.liquidev.dawd3.Mod +import net.minecraft.item.Item +import net.minecraft.item.ItemGroup +import net.minecraft.util.Identifier +import net.minecraft.util.registry.Registry + +object Items { + var registry = object : D3Registry() { + override fun doRegister(identifier: Identifier, item: RegisteredItem) { + Registry.register(Registry.ITEM, identifier, item.item) + } + } + + // Creative tab + val creativeTab: ItemGroup = FabricItemGroupBuilder.create(Identifier(Mod.id, "main")) + .icon { dawd3.item.item.defaultStack } + .appendItems { list -> + registry.registered.forEach { reg -> + val item = reg.item + if (item.showInCreativeTab) { + list.add(reg.item.item.defaultStack) + } + } + } + .build() + + // Icon for creative tab + val dawd3 = registry.add("dawd3", RegisteredItem(Item(FabricItemSettings())).hiddenFromCreativeTab()) + + // Tools + val patchCable = addItem("patch_cable", PatchCable(FabricItemSettings().group(ItemGroup.REDSTONE))) + + fun addItem(name: String, item: Item) { + registry.add(name, RegisteredItem(item)) + } + + data class RegisteredItem( + val item: Item, + var showInCreativeTab: Boolean = true, + ) { + fun hiddenFromCreativeTab(): RegisteredItem { + this.showInCreativeTab = false + return this + } + } +} + diff --git a/src/main/kotlin/net/liquidev/dawd3/item/PatchCable.kt b/src/main/kotlin/net/liquidev/dawd3/item/PatchCable.kt new file mode 100644 index 0000000..54fd88a --- /dev/null +++ b/src/main/kotlin/net/liquidev/dawd3/item/PatchCable.kt @@ -0,0 +1,16 @@ +package net.liquidev.dawd3.item + +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.item.Item +import net.minecraft.item.ItemStack +import net.minecraft.sound.SoundEvents +import net.minecraft.util.Hand +import net.minecraft.util.TypedActionResult +import net.minecraft.world.World + +class PatchCable(settings: Settings) : Item(settings) { + override fun use(world: World, user: PlayerEntity, hand: Hand): TypedActionResult { + user.playSound(SoundEvents.BLOCK_METAL_PLACE, 1.0f, 1.0f) + return TypedActionResult.success(user.getStackInHand(hand)) + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/liquidev/dawd3/mixin/SoundManagerAccessor.kt b/src/main/kotlin/net/liquidev/dawd3/mixin/SoundManagerAccessor.kt new file mode 100644 index 0000000..812c20e --- /dev/null +++ b/src/main/kotlin/net/liquidev/dawd3/mixin/SoundManagerAccessor.kt @@ -0,0 +1,12 @@ +package net.liquidev.dawd3.mixin + +import net.minecraft.client.sound.SoundManager +import net.minecraft.client.sound.SoundSystem +import org.spongepowered.asm.mixin.Mixin +import org.spongepowered.asm.mixin.gen.Accessor + +@Mixin(SoundManager::class) +interface SoundManagerAccessor { + @Accessor + fun getSoundSystem(): SoundSystem +} diff --git a/src/main/kotlin/net/liquidev/dawd3/mixin/SoundSystemAccessor.kt b/src/main/kotlin/net/liquidev/dawd3/mixin/SoundSystemAccessor.kt new file mode 100644 index 0000000..1b873cc --- /dev/null +++ b/src/main/kotlin/net/liquidev/dawd3/mixin/SoundSystemAccessor.kt @@ -0,0 +1,12 @@ +package net.liquidev.dawd3.mixin + +import net.minecraft.client.sound.Channel +import net.minecraft.client.sound.SoundSystem +import org.spongepowered.asm.mixin.Mixin +import org.spongepowered.asm.mixin.gen.Accessor + +@Mixin(SoundSystem::class) +interface SoundSystemAccessor { + @Accessor + fun getChannel(): Channel +} \ No newline at end of file diff --git a/src/main/kotlin/net/liquidev/dawd3/sound/AudioGenerator.kt b/src/main/kotlin/net/liquidev/dawd3/sound/AudioGenerator.kt new file mode 100644 index 0000000..5446ce1 --- /dev/null +++ b/src/main/kotlin/net/liquidev/dawd3/sound/AudioGenerator.kt @@ -0,0 +1,27 @@ +package net.liquidev.dawd3.sound + +import net.liquidev.d3r.AudioOutputStream + +abstract class AudioGenerator : AudioOutputStream { + private var outputBuffer: FloatArray? = null + + private fun allocateOutputBuffer(sampleCount: Int): FloatArray { + val inOutputBuffer = outputBuffer + if (inOutputBuffer == null || inOutputBuffer.size < sampleCount) { + outputBuffer = FloatArray(sampleCount) + } + return outputBuffer!! + } + + abstract fun generate(output: FloatArray, sampleCount: Int, channels: Int) + + override fun getOutputBuffer(sampleCount: Int, channels: Int): FloatArray { + val outputBuffer = allocateOutputBuffer(sampleCount) + generate(outputBuffer, sampleCount, channels) + return outputBuffer + } + + override fun error(message: String) { + println("Error reported by audio stream: $message") + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/liquidev/dawd3/sound/SineOscGenerator.kt b/src/main/kotlin/net/liquidev/dawd3/sound/SineOscGenerator.kt new file mode 100644 index 0000000..f6d5240 --- /dev/null +++ b/src/main/kotlin/net/liquidev/dawd3/sound/SineOscGenerator.kt @@ -0,0 +1,21 @@ +package net.liquidev.dawd3.sound + +import kotlin.math.sin + +class SineOscGenerator(frequency: Float, private val amplitude: Float) : AudioGenerator() { + private val phaseStep = (1.0f / Sound.sampleRate.toFloat()) * frequency + private var phase = 0.0f + + private fun synthesize(): Float { + phase += phaseStep + phase %= 1.0f + return sin(phase * 2.0f * kotlin.math.PI.toFloat()) * amplitude + } + + override fun generate(output: FloatArray, sampleCount: Int, channels: Int) { + for (i in 0 until sampleCount) { + val sample = synthesize() + output[i] = sample + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/liquidev/dawd3/sound/Sound.kt b/src/main/kotlin/net/liquidev/dawd3/sound/Sound.kt new file mode 100644 index 0000000..18ef4cc --- /dev/null +++ b/src/main/kotlin/net/liquidev/dawd3/sound/Sound.kt @@ -0,0 +1,32 @@ +package net.liquidev.dawd3.sound + +import net.liquidev.d3r.D3r + +/** Common sound utilities. */ +object Sound { + const val sampleRate = 48000 + private const val bufferSize = 256 + + val outputDeviceId: Int + val outputStreamId: Int + + init { + D3r.openDefaultHost() + outputDeviceId = D3r.openDefaultOutputDevice() + outputStreamId = D3r.openOutputStream( + outputDeviceId, + sampleRate, + 1, + bufferSize, + SineOscGenerator(frequency = 440.0f, amplitude = 0.5f) + ) + D3r.startPlayback(outputStreamId) + } + + fun forceInitializationNow() {} + + fun deinitialize() { + D3r.closeOutputStream(outputStreamId) + D3r.closeOutputDevice(outputDeviceId) + } +} \ No newline at end of file diff --git a/src/main/resources/assets/dawd3/blockstates/speaker.json b/src/main/resources/assets/dawd3/blockstates/speaker.json new file mode 100644 index 0000000..0016ef0 --- /dev/null +++ b/src/main/resources/assets/dawd3/blockstates/speaker.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=north": { "model": "dawd3:block/speaker" }, + "facing=east": { "model": "dawd3:block/speaker", "y": 90 }, + "facing=south": { "model": "dawd3:block/speaker", "y": 180 }, + "facing=west": { "model": "dawd3:block/speaker", "y": 270 } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/dawd3/icon.png b/src/main/resources/assets/dawd3/icon.png new file mode 100644 index 0000000..326ce94 Binary files /dev/null and b/src/main/resources/assets/dawd3/icon.png differ diff --git a/src/main/resources/assets/dawd3/lang/en_us.json b/src/main/resources/assets/dawd3/lang/en_us.json new file mode 100644 index 0000000..00510bb --- /dev/null +++ b/src/main/resources/assets/dawd3/lang/en_us.json @@ -0,0 +1,3 @@ +{ + "item.dawd3.patch_cable": "Patch Cable" +} \ No newline at end of file diff --git a/src/main/resources/assets/dawd3/models/block/module_with_front.json b/src/main/resources/assets/dawd3/models/block/module_with_front.json new file mode 100644 index 0000000..3636bf9 --- /dev/null +++ b/src/main/resources/assets/dawd3/models/block/module_with_front.json @@ -0,0 +1,21 @@ +{ + "parent": "block/block", + "textures": { + "side": "dawd3:block/module_side", + "particle": "#side" + }, + "elements": [ + { + "from": [0, 0, 0], + "to": [16, 16, 16], + "faces": { + "down": { "texture": "#side", "cullface": "down" }, + "up": { "texture": "#side", "cullface": "up" }, + "north": { "texture": "#front", "cullface": "north" }, + "east": { "texture": "#side", "cullface": "east" }, + "south": { "texture": "#side", "cullface": "south" }, + "west": { "texture": "#side", "cullface": "west" } + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/dawd3/models/block/speaker.json b/src/main/resources/assets/dawd3/models/block/speaker.json new file mode 100644 index 0000000..7a6ef38 --- /dev/null +++ b/src/main/resources/assets/dawd3/models/block/speaker.json @@ -0,0 +1,6 @@ +{ + "parent": "dawd3:block/module_with_front", + "textures": { + "front": "dawd3:block/speaker_front" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/dawd3/models/item/dawd3.json b/src/main/resources/assets/dawd3/models/item/dawd3.json new file mode 100644 index 0000000..254b4e4 --- /dev/null +++ b/src/main/resources/assets/dawd3/models/item/dawd3.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "dawd3:item/dawd3" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/dawd3/models/item/patch_cable.json b/src/main/resources/assets/dawd3/models/item/patch_cable.json new file mode 100644 index 0000000..38bcc5a --- /dev/null +++ b/src/main/resources/assets/dawd3/models/item/patch_cable.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "dawd3:item/patch_cable" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/dawd3/models/item/speaker.json b/src/main/resources/assets/dawd3/models/item/speaker.json new file mode 100644 index 0000000..5bbb1c4 --- /dev/null +++ b/src/main/resources/assets/dawd3/models/item/speaker.json @@ -0,0 +1,3 @@ +{ + "parent": "dawd3:block/speaker" +} \ No newline at end of file diff --git a/src/main/resources/assets/dawd3/textures/block/module_side.png b/src/main/resources/assets/dawd3/textures/block/module_side.png new file mode 100644 index 0000000..f47fc1d Binary files /dev/null and b/src/main/resources/assets/dawd3/textures/block/module_side.png differ diff --git a/src/main/resources/assets/dawd3/textures/block/speaker_front.png b/src/main/resources/assets/dawd3/textures/block/speaker_front.png new file mode 100644 index 0000000..38806f8 Binary files /dev/null and b/src/main/resources/assets/dawd3/textures/block/speaker_front.png differ diff --git a/src/main/resources/assets/dawd3/textures/item/dawd3.png b/src/main/resources/assets/dawd3/textures/item/dawd3.png new file mode 100644 index 0000000..f6a5b91 Binary files /dev/null and b/src/main/resources/assets/dawd3/textures/item/dawd3.png differ diff --git a/src/main/resources/assets/dawd3/textures/item/patch_cable.png b/src/main/resources/assets/dawd3/textures/item/patch_cable.png new file mode 100644 index 0000000..0eec2b1 Binary files /dev/null and b/src/main/resources/assets/dawd3/textures/item/patch_cable.png differ diff --git a/src/main/resources/dawd3.mixins.json b/src/main/resources/dawd3.mixins.json new file mode 100644 index 0000000..42a5c47 --- /dev/null +++ b/src/main/resources/dawd3.mixins.json @@ -0,0 +1,12 @@ +{ + "required": true, + "package": "net.liquidev.dawd3.mixin", + "compatibilityLevel": "JAVA_${java}", + "injectors": { + "defaultRequire": 1 + }, + "mixins": [ + "SoundManagerAccessor", + "SoundSystemAccessor" + ] +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..7ef8c28 --- /dev/null +++ b/src/main/resources/fabric.mod.json @@ -0,0 +1,42 @@ +{ + "schemaVersion": 1, + "id": "dawd3", + "version": "${version}", + "name": "dawd³", + "description": "music making experiments", + "authors": [ + "liquidev" + ], + "contact": { + "homepage": "https://liquidev.net/", + "issues": "https://liquidev.net/", + "sources": "https://liquidev.net/" + }, + "license": "MIT", + "icon": "assets/dawd3/icon.png", + "environment": "*", + "entrypoints": { + "main": [ + { + "adapter": "kotlin", + "value": "net.liquidev.dawd3.Mod" + } + ], + "client": [ + { + "adapter": "kotlin", + "value": "net.liquidev.dawd3.Mod" + } + ] + }, + "mixins": [ + "dawd3.mixins.json" + ], + "depends": { + "fabricloader": ">=${fabricloader}", + "fabric-api": ">=${fabric_api}", + "fabric-language-kotlin": ">=${fabric_language_kotlin}", + "minecraft": ">=${minecraft}", + "java": ">=${java}" + } +}