質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

198閲覧

電子ドラムを叩いた時に2回判定になる

zakky79

総合スコア23

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2018/01/30 07:33

おーぷんmidiぷろじぇくとというライブラリを使用しています。
電子ドラムで叩いた音を楽譜に表示させようとしているのですが、
叩いた音は表示できているものの、何故か一度しか叩いていないのですが、2回たたいたことになり、音符が2個ならんで、2回叩いた判定になってしまいます。原因が分からず、困っています。元々ピアノベースに作られたプログラムなので、鍵盤を押したときと、離した時の判定がドラムにも同じような判定になってしまっていると考えているのですが、それにしても、1度叩いて2個並ぶ音符の表示に少し距離があるので、分からずです。原因であろう箇所のプログラムだけおいてます(入りきらないので)。よろしくお願いします。黒は元々表示されている楽譜で、青が電子ドラムで叩いた時の音符です。一度しか叩いていないのに、なぜか2回叩いた判定になってしまっています。

c++

1HANDLE hGetNotesMutex; //ミューテックスのハンドル 2HANDLE hNoteXMutex; 3 4std::vector<int> note_correct_x; 5std::vector<int> note_correct_y; 6std::vector<int> note_player_x; 7std::vector<int> note_player_y; 8 9 10 11void PutNoteData(int mode, cv::Mat& sheet, unsigned char status, unsigned char data1, unsigned char data2, long duration, cv::Scalar color, int note_x) { 12 int index = -1; 13 PutNote(sheet, status, data1, data2, duration, color, note_x, index); 14 if (mode == 0) { // 楽譜構築モード 15 note_correct_x.push_back(note_x); 16 note_correct_y.push_back(index); 17 } 18 else if (mode == 1) { // ユーザによる演奏音符反映モード 19 note_player_x.push_back(note_x); 20 note_player_y.push_back(index); 21 } 22 else { 23 // mode == -1 // 時刻に対応する音符反映モード 24 } 25} 26 27unsigned __stdcall GetNotesThread(void *p) 28{ 29 30 long lLen; 31 unsigned char byMessage[256]; 32 33 /* MIDIメッセージの取得ループ */ 34 while (g_bContinue) { 35 WaitForSingleObject(hGetNotesMutex, INFINITE); //mutex 間は他のスレッドから変数を変更できない 36 lLen = MIDIIn_GetMIDIMessage(pMIDIIn, byMessage, 256); 37 ReleaseMutex(hGetNotesMutex); 38 39 /* MIDIメッセージを取得した */ 40 if (lLen > 0) { 41 42 /* スレッド */ 43 WaitForSingleObject(hGetNotesMutex, INFINITE); 44 MIDIOut_PutMIDIMessage(pMIDIOut, byMessage, lLen); 45 for (int i = 0; i < lLen; i++) { 46 std::cerr << "0x" << std::setw(2) << std::setfill('0') << std::hex << std::uppercase << (int)byMessage[i] << " "; 47 } 48 std::cerr << "/ ";; 49 ReleaseMutex(hGetNotesMutex); 50 51 unsigned char status = byMessage[0]; 52 unsigned char data1 = byMessage[1]; 53 unsigned char data2 = byMessage[2]; 54 if ((status & 0xF0) == 0x90 && ((status & 0x0F) == 9 || data2 != 0x00)) { 55 hitcount++; 56 57 WaitForSingleObject(hNoteXMutex, INFINITE); //mutex 間は他のスレッドから変数を変更できない 58 PutNoteData(1, sheet_base2[0], status, data1, data2, 120, cv::Scalar(127, 127, 127), current_x); 59 60 int key_x = note_player_x[note_player_x.size() - 1]; 61 int key_y = note_player_y[note_player_y.size() - 1]; 62 63 int nearest_index = 0; 64 int nearest_length = 99999; 65 66 for (int i = 0; i < note_correct_x.size(); i++) { 67 if (abs(note_correct_x[i] - key_x) < nearest_length) { 68 nearest_index = i; 69 nearest_length = abs(note_correct_x[i] - key_x); 70 } 71 } 72 73 int near_x = note_correct_x[nearest_index]; 74 int near_y = note_correct_y[nearest_index]; 75 double diff;

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

iwanote

2018/01/30 08:58

ドラムですとチャタリングのような影響が大きいと思いますが対策はしていますか?
guest

回答1

0

ベストアンサー

手元で動きを確認できないことと、MIDIから遠ざかってすでに20年近くたち、うろ覚えをGoogle先生で補完しつつ回答するので、もしかしたら的外れかもしれませんがご容赦を。

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

このif文は、チャンネル10(チャンネル値9)に対するノートONかどうかの判定だと思いますが、この条件式では、ノートON、かつ、「チャンネル値が9、または、ベロシティが0以外」となります。それだと、チャンネル値が9でなくてもベロシティが0以外なら条件が成立してしまい、おそらくそれは意図していない挙動だと思います。つまり、チャンネル10(チャンネル値9)以外からの入力があると、それにも反応してしまうことになります。

ノートON判定としては、こうすべきだと思います。

C++

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

投稿2018/01/30 08:18

編集2018/01/30 09:15
catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KSwordOfHaste

2018/01/30 08:48

MIDIではバイナリーデータ上の9をCH#10と呼ぶ習慣なのですが、多分お忘れなのだと思います・・・。細かい点で恐縮です。
catsforepaw

2018/01/30 09:03

ご指摘ありがとうございます。 一応、MIDIのチャンネルは1~16で、データ上は0~15というのは覚えています。ついでにパーカションがデフォルトでチャンネル10ということもググりながら思い出しました。 ただ、条件式の説明なので、ソース中の`9`を`チャンネル10`と表現するのは違和感があるので、数値通りにチャンネル9と表現した次第であります。
catsforepaw

2018/01/30 09:16

文言修正してみました。
KSwordOfHaste

2018/01/30 09:17

了解です。1から数え始める習慣というのは特にプログラミングしているときは混乱するものですよね。ch#だけでなくprogram#も何もかも1始まりなので0始まりにしてくれたらよかったのに・・・とよく思います。
catsforepaw

2018/01/30 09:23

それはありますね。下手すると不具合が生じるケースもあるので、修正後のようにいちいち言い換えをする必要があって面倒です。 まぁ、それを防ぐためにコード上はenumとかでシンボル定義しますが。
zakky79

2018/01/30 11:43

お二方ありがとうございます!ひとつになりました!ほんと助かります;w;
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問