| Chris@562 | 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */ | 
| Chris@562 | 2 | 
| Chris@562 | 3 /* | 
| Chris@562 | 4     Sonic Visualiser | 
| Chris@562 | 5     An audio file viewer and annotation editor. | 
| Chris@562 | 6     Centre for Digital Music, Queen Mary, University of London. | 
| Chris@562 | 7     This file copyright 2006-2009 Chris Cannam and QMUL. | 
| Chris@562 | 8 | 
| Chris@562 | 9     This program is free software; you can redistribute it and/or | 
| Chris@562 | 10     modify it under the terms of the GNU General Public License as | 
| Chris@562 | 11     published by the Free Software Foundation; either version 2 of the | 
| Chris@562 | 12     License, or (at your option) any later version.  See the file | 
| Chris@562 | 13     COPYING included with this distribution for more information. | 
| Chris@562 | 14 */ | 
| Chris@562 | 15 | 
| Chris@562 | 16 #include "MIDIInput.h" | 
| Chris@562 | 17 | 
| Chris@562 | 18 #include "rtmidi/RtMidi.h" | 
| Chris@562 | 19 | 
| Chris@1219 | 20 #include "system/System.h" | 
| Chris@608 | 21 | 
| Chris@567 | 22 MIDIInput::MIDIInput(QString name, FrameTimer *timer) : | 
| Chris@562 | 23     m_rtmidi(), | 
| Chris@567 | 24     m_frameTimer(timer), | 
| Chris@562 | 25     m_buffer(1023) | 
| Chris@562 | 26 { | 
| Chris@562 | 27     try { | 
| Chris@562 | 28         m_rtmidi = new RtMidiIn(name.toStdString()); | 
| Chris@562 | 29         m_rtmidi->setCallback(staticCallback, this); | 
| Chris@565 | 30         m_rtmidi->openPort(0, tr("Input").toStdString()); | 
| Chris@562 | 31     } catch (RtError e) { | 
| Chris@562 | 32         e.printMessage(); | 
| Chris@562 | 33         delete m_rtmidi; | 
| Chris@562 | 34         m_rtmidi = 0; | 
| Chris@562 | 35     } | 
| Chris@562 | 36 } | 
| Chris@562 | 37 | 
| Chris@562 | 38 MIDIInput::~MIDIInput() | 
| Chris@562 | 39 { | 
| Chris@562 | 40     delete m_rtmidi; | 
| Chris@562 | 41 } | 
| Chris@562 | 42 | 
| Chris@562 | 43 void | 
| Chris@562 | 44 MIDIInput::staticCallback(double timestamp, std::vector<unsigned char> *message, | 
| Chris@562 | 45                           void *userData) | 
| Chris@562 | 46 { | 
| Chris@562 | 47     ((MIDIInput *)userData)->callback(timestamp, message); | 
| Chris@562 | 48 } | 
| Chris@562 | 49 | 
| Chris@562 | 50 void | 
| Chris@562 | 51 MIDIInput::callback(double timestamp, std::vector<unsigned char> *message) | 
| Chris@562 | 52 { | 
| Chris@690 | 53     SVDEBUG << "MIDIInput::callback(" << timestamp << ")" << endl; | 
| Chris@567 | 54     // In my experience so far, the timings passed to this function | 
| Chris@567 | 55     // are not reliable enough to use.  We request instead an audio | 
| Chris@567 | 56     // frame time from whatever FrameTimer we have been given, and use | 
| Chris@567 | 57     // that as the event time. | 
| Chris@566 | 58     if (!message || message->empty()) return; | 
| Chris@567 | 59     unsigned long t = m_frameTimer->getFrame(); | 
| Chris@569 | 60     MIDIByte code = (*message)[0]; | 
| Chris@567 | 61     MIDIEvent ev(t, | 
| Chris@569 | 62                  code, | 
| Chris@566 | 63                  message->size() > 1 ? (*message)[1] : 0, | 
| Chris@566 | 64                  message->size() > 2 ? (*message)[2] : 0); | 
| Chris@566 | 65     postEvent(ev); | 
| Chris@562 | 66 } | 
| Chris@562 | 67 | 
| Chris@562 | 68 MIDIEvent | 
| Chris@562 | 69 MIDIInput::readEvent() | 
| Chris@562 | 70 { | 
| Chris@562 | 71     MIDIEvent *event = m_buffer.readOne(); | 
| Chris@562 | 72     MIDIEvent revent = *event; | 
| Chris@562 | 73     delete event; | 
| Chris@562 | 74     return revent; | 
| Chris@562 | 75 } | 
| Chris@562 | 76 | 
| Chris@562 | 77 void | 
| Chris@562 | 78 MIDIInput::postEvent(MIDIEvent e) | 
| Chris@562 | 79 { | 
| Chris@562 | 80     int count = 0, max = 5; | 
| Chris@562 | 81     while (m_buffer.getWriteSpace() == 0) { | 
| Chris@562 | 82         if (count == max) { | 
| Chris@843 | 83             cerr << "ERROR: MIDIInput::postEvent: MIDI event queue is full and not clearing -- abandoning incoming event" << endl; | 
| Chris@562 | 84             return; | 
| Chris@562 | 85         } | 
| Chris@843 | 86         cerr << "WARNING: MIDIInput::postEvent: MIDI event queue (capacity " << m_buffer.getSize() << " is full!" << endl; | 
| Chris@690 | 87         SVDEBUG << "Waiting for something to be processed" << endl; | 
| Chris@562 | 88 #ifdef _WIN32 | 
| Chris@562 | 89         Sleep(1); | 
| Chris@562 | 90 #else | 
| Chris@562 | 91         sleep(1); | 
| Chris@562 | 92 #endif | 
| Chris@562 | 93         count++; | 
| Chris@562 | 94     } | 
| Chris@562 | 95 | 
| Chris@562 | 96     MIDIEvent *me = new MIDIEvent(e); | 
| Chris@562 | 97     m_buffer.write(&me, 1); | 
| Chris@562 | 98     emit eventsAvailable(); | 
| Chris@562 | 99 } | 
| Chris@562 | 100 |