Ticket #15562: midi_kdl_repro.cpp

File midi_kdl_repro.cpp, 4.0 KB (added by nilsding, 4 years ago)

testing program that causes a KDL

Line 
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
16BMidiConsumer* gMidiOutConsumer;
17BMidiLocalProducer* gMidiOutLocProd;
18
19void 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
42void 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
64void 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
89int 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}