• home
  • WebAudioAPI触ってみた

WebAudioAPI触ってみた

はじめに

Wanoインターンの齋藤です。遅ればせながら3月15日に行った開発合宿でやった内容のまとめです。
今年は特にテーマはなかったんですが自分はオーディオ関係触ろうと思い、WebAudioAPIをいい感じにするフレームワークのTone.jsで何か作ろうと思いました。

当日まで特に考えていなかったのですが、ふとiOSのGarageBandのビートシーケンサー的なものを作りたいと思ったので、やってみることにしましたが、最終的にはWebAudioAPIを触ることになりました。

Tone.jsを触る

Tone.js

https://tonejs.github.io/

WebAudioAPIを楽に扱えるようにするライブラリで、GitHubのスター数も7500超えでCHROME MUSIC LABなどでも使われています。APIドキュメントやExamplesも豊富で親切です。MITライセンスです。

Pixi.js

http://www.pixijs.com/

WebGLとHTML5Canvasをサポートした2Dグラフィックエンジンです。こちらもGitHubスター数22000超えで、デモも多く親切なライブラリです。MITライセンスです。

実装

デモがなくて申し訳ありませんが、最終的にこんな感じのができました。

都合でドラムではなく音程が違う音が鳴るだけですが、縦が音程で横が時間で、クリックして明るくなっているマスで音が鳴るという簡単なものです。ループや同時に音を鳴らすことも出来ませんが、とりあえず最小限は出来たかな、という感じです。
少しだけ中身を説明すると、再生ボタンを押した時に押されたノードから音の再生位置と音程をとってきてPartを作って再生するという流れです。

notes = [];
nodes.forEach(node => {
    if (node != null) {
        notes.push(node.note)
    }
});
new Tone.Part(function (time, note) {
    synth.triggerAttackRelease(note.pitch, '8n', time);
}, notes).start(0);
Tone.Transport.start();

WebAudioAPIを触る

この時点で開発合宿の残り時間もあまりなかったのですが、再生する音を録音できないかと思ったんですが、調べるとWebAudioAPIを理解していないと無理そうだったので、ここからWebAudioAPIを直接触ってみることにしました。

音声をファイルとして出力するのに必要そうなAPI
Web Audio API
Media Capture and Streams API (Media Streams)
MediaStream Recording API

処理の流れは以下の通り
1. AudioContext作る
2. OscillatorをAudioContextの送信先に繋ぐ
3. AudioContextの送信先のストリームでMediaRecoder作る
4. MediaRecoder.ondataavailableでデータを受け取る

<div>
    <audio id="player" controls></audio>
</div>
<script>
    window.onload = function () {
        var audioCtx = new AudioContext();
        var gainCtx = audioCtx.createGain();
        gainCtx.connect(audioCtx.destination);
        var dest = audioCtx.createMediaStreamDestination();

        var osc = audioCtx.createOscillator();
        osc.connect(dest);
        osc.type = "sawtooth"
        osc.frequency.value = 440;
        osc.connect(gainCtx);

        mediaRecorder = new MediaRecorder(dest.stream);
        mediaRecorder.start();
        osc.start();

        setTimeout(function () {
            osc.stop()
            mediaRecorder.stop();
            mediaRecorder.ondataavailable = function (e) {
                document.getElementById('player').src = URL.createObjectURL(e.data);
            }
        }, 1000);
    }
</script>

出力はwebmですが思ってたより簡単にできました。しかし、ここで時間切れということで今回はここまで。

おわりに

最初はWebAudioAPIは直接触らず楽しようと思っていたんですが、結局ライブラリの中身を理解しているに越したことはないですね。色々調べて行くうちにわかったのですが、WebAudioAPIは思ったより自由度が高いっぽいですが、その分使いこなすのは大変そうです。開発合宿なので普段やらないことをやってみたのですが、新しい発見もあり楽しかったです。そのうちもうちょっと深く勉強してみたいですね。