drumstick  1.0.0
midiparser.cpp
1 /*
2  Drumstick MIDI realtime input-output
3  Copyright (C) 2009-2014 Pedro Lopez-Cabanillas <plcl@users.sf.net>
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License along
16  with this program; if not, write to the Free Software Foundation, Inc.,
17  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19 
20 #include <QDebug>
21 #include "midiparser.h"
22 #include "rtmidioutput.h"
23 
24 namespace drumstick {
25 namespace rt {
26 
27 class MIDIParser::MIDIParserPrivate {
28 public:
29  MIDIParserPrivate(): m_in(0), m_out(0), m_running_status(0) { }
30  MIDIInput *m_in;
31  MIDIOutput *m_out;
32  unsigned char m_running_status;
33  QByteArray m_buffer;
34 
35  void processNoteOff(const int chan, const int note, const int vel)
36  {
37  //qDebug() << "NoteOff(" << hex << chan << "," << note << "," << vel << ")";
38  if (m_in != 0 && m_in->isEnabledMIDIThru() && m_out != 0) {
39  m_out->sendNoteOff(chan, note, vel);
40  }
41  if (m_in != 0) {
42  m_in->emit midiNoteOff(chan, note, vel);
43  }
44  }
45 
46  void processNoteOn(const int chan, const int note, const int vel)
47  {
48  //qDebug() << "NoteOn(" << hex << chan << "," << note << "," << vel << ")";
49  if (m_in != 0 && m_in->isEnabledMIDIThru() && m_out != 0) {
50  m_out->sendNoteOn(chan, note, vel);
51  }
52  if (m_in != 0) {
53  m_in->emit midiNoteOn(chan, note, vel);
54  }
55  }
56 
57  void processKeyPressure(const int chan, const int note, const int value)
58  {
59  //qDebug() << "KeyPressure(" << hex << chan << "," << note << "," << value << ")";
60  if (m_in != 0 && m_in->isEnabledMIDIThru() && m_out != 0) {
61  m_out->sendKeyPressure(chan, note, value);
62  }
63  if (m_in != 0) {
64  m_in->emit midiKeyPressure(chan, note, value);
65  }
66  }
67 
68  void processController(const int chan, const int control, const int value)
69  {
70  //qDebug() << "Controller(" << chan << "," << control << "," << value << ")";
71  if (m_in != 0 && m_in->isEnabledMIDIThru() && m_out != 0) {
72  m_out->sendController(chan, control, value);
73  }
74  if (m_in != 0) {
75  m_in->emit midiController(chan, control, value);
76  }
77  }
78 
79  void processProgram(const int chan, const int program)
80  {
81  //qDebug() << "Program(" << hex << chan << "," << program << ")";
82  if (m_in != 0 && m_in->isEnabledMIDIThru() && m_out != 0) {
83  m_out->sendProgram(chan, program);
84  }
85  if (m_in != 0) {
86  m_in->emit midiProgram(chan, program);
87  }
88  }
89 
90  void processChannelPressure(const int chan, const int value)
91  {
92  //qDebug() << "ChannelPressure(" << chan << "," << value << ")";
93  if (m_in != 0 && m_in->isEnabledMIDIThru() && m_out != 0) {
94  m_out->sendChannelPressure(chan, value);
95  }
96  if (m_in != 0) {
97  m_in->emit midiChannelPressure(chan, value);
98  }
99  }
100 
101  void processPitchBend(const int chan, const int value)
102  {
103  //qDebug() << "PitchBend(" << chan << "," << value << ")";
104  if (m_in != 0 && m_in->isEnabledMIDIThru() && m_out != 0) {
105  m_out->sendPitchBend(chan, value);
106  }
107  if (m_in != 0) {
108  m_in->emit midiPitchBend(chan, value);
109  }
110  }
111 
112  void processSysex(const QByteArray &data)
113  {
114  //qDebug() << "Sysex(" << data.toHex() << ")";
115  if (m_in != 0 && m_in->isEnabledMIDIThru() && m_out != 0) {
116  m_out->sendSysex(data);
117  }
118  if (m_in != 0) {
119  m_in->emit midiSysex(data);
120  }
121  }
122 
123  void processSystemCommon(const int status)
124  {
125  //qDebug() << "common SystemMsg(" << hex << status << ")";
126  if (m_in != 0 && m_in->isEnabledMIDIThru() && m_out != 0) {
127  m_out->sendSystemMsg(status);
128  }
129  if (m_in != 0) {
130  m_in->emit midiSystemCommon(status);
131 
132  }
133  }
134 
135  void processSystemRealtime(unsigned char byte)
136  {
137  //qDebug() << "realtime SystemMsg(" << hex << byte << ")";
138  if (m_in != 0 && m_in->isEnabledMIDIThru() && m_out != 0) {
139  m_out->sendSystemMsg(byte);
140  }
141  if (m_in != 0) {
142  m_in->emit midiSystemRealtime(byte);
143  }
144  }
145 
146 };
147 
148 MIDIParser::MIDIParser(MIDIInput *in, QObject *parent) :
149  QObject(parent),
150  d(new MIDIParser::MIDIParserPrivate)
151 {
152  d->m_buffer.clear();
153  d->m_in = in;
154 }
155 
156 MIDIParser::~MIDIParser()
157 {
158  delete d;
159 }
160 
161 void MIDIParser::setMIDIThruDevice(MIDIOutput *device)
162 {
163  d->m_out = device;
164 }
165 
166 void MIDIParser::parse(unsigned char byte)
167 {
168  unsigned char status;
169  int chan, m1, m2, v;
170 
171  if (byte >= MIDI_STATUS_REALTIME) { // system realtime
172  d->processSystemRealtime(byte);
173  return;
174  } else
175  d->m_buffer.append(byte);
176 
177  while(d->m_buffer.length() > 0) {
178  status = static_cast<unsigned>(d->m_buffer.at(0));
179  if (status == MIDI_STATUS_SYSEX) { // system exclusive
180  if (byte == MIDI_STATUS_ENDSYSEX) {
181  d->processSysex(d->m_buffer);
182  d->m_buffer.clear();
183  } else
184  return;
185  } else
186  if (status > MIDI_STATUS_SYSEX &&
187  status < MIDI_STATUS_ENDSYSEX) { // system common
188  d->processSystemCommon(status);
189  d->m_buffer.clear();
190  } else
191  if (status < MIDI_STATUS_SYSEX &&
192  status >= MIDI_STATUS_NOTEOFF) { // channel message
193  d->m_running_status = status;
194  chan = status & MIDI_CHANNEL_MASK;
195  status = status & MIDI_STATUS_MASK;
196  switch(status) {
197  case MIDI_STATUS_NOTEOFF:
198  if (d->m_buffer.length() < 3)
199  return;
200  m1 = static_cast<unsigned>(d->m_buffer.at(1));
201  m2 = static_cast<unsigned>(d->m_buffer.at(2));
202  d->processNoteOff(chan, m1, m2);
203  break;
204  case MIDI_STATUS_NOTEON:
205  if (d->m_buffer.length() < 3)
206  return;
207  m1 = static_cast<unsigned>(d->m_buffer.at(1));
208  m2 = static_cast<unsigned>(d->m_buffer.at(2));
209  d->processNoteOn(chan, m1, m2);
210  break;
211  case MIDI_STATUS_KEYPRESURE:
212  if (d->m_buffer.length() < 3)
213  return;
214  m1 = static_cast<unsigned>(d->m_buffer.at(1));
215  m2 = static_cast<unsigned>(d->m_buffer.at(2));
216  d->processKeyPressure(chan, m1, m2);
217  break;
218  case MIDI_STATUS_CONTROLCHANGE:
219  if (d->m_buffer.length() < 3)
220  return;
221  m1 = static_cast<unsigned>(d->m_buffer.at(1));
222  m2 = static_cast<unsigned>(d->m_buffer.at(2));
223  d->processController(chan, m1, m2);
224  break;
225  case MIDI_STATUS_PROGRAMCHANGE:
226  if (d->m_buffer.length() < 2)
227  return;
228  m1 = static_cast<unsigned>(d->m_buffer.at(1));
229  d->processProgram(chan, m1);
230  break;
231  case MIDI_STATUS_CHANNELPRESSURE:
232  if (d->m_buffer.length() < 2)
233  return;
234  m1 = static_cast<unsigned>(d->m_buffer.at(1));
235  d->processChannelPressure(chan, m1);
236  break;
237  case MIDI_STATUS_PITCHBEND:
238  if (d->m_buffer.length() < 3)
239  return;
240  m1 = static_cast<unsigned>(d->m_buffer.at(1));
241  m2 = static_cast<unsigned>(d->m_buffer.at(2));
242  v = m1 + m2 * 0x80 - 0x2000;
243  d->processPitchBend(chan, v);
244  break;
245  }
246  d->m_buffer.clear();
247  } else { // running status
248  d->m_buffer.insert(0, d->m_running_status);
249  }
250  }
251 }
252 
253 void MIDIParser::parse(QByteArray bytes)
254 {
255  foreach(unsigned char byte, bytes) {
256  parse(byte);
257  }
258 }
259 
260 }}
261 
The QObject class is the base class of all Qt objects.