js 选择一个音频文件,绘制音频的波形,从右向左逐渐前进。

news2025/1/19 23:22:30

选择一个音频文件,绘制波形,从右向左逐渐前进。
在这里插入图片描述

在这里插入图片描述

完整代码:

<template>
  <div>
    <input type="file" ="handleFileChange" accept="audio/*" />
    <button ="stopPlayback" :disabled="!isLoaded">停止</button>
    <canvas ref="canvas" width="1201" height="211"></canvas>
  </div>
</template>

<script>
import axios from "axios";

export default {
  data() {
    return {
      // audioUrl:"http://121.41.225.74:9091/mintti/app/storage/newFile/b26uvk9ipd8n5iop1lzs.wav",
      audioUrl: "http://121.41.225.74:9091/mintti/app/storage/newFile/c19xqqqtd8ywqyaf8gno.wav",
      // audioUrl: "http://121.41.225.74:9091/mintti/app/storage/newFile/d3msxipdfxrbyijm3ys0.wav",
      // audioUrl:"http://121.41.225.74:9091/mintti/app/storage/newFile/xm456t9dptsrigxye84q.wav",

      dataArray: [],
      isPlaying: false,
      isLoaded: false,
      drawInterval: 200, // 设置绘制的时间间隔(单位:毫秒)
      drawIntervalId: null,
      fileData: new Int8Array(0),
      index: 0,
      mWidth: 0,
      mHeight: 0,
    }
  },
  mounted() {
    const ctx = this.$refs.canvas.getContext('2d')
    this.drawGrid(ctx)
    this.downloadAudio()
  },
  methods: {
    // 下载音频文件
    downloadAudio() {
      axios({
        method: 'get',
        url: this.audioUrl,
        responseType: 'arraybuffer'
      }).then(res => {
        if (!res) {
          return;
        }

        console.log("decodeAudioData")
        this.loadAudio(res.data)
      }).catch(error => {
        console.error('下载音频时出错:', error);
      });;
    },

    handleFileChange(event) {
      this.isLoaded = false
      const file = event.target.files[0]

      this.stopPlayback()
      const reader = new FileReader();
      reader.onload = (e) => {
        console.log("onLoad")
        this.loadAudio(e.target.result)

      };

      reader.readAsArrayBuffer(file);
    },

    loadAudio(res) {
      this.dataArray = []
      this.isLoaded = true
      this.index = 0;
      // 获取文件的前 100 个字节
      this.fileData = new Int8Array(res);
      this.refreshData()

      this.drawIntervalId = setInterval(() => {
        console.log("定时器执行了")
        this.refreshData()
      }, this.drawInterval)//循环读取
    },
    refreshData() {
      let i = this.index
      console.log("文件总长度:" + this.fileData.byteLength + ",,i=" + i)
      if (i * 1600 + 44 > this.fileData.byteLength) {
        clearInterval(this.drawIntervalId)
        return
      }
      const byteArray = this.fileData.slice(i * 1600 + 44, (i + 1) * 1600 + 44);

      // 创建一个新的 Uint16Array,长度为 byteArray 的一半
      let shortArray = new Int16Array(byteArray.length / 2)

      //遍历 byteArray,将每两个字节合并成一个短整型
      for (let i = 0; i < byteArray.length; i += 2) {
        shortArray[i / 2] = (byteArray[i] & 0xFF) | (byteArray[i + 1] & 0xFF) << 8;
      }

      const step = 10;

      for (let i = 0; i < shortArray.length; i += step) {
        // console.log(i + "文件short值:" + shortArray[i])
        if (this.mWidth > 0 && this.dataArray.length >= this.mWidth) {
          this.dataArray.shift()
        }
        this.dataArray.push(shortArray[i])
      }

      this.isPlaying = true
      this.draw2();
      this.index += 1;
    },
    stopPlayback() {
      console.log("停止播放-stopPlayback")
      this.isPlaying = false

      clearInterval(this.drawIntervalId)
      const ctx = this.$refs.canvas.getContext('2d')
      ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
      this.drawGrid(ctx)
    },

    draw2() {
      if (!this.isPlaying) {
        return
      }
      // console.log('开始绘图-draw')

      const ctx = this.$refs.canvas.getContext('2d')
      ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
      this.drawGrid(ctx)
      this.drawWaveform(ctx)
    },
    drawGrid(ctx) {
      const { width, height } = ctx.canvas
      this.mWidth = ctx.canvas.width
      this.mHeight = ctx.canvas.height

      ctx.strokeStyle = '#ccc'
      ctx.lineWidth = 1

      for (let i = 0; i < height; i += 10) {
        ctx.beginPath()
        ctx.moveTo(0, i)
        ctx.lineTo(width, i)
        ctx.stroke()
      }

      for (let j = 0; j < width; j += 10) {
        ctx.beginPath()
        ctx.moveTo(j, 0)
        ctx.lineTo(j, height)
        ctx.stroke()
      }
    },
    drawWaveform(ctx) {
      ctx.beginPath()
      ctx.lineWidth = 1
      ctx.strokeStyle = '#25ebd7'


      let x = 0
      let len = this.dataArray.length;
      let index = this.mWidth - len;
      for (let i = index + 1; i < this.mWidth; i++) {
        const mCenterY = this.mHeight / 2;
        const y = mCenterY - (this.dataArray[i - index - 1] / (32768 / mCenterY));
        // console.log(`i=${i},position=${i - index - 1},,data=${this.dataArray[i - index - 1]},,y=${y},,mCenterY=${mCenterY}`)
        x = i - 1;

        ctx.lineTo(x, y)
        ctx.stroke()
      }
    },
  }
}
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1801750.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

