init rust lib

This commit is contained in:
Djkáťo 2023-12-22 14:05:46 +01:00
parent 4a425a30a8
commit 51f135b6fa
26 changed files with 541 additions and 541 deletions

View file

@ -1,3 +1,4 @@
/target
# Logs
logs
*.log
@ -24,7 +25,7 @@ dist-ssr
*.sw?
# public samples
public/samples/*
public/media/*
src/song_list.ts
src/db.js
# public/samples/*
# public/media/*
# src/song_list.ts
# src/db.js

View file

@ -0,0 +1,11 @@
import { LoaderConfig, T } from "hyperimport";
export default {
buildCommand: ["rustc", "--crate-type", "cdylib", "/home/djkato/Code PF/euterpe-preprocessor/src/lib.rs", "--out-dir", "build/lib.rs"],
outDir: "build/lib.rs",
symbols: {
get_fft_data: {
args: [],
returns: T.cstring
},
}
} satisfies LoaderConfig.Main;

View file

@ -0,0 +1 @@
1697374218769

View file

@ -0,0 +1,4 @@
declare module "*/lib.rs" {
const symbols: import("bun:ffi").ConvertFns<typeof import("./config.ts").default.symbols>;
export = symbols;
}

161
packages/preprocessor/Cargo.lock generated Normal file
View file

@ -0,0 +1,161 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "anyhow"
version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crossbeam-deque"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
dependencies = [
"cfg-if",
]
[[package]]
name = "either"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]]
name = "euterpe-preprocessor"
version = "0.1.0"
dependencies = [
"anyhow",
"hound",
"rayon",
"walkdir",
]
[[package]]
name = "hound"
version = "3.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f"
[[package]]
name = "memoffset"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
dependencies = [
"autocfg",
]
[[package]]
name = "rayon"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "walkdir"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View file

@ -0,0 +1,12 @@
[package]
name = "euterpe-preprocessor"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0.75"
hound = "3.5.1"
rayon = "1.8.0"
walkdir = "2.4.0"

View file

@ -0,0 +1,14 @@
# How to use
To extend the Rust library, make sure the functions you're exporting have `#[no_mangle]` derived
and they `extern "C"`. To use, just import `{func} from "./lib.rs"`.
To make sure args and return types match, go to `@types/lib.rs/config.ts`
and change the types of args and returns.
```
bun i
bun dev
```
```
open http://localhost:3000
```

Binary file not shown.

BIN
packages/preprocessor/bun.lockb Executable file

Binary file not shown.

View file

@ -0,0 +1,4 @@
preload = ["./node_modules/hyperimport/preload.ts"]
[hyperimport]
loaders = ["rs"]

View file

@ -1,75 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FFT generator</title>
</head>
<body>
<audio id="audio"></audio>
<div id="app"></div>
<script type="module" src="/src/main.ts">
</script>
<div class="button-wrapper">
<button id="analyze">Analyze!</button>
<button id="create-svg">Create svgs!</button>
<div class="button-wrapper">
<div>
<input id="upload" type="file" />
<p>Upload DB</p>
</div>
<a id="download" href="">Download DB</a>
</div>
</div>
<div class="canvas-wrapper">
<svg id="waveform-canvas" viewBox="0 0 500 500" preserveAspectRatio="none"></svg>
</div>
<style>
body {
width: 100%;
min-height: 100vh;
padding: 0;
margin: 0;
/*
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
*/
}
.button-wrapper {
display: flex;
width: 100%;
height: 4rem;
justify-content: center;
align-items: center;
}
.button-wrapper>* {
padding: 1.2rem 2rem;
width: 100%;
margin: 0 auto;
}
svg {
width: 100%;
height: 200px;
border: 1px solid black;
grid-column-start: content;
}
.canvas-wrapper {
display: grid;
grid-template-columns: 0.5fr [content] 1fr 0.5fr;
column-gap: 20px;
justify-items: stretch;
align-items: stretch;
}
</style>
</body>
</html>

View file

