maybe another fix
This commit is contained in:
parent
ccbec7a26f
commit
4a425a30a8
12 changed files with 117 additions and 60 deletions
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 })
|
||||
|
||||
|
|
|
@ -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 })
|
|
@ -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>
|
||||
|
|
|
@ -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",
|
||||
|
|
4
packages/preprocessor/src/crawler.mjs
Normal file
4
packages/preprocessor/src/crawler.mjs
Normal 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 })
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -63,7 +63,7 @@ function generateNewVideoSizes(file, currentExtention, width_resolutions) {
|
|||
})
|
||||
}
|
||||
let dirs = filehound.create()
|
||||
.path("../public/")
|
||||
.path("../public/samples")
|
||||
.directory()
|
||||
.findSync()
|
||||
console.log(dirs)
|
||||
|
|
|
@ -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"]
|
|
@ -24,6 +24,7 @@
|
|||
]
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
"src",
|
||||
"src/media_process.js"
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue