teratail header banner
teratail header banner
質問するログイン新規登録

質問編集履歴

1

プログラムのint mainまでの部分を追記しました。

2017/12/21 14:30

投稿

zakky79
zakky79

スコア23

title CHANGED
File without changes
body CHANGED
@@ -1,57 +1,271 @@
1
1
  MIDIデータを読み込んで、それを楽譜の模範演奏として表示したいと考えています。
2
2
  この質問のひとつ前に質問をした時のちょうちょ(音はピアノ)を楽譜で表示すると画像のようになります。
3
3
  ```c++
4
+ #include <windows.h>
4
- void PutNote(cv::Mat& sheet, unsigned char status, unsigned char data1, unsigned char data2, long duration, cv::Scalar color, int note_x, int& index){ //音符の配置
5
+ #include <iostream>
6
+ #include <fstream>
7
+ #include <iomanip>
8
+ #include <stdio.h>
9
+ #include <time.h>
10
+ #include <process.h>
5
11
 
12
+ #include "MIDIIO.h"
13
+ #include "MIDIData.h"
14
+ #include "MIDIClock.h"
6
- if (status == 0x90 && data2 != 0x00){
15
+ #include <opencv2/opencv.hpp>
7
16
 
17
+ SYSTEMTIME stTime; /* 現在時刻獲得用変数 */
18
+ static char strTime[128]; /* 現在時刻表示用の文字列 */
19
+ double cur_time; /* 現在時刻の,当日午前0時からの秒数 */
20
+
21
+
22
+ #define SHEET_GAP 20 //楽譜の表示位置の初期の値
23
+ #define NOTE_GAP 60 //音符の表示位置の初期の値
24
+
25
+ #define NOTE_H 12 //四分音符の表示する高さの初期の値
26
+ #define NOTE_W (NOTE_H * 1.05) //二分音符の表示する高さの初期の値
27
+ #define NOTE_ANGLE (-20) //音符の大きさ
28
+
29
+ #define SHEET_W (SHEET_GAP * 2 + NOTE_GAP * 4 * 4) //楽譜の横の長さ
30
+ #define SHEET_H (SHEET_GAP * 2 + NOTE_H * 4 + SHEET_GAP * 2) //楽譜の縦の長さ
31
+
32
+ #define NOTE_OFFSET (12 * 3) //音符表示できる数
33
+
34
+ #define USE_KEYBOARD 1 //0ならキーボード不使用、1ならキーボード使用
35
+
36
+ char* winname = "Sheet";
37
+
38
+ bool g_bContinue = true;
39
+
40
+ MIDIIn* pMIDIIn; //MIDIの初期化
41
+ MIDIOut* pMIDIOut;
42
+
43
+ HANDLE hGetNotesMutex; //ミューテックスのハンドル
44
+ HANDLE hNoteXMutex;
45
+
46
+ int note_x;
47
+ int note_x_by_midi;
48
+ int note_y[11];
49
+ int flag[2] = { 1, 1 }; // [0] for midi input, [1] for keyboard input
50
+
51
+ cv::Mat sheet_base;
52
+ cv::Mat sheet_note;
53
+ cv::Mat sheet_draw;
54
+ cv::Mat sheet_base2[4];
55
+
56
+
57
+ int current_x = SHEET_GAP;
58
+
59
+ std::vector<int> note_correct_x;
60
+ std::vector<int> note_correct_y;
61
+
62
+ std::vector<int> note_player_x;
63
+ std::vector<int> note_player_y;
64
+
65
+ int hitcount = 0;
66
+ double avelen = 0.0;
67
+ double avelen2[4] = { 0.0, 0.0, 0.0, 0.0 };
68
+
69
+ void pseudoColor(double index, unsigned char& B, unsigned char& G, unsigned char& R) { //擬似カラーの設定
70
+ // 0.0 <= index <= 1.0
71
+ if (0.0 <= index && index <= 0.25) {
72
+ B = 255;
73
+ R = 0;
74
+ G = (int)(256.0 / 64.0 * index * 255.0);
75
+ }
76
+ else if (0.25 < index && index <= 0.5) {
77
+ G = 255;
78
+ R = 0;
79
+ B = (int)(-256.0 / 64.0 * index * 255.0 + 511.0);
80
+
81
+ }
82
+ else if (0.5 < index && index <= 0.75) {
83
+ B = 0;
84
+ G = 255;
85
+ R = (int)(256.0 / 64.0 * index * 255.0 - 511.0);
86
+ }
87
+ else if (0.75 < index && index <= 1.0) {
88
+ R = 255;
89
+ B = 0;
90
+ G = (int)(-256.0 / 64.0 * index * 255.0 + 256 * 3 - 1);
91
+ }
92
+ else {
93
+ // Error
94
+ }
95
+ }
96
+
97
+ void PutNote(cv::Mat& sheet, unsigned char status, unsigned char data1, unsigned char data2, long duration, cv::Scalar color, int note_x, int& index) { //音符の配置
98
+
99
+ if ((status & 0xF0) == 0x90 && data2 != 0x00) {
100
+
8
- if (data1 == (0x18 + NOTE_OFFSET)){ // Do C
101
+ if (data1 == (0x18 + NOTE_OFFSET)) { // Do C
9
102
  index = 0;
10
103
  }
11
- else if (data1 == (0x1A + NOTE_OFFSET)){ // Re D
104
+ else if (data1 == (0x26 + NOTE_OFFSET)) { // Re D
12
105
  index = 1;
13
106
  }
14
- else if (data1 == (0x1C + NOTE_OFFSET)){ // Mi E
107
+ else if (data1 == (0x1C + NOTE_OFFSET)) { // Mi E
15
108
  index = 2;
16
109
  }
17
- else if (data1 == (0x1D + NOTE_OFFSET)){ // Fa F
110
+ else if (data1 == (0x1D + NOTE_OFFSET)) { // Fa F
18
111
  index = 3;
19
112
  }
20
- else if (data1 == (0x1F + NOTE_OFFSET)){ // So G
113
+ else if (data1 == (0x1F + NOTE_OFFSET)) { // So G
21
114
  index = 4;
22
115
  }
23
- else if (data1 == (0x21 + NOTE_OFFSET)){ // Ra
116
+ else if (data1 == (0x21 + NOTE_OFFSET)) { // Ra
24
117
  index = 5;
25
118
  }
26
- else if (data1 == (0x23 + NOTE_OFFSET)){ //Shi
119
+ else if (data1 == (0x23 + NOTE_OFFSET)) { //Shi
27
120
  index = 6;
28
121
  }
29
- else if (data1 == (0x24 + NOTE_OFFSET)){ // Do
122
+ else if (data1 == (0x24 + NOTE_OFFSET)) { // Do
30
123
  index = 7;
31
124
  }
32
- else if (data1 == (0x26 + NOTE_OFFSET)){ // Re
125
+ else if (data1 == (0x1A + NOTE_OFFSET)) { // Re
33
126
  index = 8;
34
127
  }
35
- else if (data1 == (0x28 + NOTE_OFFSET)){
128
+ else if (data1 == (0x28 + NOTE_OFFSET)) {
36
129
  index = 9;
37
130
  }
38
- else if (data1 == (0x19 + NOTE_OFFSET)){
131
+ else if (data1 == (0x19 + NOTE_OFFSET)) {
39
132
  index = 10;
40
133
  }
41
- if (index != -1){
134
+ if (index != -1) {
42
- if (duration == 120){
135
+ if (duration == 120) {
43
136
  cv::ellipse(sheet, cv::Point(note_x, note_y[index]), cv::Size(NOTE_W, NOTE_H / 2), NOTE_ANGLE, 0, 360, color, -1);
44
137
  }
45
- else if (duration == 240){
138
+ else if (duration == 240) {
46
139
  cv::ellipse(sheet, cv::Point(note_x, note_y[index]), cv::Size(NOTE_W, NOTE_H / 2), NOTE_ANGLE, 0, 360, color, 2);
47
140
  }
48
- else{
141
+ else {
49
142
  }
50
143
  }
51
144
  }
52
- else if (status == 0x80 || data2 == 0x00){
145
+ else if (status == 0x80 || data2 == 0x00) {
53
146
  }
54
147
  }
55
148
 
149
+ void PutNoteData(int mode, cv::Mat& sheet, unsigned char status, unsigned char data1, unsigned char data2, long duration, cv::Scalar color, int note_x) {
150
+ int index = -1;
151
+ PutNote(sheet, status, data1, data2, duration, color, note_x, index);
152
+ if (mode == 0) { // 楽譜構築モード
153
+ note_correct_x.push_back(note_x);
154
+ note_correct_y.push_back(index);
155
+ }
156
+ else if (mode == 1) { // ユーザによる演奏音符反映モード
157
+ note_player_x.push_back(note_x);
158
+ note_player_y.push_back(index);
159
+ }
160
+ else {
161
+ // mode == -1 // 時刻に対応する音符反映モード
162
+ }
163
+ }
164
+
165
+ unsigned __stdcall GetNotesThread(void *p)
166
+ {
167
+
168
+ long lLen;
169
+ unsigned char byMessage[256];
170
+
171
+ /* MIDIメッセージの取得ループ */
172
+ while (g_bContinue) {
173
+ WaitForSingleObject(hGetNotesMutex, INFINITE); //mutex 間は他のスレッドから変数を変更できない
174
+ lLen = MIDIIn_GetMIDIMessage(pMIDIIn, byMessage, 256);
175
+ ReleaseMutex(hGetNotesMutex);
176
+
177
+ /* MIDIメッセージを取得した */
178
+ if (lLen > 0) {
179
+
180
+ /* スレッド */
181
+ WaitForSingleObject(hGetNotesMutex, INFINITE);
182
+ MIDIOut_PutMIDIMessage(pMIDIOut, byMessage, lLen);
183
+ for (int i = 0; i < lLen; i++) {
184
+ std::cerr << "0x" << std::setw(2) << std::setfill('0') << std::hex << std::uppercase << (int)byMessage[i] << " ";
185
+ }
186
+ std::cerr << "/ ";;
187
+ ReleaseMutex(hGetNotesMutex);
188
+
189
+ unsigned char status = byMessage[0];
190
+ unsigned char data1 = byMessage[1];
191
+ unsigned char data2 = byMessage[2];
192
+ if ((status & 0xF0) == 0x99 && data2 != 0x00) {
193
+ hitcount++;
194
+
195
+ WaitForSingleObject(hNoteXMutex, INFINITE); //mutex 間は他のスレッドから変数を変更できない
196
+ PutNoteData(1, sheet_base2[0], status, data1, data2, 120, cv::Scalar(127, 127, 127), current_x);
197
+
198
+ int key_x = note_player_x[note_player_x.size() - 1];
199
+ int key_y = note_player_y[note_player_y.size() - 1];
200
+
201
+ int nearest_index = 0;
202
+ int nearest_length = 99999;
203
+
204
+ for (int i = 0; i < note_correct_x.size(); i++) {
205
+ if (abs(note_correct_x[i] - key_x) < nearest_length) {
206
+ nearest_index = i;
207
+ nearest_length = abs(note_correct_x[i] - key_x);
208
+ }
209
+ }
210
+
211
+ int near_x = note_correct_x[nearest_index];
212
+ int near_y = note_correct_y[nearest_index];
213
+ double diff;
214
+
215
+ // CalcPseudoColor
216
+ unsigned char b, g, r;
217
+
218
+ //ずれ情報なし
219
+ diff = 0.0;
220
+ pseudoColor(diff, b, g, r);
221
+ PutNoteData(-1, sheet_base2[0], status, data1, data2, 120, cv::Scalar(b, g, r), current_x);
222
+ avelen2[0] += diff;
223
+
224
+ //時間のずれ
225
+ diff = abs(key_x - near_x) / 30.0; // 0 ~ 30
226
+ if (diff > 1.0) {
227
+ diff = 1.0;
228
+ }
229
+ pseudoColor(diff, b, g, r);
230
+ PutNoteData(-1, sheet_base2[1], status, data1, data2, 120, cv::Scalar(b, g, r), current_x);
231
+ avelen2[1] += diff;
232
+
233
+ //音程のずれ
234
+ diff = abs((double)key_y - (double)near_y) / 4.0; //高さのindexの差
235
+ fprintf(stderr, "diff0 = %f\n", diff);
236
+ if (diff > 1.0) {
237
+ diff = 1.0;
238
+ }
239
+ pseudoColor(diff, b, g, r);
240
+ PutNoteData(-1, sheet_base2[2], status, data1, data2, 120, cv::Scalar(b, g, r), current_x);
241
+ avelen2[2] += diff;
242
+ fprintf(stderr, "diff = %f\n", diff);
243
+ fprintf(stderr, "hitcount = %d\n", hitcount);
244
+
245
+ //音程と時間両方のずれ
246
+ double diff0 = abs(key_x - near_x) / 30.0;
247
+ double diff1 = abs((double)key_y - (double)near_y) / 4.0;
248
+ diff = sqrt(diff0 * diff0 + diff1 * diff1) / sqrt(2.0);
249
+ if (diff > 1.0) {
250
+ diff = 1.0;
251
+ }
252
+ pseudoColor(diff, b, g, r);
253
+ PutNoteData(-1, sheet_base2[3], status, data1, data2, 120, cv::Scalar(b, g, r), current_x);
254
+ avelen2[3] += diff;
255
+
256
+ ReleaseMutex(hNoteXMutex);
257
+ }
258
+ }
259
+ /* MIDIメッセージを取得しなかった */
260
+ else {
261
+ /* スリープ処理 */
262
+ Sleep(1);
263
+ }
264
+ }
265
+
266
+ _endthreadex(0);
267
+
268
+ return 0; //コンパイラの警告を殺す
269
+ }
56
270
  ```
57
271
  これをドラムの音でも同じように楽譜に表示させたいと思うんですが、0x00を0x09に変え、スネアドラムは16進数で0x26なので、ドの0x18を0x26に変えて実行したところ、何も表示されませんでした。midiの音も鳴っていないので、midiの読み込みから失敗しているのでしょうか。ピアノの音のmidiは鳴っています。