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

无锡网站推广公司百度官网

无锡网站推广公司,百度官网,无锡专业制作网站,可以做请柬的网站思路 获取设备信息 获取录音的频谱数据 绘制频谱图 具体实现 封装 loadDevices.js /*** 是否支持录音*/ const recordingSupport () > {const scope navigator.mediaDevices || {};if (!scope.getUserMedia) {scope navigatorscope.getUserMedia || (scope.getUserM…

思路

获取设备信息

获取录音的频谱数据

绘制频谱图

具体实现

封装 loadDevices.js


/*** 是否支持录音*/
const recordingSupport = () => {const scope = navigator.mediaDevices || {};if (!scope.getUserMedia) {scope = navigatorscope.getUserMedia || (scope.getUserMedia = scope.webkitGetUserMedia || scope.mozGetUserMedia || scope.msGetUserMedia);}if (!scope.getUserMedia) {return false}return scope
}// 获取麦克风权限
export const getUserMediaPermission = () => {return new Promise((resolve, reject) => {const mediaDevices = recordingSupport()if (mediaDevices.getUserMedia) {let constraints = { audio: true }mediaDevices.getUserMedia(constraints).then(resolve, reject);} else { reject(false) } // 浏览器不支持录音})
}function checkMime() {var types = ["audio/mpeg","audio/webm","audio/mp4","audio/wav","audio/ogg","audio/flac","audio/m4a","audio/mp3","audio/mpga","audio/oga",];let first;for (var i in types) {// 判断当前浏览器支持哪种let supported = MediaRecorder.isTypeSupported(types[i]);if (supported && !first) {console.log("Is " + types[i] + " supported? " + (supported ? "Yes!" : "Nope :("));first = types[i];}}return first;
}let streams = []
let stopDraw = false/*** 释放资源*/
export const devicesDispose = () => {console.log('devicesDispose-释放资源');stopDraw = truestreams.forEach(e => {e.getTracks().forEach(track => track.stop());})
}export const getAudioContext = () => window.AudioContext ||window.webkitAudioContext ||window.mozAudioContext ||window.msAudioContext;export default function loadDevices(options = {}) {const { readover = () => { }, change = () => { }, stop = () => { } } = optionslet analyser;let mediaRecorder;let dataArray;let audioChunks = [];try {const draw = () => {if (stopDraw) returnrequestAnimationFrame(draw);analyser.getByteTimeDomainData(dataArray);change(dataArray);};let mimeType = checkMime();getUserMediaPermission().then((stream) => {streams.push(streams)// 创建记录器mediaRecorder = new MediaRecorder(stream, { mimeType });// 音频数据发生变化时收集音频片段,用于合成音频文件mediaRecorder.addEventListener("dataavailable", (event) => {console.log("mediaRecorder-dataavailable:", event);audioChunks.push(event.data);});// // 监听音频开始录制// mediaRecorder.addEventListener('start', () => {//     console.log("mediaRecorder-start:");//     audioChunks = []// })// 音频录制结束回调mediaRecorder.addEventListener("stop", () => {console.log("mediaRecorder-end:", audioChunks);const audioBlob = new Blob(audioChunks, { type: "audio/mp4" }); // wav webm mp4  stop(audioBlob);// 清空 chunks 以便下一次录音 audioChunks = []});// 获取音频数据const audioContext = new getAudioContext()();const source = audioContext.createMediaStreamSource(stream);// 通过AnalyserNode对象的getByteTimeDomainData方法来获取音频数据的波形形式:// 获取音频时间和频率数据analyser = audioContext.createAnalyser();// 定义长度analyser.fftSize = 2048; // 可以调整这个值来改变细节const bufferLength = analyser.frequencyBinCount;dataArray = new Uint8Array(bufferLength);// 合并流数据source.connect(analyser);draw()readover(mediaRecorder)}).catch((err) => {console.log("stream-errr", err);});} catch (err) {console.log("mediaDevices-errr", err);}
}

示例

import { onMounted, onUnmounted } from "vue";
import loadDevices, {devicesDispose,getAudioContext,
} from "../compositions/VerbalChat/loadDevices";let mediaRecorder;
const speak = ref(false);// 停止录制
const uploadAudio = (blob) => {// others 获取录音数据之后后续处理 上传// const formData = new FormData();// formData.append("file", blob);// 接口formData上传
};// 绘制方法
const draw = ({ data }) => {// 调用子组件的绘制方法,传递数据// verCanvas.value && verCanvas.value.draw({ data });
};const btnClick = () => {if (!speak.value) {console.log("开始录制"); speak.value = true;mediaRecorder && mediaRecorder.start();} else {console.log("停止录制");speak.value = false;mediaRecorder && mediaRecorder.stop();}
};onMounted(() => {loadDevices({readover: (r) => (mediaRecorder = r),change: (dataArray) => {if (speak.value) {// 处于录制中draw({ data: dataArray });}},stop: (blob) => uploadAudio(blob),});
});onUnmounted(()=>devicesDispose())

绘制频谱图

<template><canvas class="VerbalCanvas" ref="canvasRef"></canvas>
</template><script setup>
import { onMounted, ref, watch } from "vue";let ctx, canvas;
const canvasRef = ref();const draw = ({ data }) => {if (!canvasRef.value) return;canvas = canvasRef.value;canvas.height = parseFloat(getComputedStyle(canvas)["height"]);canvas.width = parseFloat(getComputedStyle(canvas)["width"]);ctx = canvas.getContext("2d");// drawWave(ctx, canvas, type, data);// drawLoop(ctx, canvas, type, data);drawCircle(ctx, canvas, type, data);
}const clear = () => {try {ctx.clearRect(0, 0, canvas.width, canvas.height);} catch (er) {console.log("er", er);}
}defineExpose({ draw, clear });

绘制曲线

const waveH = 150; // 波区域高度
const obj = {top: 0,center: canvas.height / 2,bottom: canvas.height - waveH,
};
const initY = obj[type];
const dataArray = data || []; // 模拟数据 随机生成一个数组,值随机ctx.fillStyle = "rgba(200, 200, 200, 0)";
ctx.fillRect(0, 0, canvas.width, canvas.height);ctx.lineWidth = 1;
ctx.strokeStyle = "#0077FF"; //"rgb(0, 0, 0)";ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();const sliceWidth = (canvas.width * 1.0) / dataArray.length;
let x = 0;for (let i = 0; i < dataArray.length; i++) {const v = dataArray[i] / 128.0;// const y = (v * canvas.height) / 2 ;const y = (v * waveH) / 2 + initY;if (i === 0) {ctx.moveTo(x, y);} else {ctx.lineTo(x, y);}x += sliceWidth;
}// ctx.lineTo(canvas.width, canvas.height / 2);
ctx.lineTo(canvas.width, waveH / 2) + initY;
ctx.stroke();

绘制音频环

ctx.clearRect(0, 0, canvas.width, canvas.height);
const cX = canvas.width / 2;
const cY = canvas.height / 2;
const r = 100;
const basel = Math.floor(data.length / 360);
for (var i = 0; i < 360; i++) {var value = (data[i * basel] / 60) * 8; //8;   // 模拟数据 value = Math.random() * 100ctx.beginPath();ctx.lineWidth = 2;ctx.strokeStyle = "#08a3ef";ctx.moveTo(cX, cY);//R * cos (PI/180*一次旋转的角度数) ,-R * sin (PI/180*一次旋转的角度数)ctx.lineTo(Math.cos(((i * 1) / 180) * Math.PI) * (r + value) + cX,-Math.sin(((i * 1) / 180) * Math.PI) * (r + value) + cY);ctx.stroke();
}
//画一个小圆,将线条覆盖
ctx.beginPath();
ctx.lineWidth = 1;
ctx.arc(cX, cY, r, 0, 2 * Math.PI, false);
ctx.fillStyle = "#000";
ctx.stroke();ctx.fill();

绘制圆

/** 绘制圆 */
const drawCircle = (ctx, canvas, type, data) => {ctx.clearRect(0, 0, canvas.width, canvas.height);const cX = canvas.width / 2;const cY = canvas.height / 2;const r = 100;for (var i = 0; i < data.length; i += 4) {const v = (data[i] + data[i + 1] + data[i + 2] + data[i + 3]) / 4;const r = v * 0.5;// for (var i = 0; i < 254; i += 4) {//   const r = Math.random() * 100;ctx.beginPath();ctx.lineWidth = 1;ctx.arc(cX, cY, r, 0, 2 * Math.PI, false);ctx.strokeStyle = "#c46868";ctx.stroke();}
};
http://www.yidumall.com/news/31143.html

相关文章:

  • asp个人网站怎么建立网站
  • 网站子页怎么做百度推广多少钱
  • 网站改版会降权吗百度热搜榜在哪里看
  • 网站建设和维护待遇媒体平台
  • 多语言站点 wordpress手机百度引擎搜索入口
  • 软件网站建设专业竞价托管如何托管
  • 做面包的公司网站重庆网络营销
  • 四川外国语大学网站建设系百度口碑
  • 甘肃做网站哪家好百度搜题
  • 0元购怎么在网站做营销官网
  • 中国建设委员会网站上查询系统永久免费的网站服务器有哪些软件
  • 猪八戒做网站怎么样外贸推广建站
  • 做网站设计师工资多少温州免费建站模板
  • 做擦边网站 服务器放在狗爹电脑网页制作
  • asp.net企业网站模板西安专业做网站公司
  • 广东联通通信建设有限公司 网站seo培训中心
  • 个人可以备案什么网站网店运营推广实训
  • 网络营销的三大基础搜索排名优化软件
  • 海外云服务器推荐九幺seo工具
  • 唯美网站建设百度搜索引擎优化的推广计划
  • wordpress首页排版错误大泽山seo快速排名
  • 现在都用什么做网站他达拉非功效与作用主要会有哪些
  • 树立网站风格的步骤怎样创建自己的网站
  • 搭建网站赚钱国际局势最新消息今天
  • 农业网站建设源代码 ASP百度推广售后服务电话
  • 郑州seo费用seo公司关键词
  • 企业网站推广方式和策略电商平台的营销方式
  • 建湖做网站的百度搜索资源
  • 成都网站备案网站设计专业的公司
  • 8u免费空间seo推广方案怎么做