From 4a425a30a8c8680c077aef92c68eda18a70bba4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Djk=C3=A1=C5=A5o?= Date: Thu, 10 Aug 2023 14:02:23 +0200 Subject: [PATCH] maybe another fix --- packages/euterpe/package.json | 2 +- packages/player/package.json | 2 +- packages/player/src/index.ts | 15 ++- packages/preprocessor/crawler.mjs | 4 - packages/preprocessor/index.html | 11 +- packages/preprocessor/package.json | 4 +- packages/preprocessor/src/crawler.mjs | 4 + packages/preprocessor/src/generate_db.ts | 6 +- packages/preprocessor/src/main.ts | 122 ++++++++++++++------- packages/preprocessor/src/media_process.js | 2 +- packages/preprocessor/src/songs_list.ts | 2 +- packages/preprocessor/tsconfig.json | 3 +- 12 files changed, 117 insertions(+), 60 deletions(-) delete mode 100644 packages/preprocessor/crawler.mjs create mode 100644 packages/preprocessor/src/crawler.mjs diff --git a/packages/euterpe/package.json b/packages/euterpe/package.json index d37d1a8..a72127a 100644 --- a/packages/euterpe/package.json +++ b/packages/euterpe/package.json @@ -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", diff --git a/packages/player/package.json b/packages/player/package.json index 2d5f86e..51b67ef 100644 --- a/packages/player/package.json +++ b/packages/player/package.json @@ -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", diff --git a/packages/player/src/index.ts b/packages/player/src/index.ts index b6a0cba..b983972 100644 --- a/packages/player/src/index.ts +++ b/packages/player/src/index.ts @@ -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((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 }) diff --git a/packages/preprocessor/crawler.mjs b/packages/preprocessor/crawler.mjs deleted file mode 100644 index 5233a9f..0000000 --- a/packages/preprocessor/crawler.mjs +++ /dev/null @@ -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 }) \ No newline at end of file diff --git a/packages/preprocessor/index.html b/packages/preprocessor/index.html index 730b0f5..6de99d0 100644 --- a/packages/preprocessor/index.html +++ b/packages/preprocessor/index.html @@ -13,8 +13,15 @@
- - Download DB + + +
+
+ +

Upload DB

+
+ Download DB +
diff --git a/packages/preprocessor/package.json b/packages/preprocessor/package.json index 9db2696..4c463e5 100644 --- a/packages/preprocessor/package.json +++ b/packages/preprocessor/package.json @@ -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", diff --git a/packages/preprocessor/src/crawler.mjs b/packages/preprocessor/src/crawler.mjs new file mode 100644 index 0000000..6e84a80 --- /dev/null +++ b/packages/preprocessor/src/crawler.mjs @@ -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 }) \ No newline at end of file diff --git a/packages/preprocessor/src/generate_db.ts b/packages/preprocessor/src/generate_db.ts index 04ee559..8246948 100644 --- a/packages/preprocessor/src/generate_db.ts +++ b/packages/preprocessor/src/generate_db.ts @@ -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) diff --git a/packages/preprocessor/src/main.ts b/packages/preprocessor/src/main.ts index 5c680ee..359bbac 100644 --- a/packages/preprocessor/src/main.ts +++ b/packages/preprocessor/src/main.ts @@ -1,53 +1,95 @@ -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) => { - console.log("Creating svgs...") - const waveform_canvas = document.querySelector("#waveform-canvas") as SVGSVGElement - 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_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((done) => setTimeout(() => done(), 300)) - // @ts-ignore - song.metadata[0] = curr_waveform_canvas.children[0].getAttribute("d") - song.fft_data = [] + +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 + } + } } - waveform_canvas.remove() - console.dir(result.db, { depth: null }) - download(JSON.stringify(result.db), "db.json", "text/plain") - }) + 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((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 { 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 { 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 @@ -97,4 +139,4 @@ function awaitLoad(audioEl: HTMLAudioElement) { } }) }) -} \ No newline at end of file +} diff --git a/packages/preprocessor/src/media_process.js b/packages/preprocessor/src/media_process.js index 7cca222..20ceca2 100644 --- a/packages/preprocessor/src/media_process.js +++ b/packages/preprocessor/src/media_process.js @@ -63,7 +63,7 @@ function generateNewVideoSizes(file, currentExtention, width_resolutions) { }) } let dirs = filehound.create() - .path("../public/") + .path("../public/samples") .directory() .findSync() console.log(dirs) diff --git a/packages/preprocessor/src/songs_list.ts b/packages/preprocessor/src/songs_list.ts index 6faad0d..df3ec20 100644 --- a/packages/preprocessor/src/songs_list.ts +++ b/packages/preprocessor/src/songs_list.ts @@ -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"] \ No newline at end of file +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"] \ No newline at end of file diff --git a/packages/preprocessor/tsconfig.json b/packages/preprocessor/tsconfig.json index 85e7800..6068edb 100644 --- a/packages/preprocessor/tsconfig.json +++ b/packages/preprocessor/tsconfig.json @@ -24,6 +24,7 @@ ] }, "include": [ - "src" + "src", + "src/media_process.js" ] } \ No newline at end of file