Octave Band
Filter

[ ["none","None"], ["octave","Octave"], ["third","Third"], ["sixth","Sixth"] ]

Weighting

[ ["none","none"], ["Z","Z"], ["A","A"], ["C","C"] ]

Mark Hovered Freq.

Harmonics

Freq. Scale

\bold{\text{Sample Rate:}} \large{\reg{}{sample-rate}} kHz \bold{\text{Bin Rate:}} \large{\reg{}{bin-rate-text}} Hz \bold{\text{Bin Size:}} \large{2\sup{\reg{}{bin-size-exp}}} Samples \bold{\text{Time Averaging}}
const mic = reg.mic const fs = mic.audioCtx.sampleRate const pP = this.newPlot({ position: [this.left + 100 , this.top - this.height/4], size: [this.width - 130, this.height/4 -20], rangeX: [0,mic.binSize / fs], rangeY: [-1,1], labelX: "Time [s]", labelGapX: 20, labelY: "Waveform", tickStepY: 0.5, tickArrayX: [0,...sampleLin(5,15,11).map(v=>(2**v) / fs)], tickEndsX: false, labelGapX: 30, }) const pF = this.newPlot({ position: [this.left + 100 , this.bottom + 100], size: [this.width - 130, this.height/2 + 50], rangeX: [22,22720], rangeY: [0,100], labelX: "Frequency [Hz]", labelY: "Level [dB]", labelGapX: 20, tickArrayX: mic.bands.octaveCenters, tickStepY: 20, typeX: "log", labelGapX: 30, }) const oscLine = pP.line({ x: ()=>mic.timeArray, y: ()=>mic.waveForm }) const specLine = pF.line({ x: ()=>mic.freqArray, y: ()=>mic.spectrum }) const hitbox = pF.rect({ position: ()=>pF.position, size: ()=>pF.size, anchor: ()=>[0,0], screen: true, fill:"transparent" }) const octBar = pF.bar({ bins:()=>mic.getBandArray(reg.octaveFilter.value), y: ()=>mic.bandLevels(reg.octaveFilter.value), opacity: 0.8, }) const weightLine = pF.plotFn({ y:f=>mic.getWeightFn(reg.weighting.value)(f) + 80, dash: "20 20", stroke: color.neutral }) let mx = 100 const markers = pF.group("markers") markers.classList.add("hidden") for(let i = 1; i <= reg.harmonics.max+1; i++){ pF.line({ x:()=>[i*mx,i*mx], y:()=>[pF.y.range[0],pF.y.range[1]], stroke:color.highlight, strokeWidth:1, group:markers, }).i = i - 1 pF.text({ position: ()=>[pF.x.scale.toRange(i*mx)+1,pF.y.scale.toRange(pF.y.range[1])], text: ()=>{ const x = round(i*mx) return x>=1e3?round(x/1000,i<3?2:1)+" k ":x }, anchor: ()=>[ i>4?i>5?0.1:0.25:0.5, i>4?i>5?2:1.75:1.5 ], screen:true, clip:false, color:color.highlight, fontSize:22, group:markers, opaque:true, }).i = i - 1 } const ttg = pF.group("tooltip") ttg.classList.add("hidden") let ttPos = [this.middle,this.center] let ttCenter, ttMin, ttMax, ttLevel pF.rect({ position: ()=>ttPos, size: ()=>[250,140], corner: 15, group: ttg, screen: true, clip: false, fill: color.plotBackground, stroke: color.neutral, }) pF.text({ position: ()=>[ttPos[0],ttPos[1]+40], text: ()=>ttLevel, screen: true, clip: false, group: ttg, }) pF.text({ position: ()=>[ttPos[0],ttPos[1]], text: ()=>ttCenter, screen: true, clip: false, group: ttg, }) pF.text({ position: ()=>[ttPos[0],ttPos[1]-40], text: ()=>ttMax, screen: true, clip: false, group: ttg, }) mic.onUpdate(m=>{ oscLine.update() specLine.update() if (reg.octaveFilter.value != "none") octBar.update() }) reg.octaveFilter.onUpdate(v=>{ octBar.classList.toggle("hidden",v=="none") if (v!="none") octBar.updateBins() octBar.subs.forEach(b=>{ b.addAction(p=>{ ttg.classList.remove("hidden") ttLevel = "Level: " + round(b.value,1) + " dB" ttCenter = "Center: " + formatPre(b.center) + "Hz" ttMax = formatPre(b.min,true)+"- "+formatPre(b.max) + "Hz" ttPos = [min(pF.toX(b.center),this.width - 125),pF.toY(b.value) + 80] ttg.update() b.style.opacity = 0.95 },"hover") b.addAction(p=>{ ttg.classList.add("hidden") b.style.opacity = 0.8 },"unhover") }) }) reg.weighting.onUpdate(v=>{ weightLine.classList.toggle("hidden",v=="none") mic.weighting = v weightLine.update() }) reg.sampleRate.textContent = format(fs/1e3) reg.binSizeExp.textContent = format(reg.binSize.value) reg.binSize.onUpdate(v=>{ mic.binSize = 2**v if(v>7) pP.x.max = 1.001 * mic.binSize / fs reg.binSizeExp.textContent = format(v) }) reg.binRateText.textContent = format(reg.binRate.value) reg.binRate.onUpdate(v=>{ mic.binRate = v reg.binRateText.textContent = round(v) }) reg.binSmooth.onUpdate(v=>{ mic.binSmoothing = v }) reg.freqScale.onUpdate(v=>{ pF.x.type = v?"lin":"log" weightLine.update() specLine.update() if (reg.octaveFilter.value != "none") octBar.update() }) hitbox.addAction(p=>{ mx = round(p.x) markers.update() }) reg.harmonics.onUpdate(v=>{ markers.forEach(t=>t.classList.toggle("hidden",t.i>v)) markers.update() }) reg.harmonics.value = 2 reg.harmonicMarks.onUpdate((v,V,el)=>{ mx = 100 markers.update() markers.classList.toggle("hidden",!v) el.button.style.background = v?color.highlight:"" el.button.style.color = v?color.textInv:"" reg.harmonics.handleText.style.color = v?color.textInv:"" reg.harmonics.handleGroup.firstChild.style.fill = v?color.highlight:"" }) document.addEventListener("keydown",e=>{ e.preventDefault() if(e.code=="Space") mic.toggle() })