1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
|
<HTML>
<HEAD>
<TITLE>The Synthesis ToolKit in C++ (STK)</TITLE>
<LINK HREF="doxygen.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<CENTER>
<img src="princeton.gif"> <img src="ccrma.gif"><P>
<a class="qindex" href="index.html">Home</a> <a class="qindex" href="information.html">Information</a> <a class="qindex" href="classes.html">Classes</a> <a class="qindex" href="download.html">Download</a> <a class="qindex" href="usage.html">Usage</a> <a class="qindex" href="maillist.html">Mail List</a> <a class="qindex" href="system.html">Requirements</a> <a class="qindex" href="links.html">Links</a> <a class="qindex" href="tutorial.html">Tutorial</a></CENTER>
<HR>
<!-- Generated by Doxygen 1.3-rc3 -->
<h1>RtMidi.cpp</h1><div class="fragment"><pre>00001 <span class="comment">/**********************************************************************/</span>
00010 <span class="comment">/**********************************************************************/</span>
00011
00012 <span class="preprocessor">#include "RtMidi.h"</span>
00013 <span class="preprocessor">#include <sstream></span>
00014
00015 RtMidi :: RtMidi()
00016 : apiData_( 0 ), connected_( false )
00017 {
00018 }
00019
00020 <span class="keywordtype">void</span> RtMidi :: error( RtError::Type type )
00021 {
00022 <span class="keywordflow">if</span> (type == RtError::WARNING) {
00023 std::cerr << <span class="charliteral">'\n'</span> << errorString_ << <span class="stringliteral">"\n\n"</span>;
00024 }
00025 <span class="keywordflow">else</span> <span class="keywordflow">if</span> (type == RtError::DEBUG_WARNING) {
00026 <span class="preprocessor">#if defined(__RTMIDI_DEBUG__)</span>
00027 <span class="preprocessor"></span> std::cerr << <span class="charliteral">'\n'</span> << errorString_ << <span class="stringliteral">"\n\n"</span>;
00028 <span class="preprocessor">#endif</span>
00029 <span class="preprocessor"></span> }
00030 <span class="keywordflow">else</span> {
00031 std::cerr << <span class="charliteral">'\n'</span> << errorString_ << <span class="stringliteral">"\n\n"</span>;
00032 <span class="keywordflow">throw</span> <a class="code" href="classRtError.html#a0">RtError</a>( errorString_, type );
00033 }
00034 }
00035
<a name="l00036"></a><a class="code" href="classRtMidiIn.html#a0">00036</a> <a class="code" href="classRtMidiIn.html#a0">RtMidiIn :: RtMidiIn</a>() : <a class="code" href="classRtMidi.html">RtMidi</a>()
00037 {
00038 }
00039
<a name="l00040"></a><a class="code" href="classRtMidiIn.html#a1">00040</a> <a class="code" href="classRtMidiIn.html#a0">RtMidiIn :: RtMidiIn</a>( <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> portNumber, RtMidiCallback callback, <span class="keywordtype">void</span> *userData ) : <a class="code" href="classRtMidi.html">RtMidi</a>()
00041
00042 {
00043 <span class="comment">// Attempt to make the connection.</span>
00044 this-><a class="code" href="classRtMidiIn.html#a3">openPort</a>( portNumber, callback, userData );
00045 }
00046
<a name="l00047"></a><a class="code" href="classRtMidiIn.html#a2">00047</a> <a class="code" href="classRtMidiIn.html#a2">RtMidiIn :: ~RtMidiIn</a>()
00048 {
00049 <a class="code" href="classRtMidiIn.html#a4">closePort</a>();
00050 }
00051
<a name="l00052"></a><a class="code" href="classRtMidiOut.html#a0">00052</a> <a class="code" href="classRtMidiOut.html#a0">RtMidiOut :: RtMidiOut</a>() : <a class="code" href="classRtMidi.html">RtMidi</a>()
00053 {
00054 }
00055
<a name="l00056"></a><a class="code" href="classRtMidiOut.html#a1">00056</a> <a class="code" href="classRtMidiOut.html#a0">RtMidiOut :: RtMidiOut</a>( <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> portNumber ) : <a class="code" href="classRtMidi.html">RtMidi</a>()
00057 {
00058 <span class="comment">// Attempt to make the connection.</span>
00059 this-><a class="code" href="classRtMidiOut.html#a3">openPort</a>( portNumber );
00060 }
00061
<a name="l00062"></a><a class="code" href="classRtMidiOut.html#a2">00062</a> <a class="code" href="classRtMidiOut.html#a2">RtMidiOut :: ~RtMidiOut</a>()
00063 {
00064 <a class="code" href="classRtMidiOut.html#a4">closePort</a>();
00065 }
00066
00067
00068 <span class="preprocessor">#if defined(__MACOSX_CORE__)</span>
00069 <span class="preprocessor"></span>
00070 <span class="comment">// The CoreMIDI API is based on the use of a callback function for</span>
00071 <span class="comment">// MIDI input. We convert the system specific time stamps to delta</span>
00072 <span class="comment">// time values.</span>
00073
00074 <span class="comment">// OS-X CoreMIDI header files.</span>
00075 <span class="preprocessor">#include <CoreMIDI/CoreMIDI.h></span>
00076 <span class="preprocessor">#include <CoreAudio/HostTime.h></span>
00077
00078 <span class="comment">// A structure to hold variables related to the CoreMIDI API</span>
00079 <span class="comment">// implementation.</span>
00080 <span class="keyword">struct </span>CoreMidiData {
00081 MIDIClientRef client;
00082 MIDIPortRef port;
00083 MIDIEndpointRef destinationId;
00084 };
00085
00086 <span class="keywordtype">void</span> midiInputCallback( <span class="keyword">const</span> MIDIPacketList *list, <span class="keywordtype">void</span> *procRef, <span class="keywordtype">void</span> *srcRef )
00087 {
00088 RtMidiIn::RtMidiInData *data = static_cast<RtMidiIn::RtMidiInData *> (procRef);
00089
00090 <span class="keywordtype">bool</span> continueSysex = <span class="keyword">false</span>;
00091 <span class="keywordtype">unsigned</span> <span class="keywordtype">char</span> status;
00092 <span class="keywordtype">unsigned</span> <span class="keywordtype">short</span> nBytes, iByte, size;
00093 <span class="keywordtype">unsigned</span> <span class="keywordtype">long</span> <span class="keywordtype">long</span> time;
00094 RtMidiIn::MidiMessage message;
00095 <span class="keyword">const</span> MIDIPacket *packet = &list->packet[0];
00096 <span class="keywordflow">for</span> ( <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> i=0; i<list->numPackets; ++i ) {
00097
00098 <span class="comment">// My interpretation of the CoreMIDI documentation: all message</span>
00099 <span class="comment">// types, except sysex, are complete within a packet and there may</span>
00100 <span class="comment">// be several of them in a single packet. Sysex messages can be</span>
00101 <span class="comment">// broken across multiple packets but are bundled alone within a</span>
00102 <span class="comment">// packet. I'm assuming that sysex messages, if segmented, must</span>
00103 <span class="comment">// be complete within the same MIDIPacketList.</span>
00104
00105 nBytes = packet->length;
00106 <span class="keywordflow">if</span> ( nBytes == 0 ) <span class="keywordflow">continue</span>;
00107
00108 <span class="comment">// Calculate time stamp.</span>
00109 message.timeStamp = 0.0;
00110 time = packet->timeStamp;
00111 time -= data->lastTime;
00112 data->lastTime = packet->timeStamp;
00113 time = AudioConvertHostTimeToNanos( time );
00114 message.timeStamp = time * 0.000000001;
00115
00116 iByte = 0;
00117 <span class="keywordflow">if</span> ( continueSysex ) {
00118 <span class="comment">// We have a continuing, segmented sysex message.</span>
00119 <span class="keywordflow">if</span> ( !(data->ignoreFlags & 0x01) ) {
00120 <span class="comment">// If we're not ignoring sysex messages, copy the entire packet.</span>
00121 message.bytes.assign( packet->data, &packet->data[nBytes] );
00122 }
00123 <span class="keywordflow">if</span> ( packet->data[nBytes] == 0xF7 ) continueSysex = <span class="keyword">false</span>;
00124 <span class="keywordflow">if</span> ( !continueSysex ) {
00125 <span class="comment">// If not a continuing sysex message, invoke the user callback function or queue the message.</span>
00126 <span class="keywordflow">if</span> ( data->usingCallback && message.bytes.size() > 0 ) {
00127 <a class="code" href="classRtMidiIn.html#s0">RtMidiIn::RtMidiCallback</a> callback = (RtMidiIn::RtMidiCallback) data->userCallback;
00128 callback( message.timeStamp, &message.bytes, data->userData );
00129 }
00130 <span class="keywordflow">else</span> {
00131 <span class="comment">// As long as we haven't reached our queue size limit, push the message.</span>
00132 <span class="keywordflow">if</span> ( data->queueLimit > data->queue.size() )
00133 data->queue.push( message );
00134 <span class="keywordflow">else</span>
00135 std::cerr << <span class="stringliteral">"\nRtMidiIn: message queue limit reached!!\n\n"</span>;
00136 }
00137 message.bytes.clear();
00138 }
00139 }
00140 <span class="keywordflow">else</span> {
00141 <span class="keywordflow">while</span> ( iByte < nBytes ) {
00142 size = 0;
00143 <span class="comment">// We are expecting that the next byte in the packet is a status byte.</span>
00144 status = packet->data[iByte];
00145 <span class="keywordflow">if</span> ( !(status & 0x80) ) <span class="keywordflow">break</span>;
00146 <span class="comment">// Determine the number of bytes in the MIDI message.</span>
00147 <span class="keywordflow">if</span> ( status < 0xC0 ) size = 3;
00148 <span class="keywordflow">else</span> <span class="keywordflow">if</span> ( status < 0xE0 ) size = 2;
00149 <span class="keywordflow">else</span> <span class="keywordflow">if</span> ( status < 0xF0 ) size = 3;
00150 <span class="keywordflow">else</span> <span class="keywordflow">if</span> ( status == 0xF0 ) {
00151 <span class="comment">// A MIDI sysex</span>
00152 <span class="keywordflow">if</span> ( data->ignoreFlags & 0x01 ) {
00153 size = 0;
00154 iByte = nBytes;
00155 }
00156 <span class="keywordflow">else</span> size = nBytes - iByte;
00157 <span class="keywordflow">if</span> ( packet->data[nBytes] == 0xF7 ) continueSysex = <span class="keyword">false</span>;
00158 }
00159 <span class="keywordflow">else</span> <span class="keywordflow">if</span> ( status < 0xF3 ) {
00160 <span class="keywordflow">if</span> ( status == 0xF1 && (data->ignoreFlags & 0x02) ) {
00161 <span class="comment">// A MIDI time code message and we're ignoring it.</span>
00162 size = 0;
00163 iByte += 3;
00164 }
00165 <span class="keywordflow">else</span> size = 3;
00166 }
00167 <span class="keywordflow">else</span> <span class="keywordflow">if</span> ( status == 0xF3 ) size = 2;
00168 <span class="keywordflow">else</span> <span class="keywordflow">if</span> ( status == 0xFE && (data->ignoreFlags & 0x04) ) {
00169 <span class="comment">// A MIDI active sensing message and we're ignoring it.</span>
00170 size = 0;
00171 iByte += 1;
00172 }
00173 <span class="keywordflow">else</span> size = 1;
00174
00175 <span class="comment">// Copy the MIDI data to our vector.</span>
00176 <span class="keywordflow">if</span> ( size ) {
00177 message.bytes.assign( &packet->data[iByte], &packet->data[iByte+size] );
00178 <span class="keywordflow">if</span> ( !continueSysex ) {
00179 <span class="comment">// If not a continuing sysex message, invoke the user callback function or queue the message.</span>
00180 <span class="keywordflow">if</span> ( data->usingCallback ) {
00181 <a class="code" href="classRtMidiIn.html#s0">RtMidiIn::RtMidiCallback</a> callback = (RtMidiIn::RtMidiCallback) data->userCallback;
00182 callback( message.timeStamp, &message.bytes, data->userData );
00183 }
00184 <span class="keywordflow">else</span> {
00185 <span class="comment">// As long as we haven't reached our queue size limit, push the message.</span>
00186 <span class="keywordflow">if</span> ( data->queueLimit > data->queue.size() )
00187 data->queue.push( message );
00188 <span class="keywordflow">else</span>
00189 std::cerr << <span class="stringliteral">"\nRtMidiIn: message queue limit reached!!\n\n"</span>;
00190 }
00191 message.bytes.clear();
00192 }
00193 iByte += size;
00194 }
00195 }
00196 }
00197 packet = MIDIPacketNext(packet);
00198 }
00199 }
00200
00201 <span class="keywordtype">void</span> <a class="code" href="classRtMidiIn.html#a3">RtMidiIn :: openPort</a>( <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> portNumber, RtMidiCallback callback, <span class="keywordtype">void</span> *userData )
00202 {
00203 <span class="keywordflow">if</span> ( connected_ ) {
00204 errorString_ = <span class="stringliteral">"RtMidiIn::openPort: a valid connection already exists!"</span>;
00205 error( RtError::WARNING );
00206 <span class="keywordflow">return</span>;
00207 }
00208
00209 <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> nSrc = MIDIGetNumberOfSources();
00210 <span class="keywordflow">if</span> (nSrc < 1) {
00211 errorString_ = <span class="stringliteral">"RtMidiIn::openPort: no MIDI input sources found!"</span>;
00212 error( RtError::NO_DEVICES_FOUND );
00213 }
00214
00215 std::ostringstream ost;
00216 <span class="keywordflow">if</span> ( portNumber >= nSrc ) {
00217 ost << <span class="stringliteral">"RtMidiIn::openPort: the 'portNumber' argument ("</span> << portNumber << <span class="stringliteral">") is invalid."</span>;
00218 errorString_ = ost.str();
00219 error( RtError::INVALID_PARAMETER );
00220 }
00221
00222 MIDIClientRef client;
00223 OSStatus result = MIDIClientCreate( CFSTR(<span class="stringliteral">"RtMidi Input Client"</span>), NULL, NULL, &client );
00224 <span class="keywordflow">if</span> ( result != noErr ) {
00225 errorString_ = <span class="stringliteral">"RtMidiIn::openPort: error creating OS-X MIDI client object."</span>;
00226 error( RtError::DRIVER_ERROR );
00227 }
00228
00229 MIDIPortRef port;
00230 result = MIDIInputPortCreate( client, CFSTR(<span class="stringliteral">"RtMidi Virtual MIDI Input Port"</span>), midiInputCallback, (<span class="keywordtype">void</span> *)&inputData_, &port );
00231 <span class="keywordflow">if</span> ( result != noErr ) {
00232 MIDIClientDispose( client );
00233 errorString_ = <span class="stringliteral">"RtMidiIn::openPort: error creating OS-X MIDI input port."</span>;
00234 error( RtError::DRIVER_ERROR );
00235 }
00236
00237 <span class="comment">// Get the desired input source identifier.</span>
00238 MIDIEndpointRef src = MIDIGetSource( portNumber );
00239 <span class="keywordflow">if</span> ( src == NULL ) {
00240 MIDIPortDispose( port );
00241 MIDIClientDispose( client );
00242 errorString_ = <span class="stringliteral">"RtMidiIn::openPort: error getting MIDI input source reference."</span>;
00243 error( RtError::DRIVER_ERROR );
00244 }
00245
00246 <span class="comment">// Make the connection.</span>
00247 result = MIDIPortConnectSource(port, src, NULL );
00248 <span class="keywordflow">if</span> ( result != noErr ) {
00249 MIDIPortDispose( port );
00250 MIDIClientDispose( client );
00251 errorString_ = <span class="stringliteral">"RtMidiIn::openPort: error connecting OS-X MIDI input port."</span>;
00252 error( RtError::DRIVER_ERROR );
00253 }
00254
00255 <span class="comment">// Save our api-specific connection information.</span>
00256 CoreMidiData *data = (CoreMidiData *) <span class="keyword">new</span> CoreMidiData;
00257 data->client = client;
00258 data->port = port;
00259 apiData_ = (<span class="keywordtype">void</span> *) data;
00260
00261 <span class="keywordflow">if</span> ( callback ) {
00262 inputData_.userCallback = (<span class="keywordtype">void</span> *) callback;
00263 inputData_.userData = userData;
00264 inputData_.usingCallback = <span class="keyword">true</span>;
00265 }
00266
00267 inputData_.lastTime = AudioGetCurrentHostTime();
00268
00269 connected_ = <span class="keyword">true</span>;
00270 }
00271
00272 <span class="keywordtype">void</span> <a class="code" href="classRtMidiIn.html#a4">RtMidiIn :: closePort</a>( <span class="keywordtype">void</span> )
00273 {
00274 <span class="keywordflow">if</span> ( connected_ ) {
00275 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
00276 MIDIClientDispose( data->client );
00277 MIDIPortDispose( data->port );
00278 <span class="keyword">delete</span> data;
00279 apiData_ = 0;
00280 }
00281
00282 connected_ = <span class="keyword">false</span>;
00283 }
00284
00285 <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> <a class="code" href="classRtMidiIn.html#a5">RtMidiIn :: getPortCount</a>()
00286 {
00287 <span class="keywordflow">return</span> MIDIGetNumberOfSources();
00288 }
00289
00290 std::string <a class="code" href="classRtMidiIn.html#a6">RtMidiIn :: getPortName</a>( <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> portNumber )
00291 {
00292 CFStringRef nameRef;
00293 MIDIEndpointRef portRef;
00294 std::ostringstream ost;
00295 <span class="keywordtype">char</span> name[128];
00296
00297 <span class="keywordflow">if</span> ( portNumber >= MIDIGetNumberOfSources() ) {
00298 ost << <span class="stringliteral">"RtMidiIn::getPortName: the 'portNumber' argument ("</span> << portNumber << <span class="stringliteral">") is invalid."</span>;
00299 errorString_ = ost.str();
00300 error( RtError::INVALID_PARAMETER );
00301 }
00302 portRef = MIDIGetSource( portNumber );
00303
00304 MIDIObjectGetStringProperty( portRef, kMIDIPropertyName, &nameRef );
00305 CFStringGetCString( nameRef, name, <span class="keyword">sizeof</span>(name), 0);
00306 CFRelease( nameRef );
00307 std::string stringName = name;
00308 <span class="keywordflow">return</span> stringName;
00309 }
00310
00311 <span class="keywordtype">void</span> <a class="code" href="classRtMidiIn.html#a7">RtMidiIn :: setQueueSizeLimit</a>( <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> queueSize )
00312 {
00313 inputData_.queueLimit = queueSize;
00314 }
00315
00316 <span class="keywordtype">void</span> <a class="code" href="classRtMidiIn.html#a8">RtMidiIn :: ignoreTypes</a>( <span class="keywordtype">bool</span> midiSysex, <span class="keywordtype">bool</span> midiTime, <span class="keywordtype">bool</span> midiSense )
00317 {
00318 inputData_.ignoreFlags = 0;
00319 <span class="keywordflow">if</span> ( midiSysex ) inputData_.ignoreFlags = 0x01;
00320 <span class="keywordflow">if</span> ( midiTime ) inputData_.ignoreFlags |= 0x02;
00321 <span class="keywordflow">if</span> ( midiSense ) inputData_.ignoreFlags |= 0x04;
00322 }
00323
00324 <span class="keywordtype">double</span> <a class="code" href="classRtMidiIn.html#a9">RtMidiIn :: getMessage</a>( std::vector<unsigned char> *message )
00325 {
00326 message->clear();
00327 <span class="keywordflow">if</span> ( !connected_ ) {
00328 errorString_ = <span class="stringliteral">"RtMidiIn::getNextMessage: a port is not open!"</span>;
00329 error( RtError::WARNING );
00330 <span class="keywordflow">return</span> 0.0;
00331 }
00332
00333 <span class="keywordflow">if</span> ( inputData_.usingCallback ) {
00334 errorString_ = <span class="stringliteral">"RtMidiIn::getNextMessage: a user callback is currently set for this port."</span>;
00335 error( RtError::WARNING );
00336 <span class="keywordflow">return</span> 0.0;
00337 }
00338
00339 <span class="keywordflow">if</span> ( inputData_.queue.size() == 0 ) <span class="keywordflow">return</span> 0.0;
00340
00341 <span class="comment">// Copy queued message to the vector pointer argument and then "pop" it.</span>
00342 std::vector<unsigned char> *bytes = &(inputData_.queue.front().bytes);
00343 message->assign( bytes->begin(), bytes->end() );
00344 <span class="keywordtype">double</span> deltaTime = inputData_.queue.front().timeStamp;
00345 inputData_.queue.pop();
00346
00347 <span class="keywordflow">return</span> deltaTime;
00348 }
00349
00350 <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> <a class="code" href="classRtMidiOut.html#a5">RtMidiOut :: getPortCount</a>()
00351 {
00352 <span class="keywordflow">return</span> MIDIGetNumberOfDestinations();
00353 }
00354
00355 std::string <a class="code" href="classRtMidiOut.html#a6">RtMidiOut :: getPortName</a>( <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> portNumber )
00356 {
00357 CFStringRef nameRef;
00358 MIDIEndpointRef portRef;
00359 std::ostringstream ost;
00360 <span class="keywordtype">char</span> name[128];
00361
00362 <span class="keywordflow">if</span> ( portNumber >= MIDIGetNumberOfDestinations() ) {
00363 ost << <span class="stringliteral">"RtMidiOut::getPortName: the 'portNumber' argument ("</span> << portNumber << <span class="stringliteral">") is invalid."</span>;
00364 errorString_ = ost.str();
00365 error( RtError::INVALID_PARAMETER );
00366 }
00367 portRef = MIDIGetDestination( portNumber );
00368
00369 MIDIObjectGetStringProperty( portRef, kMIDIPropertyName, &nameRef );
00370 CFStringGetCString( nameRef, name, <span class="keyword">sizeof</span>(name), 0);
00371 CFRelease( nameRef );
00372 std::string stringName = name;
00373 <span class="keywordflow">return</span> stringName;
00374 }
00375
00376 <span class="keywordtype">void</span> <a class="code" href="classRtMidiOut.html#a3">RtMidiOut :: openPort</a>( <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> portNumber )
00377 {
00378 <span class="keywordflow">if</span> ( connected_ ) {
00379 errorString_ = <span class="stringliteral">"RtMidiOut::openPort: a valid connection already exists!"</span>;
00380 error( RtError::WARNING );
00381 <span class="keywordflow">return</span>;
00382 }
00383
00384 <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> nDest = MIDIGetNumberOfDestinations();
00385 <span class="keywordflow">if</span> (nDest < 1) {
00386 errorString_ = <span class="stringliteral">"RtMidiOut::openPort: no MIDI output destinations found!"</span>;
00387 error( RtError::NO_DEVICES_FOUND );
00388 }
00389
00390 std::ostringstream ost;
00391 <span class="keywordflow">if</span> ( portNumber >= nDest ) {
00392 ost << <span class="stringliteral">"RtMidiOut::openPort: the 'portNumber' argument ("</span> << portNumber << <span class="stringliteral">") is invalid."</span>;
00393 errorString_ = ost.str();
00394 error( RtError::INVALID_PARAMETER );
00395 }
00396
00397 MIDIClientRef client;
00398 OSStatus result = MIDIClientCreate( CFSTR(<span class="stringliteral">"RtMidi Output Client"</span>), NULL, NULL, &client );
00399 <span class="keywordflow">if</span> ( result != noErr ) {
00400 errorString_ = <span class="stringliteral">"RtMidiOut::openPort: error creating OS-X MIDI client object."</span>;
00401 error( RtError::DRIVER_ERROR );
00402 }
00403
00404 MIDIPortRef port;
00405 result = MIDIOutputPortCreate( client, CFSTR(<span class="stringliteral">"RtMidi Virtual MIDI Output Port"</span>), &port );
00406 <span class="keywordflow">if</span> ( result != noErr ) {
00407 MIDIClientDispose( client );
00408 errorString_ = <span class="stringliteral">"RtMidiOut::openPort: error creating OS-X MIDI output port."</span>;
00409 error( RtError::DRIVER_ERROR );
00410 }
00411
00412 <span class="comment">// Get the desired output port identifier.</span>
00413 MIDIEndpointRef destinationId = MIDIGetDestination( portNumber );
00414 <span class="keywordflow">if</span> ( destinationId == NULL ) {
00415 MIDIPortDispose( port );
00416 MIDIClientDispose( client );
00417 errorString_ = <span class="stringliteral">"RtMidiOut::openPort: error getting MIDI output destination reference."</span>;
00418 error( RtError::DRIVER_ERROR );
00419 }
00420
00421 <span class="comment">// Save our api-specific connection information.</span>
00422 CoreMidiData *data = (CoreMidiData *) <span class="keyword">new</span> CoreMidiData;
00423 data->client = client;
00424 data->port = port;
00425 data->destinationId = destinationId;
00426 apiData_ = (<span class="keywordtype">void</span> *) data;
00427
00428 connected_ = <span class="keyword">true</span>;
00429 }
00430
00431 <span class="keywordtype">void</span> <a class="code" href="classRtMidiOut.html#a4">RtMidiOut :: closePort</a>( <span class="keywordtype">void</span> )
00432 {
00433 <span class="keywordflow">if</span> ( connected_ ) {
00434 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
00435 MIDIClientDispose( data->client );
00436 MIDIPortDispose( data->port );
00437 <span class="keyword">delete</span> data;
00438 apiData_ = 0;
00439 }
00440
00441 connected_ = <span class="keyword">false</span>;
00442 }
00443
00444 <span class="keywordtype">void</span> <a class="code" href="classRtMidiOut.html#a7">RtMidiOut :: sendMessage</a>( std::vector<unsigned char> *message )
00445 {
00446 <span class="keywordflow">if</span> ( !connected_ ) {
00447 errorString_ = <span class="stringliteral">"RtMidiOut::sendMessage: a port is not open!"</span>;
00448 error( RtError::WARNING );
00449 <span class="keywordflow">return</span>;
00450 }
00451
00452 <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> nBytes = message->size();
00453 <span class="comment">// Pad the buffer for extra (unknown) structure data.</span>
00454 Byte buffer[nBytes+32];
00455 MIDIPacketList *pktlist = (MIDIPacketList *) buffer;
00456 MIDIPacket *curPacket = MIDIPacketListInit( pktlist );
00457
00458 MIDITimeStamp timeStamp = 0;
00459 curPacket = MIDIPacketListAdd( pktlist, <span class="keyword">sizeof</span>(buffer), curPacket, timeStamp, nBytes, &message->at(0) );
00460
00461 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
00462 OSStatus result = MIDISend( data->port, data->destinationId, pktlist );
00463 <span class="keywordflow">if</span> ( result != noErr ) {
00464 errorString_ = <span class="stringliteral">"RtMidiOut::sendMessage: error sending MIDI message."</span>;
00465 error( RtError::WARNING );
00466 }
00467 }
00468
00469 <span class="preprocessor">#endif</span>
00470 <span class="preprocessor"></span>
</pre></div><HR>
<table>
<tr><td><A HREF="http://www-ccrma.stanford.edu/software/stk/"><I>The Synthesis ToolKit in C++ (STK)</I></A></td></tr>
<tr><td>©1995-2002 Perry R. Cook and Gary P. Scavone. All Rights Reserved.</td></tr>
</table>
</BODY>
</HTML>
|