opencv,c++で楽譜のリアルタイムでの描画

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
zakky

opencv,c++で楽譜のリアルタイムでの描画

#1

投稿記事 by zakky » 3ヶ月前

opencv,c++,おーぷんMIDIライブラリを使用して、五線譜に電子ドラムで叩いた音と、模範演奏(MIDIデータ)の楽譜を表示させようとしています。元々電子ドラムではなく、ピアノを元に作られたプログラムで、それを電子ドラム用に作ろうと考えました。ピアノでの実行時画像はこちらになります。黒の音符が模範演奏で、青がリアルタイムに演奏者が弾いた音符になります。画像
しかし、電子ドラムで実行すると、模範演奏と演奏者がリアルタイムに叩いた音が表示できません。模範演奏のMIDIデータは読み込んで音は流れます。リアルタイムにドラムからメッセージ0x99 0x2B 0x00といった3バイトが送られてきます。(何も叩かないときは常に0xF8、たまに0xFEが送られてきます。)なんとかして上の画像のように模範演奏の音符と電子ドラムの音符の描画をできるようにしたいです。色々と試みたのですが、自分の知識ではまだまだでわからないことが多く、うまくいきません。なんとかお力を借りれないでしょうか。

コード: 全て選択

#include <windows.h>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <stdio.h>
#include <time.h>
#include <process.h>

#include "MIDIIO.h"
#include "MIDIData.h"
#include "MIDIClock.h"
#include <opencv2/opencv.hpp>

SYSTEMTIME stTime;             /* 現在時刻獲得用変数         */
static char strTime[128];      /* 現在時刻表示用の文字列     */
double cur_time;               /* 現在時刻の,当日午前0時からの秒数 */


#define SHEET_GAP 20 //楽譜の表示位置の初期の値
#define NOTE_GAP 60 //音符の表示位置の初期の値

#define NOTE_H 12 //四分音符の表示する高さの初期の値
#define NOTE_W (NOTE_H * 1.05) //二分音符の表示する高さの初期の値
#define NOTE_ANGLE (-20) //音符の大きさ

#define SHEET_W (SHEET_GAP * 2 + NOTE_GAP * 4 * 4) //楽譜の横の長さ
#define SHEET_H (SHEET_GAP * 2 + NOTE_H * 4 + SHEET_GAP * 2) //楽譜の縦の長さ

#define NOTE_OFFSET (12 * 3) //音符表示できる数

#define USE_KEYBOARD 1 //0ならキーボード不使用、1ならキーボード使用

char* winname = "Sheet";

bool g_bContinue = true;

MIDIIn* pMIDIIn; //MIDIの初期化
MIDIOut* pMIDIOut;

HANDLE hGetNotesMutex; //ミューテックスのハンドル
HANDLE hNoteXMutex;

int note_x;
int note_x_by_midi;
int note_y[11];
int flag[2] = { 1, 1 }; // [0] for midi input, [1] for keyboard input

cv::Mat sheet_base;
cv::Mat sheet_note;
cv::Mat sheet_draw;
cv::Mat sheet_base2[4];


int current_x = SHEET_GAP;

std::vector<int> note_correct_x;
std::vector<int> note_correct_y;

std::vector<int> note_player_x;
std::vector<int> note_player_y;

int hitcount = 0;
double avelen = 0.0;
double avelen2[4] = { 0.0, 0.0, 0.0, 0.0 };

void pseudoColor(double index, unsigned char& B, unsigned char& G, unsigned char& R) { //擬似カラーの設定
																					   // 0.0 <= index <= 1.0
	if (0.0 <= index && index <= 0.25) {
		B = 255;
		R = 0;
		G = (int)(256.0 / 64.0 * index * 255.0);
	}
	else if (0.25 < index && index <= 0.5) {
		G = 255;
		R = 0;
		B = (int)(-256.0 / 64.0 * index * 255.0 + 511.0);

	}
	else if (0.5 < index && index <= 0.75) {
		B = 0;
		G = 255;
		R = (int)(256.0 / 64.0 * index * 255.0 - 511.0);
	}
	else if (0.75 < index && index <= 1.0) {
		R = 255;
		B = 0;
		G = (int)(-256.0 / 64.0 * index * 255.0 + 256 * 3 - 1);
	}
	else {
		// Error
	}
}

