見出し画像

Vite+Svelteを使ってWebAudio API の練習

今朝は5時から開発開始です。
昨日、近くの温泉に行って昼食食べ過ぎのための調子が悪く早く寝ました。助手の猫が天から
調子が悪い時は寝るのが一番
と言っています。
さて、WebAudio APIを使った開発が必要になって練習することにしました。

解説やサンプルのソースコードは豊富にあります。index.htmlにJavaScriptを書いて試すこともできますが、ちょっと面倒なので、やる気がおきません。Wailsで採用された、Viteというツール

 を使ってテストプログラムを作れないかやってみることにしました。

npm create vite@latest

で簡単にプロジェクト作れるようなので、やってみました。
プロジェクト名をいれると

いろいろ、フレームワークが選べます。最近気に入っているSvelteにしました。「ソフトウェアデザイン」でも特集されています。
SolidとQwikが気になります。Wailsでみたことないフレームワークです。
後でしらべようと思います。
プロジェクトができると

のような感じです。書いてある通りにコマンドを実行すれば、開発サーバーが立ち上がります。

書いてるURLにアクセスすれば、

のような画面が表示されます。エディタで不要な部分を削除すれば、途中で

のようなエラーがでましたが、気にせず削除を続けると空のプロジェクトにしました。
 App.slevteに、WebAudio APIのサンプルから移植したテストプログラム

<script lang="ts">
  window.AudioContext = window.AudioContext || window.webkitAudioContext;
  const audioCtx = new AudioContext();
  let oscillator: OscillatorNode | undefined = undefined;
  let isPlaying = false;
  let audioStream : MediaStream | undefined =  undefined;

  const play = async (mic :boolean) => {
    if (isPlaying) return;
    const analyser = audioCtx.createAnalyser();
    const LENGTH = 128;
    const data = new Uint8Array(LENGTH);
    const canvas = document.getElementById('canvas') as HTMLCanvasElement;
    const canvasCtx = canvas.getContext('2d');

    analyser.fftSize = 1024;
    if(mic) {
      audioStream = await navigator.mediaDevices.getUserMedia({audio: true,video: false});
      const source = audioCtx.createMediaStreamSource(audioStream);
      source.connect(analyser);
    } else {
      oscillator = audioCtx.createOscillator();
      oscillator.type = "sine";
      oscillator.frequency.setValueAtTime(440, audioCtx.currentTime);
      oscillator.connect(analyser);
      oscillator.start();
    }

    canvas.width = 800;
    canvas.height = 150;
    canvasCtx.clearRect(0, 0, canvas.width, canvas.height);
    const  tick = () => {
      canvasCtx.fillStyle = "rgb(0, 0, 0)";
      canvasCtx.fillRect(0, 0,canvas.width, canvas.height);
      const w = canvas.width / LENGTH;
      analyser.getByteFrequencyData(data);
      for (let i = 0; i < LENGTH; ++i) {
        canvasCtx.fillStyle = `rgb(${data[i] + 100}, 50, 50)`;
        canvasCtx.fillRect(i * w, canvas.height - data[i]/2, w, data[i]/2);
      }
      requestAnimationFrame(tick);
    }   
    tick();
    isPlaying = true;
  }

  const stop = () => {
    oscillator?.stop();
    isPlaying = false;
    oscillator = undefined;
    if (audioStream) {
      for(const t of audioStream.getTracks()) {
        t.stop();
      }
    } 
  }

</script>

<main>
  <h1>WebAudio Test</h1>
  {#if !isPlaying}
    <button on:click={()=>play(true)}>FFT(mic)</button>
    <button on:click={()=>play(false)}>FFT(Sine)</button>
  {:else}
   <button on:click={stop}>stop</button>
   {/if}
  <div style="margin-top: 10px;">
    <canvas id="canvas"></canvas>
  </div>
</main>

のように書けば、

のようなものが作れました。
修正して結果を確認するまで数秒です。かなり快適に開発できます。楽しくなってきました。

明日に続く

開発のための諸経費(機材、Appleの開発者、サーバー運用)に利用します。 ソフトウェアのマニュアルをnoteの記事で提供しています。 サポートによりnoteの運営にも貢献できるのでよろしくお願います。