マイクから入力された音の高さを検出する手順

豊田高専コンピュータ部 Advent Calendar 2019の9日目の記事です。

前置き

研究で、マイクから入力された音の高さを検出する必要がありました。そこで自分で考えた方法で実装したところ、単音の音高はうまく検知できたのですが、人間の声などの音高は誤りが多く、実用的ではありませんでした。そこでよりスマートな音高の検出方法を調べたところ、「A SMARTER WAY TO FIND PITCH」という論文を見つけました。利用する式などは論文で確認してください。具体的なソースコードは他の方が公開しているので、そちらを御覧ください。

手順

平方差分関数を使って元の波形との一致度を求める

入力された音の波形から、平方差分関数を使って、元の波形を時間軸でずらした場合にどれくらい元の波形と一致しているかを求めます。一致度が高ければ、ずらした量が元の波形の周期倍である可能性が高いと言えます。平方差分関数は高速に計算する方法があり、元の波形を高速フーリエ変換してパワースペクトルを求め、逆高速フーリエ変換をすることで求まります。 f:id:mkmokymh:20191208233033j:plain

正規化する

平方差分関数から求められる一致度ですが、値が一定ではありません。そこで-1.0~1.0までの値をとるように正規化します。

ピークピッキング

ここからは、一致度が高くなっている部分を検出します。検出は、一致度がマイナスからプラスになってからマイナスに戻るまでを1区間として、1区間での最大値をピークとします。もし小さい値が誤って検出された場合は、他の値と比べて削除します。検出したピークの中でも最も大きいピーク値を基準値として、一番最初のピークがどこで現れているかを見つけます。1.0~0.8の値を基準値にかけて、それをしきい値とします。このしきい値を超える最初のピークを見つけます。測定された波形は実際は離散的なものなので、最初のピーク直近の2つの値をつかって放物線補完を行い、より正確なピークを見つけます。 f:id:mkmokymh:20191208233059j:plain

音高計算

ピークピッキングで検出した最初のピークの位置を元の波形の周期とします。マイクのサンプリングレートを周期で割ることで周波数を求められます。

終わりに

マイクから入力された音の高さを求めるのは意外と面倒臭いですね。 単音ではない音はこのような方法でないと精度がよくないです。 実際に学校の授業で習っていたフーリエ変換を活用したので、授業の大切さを改めて実感しました。

参考文献

(PDF) A smarter way to find pitch MPMアルゴリズムのNSDFの求めかた

2018年の目標

あけましておめでとうございます

2018年は成長の年にしていけたらと思っています。

目標を幾つか立て、実際に達成していきます。

1.ゲーム作り

数名ほどでUE4を作ってゲームを作ろうと企画しています。

12月頃にゼロからスタートしたばかりでまだまだ道のりは遠いですが今年中にゲームを完成させたいです。個人個人熱心に勉強しています。僕は玉を転がすクソゲーを勉強がてら作成しております。玉の慣性が非常に強く、コリジョンが見た目よりも小さいのでよく落ちます。ステージのギミックを付け加えていきたいです。

f:id:mkmokymh:20180101044057p:plain

2.サイト作りとgit,Github

自分の所属する部のサイトを作っています。今は1ページだけの静的なものなので物足りなさMAXです。部員がログインして進捗をブログ形式で公開できるようにしたいと思っています。PHPmySQLの勉強をしていきます。見た目も華やかにしたいのでCSSももっと勉強したいです。また、自分だけのサイトを作成したいとも思っています。git,Githubはサイト作成の過程で使っていくので並行して勉強を進めていきます。

3.英語

生まれてきたからずっと英語が嫌いです。UnityをつかってAndroidアプリを作っていたときに英語のリファレンスを見たりしていますが未だに慣れません。リスニングも苦手で英語を聞いただけで頭が痛くなりそうなくらいです。2018年は耳に英語を慣れさせ、英語を読む機会を定期的に作りたいと思っています。今年中にTOEICを受けて600点以上を目指したいです。

4.生活習慣の見直し

冬休みで平均睡眠時間が12時間を越えました。寝すぎです。ディスプレイの見すぎやもともと睡眠時間が長いなど色々な原因は考えられますが、一つ一つ改善していきたいです。例えば一定間隔で休憩したり、寝る時間と起きる時間を統一するなどです。

 

まあこの記事書いているの1月1日の午前5:00なんですけど。

Unreal Engine 4 を勉強する。

どうもお久しぶりのブログです。

クラブでVR対応のグラボを積んだPCを購入しました。

そこでVRを使った作品を制作したいと思いました。

せっかくなのでUnityではなくUE4を新しく覚えようと決意。

