To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / CollidoscopeApp / src / RtMidi.cpp @ 18:f1ff1a81be20

History | View | Annotate | Download (91.1 KB)

1
/**********************************************************************/
2
/*! \class RtMidi
3
    \brief An abstract base class for realtime MIDI input/output.
4

5
    This class implements some common functionality for the realtime
6
    MIDI input/output subclasses RtMidiIn and RtMidiOut.
7

8
    RtMidi WWW site: http://music.mcgill.ca/~gary/rtmidi/
9

10
    RtMidi: realtime MIDI i/o C++ classes
11
    Copyright (c) 2003-2016 Gary P. Scavone
12

13
    Permission is hereby granted, free of charge, to any person
14
    obtaining a copy of this software and associated documentation files
15
    (the "Software"), to deal in the Software without restriction,
16
    including without limitation the rights to use, copy, modify, merge,
17
    publish, distribute, sublicense, and/or sell copies of the Software,
18
    and to permit persons to whom the Software is furnished to do so,
19
    subject to the following conditions:
20

21
    The above copyright notice and this permission notice shall be
22
    included in all copies or substantial portions of the Software.
23

24
    Any person wishing to distribute modifications to the Software is
25
    asked to send the modifications to the original developer so that
26
    they can be incorporated into the canonical version.  This is,
27
    however, not a binding provision of this license.
28

29
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31
    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
32
    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
33
    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
34
    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35
    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36
*/
37
/**********************************************************************/
38

    
39
#include "RtMidi.h"
40
#include <sstream>
41

    
42
#if defined(__MACOSX_CORE__)
43
  #if TARGET_OS_IPHONE
44
    #define AudioGetCurrentHostTime CAHostTimeBase::GetCurrentTime
45
    #define AudioConvertHostTimeToNanos CAHostTimeBase::ConvertToNanos
46
  #endif
47
#endif
48

    
49
//*********************************************************************//
50
//  RtMidi Definitions
51
//*********************************************************************//
52

    
53
RtMidi :: RtMidi()
54
  : rtapi_(0)
55
{
56
}
57

    
58
RtMidi :: ~RtMidi()
59
{
60
  if ( rtapi_ )
61
    delete rtapi_;
62
  rtapi_ = 0;
63
}
64

    
65
std::string RtMidi :: getVersion( void ) throw()
66
{
67
  return std::string( RTMIDI_VERSION );
68
}
69

    
70
void RtMidi :: getCompiledApi( std::vector<RtMidi::Api> &apis ) throw()
71
{
72
  apis.clear();
73

    
74
  // The order here will control the order of RtMidi's API search in
75
  // the constructor.
76
#if defined(__MACOSX_CORE__)
77
  apis.push_back( MACOSX_CORE );
78
#endif
79
#if defined(__LINUX_ALSA__)
80
  apis.push_back( LINUX_ALSA );
81
#endif
82
#if defined(__UNIX_JACK__)
83
  apis.push_back( UNIX_JACK );
84
#endif
85
#if defined(__WINDOWS_MM__)
86
  apis.push_back( WINDOWS_MM );
87
#endif
88
#if defined(__RTMIDI_DUMMY__)
89
  apis.push_back( RTMIDI_DUMMY );
90
#endif
91
}
92

    
93
//*********************************************************************//
94
//  RtMidiIn Definitions
95
//*********************************************************************//
96

    
97
void RtMidiIn :: openMidiApi( RtMidi::Api api, const std::string clientName, unsigned int queueSizeLimit )
98
{
99
  if ( rtapi_ )
100
    delete rtapi_;
101
  rtapi_ = 0;
102

    
103
#if defined(__UNIX_JACK__)
104
  if ( api == UNIX_JACK )
105
    rtapi_ = new MidiInJack( clientName, queueSizeLimit );
106
#endif
107
#if defined(__LINUX_ALSA__)
108
  if ( api == LINUX_ALSA )
109
    rtapi_ = new MidiInAlsa( clientName, queueSizeLimit );
110
#endif
111
#if defined(__WINDOWS_MM__)
112
  if ( api == WINDOWS_MM )
113
    rtapi_ = new MidiInWinMM( clientName, queueSizeLimit );
114
#endif
115
#if defined(__MACOSX_CORE__)
116
  if ( api == MACOSX_CORE )
117
    rtapi_ = new MidiInCore( clientName, queueSizeLimit );
118
#endif
119
#if defined(__RTMIDI_DUMMY__)
120
  if ( api == RTMIDI_DUMMY )
121
    rtapi_ = new MidiInDummy( clientName, queueSizeLimit );
122
#endif
123
}
124

    
125
RtMidiIn :: RtMidiIn( RtMidi::Api api, const std::string clientName, unsigned int queueSizeLimit )
126
  : RtMidi()
127
{
128
  if ( api != UNSPECIFIED ) {
129
    // Attempt to open the specified API.
130
    openMidiApi( api, clientName, queueSizeLimit );
131
    if ( rtapi_ ) return;
132

    
133
    // No compiled support for specified API value.  Issue a warning
134
    // and continue as if no API was specified.
135
    std::cerr << "\nRtMidiIn: no compiled support for specified API argument!\n\n" << std::endl;
136
  }
137

    
138
  // Iterate through the compiled APIs and return as soon as we find
139
  // one with at least one port or we reach the end of the list.
140
  std::vector< RtMidi::Api > apis;
141
  getCompiledApi( apis );
142
  for ( unsigned int i=0; i<apis.size(); i++ ) {
143
    openMidiApi( apis[i], clientName, queueSizeLimit );
144
    if ( rtapi_->getPortCount() ) break;
145
  }
146

    
147
  if ( rtapi_ ) return;
148

    
149
  // It should not be possible to get here because the preprocessor
150
  // definition __RTMIDI_DUMMY__ is automatically defined if no
151
  // API-specific definitions are passed to the compiler. But just in
152
  // case something weird happens, we'll throw an error.
153
  std::string errorText = "RtMidiIn: no compiled API support found ... critical error!!";
154
  throw( RtMidiError( errorText, RtMidiError::UNSPECIFIED ) );
155
}
156

    
157
RtMidiIn :: ~RtMidiIn() throw()
158
{
159
}
160

    
161

    
162
//*********************************************************************//
163
//  RtMidiOut Definitions
164
//*********************************************************************//
165

    
166
void RtMidiOut :: openMidiApi( RtMidi::Api api, const std::string clientName )
167
{
168
  if ( rtapi_ )
169
    delete rtapi_;
170
  rtapi_ = 0;
171

    
172
#if defined(__UNIX_JACK__)
173
  if ( api == UNIX_JACK )
174
    rtapi_ = new MidiOutJack( clientName );
175
#endif
176
#if defined(__LINUX_ALSA__)
177
  if ( api == LINUX_ALSA )
178
    rtapi_ = new MidiOutAlsa( clientName );
179
#endif
180
#if defined(__WINDOWS_MM__)
181
  if ( api == WINDOWS_MM )
182
    rtapi_ = new MidiOutWinMM( clientName );
183
#endif
184
#if defined(__MACOSX_CORE__)
185
  if ( api == MACOSX_CORE )
186
    rtapi_ = new MidiOutCore( clientName );
187
#endif
188
#if defined(__RTMIDI_DUMMY__)
189
  if ( api == RTMIDI_DUMMY )
190
    rtapi_ = new MidiOutDummy( clientName );
191
#endif
192
}
193

    
194
RtMidiOut :: RtMidiOut( RtMidi::Api api, const std::string clientName )
195
{
196
  if ( api != UNSPECIFIED ) {
197
    // Attempt to open the specified API.
198
    openMidiApi( api, clientName );
199
    if ( rtapi_ ) return;
200

    
201
    // No compiled support for specified API value.  Issue a warning
202
    // and continue as if no API was specified.
203
    std::cerr << "\nRtMidiOut: no compiled support for specified API argument!\n\n" << std::endl;
204
  }
205

    
206
  // Iterate through the compiled APIs and return as soon as we find
207
  // one with at least one port or we reach the end of the list.
208
  std::vector< RtMidi::Api > apis;
209
  getCompiledApi( apis );
210
  for ( unsigned int i=0; i<apis.size(); i++ ) {
211
    openMidiApi( apis[i], clientName );
212
    if ( rtapi_->getPortCount() ) break;
213
  }
214

    
215
  if ( rtapi_ ) return;
216

    
217
  // It should not be possible to get here because the preprocessor
218
  // definition __RTMIDI_DUMMY__ is automatically defined if no
219
  // API-specific definitions are passed to the compiler. But just in
220
  // case something weird happens, we'll thrown an error.
221
  std::string errorText = "RtMidiOut: no compiled API support found ... critical error!!";
222
  throw( RtMidiError( errorText, RtMidiError::UNSPECIFIED ) );
223
}
224

    
225
RtMidiOut :: ~RtMidiOut() throw()
226
{
227
}
228

    
229
//*********************************************************************//
230
//  Common MidiApi Definitions
231
//*********************************************************************//
232

    
233
MidiApi :: MidiApi( void )
234
  : apiData_( 0 ), connected_( false ), errorCallback_(0), errorCallbackUserData_(0)
235
{
236
}
237

    
238
MidiApi :: ~MidiApi( void )
239
{
240
}
241

    
242
void MidiApi :: setErrorCallback( RtMidiErrorCallback errorCallback, void *userData = 0 )
243
{
244
    errorCallback_ = errorCallback;
245
    errorCallbackUserData_ = userData;
246
}
247

    
248
void MidiApi :: error( RtMidiError::Type type, std::string errorString )
249
{
250
  if ( errorCallback_ ) {
251

    
252
    if ( firstErrorOccurred_ )
253
      return;
254

    
255
    firstErrorOccurred_ = true;
256
    const std::string errorMessage = errorString;
257

    
258
    errorCallback_( type, errorMessage, errorCallbackUserData_);
259
    firstErrorOccurred_ = false;
260
    return;
261
  }
262

    
263
  if ( type == RtMidiError::WARNING ) {
264
    std::cerr << '\n' << errorString << "\n\n";
265
  }
266
  else if ( type == RtMidiError::DEBUG_WARNING ) {
267
#if defined(__RTMIDI_DEBUG__)
268
    std::cerr << '\n' << errorString << "\n\n";
269
#endif
270
  }
271
  else {
272
    std::cerr << '\n' << errorString << "\n\n";
273
    throw RtMidiError( errorString, type );
274
  }
275
}
276

    
277
//*********************************************************************//
278
//  Common MidiInApi Definitions
279
//*********************************************************************//
280

    
281
MidiInApi :: MidiInApi( unsigned int queueSizeLimit )
282
  : MidiApi()
283
{
284
  // Allocate the MIDI queue.
285
  inputData_.queue.ringSize = queueSizeLimit;
286
  if ( inputData_.queue.ringSize > 0 )
287
    inputData_.queue.ring = new MidiMessage[ inputData_.queue.ringSize ];
288
}
289

    
290
MidiInApi :: ~MidiInApi( void )
291
{
292
  // Delete the MIDI queue.
293
  if ( inputData_.queue.ringSize > 0 ) delete [] inputData_.queue.ring;
294
}
295

    
296
void MidiInApi :: setCallback( RtMidiIn::RtMidiCallback callback, void *userData )
297
{
298
  if ( inputData_.usingCallback ) {
299
    errorString_ = "MidiInApi::setCallback: a callback function is already set!";
300
    error( RtMidiError::WARNING, errorString_ );
301
    return;
302
  }
303

    
304
  if ( !callback ) {
305
    errorString_ = "RtMidiIn::setCallback: callback function value is invalid!";
306
    error( RtMidiError::WARNING, errorString_ );
307
    return;
308
  }
309

    
310
  inputData_.userCallback = callback;
311
  inputData_.userData = userData;
312
  inputData_.usingCallback = true;
313
}
314

    
315
void MidiInApi :: cancelCallback()
316
{
317
  if ( !inputData_.usingCallback ) {
318
    errorString_ = "RtMidiIn::cancelCallback: no callback function was set!";
319
    error( RtMidiError::WARNING, errorString_ );
320
    return;
321
  }
322

    
323
  inputData_.userCallback = 0;
324
  inputData_.userData = 0;
325
  inputData_.usingCallback = false;
326
}
327

    
328
void MidiInApi :: ignoreTypes( bool midiSysex, bool midiTime, bool midiSense )
329
{
330
  inputData_.ignoreFlags = 0;
331
  if ( midiSysex ) inputData_.ignoreFlags = 0x01;
332
  if ( midiTime ) inputData_.ignoreFlags |= 0x02;
333
  if ( midiSense ) inputData_.ignoreFlags |= 0x04;
334
}
335

    
336
double MidiInApi :: getMessage( std::vector<unsigned char> *message )
337
{
338
  message->clear();
339

    
340
  if ( inputData_.usingCallback ) {
341
    errorString_ = "RtMidiIn::getNextMessage: a user callback is currently set for this port.";
342
    error( RtMidiError::WARNING, errorString_ );
343
    return 0.0;
344
  }
345

    
346
  if ( inputData_.queue.size == 0 ) return 0.0;
347

    
348
  // Copy queued message to the vector pointer argument and then "pop" it.
349
  std::vector<unsigned char> *bytes = &(inputData_.queue.ring[inputData_.queue.front].bytes);
350
  message->assign( bytes->begin(), bytes->end() );
351
  double deltaTime = inputData_.queue.ring[inputData_.queue.front].timeStamp;
352
  inputData_.queue.size--;
353
  inputData_.queue.front++;
354
  if ( inputData_.queue.front == inputData_.queue.ringSize )
355
    inputData_.queue.front = 0;
356

    
357
  return deltaTime;
358
}
359

    
360
//*********************************************************************//
361
//  Common MidiOutApi Definitions
362
//*********************************************************************//
363

    
364
MidiOutApi :: MidiOutApi( void )
365
  : MidiApi()
