トップページ > 記事閲覧
音声データの周波数の取得について
名前:東海鉄道 日時: 2022/04/24 19:25

お久しぶりです 音声データからその音の周波数(例えばA4の音ならば440Hz)を取得したいです 何か良い方法はありますでしょうか よろしくお願いします
メンテ

Page: 1 |

Re: 音声データの周波数の取得について ( No.1 )
名前:管理人 日時:2022/04/24 23:31

『鳴っている音の周波数を取得する』という関数はありませんが、一応 GetFFTVibrationSoftSound という関数で 音声データを高速フーリエ変換で周波数毎の振幅情報を取得することが出来ます // ソフトウエアで扱う波形データハンドルの指定の範囲を高速フーリエ変換を行い、各周波数域の振幅を取得する // SoftSoundHandle : ソフトサウンドハンドル // Channel : フーリエ変換を行うチャンネル( -1 を指定するとすべてのチャンネルを合成した結果になります ) // SamplePosition : フーリエ変換で使用するサンプルの範囲の開始サンプル位置 // SampleNum : フーリエ変換で使用するサンプルの数( 256, 512, 1024, 2048, 4096, 8192, 16384 の何れかである必要があります ) // Buffer : フーリエ変換を行った結果を代入する float 型配列の先頭アドレス // BufferLength : Buffer の配列の長さ、こちらは長さに制限はありません int GetFFTVibrationSoftSound( int SoftSoundHandle, int Channel, int SamplePosition, int SampleNum, float *Buffer_Array, int BufferLength ) ; 実装時のスレッドに使い方などの解説がありますのでご覧ください https://dxlib.xsrv.jp/cgi/patiobbs/patio.cgi?mode=view&no=3674 こちらの関数で Buffer_Array に格納される各周波数毎の振幅幅の値で、一番値の大きい配列要素番号が示す 周波数域を『鳴っている音の周波数』として扱えば、意図される処理を実現できるかもしれません
メンテ
Re: 音声データの周波数の取得について ( No.2 )
名前:東海鉄道 日時:2022/04/25 18:41

#include <iostream> #include "resource.h" #include "DxLib.h" using namespace std; // グローバル変数: HINSTANCE hInst; // このコード モジュールに含まれる関数の宣言を転送します: LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); BOOL CALLBACK MyDlgProc(HWND, UINT, WPARAM, LPARAM); void message_box() { int flag; flag = MessageBox( NULL, TEXT("フルスクリーンモードで起動しますか?"), TEXT("スクリーン設定"), MB_YESNO | MB_ICONQUESTION); if (flag == IDNO) ChangeWindowMode(TRUE); } // ダイアログプロシージャ BOOL CALLBACK MyDlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; case IDC_BUTTON1: MessageBox(NULL, "", "", MB_OK); break; } return FALSE; } return FALSE; } int main(){ /*int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { hInst = hInstance; */ message_box(); #define BUFFERLENGTH 16384 //DialogBox(hInst, "MyTestDlgBase_Main", NULL, (DLGPROC)MyDlgProc); int SoundHandle; int SoftSoundHandle; float ParamList[BUFFERLENGTH]; int SamplePos; int i; string filepath; //cin >> filepath; filepath = ".\\C5.wav";//ファイルのパス if (DxLib_Init() == -1) return -1; //初期化処理 SoftSoundHandle = LoadSoftSound(filepath.c_str()); // ソフトサウンドハンドルからサウンドハンドルを作成( もう一度ファイルから読み込んでも同じです ) SoundHandle = LoadSoundMemFromSoftSound(SoftSoundHandle); // サウンドの再生開始 PlaySoundMem(SoundHandle, DX_PLAYTYPE_BACK); // 描画先を裏画面に変更 SetDrawScreen(DX_SCREEN_BACK); cout << GetFrequencySoundMem(SoundHandle) << endl; // メインループ //while (ProcessMessage() == 0) { // 画面を初期化 ClearDrawScreen(); // 現在の再生位置を取得 SamplePos = GetCurrentPositionSoundMem(SoundHandle); // 現在の再生位置から 4096 サンプルを使用して周波数分布を得る GetFFTVibrationSoftSound(SoftSoundHandle, -1, SamplePos, 4096, ParamList, BUFFERLENGTH); // 周波数分布を画面に描画する //for (i = 0; i < BUFFERLENGTH; i++) { float Param; // 関数から取得できる値を描画に適した値に調整 //Param = pow(ParamList[i], 0.5f) * 4.0f; cout << ParamList[BUFFERLENGTH-1] << endl; // 縦線を描画 //DrawBox(i, 600 - (int)(Param * 600), i + 1, 600, GetColor(255, 255, 0), TRUE); } // 裏画面の内容を表画面に反映 ScreenFlip(); } WaitKey(); DxLib_End(); return 0; } というコードを実行してみたのですが(実際にはファイルパスがちょっと違う) coutで出力できた数値は6.45153e-06となり目的としている523.251という数字が表れません なおC5.wavはDominoでC5にノートを置き https://audio-convert.com/ja/midi-converter/midi-to-wav?msclkid=3ed70ae6c47a11ec9eacde586171c52f のサイトでwavに変換しました
メンテ
Re: 音声データの周波数の取得について ( No.3 )
名前:管理人 日時:2022/04/26 23:03