无延迟,持续畅玩 - Wi-Fi 6 助力打造游戏厅极致体验

1、需求背景&#xff1a; 连锁游戏厅行业竞争激烈&#xff0c;顾客对高品质的游戏体验有着高要求。网络是游戏厅的核心基础设施之一&#xff0c;需要确保游戏过程中的网络连接稳定性和顾客满意度。 长时间稳定连接 为保证顾客的游戏体验感&#xff0c;游戏厅要确保网络连接长…

SpringBoot实现参数校验拦截(采用AOP方式)

一、AOP是什么&#xff1f; 目的&#xff1a;分离横切关注点&#xff08;如日志记录、事务管理&#xff09;与核心业务逻辑。 优势&#xff1a;提高代码的可读性和可维护性。 关键概念 切面&#xff08;Aspect&#xff09;&#xff1a;包含横切关注点代码的模块。通知&#xff…

vscode编译c/c++找不到jni.h文件

解决办法: 一、下载JDK 访问Oracle官网的Java下载页面&#xff1a;Java Downloads | Oracle 选择适合您操作系统的JDK版本&#xff1a; 对于Windows&#xff0c;选择“Windows x64”或“Windows x86”&#xff08;取决于您的系统是64位还是32位&#xff09;。对于Linux&#…

STM32 HAL库开发——入门篇(3):OLED、LCD

源自正点原子视频教程&#xff1a; 【正点原子】手把手教你学STM32 HAL库开发全集【真人出镜】STM32入门教学视频教程 单片机 嵌入式_哔哩哔哩_bilibili 一、OLED 二、内存保护&#xff08;MPU&#xff09;实验 2.1 内存保护单元 三、LCD 3.1 显示屏分类 3.2 LCD简介 3.3 LCD…

基于Seatunnel最新2.3.5版本分布式集群安装部署指南(小白版)

基于Seatunnel2.3.5版本分布式集群安装部署 1.环境准备2.JDK安装3.Maven安装4.Seatunnel在master节点安装部署配置4.1.下载Seatunnel安装包4.2.解压下载好的tar.gz包4.3.下载连接器4.4.配置Seatunnel的系统环境变量4.5.配置 SeaTunnel Engine服务 JVM参数4.6.配置文件中集群相关…

阅读笔记——《AFLNET: A Greybox Fuzzer for Network Protocols》

【参考文献】Pham V T, Bhme M, Roychoudhury A. Aflnet: a greybox fuzzer for network protocols[C]//2020 IEEE 13th International Conference on Software Testing, Validation and Verification (ICST). IEEE, 2020: 460-465.【注】本文仅为作者个人学习笔记&#xff0c;…

socket通信(C语言+Python)

在socket文件夹下创建server.c和client.c。 服务端代码&#xff08;server.c&#xff09;&#xff1a; #include <stdio.h> #include <Winsock2.h> void main() {WORD wVersionRequested;WSADATA wsaData;int err;wVersionRequested MAKEWORD( 1, 1 );err WSAS…

单片机原理及技术(三)—— AT89S51单片机(二)(C51编程)

一、AT89S51单片机的并行I/O端口 1.1 P0口 AT89S51的P0口是一个通用的I/O口&#xff0c;可以用于输入和输出。每个引脚都可以通过软件控制为输入或输出模式。 1.1.1 P0口的工作原理 P0口的工作原理是通过对P0寄存器的读写操作来控制P0口的引脚。 输出模式&#xff1a;当P0口…

从大到小吗?-分支c++

题目描述 给出 4 个整数&#xff0c;a , b , c , d 。 判断这四个数字是否满足从大到小。 输入 输入 4 个整数&#xff0c;a , b , c , d 。 输出 输出 Yes 或者 No 。 样例输入 4 3 2 1 样例输出 Yes 提示 分析&#xff1a; 这道题十分的简单&#xff0c;只需判断…

