giuliomoro@181
|
1 /*
|
giuliomoro@181
|
2 * Midi.h
|
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 #ifndef MIDI_H_
|
giuliomoro@181
|
9 #define MIDI_H_
|
giuliomoro@181
|
10
|
giuliomoro@181
|
11 #include <BeagleRT.h>
|
giuliomoro@181
|
12 #include <vector>
|
giuliomoro@181
|
13
|
giuliomoro@181
|
14 typedef unsigned char midi_byte_t;
|
giuliomoro@181
|
15
|
giuliomoro@197
|
16
|
giuliomoro@197
|
17 typedef enum midiMessageType{
|
giuliomoro@197
|
18 kmmNoteOff = 0,
|
giuliomoro@197
|
19 kmmNoteOn,
|
giuliomoro@197
|
20 kmmPolyphonicKeyPressure,
|
giuliomoro@197
|
21 kmmControlChange,
|
giuliomoro@197
|
22 kmmProgramChange,
|
giuliomoro@197
|
23 kmmChannelPressure,
|
giuliomoro@197
|
24 kmmPitchBend,
|
giuliomoro@197
|
25 kmmNone,
|
giuliomoro@197
|
26 kmmAny,
|
giuliomoro@197
|
27 } MidiMessageType;
|
giuliomoro@197
|
28 #define midiMessageStatusBytesLength 7+2 //2 being kmmNone and kmmAny
|
giuliomoro@197
|
29
|
giuliomoro@197
|
30 extern midi_byte_t midiMessageStatusBytes[midiMessageStatusBytesLength];
|
giuliomoro@197
|
31 extern unsigned int midiMessageNumDataBytes[midiMessageStatusBytesLength];
|
giuliomoro@197
|
32
|
giuliomoro@197
|
33 class MidiChannelMessage{
|
giuliomoro@197
|
34 public:
|
giuliomoro@197
|
35 MidiChannelMessage();
|
giuliomoro@197
|
36 MidiChannelMessage(MidiMessageType type);
|
giuliomoro@197
|
37 virtual ~MidiChannelMessage();
|
giuliomoro@197
|
38 MidiMessageType getType();
|
giuliomoro@197
|
39 int getChannel();
|
giuliomoro@197
|
40 unsigned int getNumDataBytes(){
|
giuliomoro@197
|
41 return midiMessageNumDataBytes[(unsigned int)_type];
|
giuliomoro@197
|
42 }
|
giuliomoro@197
|
43 void setDataByte(unsigned int dataByteIndex, midi_byte_t input){
|
giuliomoro@197
|
44 _dataBytes[dataByteIndex] = input;
|
giuliomoro@197
|
45 }
|
giuliomoro@197
|
46 void setType(MidiMessageType type){
|
giuliomoro@197
|
47 _type = type;
|
giuliomoro@197
|
48 _statusByte = midiMessageStatusBytes[_type];
|
giuliomoro@197
|
49 }
|
giuliomoro@197
|
50 void setChannel(midi_byte_t channel){
|
giuliomoro@197
|
51 _channel = channel;
|
giuliomoro@197
|
52 }
|
giuliomoro@197
|
53 midi_byte_t getDataByte(unsigned int index){
|
giuliomoro@197
|
54 return _dataBytes[index];
|
giuliomoro@197
|
55 }
|
giuliomoro@197
|
56 void clear(){
|
giuliomoro@197
|
57 for(int n = 0; n<maxDataBytes; n++){
|
giuliomoro@197
|
58 _dataBytes[n] = 0;
|
giuliomoro@197
|
59 }
|
giuliomoro@197
|
60 _type = kmmNone;
|
giuliomoro@197
|
61 _statusByte = 0;
|
giuliomoro@197
|
62 }
|
giuliomoro@197
|
63 void prettyPrint(){
|
giuliomoro@197
|
64 rt_printf("MessageType: %x, ", this->getType());
|
giuliomoro@197
|
65 rt_printf("channel: %u, ", this->getChannel());
|
giuliomoro@197
|
66 for(int n = 0; n < this->getNumDataBytes(); n++){
|
giuliomoro@197
|
67 rt_printf("data%d: %d, ", n + 1, this->getDataByte(n));
|
giuliomoro@197
|
68 }
|
giuliomoro@197
|
69 rt_printf("\n");
|
giuliomoro@197
|
70 }
|
giuliomoro@197
|
71
|
giuliomoro@197
|
72 private:
|
giuliomoro@197
|
73 const static int maxDataBytes = 2;
|
giuliomoro@197
|
74 protected:
|
giuliomoro@197
|
75 midi_byte_t _statusByte;
|
giuliomoro@197
|
76 midi_byte_t _dataBytes[maxDataBytes]; // where 2 is the maximum number of data bytes for a channel message
|
giuliomoro@197
|
77 MidiMessageType _type;
|
giuliomoro@197
|
78 midi_byte_t _channel;
|
giuliomoro@197
|
79 };
|
giuliomoro@197
|
80 /*
|
giuliomoro@197
|
81 class MidiControlChangeMessage : public MidiChannelMessage{
|
giuliomoro@197
|
82 int number;
|
giuliomoro@197
|
83 int value;
|
giuliomoro@197
|
84 public:
|
giuliomoro@197
|
85 int getNumber();
|
giuliomoro@197
|
86 int getNumDataBytes();
|
giuliomoro@197
|
87 int setDataByte(midi_byte_t input, unsigned int dataByteIndex);
|
giuliomoro@197
|
88 int getValue();
|
giuliomoro@197
|
89 int set(midi_byte_t* input);
|
giuliomoro@197
|
90 };
|
giuliomoro@197
|
91
|
giuliomoro@197
|
92 class MidiNoteMessage : public MidiChannelMessage{
|
giuliomoro@197
|
93 int note;
|
giuliomoro@197
|
94 int velocity;
|
giuliomoro@197
|
95 public:
|
giuliomoro@197
|
96 int getNote();
|
giuliomoro@197
|
97 int getVelocity();
|
giuliomoro@197
|
98 int getNumDataBytes();
|
giuliomoro@197
|
99 int setDataByte(midi_byte_t input, unsigned int dataByteIndex);
|
giuliomoro@197
|
100 };
|
giuliomoro@197
|
101
|
giuliomoro@197
|
102 class MidiProgramChangeMessage : public MidiChannelMessage{
|
giuliomoro@197
|
103 midi_byte_t program;
|
giuliomoro@197
|
104 public:
|
giuliomoro@197
|
105 int getNumDataBytes();
|
giuliomoro@197
|
106 int setDataByte(midi_byte_t input, unsigned int dataByteIndex);
|
giuliomoro@197
|
107 midi_byte_t getProgram();
|
giuliomoro@197
|
108 };
|
giuliomoro@197
|
109 */
|
giuliomoro@197
|
110
|
giuliomoro@197
|
111 class MidiParser{
|
giuliomoro@197
|
112 private:
|
giuliomoro@197
|
113 std::vector<MidiChannelMessage> messages;
|
giuliomoro@197
|
114 unsigned int writePointer;
|
giuliomoro@197
|
115 unsigned int readPointer;
|
giuliomoro@197
|
116 unsigned int elapsedDataBytes;
|
giuliomoro@197
|
117 bool waitingForStatus;
|
giuliomoro@197
|
118 public:
|
giuliomoro@197
|
119 MidiParser(){
|
giuliomoro@197
|
120 waitingForStatus = true;
|
giuliomoro@197
|
121 elapsedDataBytes= 0;
|
giuliomoro@197
|
122 messages.resize(100); // 100 is the number of messages that can be buffered
|
giuliomoro@197
|
123 writePointer = 0;
|
giuliomoro@197
|
124 readPointer = 0;
|
giuliomoro@197
|
125 }
|
giuliomoro@197
|
126
|
giuliomoro@197
|
127 /**
|
giuliomoro@197
|
128 * Parses some midi messages.
|
giuliomoro@197
|
129 *
|
giuliomoro@197
|
130 * @param input the array to read from
|
giuliomoro@197
|
131 * @param length the maximum number of values available at the array
|
giuliomoro@197
|
132 *
|
giuliomoro@197
|
133 * @return the number of bytes parsed
|
giuliomoro@197
|
134 */
|
giuliomoro@197
|
135 int parse(midi_byte_t* input, unsigned int length);
|
giuliomoro@197
|
136 int callme(){
|
giuliomoro@197
|
137 return readPointer;
|
giuliomoro@197
|
138 };
|
giuliomoro@197
|
139 int numAvailableMessages(){
|
giuliomoro@197
|
140 int num = (writePointer - readPointer + messages.size() ) % messages.size();
|
giuliomoro@197
|
141 if(num > 0){
|
giuliomoro@197
|
142 int a = a +1;
|
giuliomoro@197
|
143 a = callme();
|
giuliomoro@197
|
144 }
|
giuliomoro@197
|
145 return num;
|
giuliomoro@197
|
146 }
|
giuliomoro@197
|
147 /**
|
giuliomoro@197
|
148 * Get the oldest channel message in the buffer.
|
giuliomoro@197
|
149 *
|
giuliomoro@197
|
150 * You should not call this function when numAvailableMessages() returns 0.
|
giuliomoro@197
|
151 * @param type the type of the message to retrieve
|
giuliomoro@197
|
152 * @return a copy of the oldest message of the give type in the buffer
|
giuliomoro@197
|
153 */
|
giuliomoro@197
|
154 MidiChannelMessage getNextChannelMessage(/*MidiMessageType type*/){
|
giuliomoro@197
|
155 MidiChannelMessage message;
|
giuliomoro@197
|
156 message = messages[readPointer];
|
giuliomoro@197
|
157 if(message.getType() == kmmNone){
|
giuliomoro@197
|
158 message.clear();
|
giuliomoro@197
|
159 }
|
giuliomoro@197
|
160 messages[readPointer].setType(kmmNone); // do not use it again
|
giuliomoro@197
|
161 readPointer++;
|
giuliomoro@197
|
162 if(readPointer == messages.size()){
|
giuliomoro@197
|
163 readPointer = 0;
|
giuliomoro@197
|
164 }
|
giuliomoro@197
|
165 return message;
|
giuliomoro@197
|
166 };
|
giuliomoro@197
|
167
|
giuliomoro@197
|
168 // MidiChannelMessage getNextChannelMessage(){
|
giuliomoro@197
|
169 // getNextChannelMessage(kmmAny);
|
giuliomoro@197
|
170 // }
|
giuliomoro@197
|
171 // MidiControlChangeMessage* getNextControlChangeMessage(){
|
giuliomoro@197
|
172 // return (MidiControlChangeMessage*)getNextChannelMessage(kmmControlChange);
|
giuliomoro@197
|
173 // };
|
giuliomoro@197
|
174 // MidiProgramChangeMessage* getNextProgramChangeMessage(){
|
giuliomoro@197
|
175 // return (MidiProgramChangeMessage*)getNextChannelMessage(kmmProgramChange);
|
giuliomoro@197
|
176 // };
|
giuliomoro@197
|
177 // MidiNoteMessage* getNextNoteOnMessage(){
|
giuliomoro@197
|
178 // return (MidiNoteMessage*)getNextChannelMessage(kmmNoteOn);
|
giuliomoro@197
|
179 // };
|
giuliomoro@197
|
180 };
|
giuliomoro@197
|
181
|
giuliomoro@197
|
182
|
giuliomoro@181
|
183 class Midi {
|
giuliomoro@181
|
184 public:
|
giuliomoro@181
|
185 Midi();
|
giuliomoro@197
|
186
|
giuliomoro@197
|
187 /**
|
giuliomoro@197
|
188 * Enable the input MidiParser.
|
giuliomoro@197
|
189 *
|
giuliomoro@197
|
190 * If the parser is enabled, readFrom() will return an error code.
|
giuliomoro@197
|
191 * Midi messages should instead be retrieved via, e.g.: getMidiParser()->getNextChannelMessage();
|
giuliomoro@197
|
192 *
|
giuliomoro@197
|
193 * @param enable true to enable the input MidiParser, false to disable it.
|
giuliomoro@197
|
194 */
|
giuliomoro@197
|
195 void enableParser(bool enable);
|
giuliomoro@197
|
196
|
giuliomoro@197
|
197 /**
|
giuliomoro@197
|
198 * Get access to the input parser in use, if any.
|
giuliomoro@197
|
199 *
|
giuliomoro@197
|
200 * @return a pointer to the instance of MidiParser, if currently enabled, zero otherwise.
|
giuliomoro@197
|
201 */
|
giuliomoro@197
|
202 MidiParser* getParser();
|
giuliomoro@197
|
203
|
giuliomoro@181
|
204 /**
|
giuliomoro@181
|
205 * Open the specified input Midi port and start reading from it.
|
giuliomoro@181
|
206 * @param port Midi port to open
|
giuliomoro@181
|
207 * @return 1 on success, -1 on failure
|
giuliomoro@181
|
208 */
|
giuliomoro@181
|
209 int readFrom(int port);
|
giuliomoro@181
|
210 /**
|
giuliomoro@181
|
211 * Open the specified output Midi port and prepares to write to it.
|
giuliomoro@181
|
212 * @param port Midi port to open
|
giuliomoro@181
|
213 * @return 1 on success, -1 on failure
|
giuliomoro@181
|
214 */
|
giuliomoro@181
|
215 int writeTo(int port);
|
giuliomoro@181
|
216
|
giuliomoro@181
|
217 /**
|
giuliomoro@191
|
218 * Get received midi bytes, one at a time.
|
giuliomoro@181
|
219 * @return -1 if no new byte is available, -2 on error,
|
giuliomoro@181
|
220 * the oldest not yet retrieved midi byte otherwise
|
giuliomoro@181
|
221 */
|
giuliomoro@181
|
222 int getInput();
|
giuliomoro@181
|
223
|
giuliomoro@181
|
224 /**
|
giuliomoro@181
|
225 * Writes a Midi byte to the output port
|
giuliomoro@181
|
226 * @param byte the Midi byte to write
|
giuliomoro@181
|
227 * @return 1 on success, -1 on error
|
giuliomoro@181
|
228 */
|
giuliomoro@181
|
229 int writeOutput(midi_byte_t byte);
|
giuliomoro@181
|
230
|
giuliomoro@181
|
231 /**
|
giuliomoro@181
|
232 * Writes Midi bytes to the output port
|
giuliomoro@181
|
233 * @param bytes an array of bytes to be written
|
giuliomoro@181
|
234 * @param length number of bytes to write
|
giuliomoro@181
|
235 * @return 1 on success, -1 on error
|
giuliomoro@181
|
236 */
|
giuliomoro@191
|
237 int writeOutput(midi_byte_t* bytes, unsigned int length);
|
giuliomoro@197
|
238 /**
|
giuliomoro@197
|
239 * Gives access to the midi parser, if it has been activated.
|
giuliomoro@197
|
240 *
|
giuliomoro@197
|
241 * @return a pointer to the midi parser if active, zero otherwise
|
giuliomoro@197
|
242 */
|
giuliomoro@197
|
243 MidiParser* getMidiParser();
|
giuliomoro@181
|
244 virtual ~Midi();
|
giuliomoro@181
|
245 static void midiInputLoop();
|
giuliomoro@191
|
246 static void midiOutputLoop();
|
giuliomoro@181
|
247 static bool staticConstructed;
|
giuliomoro@181
|
248 static void staticConstructor();
|
giuliomoro@181
|
249 private:
|
giuliomoro@181
|
250 void readInputLoop();
|
giuliomoro@191
|
251 void writeOutputLoop();
|
giuliomoro@181
|
252 int outputPort;
|
giuliomoro@181
|
253 int inputPort;
|
giuliomoro@181
|
254 std::vector<midi_byte_t> inputBytes;
|
giuliomoro@181
|
255 unsigned int inputBytesWritePointer;
|
giuliomoro@181
|
256 unsigned int inputBytesReadPointer;
|
giuliomoro@181
|
257 std::vector<midi_byte_t> outputBytes;
|
giuliomoro@191
|
258 unsigned int outputBytesWritePointer;
|
giuliomoro@191
|
259 unsigned int outputBytesReadPointer;
|
giuliomoro@197
|
260 MidiParser* inputParser;
|
giuliomoro@197
|
261 bool parserEnabled;
|
giuliomoro@191
|
262 static std::vector<Midi*> objAddrs[2];
|
giuliomoro@181
|
263 static AuxiliaryTask midiInputTask;
|
giuliomoro@181
|
264 static AuxiliaryTask midiOutputTask;
|
giuliomoro@181
|
265 };
|
giuliomoro@181
|
266
|
giuliomoro@181
|
267
|
giuliomoro@181
|
268 #endif /* MIDI_H_ */
|