giuliomoro@181
|
1 /*
|
giuliomoro@181
|
2 * Midi.cpp
|
giuliomoro@181
|
3 *
|
giuliomoro@181
|
4 * Created on: 15 Jan 2016
|
giuliomoro@181
|
5 * Author: giulio
|
giuliomoro@181
|
6 */
|
giuliomoro@181
|
7
|
giuliomoro@181
|
8 #include "Midi.h"
|
giuliomoro@181
|
9 #include <fcntl.h>
|
giuliomoro@181
|
10 #include <errno.h>
|
giuliomoro@181
|
11
|
giuliomoro@191
|
12 #define kMidiInput 0
|
giuliomoro@191
|
13 #define kMidiOutput 1
|
giuliomoro@191
|
14
|
giuliomoro@197
|
15
|
giuliomoro@197
|
16 midi_byte_t midiMessageStatusBytes[midiMessageStatusBytesLength]=
|
giuliomoro@197
|
17 {
|
giuliomoro@197
|
18 0x80,
|
giuliomoro@197
|
19 0x90,
|
giuliomoro@197
|
20 0xA0,
|
giuliomoro@197
|
21 0xB0,
|
giuliomoro@197
|
22 0xC0,
|
giuliomoro@197
|
23 0xD0,
|
giuliomoro@197
|
24 0xE0,
|
giuliomoro@197
|
25 0
|
giuliomoro@197
|
26 };
|
giuliomoro@197
|
27
|
giuliomoro@197
|
28 unsigned int midiMessageNumDataBytes[midiMessageStatusBytesLength]={2, 2, 2, 2, 1, 1, 2, 0};
|
giuliomoro@197
|
29
|
giuliomoro@181
|
30 bool Midi::staticConstructed;
|
giuliomoro@181
|
31 AuxiliaryTask Midi::midiInputTask;
|
giuliomoro@181
|
32 AuxiliaryTask Midi::midiOutputTask;
|
giuliomoro@191
|
33 std::vector<Midi *> Midi::objAddrs[2];
|
giuliomoro@181
|
34
|
giuliomoro@197
|
35 int MidiParser::parse(midi_byte_t* input, unsigned int length){
|
giuliomoro@197
|
36 unsigned int consumedBytes = 0;
|
giuliomoro@197
|
37 for(unsigned int n = 0; n < length; n++){
|
giuliomoro@197
|
38 consumedBytes++;
|
giuliomoro@197
|
39 if(waitingForStatus == true){
|
giuliomoro@197
|
40 int statusByte = input[n];
|
giuliomoro@197
|
41 MidiMessageType newType = kmmNone;
|
giuliomoro@197
|
42 if (statusByte >= 0x80){//it actually is a status byte
|
giuliomoro@197
|
43 for(int n = 0; n < midiMessageStatusBytesLength; n++){ //find the statusByte in the array
|
giuliomoro@197
|
44 if(midiMessageStatusBytes[n] == (statusByte&0xf0)){
|
giuliomoro@197
|
45 newType = (MidiMessageType)n;
|
giuliomoro@197
|
46 break;
|
giuliomoro@197
|
47 }
|
giuliomoro@197
|
48 }
|
giuliomoro@197
|
49 elapsedDataBytes = 0;
|
giuliomoro@197
|
50 waitingForStatus = false;
|
giuliomoro@197
|
51 messages[writePointer].setType(newType);
|
giuliomoro@197
|
52 messages[writePointer].setChannel((midi_byte_t)(statusByte&0xf));
|
giuliomoro@197
|
53 consumedBytes++;
|
giuliomoro@197
|
54 } else { // either something went wrong or it's a system message
|
giuliomoro@197
|
55 continue;
|
giuliomoro@197
|
56 }
|
giuliomoro@197
|
57 } else {
|
giuliomoro@197
|
58 messages[writePointer].setDataByte(elapsedDataBytes, input[n]);
|
giuliomoro@197
|
59 elapsedDataBytes++;
|
giuliomoro@197
|
60 if(elapsedDataBytes == messages[writePointer].getNumDataBytes()){
|
giuliomoro@224
|
61 // done with the current message
|
giuliomoro@224
|
62 // call the callback if available
|
giuliomoro@224
|
63 if(isCallbackEnabled() == true){
|
giuliomoro@224
|
64 messageReadyCallback(getNextChannelMessage());
|
giuliomoro@224
|
65 }
|
giuliomoro@197
|
66 waitingForStatus = true;
|
giuliomoro@197
|
67 writePointer++;
|
giuliomoro@197
|
68 if(writePointer == messages.size()){
|
giuliomoro@197
|
69 writePointer = 0;
|
giuliomoro@197
|
70 }
|
giuliomoro@197
|
71 }
|
giuliomoro@197
|
72 }
|
giuliomoro@197
|
73 }
|
giuliomoro@224
|
74
|
giuliomoro@197
|
75 return consumedBytes;
|
giuliomoro@197
|
76 };
|
giuliomoro@197
|
77
|
giuliomoro@197
|
78
|
giuliomoro@181
|
79 Midi::Midi(){
|
giuliomoro@181
|
80 outputPort = -1;
|
giuliomoro@181
|
81 inputPort = -1;
|
giuliomoro@197
|
82 inputParser = 0;
|
giuliomoro@181
|
83 size_t inputBytesInitialSize = 1000;
|
giuliomoro@181
|
84 inputBytes.resize(inputBytesInitialSize);
|
giuliomoro@191
|
85 outputBytes.resize(inputBytesInitialSize);
|
giuliomoro@181
|
86 inputBytesWritePointer = 0;
|
giuliomoro@181
|
87 inputBytesReadPointer = inputBytes.size() - 1;
|
giuliomoro@181
|
88 if(!staticConstructed){
|
giuliomoro@181
|
89 staticConstructor();
|
giuliomoro@181
|
90 }
|
giuliomoro@181
|
91 }
|
giuliomoro@181
|
92
|
giuliomoro@181
|
93 void Midi::staticConstructor(){
|
giuliomoro@181
|
94 staticConstructed = true;
|
giuliomoro@181
|
95 midiInputTask = BeagleRT_createAuxiliaryTask(Midi::midiInputLoop, 50, "MidiInput");
|
giuliomoro@191
|
96 midiOutputTask = BeagleRT_createAuxiliaryTask(Midi::midiOutputLoop, 50, "MidiOutupt");
|
giuliomoro@181
|
97 }
|
giuliomoro@181
|
98
|
giuliomoro@181
|
99 Midi::~Midi(){}
|
giuliomoro@197
|
100
|
giuliomoro@197
|
101 void Midi::enableParser(bool enable){
|
giuliomoro@197
|
102 if(enable == true){
|
giuliomoro@197
|
103 delete inputParser;
|
giuliomoro@197
|
104 inputParser = new MidiParser();
|
giuliomoro@197
|
105 parserEnabled = true;
|
giuliomoro@197
|
106 } else {
|
giuliomoro@197
|
107 delete inputParser;
|
giuliomoro@197
|
108 parserEnabled = false;
|
giuliomoro@197
|
109 }
|
giuliomoro@197
|
110 }
|
giuliomoro@197
|
111
|
giuliomoro@191
|
112 void Midi::midiInputLoop(){
|
giuliomoro@191
|
113 for(unsigned int n = 0; n < objAddrs[kMidiInput].size(); n++){
|
giuliomoro@191
|
114 objAddrs[kMidiInput][n] -> readInputLoop();
|
giuliomoro@191
|
115 }
|
giuliomoro@191
|
116 }
|
giuliomoro@181
|
117
|
giuliomoro@191
|
118 void Midi::midiOutputLoop(){
|
giuliomoro@191
|
119 for(unsigned int n = 0; n < objAddrs[kMidiOutput].size(); n++){
|
giuliomoro@191
|
120 objAddrs[kMidiOutput][n] -> writeOutputLoop();
|
giuliomoro@181
|
121 }
|
giuliomoro@181
|
122 }
|
giuliomoro@181
|
123
|
giuliomoro@181
|
124 void Midi::readInputLoop(){
|
giuliomoro@181
|
125 while(!gShouldStop){
|
giuliomoro@181
|
126 int maxBytesToRead = inputBytes.size() - inputBytesWritePointer;
|
giuliomoro@181
|
127 int ret = read(inputPort, &inputBytes[inputBytesWritePointer], sizeof(midi_byte_t)*maxBytesToRead);
|
giuliomoro@181
|
128 if(ret < 0){
|
giuliomoro@181
|
129 if(errno != EAGAIN){ // read() would return EAGAIN when no data are available to read just now
|
giuliomoro@181
|
130 rt_printf("Error while reading midi %d\n", errno);
|
giuliomoro@181
|
131 }
|
giuliomoro@181
|
132 usleep(1000);
|
giuliomoro@181
|
133 continue;
|
giuliomoro@181
|
134 }
|
giuliomoro@181
|
135 inputBytesWritePointer += ret;
|
giuliomoro@181
|
136 if(inputBytesWritePointer == inputBytes.size()){ //wrap pointer around
|
giuliomoro@181
|
137 inputBytesWritePointer = 0;
|
giuliomoro@181
|
138 }
|
giuliomoro@224
|
139
|
giuliomoro@197
|
140 if(parserEnabled == true && ret > 0){ // if the parser is enabled and there is new data, send the data to it
|
giuliomoro@197
|
141 int input;
|
giuliomoro@199
|
142 while((input=_getInput()) >= 0){
|
giuliomoro@197
|
143 midi_byte_t inputByte = (midi_byte_t)(input);
|
giuliomoro@197
|
144 inputParser->parse(&inputByte, 1);
|
giuliomoro@197
|
145 }
|
giuliomoro@197
|
146 }
|
giuliomoro@181
|
147 if(ret < maxBytesToRead){ //no more data to retrieve at the moment
|
giuliomoro@181
|
148 usleep(1000);
|
giuliomoro@197
|
149 } // otherwise there might be more data ready to be read (we were at the end of the buffer), so don't sleep
|
giuliomoro@181
|
150 }
|
giuliomoro@181
|
151 }
|
giuliomoro@181
|
152
|
giuliomoro@191
|
153 void Midi::writeOutputLoop(){
|
giuliomoro@191
|
154 while(!gShouldStop){
|
giuliomoro@191
|
155 usleep(1000);
|
giuliomoro@191
|
156 int length = outputBytesWritePointer - outputBytesReadPointer;
|
giuliomoro@191
|
157 if(length < 0){
|
giuliomoro@191
|
158 length = outputBytes.size() - outputBytesReadPointer;
|
giuliomoro@191
|
159 }
|
giuliomoro@191
|
160 if(length == 0){ //nothing to be written
|
giuliomoro@191
|
161 continue;
|
giuliomoro@191
|
162 }
|
giuliomoro@191
|
163 int ret;
|
giuliomoro@191
|
164 ret = write(outputPort, &outputBytes[outputBytesReadPointer], sizeof(midi_byte_t)*length);
|
giuliomoro@191
|
165 if(ret < 0){ //error occurred
|
giuliomoro@191
|
166 rt_printf("error occurred while writing: %d\n", errno);
|
giuliomoro@191
|
167 usleep(10000); //wait before retrying
|
giuliomoro@191
|
168 continue;
|
giuliomoro@191
|
169 }
|
giuliomoro@191
|
170 }
|
giuliomoro@191
|
171 }
|
giuliomoro@181
|
172 int Midi::readFrom(int port){
|
giuliomoro@191
|
173 objAddrs[kMidiInput].push_back(this);
|
giuliomoro@181
|
174 inputPort = open("/dev/midi1", O_RDONLY | O_NONBLOCK | O_NOCTTY);
|
giuliomoro@181
|
175 if(inputPort < 0){
|
giuliomoro@191
|
176 printf("Error occurred while opening midi input port %d: %d", port, inputPort);
|
giuliomoro@181
|
177 return -1;
|
giuliomoro@181
|
178 } else {
|
giuliomoro@191
|
179 printf("Reading from port %d\n", port);
|
giuliomoro@181
|
180 BeagleRT_scheduleAuxiliaryTask(midiInputTask);
|
giuliomoro@181
|
181 return 1;
|
giuliomoro@181
|
182 }
|
giuliomoro@181
|
183 }
|
giuliomoro@181
|
184
|
giuliomoro@191
|
185 int Midi::writeTo(int port){
|
giuliomoro@191
|
186 objAddrs[kMidiOutput].push_back(this);
|
giuliomoro@191
|
187 outputPort = open("/dev/midi1", O_WRONLY, 0);
|
giuliomoro@191
|
188 if(outputPort < 0){
|
giuliomoro@191
|
189 printf("Error occurred while opening midi output port %d: %d", port, outputPort);
|
giuliomoro@191
|
190 return -1;
|
giuliomoro@191
|
191 } else {
|
giuliomoro@191
|
192 printf("Writing to Midi port %d\n", port);
|
giuliomoro@191
|
193 BeagleRT_scheduleAuxiliaryTask(midiOutputTask);
|
giuliomoro@191
|
194 return 1;
|
giuliomoro@191
|
195 }
|
giuliomoro@191
|
196 }
|
giuliomoro@191
|
197
|
giuliomoro@199
|
198 int Midi::_getInput(){
|
giuliomoro@181
|
199 if(inputPort < 0)
|
giuliomoro@181
|
200 return -2;
|
giuliomoro@181
|
201 if(inputBytesReadPointer == inputBytesWritePointer){
|
giuliomoro@181
|
202 return -1; // no bytes to read
|
giuliomoro@181
|
203 }
|
giuliomoro@181
|
204 midi_byte_t inputMessage = inputBytes[inputBytesReadPointer++];
|
giuliomoro@181
|
205 if(inputBytesReadPointer == inputBytes.size()){ // wrap pointer
|
giuliomoro@181
|
206 inputBytesReadPointer = 0;
|
giuliomoro@181
|
207 }
|
giuliomoro@181
|
208 return inputMessage;
|
giuliomoro@181
|
209 }
|
giuliomoro@191
|
210
|
giuliomoro@199
|
211 int Midi::getInput(){
|
giuliomoro@199
|
212 if(parserEnabled == true) {
|
giuliomoro@199
|
213 return -3;
|
giuliomoro@199
|
214 }
|
giuliomoro@199
|
215 return _getInput();
|
giuliomoro@199
|
216 }
|
giuliomoro@199
|
217
|
giuliomoro@197
|
218 MidiParser* Midi::getParser(){
|
giuliomoro@197
|
219 if(parserEnabled == false){
|
giuliomoro@197
|
220 return 0;
|
giuliomoro@197
|
221 }
|
giuliomoro@197
|
222 return inputParser;
|
giuliomoro@197
|
223 };
|
giuliomoro@197
|
224
|
giuliomoro@191
|
225 int Midi::writeOutput(midi_byte_t byte){
|
giuliomoro@191
|
226 return writeOutput(&byte, 1);
|
giuliomoro@191
|
227 }
|
giuliomoro@191
|
228
|
giuliomoro@191
|
229 int Midi::writeOutput(midi_byte_t* bytes, unsigned int length){
|
giuliomoro@191
|
230 int ret = write(outputPort, bytes, length);
|
giuliomoro@191
|
231 if(ret < 0)
|
giuliomoro@191
|
232 return -1;
|
giuliomoro@191
|
233 else
|
giuliomoro@191
|
234 return 1;
|
giuliomoro@191
|
235 }
|
giuliomoro@197
|
236
|
giuliomoro@197
|
237 MidiChannelMessage::MidiChannelMessage(){};
|
giuliomoro@197
|
238 MidiChannelMessage::MidiChannelMessage(MidiMessageType type){
|
giuliomoro@197
|
239 setType(type);
|
giuliomoro@197
|
240 };
|
giuliomoro@197
|
241 MidiChannelMessage::~MidiChannelMessage(){};
|
giuliomoro@197
|
242 MidiMessageType MidiChannelMessage::getType(){
|
giuliomoro@197
|
243 return _type;
|
giuliomoro@197
|
244 };
|
giuliomoro@197
|
245 int MidiChannelMessage::getChannel(){
|
giuliomoro@197
|
246 return _channel;
|
giuliomoro@197
|
247 };
|
giuliomoro@197
|
248 //int MidiChannelMessage::set(midi_byte_t* input);
|
giuliomoro@197
|
249 //
|
giuliomoro@197
|
250 //int MidiControlChangeMessage ::getValue();
|
giuliomoro@197
|
251 //int MidiControlChangeMessage::set(midi_byte_t* input){
|
giuliomoro@197
|
252 // channel = input[0];
|
giuliomoro@197
|
253 // number = input[1];
|
giuliomoro@197
|
254 // value = input[2];
|
giuliomoro@197
|
255 // return 3;
|
giuliomoro@197
|
256 //}
|
giuliomoro@197
|
257
|
giuliomoro@197
|
258 //int MidiNoteMessage::getNote();
|
giuliomoro@197
|
259 //int MidiNoteMessage::getVelocity();
|
giuliomoro@197
|
260
|
giuliomoro@197
|
261 //midi_byte_t MidiProgramChangeMessage::getProgram();
|