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@199
|
137 while((input=_getInput()) >= 0){
|
giuliomoro@197
|
138 midi_byte_t inputByte = (midi_byte_t)(input);
|
giuliomoro@197
|
139 inputParser->parse(&inputByte, 1);
|
giuliomoro@197
|
140 }
|
giuliomoro@197
|
141 }
|
giuliomoro@181
|
142 if(ret < maxBytesToRead){ //no more data to retrieve at the moment
|
giuliomoro@181
|
143 usleep(1000);
|
giuliomoro@197
|
144 } // otherwise there might be more data ready to be read (we were at the end of the buffer), so don't sleep
|
giuliomoro@181
|
145 }
|
giuliomoro@181
|
146 }
|
giuliomoro@181
|
147
|
giuliomoro@191
|
148 void Midi::writeOutputLoop(){
|
giuliomoro@191
|
149 while(!gShouldStop){
|
giuliomoro@191
|
150 usleep(1000);
|
giuliomoro@191
|
151 int length = outputBytesWritePointer - outputBytesReadPointer;
|
giuliomoro@191
|
152 if(length < 0){
|
giuliomoro@191
|
153 length = outputBytes.size() - outputBytesReadPointer;
|
giuliomoro@191
|
154 }
|
giuliomoro@191
|
155 if(length == 0){ //nothing to be written
|
giuliomoro@191
|
156 continue;
|
giuliomoro@191
|
157 }
|
giuliomoro@191
|
158 int ret;
|
giuliomoro@191
|
159 ret = write(outputPort, &outputBytes[outputBytesReadPointer], sizeof(midi_byte_t)*length);
|
giuliomoro@191
|
160 if(ret < 0){ //error occurred
|
giuliomoro@191
|
161 rt_printf("error occurred while writing: %d\n", errno);
|
giuliomoro@191
|
162 usleep(10000); //wait before retrying
|
giuliomoro@191
|
163 continue;
|
giuliomoro@191
|
164 }
|
giuliomoro@191
|
165 }
|
giuliomoro@191
|
166 }
|
giuliomoro@181
|
167 int Midi::readFrom(int port){
|
giuliomoro@191
|
168 objAddrs[kMidiInput].push_back(this);
|
giuliomoro@181
|
169 inputPort = open("/dev/midi1", O_RDONLY | O_NONBLOCK | O_NOCTTY);
|
giuliomoro@181
|
170 if(inputPort < 0){
|
giuliomoro@191
|
171 printf("Error occurred while opening midi input port %d: %d", port, inputPort);
|
giuliomoro@181
|
172 return -1;
|
giuliomoro@181
|
173 } else {
|
giuliomoro@191
|
174 printf("Reading from port %d\n", port);
|
giuliomoro@181
|
175 BeagleRT_scheduleAuxiliaryTask(midiInputTask);
|
giuliomoro@181
|
176 return 1;
|
giuliomoro@181
|
177 }
|
giuliomoro@181
|
178 }
|
giuliomoro@181
|
179
|
giuliomoro@191
|
180 int Midi::writeTo(int port){
|
giuliomoro@191
|
181 objAddrs[kMidiOutput].push_back(this);
|
giuliomoro@191
|
182 outputPort = open("/dev/midi1", O_WRONLY, 0);
|
giuliomoro@191
|
183 if(outputPort < 0){
|
giuliomoro@191
|
184 printf("Error occurred while opening midi output port %d: %d", port, outputPort);
|
giuliomoro@191
|
185 return -1;
|
giuliomoro@191
|
186 } else {
|
giuliomoro@191
|
187 printf("Writing to Midi port %d\n", port);
|
giuliomoro@191
|
188 BeagleRT_scheduleAuxiliaryTask(midiOutputTask);
|
giuliomoro@191
|
189 return 1;
|
giuliomoro@191
|
190 }
|
giuliomoro@191
|
191 }
|
giuliomoro@191
|
192
|
giuliomoro@199
|
193 int Midi::_getInput(){
|
giuliomoro@181
|
194 if(inputPort < 0)
|
giuliomoro@181
|
195 return -2;
|
giuliomoro@181
|
196 if(inputBytesReadPointer == inputBytesWritePointer){
|
giuliomoro@181
|
197 return -1; // no bytes to read
|
giuliomoro@181
|
198 }
|
giuliomoro@181
|
199 midi_byte_t inputMessage = inputBytes[inputBytesReadPointer++];
|
giuliomoro@181
|
200 if(inputBytesReadPointer == inputBytes.size()){ // wrap pointer
|
giuliomoro@181
|
201 inputBytesReadPointer = 0;
|
giuliomoro@181
|
202 }
|
giuliomoro@181
|
203 return inputMessage;
|
giuliomoro@181
|
204 }
|
giuliomoro@191
|
205
|
giuliomoro@199
|
206 int Midi::getInput(){
|
giuliomoro@199
|
207 if(parserEnabled == true) {
|
giuliomoro@199
|
208 return -3;
|
giuliomoro@199
|
209 }
|
giuliomoro@199
|
210 return _getInput();
|
giuliomoro@199
|
211 }
|
giuliomoro@199
|
212
|
giuliomoro@197
|
213 MidiParser* Midi::getParser(){
|
giuliomoro@197
|
214 if(parserEnabled == false){
|
giuliomoro@197
|
215 return 0;
|
giuliomoro@197
|
216 }
|
giuliomoro@197
|
217 return inputParser;
|
giuliomoro@197
|
218 };
|
giuliomoro@197
|
219
|
giuliomoro@191
|
220 int Midi::writeOutput(midi_byte_t byte){
|
giuliomoro@191
|
221 return writeOutput(&byte, 1);
|
giuliomoro@191
|
222 }
|
giuliomoro@191
|
223
|
giuliomoro@191
|
224 int Midi::writeOutput(midi_byte_t* bytes, unsigned int length){
|
giuliomoro@191
|
225 int ret = write(outputPort, bytes, length);
|
giuliomoro@191
|
226 if(ret < 0)
|
giuliomoro@191
|
227 return -1;
|
giuliomoro@191
|
228 else
|
giuliomoro@191
|
229 return 1;
|
giuliomoro@191
|
230 }
|
giuliomoro@197
|
231
|
giuliomoro@197
|
232 MidiChannelMessage::MidiChannelMessage(){};
|
giuliomoro@197
|
233 MidiChannelMessage::MidiChannelMessage(MidiMessageType type){
|
giuliomoro@197
|
234 setType(type);
|
giuliomoro@197
|
235 };
|
giuliomoro@197
|
236 MidiChannelMessage::~MidiChannelMessage(){};
|
giuliomoro@197
|
237 MidiMessageType MidiChannelMessage::getType(){
|
giuliomoro@197
|
238 return _type;
|
giuliomoro@197
|
239 };
|
giuliomoro@197
|
240 int MidiChannelMessage::getChannel(){
|
giuliomoro@197
|
241 return _channel;
|
giuliomoro@197
|
242 };
|
giuliomoro@197
|
243 //int MidiChannelMessage::set(midi_byte_t* input);
|
giuliomoro@197
|
244 //
|
giuliomoro@197
|
245 //int MidiControlChangeMessage ::getValue();
|
giuliomoro@197
|
246 //int MidiControlChangeMessage::set(midi_byte_t* input){
|
giuliomoro@197
|
247 // channel = input[0];
|
giuliomoro@197
|
248 // number = input[1];
|
giuliomoro@197
|
249 // value = input[2];
|
giuliomoro@197
|
250 // return 3;
|
giuliomoro@197
|
251 //}
|
giuliomoro@197
|
252
|
giuliomoro@197
|
253 //int MidiNoteMessage::getNote();
|
giuliomoro@197
|
254 //int MidiNoteMessage::getVelocity();
|
giuliomoro@197
|
255
|
giuliomoro@197
|
256 //midi_byte_t MidiProgramChangeMessage::getProgram();
|