推しへの愛を叫べ！推し愛メーター


##クラファン作成物への一歩
近々自作アイドルグッズをクラファンにかけようと思っています。
そのための第一歩として今回のものを作成しました。
クラファンは推しの声を自作グッズに閉じ込めるものを作成しようと思っています。
今回は声を数値化するものを作成しました。

##推しへの愛ありますか？
皆さんの推しへの愛はどのくらいですか？
その愛を声量に変えて可視化できるwebアプリケーションを作成しました。

https://zealous-dubinsky-ba4c83.netlify.app

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1269684/e57a9c7c-3e26-7c3a-811f-d1961eca6d99.png)

##ソースコード

```HTML
<div id="app">
  
  <p>
    推しを聞き取る※開発中<br>
    <button @click="listen">{{ recogButton }}</button> {{ result }}
  </p>
</div>
  <div class="level-monitor">
    <div class="indicator"></div>
  </div>
  <div class="percent"></div>
  <input type="button" value="推しへの愛を叫ぶ" onclick="main()">
```

```CSS
:root {
    --opacity: 0.6;
    --radius: 0.2;
    --red-limit: 70%;
    --yellow-limit: 30%;
}

.level-monitor {
    width: 50px;
    height: 300px;
    background-color: pink;
    position: relative;
    border-radius: var(--radius);
}

.indicator {
    width: 80%;
    background-color: rgba(0, 0, 0, 0.3);*/
    background-attachment: fixed;
    position: absolute;
    bottom: 0;
    left: 10%;
    border-radius: var(--radius);
}

.percent {
    width: 50px;
    font-family: Verdana, Geneva, Tahoma, sans-serif;
    font-size: 18px;
    text-align: center;
    padding: 5px 0;
}
```

```javascript
const app = new Vue({
  el: '#app',
  
  data: {
    recogButton: '聞き取り開始！',
    recog: null,
    result: '',
    speech: null,
    message: '',
    changecolor: 'red',
  },
  
  mounted() {
    // 音声認識の準備
    const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.msSpeechRecognition || null;
    this.recog = new SpeechRecognition();
    this.recog.lang = 'ja-JP';
    this.recog.interimResults = false;
    this.recog.continuous = false;
    
    // 音声認識が開始されたら
    this.recog.onstart = () => {
      this.result = '';
      this.recogButton = 'ききとりちゅう…';
    };
    
    // 音声を認識できたら
    this.recog.onresult = (event) => {
      // 認識されしだい、this.resultにその文字をいれる
      // Vueなので、文字をいれただけで画面表示も更新される
      this.result = event.results[0][0].transcript;
    };
    
    // 音声認識が終了したら
    this.recog.onspeechend = () => {
      this.recog.stop();
      this.recogButton = '停止（クリックして再開）';
    };
    
    // 認識できなかったら
    this.recog.onerror = () => {
      this.result = '（認識できませんでした）';
      this.recog.stop();
      this.recogButton = '停止（クリックして再開）';
    };
  },
  
  methods: {
    
    // 認識（聞き取り）
    listen() {
      this.recog.start();
    },    
    
    // 認識（聞き取り）
    changecolor() {
      this.recog.start();
    }, 
  },
});

let maxvolume = 0;
// Copied from https://stackoverflow.com/a/52952907/1204375
async function listen(cb) {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
    const audioContext = new AudioContext();
    const analyser = audioContext.createAnalyser();
    const microphone = audioContext.createMediaStreamSource(stream);
    const javascriptNode = audioContext.createScriptProcessor(2048, 1, 1);

    analyser.smoothingTimeConstant = 0.8;
    analyser.fftSize = 1024;

    microphone.connect(analyser);
    analyser.connect(javascriptNode);
    javascriptNode.connect(audioContext.destination);
    javascriptNode.onaudioprocess = function () {
        const array = new Uint8Array(analyser.frequencyBinCount);
        analyser.getByteFrequencyData(array);
        let values = 0;

        const length = array.length;
        for (let i = 0; i < length; i++) {
            values += (array[i]);
        }

        const average = Math.round(values / length);
        cb(average);
    }
}

function updateBarIndicator(average) {
    const $el = document.querySelector('.indicator');
    if(maxvolume<average){
      maxvolume = average
      $el.style.height = `${maxvolume}%`;
    }
}

function updateTextIndicator(average) {
    const $el = document.querySelector('.percent');
      $el.textContent = `${maxvolume}%`;
}

function main() {
    listen((percent) => {
        updateBarIndicator(percent);
        updateTextIndicator(percent);
    });
}
```

今回は以下のコードを参考に書きました。

https://github.com/piecioshka/microphone-volume-level-monitor

##レビュー
今回は母と妹にレビューをお願いしました。
前提として自分がなぜこれを作ったのかを説明しました。
フィードバック
・上のボタンは下のグラフには何も影響しないのか？
・機能がすくない
・Webアプリケーションと呼んでいいのか？

かなり酷なフィードバックをいただきました。
上のボタンとグラフが連動しなかったのはソースコードを見ておかしいとおもったかたもいるかもしれませんがJavaScriptとVue.jsが混在しているんです。
サンプルを参照して作ったのですが変換がうまくいかず相互の関係がないものになってしまいました。
ほかの二つはもうぐうの音もでませんでした。