🎻

うねりの可視化~Nihon University Advent Calendar 2023~

2023/12/17に公開

こちらはNihon University Advent Calendar 2023 17日目の記事になります。

Qiitaの方で書こうと思ったのですが、動画の再生がZennの方が手っ取り早かったのでこちらで書かせてもらっています。

はじめに

突然ですが皆さん、楽器のチューニング[1]ってしたことありますか?

もちろんありますよね。
ってことで次の動画では2つの音が同時に鳴っているのですが、音程が合っていないことがわかりますか?

...わかりますよね?

https://www.youtube.com/watch?v=z8ZQbVN2XNg

うーーーん、そうなの?って方が多いのではないかと思いますが、かという自分も吹奏楽部に入ってから耳[2]でチューニングができるようになるのにしばらく苦労しました。

耳を鍛える中で、基準音の音を覚えるだとか、高い音・低い音を聴き比べて慣れていくといったことをよく聞きますが、まぁ時間がかかりますし初めはなにが正解かわかりません。
そこで言われたのが、音があっていないと「うなり」が聞こえるということ。
でもうなりって言われてもはじめはわからなかったんですね。見えたらわかりやすいのにとか思っていた時期がありました。ってことで今更ですが、うなりの可視化をしてみました。

なぜ「うなり」が発生するのかについての説明はラムダ技術部さんのShort動画にわかりやすい説明がありましたので引用させてもらいます。

https://www.youtube.com/watch?v=gtGcekNCbEU

要するにうなりの正体は振幅の強弱なんですね。
二つの音を再生し、その振幅と同期するアニメーションを作ればうなりを見ることができそうです。
ということでLet's作成。

うなり可視化ツールの作成

今回はReactとp5js[3]を使用して作成しています。
といってもほぼp5jsですね。音を出力するためにp5.sound[4]の使用もしています。

また、p5jsをReactで動かすのにreact-p5-wrapperを使用しています。使い方については公式ドキュメントを参考にということで割愛します。また、react-p5-wrapperではp5jsのコード部分をsketchと呼んでいます。

音の再生とアニメーション

音の出力にはOscillator[5]を使います。p5jsでは4種類から波形を選ぶことができ、今回はsine(正弦波)を選択しています。442Hzの正弦波を出力するコードは以下になります。

const osc1 = new p5.Oscillator();
osc1.setType("sine");
osc1.freq(440);
osc1.amp(0.5);
osc1.start();

また、波の振幅はAmplitude.getLevel()を使用することで取得できます。Amplitudeではsketch[^6]内のすべてのサウンドのレベルを取得するので、二つの音を鳴らせば同時になっている2つの音の振幅を取得します。「はじめに」で述べたようにこれが今回の題材である「うなり」になります。

const amplitude = new p5.Amplitude();
level = amplitude.getLevel();

これらを使用して、440Hzと442Hzの二つの音を鳴らし、うなりと同期した円のアニメーションをするコード(sketch部分のみ)が以下になります。

const sketch = (p) => {
    let osc1, osc2;
    let amplitude;

    p.setup = () => {
      p.createCanvas(400, 400);

      osc1 = new p5.Oscillator();
      osc1.setType("sine");
      osc1.freq(440);
      osc1.amp(0.5);

      osc2 = new p5.Oscillator();
      osc2.setType("sine");
      osc2.freq(442);
      osc2.amp(0.5);

      amplitude = new p5.Amplitude();
    };

    p.draw = () => {
      p.background(255);

      const level = amplitude.getLevel();
      const diameter = p.map(level, 0, 1, 0, 400);
      p.noFill();
      p.stroke(0);
      p.ellipse(p.width / 2, p.height / 2, diameter, diameter);
    };

    p.mouseClicked = () => {
      osc1.start();
      osc2.start();
    };
  };

するとこのように、うなりのワンワンワンワンワンと同期して伸縮する円のアニメーションが表示されます。

Let's チューニング

さてこれだけだと味気ないので、実際にマウスを上下にドラッグ&ドロップすることで442Hzの方の音のピッチを変えれるようにしてみます。耳と目を使ってのチューニングをしてみようってことです。さらに諸々機能を追加して出来上がったものがこちら。画質が酷いことになっていますがこんな感じになりました。
https://www.youtube.com/watch?v=01RX4t_pnms

うなりに合わせて円が伸縮していますね。操作音のピッチをを基準音のピッチに近づけるにつれてうなりの周期が長くなり、440Hzになるとうなりが消え、円の伸縮もなくなることが確認できます。

実際に触れるようにサイトも公開してあるのでぜひチューニング体験をしてみてください。
https://tsubame33-lets-tuning.netlify.app

おわりに

さて皆さん、これでうなりの感覚が掴めましたね。
ということでもう一度冒頭の動画を見てみましょう。

https://www.youtube.com/watch?v=z8ZQbVN2XNg

音程が合っていないことがわかりますか?

え?うなりの感じが全然違うじゃないかって?

そうなんです。この動画ではギターの音を使っているのですが、実際の楽器の音は正弦波などのように単純な形をしていません。さらに、音が減衰していったりするためうなりはここまでわかりやすく発生しません。とはいえ、この記事を読む前よりは音程がずれていることの感覚が少しわかるようになったのではないでしょうか?

これを機に何か楽器を始めてみてもいいかもしれませんね。

ps : Web Audio Apiで実装するのをサボったのでそのうちそっちでも音をコネコネしてみたい気持ちがあったり。

脚注
  1. 楽器の音を、ある目的の高さに整えること ↩︎

  2. チューナーという音高を確認するための機材を使わずに、基準音を鳴らしてそれに揃えるように聴覚を使って音高を調整すること ↩︎

  3. ProcessingをJavaScriptで記述できるライブラリ。Processingとは電子アートとビジュアルデザインのためのプログラミング言語。 ↩︎

  4. p5.jsのコアライブラリとして提供されている拡張機能。音に関する操作、情報の取得ができる。 ↩︎

  5. オシレータ(発振器):音の元となる波形を作る機械。シンセサイザーを扱う人にとってはおなじみかもしれません。 ↩︎

Discussion