void PutNote(cv::Mat& sheet, unsigned char status, unsigned char data1, unsigned char data2, long duration, cv::Scalar color, int note_x, int& index) { //音符の配置

	if ((status & 0xF0) == 0x90 && ((status & 0x0F) == 9 || data2 != 0x00)) {

		if (data1 == (0x18 + NOTE_OFFSET)) { // Do C
			index = 0;
		}
		else if (data1 == (0x1A + NOTE_OFFSET)) { // Re D
			index = 1;
		}
		else if (data1 == (0x1C + NOTE_OFFSET)) { // Mi E
			index = 2;
		}
		else if (data1 == (0x1D + NOTE_OFFSET)) { // Fa F
			index = 3;
		}
		else if (data1 == (0x26 + NOTE_OFFSET)) { // So G
			index = 4;
		}
		else if (data1 == (0x21 + NOTE_OFFSET)) { // Ra
			index = 5;
		}
		else if (data1 == (0x23 + NOTE_OFFSET)) { //Shi
			index = 6;
		}
		else if (data1 == (0x24 + NOTE_OFFSET)) { // Do
			index = 7;
		}
		else if (data1 == (0x1F + NOTE_OFFSET)) { // Re
			index = 8;
		}
		else if (data1 == (0x28 + NOTE_OFFSET)) {
			index = 9;
		}
		else if (data1 == (0x19 + NOTE_OFFSET)) {
			index = 10;
		}
		if (index != -1) {
			if (duration == 120) {
				cv::ellipse(sheet, cv::Point(note_x, note_y[index]), cv::Size(NOTE_W, NOTE_H / 2), NOTE_ANGLE, 0, 360, color, -1);
			}
			else if (duration == 240) {
				cv::ellipse(sheet, cv::Point(note_x, note_y[index]), cv::Size(NOTE_W, NOTE_H / 2), NOTE_ANGLE, 0, 360, color, 2);
			}
			else {
			}
		}
	}
	else if (status == 0x80 || data2 == 0x00) {
	}
}

void PutNoteData(int mode, cv::Mat& sheet, unsigned char status, unsigned char data1, unsigned char data2, long duration, cv::Scalar color, int note_x) {
	int index = -1;
	PutNote(sheet, status, data1, data2, duration, color, note_x, index);
	if (mode == 0) { // 楽譜構築モード
		note_correct_x.push_back(note_x);
		note_correct_y.push_back(index);
	}
	else if (mode == 1) { // ユーザによる演奏音符反映モード
		note_player_x.push_back(note_x);
		note_player_y.push_back(index);
	}
	else {
		// mode == -1 // 時刻に対応する音符反映モード
	}
}