366
{
367
}
368

    
369
MidiOutApi :: ~MidiOutApi( void )
370
{
371
}
372

    
373
// *************************************************** //
374
//
375
// OS/API-specific methods.
376
//
377
// *************************************************** //
378

    
379
#if defined(__MACOSX_CORE__)
380

    
381
// The CoreMIDI API is based on the use of a callback function for
382
// MIDI input.  We convert the system specific time stamps to delta
383
// time values.
384

    
385
// OS-X CoreMIDI header files.
386
#include <CoreMIDI/CoreMIDI.h>
387
#include <CoreAudio/HostTime.h>
388
#include <CoreServices/CoreServices.h>
389

    
390
// A structure to hold variables related to the CoreMIDI API
391
// implementation.
392
struct CoreMidiData {
393
  MIDIClientRef client;
394
  MIDIPortRef port;
395
  MIDIEndpointRef endpoint;
396
  MIDIEndpointRef destinationId;
397
  unsigned long long lastTime;
398
  MIDISysexSendRequest sysexreq;
399
};
400

    
401
//*********************************************************************//
402
//  API: OS-X
403
//  Class Definitions: MidiInCore
404
//*********************************************************************//
405

    
406
static void midiInputCallback( const MIDIPacketList *list, void *procRef, void */*srcRef*/ )
407
{
408
  MidiInApi::RtMidiInData *data = static_cast<MidiInApi::RtMidiInData *> (procRef);
409
  CoreMidiData *apiData = static_cast<CoreMidiData *> (data->apiData);
410

    
411
  unsigned char status;
412
  unsigned short nBytes, iByte, size;
413
  unsigned long long time;
414

    
415
  bool& continueSysex = data->continueSysex;
416
  MidiInApi::MidiMessage& message = data->message;
417

    
418
  const MIDIPacket *packet = &list->packet[0];
419
  for ( unsigned int i=0; i<list->numPackets; ++i ) {
420

    
421
    // My interpretation of the CoreMIDI documentation: all message
422
    // types, except sysex, are complete within a packet and there may
423
    // be several of them in a single packet.  Sysex messages can be
424
    // broken across multiple packets and PacketLists but are bundled
425
    // alone within each packet (these packets do not contain other
426
    // message types).  If sysex messages are split across multiple
427
    // MIDIPacketLists, they must be handled by multiple calls to this
428
    // function.
429

    
430
    nBytes = packet->length;
431
    if ( nBytes == 0 ) continue;
432

    
433
    // Calculate time stamp.
434

    
435
    if ( data->firstMessage ) {
436
      message.timeStamp = 0.0;
437
      data->firstMessage = false;
438
    }
439
    else {
440
      time = packet->timeStamp;
441
      if ( time == 0 ) { // this happens when receiving asynchronous sysex messages
442
        time = AudioGetCurrentHostTime();
443
      }
444
      time -= apiData->lastTime;
445
      time = AudioConvertHostTimeToNanos( time );
446
      if ( !continueSysex )
447
        message.timeStamp = time * 0.000000001;
448
    }
449
    apiData->lastTime = packet->timeStamp;
450
    if ( apiData->lastTime == 0 ) { // this happens when receiving asynchronous sysex messages
451
      apiData->lastTime = AudioGetCurrentHostTime();
452
    }
453
    //std::cout << "TimeStamp = " << packet->timeStamp << std::endl;
454

    
455
    iByte = 0;
456
    if ( continueSysex ) {
457
      // We have a continuing, segmented sysex message.
458
      if ( !( data->ignoreFlags & 0x01 ) ) {
459
        // If we're not ignoring sysex messages, copy the entire packet.
460
        for ( unsigned int j=0; j<nBytes; ++j )
461
          message.bytes.push_back( packet->data[j] );
462
      }
463
      continueSysex = packet->data[nBytes-1] != 0xF7;
464

    
465
      if ( !( data->ignoreFlags & 0x01 ) && !continueSysex ) {
466
        // If not a continuing sysex message, invoke the user callback function or queue the message.
467
        if ( data->usingCallback ) {
468
          RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
469
          callback( message.timeStamp, &message.bytes, data->userData );
470
        }
471
        else {
472
          // As long as we haven't reached our queue size limit, push the message.
473
          if ( data->queue.size < data->queue.ringSize ) {
474
            data->queue.ring[data->queue.back++] = message;
475
            if ( data->queue.back == data->queue.ringSize )
476
              data->queue.back = 0;
477
            data->queue.size++;
478
          }
479
          else
480
            std::cerr << "\nMidiInCore: message queue limit reached!!\n\n";
481
        }
482
        message.bytes.clear();
483
      }
484
    }
485
    else {
486
      while ( iByte < nBytes ) {
487
        size = 0;
488
        // We are expecting that the next byte in the packet is a status byte.
489
        status = packet->data[iByte];
490
        if ( !(status & 0x80) ) break;
491
        // Determine the number of bytes in the MIDI message.
492
        if ( status < 0xC0 ) size = 3;
493
        else if ( status < 0xE0 ) size = 2;
494
        else if ( status < 0xF0 ) size = 3;
495
        else if ( status == 0xF0 ) {
496
          // A MIDI sysex
497
          if ( data->ignoreFlags & 0x01 ) {
498
            size = 0;
499
            iByte = nBytes;
500
          }
501
          else size = nBytes - iByte;
502
          continueSysex = packet->data[nBytes-1] != 0xF7;
503
        }
504
        else if ( status == 0xF1 ) {
505
            // A MIDI time code message
506
           if ( data->ignoreFlags & 0x02 ) {
507
            size = 0;
508
            iByte += 2;
509
           }
510
           else size = 2;
511
        }
512
        else if ( status == 0xF2 ) size = 3;
513
        else if ( status == 0xF3 ) size = 2;
514
        else if ( status == 0xF8 && ( data->ignoreFlags & 0x02 ) ) {
515
          // A MIDI timing tick message and we're ignoring it.
516
          size = 0;
517
          iByte += 1;
518
        }
519
        else if ( status == 0xFE && ( data->ignoreFlags & 0x04 ) ) {
520
          // A MIDI active sensing message and we're ignoring it.
521
          size = 0;
522
          iByte += 1;
523
        }
524
        else size = 1;
525

    
526
        // Copy the MIDI data to our vector.
527
        if ( size ) {
528
          message.bytes.assign( &packet->data[iByte], &packet->data[iByte+size] );
529
          if ( !continueSysex ) {
530
            // If not a continuing sysex message, invoke the user callback function or queue the message.
531
            if ( data->usingCallback ) {
532
              RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
533
              callback( message.timeStamp, &message.bytes, data->userData );
534
            }
535
            else {
536
              // As long as we haven't reached our queue size limit, push the message.
537
              if ( data->queue.size < data->queue.ringSize ) {
538
                data->queue.ring[data->queue.back++] = message;
539
                if ( data->queue.back == data->queue.ringSize )
540
                  data->queue.back = 0;
541
                data->queue.size++;
542
              }
543
              else
544
                std::cerr << "\nMidiInCore: message queue limit reached!!\n\n";
545
            }
546
            message.bytes.clear();
547
          }
548
          iByte += size;
549
        }
550
      }
551
    }
552
    packet = MIDIPacketNext(packet);
553
  }
554
}
555

    
556
MidiInCore :: MidiInCore( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
557
{
558
  initialize( clientName );
559
}
560

    
561
MidiInCore :: ~MidiInCore( void )
562
{
563
  // Close a connection if it exists.
564
  closePort();
565

    
566
  // Cleanup.
567
  CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
568
  MIDIClientDispose( data->client );
569
  if ( data->endpoint ) MIDIEndpointDispose( data->endpoint );
570
  delete data;
571
}
572

    
573
void MidiInCore :: initialize( const std::string& clientName )
574
{
575
  // Set up our client.
576
  MIDIClientRef client;
577
  CFStringRef name = CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII );
578
  OSStatus result = MIDIClientCreate(name, NULL, NULL, &client );
579
  if ( result != noErr ) {
580
    errorString_ = "MidiInCore::initialize: error creating OS-X MIDI client object.";
581
    error( RtMidiError::DRIVER_ERROR, errorString_ );
582
    return;
583
  }
584

    
585
  // Save our api-specific connection information.
586
  CoreMidiData *data = (CoreMidiData *) new CoreMidiData;
587
  data->client = client;
588
  data->endpoint = 0;
589
  apiData_ = (void *) data;
590
  inputData_.apiData = (void *) data;
591
  CFRelease(name);
592
}
593

    
594
void MidiInCore :: openPort( unsigned int portNumber, const std::string portName )
595
{
596
  if ( connected_ ) {
597
    errorString_ = "MidiInCore::openPort: a valid connection already exists!";
598
    error( RtMidiError::WARNING, errorString_ );
599
    return;
600
  }
601

    
602
  CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
603
  unsigned int nSrc = MIDIGetNumberOfSources();
604
  if (nSrc < 1) {
605
    errorString_ = "MidiInCore::openPort: no MIDI input sources found!";
606
    error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
607
    return;
608
  }
609

    
610
  if ( portNumber >= nSrc ) {
611
    std::ostringstream ost;
612
    ost << "MidiInCore::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
613
    errorString_ = ost.str();
614
    error( RtMidiError::INVALID_PARAMETER, errorString_ );
615
    return;
616
  }
617

    
618
  MIDIPortRef port;
619
  CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
620
  OSStatus result = MIDIInputPortCreate( data->client, 
621
                                         CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ),
622
                                         midiInputCallback, (void *)&inputData_, &port );
623
  if ( result != noErr ) {
624
    MIDIClientDispose( data->client );
625
    errorString_ = "MidiInCore::openPort: error creating OS-X MIDI input port.";
626
    error( RtMidiError::DRIVER_ERROR, errorString_ );
627
    return;
628
  }
629

    
630
  // Get the desired input source identifier.
631
  MIDIEndpointRef endpoint = MIDIGetSource( portNumber );
632
  if ( endpoint == 0 ) {
633
    MIDIPortDispose( port );
634
    MIDIClientDispose( data->client );
635
    errorString_ = "MidiInCore::openPort: error getting MIDI input source reference.";
636
    error( RtMidiError::DRIVER_ERROR, errorString_ );
637
    return;
638
  }
639

    
640
  // Make the connection.
641
  result = MIDIPortConnectSource( port, endpoint, NULL );
642
  if ( result != noErr ) {
643
    MIDIPortDispose( port );
644
    MIDIClientDispose( data->client );
645
    errorString_ = "MidiInCore::openPort: error connecting OS-X MIDI input port.";
646
    error( RtMidiError::DRIVER_ERROR, errorString_ );
647
    return;
648
  }
649

    
650
  // Save our api-specific port information.
651
  data->port = port;
652

    
653
  connected_ = true;
654
}
655

    
656
void MidiInCore :: openVirtualPort( const std::string portName )
657
{
658
  CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
659

    
660
  // Create a virtual MIDI input destination.
661
  MIDIEndpointRef endpoint;
662
  OSStatus result = MIDIDestinationCreate( data->client,
663
                                           CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ),
664
                                           midiInputCallback, (void *)&inputData_, &endpoint );
665
  if ( result != noErr ) {
666
    errorString_ = "MidiInCore::openVirtualPort: error creating virtual OS-X MIDI destination.";
667
    error( RtMidiError::DRIVER_ERROR, errorString_ );
668
    return;
669
  }
670

    
671
  // Save our api-specific connection information.
672
  data->endpoint = endpoint;
