mirror of
https://github.com/exoticorn/microw8.git
synced 2026-01-20 19:26:43 +01:00
Compare commits
35 Commits
37f12f5a2c
...
v0.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
| e7a00dd9c6 | |||
| a02243d98c | |||
| 599873890a | |||
| 8e9bb002bc | |||
| b2b990333e | |||
| d1556f7be8 | |||
| 9f548cd6f0 | |||
| 7cea4eebd3 | |||
| 3f67e92c5c | |||
| a2714f25e4 | |||
| 7e203d93e6 | |||
| e44c87d1f6 | |||
| 614b7cf358 | |||
| c42a484adb | |||
| 3a5f2bf865 | |||
| 2dee1b30a4 | |||
| 42f7887ab2 | |||
| 4c82f4ad02 | |||
| 4dd8c3b029 | |||
| 2bf8938183 | |||
| 491bf88ade | |||
| e05701300c | |||
| df0c169d54 | |||
| 61941bceeb | |||
| 8fa64519e4 | |||
| 7a52ce4e4c | |||
| 6f20d303c8 | |||
| a5edeb21d8 | |||
| 2839fe5be4 | |||
| 893158e136 | |||
| 7c5f43f152 | |||
| f32b0762b0 | |||
| 9ebb6b6d34 | |||
| 8a10b99eeb | |||
| 6c064a1dd8 |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install -y libxkbcommon-dev
|
||||
run: sudo apt-get install -y libxkbcommon-dev libasound2-dev
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
431
Cargo.lock
generated
431
Cargo.lock
generated
@@ -35,6 +35,28 @@ 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",
|
||||
]
|
||||
|
||||
[[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 = "ansi_term"
|
||||
version = "0.12.1"
|
||||
@@ -83,9 +105,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
@@ -124,7 +146,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2da379dbebc0b76ef63ca68d8fc6e71c0f13e59432e0987e508c1820e6ab5239"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cexpr",
|
||||
"cexpr 0.4.0",
|
||||
"clang-sys",
|
||||
"clap",
|
||||
"env_logger 0.8.4",
|
||||
@@ -136,10 +158,29 @@ dependencies = [
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
"shlex 0.1.1",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.59.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cexpr 0.6.0",
|
||||
"clang-sys",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"peeking_take_while",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@@ -223,7 +264,16 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27"
|
||||
dependencies = [
|
||||
"nom",
|
||||
"nom 5.1.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||
dependencies = [
|
||||
"nom 7.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -314,6 +364,56 @@ dependencies = [
|
||||
"tiny-keccak",
|
||||
]
|
||||
|
||||
[[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.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dff444d80630d7073077d38d40b4501fd518bd2b922c2a55edcc8b0f7be57e6"
|
||||
dependencies = [
|
||||
"bindgen 0.59.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpal"
|
||||
version = "0.13.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74117836a5124f3629e4b474eed03e479abaf98988b4bb317e29f08cfe0e4116"
|
||||
dependencies = [
|
||||
"alsa",
|
||||
"core-foundation-sys",
|
||||
"coreaudio-rs",
|
||||
"jni",
|
||||
"js-sys",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"mach",
|
||||
"ndk",
|
||||
"ndk-glue",
|
||||
"nix",
|
||||
"oboe",
|
||||
"parking_lot",
|
||||
"stdweb",
|
||||
"thiserror",
|
||||
"web-sys",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpp_demangle"
|
||||
version = "0.3.5"
|
||||
@@ -334,18 +434,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-bforest"
|
||||
version = "0.81.1"
|
||||
version = "0.82.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32f027f29ace03752bb83c112eb4f53744bc4baadf19955e67fcde1d71d2f39d"
|
||||
checksum = "38faa2a16616c8e78a18d37b4726b98bfd2de192f2fdc8a39ddf568a408a0f75"
|
||||
dependencies = [
|
||||
"cranelift-entity",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen"
|
||||
version = "0.81.1"
|
||||
version = "0.82.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c10af69cbf4e228c11bdc26d8f9d5276773909152a769649a160571b282f92f"
|
||||
checksum = "26f192472a3ba23860afd07d2b0217dc628f21fcc72617aa1336d98e1671f33b"
|
||||
dependencies = [
|
||||
"cranelift-bforest",
|
||||
"cranelift-codegen-meta",
|
||||
@@ -360,33 +460,33 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-meta"
|
||||
version = "0.81.1"
|
||||
version = "0.82.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290ac14d2cef43cbf1b53ad5c1b34216c9e32e00fa9b6ac57b5e5a2064369e02"
|
||||
checksum = "0f32ddb89e9b89d3d9b36a5b7d7ea3261c98235a76ac95ba46826b8ec40b1a24"
|
||||
dependencies = [
|
||||
"cranelift-codegen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-shared"
|
||||
version = "0.81.1"
|
||||
version = "0.82.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "beb9142d134a03d01e3995e6d8dd3aecf16312261d0cb0c5dcd73d5be2528c1c"
|
||||
checksum = "01fd0d9f288cc1b42d9333b7a776b17e278fc888c28e6a0f09b5573d45a150bc"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-entity"
|
||||
version = "0.81.1"
|
||||
version = "0.82.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1268a50b7cbbfee8514d417fc031cedd9965b15fa9e5ed1d4bc16de86f76765e"
|
||||
checksum = "9e3bfe172b83167604601faf9dc60453e0d0a93415b57a9c4d1a7ae6849185cf"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-frontend"
|
||||
version = "0.81.1"
|
||||
version = "0.82.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97ac0d440469e19ab12183e31a9e41b4efd8a4ca5fbde2a10c78c7bb857cc2a4"
|
||||
checksum = "a006e3e32d80ce0e4ba7f1f9ddf66066d052a8c884a110b91d05404d6ce26dce"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"log",
|
||||
@@ -396,9 +496,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-native"
|
||||
version = "0.81.1"
|
||||
version = "0.82.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "794cd1a5694a01c68957f9cfdc5ac092cf8b4e9c2d1697c4a5100f90103e9e9e"
|
||||
checksum = "501241b0cdf903412ec9075385ac9f2b1eb18a89044d1538e97fab603231f70c"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"libc",
|
||||
@@ -407,9 +507,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-wasm"
|
||||
version = "0.81.1"
|
||||
version = "0.82.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2ddd4ca6963f6e94d00e8935986411953581ac893587ab1f0eb4f0b5a40ae65"
|
||||
checksum = "16d9e4211bbc3268042a96dd4de5bd979cda22434991d035f5f8eacba987fad2"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"cranelift-entity",
|
||||
@@ -417,7 +517,7 @@ dependencies = [
|
||||
"itertools",
|
||||
"log",
|
||||
"smallvec",
|
||||
"wasmparser 0.82.0",
|
||||
"wasmparser 0.83.0",
|
||||
"wasmtime-types",
|
||||
]
|
||||
|
||||
@@ -499,7 +599,7 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
|
||||
[[package]]
|
||||
name = "curlywas"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/exoticorn/curlywas.git?rev=557c3a84#557c3a842675a1ebd77e84021f9f5236d4fa5648"
|
||||
source = "git+https://github.com/exoticorn/curlywas.git?rev=0a0d90c#0a0d90c8013f1d7856a9b71a19d3d006300f31f9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ariadne",
|
||||
@@ -1060,6 +1160,15 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||
|
||||
[[package]]
|
||||
name = "ittapi-rs"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f712648a1ad72fbfb7adc2772c331e8d90f022f8cf30cbabefba2878dd3172b0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jni"
|
||||
version = "0.19.0"
|
||||
@@ -1148,6 +1257,16 @@ version = "0.0.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5284f00d480e1c39af34e72f8ad60b94f47007e3481cd3b731c1d67190ddc7b7"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.14"
|
||||
@@ -1178,6 +1297,15 @@ version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "memfd"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6627dc657574b49d6ad27105ed671822be56e0d2547d413bfbf3e8d8fa92e7a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.5"
|
||||
@@ -1205,19 +1333,25 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "minifb"
|
||||
version = "0.20.0"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f669be3941549a8291969021bf155ffb7bb337d4d2832d24ad7ab91c426c51a7"
|
||||
checksum = "6e52abe7ff0cb18cd88a6e9d7a91ca1ff74876587e7b6b1f30d1aeee9aa89aed"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"orbclient",
|
||||
"raw-window-handle 0.3.4",
|
||||
"raw-window-handle 0.4.2",
|
||||
"winapi 0.3.9",
|
||||
"x11-dl",
|
||||
"xkb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.4.4"
|
||||
@@ -1384,6 +1518,19 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cc",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "5.1.2"
|
||||
@@ -1394,6 +1541,16 @@ dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[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 = "notify"
|
||||
version = "4.0.17"
|
||||
@@ -1421,6 +1578,36 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26873667bbbb7c5182d4a37c1add32cdf09f841af72da53318fdb81543c15085"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[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-integer"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.14"
|
||||
@@ -1472,6 +1659,29 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oboe"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2463c8f2e19b4e0d0710a21f8e4011501ff28db1c95d7a5482a553b2100502d2"
|
||||
dependencies = [
|
||||
"jni",
|
||||
"ndk",
|
||||
"ndk-glue",
|
||||
"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.9.0"
|
||||
@@ -1499,6 +1709,31 @@ dependencies = [
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.6"
|
||||
@@ -1579,6 +1814,15 @@ version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||
|
||||
[[package]]
|
||||
name = "primal-check"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01419cee72c1a1ca944554e23d83e483e1bccf378753344e881de28b5487511d"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "1.1.2"
|
||||
@@ -1712,6 +1956,15 @@ dependencies = [
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "realfft"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a83b876fe55da7e1bf5deeacb93d6411edf81eba0e1a497e79c067734729053a"
|
||||
dependencies = [
|
||||
"rustfft",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
@@ -1780,6 +2033,18 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rubato"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ceb88cff5e2414abd59f1470673e1bba0627118dfc13ce33cebf67ea4a8acb0"
|
||||
dependencies = [
|
||||
"num-complex",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"realfft",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.21"
|
||||
@@ -1792,6 +2057,20 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustfft"
|
||||
version = "6.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1d089e5c57521629a59f5f39bca7434849ff89bd6873b521afe389c1c602543"
|
||||
dependencies = [
|
||||
"num-complex",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"primal-check",
|
||||
"strength_reduce",
|
||||
"transpose",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.33.3"
|
||||
@@ -1962,6 +2241,12 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.5"
|
||||
@@ -1990,6 +2275,18 @@ version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "stdweb"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e"
|
||||
|
||||
[[package]]
|
||||
name = "strength_reduce"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3ff2f71c82567c565ba4b3009a9350a96a7269eaa4001ebedae926230bc2254"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
@@ -2206,6 +2503,16 @@ dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "transpose"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95f9c900aa98b6ea43aee227fd680550cdec726526aab8ac801549eadb25e39f"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"strength_reduce",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "try-lock"
|
||||
version = "0.2.3"
|
||||
@@ -2330,13 +2637,16 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||
|
||||
[[package]]
|
||||
name = "uw8"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"anyhow",
|
||||
"cpal",
|
||||
"curlywas",
|
||||
"minifb",
|
||||
"notify",
|
||||
"pico-args",
|
||||
"rubato",
|
||||
"same-file",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
@@ -2345,6 +2655,7 @@ dependencies = [
|
||||
"wasmtime",
|
||||
"wat",
|
||||
"webbrowser",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2545,12 +2856,6 @@ version = "0.81.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98930446519f63d00a836efdc22f67766ceae8dbcc1571379f2bcabc6b2b9abc"
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.82.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0559cc0f1779240d6f894933498877ea94f693d84f3ee39c9a9932c6c312bd70"
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.83.0"
|
||||
@@ -2559,9 +2864,9 @@ checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a"
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime"
|
||||
version = "0.34.1"
|
||||
version = "0.35.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4882e78d9daceeaff656d82869f298fd472ea8d8ccf96fbd310da5c1687773ac"
|
||||
checksum = "21ffb4705016d5ca91e18a72ed6822dab50e6d5ddd7045461b17ef19071cdef1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -2580,7 +2885,7 @@ dependencies = [
|
||||
"region",
|
||||
"serde",
|
||||
"target-lexicon",
|
||||
"wasmparser 0.82.0",
|
||||
"wasmparser 0.83.0",
|
||||
"wasmtime-cache",
|
||||
"wasmtime-cranelift",
|
||||
"wasmtime-environ",
|
||||
@@ -2593,9 +2898,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-cache"
|
||||
version = "0.34.1"
|
||||
version = "0.35.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf5b9af2d970624455f9ea109acc60cc477afe097f86c190eb519a8b7d6646cd"
|
||||
checksum = "85c6ab24291fa7cb3a181f5669f6c72599b7ef781669759b45c7828c5999d0c0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
@@ -2613,9 +2918,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-cranelift"
|
||||
version = "0.34.1"
|
||||
version = "0.35.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ed6ff21d2dbfe568af483f0c508e049fc6a497c73635e2c50c9b1baf3a93ed8"
|
||||
checksum = "f04c810078a491b7bc4866ebe045f714d2b95e6b539e1f64009a4a7606be11de"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
@@ -2629,15 +2934,15 @@ dependencies = [
|
||||
"object",
|
||||
"target-lexicon",
|
||||
"thiserror",
|
||||
"wasmparser 0.82.0",
|
||||
"wasmparser 0.83.0",
|
||||
"wasmtime-environ",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-environ"
|
||||
version = "0.34.1"
|
||||
version = "0.35.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "860936d38df423b4291b3e31bc28d4895e2208f9daba351c2397d18a0a10e0bf"
|
||||
checksum = "61448266ea164b1ac406363cdcfac81c7c44db4d94c7a81c8620ac6c5c6cdf59"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-entity",
|
||||
@@ -2649,15 +2954,15 @@ dependencies = [
|
||||
"serde",
|
||||
"target-lexicon",
|
||||
"thiserror",
|
||||
"wasmparser 0.82.0",
|
||||
"wasmparser 0.83.0",
|
||||
"wasmtime-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-fiber"
|
||||
version = "0.34.1"
|
||||
version = "0.35.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67e285306aa274d85a22753bef826226e1cc473bac0b541523f46dccf80751cc"
|
||||
checksum = "bbaaa38c3b48822ab27044e1d4a25a1052157de4c8f27574cb00167e127e320f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"rustix",
|
||||
@@ -2666,9 +2971,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-jit"
|
||||
version = "0.34.1"
|
||||
version = "0.35.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e794310a0df5266c7ac73e8211a024a49e3860ac0ca2af5db8527be942ad063e"
|
||||
checksum = "156b4623c6b0d4b8c24afb846c20525922f538ef464cc024abab7ea8de2109a2"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"anyhow",
|
||||
@@ -2676,6 +2981,7 @@ dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cpp_demangle",
|
||||
"gimli",
|
||||
"ittapi-rs",
|
||||
"log",
|
||||
"object",
|
||||
"region",
|
||||
@@ -2685,25 +2991,37 @@ dependencies = [
|
||||
"target-lexicon",
|
||||
"thiserror",
|
||||
"wasmtime-environ",
|
||||
"wasmtime-jit-debug",
|
||||
"wasmtime-runtime",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-runtime"
|
||||
version = "0.34.1"
|
||||
name = "wasmtime-jit-debug"
|
||||
version = "0.35.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90ffe5cb3db705ea43fcf37475a79891a3ada754c1cbe333540879649de943d5"
|
||||
checksum = "d5dc31f811760a6c76b2672c404866fd19b75e5fb3b0075a3e377a6846490654"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"object",
|
||||
"rustix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-runtime"
|
||||
version = "0.35.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f907beaff69d4d920fa4688411ee4cc75c0f01859e424677f9e426e2ef749864"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"backtrace",
|
||||
"cc",
|
||||
"cfg-if 1.0.0",
|
||||
"indexmap",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"mach",
|
||||
"memfd",
|
||||
"memoffset",
|
||||
"more-asserts",
|
||||
"rand",
|
||||
@@ -2712,19 +3030,20 @@ dependencies = [
|
||||
"thiserror",
|
||||
"wasmtime-environ",
|
||||
"wasmtime-fiber",
|
||||
"wasmtime-jit-debug",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-types"
|
||||
version = "0.34.1"
|
||||
version = "0.35.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70a5b60d70c1927c5a403f7c751de179414b6b91da75b2312c3ae78196cf9dc3"
|
||||
checksum = "514ef0e5fd197b9609dc9eb74beba0c84d5a12b2417cbae55534633329ba4852"
|
||||
dependencies = [
|
||||
"cranelift-entity",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"wasmparser 0.82.0",
|
||||
"wasmparser 0.83.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2876,7 +3195,7 @@ version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59a001b79d45b0b4541c228a501177f2b35db976bf7ee3f7fce8fa2381554ab5"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"bindgen 0.56.0",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
16
Cargo.toml
16
Cargo.toml
@@ -1,26 +1,30 @@
|
||||
[package]
|
||||
name = "uw8"
|
||||
version = "0.1.2"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
default = ["native", "browser"]
|
||||
native = ["wasmtime"]
|
||||
native = ["wasmtime", "minifb", "cpal", "rubato", "winapi" ]
|
||||
browser = ["warp", "tokio", "tokio-stream", "webbrowser"]
|
||||
|
||||
[dependencies]
|
||||
wasmtime = { version = "0.34", optional = true }
|
||||
wasmtime = { version = "0.35.3", optional = true }
|
||||
anyhow = "1"
|
||||
minifb = { version = "0.20", default-features = false, features = ["x11"] }
|
||||
minifb = { version = "0.22", default-features = false, features = ["x11"], optional = true }
|
||||
notify = "4"
|
||||
pico-args = "0.4"
|
||||
curlywas = { git = "https://github.com/exoticorn/curlywas.git", rev = "557c3a84" }
|
||||
curlywas = { git = "https://github.com/exoticorn/curlywas.git", rev = "0a0d90c" }
|
||||
wat = "1"
|
||||
uw8-tool = { path = "uw8-tool" }
|
||||
same-file = "1"
|
||||
warp = { version = "0.3.2", optional = true }
|
||||
tokio = { version = "1.17.0", features = ["sync", "rt"], optional = true }
|
||||
tokio-stream = { version = "0.1.8", features = ["sync"], optional = true }
|
||||
webbrowser = { version = "0.6.0", optional = true }
|
||||
webbrowser = { version = "0.6.0", optional = true }
|
||||
ansi_term = "0.12.1"
|
||||
cpal = { version = "0.13.5", optional = true }
|
||||
rubato = { version = "0.11.0", optional = true }
|
||||
winapi = { version = "0.3.9", features = ["timeapi"], optional = true }
|
||||
55
examples/curlywas/cracklebass.cwa
Normal file
55
examples/curlywas/cracklebass.cwa
Normal file
@@ -0,0 +1,55 @@
|
||||
// port of cracklebass by pestis (originally on TIC-80)
|
||||
|
||||
include "../include/microw8-api.cwa"
|
||||
|
||||
const MUSIC_DATA = 0x20000;
|
||||
|
||||
export fn upd() {
|
||||
let inline t = 32!32 * 6 / 100;
|
||||
let inline p = t / 1024;
|
||||
|
||||
let channel:i32;
|
||||
|
||||
loop channels {
|
||||
let inline e = t * channel?MUSIC_DATA / 8;
|
||||
let lazy pattern = (8 * channel + p)?(MUSIC_DATA + 56);
|
||||
let lazy n = !!pattern * (8 * pattern + e / 16 % 8)?MUSIC_DATA;
|
||||
let inline prev_ctrl = (channel * 6)?80;
|
||||
(channel * 6)?80 = if n {
|
||||
let inline base_note = 12 + 12 * channel?(MUSIC_DATA + 4) + n;
|
||||
let inline pitch_drop = e % 16 * channel?(MUSIC_DATA + 94);
|
||||
let inline key_pattern = p?(MUSIC_DATA + 8*4 + 56);
|
||||
let inline key = select(key_pattern, (8 * key_pattern + t / 128 % 8)?MUSIC_DATA, 1);
|
||||
(channel * 6)?83 = base_note - pitch_drop / 4 + key;
|
||||
prev_ctrl & 0xfc | (e / 8 & 2) | 1
|
||||
} else {
|
||||
prev_ctrl & 0xfe
|
||||
};
|
||||
|
||||
branch_if (channel := channel + 1) < 4: channels;
|
||||
}
|
||||
}
|
||||
|
||||
data 80 {
|
||||
i8(
|
||||
0x44, 0, 0, 0, 0x50, 0x40,
|
||||
0x4, 0x50, 0, 0, 0x80, 0x80,
|
||||
0x40, 0x80, 0, 0, 0x40, 0x40,
|
||||
0, 0, 0, 0, 0x50, 0x50
|
||||
)
|
||||
}
|
||||
|
||||
data MUSIC_DATA {
|
||||
i8(
|
||||
16, 2, 8, 8, 1, 2, 2, 3, 1, 0,
|
||||
1,13,16, 0, 1, 8, 1, 0, 1,13,
|
||||
16, 1, 1, 8, 1, 0, 8,13,13, 0,
|
||||
16,13, 1, 0, 1, 0, 1, 0, 1, 1,
|
||||
1, 0, 0, 0, 1, 0,13, 1, 1, 1,
|
||||
6, 8, 1, 1, 6, 8, 1, 1, 2, 1,
|
||||
2, 1, 2, 0, 0, 0, 0, 3, 3, 3,
|
||||
5, 0, 0, 2, 1, 2, 1, 2, 1, 2,
|
||||
0, 4, 4, 0, 4, 4, 4, 4, 0, 0,
|
||||
0, 0, 6, 6, 0, 0, 0, 8
|
||||
)
|
||||
}
|
||||
38
examples/curlywas/simple_music.cwa
Normal file
38
examples/curlywas/simple_music.cwa
Normal file
@@ -0,0 +1,38 @@
|
||||
include "../include/microw8-api.cwa"
|
||||
|
||||
global mut frame = 0;
|
||||
|
||||
export fn upd() {
|
||||
if frame % 16 == 0 {
|
||||
let ch: i32;
|
||||
loop channels {
|
||||
playNote(ch, (ch * 32 + (frame / 16) % 32)?0x20000);
|
||||
branch_if ch := (ch + 1) % 4: channels;
|
||||
}
|
||||
}
|
||||
frame = frame + 1;
|
||||
}
|
||||
|
||||
data 0x20000 {
|
||||
i8(
|
||||
0x4e, 0x0, 0x0, 0x4c, 0x49, 0x0, 0x45, 0x47,
|
||||
0x49, 0x47, 0x45, 0x44, 0x42, 0x0, 0x3d, 0x41,
|
||||
0x44, 0x0, 0x0, 0x47, 0x49, 0x47, 0x45, 0x41,
|
||||
0x44, 0x0, 0x0, 0x0, 0x42, 0x0, 0x0, 0x0,
|
||||
|
||||
0x25, 0, 0x49, 0x25, 0x25, 0, 0x49, 0x38,
|
||||
0x25, 0, 0x49, 0x25, 0x25, 0, 0x49, 0x38,
|
||||
0x25, 0, 0x49, 0x25, 0x25, 0, 0x49, 0x38,
|
||||
0x25, 0, 0x49, 0x25, 0x25, 0, 0x49, 0x38,
|
||||
|
||||
0x2a, 0x0, 0x0, 0x0, 0x2d, 0x0, 0x0, 0x0,
|
||||
0x2c, 0x0, 0x28, 0x0, 0x2a, 0x0, 0x0, 0x0,
|
||||
0x25, 0x0, 0x0, 0x0, 0x29, 0x0, 0x0, 0x0,
|
||||
0x2c, 0x0, 0x2d, 0x0, 0x2a, 0x0, 0x25, 0x0,
|
||||
|
||||
0x0, 0x0, 0x31, 0x0, 0x34, 0x0, 0x0, 0x36,
|
||||
0x38, 0x39, 0x38, 0x34, 0x36, 0x0, 0x0, 0x0,
|
||||
0x0, 0x3d, 0x3b, 0x39, 0x38, 0x0, 0x0, 0x0,
|
||||
0x0, 0x39, 0x38, 0x39, 0x38, 0x0, 0x36, 0x0
|
||||
)
|
||||
}
|
||||
@@ -8,7 +8,7 @@ global mut f: f32 = 2.0;
|
||||
|
||||
export fn upd() {
|
||||
let y: i32;
|
||||
let inline zero = 0.0;
|
||||
let inline zero = 0_f;
|
||||
|
||||
let lazy control_speed = 0.03125;
|
||||
s = s + 0.1875 - (f + control_speed) * isButtonPressed(4 <| cls(4)) as f32;
|
||||
@@ -30,6 +30,8 @@ export fn upd() {
|
||||
|
||||
if y == 180 & py > zero {
|
||||
if x > w | x < zero {
|
||||
0?80 = 0xc3;
|
||||
3?80 = 32;
|
||||
return;
|
||||
}
|
||||
py = zero;
|
||||
@@ -43,6 +45,9 @@ export fn upd() {
|
||||
circle(160 as f32, 160 as f32 + py, 22 as f32, -28);
|
||||
circle((160 - 6) as f32, (160 - 6) as f32 + py, 6 as f32, -26);
|
||||
|
||||
0?86 = py < zero;
|
||||
3?86 = 32 - py as i32;
|
||||
|
||||
px = px + (isButtonPressed(3) - isButtonPressed(2)) as f32 * control_speed;
|
||||
py = py + s;
|
||||
pz = pz + 1;
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// Steady On Tim, It's Only A Budget Game
|
||||
// original bytebeat by Gasman / Hooy-Program
|
||||
// ported to MicroW8/GES by exoticorn/icebird
|
||||
|
||||
import "env.memory" memory(4);
|
||||
|
||||
fn melody(ch: i32, t: i32, T: i32) {
|
||||
@@ -9,7 +13,7 @@ fn melody(ch: i32, t: i32, T: i32) {
|
||||
let inline riff_note = 5514 >> (riff_pos % note_count * 4) & 15;
|
||||
let inline melody_note = shift + octave - riff_note;
|
||||
|
||||
ch?1 = 248 - riff_pos * 15;
|
||||
ch?1 = 230 - riff_pos * 14;
|
||||
ch?3 = melody_note + 64;
|
||||
|
||||
let inline arp_note = shift + ((0x85>>((t/2)%3*4)) & 15) - 1;
|
||||
@@ -22,13 +26,13 @@ export fn upd() {
|
||||
melody(98, t, T - 3);
|
||||
melody(92, t, T);
|
||||
|
||||
80?0 = ((T >= 256) & (T/12+(T-3)/12)) * 2 | 0x44; // arp trigger
|
||||
80?0 = ((T >= 256) & (T/12+(T-3)/12)) * 2 | 0x48; // arp trigger
|
||||
|
||||
if T >= 128 {
|
||||
let inline bass_step = T % 8;
|
||||
86?3 = if bass_step / 2 == 2 {
|
||||
86?0 = 0xc2;
|
||||
80
|
||||
86?0 = 0xd6;
|
||||
81
|
||||
} else {
|
||||
86?0 = ((197 >> bass_step) & 1) | 0x48;
|
||||
((T & 4) * ((T & 7) - 1)) / 2 + 28
|
||||
@@ -38,12 +42,12 @@ export fn upd() {
|
||||
|
||||
data 80 {
|
||||
i8(
|
||||
0, 0x81, 0, 0, 0, 0x90,
|
||||
0, 0x4c, 0, 0, 0, 0x5c,
|
||||
5, 0, 0, 0, 0, 0x4c,
|
||||
5, 0, 0, 0, 0, 0x4c,
|
||||
0xfa, 0x85,
|
||||
0x81, 0x81, 0, 110, 0, 90
|
||||
0, 0x90, 0, 0, 0, 0x90,
|
||||
0, 0x4c, 0, 0, 0, 0x4c,
|
||||
0x19, 0, 0, 0, 0, 0x4c,
|
||||
0x19, 0, 0, 0, 0, 0x4c,
|
||||
0xfa, 0x84,
|
||||
0xc1, 0xc1, 0, 107, 0, 0x4c
|
||||
)
|
||||
}
|
||||
|
||||
@@ -51,6 +55,7 @@ data 80 {
|
||||
include "../../platform/src/ges.cwa"
|
||||
|
||||
import "env.pow" fn pow(f32, f32) -> f32;
|
||||
import "env.exp" fn exp(f32) -> f32;
|
||||
import "env.sin" fn sin(f32) -> f32;
|
||||
|
||||
export fn snd(t: i32) -> f32 {
|
||||
|
||||
@@ -33,6 +33,7 @@ import "env.setCursorPosition" fn setCursorPosition(i32, i32);
|
||||
import "env.rectangle_outline" fn rectangle_outline(f32, f32, f32, f32, i32);
|
||||
import "env.circle_outline" fn circle_outline(f32, f32, f32, i32);
|
||||
import "env.exp" fn exp(f32) -> f32;
|
||||
import "env.playNote" fn playNote(i32, i32);
|
||||
|
||||
const TIME_MS = 0x40;
|
||||
const GAMEPAD = 0x44;
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
(import "env" "rectangle_outline" (func $rectangle_outline (param f32) (param f32) (param f32) (param f32) (param i32)))
|
||||
(import "env" "circle_outline" (func $circle_outline (param f32) (param f32) (param f32) (param i32)))
|
||||
(import "env" "exp" (func $exp (param f32) (result f32)))
|
||||
(import "env" "playNote" (func $playNote (param i32) (param i32)))
|
||||
|
||||
;; to use defines, include this file with a preprocessor
|
||||
;; like gpp (https://logological.org/gpp).
|
||||
|
||||
2
platform/Cargo.lock
generated
2
platform/Cargo.lock
generated
@@ -146,7 +146,7 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||
[[package]]
|
||||
name = "curlywas"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/exoticorn/curlywas.git?rev=557c3a84#557c3a842675a1ebd77e84021f9f5236d4fa5648"
|
||||
source = "git+https://github.com/exoticorn/curlywas.git?rev=0a0d90c#0a0d90c8013f1d7856a9b71a19d3d006300f31f9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ariadne",
|
||||
|
||||
@@ -6,7 +6,7 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
curlywas = { git="https://github.com/exoticorn/curlywas.git", rev="557c3a84" }
|
||||
curlywas = { git="https://github.com/exoticorn/curlywas.git", rev="0a0d90c" }
|
||||
uw8-tool = { path="../uw8-tool" }
|
||||
anyhow = "1"
|
||||
lodepng = "3.4"
|
||||
Binary file not shown.
Binary file not shown.
@@ -7,21 +7,22 @@ const GesChannelState.Size = 8;
|
||||
const GesState.Filter = GesChannelState.Size * 4;
|
||||
const GesState.Size = GesState.Filter + 8*4;
|
||||
|
||||
const GesStateOffset = 112;
|
||||
const GesBufferOffset = 112 + GesState.Size;
|
||||
const GesStateOffset = 32;
|
||||
const GesBufferOffset = 32 + GesState.Size;
|
||||
|
||||
export fn gesSnd(t: i32) -> f32 {
|
||||
let baseAddr = 0!0x12c78;
|
||||
if !(t & 127) {
|
||||
let i: i32;
|
||||
loop clearLoop {
|
||||
i!GesBufferOffset = 0;
|
||||
branch_if (i := i + 4) < 128*8: clearLoop;
|
||||
(baseAddr + i)!GesBufferOffset = 0;
|
||||
branch_if (i := i + 4) < 128*4: clearLoop;
|
||||
}
|
||||
|
||||
let ch: i32;
|
||||
loop channelLoop {
|
||||
let lazy channelState = GesStateOffset + ch * GesChannelState.Size;
|
||||
let lazy channelReg = 80 + ch * 6;
|
||||
let lazy channelState = baseAddr + GesStateOffset + ch * GesChannelState.Size;
|
||||
let lazy channelReg = baseAddr + ch * 6;
|
||||
let envState = channelState?GesChannelState.EnvState;
|
||||
let envVol = i32.load16_u(channelState, GesChannelState.EnvVol);
|
||||
|
||||
@@ -77,7 +78,7 @@ export fn gesSnd(t: i32) -> f32 {
|
||||
let saw2 = saw2 -
|
||||
polyBlep((p - pulsePhase1) >> 16, invPhaseInc, -saw) -
|
||||
polyBlep((p - pulsePhase2) >> 16, invPhaseInc, saw);
|
||||
i!(GesBufferOffset + 128*4) = saw2;
|
||||
(baseAddr + i)!(GesBufferOffset + 128*4) = saw2;
|
||||
phase = phase + phaseInc;
|
||||
branch_if (i := i + 4) < 64*4: sawLoop;
|
||||
}
|
||||
@@ -86,7 +87,7 @@ export fn gesSnd(t: i32) -> f32 {
|
||||
{
|
||||
let pulsePhase = 32768 + pulseWidth * 128;
|
||||
loop rectLoop {
|
||||
i!(GesBufferOffset + 128*4) = select((phase & 65535) < pulsePhase, -32768, 32767) -
|
||||
(baseAddr + i)!(GesBufferOffset + 128*4) = select((phase & 65535) < pulsePhase, -32768, 32767) -
|
||||
polyBlep(phase, invPhaseInc, -32767) -
|
||||
polyBlep(phase - pulsePhase, invPhaseInc, 32767);
|
||||
phase = phase + phaseInc;
|
||||
@@ -101,7 +102,7 @@ export fn gesSnd(t: i32) -> f32 {
|
||||
s = (s ^ (s >> 31));
|
||||
s = (s >> 8) * scale;
|
||||
s = (s ^ (s >> 31));
|
||||
i!(GesBufferOffset + 128*4) = (s >> 15) - 32768;
|
||||
(baseAddr + i)!(GesBufferOffset + 128*4) = (s >> 15) - 32768;
|
||||
phase = phase + phaseInc;
|
||||
branch_if (i := i + 4) < 64*4: triLoop;
|
||||
}
|
||||
@@ -111,7 +112,7 @@ export fn gesSnd(t: i32) -> f32 {
|
||||
let inline pulse = ((phase >> 8) & 255) >= pulseWidth;
|
||||
s = s * 0x6746ba73;
|
||||
s = s ^ (s >> 15) * pulse;
|
||||
i!(GesBufferOffset + 128*4) = (s * 0x835776c7) >> 16;
|
||||
(baseAddr + i)!(GesBufferOffset + 128*4) = (s * 0x835776c7) >> 16;
|
||||
phase = phase + phaseInc;
|
||||
branch_if (i := i + 4) < 64*4: noiseLoop;
|
||||
}
|
||||
@@ -122,8 +123,8 @@ export fn gesSnd(t: i32) -> f32 {
|
||||
|
||||
if ctrl & 32 {
|
||||
let lazy modSrc = (ch - 1) & 3;
|
||||
let inline channelState = GesStateOffset + modSrc * GesChannelState.Size;
|
||||
let inline channelReg = 80 + modSrc * 6;
|
||||
let inline channelState = baseAddr + GesStateOffset + modSrc * GesChannelState.Size;
|
||||
let inline channelReg = baseAddr + modSrc * 6;
|
||||
|
||||
let inline note = i32.load16_u(channelReg, 2);
|
||||
let inline freq = 440 as f32 * pow(2.0, (note - 69*256) as f32 / (12*256) as f32);
|
||||
@@ -138,13 +139,13 @@ export fn gesSnd(t: i32) -> f32 {
|
||||
loop ringLoop {
|
||||
let s = phase << 16;
|
||||
s = (s ^ (s >> 31));
|
||||
i!(GesBufferOffset + 128*4) = (i!(GesBufferOffset + 128*4) * ((s >> 15) - 32768)) >> 15;
|
||||
(baseAddr + i)!(GesBufferOffset + 128*4) = ((baseAddr + i)!(GesBufferOffset + 128*4) * ((s >> 15) - 32768)) >> 15;
|
||||
phase = phase + phaseInc;
|
||||
branch_if (i := i + 4) < 64*4: ringLoop;
|
||||
}
|
||||
}
|
||||
|
||||
let channelVol = ((ch >> 1)?0x68 >> ((ch & 1) * 4)) & 15;
|
||||
let channelVol = ((baseAddr + (ch >> 1))?24 >> ((ch & 1) * 4)) & 15;
|
||||
envVol = envVol * channelVol / 15;
|
||||
|
||||
let leftVol = (select(ctrl & 16, 0x3d5b, 0x6a79) >> (ch * 4)) & 15;
|
||||
@@ -156,30 +157,30 @@ export fn gesSnd(t: i32) -> f32 {
|
||||
if filter < 2 {
|
||||
if filter {
|
||||
let f = (4096 as f32 - min(4096 as f32, 4096 as f32 * exp(freq * (-8.0 * 3.141 / 44100.0)))) as i32;
|
||||
let low = (ch * 8)!(GesStateOffset + GesState.Filter);
|
||||
let low = (baseAddr + ch * 8)!(GesStateOffset + GesState.Filter);
|
||||
loop filterLoop {
|
||||
let in = (i!(GesBufferOffset + 128*4) * envVol) >> 18;
|
||||
let in = ((baseAddr + i)!(GesBufferOffset + 128*4) * envVol) >> 18;
|
||||
low = low + (((in - low) * f) >> 12);
|
||||
(i * 2)!GesBufferOffset = (i * 2)!GesBufferOffset + ((low * leftVol) >> 4);
|
||||
(i * 2)!(GesBufferOffset + 4) = (i * 2)!(GesBufferOffset + 4) + ((low * rightVol) >> 4);
|
||||
(baseAddr + i * 2)!GesBufferOffset = (baseAddr + i * 2)!GesBufferOffset + ((low * leftVol) >> 4);
|
||||
(baseAddr + i * 2)!(GesBufferOffset + 4) = (baseAddr + i * 2)!(GesBufferOffset + 4) + ((low * rightVol) >> 4);
|
||||
branch_if (i := i + 4) < 64*4: filterLoop;
|
||||
(ch * 8)!(GesStateOffset + GesState.Filter) = low;
|
||||
(ch * 8)!(GesStateOffset + GesState.Filter + 4) = 0;
|
||||
(baseAddr + ch * 8)!(GesStateOffset + GesState.Filter) = low;
|
||||
(baseAddr + ch * 8)!(GesStateOffset + GesState.Filter + 4) = 0;
|
||||
}
|
||||
} else {
|
||||
loop mixLoop {
|
||||
let sample = (i!(GesBufferOffset + 128*4) * envVol) >> 18;
|
||||
(i * 2)!GesBufferOffset = (i * 2)!GesBufferOffset + ((sample * leftVol) >> 4);
|
||||
(i * 2)!(GesBufferOffset + 4) = (i * 2)!(GesBufferOffset + 4) + ((sample * rightVol) >> 4);
|
||||
let sample = ((baseAddr + i)!(GesBufferOffset + 128*4) * envVol) >> 18;
|
||||
(baseAddr + i * 2)!GesBufferOffset = (baseAddr + i * 2)!GesBufferOffset + ((sample * leftVol) >> 4);
|
||||
(baseAddr + i * 2)!(GesBufferOffset + 4) = (baseAddr + i * 2)!(GesBufferOffset + 4) + ((sample * rightVol) >> 4);
|
||||
branch_if (i := i + 4) < 64*4: mixLoop;
|
||||
(ch * 8)!(GesStateOffset + GesState.Filter) = sample;
|
||||
(ch * 8)!(GesStateOffset + GesState.Filter + 4) = 0;
|
||||
(baseAddr + ch * 8)!(GesStateOffset + GesState.Filter) = sample;
|
||||
(baseAddr + ch * 8)!(GesStateOffset + GesState.Filter + 4) = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
filter = filter - 2;
|
||||
let ctrl = filter?0x6a;
|
||||
let note = i32.load16_u(filter * 2, 0x6c);
|
||||
let ctrl = (baseAddr + filter)?26;
|
||||
let note = i32.load16_u(baseAddr + filter * 2, 28);
|
||||
let inline freq = 440 as f32 * pow(2.0, (note - 69*256) as f32 / (12*256) as f32);
|
||||
let F = (8192 as f32 * sin(min(0.25, freq / 44100 as f32) * 3.1415)) as i32;
|
||||
let Q = 8192 - (ctrl >> 4) * (7000/15);
|
||||
@@ -190,28 +191,28 @@ export fn gesSnd(t: i32) -> f32 {
|
||||
let low_out = ctrl & 1;
|
||||
let high_out = (ctrl >> 1) & 1;
|
||||
let band_out = (ctrl >> 2) & 1;
|
||||
let low = (ch * 8)!(GesStateOffset + GesState.Filter);
|
||||
let band = (ch * 8)!(GesStateOffset + GesState.Filter + 4);
|
||||
let low = (baseAddr + ch * 8)!(GesStateOffset + GesState.Filter);
|
||||
let band = (baseAddr + ch * 8)!(GesStateOffset + GesState.Filter + 4);
|
||||
loop filterLoop {
|
||||
let in = (i!(GesBufferOffset + 128*4) * envVol) >> 18;
|
||||
let in = ((baseAddr + i)!(GesBufferOffset + 128*4) * envVol) >> 18;
|
||||
|
||||
let high = in - low - ((band * Q) >> 12);
|
||||
band = band + ((F * high) >> 12);
|
||||
low = low + ((F * band) >> 12);
|
||||
|
||||
let sample = low * low_out + high * high_out + band * band_out;
|
||||
(i * 2)!GesBufferOffset = (i * 2)!GesBufferOffset + ((sample * leftVol) >> 4);
|
||||
(i * 2)!(GesBufferOffset + 4) = (i * 2)!(GesBufferOffset + 4) + ((sample * rightVol) >> 4);
|
||||
(baseAddr + i * 2)!GesBufferOffset = (baseAddr + i * 2)!GesBufferOffset + ((sample * leftVol) >> 4);
|
||||
(baseAddr + i * 2)!(GesBufferOffset + 4) = (baseAddr + i * 2)!(GesBufferOffset + 4) + ((sample * rightVol) >> 4);
|
||||
branch_if (i := i + 4) < 64*4: filterLoop;
|
||||
(ch * 8)!(GesStateOffset + GesState.Filter) = low;
|
||||
(ch * 8)!(GesStateOffset + GesState.Filter + 4) = band;
|
||||
(baseAddr + ch * 8)!(GesStateOffset + GesState.Filter) = low;
|
||||
(baseAddr + ch * 8)!(GesStateOffset + GesState.Filter + 4) = band;
|
||||
}
|
||||
}
|
||||
|
||||
branch_if (ch := ch + 1) < 4: channelLoop;
|
||||
}
|
||||
}
|
||||
(((t & 127) * 4)!GesBufferOffset) as f32 / 32768 as f32
|
||||
((baseAddr + (t & 127) * 4)!GesBufferOffset) as f32 / 32768 as f32
|
||||
}
|
||||
|
||||
fn polyBlep(transientPhase: i32, invPhaseInc: f32, magnitude: i32) -> i32 {
|
||||
|
||||
@@ -4,6 +4,7 @@ import "env.sin" fn sin(f32) -> f32;
|
||||
import "env.cos" fn cos(f32) -> f32;
|
||||
import "env.pow" fn pow(f32, f32) -> f32;
|
||||
import "env.exp" fn exp(f32) -> f32;
|
||||
import "env.logChar" fn logChar(i32);
|
||||
|
||||
export fn time() -> f32 {
|
||||
(0!64) as f32 / 1000 as f32
|
||||
@@ -32,11 +33,9 @@ export fn random() -> i32 {
|
||||
}
|
||||
|
||||
export fn random64() -> i64 {
|
||||
let state: i64;
|
||||
randomState = (state := (
|
||||
state := randomState ^ (randomState #>> 12i64)
|
||||
) ^ (state << 25i64)
|
||||
) ^ (state #>> 27i64);
|
||||
let lazy state = randomState ^ (randomState #>> 12i64);
|
||||
let lazy state = state ^ (state << 25i64);
|
||||
randomState = state ^ (state #>> 27i64);
|
||||
randomState * 0x2545f4914f6cdd1di64
|
||||
}
|
||||
|
||||
@@ -62,7 +61,7 @@ export fn cls(col: i32) {
|
||||
let i: i32;
|
||||
textCursorX = 0;
|
||||
textCursorY = 0;
|
||||
graphicsText = 0;
|
||||
outputChannel = 0;
|
||||
col = (col & 255) * 0x1010101;
|
||||
loop pixels {
|
||||
i!120 = col;
|
||||
@@ -307,7 +306,7 @@ global mut textCursorX = 0;
|
||||
global mut textCursorY = 0;
|
||||
global mut textColor = 15;
|
||||
global mut bgColor = 0;
|
||||
global mut graphicsText = 0;
|
||||
global mut outputChannel = 0;
|
||||
|
||||
export fn printChar(char: i32) {
|
||||
loop chars {
|
||||
@@ -319,6 +318,20 @@ export fn printChar(char: i32) {
|
||||
global mut controlCodeLength = 0;
|
||||
|
||||
fn printSingleChar(char: i32) {
|
||||
if char >= 4 & char <= 6 {
|
||||
outputChannel = char - 4;
|
||||
if !outputChannel {
|
||||
textCursorX = 0;
|
||||
textCursorY = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if outputChannel >= 2 {
|
||||
logChar(char);
|
||||
return;
|
||||
}
|
||||
|
||||
controlCodeLength?0x12d20 = char;
|
||||
controlCodeLength = controlCodeLength + 1;
|
||||
char = 0x12d20?0;
|
||||
@@ -332,16 +345,14 @@ fn printSingleChar(char: i32) {
|
||||
return;
|
||||
}
|
||||
|
||||
if char == 4 | char == 5 {
|
||||
graphicsText = char == 5;
|
||||
textCursorX = 0;
|
||||
textCursorY = 0;
|
||||
if char == 7 {
|
||||
80?0 = 80?0 ^ 2;
|
||||
return;
|
||||
}
|
||||
|
||||
if char == 8 {
|
||||
textCursorX = textCursorX - 8;
|
||||
if !graphicsText & textCursorX < 0 {
|
||||
if !outputChannel & textCursorX < 0 {
|
||||
textCursorX = 320-8;
|
||||
printSingleChar(11);
|
||||
}
|
||||
@@ -349,7 +360,7 @@ fn printSingleChar(char: i32) {
|
||||
}
|
||||
|
||||
if char == 9 {
|
||||
if !graphicsText & textCursorX >= 320 {
|
||||
if !outputChannel & textCursorX >= 320 {
|
||||
printChar(0xd0a);
|
||||
}
|
||||
textCursorX = textCursorX + 8;
|
||||
@@ -358,7 +369,7 @@ fn printSingleChar(char: i32) {
|
||||
|
||||
if char == 10 {
|
||||
textCursorY = textCursorY + 8;
|
||||
if !graphicsText & textCursorY >= 240 {
|
||||
if !outputChannel & textCursorY >= 240 {
|
||||
textCursorY = 240 - 8;
|
||||
let i: i32;
|
||||
loop scroll_copy {
|
||||
@@ -372,7 +383,7 @@ fn printSingleChar(char: i32) {
|
||||
|
||||
if char == 11 {
|
||||
textCursorY = textCursorY - 8;
|
||||
if !graphicsText & textCursorY < 0 {
|
||||
if !outputChannel & textCursorY < 0 {
|
||||
textCursorY = 0;
|
||||
let i = 320 * (240 - 8);
|
||||
loop scroll_copy {
|
||||
@@ -412,8 +423,8 @@ fn printSingleChar(char: i32) {
|
||||
}
|
||||
|
||||
if char == 31 {
|
||||
textCursorX = 0x12d20?1 * (8 - graphicsText * 6);
|
||||
textCursorY = 0x12d20?2 * (8 - graphicsText * 7);
|
||||
textCursorX = 0x12d20?1 * (8 - outputChannel * 6);
|
||||
textCursorY = 0x12d20?2 * (8 - outputChannel * 7);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -438,7 +449,7 @@ data(0x12d00) {
|
||||
}
|
||||
|
||||
fn drawChar(char: i32) {
|
||||
if !graphicsText & textCursorX >= 320 {
|
||||
if !outputChannel & textCursorX >= 320 {
|
||||
printChar(0xd0a);
|
||||
}
|
||||
|
||||
@@ -446,7 +457,7 @@ fn drawChar(char: i32) {
|
||||
loop rows {
|
||||
let bits = (char * 8 + y)?0x13400;
|
||||
let x = 0;
|
||||
if graphicsText {
|
||||
if outputChannel {
|
||||
loop pixels {
|
||||
if (bits := bits << 1) & 256 {
|
||||
setPixel(textCursorX + x, textCursorY + y, textColor);
|
||||
@@ -498,7 +509,7 @@ export fn setBackgroundColor(col: i32) {
|
||||
}
|
||||
|
||||
export fn setCursorPosition(x: i32, y: i32) {
|
||||
let lazy scale = select(graphicsText, 1, 8);
|
||||
let lazy scale = select(outputChannel, 1, 8);
|
||||
textCursorX = x * scale;
|
||||
textCursorY = y * scale;
|
||||
}
|
||||
@@ -509,6 +520,26 @@ export fn setCursorPosition(x: i32, y: i32) {
|
||||
|
||||
include "ges.cwa"
|
||||
|
||||
export fn playNote(channel: i32, note: i32) {
|
||||
(channel * 6)?80 = (channel * 6)?80 & 0xfe ^ if note {
|
||||
(channel * 6)?83 = note & 127;
|
||||
2 | !(note >> 7)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
data 80 {
|
||||
i8(
|
||||
0x80, 0xc0, 0, 81, 0xa0, 0x50,
|
||||
0xc4, 0, 0, 69, 0x60, 0x40,
|
||||
0x44, 0xb0, 0, 69, 0x90, 0x43,
|
||||
0x4, 0xf0, 0, 69, 0xa4, 0x44,
|
||||
0xff, 0xff,
|
||||
1, 1, 0, 100, 0, 100
|
||||
)
|
||||
}
|
||||
|
||||
///////////
|
||||
// SETUP //
|
||||
///////////
|
||||
@@ -565,15 +596,8 @@ start fn setup() {
|
||||
randomSeed(random());
|
||||
}
|
||||
|
||||
data 80 {
|
||||
i8(
|
||||
0, 128, 0, 69, 0x8, 0xc8,
|
||||
0, 128, 0, 69, 0x8, 0xc8,
|
||||
0, 128, 0, 69, 0x8, 0xc8,
|
||||
0, 128, 0, 69, 0x8, 0xc8,
|
||||
0xff, 0xff,
|
||||
1, 1, 0, 100, 0, 100
|
||||
)
|
||||
data 0x12c78 {
|
||||
i32(80)
|
||||
}
|
||||
|
||||
data 0x13000+192*4 {
|
||||
|
||||
@@ -15,11 +15,11 @@ The initial motivation behind MicroW8 was to explore whether there was a way to
|
||||
* Gamepad input (D-Pad + 4 Buttons)
|
||||
|
||||
## Examples
|
||||
* [Fireworks](v0.1.2#AgwvgP+M59snqjl4CMKw5sqm1Zw9yJCbSviMjeLUdHus2a3yl/a99+uiBeqZgP/2jqSjrLjRk73COMM6OSLpsxK8ugT1kuk/q4hQUqqPpGozHoa0laulzGGcahzdfdJsYaK1sIdeIYS9M5PnJx/Wk9H+PvWEPy2Zvv7I6IW7Fg==) (127 bytes): Some fireworks to welcome 2022.
|
||||
* [Skip Ahead](v0.1.2#AgyfpZ80wkW28kiUZ9VIK4v+RPnVxqjK1dz2BcDoNyQPsS2g4OgEzkTe6jyoAfFOmqKrS8SM2aRljBal9mjNn8i4fP9eBK+RehQKxxGtJa9FqftvqEnh3ez1YaYxqj7jgTdzJ/WAYVmKMovBT1myrX3FamqKSOgMsNedLhVTLAhQup3sNcYEjGNo8b0HZ5+AgMgCwYRGCe//XQOMAaAAzqDILgmpEZ/43RKHcQpHEQwbURfNQJpadJe2sz3q5FlQnTGXQ9oSMokidhlC+aR/IpNHieuBGLhFZ2GfnwVQ0geBbQpTPA==) (229 bytes): A port of my [TIC-80 256byte game](http://tic80.com/play?cart=1735) from LoveByte'21
|
||||
* [OhNoAnotherTunnel](v0.1.2#AgPP1oEFvPzY/rBZwTumtYn37zeMFgpir1Bkn91jsNcp26VzoUpkAOOJTtnzVBfW+/dGnnIdbq/irBUJztY5wuua80DORTYZndgdwZHcSk15ajc4nyO0g1A6kGWyW56oZk0iPYJA9WtUmoj0Plvy1CGwIZrMe57X7QZcdqc3u6zjTA41Tpiqi9vnO3xbhi8o594Vx0XPXwVzpYq1ZCTYenfAGaXKkDmAFJqiVIsiCg==) (175 bytes): A port of my [entry](http://tic80.com/play?cart=1871) in the Outline'21 bytebattle final
|
||||
* [Technotunnel](v0.1.2#AhPXpq894LaUhp5+HQf39f39/Jc8g5zUrBSc0uyKh36ivskczhY84h55zL8gWpkdvKuRQI+KIt80isKzh8jkM8nILcx0RUvyk8yjE8TgNsgkcORVI0RY5k3qE4ySjaycxa2DVZH61UWZuLsCouuwT7I80TbmmetQSbMywJ/avrrCZIAH0UzQfvOiCJNG48NI0FFY1vjB7a7dcp8Uqg==) (157 bytes): A port of my [entry](https://tic80.com/play?cart=1873) in the Outline'21 bytebattle quater final
|
||||
* [Font & Palette](v0.1.2#At/p39+IBnj6ry1TRe7jzVy2A4tXgBvmoW2itzoyF2aM28pGy5QDiKxqrk8l9sbWZLtnAb+jgOfU+9QhpuyCAkhN6gPOU481IUL/df96vNe3h288Dqwhd3sfFpothIVFsMwRK72kW2hiR7zWsaXyy5pNmjR6BJk4piWx9ApT1ZwoUajhk6/zij6itq/FD1U3jj/J3MOwqZ2ef8Bv6ZPQlJIYVf62icGa69wS6SI1qBpIFiF14F8PcztRVbKIxLpT4ArCS6nz6FPnyUkqATGSBNPJ): Just a simple viewer for the default font and palette.
|
||||
* [Skip Ahead](v0.2.0#AgVfq24KI2Ok2o8qVtPYj27fSuGnfeSKgbOkIOsaEQMov8TDYQ6UjdjwkZrYcM1i9alo4/+Bhm1PRFEa0YHJlJAk/PGoc2K41rejv9ZSqJqIHNjr7cappqhOR2jT+jk+0b0+U6hO+geRCTP2aufWs7L+f/Z27NFY8LKlqPSv+C6Rd6+ohoKi6sYl5Kcrlf1cyTinV7jTTnmbcXWVDBA5rRKxAGMUTDS8rHxqSztRITOaQVP1pSdYgi/BDdOJOxSOIkeaId84S+Ycls5na7EgwSfVIpgqF+tcfkUecb8t2mQrXA7pyKrh/wzHn5N6Oe5aOgmzY2YpTIct) (249 bytes): A port of my [TIC-80 256byte game](http://tic80.com/play?cart=1735) from LoveByte'21, now with sound
|
||||
* [Fireworks](v0.2.0#AgwvgP+M59snqjl4CMKw5sqm1Zw9yJCbSviMjeLUdHus2a3yl/a99+uiBeqZgP/2jqSjrLjRk73COMM6OSLpsxK8ugT1kuk/q4hQUqqPpGozHoa0laulzGGcahzdfdJsYaK1sIdeIYS9M5PnJx/Wk9H+PvWEPy2Zvv7I6IW7Fg==) (127 bytes): Some fireworks to welcome 2022.
|
||||
* [OhNoAnotherTunnel](v0.2.0#AgPP1oEFvPzY/rBZwTumtYn37zeMFgpir1Bkn91jsNcp26VzoUpkAOOJTtnzVBfW+/dGnnIdbq/irBUJztY5wuua80DORTYZndgdwZHcSk15ajc4nyO0g1A6kGWyW56oZk0iPYJA9WtUmoj0Plvy1CGwIZrMe57X7QZcdqc3u6zjTA41Tpiqi9vnO3xbhi8o594Vx0XPXwVzpYq1ZCTYenfAGaXKkDmAFJqiVIsiCg==) (175 bytes): A port of my [entry](http://tic80.com/play?cart=1871) in the Outline'21 bytebattle final
|
||||
* [Technotunnel](v0.2.0#AhPXpq894LaUhp5+HQf39f39/Jc8g5zUrBSc0uyKh36ivskczhY84h55zL8gWpkdvKuRQI+KIt80isKzh8jkM8nILcx0RUvyk8yjE8TgNsgkcORVI0RY5k3qE4ySjaycxa2DVZH61UWZuLsCouuwT7I80TbmmetQSbMywJ/avrrCZIAH0UzQfvOiCJNG48NI0FFY1vjB7a7dcp8Uqg==) (157 bytes): A port of my [entry](https://tic80.com/play?cart=1873) in the Outline'21 bytebattle quater final
|
||||
* [Font & Palette](v0.2.0#At/p39+IBnj6ry1TRe7jzVy2A4tXgBvmoW2itzoyF2aM28pGy5QDiKxqrk8l9sbWZLtnAb+jgOfU+9QhpuyCAkhN6gPOU481IUL/df96vNe3h288Dqwhd3sfFpothIVFsMwRK72kW2hiR7zWsaXyy5pNmjR6BJk4piWx9ApT1ZwoUajhk6/zij6itq/FD1U3jj/J3MOwqZ2ef8Bv6ZPQlJIYVf62icGa69wS6SI1qBpIFiF14F8PcztRVbKIxLpT4ArCS6nz6FPnyUkqATGSBNPJ): Just a simple viewer for the default font and palette.
|
||||
|
||||
Examplers for older versions:
|
||||
|
||||
@@ -29,41 +29,24 @@ Examplers for older versions:
|
||||
|
||||
## Versions
|
||||
|
||||
### v0.1.2
|
||||
### v0.2.0
|
||||
|
||||
* [Web runtime](v0.1.2)
|
||||
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.1.2/microw8-0.1.2-linux.tgz)
|
||||
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.1.2/microw8-0.1.2-macos.tgz)
|
||||
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.1.2/microw8-0.1.2-windows.zip)
|
||||
* [Web runtime](v0.2.0)
|
||||
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.2.0/microw8-0.2.0-linux.tgz)
|
||||
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.2.0/microw8-0.2.0-macos.tgz)
|
||||
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.2.0/microw8-0.2.0-windows.zip)
|
||||
|
||||
Changes:
|
||||
|
||||
* add option to `uw8 run` to run the cart in the browser using the web runtime
|
||||
* CurlyWas: implement `include` support
|
||||
* CurlyWas: implement support for constants
|
||||
* fix crash when trying to draw zero sized line
|
||||
* [add sound support!](docs#sound)
|
||||
* add support to redirect text output to the console for debugging using control code 6
|
||||
* update curlywas:
|
||||
* * add support for `else if`
|
||||
* * add support for escape sequences in strings
|
||||
* * add support for char literals
|
||||
* * add support for binop-assignment, eg. `+=`, `^=`, `<<=` etc. (also support for the tee operator: `+:=`)
|
||||
* * "integer constant cast to float" literal syntax in CurlyWas (ex. `1_f` is equivalent to `1 as f32`)
|
||||
|
||||
### v0.1.1
|
||||
### Older versions
|
||||
|
||||
* [Web runtime](v0.1.1)
|
||||
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.1.1/microw8-0.1.1-linux.tgz)
|
||||
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.1.1/microw8-0.1.1-macos.tgz)
|
||||
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.1.1/microw8-0.1.1-windows.zip)
|
||||
|
||||
Changes:
|
||||
|
||||
* implement more robust file watcher
|
||||
* add basic video recording on F10 in web runtime
|
||||
* add screenshot on F9
|
||||
* add watchdog to interrupt hanging update in native runtime
|
||||
* add devkit mode to web runtime
|
||||
* add unpack and compile commands to uw8
|
||||
* add support for table/element section in pack command
|
||||
* disable wayland support (caused missing window decorations in gnome)
|
||||
|
||||
### v0.1.0
|
||||
|
||||
* [Web runtime](v0.1.0)
|
||||
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.1.0/microw8-0.1.0-linux.tgz)
|
||||
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.1.0/microw8-0.1.0-macos.tgz)
|
||||
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.1.0/microw8-0.1.0-windows.zip)
|
||||
[Find older versions here.](versions)
|
||||
@@ -19,10 +19,11 @@ The memory has to be imported as `env` `memory` and has a maximum size of 256kb
|
||||
00040-00044: time since module start in ms
|
||||
00044-0004c: gamepad state
|
||||
0004c-00050: reserved
|
||||
00050-00070: sound registers
|
||||
00050-00070: sound data (synced to sound thread)
|
||||
00070-00078: reserved
|
||||
00078-12c78: frame buffer
|
||||
12c78-13000: reserved
|
||||
12c78-12c7c: sound registers/work area base address (for sndGes function)
|
||||
12c7c-13000: reserved
|
||||
13000-13400: palette
|
||||
13400-13c00: font
|
||||
13c00-14000: reserved
|
||||
@@ -224,29 +225,45 @@ Moving/printing past any border does not cause any special operation, the cursor
|
||||
Characters 0-31 are control characters and don't print by default. They take the next 0-2 following characters as parameters.
|
||||
Avoid the reserved control chars, they are currently NOPs but their behavior can change in later MicroW8 versions.
|
||||
|
||||
| Code | Parameters | Operation |
|
||||
| ----- | ---------- | ------------------------------------ |
|
||||
| 0 | - | Nop |
|
||||
| 1 | char | Print char (including control chars) |
|
||||
| 2-3 | - | Reserved |
|
||||
| 4 | - | Switch to normal mode |
|
||||
| 5 | - | Switch to graphics mode |
|
||||
| 6-7 | - | Reserved |
|
||||
| 8 | - | Move cursor left |
|
||||
| 9 | - | Move cursor right |
|
||||
| 10 | - | Move cursor down |
|
||||
| 11 | - | Move cursor up |
|
||||
| 12 | - | do `cls(background_color)` |
|
||||
| 13 | - | Move cursor to the left border |
|
||||
| 14 | color | Set the background color |
|
||||
| 15 | color | Set the text color |
|
||||
| 16-23 | - | Reserved |
|
||||
| 24 | - | Swap text/background colors |
|
||||
| 25-30 | - | Reserved |
|
||||
| 31 | x, y | Set cursor position (*) |
|
||||
| Code | Parameters | Operation |
|
||||
| ----- | ---------- | ------------------------------------------ |
|
||||
| 0 | - | Nop |
|
||||
| 1 | char | Print char (including control chars) |
|
||||
| 2-3 | - | Reserved |
|
||||
| 4 | - | Switch to normal mode, reset cursor to 0,0 |
|
||||
| 5 | - | Switch to graphics mode |
|
||||
| 6 | - | Switch output to (debug) console |
|
||||
| 7 | - | Bell / trigger sound channel 0 |
|
||||
| 8 | - | Move cursor left |
|
||||
| 9 | - | Move cursor right |
|
||||
| 10 | - | Move cursor down |
|
||||
| 11 | - | Move cursor up |
|
||||
| 12 | - | do `cls(background_color)` |
|
||||
| 13 | - | Move cursor to the left border |
|
||||
| 14 | color | Set the background color |
|
||||
| 15 | color | Set the text color |
|
||||
| 16-23 | - | Reserved |
|
||||
| 24 | - | Swap text/background colors |
|
||||
| 25-30 | - | Reserved |
|
||||
| 31 | x, y | Set cursor position (*) |
|
||||
|
||||
(*) In graphics mode, the x coordinate is doubled when using control char 31 to be able to cover the whole screen with one byte.
|
||||
|
||||
#### Debug output
|
||||
|
||||
Control code 6 switches all text output (except codes 4 and 5 to switch output back to the screen) to the console. Where exactly this ends
|
||||
up (if at all) is an implementation detail of the runtimes. The native dev-runtime writes the debug output to `stdout`, the web runtime to
|
||||
the debug console using `console.log`. Both implementation buffer the output until they encounter a newline character (10) in the output stream.
|
||||
|
||||
There may be future runtimes that ignore the debug output completely.
|
||||
|
||||
In CurlyWas, a simple way to log some value might look like this:
|
||||
```
|
||||
printChar('\06V: '); // switch to console out, print some prefix
|
||||
printInt(some_value);
|
||||
printChar('\n\4'); // newline and switch back to screen
|
||||
```
|
||||
|
||||
### fn printChar(char: i32)
|
||||
|
||||
Prints the character in the lower 8 bits of `char`. If the upper 24 bits are non-zero, right-shifts `char` by 8 bits and loops back to the beginning.
|
||||
@@ -273,34 +290,126 @@ Sets the cursor position. In normal mode `x` and `y` are multiplied by 8 to get
|
||||
|
||||
## Sound
|
||||
|
||||
### Low level operation
|
||||
|
||||
MicroW8 actually runs two instances of your module. On the first instance, it calls `upd` and displays the framebuffer found in its memory. On the
|
||||
second instance, it calls `snd` instead with an incrementing sample index and expects that function to return sound samples for the left and right
|
||||
channel at 44100 Hz. If your module does not export a `snd` function, it calls the api function `sndGes` instead.
|
||||
|
||||
As the only means of communication, 32 bytes starting at address 0x00050 are copied from main to sound memory after `upd` returns.
|
||||
|
||||
By default, the `sndGes` function generates sound based on the 32 bytes at 0x00050. This means that in the default configuration those 32 bytes act
|
||||
as sound registers. See the `sndGes` function for the meaning of those registers.
|
||||
|
||||
### export fn snd(sampleIndex: i32) -> f32
|
||||
|
||||
If the module exports a `snd` function, it is called 88200 times per second to provide PCM sample data for playback (44.1kHz stereo).
|
||||
The `sampleIndex` will start at 0 and increments by 1 for each call. On even indices the function is expected to return a sample value for
|
||||
the left channel, on odd indices for the right channel.
|
||||
|
||||
### fn playNote(channel: i32, note: i32)
|
||||
|
||||
Triggers a note (1-127) on the given channel (0-3). Notes are semitones with 69 being A4 (same as MIDI). A note value of 0 stops the
|
||||
sound playing on that channel. A note value 128-255 will trigger note-128 and immediately stop it (playing attack+release parts of envelope).
|
||||
|
||||
This function assumes the default setup, with the `sndGes` registers located at 0x00050.
|
||||
|
||||
### fn sndGes(sampleIndex: i32) -> f32
|
||||
|
||||
This implements a sound chip, generating sound based on 32 bytes of sound registers.
|
||||
|
||||
The spec of this sound chip are:
|
||||
|
||||
- 4 channels with individual volume control (0-15)
|
||||
- rect, saw, tri, noise wave forms selectable per channel
|
||||
- each wave form supports some kind of pulse width modulation
|
||||
- each channel has an optional automatic low pass filter, or can be sent to one of two manually controllable filters
|
||||
- each channel can select between a narrow and a wide stereo positioning. The two stereo positions of each channel are fixed.
|
||||
- optional ring modulation
|
||||
|
||||
This function requires 1024 bytes of working memory, the first 32 bytes of which are interpreted as the sound registers.
|
||||
The base address of its working memory can be configured by writing the address to 0x12c78. It defaults to 0x00050.
|
||||
|
||||
Here is a short description of the 32 sound registers.
|
||||
|
||||
```
|
||||
Per channel:
|
||||
00 - CTRL0
|
||||
06 - CTRL1
|
||||
0c - CTRL2
|
||||
12 - CTRL3
|
||||
| 7 6 | 5 | 4 | 3 2 | 1 | 0 |
|
||||
| wave | ring | wide | filter | trigger | note on |
|
||||
|
||||
00 : CTRL - wave form, ring, sync, filter send, trigger
|
||||
bit 0: note on flag
|
||||
bit 1: note trigger
|
||||
bit 2,3: filter 0,1 send
|
||||
bit 6,7: wave form (rect, saw, tri, noise)
|
||||
01 : PULS - pulse width
|
||||
02 : FINE - fine tuning
|
||||
03 : NOTE - note
|
||||
04 : ENVA - attack, decay
|
||||
05 : ENVR - sustain, release
|
||||
note on: stay in decay/sustain part of envelope
|
||||
trigger: the attack part of the envlope is triggered when either this changes
|
||||
or note on is changed from 0 to 1.
|
||||
filter : 0 - no filter
|
||||
1 - fixed 6db 1-pole filter with cutoff two octaves above note
|
||||
2 - programmable filter 0
|
||||
3 - programmable filter 1
|
||||
wide : use wide stereo panning
|
||||
ring : ring modulate with triangle wave at frequency of previous channel
|
||||
wave : 0 - rectangle
|
||||
1 - saw
|
||||
2 - triangle
|
||||
3 - noise
|
||||
|
||||
50-56: channel 0
|
||||
56-5b: channel 1
|
||||
5c-61: channel 2
|
||||
62-67: channel 3
|
||||
01 - PULS0
|
||||
07 - PULS1
|
||||
0d - PULS2
|
||||
13 - PULS3
|
||||
Pulse width 0-255, with 0 being the plain version of each wave form.
|
||||
rectangle - 50%-100% pulse width
|
||||
saw - inverts 0%-100% of the saw wave form around the center
|
||||
triangle - morphs into an octave up triangle wave
|
||||
noise - blends into a decimated saw wave (just try it out)
|
||||
|
||||
68: VO01 - volumes channel 0&1
|
||||
69: VO23 - volumes channel 2&3
|
||||
02 - FINE0
|
||||
08 - FINE1
|
||||
0e - FINE2
|
||||
14 - FINE3
|
||||
Fractional note
|
||||
|
||||
6a : FCTR 0 - type, resonance
|
||||
6b : FCTR 1 - type, resonance
|
||||
6c : FFIN 0 - cutoff fine tuning
|
||||
6d : FNOT 0 - cutoff note
|
||||
6e : FFIN 1 - cutoff fine tuning
|
||||
6f : FNOT 1 - cutoff note
|
||||
03 - NOTE0
|
||||
09 - NOTE1
|
||||
0f - NOTE2
|
||||
15 - NOTE3
|
||||
Note, 69 = A4
|
||||
|
||||
04 - ENVA0
|
||||
0a - ENVA1
|
||||
10 - ENVA2
|
||||
16 - ENVA3
|
||||
| 7 6 5 4 | 3 2 1 0 |
|
||||
| decay | attack |
|
||||
|
||||
05 - ENVB0
|
||||
0b - ENVB1
|
||||
11 - ENVB2
|
||||
17 - ENVB3
|
||||
| 7 6 5 4 | 3 2 1 0 |
|
||||
| release | sustain |
|
||||
|
||||
18 - VO01
|
||||
| 7 6 5 4 | 3 2 1 0 |
|
||||
| volume 1 | volume 0 |
|
||||
|
||||
19 - VO23
|
||||
| 7 6 5 4 | 3 2 1 0 |
|
||||
| volume 3 | volume 2 |
|
||||
|
||||
1a - FCTR0
|
||||
1b - FCTR1
|
||||
| 7 6 5 4 | 3 | 2 | 1 | 0 |
|
||||
| resonance | 0 | band | high | low |
|
||||
|
||||
1c - FFIN0
|
||||
1e - FFIN1
|
||||
cutoff frequency - fractional note
|
||||
|
||||
1d - FNOT0
|
||||
1f - FNOT1
|
||||
cutoff frequency - note
|
||||
```
|
||||
|
||||
# The `uw8` tool
|
||||
|
||||
105
site/content/versions.md
Normal file
105
site/content/versions.md
Normal file
@@ -0,0 +1,105 @@
|
||||
+++
|
||||
description = "Versions"
|
||||
+++
|
||||
|
||||
### v0.2.0
|
||||
|
||||
* [Web runtime](v0.2.0)
|
||||
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.2.0/microw8-0.2.0-linux.tgz)
|
||||
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.2.0/microw8-0.2.0-macos.tgz)
|
||||
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.2.0/microw8-0.2.0-windows.zip)
|
||||
|
||||
Changes:
|
||||
|
||||
* [add sound support!](docs#sound)
|
||||
* add support to redirect text output to the console for debugging using control code 6
|
||||
* update curlywas:
|
||||
* * add support for `else if`
|
||||
* * add support for escape sequences in strings
|
||||
* * add support for char literals
|
||||
* * add support for binop-assignment, eg. `+=`, `^=`, `<<=` etc. (also support for the tee operator: `+:=`)
|
||||
* * "integer constant cast to float" literal syntax in CurlyWas (ex. `1_f` is equivalent to `1 as f32`)
|
||||
|
||||
### v0.2.0-rc3
|
||||
|
||||
* [Web runtime](v0.2.0-rc3)
|
||||
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.2.0-rc3/microw8-0.2.0-rc3-linux.tgz)
|
||||
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.2.0-rc3/microw8-0.2.0-rc3-macos.tgz)
|
||||
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.2.0-rc3/microw8-0.2.0-rc3-windows.zip)
|
||||
|
||||
Changes:
|
||||
|
||||
* improve timing stability some more. essentially now guaranteeing that "frame = time_ms * 6 / 100" returns
|
||||
consecutive frame numbers, provided the module can be run at 60 fps
|
||||
* add support to redirect text output to the console for debugging using control code 6
|
||||
* update curlywas:
|
||||
* * add support for `else if`
|
||||
* * add support for escape sequences in strings
|
||||
* * add support for char literals
|
||||
* * add support for binop-assignment, eg. `+=`, `^=`, `<<=` etc. (also support for the tee operator: `+:=`)
|
||||
|
||||
### v0.2.0-rc2
|
||||
|
||||
* [Web runtime](v0.2.0-rc2)
|
||||
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.2.0-rc2/microw8-0.2.0-rc2-linux.tgz)
|
||||
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.2.0-rc2/microw8-0.2.0-rc2-macos.tgz)
|
||||
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.2.0-rc2/microw8-0.2.0-rc2-windows.zip)
|
||||
|
||||
Changes:
|
||||
|
||||
* fix timing issues of sound playback, especially on systems with large sound buffers
|
||||
|
||||
### v0.2.0-rc1
|
||||
|
||||
* [Web runtime](v0.2.0-rc1)
|
||||
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.2.0-rc1/microw8-0.2.0-rc1-linux.tgz)
|
||||
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.2.0-rc1/microw8-0.2.0-rc1-macos.tgz)
|
||||
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.2.0-rc1/microw8-0.2.0-rc1-windows.zip)
|
||||
|
||||
Changes:
|
||||
|
||||
* [add sound support](docs#sound)
|
||||
* "integer constant cast to float" literal syntax in CurlyWas (ex. `1_f` is equivalent to `1 as f32`)
|
||||
|
||||
Known issues:
|
||||
|
||||
* timing accuracy/update frequency of sound support currently depends on sound buffer size
|
||||
|
||||
### v0.1.2
|
||||
|
||||
* [Web runtime](v0.1.2)
|
||||
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.1.2/microw8-0.1.2-linux.tgz)
|
||||
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.1.2/microw8-0.1.2-macos.tgz)
|
||||
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.1.2/microw8-0.1.2-windows.zip)
|
||||
|
||||
Changes:
|
||||
|
||||
* add option to `uw8 run` to run the cart in the browser using the web runtime
|
||||
* CurlyWas: implement `include` support
|
||||
* CurlyWas: implement support for constants
|
||||
* fix crash when trying to draw zero sized line
|
||||
|
||||
### v0.1.1
|
||||
|
||||
* [Web runtime](v0.1.1)
|
||||
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.1.1/microw8-0.1.1-linux.tgz)
|
||||
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.1.1/microw8-0.1.1-macos.tgz)
|
||||
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.1.1/microw8-0.1.1-windows.zip)
|
||||
|
||||
Changes:
|
||||
|
||||
* implement more robust file watcher
|
||||
* add basic video recording on F10 in web runtime
|
||||
* add screenshot on F9
|
||||
* add watchdog to interrupt hanging update in native runtime
|
||||
* add devkit mode to web runtime
|
||||
* add unpack and compile commands to uw8
|
||||
* add support for table/element section in pack command
|
||||
* disable wayland support (caused missing window decorations in gnome)
|
||||
|
||||
### v0.1.0
|
||||
|
||||
* [Web runtime](v0.1.0)
|
||||
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.1.0/microw8-0.1.0-linux.tgz)
|
||||
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.1.0/microw8-0.1.0-macos.tgz)
|
||||
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.1.0/microw8-0.1.0-windows.zip)
|
||||
1
site/static/v0.2.0-rc1/index.html
Normal file
1
site/static/v0.2.0-rc1/index.html
Normal file
File diff suppressed because one or more lines are too long
1
site/static/v0.2.0-rc2/index.html
Normal file
1
site/static/v0.2.0-rc2/index.html
Normal file
File diff suppressed because one or more lines are too long
1
site/static/v0.2.0-rc3/index.html
Normal file
1
site/static/v0.2.0-rc3/index.html
Normal file
File diff suppressed because one or more lines are too long
1
site/static/v0.2.0/index.html
Normal file
1
site/static/v0.2.0/index.html
Normal file
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@
|
||||
<section>
|
||||
<h1 class="text-center heading-text">A WebAssembly based fantasy console</h1>
|
||||
</section>
|
||||
<a href="v0.1.2">
|
||||
<a href="v0.2.0">
|
||||
<img class="demonstration-gif" style="width:640px;height:480px;image-rendering:pixelated" src="img/technotunnel.png"></img>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
14
src/main.rs
14
src/main.rs
@@ -15,6 +15,10 @@ use uw8::Runtime;
|
||||
fn main() -> Result<()> {
|
||||
let mut args = Arguments::from_env();
|
||||
|
||||
// try to enable ansi support in win10 cmd shell
|
||||
#[cfg(target_os = "windows")]
|
||||
let _ = ansi_term::enable_ansi_support();
|
||||
|
||||
match args.subcommand()?.as_deref() {
|
||||
Some("version") => {
|
||||
println!("{}", env!("CARGO_PKG_VERSION"));
|
||||
@@ -75,6 +79,8 @@ fn run(mut args: Arguments) -> Result<()> {
|
||||
#[cfg(not(feature = "native"))]
|
||||
let run_browser = args.contains(["-b", "--browser"]) || true;
|
||||
|
||||
let disable_audio = args.contains(["-m", "--disable-audio"]);
|
||||
|
||||
let filename = args.free_from_os_str::<PathBuf, bool>(|s| Ok(s.into()))?;
|
||||
|
||||
let mut watcher = uw8::FileWatcher::new()?;
|
||||
@@ -85,7 +91,13 @@ fn run(mut args: Arguments) -> Result<()> {
|
||||
#[cfg(not(feature = "native"))]
|
||||
unimplemented!();
|
||||
#[cfg(feature = "native")]
|
||||
Box::new(MicroW8::new()?)
|
||||
{
|
||||
let mut microw8 = MicroW8::new()?;
|
||||
if disable_audio {
|
||||
microw8.disable_audio();
|
||||
}
|
||||
Box::new(microw8)
|
||||
}
|
||||
} else {
|
||||
#[cfg(not(feature = "browser"))]
|
||||
unimplemented!();
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,9 +1,11 @@
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::{mpsc, Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
use std::{thread, time::Instant};
|
||||
|
||||
use anyhow::Result;
|
||||
use anyhow::{anyhow, Result};
|
||||
use cpal::traits::*;
|
||||
use minifb::{Key, Window, WindowOptions};
|
||||
use rubato::Resampler;
|
||||
use wasmtime::{
|
||||
Engine, GlobalType, Memory, MemoryType, Module, Mutability, Store, TypedFunc, ValType,
|
||||
};
|
||||
@@ -26,16 +28,19 @@ pub struct MicroW8 {
|
||||
window_buffer: Vec<u32>,
|
||||
instance: Option<UW8Instance>,
|
||||
timeout: u32,
|
||||
disable_audio: bool,
|
||||
}
|
||||
|
||||
struct UW8Instance {
|
||||
store: Store<()>,
|
||||
memory: Memory,
|
||||
end_frame: TypedFunc<(), ()>,
|
||||
update: TypedFunc<(), ()>,
|
||||
update: Option<TypedFunc<(), ()>>,
|
||||
start_time: Instant,
|
||||
next_frame: Instant,
|
||||
module: Vec<u8>,
|
||||
watchdog: Arc<Mutex<UW8WatchDog>>,
|
||||
sound: Option<Uw8Sound>,
|
||||
}
|
||||
|
||||
impl Drop for UW8Instance {
|
||||
@@ -54,6 +59,9 @@ struct UW8WatchDog {
|
||||
|
||||
impl MicroW8 {
|
||||
pub fn new() -> Result<MicroW8> {
|
||||
#[cfg(target_os = "windows")]
|
||||
unsafe { winapi::um::timeapi::timeBeginPeriod(1); }
|
||||
|
||||
let engine = wasmtime::Engine::new(wasmtime::Config::new().interruptable(true))?;
|
||||
|
||||
let loader_module =
|
||||
@@ -65,8 +73,7 @@ impl MicroW8 {
|
||||
resize: true,
|
||||
..Default::default()
|
||||
};
|
||||
let mut window = Window::new("MicroW8", 320, 240, options)?;
|
||||
window.limit_update_rate(Some(std::time::Duration::from_micros(16666)));
|
||||
let window = Window::new("MicroW8", 320, 240, options)?;
|
||||
|
||||
Ok(MicroW8 {
|
||||
engine,
|
||||
@@ -75,6 +82,7 @@ impl MicroW8 {
|
||||
window_buffer: vec![0u32; 320 * 240],
|
||||
instance: None,
|
||||
timeout: 30,
|
||||
disable_audio: false,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -84,6 +92,10 @@ impl MicroW8 {
|
||||
*v = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn disable_audio(&mut self) {
|
||||
self.disable_audio = true;
|
||||
}
|
||||
}
|
||||
|
||||
impl super::Runtime for MicroW8 {
|
||||
@@ -119,42 +131,9 @@ impl super::Runtime for MicroW8 {
|
||||
let module_length = load_uw8.call(&mut store, module_data.len() as i32)? as u32 as usize;
|
||||
let module = wasmtime::Module::new(&self.engine, &memory.data(&store)[..module_length])?;
|
||||
|
||||
linker.func_wrap("env", "acos", |v: f32| v.acos())?;
|
||||
linker.func_wrap("env", "asin", |v: f32| v.asin())?;
|
||||
linker.func_wrap("env", "atan", |v: f32| v.atan())?;
|
||||
linker.func_wrap("env", "atan2", |x: f32, y: f32| x.atan2(y))?;
|
||||
linker.func_wrap("env", "cos", |v: f32| v.cos())?;
|
||||
linker.func_wrap("env", "exp", |v: f32| v.exp())?;
|
||||
linker.func_wrap("env", "log", |v: f32| v.ln())?;
|
||||
linker.func_wrap("env", "sin", |v: f32| v.sin())?;
|
||||
linker.func_wrap("env", "tan", |v: f32| v.tan())?;
|
||||
linker.func_wrap("env", "pow", |a: f32, b: f32| a.powf(b))?;
|
||||
for i in 9..64 {
|
||||
linker.func_wrap("env", &format!("reserved{}", i), || {})?;
|
||||
}
|
||||
for i in 0..16 {
|
||||
linker.define(
|
||||
"env",
|
||||
&format!("g_reserved{}", i),
|
||||
wasmtime::Global::new(
|
||||
&mut store,
|
||||
GlobalType::new(ValType::I32, Mutability::Const),
|
||||
0.into(),
|
||||
)?,
|
||||
)?;
|
||||
}
|
||||
add_native_functions(&mut linker, &mut store)?;
|
||||
|
||||
let platform_instance = linker.instantiate(&mut store, &platform_module)?;
|
||||
|
||||
for export in platform_instance.exports(&mut store) {
|
||||
linker.define(
|
||||
"env",
|
||||
export.name(),
|
||||
export
|
||||
.into_func()
|
||||
.expect("platform surely only exports functions"),
|
||||
)?;
|
||||
}
|
||||
let platform_instance = instantiate_platform(&mut linker, &mut store, &platform_module)?;
|
||||
|
||||
let watchdog = Arc::new(Mutex::new(UW8WatchDog {
|
||||
interupt: store.interrupt_handle()?,
|
||||
@@ -187,7 +166,22 @@ impl super::Runtime for MicroW8 {
|
||||
watchdog.timeout = 0;
|
||||
}
|
||||
let end_frame = platform_instance.get_typed_func::<(), (), _>(&mut store, "endFrame")?;
|
||||
let update = instance.get_typed_func::<(), (), _>(&mut store, "upd")?;
|
||||
let update = instance.get_typed_func::<(), (), _>(&mut store, "upd").ok();
|
||||
|
||||
let sound = if self.disable_audio {
|
||||
None
|
||||
} else {
|
||||
match init_sound(&self.engine, &platform_module, &module) {
|
||||
Ok(sound) => {
|
||||
sound.stream.play()?;
|
||||
Some(sound)
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("Failed to init sound: {}", err);
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.instance = Some(UW8Instance {
|
||||
store,
|
||||
@@ -195,8 +189,10 @@ impl super::Runtime for MicroW8 {
|
||||
end_frame,
|
||||
update,
|
||||
start_time: Instant::now(),
|
||||
next_frame: Instant::now(),
|
||||
module: module_data.into(),
|
||||
watchdog,
|
||||
sound,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
@@ -206,7 +202,19 @@ impl super::Runtime for MicroW8 {
|
||||
let mut result = Ok(());
|
||||
if let Some(mut instance) = self.instance.take() {
|
||||
{
|
||||
let time = instance.start_time.elapsed().as_millis() as i32;
|
||||
if let Some(sleep) = instance.next_frame.checked_duration_since(Instant::now()) {
|
||||
std::thread::sleep(sleep);
|
||||
}
|
||||
}
|
||||
|
||||
let now = Instant::now();
|
||||
let time = (now - instance.start_time).as_millis() as i32;
|
||||
{
|
||||
let offset = ((time as u32 as i64 * 6) % 100 - 50) / 6;
|
||||
instance.next_frame = now + Duration::from_millis((16 - offset) as u64);
|
||||
}
|
||||
|
||||
{
|
||||
let mut gamepad: u32 = 0;
|
||||
for key in self.window.get_keys() {
|
||||
if let Some(index) = GAMEPAD_KEYS
|
||||
@@ -227,13 +235,25 @@ impl super::Runtime for MicroW8 {
|
||||
if let Ok(mut watchdog) = instance.watchdog.lock() {
|
||||
watchdog.timeout = self.timeout;
|
||||
}
|
||||
result = instance.update.call(&mut instance.store, ());
|
||||
if let Some(ref update) = instance.update {
|
||||
result = update.call(&mut instance.store, ());
|
||||
}
|
||||
if let Ok(mut watchdog) = instance.watchdog.lock() {
|
||||
watchdog.timeout = 0;
|
||||
}
|
||||
instance.end_frame.call(&mut instance.store, ())?;
|
||||
|
||||
let memory = instance.memory.data(&instance.store);
|
||||
|
||||
let mut sound_regs = [0u8; 32];
|
||||
sound_regs.copy_from_slice(&memory[80..112]);
|
||||
if let Some(ref sound) = instance.sound {
|
||||
sound.tx.send(RegisterUpdate {
|
||||
time,
|
||||
data: sound_regs,
|
||||
})?;
|
||||
}
|
||||
|
||||
let framebuffer = &memory[120..(120 + 320 * 240)];
|
||||
let palette = &memory[0x13000..];
|
||||
for (i, &color_index) in framebuffer.iter().enumerate() {
|
||||
@@ -258,3 +278,254 @@ impl super::Runtime for MicroW8 {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn add_native_functions(
|
||||
linker: &mut wasmtime::Linker<()>,
|
||||
store: &mut wasmtime::Store<()>,
|
||||
) -> Result<()> {
|
||||
linker.func_wrap("env", "acos", |v: f32| v.acos())?;
|
||||
linker.func_wrap("env", "asin", |v: f32| v.asin())?;
|
||||
linker.func_wrap("env", "atan", |v: f32| v.atan())?;
|
||||
linker.func_wrap("env", "atan2", |x: f32, y: f32| x.atan2(y))?;
|
||||
linker.func_wrap("env", "cos", |v: f32| v.cos())?;
|
||||
linker.func_wrap("env", "exp", |v: f32| v.exp())?;
|
||||
linker.func_wrap("env", "log", |v: f32| v.ln())?;
|
||||
linker.func_wrap("env", "sin", |v: f32| v.sin())?;
|
||||
linker.func_wrap("env", "tan", |v: f32| v.tan())?;
|
||||
linker.func_wrap("env", "pow", |a: f32, b: f32| a.powf(b))?;
|
||||
for i in 10..64 {
|
||||
linker.func_wrap("env", &format!("reserved{}", i), || {})?;
|
||||
}
|
||||
let log_line = std::sync::Mutex::new(String::new());
|
||||
linker.func_wrap("env", "logChar", move |c: i32| {
|
||||
let mut log_line = log_line.lock().unwrap();
|
||||
if c == 10 {
|
||||
println!("{}", log_line);
|
||||
log_line.clear();
|
||||
} else {
|
||||
log_line.push(c as u8 as char);
|
||||
}
|
||||
})?;
|
||||
for i in 0..16 {
|
||||
linker.define(
|
||||
"env",
|
||||
&format!("g_reserved{}", i),
|
||||
wasmtime::Global::new(
|
||||
&mut *store,
|
||||
GlobalType::new(ValType::I32, Mutability::Const),
|
||||
0.into(),
|
||||
)?,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn instantiate_platform(
|
||||
linker: &mut wasmtime::Linker<()>,
|
||||
store: &mut wasmtime::Store<()>,
|
||||
platform_module: &wasmtime::Module,
|
||||
) -> Result<wasmtime::Instance> {
|
||||
let platform_instance = linker.instantiate(&mut *store, &platform_module)?;
|
||||
|
||||
for export in platform_instance.exports(&mut *store) {
|
||||
linker.define(
|
||||
"env",
|
||||
export.name(),
|
||||
export
|
||||
.into_func()
|
||||
.expect("platform surely only exports functions"),
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(platform_instance)
|
||||
}
|
||||
|
||||
struct RegisterUpdate {
|
||||
time: i32,
|
||||
data: [u8; 32],
|
||||
}
|
||||
|
||||
struct Uw8Sound {
|
||||
stream: cpal::Stream,
|
||||
tx: mpsc::SyncSender<RegisterUpdate>,
|
||||
}
|
||||
|
||||
fn init_sound(
|
||||
engine: &wasmtime::Engine,
|
||||
platform_module: &wasmtime::Module,
|
||||
module: &wasmtime::Module,
|
||||
) -> Result<Uw8Sound> {
|
||||
let mut store = wasmtime::Store::new(engine, ());
|
||||
|
||||
let memory = wasmtime::Memory::new(&mut store, MemoryType::new(4, Some(4)))?;
|
||||
|
||||
let mut linker = wasmtime::Linker::new(engine);
|
||||
linker.define("env", "memory", memory)?;
|
||||
add_native_functions(&mut linker, &mut store)?;
|
||||
|
||||
let platform_instance = instantiate_platform(&mut linker, &mut store, platform_module)?;
|
||||
let instance = linker.instantiate(&mut store, module)?;
|
||||
|
||||
let snd = instance
|
||||
.get_typed_func::<(i32,), f32, _>(&mut store, "snd")
|
||||
.or_else(|_| platform_instance.get_typed_func::<(i32,), f32, _>(&mut store, "gesSnd"))?;
|
||||
|
||||
let host = cpal::default_host();
|
||||
let device = host
|
||||
.default_output_device()
|
||||
.ok_or_else(|| anyhow!("No audio output device available"))?;
|
||||
let mut configs: Vec<_> = device
|
||||
.supported_output_configs()?
|
||||
.filter(|config| {
|
||||
config.channels() == 2 && config.sample_format() == cpal::SampleFormat::F32
|
||||
})
|
||||
.collect();
|
||||
configs.sort_by_key(|config| {
|
||||
let rate = 44100
|
||||
.max(config.min_sample_rate().0)
|
||||
.min(config.max_sample_rate().0);
|
||||
if rate >= 44100 {
|
||||
rate - 44100
|
||||
} else {
|
||||
(44100 - rate) * 1000
|
||||
}
|
||||
});
|
||||
let config = configs
|
||||
.into_iter()
|
||||
.next()
|
||||
.ok_or_else(|| anyhow!("Could not find float output config"))?;
|
||||
let sample_rate = cpal::SampleRate(44100)
|
||||
.max(config.min_sample_rate())
|
||||
.max(config.max_sample_rate());
|
||||
let config = config.with_sample_rate(sample_rate);
|
||||
let buffer_size = match *config.buffer_size() {
|
||||
cpal::SupportedBufferSize::Unknown => cpal::BufferSize::Default,
|
||||
cpal::SupportedBufferSize::Range { min, max } => {
|
||||
cpal::BufferSize::Fixed(256.max(min).min(max))
|
||||
}
|
||||
};
|
||||
let config = cpal::StreamConfig {
|
||||
buffer_size,
|
||||
..config.config()
|
||||
};
|
||||
|
||||
let sample_rate = config.sample_rate.0 as usize;
|
||||
|
||||
let (tx, rx) = mpsc::sync_channel::<RegisterUpdate>(30);
|
||||
|
||||
struct Resampler {
|
||||
resampler: rubato::FftFixedIn<f32>,
|
||||
input_buffers: Vec<Vec<f32>>,
|
||||
output_buffers: Vec<Vec<f32>>,
|
||||
output_index: usize,
|
||||
}
|
||||
let mut resampler: Option<Resampler> = if sample_rate == 44100 {
|
||||
None
|
||||
} else {
|
||||
let rs = rubato::FftFixedIn::new(44100, sample_rate, 128, 1, 2)?;
|
||||
let input_buffers = rs.input_buffer_allocate();
|
||||
let output_buffers = rs.output_buffer_allocate();
|
||||
Some(Resampler {
|
||||
resampler: rs,
|
||||
input_buffers,
|
||||
output_buffers,
|
||||
output_index: usize::MAX,
|
||||
})
|
||||
};
|
||||
|
||||
let mut sample_index = 0;
|
||||
let mut pending_updates: Vec<RegisterUpdate> = Vec::with_capacity(30);
|
||||
let mut current_time = 0;
|
||||
let stream = device.build_output_stream(
|
||||
&config,
|
||||
move |mut outer_buffer: &mut [f32], _| {
|
||||
let mut first_update = true;
|
||||
while let Ok(update) = rx.try_recv() {
|
||||
if first_update {
|
||||
current_time += update.time.wrapping_sub(current_time) / 8;
|
||||
first_update = false;
|
||||
}
|
||||
pending_updates.push(update);
|
||||
}
|
||||
|
||||
while !outer_buffer.is_empty() {
|
||||
while pending_updates
|
||||
.first()
|
||||
.into_iter()
|
||||
.any(|u| u.time.wrapping_sub(current_time) <= 0)
|
||||
{
|
||||
let update = pending_updates.remove(0);
|
||||
memory.write(&mut store, 80, &update.data).unwrap();
|
||||
}
|
||||
|
||||
let duration = if let Some(update) = pending_updates.first() {
|
||||
((update.time.wrapping_sub(current_time) as usize) * sample_rate + 999) / 1000
|
||||
} else {
|
||||
outer_buffer.len()
|
||||
};
|
||||
let step_size = (duration.max(64) * 2).min(outer_buffer.len());
|
||||
|
||||
let mut buffer = &mut outer_buffer[..step_size];
|
||||
|
||||
{
|
||||
let mem = memory.data_mut(&mut store);
|
||||
mem[64..68].copy_from_slice(¤t_time.to_le_bytes());
|
||||
}
|
||||
|
||||
if let Some(ref mut resampler) = resampler {
|
||||
while !buffer.is_empty() {
|
||||
let copy_size = resampler.output_buffers[0]
|
||||
.len()
|
||||
.saturating_sub(resampler.output_index)
|
||||
.min(buffer.len() / 2);
|
||||
if copy_size == 0 {
|
||||
resampler.input_buffers[0].clear();
|
||||
resampler.input_buffers[1].clear();
|
||||
for _ in 0..resampler.resampler.input_frames_next() {
|
||||
resampler.input_buffers[0]
|
||||
.push(snd.call(&mut store, (sample_index,)).unwrap_or(0.0));
|
||||
resampler.input_buffers[1]
|
||||
.push(snd.call(&mut store, (sample_index + 1,)).unwrap_or(0.0));
|
||||
sample_index = sample_index.wrapping_add(2);
|
||||
}
|
||||
|
||||
resampler
|
||||
.resampler
|
||||
.process_into_buffer(
|
||||
&resampler.input_buffers,
|
||||
&mut resampler.output_buffers,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
resampler.output_index = 0;
|
||||
} else {
|
||||
for i in 0..copy_size {
|
||||
buffer[i * 2] =
|
||||
resampler.output_buffers[0][resampler.output_index + i];
|
||||
buffer[i * 2 + 1] =
|
||||
resampler.output_buffers[1][resampler.output_index + i];
|
||||
}
|
||||
resampler.output_index += copy_size;
|
||||
buffer = &mut buffer[copy_size * 2..];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for v in buffer {
|
||||
*v = snd.call(&mut store, (sample_index,)).unwrap_or(0.0);
|
||||
sample_index = sample_index.wrapping_add(1);
|
||||
}
|
||||
}
|
||||
|
||||
outer_buffer = &mut outer_buffer[step_size..];
|
||||
current_time =
|
||||
current_time.wrapping_add((step_size * 500 / sample_rate).max(1) as i32);
|
||||
}
|
||||
},
|
||||
move |err| {
|
||||
dbg!(err);
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(Uw8Sound { stream, tx })
|
||||
}
|
||||
|
||||
20
test/frame_time.cwa
Normal file
20
test/frame_time.cwa
Normal file
@@ -0,0 +1,20 @@
|
||||
include "../examples/include/microw8-api.cwa"
|
||||
|
||||
global mut pos = 0;
|
||||
global mut next = 0;
|
||||
|
||||
export fn upd() {
|
||||
let lazy t = 32!32;
|
||||
let lazy tick = t * 6 / 100;
|
||||
let lazy rel = t - tick * 100 / 6;
|
||||
|
||||
setBackgroundColor(select(tick == next, 0, select(tick < next, 0x35, 0x55)));
|
||||
setCursorPosition(pos % 13 * 3, pos / 13 % 30);
|
||||
if rel < 10 {
|
||||
printChar(32);
|
||||
}
|
||||
printInt(rel);
|
||||
|
||||
pos = pos + 1;
|
||||
next = tick + 1;
|
||||
}
|
||||
7
test/log.cwa
Normal file
7
test/log.cwa
Normal file
@@ -0,0 +1,7 @@
|
||||
include "../examples/include/microw8-api.cwa"
|
||||
|
||||
export fn upd() {
|
||||
printChar('\06f: ');
|
||||
printInt(32!32 * 6 / 100);
|
||||
printChar('\n\4');
|
||||
}
|
||||
@@ -166,6 +166,8 @@ impl BaseModule {
|
||||
|
||||
add_function(&mut functions, &type_map, "exp", &[F32], Some(F32));
|
||||
|
||||
add_function(&mut functions, &type_map, "playNote", &[I32, I32], None);
|
||||
|
||||
for i in functions.len()..64 {
|
||||
add_function(
|
||||
&mut functions,
|
||||
@@ -291,7 +293,10 @@ impl BaseModule {
|
||||
|
||||
pub fn write_as_cwa<P: AsRef<Path>>(&self, path: P) -> Result<()> {
|
||||
fn inner(mut file: File, base: &BaseModule) -> Result<()> {
|
||||
writeln!(file, "// MicroW8 APIs, to be `include`d in CurlyWas sources")?;
|
||||
writeln!(
|
||||
file,
|
||||
"// MicroW8 APIs, to be `include`d in CurlyWas sources"
|
||||
)?;
|
||||
writeln!(file, "import \"env.memory\" memory({});", base.memory)?;
|
||||
writeln!(file)?;
|
||||
for &(module, ref name, type_id) in &base.function_imports {
|
||||
@@ -402,5 +407,5 @@ const CONSTANTS: &[(&str, u32)] = &[
|
||||
("BUTTON_A", 4),
|
||||
("BUTTON_B", 5),
|
||||
("BUTTON_X", 6),
|
||||
("BUTTON_Y", 7)
|
||||
("BUTTON_Y", 7),
|
||||
];
|
||||
|
||||
@@ -3,9 +3,17 @@ class APU extends AudioWorkletProcessor {
|
||||
constructor() {
|
||||
super();
|
||||
this.sampleIndex = 0;
|
||||
this.currentTime = 0;
|
||||
this.isFirstMessage = true;
|
||||
this.pendingUpdates = [];
|
||||
this.port.onmessage = (ev) => {
|
||||
if(this.memory) {
|
||||
U8(this.memory.buffer, 80, 32).set(U8(ev.data));
|
||||
if(this.isFirstMessage)
|
||||
{
|
||||
this.currentTime += (ev.data.t - this.currentTime) / 8;
|
||||
this.isFirstMessage = false;
|
||||
}
|
||||
this.pendingUpdates.push(ev.data);
|
||||
} else {
|
||||
this.load(ev.data[0], ev.data[1]);
|
||||
}
|
||||
@@ -29,6 +37,16 @@ class APU extends AudioWorkletProcessor {
|
||||
importObject.env['reserved' + i] = () => { };
|
||||
}
|
||||
|
||||
let logLine = '';
|
||||
importObject.env['logChar'] = (c) => {
|
||||
if(c == 10) {
|
||||
console.log(logLine);
|
||||
logLine = '';
|
||||
} else {
|
||||
logLine += String.fromCharCode(c);
|
||||
}
|
||||
};
|
||||
|
||||
for (let i = 0; i < 16; ++i) {
|
||||
importObject.env['g_reserved' + i] = 0;
|
||||
}
|
||||
@@ -51,7 +69,13 @@ class APU extends AudioWorkletProcessor {
|
||||
}
|
||||
|
||||
process(inputs, outputs, parameters) {
|
||||
this.isFirstMessage = true;
|
||||
if(this.snd) {
|
||||
while(this.pendingUpdates.length > 0 && this.pendingUpdates[0].t <= this.currentTime) {
|
||||
U8(this.memory.buffer, 80, 32).set(U8(this.pendingUpdates.shift().r));
|
||||
}
|
||||
let u32Mem = new Uint32Array(this.memory.buffer);
|
||||
u32Mem[16] = this.currentTime;
|
||||
let channels = outputs[0];
|
||||
let index = this.sampleIndex;
|
||||
let numSamples = channels[0].length;
|
||||
@@ -60,6 +84,7 @@ class APU extends AudioWorkletProcessor {
|
||||
channels[1][i] = this.snd(index++);
|
||||
}
|
||||
this.sampleIndex = index & 0xffffffff;
|
||||
this.currentTime += numSamples / 44.1;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="uw8">
|
||||
<a href="https://exoticorn.github.io/microw8">MicroW8</a> 0.1.2
|
||||
<a href="https://exoticorn.github.io/microw8">MicroW8</a> 0.2.0
|
||||
</div>
|
||||
<div id="centered">
|
||||
<canvas class="screen" id="screen" width="320" height="240">
|
||||
|
||||
@@ -90,6 +90,9 @@ export default function MicroW8(screen, config = {}) {
|
||||
keyboardElement.onkeydown = keyHandler;
|
||||
keyboardElement.onkeyup = keyHandler;
|
||||
}
|
||||
|
||||
let audioContext;
|
||||
let audioNode;
|
||||
|
||||
async function runModule(data, keepUrl) {
|
||||
if (cancelFunction) {
|
||||
@@ -97,12 +100,14 @@ export default function MicroW8(screen, config = {}) {
|
||||
cancelFunction = null;
|
||||
}
|
||||
|
||||
let audioContext = new AudioContext({sampleRate: 44100});
|
||||
audioContext = new AudioContext({sampleRate: 44100});
|
||||
let keepRunning = true;
|
||||
let abortController = new AbortController();
|
||||
cancelFunction = () => {
|
||||
audioContext.close();
|
||||
keepRunning = false;
|
||||
}
|
||||
abortController.abort();
|
||||
};
|
||||
|
||||
let cartridgeSize = data.byteLength;
|
||||
|
||||
@@ -112,7 +117,7 @@ export default function MicroW8(screen, config = {}) {
|
||||
}
|
||||
|
||||
await audioContext.audioWorklet.addModule(audioWorkletUrl);
|
||||
let audioNode = new AudioNode(audioContext);
|
||||
audioNode = new AudioNode(audioContext);
|
||||
|
||||
let audioReadyFlags = 0;
|
||||
let audioReadyResolve;
|
||||
@@ -124,7 +129,6 @@ export default function MicroW8(screen, config = {}) {
|
||||
audioReadyResolve = null;
|
||||
}
|
||||
};
|
||||
audioNode.port.onmessage = (e) => updateAudioReady(e.data);
|
||||
let audioStateChange = () => {
|
||||
if(audioContext.state == 'suspended') {
|
||||
if(config.startButton) {
|
||||
@@ -202,6 +206,16 @@ export default function MicroW8(screen, config = {}) {
|
||||
importObject.env['reserved' + i] = () => { };
|
||||
}
|
||||
|
||||
let logLine = '';
|
||||
importObject.env['logChar'] = (c) => {
|
||||
if(c == 10) {
|
||||
console.log(logLine);
|
||||
logLine = '';
|
||||
} else {
|
||||
logLine += String.fromCharCode(c);
|
||||
}
|
||||
};
|
||||
|
||||
for (let i = 0; i < 16; ++i) {
|
||||
importObject.env['g_reserved' + i] = 0;
|
||||
}
|
||||
@@ -209,6 +223,8 @@ export default function MicroW8(screen, config = {}) {
|
||||
data = loadModuleData(data);
|
||||
|
||||
let platform_data = await loadModuleURL(platformUrl);
|
||||
|
||||
audioNode.port.onmessage = (e) => updateAudioReady(e.data);
|
||||
audioNode.port.postMessage([platform_data, data]);
|
||||
|
||||
let platform_instance = await instantiate(platform_data);
|
||||
@@ -226,19 +242,36 @@ export default function MicroW8(screen, config = {}) {
|
||||
let startTime = Date.now();
|
||||
|
||||
const timePerFrame = 1000 / 60;
|
||||
let nextFrame = startTime;
|
||||
|
||||
audioNode.connect(audioContext.destination);
|
||||
|
||||
|
||||
let isPaused = false;
|
||||
let pauseTime = startTime;
|
||||
let updateVisibility = isVisible => {
|
||||
let now = Date.now();
|
||||
if(isVisible) {
|
||||
isPaused = false;
|
||||
audioContext.resume();
|
||||
startTime += now - pauseTime;
|
||||
} else {
|
||||
isPaused = true;
|
||||
audioContext.suspend();
|
||||
pauseTime = now;
|
||||
}
|
||||
};
|
||||
window.addEventListener('focus', () => updateVisibility(true), { signal: abortController.signal });
|
||||
window.addEventListener('blur', () => updateVisibility(false), { signal: abortController.signal });
|
||||
updateVisibility(document.hasFocus());
|
||||
|
||||
function mainloop() {
|
||||
if (!keepRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
let now = Date.now();
|
||||
let restart = false;
|
||||
if (now >= nextFrame) {
|
||||
let thisFrame;
|
||||
if (!isPaused) {
|
||||
let gamepads = navigator.getGamepads();
|
||||
let gamepad = 0;
|
||||
for (let i = 0; i < 4; ++i) {
|
||||
@@ -266,7 +299,8 @@ export default function MicroW8(screen, config = {}) {
|
||||
}
|
||||
|
||||
let u32Mem = U32(memory.buffer);
|
||||
u32Mem[16] = now - startTime;
|
||||
let time = Date.now() - startTime;
|
||||
u32Mem[16] = time;
|
||||
u32Mem[17] = pad | gamepad;
|
||||
if(instance.exports.upd) {
|
||||
instance.exports.upd();
|
||||
@@ -275,20 +309,26 @@ export default function MicroW8(screen, config = {}) {
|
||||
|
||||
let soundRegisters = new ArrayBuffer(32);
|
||||
U8(soundRegisters).set(U8(memory.buffer, 80, 32));
|
||||
audioNode.port.postMessage(soundRegisters, [soundRegisters]);
|
||||
audioNode.port.postMessage({t: time, r: soundRegisters}, [soundRegisters]);
|
||||
|
||||
let palette = U32(memory.buffer, 0x13000, 1024);
|
||||
for (let i = 0; i < 320 * 240; ++i) {
|
||||
buffer[i] = palette[memU8[i + 120]] | 0xff000000;
|
||||
}
|
||||
canvasCtx.putImageData(imageData, 0, 0);
|
||||
nextFrame = Math.max(nextFrame + timePerFrame, now);
|
||||
|
||||
let timeOffset = ((time * 6) % 100 - 50) / 6;
|
||||
thisFrame = startTime + time - timeOffset / 8;
|
||||
} else {
|
||||
thisFrame = Date.now();
|
||||
}
|
||||
let now = Date.now();
|
||||
let nextFrame = Math.max(thisFrame + timePerFrame, now);
|
||||
|
||||
if (restart) {
|
||||
runModule(currentData);
|
||||
} else {
|
||||
window.requestAnimationFrame(mainloop);
|
||||
window.setTimeout(mainloop, nextFrame - now)
|
||||
}
|
||||
} catch (err) {
|
||||
config.setMessage(cartridgeSize, err.toString());
|
||||
@@ -311,14 +351,25 @@ export default function MicroW8(screen, config = {}) {
|
||||
|
||||
let videoRecorder;
|
||||
let videoStartTime;
|
||||
let videoAudioSourceNode;
|
||||
let videoAudioStreamNode;
|
||||
function recordVideo() {
|
||||
if(videoRecorder) {
|
||||
videoRecorder.stop();
|
||||
videoRecorder = null;
|
||||
videoAudioSourceNode.disconnect(videoAudioStreamNode);
|
||||
videoAudioSourceNode = null;
|
||||
videoAudioStreamNode = null;
|
||||
return;
|
||||
}
|
||||
|
||||
let stream = screen.captureStream();
|
||||
videoAudioStreamNode = audioContext.createMediaStreamDestination();
|
||||
videoAudioSourceNode = audioNode;
|
||||
audioNode.connect(videoAudioStreamNode);
|
||||
stream.addTrack(videoAudioStreamNode.stream.getAudioTracks()[0]);
|
||||
|
||||
videoRecorder = new MediaRecorder(screen.captureStream(), {
|
||||
videoRecorder = new MediaRecorder(stream, {
|
||||
mimeType: 'video/webm',
|
||||
videoBitsPerSecond: 25000000
|
||||
});
|
||||
|
||||
4559
web/yarn.lock
4559
web/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user