unsigned __stdcall GetNotesThread(void *p)
{

	long lLen;
	unsigned char byMessage[256];

	/* MIDIメッセージの取得ループ */
	while (g_bContinue) {
		WaitForSingleObject(hGetNotesMutex, INFINITE); //mutex 間は他のスレッドから変数を変更できない
		lLen = MIDIIn_GetMIDIMessage(pMIDIIn, byMessage, 256);
		ReleaseMutex(hGetNotesMutex);

		/* MIDIメッセージを取得した */
		if (lLen > 0) {

			/* スレッド */
			WaitForSingleObject(hGetNotesMutex, INFINITE);
			MIDIOut_PutMIDIMessage(pMIDIOut, byMessage, lLen);
			for (int i = 0; i < lLen; i++) {
				std::cerr << "0x" << std::setw(2) << std::setfill('0') << std::hex << std::uppercase << (int)byMessage[i] << " ";
			}
			std::cerr << "/ ";;
			ReleaseMutex(hGetNotesMutex);

			unsigned char status = byMessage[0];
			unsigned char data1 = byMessage[1];
			unsigned char data2 = byMessage[2];
			if  ((status & 0xF0) == 0x99 && data2 != 0x00) {
				hitcount++;

				WaitForSingleObject(hNoteXMutex, INFINITE); //mutex 間は他のスレッドから変数を変更できない
				PutNoteData(1, sheet_base2[0], status, data1, data2, 120, cv::Scalar(127, 127, 127), current_x);

				int key_x = note_player_x[note_player_x.size() - 1];
				int key_y = note_player_y[note_player_y.size() - 1];

				int nearest_index = 0;
				int nearest_length = 99999;

				for (int i = 0; i < note_correct_x.size(); i++) {
					if (abs(note_correct_x[i] - key_x) < nearest_length) {
						nearest_index = i;
						nearest_length = abs(note_correct_x[i] - key_x);
					}
				}

				int near_x = note_correct_x[nearest_index];
				int near_y = note_correct_y[nearest_index];
				double diff;

				// CalcPseudoColor
				unsigned char b, g, r;

				//ずれ情報なし
				diff = 0.0;
				pseudoColor(diff, b, g, r);
				PutNoteData(-1, sheet_base2[0], status, data1, data2, 120, cv::Scalar(b, g, r), current_x);
				avelen2[0] += diff;

				//時間のずれ
				diff = abs(key_x - near_x) / 30.0; // 0 ~ 30
				if (diff > 1.0) {
					diff = 1.0;
				}
				pseudoColor(diff, b, g, r);
				PutNoteData(-1, sheet_base2[1], status, data1, data2, 120, cv::Scalar(b, g, r), current_x);
				avelen2[1] += diff;

				//音程のずれ	
				diff = abs((double)key_y - (double)near_y) / 4.0; //高さのindexの差
				fprintf(stderr, "diff0 = %f\n", diff);
				if (diff > 1.0) {
					diff = 1.0;
				}
				pseudoColor(diff, b, g, r);
				PutNoteData(-1, sheet_base2[2], status, data1, data2, 120, cv::Scalar(b, g, r), current_x);
				avelen2[2] += diff;
				fprintf(stderr, "diff = %f\n", diff);
				fprintf(stderr, "hitcount = %d\n", hitcount);

				//音程と時間両方のずれ
				double diff0 = abs(key_x - near_x) / 30.0;
				double diff1 = abs((double)key_y - (double)near_y) / 4.0;
				diff = sqrt(diff0 * diff0 + diff1 * diff1) / sqrt(2.0);
				if (diff > 1.0) {
					diff = 1.0;
				}
				pseudoColor(diff, b, g, r);
				PutNoteData(-1, sheet_base2[3], status, data1, data2, 120, cv::Scalar(b, g, r), current_x);
				avelen2[3] += diff;

				ReleaseMutex(hNoteXMutex);
			}
		}
		/* MIDIメッセージを取得しなかった */
		else {
			/* スリープ処理 */
			Sleep(1);
		}
	}

	_endthreadex(0);

	return 0; //コンパイラの警告を殺す
}