673
}
674

    
675
void MidiInCore :: closePort( void )
676
{
677
  CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
678

    
679
  if ( data->endpoint ) {
680
    MIDIEndpointDispose( data->endpoint );
681
  }
682

    
683
  if ( data->port ) {
684
    MIDIPortDispose( data->port );
685
  }
686

    
687
  connected_ = false;
688
}
689

    
690
unsigned int MidiInCore :: getPortCount()
691
{
692
  CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
693
  return MIDIGetNumberOfSources();
694
}
695

    
696
// This function was submitted by Douglas Casey Tucker and apparently
697
// derived largely from PortMidi.
698
CFStringRef EndpointName( MIDIEndpointRef endpoint, bool isExternal )
699
{
700
  CFMutableStringRef result = CFStringCreateMutable( NULL, 0 );
701
  CFStringRef str;
702

    
703
  // Begin with the endpoint's name.
704
  str = NULL;
705
  MIDIObjectGetStringProperty( endpoint, kMIDIPropertyName, &str );
706
  if ( str != NULL ) {
707
    CFStringAppend( result, str );
708
    CFRelease( str );
709
  }
710

    
711
  MIDIEntityRef entity = 0;
712
  MIDIEndpointGetEntity( endpoint, &entity );
713
  if ( entity == 0 )
714
    // probably virtual
715
    return result;
716

    
717
  if ( CFStringGetLength( result ) == 0 ) {
718
    // endpoint name has zero length -- try the entity
719
    str = NULL;
720
    MIDIObjectGetStringProperty( entity, kMIDIPropertyName, &str );
721
    if ( str != NULL ) {
722
      CFStringAppend( result, str );
723
      CFRelease( str );
724
    }
725
  }
726
  // now consider the device's name
727
  MIDIDeviceRef device = 0;
728
  MIDIEntityGetDevice( entity, &device );
729
  if ( device == 0 )
730
    return result;
731

    
732
  str = NULL;
733
  MIDIObjectGetStringProperty( device, kMIDIPropertyName, &str );
734
  if ( CFStringGetLength( result ) == 0 ) {
735
      CFRelease( result );
736
      return str;
737
  }
738
  if ( str != NULL ) {
739
    // if an external device has only one entity, throw away
740
    // the endpoint name and just use the device name
741
    if ( isExternal && MIDIDeviceGetNumberOfEntities( device ) < 2 ) {
742
      CFRelease( result );
743
      return str;
744
    } else {
745
      if ( CFStringGetLength( str ) == 0 ) {
746
        CFRelease( str );
747
        return result;
748
      }
749
      // does the entity name already start with the device name?
750
      // (some drivers do this though they shouldn't)
751
      // if so, do not prepend
752
        if ( CFStringCompareWithOptions( result, /* endpoint name */
753
             str /* device name */,
754
             CFRangeMake(0, CFStringGetLength( str ) ), 0 ) != kCFCompareEqualTo ) {
755
        // prepend the device name to the entity name
756
        if ( CFStringGetLength( result ) > 0 )
757
          CFStringInsert( result, 0, CFSTR(" ") );
758
        CFStringInsert( result, 0, str );
759
      }
760
      CFRelease( str );
761
    }
762
  }
763
  return result;
764
}
765

    
766
// This function was submitted by Douglas Casey Tucker and apparently
767
// derived largely from PortMidi.
768
static CFStringRef ConnectedEndpointName( MIDIEndpointRef endpoint )
769
{
770
  CFMutableStringRef result = CFStringCreateMutable( NULL, 0 );
771
  CFStringRef str;
772
  OSStatus err;
773
  int i;
774

    
775
  // Does the endpoint have connections?
776
  CFDataRef connections = NULL;
777
  int nConnected = 0;
778
  bool anyStrings = false;
779
  err = MIDIObjectGetDataProperty( endpoint, kMIDIPropertyConnectionUniqueID, &connections );
780
  if ( connections != NULL ) {
781
    // It has connections, follow them
782
    // Concatenate the names of all connected devices
783
    nConnected = CFDataGetLength( connections ) / sizeof(MIDIUniqueID);
784
    if ( nConnected ) {
785
      const SInt32 *pid = (const SInt32 *)(CFDataGetBytePtr(connections));
786
      for ( i=0; i<nConnected; ++i, ++pid ) {
787
        MIDIUniqueID id = EndianS32_BtoN( *pid );
788
        MIDIObjectRef connObject;
789
        MIDIObjectType connObjectType;
790
        err = MIDIObjectFindByUniqueID( id, &connObject, &connObjectType );
791
        if ( err == noErr ) {
792
          if ( connObjectType == kMIDIObjectType_ExternalSource  ||
793
              connObjectType == kMIDIObjectType_ExternalDestination ) {
794
            // Connected to an external device's endpoint (10.3 and later).
795
            str = EndpointName( (MIDIEndpointRef)(connObject), true );
796
          } else {
797
            // Connected to an external device (10.2) (or something else, catch-
798
            str = NULL;
799
            MIDIObjectGetStringProperty( connObject, kMIDIPropertyName, &str );
800
          }
801
          if ( str != NULL ) {
802
            if ( anyStrings )
803
              CFStringAppend( result, CFSTR(", ") );
804
            else anyStrings = true;
805
            CFStringAppend( result, str );
806
            CFRelease( str );
807
          }
808
        }
809
      }
810
    }
811
    CFRelease( connections );
812
  }
813
  if ( anyStrings )
814
    return result;
815

    
816
  CFRelease( result );
817

    
818
  // Here, either the endpoint had no connections, or we failed to obtain names 
819
  return EndpointName( endpoint, false );
820
}
821

    
822
std::string MidiInCore :: getPortName( unsigned int portNumber )
823
{
824
  CFStringRef nameRef;
825
  MIDIEndpointRef portRef;
826
  char name[128];
827

    
828
  std::string stringName;
829
  CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
830
  if ( portNumber >= MIDIGetNumberOfSources() ) {
831
    std::ostringstream ost;
832
    ost << "MidiInCore::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
833
    errorString_ = ost.str();
834
    error( RtMidiError::WARNING, errorString_ );
835
    return stringName;
836
  }
837

    
838
  portRef = MIDIGetSource( portNumber );
839
  nameRef = ConnectedEndpointName(portRef);
840
  CFStringGetCString( nameRef, name, sizeof(name), CFStringGetSystemEncoding());
841
  CFRelease( nameRef );
842

    
843
  return stringName = name;
844
}
845

    
846
//*********************************************************************//
847
//  API: OS-X
848
//  Class Definitions: MidiOutCore
849
//*********************************************************************//
850

    
851
MidiOutCore :: MidiOutCore( const std::string clientName ) : MidiOutApi()
852
{
853
  initialize( clientName );
854
}
855

    
856
MidiOutCore :: ~MidiOutCore( void )
857
{
858
  // Close a connection if it exists.
859
  closePort();
860

    
861
  // Cleanup.
862
  CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
863
  MIDIClientDispose( data->client );
864
  if ( data->endpoint ) MIDIEndpointDispose( data->endpoint );
865
  delete data;
866
}
867

    
868
void MidiOutCore :: initialize( const std::string& clientName )
869
{
870
  // Set up our client.
871
  MIDIClientRef client;
872
  CFStringRef name = CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII );
873
  OSStatus result = MIDIClientCreate(name, NULL, NULL, &client );
874
  if ( result != noErr ) {
875
    errorString_ = "MidiOutCore::initialize: error creating OS-X MIDI client object.";
876
    error( RtMidiError::DRIVER_ERROR, errorString_ );
877
    return;
878
  }
879

    
880
  // Save our api-specific connection information.
881
  CoreMidiData *data = (CoreMidiData *) new CoreMidiData;
882
  data->client = client;
883
  data->endpoint = 0;
884
  apiData_ = (void *) data;
885
  CFRelease( name );
886
}
887

    
888
unsigned int MidiOutCore :: getPortCount()
889
{
890
  CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
891
  return MIDIGetNumberOfDestinations();
892
}
893

    
894
std::string MidiOutCore :: getPortName( unsigned int portNumber )
895
{
896
  CFStringRef nameRef;
897
  MIDIEndpointRef portRef;
898
  char name[128];
899

    
900
  std::string stringName;
901
  CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
902
  if ( portNumber >= MIDIGetNumberOfDestinations() ) {
903
    std::ostringstream ost;
904
    ost << "MidiOutCore::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
905
    errorString_ = ost.str();
906
    error( RtMidiError::WARNING, errorString_ );
907
    return stringName;
908
  }
909

    
910
  portRef = MIDIGetDestination( portNumber );
911
  nameRef = ConnectedEndpointName(portRef);
912
  CFStringGetCString( nameRef, name, sizeof(name), CFStringGetSystemEncoding());
913
  CFRelease( nameRef );
914
  
915
  return stringName = name;
916
}
917

    
918
void MidiOutCore :: openPort( unsigned int portNumber, const std::string portName )
919
{
920
  if ( connected_ ) {
921
    errorString_ = "MidiOutCore::openPort: a valid connection already exists!";
922
    error( RtMidiError::WARNING, errorString_ );
923
    return;
924
  }
925

    
926
  CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
927
  unsigned int nDest = MIDIGetNumberOfDestinations();
928
  if (nDest < 1) {
929
    errorString_ = "MidiOutCore::openPort: no MIDI output destinations found!";
930
    error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
931
    return;
932
  }
933

    
934
  if ( portNumber >= nDest ) {
935
    std::ostringstream ost;
936
    ost << "MidiOutCore::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
937
    errorString_ = ost.str();
938
    error( RtMidiError::INVALID_PARAMETER, errorString_ );
939
    return;
940
  }
941

    
942
  MIDIPortRef port;
943
  CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
944
  OSStatus result = MIDIOutputPortCreate( data->client, 
945
                                          CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ),
946
                                          &port );
947
  if ( result != noErr ) {
948
    MIDIClientDispose( data->client );
949
    errorString_ = "MidiOutCore::openPort: error creating OS-X MIDI output port.";
950
    error( RtMidiError::DRIVER_ERROR, errorString_ );
951
    return;
952
  }
953

    
954
  // Get the desired output port identifier.
955
  MIDIEndpointRef destination = MIDIGetDestination( portNumber );
956
  if ( destination == 0 ) {
957
    MIDIPortDispose( port );
958
    MIDIClientDispose( data->client );
959
    errorString_ = "MidiOutCore::openPort: error getting MIDI output destination reference.";
960
    error( RtMidiError::DRIVER_ERROR, errorString_ );
961
    return;
962
  }
963

    
964
  // Save our api-specific connection information.
965
  data->port = port;
966
  data->destinationId = destination;
967
  connected_ = true;
968
}
969

    
970
void MidiOutCore :: closePort( void )
971
{
972
  CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
973

    
974
  if ( data->endpoint ) {
975
    MIDIEndpointDispose( data->endpoint );
976
  }
977

    
978
  if ( data->port ) {
979
    MIDIPortDispose( data->port );
980
  }
981

    
982
  connected_ = false;
983
}
984

    
985
void MidiOutCore :: openVirtualPort( std::string portName )
986
{
987
  CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
988

    
989
  if ( data->endpoint ) {
990
    errorString_ = "MidiOutCore::openVirtualPort: a virtual output port already exists!";
991
    error( RtMidiError::WARNING, errorString_ );
992
    return;
993
  }
994

    
995
  // Create a virtual MIDI output source.
996
  MIDIEndpointRef endpoint;
997
  OSStatus result = MIDISourceCreate( data->client,
998
                                      CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ),
999
                                      &endpoint );
1000
  if ( result != noErr ) {
1001
    errorString_ = "MidiOutCore::initialize: error creating OS-X virtual MIDI source.";
1002
    error( RtMidiError::DRIVER_ERROR, errorString_ );
1003
    return;
1004
  }
1005

    
1006
  // Save our api-specific connection information.
1007
  data->endpoint = endpoint;
