Chris@562: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@562: Chris@562: /* Chris@562: Sonic Visualiser Chris@562: An audio file viewer and annotation editor. Chris@562: Centre for Digital Music, Queen Mary, University of London. Chris@562: This file copyright 2006-2009 Chris Cannam and QMUL. Chris@562: Chris@562: This program is free software; you can redistribute it and/or Chris@562: modify it under the terms of the GNU General Public License as Chris@562: published by the Free Software Foundation; either version 2 of the Chris@562: License, or (at your option) any later version. See the file Chris@562: COPYING included with this distribution for more information. Chris@562: */ Chris@562: Chris@562: #include "MIDIInput.h" Chris@562: Chris@562: #include "rtmidi/RtMidi.h" Chris@562: Chris@1219: #include "system/System.h" Chris@608: Chris@567: MIDIInput::MIDIInput(QString name, FrameTimer *timer) : Chris@562: m_rtmidi(), Chris@567: m_frameTimer(timer), Chris@562: m_buffer(1023) Chris@562: { Chris@562: try { Chris@562: m_rtmidi = new RtMidiIn(name.toStdString()); Chris@562: m_rtmidi->setCallback(staticCallback, this); Chris@565: m_rtmidi->openPort(0, tr("Input").toStdString()); Chris@562: } catch (RtError e) { Chris@562: e.printMessage(); Chris@562: delete m_rtmidi; Chris@562: m_rtmidi = 0; Chris@562: } Chris@562: } Chris@562: Chris@562: MIDIInput::~MIDIInput() Chris@562: { Chris@562: delete m_rtmidi; Chris@562: } Chris@562: Chris@562: void Chris@562: MIDIInput::staticCallback(double timestamp, std::vector *message, Chris@562: void *userData) Chris@562: { Chris@562: ((MIDIInput *)userData)->callback(timestamp, message); Chris@562: } Chris@562: Chris@562: void Chris@562: MIDIInput::callback(double timestamp, std::vector *message) Chris@562: { Chris@690: SVDEBUG << "MIDIInput::callback(" << timestamp << ")" << endl; Chris@567: // In my experience so far, the timings passed to this function Chris@567: // are not reliable enough to use. We request instead an audio Chris@567: // frame time from whatever FrameTimer we have been given, and use Chris@567: // that as the event time. Chris@566: if (!message || message->empty()) return; Chris@567: unsigned long t = m_frameTimer->getFrame(); Chris@569: MIDIByte code = (*message)[0]; Chris@567: MIDIEvent ev(t, Chris@569: code, Chris@566: message->size() > 1 ? (*message)[1] : 0, Chris@566: message->size() > 2 ? (*message)[2] : 0); Chris@566: postEvent(ev); Chris@562: } Chris@562: Chris@562: MIDIEvent Chris@562: MIDIInput::readEvent() Chris@562: { Chris@562: MIDIEvent *event = m_buffer.readOne(); Chris@562: MIDIEvent revent = *event; Chris@562: delete event; Chris@562: return revent; Chris@562: } Chris@562: Chris@562: void Chris@562: MIDIInput::postEvent(MIDIEvent e) Chris@562: { Chris@562: int count = 0, max = 5; Chris@562: while (m_buffer.getWriteSpace() == 0) { Chris@562: if (count == max) { Chris@843: cerr << "ERROR: MIDIInput::postEvent: MIDI event queue is full and not clearing -- abandoning incoming event" << endl; Chris@562: return; Chris@562: } Chris@843: cerr << "WARNING: MIDIInput::postEvent: MIDI event queue (capacity " << m_buffer.getSize() << " is full!" << endl; Chris@690: SVDEBUG << "Waiting for something to be processed" << endl; Chris@562: #ifdef _WIN32 Chris@562: Sleep(1); Chris@562: #else Chris@562: sleep(1); Chris@562: #endif Chris@562: count++; Chris@562: } Chris@562: Chris@562: MIDIEvent *me = new MIDIEvent(e); Chris@562: m_buffer.write(&me, 1); Chris@562: emit eventsAvailable(); Chris@562: } Chris@562: