2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【学習】駆け出しエンジニアがWeb Audio API音を鳴らす仕組みの実装をしてみた

Posted at

はじめに

今回は、前回同様、簡単なミニアプリ作成において使用したAPIについて。
「Web Audio API」というものを使用しました。
参考サイトから、こんな便利な機能があるとは。驚きです。

参考サイト

こちらのサイトで動作確認できます

以下に示すコードを自分の手元で試してみたい方はこちらのサイトを利用されてみる事をお勧めします。(私も今回初めて知りました。)

こんな感じのコード

以下コードはあくまで参考。
ボタンを押したら音が再生するというものになります。

👇まずはhtmlファイルにボタンを配置

.smilr.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebAudio API テスト</title>
</head>
<body>
    <h1>ボタンを押すと音が鳴る</h1>
    <button id="myButton">ボタン</button>

    <script src="smilescript.js"></script>
</body>
</html>

👇次にボタンを押したら音が鳴る仕組みを作る

.smilescript.js
// 音を鳴らす関数(周波数と長さを指定)
function playTone(frequency, duration) {
    return new Promise(resolve => {
        const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
        const oscillator = audioCtx.createOscillator();
        const gainNode = audioCtx.createGain();

        oscillator.type = "sine"; // 正弦波
        oscillator.frequency.value = frequency; // 周波数を設定
        gainNode.gain.setValueAtTime(0.5, audioCtx.currentTime); // 音量調整

        oscillator.connect(gainNode);
        gainNode.connect(audioCtx.destination);

        oscillator.start();
        setTimeout(() => {
            oscillator.stop();
            resolve();
        }, duration);
    });
}

// 休符(無音時間を作る)
function rest(duration) {
    return new Promise(resolve => setTimeout(resolve, duration));
}

// 休符 → ド(C4)の音を鳴らす
async function playRestThenDo() {
    await rest(1000); // 休符(1秒)
    await playTone(261.63, 1000); // ドの音(1秒)
}

// ボタンがクリックされたときの処理
document.getElementById("myButton").addEventListener("click", () => {
    playRestThenDo();
});

コードの解説(Javascript)

「〇〇でもわかる!」を目指してコードをかみ砕いてみます

:one: ボタンを押したら音を鳴らす

document.getElementById("myButton").addEventListener("click", () => {
    playRestThenDo();
});

上からコードを見ていくと順番が「?」に感じることがあるのですが、まずは「ボタン」の処理からスタートします
ここで、ボタンがクリックされたときに playRestThenDo() を実行します。

:two: 音を鳴らす

// 休符 → ド(C4)の音を鳴らす
async function playRestThenDo() {
    await rest(1000); // 休符(1秒)
    await playTone(261.63, 1000); // ドの音(1秒)
}

async function 宣言は、AsyncFunction オブジェクトを作成します。非同期関数が呼び出されるたびに、新しいプロミス (Promise) が返され、非同期関数によって返された値で解決されます。または、非同期関数内で捕捉されなかった例外で拒否されます。

「エイシンク ファンクション」によって、await を使って処理の順番をコントロールしています。

rest(1000) は 1秒後に完了する Promise を返す → 「1秒待つ」
playTone(261.63, 1000)Promise を返す → 「ドの音を1秒鳴らす」
await を使うことで、「1秒待ってから、ドの音を1秒鳴らす」
という動きが可能に。

:three: 実際に音を鳴らす関数での処理

// 音を鳴らす関数(周波数と長さを指定)
function playTone(frequency, duration) {
    return new Promise(resolve => {
        // audioCtx = 音の作業場。
        const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
        const oscillator = audioCtx.createOscillator();
        const gainNode = audioCtx.createGain();

        oscillator.type = "sine"; // 正弦波
        oscillator.frequency.value = frequency; // 周波数を設定
        gainNode.gain.setValueAtTime(0.5, audioCtx.currentTime); // 音量調整

        oscillator.connect(gainNode);  // 発振器と音量調整を接続する
        gainNode.connect(audioCtx.destination);  // 音をスピーカーに送る

        oscillator.start();  // 音を鳴らす
        setTimeout(() => {
            oscillator.stop();  // 一定時間経ったら音を止める
            resolve();  // 終わったら次に進む
        }, duration);
    });
}

// 休符(無音時間を作る)
function rest(duration) {
    return new Promise(resolve => setTimeout(resolve, duration));
}

やたらplayToneに関する部分が多いので、「???」が多くなりますが、少しずつ見ていくと意外と単純。公式の説明を見たうえで、ここではコメント形式で意味を記載します。

また、swetTimeoutについては以下を参考にすると次のような意味になります。

rest(1000) を実行
new Promise(resolve => setTimeout(resolve, 1000)) が作られる
setTimeout() が 1秒後に resolve() を実行
await があるので 「1秒経つまで次の処理を止める」
1秒後に Promise が完了し、次の処理へ進む

さいごに

今回実装にあたり、定数の名前で「?」が生じました。一般的に使用されているものですが、いままでなじみがなかったので知る事、発見が多いです。
今回の記事が何か参考になれば幸いです。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?