2022-11-07 14:23:59 +00:00
|
|
|
import { audioService } from '@/services'
|
|
|
|
|
|
|
|
export class AudioAnalyzer {
|
2024-10-13 17:37:01 +00:00
|
|
|
private bass = 0.0
|
|
|
|
private mid = 0.0
|
|
|
|
private high = 0.0
|
|
|
|
private level = 0.0
|
|
|
|
private history = 0.0
|
2022-11-07 14:23:59 +00:00
|
|
|
private frame = 0
|
|
|
|
|
|
|
|
private readonly frequencyBinCount: number
|
|
|
|
|
|
|
|
// [!] this can't be read-only regardless of IDE's suggestion
|
2024-04-04 22:20:42 +00:00
|
|
|
// noinspection TypeScriptFieldCanBeMadeReadonly
|
2022-11-07 14:23:59 +00:00
|
|
|
private audioBuffer: Uint8Array
|
|
|
|
|
|
|
|
private analyzer: AnalyserNode
|
|
|
|
|
|
|
|
constructor () {
|
|
|
|
this.analyzer = audioService.analyzer
|
|
|
|
this.analyzer.fftSize = 128
|
|
|
|
this.frequencyBinCount = this.analyzer.frequencyBinCount
|
|
|
|
this.audioBuffer = new Uint8Array(this.frequencyBinCount)
|
|
|
|
}
|
|
|
|
|
|
|
|
update () {
|
|
|
|
this.analyzer.getByteFrequencyData(this.audioBuffer)
|
2024-10-13 17:37:01 +00:00
|
|
|
let bass = 0.0; let mid = 0.0; let high = 0.0
|
2022-11-07 14:23:59 +00:00
|
|
|
|
|
|
|
if (this.audioBuffer[0] === 0) {
|
|
|
|
// create a "pulse" effect on audio idle
|
2024-10-13 17:37:01 +00:00
|
|
|
if (this.frame % 40 == (Math.floor(Math.random() * 40.0))) {
|
2022-11-07 14:23:59 +00:00
|
|
|
bass = Math.random()
|
|
|
|
mid = Math.random()
|
|
|
|
high = Math.random()
|
|
|
|
}
|
|
|
|
} else {
|
2024-10-13 17:37:01 +00:00
|
|
|
const passSize = this.frequencyBinCount / 3.0
|
2022-11-07 14:23:59 +00:00
|
|
|
|
|
|
|
for (let i = 0; i < this.frequencyBinCount; i++) {
|
2024-10-13 17:37:01 +00:00
|
|
|
const val = (this.audioBuffer[i] / 196.0) ** 3.0
|
2022-11-07 14:23:59 +00:00
|
|
|
|
2024-10-13 17:37:01 +00:00
|
|
|
if (i < passSize) {
|
2022-11-07 14:23:59 +00:00
|
|
|
bass += val
|
2024-10-13 17:37:01 +00:00
|
|
|
} else if (i >= passSize && i < passSize * 2) {
|
2022-11-07 14:23:59 +00:00
|
|
|
mid += val
|
2024-10-13 17:37:01 +00:00
|
|
|
} else if (i >= passSize * 2) {
|
2022-11-07 14:23:59 +00:00
|
|
|
high += val
|
2024-10-13 17:37:01 +00:00
|
|
|
}
|
2022-11-07 14:23:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bass /= passSize
|
|
|
|
mid /= passSize
|
|
|
|
high /= passSize
|
|
|
|
}
|
|
|
|
|
2024-10-13 17:37:01 +00:00
|
|
|
this.bass = this.bass > bass ? this.bass * 0.96 : bass
|
|
|
|
this.mid = this.mid > mid ? this.mid * 0.96 : mid
|
|
|
|
this.high = this.high > high ? this.high * 0.96 : high
|
2022-11-07 14:23:59 +00:00
|
|
|
|
2024-10-13 17:37:01 +00:00
|
|
|
this.level = (this.bass + this.mid + this.high) / 3.0
|
2022-11-07 14:23:59 +00:00
|
|
|
|
2024-10-13 17:37:01 +00:00
|
|
|
this.history += this.level * 0.01 + 0.005
|
2022-11-07 14:23:59 +00:00
|
|
|
|
|
|
|
this.frame++
|
|
|
|
}
|
|
|
|
|
|
|
|
getBass () {
|
2024-10-13 17:37:01 +00:00
|
|
|
return this.bass || 0.0
|
2022-11-07 14:23:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
getMid () {
|
2024-10-13 17:37:01 +00:00
|
|
|
return this.mid || 0.0
|
2022-11-07 14:23:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
getHigh () {
|
2024-10-13 17:37:01 +00:00
|
|
|
return this.high || 0.0
|
2022-11-07 14:23:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
getLevel () {
|
2024-10-13 17:37:01 +00:00
|
|
|
return this.level || 0.0
|
2022-11-07 14:23:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
getHistory () {
|
2024-10-13 17:37:01 +00:00
|
|
|
return this.history || 0.0
|
2022-11-07 14:23:59 +00:00
|
|
|
}
|
|
|
|
}
|