svcore  1.9
MIDIInput.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006-2009 Chris Cannam and QMUL.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "MIDIInput.h"
00017 
00018 #include "rtmidi/RtMidi.h"
00019 
00020 #include <unistd.h>
00021 
00022 MIDIInput::MIDIInput(QString name, FrameTimer *timer) :
00023     m_rtmidi(),
00024     m_frameTimer(timer),
00025     m_buffer(1023)
00026 {
00027     try {
00028         m_rtmidi = new RtMidiIn(name.toStdString());
00029         m_rtmidi->setCallback(staticCallback, this);
00030         m_rtmidi->openPort(0, tr("Input").toStdString());
00031     } catch (RtError e) {
00032         e.printMessage();
00033         delete m_rtmidi;
00034         m_rtmidi = 0;
00035     }
00036 }
00037 
00038 MIDIInput::~MIDIInput()
00039 {
00040     delete m_rtmidi;
00041 }
00042 
00043 void
00044 MIDIInput::staticCallback(double timestamp, std::vector<unsigned char> *message,
00045                           void *userData)
00046 {
00047     ((MIDIInput *)userData)->callback(timestamp, message);
00048 }
00049 
00050 void
00051 MIDIInput::callback(double timestamp, std::vector<unsigned char> *message)
00052 {
00053     SVDEBUG << "MIDIInput::callback(" << timestamp << ")" << endl;
00054     // In my experience so far, the timings passed to this function
00055     // are not reliable enough to use.  We request instead an audio
00056     // frame time from whatever FrameTimer we have been given, and use
00057     // that as the event time.
00058     if (!message || message->empty()) return;
00059     unsigned long t = m_frameTimer->getFrame();
00060     MIDIByte code = (*message)[0];
00061     MIDIEvent ev(t,
00062                  code,
00063                  message->size() > 1 ? (*message)[1] : 0,
00064                  message->size() > 2 ? (*message)[2] : 0);
00065     postEvent(ev);
00066 }
00067 
00068 MIDIEvent
00069 MIDIInput::readEvent()
00070 {
00071     MIDIEvent *event = m_buffer.readOne();
00072     MIDIEvent revent = *event;
00073     delete event;
00074     return revent;
00075 }
00076 
00077 void
00078 MIDIInput::postEvent(MIDIEvent e)
00079 {
00080     int count = 0, max = 5;
00081     while (m_buffer.getWriteSpace() == 0) {
00082         if (count == max) {
00083             cerr << "ERROR: MIDIInput::postEvent: MIDI event queue is full and not clearing -- abandoning incoming event" << endl;
00084             return;
00085         }
00086         cerr << "WARNING: MIDIInput::postEvent: MIDI event queue (capacity " << m_buffer.getSize() << " is full!" << endl;
00087         SVDEBUG << "Waiting for something to be processed" << endl;
00088 #ifdef _WIN32
00089         Sleep(1);
00090 #else
00091         sleep(1);
00092 #endif
00093         count++;
00094     }
00095 
00096     MIDIEvent *me = new MIDIEvent(e);
00097     m_buffer.write(&me, 1);
00098     emit eventsAvailable();
00099 }
00100