開発環境 Microsoft Visual C++ 2010 Express (SP1)
実行環境 Microsoft Windows XP Home Edition (SP3)
プロジェクトの種類 Win32 コンソール アプリケーション
プロジェクト名 wave
アプリケーションの種類 コンソール アプリケーション
追加のオプション 空のプロジェクト

周波数の特定に最小二乗法を用いているが、相互相関でもいいかもしれない。

  • 自己相関(Autocorrelation)
波長を求めるのに適しているが、倍音の判定に工夫が必要。

  • フーリエ級数展開(Fourier series expansion)
ある波長の1/nの波長のサイン波がどの程度含まれているかを調べるのに適している。

wave.cpp
// 音階判定2
 
#define _USE_MATH_DEFINES
 
#include <stdio.h>
#include <math.h>
#include <vector>
 
using namespace std;
 
typedef unsigned char BYTE;
typedef struct {
	int pos;
	int noteNum;
	double vol;
} Wave;
typedef vector<Wave> VWave;
 
// note number
#define A1	33
#define A4	69
#define A5	81
 
#define SAMPLING_RATE	11025
#define DATA_NUM	1000
#define WAVE_LEN	100.23	// 波長
 
// 関数プロトタイプ宣言
double LeastSquares(int pos, double freq, double waveLen);
double Volume(int pos, int wl);
 
// 音階
const char *scale[] = {"C","C#","D","D#","E","F","F#","G","G#","A","A#","B"};
 
// 外部変数
BYTE waveformData[DATA_NUM];
VWave vWave;
 
//==============================================================================
int main()
{
	for (int i = 0; i < DATA_NUM; i++) {
		double t = fmod(i / WAVE_LEN, 1.0);
//		double y = t < 0.5 ? t * 2 : (t - 1) * 2;
		double y = sin(2 * M_PI * t);
		waveformData[i] = BYTE(128 + 64 * y);
//		printf("%d %u\n", i, waveformData[i]);
	}
 
	for (int pos = 0; pos <= DATA_NUM - 201; ) {
		int noteNum = -1;
		double jMin = 4.0;
		int wl;
		for (int n = A1; n <= A5; n++) {
			double freq = 440.0 * pow(pow(2.0, n - A4), 1.0 / 12);
			double waveLen = SAMPLING_RATE / freq;
			double j = LeastSquares(pos, freq, waveLen);
			//printf("#%d %-2s%d %.2fHz %.2f %.6f\n",
			//	n, scale[n % 12], n / 12 - 1, freq, waveLen, j);
			if (j < jMin) {
				noteNum = n;
				jMin = j;
				wl = (int)ceil(waveLen);
			}
		}
		Wave wave;
		wave.pos	= pos;
		wave.noteNum	= noteNum;
		wave.vol	= Volume(pos, wl);
		vWave.push_back(wave);
 
		printf("%.2f Note#%d\n", WAVE_LEN, noteNum);
		pos += wl;
	}
 
	for (VWave::iterator it = vWave.begin(); it != vWave.end(); it++) {
		printf("%d #%d %.6f\n", it->pos, it->noteNum, it->vol);
	}
	return 0;
}
 
// 最小二乗法
double LeastSquares(int pos, double freq, double waveLen)
{
	double sum = 0;
	int wl = (int)ceil(waveLen);
	for (int i = 0; i < wl; i++) {
		double t = i * freq / SAMPLING_RATE;
		double y = sin(2 * M_PI * t);
		double d = (waveformData[pos + i] - 128.0) / 128 - y;
		sum += d * d;
//		printf("%d t=%.6f y=%.6f\n", i, t, y);
	}
	return sum / waveLen;
}
 
// 音量
double Volume(int pos, int wl)
{
	double sum = 0;
	for (int i = 0; i < wl; i++) {
		sum += abs((waveformData[pos + i] - 128.0) / 128);
	}
	return sum / wl;
}
 
最終更新:2013年02月04日 18:17