1008
}
1009

    
1010
void MidiOutCore :: sendMessage( std::vector<unsigned char> *message )
1011
{
1012
  // We use the MIDISendSysex() function to asynchronously send sysex
1013
  // messages.  Otherwise, we use a single CoreMidi MIDIPacket.
1014
  unsigned int nBytes = message->size();
1015
  if ( nBytes == 0 ) {
1016
    errorString_ = "MidiOutCore::sendMessage: no data in message argument!";      
1017
    error( RtMidiError::WARNING, errorString_ );
1018
    return;
1019
  }
1020

    
1021
  MIDITimeStamp timeStamp = AudioGetCurrentHostTime();
1022
  CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
1023
  OSStatus result;
1024

    
1025
  if ( message->at(0) != 0xF0 && nBytes > 3 ) {
1026
    errorString_ = "MidiOutCore::sendMessage: message format problem ... not sysex but > 3 bytes?";
1027
    error( RtMidiError::WARNING, errorString_ );
1028
    return;
1029
  }
1030

    
1031
  Byte buffer[nBytes+(sizeof(MIDIPacketList))];
1032
  ByteCount listSize = sizeof(buffer);
1033
  MIDIPacketList *packetList = (MIDIPacketList*)buffer;
1034
  MIDIPacket *packet = MIDIPacketListInit( packetList );
1035

    
1036
  ByteCount remainingBytes = nBytes;
1037
  while (remainingBytes && packet) {
1038
    ByteCount bytesForPacket = remainingBytes > 65535 ? 65535 : remainingBytes; // 65535 = maximum size of a MIDIPacket
1039
    const Byte* dataStartPtr = (const Byte *) &message->at( nBytes - remainingBytes );
1040
    packet = MIDIPacketListAdd( packetList, listSize, packet, timeStamp, bytesForPacket, dataStartPtr);
1041
    remainingBytes -= bytesForPacket; 
1042
  }
1043

    
1044
  if ( !packet ) {
1045
    errorString_ = "MidiOutCore::sendMessage: could not allocate packet list";      
1046
    error( RtMidiError::DRIVER_ERROR, errorString_ );
1047
    return;
1048
  }
1049

    
1050
  // Send to any destinations that may have connected to us.
1051
  if ( data->endpoint ) {
1052
    result = MIDIReceived( data->endpoint, packetList );
1053
    if ( result != noErr ) {
1054
      errorString_ = "MidiOutCore::sendMessage: error sending MIDI to virtual destinations.";
1055
      error( RtMidiError::WARNING, errorString_ );
1056
    }
1057
  }
1058

    
1059
  // And send to an explicit destination port if we're connected.
1060
  if ( connected_ ) {
1061
    result = MIDISend( data->port, data->destinationId, packetList );
1062
    if ( result != noErr ) {
1063
      errorString_ = "MidiOutCore::sendMessage: error sending MIDI message to port.";
1064
      error( RtMidiError::WARNING, errorString_ );
1065
    }
1066
  }
1067
}
1068

    
1069
#endif  // __MACOSX_CORE__
1070

    
1071

    
1072
//*********************************************************************//
1073
//  API: LINUX ALSA SEQUENCER
1074
//*********************************************************************//
1075

    
1076
// API information found at:
1077
//   - http://www.alsa-project.org/documentation.php#Library
1078

    
1079
#if defined(__LINUX_ALSA__)
1080

    
1081
// The ALSA Sequencer API is based on the use of a callback function for
1082
// MIDI input.
1083
//
1084
// Thanks to Pedro Lopez-Cabanillas for help with the ALSA sequencer
1085
// time stamps and other assorted fixes!!!
1086

    
1087
// If you don't need timestamping for incoming MIDI events, define the
1088
// preprocessor definition AVOID_TIMESTAMPING to save resources
1089
// associated with the ALSA sequencer queues.
1090

    
1091
#include <pthread.h>
1092
#include <sys/time.h>
1093

    
1094
// ALSA header file.
1095
#include <alsa/asoundlib.h>
1096

    
1097
// A structure to hold variables related to the ALSA API
1098
// implementation.
1099
struct AlsaMidiData {
1100
  snd_seq_t *seq;
1101
  unsigned int portNum;
1102
  int vport;
1103
  snd_seq_port_subscribe_t *subscription;
1104
  snd_midi_event_t *coder;
1105
  unsigned int bufferSize;
1106
  unsigned char *buffer;
1107
  pthread_t thread;
1108
  pthread_t dummy_thread_id;
1109
  unsigned long long lastTime;
1110
  int queue_id; // an input queue is needed to get timestamped events
1111
  int trigger_fds[2];
1112
};
1113

    
1114
#define PORT_TYPE( pinfo, bits ) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits))
1115

    
1116
//*********************************************************************//
1117
//  API: LINUX ALSA
1118
//  Class Definitions: MidiInAlsa
1119
//*********************************************************************//
1120

    
1121
static void *alsaMidiHandler( void *ptr )
1122
{
1123
  MidiInApi::RtMidiInData *data = static_cast<MidiInApi::RtMidiInData *> (ptr);
1124
  AlsaMidiData *apiData = static_cast<AlsaMidiData *> (data->apiData);
1125

    
1126
  long nBytes;
1127
  unsigned long long time, lastTime;
1128
  bool continueSysex = false;
1129
  bool doDecode = false;
1130
  MidiInApi::MidiMessage message;
1131
  int poll_fd_count;
1132
  struct pollfd *poll_fds;
1133

    
1134
  snd_seq_event_t *ev;
1135
  int result;
1136
  apiData->bufferSize = 32;
1137
  result = snd_midi_event_new( 0, &apiData->coder );
1138
  if ( result < 0 ) {
1139
    data->doInput = false;
1140
    std::cerr << "\nMidiInAlsa::alsaMidiHandler: error initializing MIDI event parser!\n\n";
1141
    return 0;
1142
  }
1143
  unsigned char *buffer = (unsigned char *) malloc( apiData->bufferSize );
1144
  if ( buffer == NULL ) {
1145
    data->doInput = false;
1146
    snd_midi_event_free( apiData->coder );
1147
    apiData->coder = 0;
1148
    std::cerr << "\nMidiInAlsa::alsaMidiHandler: error initializing buffer memory!\n\n";
1149
    return 0;
1150
  }
1151
  snd_midi_event_init( apiData->coder );
1152
  snd_midi_event_no_status( apiData->coder, 1 ); // suppress running status messages
1153

    
1154
  poll_fd_count = snd_seq_poll_descriptors_count( apiData->seq, POLLIN ) + 1;
1155
  poll_fds = (struct pollfd*)alloca( poll_fd_count * sizeof( struct pollfd ));
1156
  snd_seq_poll_descriptors( apiData->seq, poll_fds + 1, poll_fd_count - 1, POLLIN );
1157
  poll_fds[0].fd = apiData->trigger_fds[0];
1158
  poll_fds[0].events = POLLIN;
1159

    
1160
  while ( data->doInput ) {
1161

    
1162
    if ( snd_seq_event_input_pending( apiData->seq, 1 ) == 0 ) {
1163
      // No data pending
1164
      if ( poll( poll_fds, poll_fd_count, -1) >= 0 ) {
1165
        if ( poll_fds[0].revents & POLLIN ) {
1166
          bool dummy;
1167
          int res = read( poll_fds[0].fd, &dummy, sizeof(dummy) );
1168
          (void) res;
1169
        }
1170
      }
1171
      continue;
1172
    }
1173

    
1174
    // If here, there should be data.
1175
    result = snd_seq_event_input( apiData->seq, &ev );
1176
    if ( result == -ENOSPC ) {
1177
      std::cerr << "\nMidiInAlsa::alsaMidiHandler: MIDI input buffer overrun!\n\n";
1178
      continue;
1179
    }
1180
    else if ( result <= 0 ) {
1181
      std::cerr << "\nMidiInAlsa::alsaMidiHandler: unknown MIDI input error!\n";
1182
      perror("System reports");
1183
      continue;
1184
    }
1185

    
1186
    // This is a bit weird, but we now have to decode an ALSA MIDI
1187
    // event (back) into MIDI bytes.  We'll ignore non-MIDI types.
1188
    if ( !continueSysex ) message.bytes.clear();
1189

    
1190
    doDecode = false;
1191
    switch ( ev->type ) {
1192

    
1193
    case SND_SEQ_EVENT_PORT_SUBSCRIBED:
1194
#if defined(__RTMIDI_DEBUG__)
1195
      std::cout << "MidiInAlsa::alsaMidiHandler: port connection made!\n";
1196
#endif
1197
      break;
1198

    
1199
    case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
1200
#if defined(__RTMIDI_DEBUG__)
1201
      std::cerr << "MidiInAlsa::alsaMidiHandler: port connection has closed!\n";
1202
      std::cout << "sender = " << (int) ev->data.connect.sender.client << ":"
1203
                << (int) ev->data.connect.sender.port
1204
                << ", dest = " << (int) ev->data.connect.dest.client << ":"
1205
                << (int) ev->data.connect.dest.port
1206
                << std::endl;
1207
#endif
1208
      break;
1209

    
1210
    case SND_SEQ_EVENT_QFRAME: // MIDI time code
1211
      if ( !( data->ignoreFlags & 0x02 ) ) doDecode = true;
1212
      break;
1213

    
1214
    case SND_SEQ_EVENT_TICK: // 0xF9 ... MIDI timing tick
1215
      if ( !( data->ignoreFlags & 0x02 ) ) doDecode = true;
1216
      break;
1217

    
1218
    case SND_SEQ_EVENT_CLOCK: // 0xF8 ... MIDI timing (clock) tick
1219
      if ( !( data->ignoreFlags & 0x02 ) ) doDecode = true;
1220
      break;
1221

    
1222
    case SND_SEQ_EVENT_SENSING: // Active sensing
1223
      if ( !( data->ignoreFlags & 0x04 ) ) doDecode = true;
1224
      break;
1225

    
1226
                case SND_SEQ_EVENT_SYSEX:
1227
      if ( (data->ignoreFlags & 0x01) ) break;
1228
      if ( ev->data.ext.len > apiData->bufferSize ) {
1229
        apiData->bufferSize = ev->data.ext.len;
1230
        free( buffer );
1231
        buffer = (unsigned char *) malloc( apiData->bufferSize );
1232
        if ( buffer == NULL ) {
1233
          data->doInput = false;
1234
          std::cerr << "\nMidiInAlsa::alsaMidiHandler: error resizing buffer memory!\n\n";
1235
          break;
1236
        }
1237
      }
1238

    
1239
    default:
1240
      doDecode = true;
1241
    }
1242

    
1243
    if ( doDecode ) {
1244

    
1245
      nBytes = snd_midi_event_decode( apiData->coder, buffer, apiData->bufferSize, ev );
1246
      if ( nBytes > 0 ) {
1247
        // The ALSA sequencer has a maximum buffer size for MIDI sysex
1248
        // events of 256 bytes.  If a device sends sysex messages larger
1249
        // than this, they are segmented into 256 byte chunks.  So,
1250
        // we'll watch for this and concatenate sysex chunks into a
1251
        // single sysex message if necessary.
1252
        if ( !continueSysex )
1253
          message.bytes.assign( buffer, &buffer[nBytes] );
1254
        else
1255
          message.bytes.insert( message.bytes.end(), buffer, &buffer[nBytes] );
1256

    
1257
        continueSysex = ( ( ev->type == SND_SEQ_EVENT_SYSEX ) && ( message.bytes.back() != 0xF7 ) );
1258
        if ( !continueSysex ) {
1259

    
1260
          // Calculate the time stamp:
1261
          message.timeStamp = 0.0;
1262

    
1263
          // Method 1: Use the system time.
1264
          //(void)gettimeofday(&tv, (struct timezone *)NULL);
1265
          //time = (tv.tv_sec * 1000000) + tv.tv_usec;
1266

    
1267
          // Method 2: Use the ALSA sequencer event time data.
1268
          // (thanks to Pedro Lopez-Cabanillas!).
1269
          time = ( ev->time.time.tv_sec * 1000000 ) + ( ev->time.time.tv_nsec/1000 );
1270
          lastTime = time;
1271
          time -= apiData->lastTime;
1272
          apiData->lastTime = lastTime;
1273
          if ( data->firstMessage == true )
1274
            data->firstMessage = false;
1275
          else
1276
            message.timeStamp = time * 0.000001;
1277
        }
1278
        else {
1279
#if defined(__RTMIDI_DEBUG__)
1280
          std::cerr << "\nMidiInAlsa::alsaMidiHandler: event parsing error or not a MIDI event!\n\n";
1281
#endif
1282
        }
1283
      }
1284
    }
1285

    
1286
    snd_seq_free_event( ev );
1287
    if ( message.bytes.size() == 0 || continueSysex ) continue;
1288

    
1289
    if ( data->usingCallback ) {
1290
      RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
1291
      callback( message.timeStamp, &message.bytes, data->userData );
1292
    }
1293
    else {
1294
      // As long as we haven't reached our queue size limit, push the message.
1295
      if ( data->queue.size < data->queue.ringSize ) {
1296
        data->queue.ring[data->queue.back++] = message;
1297
        if ( data->queue.back == data->queue.ringSize )
1298
          data->queue.back = 0;
1299
        data->queue.size++;
1300
      }
1301
      else
1302
        std::cerr << "\nMidiInAlsa: message queue limit reached!!\n\n";
1303
    }
1304
  }
1305

    
1306
  if ( buffer ) free( buffer );
1307
  snd_midi_event_free( apiData->coder );
1308
  apiData->coder = 0;
1309
  apiData->thread = apiData->dummy_thread_id;
1310
  return 0;
1311
}
1312

    
1313
MidiInAlsa :: MidiInAlsa( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
1314
{
1315
  initialize( clientName );
1316
}
1317

    
1318
MidiInAlsa :: ~MidiInAlsa()
1319
{
1320
  // Close a connection if it exists.
1321
  closePort();
1322

    
1323
  // Shutdown the input thread.
1324
  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1325
  if ( inputData_.doInput ) {
1326
    inputData_.doInput = false;
1327
    int res = write( data->trigger_fds[1], &inputData_.doInput, sizeof(inputData_.doInput) );
1328
    (void) res;
1329
    if ( !pthread_equal(data->thread, data->dummy_thread_id) )
1330
      pthread_join( data->thread, NULL );
1331
  }
1332

    
1333
  // Cleanup.
1334
  close ( data->trigger_fds[0] );
1335
  close ( data->trigger_fds[1] );
1336
  if ( data->vport >= 0 ) snd_seq_delete_port( data->seq, data->vport );
1337
#ifndef AVOID_TIMESTAMPING
1338
  snd_seq_free_queue( data->seq, data->queue_id );
1339
#endif
1340
  snd_seq_close( data->seq );
1341
  delete data;
1342
}
1343

    
1344
void MidiInAlsa :: initialize( const std::string& clientName )
1345
{
1346
  // Set up the ALSA sequencer client.
1347
  snd_seq_t *seq;
1348
  int result = snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK);
1349
  if ( result < 0 ) {
1350
    errorString_ = "MidiInAlsa::initialize: error creating ALSA sequencer client object.";
1351
    error( RtMidiError::DRIVER_ERROR, errorString_ );
1352
    return;
1353
  }
1354

    
1355
  // Set client name.
1356
  snd_seq_set_client_name( seq, clientName.c_str() );
1357

    
1358
  // Save our api-specific connection information.
1359
  AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData;
1360
  data->seq = seq;
1361
  data->portNum = -1;
1362
  data->vport = -1;
1363
  data->subscription = 0;
1364
  data->dummy_thread_id = pthread_self();
1365
  data->thread = data->dummy_thread_id;
1366
  data->trigger_fds[0] = -1;
1367
  data->trigger_fds[1] = -1;
1368
  apiData_ = (void *) data;
1369
  inputData_.apiData = (void *) data;
1370

    
1371
   if ( pipe(data->trigger_fds) == -1 ) {
1372
    errorString_ = "MidiInAlsa::initialize: error creating pipe objects.";
1373
    error( RtMidiError::DRIVER_ERROR, errorString_ );
1374
    return;
1375
  }
1376

    
1377
  // Create the input queue
1378
#ifndef AVOID_TIMESTAMPING
1379
  data->queue_id = snd_seq_alloc_named_queue(seq, "RtMidi Queue");
1380
  // Set arbitrary tempo (mm=100) and resolution (240)
1381
  snd_seq_queue_tempo_t *qtempo;
1382
  snd_seq_queue_tempo_alloca(&qtempo);
1383
  snd_seq_queue_tempo_set_tempo(qtempo, 600000);
1384
  snd_seq_queue_tempo_set_ppq(qtempo, 240);
1385
  snd_seq_set_queue_tempo(data->seq, data->queue_id, qtempo);
1386
  snd_seq_drain_output(data->seq);
1387
#endif
1388
}
1389

    
1390
// This function is used to count or get the pinfo structure for a given port number.
1391
unsigned int portInfo( snd_seq_t *seq, snd_seq_port_info_t *pinfo, unsigned int type, int portNumber )
1392
{
1393
  snd_seq_client_info_t *cinfo;
1394
  int client;
1395
  int count = 0;
1396
  snd_seq_client_info_alloca( &cinfo );
1397

    
1398
  snd_seq_client_info_set_client( cinfo, -1 );
1399
  while ( snd_seq_query_next_client( seq, cinfo ) >= 0 ) {
1400
    client = snd_seq_client_info_get_client( cinfo );
1401
    if ( client == 0 ) continue;
1402
    // Reset query info
1403
    snd_seq_port_info_set_client( pinfo, client );
1404
    snd_seq_port_info_set_port( pinfo, -1 );
1405
    while ( snd_seq_query_next_port( seq, pinfo ) >= 0 ) {
1406
      unsigned int atyp = snd_seq_port_info_get_type( pinfo );
1407
      if ( ( ( atyp & SND_SEQ_PORT_TYPE_MIDI_GENERIC ) == 0 ) &&
1408
        ( ( atyp & SND_SEQ_PORT_TYPE_SYNTH ) == 0 ) ) continue;
1409
      unsigned int caps = snd_seq_port_info_get_capability( pinfo );
1410
      if ( ( caps & type ) != type ) continue;
1411
      if ( count == portNumber ) return 1;
1412
      ++count;
1413
    }
1414
  }
1415

    
1416
  // If a negative portNumber was used, return the port count.
1417
  if ( portNumber < 0 ) return count;
1418
  return 0;
1419
}
1420

    
1421
unsigned int MidiInAlsa :: getPortCount()
1422
{
1423
  snd_seq_port_info_t *pinfo;
1424
  snd_seq_port_info_alloca( &pinfo );
1425

    
1426
  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1427
  return portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, -1 );
1428
}
1429

    
1430
std::string MidiInAlsa :: getPortName( unsigned int portNumber )
1431
{
1432
  snd_seq_client_info_t *cinfo;
1433
  snd_seq_port_info_t *pinfo;
1434
  snd_seq_client_info_alloca( &cinfo );
1435
  snd_seq_port_info_alloca( &pinfo );
1436

    
1437
  std::string stringName;
1438
  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1439
  if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, (int) portNumber ) ) {
1440
    int cnum = snd_seq_port_info_get_client( pinfo );
1441
    snd_seq_get_any_client_info( data->seq, cnum, cinfo );
1442
    std::ostringstream os;
1443
    os << snd_seq_client_info_get_name( cinfo );
1444
    os << " ";                                    // These lines added to make sure devices are listed
1445
    os << snd_seq_port_info_get_client( pinfo );  // with full portnames added to ensure individual device names
1446
    os << ":";
1447
    os << snd_seq_port_info_get_port( pinfo );
1448
    stringName = os.str();
1449
    return stringName;
1450
  }
1451

    
1452
  // If we get here, we didn't find a match.
1453
  errorString_ = "MidiInAlsa::getPortName: error looking for port name!";
1454
  error( RtMidiError::WARNING, errorString_ );
1455
  return stringName;
1456
}
1457

    
1458
void MidiInAlsa :: openPort( unsigned int portNumber, const std::string portName )
1459
{
1460
  if ( connected_ ) {
1461
    errorString_ = "MidiInAlsa::openPort: a valid connection already exists!";
1462
    error( RtMidiError::WARNING, errorString_ );
1463
    return;
1464
  }
1465

    
1466
  unsigned int nSrc = this->getPortCount();
1467
  if ( nSrc < 1 ) {
1468
    errorString_ = "MidiInAlsa::openPort: no MIDI input sources found!";
1469
    error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
1470
    return;
1471
  }
1472

    
1473
  snd_seq_port_info_t *src_pinfo;
1474
  snd_seq_port_info_alloca( &src_pinfo );
1475
  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1476
  if ( portInfo( data->seq, src_pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, (int) portNumber ) == 0 ) {
1477
    std::ostringstream ost;
1478
    ost << "MidiInAlsa::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
1479
    errorString_ = ost.str();
1480
    error( RtMidiError::INVALID_PARAMETER, errorString_ );
1481
    return;
1482
  }
1483

    
1484
  snd_seq_addr_t sender, receiver;
1485
  sender.client = snd_seq_port_info_get_client( src_pinfo );
1486
  sender.port = snd_seq_port_info_get_port( src_pinfo );
1487
  receiver.client = snd_seq_client_id( data->seq );
1488

    
1489
  snd_seq_port_info_t *pinfo;
1490
  snd_seq_port_info_alloca( &pinfo );
1491
  if ( data->vport < 0 ) {
1492
    snd_seq_port_info_set_client( pinfo, 0 );
1493
    snd_seq_port_info_set_port( pinfo, 0 );
1494
    snd_seq_port_info_set_capability( pinfo,
1495
                                      SND_SEQ_PORT_CAP_WRITE |
1496
                                      SND_SEQ_PORT_CAP_SUBS_WRITE );
1497
    snd_seq_port_info_set_type( pinfo,
1498
                                SND_SEQ_PORT_TYPE_MIDI_GENERIC |
1499
                                SND_SEQ_PORT_TYPE_APPLICATION );
1500
    snd_seq_port_info_set_midi_channels(pinfo, 16);
1501
#ifndef AVOID_TIMESTAMPING
1502
    snd_seq_port_info_set_timestamping(pinfo, 1);
1503
    snd_seq_port_info_set_timestamp_real(pinfo, 1);    
1504
    snd_seq_port_info_set_timestamp_queue(pinfo, data->queue_id);
1505
#endif
1506
    snd_seq_port_info_set_name(pinfo,  portName.c_str() );
1507
    data->vport = snd_seq_create_port(data->seq, pinfo);
1508
  
1509
    if ( data->vport < 0 ) {
1510
      errorString_ = "MidiInAlsa::openPort: ALSA error creating input port.";
1511
      error( RtMidiError::DRIVER_ERROR, errorString_ );
1512
      return;
1513
    }
1514
    data->vport = snd_seq_port_info_get_port(pinfo);
1515
  }
1516

    
1517
  receiver.port = data->vport;
1518

    
1519
  if ( !data->subscription ) {
1520
    // Make subscription
1521
    if (snd_seq_port_subscribe_malloc( &data->subscription ) < 0) {
1522
      errorString_ = "MidiInAlsa::openPort: ALSA error allocation port subscription.";
1523
      error( RtMidiError::DRIVER_ERROR, errorString_ );
1524
      return;
1525
    }
1526
    snd_seq_port_subscribe_set_sender(data->subscription, &sender);
1527
    snd_seq_port_subscribe_set_dest(data->subscription, &receiver);
1528
    if ( snd_seq_subscribe_port(data->seq, data->subscription) ) {
1529
      snd_seq_port_subscribe_free( data->subscription );
1530
      data->subscription = 0;
1531
      errorString_ = "MidiInAlsa::openPort: ALSA error making port connection.";
1532
      error( RtMidiError::DRIVER_ERROR, errorString_ );
1533
      return;
1534
    }
1535
  }
1536

    
1537
  if ( inputData_.doInput == false ) {
1538
    // Start the input queue
1539
#ifndef AVOID_TIMESTAMPING
1540
    snd_seq_start_queue( data->seq, data->queue_id, NULL );
1541
    snd_seq_drain_output( data->seq );
1542
#endif
1543
    // Start our MIDI input thread.
1544
    pthread_attr_t attr;
1545
    pthread_attr_init(&attr);
1546
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1547
    pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
1548

    
1549
    inputData_.doInput = true;
1550
    int err = pthread_create(&data->thread, &attr, alsaMidiHandler, &inputData_);
1551
    pthread_attr_destroy(&attr);
1552
    if ( err ) {
1553
      snd_seq_unsubscribe_port( data->seq, data->subscription );
1554
      snd_seq_port_subscribe_free( data->subscription );
1555
      data->subscription = 0;
1556
      inputData_.doInput = false;
1557
      errorString_ = "MidiInAlsa::openPort: error starting MIDI input thread!";
1558
      error( RtMidiError::THREAD_ERROR, errorString_ );
1559
      return;
1560
    }
1561
  }
1562

    
1563
  connected_ = true;
1564
}
1565

    
1566
void MidiInAlsa :: openVirtualPort( std::string portName )
1567
{
1568
  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1569
  if ( data->vport < 0 ) {
1570
    snd_seq_port_info_t *pinfo;
1571
    snd_seq_port_info_alloca( &pinfo );
1572
    snd_seq_port_info_set_capability( pinfo,
1573
                                      SND_SEQ_PORT_CAP_WRITE |
1574
                                      SND_SEQ_PORT_CAP_SUBS_WRITE );
1575
    snd_seq_port_info_set_type( pinfo,
1576
                                SND_SEQ_PORT_TYPE_MIDI_GENERIC |
1577
                                SND_SEQ_PORT_TYPE_APPLICATION );
1578
    snd_seq_port_info_set_midi_channels(pinfo, 16);
1579
#ifndef AVOID_TIMESTAMPING
1580
    snd_seq_port_info_set_timestamping(pinfo, 1);
1581
    snd_seq_port_info_set_timestamp_real(pinfo, 1);    
1582
    snd_seq_port_info_set_timestamp_queue(pinfo, data->queue_id);
1583
#endif
1584
    snd_seq_port_info_set_name(pinfo, portName.c_str());
1585
    data->vport = snd_seq_create_port(data->seq, pinfo);
1586

    
1587
    if ( data->vport < 0 ) {
1588
      errorString_ = "MidiInAlsa::openVirtualPort: ALSA error creating virtual port.";
1589
      error( RtMidiError::DRIVER_ERROR, errorString_ );
1590
      return;
1591
    }
1592
    data->vport = snd_seq_port_info_get_port(pinfo);
1593
  }
1594

    
1595
  if ( inputData_.doInput == false ) {
1596
    // Wait for old thread to stop, if still running
1597
    if ( !pthread_equal(data->thread, data->dummy_thread_id) )
1598
      pthread_join( data->thread, NULL );
1599

    
1600
    // Start the input queue
1601
#ifndef AVOID_TIMESTAMPING
1602
    snd_seq_start_queue( data->seq, data->queue_id, NULL );
1603
    snd_seq_drain_output( data->seq );
1604
#endif
1605
    // Start our MIDI input thread.
1606
    pthread_attr_t attr;
1607
    pthread_attr_init(&attr);
1608
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1609
    pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
1610

    
1611
    inputData_.doInput = true;
1612
    int err = pthread_create(&data->thread, &attr, alsaMidiHandler, &inputData_);
1613
    pthread_attr_destroy(&attr);
1614
    if ( err ) {
1615
      if ( data->subscription ) {
1616
        snd_seq_unsubscribe_port( data->seq, data->subscription );
1617
        snd_seq_port_subscribe_free( data->subscription );
1618
        data->subscription = 0;
1619
      }
1620
      inputData_.doInput = false;
1621
      errorString_ = "MidiInAlsa::openPort: error starting MIDI input thread!";
1622
      error( RtMidiError::THREAD_ERROR, errorString_ );
1623
      return;
1624
    }
1625
  }
1626
}
1627

    
1628
void MidiInAlsa :: closePort( void )
1629
{
1630
  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1631

    
1632
  if ( connected_ ) {
1633
    if ( data->subscription ) {
1634
      snd_seq_unsubscribe_port( data->seq, data->subscription );
1635
      snd_seq_port_subscribe_free( data->subscription );
1636
      data->subscription = 0;
1637
    }
1638
    // Stop the input queue
1639
#ifndef AVOID_TIMESTAMPING
1640
    snd_seq_stop_queue( data->seq, data->queue_id, NULL );
1641
    snd_seq_drain_output( data->seq );
1642
#endif
1643
    connected_ = false;
1644
  }
1645

    
1646
  // Stop thread to avoid triggering the callback, while the port is intended to be closed
1647
  if ( inputData_.doInput ) {
1648
    inputData_.doInput = false;
1649
    int res = write( data->trigger_fds[1], &inputData_.doInput, sizeof(inputData_.doInput) );
1650
    (void) res;
1651
    if ( !pthread_equal(data->thread, data->dummy_thread_id) )
1652
      pthread_join( data->thread, NULL );
1653
  }
1654
}
1655

    
1656
//*********************************************************************//
1657
//  API: LINUX ALSA
1658
//  Class Definitions: MidiOutAlsa
1659
//*********************************************************************//
1660

    
1661
MidiOutAlsa :: MidiOutAlsa( const std::string clientName ) : MidiOutApi()
1662
{
1663
  initialize( clientName );
1664
}
1665

    
1666
MidiOutAlsa :: ~MidiOutAlsa()
1667
{
1668
  // Close a connection if it exists.
1669
  closePort();
1670

    
1671
  // Cleanup.
1672
  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1673
  if ( data->vport >= 0 ) snd_seq_delete_port( data->seq, data->vport );
1674
  if ( data->coder ) snd_midi_event_free( data->coder );
1675
  if ( data->buffer ) free( data->buffer );
1676
  snd_seq_close( data->seq );
1677
  delete data;
1678
}
1679

    
1680
void MidiOutAlsa :: initialize( const std::string& clientName )
1681
{
1682
  // Set up the ALSA sequencer client.
1683
  snd_seq_t *seq;
1684
  int result1 = snd_seq_open( &seq, "default", SND_SEQ_OPEN_OUTPUT, SND_SEQ_NONBLOCK );
1685
  if ( result1 < 0 ) {
1686
    errorString_ = "MidiOutAlsa::initialize: error creating ALSA sequencer client object.";
1687
    error( RtMidiError::DRIVER_ERROR, errorString_ );
1688
    return;
1689
        }
1690

    
1691
  // Set client name.
1692
  snd_seq_set_client_name( seq, clientName.c_str() );
1693

    
1694
  // Save our api-specific connection information.
1695
  AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData;
1696
  data->seq = seq;
1697
  data->portNum = -1;
1698
  data->vport = -1;
1699
  data->bufferSize = 32;
1700
  data->coder = 0;
1701
  data->buffer = 0;
1702
  int result = snd_midi_event_new( data->bufferSize, &data->coder );
1703
  if ( result < 0 ) {
1704
    delete data;
1705
    errorString_ = "MidiOutAlsa::initialize: error initializing MIDI event parser!\n\n";
1706
    error( RtMidiError::DRIVER_ERROR, errorString_ );
1707
    return;
1708
  }
1709
  data->buffer = (unsigned char *) malloc( data->bufferSize );
1710
  if ( data->buffer == NULL ) {
1711
    delete data;
1712
    errorString_ = "MidiOutAlsa::initialize: error allocating buffer memory!\n\n";
1713
    error( RtMidiError::MEMORY_ERROR, errorString_ );
1714
    return;
1715
  }
1716
  snd_midi_event_init( data->coder );
1717
  apiData_ = (void *) data;
1718
}
1719

    
1720
unsigned int MidiOutAlsa :: getPortCount()
1721
{
1722
        snd_seq_port_info_t *pinfo;
1723
        snd_seq_port_info_alloca( &pinfo );
1724

    
1725
  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1726
  return portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, -1 );
1727
}
1728

    
1729
std::string MidiOutAlsa :: getPortName( unsigned int portNumber )
1730
{
1731
  snd_seq_client_info_t *cinfo;
1732
  snd_seq_port_info_t *pinfo;
1733
  snd_seq_client_info_alloca( &cinfo );
1734
  snd_seq_port_info_alloca( &pinfo );
1735

    
1736
  std::string stringName;
1737
  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1738
  if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber ) ) {
1739
    int cnum = snd_seq_port_info_get_client(pinfo);
1740
    snd_seq_get_any_client_info( data->seq, cnum, cinfo );
1741
    std::ostringstream os;
1742
    os << snd_seq_client_info_get_name(cinfo);
1743
    os << " ";                                    // These lines added to make sure devices are listed
1744
    os << snd_seq_port_info_get_client( pinfo );  // with full portnames added to ensure individual device names
1745
    os << ":";
1746
    os << snd_seq_port_info_get_port(pinfo);
1747
    stringName = os.str();
1748
    return stringName;
1749
  }
1750

    
1751
  // If we get here, we didn't find a match.
1752
  errorString_ = "MidiOutAlsa::getPortName: error looking for port name!";
1753
  error( RtMidiError::WARNING, errorString_ );
1754
  return stringName;
1755
}
1756

    
1757
void MidiOutAlsa :: openPort( unsigned int portNumber, const std::string portName )
1758
{
1759
  if ( connected_ ) {
1760
    errorString_ = "MidiOutAlsa::openPort: a valid connection already exists!";
1761
    error( RtMidiError::WARNING, errorString_ );
1762
    return;
1763
  }
1764

    
1765
  unsigned int nSrc = this->getPortCount();
1766
  if (nSrc < 1) {
1767
    errorString_ = "MidiOutAlsa::openPort: no MIDI output sources found!";
1768
    error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
1769
    return;
1770
  }
1771

    
1772
        snd_seq_port_info_t *pinfo;
1773
        snd_seq_port_info_alloca( &pinfo );
1774
  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1775
  if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber ) == 0 ) {
1776
    std::ostringstream ost;
1777
    ost << "MidiOutAlsa::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
1778
    errorString_ = ost.str();
1779
    error( RtMidiError::INVALID_PARAMETER, errorString_ );
1780
    return;
1781
  }
