initial commit

This commit is contained in:
Franz Heinzmann (Frando) 2021-06-07 16:22:13 +02:00
commit 0024f44c80
34 changed files with 1991 additions and 0 deletions

254
frontend/src/meter.jsx Normal file
View file

@ -0,0 +1,254 @@
import React, { useState, useEffect } from 'react'
const SCALE_MIN = -60
const SCALE_MAX = 0
function toPx (val) {
return value2px(val, SCALE_MIN, SCALE_MAX, 0, 100)
}
function toY (val) {
return 100 - value2px(val)
}
function MeterDefs (props) {
const { width } = props
let green = [0, toPx(-8)]
let yellow = [toPx(-8), toPx(-5)]
let red = [toPx(-5), toPx(0)]
const common = { x: 0, width }
return (
<defs>
<g id='peakbg'>
<rect
y={100 - red[1]}
height={100 - red[0]}
{...common}
{...style('#ff2244')}
/>
<rect
y={100 - yellow[1]}
height={100 - yellow[0]}
{...common}
{...style('#eeee00')}
/>
<rect
y={100 - green[1]}
height={100 - green[0]}
{...common}
{...style('#88ff00')}
/>
</g>
<linearGradient id='fadeGrad' y2='0' x2='1'>
<stop offset='0' stopColor='white' stopOpacity='0.2' />
<stop offset='0.5' stopColor='white' stopOpacity='0.5' />
<stop offset='1' stopColor='white' stopOpacity='0.2' />
</linearGradient>
<mask id='bgfade' maskContentUnits='objectBoundingBox'>
<rect width='1' height='1' fill='url(#fadeGrad)' />
</mask>
</defs>
)
}
let max = 0
let last = 0
function getMax (time, val) {
// let newmax = Math.max(val, max)
if (val > max) {
max = val
last = time
} else if (time - last > 3) {
max = val
} else if (time - last > 1) {
max = max - 1
// max = val
}
return max
}
export function EbuMeter (props) {
const { value } = props
const val = value
// let [max, setMax] = useState(0)
const width = 40
const gutter = 1
let min = SCALE_MIN
// let min = -30 // mic
// let peakMax = -2
// let ebuMax = -5
let peakMax = SCALE_MAX
let ebuMax = SCALE_MAX
// Momentary peak
// let peakM = value2px(val.M, min, ebuMax, 0, 100)
// Short-term peak
let peakS = value2px(val.S, min, ebuMax, 0, 100)
let peakL = 0
let peakR = 0
if (val.FTPK) {
peakL = value2px(val.FTPK[0], min, peakMax, 0, 100)
peakR = value2px(val.FTPK[1], min, peakMax, 0, 100)
}
if (peakL > 100) peakL = 0
if (peakR > 100) peakR = 0
if (peakS > 100) peakS = 0
let max = getMax(val.t, Math.max(peakL, peakR))
const meterWidth = width / 2 - gutter / 2
const peakMeterL = {
id: 'peakL',
peak: peakL,
x: 0,
width: meterWidth
}
const peakMeterR = {
id: 'peakR',
peak: peakR,
x: meterWidth + gutter,
width: meterWidth
}
return (
<svg
xmlns='http://www.w3.org/2000/svg'
width='100%'
heigh='100%'
viewBox={`0 0 ${width} 100`}
preserveAspectRatio='xMaxYMax meet'
>
<MeterDefs width={width} />
<PeakMeter {...peakMeterL} />
<PeakMeter {...peakMeterR} />
{/* <rect y={100 - max} x='0' width={width} height='0.8' fill='#a9f' /> */}
</svg>
)
}
function PeakMeter (props = {}) {
const { peak, width, x, id } = props
const mask = {
y: 100 - peak,
height: peak,
x,
width
}
// const range = -60
// const gutter = 0.5
// const steps = 24
// const dbPerStep = range / steps
// const scale = new Array(steps).fill(null).map((_, i) => {
// const bottom = toPx(dbPerStep * (i)) - gutter
// const top = toPx(dbPerStep * (i + 1))
// let fill = '#fff'
// // if (bottom > peak) fill = '#444'
// return {
// fill,
// x,
// width,
// y: 100 - top,
// height: top - bottom
// }
// })
const height = 100
const gutter = 0.8
const steps = 24
const heightPerStep = height / steps
// const filledSteps = Math.ceil(peak / steps)
const scale = new Array(steps).fill(null).map((_, i) => {
const bottom = heightPerStep * i
const top = bottom + heightPerStep - gutter
let fill = 'white'
if (((top + bottom) / 2) > peak) fill = '#444'
// if ((steps * i) > peak) return
// const y = 100 - heightPerStep * i
return {
fill,
x,
width,
y: 100 - top,
height: top - bottom
}
}).filter(x => x)
return (
<>
<defs>
<mask id={id}>
<rect fill='#000' {...mask} />
{scale.map((rect, i) => <rect key={i} {...rect} />)}
</mask>
</defs>
<g
mask={`url(#${id})`}
style={{ opacity: 0.9 }}
>
<use xlinkHref='#peakbg' />
</g>
</>
)
}
function sigLog (n) {
return Math.log(Math.abs(n) + 1) / Math.log(10) * sig(n)
}
function sig (n) {
return n === 0 ? 0 : Math.abs(n) / n
}
function sigExp (n) {
return (Math.pow(10, Math.abs(n)) - 1) * sig(n)
}
function value2px (value, valueMin, valueMax, pxMin, pxMax) {
if (value < valueMin) value = valueMin
if (value > valueMax) value = valueMax
if (isNaN(value) || value === null) value = valueMin
const valueWidth = valueMax - valueMin
const pixelWidth = pxMax - pxMin
const ratio = pixelWidth / valueWidth
return ratio * (value - valueMin) + pxMin
// const ratio = value / (valueMax - valueMin)
// const scaled = ratio * (pxMax - pxMin)
// return pxMin + scaled
}
// This is the original function that display the meter in a log scale.
function value2pxLog (value, valueMin, valueMax, pxMin, pxMax) {
var valueWidth = sigLog(valueMax) - sigLog(valueMin)
var pixelWidth = pxMax - pxMin
var ratio = pixelWidth / valueWidth
return ratio * (sigLog(value) - sigLog(valueMin)) + pxMin
}
function px2value (px, valueMin, valueMax, pxMin, pxMax) {
var valueWidth = sigLog(valueMax) - sigLog(valueMin)
var pixelWidth = pxMax - pxMin
var ratio = pixelWidth / valueWidth
return sigExp((px - pxMin) / ratio + sigLog(valueMin))
}
function prettify (n) {
var exp = Math.round(Math.pow(10, Math.log(Math.abs(n)) / Math.log(10)))
return exp === 0 ? 0 : Math.round(n / exp) * exp
}
function style (color) {
return { style: { fill: color } }
}