TadaoYamaokaの開発日記

個人開発しているスマホアプリや将棋AIの開発ネタを中心に書いていきます。

CQTでスペクトログラムを描く その5(拍の表示)

スペクトログラム解析VST3プラグインに拍の表示を追加した。

拍の表示

VSTのホスト側から拍の情報を受け取り、拍の位置に縦の線を描くようにした。
小節の開始は、色を明るくして目立つようにした。


処理方法

Processorで、IProcessContextRequirementsをインプリメントすることで、拍の情報を受け取ることができる。

ホストから受け取るtempo、timeSigDenominator、timeSigNumerator、projectTimeMusic、barPositionMusicと、サンプリング周波数から現在のブロックが拍の位置か、小節内の何拍目かを計算する必要がある。
ややこしいので、GPT-5で生成したコードをそのまま使った。

uint8_t VstCqtProcessor::computeBeatClass (const Vst::ProcessData& data, int sampleIndexInBlock) const
{
	using namespace Steinberg::Vst;
	const ProcessContext* ctx = data.processContext;
	if (!ctx)
		return 0;
	const double tempo = ctx->tempo; // assume host provides valid fields when non-null
	if (!(tempo > 0.0))
		return 0;
	const int den = (std::max)(1, static_cast<int> (ctx->timeSigDenominator));
	const int num = (std::max)(1, static_cast<int> (ctx->timeSigNumerator));
	const double beatLenQN = 4.0 / static_cast<double> (den); // length of one beat in quarter notes
	const double barLenQN = beatLenQN * static_cast<double> (num);
	const double qnPerSample = tempo / (60.0 * (std::max)(1.0, sampleRate_));
	const double dq = static_cast<double> (sampleIndexInBlock) * qnPerSample;
	const double qNotesIntoBar = (ctx->projectTimeMusic + dq) - ctx->barPositionMusic;
	// wrap to [0, period)
	auto wrapMod = [] (double x, double p) -> double {
		double k = std::floor (x / p);
		x -= k * p;
		if (x < 0.0) x += p;
		return x;
	};
	const double qnBeatMod = wrapMod (qNotesIntoBar, beatLenQN);
	const double qnBarMod  = wrapMod (qNotesIntoBar,  barLenQN);
	// tolerance: half of the quarter-notes advanced between analysis columns
	const double qnPerColumn = tempo / (60.0 * ANALYZE_FPS);
	const double eps = (std::max)(1e-4, qnPerColumn * 0.5);
	bool atBeat = (qnBeatMod <= eps) || ((beatLenQN - qnBeatMod) <= eps);
	bool atBar  = (qnBarMod  <= eps) || ((barLenQN  - qnBarMod)  <= eps);
	if (atBar)
		return 2; // thick line
	if (atBeat)
		return 1; // thin line
	return 0;
}

まとめ

スペクトログラムに拍の位置を表示するようにした。

次は、基本周波数解析を実装したい。