1782

    
1783
  snd_seq_addr_t sender, receiver;
1784
  receiver.client = snd_seq_port_info_get_client( pinfo );
1785
  receiver.port = snd_seq_port_info_get_port( pinfo );
1786
  sender.client = snd_seq_client_id( data->seq );
1787

    
1788
  if ( data->vport < 0 ) {
1789
    data->vport = snd_seq_create_simple_port( data->seq, portName.c_str(),
1790
                                              SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
1791
                                              SND_SEQ_PORT_TYPE_MIDI_GENERIC|SND_SEQ_PORT_TYPE_APPLICATION );
1792
    if ( data->vport < 0 ) {
1793
      errorString_ = "MidiOutAlsa::openPort: ALSA error creating output port.";
1794
      error( RtMidiError::DRIVER_ERROR, errorString_ );
1795
      return;
1796
    }
1797
  }
1798

    
1799
  sender.port = data->vport;
1800

    
1801
  // Make subscription
1802
  if (snd_seq_port_subscribe_malloc( &data->subscription ) < 0) {
1803
    snd_seq_port_subscribe_free( data->subscription );
1804
    errorString_ = "MidiOutAlsa::openPort: error allocating port subscription.";
1805
    error( RtMidiError::DRIVER_ERROR, errorString_ );
1806
    return;
1807
  }
1808
  snd_seq_port_subscribe_set_sender(data->subscription, &sender);
1809
  snd_seq_port_subscribe_set_dest(data->subscription, &receiver);
1810
  snd_seq_port_subscribe_set_time_update(data->subscription, 1);
1811
  snd_seq_port_subscribe_set_time_real(data->subscription, 1);
1812
  if ( snd_seq_subscribe_port(data->seq, data->subscription) ) {
1813
    snd_seq_port_subscribe_free( data->subscription );
1814
    errorString_ = "MidiOutAlsa::openPort: ALSA error making port connection.";
1815
    error( RtMidiError::DRIVER_ERROR, errorString_ );
1816
    return;
1817
  }
1818

    
1819
  connected_ = true;
1820
}
1821

    
1822
void MidiOutAlsa :: closePort( void )
1823
{
1824
  if ( connected_ ) {
1825
    AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1826
    snd_seq_unsubscribe_port( data->seq, data->subscription );
1827
    snd_seq_port_subscribe_free( data->subscription );
1828
    connected_ = false;
1829
  }
1830
}
1831

    
1832
void MidiOutAlsa :: openVirtualPort( std::string portName )
1833
{
1834
  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1835
  if ( data->vport < 0 ) {
1836
    data->vport = snd_seq_create_simple_port( data->seq, portName.c_str(),
1837
                                              SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
1838
                                              SND_SEQ_PORT_TYPE_MIDI_GENERIC|SND_SEQ_PORT_TYPE_APPLICATION );
1839

    
1840
    if ( data->vport < 0 ) {
1841
      errorString_ = "MidiOutAlsa::openVirtualPort: ALSA error creating virtual port.";
1842
      error( RtMidiError::DRIVER_ERROR, errorString_ );
1843
    }
1844
  }
1845
}
1846

    
1847
void MidiOutAlsa :: sendMessage( std::vector<unsigned char> *message )
1848
{
1849
  int result;
1850
  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1851
  unsigned int nBytes = message->size();
1852
  if ( nBytes > data->bufferSize ) {
1853
    data->bufferSize = nBytes;
1854
    result = snd_midi_event_resize_buffer ( data->coder, nBytes);
1855
    if ( result != 0 ) {
1856
      errorString_ = "MidiOutAlsa::sendMessage: ALSA error resizing MIDI event buffer.";
1857
      error( RtMidiError::DRIVER_ERROR, errorString_ );
1858
      return;
1859
    }
1860
    free (data->buffer);
1861
    data->buffer = (unsigned char *) malloc( data->bufferSize );
1862
    if ( data->buffer == NULL ) {
1863
    errorString_ = "MidiOutAlsa::initialize: error allocating buffer memory!\n\n";
1864
    error( RtMidiError::MEMORY_ERROR, errorString_ );
1865
    return;
1866
    }
1867
  }
1868

    
1869
  snd_seq_event_t ev;
1870
  snd_seq_ev_clear(&ev);
1871
  snd_seq_ev_set_source(&ev, data->vport);
1872
  snd_seq_ev_set_subs(&ev);
1873
  snd_seq_ev_set_direct(&ev);
1874
  for ( unsigned int i=0; i<nBytes; ++i ) data->buffer[i] = message->at(i);
1875
  result = snd_midi_event_encode( data->coder, data->buffer, (long)nBytes, &ev );
1876
  if ( result < (int)nBytes ) {
1877
    errorString_ = "MidiOutAlsa::sendMessage: event parsing error!";
1878
    error( RtMidiError::WARNING, errorString_ );
1879
    return;
1880
  }
1881

    
1882
  // Send the event.
1883
  result = snd_seq_event_output(data->seq, &ev);
1884
  if ( result < 0 ) {
1885
    errorString_ = "MidiOutAlsa::sendMessage: error sending MIDI message to port.";
1886
    error( RtMidiError::WARNING, errorString_ );
1887
    return;
1888
  }
1889
  snd_seq_drain_output(data->seq);
1890
}
1891

    
1892
#endif // __LINUX_ALSA__
1893

    
1894

    
1895
//*********************************************************************//
1896
//  API: Windows Multimedia Library (MM)
1897
//*********************************************************************//
1898

    
1899
// API information deciphered from:
1900
//  - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_midi_reference.asp
1901

    
1902
// Thanks to Jean-Baptiste Berruchon for the sysex code.
1903

    
1904
#if defined(__WINDOWS_MM__)
1905

    
1906
// The Windows MM API is based on the use of a callback function for
1907
// MIDI input.  We convert the system specific time stamps to delta
1908
// time values.
1909

    
1910
// Windows MM MIDI header files.
1911
#include <windows.h>
1912
#include <mmsystem.h>
1913

    
1914
#define  RT_SYSEX_BUFFER_SIZE 1024
1915
#define  RT_SYSEX_BUFFER_COUNT 4
1916

    
1917
// A structure to hold variables related to the CoreMIDI API
1918
// implementation.
1919
struct WinMidiData {
1920
  HMIDIIN inHandle;    // Handle to Midi Input Device
1921
  HMIDIOUT outHandle;  // Handle to Midi Output Device
1922
  DWORD lastTime;
1923
  MidiInApi::MidiMessage message;
1924
  LPMIDIHDR sysexBuffer[RT_SYSEX_BUFFER_COUNT];
1925
  CRITICAL_SECTION _mutex; // [Patrice] see https://groups.google.com/forum/#!topic/mididev/6OUjHutMpEo
1926
};
1927

    
1928
//*********************************************************************//
1929
//  API: Windows MM
1930
//  Class Definitions: MidiInWinMM
1931
//*********************************************************************//
1932

    
1933
static void CALLBACK midiInputCallback( HMIDIIN /*hmin*/,
1934
                                        UINT inputStatus, 
1935
                                        DWORD_PTR instancePtr,
1936
                                        DWORD_PTR midiMessage,
1937
                                        DWORD timestamp )
1938
{
1939
  if ( inputStatus != MIM_DATA && inputStatus != MIM_LONGDATA && inputStatus != MIM_LONGERROR ) return;
1940

    
1941
  //MidiInApi::RtMidiInData *data = static_cast<MidiInApi::RtMidiInData *> (instancePtr);
1942
  MidiInApi::RtMidiInData *data = (MidiInApi::RtMidiInData *)instancePtr;
1943
  WinMidiData *apiData = static_cast<WinMidiData *> (data->apiData);
1944

    
1945
  // Calculate time stamp.
1946
  if ( data->firstMessage == true ) {
1947
    apiData->message.timeStamp = 0.0;
1948
    data->firstMessage = false;
1949
  }
1950
  else apiData->message.timeStamp = (double) ( timestamp - apiData->lastTime ) * 0.001;
1951
  apiData->lastTime = timestamp;
1952

    
1953
  if ( inputStatus == MIM_DATA ) { // Channel or system message
1954

    
1955
    // Make sure the first byte is a status byte.
1956
    unsigned char status = (unsigned char) (midiMessage & 0x000000FF);
1957
    if ( !(status & 0x80) ) return;
1958

    
1959
    // Determine the number of bytes in the MIDI message.
1960
    unsigned short nBytes = 1;
1961
    if ( status < 0xC0 ) nBytes = 3;
1962
    else if ( status < 0xE0 ) nBytes = 2;
1963
    else if ( status < 0xF0 ) nBytes = 3;
1964
    else if ( status == 0xF1 ) {
1965
      if ( data->ignoreFlags & 0x02 ) return;
1966
      else nBytes = 2;
1967
    }
1968
    else if ( status == 0xF2 ) nBytes = 3;
1969
    else if ( status == 0xF3 ) nBytes = 2;
1970
    else if ( status == 0xF8 && (data->ignoreFlags & 0x02) ) {
1971
      // A MIDI timing tick message and we're ignoring it.
1972
      return;
1973
    }
1974
    else if ( status == 0xFE && (data->ignoreFlags & 0x04) ) {
1975
      // A MIDI active sensing message and we're ignoring it.
1976
      return;
1977
    }
1978

    
1979
    // Copy bytes to our MIDI message.
1980
    unsigned char *ptr = (unsigned char *) &midiMessage;
1981
    for ( int i=0; i<nBytes; ++i ) apiData->message.bytes.push_back( *ptr++ );
1982
  }
1983
  else { // Sysex message ( MIM_LONGDATA or MIM_LONGERROR )
1984
    MIDIHDR *sysex = ( MIDIHDR *) midiMessage; 
1985
    if ( !( data->ignoreFlags & 0x01 ) && inputStatus != MIM_LONGERROR ) {  
1986
      // Sysex message and we're not ignoring it
1987
      for ( int i=0; i<(int)sysex->dwBytesRecorded; ++i )
1988
        apiData->message.bytes.push_back( sysex->lpData[i] );
1989
    }
1990

    
1991
    // The WinMM API requires that the sysex buffer be requeued after
1992
    // input of each sysex message.  Even if we are ignoring sysex
1993
    // messages, we still need to requeue the buffer in case the user
1994
    // decides to not ignore sysex messages in the future.  However,
1995
    // it seems that WinMM calls this function with an empty sysex
1996
    // buffer when an application closes and in this case, we should
1997
    // avoid requeueing it, else the computer suddenly reboots after
1998
    // one or two minutes.
1999
    if ( apiData->sysexBuffer[sysex->dwUser]->dwBytesRecorded > 0 ) {
2000
      //if ( sysex->dwBytesRecorded > 0 ) {
2001
      EnterCriticalSection( &(apiData->_mutex) );
2002
      MMRESULT result = midiInAddBuffer( apiData->inHandle, apiData->sysexBuffer[sysex->dwUser], sizeof(MIDIHDR) );
2003
      LeaveCriticalSection( &(apiData->_mutex) );
2004
      if ( result != MMSYSERR_NOERROR )
2005
        std::cerr << "\nRtMidiIn::midiInputCallback: error sending sysex to Midi device!!\n\n";
2006

    
2007
      if ( data->ignoreFlags & 0x01 ) return;
2008
    }
2009
    else return;
2010
  }
2011

    
2012
  if ( data->usingCallback ) {
2013
    RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
2014
    callback( apiData->message.timeStamp, &apiData->message.bytes, data->userData );
2015
  }
2016
  else {
2017
    // As long as we haven't reached our queue size limit, push the message.
2018
    if ( data->queue.size < data->queue.ringSize ) {
2019
      data->queue.ring[data->queue.back++] = apiData->message;
2020
      if ( data->queue.back == data->queue.ringSize )
2021
        data->queue.back = 0;
2022
      data->queue.size++;
2023
    }
2024
    else
2025
      std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
2026
  }
2027

    
2028
  // Clear the vector for the next input message.
2029
  apiData->message.bytes.clear();
2030
}
2031

    
2032
MidiInWinMM :: MidiInWinMM( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
2033
{
2034
  initialize( clientName );
2035
}
2036

    
2037
MidiInWinMM :: ~MidiInWinMM()
2038
{
2039
  // Close a connection if it exists.
2040
  closePort();
2041

    
2042
  WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2043
  DeleteCriticalSection( &(data->_mutex) );
2044

    
2045
  // Cleanup.
2046
  delete data;
2047
}
2048

    
2049
void MidiInWinMM :: initialize( const std::string& /*clientName*/ )
2050
{
2051
  // We'll issue a warning here if no devices are available but not
2052
  // throw an error since the user can plugin something later.
2053
  unsigned int nDevices = midiInGetNumDevs();
2054
  if ( nDevices == 0 ) {
2055
    errorString_ = "MidiInWinMM::initialize: no MIDI input devices currently available.";
2056
    error( RtMidiError::WARNING, errorString_ );
2057
  }
2058

    
2059
  // Save our api-specific connection information.
2060
  WinMidiData *data = (WinMidiData *) new WinMidiData;
2061
  apiData_ = (void *) data;
2062
  inputData_.apiData = (void *) data;
2063
  data->message.bytes.clear();  // needs to be empty for first input message
2064

    
2065
  if ( !InitializeCriticalSectionAndSpinCount(&(data->_mutex), 0x00000400) ) {
2066
    errorString_ = "MidiInWinMM::initialize: InitializeCriticalSectionAndSpinCount failed.";
2067
    error( RtMidiError::WARNING, errorString_ );
2068
  }
2069
}
2070

    
2071
void MidiInWinMM :: openPort( unsigned int portNumber, const std::string /*portName*/ )
2072
{
2073
  if ( connected_ ) {
2074
    errorString_ = "MidiInWinMM::openPort: a valid connection already exists!";
2075
    error( RtMidiError::WARNING, errorString_ );
2076
    return;
2077
  }
2078

    
2079
  unsigned int nDevices = midiInGetNumDevs();
2080
  if (nDevices == 0) {
2081
    errorString_ = "MidiInWinMM::openPort: no MIDI input sources found!";
2082
    error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
2083
    return;
2084
  }
2085

    
2086
  if ( portNumber >= nDevices ) {
2087
    std::ostringstream ost;
2088
    ost << "MidiInWinMM::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
2089
    errorString_ = ost.str();
2090
    error( RtMidiError::INVALID_PARAMETER, errorString_ );
2091
    return;
2092
  }
2093

    
2094
  WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2095
  MMRESULT result = midiInOpen( &data->inHandle,
2096
                                portNumber,
2097
                                (DWORD_PTR)&midiInputCallback,
2098
                                (DWORD_PTR)&inputData_,
2099
                                CALLBACK_FUNCTION );
2100
  if ( result != MMSYSERR_NOERROR ) {
2101
    errorString_ = "MidiInWinMM::openPort: error creating Windows MM MIDI input port.";
2102
    error( RtMidiError::DRIVER_ERROR, errorString_ );
2103
    return;
2104
  }
2105

    
2106
  // Allocate and init the sysex buffers.
2107
  for ( int i=0; i<RT_SYSEX_BUFFER_COUNT; ++i ) {
2108
    data->sysexBuffer[i] = (MIDIHDR*) new char[ sizeof(MIDIHDR) ];
2109
    data->sysexBuffer[i]->lpData = new char[ RT_SYSEX_BUFFER_SIZE ];
2110
    data->sysexBuffer[i]->dwBufferLength = RT_SYSEX_BUFFER_SIZE;
2111
    data->sysexBuffer[i]->dwUser = i; // We use the dwUser parameter as buffer indicator
2112
    data->sysexBuffer[i]->dwFlags = 0;
2113

    
2114
    result = midiInPrepareHeader( data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR) );
2115
    if ( result != MMSYSERR_NOERROR ) {
2116
      midiInClose( data->inHandle );
2117
      errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port (PrepareHeader).";
2118
      error( RtMidiError::DRIVER_ERROR, errorString_ );
2119
      return;
2120
    }
2121

    
2122
    // Register the buffer.
2123
    result = midiInAddBuffer( data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR) );
2124
    if ( result != MMSYSERR_NOERROR ) {
2125
      midiInClose( data->inHandle );
2126
      errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port (AddBuffer).";
2127
      error( RtMidiError::DRIVER_ERROR, errorString_ );
2128
      return;
2129
    }
2130
  }
2131

    
2132
  result = midiInStart( data->inHandle );
2133
  if ( result != MMSYSERR_NOERROR ) {
2134
    midiInClose( data->inHandle );
2135
    errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port.";
2136
    error( RtMidiError::DRIVER_ERROR, errorString_ );
2137
    return;
2138
  }
2139

    
2140
  connected_ = true;
2141
}
2142

    
2143
void MidiInWinMM :: openVirtualPort( std::string /*portName*/ )
2144
{
2145
  // This function cannot be implemented for the Windows MM MIDI API.
2146
  errorString_ = "MidiInWinMM::openVirtualPort: cannot be implemented in Windows MM MIDI API!";
2147
  error( RtMidiError::WARNING, errorString_ );
2148
}
2149

    
2150
void MidiInWinMM :: closePort( void )
2151
{
2152
  if ( connected_ ) {
2153
    WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2154
    EnterCriticalSection( &(data->_mutex) );
2155
    midiInReset( data->inHandle );
2156
    midiInStop( data->inHandle );
2157

    
2158
    for ( int i=0; i<RT_SYSEX_BUFFER_COUNT; ++i ) {
2159
      int result = midiInUnprepareHeader(data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR));
2160
      delete [] data->sysexBuffer[i]->lpData;
2161
      delete [] data->sysexBuffer[i];
2162
      if ( result != MMSYSERR_NOERROR ) {
2163
        midiInClose( data->inHandle );
2164
        errorString_ = "MidiInWinMM::openPort: error closing Windows MM MIDI input port (midiInUnprepareHeader).";
2165
        error( RtMidiError::DRIVER_ERROR, errorString_ );
2166
        return;
2167
      }
2168
    }
2169

    
2170
    midiInClose( data->inHandle );
2171
    connected_ = false;
2172
    LeaveCriticalSection( &(data->_mutex) );
2173
  }
2174
}
2175

    
2176
unsigned int MidiInWinMM :: getPortCount()
2177
{
2178
  return midiInGetNumDevs();
2179
}
2180

    
2181
std::string MidiInWinMM :: getPortName( unsigned int portNumber )
2182
{
2183
  std::string stringName;
2184
  unsigned int nDevices = midiInGetNumDevs();
2185
  if ( portNumber >= nDevices ) {
2186
    std::ostringstream ost;
2187
    ost << "MidiInWinMM::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
2188
    errorString_ = ost.str();
2189
    error( RtMidiError::WARNING, errorString_ );
2190
    return stringName;
2191
  }
2192

    
2193
  MIDIINCAPS deviceCaps;
2194
  midiInGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIINCAPS));
2195

    
2196
#if defined( UNICODE ) || defined( _UNICODE )
2197
  int length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, -1, NULL, 0, NULL, NULL) - 1;
2198
  stringName.assign( length, 0 );
2199
  length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, static_cast<int>(wcslen(deviceCaps.szPname)), &stringName[0], length, NULL, NULL);
2200
#else
2201
  stringName = std::string( deviceCaps.szPname );
2202
#endif
2203

    
2204
  // Next lines added to add the portNumber to the name so that 
2205
  // the device's names are sure to be listed with individual names
2206
  // even when they have the same brand name
2207
  std::ostringstream os;
2208
  os << " ";
2209
  os << portNumber;
2210
  stringName += os.str();
2211

    
2212
  return stringName;
2213
}
2214

    
2215
//*********************************************************************//
2216
//  API: Windows MM
2217
//  Class Definitions: MidiOutWinMM
2218
//*********************************************************************//
2219

    
2220
MidiOutWinMM :: MidiOutWinMM( const std::string clientName ) : MidiOutApi()
2221
{
2222
  initialize( clientName );
2223
}
2224

    
2225
MidiOutWinMM :: ~MidiOutWinMM()
2226
{
2227
  // Close a connection if it exists.
2228
  closePort();
2229

    
2230
  // Cleanup.
2231
  WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2232
  delete data;
2233
}
2234

    
2235
void MidiOutWinMM :: initialize( const std::string& /*clientName*/ )
2236
{
2237
  // We'll issue a warning here if no devices are available but not
2238
  // throw an error since the user can plug something in later.
2239
  unsigned int nDevices = midiOutGetNumDevs();
2240
  if ( nDevices == 0 ) {
2241
    errorString_ = "MidiOutWinMM::initialize: no MIDI output devices currently available.";
2242
    error( RtMidiError::WARNING, errorString_ );
2243
  }
2244

    
2245
  // Save our api-specific connection information.
2246
  WinMidiData *data = (WinMidiData *) new WinMidiData;
2247
  apiData_ = (void *) data;
2248
}
2249

    
2250
unsigned int MidiOutWinMM :: getPortCount()
2251
{
2252
  return midiOutGetNumDevs();
2253
}
2254

    
2255
std::string MidiOutWinMM :: getPortName( unsigned int portNumber )
2256
{
2257
  std::string stringName;
2258
  unsigned int nDevices = midiOutGetNumDevs();
2259
  if ( portNumber >= nDevices ) {
2260
    std::ostringstream ost;
2261
    ost << "MidiOutWinMM::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
2262
    errorString_ = ost.str();
2263
    error( RtMidiError::WARNING, errorString_ );
2264
    return stringName;
2265
  }
2266

    
2267
  MIDIOUTCAPS deviceCaps;
2268
  midiOutGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIOUTCAPS));
2269

    
2270
#if defined( UNICODE ) || defined( _UNICODE )
2271
  int length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, -1, NULL, 0, NULL, NULL) - 1;
2272
  stringName.assign( length, 0 );
2273
  length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, static_cast<int>(wcslen(deviceCaps.szPname)), &stringName[0], length, NULL, NULL);
2274
#else
2275
  stringName = std::string( deviceCaps.szPname );
2276
#endif
2277

    
2278
  // Next lines added to add the portNumber to the name so that 
2279
  // the device's names are sure to be listed with individual names
2280
  // even when they have the same brand name
2281
  std::ostringstream os;
2282
  os << " ";
2283
  os << portNumber;
2284
  stringName += os.str();
2285

    
2286
  return stringName;
2287
}
2288

    
2289
void MidiOutWinMM :: openPort( unsigned int portNumber, const std::string /*portName*/ )
2290
{
2291
  if ( connected_ ) {
2292
    errorString_ = "MidiOutWinMM::openPort: a valid connection already exists!";
2293
    error( RtMidiError::WARNING, errorString_ );
2294
    return;
2295
  }
2296

    
2297
  unsigned int nDevices = midiOutGetNumDevs();
2298
  if (nDevices < 1) {
2299
    errorString_ = "MidiOutWinMM::openPort: no MIDI output destinations found!";
2300
    error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
2301
    return;
2302
  }
2303

    
2304
  if ( portNumber >= nDevices ) {
2305
    std::ostringstream ost;
2306
    ost << "MidiOutWinMM::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
2307
    errorString_ = ost.str();
2308
    error( RtMidiError::INVALID_PARAMETER, errorString_ );
2309
    return;
2310
  }
2311

    
2312
  WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2313
  MMRESULT result = midiOutOpen( &data->outHandle,
2314
                                 portNumber,
2315
                                 (DWORD)NULL,
2316
                                 (DWORD)NULL,
2317
                                 CALLBACK_NULL );
2318
  if ( result != MMSYSERR_NOERROR ) {
2319
    errorString_ = "MidiOutWinMM::openPort: error creating Windows MM MIDI output port.";
2320
    error( RtMidiError::DRIVER_ERROR, errorString_ );
2321
    return;
2322
  }
2323

    
2324
  connected_ = true;
2325
}
2326

    
2327
void MidiOutWinMM :: closePort( void )
2328
{
2329
  if ( connected_ ) {
2330
    WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2331
    midiOutReset( data->outHandle );
2332
    midiOutClose( data->outHandle );
2333
    connected_ = false;
2334
  }
2335
}
2336

    
2337
void MidiOutWinMM :: openVirtualPort( std::string /*portName*/ )
2338
{
2339
  // This function cannot be implemented for the Windows MM MIDI API.
2340
  errorString_ = "MidiOutWinMM::openVirtualPort: cannot be implemented in Windows MM MIDI API!";
2341
  error( RtMidiError::WARNING, errorString_ );
2342
}
2343

    
2344
void MidiOutWinMM :: sendMessage( std::vector<unsigned char> *message )
2345
{
2346
  if ( !connected_ ) return;
2347

    
2348
  unsigned int nBytes = static_cast<unsigned int>(message->size());
2349
  if ( nBytes == 0 ) {
2350
    errorString_ = "MidiOutWinMM::sendMessage: message argument is empty!";
2351
    error( RtMidiError::WARNING, errorString_ );
2352
    return;
2353
  }
2354

    
2355
  MMRESULT result;
2356
  WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2357
  if ( message->at(0) == 0xF0 ) { // Sysex message
2358

    
2359
    // Allocate buffer for sysex data.
2360
    char *buffer = (char *) malloc( nBytes );
2361
    if ( buffer == NULL ) {
2362
      errorString_ = "MidiOutWinMM::sendMessage: error allocating sysex message memory!";
2363
      error( RtMidiError::MEMORY_ERROR, errorString_ );
2364
      return;
2365
    }
2366

    
2367
    // Copy data to buffer.
2368
    for ( unsigned int i=0; i<nBytes; ++i ) buffer[i] = message->at(i);
2369

    
2370
    // Create and prepare MIDIHDR structure.
2371
    MIDIHDR sysex;
2372
    sysex.lpData = (LPSTR) buffer;
2373
    sysex.dwBufferLength = nBytes;
2374
    sysex.dwFlags = 0;
2375
    result = midiOutPrepareHeader( data->outHandle,  &sysex, sizeof(MIDIHDR) ); 
2376
    if ( result != MMSYSERR_NOERROR ) {
2377
      free( buffer );
2378
      errorString_ = "MidiOutWinMM::sendMessage: error preparing sysex header.";
2379
      error( RtMidiError::DRIVER_ERROR, errorString_ );
2380
      return;
2381
    }
2382

    
2383
    // Send the message.
2384
    result = midiOutLongMsg( data->outHandle, &sysex, sizeof(MIDIHDR) );
2385
    if ( result != MMSYSERR_NOERROR ) {
2386
      free( buffer );
2387
      errorString_ = "MidiOutWinMM::sendMessage: error sending sysex message.";
2388
      error( RtMidiError::DRIVER_ERROR, errorString_ );
2389
      return;
2390
    }
2391

    
2392
    // Unprepare the buffer and MIDIHDR.
2393
    while ( MIDIERR_STILLPLAYING == midiOutUnprepareHeader( data->outHandle, &sysex, sizeof (MIDIHDR) ) ) Sleep( 1 );
2394
    free( buffer );
2395
  }
2396
  else { // Channel or system message.
2397

    
2398
    // Make sure the message size isn't too big.
2399
    if ( nBytes > 3 ) {
2400
      errorString_ = "MidiOutWinMM::sendMessage: message size is greater than 3 bytes (and not sysex)!";
2401
      error( RtMidiError::WARNING, errorString_ );
2402
      return;
2403
    }
2404

    
2405
    // Pack MIDI bytes into double word.
2406
    DWORD packet;
2407
    unsigned char *ptr = (unsigned char *) &packet;
2408
    for ( unsigned int i=0; i<nBytes; ++i ) {
2409
      *ptr = message->at(i);
2410
      ++ptr;
2411
    }
2412

    
2413
    // Send the message immediately.
2414
    result = midiOutShortMsg( data->outHandle, packet );
2415
    if ( result != MMSYSERR_NOERROR ) {
2416
      errorString_ = "MidiOutWinMM::sendMessage: error sending MIDI message.";
2417
      error( RtMidiError::DRIVER_ERROR, errorString_ );
2418
    }
2419
  }
2420
}
2421

    
2422
#endif  // __WINDOWS_MM__
2423

    
2424

    
2425
//*********************************************************************//
2426
//  API: UNIX JACK
2427
//
2428
//  Written primarily by Alexander Svetalkin, with updates for delta
2429
//  time by Gary Scavone, April 2011.
2430
//
2431
//  *********************************************************************//
2432

    
2433
#if defined(__UNIX_JACK__)
2434

    
2435
// JACK header files
2436
#include <jack/jack.h>
2437
#include <jack/midiport.h>
2438
#include <jack/ringbuffer.h>
2439

    
2440
#define JACK_RINGBUFFER_SIZE 16384 // Default size for ringbuffer
2441

    
2442
struct JackMidiData {
2443
  jack_client_t *client;
2444
  jack_port_t *port;
2445
  jack_ringbuffer_t *buffSize;
2446
  jack_ringbuffer_t *buffMessage;
2447
  jack_time_t lastTime;
2448
  MidiInApi :: RtMidiInData *rtMidiIn;
2449
  };