参考書を購入。

www.borndigital.co.jp

少し読んでみたところ、私のような初心者でもわかりやすく、それでいてすごく実践的な内容でした。ゲームを作成する際の流れや効率の話がありすごくためになりました。

これから実際に手を動かしてUE4でVRをつかった作品を制作したいと思います。

UE4頑張るぞ!

C#でグラフ描画(Visual Studio2017)

今回はC#とVisual Studio2017を使ってグラフの描画をしてみます。

1. プロジェクトの作成

Visual Studio2017を起動して、ファイル(F) > 新規作成(N) > プロジェクト(P) 

Visual C#Windowsフォームアプリケーションを選択してプロジェクトを作成。
f:id:mkmokymh:20170827113536p:plain
 

2. Chartの追加

画面左端のツールボックスをクリックしてデータ>Chartをダブルクリック。
f:id:mkmokymh:20170827113522p:plain

するとForm1.cs[デザイン]がこんな風に表示される。
f:id:mkmokymh:20170827113234p:plain

直感的にウィンドウの大きさを変えられるので適当にサイズを変えておいてください。

 

3. sin,cos波を表示させてみる。

このサイトを参考にさせていただき、sin,cos波を表示させてみる。


C#でグラフを描く(Chartコントロールによる方法) - whoopsidaisies's diary

 

まずForm1.cs[デザイン]のグラフをダブルクリック。するとForm1.csが開く。

クラスの中にコードを追加。コードの意味は上の参考サイトを御覧ください。

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void chart1_Click(object sender, EventArgs e)
        {
            
        }

        //written by whoopsidaisies
        private void PlotSinCos()
        {
            // 1.Seriesの追加
            chart1.Series.Clear();
            chart1.Series.Add("sin");
            chart1.Series.Add("cos");

            // 2.グラフのタイプの設定
            chart1.Series["sin"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
            chart1.Series["cos"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;

            // 3.座標の入力
            for (double theta = 0.0; theta <= 2 * Math.PI; theta += Math.PI / 360)
            {
                chart1.Series["sin"].Points.AddXY(theta, Math.Sin(theta));
                chart1.Series["cos"].Points.AddXY(theta, Math.Cos(theta));
            }
        }
    }
}

そうしたら次にForm1()にPlotSinCos()を記入します。

public Form1()
{
    InitializeComponent();
    PlotSinCos();
}

この状態で緑色三角の開始ボタンを押してみてください。ビルトして実行されます。
このようなウィンドウが出ていれば成功です。
f:id:mkmokymh:20170827113203p:plain

4. 自分が知りたい関数のグラフを記入する。

今回私が知りたいのは、x=n*cos(t)+cos(n*t),y=n*sin(t)+sin(n*t) のグラフです。
同じクラス内にnとtの値を渡したらそれぞれx,yが返る関数を作ります。

//written by whoopsidaisies
private void PlotSinCos()
{
    // 1.Seriesの追加
    chart1.Series.Clear();
    chart1.Series.Add("test");

    // 2.グラフのタイプの設定
    chart1.Series["test"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;

    // 3.座標の入力
    for (double theta = 0.0; theta <= 2 * Math.PI; theta += Math.PI / 360)
    {
        chart1.Series["test"].Points.AddXY(Keisan(2,theta,0), Keisan(2,theta,1)); //書き換え
    }
}

//関数を追加
private double Keisan(double n, double t, int selectXY)
{
    double x, y;

    x = n * Math.Cos(t) + Math.Cos(n * t);
    y = n * Math.Sin(t) + Math.Sin(n * t);

    return (selectXY == 0) ? x : y;
}

ビルトして実行するとこんな形に。
f:id:mkmokymh:20170827113038p:plain

Blogはじめました&HackUに参加しました

皆さんはじめまして。asasigureと申します。情報工学を専攻している学生です。

今日からBlogを始めてみました。色々勉強したことや日常で思ったことをBlogにします。

HackUに参加した話

 先日ヤフージャパンさんが開催するHackUに参加しました。

夏休みの数日間で開発を行い、社員の方に相談できるハッカソンです。

hacku.yahoo.co.jp

初めての開発だったので受賞とはいかなかったものの、参加しただけで貴重なお話が聞けたり豪華な粗品をいただくことができました。

ハッカソンの様子はYoutubeで見ることができます。

 

www.youtube.com

頂いたもの

 ステッカーとファイル、ステンレスタンブラーをいただきました。

終了後の懇談会ではピザや串かつなど、食事までいただきました。

ここまでサポートがしっかりしているとは流石ヤフーさんだなと痛感。

来年は受賞目指して今から勉強!