1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
| <template> <div class="BaseRecorder"> <div class="BaseRecorder-record"> <i @click="startRecorder()" title="開始錄音" class="fa-solid fa-microphone"></i> <i @click="resumeRecorder()" title="继续錄音" class="fa-solid fa-microphone-lines"></i> <i @click="pauseRecorder()" title="暂停錄音" class="fa-solid fa-microphone-lines-slash"></i> <i @click="stopRecorder()" title="停止錄音" class="fa-solid fa-microphone-slash"></i> </div> <div class="BaseRecorder-play"> <i @click="playRecorder()" class="fa-solid fa-volume-high"></i> <i @click="pausePlayRecorder()" class="fa-solid fa-volume-xmark"></i>
<button @click="resumePlayRecorder()">恢复錄音播放</button> <button @click="stopPlayRecorder()">停止錄音播放</button> </div> <div class="BaseRecorder-download"> <i @click="downPCM()" title="下载PCM" class="fa-solid fa-cloud-arrow-down"></i> <i @click="downWAV()" title="下载WAV" class="fa-solid fa-cloud-arrow-down"></i>
</div> <div class="BaseRecorder-destroy"> <button @click="destroyRecorder()">销毁錄音</button> </div> <div class="BaseRecorder-wave"> <canvas ref="record"></canvas> <canvas ref="play"></canvas> </div> </div>
</template>
<script setup lang="ts"> import Recorder from 'js-audio-recorder' import { ref, computed,onMounted} from 'vue' const recorder = ref<any>(null) //波浪图-录音 const drawRecordId = ref<any>(null) //波浪图-播放 const drawPlayId = ref<any>(null) const init = () => { let query = { // 取樣位數,支援 8 或 16,預設是 16 sampleBits: 16, // 取樣率,支援11025、16000、22050、24000、44100、48000,依瀏覽器預設值 sampleRate: 48000, // 聲道,支援1或2,預設是1 numChannels: 1, // 是否記錄邊,預設是false compiling: false } recorder.value = new Recorder(query) // console.log('recorder.value',recorder.value) }
//開始錄音 const startRecorder =() =>{ recorder.value.start() .then( () => { drawRecord() }, error => { // 出错了 console.log(`${error.name} : ${error.message}`) } ) } //ref="record" =>this.$refs.record const record = ref<any>() //繪製記錄 const drawRecord = () => { //**方法通知瀏覽器我們想要產生動畫,並且要求瀏覽器在下次重繪畫面前呼叫特定函數更新動畫。這個方法接受一個引數作為下次重繪前調用的回呼函數。 let query = { canvas: record.value, dataArray: recorder.value.getRecordAnalyseData(), bgcolor: 'rgb(50 65 150)', lineWidth: 2, lineColor: 'rgb(255, 255, 255)' } drawRecordId.value = requestAnimationFrame(drawRecord) drawWave(query) console.log('query', query) console.log('drawRecordId.value', drawRecordId.value) } //畫波 const drawWave = ({ canvas, dataArray, bgcolor = 'rgb(200, 200, 200)', lineWidth = 2, lineColor = 'rgb(0, 0, 0)' }) => { if (!canvas) return const ctx = record.value.getContext('2d') const bufferLength = dataArray.length // 一個點佔多少位置,每個bufferLength個點要控制 const sliceWidth = canvas.width / bufferLength // 受傷點的x軸位 let x = 0
// 填充背景色 ctx.fillStyle = bgcolor ctx.fillRect(0, 0, canvas.width, canvas.height)
// 設定,設計顏色 ctx.lineWidth = lineWidth ctx.strokeStyle = lineColor
ctx.beginPath()
for (let i = 0; i < bufferLength; i++) { const v = dataArray[i] / 128 const y = (v * canvas.height) / 2
if (i === 0) { // 第一个点 ctx.moveTo(x, y) } else { // 剩余的点 ctx.lineTo(x, y) } // 依次平移,绘制所有点 x += sliceWidth }
// 最后一个点 ctx.lineTo(canvas.width, canvas.height / 2) ctx.stroke() } // 继续錄音 const resumeRecorder = () => { recorder.value.resume(); } //暂停錄音 const pauseRecorder = () => { recorder.value.pause(); //cancelAnimationFrame:是一種JavaScript實作動畫的技巧,它解決了傳統計時器(setTimeout和setInterval)在處理動畫時的一些問題,特別是與瀏覽器重繪 drawRecordId.value && cancelAnimationFrame(drawRecordId.value) drawRecordId.value = null } // 停止錄音 const stopRecorder = () => { recorder.value.stop(); drawRecordId.value && cancelAnimationFrame(drawRecordId.value) drawRecordId.value = null } //录音播放 const playRecorder = () => { recorder.value.play() drawPlay() } /** * 绘制波浪图-播放 * */ const play = ref<any>(null) // const drawPlay = () => { drawPlayId.value = requestAnimationFrame(drawPlay) drawWave({ canvas: play, dataArray: recorder.value.getPlayAnalyseData() }) console.log('recorder.value.getPlayAnalyseData()', recorder.value.getPlayAnalyseData()) } //暂停录音播放 const pausePlayRecorder = () => { recorder.value.pausePlay() } //恢复录音播放 const resumePlayRecorder = () => { recorder.value.resumePlay() drawPlay() // 绘制波浪图 } // const stopPlayRecorder = () => { recorder.value.stopPlay(); }
const downPCM = () => { recorder.value.downloadPCM('新文件'); console.log(recorder.value.downloadPCM('新文件')) } const downWAV = () => { recorder.value.downloadWAV('新文件'); console.log(recorder.value.downloadWAV('新文件')) } const destroyRecorder = () => { recorder.value.destroy().then(function () { drawRecordId.value && cancelAnimationFrame(drawRecordId.value) drawRecordId.value = null
drawPlayId.value && cancelAnimationFrame(drawPlayId.value) drawPlayId.value = null recorder.value = null }) }
onMounted(() => { init(); }) </script>
|