int main(int argc, char* argv[]) {

	hGetNotesMutex = CreateMutex(NULL, FALSE, NULL);	//ミューテックス生成
	hNoteXMutex = CreateMutex(NULL, FALSE, NULL);	// note_xのためのミューテックス生成

	HANDLE	hThread;
	char szDeviceName[32];

	MIDIData* pMIDIData;
	MIDITrack* pMIDITrack;
	MIDIEvent* pMIDIEvent;
	MIDIClock* pMIDIClock = NULL;
	long lMillisec = 0;
	long lTickCount = 0;

	/* MIDIクロックの生成(TPQNベース, 分解能=120, テンポ:4分音符=100) */
	pMIDIClock = MIDIClock_Create(MIDICLOCK_TPQNBASE, 120, 60000000 / 100);
	if (pMIDIClock == NULL) {
		printf("MIDIクロックの生成に失敗しました。\n");
		return 0;
	}

	/* スタンダードMIDIファイル(*.mid)からMIDIデータの読み込み */
	pMIDIData = MIDIData_LoadFromSMF("drum.mid");
	if (pMIDIData == NULL) {
		/* 異常終了時の処理 */
		std::cerr << "MIDIデータの読み込みに失敗しました." << std::endl;
		return -1;
	}

	/* MIDIデータのプロパティを出力する。*/
	printf("[MIDIデータ]\n");
	printf("フォーマット=%d\n", MIDIData_GetFormat(pMIDIData));
	printf("トラック数=%d\n", MIDIData_GetNumTrack(pMIDIData));
	printf("タイムモード=%d\n", MIDIData_GetTimeMode(pMIDIData));
	printf("タイムレゾリューション=%d\n", MIDIData_GetTimeResolution(pMIDIData));

	/* 正常終了時の処理 */
	forEachTrack(pMIDIData, pMIDITrack) {
		forEachEvent(pMIDITrack, pMIDIEvent) {
			if (MIDIEvent_IsNoteOn(pMIDIEvent)) {
				MIDIEvent_Combine(pMIDIEvent);
			}
		}
	}

	char szBuf[1024];
	forEachTrack(pMIDIData, pMIDITrack) {
		printf("[MIDIトラック]\n");
		printf("小節:拍:ティック 種類              長さ  内容\n");
		/* それぞれのイベントについて */
		forEachEvent(pMIDITrack, pMIDIEvent) {
			printf("%s\n", MIDIEvent_ToString(pMIDIEvent, szBuf, sizeof(szBuf)));
		}
	}

	/* 音符画像(ベース)の表示*/
	for (int i = 0; i < 10; i++) {
		note_y[i] = (SHEET_GAP * 2 + NOTE_H * 5) - NOTE_H * 0.5 * i;
	}

	sheet_base.create(cv::Size(SHEET_W, SHEET_H), CV_8UC3);
	sheet_base = cv::Scalar(255, 255, 255);

	for (int i = 0; i < 5; i++) {
		cv::line(sheet_base, cv::Point(SHEET_GAP, SHEET_GAP * 2 + NOTE_H * i), cv::Point(SHEET_W - SHEET_GAP, SHEET_GAP * 2 + NOTE_H * i), cv::Scalar(0, 0, 0));
	}

	note_x = SHEET_GAP + NOTE_GAP / 2; // 初期化
	note_x_by_midi = SHEET_GAP + NOTE_GAP / 2; // 初期化

											   /***** 楽譜の描画 *****/
	forEachTrack(pMIDIData, pMIDITrack) {
		forEachEvent(pMIDITrack, pMIDIEvent) {

			int lLen = pMIDIEvent->m_lLen;

			if (note_x < SHEET_W - SHEET_GAP * 2 && MIDIEvent_IsNoteOn(pMIDIEvent)/*&& counttest < 30*/) {
				std::cerr << "Event Size: " << lLen << "(Bytes)" << std::endl;
				unsigned char status = pMIDIEvent->m_pData[0];
				unsigned char data1 = pMIDIEvent->m_pData[1];
				unsigned char data2 = pMIDIEvent->m_pData[2];
				long duration = MIDIEvent_GetDuration(pMIDIEvent);

				PutNoteData(0, sheet_base, status, data1, data2, duration, cv::Scalar(0, 0, 0), note_x);

				if (duration == 120) {
					note_x += NOTE_GAP;
				}
				else if (duration == 240) {
					note_x += NOTE_GAP * 2;
				}
				else {
					//Error
				}
			}
		}
	}

	note_x = SHEET_GAP + NOTE_GAP / 2; // 初期化
	note_x_by_midi = SHEET_GAP + NOTE_GAP / 2; // 初期化
	cv::imshow(winname, sheet_base);
	cv::moveWindow(winname, 0, 0);
	int key = cv::waitKey(1);

	/* */
	long lRet;

#if USE_KEYBOARD
	lRet = MIDIIn_GetDeviceNum();
	std::cerr << "Connected MIDI Device Num = " << lRet << std::endl;

	lRet = MIDIIn_GetDeviceName(0, szDeviceName, 32);
	if (lRet == 0) {
		printf("利用できるMIDI入力デバイスはありません。\n");
		system("PAUSE");
		return 0;
	}

	pMIDIIn = MIDIIn_Open(szDeviceName);

	if (pMIDIIn == NULL) {
		std::cerr << "MIDI入力デバイス「" << szDeviceName << "」を開けません。" << std::endl;
		return 0;
	}

	std::cerr << "MIDI入力デバイス「" << szDeviceName << "」を開きました。" << std::endl;

#endif

	/* MIDI出力デバイス(No.0)の名前を調べる */
	lRet = MIDIOut_GetDeviceName(0, szDeviceName, 32);
	if (lRet == 0) {
		std::cerr << "利用できるMIDI出力デバイスはありません。" << std::endl;
		return 0;
	}
	/* MIDI出力デバイスを開く */
	pMIDIOut = MIDIOut_Open(szDeviceName);
	if (pMIDIOut == NULL) {
		std::cerr << "MIDI出力デバイス「" << szDeviceName << "」を開けません。" << std::endl;
		return 0;
	}
	std::cerr << "MIDI出力デバイス「" << szDeviceName << "」を開きました。" << std::endl;
	hThread = (HANDLE)_beginthreadex(NULL, 0, GetNotesThread, "GetNotesThread", 0, NULL);
	sheet_base.copyTo(sheet_note);
	sheet_base.copyTo(sheet_draw);
	sheet_base.copyTo(sheet_base2[0]);
	sheet_base.copyTo(sheet_base2[1]);
	sheet_base.copyTo(sheet_base2[2]);
	sheet_base.copyTo(sheet_base2[3]);

	/* MIDIクロックのリセットとスタート */
	MIDIClock_Reset(pMIDIClock);
	MIDIClock_Start(pMIDIClock);

	forEachTrack(pMIDIData, pMIDITrack) {
		lTickCount = 0;

		printf("トラック名:%s\n", MIDITrack_GetName(pMIDITrack, szBuf, sizeof(szBuf)));

		/* 最初のNOTE_ONイベントを獲得 */
		pMIDIEvent = pMIDITrack->m_pFirstEvent;
		long breakTickCount = 120 / 2;

		while (lTickCount < 120 * 4 * 4 && pMIDIEvent != NULL) {

			/* 移動する縦線を引く*/
			sheet_note.copyTo(sheet_draw);

			current_x = SHEET_GAP + (lTickCount * (SHEET_W - SHEET_GAP * 2)) / (480 * 4);

			cv::line(sheet_draw, cv::Point(current_x, SHEET_GAP), cv::Point(current_x, SHEET_H - SHEET_GAP), cv::Scalar(0, 0, 255));
			cv::imshow(winname, sheet_draw);
			key = cv::waitKey(1);

			if (breakTickCount < lTickCount) {

				while (!MIDIEvent_IsNoteOn(pMIDIEvent)) {
					std::cerr << MIDIEvent_ToString(pMIDIEvent, szBuf, sizeof(szBuf)) << std::endl;
					pMIDIEvent = pMIDIEvent->m_pNextEvent;
				}
				long duration = MIDIEvent_GetDuration(pMIDIEvent);
				breakTickCount = lTickCount + duration;

				unsigned char status = pMIDIEvent->m_pData[0];
				unsigned char data1 = pMIDIEvent->m_pData[1];
				unsigned char data2 = pMIDIEvent->m_pData[2];

				if (status == 0x99) {

					int lRet = pMIDIEvent->m_lLen;
					/* MIDI出力デバイスからメッセージを送出する */
					WaitForSingleObject(hGetNotesMutex, INFINITE);
					MIDIOut_PutMIDIMessage(pMIDIOut, pMIDIEvent->m_pData, lRet);
					for (int i = 0; i < lRet; i++) {
						fprintf(stderr, "0x%02X ", pMIDIEvent->m_pData[i]);
					}
					printf("/ ");
					ReleaseMutex(hGetNotesMutex);
				}

				sheet_base.copyTo(sheet_note);
				PutNoteData(-1, sheet_note, status, data1, data2, duration, cv::Scalar(255, 255, 0), note_x_by_midi);
				if (duration == 120) {
					note_x_by_midi += NOTE_GAP;
				}
				else if (duration == 240) {
					note_x_by_midi += NOTE_GAP * 2;
				}
				else {

				}
				pMIDIEvent = pMIDIEvent->m_pNextEvent;
			}

			lTickCount = MIDIClock_GetTickCount(pMIDIClock);
		}
	}

	if (hitcount == 0) {
		std::cerr << "No Count" << std::endl;
	}
	else {
		fprintf(stderr, "Average Length[0] = %f\n", (double)avelen2[0] / hitcount);
		fprintf(stderr, "Average Length[1] = %f\n", (double)avelen2[1] / hitcount);
		fprintf(stderr, "Average Length[2] = %f\n", (double)avelen2[2] / hitcount);
		fprintf(stderr, "Average Length[3] = %f\n", (double)avelen2[3] / hitcount);
	}
	key = cv::waitKey(0);
	GetLocalTime(&stTime);         /* 現在時刻獲得 */

								   /* 獲得した時刻を文字列に変換 */
	for (int i = 0; i < 4; i++) {
		sprintf_s(strTime, 128, "%04d%02d%02d_%02d%02d%02d_%1d.png",
			stTime.wYear, stTime.wMonth, stTime.wDay,
			stTime.wHour, stTime.wMinute, stTime.wSecond, i);
		cv::imwrite(strTime, sheet_base2[i]);
	}
#if USE_KEYBOARD
	WaitForSingleObject(hThread, INFINITE); /* スレッドが終了するまで待つ。 */
	CloseHandle(hThread); /* ハンドルを閉じる */
#endif
						  /* MIDI入力デバイスを閉じる */
	MIDIIn_Close(pMIDIIn);
	/* MIDI出力デバイスを閉じる */
	MIDIOut_Close(pMIDIOut);
	return 0;
}

