MIDIInput.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7  This file copyright 2006-2009 Chris Cannam and QMUL.
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of the
12  License, or (at your option) any later version. See the file
13  COPYING included with this distribution for more information.
14 */
15 
16 #include "MIDIInput.h"
17 
18 #include "rtmidi/RtMidi.h"
19 
20 #include "system/System.h"
21 
22 MIDIInput::MIDIInput(QString name, FrameTimer *timer) :
23  m_rtmidi(nullptr),
24  m_frameTimer(timer),
25  m_buffer(1023)
26 {
27  try {
28  std::vector<RtMidi::Api> apis;
29  RtMidi::getCompiledApi(apis);
30  RtMidi::Api preferredApi = RtMidi::UNSPECIFIED;
31  for (auto a: apis) {
32  if (a == RtMidi::UNSPECIFIED || a == RtMidi::RTMIDI_DUMMY) {
33  continue;
34  }
35  preferredApi = a;
36  break;
37  }
38  if (preferredApi == RtMidi::UNSPECIFIED) {
39  SVCERR << "ERROR: MIDIInput: No RtMidi APIs compiled in" << endl;
40  } else {
41 
42  m_rtmidi = new RtMidiIn(preferredApi, name.toStdString());
43 
44  int n = m_rtmidi->getPortCount();
45 
46  if (n == 0) {
47 
48  SVDEBUG << "NOTE: MIDIInput: No input ports available" << endl;
49  delete m_rtmidi;
50  m_rtmidi = nullptr;
51 
52  } else {
53 
54  m_rtmidi->setCallback(staticCallback, this);
55 
56  SVDEBUG << "MIDIInput: Available ports are:" << endl;
57  for (int i = 0; i < n; ++i) {
58  SVDEBUG << i << ". " << m_rtmidi->getPortName(i) << endl;
59  }
60  SVDEBUG << "MIDIInput: Using first port (\""
61  << m_rtmidi->getPortName(0) << "\")" << endl;
62 
63  m_rtmidi->openPort(0, tr("Input").toStdString());
64  }
65  }
66 
67  } catch (const RtMidiError &e) {
68  SVCERR << "ERROR: RtMidi error: " << e.getMessage() << endl;
69  delete m_rtmidi;
70  m_rtmidi = nullptr;
71  }
72 }
73 
75 {
76  delete m_rtmidi;
77 }
78 
79 void
80 MIDIInput::staticCallback(double timestamp, std::vector<unsigned char> *message,
81  void *userData)
82 {
83  ((MIDIInput *)userData)->callback(timestamp, message);
84 }
85 
86 void
87 MIDIInput::callback(double timestamp, std::vector<unsigned char> *message)
88 {
89  SVDEBUG << "MIDIInput::callback(" << timestamp << ")" << endl;
90  // In my experience so far, the timings passed to this function
91  // are not reliable enough to use. We request instead an audio
92  // frame time from whatever FrameTimer we have been given, and use
93  // that as the event time.
94  if (!message || message->empty()) return;
95  unsigned long t = m_frameTimer->getFrame();
96  MIDIByte code = (*message)[0];
97  MIDIEvent ev(t,
98  code,
99  message->size() > 1 ? (*message)[1] : 0,
100  message->size() > 2 ? (*message)[2] : 0);
101  postEvent(ev);
102 }
103 
104 MIDIEvent
106 {
107  MIDIEvent *event = m_buffer.readOne();
108  MIDIEvent revent = *event;
109  delete event;
110  return revent;
111 }
112 
113 void
115 {
116  int count = 0, max = 5;
117  while (m_buffer.getWriteSpace() == 0) {
118  if (count == max) {
119  SVCERR << "ERROR: MIDIInput::postEvent: MIDI event queue is full and not clearing -- abandoning incoming event" << endl;
120  return;
121  }
122  SVCERR << "WARNING: MIDIInput::postEvent: MIDI event queue (capacity " << m_buffer.getSize() << ") is full!" << endl;
123  SVDEBUG << "Waiting for something to be processed" << endl;
124 #ifdef _WIN32
125  Sleep(1);
126 #else
127  sleep(1);
128 #endif
129  count++;
130  }
131 
132  MIDIEvent *me = new MIDIEvent(e);
133  m_buffer.write(&me, 1);
134  emit eventsAvailable();
135 }
136 
virtual sv_frame_t getFrame() const =0
int getSize() const
Return the total capacity of the ring buffer in samples.
Definition: RingBuffer.h:189
RingBuffer< MIDIEvent * > m_buffer
Definition: MIDIInput.h:53
FrameTimer * m_frameTimer
Definition: MIDIInput.h:47
void eventsAvailable()
T readOne(int R=0)
Read one sample from the buffer, for reader R.
Definition: RingBuffer.h:354
virtual ~MIDIInput()
Definition: MIDIInput.cpp:74
MIDIEvent readEvent()
Definition: MIDIInput.cpp:105
MIDIInput(QString name, FrameTimer *timer)
Definition: MIDIInput.cpp:22
int write(const T *source, int n)
Write n samples to the buffer.
Definition: RingBuffer.h:449
A trivial interface for things that permit retrieving "the current frame".
Definition: FrameTimer.h:27
#define SVDEBUG
Definition: Debug.h:106
static void staticCallback(double, std::vector< unsigned char > *, void *)
Definition: MIDIInput.cpp:80
#define SVCERR
Definition: Debug.h:109
int getWriteSpace() const
Return the amount of space available for writing, in samples.
Definition: RingBuffer.h:254
RtMidiIn * m_rtmidi
Definition: MIDIInput.h:46
unsigned char MIDIByte
void postEvent(MIDIEvent)
Definition: MIDIInput.cpp:114
void callback(double, std::vector< unsigned char > *)
Definition: MIDIInput.cpp:87