CFugue
AlsaDriver.cpp
1 /*
2  This is part of CFugue, a C++ Runtime for MIDI Score Programming
3  Copyright (C) 2011 Gopalakrishna Palem
4 
5  For links to further information, or to contact the author,
6  see <http://cfugue.sourceforge.net/>.
7 */
8 #if defined _WIN32 || defined WIN32
9 
10 #else // only if not Windows
11 
12 #include "AlsaDriver.h"
13 #include "MidiTimer.h"
14 
15 using namespace jdkmidi;
16 
17 namespace CFugue
18 {
19  MIDIDriverAlsa::MIDIDriverAlsa ( int queue_size )
20  :
21  MIDIDriver ( queue_size ),
22  m_pMidiIn ( 0 ),
23  m_pMidiOut ( 0 ),
24  m_pThread ( NULL )
25  {
26  }
27 
28  MIDIDriverAlsa::~MIDIDriverAlsa()
29  {
30  StopTimer();
31  CloseMIDIInPort();
32  CloseMIDIOutPort();
33  }
34 
35  bool MIDIDriverAlsa::OpenMIDIInPort ( int id )
36  {
37  if(m_pMidiIn != NULL) // close any open port
38  {
39  delete m_pMidiIn;
40  m_pMidiIn = NULL;
41  }
42  if(m_pMidiIn == NULL)
43  {
44  try
45  {
46  m_pMidiIn = new RtMidiIn("MIDIDriverAlsa Client");
47  }
48  catch ( RtError &error )
49  {
50  error.printMessage();
51  return false;
52  }
53  }
54  if(m_pMidiIn != NULL)
55  {
56  try
57  {
58  m_pMidiIn->openPort(id);
59  }
60  catch(RtError& error)
61  {
62  error.printMessage();
63  return false;
64  }
65  }
66  return true;
67  }
68 
69 
70  bool MIDIDriverAlsa::OpenMIDIOutPort ( int id )
71  {
72  if(m_pMidiOut != NULL) // close any open port
73  {
74  delete m_pMidiOut;
75  m_pMidiOut = NULL;
76  }
77  if(m_pMidiOut == NULL)
78  {
79  try
80  {
81  m_pMidiOut = new RtMidiOut("MIDIDriverAlsa Client");
82  }
83  catch(RtError &error)
84  {
85  error.printMessage();
86  return false;
87  }
88  }
89  if(m_pMidiOut != NULL)
90  {
91  try
92  {
93  m_pMidiOut->openPort(id);
94  }
95  catch(RtError &error)
96  {
97  error.printMessage();
98  return false;
99  }
100  }
101  return true;
102  }
103 
104  bool MIDIDriverAlsa::HardwareMsgOut ( const jdkmidi::MIDITimedBigMessage &msg )
105  {
106  if(m_pMidiOut != NULL)
107  {
108  unsigned char status = msg.GetStatus();
109 
110  // dont send sysex or meta-events
111 
112  if ( status <0xff && status !=0xf0 )
113  {
114  unsigned char msgBytes[] = {status, msg.GetByte1(), msg.GetByte2(), msg.GetByte3()};
115 
116  std::vector<unsigned char> vec(msgBytes, msgBytes+3);
117 
118  m_pMidiOut->sendMessage(&vec);
119  }
120 
121  return true;
122  }
123  return false;
124  }
125 
126  // This is thread procedure to pump MIDI events
127  // We maintain the supplied Timer Resolution by adjusting the sleep duration
128  bool AlsaDriverThreadProc(MIDIDriverAlsa* pAlsaDriver, int nTimerResMS)
129  {
130  MidiTimer::TimePoint tBefore, tAfter;
131  unsigned long nElapsed, nTimeToSleep;
132 
133  while(true)
134  {
135  tBefore = MidiTimer::Now();
136 
137  if(pAlsaDriver->TimeTick(tBefore) == false) break;
138 
139  tAfter = MidiTimer::Now();
140 
141  nElapsed = std::chrono::duration_cast<MidiTimer::Duration>(tAfter - tBefore).count();
142 
143  nTimeToSleep = (nElapsed > nTimerResMS ? 0 : nTimerResMS - nElapsed);
144 
145  MidiTimer::Sleep(nTimeToSleep);
146  }
147 
148  return true;
149  }
150 
151  bool MIDIDriverAlsa::StartTimer ( int res )
152  {
153  if(m_bgTaskResult.valid()) // Already running
154  return false;
155 
156  m_bgTaskResult = std::async(std::launch::async, &AlsaDriverThreadProc, this, res);
157 
158  return m_bgTaskResult.valid();
159  }
160 
161  void MIDIDriverAlsa::WaitTillDone()
162  {
163  if(m_bgTaskResult.valid() == false) return; // if not running
164 
165  auto waitStatus = m_bgTaskResult.wait_for(std::chrono::milliseconds(0));
166 
167  while(waitStatus != std::future_status::ready)
168  {
169  waitStatus = m_bgTaskResult.wait_for(std::chrono::milliseconds(500));
170  }
171  }
172 
173  void MIDIDriverAlsa::StopTimer()
174  {
175  // std::future requires get() to be called before it can be used again.
176  // valid() keeps returning true till get() is called. And get() can be
177  // called only once. Once it is called valid() becomes false again.
178  if(m_bgTaskResult.valid())
179  m_bgTaskResult.get();
180  }
181 
182  void MIDIDriverAlsa::CloseMIDIInPort()
183  {
184  if(m_pMidiIn != NULL)
185  {
186  m_pMidiIn->closePort();
187  delete m_pMidiIn;
188  m_pMidiIn = NULL;
189  }
190  }
191 
192  void MIDIDriverAlsa::CloseMIDIOutPort()
193  {
194  if(m_pMidiOut != NULL)
195  {
196  m_pMidiOut->closePort();
197  delete m_pMidiOut;
198  m_pMidiOut = NULL;
199  }
200  }
201 
202 } // namespace CFugue
203 
204 
205 
206 #endif // _ifndef _Win32
Declares MIDIDriverAlsa class for CFugue.

CFugue, the C++ Music Programming Library © Copyright 2009 Cenacle Research India Private Limited Gopalakrishna Palem