Cap fullscreen pulse brightness
This commit is contained in:
1 parent
d07221f600
commit
ebd6fedd89
2 files changed
+29
-15
No files matched your search
@@ -148,6 +148,7 @@ function draw(now: number) {
|
|||||||
const colors = palette.value ?? fallback
|
const colors = palette.value ?? fallback
|
||||||
const dominant = toOkLab(colors.dominant)
|
const dominant = toOkLab(colors.dominant)
|
||||||
const accent = toOkLab(colors.accent)
|
const accent = toOkLab(colors.accent)
|
||||||
|
const maxPaletteLightness = Math.max(dominant[0], accent[0])
|
||||||
const motionTime = time * ANIMATION_SPEED
|
const motionTime = time * ANIMATION_SPEED
|
||||||
for (let y = 0; y < height; y++) {
|
for (let y = 0; y < height; y++) {
|
||||||
for (let x = 0; x < width; x++) {
|
for (let x = 0; x < width; x++) {
|
||||||
@@ -161,7 +162,7 @@ function draw(now: number) {
|
|||||||
value * (1 - blend) + accent[channel] * blend,
|
value * (1 - blend) + accent[channel] * blend,
|
||||||
) as [number, number, number]
|
) as [number, number, number]
|
||||||
const beat = shapeBeatPulse(beatEnergy.value)
|
const beat = shapeBeatPulse(beatEnergy.value)
|
||||||
lab[0] = Math.min(1, lab[0] + beat * 0.01)
|
lab[0] = Math.min(maxPaletteLightness, lab[0] + beat * 0.01)
|
||||||
lab[1] *= 1 + beat * 0.02
|
lab[1] *= 1 + beat * 0.02
|
||||||
lab[2] *= 1 + beat * 0.02
|
lab[2] *= 1 + beat * 0.02
|
||||||
const color = fromOkLab(lab)
|
const color = fromOkLab(lab)
|
||||||
|
|||||||
+27
-14
@@ -109,7 +109,9 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
const mediaElement = (howl as HowlWithMediaNode)._sounds?.[0]?._node
|
const mediaElement = (howl as HowlWithMediaNode)._sounds?.[0]?._node
|
||||||
if (!mediaElement) {
|
if (!mediaElement) {
|
||||||
if (DEBUG_BEAT_ANALYSIS)
|
if (DEBUG_BEAT_ANALYSIS)
|
||||||
console.warn("[beat analyzer] failed: Howler media element unavailable")
|
console.warn(
|
||||||
|
"[beat analyzer] failed: Howler media element unavailable",
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +126,9 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
elementWithCapture.webkitCaptureStream
|
elementWithCapture.webkitCaptureStream
|
||||||
if (!capture) {
|
if (!capture) {
|
||||||
if (DEBUG_BEAT_ANALYSIS)
|
if (DEBUG_BEAT_ANALYSIS)
|
||||||
console.warn("[beat analyzer] failed: media capture unsupported")
|
console.warn(
|
||||||
|
"[beat analyzer] failed: media capture unsupported",
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +136,9 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
const stream = capture.call(mediaElement)
|
const stream = capture.call(mediaElement)
|
||||||
if (stream.getAudioTracks().length === 0) {
|
if (stream.getAudioTracks().length === 0) {
|
||||||
if (DEBUG_BEAT_ANALYSIS)
|
if (DEBUG_BEAT_ANALYSIS)
|
||||||
console.warn("[beat analyzer] failed: capture has no audio tracks")
|
console.warn(
|
||||||
|
"[beat analyzer] failed: capture has no audio tracks",
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
analysisContext ??= new AudioContext()
|
analysisContext ??= new AudioContext()
|
||||||
@@ -140,7 +146,7 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
void analysisContext.resume().catch(() => {})
|
void analysisContext.resume().catch(() => {})
|
||||||
analysisNode = analysisContext.createAnalyser()
|
analysisNode = analysisContext.createAnalyser()
|
||||||
analysisNode.fftSize = 2048
|
analysisNode.fftSize = 2048
|
||||||
analysisNode.smoothingTimeConstant = 0.3
|
analysisNode.smoothingTimeConstant = 0.05
|
||||||
analysisSource = analysisContext.createMediaStreamSource(stream)
|
analysisSource = analysisContext.createMediaStreamSource(stream)
|
||||||
analysisSource.connect(analysisNode)
|
analysisSource.connect(analysisNode)
|
||||||
|
|
||||||
@@ -155,13 +161,17 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
if (!analysisNode) return
|
if (!analysisNode) return
|
||||||
analysisNode.getByteFrequencyData(samples)
|
analysisNode.getByteFrequencyData(samples)
|
||||||
const sampleRate = analysisContext!.sampleRate
|
const sampleRate = analysisContext!.sampleRate
|
||||||
const firstBin = Math.max(1, Math.floor((45 * 2048) / sampleRate))
|
const firstBin = Math.max(
|
||||||
|
1,
|
||||||
|
Math.floor((45 * 2048) / sampleRate),
|
||||||
|
)
|
||||||
const lastBin = Math.min(
|
const lastBin = Math.min(
|
||||||
samples.length - 1,
|
samples.length - 1,
|
||||||
Math.ceil((130 * 2048) / sampleRate),
|
Math.ceil((130 * 2048) / sampleRate),
|
||||||
)
|
)
|
||||||
let bass = 0
|
let bass = 0
|
||||||
for (let bin = firstBin; bin <= lastBin; bin++) bass += samples[bin]
|
for (let bin = firstBin; bin <= lastBin; bin++)
|
||||||
|
bass += samples[bin]
|
||||||
bass /= Math.max(1, lastBin - firstBin + 1) * 255
|
bass /= Math.max(1, lastBin - firstBin + 1) * 255
|
||||||
if (previousBass === null) previousBass = bass
|
if (previousBass === null) previousBass = bass
|
||||||
const rise = Math.max(0, bass - previousBass)
|
const rise = Math.max(0, bass - previousBass)
|
||||||
@@ -178,15 +188,13 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
)
|
)
|
||||||
const now = performance.now()
|
const now = performance.now()
|
||||||
const isStrongThump =
|
const isStrongThump =
|
||||||
rise >= strongThumpThreshold && now - lastBeatLogAt > thumpCooldown
|
rise >= strongThumpThreshold &&
|
||||||
|
now - lastBeatLogAt > thumpCooldown
|
||||||
const riseDelta = rise - riseAverage
|
const riseDelta = rise - riseAverage
|
||||||
riseAverage += riseDelta * 0.01
|
riseAverage += riseDelta * 0.01
|
||||||
riseVariance += (riseDelta * riseDelta - riseVariance) * 0.01
|
riseVariance += (riseDelta * riseDelta - riseVariance) * 0.01
|
||||||
if (isStrongThump) {
|
if (isStrongThump) {
|
||||||
const thumpStrength = Math.min(
|
const thumpStrength = Math.min(0.38, 0.1 + attack * 2.5)
|
||||||
0.38,
|
|
||||||
0.1 + attack * 2.5,
|
|
||||||
)
|
|
||||||
pulse = Math.max(pulse, thumpStrength)
|
pulse = Math.max(pulse, thumpStrength)
|
||||||
if (DEBUG_BEAT_ANALYSIS) {
|
if (DEBUG_BEAT_ANALYSIS) {
|
||||||
console.log(
|
console.log(
|
||||||
@@ -247,7 +255,10 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
album: currentSong.value.album.name,
|
album: currentSong.value.album.name,
|
||||||
artwork: [
|
artwork: [
|
||||||
{
|
{
|
||||||
src: GET_FILE(currentSong.value.album.file, mediaBaseUrl),
|
src: GET_FILE(
|
||||||
|
currentSong.value.album.file,
|
||||||
|
mediaBaseUrl,
|
||||||
|
),
|
||||||
sizes: "512x512",
|
sizes: "512x512",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -480,7 +491,8 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
event.ctrlKey ||
|
event.ctrlKey ||
|
||||||
event.metaKey ||
|
event.metaKey ||
|
||||||
event.altKey
|
event.altKey
|
||||||
) return
|
)
|
||||||
|
return
|
||||||
|
|
||||||
const target = event.target
|
const target = event.target
|
||||||
if (
|
if (
|
||||||
@@ -488,7 +500,8 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
target.closest(
|
target.closest(
|
||||||
"input, textarea, select, button, [contenteditable='true'], [role='slider']",
|
"input, textarea, select, button, [contenteditable='true'], [role='slider']",
|
||||||
)
|
)
|
||||||
) return
|
)
|
||||||
|
return
|
||||||
|
|
||||||
switch (event.code) {
|
switch (event.code) {
|
||||||
case "Space":
|
case "Space":
|
||||||
|
|||||||
Reference in new issue
Block a user