@ -1,22 +1,15 @@
{
"name": "@euterpe.js/preprocessor",
"private": true,
"version": "0.0.0",
"name": "euterpe-preprocessor",
"module": "src/index.ts",
"type": "module",
"scripts": {
"crawl": "cd src && node crawler.mjs",
"process": "npm run crawl && vite",
"media-process": "cd src && node media_process.js",
"serve": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"devDependencies": {
"typescript": "^5.0.2",
"vite": "^4.4.0"
"dev": "bun run --hot src/index.ts"
},
"dependencies": {
"@euterpe.js/music-library": "*",
"filehound": "^1.17.6"
"hono": "^3.7.2",
"hyperimport": "^0.1.0"
},
"devDependencies": {
"bun-types": "^0.6.2"
}
}

View file

@ -6,7 +6,7 @@
"tags": [],
"targets": {
"build": {
"executor": "@nx/vite:build",
"executor": "bun:build",
"outputs": [
"{options.outputPath}"
],
@ -24,7 +24,7 @@
}
},
"serve": {
"executor": "@nx/vite:dev-server",
"executor": "bun:dev",
"defaultConfiguration": "development",
"options": {
"buildTarget": "preprocessor:build"
@ -41,7 +41,7 @@
}
},
"preview": {
"executor": "@nx/vite:preview-server",
"executor": "bun:start",
"defaultConfiguration": "development",
"options": {
"buildTarget": "preprocessor:build"

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -0,0 +1,72 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FFT generator</title>
</head>
<body>
<audio id="audio"></audio>
<div id="app"></div>
<script type="module" src="main.ts">
</script>
<div class="button-wrapper">
<button id="regenerate">Regenerate</button>
<div>
<input id="upload" type="file" />
<p>Upload DB</p>
</div>
<a id="download" href="">Download DB</a>
</div>
<div class="canvas-wrapper">
<svg id="waveform-canvas" viewBox="0 0 500 500" preserveAspectRatio="none"></svg>
</div>
<style>
body {
width: 100%;
min-height: 100vh;
padding: 0;
margin: 0;
/*
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
*/
}
.button-wrapper {
display: flex;
width: 100%;
height: 4rem;
justify-content: center;
align-items: center;
}
.button-wrapper>* {
padding: 1.2rem 2rem;
width: 100%;
margin: 0 auto;
}
svg {
width: 100%;
height: 200px;
border: 1px solid black;
grid-column-start: content;
}
.canvas-wrapper {
display: grid;
grid-template-columns: 0.5fr [content] 1fr 0.5fr;
column-gap: 20px;
justify-items: stretch;
align-items: stretch;
}
</style>
</body>
</html>

View file

@ -0,0 +1,33 @@
document.getElementById("regenerate").addEventListener("click", async (ev) => {
result = await analyze()
download(JSON.stringify(result.db), "db.json", "text/plain")
})
document.getElementById("upload").addEventListener("change", (ev) => {
/*
audioContext.resume()
const fileReader = new FileReader()
fileReader.readAsText(ev.target.files[0])
fileReader.onload = event => {
let str = JSON.parse(event.target.result)
let new_db = from_json(str)
//-infinity get stringified to null, undo that
for (const song of new_db.songs) {
if (song.fft_data) {
for (let i = 0; i < song.fft_data.length; i++) {
if (song.fft_data[i] === null || song.fft_data[i] === undefined) song.fft_data[i] = -Infinity
}
}
}
result = { db: new_db, analyzer_node: audioContextAnalyser }
}
*/
})
function download(content, fileName, contentType) {
var a = document.querySelector("#download");
var file = new Blob([content], { type: contentType });
a.href = URL.createObjectURL(file);
a.download = fileName;
// a.click();
}

View file

@ -1,4 +0,0 @@
import filehound from "filehound"
import fs from "fs"
const songs = filehound.create().path("../public/samples").ext(["ogg"]).findSync()
fs.writeFile('songs_list.ts', `export const songs = ` + JSON.stringify(songs), 'utf8', () => { 1 + 1 })

View file

@ -1,54 +0,0 @@
import { Collection, Ref, RefTo, Song, DB, } from "@euterpe.js/music-library"
import { songs } from "./songs_list"
export function generate_db() {
console.log(songs)
// construct db
let db = new DB
let collections: string[] = new Array()
let new_songs = []
//create collections by folder names
for (let i = 0; i < songs.length; i++) {
const song = songs[i]
const last_i = song.lastIndexOf("\\")
const collection_name = song.slice(song.slice(0, last_i).lastIndexOf("\\") + 1, last_i)
/*
const foreforelast_i = song.slice(0, forelast_i - 1)
const foreforeforelast_i = song.slice(0, foreforelast_i - 1).lastIndexOf("\\")
*/
if (!collections.includes(collection_name)) {
console.log(`creating collection ${collection_name}`)
db.add([new Collection({
name: collection_name,
songs: [],
artists: [],
})])
collections.push(collection_name)
}
let col = db.collections.find(col => col.name == collection_name)!
let col_id = col.id
new_songs.push({ song: song, collection_id: col_id! })
}
//create songs
for (let i = 0; i < new_songs.length; i++) {
let song = new_songs[i]
const last_i = song.song.lastIndexOf("\\")
const name = song.song.slice(last_i + 1)
const song_url = song.song.slice(song.song.indexOf("public\\") + 7)
const db_song = new Song({
name: name.slice(0, name.lastIndexOf(".")),
artists: [],
url: new URL(`${window.location.href}${song_url}`.replaceAll("\\", "/")),
duration: 0,
remix_artists: [],
in_collection: new Ref(RefTo.Collections, song.collection_id)
})
db.add([db_song])
}
console.log(db)
return db
}

View file

@ -0,0 +1,14 @@
import { Hono } from 'hono'
import { get_fft_data } from "./lib.rs"
import { serveStatic } from 'hono/cloudflare-workers'
const app = new Hono()
app.use("/media", serveStatic({ root: "./public/media" }))
app.use("/samples", serveStatic({ root: "./public/samples" }))
app.use('/', serveStatic({ root: "./client" }))
app.get("/api/generate", (c) => {
let res = get_fft_data()
return c.json({ res })
})
export default app

View file

@ -0,0 +1,104 @@
use std::{
ffi::{c_char, CString},
path::PathBuf,
};
use anyhow::{bail, Context};
use walkdir::WalkDir;
// Actually returns JSON but ye...
#[no_mangle]
pub extern "C" fn get_fft_data() -> *mut c_char {
let files = crawl_and_analyze(PathBuf::from("../public/media"));
let SVG::from("");
return CString::new("Hello!").unwrap().into_raw();
}
struct File {
pub svg: Option<SVG>,
pub samples: Vec<i16>,
pub path_buf: PathBuf,
}
struct Points {
pub x: i16,
pub y: i16,
}
struct ViewBox {
pub h_0: i16,
pub h_max: i16,
pub w_0: i16,
pub w_max: i16,
}
impl ViewBox {
pub fn default() -> Self {
ViewBox {
h_0: 0,
w_0: 0,
h_max: 500,
w_max: 500,
}
}
}
struct SVG {
view_box: ViewBox,
points: Points,
path: Option<String>,
}
impl SVG {
fn from(samples: Vec<i16>) -> Self {}
fn mutate_points(&mut self) {}
fn catmull_rom_smooth(&mut self) {}
fn normalize(&mut self) {
// Set lowest sample value to 0, max to 1 and make it linear instead of logarythmic
}
}
fn crawl_and_analyze(root: PathBuf) -> anyhow::Result<Vec<PathBuf>> {
// Find all WAV files, return their paths
let file_paths = crawl(root)?;
let files = file_paths.into_iter().map(|p| File {
samples: get_file_samples(p).unwrap(),
svg: None,
path_buf: p,
});
bail!("")
}
fn crawl(root: PathBuf) -> anyhow::Result<Vec<PathBuf>> {
let mut file_paths = vec![];
for path in WalkDir::new(root).max_depth(5) {
if let Ok(path) = path {
if path.file_type().is_file() {
if let Some(ext) = path.path().extension() {
if ext == "wav" {
file_paths.push(path.path().to_path_buf());
}
}
}
}
}
Ok(file_paths)
}
fn get_file_samples(path: PathBuf) -> anyhow::Result<Vec<i16>> {
// Read wav file, return its samples
bail!("")
}
/*
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}*/

View file

@ -1,142 +0,0 @@
import { DB, from_json } from "@euterpe.js/music-library"
import { generate_db } from "./generate_db"
import { AudioVisualBuilder, SmoothingAlgorythm, ShapeType, WaveformOrientation, WaveformShape } from "@euterpe.js/visualizer"
let result: AnalyzeReturn | undefined;
let db = generate_db()
//Create all audio nodes
const audioEl = document.querySelector("#audio") as HTMLAudioElement
const audioContext = new AudioContext()
const track = audioContext.createMediaElementSource(audioEl)
const gain = audioContext.createGain()
gain.gain.value = 0
const audioContextAnalyser = audioContext.createAnalyser()
audioContextAnalyser.fftSize = 32
audioContextAnalyser.smoothingTimeConstant = 0
const analyserBufferLength = audioContextAnalyser.frequencyBinCount
const FFTDataArray = new Float32Array(analyserBufferLength)
//Connect all audio Nodes
track.connect(audioContextAnalyser).connect(gain).connect(audioContext.destination)
document.getElementById("analyze")!.addEventListener("click", async (ev) => {
audioContext.resume()
result = await analyze()
download(JSON.stringify(result.db), "db.json", "text/plain")
})
document.getElementById("create-svg")!.addEventListener("click", (ev) => {
audioContext.resume()
svg()
})
document.getElementById("upload")!.addEventListener("change", (ev) => {
audioContext.resume()
const fileReader = new FileReader()
fileReader.readAsText(ev.target.files[0])
fileReader.onload = event => {
let str = JSON.parse(event.target.result)
let new_db = from_json(str)
//-infinity get stringified to null, undo that
for (const song of new_db.songs) {
if (song.fft_data) {
for (let i = 0; i < song.fft_data.length; i++) {
if (song.fft_data[i] === null || song.fft_data[i] === undefined) song.fft_data[i] = -Infinity
}
}
}
result = { db: new_db, analyzer_node: audioContextAnalyser }
}
})
async function svg() {
if (!result) {
alert("not analyzed yet!")
return
}
console.log("Creating svgs...")
const canvas_wrapper = document.querySelector(".canvas-wrapper") as HTMLElement
const waveform_canvas = document.querySelector("#waveform-canvas")?.cloneNode() as SVGSVGElement
canvas_wrapper.childNodes.forEach((c) => c.remove())
canvas_wrapper.appendChild(waveform_canvas)
for (const song of result.db.songs) {
console.log("creating waveform for -> " + song.name)
const curr_waveform_canvas = waveform_canvas.cloneNode() as SVGSVGElement
waveform_canvas.parentElement?.append(curr_waveform_canvas)
const waveform_visual_builder = new AudioVisualBuilder(result.analyzer_node, curr_waveform_canvas)
.set_fft_data_tresholds({ point_count_i: 100, fft_multiplier_i: .9, fft_offset_i: -65 })
.set_fft_time_smoothing(0.8)
.set_smoothing_algorythm(SmoothingAlgorythm.CatmullRom)
const waveform_visual = waveform_visual_builder.build(ShapeType.Waveform, true, { fft_data: new Float32Array(new Float64Array(song.fft_data!)), orientation: WaveformOrientation.Horizontal, shape_type: WaveformShape.LineLike })
waveform_visual.draw_once()
// await new Promise<void>((done) => setTimeout(() => done(), 500))
// @ts-ignore
song.metadata[0] = curr_waveform_canvas.children[0].getAttribute("d")
song.fft_data = []
}
waveform_canvas.remove()
console.dir(result.db, { depth: null })
download(JSON.stringify(result.db), "db.json", "text/plain")
}
async function analyze(): Promise<AnalyzeReturn> {
console.clear()
const audioEl = document.querySelector("#audio") as HTMLAudioElement
console.log("analysing...")
const samplingRate = 100
// db.songs.splice(0, 10)
// db.songs.splice(2)
console.log(db)
for (const song of db.songs) {
// const song = db.songs[db.songs.length - 1]
console.log(`Analyzing ${song.name}, ${db.songs.indexOf(song) + 1}/${db.songs.length}`)
//if not loaded yet keep trying
audioEl.src = song.url.href
await awaitLoad(audioEl)
song.duration = audioEl.duration
let currentFFTData = []
for (let curSecond = 0; curSecond < song.duration; curSecond += song.duration / samplingRate) {
console.log("working...")
audioEl.currentTime = curSecond
await audioEl.play()
await new Promise<void>((done) => setTimeout(() => done(), 100))
audioContextAnalyser.getFloatFrequencyData(FFTDataArray)
let volume = 0
FFTDataArray.forEach((element) => {
volume += element
})
currentFFTData.push(Math.round((volume / FFTDataArray.length) * 100) / 100)
}
song.fft_data = currentFFTData
console.log(song.fft_data)
}
console.log("Analyzation finished!")
const result: AnalyzeReturn = { analyzer_node: audioContextAnalyser, db: db }
return result
}
function download(content: BlobPart, fileName: string, contentType: string) {
var a = document.querySelector("#download") as HTMLAnchorElement;
var file = new Blob([content], { type: contentType });
a.href = URL.createObjectURL(file);
a.download = fileName;
// a.click();
}
type AnalyzeReturn = {
analyzer_node: AnalyserNode,
db: DB
}
function awaitLoad(audioEl: HTMLAudioElement) {
return new Promise<void>((resolve, reject) => {
audioEl.addEventListener("loadeddata", function () {
if (audioEl.readyState >= 4) {
resolve()
}
})
})
}

View file

@ -1,113 +0,0 @@
/**
* TODO:
* -add back -metadata
*
*/
import filehound from "filehound"
import { execSync, exec } from 'child_process'
import { fstat, unlinkSync } from "fs"
function generate_new_photo_sizes(file, currentExtention) {
exec(`start ffmpeg -y -i "${file}.${currentExtention}" -lossless 0 -quality 85 -compression_level 6 -metadata author="Djkáťo" -metadata copyright="https://djkato.net" "${file}_ogw.webp" -vf scale=1000:-1 -lossless 0 -quality 85 -compression_level 6 -metadata author="Djkáťo" -metadata copyright="https://djkato.net" "${file}_1000w.webp" -vf scale=800:-1 -lossless 0 -quality 85 -compression_level 6 -metadata author="Djkáťo" -metadata copyright="https://djkato.net" "${file}_800w.webp" -vf scale=500:-1 -lossless 0 -quality 85 -compression_level 6 -metadata author="Djkáťo" -metadata copyright="https://djkato.net" "${file}_500w.webp" -vf scale=320:-1 -lossless 0 -quality 85 -compression_level 6 -metadata author="Djkáťo" -metadata copyright="https://djkato.net" "${file}_320w.webp" -vf scale=-1:64,gblur=sigma=10:steps=2 -lossless 0 -compression_level 6 -quality 85 -metadata author="Djkáťo" -metadata copyright="https://djkato.net" "${file}_placeholder.webp"`)
}
function generate_new_anim_photo_sizes(file, currentExtention) {
exec(`start ffmpeg -y -i "${file}.${currentExtention}" -lossless 0 -frames:v 1 -r 1 -quality 85 -compression_level 6 -metadata author="Djkáťo" -metadata copyright="https://djkato.net" "${file}_ogw_static.webp" -vf scale=1000:-1 -lossless 0 -frames:v 1 -r 1 -quality 85 -compression_level 6 -metadata author="Djkáťo" -metadata copyright="https://djkato.net" "${file}_1000w_static.webp" -vf scale=800:-1 -lossless 0 -frames:v 1 -r 1 -quality 85 -compression_level 6 -metadata author="Djkáťo" -metadata copyright="https://djkato.net" "${file}_800w_static.webp" -vf scale=500:-1 -lossless 0 -frames:v 1 -r 1 -quality 85 -compression_level 6 -metadata author="Djkáťo" -metadata copyright="https://djkato.net" "${file}_500w_static.webp" -vf scale=320:-1 -lossless 0 -frames:v 1 -r 1 -quality 85 -compression_level 6 -metadata author="Djkáťo" -metadata copyright="https://djkato.net" "${file}_320w_static.webp" -vf scale=-1:64,gblur=sigma=10:steps=2 -lossless 0 -frames:v 1 -r 1 -compression_level 6 -quality 85 -metadata author="Djkáťo" -metadata copyright="https://djkato.net" "${file}_placeholder_static.webp"`)
exec(`start ffmpeg -y -i "${file}.${currentExtention}" -lossless 0 -quality 85 -loop 0 -compression_level 6 -metadata author="Djkáťo" -metadata copyright="https://djkato.net" "${file}_ogw.webp" -vf scale=1000:-1 -lossless 0 -quality 85 -loop 0 -compression_level 6 -metadata author="Djkáťo" -metadata copyright="https://djkato.net" "${file}_1000w.webp" -vf scale=800:-1 -lossless 0 -quality 85 -loop 0 -compression_level 6 -metadata author="Djkáťo" -metadata copyright="https://djkato.net" "${file}_800w.webp" -vf scale=500:-1 -lossless 0 -quality 85 -loop 0 -compression_level 6 -metadata author="Djkáťo" -metadata copyright="https://djkato.net" "${file}_500w.webp" -vf scale=320:-1 -lossless 0 -quality 85 -loop 0 -compression_level 6 -metadata author="Djkáťo" -metadata copyright="https://djkato.net" "${file}_320w.webp" -vf scale=-1:64,gblur=sigma=10:steps=2 -frames:v 1 -lossless 0 -c:v libwebp -compression_level 6 -quality 85 -metadata author="Djkáťo" -metadata copyright="https://djkato.net" "${file}_placeholder.webp"`)
}
function generate_new_sounds_ogg(file, currentExtention) {
const path = file.substring(0, file.lastIndexOf("\\"))
file = file.substring(file.lastIndexOf("\\") + 1)
let command = ""
command += `cd "${path}" && start cmd /k "`
command += `ffmpeg -y -i "${file}.${currentExtention}" `
command += `-c:a libopus -b:a 96k "${file}.ogg"`
command += ` && exit"`
exec(command)
// console.log(command)
}
function generate_new_sounds_mp3(file, currentExtention) {
const path = file.substring(0, file.lastIndexOf("\\"))
file = file.substring(file.lastIndexOf("\\") + 1)
let command = ""
command += `cd "${path}" && start cmd /k "`
command += `ffmpeg -y -i "${file}.${currentExtention}" `
command += `-b:a 160k "${file}.mp3"`
command += ` && exit"`
exec(command)
// console.log(command)
}
function generateNewVideoSizes(file, currentExtention, width_resolutions) {
const path = file.substring(0, file.lastIndexOf("\\"))
file = file.substring(file.lastIndexOf("\\") + 1)
let command = ""
command += `cd "${path}" && `
command += `del ffmpeg2pass-0.log && `
command += `ffmpeg -y -i "${file}.${currentExtention}" `
command += `-vcodec libvpx-vp9 -cpu-used 0 -deadline good -quality good -g 240 -crf 42 -b:v 0 -c:a libopus -row-mt 1 -tile-rows 2 -tile-columns 4 -threads 16 -auto-alt-ref 6 `
command += `-pass 1 -f webm NUL && exit`
exec(command).once("exit", () => {
for (const resolution of width_resolutions) {
let res_command = ""
res_command += `start cmd /k "`
res_command += `cd "${path}" && `
res_command += `ffmpeg -y -i "${file}.${currentExtention}" `
res_command += `-vcodec libvpx-vp9 -cpu-used 0 -deadline good -quality good -g 240 -vf scale=${resolution}:-1 -crf 42 -b:v 0 -c:a libopus -row-mt 1 -tile-rows 2 -tile-columns 4 -threads 16 -auto-alt-ref 6 -pass 2 "${file}_${resolution}p.webm"`
res_command += "&& exit\""
exec(res_command)
}
})
}
let dirs = filehound.create()
.path("../public/samples")
.directory()
.findSync()
console.log(dirs)
for (let i = 0; i < dirs.length; i++) {
//gets current name file+ext
let current_folder_files = filehound.create()
.path(`${dirs[i]}`)
.findSync()
if (current_folder_files[0] != undefined) {
//if previous encode was cancelled and 2pass log not removed, remove it :)
if (current_folder_files[0].includes("ffmpeg2pass-0.log")) {
try { unlinkSync(`${dirs[i]}/ffmpeg2pass-0.log`) } catch (err) { }
current_folder_files = current_folder_files.slice(1)
}
for (let current_media of current_folder_files) {
current_media = [current_media.substring(0, current_media.lastIndexOf(".")), current_media.substring(current_media.lastIndexOf(".") + 1)]
if (current_media[1] == "wav") {
console.log(`${current_media[0]}.${current_media[1]}\n`)
generate_new_sounds_ogg(`${current_media[0]}`, `${current_media[1]}`)
generate_new_sounds_mp3(`${current_media[0]}`, `${current_media[1]}`)
}
continue
if (current_media[1] == "png" || current_media[1] == "jpg") {
console.log(`.\\${current_media[0]}.${current_media[1]}\n`)
generate_new_photo_sizes(`.\\${current_media[0]}`, `${current_media[1]}`)
}
else if (current_media[1] == "gif") {
console.log(`.\\${current_media[0]}.${current_media[1]}\n`)
generate_new_anim_photo_sizes(`.\\${current_media[0]}`, `${current_media[1]}`)
}
else if (current_media[1] == "webm" || current_media[1] == "mov" || current_media[1] == "avi" || current_media[1] == "mp4") {
console.log(`Video: ${current_media[0]}.${current_media[1]}\n`)
generateNewVideoSizes(`${current_media[0]}`, `${current_media[1]}`, [2560, 1080, 720, 480])
}
}
}
}

View file

@ -1 +0,0 @@
export const songs = ["..\\public\\samples\\bass\\01 HTS Arpeggiated Bass.ogg","..\\public\\samples\\bass\\02 HTS Hardtrance Bass.ogg","..\\public\\samples\\bass\\03 HTS Break Bass.ogg","..\\public\\samples\\bass\\04 HTS Sub Bass.ogg","..\\public\\samples\\drums\\01 HTS Rides and Hats.ogg","..\\public\\samples\\drums\\02 HTS Claps and Hats.ogg","..\\public\\samples\\drums\\03 HTS Club Snares.ogg","..\\public\\samples\\drums\\04 HTS Buildup Snares.ogg","..\\public\\samples\\FX\\01 HTS Boom Kicks.ogg","..\\public\\samples\\FX\\02 HTS Verbclaps.ogg","..\\public\\samples\\FX\\03 HTS Noisesweep.ogg","..\\public\\samples\\FX\\04 HTS Combined FX.ogg","..\\public\\samples\\kicks\\01 HTS Trancekick.ogg","..\\public\\samples\\kicks\\02 HTS Sizzle Layer.ogg","..\\public\\samples\\kicks\\03 HTS Transients.ogg","..\\public\\samples\\kicks\\04 HTS Kick Combined.ogg","..\\public\\samples\\loops\\01 HTS Closed Hat Loop.ogg","..\\public\\samples\\loops\\02 HTS Open Hat Loop.ogg","..\\public\\samples\\loops\\03 HTS Perc Loop.ogg","..\\public\\samples\\loops\\04 HTS Full Loop.ogg","..\\public\\samples\\synths\\01 HTS Pluck Leads and Arp Bass.ogg","..\\public\\samples\\synths\\02 HTS Arp Leads and Saw Pads.ogg","..\\public\\samples\\synths\\03 HTS Pluck Leads and Break Bass.ogg","..\\public\\samples\\synths\\04 HTS Saw Leads and String Pads.ogg"]

View file

@ -1 +0,0 @@
/// <reference types="vite/client" />

View file

@ -1,30 +1,30 @@
{
"extends": "../../tsconfig.base.json",
"files": [],
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": [
"ESNext",
"DOM"
],
"moduleResolution": "Node",
"strict": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"jsxImportSource": "hono/jsx",
"jsx": "react-jsx",
"lib": [
"ESNext"
],
"module": "esnext",
"target": "esnext",
"moduleResolution": "bundler",
"moduleDetection": "force",
"allowImportingTsExtensions": true,
"noEmit": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"composite": true,
"strict": true,
"downlevelIteration": true,
"skipLibCheck": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"allowJs": true,
"types": [
"vite/client"
]
},
"bun-types" // add Bun global
],
"include": [
"src",
"src/media_process.js"
]
}
}

View file

@ -1,33 +0,0 @@
/// <reference types="vitest" />
import { defineConfig } from "vite"
import viteTsConfigPaths from "vite-tsconfig-paths"
export default defineConfig({
cacheDir: "../../node_modules/.vite/preprocessor",
server: {
port: 4201,
host: "localhost"
},
preview: {
port: 4300,
host: "localhost"
},
plugins: [
viteTsConfigPaths({
root: "."
})
]
// Uncomment this if you are using workers.
// worker: {
// plugins: [
// viteTsConfigPaths({
// root: '../../',
// }),
// ],
// },
})