Python测量音视频相对音量
辛苦整理请您珍惜分贝dB为单位显示音量。html!DOCTYPE htmlhtml langzh-CNheadmeta charsetUTF-8 /meta nameviewport contentwidthdevice-width, initial-scale1.0 /title实时分贝测量仪/titlestyle/* ----- 全局样式 ----- */* {box-sizing: border-box;margin: 0;padding: 0;}body {font-family: Segoe UI, Roboto, system-ui, sans-serif;background: #0b0e17;min-height: 100vh;display: flex;justify-content: center;align-items: center;margin: 0;padding: 20px;}.card {background: #1a1f2f;border-radius: 32px;padding: 40px 36px 44px;max-width: 520px;width: 100%;box-shadow: 0 20px 50px rgba(0, 0, 0, 0.7);text-align: center;border: 1px solid #2e364a;transition: 0.2s;}h1 {font-size: 24px;font-weight: 600;letter-spacing: 1px;color: #e8edf5;margin-bottom: 6px;}.sub {color: #8892b0;font-size: 14px;margin-bottom: 28px;border-bottom: 1px solid #2a3247;padding-bottom: 16px;}/* ----- 分贝数值 ----- */.db-display {background: #0f131f;border-radius: 60px;padding: 20px 10px;margin-bottom: 18px;border: 1px solid #2e364a;}.db-number {font-size: 78px;font-weight: 700;color: #b7c9ff;line-height: 1;font-variant-numeric: tabular-nums;letter-spacing: -1px;}.db-unit {font-size: 28px;font-weight: 400;color: #6a7a9e;margin-left: 4px;}.db-label {color: #6a7a9e;font-size: 14px;letter-spacing: 2px;margin-top: 6px;}/* ----- 音量条 ----- */.meter-wrap {background: #0f131f;border-radius: 40px;height: 14px;margin: 16px 0 22px;overflow: hidden;border: 1px solid #2a3247;}.meter-fill {height: 100%;width: 0%;background: linear-gradient(90deg, #4caf9e, #f4c542, #f27a5e);border-radius: 40px;transition: width 0.08s ease-out;}/* ----- 控制区 ----- */.controls {display: flex;flex-wrap: wrap;gap: 12px;justify-content: center;margin: 18px 0 14px;}.btn {background: #283042;border: none;color: #d3defa;font-size: 15px;font-weight: 500;padding: 12px 28px;border-radius: 60px;cursor: pointer;transition: 0.15s;flex: 1 1 auto;min-width: 110px;border: 1px solid #36405a;letter-spacing: 0.3px;}.btn:hover {background: #323d5a;border-color: #5a6a8e;color: #fff;}.btn.primary {background: #3b4b8c;border-color: #4f63b0;color: #fff;}.btn.primary:hover {background: #4f66b8;border-color: #6b82d4;}.btn:disabled {opacity: 0.35;pointer-events: none;filter: grayscale(0.4);}/* ----- 文件选择 ----- */.file-area {margin: 10px 0 4px;}.file-area label {display: inline-block;background: #1f263b;padding: 10px 24px;border-radius: 60px;color: #b0c0e0;font-size: 14px;font-weight: 400;border: 1px dashed #4a5577;cursor: pointer;transition: 0.15s;width: 100%;}.file-area label:hover {background: #2a334d;border-color: #6a7ea8;}.file-area input[typefile] {display: none;}.file-name {color: #6a7a9e;font-size: 13px;margin-top: 6px;min-height: 20px;}/* ----- 状态 ----- */.status {margin-top: 18px;font-size: 14px;color: #6a7a9e;background: #121724;padding: 10px 14px;border-radius: 40px;border: 1px solid #242d44;}.status .highlight {color: #b7c9ff;font-weight: 500;}/* 响应式 */media (max-width: 460px) {.card {padding: 28px 18px 32px;}.db-number {font-size: 56px;}.btn {padding: 10px 16px;font-size: 14px;min-width: 80px;}}/style/headbodydiv classcardh1分贝测量仪/h1div classsub实时音频 · 麦克风 / 文件/div!-- 分贝数值 --div classdb-displaydiv classdb-numberspan iddbValue--/spanspan classdb-unitdB/span/divdiv classdb-label声压级 (SPL)/div/div!-- 音量条 --div classmeter-wrapdiv classmeter-fill idmeterFill stylewidth:0%;/div/div!-- 控制按钮 --div classcontrolsbutton classbtn primary idbtnMic麦克风/buttonbutton classbtn idbtnStop disabled停止/button/div!-- 文件上传 --div classfile-arealabel foraudioFile选择音频 / 视频文件/labelinput typefile idaudioFile acceptaudio/*,video/* /div classfile-name idfileName未选择文件/div/div!-- 状态 --div classstatus idstatusDisplayspan classhighlight●/span 就绪点击“麦克风”或上传文件开始/div/divscript(function() {use strict;// ----- DOM 引用 -----const dbSpan document.getElementById(dbValue);const meterFill document.getElementById(meterFill);const statusEl document.getElementById(statusDisplay);const fileNameEl document.getElementById(fileName);const btnMic document.getElementById(btnMic);const btnStop document.getElementById(btnStop);const fileInput document.getElementById(audioFile);// ----- 音频上下文 节点 -----let audioCtx null;let analyser null;let dataArray null;// 当前激活的音频源 (用于清理)let currentSource null; // MediaStream | MediaElementAudioSourceNodelet isRunning false;let rafId null;// 平滑系数 (让数值变化更柔和)const SMOOTHING 0.25;let smoothedDb -60;// ----- 工具: 更新 UI -----function updateUI(dbValue) {// 限制显示范围 (通常人耳可听范围 0~120dB, 此处映射到 0~100 更直观)let clamped Math.max(0, Math.min(100, dbValue));let displayDb Math.round(clamped);dbSpan.textContent displayDb;// 音量条宽度 (0~100%)meterFill.style.width clamped %;// 根据分贝改变数值颜色 (可选)if (clamped 30) {dbSpan.style.color #8a9bc0;} else if (clamped 60) {dbSpan.style.color #b7c9ff;} else if (clamped 80) {dbSpan.style.color #f4c542;} else {dbSpan.style.color #f27a5e;}}// ----- 核心: 从 AnalyserNode 读取数据并计算分贝 -----function analyzeAudio() {if (!analyser || !isRunning) return;// 获取时域数据 (getByteTimeDomainData) 或频域数据 (getByteFrequencyData)// 使用时域数据计算 RMS 更接近“响度”感知analyser.getByteTimeDomainData(dataArray);let sum 0;for (let i 0; i dataArray.length; i) {// 将 0-255 映射到 -1..1const val (dataArray[i] - 128) / 128;sum val * val;}const rms Math.sqrt(sum / dataArray.length);// 将 RMS 转换为 dB (满量程 0dBFS, 此处映射到 0~100 显示)// 公式: dB 20 * log10(rms) , 通常 rms 在 0~1 之间, 结果在 -inf ~ 0 之间let db 0;if (rms 0.0001) {db 20 * Math.log10(rms);} else {db -60; // 接近静音}// 映射到 0~100 显示 (将 -60dB ~ 0dB 映射到 0~100)// 即: db 从 -60 到 0 对应 0 到 100let mapped (db 60) / 60 * 100;mapped Math.max(0, Math.min(100, mapped));// 平滑处理smoothedDb smoothedDb * (1 - SMOOTHING) mapped * SMOOTHING;updateUI(smoothedDb);// 继续下一帧rafId requestAnimationFrame(analyzeAudio);}// ----- 停止所有音频 -----function stopAll() {isRunning false;if (rafId) {cancelAnimationFrame(rafId);rafId null;}// 断开 关闭上下文if (audioCtx audioCtx.state ! closed) {audioCtx.close().catch(() {});}audioCtx null;analyser null;dataArray null;currentSource null;// 重置 UIdbSpan.textContent --;meterFill.style.width 0%;dbSpan.style.color #b7c9ff;statusEl.innerHTML span classhighlight●/span 已停止;btnMic.disabled false;btnStop.disabled true;fileInput.disabled false;}// ----- 初始化音频上下文 分析器 -----function initAudioContext() {if (audioCtx audioCtx.state ! closed) {// 如果已存在且未关闭, 直接返回return audioCtx;}// 兼容旧浏览器const Ctx window.AudioContext || window.webkitAudioContext;if (!Ctx) {statusEl.innerHTML 浏览器不支持 Web Audio API;return null;}audioCtx new Ctx();analyser audioCtx.createAnalyser();analyser.fftSize 1024;analyser.smoothingTimeConstant 0.8;// 设置 min/max 分贝范围 (用于 getByteFrequencyData, 但这里我们用 getByteTimeDomainData 不受影响)analyser.minDecibels -60;analyser.maxDecibels 0;dataArray new Uint8Array(analyser.fftSize);return audioCtx;}// ----- 开始分析 (source 已连接) -----function startAnalysis() {if (!audioCtx || !analyser) {statusEl.innerHTML ❌ 音频上下文未初始化;return;}// 恢复 suspended 状态if (audioCtx.state suspended) {audioCtx.resume().catch(err {statusEl.innerHTML 无法恢复音频上下文: err.message;return;});}isRunning true;btnMic.disabled true;btnStop.disabled false;fileInput.disabled true;statusEl.innerHTML span classhighlight●/span 测量中...;// 开始分析循环if (rafId) cancelAnimationFrame(rafId);analyzeAudio();}// ----- 从麦克风获取音频 -----async function startMicrophone() {try {// 先停止之前的所有stopAll();const ctx initAudioContext();if (!ctx) return;// 请求麦克风const stream await navigator.mediaDevices.getUserMedia({audio: {echoCancellation: false,noiseSuppression: false,autoGainControl: false}});currentSource stream;// 创建 MediaStreamAudioSourceNodeconst sourceNode ctx.createMediaStreamSource(stream);sourceNode.connect(analyser);// 不连接 destination 以免产生反馈啸叫 (仅分析用)statusEl.innerHTML span classhighlight●/span 麦克风已启动;startAnalysis();} catch (err) {statusEl.innerHTML 麦克风访问被拒绝: err.message;btnMic.disabled false;console.error(err);}}// ----- 从文件读取音频/视频 -----function startFile(file) {try {// 先停止之前的所有stopAll();if (!file) {statusEl.innerHTML 请选择一个文件;return;}// 检查文件类型if (!file.type.startsWith(audio/) !file.type.startsWith(video/)) {statusEl.innerHTML 请选择音频或视频文件;return;}const ctx initAudioContext();if (!ctx) return;// 创建 URLconst url URL.createObjectURL(file);// 创建 audio 元素 (也支持视频, 但只取音频轨道)const audioEl document.createElement(audio);audioEl.src url;audioEl.controls false;audioEl.autoplay true;// 确保音频可以播放audioEl.load();// 当元数据加载完成后连接audioEl.onloadedmetadata function() {try {const sourceNode ctx.createMediaElementSource(audioEl);sourceNode.connect(analyser);// 同时也连接到 destination 才能听到声音analyser.connect(ctx.destination);currentSource sourceNode;// 显示文件名fileNameEl.textContent file.name;statusEl.innerHTML span classhighlight●/span 正在播放: file.name;startAnalysis();} catch (err) {statusEl.innerHTML 无法连接音频: err.message;console.error(err);}};audioEl.onerror function() {statusEl.innerHTML 文件加载失败请尝试其他格式;btnMic.disabled false;btnStop.disabled true;fileInput.disabled false;URL.revokeObjectURL(url);};// 如果文件加载超时或失败, 清理setTimeout(() {if (!isRunning) {URL.revokeObjectURL(url);}}, 5000);} catch (err) {statusEl.innerHTML 处理文件出错: err.message;console.error(err);}}// ----- 事件绑定 -----// 麦克风按钮btnMic.addEventListener(click, startMicrophone);// 停止按钮btnStop.addEventListener(click, function() {stopAll();// 重置状态statusEl.innerHTML span classhighlight●/span 已手动停止;btnMic.disabled false;btnStop.disabled true;fileInput.disabled false;fileNameEl.textContent 未选择文件;});// 文件选择fileInput.addEventListener(change, function(e) {const file e.target.files[0];if (file) {startFile(file);} else {fileNameEl.textContent 未选择文件;}// 重置 input 以便重复选择同一文件fileInput.value ;});// 页面卸载时释放资源window.addEventListener(beforeunload, function() {stopAll();});// 处理用户点击页面时自动恢复音频上下文 (某些浏览器策略)document.addEventListener(click, function() {if (audioCtx audioCtx.state suspended) {audioCtx.resume().catch(() {});}}, { once: false });// 初始状态statusEl.innerHTML span classhighlight●/span 就绪点击“麦克风”或上传文件开始;btnStop.disabled true;})();/script/body/html功能与使用说明两种测量模式· 麦克风模式点击后浏览器会请求麦克风权限授权后即可实时测量周围环境的声音分贝。· 文件模式点击“选择音频/视频文件”上传本地文件软件会自动播放并分析其音量。实时反馈· 中央大数字显示当前分贝值下方的彩色进度条提供直观的视觉参考。· 分贝值经过平滑处理数值变化更柔和、易读。控制与状态· 点击 “停止” 按钮可随时结束测量并释放麦克风或音频资源。· 底部的状态栏会清晰显示当前工作状态如“测量中...”、“已停止”。注意事项· 首次使用麦克风时请允许浏览器访问麦克风权限。· 分贝值为相对值用于反映音量变化趋势并非专业校准的绝对声压级SPL。· 建议在Chrome、Edge、Firefox等现代浏览器中使用。

相关新闻

Python常见问题解决方法

Python常见问题解决方法

两天整理结果,希望能为你所用。麻烦三连关注一下,下载收藏以防找不到。⚠️ 高频运行时错误 (Runtime Errors)这类错误会导致程序中断,并抛出明确的异常类型。 SyntaxError (语法错误):代码不符合Python语法规则。常见于漏写冒号(…

2026/7/1 18:46:35阅读更多 →
3分钟免费解锁全皮肤:R3nzSkin国服换肤终极指南

3分钟免费解锁全皮肤:R3nzSkin国服换肤终极指南

3分钟免费解锁全皮肤:R3nzSkin国服换肤终极指南 【免费下载链接】R3nzSkin-For-China-Server Skin changer for League of Legends (LOL) 项目地址: https://gitcode.com/gh_mirrors/r3/R3nzSkin-For-China-Server 还在为英雄联盟皮肤太贵而烦恼吗&#xff1…

2026/7/1 18:46:35阅读更多 →
【吉林工程技术师范学院本科毕业论文】基于Spring Boot的防诈骗警民交流防护网站的设计与实现

【吉林工程技术师范学院本科毕业论文】基于Spring Boot的防诈骗警民交流防护网站的设计与实现

注:仅展示部分文档内容和系统截图,需要完整的视频、代码、文章和安装调试环境请私信up主。学生的技术与实现摘 要随着信息技术的快速发展,电信网络诈骗手段不断翻新,给公众财产安全与社会稳定带来严重威胁。传统防诈骗警民交流防…

2026/7/1 18:46:35阅读更多 →
openEuler-portal-mcp:一站式AI助手如何革新开源社区信息查询体验

openEuler-portal-mcp:一站式AI助手如何革新开源社区信息查询体验

openEuler-portal-mcp:一站式AI助手如何革新开源社区信息查询体验 【免费下载链接】openEuler-portal-mcp The repository of openEuler portal MCP Server 项目地址: https://gitcode.com/openeuler/openEuler-portal-mcp 前往项目官网免费下载:…

2026/7/1 19:46:43阅读更多 →
如何用Obsidian科研笔记模板3步构建你的学术知识库:告别信息碎片化

如何用Obsidian科研笔记模板3步构建你的学术知识库:告别信息碎片化

如何用Obsidian科研笔记模板3步构建你的学术知识库:告别信息碎片化 【免费下载链接】obsidian_vault_template_for_researcher This is an vault template for researchers using obsidian. 项目地址: https://gitcode.com/gh_mirrors/ob/obsidian_vault_template…

2026/7/1 19:46:43阅读更多 →
openeuler/ssh-utils配置指南:从安装到服务器管理全流程

openeuler/ssh-utils配置指南:从安装到服务器管理全流程

openeuler/ssh-utils配置指南:从安装到服务器管理全流程 【免费下载链接】ssh-utils ssh-utils is a tool for fast ssh connections. 项目地址: https://gitcode.com/openeuler/ssh-utils 前往项目官网免费下载:https://ar.openeuler.org/ar/ s…

2026/7/1 19:46:43阅读更多 →
为什么选择utwget?开源下载工具的革命性重构之路

为什么选择utwget?开源下载工具的革命性重构之路

为什么选择utwget?开源下载工具的革命性重构之路 【免费下载链接】utwget utwget is a refactoring of wget. 项目地址: https://gitcode.com/openeuler/utwget 前往项目官网免费下载:https://ar.openeuler.org/ar/ utwget是wget的重构版本&…

2026/7/1 19:46:43阅读更多 →
Kiran会话管理器应用程序管理机制深度剖析

Kiran会话管理器应用程序管理机制深度剖析

Kiran会话管理器应用程序管理机制深度剖析 【免费下载链接】kiran-session-manager The session manager will load all necessary applications for a full-featured user session. 项目地址: https://gitcode.com/openeuler/kiran-session-manager 前往项目官网免费下…

2026/7/1 19:46:43阅读更多 →
MDK警告及排查方法

MDK警告及排查方法

本文总结了嵌入式开发中常见的编译警告和错误类型及其解决方法,涉及变量定义、函数声明、代码格式等多个方面。 编译警告部分包括:未使用变量警告(#550-D)、文件末尾缺少换行(#1-D)、不可达代码&#xff0…

2026/7/1 19:41:43阅读更多 →
AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

6个月前的2025年12月,Boris Cherny 公开宣布自己卸载了 IDE。一时间,Vibe Coding 成了全行业最热的话题。6个月后,当我们回过头来拉一份真实账本,发现事情远没有"一句话生成一个App"那么浪漫。本文从产品经理和研发两个…

2026/7/1 4:42:14阅读更多 →
审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

引言:审计结束三个月了,审计员的权限还没关某城商行每年按照监管要求开展至少一次数据安全审计。审计期间,内审部门需要抽样检查各类业务数据——交易流水、客户信息、员工操作日志、权限配置记录。这些数据分布在不同系统中,审计…

2026/7/1 5:19:01阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/1 0:01:44阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/1 0:01:44阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/1 0:01:44阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/1 0:01:44阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/1 0:01:44阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/1 0:01:44阅读更多 →