PageRenderTime 284ms CodeModel.GetById 19ms app.highlight 239ms RepoModel.GetById 1ms app.codeStats 1ms

/RtMidi.cpp

http://ewitool.googlecode.com/
C++ | 3747 lines | 2794 code | 575 blank | 378 comment | 588 complexity | b595065c57d234c35379646fa077e891 MD5 | raw file
   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-2012 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// RtMidi: Version 2.0.1
  40
  41#include "RtMidi.h"
  42#include <sstream>
  43
  44//*********************************************************************//
  45//  RtMidi Definitions
  46//*********************************************************************//
  47
  48void RtMidi :: getCompiledApi( std::vector<RtMidi::Api> &apis ) throw()
  49{
  50  apis.clear();
  51
  52  // The order here will control the order of RtMidi's API search in
  53  // the constructor.
  54#if defined(__MACOSX_CORE__)
  55  apis.push_back( MACOSX_CORE );
  56#endif
  57#if defined(__LINUX_ALSA__)
  58  apis.push_back( LINUX_ALSA );
  59#endif
  60#if defined(__UNIX_JACK__)
  61  apis.push_back( UNIX_JACK );
  62#endif
  63#if defined(__WINDOWS_MM__)
  64  apis.push_back( WINDOWS_MM );
  65#endif
  66#if defined(__WINDOWS_KS__)
  67  apis.push_back( WINDOWS_KS );
  68#endif
  69#if defined(__RTMIDI_DUMMY__)
  70  apis.push_back( RTMIDI_DUMMY );
  71#endif
  72}
  73
  74void RtMidi :: error( RtError::Type type, std::string errorString )
  75{
  76  if (type == RtError::WARNING) {
  77    std::cerr << '\n' << errorString << "\n\n";
  78  }
  79  else if (type == RtError::DEBUG_WARNING) {
  80#if defined(__RTMIDI_DEBUG__)
  81    std::cerr << '\n' << errorString << "\n\n";
  82#endif
  83  }
  84  else {
  85    std::cerr << '\n' << errorString << "\n\n";
  86    throw RtError( errorString, type );
  87  }
  88}
  89
  90//*********************************************************************//
  91//  RtMidiIn Definitions
  92//*********************************************************************//
  93
  94void RtMidiIn :: openMidiApi( RtMidi::Api api, const std::string clientName, unsigned int queueSizeLimit )
  95{
  96  if ( rtapi_ )
  97    delete rtapi_;
  98  rtapi_ = 0;
  99
 100#if defined(__UNIX_JACK__)
 101  if ( api == UNIX_JACK )
 102    rtapi_ = new MidiInJack( clientName, queueSizeLimit );
 103#endif
 104#if defined(__LINUX_ALSA__)
 105  if ( api == LINUX_ALSA )
 106    rtapi_ = new MidiInAlsa( clientName, queueSizeLimit );
 107#endif
 108#if defined(__WINDOWS_MM__)
 109  if ( api == WINDOWS_MM )
 110    rtapi_ = new MidiInWinMM( clientName, queueSizeLimit );
 111#endif
 112#if defined(__WINDOWS_KS__)
 113  if ( api == WINDOWS_KS )
 114    rtapi_ = new MidiInWinKS( clientName, queueSizeLimit );
 115#endif
 116#if defined(__MACOSX_CORE__)
 117  if ( api == MACOSX_CORE )
 118    rtapi_ = new MidiInCore( clientName, queueSizeLimit );
 119#endif
 120#if defined(__RTMIDI_DUMMY__)
 121  if ( api == RTMIDI_DUMMY )
 122    rtapi_ = new MidiInDummy( clientName, queueSizeLimit );
 123#endif
 124}
 125
 126RtMidiIn :: RtMidiIn( RtMidi::Api api, const std::string clientName, unsigned int queueSizeLimit )
 127{
 128  rtapi_ = 0;
 129
 130  if ( api != UNSPECIFIED ) {
 131    // Attempt to open the specified API.
 132    openMidiApi( api, clientName, queueSizeLimit );
 133    if ( rtapi_ ) return;
 134
 135    // No compiled support for specified API value.  Issue a debug
 136    // warning and continue as if no API was specified.
 137    RtMidi::error( RtError::WARNING, "RtMidiIn: no compiled support for specified API argument!" );
 138  }
 139
 140  // Iterate through the compiled APIs and return as soon as we find
 141  // one with at least one port or we reach the end of the list.
 142  std::vector< RtMidi::Api > apis;
 143  getCompiledApi( apis );
 144  for ( unsigned int i=0; i<apis.size(); i++ ) {
 145    openMidiApi( apis[i], clientName, queueSizeLimit );
 146    if ( rtapi_->getPortCount() ) break;
 147  }
 148
 149  if ( rtapi_ ) return;
 150
 151  // It should not be possible to get here because the preprocessor
 152  // definition __RTMIDI_DUMMY__ is automatically defined if no
 153  // API-specific definitions are passed to the compiler. But just in
 154  // case something weird happens, we'll print out an error message.
 155  RtMidi::error( RtError::WARNING, "RtMidiIn: no compiled API support found ... critical error!!" );
 156}
 157
 158RtMidiIn :: ~RtMidiIn() throw()
 159{
 160  delete rtapi_;
 161}
 162
 163
 164//*********************************************************************//
 165//  RtMidiOut Definitions
 166//*********************************************************************//
 167
 168void RtMidiOut :: openMidiApi( RtMidi::Api api, const std::string clientName )
 169{
 170  if ( rtapi_ )
 171    delete rtapi_;
 172  rtapi_ = 0;
 173
 174#if defined(__UNIX_JACK__)
 175  if ( api == UNIX_JACK )
 176    rtapi_ = new MidiOutJack( clientName );
 177#endif
 178#if defined(__LINUX_ALSA__)
 179  if ( api == LINUX_ALSA )
 180    rtapi_ = new MidiOutAlsa( clientName );
 181#endif
 182#if defined(__WINDOWS_MM__)
 183  if ( api == WINDOWS_MM )
 184    rtapi_ = new MidiOutWinMM( clientName );
 185#endif
 186#if defined(__WINDOWS_KS__)
 187  if ( api == WINDOWS_KS )
 188    rtapi_ = new MidiOutWinKS( clientName );
 189#endif
 190#if defined(__MACOSX_CORE__)
 191  if ( api == MACOSX_CORE )
 192    rtapi_ = new MidiOutCore( clientName );
 193#endif
 194#if defined(__RTMIDI_DUMMY__)
 195  if ( api == RTMIDI_DUMMY )
 196    rtapi_ = new MidiOutDummy( clientName );
 197#endif
 198}
 199
 200RtMidiOut :: RtMidiOut( RtMidi::Api api, const std::string clientName )
 201{
 202  rtapi_ = 0;
 203
 204  if ( api != UNSPECIFIED ) {
 205    // Attempt to open the specified API.
 206    openMidiApi( api, clientName );
 207    if ( rtapi_ ) return;
 208
 209    // No compiled support for specified API value.  Issue a debug
 210    // warning and continue as if no API was specified.
 211    RtMidi::error( RtError::WARNING, "RtMidiOut: no compiled support for specified API argument!" );
 212  }
 213
 214  // Iterate through the compiled APIs and return as soon as we find
 215  // one with at least one port or we reach the end of the list.
 216  std::vector< RtMidi::Api > apis;
 217  getCompiledApi( apis );
 218  for ( unsigned int i=0; i<apis.size(); i++ ) {
 219    openMidiApi( apis[i], clientName );
 220    if ( rtapi_->getPortCount() ) break;
 221  }
 222
 223  if ( rtapi_ ) return;
 224
 225  // It should not be possible to get here because the preprocessor
 226  // definition __RTMIDI_DUMMY__ is automatically defined if no
 227  // API-specific definitions are passed to the compiler. But just in
 228  // case something weird happens, we'll print out an error message.
 229  RtMidi::error( RtError::WARNING, "RtMidiOut: no compiled API support found ... critical error!!" );
 230}
 231
 232RtMidiOut :: ~RtMidiOut() throw()
 233{
 234  delete rtapi_;
 235}
 236
 237//*********************************************************************//
 238//  Common MidiInApi Definitions
 239//*********************************************************************//
 240
 241MidiInApi :: MidiInApi( unsigned int queueSizeLimit )
 242  : apiData_( 0 ), connected_( false )
 243{
 244  // Allocate the MIDI queue.
 245  inputData_.queue.ringSize = queueSizeLimit;
 246  if ( inputData_.queue.ringSize > 0 )
 247    inputData_.queue.ring = new MidiMessage[ inputData_.queue.ringSize ];
 248}
 249
 250MidiInApi :: ~MidiInApi( void )
 251{
 252  // Delete the MIDI queue.
 253  if ( inputData_.queue.ringSize > 0 ) delete [] inputData_.queue.ring;
 254}
 255
 256void MidiInApi :: setCallback( RtMidiIn::RtMidiCallback callback, void *userData )
 257{
 258  if ( inputData_.usingCallback ) {
 259    errorString_ = "MidiInApi::setCallback: a callback function is already set!";
 260    RtMidi::error( RtError::WARNING, errorString_ );
 261    return;
 262  }
 263
 264  if ( !callback ) {
 265    errorString_ = "RtMidiIn::setCallback: callback function value is invalid!";
 266    RtMidi::error( RtError::WARNING, errorString_ );
 267    return;
 268  }
 269
 270  inputData_.userCallback = (void *) callback;
 271  inputData_.userData = userData;
 272  inputData_.usingCallback = true;
 273}
 274
 275void MidiInApi :: cancelCallback()
 276{
 277  if ( !inputData_.usingCallback ) {
 278    errorString_ = "RtMidiIn::cancelCallback: no callback function was set!";
 279    RtMidi::error( RtError::WARNING, errorString_ );
 280    return;
 281  }
 282
 283  inputData_.userCallback = 0;
 284  inputData_.userData = 0;
 285  inputData_.usingCallback = false;
 286}
 287
 288void MidiInApi :: ignoreTypes( bool midiSysex, bool midiTime, bool midiSense )
 289{
 290  inputData_.ignoreFlags = 0;
 291  if ( midiSysex ) inputData_.ignoreFlags = 0x01;
 292  if ( midiTime ) inputData_.ignoreFlags |= 0x02;
 293  if ( midiSense ) inputData_.ignoreFlags |= 0x04;
 294}
 295
 296double MidiInApi :: getMessage( std::vector<unsigned char> *message )
 297{
 298  message->clear();
 299
 300  if ( inputData_.usingCallback ) {
 301    errorString_ = "RtMidiIn::getNextMessage: a user callback is currently set for this port.";
 302    RtMidi::error( RtError::WARNING, errorString_ );
 303    return 0.0;
 304  }
 305
 306  if ( inputData_.queue.size == 0 ) return 0.0;
 307
 308  // Copy queued message to the vector pointer argument and then "pop" it.
 309  std::vector<unsigned char> *bytes = &(inputData_.queue.ring[inputData_.queue.front].bytes);
 310  message->assign( bytes->begin(), bytes->end() );
 311  double deltaTime = inputData_.queue.ring[inputData_.queue.front].timeStamp;
 312  inputData_.queue.size--;
 313  inputData_.queue.front++;
 314  if ( inputData_.queue.front == inputData_.queue.ringSize )
 315    inputData_.queue.front = 0;
 316
 317  return deltaTime;
 318}
 319
 320//*********************************************************************//
 321//  Common MidiOutApi Definitions
 322//*********************************************************************//
 323
 324MidiOutApi :: MidiOutApi( void )
 325  : apiData_( 0 ), connected_( false )
 326{
 327}
 328
 329MidiOutApi :: ~MidiOutApi( void )
 330{
 331}
 332
 333// *************************************************** //
 334//
 335// OS/API-specific methods.
 336//
 337// *************************************************** //
 338
 339#if defined(__MACOSX_CORE__)
 340
 341// The CoreMIDI API is based on the use of a callback function for
 342// MIDI input.  We convert the system specific time stamps to delta
 343// time values.
 344
 345// OS-X CoreMIDI header files.
 346#include <CoreMIDI/CoreMIDI.h>
 347#include <CoreAudio/HostTime.h>
 348#include <CoreServices/CoreServices.h>
 349
 350// A structure to hold variables related to the CoreMIDI API
 351// implementation.
 352struct CoreMidiData {
 353  MIDIClientRef client;
 354  MIDIPortRef port;
 355  MIDIEndpointRef endpoint;
 356  MIDIEndpointRef destinationId;
 357  unsigned long long lastTime;
 358  MIDISysexSendRequest sysexreq;
 359};
 360
 361//*********************************************************************//
 362//  API: OS-X
 363//  Class Definitions: MidiInCore
 364//*********************************************************************//
 365
 366void midiInputCallback( const MIDIPacketList *list, void *procRef, void *srcRef )
 367{
 368  MidiInApi::RtMidiInData *data = static_cast<MidiInApi::RtMidiInData *> (procRef);
 369  CoreMidiData *apiData = static_cast<CoreMidiData *> (data->apiData);
 370
 371  unsigned char status;
 372  unsigned short nBytes, iByte, size;
 373  unsigned long long time;
 374
 375  bool& continueSysex = data->continueSysex;
 376  MidiInApi::MidiMessage& message = data->message;
 377
 378  const MIDIPacket *packet = &list->packet[0];
 379  for ( unsigned int i=0; i<list->numPackets; ++i ) {
 380
 381    // My interpretation of the CoreMIDI documentation: all message
 382    // types, except sysex, are complete within a packet and there may
 383    // be several of them in a single packet.  Sysex messages can be
 384    // broken across multiple packets and PacketLists but are bundled
 385    // alone within each packet (these packets do not contain other
 386    // message types).  If sysex messages are split across multiple
 387    // MIDIPacketLists, they must be handled by multiple calls to this
 388    // function.
 389
 390    nBytes = packet->length;
 391    if ( nBytes == 0 ) continue;
 392
 393    // Calculate time stamp.
 394
 395    if ( data->firstMessage ) {
 396      message.timeStamp = 0.0;
 397      data->firstMessage = false;
 398    }
 399    else {
 400      time = packet->timeStamp;
 401      if ( time == 0 ) { // this happens when receiving asynchronous sysex messages
 402        time = AudioGetCurrentHostTime();
 403      }
 404      time -= apiData->lastTime;
 405      time = AudioConvertHostTimeToNanos( time );
 406      if ( !continueSysex )
 407        message.timeStamp = time * 0.000000001;
 408    }
 409    apiData->lastTime = packet->timeStamp;
 410    if ( apiData->lastTime == 0 ) { // this happens when receiving asynchronous sysex messages
 411      apiData->lastTime = AudioGetCurrentHostTime();
 412    }
 413    //std::cout << "TimeStamp = " << packet->timeStamp << std::endl;
 414
 415    iByte = 0;
 416    if ( continueSysex ) {
 417      // We have a continuing, segmented sysex message.
 418      if ( !( data->ignoreFlags & 0x01 ) ) {
 419        // If we're not ignoring sysex messages, copy the entire packet.
 420        for ( unsigned int j=0; j<nBytes; ++j )
 421          message.bytes.push_back( packet->data[j] );
 422      }
 423      continueSysex = packet->data[nBytes-1] != 0xF7;
 424
 425      if ( !continueSysex ) {
 426        // If not a continuing sysex message, invoke the user callback function or queue the message.
 427        if ( data->usingCallback ) {
 428          RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
 429          callback( message.timeStamp, &message.bytes, data->userData );
 430        }
 431        else {
 432          // As long as we haven't reached our queue size limit, push the message.
 433          if ( data->queue.size < data->queue.ringSize ) {
 434            data->queue.ring[data->queue.back++] = message;
 435            if ( data->queue.back == data->queue.ringSize )
 436              data->queue.back = 0;
 437            data->queue.size++;
 438          }
 439          else
 440            std::cerr << "\nMidiInCore: message queue limit reached!!\n\n";
 441        }
 442        message.bytes.clear();
 443      }
 444    }
 445    else {
 446      while ( iByte < nBytes ) {
 447        size = 0;
 448        // We are expecting that the next byte in the packet is a status byte.
 449        status = packet->data[iByte];
 450        if ( !(status & 0x80) ) break;
 451        // Determine the number of bytes in the MIDI message.
 452        if ( status < 0xC0 ) size = 3;
 453        else if ( status < 0xE0 ) size = 2;
 454        else if ( status < 0xF0 ) size = 3;
 455        else if ( status == 0xF0 ) {
 456          // A MIDI sysex
 457          if ( data->ignoreFlags & 0x01 ) {
 458            size = 0;
 459            iByte = nBytes;
 460          }
 461          else size = nBytes - iByte;
 462          continueSysex = packet->data[nBytes-1] != 0xF7;
 463        }
 464        else if ( status == 0xF1 ) {
 465            // A MIDI time code message
 466           if ( data->ignoreFlags & 0x02 ) {
 467            size = 0;
 468            iByte += 2;
 469           }
 470           else size = 2;
 471        }
 472        else if ( status == 0xF2 ) size = 3;
 473        else if ( status == 0xF3 ) size = 2;
 474        else if ( status == 0xF8 && ( data->ignoreFlags & 0x02 ) ) {
 475          // A MIDI timing tick message and we're ignoring it.
 476          size = 0;
 477          iByte += 1;
 478        }
 479        else if ( status == 0xFE && ( data->ignoreFlags & 0x04 ) ) {
 480          // A MIDI active sensing message and we're ignoring it.
 481          size = 0;
 482          iByte += 1;
 483        }
 484        else size = 1;
 485
 486        // Copy the MIDI data to our vector.
 487        if ( size ) {
 488          message.bytes.assign( &packet->data[iByte], &packet->data[iByte+size] );
 489          if ( !continueSysex ) {
 490            // If not a continuing sysex message, invoke the user callback function or queue the message.
 491            if ( data->usingCallback ) {
 492              RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
 493              callback( message.timeStamp, &message.bytes, data->userData );
 494            }
 495            else {
 496              // As long as we haven't reached our queue size limit, push the message.
 497              if ( data->queue.size < data->queue.ringSize ) {
 498                data->queue.ring[data->queue.back++] = message;
 499                if ( data->queue.back == data->queue.ringSize )
 500                  data->queue.back = 0;
 501                data->queue.size++;
 502              }
 503              else
 504                std::cerr << "\nMidiInCore: message queue limit reached!!\n\n";
 505            }
 506            message.bytes.clear();
 507          }
 508          iByte += size;
 509        }
 510      }
 511    }
 512    packet = MIDIPacketNext(packet);
 513  }
 514}
 515
 516MidiInCore :: MidiInCore( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
 517{
 518  initialize( clientName );
 519}
 520
 521MidiInCore :: ~MidiInCore( void )
 522{
 523  // Close a connection if it exists.
 524  closePort();
 525
 526  // Cleanup.
 527  CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
 528  MIDIClientDispose( data->client );
 529  if ( data->endpoint ) MIDIEndpointDispose( data->endpoint );
 530  delete data;
 531}
 532
 533void MidiInCore :: initialize( const std::string& clientName )
 534{
 535  // Set up our client.
 536  MIDIClientRef client;
 537  OSStatus result = MIDIClientCreate( CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII ), NULL, NULL, &client );
 538  if ( result != noErr ) {
 539    errorString_ = "MidiInCore::initialize: error creating OS-X MIDI client object.";
 540    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
 541  }
 542
 543  // Save our api-specific connection information.
 544  CoreMidiData *data = (CoreMidiData *) new CoreMidiData;
 545  data->client = client;
 546  data->endpoint = 0;
 547  apiData_ = (void *) data;
 548  inputData_.apiData = (void *) data;
 549}
 550
 551void MidiInCore :: openPort( unsigned int portNumber, const std::string portName )
 552{
 553  if ( connected_ ) {
 554    errorString_ = "MidiInCore::openPort: a valid connection already exists!";
 555    RtMidi::error( RtError::WARNING, errorString_ );
 556    return;
 557  }
 558
 559  unsigned int nSrc = MIDIGetNumberOfSources();
 560  if (nSrc < 1) {
 561    errorString_ = "MidiInCore::openPort: no MIDI input sources found!";
 562    RtMidi::error( RtError::NO_DEVICES_FOUND, errorString_ );
 563  }
 564
 565  std::ostringstream ost;
 566  if ( portNumber >= nSrc ) {
 567    ost << "MidiInCore::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
 568    errorString_ = ost.str();
 569    RtMidi::error( RtError::INVALID_PARAMETER, errorString_ );
 570  }
 571
 572  MIDIPortRef port;
 573  CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
 574  OSStatus result = MIDIInputPortCreate( data->client, 
 575                                         CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ),
 576                                         midiInputCallback, (void *)&inputData_, &port );
 577  if ( result != noErr ) {
 578    MIDIClientDispose( data->client );
 579    errorString_ = "MidiInCore::openPort: error creating OS-X MIDI input port.";
 580    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
 581  }
 582
 583  // Get the desired input source identifier.
 584  MIDIEndpointRef endpoint = MIDIGetSource( portNumber );
 585  if ( endpoint == 0 ) {
 586    MIDIPortDispose( port );
 587    MIDIClientDispose( data->client );
 588    errorString_ = "MidiInCore::openPort: error getting MIDI input source reference.";
 589    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
 590  }
 591
 592  // Make the connection.
 593  result = MIDIPortConnectSource( port, endpoint, NULL );
 594  if ( result != noErr ) {
 595    MIDIPortDispose( port );
 596    MIDIClientDispose( data->client );
 597    errorString_ = "MidiInCore::openPort: error connecting OS-X MIDI input port.";
 598    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
 599  }
 600
 601  // Save our api-specific port information.
 602  data->port = port;
 603
 604  connected_ = true;
 605}
 606
 607void MidiInCore :: openVirtualPort( const std::string portName )
 608{
 609  CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
 610
 611  // Create a virtual MIDI input destination.
 612  MIDIEndpointRef endpoint;
 613  OSStatus result = MIDIDestinationCreate( data->client,
 614                                           CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ),
 615                                           midiInputCallback, (void *)&inputData_, &endpoint );
 616  if ( result != noErr ) {
 617    errorString_ = "MidiInCore::openVirtualPort: error creating virtual OS-X MIDI destination.";
 618    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
 619  }
 620
 621  // Save our api-specific connection information.
 622  data->endpoint = endpoint;
 623}
 624
 625void MidiInCore :: closePort( void )
 626{
 627  if ( connected_ ) {
 628    CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
 629    MIDIPortDispose( data->port );
 630    connected_ = false;
 631  }
 632}
 633
 634unsigned int MidiInCore :: getPortCount()
 635{
 636  return MIDIGetNumberOfSources();
 637}
 638
 639// This function was submitted by Douglas Casey Tucker and apparently
 640// derived largely from PortMidi.
 641CFStringRef EndpointName( MIDIEndpointRef endpoint, bool isExternal )
 642{
 643  CFMutableStringRef result = CFStringCreateMutable( NULL, 0 );
 644  CFStringRef str;
 645
 646  // Begin with the endpoint's name.
 647  str = NULL;
 648  MIDIObjectGetStringProperty( endpoint, kMIDIPropertyName, &str );
 649  if ( str != NULL ) {
 650    CFStringAppend( result, str );
 651    CFRelease( str );
 652  }
 653
 654  MIDIEntityRef entity = NULL;
 655  MIDIEndpointGetEntity( endpoint, &entity );
 656  if ( entity == 0 )
 657    // probably virtual
 658    return result;
 659
 660  if ( CFStringGetLength( result ) == 0 ) {
 661    // endpoint name has zero length -- try the entity
 662    str = NULL;
 663    MIDIObjectGetStringProperty( entity, kMIDIPropertyName, &str );
 664    if ( str != NULL ) {
 665      CFStringAppend( result, str );
 666      CFRelease( str );
 667    }
 668  }
 669  // now consider the device's name
 670  MIDIDeviceRef device = 0;
 671  MIDIEntityGetDevice( entity, &device );
 672  if ( device == 0 )
 673    return result;
 674
 675  str = NULL;
 676  MIDIObjectGetStringProperty( device, kMIDIPropertyName, &str );
 677  if ( CFStringGetLength( result ) == 0 ) {
 678      CFRelease( result );
 679      return str;
 680  }
 681  if ( str != NULL ) {
 682    // if an external device has only one entity, throw away
 683    // the endpoint name and just use the device name
 684    if ( isExternal && MIDIDeviceGetNumberOfEntities( device ) < 2 ) {
 685      CFRelease( result );
 686      return str;
 687    } else {
 688      if ( CFStringGetLength( str ) == 0 ) {
 689        CFRelease( str );
 690        return result;
 691      }
 692      // does the entity name already start with the device name?
 693      // (some drivers do this though they shouldn't)
 694      // if so, do not prepend
 695        if ( CFStringCompareWithOptions( result, /* endpoint name */
 696             str /* device name */,
 697             CFRangeMake(0, CFStringGetLength( str ) ), 0 ) != kCFCompareEqualTo ) {
 698        // prepend the device name to the entity name
 699        if ( CFStringGetLength( result ) > 0 )
 700          CFStringInsert( result, 0, CFSTR(" ") );
 701        CFStringInsert( result, 0, str );
 702      }
 703      CFRelease( str );
 704    }
 705  }
 706  return result;
 707}
 708
 709// This function was submitted by Douglas Casey Tucker and apparently
 710// derived largely from PortMidi.
 711static CFStringRef ConnectedEndpointName( MIDIEndpointRef endpoint )
 712{
 713  CFMutableStringRef result = CFStringCreateMutable( NULL, 0 );
 714  CFStringRef str;
 715  OSStatus err;
 716  int i;
 717
 718  // Does the endpoint have connections?
 719  CFDataRef connections = NULL;
 720  int nConnected = 0;
 721  bool anyStrings = false;
 722  err = MIDIObjectGetDataProperty( endpoint, kMIDIPropertyConnectionUniqueID, &connections );
 723  if ( connections != NULL ) {
 724    // It has connections, follow them
 725    // Concatenate the names of all connected devices
 726    nConnected = CFDataGetLength( connections ) / sizeof(MIDIUniqueID);
 727    if ( nConnected ) {
 728      const SInt32 *pid = (const SInt32 *)(CFDataGetBytePtr(connections));
 729      for ( i=0; i<nConnected; ++i, ++pid ) {
 730        MIDIUniqueID id = EndianS32_BtoN( *pid );
 731        MIDIObjectRef connObject;
 732        MIDIObjectType connObjectType;
 733        err = MIDIObjectFindByUniqueID( id, &connObject, &connObjectType );
 734        if ( err == noErr ) {
 735          if ( connObjectType == kMIDIObjectType_ExternalSource  ||
 736              connObjectType == kMIDIObjectType_ExternalDestination ) {
 737            // Connected to an external device's endpoint (10.3 and later).
 738            str = EndpointName( (MIDIEndpointRef)(connObject), true );
 739          } else {
 740            // Connected to an external device (10.2) (or something else, catch-
 741            str = NULL;
 742            MIDIObjectGetStringProperty( connObject, kMIDIPropertyName, &str );
 743          }
 744          if ( str != NULL ) {
 745            if ( anyStrings )
 746              CFStringAppend( result, CFSTR(", ") );
 747            else anyStrings = true;
 748            CFStringAppend( result, str );
 749            CFRelease( str );
 750          }
 751        }
 752      }
 753    }
 754    CFRelease( connections );
 755  }
 756  if ( anyStrings )
 757    return result;
 758
 759  // Here, either the endpoint had no connections, or we failed to obtain names 
 760  return EndpointName( endpoint, false );
 761}
 762
 763std::string MidiInCore :: getPortName( unsigned int portNumber )
 764{
 765  CFStringRef nameRef;
 766  MIDIEndpointRef portRef;
 767  std::ostringstream ost;
 768  char name[128];
 769
 770  std::string stringName;
 771  if ( portNumber >= MIDIGetNumberOfSources() ) {
 772    ost << "MidiInCore::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
 773    errorString_ = ost.str();
 774    RtMidi::error( RtError::WARNING, errorString_ );
 775    //RtMidi::error( RtError::INVALID_PARAMETER, errorString_ );
 776    return stringName;
 777  }
 778
 779  portRef = MIDIGetSource( portNumber );
 780  nameRef = ConnectedEndpointName(portRef);
 781  CFStringGetCString( nameRef, name, sizeof(name), 0);
 782  CFRelease( nameRef );
 783
 784  return stringName = name;
 785}
 786
 787//*********************************************************************//
 788//  API: OS-X
 789//  Class Definitions: MidiOutCore
 790//*********************************************************************//
 791
 792MidiOutCore :: MidiOutCore( const std::string clientName ) : MidiOutApi()
 793{
 794  initialize( clientName );
 795}
 796
 797MidiOutCore :: ~MidiOutCore( void )
 798{
 799  // Close a connection if it exists.
 800  closePort();
 801
 802  // Cleanup.
 803  CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
 804  MIDIClientDispose( data->client );
 805  if ( data->endpoint ) MIDIEndpointDispose( data->endpoint );
 806  delete data;
 807}
 808
 809void MidiOutCore :: initialize( const std::string& clientName )
 810{
 811  // Set up our client.
 812  MIDIClientRef client;
 813  OSStatus result = MIDIClientCreate( CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII ), NULL, NULL, &client );
 814  if ( result != noErr ) {
 815    errorString_ = "MidiOutCore::initialize: error creating OS-X MIDI client object.";
 816    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
 817  }
 818
 819  // Save our api-specific connection information.
 820  CoreMidiData *data = (CoreMidiData *) new CoreMidiData;
 821  data->client = client;
 822  data->endpoint = 0;
 823  apiData_ = (void *) data;
 824}
 825
 826unsigned int MidiOutCore :: getPortCount()
 827{
 828  return MIDIGetNumberOfDestinations();
 829}
 830
 831std::string MidiOutCore :: getPortName( unsigned int portNumber )
 832{
 833  CFStringRef nameRef;
 834  MIDIEndpointRef portRef;
 835  std::ostringstream ost;
 836  char name[128];
 837
 838  std::string stringName;
 839  if ( portNumber >= MIDIGetNumberOfDestinations() ) {
 840    ost << "MidiOutCore::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
 841    errorString_ = ost.str();
 842    RtMidi::error( RtError::WARNING, errorString_ );
 843    return stringName;
 844    //RtMidi::error( RtError::INVALID_PARAMETER, errorString_ );
 845  }
 846
 847  portRef = MIDIGetDestination( portNumber );
 848  nameRef = ConnectedEndpointName(portRef);
 849  CFStringGetCString( nameRef, name, sizeof(name), 0);
 850  CFRelease( nameRef );
 851  
 852  return stringName = name;
 853}
 854
 855void MidiOutCore :: openPort( unsigned int portNumber, const std::string portName )
 856{
 857  if ( connected_ ) {
 858    errorString_ = "MidiOutCore::openPort: a valid connection already exists!";
 859    RtMidi::error( RtError::WARNING, errorString_ );
 860    return;
 861  }
 862
 863  unsigned int nDest = MIDIGetNumberOfDestinations();
 864  if (nDest < 1) {
 865    errorString_ = "MidiOutCore::openPort: no MIDI output destinations found!";
 866    RtMidi::error( RtError::NO_DEVICES_FOUND, errorString_ );
 867  }
 868
 869  std::ostringstream ost;
 870  if ( portNumber >= nDest ) {
 871    ost << "MidiOutCore::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
 872    errorString_ = ost.str();
 873    RtMidi::error( RtError::INVALID_PARAMETER, errorString_ );
 874  }
 875
 876  MIDIPortRef port;
 877  CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
 878  OSStatus result = MIDIOutputPortCreate( data->client, 
 879                                          CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ),
 880                                          &port );
 881  if ( result != noErr ) {
 882    MIDIClientDispose( data->client );
 883    errorString_ = "MidiOutCore::openPort: error creating OS-X MIDI output port.";
 884    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
 885  }
 886
 887  // Get the desired output port identifier.
 888  MIDIEndpointRef destination = MIDIGetDestination( portNumber );
 889  if ( destination == 0 ) {
 890    MIDIPortDispose( port );
 891    MIDIClientDispose( data->client );
 892    errorString_ = "MidiOutCore::openPort: error getting MIDI output destination reference.";
 893    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
 894  }
 895
 896  // Save our api-specific connection information.
 897  data->port = port;
 898  data->destinationId = destination;
 899  connected_ = true;
 900}
 901
 902void MidiOutCore :: closePort( void )
 903{
 904  if ( connected_ ) {
 905    CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
 906    MIDIPortDispose( data->port );
 907    connected_ = false;
 908  }
 909}
 910
 911void MidiOutCore :: openVirtualPort( std::string portName )
 912{
 913  CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
 914
 915  if ( data->endpoint ) {
 916    errorString_ = "MidiOutCore::openVirtualPort: a virtual output port already exists!";
 917    RtMidi::error( RtError::WARNING, errorString_ );
 918    return;
 919  }
 920
 921  // Create a virtual MIDI output source.
 922  MIDIEndpointRef endpoint;
 923  OSStatus result = MIDISourceCreate( data->client,
 924                                      CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ),
 925                                      &endpoint );
 926  if ( result != noErr ) {
 927    errorString_ = "MidiOutCore::initialize: error creating OS-X virtual MIDI source.";
 928    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
 929  }
 930
 931  // Save our api-specific connection information.
 932  data->endpoint = endpoint;
 933}
 934
 935char *sysexBuffer = 0;
 936
 937void sysexCompletionProc( MIDISysexSendRequest * sreq )
 938{
 939  //std::cout << "Completed SysEx send\n";
 940 delete sysexBuffer;
 941 sysexBuffer = 0;
 942}
 943
 944void MidiOutCore :: sendMessage( std::vector<unsigned char> *message )
 945{
 946  // We use the MIDISendSysex() function to asynchronously send sysex
 947  // messages.  Otherwise, we use a single CoreMidi MIDIPacket.
 948  unsigned int nBytes = message->size();
 949  if ( nBytes == 0 ) {
 950    errorString_ = "MidiOutCore::sendMessage: no data in message argument!";      
 951    RtMidi::error( RtError::WARNING, errorString_ );
 952    return;
 953  }
 954
 955  //  unsigned int packetBytes, bytesLeft = nBytes;
 956  //  unsigned int messageIndex = 0;
 957  MIDITimeStamp timeStamp = AudioGetCurrentHostTime();
 958  CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
 959  OSStatus result;
 960
 961  if ( message->at(0) == 0xF0 ) {
 962
 963    while ( sysexBuffer != 0 ) usleep( 1000 ); // sleep 1 ms
 964
 965   sysexBuffer = new char[nBytes];
 966   if ( sysexBuffer == NULL ) {
 967     errorString_ = "MidiOutCore::sendMessage: error allocating sysex message memory!";
 968     RtMidi::error( RtError::MEMORY_ERROR, errorString_ );
 969   }
 970
 971   // Copy data to buffer.
 972   for ( unsigned int i=0; i<nBytes; ++i ) sysexBuffer[i] = message->at(i);
 973
 974   data->sysexreq.destination = data->destinationId;
 975   data->sysexreq.data = (Byte *)sysexBuffer;
 976   data->sysexreq.bytesToSend = nBytes;
 977   data->sysexreq.complete = 0;
 978   data->sysexreq.completionProc = sysexCompletionProc;
 979   data->sysexreq.completionRefCon = &(data->sysexreq);
 980
 981   result = MIDISendSysex( &(data->sysexreq) );
 982   if ( result != noErr ) {
 983     errorString_ = "MidiOutCore::sendMessage: error sending MIDI to virtual destinations.";
 984     RtMidi::error( RtError::WARNING, errorString_ );
 985   }
 986   return;
 987  }
 988  else if ( nBytes > 3 ) {
 989   errorString_ = "MidiOutCore::sendMessage: message format problem ... not sysex but > 3 bytes?";
 990   RtMidi::error( RtError::WARNING, errorString_ );
 991   return;
 992  }
 993
 994  MIDIPacketList packetList;
 995  MIDIPacket *packet = MIDIPacketListInit( &packetList );
 996  packet = MIDIPacketListAdd( &packetList, sizeof(packetList), packet, timeStamp, nBytes, (const Byte *) &message->at( 0 ) );
 997  if ( !packet ) {
 998    errorString_ = "MidiOutCore::sendMessage: could not allocate packet list";      
 999    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
1000  }
1001
1002  // Send to any destinations that may have connected to us.
1003  if ( data->endpoint ) {
1004    result = MIDIReceived( data->endpoint, &packetList );
1005    if ( result != noErr ) {
1006      errorString_ = "MidiOutCore::sendMessage: error sending MIDI to virtual destinations.";
1007      RtMidi::error( RtError::WARNING, errorString_ );
1008    }
1009  }
1010
1011  // And send to an explicit destination port if we're connected.
1012  if ( connected_ ) {
1013    result = MIDISend( data->port, data->destinationId, &packetList );
1014    if ( result != noErr ) {
1015      errorString_ = "MidiOutCore::sendMessage: error sending MIDI message to port.";
1016      RtMidi::error( RtError::WARNING, errorString_ );
1017    }
1018  }
1019
1020}
1021
1022#endif  // __MACOSX_CORE__
1023
1024
1025//*********************************************************************//
1026//  API: LINUX ALSA SEQUENCER
1027//*********************************************************************//
1028
1029// API information found at:
1030//   - http://www.alsa-project.org/documentation.php#Library
1031
1032#if defined(__LINUX_ALSA__)
1033
1034// The ALSA Sequencer API is based on the use of a callback function for
1035// MIDI input.
1036//
1037// Thanks to Pedro Lopez-Cabanillas for help with the ALSA sequencer
1038// time stamps and other assorted fixes!!!
1039
1040// If you don't need timestamping for incoming MIDI events, define the
1041// preprocessor definition AVOID_TIMESTAMPING to save resources
1042// associated with the ALSA sequencer queues.
1043
1044#include <pthread.h>
1045#include <sys/time.h>
1046
1047// ALSA header file.
1048#include <alsa/asoundlib.h>
1049
1050// Global sequencer instance created when first In/Out object is
1051// created, then destroyed when last In/Out is deleted.
1052static snd_seq_t *s_seq = NULL;
1053
1054// Variable to keep track of how many ports are open.
1055static unsigned int s_numPorts = 0;
1056
1057// The client name to use when creating the sequencer, which is
1058// currently set on the first call to createSequencer.
1059static std::string s_clientName = "RtMidi Client";
1060
1061// A structure to hold variables related to the ALSA API
1062// implementation.
1063struct AlsaMidiData {
1064  snd_seq_t *seq;
1065  unsigned int portNum;
1066  int vport;
1067  snd_seq_port_subscribe_t *subscription;
1068  snd_midi_event_t *coder;
1069  unsigned int bufferSize;
1070  unsigned char *buffer;
1071  pthread_t thread;
1072  pthread_t dummy_thread_id;
1073  unsigned long long lastTime;
1074  int queue_id; // an input queue is needed to get timestamped events
1075  int trigger_fds[2];
1076};
1077
1078#define PORT_TYPE( pinfo, bits ) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits))
1079
1080snd_seq_t* createSequencer( const std::string& clientName )
1081{
1082  // Set up the ALSA sequencer client.
1083  if ( s_seq == NULL ) {
1084    int result = snd_seq_open(&s_seq, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK);
1085    if ( result < 0 ) {
1086      s_seq = NULL;
1087    }
1088    else {
1089      // Set client name, use current name if given string is empty.
1090      if ( clientName != "" ) {
1091        s_clientName = clientName;
1092      }
1093      snd_seq_set_client_name( s_seq, s_clientName.c_str() );
1094    }
1095  }
1096
1097  // Increment port count.
1098  s_numPorts++;
1099
1100  return s_seq;
1101}
1102
1103void freeSequencer ( void )
1104{
1105  s_numPorts--;
1106  if ( s_numPorts == 0 && s_seq != NULL ) {
1107    snd_seq_close( s_seq );
1108    s_seq = NULL;
1109  }
1110}
1111
1112//*********************************************************************//
1113//  API: LINUX ALSA
1114//  Class Definitions: MidiInAlsa
1115//*********************************************************************//
1116
1117extern "C" void *alsaMidiHandler( void *ptr )
1118{
1119  MidiInApi::RtMidiInData *data = static_cast<MidiInApi::RtMidiInData *> (ptr);
1120  AlsaMidiData *apiData = static_cast<AlsaMidiData *> (data->apiData);
1121
1122  long nBytes;
1123  unsigned long long time, lastTime;
1124  bool continueSysex = false;
1125  bool doDecode = false;
1126  MidiInApi::MidiMessage message;
1127  int poll_fd_count;
1128  struct pollfd *poll_fds;
1129
1130  snd_seq_event_t *ev;
1131  int result;
1132  apiData->bufferSize = 32;
1133  result = snd_midi_event_new( 0, &apiData->coder );
1134  if ( result < 0 ) {
1135    data->doInput = false;
1136    std::cerr << "\nMidiInAlsa::alsaMidiHandler: error initializing MIDI event parser!\n\n";
1137    return 0;
1138  }
1139  unsigned char *buffer = (unsigned char *) malloc( apiData->bufferSize );
1140  if ( buffer == NULL ) {
1141    data->doInput = false;
1142    snd_midi_event_free( apiData->coder );
1143    apiData->coder = 0;
1144    std::cerr << "\nMidiInAlsa::alsaMidiHandler: error initializing buffer memory!\n\n";
1145    return 0;
1146  }
1147  snd_midi_event_init( apiData->coder );
1148  snd_midi_event_no_status( apiData->coder, 1 ); // suppress running status messages
1149
1150  poll_fd_count = snd_seq_poll_descriptors_count( apiData->seq, POLLIN ) + 1;
1151  poll_fds = (struct pollfd*)alloca( poll_fd_count * sizeof( struct pollfd ));
1152  snd_seq_poll_descriptors( apiData->seq, poll_fds + 1, poll_fd_count - 1, POLLIN );
1153  poll_fds[0].fd = apiData->trigger_fds[0];
1154  poll_fds[0].events = POLLIN;
1155
1156  while ( data->doInput ) {
1157
1158    if ( snd_seq_event_input_pending( apiData->seq, 1 ) == 0 ) {
1159      // No data pending
1160      if ( poll( poll_fds, poll_fd_count, -1) >= 0 ) {
1161        if ( poll_fds[0].revents & POLLIN ) {
1162          bool dummy;
1163          int res = read( poll_fds[0].fd, &dummy, sizeof(dummy) );
1164          (void) res;
1165        }
1166      }
1167      continue;
1168    }
1169
1170    // If here, there should be data.
1171    result = snd_seq_event_input( apiData->seq, &ev );
1172    if ( result == -ENOSPC ) {
1173      std::cerr << "\nMidiInAlsa::alsaMidiHandler: MIDI input buffer overrun!\n\n";
1174      continue;
1175    }
1176    else if ( result <= 0 ) {
1177      std::cerr << "MidiInAlsa::alsaMidiHandler: unknown MIDI input error!\n";
1178      continue;
1179    }
1180
1181    // This is a bit weird, but we now have to decode an ALSA MIDI
1182    // event (back) into MIDI bytes.  We'll ignore non-MIDI types.
1183    if ( !continueSysex ) message.bytes.clear();
1184
1185    doDecode = false;
1186    switch ( ev->type ) {
1187
1188		case SND_SEQ_EVENT_PORT_SUBSCRIBED:
1189#if defined(__RTMIDI_DEBUG__)
1190      std::cout << "MidiInAlsa::alsaMidiHandler: port connection made!\n";
1191#endif
1192      break;
1193
1194		case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
1195#if defined(__RTMIDI_DEBUG__)
1196      std::cerr << "MidiInAlsa::alsaMidiHandler: port connection has closed!\n";
1197      std::cout << "sender = " << (int) ev->data.connect.sender.client << ":"
1198                << (int) ev->data.connect.sender.port
1199                << ", dest = " << (int) ev->data.connect.dest.client << ":"
1200                << (int) ev->data.connect.dest.port
1201                << std::endl;
1202#endif
1203      break;
1204
1205    case SND_SEQ_EVENT_QFRAME: // MIDI time code
1206      if ( !( data->ignoreFlags & 0x02 ) ) doDecode = true;
1207      break;
1208
1209    case SND_SEQ_EVENT_TICK: // MIDI timing tick
1210      if ( !( data->ignoreFlags & 0x02 ) ) doDecode = true;
1211      break;
1212
1213    case SND_SEQ_EVENT_SENSING: // Active sensing
1214      if ( !( data->ignoreFlags & 0x04 ) ) doDecode = true;
1215      break;
1216
1217		case SND_SEQ_EVENT_SYSEX:
1218      if ( (data->ignoreFlags & 0x01) ) break;
1219      if ( ev->data.ext.len > apiData->bufferSize ) {
1220        apiData->bufferSize = ev->data.ext.len;
1221        free( buffer );
1222        buffer = (unsigned char *) malloc( apiData->bufferSize );
1223        if ( buffer == NULL ) {
1224          data->doInput = false;
1225          std::cerr << "\nMidiInAlsa::alsaMidiHandler: error resizing buffer memory!\n\n";
1226          break;
1227        }
1228      }
1229
1230    default:
1231      doDecode = true;
1232    }
1233
1234    if ( doDecode ) {
1235
1236      nBytes = snd_midi_event_decode( apiData->coder, buffer, apiData->bufferSize, ev );
1237      if ( nBytes > 0 ) {
1238        // The ALSA sequencer has a maximum buffer size for MIDI sysex
1239        // events of 256 bytes.  If a device sends sysex messages larger
1240        // than this, they are segmented into 256 byte chunks.  So,
1241        // we'll watch for this and concatenate sysex chunks into a
1242        // single sysex message if necessary.
1243        if ( !continueSysex )
1244          message.bytes.assign( buffer, &buffer[nBytes] );
1245        else
1246          message.bytes.insert( message.bytes.end(), buffer, &buffer[nBytes] );
1247
1248        continueSysex = ( ( ev->type == SND_SEQ_EVENT_SYSEX ) && ( message.bytes.back() != 0xF7 ) );
1249        if ( !continueSysex ) {
1250
1251          // Calculate the time stamp:
1252          message.timeStamp = 0.0;
1253
1254          // Method 1: Use the system time.
1255          //(void)gettimeofday(&tv, (struct timezone *)NULL);
1256          //time = (tv.tv_sec * 1000000) + tv.tv_usec;
1257
1258          // Method 2: Use the ALSA sequencer event time data.
1259          // (thanks to Pedro Lopez-Cabanillas!).
1260          time = ( ev->time.time.tv_sec * 1000000 ) + ( ev->time.time.tv_nsec/1000 );
1261          lastTime = time;
1262          time -= apiData->lastTime;
1263          apiData->lastTime = lastTime;
1264          if ( data->firstMessage == true )
1265            data->firstMessage = false;
1266          else
1267            message.timeStamp = time * 0.000001;
1268        }
1269        else {
1270#if defined(__RTMIDI_DEBUG__)
1271          std::cerr << "\nMidiInAlsa::alsaMidiHandler: event parsing error or not a MIDI event!\n\n";
1272#endif
1273        }
1274      }
1275    }
1276
1277    snd_seq_free_event( ev );
1278    if ( message.bytes.size() == 0 || continueSysex ) continue;
1279
1280    if ( data->usingCallback ) {
1281      RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
1282      callback( message.timeStamp, &message.bytes, data->userData );
1283    }
1284    else {
1285      // As long as we haven't reached our queue size limit, push the message.
1286      if ( data->queue.size < data->queue.ringSize ) {
1287        data->queue.ring[data->queue.back++] = message;
1288        if ( data->queue.back == data->queue.ringSize )
1289          data->queue.back = 0;
1290        data->queue.size++;
1291      }
1292      else
1293        std::cerr << "\nMidiInAlsa: message queue limit reached!!\n\n";
1294    }
1295  }
1296
1297  if ( buffer ) free( buffer );
1298  snd_midi_event_free( apiData->coder );
1299  apiData->coder = 0;
1300  apiData->thread = apiData->dummy_thread_id;
1301  return 0;
1302}
1303
1304MidiInAlsa :: MidiInAlsa( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
1305{
1306  initialize( clientName );
1307}
1308
1309MidiInAlsa :: ~MidiInAlsa()
1310{
1311  // Close a connection if it exists.
1312  closePort();
1313
1314  // Shutdown the input thread.
1315  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1316  if ( inputData_.doInput ) {
1317    inputData_.doInput = false;
1318    int res = write( data->trigger_fds[1], &inputData_.doInput, sizeof(inputData_.doInput) );
1319    (void) res;
1320    if ( !pthread_equal(data->thread, data->dummy_thread_id) )
1321      pthread_join( data->thread, NULL );
1322  }
1323
1324  // Cleanup.
1325  close ( data->trigger_fds[0] );
1326  close ( data->trigger_fds[1] );
1327  if ( data->vport >= 0 ) snd_seq_delete_port( data->seq, data->vport );
1328#ifndef AVOID_TIMESTAMPING
1329  snd_seq_free_queue( data->seq, data->queue_id );
1330#endif
1331  freeSequencer();
1332  delete data;
1333}
1334
1335void MidiInAlsa :: initialize( const std::string& clientName )
1336{
1337  snd_seq_t* seq = createSequencer( clientName );
1338  if ( seq == NULL ) {
1339    s_seq = NULL;
1340    errorString_ = "MidiInAlsa::initialize: error creating ALSA sequencer client object.";
1341    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
1342  }
1343
1344  // Save our api-specific connection information.
1345  AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData;
1346  data->seq = seq;
1347  data->portNum = -1;
1348  data->vport = -1;
1349  data->subscription = 0;
1350  data->dummy_thread_id = pthread_self();
1351  data->thread = data->dummy_thread_id;
1352  data->trigger_fds[0] = -1;
1353  data->trigger_fds[1] = -1;
1354  apiData_ = (void *) data;
1355  inputData_.apiData = (void *) data;
1356
1357   if ( pipe(data->trigger_fds) == -1 ) {
1358    errorString_ = "MidiInAlsa::initialize: error creating pipe objects.";
1359    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
1360  }
1361
1362  // Create the input queue
1363#ifndef AVOID_TIMESTAMPING
1364  data->queue_id = snd_seq_alloc_named_queue(s_seq, "RtMidi Queue");
1365  // Set arbitrary tempo (mm=100) and resolution (240)
1366  snd_seq_queue_tempo_t *qtempo;
1367  snd_seq_queue_tempo_alloca(&qtempo);
1368  snd_seq_queue_tempo_set_tempo(qtempo, 600000);
1369  snd_seq_queue_tempo_set_ppq(qtempo, 240);
1370  snd_seq_set_queue_tempo(data->seq, data->queue_id, qtempo);
1371  snd_seq_drain_output(data->seq);
1372#endif
1373}
1374
1375// This function is used to count or get the pinfo structure for a given port number.
1376unsigned int portInfo( snd_seq_t *seq, snd_seq_port_info_t *pinfo, unsigned int type, int portNumber )
1377{
1378  snd_seq_client_info_t *cinfo;
1379  int client;
1380  int count = 0;
1381  snd_seq_client_info_alloca( &cinfo );
1382
1383  snd_seq_client_info_set_client( cinfo, -1 );
1384  while ( snd_seq_query_next_client( seq, cinfo ) >= 0 ) {
1385    client = snd_seq_client_info_get_client( cinfo );
1386    if ( client == 0 ) continue;
1387    // Reset query info
1388    snd_seq_port_info_set_client( pinfo, client );
1389    snd_seq_port_info_set_port( pinfo, -1 );
1390    while ( snd_seq_query_next_port( seq, pinfo ) >= 0 ) {
1391      unsigned int atyp = snd_seq_port_info_get_type( pinfo );
1392      if ( ( atyp & SND_SEQ_PORT_TYPE_MIDI_GENERIC ) == 0 ) continue;
1393      unsigned int caps = snd_seq_port_info_get_capability( pinfo );
1394      if ( ( caps & type ) != type ) continue;
1395      if ( count == portNumber ) return 1;
1396      ++count;
1397    }
1398  }
1399
1400  // If a negative portNumber was used, return the port count.
1401  if ( portNumber < 0 ) return count;
1402  return 0;
1403}
1404
1405unsigned int MidiInAlsa :: getPortCount()
1406{
1407  snd_seq_port_info_t *pinfo;
1408  snd_seq_port_info_alloca( &pinfo );
1409
1410  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1411  return portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, -1 );
1412}
1413
1414std::string MidiInAlsa :: getPortName( unsigned int portNumber )
1415{
1416  snd_seq_client_info_t *cinfo;
1417  snd_seq_port_info_t *pinfo;
1418  snd_seq_client_info_alloca( &cinfo );
1419  snd_seq_port_info_alloca( &pinfo );
1420
1421  std::string stringName;
1422  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1423  if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, (int) portNumber ) ) {
1424    int cnum = snd_seq_port_info_get_client( pinfo );
1425    snd_seq_get_any_client_info( data->seq, cnum, cinfo );
1426    std::ostringstream os;
1427    os << snd_seq_client_info_get_name( cinfo );
1428    os << " ";                                    // GO: These lines added to make sure devices are listed
1429    os << snd_seq_port_info_get_client( pinfo );  // GO: with full portnames added to ensure individual device names
1430    os << ":";
1431    os << snd_seq_port_info_get_port( pinfo );
1432    stringName = os.str();
1433    return stringName;
1434  }
1435
1436  // If we get here, we didn't find a match.
1437  errorString_ = "MidiInAlsa::getPortName: error looking for port name!";
1438  RtMidi::error( RtError::WARNING, errorString_ );
1439  return stringName;
1440  //RtMidi::error( RtError::INVALID_PARAMETER, errorString_ );
1441}
1442
1443void MidiInAlsa :: openPort( unsigned int portNumber, const std::string portName )
1444{
1445  if ( connected_ ) {
1446    errorString_ = "MidiInAlsa::openPort: a valid connection already exists!";
1447    RtMidi::error( RtError::WARNING, errorString_ );
1448    return;
1449  }
1450
1451  unsigned int nSrc = this->getPortCount();
1452  if (nSrc < 1) {
1453    errorString_ = "MidiInAlsa::openPort: no MIDI input sources found!";
1454    RtMidi::error( RtError::NO_DEVICES_FOUND, errorString_ );
1455  }
1456
1457  snd_seq_port_info_t *pinfo;
1458  snd_seq_port_info_alloca( &pinfo );
1459  std::ostringstream ost;
1460  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1461  if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, (int) portNumber ) == 0 ) {
1462    ost << "MidiInAlsa::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
1463    errorString_ = ost.str();
1464    RtMidi::error( RtError::INVALID_PARAMETER, errorString_ );
1465  }
1466
1467
1468  snd_seq_addr_t sender, receiver;
1469  sender.client = snd_seq_port_info_get_client( pinfo );
1470  sender.port = snd_seq_port_info_get_port( pinfo );
1471  receiver.client = snd_seq_client_id( data->seq );
1472  if ( data->vport < 0 ) {
1473    snd_seq_port_info_set_client( pinfo, 0 );
1474    snd_seq_port_info_set_port( pinfo, 0 );
1475    snd_seq_port_info_set_capability( pinfo,
1476                                      SND_SEQ_PORT_CAP_WRITE |
1477                                      SND_SEQ_PORT_CAP_SUBS_WRITE );
1478    snd_seq_port_info_set_type( pinfo,
1479                                SND_SEQ_PORT_TYPE_MIDI_GENERIC |
1480                                SND_SEQ_PORT_TYPE_APPLICATION );
1481    snd_seq_port_info_set_midi_channels(pinfo, 16);
1482#ifndef AVOID_TIMESTAMPING
1483    snd_seq_port_info_set_timestamping(pinfo, 1);
1484    snd_seq_port_info_set_timestamp_real(pinfo, 1);    
1485    snd_seq_port_info_set_timestamp_queue(pinfo, data->queue_id);
1486#endif
1487    snd_seq_port_info_set_name(pinfo,  portName.c_str() );
1488    data->vport = snd_seq_create_port(data->seq, pinfo);
1489  
1490    if ( data->vport < 0 ) {
1491      errorString_ = "MidiInAlsa::openPort: ALSA error creating input port.";
1492      RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
1493    }
1494  }
1495
1496  receiver.port = data->vport;
1497
1498  if ( !data->subscription ) {
1499    // Make subscription
1500    if (snd_seq_port_subscribe_malloc( &data->subscription ) < 0) {
1501      errorString_ = "MidiInAlsa::openPort: ALSA error allocation port subscription.";
1502      RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
1503    }
1504    snd_seq_port_subscribe_set_sender(data->subscription, &sender);
1505    snd_seq_port_subscribe_set_dest(data->subscription, &receiver);
1506    if ( snd_seq_subscribe_port(data->seq, data->subscription) ) {
1507      snd_seq_port_subscribe_free( data->subscription );
1508      data->subscription = 0;
1509      errorString_ = "MidiInAlsa::openPort: ALSA error making port connection.";
1510      RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
1511    }
1512  }
1513
1514  if ( inputData_.doInput == false ) {
1515    // Start the input queue
1516#ifndef AVOID_TIMESTAMPING
1517    snd_seq_start_queue( data->seq, data->queue_id, NULL );
1518    snd_seq_drain_output( data->seq );
1519#endif
1520    // Start our MIDI input thread.
1521    pthread_attr_t attr;
1522    pthread_attr_init(&attr);
1523    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1524    pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
1525
1526    inputData_.doInput = true;
1527    int err = pthread_create(&data->thread, &attr, alsaMidiHandler, &inputData_);
1528    pthread_attr_destroy(&attr);
1529    if ( err ) {
1530      snd_seq_unsubscribe_port( data->seq, data->subscription );
1531      snd_seq_port_subscribe_free( data->subscription );
1532      data->subscription = 0;
1533      inputData_.doInput = false;
1534      errorString_ = "MidiInAlsa::openPort: error starting MIDI input thread!";
1535      RtMidi::error( RtError::THREAD_ERROR, errorString_ );
1536    }
1537  }
1538
1539  connected_ = true;
1540}
1541
1542void MidiInAlsa :: openVirtualPort( std::string portName )
1543{
1544  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1545  if ( data->vport < 0 ) {
1546    snd_seq_port_info_t *pinfo;
1547    snd_seq_port_info_alloca( &pinfo );
1548    snd_seq_port_info_set_capability( pinfo,
1549				      SND_SEQ_PORT_CAP_WRITE |
1550				      SND_SEQ_PORT_CAP_SUBS_WRITE );
1551    snd_seq_port_info_set_type( pinfo,
1552				SND_SEQ_PORT_TYPE_MIDI_GENERIC |
1553				SND_SEQ_PORT_TYPE_APPLICATION );
1554    snd_seq_port_info_set_midi_channels(pinfo, 16);
1555#ifndef AVOID_TIMESTAMPING
1556    snd_seq_port_info_set_timestamping(pinfo, 1);
1557    snd_seq_port_info_set_timestamp_real(pinfo, 1);    
1558    snd_seq_port_info_set_timestamp_queue(pinfo, data->queue_id);
1559#endif
1560    snd_seq_port_info_set_name(pinfo, portName.c_str());
1561    data->vport = snd_seq_create_port(data->seq, pinfo);
1562
1563    if ( data->vport < 0 ) {
1564      errorString_ = "MidiInAlsa::openVirtualPort: ALSA error creating virtual port.";
1565      RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
1566    }
1567  }
1568
1569  if ( inputData_.doInput == false ) {
1570    // Wait for old thread to stop, if still running
1571    if ( !pthread_equal(data->thread, data->dummy_thread_id) )
1572      pthread_join( data->thread, NULL );
1573
1574    // Start the input queue
1575#ifndef AVOID_TIMESTAMPING
1576    snd_seq_start_queue( data->seq, data->queue_id, NULL );
1577    snd_seq_drain_output( data->seq );
1578#endif
1579    // Start our MIDI input thread.
1580    pthread_attr_t attr;
1581    pthread_attr_init(&attr);
1582    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1583    pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
1584
1585    inputData_.doInput = true;
1586    int err = pthread_create(&data->thread, &attr, alsaMidiHandler, &inputData_);
1587    pthread_attr_destroy(&attr);
1588    if ( err ) {
1589      if ( data->subscription ) {
1590        snd_seq_unsubscribe_port( data->seq, data->subscription );
1591        snd_seq_port_subscribe_free( data->subscription );
1592        data->subscription = 0;
1593      }
1594      inputData_.doInput = false;
1595      errorString_ = "MidiInAlsa::openPort: error starting MIDI input thread!";
1596      RtMidi::error( RtError::THREAD_ERROR, errorString_ );
1597    }
1598  }
1599}
1600
1601void MidiInAlsa :: closePort( void )
1602{
1603  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1604
1605  if ( connected_ ) {
1606    if ( data->subscription ) {
1607      snd_seq_unsubscribe_port( data->seq, data->subscription );
1608      snd_seq_port_subscribe_free( data->subscription );
1609      data->subscription = 0;
1610    }
1611    // Stop the input queue
1612#ifndef AVOID_TIMESTAMPING
1613    snd_seq_stop_queue( data->seq, data->queue_id, NULL );
1614    snd_seq_drain_output( data->seq );
1615#endif
1616    connected_ = false;
1617  }
1618
1619  // Stop thread to avoid triggering the callback, while the port is intended to be closed
1620  if ( inputData_.doInput ) {
1621    inputData_.doInput = false;
1622    int res = write( data->trigger_fds[1], &inputData_.doInput, sizeof(inputData_.doInput) );
1623    (void) res;
1624    if ( !pthread_equal(data->thread, data->dummy_thread_id) )
1625      pthread_join( data->thread, NULL );
1626  }
1627}
1628
1629//*********************************************************************//
1630//  API: LINUX ALSA
1631//  Class Definitions: MidiOutAlsa
1632//*********************************************************************//
1633
1634MidiOutAlsa :: MidiOutAlsa( const std::string clientName ) : MidiOutApi()
1635{
1636  initialize( clientName );
1637}
1638
1639MidiOutAlsa :: ~MidiOutAlsa()
1640{
1641  // Close a connection if it exists.
1642  closePort();
1643
1644  // Cleanup.
1645  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1646  if ( data->vport >= 0 ) snd_seq_delete_port( data->seq, data->vport );
1647  if ( data->coder ) snd_midi_event_free( data->coder );
1648  if ( data->buffer ) free( data->buffer );
1649  freeSequencer();
1650  delete data;
1651}
1652
1653void MidiOutAlsa :: initialize( const std::string& clientName )
1654{
1655  snd_seq_t* seq = createSequencer( clientName );
1656  if ( seq == NULL ) {
1657    s_seq = NULL;
1658    errorString_ = "MidiOutAlsa::initialize: error creating ALSA sequencer client object.";
1659    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
1660	}
1661
1662  // Save our api-specific connection information.
1663  AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData;
1664  data->seq = seq;
1665  data->portNum = -1;
1666  data->vport = -1;
1667  data->bufferSize = 32;
1668  data->coder = 0;
1669  data->buffer = 0;
1670  int result = snd_midi_event_new( data->bufferSize, &data->coder );
1671  if ( result < 0 ) {
1672    delete data;
1673    errorString_ = "MidiOutAlsa::initialize: error initializing MIDI event parser!\n\n";
1674    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
1675  }
1676  data->buffer = (unsigned char *) malloc( data->bufferSize );
1677  if ( data->buffer == NULL ) {
1678    delete data;
1679    errorString_ = "MidiOutAlsa::initialize: error allocating buffer memory!\n\n";
1680    RtMidi::error( RtError::MEMORY_ERROR, errorString_ );
1681  }
1682  snd_midi_event_init( data->coder );
1683  apiData_ = (void *) data;
1684}
1685
1686unsigned int MidiOutAlsa :: getPortCount()
1687{
1688	snd_seq_port_info_t *pinfo;
1689	snd_seq_port_info_alloca( &pinfo );
1690
1691  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1692  return portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, -1 );
1693}
1694
1695std::string MidiOutAlsa :: getPortName( unsigned int portNumber )
1696{
1697  snd_seq_client_info_t *cinfo;
1698  snd_seq_port_info_t *pinfo;
1699  snd_seq_client_info_alloca( &cinfo );
1700  snd_seq_port_info_alloca( &pinfo );
1701
1702  std::string stringName;
1703  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1704  if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber ) ) {
1705    int cnum = snd_seq_port_info_get_client(pinfo);
1706    snd_seq_get_any_client_info( data->seq, cnum, cinfo );
1707    std::ostringstream os;
1708    os << snd_seq_client_info_get_name(cinfo);
1709    os << ":";
1710    os << snd_seq_port_info_get_port(pinfo);
1711    stringName = os.str();
1712    return stringName;
1713  }
1714
1715  // If we get here, we didn't find a match.
1716  errorString_ = "MidiOutAlsa::getPortName: error looking for port name!";
1717  //RtMidi::error( RtError::INVALID_PARAMETER, errorString_ );
1718  RtMidi::error( RtError::WARNING, errorString_ );
1719  return stringName;
1720}
1721
1722void MidiOutAlsa :: openPort( unsigned int portNumber, const std::string portName )
1723{
1724  if ( connected_ ) {
1725    errorString_ = "MidiOutAlsa::openPort: a valid connection already exists!";
1726    RtMidi::error( RtError::WARNING, errorString_ );
1727    return;
1728  }
1729
1730  unsigned int nSrc = this->getPortCount();
1731  if (nSrc < 1) {
1732    errorString_ = "MidiOutAlsa::openPort: no MIDI output sources found!";
1733    RtMidi::error( RtError::NO_DEVICES_FOUND, errorString_ );
1734  }
1735
1736	snd_seq_port_info_t *pinfo;
1737	snd_seq_port_info_alloca( &pinfo );
1738  std::ostringstream ost;
1739  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1740  if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber ) == 0 ) {
1741    ost << "MidiOutAlsa::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
1742    errorString_ = ost.str();
1743    RtMidi::error( RtError::INVALID_PARAMETER, errorString_ );
1744  }
1745
1746  snd_seq_addr_t sender, receiver;
1747  receiver.client = snd_seq_port_info_get_client( pinfo );
1748  receiver.port = snd_seq_port_info_get_port( pinfo );
1749  sender.client = snd_seq_client_id( data->seq );
1750
1751  if ( data->vport < 0 ) {
1752    data->vport = snd_seq_create_simple_port( data->seq, portName.c_str(),
1753                                              SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
1754                                              SND_SEQ_PORT_TYPE_MIDI_GENERIC|SND_SEQ_PORT_TYPE_APPLICATION );
1755    if ( data->vport < 0 ) {
1756      errorString_ = "MidiOutAlsa::openPort: ALSA error creating output port.";
1757      RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
1758    }
1759  }
1760
1761  sender.port = data->vport;
1762
1763  // Make subscription
1764  if (snd_seq_port_subscribe_malloc( &data->subscription ) < 0) {
1765    snd_seq_port_subscribe_free( data->subscription );
1766    errorString_ = "MidiOutAlsa::openPort: error allocation port subscribtion.";
1767    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
1768  }
1769  snd_seq_port_subscribe_set_sender(data->subscription, &sender);
1770  snd_seq_port_subscribe_set_dest(data->subscription, &receiver);
1771  snd_seq_port_subscribe_set_time_update(data->subscription, 1);
1772  snd_seq_port_subscribe_set_time_real(data->subscription, 1);
1773  if ( snd_seq_subscribe_port(data->seq, data->subscription) ) {
1774    snd_seq_port_subscribe_free( data->subscription );
1775    errorString_ = "MidiOutAlsa::openPort: ALSA error making port connection.";
1776    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
1777  }
1778
1779  connected_ = true;
1780}
1781
1782void MidiOutAlsa :: closePort( void )
1783{
1784  if ( connected_ ) {
1785    AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1786    snd_seq_unsubscribe_port( data->seq, data->subscription );
1787    snd_seq_port_subscribe_free( data->subscription );
1788    connected_ = false;
1789  }
1790}
1791
1792void MidiOutAlsa :: openVirtualPort( std::string portName )
1793{
1794  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1795  if ( data->vport < 0 ) {
1796    data->vport = snd_seq_create_simple_port( data->seq, portName.c_str(),
1797                                              SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
1798                                              SND_SEQ_PORT_TYPE_MIDI_GENERIC|SND_SEQ_PORT_TYPE_APPLICATION );
1799
1800    if ( data->vport < 0 ) {
1801      errorString_ = "MidiOutAlsa::openVirtualPort: ALSA error creating virtual port.";
1802      RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
1803    }
1804  }
1805}
1806
1807void MidiOutAlsa :: sendMessage( std::vector<unsigned char> *message )
1808{
1809  int result;
1810  AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1811  unsigned int nBytes = message->size();
1812  if ( nBytes > data->bufferSize ) {
1813    data->bufferSize = nBytes;
1814    result = snd_midi_event_resize_buffer ( data->coder, nBytes);
1815    if ( result != 0 ) {
1816      errorString_ = "MidiOutAlsa::sendMessage: ALSA error resizing MIDI event buffer.";
1817      RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
1818    }
1819    free (data->buffer);
1820    data->buffer = (unsigned char *) malloc( data->bufferSize );
1821    if ( data->buffer == NULL ) {
1822    errorString_ = "MidiOutAlsa::initialize: error allocating buffer memory!\n\n";
1823    RtMidi::error( RtError::MEMORY_ERROR, errorString_ );
1824    }
1825  }
1826
1827  snd_seq_event_t ev;
1828  snd_seq_ev_clear(&ev);
1829  snd_seq_ev_set_source(&ev, data->vport);
1830  snd_seq_ev_set_subs(&ev);
1831  snd_seq_ev_set_direct(&ev);
1832  for ( unsigned int i=0; i<nBytes; ++i ) data->buffer[i] = message->at(i);
1833  result = snd_midi_event_encode( data->coder, data->buffer, (long)nBytes, &ev );
1834  if ( result < (int)nBytes ) {
1835    errorString_ = "MidiOutAlsa::sendMessage: event parsing error!";
1836    RtMidi::error( RtError::WARNING, errorString_ );
1837    return;
1838  }
1839
1840  // Send the event.
1841  result = snd_seq_event_output(data->seq, &ev);
1842  if ( result < 0 ) {
1843    errorString_ = "MidiOutAlsa::sendMessage: error sending MIDI message to port.";
1844    RtMidi::error( RtError::WARNING, errorString_ );
1845  }
1846  snd_seq_drain_output(data->seq);
1847}
1848
1849#endif // __LINUX_ALSA__
1850
1851
1852//*********************************************************************//
1853//  API: Windows Multimedia Library (MM)
1854//*********************************************************************//
1855
1856// API information deciphered from:
1857//  - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_midi_reference.asp
1858
1859// Thanks to Jean-Baptiste Berruchon for the sysex code.
1860
1861#if defined(__WINDOWS_MM__)
1862
1863// The Windows MM API is based on the use of a callback function for
1864// MIDI input.  We convert the system specific time stamps to delta
1865// time values.
1866
1867// Windows MM MIDI header files.
1868#include <windows.h>
1869#include <mmsystem.h>
1870
1871#define  RT_SYSEX_BUFFER_SIZE 1024
1872#define  RT_SYSEX_BUFFER_COUNT 4
1873
1874// A structure to hold variables related to the CoreMIDI API
1875// implementation.
1876struct WinMidiData {
1877  HMIDIIN inHandle;    // Handle to Midi Input Device
1878  HMIDIOUT outHandle;  // Handle to Midi Output Device
1879  DWORD lastTime;
1880  MidiInApi::MidiMessage message;
1881  LPMIDIHDR sysexBuffer[RT_SYSEX_BUFFER_COUNT];
1882};
1883
1884//*********************************************************************//
1885//  API: Windows MM
1886//  Class Definitions: MidiInWinMM
1887//*********************************************************************//
1888
1889static void CALLBACK midiInputCallback( HMIDIIN hmin,
1890                                        UINT inputStatus, 
1891                                        DWORD_PTR instancePtr,
1892                                        DWORD_PTR midiMessage,
1893                                        DWORD timestamp )
1894{
1895  if ( inputStatus != MIM_DATA && inputStatus != MIM_LONGDATA && inputStatus != MIM_LONGERROR ) return;
1896
1897  //MidiInApi::RtMidiInData *data = static_cast<MidiInApi::RtMidiInData *> (instancePtr);
1898  MidiInApi::RtMidiInData *data = (MidiInApi::RtMidiInData *)instancePtr;
1899  WinMidiData *apiData = static_cast<WinMidiData *> (data->apiData);
1900
1901  // Calculate time stamp.
1902  if ( data->firstMessage == true ) {
1903    apiData->message.timeStamp = 0.0;
1904    data->firstMessage = false;
1905  }
1906  else apiData->message.timeStamp = (double) ( timestamp - apiData->lastTime ) * 0.001;
1907  apiData->lastTime = timestamp;
1908
1909  if ( inputStatus == MIM_DATA ) { // Channel or system message
1910
1911    // Make sure the first byte is a status byte.
1912    unsigned char status = (unsigned char) (midiMessage & 0x000000FF);
1913    if ( !(status & 0x80) ) return;
1914
1915    // Determine the number of bytes in the MIDI message.
1916    unsigned short nBytes = 1;
1917    if ( status < 0xC0 ) nBytes = 3;
1918    else if ( status < 0xE0 ) nBytes = 2;
1919    else if ( status < 0xF0 ) nBytes = 3;
1920    else if ( status == 0xF1 ) {
1921      if ( data->ignoreFlags & 0x02 ) return;
1922      else nBytes = 2;
1923    }
1924    else if ( status == 0xF2 ) nBytes = 3;
1925    else if ( status == 0xF3 ) nBytes = 2;
1926    else if ( status == 0xF8 && (data->ignoreFlags & 0x02) ) {
1927      // A MIDI timing tick message and we're ignoring it.
1928      return;
1929    }
1930    else if ( status == 0xFE && (data->ignoreFlags & 0x04) ) {
1931      // A MIDI active sensing message and we're ignoring it.
1932      return;
1933    }
1934
1935    // Copy bytes to our MIDI message.
1936    unsigned char *ptr = (unsigned char *) &midiMessage;
1937    for ( int i=0; i<nBytes; ++i ) apiData->message.bytes.push_back( *ptr++ );
1938  }
1939  else { // Sysex message ( MIM_LONGDATA or MIM_LONGERROR )
1940    MIDIHDR *sysex = ( MIDIHDR *) midiMessage; 
1941    if ( !( data->ignoreFlags & 0x01 ) && inputStatus != MIM_LONGERROR ) {  
1942      // Sysex message and we're not ignoring it
1943      for ( int i=0; i<(int)sysex->dwBytesRecorded; ++i )
1944        apiData->message.bytes.push_back( sysex->lpData[i] );
1945    }
1946
1947    // The WinMM API requires that the sysex buffer be requeued after
1948    // input of each sysex message.  Even if we are ignoring sysex
1949    // messages, we still need to requeue the buffer in case the user
1950    // decides to not ignore sysex messages in the future.  However,
1951    // it seems that WinMM calls this function with an empty sysex
1952    // buffer when an application closes and in this case, we should
1953    // avoid requeueing it, else the computer suddenly reboots after
1954    // one or two minutes.
1955	if ( apiData->sysexBuffer[sysex->dwUser]->dwBytesRecorded > 0 ) {
1956    //if ( sysex->dwBytesRecorded > 0 ) {
1957      MMRESULT result = midiInAddBuffer( apiData->inHandle, apiData->sysexBuffer[sysex->dwUser], sizeof(MIDIHDR) );
1958      if ( result != MMSYSERR_NOERROR )
1959        std::cerr << "\nRtMidiIn::midiInputCallback: error sending sysex to Midi device!!\n\n";
1960
1961      if ( data->ignoreFlags & 0x01 ) return;
1962    }
1963    else return;
1964  }
1965
1966  if ( data->usingCallback ) {
1967    RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
1968    callback( apiData->message.timeStamp, &apiData->message.bytes, data->userData );
1969  }
1970  else {
1971    // As long as we haven't reached our queue size limit, push the message.
1972    if ( data->queue.size < data->queue.ringSize ) {
1973      data->queue.ring[data->queue.back++] = apiData->message;
1974      if ( data->queue.back == data->queue.ringSize )
1975        data->queue.back = 0;
1976      data->queue.size++;
1977    }
1978    else
1979      std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
1980  }
1981
1982  // Clear the vector for the next input message.
1983  apiData->message.bytes.clear();
1984}
1985
1986MidiInWinMM :: MidiInWinMM( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
1987{
1988  initialize( clientName );
1989}
1990
1991MidiInWinMM :: ~MidiInWinMM()
1992{
1993  // Close a connection if it exists.
1994  closePort();
1995
1996  // Cleanup.
1997  WinMidiData *data = static_cast<WinMidiData *> (apiData_);
1998  delete data;
1999}
2000
2001void MidiInWinMM :: initialize( const std::string& /*clientName*/ )
2002{
2003  // We'll issue a warning here if no devices are available but not
2004  // throw an error since the user can plugin something later.
2005  unsigned int nDevices = midiInGetNumDevs();
2006  if ( nDevices == 0 ) {
2007    errorString_ = "MidiInWinMM::initialize: no MIDI input devices currently available.";
2008    RtMidi::error( RtError::WARNING, errorString_ );
2009  }
2010
2011  // Save our api-specific connection information.
2012  WinMidiData *data = (WinMidiData *) new WinMidiData;
2013  apiData_ = (void *) data;
2014  inputData_.apiData = (void *) data;
2015  data->message.bytes.clear();  // needs to be empty for first input message
2016}
2017
2018void MidiInWinMM :: openPort( unsigned int portNumber, const std::string /*portName*/ )
2019{
2020  if ( connected_ ) {
2021    errorString_ = "MidiInWinMM::openPort: a valid connection already exists!";
2022    RtMidi::error( RtError::WARNING, errorString_ );
2023    return;
2024  }
2025
2026  unsigned int nDevices = midiInGetNumDevs();
2027  if (nDevices == 0) {
2028    errorString_ = "MidiInWinMM::openPort: no MIDI input sources found!";
2029    RtMidi::error( RtError::NO_DEVICES_FOUND, errorString_ );
2030  }
2031
2032  std::ostringstream ost;
2033  if ( portNumber >= nDevices ) {
2034    ost << "MidiInWinMM::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
2035    errorString_ = ost.str();
2036    RtMidi::error( RtError::INVALID_PARAMETER, errorString_ );
2037  }
2038
2039  WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2040  MMRESULT result = midiInOpen( &data->inHandle,
2041                                portNumber,
2042                                (DWORD_PTR)&midiInputCallback,
2043                                (DWORD_PTR)&inputData_,
2044                                CALLBACK_FUNCTION );
2045  if ( result != MMSYSERR_NOERROR ) {
2046    errorString_ = "MidiInWinMM::openPort: error creating Windows MM MIDI input port.";
2047    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
2048  }
2049
2050  // Allocate and init the sysex buffers.
2051  for ( int i=0; i<RT_SYSEX_BUFFER_COUNT; ++i ) {
2052    data->sysexBuffer[i] = (MIDIHDR*) new char[ sizeof(MIDIHDR) ];
2053    data->sysexBuffer[i]->lpData = new char[ RT_SYSEX_BUFFER_SIZE ];
2054    data->sysexBuffer[i]->dwBufferLength = RT_SYSEX_BUFFER_SIZE;
2055    data->sysexBuffer[i]->dwUser = i; // We use the dwUser parameter as buffer indicator
2056    data->sysexBuffer[i]->dwFlags = 0;
2057
2058    result = midiInPrepareHeader( data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR) );
2059    if ( result != MMSYSERR_NOERROR ) {
2060      midiInClose( data->inHandle );
2061      errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port (PrepareHeader).";
2062      RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
2063    }
2064
2065    // Register the buffer.
2066    result = midiInAddBuffer( data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR) );
2067    if ( result != MMSYSERR_NOERROR ) {
2068      midiInClose( data->inHandle );
2069      errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port (AddBuffer).";
2070      RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
2071    }
2072  }
2073
2074  result = midiInStart( data->inHandle );
2075  if ( result != MMSYSERR_NOERROR ) {
2076    midiInClose( data->inHandle );
2077    errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port.";
2078    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
2079  }
2080
2081  connected_ = true;
2082}
2083
2084void MidiInWinMM :: openVirtualPort( std::string portName )
2085{
2086  // This function cannot be implemented for the Windows MM MIDI API.
2087  errorString_ = "MidiInWinMM::openVirtualPort: cannot be implemented in Windows MM MIDI API!";
2088  RtMidi::error( RtError::WARNING, errorString_ );
2089}
2090
2091void MidiInWinMM :: closePort( void )
2092{
2093  if ( connected_ ) {
2094    WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2095    midiInReset( data->inHandle );
2096    midiInStop( data->inHandle );
2097
2098    for ( int i=0; i<RT_SYSEX_BUFFER_COUNT; ++i ) {
2099      int result = midiInUnprepareHeader(data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR));
2100      delete [] data->sysexBuffer[i]->lpData;
2101      delete [] data->sysexBuffer[i];
2102      if ( result != MMSYSERR_NOERROR ) {
2103        midiInClose( data->inHandle );
2104        errorString_ = "MidiInWinMM::openPort: error closing Windows MM MIDI input port (midiInUnprepareHeader).";
2105        RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
2106      }
2107    }
2108
2109    midiInClose( data->inHandle );
2110    connected_ = false;
2111  }
2112}
2113
2114unsigned int MidiInWinMM :: getPortCount()
2115{
2116  return midiInGetNumDevs();
2117}
2118
2119std::string MidiInWinMM :: getPortName( unsigned int portNumber )
2120{
2121  std::string stringName;
2122  unsigned int nDevices = midiInGetNumDevs();
2123  if ( portNumber >= nDevices ) {
2124    std::ostringstream ost;
2125    ost << "MidiInWinMM::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
2126    errorString_ = ost.str();
2127    //RtMidi::error( RtError::INVALID_PARAMETER, errorString_ );
2128    RtMidi::error( RtError::WARNING, errorString_ );
2129    return stringName;
2130  }
2131
2132  MIDIINCAPS deviceCaps;
2133  midiInGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIINCAPS));
2134
2135#if defined( UNICODE ) || defined( _UNICODE )
2136  int length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, -1, NULL, 0, NULL, NULL);
2137  stringName.assign( length, 0 );
2138  length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, wcslen(deviceCaps.szPname), &stringName[0], length, NULL, NULL);
2139#else
2140  stringName = std::string( deviceCaps.szPname );
2141#endif
2142
2143  // Next lines added to add the portNumber to the name so that 
2144  // the device's names are sure to be listed with individual names
2145  // even when they have the same brand name
2146  std::ostringstream os;
2147  os << " ";
2148  os << portNumber;
2149  stringName += os.str();
2150
2151  return stringName;
2152}
2153
2154//*********************************************************************//
2155//  API: Windows MM
2156//  Class Definitions: MidiOutWinMM
2157//*********************************************************************//
2158
2159MidiOutWinMM :: MidiOutWinMM( const std::string clientName ) : MidiOutApi()
2160{
2161  initialize( clientName );
2162}
2163
2164MidiOutWinMM :: ~MidiOutWinMM()
2165{
2166  // Close a connection if it exists.
2167  closePort();
2168
2169  // Cleanup.
2170  WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2171  delete data;
2172}
2173
2174void MidiOutWinMM :: initialize( const std::string& /*clientName*/ )
2175{
2176  // We'll issue a warning here if no devices are available but not
2177  // throw an error since the user can plug something in later.
2178  unsigned int nDevices = midiOutGetNumDevs();
2179  if ( nDevices == 0 ) {
2180    errorString_ = "MidiOutWinMM::initialize: no MIDI output devices currently available.";
2181    RtMidi::error( RtError::WARNING, errorString_ );
2182  }
2183
2184  // Save our api-specific connection information.
2185  WinMidiData *data = (WinMidiData *) new WinMidiData;
2186  apiData_ = (void *) data;
2187}
2188
2189unsigned int MidiOutWinMM :: getPortCount()
2190{
2191  return midiOutGetNumDevs();
2192}
2193
2194std::string MidiOutWinMM :: getPortName( unsigned int portNumber )
2195{
2196  std::string stringName;
2197  unsigned int nDevices = midiOutGetNumDevs();
2198  if ( portNumber >= nDevices ) {
2199    std::ostringstream ost;
2200    ost << "MidiOutWinMM::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
2201    errorString_ = ost.str();
2202    //RtMidi::error( RtError::INVALID_PARAMETER, errorString_ );
2203    RtMidi::error( RtError::WARNING, errorString_ );
2204    return stringName;
2205  }
2206
2207  MIDIOUTCAPS deviceCaps;
2208  midiOutGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIOUTCAPS));
2209
2210#if defined( UNICODE ) || defined( _UNICODE )
2211  int length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, -1, NULL, 0, NULL, NULL);
2212  stringName.assign( length, 0 );
2213  length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, wcslen(deviceCaps.szPname), &stringName[0], length, NULL, NULL);
2214#else
2215  stringName = std::string( deviceCaps.szPname );
2216#endif
2217
2218  return stringName;
2219}
2220
2221void MidiOutWinMM :: openPort( unsigned int portNumber, const std::string /*portName*/ )
2222{
2223  if ( connected_ ) {
2224    errorString_ = "MidiOutWinMM::openPort: a valid connection already exists!";
2225    RtMidi::error( RtError::WARNING, errorString_ );
2226    return;
2227  }
2228
2229  unsigned int nDevices = midiOutGetNumDevs();
2230  if (nDevices < 1) {
2231    errorString_ = "MidiOutWinMM::openPort: no MIDI output destinations found!";
2232    RtMidi::error( RtError::NO_DEVICES_FOUND, errorString_ );
2233  }
2234
2235  std::ostringstream ost;
2236  if ( portNumber >= nDevices ) {
2237    ost << "MidiOutWinMM::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
2238    errorString_ = ost.str();
2239    RtMidi::error( RtError::INVALID_PARAMETER, errorString_ );
2240  }
2241
2242  WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2243  MMRESULT result = midiOutOpen( &data->outHandle,
2244                                 portNumber,
2245                                 (DWORD)NULL,
2246                                 (DWORD)NULL,
2247                                 CALLBACK_NULL );
2248  if ( result != MMSYSERR_NOERROR ) {
2249    errorString_ = "MidiOutWinMM::openPort: error creating Windows MM MIDI output port.";
2250    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
2251  }
2252
2253  connected_ = true;
2254}
2255
2256void MidiOutWinMM :: closePort( void )
2257{
2258  if ( connected_ ) {
2259    WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2260    midiOutReset( data->outHandle );
2261    midiOutClose( data->outHandle );
2262    connected_ = false;
2263  }
2264}
2265
2266void MidiOutWinMM :: openVirtualPort( std::string portName )
2267{
2268  // This function cannot be implemented for the Windows MM MIDI API.
2269  errorString_ = "MidiOutWinMM::openVirtualPort: cannot be implemented in Windows MM MIDI API!";
2270  RtMidi::error( RtError::WARNING, errorString_ );
2271}
2272
2273void MidiOutWinMM :: sendMessage( std::vector<unsigned char> *message )
2274{
2275  unsigned int nBytes = static_cast<unsigned int>(message->size());
2276  if ( nBytes == 0 ) {
2277    errorString_ = "MidiOutWinMM::sendMessage: message argument is empty!";
2278    RtMidi::error( RtError::WARNING, errorString_ );
2279    return;
2280  }
2281
2282  MMRESULT result;
2283  WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2284  if ( message->at(0) == 0xF0 ) { // Sysex message
2285
2286    // Allocate buffer for sysex data.
2287    char *buffer = (char *) malloc( nBytes );
2288    if ( buffer == NULL ) {
2289      errorString_ = "MidiOutWinMM::sendMessage: error allocating sysex message memory!";
2290      RtMidi::error( RtError::MEMORY_ERROR, errorString_ );
2291    }
2292
2293    // Copy data to buffer.
2294    for ( unsigned int i=0; i<nBytes; ++i ) buffer[i] = message->at(i);
2295
2296    // Create and prepare MIDIHDR structure.
2297    MIDIHDR sysex;
2298    sysex.lpData = (LPSTR) buffer;
2299    sysex.dwBufferLength = nBytes;
2300    sysex.dwFlags = 0;
2301    result = midiOutPrepareHeader( data->outHandle,  &sysex, sizeof(MIDIHDR) ); 
2302    if ( result != MMSYSERR_NOERROR ) {
2303      free( buffer );
2304      errorString_ = "MidiOutWinMM::sendMessage: error preparing sysex header.";
2305      RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
2306    }
2307
2308    // Send the message.
2309    result = midiOutLongMsg( data->outHandle, &sysex, sizeof(MIDIHDR) );
2310    if ( result != MMSYSERR_NOERROR ) {
2311      free( buffer );
2312      errorString_ = "MidiOutWinMM::sendMessage: error sending sysex message.";
2313      RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
2314    }
2315
2316    // Unprepare the buffer and MIDIHDR.
2317    while ( MIDIERR_STILLPLAYING == midiOutUnprepareHeader( data->outHandle, &sysex, sizeof (MIDIHDR) ) ) Sleep( 1 );
2318    free( buffer );
2319
2320  }
2321  else { // Channel or system message.
2322
2323    // Make sure the message size isn't too big.
2324    if ( nBytes > 3 ) {
2325      errorString_ = "MidiOutWinMM::sendMessage: message size is greater than 3 bytes (and not sysex)!";
2326      RtMidi::error( RtError::WARNING, errorString_ );
2327      return;
2328    }
2329
2330    // Pack MIDI bytes into double word.
2331    DWORD packet;
2332    unsigned char *ptr = (unsigned char *) &packet;
2333    for ( unsigned int i=0; i<nBytes; ++i ) {
2334      *ptr = message->at(i);
2335      ++ptr;
2336    }
2337
2338    // Send the message immediately.
2339    result = midiOutShortMsg( data->outHandle, packet );
2340    if ( result != MMSYSERR_NOERROR ) {
2341      errorString_ = "MidiOutWinMM::sendMessage: error sending MIDI message.";
2342      RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
2343    }
2344  }
2345}
2346
2347#endif  // __WINDOWS_MM__
2348
2349// *********************************************************************//
2350// API: WINDOWS Kernel Streaming
2351//
2352// Written by Sebastien Alaiwan, 2012.
2353//
2354// NOTE BY GARY: much of the KS-specific code below probably should go in a separate file.
2355//
2356// *********************************************************************//
2357
2358#if defined(__WINDOWS_KS__)
2359
2360#include <string>
2361#include <vector>
2362#include <memory>
2363#include <stdexcept>
2364#include <sstream>
2365#include <windows.h>
2366#include <setupapi.h>
2367#include <mmsystem.h>
2368
2369#include "ks.h"
2370#include "ksmedia.h"
2371
2372#define INSTANTIATE_GUID(a) GUID const a = { STATIC_ ## a }
2373
2374INSTANTIATE_GUID(GUID_NULL);
2375INSTANTIATE_GUID(KSPROPSETID_Pin);
2376INSTANTIATE_GUID(KSPROPSETID_Connection);
2377INSTANTIATE_GUID(KSPROPSETID_Topology);
2378INSTANTIATE_GUID(KSINTERFACESETID_Standard);
2379INSTANTIATE_GUID(KSMEDIUMSETID_Standard);
2380INSTANTIATE_GUID(KSDATAFORMAT_TYPE_MUSIC);
2381INSTANTIATE_GUID(KSDATAFORMAT_SUBTYPE_MIDI);
2382INSTANTIATE_GUID(KSDATAFORMAT_SPECIFIER_NONE);
2383
2384#undef INSTANTIATE_GUID
2385
2386typedef std::basic_string<TCHAR> tstring;
2387
2388inline bool IsValid(HANDLE handle)
2389{
2390  return handle != NULL && handle != INVALID_HANDLE_VALUE;
2391}
2392
2393class ComException : public std::runtime_error
2394{
2395private:
2396  static std::string MakeString(std::string const& s, HRESULT hr)
2397  {
2398    std::stringstream ss;
2399    ss << "(error 0x" << std::hex << hr << ")";
2400    return s + ss.str();
2401  }
2402
2403public:
2404  ComException(std::string const& s, HRESULT hr) :
2405    std::runtime_error(MakeString(s, hr))
2406  {
2407  }
2408};
2409
2410template<typename TFilterType>
2411class CKsEnumFilters
2412{
2413public:
2414  ~CKsEnumFilters()
2415  {
2416    DestroyLists();
2417  }
2418
2419  void EnumFilters(GUID const* categories, size_t numCategories)
2420  {
2421    DestroyLists();
2422
2423    if (categories == 0)
2424      throw std::runtime_error("CKsEnumFilters: invalid argument");
2425
2426    // Get a handle to the device set specified by the guid
2427    HDEVINFO hDevInfo = ::SetupDiGetClassDevs(&categories[0], NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
2428    if (!IsValid(hDevInfo))
2429      throw std::runtime_error("CKsEnumFilters: no devices found");
2430
2431    // Loop through members of the set and get details for each
2432    for (int iClassMember=0;;iClassMember++) {
2433      try {
2434        SP_DEVICE_INTERFACE_DATA DID;
2435        DID.cbSize = sizeof(DID);
2436        DID.Reserved = 0;
2437
2438        bool fRes = ::SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &categories[0], iClassMember, &DID);
2439        if (!fRes)
2440          break;
2441
2442        // Get filter friendly name
2443        HKEY hRegKey = ::SetupDiOpenDeviceInterfaceRegKey(hDevInfo, &DID, 0, KEY_READ);
2444        if (hRegKey == INVALID_HANDLE_VALUE)
2445          throw std::runtime_error("CKsEnumFilters: interface has no registry");
2446
2447        char friendlyName[256];
2448        DWORD dwSize = sizeof friendlyName;
2449        LONG lval = ::RegQueryValueEx(hRegKey, TEXT("FriendlyName"), NULL, NULL, (LPBYTE)friendlyName, &dwSize);
2450        ::RegCloseKey(hRegKey);
2451        if (lval != ERROR_SUCCESS)
2452          throw std::runtime_error("CKsEnumFilters: interface has no friendly name");
2453
2454        // Get details for the device registered in this class
2455        DWORD const cbItfDetails = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + MAX_PATH * sizeof(WCHAR);
2456        std::vector<BYTE> buffer(cbItfDetails);
2457
2458        SP_DEVICE_INTERFACE_DETAIL_DATA* pDevInterfaceDetails = reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA*>(&buffer[0]);
2459        pDevInterfaceDetails->cbSize = sizeof(*pDevInterfaceDetails);
2460
2461        SP_DEVINFO_DATA DevInfoData;
2462        DevInfoData.cbSize = sizeof(DevInfoData);
2463        DevInfoData.Reserved = 0;
2464
2465        fRes = ::SetupDiGetDeviceInterfaceDetail(hDevInfo, &DID, pDevInterfaceDetails, cbItfDetails, NULL, &DevInfoData);
2466        if (!fRes)
2467          throw std::runtime_error("CKsEnumFilters: could not get interface details");
2468
2469        // check additional category guids which may (or may not) have been supplied
2470        for (size_t i=1; i < numCategories; ++i) {
2471          SP_DEVICE_INTERFACE_DATA DIDAlias;
2472          DIDAlias.cbSize = sizeof(DIDAlias);
2473          DIDAlias.Reserved = 0;
2474
2475          fRes = ::SetupDiGetDeviceInterfaceAlias(hDevInfo, &DID, &categories[i], &DIDAlias);
2476          if (!fRes)
2477            throw std::runtime_error("CKsEnumFilters: could not get interface alias");
2478
2479          // Check if the this interface alias is enabled.
2480          if (!DIDAlias.Flags || (DIDAlias.Flags & SPINT_REMOVED))
2481            throw std::runtime_error("CKsEnumFilters: interface alias is not enabled");
2482        }
2483
2484        std::auto_ptr<TFilterType> pFilter(new TFilterType(pDevInterfaceDetails->DevicePath, friendlyName));
2485
2486        pFilter->Instantiate();
2487        pFilter->FindMidiPins();
2488        pFilter->Validate();
2489
2490        m_Filters.push_back(pFilter.release());
2491      }
2492      catch (std::runtime_error const& e) {
2493      }
2494    }
2495
2496    ::SetupDiDestroyDeviceInfoList(hDevInfo);
2497  }
2498
2499private:
2500  void DestroyLists()
2501  {
2502    for (size_t i=0;i < m_Filters.size();++i)
2503      delete m_Filters[i];
2504    m_Filters.clear();
2505  }
2506
2507public:
2508  // TODO: make this private.
2509  std::vector<TFilterType*> m_Filters;
2510};
2511
2512class CKsObject
2513{
2514public:
2515  CKsObject(HANDLE handle) : m_handle(handle)
2516  {
2517  }
2518
2519protected:
2520  HANDLE m_handle;
2521
2522  void SetProperty(REFGUID guidPropertySet, ULONG nProperty, void* pvValue, ULONG cbValue)
2523  {
2524    KSPROPERTY ksProperty;
2525    memset(&ksProperty, 0, sizeof ksProperty);
2526    ksProperty.Set = guidPropertySet;
2527    ksProperty.Id = nProperty;
2528    ksProperty.Flags = KSPROPERTY_TYPE_SET;
2529
2530    HRESULT hr = DeviceIoControlKsProperty(ksProperty, pvValue, cbValue);
2531    if (FAILED(hr))
2532      throw ComException("CKsObject::SetProperty: could not set property", hr);
2533  }
2534
2535private:
2536
2537  HRESULT DeviceIoControlKsProperty(KSPROPERTY& ksProperty, void* pvValue, ULONG cbValue)
2538  {
2539    ULONG ulReturned;
2540    return ::DeviceIoControl(
2541             m_handle,
2542             IOCTL_KS_PROPERTY,
2543             &ksProperty,
2544             sizeof(ksProperty),
2545             pvValue,
2546             cbValue,
2547             &ulReturned,
2548             NULL);
2549  }
2550};
2551
2552class CKsPin;
2553
2554class CKsFilter : public CKsObject
2555{
2556  friend class CKsPin;
2557
2558public:
2559  CKsFilter(tstring const& name, std::string const& sFriendlyName);
2560  virtual ~CKsFilter();
2561
2562  virtual void Instantiate();
2563
2564  template<typename T>
2565  T GetPinProperty(ULONG nPinId, ULONG nProperty)
2566  {
2567    ULONG ulReturned = 0;
2568    T value;
2569
2570    KSP_PIN ksPProp;
2571    ksPProp.Property.Set = KSPROPSETID_Pin;
2572    ksPProp.Property.Id = nProperty;
2573    ksPProp.Property.Flags = KSPROPERTY_TYPE_GET;
2574    ksPProp.PinId = nPinId;
2575    ksPProp.Reserved = 0;
2576
2577    HRESULT hr = ::DeviceIoControl(
2578      m_handle,
2579      IOCTL_KS_PROPERTY,
2580      &ksPProp,
2581      sizeof(KSP_PIN),
2582      &value,
2583      sizeof(value),
2584      &ulReturned,
2585      NULL);
2586    if (FAILED(hr))
2587      throw ComException("CKsFilter::GetPinProperty: failed to retrieve property", hr);
2588
2589    return value;
2590  }
2591
2592  void GetPinPropertyMulti(ULONG nPinId, REFGUID guidPropertySet, ULONG nProperty, PKSMULTIPLE_ITEM* ppKsMultipleItem)
2593  {
2594    HRESULT hr;
2595
2596    KSP_PIN ksPProp;
2597    ksPProp.Property.Set = guidPropertySet;
2598    ksPProp.Property.Id = nProperty;
2599    ksPProp.Property.Flags = KSPROPERTY_TYPE_GET;
2600    ksPProp.PinId = nPinId;
2601    ksPProp.Reserved = 0;
2602
2603    ULONG cbMultipleItem = 0;
2604    hr = ::DeviceIoControl(m_handle,
2605        IOCTL_KS_PROPERTY,
2606        &ksPProp.Property,
2607        sizeof(KSP_PIN),
2608        NULL,
2609        0,
2610        &cbMultipleItem,
2611        NULL);
2612    if (FAILED(hr))
2613      throw ComException("CKsFilter::GetPinPropertyMulti: cannot get property", hr);
2614
2615    *ppKsMultipleItem = (PKSMULTIPLE_ITEM) new BYTE[cbMultipleItem];
2616
2617    ULONG ulReturned = 0;
2618    hr = ::DeviceIoControl(
2619        m_handle,
2620        IOCTL_KS_PROPERTY,
2621        &ksPProp,
2622        sizeof(KSP_PIN),
2623        (PVOID)*ppKsMultipleItem,
2624        cbMultipleItem,
2625        &ulReturned,
2626        NULL);
2627    if (FAILED(hr))
2628      throw ComException("CKsFilter::GetPinPropertyMulti: cannot get property", hr);
2629  }
2630
2631  std::string const& GetFriendlyName() const
2632  {
2633    return m_sFriendlyName;
2634  }
2635
2636protected:
2637
2638  std::vector<CKsPin*> m_Pins; // this list owns the pins.
2639
2640  std::vector<CKsPin*> m_RenderPins;
2641  std::vector<CKsPin*> m_CapturePins;
2642
2643private:
2644  std::string const m_sFriendlyName; // friendly name eg "Virus TI Synth"
2645  tstring const m_sName; // Filter path, eg "\\?\usb#vid_133e&pid_0815...\vtimidi02"
2646};
2647
2648class CKsPin : public CKsObject
2649{
2650public:
2651  CKsPin(CKsFilter* pFilter, ULONG nId);
2652  virtual ~CKsPin();
2653
2654  virtual void Instantiate();
2655
2656  void ClosePin();
2657
2658  void SetState(KSSTATE ksState);
2659
2660  void WriteData(KSSTREAM_HEADER* pKSSTREAM_HEADER, OVERLAPPED* pOVERLAPPED);
2661  void ReadData(KSSTREAM_HEADER* pKSSTREAM_HEADER, OVERLAPPED* pOVERLAPPED);
2662
2663  KSPIN_DATAFLOW GetDataFlow() const
2664  {
2665    return m_DataFlow;
2666  }
2667
2668  bool IsSink() const
2669  {
2670    return m_Communication == KSPIN_COMMUNICATION_SINK
2671      || m_Communication == KSPIN_COMMUNICATION_BOTH;
2672  }
2673
2674
2675protected:
2676  PKSPIN_CONNECT m_pKsPinConnect;    // creation parameters of pin
2677  CKsFilter* const m_pFilter;
2678
2679  ULONG m_cInterfaces;
2680  PKSIDENTIFIER m_pInterfaces;
2681  PKSMULTIPLE_ITEM m_pmiInterfaces;
2682
2683  ULONG m_cMediums;
2684  PKSIDENTIFIER m_pMediums;
2685  PKSMULTIPLE_ITEM m_pmiMediums;
2686
2687  ULONG m_cDataRanges;
2688  PKSDATARANGE m_pDataRanges;
2689  PKSMULTIPLE_ITEM m_pmiDataRanges;
2690
2691  KSPIN_DATAFLOW m_DataFlow;
2692  KSPIN_COMMUNICATION m_Communication;
2693};
2694
2695CKsFilter::CKsFilter(tstring const& sName, std::string const& sFriendlyName) :
2696  CKsObject(INVALID_HANDLE_VALUE),
2697  m_sFriendlyName(sFriendlyName),
2698  m_sName(sName)
2699{
2700  if (sName.empty())
2701    throw std::runtime_error("CKsFilter::CKsFilter: name can't be empty");
2702}
2703
2704CKsFilter::~CKsFilter()
2705{
2706  for (size_t i=0;i < m_Pins.size();++i)
2707    delete m_Pins[i];
2708
2709  if (IsValid(m_handle))
2710    ::CloseHandle(m_handle);
2711}
2712
2713void CKsFilter::Instantiate()
2714{
2715  m_handle = CreateFile(
2716    m_sName.c_str(),
2717    GENERIC_READ | GENERIC_WRITE,
2718    0,
2719    NULL,
2720    OPEN_EXISTING,
2721    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
2722    NULL);
2723
2724  if (!IsValid(m_handle))
2725  {
2726    DWORD const dwError = GetLastError();
2727    throw ComException("CKsFilter::Instantiate: can't open driver", HRESULT_FROM_WIN32(dwError));
2728  }
2729}
2730
2731CKsPin::CKsPin(CKsFilter* pFilter, ULONG PinId) :
2732  CKsObject(INVALID_HANDLE_VALUE),
2733  m_pKsPinConnect(NULL),
2734  m_pFilter(pFilter)
2735{
2736  m_Communication = m_pFilter->GetPinProperty<KSPIN_COMMUNICATION>(PinId, KSPROPERTY_PIN_COMMUNICATION);
2737  m_DataFlow = m_pFilter->GetPinProperty<KSPIN_DATAFLOW>(PinId, KSPROPERTY_PIN_DATAFLOW);
2738
2739  // Interfaces
2740  m_pFilter->GetPinPropertyMulti(
2741      PinId,
2742      KSPROPSETID_Pin,
2743      KSPROPERTY_PIN_INTERFACES,
2744      &m_pmiInterfaces);
2745
2746  m_cInterfaces = m_pmiInterfaces->Count;
2747  m_pInterfaces = (PKSPIN_INTERFACE)(m_pmiInterfaces + 1);
2748
2749  // Mediums
2750  m_pFilter->GetPinPropertyMulti(
2751      PinId,
2752      KSPROPSETID_Pin,
2753      KSPROPERTY_PIN_MEDIUMS,
2754      &m_pmiMediums);
2755
2756  m_cMediums = m_pmiMediums->Count;
2757  m_pMediums = (PKSPIN_MEDIUM)(m_pmiMediums + 1);
2758
2759  // Data ranges
2760  m_pFilter->GetPinPropertyMulti(
2761      PinId,
2762      KSPROPSETID_Pin,
2763      KSPROPERTY_PIN_DATARANGES,
2764      &m_pmiDataRanges);
2765
2766  m_cDataRanges = m_pmiDataRanges->Count;
2767  m_pDataRanges = (PKSDATARANGE)(m_pmiDataRanges + 1);
2768}
2769
2770CKsPin::~CKsPin()
2771{
2772  ClosePin();
2773
2774  delete[] (BYTE*)m_pKsPinConnect;
2775  delete[] (BYTE*)m_pmiDataRanges;
2776  delete[] (BYTE*)m_pmiInterfaces;
2777  delete[] (BYTE*)m_pmiMediums;
2778}
2779
2780void CKsPin::ClosePin()
2781{
2782  if (IsValid(m_handle)) {
2783    SetState(KSSTATE_STOP);
2784    ::CloseHandle(m_handle);
2785  }
2786  m_handle = INVALID_HANDLE_VALUE;
2787}
2788
2789void CKsPin::SetState(KSSTATE ksState)
2790{
2791  SetProperty(KSPROPSETID_Connection, KSPROPERTY_CONNECTION_STATE, &ksState, sizeof(ksState));
2792}
2793
2794void CKsPin::Instantiate()
2795{
2796  if (!m_pKsPinConnect)
2797    throw std::runtime_error("CKsPin::Instanciate: abstract pin");
2798
2799  DWORD const dwResult = KsCreatePin(m_pFilter->m_handle, m_pKsPinConnect, GENERIC_WRITE | GENERIC_READ, &m_handle);
2800  if (dwResult != ERROR_SUCCESS)
2801    throw ComException("CKsMidiCapFilter::CreateRenderPin: Pin instanciation failed", HRESULT_FROM_WIN32(dwResult));
2802}
2803
2804void CKsPin::WriteData(KSSTREAM_HEADER* pKSSTREAM_HEADER, OVERLAPPED* pOVERLAPPED)
2805{
2806  DWORD cbWritten;
2807  BOOL fRes = ::DeviceIoControl(
2808    m_handle,
2809    IOCTL_KS_WRITE_STREAM,
2810    NULL,
2811    0,
2812    pKSSTREAM_HEADER,
2813    pKSSTREAM_HEADER->Size,
2814    &cbWritten,
2815    pOVERLAPPED);
2816  if (!fRes) {
2817    DWORD const dwError = GetLastError();
2818    if (dwError != ERROR_IO_PENDING)
2819      throw ComException("CKsPin::WriteData: DeviceIoControl failed", HRESULT_FROM_WIN32(dwError));
2820  }
2821}
2822
2823void CKsPin::ReadData(KSSTREAM_HEADER* pKSSTREAM_HEADER, OVERLAPPED* pOVERLAPPED)
2824{
2825  DWORD cbReturned;
2826  BOOL fRes = ::DeviceIoControl(
2827    m_handle,
2828    IOCTL_KS_READ_STREAM,
2829    NULL,
2830    0,
2831    pKSSTREAM_HEADER,
2832    pKSSTREAM_HEADER->Size,
2833    &cbReturned,
2834    pOVERLAPPED);
2835  if (!fRes) {
2836    DWORD const dwError = GetLastError();
2837    if (dwError != ERROR_IO_PENDING)
2838      throw ComException("CKsPin::ReadData: DeviceIoControl failed", HRESULT_FROM_WIN32(dwError));
2839  }
2840}
2841
2842class CKsMidiFilter : public CKsFilter
2843{
2844public:
2845  void FindMidiPins();
2846
2847protected:
2848  CKsMidiFilter(tstring const& sPath, std::string const& sFriendlyName);
2849};
2850
2851class CKsMidiPin : public CKsPin
2852{
2853public:
2854  CKsMidiPin(CKsFilter* pFilter, ULONG nId);
2855};
2856
2857class CKsMidiRenFilter : public CKsMidiFilter
2858{
2859public:
2860  CKsMidiRenFilter(tstring const& sPath, std::string const& sFriendlyName);
2861  CKsMidiPin* CreateRenderPin();
2862
2863  void Validate()
2864  {
2865    if (m_RenderPins.empty())
2866      throw std::runtime_error("Could not find a MIDI render pin");
2867  }
2868};
2869
2870class CKsMidiCapFilter : public CKsMidiFilter
2871{
2872public:
2873  CKsMidiCapFilter(tstring const& sPath, std::string const& sFriendlyName);
2874  CKsMidiPin* CreateCapturePin();
2875
2876  void Validate()
2877  {
2878    if (m_CapturePins.empty())
2879      throw std::runtime_error("Could not find a MIDI capture pin");
2880  }
2881};
2882
2883CKsMidiFilter::CKsMidiFilter(tstring const& sPath, std::string const& sFriendlyName) :
2884  CKsFilter(sPath, sFriendlyName)
2885{
2886}
2887
2888void CKsMidiFilter::FindMidiPins()
2889{
2890  ULONG numPins = GetPinProperty<ULONG>(0, KSPROPERTY_PIN_CTYPES);
2891
2892  for (ULONG iPin = 0; iPin < numPins; ++iPin) {
2893    try {
2894      KSPIN_COMMUNICATION com = GetPinProperty<KSPIN_COMMUNICATION>(iPin, KSPROPERTY_PIN_COMMUNICATION);
2895      if (com != KSPIN_COMMUNICATION_SINK && com != KSPIN_COMMUNICATION_BOTH)
2896        throw std::runtime_error("Unknown pin communication value");
2897
2898      m_Pins.push_back(new CKsMidiPin(this, iPin));
2899    }
2900    catch (std::runtime_error const&) {
2901      // pin instanciation has failed, continue to the next pin.
2902    }
2903  }
2904
2905  m_RenderPins.clear();
2906  m_CapturePins.clear();
2907
2908  for (size_t i = 0; i < m_Pins.size(); ++i) {
2909    CKsPin* const pPin = m_Pins[i];
2910
2911    if (pPin->IsSink()) {
2912      if (pPin->GetDataFlow() == KSPIN_DATAFLOW_IN)
2913        m_RenderPins.push_back(pPin);
2914      else
2915        m_CapturePins.push_back(pPin);
2916    }
2917  }
2918
2919  if (m_RenderPins.empty() && m_CapturePins.empty())
2920    throw std::runtime_error("No valid pins found on the filter.");
2921}
2922
2923CKsMidiRenFilter::CKsMidiRenFilter(tstring const& sPath, std::string const& sFriendlyName) :
2924  CKsMidiFilter(sPath, sFriendlyName)
2925{
2926}
2927
2928CKsMidiPin* CKsMidiRenFilter::CreateRenderPin()
2929{
2930  if (m_RenderPins.empty())
2931    throw std::runtime_error("Could not find a MIDI render pin");
2932
2933  CKsMidiPin* pPin = (CKsMidiPin*)m_RenderPins[0];
2934  pPin->Instantiate();
2935  return pPin;
2936}
2937
2938CKsMidiCapFilter::CKsMidiCapFilter(tstring const& sPath, std::string const& sFriendlyName) :
2939  CKsMidiFilter(sPath, sFriendlyName)
2940{
2941}
2942
2943CKsMidiPin* CKsMidiCapFilter::CreateCapturePin()
2944{
2945  if (m_CapturePins.empty())
2946    throw std::runtime_error("Could not find a MIDI capture pin");
2947
2948  CKsMidiPin* pPin = (CKsMidiPin*)m_CapturePins[0];
2949  pPin->Instantiate();
2950  return pPin;
2951}
2952
2953CKsMidiPin::CKsMidiPin(CKsFilter* pFilter, ULONG nId) :
2954  CKsPin(pFilter, nId)
2955{
2956  DWORD const cbPinCreateSize = sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT);
2957  m_pKsPinConnect = (PKSPIN_CONNECT) new BYTE[cbPinCreateSize];
2958
2959  m_pKsPinConnect->Interface.Set = KSINTERFACESETID_Standard;
2960  m_pKsPinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
2961  m_pKsPinConnect->Interface.Flags = 0;
2962  m_pKsPinConnect->Medium.Set = KSMEDIUMSETID_Standard;
2963  m_pKsPinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
2964  m_pKsPinConnect->Medium.Flags = 0;
2965  m_pKsPinConnect->PinId = nId;
2966  m_pKsPinConnect->PinToHandle = NULL;
2967  m_pKsPinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
2968  m_pKsPinConnect->Priority.PrioritySubClass = 1;
2969
2970  // point m_pDataFormat to just after the pConnect struct
2971  KSDATAFORMAT* m_pDataFormat = (KSDATAFORMAT*)(m_pKsPinConnect + 1);
2972  m_pDataFormat->FormatSize = sizeof(KSDATAFORMAT);
2973  m_pDataFormat->Flags = 0;
2974  m_pDataFormat->SampleSize = 0;
2975  m_pDataFormat->Reserved = 0;
2976  m_pDataFormat->MajorFormat = GUID(KSDATAFORMAT_TYPE_MUSIC);
2977  m_pDataFormat->SubFormat = GUID(KSDATAFORMAT_SUBTYPE_MIDI);
2978  m_pDataFormat->Specifier = GUID(KSDATAFORMAT_SPECIFIER_NONE);
2979
2980  bool hasStdStreamingInterface = false;
2981  bool hasStdStreamingMedium = false;
2982
2983  for ( ULONG i = 0; i < m_cInterfaces; i++ ) {
2984    if (m_pInterfaces[i].Set == KSINTERFACESETID_Standard
2985        && m_pInterfaces[i].Id == KSINTERFACE_STANDARD_STREAMING)
2986      hasStdStreamingInterface = true;
2987  }
2988
2989  for (ULONG i = 0; i < m_cMediums; i++) {
2990    if (m_pMediums[i].Set == KSMEDIUMSETID_Standard
2991        && m_pMediums[i].Id == KSMEDIUM_STANDARD_DEVIO)
2992      hasStdStreamingMedium = true;
2993  }
2994
2995  if (!hasStdStreamingInterface) // No standard streaming interfaces on the pin
2996    throw std::runtime_error("CKsMidiPin::CKsMidiPin: no standard streaming interface");
2997
2998  if (!hasStdStreamingMedium) // No standard streaming mediums on the pin
2999    throw std::runtime_error("CKsMidiPin::CKsMidiPin: no standard streaming medium");
3000
3001  bool hasMidiDataRange = false;
3002
3003  BYTE const* pDataRangePtr = reinterpret_cast<BYTE const*>(m_pDataRanges);
3004
3005  for (ULONG i = 0; i < m_cDataRanges; ++i) {
3006    KSDATARANGE const* pDataRange = reinterpret_cast<KSDATARANGE const*>(pDataRangePtr);
3007
3008    if (pDataRange->SubFormat == KSDATAFORMAT_SUBTYPE_MIDI) {
3009      hasMidiDataRange = true;
3010      break;
3011    }
3012
3013    pDataRangePtr += pDataRange->FormatSize;
3014  }
3015
3016  if (!hasMidiDataRange) // No MIDI dataranges on the pin
3017    throw std::runtime_error("CKsMidiPin::CKsMidiPin: no MIDI datarange");
3018}
3019
3020
3021struct WindowsKsData
3022{
3023  WindowsKsData() : m_pPin(NULL), m_Buffer(1024), m_hInputThread(NULL)
3024  {
3025    memset(&overlapped, 0, sizeof(OVERLAPPED));
3026    m_hExitEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
3027    overlapped.hEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
3028    m_hInputThread = NULL;
3029  }
3030
3031  ~WindowsKsData()
3032  {
3033    ::CloseHandle(overlapped.hEvent);
3034    ::CloseHandle(m_hExitEvent);
3035  }
3036
3037  OVERLAPPED overlapped;
3038  CKsPin* m_pPin;
3039  std::vector<unsigned char> m_Buffer;
3040  std::auto_ptr<CKsEnumFilters<CKsMidiCapFilter> > m_pCaptureEnum;
3041  std::auto_ptr<CKsEnumFilters<CKsMidiRenFilter> > m_pRenderEnum;
3042  HANDLE m_hInputThread;
3043  HANDLE m_hExitEvent;
3044};
3045
3046// *********************************************************************//
3047// API: WINDOWS Kernel Streaming
3048// Class Definitions: MidiInWinKS
3049// *********************************************************************//
3050
3051DWORD WINAPI midiKsInputThread(VOID* pUser)
3052{
3053  MidiInApi::RtMidiInData* data = static_cast<MidiInApi::RtMidiInData*>(pUser);
3054  WindowsKsData* apiData = static_cast<WindowsKsData*>(data->apiData);
3055
3056  HANDLE hEvents[] = { apiData->overlapped.hEvent, apiData->m_hExitEvent };
3057
3058  while ( true ) {
3059    KSSTREAM_HEADER packet;
3060    memset(&packet, 0, sizeof packet);
3061    packet.Size = sizeof(KSSTREAM_HEADER);
3062    packet.PresentationTime.Time = 0;
3063    packet.PresentationTime.Numerator = 1;
3064    packet.PresentationTime.Denominator = 1;
3065    packet.Data = &apiData->m_Buffer[0];
3066    packet.DataUsed = 0;
3067    packet.FrameExtent = apiData->m_Buffer.size();
3068    apiData->m_pPin->ReadData(&packet, &apiData->overlapped);
3069
3070    DWORD dwRet = ::WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);
3071
3072    if ( dwRet == WAIT_OBJECT_0 ) {
3073      // parse packet
3074      unsigned char* pData = (unsigned char*)packet.Data;
3075      unsigned int iOffset = 0;
3076
3077      while ( iOffset < packet.DataUsed ) {
3078        KSMUSICFORMAT* pMusic = (KSMUSICFORMAT*)&pData[iOffset];
3079        iOffset += sizeof(KSMUSICFORMAT);
3080
3081        MidiInApi::MidiMessage message;
3082        message.timeStamp = 0;
3083        for(size_t i=0;i < pMusic->ByteCount;++i)
3084          message.bytes.push_back(pData[iOffset+i]);
3085
3086        if ( data->usingCallback ) {
3087          RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback)data->userCallback;
3088          callback(message.timeStamp, &message.bytes, data->userData);
3089        }
3090        else {
3091          // As long as we haven't reached our queue size limit, push the message.
3092          if ( data->queue.size < data->queue.ringSize ) {
3093            data->queue.ring[data->queue.back++] = message;
3094            if(data->queue.back == data->queue.ringSize)
3095              data->queue.back = 0;
3096            data->queue.size++;
3097          }
3098          else
3099            std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
3100        }
3101
3102        iOffset += pMusic->ByteCount;
3103
3104        // re-align on 32 bits
3105        if ( iOffset % 4 != 0 )
3106          iOffset += (4 - iOffset % 4);
3107      }
3108    }
3109    else
3110      break;
3111  }
3112  return 0;
3113}
3114
3115MidiInWinKS :: MidiInWinKS( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
3116{
3117  initialize( clientName );
3118}
3119
3120void MidiInWinKS :: initialize( const std::string& clientName )
3121{
3122  WindowsKsData* data = new WindowsKsData;
3123  apiData_ = (void*)data;
3124  inputData_.apiData = data;
3125
3126  GUID const aguidEnumCats[] =
3127  {
3128    { STATIC_KSCATEGORY_AUDIO }, { STATIC_KSCATEGORY_CAPTURE }
3129  };
3130  data->m_pCaptureEnum.reset(new CKsEnumFilters<CKsMidiCapFilter> );
3131  data->m_pCaptureEnum->EnumFilters(aguidEnumCats, 2);
3132}
3133
3134MidiInWinKS :: ~MidiInWinKS()
3135{
3136  WindowsKsData* data = static_cast<WindowsKsData*>(apiData_);
3137  try {
3138    if ( data->m_pPin )
3139      closePort();
3140  }
3141  catch(...) {
3142  }
3143
3144  delete data;
3145}
3146
3147void MidiInWinKS :: openPort( unsigned int portNumber, const std::string portName )
3148{
3149  WindowsKsData* data = static_cast<WindowsKsData*>(apiData_);
3150
3151  if ( portNumber < 0 || portNumber >= data->m_pCaptureEnum->m_Filters.size() ) {
3152    std::stringstream ost;
3153    ost << "MidiInWinKS::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
3154    errorString_ = ost.str();
3155    RtMidi::error( RtError::WARNING, errorString_ );
3156  }
3157
3158  CKsMidiCapFilter* pFilter = data->m_pCaptureEnum->m_Filters[portNumber];
3159  data->m_pPin = pFilter->CreateCapturePin();
3160
3161  if ( data->m_pPin == NULL ) {
3162    std::stringstream ost;
3163    ost << "MidiInWinKS::openPort: KS error opening port (could not create pin)";
3164    errorString_ = ost.str();
3165    RtMidi::error( RtError::WARNING, errorString_ );
3166  }
3167
3168  data->m_pPin->SetState(KSSTATE_RUN);
3169
3170  DWORD threadId;
3171  data->m_hInputThread = ::CreateThread(NULL, 0, &midiKsInputThread, &inputData_, 0, &threadId);
3172  if ( data->m_hInputThread == NULL ) {
3173    std::stringstream ost;
3174    ost << "MidiInWinKS::initialize: Could not create input thread : Windows error " << GetLastError() << std::endl;;
3175    errorString_ = ost.str();
3176    RtMidi::error( RtError::WARNING, errorString_ );
3177  }
3178
3179  connected_ = true;
3180}
3181
3182void MidiInWinKS :: openVirtualPort( const std::string portName )
3183{
3184  // This function cannot be implemented for the Windows KS MIDI API.
3185  errorString_ = "MidiInWinKS::openVirtualPort: cannot be implemented in Windows KS MIDI API!";
3186  RtMidi::error( RtError::WARNING, errorString_ );
3187}
3188
3189unsigned int MidiInWinKS :: getPortCount()
3190{
3191  WindowsKsData* data = static_cast<WindowsKsData*>(apiData_);
3192  return (unsigned int)data->m_pCaptureEnum->m_Filters.size();
3193}
3194
3195std::string MidiInWinKS :: getPortName(unsigned int portNumber)
3196{
3197  WindowsKsData* data = static_cast<WindowsKsData*>(apiData_);
3198
3199  if(portNumber < 0 || portNumber >= data->m_pCaptureEnum->m_Filters.size()) {
3200    std::stringstream ost;
3201    ost << "MidiInWinKS::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
3202    errorString_ = ost.str();
3203    RtMidi::error( RtError::WARNING, errorString_ );
3204  }
3205
3206  CKsMidiCapFilter* pFilter = data->m_pCaptureEnum->m_Filters[portNumber];
3207  return pFilter->GetFriendlyName();
3208}
3209
3210void MidiInWinKS :: closePort()
3211{
3212  WindowsKsData* data = static_cast<WindowsKsData*>(apiData_);
3213  connected_ = false;
3214
3215  if(data->m_hInputThread) {
3216    ::SignalObjectAndWait(data->m_hExitEvent, data->m_hInputThread, INFINITE, FALSE);
3217    ::CloseHandle(data->m_hInputThread);
3218  }
3219
3220  if(data->m_pPin) {
3221    data->m_pPin->SetState(KSSTATE_PAUSE);
3222    data->m_pPin->SetState(KSSTATE_STOP);
3223    data->m_pPin->ClosePin();
3224    data->m_pPin = NULL;
3225  }
3226}
3227
3228// *********************************************************************//
3229// API: WINDOWS Kernel Streaming
3230// Class Definitions: MidiOutWinKS
3231// *********************************************************************//
3232
3233MidiOutWinKS :: MidiOutWinKS( const std::string clientName ) : MidiOutApi()
3234{
3235  initialize( clientName );
3236}
3237
3238void MidiOutWinKS :: initialize( const std::string& clientName )
3239{
3240  WindowsKsData* data = new WindowsKsData;
3241
3242  data->m_pPin = NULL;
3243  data->m_pRenderEnum.reset(new CKsEnumFilters<CKsMidiRenFilter> );
3244  GUID const aguidEnumCats[] =
3245  {
3246    { STATIC_KSCATEGORY_AUDIO }, { STATIC_KSCATEGORY_RENDER }
3247  };
3248  data->m_pRenderEnum->EnumFilters(aguidEnumCats, 2);
3249
3250  apiData_ = (void*)data;
3251}
3252
3253MidiOutWinKS :: ~MidiOutWinKS()
3254{
3255  // Close a connection if it exists.
3256  closePort();
3257
3258  // Cleanup.
3259  WindowsKsData* data = static_cast<WindowsKsData*>(apiData_);
3260  delete data;
3261}
3262
3263void MidiOutWinKS :: openPort( unsigned int portNumber, const std::string portName )
3264{
3265  WindowsKsData* data = static_cast<WindowsKsData*>(apiData_);
3266
3267  if(portNumber < 0 || portNumber >= data->m_pRenderEnum->m_Filters.size()) {
3268    std::stringstream ost;
3269    ost << "MidiOutWinKS::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
3270    errorString_ = ost.str();
3271    RtMidi::error( RtError::WARNING, errorString_ );
3272  }
3273
3274  CKsMidiRenFilter* pFilter = data->m_pRenderEnum->m_Filters[portNumber];
3275  data->m_pPin = pFilter->CreateRenderPin();
3276
3277  if(data->m_pPin == NULL) {
3278    std::stringstream ost;
3279    ost << "MidiOutWinKS::openPort: KS error opening port (could not create pin)";
3280    errorString_ = ost.str();
3281    RtMidi::error( RtError::WARNING, errorString_ );
3282  }
3283
3284  data->m_pPin->SetState(KSSTATE_RUN);
3285  connected_ = true;
3286}
3287
3288void MidiOutWinKS :: openVirtualPort( const std::string portName )
3289{
3290  // This function cannot be implemented for the Windows KS MIDI API.
3291  errorString_ = "MidiOutWinKS::openVirtualPort: cannot be implemented in Windows KS MIDI API!";
3292  RtMidi::error( RtError::WARNING, errorString_ );
3293}
3294
3295unsigned int MidiOutWinKS :: getPortCount()
3296{
3297  WindowsKsData* data = static_cast<WindowsKsData*>(apiData_);
3298
3299  return (unsigned int)data->m_pRenderEnum->m_Filters.size();
3300}
3301
3302std::string MidiOutWinKS :: getPortName( unsigned int portNumber )
3303{
3304  WindowsKsData* data = static_cast<WindowsKsData*>(apiData_);
3305
3306  if ( portNumber < 0 || portNumber >= data->m_pRenderEnum->m_Filters.size() ) {
3307    std::stringstream ost;
3308    ost << "MidiOutWinKS::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
3309    errorString_ = ost.str();
3310    RtMidi::error( RtError::WARNING, errorString_ );
3311  }
3312
3313  CKsMidiRenFilter* pFilter = data->m_pRenderEnum->m_Filters[portNumber];
3314  return pFilter->GetFriendlyName();
3315}
3316
3317void MidiOutWinKS :: closePort()
3318{
3319  WindowsKsData* data = static_cast<WindowsKsData*>(apiData_);
3320  connected_ = false;
3321
3322  if ( data->m_pPin ) {
3323    data->m_pPin->SetState(KSSTATE_PAUSE);
3324    data->m_pPin->SetState(KSSTATE_STOP);
3325    data->m_pPin->ClosePin();
3326    data->m_pPin = NULL;
3327  }
3328}
3329
3330void MidiOutWinKS :: sendMessage(std::vector<unsigned char>* pMessage)
3331{
3332  std::vector<unsigned char> const& msg = *pMessage;
3333  WindowsKsData* data = static_cast<WindowsKsData*>(apiData_);
3334  size_t iNumMidiBytes = msg.size();
3335  size_t pos = 0;
3336
3337  // write header
3338  KSMUSICFORMAT* pKsMusicFormat = reinterpret_cast<KSMUSICFORMAT*>(&data->m_Buffer[pos]);
3339  pKsMusicFormat->TimeDeltaMs = 0;
3340  pKsMusicFormat->ByteCount = iNumMidiBytes;
3341  pos += sizeof(KSMUSICFORMAT);
3342
3343  // write MIDI bytes
3344  if ( pos + iNumMidiBytes > data->m_Buffer.size() ) {
3345    std::stringstream ost;
3346    ost << "KsMidiInput::Write: MIDI buffer too small. Required " << pos + iNumMidiBytes << " bytes, only has " << data->m_Buffer.size();
3347    errorString_ = ost.str();
3348    RtMidi::error( RtError::WARNING, errorString_ );
3349  }
3350
3351  if ( data->m_pPin == NULL ) {
3352    std::stringstream ost;
3353    ost << "MidiOutWinKS::sendMessage: port is not open";
3354    errorString_ = ost.str();
3355    RtMidi::error( RtError::WARNING, errorString_ );
3356  }
3357
3358  memcpy(&data->m_Buffer[pos], &msg[0], iNumMidiBytes);
3359  pos += iNumMidiBytes;
3360
3361  KSSTREAM_HEADER packet;
3362  memset(&packet, 0, sizeof packet);
3363  packet.Size = sizeof(packet);
3364  packet.PresentationTime.Time = 0;
3365  packet.PresentationTime.Numerator = 1;
3366  packet.PresentationTime.Denominator = 1;
3367  packet.Data = const_cast<unsigned char*>(&data->m_Buffer[0]);
3368  packet.DataUsed = ((pos+3)/4)*4;
3369  packet.FrameExtent = data->m_Buffer.size();
3370
3371  data->m_pPin->WriteData(&packet, NULL);
3372}
3373
3374#endif  // __WINDOWS_KS__
3375
3376//*********************************************************************//
3377//  API: UNIX JACK
3378//
3379//  Written primarily by Alexander Svetalkin, with updates for delta
3380//  time by Gary Scavone, April 2011.
3381//
3382//  *********************************************************************//
3383
3384#if defined(__UNIX_JACK__)
3385
3386// JACK header files
3387#include <jack/jack.h>
3388#include <jack/midiport.h>
3389#include <jack/ringbuffer.h>
3390
3391#define JACK_RINGBUFFER_SIZE 16384 // Default size for ringbuffer
3392
3393struct JackMidiData {
3394  jack_client_t *client;
3395  jack_port_t *port;
3396  jack_ringbuffer_t *buffSize;
3397  jack_ringbuffer_t *buffMessage;
3398  jack_time_t lastTime;
3399  MidiInApi :: RtMidiInData *rtMidiIn;
3400  };
3401
3402//*********************************************************************//
3403//  API: JACK
3404//  Class Definitions: MidiInJack
3405//*********************************************************************//
3406
3407int jackProcessIn( jack_nframes_t nframes, void *arg )
3408{
3409  JackMidiData *jData = (JackMidiData *) arg;
3410  MidiInApi :: RtMidiInData *rtData = jData->rtMidiIn;
3411  jack_midi_event_t event;
3412  jack_time_t long long time;
3413
3414  // Is port created?
3415  if ( jData->port == NULL ) return 0;
3416  void *buff = jack_port_get_buffer( jData->port, nframes );
3417
3418  // We have midi events in buffer
3419  int evCount = jack_midi_get_event_count( buff );
3420  if ( evCount > 0 ) {
3421    MidiInApi::MidiMessage message;
3422    message.bytes.clear();
3423
3424    jack_midi_event_get( &event, buff, 0 );
3425
3426    for (unsigned int i = 0; i < event.size; i++ )
3427      message.bytes.push_back( event.buffer[i] );
3428
3429    // Compute the delta time.
3430    time = jack_get_time();
3431    if ( rtData->firstMessage == true )
3432      rtData->firstMessage = false;
3433    else
3434      message.timeStamp = ( time - jData->lastTime ) * 0.000001;
3435
3436    jData->lastTime = time;
3437
3438    if ( !rtData->continueSysex ) {
3439      if ( rtData->usingCallback ) {
3440        RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) rtData->userCallback;
3441        callback( message.timeStamp, &message.bytes, rtData->userData );
3442      }
3443      else {
3444        // As long as we haven't reached our queue size limit, push the message.
3445        if ( rtData->queue.size < rtData->queue.ringSize ) {
3446          rtData->queue.ring[rtData->queue.back++] = message;
3447          if ( rtData->queue.back == rtData->queue.ringSize )
3448            rtData->queue.back = 0;
3449          rtData->queue.size++;
3450        }
3451        else
3452          std::cerr << "\nMidiInJack: message queue limit reached!!\n\n";
3453      }
3454    }
3455  }
3456
3457  return 0;
3458}
3459
3460MidiInJack :: MidiInJack( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
3461{
3462  initialize( clientName );
3463}
3464
3465void MidiInJack :: initialize( const std::string& clientName )
3466{
3467  JackMidiData *data = new JackMidiData;
3468  apiData_ = (void *) data;
3469
3470  // Initialize JACK client
3471  if (( data->client = jack_client_open( clientName.c_str(), JackNullOption, NULL )) == 0) {
3472    errorString_ = "MidiInJack::initialize: JACK server not running?";
3473    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
3474    return;
3475  }
3476
3477  data->rtMidiIn = &inputData_;
3478  data->port = NULL;
3479
3480  jack_set_process_callback( data->client, jackProcessIn, data );
3481  jack_activate( data->client );
3482}
3483
3484MidiInJack :: ~MidiInJack()
3485{
3486  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3487  closePort();
3488
3489  jack_client_close( data->client );
3490}
3491
3492void MidiInJack :: openPort( unsigned int portNumber, const std::string portName )
3493{
3494  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3495
3496  // Creating new port
3497  if ( data->port == NULL)
3498    data->port = jack_port_register( data->client, portName.c_str(),
3499                                     JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0 );
3500
3501  if ( data->port == NULL) {
3502    errorString_ = "MidiInJack::openVirtualPort: JACK error creating virtual port";
3503    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
3504  }
3505
3506  // Connecting to the output
3507  std::string name = getPortName( portNumber );
3508  jack_connect( data->client, name.c_str(), jack_port_name( data->port ) );
3509}
3510
3511void MidiInJack :: openVirtualPort( const std::string portName )
3512{
3513  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3514
3515  if ( data->port == NULL )
3516    data->port = jack_port_register( data->client, portName.c_str(),
3517                                     JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0 );
3518
3519  if ( data->port == NULL ) {
3520    errorString_ = "MidiInJack::openVirtualPort: JACK error creating virtual port";
3521    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
3522  }
3523}
3524
3525unsigned int MidiInJack :: getPortCount()
3526{
3527  int count = 0;
3528  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3529
3530  // List of available ports
3531  const char **ports = jack_get_ports( data->client, NULL, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput );
3532
3533  if ( ports == NULL ) return 0;
3534  while ( ports[count] != NULL )
3535    count++;
3536
3537  free( ports );
3538
3539  return count;
3540}
3541
3542std::string MidiInJack :: getPortName( unsigned int portNumber )
3543{
3544  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3545  std::ostringstream ost;
3546  std::string retStr("");
3547
3548  // List of available ports
3549  const char **ports = jack_get_ports( data->client, NULL,
3550                                       JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput );
3551
3552  // Check port validity
3553  if ( ports == NULL ) {
3554    errorString_ = "MidiInJack::getPortName: no ports available!";
3555    RtMidi::error( RtError::WARNING, errorString_ );
3556    return retStr;
3557  }
3558
3559  if ( ports[portNumber] == NULL ) {
3560    ost << "MidiInJack::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
3561    errorString_ = ost.str();
3562    RtMidi::error( RtError::WARNING, errorString_ );
3563  }
3564  else retStr.assign( ports[portNumber] );
3565
3566  free( ports );
3567
3568  return retStr;
3569}
3570
3571void MidiInJack :: closePort()
3572{
3573  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3574
3575  if ( data->port == NULL ) return;
3576  jack_port_unregister( data->client, data->port );
3577  data->port = NULL;
3578}
3579
3580//*********************************************************************//
3581//  API: JACK
3582//  Class Definitions: MidiOutJack
3583//*********************************************************************//
3584
3585// Jack process callback
3586int jackProcessOut( jack_nframes_t nframes, void *arg )
3587{
3588  JackMidiData *data = (JackMidiData *) arg;
3589  jack_midi_data_t *midiData;
3590  int space;
3591
3592  // Is port created?
3593  if ( data->port == NULL ) return 0;
3594
3595  void *buff = jack_port_get_buffer( data->port, nframes );
3596  jack_midi_clear_buffer( buff );
3597
3598  while ( jack_ringbuffer_read_space( data->buffSize ) > 0 ) {
3599    jack_ringbuffer_read( data->buffSize, (char *) &space, (size_t) sizeof(space) );
3600    midiData = jack_midi_event_reserve( buff, 0, space );
3601
3602    jack_ringbuffer_read( data->buffMessage, (char *) midiData, (size_t) space );
3603  }
3604
3605  return 0;
3606}
3607
3608MidiOutJack :: MidiOutJack( const std::string clientName ) : MidiOutApi()
3609{
3610  initialize( clientName );
3611}
3612
3613void MidiOutJack :: initialize( const std::string& clientName )
3614{
3615  JackMidiData *data = new JackMidiData;
3616
3617  data->port = NULL;
3618
3619  // Initialize JACK client
3620  if (( data->client = jack_client_open( clientName.c_str(), JackNullOption, NULL )) == 0) {
3621    errorString_ = "MidiOutJack::initialize: JACK server not running?";
3622    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
3623    return;
3624  }
3625
3626  jack_set_process_callback( data->client, jackProcessOut, data );
3627  data->buffSize = jack_ringbuffer_create( JACK_RINGBUFFER_SIZE );
3628  data->buffMessage = jack_ringbuffer_create( JACK_RINGBUFFER_SIZE );
3629  jack_activate( data->client );
3630
3631  apiData_ = (void *) data;
3632}
3633
3634MidiOutJack :: ~MidiOutJack()
3635{
3636  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3637  closePort();
3638
3639  // Cleanup
3640  jack_client_close( data->client );
3641  jack_ringbuffer_free( data->buffSize );
3642  jack_ringbuffer_free( data->buffMessage );
3643
3644  delete data;
3645}
3646
3647void MidiOutJack :: openPort( unsigned int portNumber, const std::string portName )
3648{
3649  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3650
3651  // Creating new port
3652  if ( data->port == NULL )
3653    data->port = jack_port_register( data->client, portName.c_str(),
3654      JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0 );
3655
3656  if ( data->port == NULL ) {
3657    errorString_ = "MidiOutJack::openVirtualPort: JACK error creating virtual port";
3658    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
3659  }
3660
3661  // Connecting to the output
3662  std::string name = getPortName( portNumber );
3663  jack_connect( data->client, jack_port_name( data->port ), name.c_str() );
3664}
3665
3666void MidiOutJack :: openVirtualPort( const std::string portName )
3667{
3668  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3669
3670  if ( data->port == NULL )
3671    data->port = jack_port_register( data->client, portName.c_str(),
3672      JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0 );
3673
3674  if ( data->port == NULL ) {
3675    errorString_ = "MidiOutJack::openVirtualPort: JACK error creating virtual port";
3676    RtMidi::error( RtError::DRIVER_ERROR, errorString_ );
3677  }
3678}
3679
3680unsigned int MidiOutJack :: getPortCount()
3681{
3682  int count = 0;
3683  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3684
3685  // List of available ports
3686  const char **ports = jack_get_ports( data->client, NULL,
3687    JACK_DEFAULT_MIDI_TYPE, JackPortIsInput );
3688
3689  if ( ports == NULL ) return 0;
3690  while ( ports[count] != NULL )
3691    count++;
3692
3693  free( ports );
3694
3695  return count;
3696}
3697
3698std::string MidiOutJack :: getPortName( unsigned int portNumber )
3699{
3700  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3701  std::ostringstream ost;
3702  std::string retStr("");
3703
3704  // List of available ports
3705  const char **ports = jack_get_ports( data->client, NULL,
3706    JACK_DEFAULT_MIDI_TYPE, JackPortIsInput );
3707
3708  // Check port validity
3709  if ( ports == NULL) {
3710    errorString_ = "MidiOutJack::getPortName: no ports available!";
3711    RtMidi::error( RtError::WARNING, errorString_ );
3712    return retStr;
3713  }
3714
3715  if ( ports[portNumber] == NULL) {
3716    ost << "MidiOutJack::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
3717    errorString_ = ost.str();
3718    RtMidi::error( RtError::WARNING, errorString_ );
3719  }
3720  else retStr.assign( ports[portNumber] );
3721
3722  free( ports );
3723
3724  return retStr;
3725}
3726
3727void MidiOutJack :: closePort()
3728{
3729  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3730
3731  if ( data->port == NULL ) return;
3732  jack_port_unregister( data->client, data->port );
3733  data->port = NULL;
3734}
3735
3736void MidiOutJack :: sendMessage( std::vector<unsigned char> *message )
3737{
3738  int nBytes = message->size();
3739  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3740
3741  // Write full message to buffer
3742  jack_ringbuffer_write( data->buffMessage, ( const char * ) &( *message )[0],
3743                         message->size() );
3744  jack_ringbuffer_write( data->buffSize, ( char * ) &nBytes, sizeof( nBytes ) );
3745}
3746
3747#endif  // __UNIX_JACK__