前提・実現したいこと
mp3ファイルの音声の波形と音声認識からの波形の類似度などどれだけ似ているかっていうのをHTML上で表示できるように作りたいです。探してもそういう技術がないため見て判断するしかないのかなと結論がでそうなため そういったことができるようなサイトやどういった方法でやったらよいか教えていただけると幸いです。
発生している問題・エラーメッセージ
HTML上で波形がどれだけ似ているかの判定の手段がない
該当のソースコード
HTML
1#波形を表示する 2<!DOCTYPE html> 3<html> 4<head> 5<meta charset="utf-8" /> 6</head> 7<body> 8<script src="http://cdnjs.cloudflare.com/ajax/libs/wavesurfer.js/2.0.6/wavesurfer.min.js"></script> 9 10<div id="waveform"> </div> 11 12<div style="text-align: center"> 13 <button class="btn btn-primary" onclick="wavesurfer.playPause()"> 14 <i class="glyphicon glyphicon-play"></i>Play</button> 15 16<p class="row"> 17 <div class="col-xs-1"> 18 <i class="glyphicon glyphicon-zoom-in"></i> 19 </div> 20 21 <div class="col-xs-10"> 22 <input id="slider" type="range" min="1" max="200" value="1" style="width: 100%" /> 23 </div> 24 25 <div class="col-xs-1"> 26 <i class="glyphicon glyphicon-zoom-out"></i> 27 </div> 28 </p> 29 30</div> 31 32<script language="JavaScript"> 33 34var wavesurfer = WaveSurfer.create({ 35 container: '#waveform', 36 waveColor: 'red', 37 progressColor: 'purple' 38}); 39 40wavesurfer.load('sightseeing.mp3'); 41 42var slider = document.querySelector('#slider'); 43 44slider.oninput = function () { 45 var zoomLevel = Number(slider.value); 46 wavesurfer.zoom(zoomLevel); 47}; 48 49</script> 50</body> 51</html> 52
HTML
1#音声認識から波形 2<!DOCTYPE html> 3<html lang="ja"> 4<head> 5<meta charset="UTF-8"> 6<title>Document</title> 7<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"> 8<style>*{box-sizing:border-box;margin:0;padding:0;}html,body{font-family:Meiryo;height:65%;}input,button{font-family:Meiryo;}#app{display:flex;overflow-y:hidden;flex-direction:column;min-width:320px;height:100%;}#control{color:#fff;background:#424242;display:flex;align-items:center;height:50px;max-height:50px;}#content{background:#212121;height:calc(100% - 50px);}#content .col{height:calc(100% / 2);}#content .col canvas{width:100%;height:calc(100% - 40px);}#content .head{background:#455a64;display:flex;align-items:center;justify-content:space-between;height:40px;max-height:40px;padding:0 10px;}#content .head h2{font-size:18px;font-weight:normal;color:#fff;flex:1 0 0%;margin:0;}#btn-tgl-rec,#btn-tgl-mute,.btn-play,.btn-clear,.btn-download{font-size:14px;color:#333;background:#e0e0e0;display:flex;align-items:center;justify-content:center;height:30px;margin:0 0 0 10px;padding:0 10px;cursor:pointer;border:0;text-decoration:none;}.btn-download{color:#ccc;}.btn-download[href]{color:#333;}#btn-tgl-rec::before,#btn-tgl-mute::before,.btn-play::before,.btn-clear::before,.btn-download::before{font-family:"Material Icons";font-size:24px;display:inline-block;margin:0 5px 0 0;}#btn-tgl-rec::before{color:#b71c1c;content:"\E061";}#btn-tgl-rec.is-recording::before{color:#212121;content:"\E034";}#btn-tgl-mute::before{content:"\E029";}#btn-tgl-mute.is-muted::before{content:"\E02B";}.btn-play::before{content:"\E037";}.btn-play.is-played::before{content:"\E034";}.btn-clear::before{content:"\E92b";}.btn-download::before{content:"\E2C4";}</style> 9</head> 10<body> 11<div id="app"> 12<div id="control"> 13<audio id="audio"></audio> 14<button id="btn-tgl-rec"><span>REC</span></button> 15<button id="btn-tgl-mute"><span>MUTE</span></button> 16<!-- /#control --></div> 17<div id="content"> 18<div class="col"> 19<div class="head"> 20<h2>リアルタイム入力波形</h2> 21</div> 22<canvas id="input-waveform"></canvas> 23<!-- /.col --></div> 24 25<div class="col"> 26<div class="head"> 27<h2>録音した音声の波形</h2> 28<a id="btn-rec-download" class="btn-download"><span>DOWNLOAD</span></a> 29<button id="btn-rec-clear" class="btn-clear"><span>CLEAR</span></button> 30<button id="btn-rec-play" class="btn-play"><span>PLAY</span></button> 31<audio id="rec-audio"></audio> 32</div> 33<canvas id="rec-waveform"></canvas> 34<!-- /.col --></div> 35 36<div class="col"> 37<div class="head"> 38 <a id="btn-effect-download" class="btn-download"><span>DOWNLOAD</span></a> 39 <button id="btn-effect-clear" class="btn-clear"><span>CLEAR</span></button> 40 <button id="btn-effect-play" class="btn-play"><span>PLAY</span></button> 41 <audio id="effect-audio"></audio> 42 </div> 43<canvas id="effect-waveform"></canvas> 44</div> 45<!-- /.col --></div> 46<!-- /#content --></div> 47<!-- /#app --></div> 48<script src="run.js"></script> 49</body> 50</html> 51
JavaScript
1#run.js 2!function(win,doc,AudioContext,MediaRecorder){"use strict" 3 4function resizeCanvas(){$waveformInput.width="100%",$waveformInput.style.width="100%",offsetWidth=$waveformInput.offsetWidth,offsetHeight=$waveformInput.offsetHeight, 5 6function(arr){for(var i=0;i<arr.length;i++)arr[i].style.width=offsetWidth+"px",arr[i].style.height=offsetHeight+"px",arr[i].width=offsetWidth,arr[i].height=offsetHeight}([$waveformInput,$waveformRec,$waveformEffect])} 7 8 function clearCanvas(ctx){ctx.clearRect(0,0,offsetWidth,offsetHeight),ctx.beginPath()} 9 10 function createWaveform(audioBuffer,ctx,size){var bufferFl32=new Float32Array(audioBuffer.length),leng=bufferFl32.length 11 clearCanvas(ctx),bufferFl32.set(audioBuffer.getChannelData(0)) 12 13for(var idx=0;leng>idx;idx++)if(idx%size===0){var x=offsetWidth*(idx/leng),y=(1-bufferFl32[idx])/2*offsetHeight 14 0===idx?ctx.moveTo(x,y):ctx.lineTo(x,y)}var gradient=ctx.createLinearGradient(0,0,0,offsetHeight) 15 gradient.addColorStop("0","#f44336"),gradient.addColorStop("0.5","#4caf50"),gradient.addColorStop("1","#2196f3"),ctx.strokeStyle=gradient,ctx.stroke()} 16 17 function clearSection(ctx,$btnDownload,$btnPlay,$audio){clearCanvas(ctx),$btnDownload.removeAttribute("href"),$btnPlay.classList.remove("is-played"),$audio.removeAttribute("src")} 18 19 function playAudio($btnPlay,$audio){$btnPlay.classList.value.indexOf("is-played")<0?($btnPlay.classList.add("is-played"),$audio.play()):($btnPlay.classList.remove("is-played"),$audio.pause())} 20 21 function fetchArrayBufferFromURL(blob){var url=URL.createObjectURL(blob) 22 return fetch(url).then(function(response){return response.arrayBuffer()})} 23 24 function renderCanvas(data,$audio,$btnDownload,ctx){var blob=new Blob([data],{type:"audio/webm"}) 25 $audio.src=win.URL.createObjectURL(blob), 26 $btnDownload.href=$audio.src,$btnDownload.download="rec.webm",fetchArrayBufferFromURL(blob).then(function(arrayBuffer){actx.decodeAudioData(arrayBuffer).then(function(audioBuffer){createWaveform(audioBuffer,ctx,1)})})} 27 28 var offsetWidth,offsetHeight,recorder1,recorder2,recorderStream, 29 $btnRec=doc.getElementById("btn-tgl-rec"), 30 $btnMute=doc.getElementById("btn-tgl-mute"), 31 $waveformInput=doc.getElementById("input-waveform"), 32 $waveformRec=doc.getElementById("rec-waveform"), 33 $waveformEffect=doc.getElementById("effect-waveform"), 34 $btnRecDownload=doc.getElementById("btn-rec-download"), 35 $btnRecClear=doc.getElementById("btn-rec-clear"), 36 $btnRecPlay=doc.getElementById("btn-rec-play"), 37 $btnEffectDownload=doc.getElementById("btn-effect-download"), 38 $btnEffectClear=doc.getElementById("btn-effect-clear"), 39 $btnEffectPlay=doc.getElementById("btn-effect-play"), 40 41 actx=new AudioContext,ictx=$waveformInput.getContext("2d"), 42 43rctx=$waveformRec.getContext("2d"),ectx=$waveformEffect.getContext("2d"),$raudio=doc.getElementById("rec-audio"),$eaudio=doc.getElementById("effect-audio"),fft=1024,gainNode=actx.createGain(),scriptProcessor=actx.createScriptProcessor(fft,1,1),streamDestination=actx.createMediaStreamDestination(),isMute=!1,isRecording=!1 44resizeCanvas(),win.addEventListener("resize",resizeCanvas,!1),scriptProcessor.onaudioprocess=function(event){var outputBuffer=event.outputBuffer 45outputBuffer.getChannelData(0).set(event.inputBuffer.getChannelData(0)),createWaveform(outputBuffer,ictx,1)},gainNode.gain.value=50,gainNode.connect(streamDestination),scriptProcessor.connect(actx.destination),navigator.mediaDevices.getUserMedia({video:!1,audio:!0}).then(function(stream){var input=actx.createMediaStreamSource(stream) 46recorderStream=stream,$btnMute.addEventListener("click",function(){isMute?(isMute=!1,input.connect(scriptProcessor),input.connect(gainNode), 47 $btnMute.classList.remove("is-muted")):(isMute=!0,input.disconnect(scriptProcessor),input.disconnect(gainNode),$btnMute.classList.add("is-muted"))},!1),input.connect(scriptProcessor),input.connect(gainNode)}), 48 $btnRec.addEventListener("click",function(){isRecording?(isRecording=!1,$btnRec.classList.remove("is-recording"),recorder1.stop(),recorder2.stop()):(isRecording=!0,$btnRec.classList.add("is-recording"), 49 $btnRecDownload.removeAttribute("href"),recorder1=new MediaRecorder(recorderStream),recorder2=new MediaRecorder(streamDestination.stream),recorder1.ondataavailable=function(event){renderCanvas(event.data,$raudio,$btnRecDownload,rctx)},recorder2.ondataavailable=function(event){renderCanvas(event.data,$eaudio,$btnEffectDownload,ectx)},recorder1.start(),recorder2.start())},!1), 50 $btnRecClear.addEventListener("click",function(){clearSection(rctx,$btnRecDownload,$btnRecPlay,$raudio)},!1), 51 $btnEffectClear.addEventListener("click",function(){clearSection(ectx,$btnEffectDownload,$btnEffectPlay,$eaudio)},!1), 52 $btnRecPlay.addEventListener("click",function(){playAudio($btnRecPlay,$raudio)},!1), 53 $btnEffectPlay.addEventListener("click",function(){playAudio($btnEffectPlay,$eaudio)},!1)}(window,document,window.AudioContext,window.MediaRecorder)
試したこと
色々調べたがPythonやMatlabなどならできるのですがHTML上に表示する手段がなくとても困ってます。
補足情報(FW/ツールのバージョンなど)
mp3から波形を表示するJSはwavesurferというものです。
URL https://wavesurfer-js.org/
音声認識から波形を表示
URL https://www.mitsue.co.jp/knowledge/blog/frontend/201704/05_1206.html