1 /*
2  * MidiClient.cpp - base-class for MIDI-clients like ALSA-sequencer-client
3  *
4  * Copyright (c) 2005-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
5  * This file partly contains code from Fluidsynth, Peter Hanappe
6  *
7  * This file is part of LMMS - https://lmms.io
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public
20  * License along with this program (see COPYING); if not, write to the
21  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301 USA.
23  *
24  */
25 
26 #include "MidiClient.h"
27 #include "MidiPort.h"
28 #include "Note.h"
29 
30 
MidiClient()31 MidiClient::MidiClient()
32 {
33 }
34 
35 
36 
37 
~MidiClient()38 MidiClient::~MidiClient()
39 {
40 	//TODO: noteOffAll(); / clear all ports
41 	for (MidiPort* port : m_midiPorts)
42 	{
43 		port->invalidateCilent();
44 	}
45 }
46 
47 
48 
49 
applyPortMode(MidiPort *)50 void MidiClient::applyPortMode( MidiPort* )
51 {
52 }
53 
54 
55 
56 
applyPortName(MidiPort *)57 void MidiClient::applyPortName( MidiPort* )
58 {
59 }
60 
61 
62 
63 
addPort(MidiPort * port)64 void MidiClient::addPort( MidiPort* port )
65 {
66 	m_midiPorts.push_back( port );
67 }
68 
69 
70 
71 
removePort(MidiPort * port)72 void MidiClient::removePort( MidiPort* port )
73 {
74 	if( ! port )
75 	{
76 		return;
77 	}
78 
79 	QVector<MidiPort *>::Iterator it =
80 		qFind( m_midiPorts.begin(), m_midiPorts.end(), port );
81 	if( it != m_midiPorts.end() )
82 	{
83 		m_midiPorts.erase( it );
84 	}
85 }
86 
87 
88 
89 
subscribeReadablePort(MidiPort *,const QString &,bool)90 void MidiClient::subscribeReadablePort( MidiPort*, const QString& , bool )
91 {
92 }
93 
94 
95 
96 
subscribeWritablePort(MidiPort *,const QString &,bool)97 void MidiClient::subscribeWritablePort( MidiPort* , const QString& , bool )
98 {
99 }
100 
101 
102 
103 
104 
105 
106 
MidiClientRaw()107 MidiClientRaw::MidiClientRaw()
108 {
109 }
110 
111 
112 
113 
~MidiClientRaw()114 MidiClientRaw::~MidiClientRaw()
115 {
116 }
117 
118 
119 
120 
parseData(const unsigned char c)121 void MidiClientRaw::parseData( const unsigned char c )
122 {
123 	/*********************************************************************/
124 	/* 'Process' system real-time messages                               */
125 	/*********************************************************************/
126 	/* There are not too many real-time messages that are of interest here.
127 	 * They can occur anywhere, even in the middle of a noteon message!
128 	 * Real-time range: 0xF8 .. 0xFF
129 	 * Note: Real-time does not affect (running) status.
130 	 */
131 	if( c >= 0xF8 )
132 	{
133 		if( c == MidiSystemReset )
134 		{
135 			m_midiParseData.m_midiEvent.setType( MidiSystemReset );
136 			m_midiParseData.m_status = 0;
137 			processParsedEvent();
138 		}
139 		return;
140 	}
141 
142 	/*********************************************************************/
143 	/* 'Process' system common messages (again, just skip them)          */
144 	/*********************************************************************/
145 	/* There are no system common messages that are of interest here.
146 	 * System common range: 0xF0 .. 0xF7
147 	 */
148 	if( c > 0xF0 )
149 	{
150 	/* MIDI spec say: To ignore a non-real-time message, just discard all
151 	 * data up to the next status byte.  And our parser will ignore data
152 	 * that is received without a valid status.
153 	 * Note: system common cancels running status. */
154 		m_midiParseData.m_status = 0;
155 		return;
156 	}
157 
158 	/*********************************************************************/
159 	/* Process voice category messages:                                  */
160 	/*********************************************************************/
161 	/* Now that we have handled realtime and system common messages, only
162 	 * voice messages are left.
163 	 * Only a status byte has bit # 7 set.
164 	 * So no matter the status of the parser (in case we have lost sync),
165 	 * as soon as a byte >= 0x80 comes in, we are dealing with a status byte
166 	 * and start a new event.
167 	 */
168 	if( c & 0x80 )
169 	{
170 		m_midiParseData.m_channel = c & 0x0F;
171 		m_midiParseData.m_status = c & 0xF0;
172 		/* The event consumes x bytes of data...
173 					(subtract 1 for the status byte) */
174 		m_midiParseData.m_bytesTotal = eventLength( m_midiParseData.m_status ) - 1;
175 		/* of which we have read 0 at this time. */
176 		m_midiParseData.m_bytes = 0;
177 		return;
178 	}
179 
180 	/*********************************************************************/
181 	/* Process data                                                      */
182 	/*********************************************************************/
183 	/* If we made it this far, then the received char belongs to the data
184 	 * of the last event. */
185 	if( m_midiParseData.m_status == 0 )
186 	{
187 		/* We are not interested in the event currently received.
188 							Discard the data. */
189 		return;
190 	}
191 
192 	/* Store the first couple of bytes */
193 	if( m_midiParseData.m_bytes < RAW_MIDI_PARSE_BUF_SIZE )
194 	{
195 		m_midiParseData.m_buffer[m_midiParseData.m_bytes] = c;
196 	}
197 	++m_midiParseData.m_bytes;
198 
199 	/* Do we still need more data to get this event complete? */
200 	if( m_midiParseData.m_bytes < m_midiParseData.m_bytesTotal )
201 	{
202 		return;
203 	}
204 
205 	/*********************************************************************/
206 	/* Send the event                                                    */
207 	/*********************************************************************/
208 	/* The event is ready-to-go.  About 'running status':
209 	 *
210 	 * The MIDI protocol has a built-in compression mechanism. If several
211 	 * similar events are sent in-a-row, for example note-ons, then the
212 	 * event type is only sent once. For this case, the last event type
213 	 * (status) is remembered.
214 	 * We simply keep the status as it is, just reset the parameter counter.
215 	 * If another status byte comes in, it will overwrite the status.
216 	 */
217 	m_midiParseData.m_midiEvent.setType( static_cast<MidiEventTypes>( m_midiParseData.m_status ) );
218 	m_midiParseData.m_midiEvent.setChannel( m_midiParseData.m_channel );
219 	m_midiParseData.m_bytes = 0; /* Related to running status! */
220 	switch( m_midiParseData.m_midiEvent.type() )
221 	{
222 		case MidiNoteOff:
223 		case MidiNoteOn:
224 		case MidiKeyPressure:
225 		case MidiChannelPressure:
226 			m_midiParseData.m_midiEvent.setKey( m_midiParseData.m_buffer[0] - KeysPerOctave );
227 			m_midiParseData.m_midiEvent.setVelocity( m_midiParseData.m_buffer[1] );
228 			break;
229 
230 		case MidiProgramChange:
231 			m_midiParseData.m_midiEvent.setKey( m_midiParseData.m_buffer[0] );
232 			m_midiParseData.m_midiEvent.setVelocity( m_midiParseData.m_buffer[1] );
233 			break;
234 
235 		case MidiControlChange:
236 			m_midiParseData.m_midiEvent.setControllerNumber( m_midiParseData.m_buffer[0] );
237 			m_midiParseData.m_midiEvent.setControllerValue(  m_midiParseData.m_buffer[1] );
238 			break;
239 
240 		case MidiPitchBend:
241 			// Pitch-bend is transmitted with 14-bit precision.
242 			// Note: '|' does here the same as '+' (no common bits),
243 			// but might be faster
244 			m_midiParseData.m_midiEvent.setPitchBend( ( m_midiParseData.m_buffer[1] * 128 ) | m_midiParseData.m_buffer[0] );
245 			break;
246 
247 		default:
248 			// Unlikely
249 			return;
250 	}
251 
252 	processParsedEvent();
253 }
254 
255 
256 
257 
processParsedEvent()258 void MidiClientRaw::processParsedEvent()
259 {
260 	for( int i = 0; i < m_midiPorts.size(); ++i )
261 	{
262 		m_midiPorts[i]->processInEvent( m_midiParseData.m_midiEvent );
263 	}
264 }
265 
266 
267 
268 
processOutEvent(const MidiEvent & event,const MidiTime &,const MidiPort * port)269 void MidiClientRaw::processOutEvent( const MidiEvent& event, const MidiTime & , const MidiPort* port )
270 {
271 	// TODO: also evaluate _time and queue event if necessary
272 	switch( event.type() )
273 	{
274 		case MidiNoteOn:
275 		case MidiNoteOff:
276 		case MidiKeyPressure:
277 			sendByte( event.type() | event.channel() );
278 			sendByte( event.key() + KeysPerOctave );
279 			sendByte( event.velocity() );
280 			break;
281 
282 		default:
283 			qWarning( "MidiClientRaw: unhandled MIDI-event %d\n",
284 							(int) event.type() );
285 			break;
286 	}
287 }
288 
289 
290 
291 
292 
293 
294 // Taken from Nagano Daisuke's USB-MIDI driver
295 static const unsigned char REMAINS_F0F6[] =
296 {
297 	0,	/* 0xF0 */
298 	2,	/* 0XF1 */
299 	3,	/* 0XF2 */
300 	2,	/* 0XF3 */
301 	2,	/* 0XF4 (Undefined by MIDI Spec, and subject to change) */
302 	2,	/* 0XF5 (Undefined by MIDI Spec, and subject to change) */
303 	1	/* 0XF6 */
304 } ;
305 
306 static const unsigned char REMAINS_80E0[] =
307 {
308 	3,	/* 0x8X Note Off */
309 	3,	/* 0x9X Note On */
310 	3,	/* 0xAX Poly-key pressure */
311 	3,	/* 0xBX Control Change */
312 	2,	/* 0xCX Program Change */
313 	2,	/* 0xDX Channel pressure */
314 	3 	/* 0xEX PitchBend Change */
315 } ;
316 
317 
318 
319 // Returns the length of the MIDI message starting with _event.
320 // Taken from Nagano Daisuke's USB-MIDI driver
eventLength(const unsigned char event)321 int MidiClientRaw::eventLength( const unsigned char event )
322 {
323 	if ( event < 0xF0 )
324 	{
325 		return REMAINS_80E0[( ( event - 0x80 ) >> 4 ) & 0x0F];
326 	}
327 	else if ( event < 0xF7 )
328 	{
329 		return REMAINS_F0F6[event - 0xF0];
330 	}
331 	return 1;
332 }
333 
334 
335