当前位置: 首页 > news >正文

哈尔滨专业建网站哪家好小视频解析网站怎么做

哈尔滨专业建网站哪家好,小视频解析网站怎么做,网站备案地址,湘潭seo优化首选在这有两种录音时的动态效果 1.使用react-media-recorder库实现基础录音功能 2.添加录音计时器显示录音时长 3.实现音频可视化效果,通过Canvas绘制频谱图 4.处理麦克风权限状态检测 5.提供开始/停止录音和清除录音的控制按钮 先添加依赖 npm install react-media-…

在这有两种录音时的动态效果

1.使用react-media-recorder库实现基础录音功能
2.添加录音计时器显示录音时长
3.实现音频可视化效果,通过Canvas绘制频谱图
4.处理麦克风权限状态检测
5.提供开始/停止录音和清除录音的控制按钮
在这里插入图片描述

先添加依赖

npm install react-media-recorder

// export default AudioRecorder;
import React, { useState, useEffect, useRef } from 'react';
import { useReactMediaRecorder } from 'react-media-recorder';
import ECGVisualizer from './component/ECGV'
import './index.less'
const EnhancedAudioRecorder = () => {const [recordingTime, setRecordingTime] = useState(0);const timerRef = useRef(null);const canvasRef = useRef(null);const audioContextRef = useRef(null);const analyserRef = useRef(null);const animationRef = useRef(null);const [permissionStatus, setPermissionStatus] = useState<'unknown' | 'granted' | 'denied'>('unknown');const {status,startRecording,stopRecording,mediaBlobUrl,previewAudioStream,clearBlobUrl,} = useReactMediaRecorder({audio: true,onStart: () => setPermissionStatus('granted'),onStop: (blobUrl, blob) => {clearInterval(timerRef.current);cancelAnimationFrame(animationRef.current);// setRecordingTime(0);}});// 检查初始权限状态useEffect(() => {const checkPermission = async () => {try {if (navigator.permissions) {const status = await navigator.permissions.query({ name: 'microphone' });setPermissionStatus(status.state);status.onchange = () => setPermissionStatus(status.state);}} catch (e) {console.log('Permissions API not supported');}};checkPermission();return () => clearInterval(timerRef.current);}, []);// 音频可视化处理useEffect(() => {if (previewAudioStream && status === 'recording') {timerRef.current = setInterval(() => {setRecordingTime(prev => prev + 1);}, 1000);setupAudioVisualizer();}return () => {cancelAnimationFrame(animationRef.current);clearInterval(timerRef.current);};}, [previewAudioStream, status]);const setupAudioVisualizer = () => {audioContextRef.current = new (window.AudioContext || window.webkitAudioContext)();analyserRef.current = audioContextRef.current.createAnalyser();const source = audioContextRef.current.createMediaStreamSource(previewAudioStream);source.connect(analyserRef.current);analyserRef.current.fftSize = 512;const bufferLength = analyserRef.current.frequencyBinCount;const dataArray = new Uint8Array(bufferLength);const draw = () => {animationRef.current = requestAnimationFrame(draw);analyserRef.current.getByteFrequencyData(dataArray);const canvas = canvasRef.current;if (!canvas) return;const ctx = canvas.getContext('2d');const width = canvas.width;const height = canvas.height;ctx.clearRect(0, 0, width, height);const barWidth = (width / bufferLength) * 0.8;let x = 0;for (let i = 0; i < bufferLength; i++) {const barHeight = (Math.pow(dataArray[i]/255, 0.5)) * height;const hue = i / bufferLength * 360;ctx.fillStyle = `hsl(${hue}, 100%, 50%)`;ctx.fillRect(x, height - barHeight, barWidth, barHeight);x += barWidth + 1;}};draw();};const formatTime = (seconds) => {const mins = Math.floor(seconds / 60).toString().padStart(2, '0');const secs = (seconds % 60).toString().padStart(2, '0');return `${mins}:${secs}`;};// 处理开始录音逻辑const handleStartRecording = async () => {if (permissionStatus === 'denied') {alert('请在浏览器设置中允许麦克风权限后刷新页面');return;}try {await startRecording();} catch (err) {// 出错时清除定时器if (timerRef.current) {clearInterval(timerRef.current);}console.error('录音错误:', err);}};const handleClear=()=>{clearBlobUrl();   setRecordingTime(0);setupAudioVisualizer()}return (<div className="enhanced-recorder"><div className="recorder-controls"><buttononClick={handleStartRecording}disabled={status === 'recording'}>{status === 'recording' ? '录音中...' : '开始录音'}</button><buttononClick={stopRecording}disabled={status !== 'recording'}>停止录音</button><buttononClick={handleClear}>清除录音</button><div className="recording-time">录音时长: {formatTime(recordingTime)}</div></div><div className="visualizer-container"><canvasref={canvasRef}height={50}style={{  width:'100%'}}/></div><ECGVisualizer previewAudioStream={previewAudioStream} status={status} />{mediaBlobUrl && (<div className="playback-section"><h3>录音回放{mediaBlobUrl}</h3><audio src={mediaBlobUrl} controls /><ahref={mediaBlobUrl}download={`recording-${new Date().toISOString()}.wav`}className="download-btn">下载录音</a></div>)}<div className="status-info"><p>当前状态: <span className={status}>{status}</span></p></div></div>);
};export default EnhancedAudioRecorder;

第二种动态我做成了组件

import React, { useRef, useEffect } from 'react';
import { StatusMessages } from 'react-media-recorder';
import './ECGV.less'
interface ECGVisualizerProps {previewAudioStream: MediaStream | null;status: StatusMessages;
}const ECGVisualizer: React.FC<ECGVisualizerProps> = ({ previewAudioStream, status 
}) => {const canvasRef = useRef<HTMLCanvasElement>(null);const animationRef = useRef<number>();const audioContextRef = useRef<AudioContext>();const analyserRef = useRef<AnalyserNode>();const dataArrayRef = useRef<Uint8Array>();// 设置音频上下文和分析器const setupAudioContext = () => {if (!previewAudioStream || !canvasRef.current) return;audioContextRef.current = new (window.AudioContext || (window as any).webkitAudioContext)();analyserRef.current = audioContextRef.current.createAnalyser();const source = audioContextRef.current.createMediaStreamSource(previewAudioStream);source.connect(analyserRef.current);analyserRef.current.fftSize = 2048;const bufferLength = analyserRef.current.frequencyBinCount;dataArrayRef.current = new Uint8Array(bufferLength);drawECG();};// 绘制心电图效果const drawECG = () => {if (!analyserRef.current || !canvasRef.current || !dataArrayRef.current) return;const canvas = canvasRef.current;const ctx = canvas.getContext('2d');if (!ctx) return;const width = canvas.width;const height = canvas.height;analyserRef.current.getByteTimeDomainData(dataArrayRef.current);ctx.clearRect(0, 0, width, height);ctx.lineWidth = 2;ctx.strokeStyle = '#ff0000';ctx.beginPath();const sliceWidth = width / dataArrayRef.current.length;let x = 0;let lastY = height / 2;// 添加基线ctx.moveTo(0, height / 2);ctx.lineTo(width, height / 2);ctx.strokeStyle = 'rgba(255, 0, 0, 0.2)';ctx.stroke();ctx.beginPath();ctx.strokeStyle = '#ff0000';// 绘制心电图波形for (let i = 0; i < dataArrayRef.current.length; i++) {const v = dataArrayRef.current[i] / 128.0;const y = v * height / 2;if (i === 0) {ctx.moveTo(x, y);} else {if (Math.abs(y - lastY) > height / 4) {ctx.lineTo(x, y);ctx.stroke();ctx.beginPath();ctx.moveTo(x, y);} else {ctx.lineTo(x, y);}}lastY = y;x += sliceWidth;}ctx.stroke();animationRef.current = requestAnimationFrame(drawECG);};useEffect(() => {if (status === 'recording' && previewAudioStream) {setupAudioContext();}return () => {if (animationRef.current) {cancelAnimationFrame(animationRef.current);}if (audioContextRef.current && audioContextRef.current.state !== 'closed') {audioContextRef.current.close();}};}, [status, previewAudioStream]);return (<div className="ecg-container"><canvas ref={canvasRef} width={600} height={200}style={{background: '#111',display: status === 'recording' ? 'block' : 'none'}}/></div>);
};export default ECGVisualizer;
.ecg-recorder {max-width: 800px;margin: 0 auto;padding: 20px;background: #222;color: white;border-radius: 10px;font-family: 'Arial', sans-serif;
}.controls {display: flex;gap: 15px;align-items: center;margin-bottom: 20px;
}.record-btn {background: #e53935;padding: 10px 20px;border: none;border-radius: 5px;color: white;font-weight: bold;cursor: pointer;
}.record-btn:hover {background: #c62828;
}.record-btn:disabled {background: #555;cursor: not-allowed;
}.stop-btn {background: #1e88e5;padding: 10px 20px;border: none;border-radius: 5px;color: white;font-weight: bold;cursor: pointer;
}.stop-btn:hover {background: #1565c0;
}.stop-btn:disabled {background: #555;cursor: not-allowed;
}.timer {margin-left: auto;font-family: monospace;font-size: 1.2em;
}.ecg-container {margin: 20px 0;border: 1px solid #444;border-radius: 5px;overflow: hidden;
}.playback {margin-top: 20px;padding: 15px;background: #333;border-radius: 5px;
}.download-btn {display: inline-block;margin-top: 10px;padding: 8px 16px;background: #43a047;color: white;text-decoration: none;border-radius: 4px;
}.download-btn:hover {background: #2e7d32;
}audio {width: 100%;margin-top: 10px;
}
http://www.dtcms.com/a/476821.html

相关文章:

  • 西安网站建设价格仙侠手游代理平台
  • 广安网站建设哪家好郑州有什么好玩的
  • 做网站的开发软件是什么Xammp安装Wordpress
  • 淄博公司制作网站有哪些网站界面修改
  • 学网站建设哪里有培训班
  • 扬州建设工程信息网站广东深圳天气预报
  • 网站后端开发需要学什么安溪城乡建设局网站
  • 东莞网站建设电镀挂具深圳手机网站建设价格
  • 网站建设的课程推广公司产品文案该怎么写
  • 如何用iis部署网站菜鸟教程网站首页制作
  • 南阳微网站建设wordpress js文件
  • 杭州互联网网站定制公司广告投放行业
  • 建站公司是什么意思京东网站推广方式
  • 网站字体特效代码微网站如何做推广
  • 天津南洋建设集团网站福州网站模板建站
  • 傻瓜式网站制作四川城乡和建设厅网站
  • 怎么用vs2017做asp网站淘宝网上购物商城
  • 商城网站的运营产品建站工具
  • 网站说服力 营销型网站策划 下载手机网站的优缺点
  • dede如何制作手机网站遵义网址
  • 企业信息查询系统官网广东兰州网站seo外包
  • 服装网站页面设计网站建设发展指引
  • 做视频网站 许可wordpress图片调方法
  • wordpress公司网站模版网站qq在线状态
  • 外贸业务怎么利用网站开发客户百度推广登录入口登录
  • 公司网站建设及优化计划书铜陵网站建设费用
  • 微九州合作网站网站txt地图怎么做
  • 宁波网站建设活动创建全国文明城市方案
  • 互动型网站成功例子关于加强教体局网站建设
  • wordpress+国内不使用seo优化培训多少钱