1 | // Compile with the following for the case where KDL is entered:
|
---|
2 | // g++-x86 -DENTER_KDL -lmidi2 midi_kdl_repro.cpp -o midi_kdl_repro
|
---|
3 | //
|
---|
4 | // Compile it without -DENTER_KDL for the case where it works, i.e. the workaround is in place.
|
---|
5 | // See `void sendMessage()' for more info.
|
---|
6 |
|
---|
7 | #include <iostream>
|
---|
8 | #include <chrono>
|
---|
9 | #include <thread>
|
---|
10 |
|
---|
11 | #include <MidiRoster.h>
|
---|
12 | #include <MidiConsumer.h>
|
---|
13 | #include <MidiProducer.h>
|
---|
14 |
|
---|
15 |
|
---|
16 | BMidiConsumer* gMidiOutConsumer;
|
---|
17 | BMidiLocalProducer* gMidiOutLocProd;
|
---|
18 |
|
---|
19 | void printUsage(char* programName)
|
---|
20 | {
|
---|
21 | bool OK = true;
|
---|
22 | int32 id = 0;
|
---|
23 |
|
---|
24 | std::cout << "Usage: " << programName << " ID" << std::endl
|
---|
25 | << std::endl
|
---|
26 | << "Where ID is one of the following device IDs:" << std::endl;
|
---|
27 |
|
---|
28 | while (OK) {
|
---|
29 | BMidiConsumer* c = BMidiRoster::NextConsumer(&id);
|
---|
30 | if (c != NULL) {
|
---|
31 | std::cout << "\t" << id << "\t" << c->Name() << std::endl;
|
---|
32 | c->Release();
|
---|
33 | } else {
|
---|
34 | OK = false;
|
---|
35 | }
|
---|
36 | }
|
---|
37 |
|
---|
38 | std::cout << std::endl << "If no devices are shown, ensure that at least one MIDI out device"
|
---|
39 | << " is connected." << std::endl;
|
---|
40 | }
|
---|
41 |
|
---|
42 | void sendMessage(uint32 msg)
|
---|
43 | {
|
---|
44 | char buf[3];
|
---|
45 | buf[0] = msg & 0xFF;
|
---|
46 | buf[1] = (msg >> 8) & 0xFF;
|
---|
47 | buf[2] = (msg >> 16) & 0xFF;
|
---|
48 |
|
---|
49 | std::cout << "sendMessage: " << std::hex << ((int)buf[0] & 0xFF) << " "
|
---|
50 | << std::hex << (int)buf[1] << " "
|
---|
51 | << std::hex << (int)buf[2] << std::endl;
|
---|
52 |
|
---|
53 | #ifdef ENTER_KDL
|
---|
54 | gMidiOutLocProd->SprayData((void*)&buf, 3, true);
|
---|
55 | // length is always 3 bytes, which KDLs on 2 byte messages such as ProgramChange (0xC0)
|
---|
56 | // or ChannelPressure (0xD0)
|
---|
57 | #else
|
---|
58 | gMidiOutLocProd->SprayData((void*)&buf, (buf[0] & 0xFF) == 0xC0 ? 2 : 3, true);
|
---|
59 | // length will be 2 bytes for ProgramChange (0xC0) messages, 3 otherwise -- therefore this
|
---|
60 | // would still enter KDL on ChannelPressure (0xD0) messages which are also 2 bytes long.
|
---|
61 | #endif
|
---|
62 | }
|
---|
63 |
|
---|
64 | void runTests()
|
---|
65 | {
|
---|
66 | std::cout << "Sending a NoteOn message (3 bytes)" << std::endl;
|
---|
67 | sendMessage(0x007f4090);
|
---|
68 | std::cout << "waiting 1 second until sending the next message..." << std::endl;
|
---|
69 | std::this_thread::sleep_for(std::chrono::seconds(1));
|
---|
70 |
|
---|
71 | std::cout << "Sending a NoteOff message (3 bytes)" << std::endl;
|
---|
72 | sendMessage(0x00004080);
|
---|
73 | std::cout << "waiting 2 seconds until sending the next message..." << std::endl;
|
---|
74 | std::this_thread::sleep_for(std::chrono::seconds(2));
|
---|
75 |
|
---|
76 | std::cout << "Sending a ProgramChange message (2 bytes";
|
---|
77 | #ifdef ENTER_KDL
|
---|
78 | std::cout << ", but 3 bytes sent -- enjoy KDL ;-)";
|
---|
79 | #endif
|
---|
80 | std::cout << ")" << std::endl;
|
---|
81 | sendMessage(0x000001C0);
|
---|
82 |
|
---|
83 | #ifdef ENTER_KDL
|
---|
84 | std::cout << "waiting 30 more seconds..." << std::endl;
|
---|
85 | std::this_thread::sleep_for(std::chrono::seconds(30));
|
---|
86 | #endif
|
---|
87 | }
|
---|
88 |
|
---|
89 | int main(int argc, char** argv)
|
---|
90 | {
|
---|
91 | int32 id = 0;
|
---|
92 | gMidiOutConsumer = NULL;
|
---|
93 | gMidiOutLocProd = NULL;
|
---|
94 |
|
---|
95 | if (argc != 2) {
|
---|
96 | printUsage(argv[0]);
|
---|
97 | return 1;
|
---|
98 | }
|
---|
99 |
|
---|
100 | try {
|
---|
101 | id = std::stoi(argv[1]);
|
---|
102 | } catch (std::exception const &e) {
|
---|
103 | std::cerr << "error: could not parse the provided ID: " << argv[1]
|
---|
104 | << ", ensure you're passing a number" << std::endl;
|
---|
105 | printUsage(argv[0]);
|
---|
106 | return 2;
|
---|
107 | }
|
---|
108 |
|
---|
109 | std::cout << "attempting to connect to device ID " << id << std::endl;
|
---|
110 |
|
---|
111 | gMidiOutConsumer = BMidiRoster::FindConsumer(id);
|
---|
112 | if (gMidiOutConsumer == NULL) {
|
---|
113 | std::cerr << "error: could not find consumer for the provided ID: " << id << std::endl;
|
---|
114 | printUsage(argv[0]);
|
---|
115 | return 3;
|
---|
116 | }
|
---|
117 | gMidiOutLocProd = new BMidiLocalProducer("midi_kdl_repro");
|
---|
118 | if (!gMidiOutLocProd->IsValid()) {
|
---|
119 | gMidiOutLocProd->Release();
|
---|
120 | std::cerr << "error: producer is not valid" << std::endl;
|
---|
121 | printUsage(argv[0]);
|
---|
122 | return 4;
|
---|
123 | }
|
---|
124 | gMidiOutLocProd->Register();
|
---|
125 | if (gMidiOutLocProd->Connect(gMidiOutConsumer) != B_OK) {
|
---|
126 | std::cerr << "error: could not connect our local producer with the consumer" << std::endl;
|
---|
127 | printUsage(argv[0]);
|
---|
128 | return 5;
|
---|
129 | }
|
---|
130 | std::cout << "connected to " << id << std::endl;
|
---|
131 |
|
---|
132 | runTests();
|
---|
133 |
|
---|
134 | std::cout << "cleanup ..." << std::endl;
|
---|
135 | gMidiOutLocProd->Disconnect(gMidiOutConsumer);
|
---|
136 | gMidiOutConsumer->Release();
|
---|
137 | gMidiOutLocProd->Unregister();
|
---|
138 | gMidiOutLocProd->Release();
|
---|
139 |
|
---|
140 | return 0;
|
---|
141 | }
|
---|