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@197
|
61 waitingForStatus = true;
|
giuliomoro@197
|
62 writePointer++;
|
giuliomoro@197
|
63 if(writePointer == messages.size()){
|
giuliomoro@197
|
64 writePointer = 0;
|
giuliomoro@197
|
65 }
|
giuliomoro@197
|
66 }
|
giuliomoro@197
|
67 }
|
giuliomoro@197
|
68 }
|
giuliomoro@197
|
69 return consumedBytes;
|
giuliomoro@197
|
70 };
|
giuliomoro@197
|
71
|
giuliomoro@197
|
72
|
giuliomoro@181
|
73 Midi::Midi(){
|
giuliomoro@181
|
74 outputPort = -1;
|
giuliomoro@181
|
75 inputPort = -1;
|
giuliomoro@197
|
76 inputParser = 0;
|
giuliomoro@181
|
77 size_t inputBytesInitialSize = 1000;
|
giuliomoro@181
|
78 inputBytes.resize(inputBytesInitialSize);
|
giuliomoro@191
|
79 outputBytes.resize(inputBytesInitialSize);
|
giuliomoro@181
|
80 inputBytesWritePointer = 0;
|
giuliomoro@181
|
81 inputBytesReadPointer = inputBytes.size() - 1;
|
giuliomoro@181
|
82 if(!staticConstructed){
|
giuliomoro@181
|
83 staticConstructor();
|
giuliomoro@181
|
84 }
|
giuliomoro@181
|
85 }
|
giuliomoro@181
|
86
|
giuliomoro@181
|
87 void Midi::staticConstructor(){
|
giuliomoro@181
|
88 staticConstructed = true;
|
giuliomoro@181
|
89 midiInputTask = BeagleRT_createAuxiliaryTask(Midi::midiInputLoop, 50, "MidiInput");
|
giuliomoro@191
|
90 midiOutputTask = BeagleRT_createAuxiliaryTask(Midi::midiOutputLoop, 50, "MidiOutupt");
|
giuliomoro@181
|
91 }
|
giuliomoro@181
|
92
|
giuliomoro@181
|
93 Midi::~Midi(){}
|
giuliomoro@197
|
94
|
giuliomoro@197
|
95 void Midi::enableParser(bool enable){
|
giuliomoro@197
|
96 if(enable == true){
|
giuliomoro@197
|
97 delete inputParser;
|
giuliomoro@197
|
98 inputParser = new MidiParser();
|
giuliomoro@197
|
99 parserEnabled = true;
|
giuliomoro@197
|
100 } else {
|
giuliomoro@197
|
101 delete inputParser;
|
giuliomoro@197
|
102 parserEnabled = false;
|
giuliomoro@197
|
103 }
|
giuliomoro@197
|
104 }
|
giuliomoro@197
|
105
|
giuliomoro@191
|
106 void Midi::midiInputLoop(){
|
giuliomoro@191
|
107 printf("Midi input loop %d\n", objAddrs[kMidiInput].size());
|
giuliomoro@191
|
108 for(unsigned int n = 0; n < objAddrs[kMidiInput].size(); n++){
|
giuliomoro@191
|
109 objAddrs[kMidiInput][n] -> readInputLoop();
|
giuliomoro@191
|
110 }
|
giuliomoro@191
|
111 }
|
giuliomoro@181
|
112
|
giuliomoro@191
|
113 void Midi::midiOutputLoop(){
|
giuliomoro@191
|
114 printf("Midi output loop %d\n", objAddrs[kMidiOutput].size());
|
giuliomoro@191
|
115 for(unsigned int n = 0; n < objAddrs[kMidiOutput].size(); n++){
|
giuliomoro@191
|
116 objAddrs[kMidiOutput][n] -> writeOutputLoop();
|
giuliomoro@181
|
117 }
|
giuliomoro@181
|
118 }
|
giuliomoro@181
|
119
|
giuliomoro@181
|
120 void Midi::readInputLoop(){
|
giuliomoro@181
|
121 while(!gShouldStop){
|
giuliomoro@181
|
122 int maxBytesToRead = inputBytes.size() - inputBytesWritePointer;
|
giuliomoro@181
|
123 int ret = read(inputPort, &inputBytes[inputBytesWritePointer], sizeof(midi_byte_t)*maxBytesToRead);
|
giuliomoro@181
|
124 if(ret < 0){
|
giuliomoro@181
|
125 if(errno != EAGAIN){ // read() would return EAGAIN when no data are available to read just now
|
giuliomoro@181
|
126 rt_printf("Error while reading midi %d\n", errno);
|
giuliomoro@181
|
127 }
|
giuliomoro@181
|
128 usleep(1000);
|
giuliomoro@181
|
129 continue;
|
giuliomoro@181
|
130 }
|
giuliomoro@181
|
131 inputBytesWritePointer += ret;
|
giuliomoro@181
|
132 if(inputBytesWritePointer == inputBytes.size()){ //wrap pointer around
|
giuliomoro@181
|
133 inputBytesWritePointer = 0;
|
giuliomoro@181
|
134 }
|
giuliomoro@197
|
135 if(parserEnabled == true && ret > 0){ // if the parser is enabled and there is new data, send the data to it
|
giuliomoro@197
|
136 int input;
|
giuliomoro@197
|
137 while((input=getInput()) >= 0){
|
giuliomoro@197
|
138 midi_byte_t inputByte = (midi_byte_t)(input);
|
giuliomoro@197
|
139 // printf("__0x%x\n", input);
|
giuliomoro@197
|
140 inputParser->parse(&inputByte, 1);
|
giuliomoro@197
|
141 }
|
giuliomoro@197
|
142 // if(inputBytesReadPointer == inputBytesWritePointer){
|
giuliomoro@197
|
143 // this should never be the case, it should only happen when ret == 0
|
giuliomoro@197
|
144 // } else {
|
giuliomoro@197
|
145
|
giuliomoro@197
|
146 // unsigned int length = (inputBytesWritePointer - inputBytesReadPointer + inputBytes.size())
|
giuliomoro@197
|
147 // % inputBytes.size();
|
giuliomoro@197
|
148 // rt_printf("inputBytes: 0x%x 0x%x 0x%x", inputBytes[inputBytesReadPointer],
|
giuliomoro@197
|
149 // inputBytes[inputBytesReadPointer+1], inputBytes[inputBytesReadPointer+2]);
|
giuliomoro@197
|
150 // length = inputParser->parse(&inputBytes[inputBytesReadPointer], length);
|
giuliomoro@197
|
151 // inputBytesReadPointer += length; //if parserEnabled, the readPointer is incremented here,
|
giuliomoro@197
|
152 // //so calls to getInput() should be avoided
|
giuliomoro@197
|
153 // if(inputBytesReadPointer == inputBytes.size()){
|
giuliomoro@197
|
154 // inputBytesReadPointer = 0;
|
giuliomoro@197
|
155 // }
|
giuliomoro@197
|
156 // }
|
giuliomoro@197
|
157 }
|
giuliomoro@181
|
158 if(ret < maxBytesToRead){ //no more data to retrieve at the moment
|
giuliomoro@181
|
159 usleep(1000);
|
giuliomoro@197
|
160 } // otherwise there might be more data ready to be read (we were at the end of the buffer), so don't sleep
|
giuliomoro@181
|
161 }
|
giuliomoro@181
|
162 }
|
giuliomoro@181
|
163
|
giuliomoro@191
|
164 void Midi::writeOutputLoop(){
|
giuliomoro@191
|
165 while(!gShouldStop){
|
giuliomoro@191
|
166 usleep(1000);
|
giuliomoro@191
|
167 int length = outputBytesWritePointer - outputBytesReadPointer;
|
giuliomoro@191
|
168 if(length < 0){
|
giuliomoro@191
|
169 length = outputBytes.size() - outputBytesReadPointer;
|
giuliomoro@191
|
170 }
|
giuliomoro@191
|
171 if(length == 0){ //nothing to be written
|
giuliomoro@191
|
172 continue;
|
giuliomoro@191
|
173 }
|
giuliomoro@191
|
174 int ret;
|
giuliomoro@191
|
175 ret = write(outputPort, &outputBytes[outputBytesReadPointer], sizeof(midi_byte_t)*length);
|
giuliomoro@191
|
176 if(ret < 0){ //error occurred
|
giuliomoro@191
|
177 rt_printf("error occurred while writing: %d\n", errno);
|
giuliomoro@191
|
178 usleep(10000); //wait before retrying
|
giuliomoro@191
|
179 continue;
|
giuliomoro@191
|
180 }
|
giuliomoro@191
|
181 }
|
giuliomoro@191
|
182 }
|
giuliomoro@181
|
183 int Midi::readFrom(int port){
|
giuliomoro@191
|
184 objAddrs[kMidiInput].push_back(this);
|
giuliomoro@181
|
185 inputPort = open("/dev/midi1", O_RDONLY | O_NONBLOCK | O_NOCTTY);
|
giuliomoro@181
|
186 if(inputPort < 0){
|
giuliomoro@191
|
187 printf("Error occurred while opening midi input port %d: %d", port, inputPort);
|
giuliomoro@181
|
188 return -1;
|
giuliomoro@181
|
189 } else {
|
giuliomoro@191
|
190 printf("Reading from port %d\n", port);
|
giuliomoro@181
|
191 BeagleRT_scheduleAuxiliaryTask(midiInputTask);
|
giuliomoro@181
|
192 return 1;
|
giuliomoro@181
|
193 }
|
giuliomoro@181
|
194 }
|
giuliomoro@181
|
195
|
giuliomoro@191
|
196 int Midi::writeTo(int port){
|
giuliomoro@191
|
197 objAddrs[kMidiOutput].push_back(this);
|
giuliomoro@191
|
198 outputPort = open("/dev/midi1", O_WRONLY, 0);
|
giuliomoro@191
|
199 if(outputPort < 0){
|
giuliomoro@191
|
200 printf("Error occurred while opening midi output port %d: %d", port, outputPort);
|
giuliomoro@191
|
201 return -1;
|
giuliomoro@191
|
202 } else {
|
giuliomoro@191
|
203 printf("Writing to Midi port %d\n", port);
|
giuliomoro@191
|
204 BeagleRT_scheduleAuxiliaryTask(midiOutputTask);
|
giuliomoro@191
|
205 return 1;
|
giuliomoro@191
|
206 }
|
giuliomoro@191
|
207 }
|
giuliomoro@191
|
208
|
giuliomoro@191
|
209 int Midi::getInput(){
|
giuliomoro@197
|
210 // if(parserEnabled == true) {
|
giuliomoro@197
|
211 // return -3;
|
giuliomoro@197
|
212 // }
|
giuliomoro@181
|
213 if(inputPort < 0)
|
giuliomoro@181
|
214 return -2;
|
giuliomoro@181
|
215 if(inputBytesReadPointer == inputBytesWritePointer){
|
giuliomoro@181
|
216 return -1; // no bytes to read
|
giuliomoro@181
|
217 }
|
giuliomoro@181
|
218 midi_byte_t inputMessage = inputBytes[inputBytesReadPointer++];
|
giuliomoro@181
|
219 if(inputBytesReadPointer == inputBytes.size()){ // wrap pointer
|
giuliomoro@181
|
220 inputBytesReadPointer = 0;
|
giuliomoro@181
|
221 }
|
giuliomoro@181
|
222 return inputMessage;
|
giuliomoro@181
|
223 }
|
giuliomoro@191
|
224
|
giuliomoro@197
|
225 MidiParser* Midi::getParser(){
|
giuliomoro@197
|
226 if(parserEnabled == false){
|
giuliomoro@197
|
227 return 0;
|
giuliomoro@197
|
228 }
|
giuliomoro@197
|
229 return inputParser;
|
giuliomoro@197
|
230 };
|
giuliomoro@197
|
231
|
giuliomoro@191
|
232 int Midi::writeOutput(midi_byte_t byte){
|
giuliomoro@191
|
233 return writeOutput(&byte, 1);
|
giuliomoro@191
|
234 }
|
giuliomoro@191
|
235
|
giuliomoro@191
|
236 int Midi::writeOutput(midi_byte_t* bytes, unsigned int length){
|
giuliomoro@191
|
237 int ret = write(outputPort, bytes, length);
|
giuliomoro@191
|
238 if(ret < 0)
|
giuliomoro@191
|
239 return -1;
|
giuliomoro@191
|
240 else
|
giuliomoro@191
|
241 return 1;
|
giuliomoro@191
|
242 }
|
giuliomoro@197
|
243
|
giuliomoro@197
|
244 MidiChannelMessage::MidiChannelMessage(){};
|
giuliomoro@197
|
245 MidiChannelMessage::MidiChannelMessage(MidiMessageType type){
|
giuliomoro@197
|
246 setType(type);
|
giuliomoro@197
|
247 };
|
giuliomoro@197
|
248 MidiChannelMessage::~MidiChannelMessage(){};
|
giuliomoro@197
|
249 MidiMessageType MidiChannelMessage::getType(){
|
giuliomoro@197
|
250 return _type;
|
giuliomoro@197
|
251 };
|
giuliomoro@197
|
252 int MidiChannelMessage::getChannel(){
|
giuliomoro@197
|
253 return _channel;
|
giuliomoro@197
|
254 };
|
giuliomoro@197
|
255 //int MidiChannelMessage::set(midi_byte_t* input);
|
giuliomoro@197
|
256 //
|
giuliomoro@197
|
257 //int MidiControlChangeMessage ::getValue();
|
giuliomoro@197
|
258 //int MidiControlChangeMessage::set(midi_byte_t* input){
|
giuliomoro@197
|
259 // channel = input[0];
|
giuliomoro@197
|
260 // number = input[1];
|
giuliomoro@197
|
261 // value = input[2];
|
giuliomoro@197
|
262 // return 3;
|
giuliomoro@197
|
263 //}
|
giuliomoro@197
|
264
|
giuliomoro@197
|
265 //int MidiNoteMessage::getNote();
|
giuliomoro@197
|
266 //int MidiNoteMessage::getVelocity();
|
giuliomoro@197
|
267
|
giuliomoro@197
|
268 //midi_byte_t MidiProgramChangeMessage::getProgram();
|