2450

    
2451
//*********************************************************************//
2452
//  API: JACK
2453
//  Class Definitions: MidiInJack
2454
//*********************************************************************//
2455

    
2456
static int jackProcessIn( jack_nframes_t nframes, void *arg )
2457
{
2458
  JackMidiData *jData = (JackMidiData *) arg;
2459
  MidiInApi :: RtMidiInData *rtData = jData->rtMidiIn;
2460
  jack_midi_event_t event;
2461
  jack_time_t time;
2462

    
2463
  // Is port created?
2464
  if ( jData->port == NULL ) return 0;
2465
  void *buff = jack_port_get_buffer( jData->port, nframes );
2466

    
2467
  // We have midi events in buffer
2468
  int evCount = jack_midi_get_event_count( buff );
2469
  for (int j = 0; j < evCount; j++) {
2470
    MidiInApi::MidiMessage message;
2471
    message.bytes.clear();
2472

    
2473
    jack_midi_event_get( &event, buff, j );
2474

    
2475
    for ( unsigned int i = 0; i < event.size; i++ )
2476
      message.bytes.push_back( event.buffer[i] );
2477

    
2478
    // Compute the delta time.
2479
    time = jack_get_time();
2480
    if ( rtData->firstMessage == true )
2481
      rtData->firstMessage = false;
2482
    else
2483
      message.timeStamp = ( time - jData->lastTime ) * 0.000001;
2484

    
2485
    jData->lastTime = time;
2486

    
2487
    if ( !rtData->continueSysex ) {
2488
      if ( rtData->usingCallback ) {
2489
        RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) rtData->userCallback;
2490
        callback( message.timeStamp, &message.bytes, rtData->userData );
2491
      }
2492
      else {
2493
        // As long as we haven't reached our queue size limit, push the message.
2494
        if ( rtData->queue.size < rtData->queue.ringSize ) {
2495
          rtData->queue.ring[rtData->queue.back++] = message;
2496
          if ( rtData->queue.back == rtData->queue.ringSize )
2497
            rtData->queue.back = 0;
2498
          rtData->queue.size++;
2499
        }
2500
        else
2501
          std::cerr << "\nMidiInJack: message queue limit reached!!\n\n";
2502
      }
2503
    }
2504
  }
2505

    
2506
  return 0;
2507
}
2508

    
2509
MidiInJack :: MidiInJack( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
2510
{
2511
  initialize( clientName );
2512
}
2513

    
2514
void MidiInJack :: initialize( const std::string& clientName )
2515
{
2516
  JackMidiData *data = new JackMidiData;
2517
  apiData_ = (void *) data;
2518

    
2519
  data->rtMidiIn = &inputData_;
2520
  data->port = NULL;
2521
  data->client = NULL;
2522
  this->clientName = clientName;
2523

    
2524
  connect();
2525
}
2526

    
2527
void MidiInJack :: connect()
2528
{
2529
  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2530
  if ( data->client )
2531
    return;
2532

    
2533
  // Initialize JACK client
2534
  if (( data->client = jack_client_open( clientName.c_str(), JackNoStartServer, NULL )) == 0) {
2535
    errorString_ = "MidiInJack::initialize: JACK server not running?";
2536
    error( RtMidiError::WARNING, errorString_ );
2537
    return;
2538
  }
2539

    
2540
  jack_set_process_callback( data->client, jackProcessIn, data );
2541
  jack_activate( data->client );
2542
}
2543

    
2544
MidiInJack :: ~MidiInJack()
2545
{
2546
  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2547
  closePort();
2548

    
2549
  if ( data->client )
2550
    jack_client_close( data->client );
2551
  delete data;
2552
}
2553

    
2554
void MidiInJack :: openPort( unsigned int portNumber, const std::string portName )
2555
{
2556
  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2557

    
2558
  connect();
2559

    
2560
  // Creating new port
2561
  if ( data->port == NULL)
2562
    data->port = jack_port_register( data->client, portName.c_str(),
2563
                                     JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0 );
2564

    
2565
  if ( data->port == NULL) {
2566
    errorString_ = "MidiInJack::openPort: JACK error creating port";
2567
    error( RtMidiError::DRIVER_ERROR, errorString_ );
2568
    return;
2569
  }
2570

    
2571
  // Connecting to the output
2572
  std::string name = getPortName( portNumber );
2573
  jack_connect( data->client, name.c_str(), jack_port_name( data->port ) );
2574
}
2575

    
2576
void MidiInJack :: openVirtualPort( const std::string portName )
2577
{
2578
  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2579

    
2580
  connect();
2581
  if ( data->port == NULL )
2582
    data->port = jack_port_register( data->client, portName.c_str(),
2583
                                     JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0 );
2584

    
2585
  if ( data->port == NULL ) {
2586
    errorString_ = "MidiInJack::openVirtualPort: JACK error creating virtual port";
2587
    error( RtMidiError::DRIVER_ERROR, errorString_ );
2588
  }
2589
}
2590

    
2591
unsigned int MidiInJack :: getPortCount()
2592
{
2593
  int count = 0;
2594
  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2595
  connect();
2596
  if ( !data->client )
2597
    return 0;
2598

    
2599
  // List of available ports
2600
  const char **ports = jack_get_ports( data->client, NULL, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput );
2601

    
2602
  if ( ports == NULL ) return 0;
2603
  while ( ports[count] != NULL )
2604
    count++;
2605

    
2606
  free( ports );
2607

    
2608
  return count;
2609
}
2610

    
2611
std::string MidiInJack :: getPortName( unsigned int portNumber )
2612
{
2613
  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2614
  std::string retStr("");
2615

    
2616
  connect();
2617

    
2618
  // List of available ports
2619
  const char **ports = jack_get_ports( data->client, NULL,
2620
                                       JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput );
2621

    
2622
  // Check port validity
2623
  if ( ports == NULL ) {
2624
    errorString_ = "MidiInJack::getPortName: no ports available!";
2625
    error( RtMidiError::WARNING, errorString_ );
2626
    return retStr;
2627
  }
2628

    
2629
  if ( ports[portNumber] == NULL ) {
2630
    std::ostringstream ost;
2631
    ost << "MidiInJack::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
2632
    errorString_ = ost.str();
2633
    error( RtMidiError::WARNING, errorString_ );
2634
  }
2635
  else retStr.assign( ports[portNumber] );
2636

    
2637
  free( ports );
2638
  return retStr;
2639
}
2640

    
2641
void MidiInJack :: closePort()
2642
{
2643
  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2644

    
2645
  if ( data->port == NULL ) return;
2646
  jack_port_unregister( data->client, data->port );
2647
  data->port = NULL;
2648
}
2649

    
2650
//*********************************************************************//
2651
//  API: JACK
2652
//  Class Definitions: MidiOutJack
2653
//*********************************************************************//
2654

    
2655
// Jack process callback
2656
static int jackProcessOut( jack_nframes_t nframes, void *arg )
2657
{
2658
  JackMidiData *data = (JackMidiData *) arg;
2659
  jack_midi_data_t *midiData;
2660
  int space;
2661

    
2662
  // Is port created?
2663
  if ( data->port == NULL ) return 0;
2664

    
2665
  void *buff = jack_port_get_buffer( data->port, nframes );
2666
  jack_midi_clear_buffer( buff );
2667

    
2668
  while ( jack_ringbuffer_read_space( data->buffSize ) > 0 ) {
2669
    jack_ringbuffer_read( data->buffSize, (char *) &space, (size_t) sizeof(space) );
2670
    midiData = jack_midi_event_reserve( buff, 0, space );
2671

    
2672
    jack_ringbuffer_read( data->buffMessage, (char *) midiData, (size_t) space );
2673
  }
2674

    
2675
  return 0;
2676
}
2677

    
2678
MidiOutJack :: MidiOutJack( const std::string clientName ) : MidiOutApi()
2679
{
2680
  initialize( clientName );
2681
}
2682

    
2683
void MidiOutJack :: initialize( const std::string& clientName )
2684
{
2685
  JackMidiData *data = new JackMidiData;
2686
  apiData_ = (void *) data;
2687

    
2688
  data->port = NULL;
2689
  data->client = NULL;
2690
  this->clientName = clientName;
2691

    
2692
  connect();
2693
}
2694

    
2695
void MidiOutJack :: connect()
2696
{
2697
  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2698
  if ( data->client )
2699
    return;
2700
  
2701
  // Initialize output ringbuffers  
2702
  data->buffSize = jack_ringbuffer_create( JACK_RINGBUFFER_SIZE );
2703
  data->buffMessage = jack_ringbuffer_create( JACK_RINGBUFFER_SIZE );
2704

    
2705
  // Initialize JACK client
2706
  if (( data->client = jack_client_open( clientName.c_str(), JackNoStartServer, NULL )) == 0) {
2707
    errorString_ = "MidiOutJack::initialize: JACK server not running?";
2708
    error( RtMidiError::WARNING, errorString_ );
2709
    return;
2710
  }
2711

    
2712
  jack_set_process_callback( data->client, jackProcessOut, data );
2713
  jack_activate( data->client );
2714
}
2715

    
2716
MidiOutJack :: ~MidiOutJack()
2717
{
2718
  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2719
  closePort();
2720
  
2721
  // Cleanup
2722
  jack_ringbuffer_free( data->buffSize );
2723
  jack_ringbuffer_free( data->buffMessage );
2724
  if ( data->client ) {
2725
    jack_client_close( data->client );
2726
  }
2727

    
2728
  delete data;
2729
}
2730

    
2731
void MidiOutJack :: openPort( unsigned int portNumber, const std::string portName )
2732
{
2733
  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2734

    
2735
  connect();
2736

    
2737
  // Creating new port
2738
  if ( data->port == NULL )
2739
    data->port = jack_port_register( data->client, portName.c_str(),
2740
      JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0 );
2741

    
2742
  if ( data->port == NULL ) {
2743
    errorString_ = "MidiOutJack::openPort: JACK error creating port";
2744
    error( RtMidiError::DRIVER_ERROR, errorString_ );
2745
    return;
2746
  }
2747

    
2748
  // Connecting to the output
2749
  std::string name = getPortName( portNumber );
2750
  jack_connect( data->client, jack_port_name( data->port ), name.c_str() );
2751
}
2752

    
2753
void MidiOutJack :: openVirtualPort( const std::string portName )
2754
{
2755
  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2756

    
2757
  connect();
2758
  if ( data->port == NULL )
2759
    data->port = jack_port_register( data->client, portName.c_str(),
2760
      JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0 );
2761

    
2762
  if ( data->port == NULL ) {
2763
    errorString_ = "MidiOutJack::openVirtualPort: JACK error creating virtual port";
2764
    error( RtMidiError::DRIVER_ERROR, errorString_ );
2765
  }
2766
}
2767

    
2768
unsigned int MidiOutJack :: getPortCount()
2769
{
2770
  int count = 0;
2771
  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2772
  connect();
2773
  if ( !data->client )
2774
    return 0;
2775

    
2776
  // List of available ports
2777
  const char **ports = jack_get_ports( data->client, NULL,
2778
    JACK_DEFAULT_MIDI_TYPE, JackPortIsInput );
2779

    
2780
  if ( ports == NULL ) return 0;
2781
  while ( ports[count] != NULL )
2782
    count++;
2783

    
2784
  free( ports );
2785

    
2786
  return count;
2787
}
2788

    
2789
std::string MidiOutJack :: getPortName( unsigned int portNumber )
2790
{
2791
  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2792
  std::string retStr("");
2793

    
2794
  connect();
2795

    
2796
  // List of available ports
2797
  const char **ports = jack_get_ports( data->client, NULL,
2798
    JACK_DEFAULT_MIDI_TYPE, JackPortIsInput );
2799

    
2800
  // Check port validity
2801
  if ( ports == NULL) {
2802
    errorString_ = "MidiOutJack::getPortName: no ports available!";
2803
    error( RtMidiError::WARNING, errorString_ );
2804
    return retStr;
2805
  }
2806

    
2807
  if ( ports[portNumber] == NULL) {
2808
    std::ostringstream ost;
2809
    ost << "MidiOutJack::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
2810
    errorString_ = ost.str();
2811
    error( RtMidiError::WARNING, errorString_ );
2812
  }
2813
  else retStr.assign( ports[portNumber] );
2814

    
2815
  free( ports );
2816
  return retStr;
2817
}
2818

    
2819
void MidiOutJack :: closePort()
2820
{
2821
  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2822

    
2823
  if ( data->port == NULL ) return;
2824
  jack_port_unregister( data->client, data->port );
2825
  data->port = NULL;
2826
}
2827

    
2828
void MidiOutJack :: sendMessage( std::vector<unsigned char> *message )
2829
{
2830
  int nBytes = message->size();
2831
  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2832

    
2833
  // Write full message to buffer
2834
  jack_ringbuffer_write( data->buffMessage, ( const char * ) &( *message )[0],
2835
                         message->size() );
2836
  jack_ringbuffer_write( data->buffSize, ( char * ) &nBytes, sizeof( nBytes ) );
2837
}
2838

    
2839
#endif  // __UNIX_JACK__