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@1397: m_rtmidi(0), Chris@567: m_frameTimer(timer), Chris@562: m_buffer(1023) Chris@562: { Chris@562: try { Chris@1397: std::vector apis; Chris@1397: RtMidi::getCompiledApi(apis); Chris@1400: RtMidi::Api preferredApi = RtMidi::UNSPECIFIED; Chris@1400: for (auto a: apis) { Chris@1400: if (a == RtMidi::UNSPECIFIED || a == RtMidi::RTMIDI_DUMMY) { Chris@1400: continue; Chris@1400: } Chris@1400: preferredApi = a; Chris@1400: break; Chris@1400: } Chris@1400: if (preferredApi == RtMidi::UNSPECIFIED) { Chris@1400: SVCERR << "ERROR: MIDIInput: No RtMidi APIs compiled in" << endl; Chris@1397: } else { Chris@1400: Chris@1400: m_rtmidi = new RtMidiIn(preferredApi, name.toStdString()); Chris@1400: Chris@1400: int n = m_rtmidi->getPortCount(); Chris@1400: Chris@1400: if (n == 0) { Chris@1400: Chris@1400: SVDEBUG << "NOTE: MIDIInput: No input ports available" << endl; Chris@1400: delete m_rtmidi; Chris@1400: m_rtmidi = 0; Chris@1400: Chris@1400: } else { Chris@1400: Chris@1400: m_rtmidi->setCallback(staticCallback, this); Chris@1400: Chris@1400: SVDEBUG << "MIDIInput: Available ports are:" << endl; Chris@1400: for (int i = 0; i < n; ++i) { Chris@1400: SVDEBUG << i << ". " << m_rtmidi->getPortName(i) << endl; Chris@1400: } Chris@1400: SVDEBUG << "MIDIInput: Using first port (\"" Chris@1400: << m_rtmidi->getPortName(0) << "\")" << endl; Chris@1400: Chris@1400: m_rtmidi->openPort(0, tr("Input").toStdString()); Chris@1400: } Chris@1397: } Chris@1400: Chris@1465: } catch (const RtMidiError &e) { Chris@1400: SVCERR << "ERROR: RtMidi error: " << e.getMessage() << endl; 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@1400: SVCERR << "ERROR: MIDIInput::postEvent: MIDI event queue is full and not clearing -- abandoning incoming event" << endl; Chris@562: return; Chris@562: } Chris@1400: SVCERR << "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: