合計 昨日 今日

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

フォーラムルール
フォーラムルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Name: zakky
[URL]
Date: 2018年1月11日(木) 01:08
No: 1
(OFFLINE)

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

opencv,c++,おーぷんMIDIライブラリを使用して、五線譜に電子ドラムで叩いた音と、模範演奏(MIDIデータ)の楽譜を表示させようとしています。元々電子ドラムではなく、ピアノを元に作られたプログラムで、それを電子ドラム用に作ろうと考えました。ピアノでの実行時画像はこちらになります。黒の音符が模範演奏で、青がリアルタイムに演奏者が弾いた音符になります。画像
しかし、電子ドラムで実行すると、模範演奏と演奏者がリアルタイムに叩いた音が表示できません。模範演奏のMIDIデータは読み込んで音は流れます。リアルタイムにドラムからメッセージ0x99 0x2B 0x00といった3バイトが送られてきます。(何も叩かないときは常に0xF8、たまに0xFEが送られてきます。)なんとかして上の画像のように模範演奏の音符と電子ドラムの音符の描画をできるようにしたいです。色々と試みたのですが、自分の知識ではまだまだでわからないことが多く、うまくいきません。なんとかお力を借りれないでしょうか。
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
#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;
}

Name: YuO
[URL]
ハッカー(155,426 ポイント)
Date: 2018年1月11日(木) 03:13
No: 2
(OFFLINE)

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

zakky さんが書きました:リアルタイムにドラムからメッセージ0x99 0x2B 0x00といった3バイトが送られてきます。

Channel 10でNote Onが流れていきていて,Note Numberは0x2B (=43)と。GMだとLow Tom 1のようですね。
その上で,Note Onを画像として出力している部分を見ると,
zakky さんが書きました:
コード[C++]: 全て選択
1
#define NOTE_OFFSET (12 * 3) //音符表示できる数

zakky さんが書きました:
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
    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

Name: zakky
[URL]
Date: 2018年1月11日(木) 03:59
No: 3
(OFFLINE)

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

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

Name: YuO
[URL]
ハッカー(155,426 ポイント)
Date: 2018年1月14日(日) 22:15
No: 4
(OFFLINE)

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

  • PutNoteに来る値は正しいか
    コード[C++]: 全て選択
    1
    printf("status %u (%x) / data1 %u (%x) / data2 %u (%x)\n", status, status, data1, data1, data2, data2);
    をPutNoteの最初の行に入れて,想定通りの値が来ていることを確かめる。
  • 比較は正しいか
    コード[C++]: 全て選択
    1
    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はベロシティ)。


Return to C言語何でも質問掲示板

オンラインデータ

このフォーラムを閲覧中のユーザー: なし & ゲスト[14人]