音を作ってみる!?(後編)

こんにちは、きうちです。

今回は前回の

「音を作ってみる!?」

の続きをお届けします。

前回は波(正弦波)の図形を画面に表示させたあと、そのデータをWAVE形式のファイルに出力し、メディアプレイヤーで再生してみました。

今回は、それをいろいろな波形に変えてみて、音色を楽しんでみます。

なお、音声ファイルはEXEと同じ場所にできます(前回書き忘れたかも)。

動画再生の際は
!!音量注意!!
でお願いしますm(_ _)m

★ ★ ★

まずは、前回の正弦波の角度増分を5倍にしてみます。

前回よりも波の数が多くなります。

コードはこんな感じ。コンストラクタを変更します。

        /// <summary>コンストラクタ</summary>
        public Form1()
        {
            InitializeComponent();

            width = pictureBox1.Width;
            height = pictureBox1.Height / 2;

            //waveData = MakeWave(128000, 2000, 0.1);
            waveData = MakeWave(128000, 2000, 0.5);

            WaveWriter w = new WaveWriter();
            w.Execute("test.wav", waveData);
        }

実行すると、こう!

再生すると・・・

前回よりも音が高くなりましたね!

「ぽー」ではなくて「ぴー」と聞こえると思います。

★ ★ ★

矩形波いきましょう。

正弦波が滑らかなカーブを描く曲線なのに対し、矩形波はプラスかマイナスか、かくかくした線になります。

コードはこんな感じ。矩形波の作り方は何通りかあると思いますが、ここではもとの正弦波のプログラムを生かすことにします。

        private int[] MakeWave(int dataSize, int r, double dt)
        {
            var list = new List();

            double theta = 0;
            for (int i = 0; i < dataSize; i++)
            {
                int a = (int)(Math.Sin(theta) * r);
                list.Add(a > 0 ? 1 : -r);
                theta += dt;
            }

            return list.ToArray();
        }

実行すると、こう!

再生すると・・・

正弦波にちょっと似ているけどちょっと違う音が聞こえると思います。

★ ★ ★

お次はノイズ。カーブの代わりに乱数でデータを作ります。

コードはこんな感じ。

        private int[] MakeWave(int dataSize, int r, double dt)
        {
            var list = new List();
            var rand = new Random();

            for (int i = 0; i < dataSize; i++)
            {
                int a = rand.Next(0, r);
                list.Add(a);
            }

            return list.ToArray();
        }

実行すると、こう!

再生すると・・・

「しゃー・・・」というような音が聞こえると思います。
今のテレビでは聞けないかもしれませんが、昔は電波が受信できていない状態のテレビは「砂嵐」と呼ばれる映像?が表示されて、音がこんな感じでした。

★ ★ ★

ご存じのかたもいらっしゃると思いますが、波の振幅は音の大きさを表しています。
そこで、途中で音量が小さくなっていくようにしてみます。

コードはこんな感じ。

        private int[] MakeWave(int dataSize, int r, double dt)
        {
            var list = new List();
            double r2 = r;
            double dr = r2 / dataSize * 2;

            double theta = 0;
            for (int i = 0; i < dataSize; i++)
            {
                int a = (int)(Math.Sin(theta) * r2);
                list.Add(a);
                theta += dt;
                r2 -= dr;
                if (r2 < 0) r2 = 0;
            }

            return list.ToArray();
        }

また、これまでは波の表示を今のPictureBoxの幅で表示できる分だけにしていましたが、詰めて、終わりまで表示できるようにしてみます。

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            if (waveData != null)
            {
                float x = 0;
                float y = CalcY(waveData[0]);
                int max = waveData.Length;
                float dx = (float)width / max;
                //if (max > width) max = width;
                for (int i = 1; i < max; i++)
                {
                    //float x2 = x + 1;
                    float x2 = i * dx + dx;
                    float y2 = CalcY(waveData[i]);
                    e.Graphics.DrawLine(Pens.Yellow, x, y, x2, y2);
                    x = x2;
                    y = y2;
                }
            }
        }

実行すると、こう!

再生すると・・・

「ぴー」ではなく、「ぴーん」という感じの音になったと思います。

★ ★ ★

周波数がだんだん変化するようにしてみましょう。

コードはこんな感じ。

        private int[] MakeWave(int dataSize, int r, double dt)
        {
            var list = new List();

            double theta = 0;
            for (int i = 0; i < dataSize; i++)
            {
                int a = (int)(Math.Sin(theta) * r);
                list.Add(a);
                theta += dt;
                if (i > 0 && i % 10000 == 0) dt /= 2.0;
            }

            return list.ToArray();
        }

実行すると、こう!

再生すると・・・

いわゆる「ピコピコ音」みたいなものになったと思います。

★ ★ ★

音階を付けてみましょう。
ドレミファのそれぞれの音が何Hzか、というのはWebで調べればわかりますので、
これを配列にして、少しずつ(ここでは7800サンプルずつ)その要素の値になるようにします。

コードはこんな感じ。

        private int[] MakeWave(int dataSize, int r, double dt)
        {
            var list = new List();
            double[] hz = { 261.626, 293.665, 329.628, 349.228, 391.995, 440.000, 493.883, 523.251 };
            var omega = new double[hz.Length];
            for(int i = 0; i < hz.Length; i++)
            {
                omega[i] = 2 * Math.PI * hz[i] / 44100;
            }
            dt = omega[0];
            int j = 1;

            double theta = 0;
            for (int i = 0; i < dataSize; i++)
            {
                int a = (int)(Math.Sin(theta) * r);
                list.Add(a);
                theta += dt;
                if (i > 0 && i % 7800 == 0)
                {
                    dt = omega[j++];
                    if (j >= omega.Length) j = omega.Length - 1;
                }
            }

            return list.ToArray();
        }

実行すると、こう!

・・・つぶれちゃって何も見えんですね💦

再生すると・・・

ドレミファソラシド になりましたね!

★ ★ ★

やっぱなにか音が鳴ると楽しいですね!

今回はこんなところで^^

ではまた!

追伸

ソースを公開しました。
実行するとWAVEファイルができますが、それを再生する際も
!!音量注意!!
でお願いしますm(_ _)m
こちら。