maybe another fix

This commit is contained in:
Djkáťo 2023-08-10 14:02:23 +02:00
parent ccbec7a26f
commit 4a425a30a8
12 changed files with 117 additions and 60 deletions

View file

@ -1,6 +1,6 @@
{
"name": "@euterpe.js/euterpe",
"version": "2.0.0",
"version": "2.0.1",
"type": "module",
"description": "Fully featured solution for playing music on the web. Support for local library, audio visuals and more!",
"main": "./src/index.js",

View file

@ -1,6 +1,6 @@
{
"name": "@euterpe.js/player",
"version": "2.0.0",
"version": "2.0.1",
"type": "module",
"description": "A simple, safe AudioContext web music player",
"main": "./src/index.js",

View file

@ -218,21 +218,28 @@ export class MusicPlayer {
* Will only load metadata of the upcoming song. Need to call try_play_async() afterwards to start the playback
* @throws Error if adding element throwed Error or Stalled
*/
try_new_song(path: string) {
async try_new_song(path: string) {
if (this.audio_context.state !== "running") {
try {
await this.audio_context.resume()
} catch (e) {
console.log("loading new song - couldn't resume context before hand", e)
}
}
return new Promise<void>((resolve, reject) => {
this.audio_element.src = this.current_song_path = path
//Found out today about this. Such a nice new way to mass remove event listeners!
const controller = new AbortController();
this.audio_element.addEventListener("canplay", function canplay_listener(s) {
this.audio_element.addEventListener("canplaythrough", function canplay_listener() {
controller.abort()
}, { signal: controller.signal })
this.audio_element.addEventListener("error", function error_listener(e) {
this.audio_element.addEventListener("error", function error_listener() {
controller.abort("new src error")
}, { signal: controller.signal })
this.audio_element.addEventListener("stalled", function stalled_listener(e) {
this.audio_element.addEventListener("stalled", function stalled_listener() {
controller.abort("new src stalled")
}, { signal: controller.signal })

View file

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

View file

@ -13,9 +13,16 @@
<script type="module" src="/src/main.ts">
</script>
<div class="button-wrapper">
<button id="button">Analyze!</button>
<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>

View file

@ -4,8 +4,8 @@
"version": "0.0.0",
"type": "module",
"scripts": {
"crawl": "node crawler.mjs",
"process": "node crawler.mjs && vite",
"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",

View file

@ -0,0 +1,4 @@
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

@ -3,7 +3,7 @@ import { songs } from "./songs_list"
export function generate_db() {
console.log(songs)
//construct db
// construct db
let db = new DB
let collections: string[] = new Array()
let new_songs = []
@ -38,11 +38,11 @@ export function generate_db() {
const last_i = song.song.lastIndexOf("\\")
const name = song.song.slice(last_i + 1)
const song_url = song.song.replace("\\\\", "/").slice(7)
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("http://localhost:4201/" + song_url),
url: new URL(`${window.location.href}${song_url}`.replaceAll("\\", "/")),
duration: 0,
remix_artists: [],
in_collection: new Ref(RefTo.Collections, song.collection_id)

View file

@ -1,25 +1,80 @@
import { DB } from "@euterpe.js/music-library"
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"
document.getElementById("button")!.addEventListener("click", (ev) => {
start()
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")
})
export async function start() {
analyze().then(async (result) => {
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 waveform_canvas = document.querySelector("#waveform-canvas") as SVGSVGElement
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: .6, fft_offset_i: -75 })
.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(), 300))
// await new Promise<void>((done) => setTimeout(() => done(), 500))
// @ts-ignore
song.metadata[0] = curr_waveform_canvas.children[0].getAttribute("d")
song.fft_data = []
@ -27,27 +82,14 @@ export async function start() {
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
//Create all audio nodes
const audioContext = new AudioContext()
const track = audioContext.createMediaElementSource(audioEl)
const gain = audioContext.createGain()
gain.gain.value = 0
const audioContextAnalyser = audioContext.createAnalyser()
audioContextAnalyser.fftSize = 64
audioContextAnalyser.smoothingTimeConstant = 0
const analyserBufferLength = audioContextAnalyser.frequencyBinCount
const FFTDataArray = new Float32Array(analyserBufferLength)
//Connect all audio Nodes
track.connect(audioContextAnalyser).connect(gain).connect(audioContext.destination)
let db = generate_db()
// db.songs.splice(0, 10)
// db.songs.splice(2)
console.log(db)
@ -72,6 +114,7 @@ async function analyze(): Promise<AnalyzeReturn> {
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 }
@ -84,7 +127,6 @@ function download(content: BlobPart, fileName: string, contentType: string) {
a.download = fileName;
// a.click();
}
type AnalyzeReturn = {
analyzer_node: AnalyserNode,
db: DB

View file

@ -63,7 +63,7 @@ function generateNewVideoSizes(file, currentExtention, width_resolutions) {
})
}
let dirs = filehound.create()
.path("../public/")
.path("../public/samples")
.directory()
.findSync()
console.log(dirs)

View file

@ -1 +1 @@
export const songs = ["public\\samples\\bass\\arp bass noise 5.ogg","public\\samples\\bass\\arp bass noise 6.ogg","public\\samples\\bass\\lead bass 7.ogg","public\\samples\\bass\\sub bass 5.ogg","public\\samples\\demos\\nuphory - NVISION (EXTENDED MIX).ogg","public\\samples\\drums\\H2 buildsnares long 11.ogg","public\\samples\\drums\\H2 Claps 21.ogg","public\\samples\\drums\\H2 clubsnares 14.ogg","public\\samples\\drums\\H2 Trancekick 08.ogg","public\\samples\\FX\\H2 Boom Kicks 05.ogg","public\\samples\\FX\\H2 Depth Charge 07.ogg","public\\samples\\FX\\H2 Downlifters 11.ogg","public\\samples\\FX\\H2 Noisesweeps 08.ogg","public\\samples\\kicks\\H2 Trancekick 08.ogg","public\\samples\\kicks\\H2 Trancekick 20.ogg","public\\samples\\kicks\\H2 Trancekick 28.ogg","public\\samples\\kicks\\H2 Trancekick 34.ogg","public\\samples\\loops\\H2 Closed Hat Loop 160BPM 02.ogg","public\\samples\\loops\\H2 loops 04.ogg","public\\samples\\loops\\H2 Open Hat Loop 160BPM 06.ogg","public\\samples\\loops\\H2 Perc Loop 160BPM 03.ogg","public\\samples\\synths\\H2 Pads 01 C Saw.ogg","public\\samples\\synths\\H2 Pads 13 F Voc.ogg","public\\samples\\synths\\H2 Pads 20 G Saw.ogg","public\\samples\\synths\\H2 Pads 23 D String.ogg"]
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

@ -24,6 +24,7 @@
]
},
"include": [
"src"
"src",
"src/media_process.js"
]
}