当前位置:   article > 正文

js-audio-recorder录音带声波图_js 录音声纹动画

js 录音声纹动画
  1. <!-- 听说组件 -->
  2. <template>
  3. <div class="lestening-speaking-container">
  4. <p class="middleSizeBlob">Type the statement that you hear.</p>
  5. <img style="width: 1.32rem;height:1.24rem;margin-top: .07rem;" src="../assets/images/secondary/lesting.png" alt="">
  6. <!-- <p><span>可播放次数:</span><span style="color: #4581e1;font-weight: blob;">{{ count }}</span></p> -->
  7. <div class="btn-trim">
  8. <!-- <tiny-button type="primary" :disabled="disabled" :icon="iconStartCircle" @click="Play"> Play </tiny-button> -->
  9. <span>{{ audioData.starTime }} / {{ audioData.endTime }}</span>
  10. <audio src="" :muted="audioData.muted"></audio>
  11. </div>
  12. <div class="function-box">
  13. <canvas id="canvas"></canvas>
  14. <canvas id="playChart"></canvas>
  15. <tiny-button :disabled="disabled" type="primary" native-type="submit" @click="nextStep"> Speaking/Stop
  16. </tiny-button>
  17. </div>
  18. <tiny-dialog-box v-model:visible="dialogData.visible" top="42%" title="音频将在倒计时结束后自动播放" width="30%">
  19. <span style="font-size: .14rem;font-weight: 700;">{{ dialogData.countNum }}</span>
  20. </tiny-dialog-box>
  21. </div>
  22. </template>
  23. <script setup>
  24. import { ref, reactive, onMounted } from 'vue'
  25. import { Button as TinyButton, DialogBox as TinyDialogBox } from '@opentiny/vue'
  26. import Recorder from 'js-audio-recorder'
  27. const lamejs = require('lamejs')
  28. // 子组件向父组件传参数
  29. const emits = defineEmits(['nextQuestion'])
  30. onMounted(() => {
  31. data.startCanvas()
  32. data.voice()
  33. })
  34. // 录音所需的信息
  35. const data = reactive({
  36. //用于存储创建的语音对象
  37. recorder: new Recorder({
  38. sampleBits: 16, // 采样位数,支持 8 或 16,默认是16
  39. sampleRate: 48000, // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000
  40. numChannels: 1, // 声道,支持 1 或 2, 默认是1
  41. // compiling: false,(0.x版本中生效,1.x增加中) // 是否边录边转换,默认是false
  42. }),
  43. formData: null,
  44. // 控制录音动画的显示隐藏
  45. showAnima: false,
  46. mation: true,
  47. isHistory: true,
  48. soundSize: 0,
  49. // 录音时长
  50. duration: 0,
  51. //波浪图-录音
  52. drawRecordId: null,
  53. oCanvas: null,
  54. ctx: null,
  55. //波浪图-播放
  56. drawPlayId: null,
  57. pCanvas: null,
  58. pCtx: null,
  59. startCanvas() {
  60. //录音波浪
  61. data.oCanvas = document.getElementById('canvas');
  62. data.ctx = data.oCanvas.getContext("2d");
  63. //播放波浪
  64. data.pCanvas = document.getElementById('playChart');
  65. data.pCtx = data.pCanvas.getContext("2d");
  66. },
  67. drawRecord() {
  68. // 用requestAnimationFrame稳定60fps绘制
  69. data.drawRecordId = requestAnimationFrame(data.drawRecord);
  70. // 实时获取音频大小数据
  71. // console.log(data.recorder.getRecordAnalyseData())
  72. // return
  73. let dataArray = data.recorder.getRecordAnalyseData()
  74. let bufferLength = dataArray.length;
  75. // 填充背景色
  76. data.ctx.fillStyle = 'rgb(200, 200, 200)';
  77. data.ctx.fillRect(0, 0, data.oCanvas.width, data.oCanvas.height);
  78. // 设定波形绘制颜色
  79. data.ctx.lineWidth = 2;
  80. data.ctx.strokeStyle = 'rgb(0, 0, 0)';
  81. data.ctx.beginPath();
  82. var sliceWidth = data.oCanvas.width * 1.0 / bufferLength, // 一个点占多少位置,共有bufferLength个点要绘制
  83. x = 0; // 绘制点的x轴位置
  84. for (var i = 0; i < bufferLength; i++) {
  85. var v = dataArray[i] / 128.0;
  86. var y = v * data.oCanvas.height / 2;
  87. if (i === 0) {
  88. // 第一个点
  89. data.ctx.moveTo(x, y);
  90. } else {
  91. // 剩余的点
  92. data.ctx.lineTo(x, y);
  93. }
  94. // 依次平移,绘制所有点
  95. x += sliceWidth;
  96. }
  97. data.ctx.lineTo(data.oCanvas.width, data.oCanvas.height / 2);
  98. data.ctx.stroke();
  99. },
  100. submit() { // 发送语音的方法
  101. data.recorder.pause() // 暂停录音
  102. data.timer = null
  103. console.log('上传录音')// 上传录音
  104. var formData = new FormData()
  105. var blob = data.recorder.getWAVBlob()//获取wav格式音频数据
  106. //此处获取到blob对象后需要设置fileName满足当前项目上传需求,其它项目可直接传把blob作为 file塞入formData
  107. var newbolb = new Blob([blob], { type: 'audio/wav' })
  108. var fileOfBlob = new File([newbolb], new Date().getTime() + '.wav')
  109. //formData是传给后端的对象,
  110. formData.append('file', fileOfBlob)
  111. //计算出录音时长
  112. data.duration = Math.ceil((new Date() - data.duration) / 1000);
  113. console.log(data.duration);
  114. //发送给后端的方法
  115. sendAudio(formData).then(res => {
  116. console.log(res);
  117. })
  118. },
  119. // 录音按钮的点击事件
  120. voice() {
  121. //实例化语音对象
  122. // data.recorder = new Recorder({
  123. // sampleBits: 16, // 采样位数,支持 8 或 16,默认是16
  124. // sampleRate: 16000, // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000
  125. // numChannels: 1 // 声道,支持 1 或 2, 默认是1
  126. // })
  127. //记录开始录音的时间
  128. data.duration = new Date();
  129. Recorder.getPermission().then(() => {
  130. console.log('开始录音')
  131. data.recorder.start().then(() => {
  132. data.drawRecord();//开始绘制图片
  133. }, (error) => {
  134. // 出错了
  135. console.log(`${error.name} : ${error.message}`);
  136. }); // 开始录音
  137. data.recorder.onprogress = function (params) {
  138. // console.log('录音时长(秒)', params.duration);
  139. // console.log('录音大小(字节)', params.fileSize);
  140. data.soundSize = params.vol
  141. // console.log('录音音量百分比(%)', params.vol);
  142. // console.log('当前录音的总数据([DataView, DataView...])', params.data);
  143. }
  144. }, (error) => {
  145. console.log(`${error.name} : ${error.message}`)
  146. })
  147. },
  148. handleStop() {
  149. console.log('停止录音')
  150. data.recorder.stop() // 停止录音
  151. data.mation = false;
  152. },
  153. handlePlay() {
  154. console.log('播放录音')
  155. data.recorder.play() // 播放录音
  156. },
  157. handleDestroy() {
  158. console.log('销毁实例')
  159. if (data.recorder) {
  160. data.recorder.destroy() // 毁实例
  161. }
  162. },
  163. })
  164. // 本地音频播放所需要的信息
  165. const audioData = reactive({
  166. starTime: '00:00',
  167. endTime: '00:00',
  168. muted: true,
  169. })
  170. // 弹出层的信息
  171. const dialogData = reactive({
  172. visible: false,
  173. countNum: 2,
  174. })
  175. // 录音和停止录音的的按钮
  176. const disabled = ref(true)
  177. // 点击按钮时触发
  178. function nextStep() {
  179. emits('nextQuestion')
  180. }
  181. </script>
  182. <style lang="scss" scoped>
  183. .lestening-speaking-container {
  184. width: 100%;
  185. height: 100%;
  186. text-align: center;
  187. font-size: .11rem;
  188. border: 1px solid red;
  189. .btn-trim {
  190. display: flex;
  191. align-items: center;
  192. justify-content: center;
  193. font-size: .1rem;
  194. font-weight: normal;
  195. height: .18rem;
  196. margin-top: .14rem;
  197. .tiny-button {
  198. width: .72rem;
  199. height: .18rem;
  200. // margin: 0 auto;
  201. font-size: .08rem;
  202. border-radius: .1rem;
  203. font-weight: 700;
  204. margin-top: .04rem;
  205. margin-right: .04rem;
  206. }
  207. ::v-deep .tiny-svg {
  208. width: .1rem !important;
  209. height: .1rem !important;
  210. }
  211. }
  212. .function-box {
  213. width: 5.59rem;
  214. height: 1.15rem;
  215. opacity: 1;
  216. background: rgba(252, 252, 252, 0.94);
  217. box-shadow: 0rem .01rem .03rem rgba(0, 0, 0, 0.25);
  218. margin: .07rem auto 0rem;
  219. #playChart,
  220. #canvas {
  221. height: .28rem;
  222. width: 100%;
  223. border: 1px solid aqua;
  224. margin-top: .29rem;
  225. }
  226. .tiny-button {
  227. width: 1.42rem;
  228. height: .24rem;
  229. margin: .21rem auto 0;
  230. font-size: .11rem;
  231. border-radius: .13rem;
  232. }
  233. }
  234. ::v-deep .tiny-dialog-box__body {
  235. padding-bottom: .21rem;
  236. text-align: center;
  237. }
  238. ::v-deep .tiny-dialog-box__headerbtn {
  239. display: none;
  240. }
  241. }
  242. </style>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/571431
推荐阅读
相关标签
  

闽ICP备14008679号