rewrite player, start db
|
@ -1,13 +0,0 @@
|
||||||
# Editor configuration, see http://editorconfig.org
|
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
charset = utf-8
|
|
||||||
indent_style = tab
|
|
||||||
indent_size = 4
|
|
||||||
insert_final_newline = true
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
|
|
||||||
[*.md]
|
|
||||||
max_line_length = off
|
|
||||||
trim_trailing_whitespace = false
|
|
|
@ -1,56 +0,0 @@
|
||||||
{
|
|
||||||
"root": true,
|
|
||||||
"ignorePatterns": [
|
|
||||||
"**/*"
|
|
||||||
],
|
|
||||||
"plugins": [
|
|
||||||
"@nx"
|
|
||||||
],
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"files": [
|
|
||||||
"*.ts",
|
|
||||||
"*.tsx",
|
|
||||||
"*.js",
|
|
||||||
"*.jsx"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"@nx/enforce-module-boundaries": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"enforceBuildableLibDependency": true,
|
|
||||||
"allow": [],
|
|
||||||
"depConstraints": [
|
|
||||||
{
|
|
||||||
"sourceTag": "*",
|
|
||||||
"onlyDependOnLibsWithTags": [
|
|
||||||
"*"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"files": [
|
|
||||||
"*.ts",
|
|
||||||
"*.tsx"
|
|
||||||
],
|
|
||||||
"extends": [
|
|
||||||
"plugin:@nx/typescript"
|
|
||||||
],
|
|
||||||
"rules": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"files": [
|
|
||||||
"*.js",
|
|
||||||
"*.jsx"
|
|
||||||
],
|
|
||||||
"extends": [
|
|
||||||
"plugin:@nx/javascript"
|
|
||||||
],
|
|
||||||
"rules": {}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
6
.gitignore
vendored
|
@ -50,4 +50,8 @@ Thumbs.db
|
||||||
*.png
|
*.png
|
||||||
*.jpeg
|
*.jpeg
|
||||||
*.jpg
|
*.jpg
|
||||||
*.exr
|
*.exr
|
||||||
|
|
||||||
|
# Added by cargo
|
||||||
|
|
||||||
|
/target
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
# Add files here to ignore them from prettier formatting
|
|
||||||
/dist
|
|
||||||
/coverage
|
|
13
.prettierrc
|
@ -1,13 +0,0 @@
|
||||||
{
|
|
||||||
"parser": "typescript",
|
|
||||||
"trailingComma": "none",
|
|
||||||
"useTabs": true,
|
|
||||||
"tabWidth": 4,
|
|
||||||
"semi": false,
|
|
||||||
"singleQuote": false,
|
|
||||||
"endOfLine": "lf",
|
|
||||||
"bracketSpacing": true,
|
|
||||||
"bracketSameLine": false,
|
|
||||||
"arrowParens": "always",
|
|
||||||
"printWidth": 150
|
|
||||||
}
|
|
402
Cargo.lock
generated
Normal file
|
@ -0,0 +1,402 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bumpalo"
|
||||||
|
version = "3.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "discard"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "euterpe"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "euterpe_db"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "euterpe_dj"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "euterpe_player"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"futures-signals",
|
||||||
|
"thiserror",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "euterpe_preprocessor"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "euterpe_visualizer"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-channel"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-core"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-macro"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-signals"
|
||||||
|
version = "0.3.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3b175f2f6600dd81d92d20cf10872b03ea9df6b2513ca7f672341260dacb1ab2"
|
||||||
|
dependencies = [
|
||||||
|
"discard",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"gensym",
|
||||||
|
"log",
|
||||||
|
"pin-project",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-task"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-util"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-macro",
|
||||||
|
"futures-task",
|
||||||
|
"pin-project-lite",
|
||||||
|
"pin-utils",
|
||||||
|
"slab",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gensym"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "913dce4c5f06c2ea40fc178c06f777ac89fc6b1383e90c254fafb1abe4ba3c82"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "js-sys"
|
||||||
|
version = "0.3.69"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
|
||||||
|
dependencies = [
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.153"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project"
|
||||||
|
version = "1.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
|
||||||
|
dependencies = [
|
||||||
|
"pin-project-internal",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-internal"
|
||||||
|
version = "1.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-lite"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.79"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.36"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.197"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.197"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "slab"
|
||||||
|
version = "0.4.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.58"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "1.0.58"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "1.0.58"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen"
|
||||||
|
version = "0.2.92"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"wasm-bindgen-macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-backend"
|
||||||
|
version = "0.2.92"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
|
||||||
|
dependencies = [
|
||||||
|
"bumpalo",
|
||||||
|
"log",
|
||||||
|
"once_cell",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-futures"
|
||||||
|
version = "0.4.42"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro"
|
||||||
|
version = "0.2.92"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"wasm-bindgen-macro-support",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro-support"
|
||||||
|
version = "0.2.92"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"wasm-bindgen-backend",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-shared"
|
||||||
|
version = "0.2.92"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "web-sys"
|
||||||
|
version = "0.3.69"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
|
||||||
|
dependencies = [
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
19
Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[workspace]
|
||||||
|
members = [
|
||||||
|
"libs/dj",
|
||||||
|
"libs/euterpe",
|
||||||
|
"libs/db",
|
||||||
|
"libs/player",
|
||||||
|
"libs/preprocessor",
|
||||||
|
"libs/visualizer",
|
||||||
|
]
|
||||||
|
resolver = "2"
|
||||||
|
|
||||||
|
[workspace.dependencies]
|
||||||
|
thiserror = "1.0.58"
|
||||||
|
wasm-bindgen = "0.2.92"
|
||||||
|
futures-signals = "0.3.33"
|
||||||
|
|
||||||
|
[workspace.dependencies.web-sys]
|
||||||
|
version = "0.3.69"
|
||||||
|
features = ["AudioContext"]
|
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"babelrcRoots": [
|
|
||||||
"*"
|
|
||||||
]
|
|
||||||
}
|
|
19
libs/db/Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[package]
|
||||||
|
name = "euterpe_db"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
authors = ["Djkáťo <djkatovfx@gmail.com>"]
|
||||||
|
description = "Fully featured web player"
|
||||||
|
homepage = "https://github.com/euterpe/euterpe-source"
|
||||||
|
repository = "https://github.com/euterpe/euterpe-source"
|
||||||
|
documentation = "https://github.com/euterpe/euterpe-source"
|
||||||
|
# keywords = ["player", "web"]
|
||||||
|
# categories = ["web-programming::http-server"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
thiserror.workspace = true
|
||||||
|
wasm-bindgen.workspace = true
|
||||||
|
|
||||||
|
[dependencies.web-sys]
|
||||||
|
workspace = true
|
||||||
|
features = []
|
19
libs/dj/Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[package]
|
||||||
|
name = "euterpe_dj"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
authors = ["Djkáťo <djkatovfx@gmail.com>"]
|
||||||
|
description = "Fully featured web player"
|
||||||
|
homepage = "https://github.com/euterpe/euterpe-source"
|
||||||
|
repository = "https://github.com/euterpe/euterpe-source"
|
||||||
|
documentation = "https://github.com/euterpe/euterpe-source"
|
||||||
|
# keywords = ["player", "web"]
|
||||||
|
# categories = ["web-programming::http-server"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
thiserror.workspace = true
|
||||||
|
wasm-bindgen.workspace = true
|
||||||
|
|
||||||
|
[dependencies.web-sys]
|
||||||
|
workspace = true
|
||||||
|
features = []
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
19
libs/euterpe/Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[package]
|
||||||
|
name = "euterpe"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
authors = ["Djkáťo <djkatovfx@gmail.com>"]
|
||||||
|
description = "Fully featured web player"
|
||||||
|
homepage = "https://github.com/euterpe/euterpe-source"
|
||||||
|
repository = "https://github.com/euterpe/euterpe-source"
|
||||||
|
documentation = "https://github.com/euterpe/euterpe-source"
|
||||||
|
# keywords = ["player", "web"]
|
||||||
|
# categories = ["web-programming::http-server"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
thiserror.workspace = true
|
||||||
|
wasm-bindgen.workspace = true
|
||||||
|
|
||||||
|
[dependencies.web-sys]
|
||||||
|
workspace = true
|
||||||
|
features = []
|
16
libs/euterpe/README.md
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# Euterpe
|
||||||
|
|
||||||
|
Fully featured AudioContext music player for the web, written in Rust.
|
||||||
|
|
||||||
|
## Euterpe in production:
|
||||||
|
|
||||||
|
- Hypertrance ( [site](https://hypertrance.eu/), [repository](https://github.com/nuphory/hypertrance.eu) )
|
||||||
|
|
||||||
|
Features:
|
||||||
|
|
||||||
|
- "Local" library/database for songs, collections, artists, waveforms, artist links and much more!
|
||||||
|
- Queue and history
|
||||||
|
- Easy way to create Vector based audio visuals
|
||||||
|
- Library automatization based on folder/file structure, preprocessing and encoding media files for all platforms
|
||||||
|
- Safe. Provides wrappers for all functions that are either unsafe or don't give a success return. (very Rust inspired, yes.)
|
||||||
|
- Frontend library agnostic
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
2
libs/player-web-test/Cargo.toml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[dependencies]
|
||||||
|
euterpe_player = { path = "player", version = "*" }
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
0
libs/player-web-test/src/assets/.gitkeep
Normal file
0
libs/player-web-test/src/main.rs
Normal file
36
libs/player/Cargo.toml
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
[package]
|
||||||
|
name = "euterpe_player"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
authors = ["Djkáťo <djkatovfx@gmail.com>"]
|
||||||
|
description = "Fully featured web player"
|
||||||
|
homepage = "https://github.com/euterpe/euterpe-source"
|
||||||
|
repository = "https://github.com/euterpe/euterpe-source"
|
||||||
|
documentation = "https://github.com/euterpe/euterpe-source"
|
||||||
|
# keywords = ["player", "web"]
|
||||||
|
# categories = ["web-programming::http-server"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
thiserror.workspace = true
|
||||||
|
wasm-bindgen.workspace = true
|
||||||
|
futures-signals = "0.3.33"
|
||||||
|
wasm-bindgen-futures = "0.4.42"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[dependencies.web-sys]
|
||||||
|
features = [
|
||||||
|
"AudioContext",
|
||||||
|
"AbortController",
|
||||||
|
"Event",
|
||||||
|
"MediaElementAudioSourceNode",
|
||||||
|
"AnalyserNode",
|
||||||
|
"AudioDestinationNode",
|
||||||
|
"AudioContextState",
|
||||||
|
"HtmlAudioElement",
|
||||||
|
"BaseAudioContext",
|
||||||
|
"GainNode",
|
||||||
|
"AudioParam",
|
||||||
|
]
|
||||||
|
workspace = true
|
277
libs/player/src/lib.rs
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
use futures_signals::signal::Mutable;
|
||||||
|
use wasm_bindgen::JsValue;
|
||||||
|
use wasm_bindgen_futures::JsFuture;
|
||||||
|
use web_sys::{
|
||||||
|
AudioContext, AudioContextState, AudioNode, GainNode, HtmlAudioElement,
|
||||||
|
MediaElementAudioSourceNode,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct MusicPlayerBuilder {
|
||||||
|
audio_context: AudioContext,
|
||||||
|
audio_element: HtmlAudioElement,
|
||||||
|
gain: GainNode,
|
||||||
|
track: MediaElementAudioSourceNode,
|
||||||
|
volume: f32,
|
||||||
|
prev_node: Option<AudioNode>,
|
||||||
|
is_gain_connected: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MusicPlayerBuilder {
|
||||||
|
pub fn new(audio_element: HtmlAudioElement) -> Result<MusicPlayerBuilder, JsValue> {
|
||||||
|
if audio_element.is_undefined() {
|
||||||
|
return Err("Audio Element is undefined".into());
|
||||||
|
}
|
||||||
|
let audio_context = AudioContext::new()?;
|
||||||
|
let track = audio_context.create_media_element_source(&audio_element)?;
|
||||||
|
let gain = audio_context.create_gain()?;
|
||||||
|
Ok(MusicPlayerBuilder {
|
||||||
|
audio_context,
|
||||||
|
audio_element,
|
||||||
|
gain,
|
||||||
|
track,
|
||||||
|
volume: 1.,
|
||||||
|
prev_node: None,
|
||||||
|
is_gain_connected: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_analyzer(mut self) -> Result<MusicPlayerBuilder, JsValue> {
|
||||||
|
let analyzer = self.audio_context.create_analyser()?;
|
||||||
|
if let Some(node) = &self.prev_node {
|
||||||
|
node.connect_with_audio_node(&analyzer)?;
|
||||||
|
} else {
|
||||||
|
self.track.connect_with_audio_node(&analyzer)?;
|
||||||
|
}
|
||||||
|
self.prev_node = Some(analyzer.into());
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_custom_node(mut self, node: AudioNode) -> Result<MusicPlayerBuilder, JsValue> {
|
||||||
|
match &self.prev_node {
|
||||||
|
Some(n) => n.connect_with_audio_node(&node)?,
|
||||||
|
None => self.track.connect_with_audio_node(&node)?,
|
||||||
|
};
|
||||||
|
self.prev_node = Some(node);
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(self) -> Result<MusicPlayer, JsValue> {
|
||||||
|
if !self.is_gain_connected {
|
||||||
|
match &self.prev_node {
|
||||||
|
None => {
|
||||||
|
self.track.connect_with_audio_node(self.gain.as_ref())?;
|
||||||
|
}
|
||||||
|
Some(node) => {
|
||||||
|
node.connect_with_audio_node(self.gain.as_ref())?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if let Some(node) = &self.prev_node {
|
||||||
|
node.connect_with_audio_node(self.audio_context.destination().as_ref())?;
|
||||||
|
}
|
||||||
|
Ok(MusicPlayer {
|
||||||
|
audio_context: self.audio_context,
|
||||||
|
gain: self.gain,
|
||||||
|
volume: Mutable::new(self.volume),
|
||||||
|
audio_element: self.audio_element,
|
||||||
|
volume_cache: 0.,
|
||||||
|
current_song_duration: Mutable::new(0.),
|
||||||
|
is_playing: Mutable::new(false),
|
||||||
|
time: Mutable::new(0.),
|
||||||
|
current_song_path: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MusicPlayer {
|
||||||
|
pub current_song_duration: Mutable<f64>,
|
||||||
|
pub is_playing: Mutable<bool>,
|
||||||
|
pub time: Mutable<f32>,
|
||||||
|
pub audio_context: AudioContext,
|
||||||
|
pub audio_element: HtmlAudioElement,
|
||||||
|
pub gain: GainNode,
|
||||||
|
pub volume: Mutable<f32>,
|
||||||
|
current_song_path: Option<String>,
|
||||||
|
volume_cache: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MusicPlayer {
|
||||||
|
pub fn mute_toggle(&mut self) {
|
||||||
|
if self.gain.gain().value() == 0. {
|
||||||
|
self.unmute();
|
||||||
|
} else {
|
||||||
|
self.mute()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mute(&mut self) {
|
||||||
|
self.volume_cache = self.gain.gain().value();
|
||||||
|
/* Gentler mute, doesn't pop
|
||||||
|
gain.gain.linearRampToValueAtTime(
|
||||||
|
0,
|
||||||
|
audio_context.currentTime + 0.1
|
||||||
|
);*/
|
||||||
|
self.volume.set(0.);
|
||||||
|
self.gain.gain().set_value(0.);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unmute(&mut self) {
|
||||||
|
self.volume.set(self.volume_cache);
|
||||||
|
self.gain.gain().set_value(self.volume_cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn change_volume(&mut self, volume: f32) {
|
||||||
|
self.volume.set(volume);
|
||||||
|
self.gain.gain().set_value(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn seek(&mut self, new_time: f64) -> Result<(), ()> {
|
||||||
|
if self.audio_context.state() != AudioContextState::Running {
|
||||||
|
self.is_playing.set(false);
|
||||||
|
}
|
||||||
|
self.audio_element.set_current_time(new_time);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn play_toggle(&mut self) -> Result<(), ()> {
|
||||||
|
if self.audio_context.state() != AudioContextState::Running {
|
||||||
|
JsFuture::from(self.audio_context.resume().unwrap())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
if self.audio_element.paused() {
|
||||||
|
// try {
|
||||||
|
JsFuture::from(self.audio_element.play().unwrap())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
self.is_playing.set(true);
|
||||||
|
// } catch (e) {
|
||||||
|
self.is_playing.set(false);
|
||||||
|
// throw e
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
self.audio_element.pause().unwrap();
|
||||||
|
self.is_playing.set(false);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn play(&mut self) -> Result<&mut Self, JsValue> {
|
||||||
|
if self.is_playing.get() {
|
||||||
|
return Ok(self);
|
||||||
|
}
|
||||||
|
if self.audio_context.state() != AudioContextState::Running {
|
||||||
|
JsFuture::from(self.audio_context.resume()?).await?;
|
||||||
|
}
|
||||||
|
if self.audio_element.paused() {
|
||||||
|
// try {
|
||||||
|
JsFuture::from(self.audio_element.play()?).await?;
|
||||||
|
self.is_playing.set(true);
|
||||||
|
// } catch (e) {
|
||||||
|
self.is_playing.set(false);
|
||||||
|
// throw e
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pause(&mut self) -> Result<&mut Self, JsValue> {
|
||||||
|
self.audio_element.pause()?;
|
||||||
|
self.is_playing.set(false);
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn new_song(&mut self, path: String) -> Result<&mut Self, JsValue> {
|
||||||
|
if self.audio_context.state() != AudioContextState::Running {
|
||||||
|
JsFuture::from(self.audio_context.resume()?).await?;
|
||||||
|
}
|
||||||
|
self.audio_element.set_src(&path);
|
||||||
|
Ok(self)
|
||||||
|
/*
|
||||||
|
let good_abort_controller = AbortController::new()?;
|
||||||
|
let bad_abort_controller = AbortController::new()?;
|
||||||
|
|
||||||
|
let can_play_through: Box<dyn FnMut(_)> = Box::new(move |_: web_sys::Event| {
|
||||||
|
good_abort_controller.abort();
|
||||||
|
});
|
||||||
|
let can_play_through_cb = Closure::wrap(can_play_through);
|
||||||
|
|
||||||
|
let bad_event: Box<dyn FnMut(_)> = Box::new(move |_: web_sys::Event| {
|
||||||
|
bad_abort_controller.abort();
|
||||||
|
});
|
||||||
|
let bad_event_cb = Closure::wrap(bad_event);
|
||||||
|
|
||||||
|
self.audio_element.add_event_listener_with_callback(
|
||||||
|
"canplaythrough",
|
||||||
|
can_play_through_cb.as_ref().unchecked_ref(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
self.audio_element
|
||||||
|
.add_event_listener_with_callback("error", abort_cb.as_ref().unchecked_ref())?;
|
||||||
|
|
||||||
|
self.audio_element.remove_event_listener_with_callback(
|
||||||
|
"canplaythrough",
|
||||||
|
abort_cb.as_ref().unchecked_ref(),
|
||||||
|
)?;
|
||||||
|
self.audio_element
|
||||||
|
.remove_event_listener_with_callback("error", abort_cb.as_ref().unchecked_ref())?;
|
||||||
|
self.audio_element
|
||||||
|
.remove_event_listener_with_callback("stalled", abort_cb.as_ref().unchecked_ref())?;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Will parse the duration of the song to make it easy to display in UI
|
||||||
|
// * If somethings undefined it returns "0:00"
|
||||||
|
// */
|
||||||
|
// pub fn get_formatted_duration() {
|
||||||
|
// let dur = self.audio_element.duration;
|
||||||
|
// self.current_song_duration = self.audio_element.duration;
|
||||||
|
//
|
||||||
|
// if (dur == 0 || !dur) return "0:00";
|
||||||
|
//
|
||||||
|
// // ~ is Bitwise NOT, equivalent to Math.floor()
|
||||||
|
// let hrs = ~~(dur / 3600)
|
||||||
|
// let mins = ~~((dur % 3600) / 60)
|
||||||
|
// let secs = ~~dur % 60
|
||||||
|
//
|
||||||
|
// let ret = ""
|
||||||
|
// if (hrs > 0) {
|
||||||
|
// ret += "" + hrs + ":" + (mins < 10 ? "0" : "")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ret += "" + mins + ":" + (secs < 10 ? "0" : "")
|
||||||
|
// ret += "" + secs
|
||||||
|
// return ret
|
||||||
|
// }
|
||||||
|
// /**
|
||||||
|
// * Will parse the current time of the song to make it easy to display in UI
|
||||||
|
// * If somethings undefined it returns "0:00"
|
||||||
|
// */
|
||||||
|
fn get_formatted_current_time(time: f64) -> String {
|
||||||
|
if time == 0. {
|
||||||
|
return "0:00".to_owned();
|
||||||
|
}
|
||||||
|
let hrs = f64::floor(time / 3600.);
|
||||||
|
let mins = f64::floor((time % 3600.) / 60.);
|
||||||
|
let secs = time / 60.;
|
||||||
|
let mut res = "".to_owned();
|
||||||
|
if hrs > 0. {
|
||||||
|
res = hrs.to_string()
|
||||||
|
+ ":"
|
||||||
|
+ match mins < 10. {
|
||||||
|
true => "0",
|
||||||
|
false => "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
res = res
|
||||||
|
+ &mins.to_string()
|
||||||
|
+ ":"
|
||||||
|
+ match secs < 10. {
|
||||||
|
true => "0",
|
||||||
|
false => "",
|
||||||
|
};
|
||||||
|
res = res + &secs.to_string();
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
1
.eslintignore → libs/preprocessor/.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
|
.git
|
||||||
node_modules
|
node_modules
|
19
libs/preprocessor/Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[package]
|
||||||
|
name = "euterpe_preprocessor"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
authors = ["Djkáťo <djkatovfx@gmail.com>"]
|
||||||
|
description = "Fully featured web player"
|
||||||
|
homepage = "https://github.com/euterpe/euterpe-source"
|
||||||
|
repository = "https://github.com/euterpe/euterpe-source"
|
||||||
|
documentation = "https://github.com/euterpe/euterpe-source"
|
||||||
|
# keywords = ["player", "web"]
|
||||||
|
# categories = ["web-programming::http-server"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
thiserror.workspace = true
|
||||||
|
wasm-bindgen.workspace = true
|
||||||
|
|
||||||
|
[dependencies.web-sys]
|
||||||
|
workspace = true
|
||||||
|
features = []
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
3
libs/preprocessor/src/main.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
fn main() {
|
||||||
|
todo!();
|
||||||
|
}
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
0
libs/visualizer-web-test/src/assets/.gitkeep
Normal file
19
libs/visualizer/Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[package]
|
||||||
|
name = "euterpe_visualizer"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
authors = ["Djkáťo <djkatovfx@gmail.com>"]
|
||||||
|
description = "Fully featured web player"
|
||||||
|
homepage = "https://github.com/euterpe/euterpe-source"
|
||||||
|
repository = "https://github.com/euterpe/euterpe-source"
|
||||||
|
documentation = "https://github.com/euterpe/euterpe-source"
|
||||||
|
# keywords = ["player", "web"]
|
||||||
|
# categories = ["web-programming::http-server"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
thiserror.workspace = true
|
||||||
|
wasm-bindgen.workspace = true
|
||||||
|
|
||||||
|
[dependencies.web-sys]
|
||||||
|
workspace = true
|
||||||
|
features = []
|
0
libs/visualizer/src/lib.rs
Normal file
76
nx.json
|
@ -1,76 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "./node_modules/nx/schemas/nx-schema.json",
|
|
||||||
"affected": {
|
|
||||||
"defaultBase": "master"
|
|
||||||
},
|
|
||||||
"tasksRunnerOptions": {
|
|
||||||
"default": {
|
|
||||||
"runner": "nx/tasks-runners/default",
|
|
||||||
"options": {
|
|
||||||
"cacheableOperations": [
|
|
||||||
"build",
|
|
||||||
"lint",
|
|
||||||
"test",
|
|
||||||
"e2e"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"targetDefaults": {
|
|
||||||
"build": {
|
|
||||||
"dependsOn": [
|
|
||||||
"^build"
|
|
||||||
],
|
|
||||||
"inputs": [
|
|
||||||
"production",
|
|
||||||
"^production"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"lint": {
|
|
||||||
"inputs": [
|
|
||||||
"default",
|
|
||||||
"{workspaceRoot}/.eslintrc.json",
|
|
||||||
"{workspaceRoot}/.eslintignore"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"e2e": {
|
|
||||||
"inputs": [
|
|
||||||
"default",
|
|
||||||
"^production"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"test": {
|
|
||||||
"inputs": [
|
|
||||||
"default",
|
|
||||||
"^production"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"namedInputs": {
|
|
||||||
"default": [
|
|
||||||
"{projectRoot}/**/*",
|
|
||||||
"sharedGlobals"
|
|
||||||
],
|
|
||||||
"production": [
|
|
||||||
"default",
|
|
||||||
"!{projectRoot}/.eslintrc.json",
|
|
||||||
"!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)",
|
|
||||||
"!{projectRoot}/tsconfig.spec.json"
|
|
||||||
],
|
|
||||||
"sharedGlobals": [
|
|
||||||
"{workspaceRoot}/babel.config.json"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"workspaceLayout": {
|
|
||||||
"appsDir": "packages",
|
|
||||||
"libsDir": "packages"
|
|
||||||
},
|
|
||||||
"generators": {
|
|
||||||
"@nx/web:application": {
|
|
||||||
"style": "css",
|
|
||||||
"linter": "eslint",
|
|
||||||
"unitTestRunner": "vitest",
|
|
||||||
"e2eTestRunner": "cypress"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
10994
package-lock.json
generated
45
package.json
|
@ -1,45 +0,0 @@
|
||||||
{
|
|
||||||
"name": "@euterpe.js/source",
|
|
||||||
"version": "0.0.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"scripts": {
|
|
||||||
"format": "prettier --write '**/*.{js,ts,css,html,json,mjs}'",
|
|
||||||
"publish-player": "nx build player && cd dist/packages/player && npm publish --access=public",
|
|
||||||
"publish-visualizer": "nx build visualizer && cd dist/packages/visualizer && npm publish --access=public",
|
|
||||||
"publish-library": "nx build music-library && cd dist/packages/music-library && npm publish --access=public",
|
|
||||||
"publish-euterpe": "nx build euterpe && cd dist/packages/euterpe && npm publish --access=public",
|
|
||||||
"publish-all": "npm run publish-player && npm run publish-library && npm run publish-visualizer && npm run publish-euterpe"
|
|
||||||
},
|
|
||||||
"private": false,
|
|
||||||
"devDependencies": {
|
|
||||||
"@nx/cypress": "16.2.1",
|
|
||||||
"@nx/eslint-plugin": "16.2.1",
|
|
||||||
"@nx/js": "16.2.1",
|
|
||||||
"@nx/linter": "16.2.1",
|
|
||||||
"@nx/vite": "^16.2.1",
|
|
||||||
"@nx/web": "^16.2.1",
|
|
||||||
"@nx/workspace": "16.2.1",
|
|
||||||
"@swc/core": "~1.3.51",
|
|
||||||
"@types/node": "^20.2.1",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^5.58.0",
|
|
||||||
"@typescript-eslint/parser": "^5.58.0",
|
|
||||||
"@vitest/coverage-c8": "^0.31.0",
|
|
||||||
"@vitest/ui": "^0.31.0",
|
|
||||||
"cypress": "^12.11.0",
|
|
||||||
"eslint": "~8.15.0",
|
|
||||||
"eslint-config-prettier": "8.1.0",
|
|
||||||
"eslint-plugin-cypress": "^2.10.3",
|
|
||||||
"jsdom": "~20.0.3",
|
|
||||||
"nx": "16.2.1",
|
|
||||||
"prettier": "^2.6.2",
|
|
||||||
"swc-loader": "0.1.15",
|
|
||||||
"typescript": "~5.0.2",
|
|
||||||
"vite": "^4.3.4",
|
|
||||||
"vite-plugin-eslint": "^1.8.1",
|
|
||||||
"vite-tsconfig-paths": "^4.0.2",
|
|
||||||
"vitest": "^0.31.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"tslib": "^2.3.0"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"name": "@euterpe.js/dj",
|
|
||||||
"version": "0.0.1",
|
|
||||||
"type": "module"
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
{
|
|
||||||
"name": "dj",
|
|
||||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
||||||
"sourceRoot": "packages/dj/src",
|
|
||||||
"projectType": "library",
|
|
||||||
"targets": {
|
|
||||||
"build": {
|
|
||||||
"executor": "@nx/js:tsc",
|
|
||||||
"outputs": [
|
|
||||||
"{options.outputPath}"
|
|
||||||
],
|
|
||||||
"options": {
|
|
||||||
"outputPath": "dist/packages/dj",
|
|
||||||
"main": "packages/dj/src/index.ts",
|
|
||||||
"tsConfig": "packages/dj/tsconfig.lib.json",
|
|
||||||
"assets": [
|
|
||||||
"packages/dj/*.md"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"publish": {
|
|
||||||
"command": "node tools/scripts/publish.mjs dj {args.ver} {args.tag}",
|
|
||||||
"dependsOn": [
|
|
||||||
"build"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"lint": {
|
|
||||||
"executor": "@nx/linter:eslint",
|
|
||||||
"outputs": [
|
|
||||||
"{options.outputFile}"
|
|
||||||
],
|
|
||||||
"options": {
|
|
||||||
"lintFilePatterns": [
|
|
||||||
"packages/dj/**/*.ts"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tags": []
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "../../tsconfig.base.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "commonjs",
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"strict": true,
|
|
||||||
"noImplicitOverride": true,
|
|
||||||
"noPropertyAccessFromIndexSignature": true,
|
|
||||||
"noImplicitReturns": true,
|
|
||||||
"noFallthroughCasesInSwitch": true
|
|
||||||
},
|
|
||||||
"files": [],
|
|
||||||
"include": [],
|
|
||||||
"references": [
|
|
||||||
{
|
|
||||||
"path": "./tsconfig.lib.json"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "./tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "../../dist/out-tsc",
|
|
||||||
"declaration": true,
|
|
||||||
"types": ["node"]
|
|
||||||
},
|
|
||||||
"include": ["src/**/*.ts"],
|
|
||||||
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
|
|
||||||
}
|
|
|
@ -1,176 +0,0 @@
|
||||||
# Euterpe
|
|
||||||
|
|
||||||
Fully featured AudioContext music player for the web.
|
|
||||||
|
|
||||||
## Euterpe in production:
|
|
||||||
- Hypertrance ( [site](https://hypertrance.eu/), [repository](https://github.com/nuphory/hypertrance.eu) )
|
|
||||||
|
|
||||||
Features:
|
|
||||||
- "Local" library/database for songs, collections, artists, waveforms, artist links and much more!
|
|
||||||
- Queue and history
|
|
||||||
- Easy way to create Vector based audio visuals
|
|
||||||
- Library automatization based on folder/file structure, preprocessing and encoding media files for all platforms
|
|
||||||
- Safe. Provides wrappers for all functions that are either unsafe or don't give a success return. (very Rust inspired, yes.)
|
|
||||||
- Frontend library agnostic
|
|
||||||
|
|
||||||
## How to use:
|
|
||||||
|
|
||||||
#### Simple demo [here](https://github.com/euterpe-js/euterpe-source/tree/master/packages/euterpe-web-test)
|
|
||||||
|
|
||||||
Since this package is just a compilation of our smaller modules, you can read individual modules' tutorials on their respective npm page:
|
|
||||||
- [Euterpe Player](https://www.npmjs.com/package/@euterpe.js/player)
|
|
||||||
- [Euterpe Visualizer](https://www.npmjs.com/package/@euterpe.js/visualizer)
|
|
||||||
- [Euterpe Music Library](https://www.npmjs.com/package/@euterpe.js/music-library)
|
|
||||||
|
|
||||||
You can further check out how to automate database creation from folder structure, auto encode media for all platforms and create waveform svgs for songs here:
|
|
||||||
- [Euterpe Preprocessor](https://www.npmjs.com/package/@euterpe.js/preprocessor)
|
|
||||||
|
|
||||||
This module builds on those, and further adds functions for playing backwards, forwards and managing the queue.
|
|
||||||
|
|
||||||
First we create a database with our songs
|
|
||||||
|
|
||||||
`db.ts`
|
|
||||||
```ts
|
|
||||||
import { DB, Song, Artist, Ref, RefTo, Platforms } from "@euterpe.js/music-library"
|
|
||||||
export const db = new DB
|
|
||||||
|
|
||||||
db.add([
|
|
||||||
//The IDs are added incrementally & are 0 based., so first artists ID added is 0, next 1 etc...
|
|
||||||
//You can specify the ID manually if you want
|
|
||||||
new Artist({
|
|
||||||
name: "Machinedrum",
|
|
||||||
}),
|
|
||||||
new Artist({
|
|
||||||
name: "Tanerélle",
|
|
||||||
}),
|
|
||||||
new Artist({
|
|
||||||
name: "Mono/Poly",
|
|
||||||
}),
|
|
||||||
new Artist({
|
|
||||||
name: "IMANU",
|
|
||||||
links: [
|
|
||||||
[Platforms.Spotify, new URL("https://open.spotify.com/artist/5Y7rFm0tiJTVDzGLMzz0W1?si=DRaZyugTTIqlBHDkMGKVqA&nd=1")]
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
db.add([
|
|
||||||
new Song({
|
|
||||||
//Refrences are constructed as such. This allows to get to the artist from either collection or song
|
|
||||||
artists: [new Ref(RefTo.Artists, 2), new Ref(RefTo.Artists, 3), new Ref(RefTo.Artists, 4)],
|
|
||||||
duration: 252,
|
|
||||||
name: "Star",
|
|
||||||
remix_artists: [new Ref(RefTo.Artists, 5)],
|
|
||||||
url: new URL("http://" + window.location.host + "/Machinedrum, Tanerelle & Mono Poly - Star (IMANU Remix) final.mp3")
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Then we build our Euterpe player and assign the db to it. Then it's just a matter of creating event listeners to the dom and binding them to Euterpes functions.
|
|
||||||
|
|
||||||
`main.ts`
|
|
||||||
```ts
|
|
||||||
import { db } from "./db";
|
|
||||||
import { EuterpeBuilder } from "@euterpe.js/euterpe"
|
|
||||||
|
|
||||||
let is_seeking = false
|
|
||||||
const euterpe = new EuterpeBuilder(document.querySelector("#audio")!, db)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
document.querySelector("#seek")?.addEventListener("mouseup", (e) => {
|
|
||||||
try {
|
|
||||||
euterpe.try_seek(e.target?.valueAsNumber)
|
|
||||||
} catch {
|
|
||||||
alert("Failed seeking! " + e)
|
|
||||||
}
|
|
||||||
is_seeking = false
|
|
||||||
})
|
|
||||||
|
|
||||||
euterpe.on_song_change((_, song_name) => {
|
|
||||||
document.querySelector("#text-playing")!.innerHTML = song_name
|
|
||||||
})
|
|
||||||
|
|
||||||
document.querySelector("#previous")?.addEventListener("click", () => {
|
|
||||||
euterpe.try_previous_song_looping().catch((e) => alert(e + "Failed to change song"))
|
|
||||||
})
|
|
||||||
|
|
||||||
document.querySelector("#next")?.addEventListener("click", () => {
|
|
||||||
euterpe.try_next_song_looping().catch((e) => alert(e + "Failed to change song"))
|
|
||||||
})
|
|
||||||
|
|
||||||
document.querySelector("#mute")?.addEventListener("click", () => {
|
|
||||||
euterpe.mute()
|
|
||||||
})
|
|
||||||
|
|
||||||
document.querySelector("#unmute")?.addEventListener("click", () => {
|
|
||||||
euterpe.unmute()
|
|
||||||
})
|
|
||||||
|
|
||||||
document.querySelector("#toggle-play")?.addEventListener("click", () => {
|
|
||||||
euterpe.try_play_toggle().catch((e) => alert("failed to toggle pause/play!" + e))
|
|
||||||
})
|
|
||||||
|
|
||||||
document.querySelector("#volume")?.addEventListener("input", (e) => {
|
|
||||||
euterpe.change_volume(e.target?.valueAsNumber)
|
|
||||||
})
|
|
||||||
|
|
||||||
//disables time updates so the time slider doesn't slip away from user
|
|
||||||
document.querySelector("#seek")?.addEventListener("mousedown", () => {
|
|
||||||
is_seeking = true
|
|
||||||
})
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Then we can set up listeners to Euterpes events to keep the UI up todate as well
|
|
||||||
|
|
||||||
`main.ts`
|
|
||||||
```ts
|
|
||||||
//...
|
|
||||||
// Subscriptions to song and AudioContext changes, eg. time, name..
|
|
||||||
euterpe.on_duration_formatted((time) => {
|
|
||||||
document.querySelector("#duration")!.innerHTML = time
|
|
||||||
document.querySelector("#seek")!.max = "" + euterpe.current_song_duration
|
|
||||||
})
|
|
||||||
|
|
||||||
euterpe.on_time_tick_formatted((time) => {
|
|
||||||
document.querySelector("#current")!.innerHTML = time
|
|
||||||
})
|
|
||||||
|
|
||||||
euterpe.on_time_tick((time) => {
|
|
||||||
if (is_seeking) return
|
|
||||||
document.querySelector("#seek")!.value = "" + time
|
|
||||||
dev_queue_update()
|
|
||||||
dev_history_update()
|
|
||||||
})
|
|
||||||
|
|
||||||
euterpe.on_song_change((_, song_name) => {
|
|
||||||
document.querySelector("#text-playing")!.innerHTML = song_name
|
|
||||||
})
|
|
||||||
|
|
||||||
//preload after setting all listeners to make sure you capture the song update!
|
|
||||||
euterpe.try_preload_song(0).catch((e) => console.log(e + " Failed to preload"))
|
|
||||||
|
|
||||||
//..
|
|
||||||
function dev_queue_update() {
|
|
||||||
const p = document.querySelector("#queue-info") as HTMLParagraphElement
|
|
||||||
const dev_arr = []
|
|
||||||
for (const song of euterpe.queue) {
|
|
||||||
dev_arr.push(`Name: ${song.name}, ID: ${song.id} |`)
|
|
||||||
}
|
|
||||||
p.innerHTML = dev_arr.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
function dev_history_update() {
|
|
||||||
const p = document.querySelector("#history-info") as HTMLParagraphElement
|
|
||||||
const dev_arr = []
|
|
||||||
for (const song of euterpe.played_history) {
|
|
||||||
dev_arr.push(`Name: ${song.name}, ID: ${song.id} |`)
|
|
||||||
}
|
|
||||||
p.innerHTML = dev_arr.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
and it's done!
|
|
||||||
For vizualizer demo, or how to use the core parts of the Euterpe libraries separately, check out the individual repos readmes.
|
|
||||||
|
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
{
|
|
||||||
"name": "@euterpe.js/euterpe",
|
|
||||||
"version": "2.1.0",
|
|
||||||
"type": "module",
|
|
||||||
"description": "Fully featured solution for playing music on the web. Support for local library, audio visuals and more!",
|
|
||||||
"main": "./src/index.js",
|
|
||||||
"author": {
|
|
||||||
"name": "Djkáťo",
|
|
||||||
"email": "djkatovfx@gmail.com"
|
|
||||||
},
|
|
||||||
"license": "MIT",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/euterpe-js/euterpe-source.git"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/euterpe-js/euterpe-source/tree/master/packages/euterpe#readme",
|
|
||||||
"keywords": [
|
|
||||||
"audio",
|
|
||||||
"library",
|
|
||||||
"music-database",
|
|
||||||
"audio-player",
|
|
||||||
"webaudio",
|
|
||||||
"database",
|
|
||||||
"db"
|
|
||||||
],
|
|
||||||
"exports": {
|
|
||||||
".": {
|
|
||||||
"types": "./src/index.d.ts",
|
|
||||||
"import": "./src/index.js",
|
|
||||||
"require": "./src/lib/euterpe.js"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
{
|
|
||||||
"name": "euterpe",
|
|
||||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
||||||
"sourceRoot": "packages/euterpe/src",
|
|
||||||
"projectType": "library",
|
|
||||||
"targets": {
|
|
||||||
"build": {
|
|
||||||
"executor": "@nx/js:tsc",
|
|
||||||
"outputs": [
|
|
||||||
"{options.outputPath}"
|
|
||||||
],
|
|
||||||
"options": {
|
|
||||||
"outputPath": "dist/packages/euterpe",
|
|
||||||
"main": "packages/euterpe/src/index.ts",
|
|
||||||
"tsConfig": "packages/euterpe/tsconfig.lib.json",
|
|
||||||
"assets": [
|
|
||||||
"packages/euterpe/*.md"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"publish": {
|
|
||||||
"command": "node tools/scripts/publish.mjs euterpe {args.ver} {args.tag}",
|
|
||||||
"dependsOn": [
|
|
||||||
"build"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"lint": {
|
|
||||||
"executor": "@nx/linter:eslint",
|
|
||||||
"outputs": [
|
|
||||||
"{options.outputFile}"
|
|
||||||
],
|
|
||||||
"options": {
|
|
||||||
"lintFilePatterns": [
|
|
||||||
"packages/euterpe/**/*.ts"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tags": []
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
export function euterpe(): string {
|
|
||||||
return "euterpe"
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "../../tsconfig.base.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "ESNext",
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"strict": true,
|
|
||||||
"noImplicitOverride": true,
|
|
||||||
"noPropertyAccessFromIndexSignature": true,
|
|
||||||
"noImplicitReturns": true,
|
|
||||||
"noFallthroughCasesInSwitch": true
|
|
||||||
},
|
|
||||||
"files": [],
|
|
||||||
"include": [],
|
|
||||||
"references": [
|
|
||||||
{
|
|
||||||
"path": "./tsconfig.lib.json"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "./tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "../../dist/out-tsc",
|
|
||||||
"declaration": true,
|
|
||||||
"types": ["node"]
|
|
||||||
},
|
|
||||||
"include": ["src/**/*.ts"],
|
|
||||||
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
|
|
||||||
}
|
|