]>
git.gir.st - tmk_keyboard.git/blob - tmk_core/tool/mbed/mbed-sdk/libraries/USBHost/USBHostMIDI/USBHostMIDI.cpp
1 /* Copyright (c) 2014 mbed.org, MIT License
3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
4 * and associated documentation files (the "Software"), to deal in the Software without
5 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
6 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
7 * Software is furnished to do so, subject to the following conditions:
9 * The above copyright notice and this permission notice shall be included in all copies or
10 * substantial portions of the Software.
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 #include "USBHostMIDI.h"
25 #define SET_LINE_CODING 0x20
27 USBHostMIDI :: USBHostMIDI () {
28 host
= USBHost :: getHostInst ();
34 void USBHostMIDI :: init () {
38 dev_connected
= false ;
40 midi_device_found
= false ;
44 bool USBHostMIDI :: connected () {
48 bool USBHostMIDI :: connect () {
53 for ( uint8_t i
= 0 ; i
< MAX_DEVICE_CONNECTED
; i
++) {
54 if (( dev
= host
-> getDevice ( i
)) != NULL
) {
56 USB_DBG ( "Trying to connect MIDI device \r\n " );
58 if ( host
-> enumerate ( dev
, this )) {
62 if ( midi_device_found
) {
63 bulk_in
= dev
-> getEndpoint ( midi_intf
, BULK_ENDPOINT
, IN
);
64 bulk_out
= dev
-> getEndpoint ( midi_intf
, BULK_ENDPOINT
, OUT
);
66 if (! bulk_in
|| ! bulk_out
) {
70 USB_INFO ( "New MIDI device: VID:%04x PID:%04x [dev: %p - intf: %d]" , dev
-> getVid (), dev
-> getPid (), dev
, midi_intf
);
71 dev
-> setName ( "MIDI" , midi_intf
);
72 host
-> registerDriver ( dev
, midi_intf
, this , & USBHostMIDI :: init
);
74 size_bulk_in
= bulk_in
-> getSize ();
75 size_bulk_out
= bulk_out
-> getSize ();
77 bulk_in
-> attach ( this , & USBHostMIDI :: rxHandler
);
79 host
-> bulkRead ( dev
, bulk_in
, buf
, size_bulk_in
, false );
90 void USBHostMIDI :: rxHandler () {
93 int length
= bulk_in
-> getLengthTransferred ();
94 if ( bulk_in
-> getState () == USB_TYPE_IDLE
|| bulk_in
-> getState () == USB_TYPE_FREE
) {
95 // MIDI event handling
96 for ( int i
= 0 ; i
< length
; i
+= 4 ) {
98 // length shortage, ignored.
102 // read each four bytes
104 // process MIDI message
105 // switch by code index number
106 switch ( midi
[ 0 ] & 0xf ) {
107 case 0 : // miscellaneous function codes
108 miscellaneousFunctionCode ( midi
[ 1 ], midi
[ 2 ], midi
[ 3 ]);
110 case 1 : // cable events
111 cableEvent ( midi
[ 1 ], midi
[ 2 ], midi
[ 3 ]);
113 case 2 : // two bytes system common messages
114 systemCommonTwoBytes ( midi
[ 1 ], midi
[ 2 ]);
116 case 3 : // three bytes system common messages
117 systemCommonThreeBytes ( midi
[ 1 ], midi
[ 2 ], midi
[ 3 ]);
119 case 4 : // SysEx starts or continues
120 sysExBuffer
[ sysExBufferPos
++] = midi
[ 1 ];
121 if ( sysExBufferPos
>= 64 ) {
122 systemExclusive ( sysExBuffer
, sysExBufferPos
, true );
125 sysExBuffer
[ sysExBufferPos
++] = midi
[ 2 ];
126 if ( sysExBufferPos
>= 64 ) {
127 systemExclusive ( sysExBuffer
, sysExBufferPos
, true );
130 sysExBuffer
[ sysExBufferPos
++] = midi
[ 3 ];
131 // SysEx continues. don't send
133 case 5 : // SysEx ends with single byte
134 sysExBuffer
[ sysExBufferPos
++] = midi
[ 1 ];
135 systemExclusive ( sysExBuffer
, sysExBufferPos
, false );
138 case 6 : // SysEx ends with two bytes
139 sysExBuffer
[ sysExBufferPos
++] = midi
[ 1 ];
140 if ( sysExBufferPos
>= 64 ) {
141 systemExclusive ( sysExBuffer
, sysExBufferPos
, true );
144 sysExBuffer
[ sysExBufferPos
++] = midi
[ 2 ];
145 systemExclusive ( sysExBuffer
, sysExBufferPos
, false );
148 case 7 : // SysEx ends with three bytes
149 sysExBuffer
[ sysExBufferPos
++] = midi
[ 1 ];
150 if ( sysExBufferPos
>= 64 ) {
151 systemExclusive ( sysExBuffer
, sysExBufferPos
, true );
154 sysExBuffer
[ sysExBufferPos
++] = midi
[ 2 ];
155 if ( sysExBufferPos
>= 64 ) {
156 systemExclusive ( sysExBuffer
, sysExBufferPos
, true );
159 sysExBuffer
[ sysExBufferPos
++] = midi
[ 3 ];
160 systemExclusive ( sysExBuffer
, sysExBufferPos
, false );
164 noteOff ( midi
[ 1 ] & 0xf , midi
[ 2 ], midi
[ 3 ]);
168 noteOn ( midi
[ 1 ] & 0xf , midi
[ 2 ], midi
[ 3 ]);
170 noteOff ( midi
[ 1 ] & 0xf , midi
[ 2 ], midi
[ 3 ]);
174 polyKeyPress ( midi
[ 1 ] & 0xf , midi
[ 2 ], midi
[ 3 ]);
177 controlChange ( midi
[ 1 ] & 0xf , midi
[ 2 ], midi
[ 3 ]);
180 programChange ( midi
[ 1 ] & 0xf , midi
[ 2 ]);
183 channelPressure ( midi
[ 1 ] & 0xf , midi
[ 2 ]);
186 pitchBend ( midi
[ 1 ] & 0xf , midi
[ 2 ] | ( midi
[ 3 ] << 7 ));
194 // read another message
195 host
-> bulkRead ( dev
, bulk_in
, buf
, size_bulk_in
, false );
200 bool USBHostMIDI :: sendMidiBuffer ( uint8_t data0
, uint8_t data1
, uint8_t data2
, uint8_t data3
) {
208 if ( host
-> bulkWrite ( dev
, bulk_out
, ( uint8_t *) midi
, 4 ) == USB_TYPE_OK
) {
215 bool USBHostMIDI :: sendMiscellaneousFunctionCode ( uint8_t data1
, uint8_t data2
, uint8_t data3
) {
216 return sendMidiBuffer ( 0 , data1
, data2
, data3
);
219 bool USBHostMIDI :: sendCableEvent ( uint8_t data1
, uint8_t data2
, uint8_t data3
) {
220 return sendMidiBuffer ( 1 , data1
, data2
, data3
);
223 bool USBHostMIDI :: sendSystemCommmonTwoBytes ( uint8_t data1
, uint8_t data2
) {
224 return sendMidiBuffer ( 2 , data1
, data2
, 0 );
227 bool USBHostMIDI :: sendSystemCommmonThreeBytes ( uint8_t data1
, uint8_t data2
, uint8_t data3
) {
228 return sendMidiBuffer ( 3 , data1
, data2
, 0 );
231 bool USBHostMIDI :: sendSystemExclusive ( uint8_t * buffer
, int length
) {
236 for ( int i
= 0 ; i
< length
; i
+= 48 ) {
237 if ( i
+ 48 >= length
) {
238 // contains last data
239 midiLength
= ((( length
- i
) + 2 ) / 3 ) * 4 ;
240 for ( int pos
= i
; pos
< length
; pos
+= 3 ) {
241 midiPos
= ( pos
+ 2 ) / 3 * 4 ;
242 if ( pos
+ 3 >= length
) {
247 midi
[ midiPos
+ 1 ] = buffer
[ pos
];
248 midi
[ midiPos
+ 2 ] = buffer
[ pos
+ 1 ];
249 midi
[ midiPos
+ 3 ] = buffer
[ pos
+ 2 ];
253 midi
[ midiPos
+ 1 ] = buffer
[ pos
];
254 midi
[ midiPos
+ 2 ] = 0 ;
255 midi
[ midiPos
+ 3 ] = 0 ;
259 midi
[ midiPos
+ 1 ] = buffer
[ pos
];
260 midi
[ midiPos
+ 2 ] = buffer
[ pos
+ 1 ];
261 midi
[ midiPos
+ 3 ] = 0 ;
267 midi
[ midiPos
+ 1 ] = buffer
[ pos
];
268 midi
[ midiPos
+ 2 ] = buffer
[ pos
+ 1 ];
269 midi
[ midiPos
+ 3 ] = buffer
[ pos
+ 2 ];
275 for ( int pos
= i
; pos
< length
; pos
+= 3 ) {
276 midiPos
= ( pos
+ 2 ) / 3 * 4 ;
278 midi
[ midiPos
+ 1 ] = buffer
[ pos
];
279 midi
[ midiPos
+ 2 ] = buffer
[ pos
+ 1 ];
280 midi
[ midiPos
+ 3 ] = buffer
[ pos
+ 2 ];
284 if ( host
-> bulkWrite ( dev
, bulk_out
, ( uint8_t *) midi
, midiLength
) != USB_TYPE_OK
) {
293 bool USBHostMIDI :: sendNoteOff ( uint8_t channel
, uint8_t note
, uint8_t velocity
) {
294 return sendMidiBuffer ( 8 , channel
& 0xf | 0x80 , note
& 0x7f , velocity
& 0x7f );
297 bool USBHostMIDI :: sendNoteOn ( uint8_t channel
, uint8_t note
, uint8_t velocity
) {
298 return sendMidiBuffer ( 9 , channel
& 0xf | 0x90 , note
& 0x7f , velocity
& 0x7f );
301 bool USBHostMIDI :: sendPolyKeyPress ( uint8_t channel
, uint8_t note
, uint8_t pressure
) {
302 return sendMidiBuffer ( 10 , channel
& 0xf | 0xa0 , note
& 0x7f , pressure
& 0x7f );
305 bool USBHostMIDI :: sendControlChange ( uint8_t channel
, uint8_t key
, uint8_t value
) {
306 return sendMidiBuffer ( 11 , channel
& 0xf | 0xb0 , key
& 0x7f , value
& 0x7f );
309 bool USBHostMIDI :: sendProgramChange ( uint8_t channel
, uint8_t program
) {
310 return sendMidiBuffer ( 12 , channel
& 0xf | 0xc0 , program
& 0x7f , 0 );
313 bool USBHostMIDI :: sendChannelPressure ( uint8_t channel
, uint8_t pressure
) {
314 return sendMidiBuffer ( 13 , channel
& 0xf | 0xd0 , pressure
& 0x7f , 0 );
317 bool USBHostMIDI :: sendPitchBend ( uint8_t channel
, uint16_t value
) {
318 return sendMidiBuffer ( 14 , channel
& 0xf | 0xe0 , value
& 0x7f , ( value
>> 7 ) & 0x7f );
321 bool USBHostMIDI :: sendSingleByte ( uint8_t data
) {
322 return sendMidiBuffer ( 15 , data
, 0 , 0 );
325 /*virtual*/ void USBHostMIDI :: setVidPid ( uint16_t vid
, uint16_t pid
)
327 // we don't check VID/PID for this driver
330 /*virtual*/ bool USBHostMIDI :: parseInterface ( uint8_t intf_nb
, uint8_t intf_class
, uint8_t intf_subclass
, uint8_t intf_protocol
) //Must return true if the interface should be parsed
332 // USB MIDI class/subclass
333 if (( midi_intf
== - 1 ) &&
334 ( intf_class
== AUDIO_CLASS
) &&
335 ( intf_subclass
== 0x03 )) {
340 // vendor specific device
341 if (( midi_intf
== - 1 ) &&
342 ( intf_class
== 0xff ) &&
343 ( intf_subclass
== 0x03 )) {
351 /*virtual*/ bool USBHostMIDI :: useEndpoint ( uint8_t intf_nb
, ENDPOINT_TYPE type
, ENDPOINT_DIRECTION dir
) //Must return true if the endpoint will be used
353 if ( intf_nb
== midi_intf
) {
354 if ( type
== BULK_ENDPOINT
) {
355 midi_device_found
= true ;