載せていただいたプログラムは出力された振幅情報の配列の一番高い周波数の振幅( 配列の一番後ろの要素 )を出力しているので、 523.251 という周波数の音では 22050Hz 付近の音量は限りなく 0 に近いと思いますので、6.45153e-06 という値が出力されたのは妥当かと思います 私も試しに GetFFTVibrationSoftSound で音の周波数を出力するプログラムを組んでみましたので、 よろしければ参考にしてください m(_ _)m #include "DxLib.h" #define SAMPLENUM /* 1024 */ /* 2048 */ /* 4096 */ /* 8192 */ /* 16384 */ 32768 /* 65536 */ // 値が大きいほど精度が高い ( 最大 65536 ) #define BUFFERLENGTH 22050 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { int Sound ; int i ; int MaxIndex ; float MaxParam ; float ParamList[ BUFFERLENGTH ] ; // ウインドウモードで起動 ChangeWindowMode( TRUE ) ; // DXライブラリの初期化 if( DxLib_Init() < 0 ) return -1 ; // サウンドファイルの読み込み Sound = LoadSoftSound( "C5.wav" ) ; // 先頭の SAMPLENUM サンプルを高速フーリエ変換 GetFFTVibrationSoftSound( Sound, -1, 0, SAMPLENUM, ParamList, BUFFERLENGTH ) ; // サウンドファイルの破棄 DeleteSoftSound( Sound ) ; // 出力された振幅情報の中で一番振幅が大きい周波数を検出 MaxParam = ParamList[ 0 ] ; MaxIndex = 0 ; for( i = 1 ; i < BUFFERLENGTH ; i ++ ) { if( MaxParam < ParamList[ i ] ) { MaxIndex = i ; MaxParam = ParamList[ i ] ; } } // 一番振幅が大きかった周波数を画面に表示 DrawFormatString( 0, 0, GetColor( 255,255,255 ), "周波数:%d", MaxIndex ) ; // キー入力待ち WaitKey() ; // DXライブラリの後始末 DxLib_End() ; // ソフトの終了 return 0 ; } Domino で C5 にノートを置いた midファイルを載せていただいた URL のサイトで wavファイルに変換したものを 上記プログラムで使用した所 「周波数:524」 という結果が得られました 整数値の精度までしか出ないので、それなりに期待した結果が得られたと思います 因みに SAMPLENUM の値を 32768 で実行しましたが、値が大きいほど GetFFTVibrationSoftSound の実行に必要な時間が長くなります 値を小さくすることで実行時間を短くすることができますが、その分得られる結果の誤差が大きくなります
メンテ
Re: 音声データの周波数の取得について ( No.4 )
名前:東海鉄道 日時:2022/04/28 21:18

こっちでやってみるとうまくいきませんでした midiファイルの問題の可能性もありますのでDominoのMea Tick Step Event Gate Vel/Value と書いてあるところを教えていただけませんか?
メンテ
Re: 音声データの周波数の取得について ( No.5 )
名前:管理人 日時:2022/04/29 01:34

> midiファイルの問題の可能性もありますのでDominoのMea Tick Step Event Gate Vel/Value > と書いてあるところを教えていただけませんか? 手元で試した mid では以下のようになっています Mea 1 Tick 0 Step 1920 Event C 5 [ 72] Gate 1920 Vel/Value 100
メンテ
Re: 音声データの周波数の取得について ( No.6 )
名前:東海鉄道 日時:2022/04/29 20:02

