Download frontend/src/components/SpectrogramViewer.tsx from vipan-kumar/Audio_Deepfake_Detection: direct link, hf CLI and curl.
- Browser
- Download file 2.64 kB
-
https://huggingface.co/spaces/vipan-kumar/Audio_Deepfake_Detection/resolve/main/frontend/src/components/SpectrogramViewer.tsx
- Command line
-
hf download hf://spaces/vipan-kumar/Audio_Deepfake_Detection/frontend/src/components/SpectrogramViewer.tsx
-
curl -L -o SpectrogramViewer.tsx https://huggingface.co/spaces/vipan-kumar/Audio_Deepfake_Detection/resolve/main/frontend/src/components/SpectrogramViewer.tsx
2.64 kB
| import { useEffect, useRef } from "react"; | |
| interface Props { | |
| /** mel spectrogram values normalised to [0,1], shape [n_mels][T]. */ | |
| data: number[][]; | |
| height?: number; | |
| } | |
| /** Canvas mel-spectrogram with a cyan→amber→red colour ramp. */ | |
| export default function SpectrogramViewer({ data, height = 160 }: Props) { | |
| const ref = useRef<HTMLCanvasElement | null>(null); | |
| useEffect(() => { | |
| const cv = ref.current; | |
| if (!cv) return; | |
| if (!data.length) return; | |
| const T = data[0]?.length ?? 0; | |
| const F = data.length; | |
| if (T === 0) return; | |
| cv.width = T; | |
| cv.height = F; | |
| const ctx = cv.getContext("2d"); | |
| if (!ctx) return; | |
| const img = ctx.createImageData(T, F); | |
| // Colour ramp: cyber (cool) → amber → danger (hot) | |
| const ramp = (v: number): [number, number, number] => { | |
| const x = Math.max(0, Math.min(1, v)); | |
| // Three-stop interpolation | |
| const stops: [number, [number, number, number]][] = [ | |
| [0.0, [10, 18, 32]], // near-black bg | |
| [0.35, [0, 110, 145]], // dim cyan | |
| [0.6, [0, 212, 255]], // cyan | |
| [0.8, [245, 158, 11]], // amber | |
| [1.0, [255, 61, 90]], // danger red | |
| ]; | |
| for (let i = 0; i < stops.length - 1; i += 1) { | |
| const [a, ca] = stops[i]; | |
| const [b, cb] = stops[i + 1]; | |
| if (x >= a && x <= b) { | |
| const t = (x - a) / Math.max(1e-9, b - a); | |
| return [ | |
| ca[0] + t * (cb[0] - ca[0]), | |
| ca[1] + t * (cb[1] - ca[1]), | |
| ca[2] + t * (cb[2] - ca[2]), | |
| ]; | |
| } | |
| } | |
| return stops[stops.length - 1][1]; | |
| }; | |
| // mel rows are low → high frequency; canvas y=0 is top so flip vertically. | |
| for (let f = 0; f < F; f += 1) { | |
| const row = data[F - 1 - f]; | |
| for (let t = 0; t < T; t += 1) { | |
| const v = row[t] ?? 0; | |
| const [r, g, b] = ramp(v); | |
| const idx = (f * T + t) * 4; | |
| img.data[idx] = r | 0; | |
| img.data[idx + 1] = g | 0; | |
| img.data[idx + 2] = b | 0; | |
| img.data[idx + 3] = 255; | |
| } | |
| } | |
| ctx.putImageData(img, 0, 0); | |
| }, [data]); | |
| if (!data.length) { | |
| return ( | |
| <div className="panel-alt flex items-center justify-center font-mono text-xs text-ink-dim" style={{ height }}> | |
| spectrogram will appear after analysis | |
| </div> | |
| ); | |
| } | |
| return ( | |
| <div className="panel-alt overflow-hidden" style={{ height }}> | |
| <canvas | |
| ref={ref} | |
| className="block h-full w-full" | |
| style={{ imageRendering: "pixelated" }} | |
| aria-label="mel spectrogram" | |
| /> | |
| </div> | |
| ); | |
| } | |