drumstick  1.0.2
midiparser.cpp
00001 /*
00002     Drumstick MIDI realtime input-output
00003     Copyright (C) 2009-2015 Pedro Lopez-Cabanillas <plcl@users.sf.net>
00004 
00005     This program is free software; you can redistribute it and/or modify
00006     it under the terms of the GNU General Public License as published by
00007     the Free Software Foundation; either version 2 of the License, or
00008     (at your option) any later version.
00009 
00010     This program is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License along
00016     with this program; if not, write to the Free Software Foundation, Inc.,
00017     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00018 */
00019 
00020 #include <QDebug>
00021 #include "midiparser.h"
00022 #include "rtmidioutput.h"
00023 
00024 namespace drumstick {
00025 namespace rt {
00026 
00027 class MIDIParser::MIDIParserPrivate {
00028 public:
00029     MIDIParserPrivate(): m_in(0), m_out(0), m_running_status(0) { }
00030     MIDIInput *m_in;
00031     MIDIOutput *m_out;
00032     unsigned char m_running_status;
00033     QByteArray m_buffer;
00034 
00035     void processNoteOff(const int chan, const int note, const int vel)
00036     {
00037         //qDebug() << "NoteOff(" << hex << chan << "," << note << "," << vel << ")";
00038         if (m_in != 0 && m_in->isEnabledMIDIThru() && m_out != 0) {
00039             m_out->sendNoteOff(chan, note, vel);
00040         }
00041         if (m_in != 0) {
00042             m_in->emit midiNoteOff(chan, note, vel);
00043         }
00044     }
00045 
00046     void processNoteOn(const int chan, const int note, const int vel)
00047     {
00048         //qDebug() << "NoteOn(" << hex << chan << "," << note << "," << vel << ")";
00049         if (m_in != 0 && m_in->isEnabledMIDIThru() && m_out != 0) {
00050             m_out->sendNoteOn(chan, note, vel);
00051         }
00052         if (m_in != 0) {
00053             m_in->emit midiNoteOn(chan, note, vel);
00054         }
00055     }
00056 
00057     void processKeyPressure(const int chan, const int note, const int value)
00058     {
00059         //qDebug() << "KeyPressure(" << hex << chan << "," << note << "," << value << ")";
00060         if (m_in != 0 && m_in->isEnabledMIDIThru() && m_out != 0) {
00061             m_out->sendKeyPressure(chan, note, value);
00062         }
00063         if (m_in != 0) {
00064             m_in->emit midiKeyPressure(chan, note, value);
00065         }
00066     }
00067 
00068     void processController(const int chan, const int control, const int value)
00069     {
00070         //qDebug() << "Controller(" << chan << "," << control << "," << value << ")";
00071         if (m_in != 0 && m_in->isEnabledMIDIThru() && m_out != 0) {
00072             m_out->sendController(chan, control, value);
00073         }
00074         if (m_in != 0) {
00075             m_in->emit midiController(chan, control, value);
00076         }
00077     }
00078 
00079     void processProgram(const int chan, const int program)
00080     {
00081         //qDebug() << "Program(" << hex << chan << "," << program << ")";
00082         if (m_in != 0 && m_in->isEnabledMIDIThru() && m_out != 0) {
00083             m_out->sendProgram(chan, program);
00084         }
00085         if (m_in != 0) {
00086             m_in->emit midiProgram(chan, program);
00087         }
00088     }
00089 
00090     void processChannelPressure(const int chan, const int value)
00091     {
00092         //qDebug() << "ChannelPressure(" << chan << "," << value << ")";
00093         if (m_in != 0 && m_in->isEnabledMIDIThru() && m_out != 0) {
00094             m_out->sendChannelPressure(chan, value);
00095         }
00096         if (m_in != 0) {
00097             m_in->emit midiChannelPressure(chan, value);
00098         }
00099     }
00100 
00101     void processPitchBend(const int chan, const int value)
00102     {
00103         //qDebug() << "PitchBend(" << chan << "," << value << ")";
00104         if (m_in != 0 && m_in->isEnabledMIDIThru() && m_out != 0) {
00105             m_out->sendPitchBend(chan, value);
00106         }
00107         if (m_in != 0) {
00108             m_in->emit midiPitchBend(chan, value);
00109         }
00110     }
00111 
00112     void processSysex(const QByteArray &data)
00113     {
00114         //qDebug() << "Sysex(" << data.toHex() << ")";
00115         if (m_in != 0 && m_in->isEnabledMIDIThru() && m_out != 0) {
00116             m_out->sendSysex(data);
00117         }
00118         if (m_in != 0) {
00119             m_in->emit midiSysex(data);
00120         }
00121     }
00122 
00123     void processSystemCommon(const int status)
00124     {
00125         //qDebug() << "common SystemMsg(" << hex << status << ")";
00126         if (m_in != 0 && m_in->isEnabledMIDIThru() && m_out != 0) {
00127             m_out->sendSystemMsg(status);
00128         }
00129         if (m_in != 0) {
00130             m_in->emit midiSystemCommon(status);
00131 
00132         }
00133     }
00134 
00135     void processSystemRealtime(unsigned char byte)
00136     {
00137         //qDebug() << "realtime SystemMsg(" << hex << byte << ")";
00138         if (m_in != 0 && m_in->isEnabledMIDIThru() && m_out != 0) {
00139             m_out->sendSystemMsg(byte);
00140         }
00141         if (m_in != 0) {
00142             m_in->emit midiSystemRealtime(byte);
00143         }
00144     }
00145 
00146 };
00147 
00148 MIDIParser::MIDIParser(MIDIInput *in, QObject *parent) :
00149     QObject(parent),
00150     d(new MIDIParser::MIDIParserPrivate)
00151 {
00152     d->m_buffer.clear();
00153     d->m_in = in;
00154 }
00155 
00156 MIDIParser::~MIDIParser()
00157 {
00158     delete d;
00159 }
00160 
00161 void MIDIParser::setMIDIThruDevice(MIDIOutput *device)
00162 {
00163     d->m_out = device;
00164 }
00165 
00166 void MIDIParser::parse(unsigned char byte)
00167 {
00168     unsigned char status;
00169     int chan, m1, m2, v;
00170 
00171     if (byte >= MIDI_STATUS_REALTIME) { // system realtime
00172         d->processSystemRealtime(byte);
00173         return;
00174     } else
00175         d->m_buffer.append(byte);
00176 
00177     while(d->m_buffer.length() > 0) {
00178         status = static_cast<unsigned>(d->m_buffer.at(0));
00179         if (status == MIDI_STATUS_SYSEX) { // system exclusive
00180             if (byte == MIDI_STATUS_ENDSYSEX) {
00181                 d->processSysex(d->m_buffer);
00182                 d->m_buffer.clear();
00183             } else
00184                 return;
00185         } else
00186         if (status > MIDI_STATUS_SYSEX &&
00187             status < MIDI_STATUS_ENDSYSEX) { // system common
00188             d->processSystemCommon(status);
00189             d->m_buffer.clear();
00190         } else
00191         if (status < MIDI_STATUS_SYSEX &&
00192             status >= MIDI_STATUS_NOTEOFF) { // channel message
00193             d->m_running_status = status;
00194             chan = status & MIDI_CHANNEL_MASK;
00195             status = status & MIDI_STATUS_MASK;
00196             switch(status) {
00197             case MIDI_STATUS_NOTEOFF:
00198                 if (d->m_buffer.length() < 3)
00199                     return;
00200                 m1 = static_cast<unsigned>(d->m_buffer.at(1));
00201                 m2 = static_cast<unsigned>(d->m_buffer.at(2));
00202                 d->processNoteOff(chan, m1, m2);
00203                 break;
00204             case MIDI_STATUS_NOTEON:
00205                 if (d->m_buffer.length() < 3)
00206                     return;
00207                 m1 = static_cast<unsigned>(d->m_buffer.at(1));
00208                 m2 = static_cast<unsigned>(d->m_buffer.at(2));
00209                 d->processNoteOn(chan, m1, m2);
00210                 break;
00211             case MIDI_STATUS_KEYPRESURE:
00212                 if (d->m_buffer.length() < 3)
00213                     return;
00214                 m1 = static_cast<unsigned>(d->m_buffer.at(1));
00215                 m2 = static_cast<unsigned>(d->m_buffer.at(2));
00216                 d->processKeyPressure(chan, m1, m2);
00217                 break;
00218             case MIDI_STATUS_CONTROLCHANGE:
00219                 if (d->m_buffer.length() < 3)
00220                     return;
00221                 m1 = static_cast<unsigned>(d->m_buffer.at(1));
00222                 m2 = static_cast<unsigned>(d->m_buffer.at(2));
00223                 d->processController(chan, m1, m2);
00224                 break;
00225             case MIDI_STATUS_PROGRAMCHANGE:
00226                 if (d->m_buffer.length() < 2)
00227                     return;
00228                 m1 = static_cast<unsigned>(d->m_buffer.at(1));
00229                 d->processProgram(chan, m1);
00230                 break;
00231             case MIDI_STATUS_CHANNELPRESSURE:
00232                 if (d->m_buffer.length() < 2)
00233                     return;
00234                 m1 = static_cast<unsigned>(d->m_buffer.at(1));
00235                 d->processChannelPressure(chan, m1);
00236                 break;
00237             case MIDI_STATUS_PITCHBEND:
00238                 if (d->m_buffer.length() < 3)
00239                     return;
00240                 m1 = static_cast<unsigned>(d->m_buffer.at(1));
00241                 m2 = static_cast<unsigned>(d->m_buffer.at(2));
00242                 v = m1 + m2 * 0x80 - 0x2000;
00243                 d->processPitchBend(chan, v);
00244                 break;
00245             }
00246             d->m_buffer.clear();
00247         } else { // running status
00248             d->m_buffer.insert(0, d->m_running_status);
00249         }
00250     }
00251 }
00252 
00253 void MIDIParser::parse(QByteArray bytes)
00254 {
00255     foreach(unsigned char byte, bytes) {
00256         parse(byte);
00257     }
00258 }
00259 
00260 }}
00261