/* やはり"周波数:0"でした 他のMea Tick Step Event Gate Vel/Valueも教えていただけませんか? こちらのものは Mea Tick Step Event Gate Vel/Value 1 0 0 ---- System Setup ------------- 1 0 1920 C 5 [ 72] 1920 100 2 1680 0 ---- CH Setup ----------------- 2 1680 1 121 Reset All Control 0 ON 2 1680 3 PC:Piano 1 0/0 1 2 1681 1 010 Panpot 64 ±0 2 1685 1 007 Volume 100 2 1686 1 091 Reverb 0 2 1687 1 011 Expression 127 2 1688 1 001 Modulation 0 2 1689 4 152 音程微調整 0 2 1693 3 153 GM ノートシフト 64 ±0 2 1696 3 151 ベンド幅 12 2 1699 1 130 Pitch Bend 0 2 1700 2 154 RPN Null 2 1702 30 ---- End of CH Setup ---------- 2 1732 2348 255 Rest (休符) 4 240 ---- End of Track です なお */ #include <string> #include <stdio.h> #include <iostream> #include <sstream> #include <fstream> using namespace std; int main() { string fileName; //ファイル名 //キーボード入力からファイル名を取得する getline(cin, fileName); //ファイル名からバイナリファイルで読み込む std::ifstream ifs(fileName, std::ios::binary); //読込サイズを調べる。 ifs.seekg(0, std::ios::end); long long int size = ifs.tellg(); ifs.seekg(0); //読み込んだデータをchar型に出力する char* data = new char[size]; ifs.read(data, size); #ifdef LOG //サイズを出力する std::cout << "size = " << size << "\n"; for (int i = 1; i < size + 1; i++) { std::stringstream ss; /*16進数文字列に変換する  char型をASCIIではなく、数値で出力する場合は先頭に+を付ける*/ ss << std::hex << +data[i - 1]; string test = ss.str(); //符号付きであるか判定する if (test.size() > 5) { //符号付きの場合fが付くため、fを削除する string test = ss.str().erase(0, 6); std::cout << test << " "; } else { //符号付きでない場合そのまま出力する std::cout << ss.str() << " "; } //16バイト毎に改行する if ((i % 16) == 0) { std::cout << "\n"; } } #endif // LOG hash<string> hash_function; size_t hash = hash_function(string(data)); std::cout << "\nEnd!\n"; std::cout << hash << endl; delete data; int end; cin >> end; return 0; } /* をVisual Studioでデバッグコンパイルし実行 それぞれのファイルのパスを入れると .mid:17262091415918939552 .wav:15370947917366009228 になりました */
メンテ
Re: 音声データの周波数の取得について ( No.7 )
名前:管理人 日時:2022/04/30 04:53

> 他のMea Tick Step Event Gate Vel/Valueも教えていただけませんか? 画面に表示されているのは以下の2行のみです Mea Tick Step Event Gate Vel/Value 1 0 1920 C 5 [ 72] 1920 100 2 0 ---- End of Track 載せていただいたプログラムを実行した結果は以下のようになりました .mid:72000960 .wav:1279734454
メンテ
Re: 音声データの周波数の取得について ( No.8 )
名前:東海鉄道 日時:2022/05/05 17:28

返信ありがとうございます やはり周波数:0のまま hashも以前と変わらずでした
メンテ
Re: 音声データの周波数の取得について ( No.9 )
名前:管理人 日時:2022/05/06 01:56

よろしければ東海鉄道さんが作成された C5.wav をメールで BQE00322(あっとまーく)nifty.com ( (あっとまーく)を@に置き換えてください ) に送っていただけないでしょうか? m(_ _)m 手元で周波数:0 になるのを確認できれば原因も分かると思いますので…
メンテ
Re: 音声データの周波数の取得について ( No.10 )
名前:東海鉄道 日時:2022/05/06 16:26

送信いたしました 正しく送れていますでしょうか
メンテ
Re: 音声データの周波数の取得について ( No.11 )
名前:管理人 日時:2022/05/07 03:53

メールありがとうございます、無事 C5.wav を受け取れました 手元で送っていただいた C5.wav を使用して No.3 のプログラムを実行してみましたが、実行結果は 周波数:523 と表示され、問題なく周波数を検出できていました 東海鉄道さんの環境では 0 と表示されるとのことですが、パスの指定ミスなどで LoadSoftSound が失敗している( 戻り値が -1 になっている )ということはないでしょうか?
メンテ
Re: 音声データの周波数の取得について ( No.12 )
名前:東海鉄道 日時:2022/05/07 17:16

Sound 268500992 で周波数:0でした LoadSoftSoundはおそらく成功していると思われます
メンテ
Re: 音声データの周波数の取得について ( No.13 )
名前:管理人 日時:2022/05/08 01:01

確かに正常に読み込めているようです となると何故『周波数:0』になってしまうのか…謎です… お使いのDXライブラリのバージョンは幾つでしょうか? もしかしたら最新のバージョンでは正常な結果を得られるかもしれませんので、 よろしければこちらの暫定最新バージョンをお試しになってみてください m(_ _)m https://dxlib.xsrv.jp/temp/DxLibVCTest.zip // Windows版 VisualC++ 用 https://dxlib.xsrv.jp/temp/DxLibBCCTest.zip // Windows版 BorlandC++ 用 https://dxlib.xsrv.jp/temp/DxLibBCC2Test.zip // Windows版 C++ Builder 10.3 用 https://dxlib.xsrv.jp/temp/DxLibGCC_MinGWTest.zip // Windows版 MinGW 用 https://dxlib.xsrv.jp/temp/DxLibDotNet.zip // Windows版 .NET用 https://dxlib.xsrv.jp/temp/DxLibMakeTest.zip // ソース (中身を既存のライブラリのファイルに上書きして『リビルド』をして下さい)
メンテ
Re: 音声データの周波数の取得について ( No.14 )
名前:東海鉄道(解決済み) 日時:2022/05/08 19:53

Ver3.18eでした 3.23aにすると周波数:523になりました バージョンの存在をすっかり忘れていました ありがとうございました お騒がせしました
メンテ

Page: 1 |

題名
名前
コメント
パスワード (記事メンテ時に使用)

   クッキー保存