技术管理之巅—如何从零打造高质效互联网技术团队阅读体验

技术管理之巅—如何从零打造高质效互联网技术团队 《技术管理之巅&#xff1a;如何从零打造高质效互联网技术团队》是黄哲铿所著的一本书&#xff0c;致力于帮助技术管理者从零开始打造高效的互联网技术团队。该书分为多个章节&#xff0c;分别探讨了从团队文化建设到技术架构…

【Redis】 Redis 集成到 Spring Boot上面

文章目录 &#x1f343;前言&#x1f384;Spring Boot连接redis客户端&#x1f6a9;项目的创建&#x1f6a9;配置端⼝转发&#x1f6a9;配置 redis 服务地址&#x1f6a9;更改 Redis 配置文件&#x1f6a9;使用 StringRedisTemplate 类操作 &#x1f38d;Spring Boot操作Redis客…

SAP HCM HR_PAD_HIRE_EMPLOYEE 自定义信息类型字段保存问题

导读 INTRODUCTION SAP HCM入职程序&#xff1a;SAP HCM入职程序有两个一个是HR_PAD_HIRE_EMPLOYEE一个是HR_MAINTAIN_MASTERDATA&#xff0c;前面的函数是SAP为新框架开发的&#xff0c;后面函数是旧的逻辑&#xff0c;这两个函数的在于底层的结构不一致&#xff0c;对于自定…

应用matplotlib.animation.FuncAnimation绘制摆线

上次尝试了用matplotlib.animation.ArtistAnimation绘制摆线&#xff0c;实际上也可以用matplotlib.animation.FuncAnimation实现同样的功能。 导入相关文件 引用的库包括numpy&#xff0c;matplotlib&#xff0c;代码如下&#xff1a; import numpy as np import matplotli…

【启程Golang之旅】让文件操作变得简单

欢迎来到Golang的世界&#xff01;在当今快节奏的软件开发领域&#xff0c;选择一种高效、简洁的编程语言至关重要。而在这方面&#xff0c;Golang&#xff08;又称Go&#xff09;无疑是一个备受瞩目的选择。在本文中&#xff0c;带领您探索Golang的世界&#xff0c;一步步地了…

Spring Boot集成pmd插件快速入门Demo

1.什么是pmd插件&#xff1f; PMD 插件允许您在项目的源代码上自动运行PMD代码分析工具&#xff0c;并生成带有其结果的站点报告。它还支持与 PMD 一起分发的单独的复制/粘贴检测器工具&#xff08;或 CPD&#xff09;。 此版本的 Maven PMD 插件使用 PMD 6.42.0 并且需要 Jav…

新增FTP功能、支持添加Redis远程数据库,专业版新增网站监控和黑金主题,1Panel开源面板v1.10.10版本发布

2024年6月7日&#xff0c;现代化、开源的Linux服务器运维管理面板1Panel发布v1.10.10版本。 在这一版本中&#xff0c;1Panel新增了多项实用功能。社区版方面&#xff0c;新增了FTP功能、支持添加Redis远程数据库、支持设置压缩密码&#xff0c;并新增了清理镜像构建缓存的功能…

从 Android 恢复已删除的备份录

本文介绍了几种在 Android 上恢复丢失和删除的短信的方法。这些方法都不能保证一定成功&#xff0c;但您可能能够恢复一些短信或其中存储的文件。 首先要尝试什么 首先&#xff0c;尝试保留数据。如果你刚刚删除了信息&#xff0c;请立即将手机置于飞行模式&#xff0c;方法是…

若依原生框架集成mybatisplus

1、进入父级依赖 将这个阿里数据库连接池druid注释掉&#xff0c;然后将pagehelper排除jsqlparser分页&#xff0c;使用mybatisplus分页查询防止mybatisplus与pagehelper版本不匹配&#xff0c;不然会报错 2、进入disease-framework模块&#xff1a; config的下面DruidConf…

【Python报错】已解决TypeError: can only concatenate str (not “int“) to str

解决Python报错&#xff1a;TypeError: can only concatenate str (not “int”) to str 在Python中&#xff0c;字符串连接是常见的操作&#xff0c;但如果你尝试将整数&#xff08;int&#xff09;与字符串&#xff08;str&#xff09;直接连接&#xff0c;会遇到TypeError: …

(函数)判断一句话中最长的单词(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>//声明函数&#xff1b; int aiphabetic(char); int longest(char[]);int main() {//初始化变量值&#xff1b;int i;char line[100] { 0 };//获取用户输入字符…