YuO
記事: 908
登録日時: 7年前
住所: 東京都世田谷区

Re: opencv,c++で楽譜のリアルタイムでの描画

#2

投稿記事 by YuO » 3ヶ月前

zakky さんが書きました:リアルタイムにドラムからメッセージ0x99 0x2B 0x00といった3バイトが送られてきます。
Channel 10でNote Onが流れていきていて,Note Numberは0x2B (=43)と。GMだとLow Tom 1のようですね。
その上で,Note Onを画像として出力している部分を見ると,
zakky さんが書きました:

コード: 全て選択

#define NOTE_OFFSET (12 * 3) //音符表示できる数
zakky さんが書きました:

コード: 全て選択

	if ((status & 0xF0) == 0x90 && ((status & 0x0F) == 9 || data2 != 0x00)) {

		if (data1 == (0x18 + NOTE_OFFSET)) { // Do C
			index = 0;
		}
		else if (data1 == (0x1A + NOTE_OFFSET)) { // Re D
			index = 1;
		}
		else if (data1 == (0x1C + NOTE_OFFSET)) { // Mi E
			index = 2;
		}
		else if (data1 == (0x1D + NOTE_OFFSET)) { // Fa F
			index = 3;
		}
		else if (data1 == (0x26 + NOTE_OFFSET)) { // So G
			index = 4;
		}
		else if (data1 == (0x21 + NOTE_OFFSET)) { // Ra
			index = 5;
		}
		else if (data1 == (0x23 + NOTE_OFFSET)) { //Shi
			index = 6;
		}
		else if (data1 == (0x24 + NOTE_OFFSET)) { // Do
			index = 7;
		}
		else if (data1 == (0x1F + NOTE_OFFSET)) { // Re
			index = 8;
		}
		else if (data1 == (0x28 + NOTE_OFFSET)) {
			index = 9;
		}
		else if (data1 == (0x19 + NOTE_OFFSET)) {
			index = 10;
		}
となっています。
data1はNote Numberが入っているわけですが,0x18 + 12 * 3 = 60なので,Note Numberが43ではこのif文群に引っかかることはありません。
# そもそも,NOTE_OFFSETのコメントがおかしいですが……。

このif文群を,電子ドラムの発生させるNote Numberに合わせて修正してやれば,正しく表示されると思います。
ref) General MIDI - Wikipedia#Percussion notes

