Animate mugshot party identification
This commit is contained in:
@@ -21,6 +21,22 @@ function noise(context: AudioContext) {
|
||||
return noiseBuffer
|
||||
}
|
||||
|
||||
let markerNoiseBuffer:AudioBuffer | null=null
|
||||
function markerNoise(context:AudioContext) {
|
||||
if (!markerNoiseBuffer) {
|
||||
const length=Math.floor(context.sampleRate * .31)
|
||||
markerNoiseBuffer=context.createBuffer(1,length,context.sampleRate)
|
||||
const data=markerNoiseBuffer.getChannelData(0)
|
||||
let previous=0
|
||||
for (let index=0;index < length;index++) {
|
||||
const white=Math.random() * 2 - 1
|
||||
previous=previous * .66 + white * .34
|
||||
data[index]=previous * (.72 + Math.sin(index / 37) * .18)
|
||||
}
|
||||
}
|
||||
return markerNoiseBuffer
|
||||
}
|
||||
|
||||
const music = typeof Audio !== 'undefined' ? new Audio() : null
|
||||
if (music) music.loop = true
|
||||
let currentUrl: string | null = null
|
||||
@@ -100,6 +116,28 @@ export const audio = {
|
||||
src.connect(filter).connect(gain).connect(context.destination)
|
||||
src.start(now); src.stop(now + 0.04)
|
||||
},
|
||||
// A restrained felt-tip-on-paper scratch. The caller supplies the handwriting
|
||||
// duration so the sound ends with the incremental letter reveal.
|
||||
sharpie(durationMs:number) {
|
||||
if (muted) return undefined
|
||||
const context=audioContext()
|
||||
if (!context) return undefined
|
||||
if (context.state === 'suspended') void context.resume()
|
||||
const duration=Math.max(.12,Math.min(3,durationMs / 1000))
|
||||
const source=context.createBufferSource();source.buffer=markerNoise(context);source.loop=true
|
||||
const filter=context.createBiquadFilter();filter.type='bandpass';filter.frequency.value=1180;filter.Q.value=.62
|
||||
const gain=context.createGain()
|
||||
const now=context.currentTime + .012,end=now + duration
|
||||
gain.gain.setValueAtTime(.0001,now)
|
||||
gain.gain.linearRampToValueAtTime(.032,now + .035)
|
||||
for (let at=now + .055;at < end - .04;at += .045) gain.gain.setValueAtTime(.018 + Math.random() * .026,at)
|
||||
gain.gain.exponentialRampToValueAtTime(.0001,end)
|
||||
source.connect(filter).connect(gain).connect(context.destination)
|
||||
let ended=false
|
||||
source.onended=() => { ended=true }
|
||||
source.start(now);source.stop(end + .02)
|
||||
return () => { if (!ended) { try { source.stop() } catch { /* already stopped */ } } }
|
||||
},
|
||||
// Resume the context and retry pending music on a user gesture.
|
||||
resume() {
|
||||
void audioContext()?.resume?.()
|
||||
|
||||
Reference in New Issue
Block a user