zakky

Re: opencv,c++で楽譜のリアルタイムでの描画

#3

投稿記事 by zakky » 3ヶ月前

すいません。
変更する前のプログラムを書いてしまっていたようです。
スネアドラムをたたいた時に0x26で、ピアノのソの音と同じ値になります。
スネアドラムだけを鳴らしたMIDIを用意し、それを読み込ませましたが、楽譜でソの音の位置にスネアドラムの音符の描画はされませんでした。電子ドラムから送られてくるNote Numberに変更しても描画がされないのでどうしたもんやら。。。という感じになっている状況です。

YuO
記事: 908
登録日時: 7年前
住所: 東京都世田谷区

Re: opencv,c++で楽譜のリアルタイムでの描画

#4

投稿記事 by YuO » 3ヶ月前

  • PutNoteに来る値は正しいか

    コード: 全て選択

    printf("status %u (%x) / data1 %u (%x) / data2 %u (%x)\n", status, status, data1, data1, data2, data2);
    をPutNoteの最初の行に入れて,想定通りの値が来ていることを確かめる。
  • 比較は正しいか

    コード: 全て選択

    printf("index %i\n", index);
    を131行目のif文の前に入れて,正しいindexが得られているかを確かめる。
あたりを調べてみてはどうでしょうか。
もちろん,IDEやデバッガのブレークポイントとウォッチ機能を使っても構いません。

想定通りに動いていないということは,恐らく想定通りの値が来ていないはずです。
今回の場合,プログラムの方が間違っている可能性が高いので,
  • 本来どのような値がくるのか
  • どのような動作をすればいいのか
を考えて,それをプログラムに落とし込めばよいかと思います。


でもって,
zakky さんが書きました:スネアドラムをたたいた時に0x26で、ピアノのソの音と同じ値になります。
音は60 (=12 * 5 + 0)→C4を基準として,61 (=12 * 5 + 1)→C#4, 62→D4, 63→D#4, 64→E4, 65→F4, 66→F#4, 67→G4, 68→G#4, 69→A4, 70→A#4, 71→B4となります。
0x26 = 16 * 2 + 6 = 38 = 12 * 3 + 2なので,0x26はD2,レの音になるはずです。
つまり,MIDIキーボードの中央ドから2オクターブ下のレを押せば,0x90 0x26 vvが来るはずです (vvはベロシティ)。

返信

“C言語何でも質問掲示板” へ戻る