فهرست منبع

Version 1.0.15

Gary Scavone 11 سال پیش
والد
کامیت
1541e77944
5فایلهای تغییر یافته به همراه116 افزوده شده و 58 حذف شده
  1. 85 39
      RtMidi.cpp
  2. 24 17
      RtMidi.h
  3. 1 1
      doc/doxygen/Doxyfile
  4. 1 1
      doc/doxygen/tutorial.txt
  5. 5 0
      doc/release.txt

+ 85 - 39
RtMidi.cpp

@@ -35,7 +35,7 @@
 */
 /**********************************************************************/
 
-// RtMidi: Version 1.0.14
+// RtMidi: Version 1.0.15
 
 #include "RtMidi.h"
 #include <sstream>
@@ -69,9 +69,14 @@ void RtMidi :: error( RtError::Type type )
 //  Common RtMidiIn Definitions
 //*********************************************************************//
 
-RtMidiIn :: RtMidiIn( const std::string clientName ) : RtMidi()
+RtMidiIn :: RtMidiIn( const std::string clientName, unsigned int queueSizeLimit ) : RtMidi()
 {
   this->initialize( clientName );
+
+  // Allocate the MIDI queue.
+  inputData_.queue.ringSize = queueSizeLimit;
+  if ( inputData_.queue.ringSize > 0 )
+    inputData_.queue.ring = new MidiMessage[ inputData_.queue.ringSize ];
 }
 
 void RtMidiIn :: setCallback( RtMidiCallback callback, void *userData )
@@ -106,11 +111,6 @@ void RtMidiIn :: cancelCallback()
   inputData_.usingCallback = false;
 }
 
-void RtMidiIn :: setQueueSizeLimit( unsigned int queueSize )
-{
-  inputData_.queueLimit = queueSize;
-}
-
 void RtMidiIn :: ignoreTypes( bool midiSysex, bool midiTime, bool midiSense )
 {
   inputData_.ignoreFlags = 0;
@@ -129,13 +129,16 @@ double RtMidiIn :: getMessage( std::vector<unsigned char> *message )
     return 0.0;
   }
 
-  if ( inputData_.queue.size() == 0 ) return 0.0;
+  if ( inputData_.queue.size == 0 ) return 0.0;
 
   // Copy queued message to the vector pointer argument and then "pop" it.
-  std::vector<unsigned char> *bytes = &(inputData_.queue.front().bytes);
+  std::vector<unsigned char> *bytes = &(inputData_.queue.ring[inputData_.queue.front].bytes);
   message->assign( bytes->begin(), bytes->end() );
-  double deltaTime = inputData_.queue.front().timeStamp;
-  inputData_.queue.pop();
+  double deltaTime = inputData_.queue.ring[inputData_.queue.front].timeStamp;
+  inputData_.queue.size--;
+  inputData_.queue.front++;
+  if ( inputData_.queue.front == inputData_.queue.ringSize )
+    inputData_.queue.front = 0;
 
   return deltaTime;
 }
@@ -248,8 +251,12 @@ void midiInputCallback( const MIDIPacketList *list, void *procRef, void *srcRef
         }
         else {
           // As long as we haven't reached our queue size limit, push the message.
-          if ( data->queueLimit > data->queue.size() )
-            data->queue.push( message );
+          if ( data->queue.size < data->queue.ringSize ) {
+            data->queue.ring[data->queue.back++] = message;
+            if ( data->queue.back == data->queue.ringSize )
+              data->queue.back = 0;
+            data->queue.size++;
+          }
           else
             std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
         }
@@ -308,8 +315,12 @@ void midiInputCallback( const MIDIPacketList *list, void *procRef, void *srcRef
             }
             else {
               // As long as we haven't reached our queue size limit, push the message.
-              if ( data->queueLimit > data->queue.size() )
-                data->queue.push( message );
+              if ( data->queue.size < data->queue.ringSize ) {
+                data->queue.ring[data->queue.back++] = message;
+                if ( data->queue.back == data->queue.ringSize )
+                  data->queue.back = 0;
+                data->queue.size++;
+              }
               else
                 std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
             }
@@ -434,6 +445,9 @@ RtMidiIn :: ~RtMidiIn()
   MIDIClientDispose( data->client );
   if ( data->endpoint ) MIDIEndpointDispose( data->endpoint );
   delete data;
+
+  // Delete the MIDI queue.
+  if ( inputData_.queue.ringSize > 0 ) delete [] inputData_.queue.ring;
 }
 
 unsigned int RtMidiIn :: getPortCount()
@@ -1021,8 +1035,12 @@ extern "C" void *alsaMidiHandler( void *ptr )
     }
     else {
       // As long as we haven't reached our queue size limit, push the message.
-      if ( data->queueLimit > data->queue.size() )
-        data->queue.push( message );
+      if ( data->queue.size < data->queue.ringSize ) {
+        data->queue.ring[data->queue.back++] = message;
+        if ( data->queue.back == data->queue.ringSize )
+          data->queue.back = 0;
+        data->queue.size++;
+      }
       else
         std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
     }
@@ -1274,6 +1292,9 @@ RtMidiIn :: ~RtMidiIn()
 #endif
   snd_seq_close( data->seq );
   delete data;
+
+  // Delete the MIDI queue.
+  if ( inputData_.queue.ringSize > 0 ) delete [] inputData_.queue.ring;
 }
 
 unsigned int RtMidiIn :: getPortCount()
@@ -1625,8 +1646,12 @@ extern "C" void *irixMidiHandler( void *ptr )
             }
             else {
               // As long as we haven't reached our queue size limit, push the message.
-              if ( data->queueLimit > data->queue.size() )
-                data->queue.push( message );
+              if ( data->queue.size < data->queue.ringSize ) {
+                data->queue.ring[data->queue.back++] = message;
+                if ( data->queue.back == data->queue.ringSize )
+                  data->queue.back = 0;
+                data->queue.size++;
+              }
               else
                 std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
             }
@@ -1668,8 +1693,12 @@ extern "C" void *irixMidiHandler( void *ptr )
       }
       else {
         // As long as we haven't reached our queue size limit, push the message.
-        if ( data->queueLimit > data->queue.size() )
-          data->queue.push( message );
+        if ( data->queue.size < data->queue.ringSize ) {
+          data->queue.ring[data->queue.back++] = message;
+          if ( data->queue.back == data->queue.ringSize )
+            data->queue.back = 0;
+          data->queue.size++;
+        }
         else
           std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
       }
@@ -1770,6 +1799,9 @@ RtMidiIn :: ~RtMidiIn()
   // Cleanup.
   IrixMidiData *data = static_cast<IrixMidiData *> (apiData_);
   delete data;
+
+  // Delete the MIDI queue.
+  if ( inputData_.queue.ringSize > 0 ) delete [] inputData_.queue.ring;
 }
 
 unsigned int RtMidiIn :: getPortCount()
@@ -2051,8 +2083,12 @@ static void CALLBACK midiInputCallback( HMIDIIN hmin,
   }
   else {
     // As long as we haven't reached our queue size limit, push the message.
-    if ( data->queueLimit > data->queue.size() )
-      data->queue.push( apiData->message );
+    if ( data->queue.size < data->queue.ringSize ) {
+      data->queue.ring[data->queue.back++] = apiData->message;
+      if ( data->queue.back == data->queue.ringSize )
+        data->queue.back = 0;
+      data->queue.size++;
+    }
     else
       std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
   }
@@ -2182,6 +2218,9 @@ RtMidiIn :: ~RtMidiIn()
   // Cleanup.
   WinMidiData *data = static_cast<WinMidiData *> (apiData_);
   delete data;
+
+  // Delete the MIDI queue.
+  if ( inputData_.queue.ringSize > 0 ) delete [] inputData_.queue.ring;
 }
 
 unsigned int RtMidiIn :: getPortCount()
@@ -2205,14 +2244,14 @@ std::string RtMidiIn :: getPortName( unsigned int portNumber )
   MIDIINCAPS deviceCaps;
   midiInGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIINCAPS));
 
-  // For some reason, we need to copy character by character with
-  // UNICODE (thanks to Eduardo Coutinho!).
-  //std::string stringName = std::string( deviceCaps.szPname );
-  char nameString[MAXPNAMELEN];
-  for( int i=0; i<MAXPNAMELEN; ++i )
-    nameString[i] = (char)( deviceCaps.szPname[i] );
+#if defined( UNICODE ) || defined( _UNICODE )
+  int length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, -1, NULL, 0, NULL, NULL);
+  stringName.assign( length, 0 );
+  length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, wcslen(deviceCaps.szPname), &stringName[0], length, NULL, NULL);
+#else
+  stringName = std::string( deviceCaps.szPname );
+#endif
 
-  stringName = nameString;
   return stringName;
 }
 
@@ -2242,14 +2281,14 @@ std::string RtMidiOut :: getPortName( unsigned int portNumber )
   MIDIOUTCAPS deviceCaps;
   midiOutGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIOUTCAPS));
 
-  // For some reason, we need to copy character by character with
-  // UNICODE (thanks to Eduardo Coutinho!).
-  //std::string stringName = std::string( deviceCaps.szPname );
-  char nameString[MAXPNAMELEN];
-  for( int i=0; i<MAXPNAMELEN; ++i )
-    nameString[i] = (char)( deviceCaps.szPname[i] );
+#if defined( UNICODE ) || defined( _UNICODE )
+  int length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, -1, NULL, 0, NULL, NULL);
+  stringName.assign( length, 0 );
+  length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, wcslen(deviceCaps.szPname), &stringName[0], length, NULL, NULL);
+#else
+  stringName = std::string( deviceCaps.szPname );
+#endif
 
-  stringName = nameString;
   return stringName;
 }
 
@@ -2478,8 +2517,12 @@ int jackProcessIn( jack_nframes_t nframes, void *arg )
     }
     else {
       // As long as we haven't reached our queue size limit, push the message.
-      if ( rtData->queueLimit > rtData->queue.size() )
-        rtData->queue.push( message );
+      if ( rtData->queue.size < rtData->queue.ringSize ) {
+        rtData->queue.ring[rtData->queue.back++] = message;
+        if ( rtData->queue.back == rtData->queue.ringSize )
+          rtData->queue.back = 0;
+        rtData->queue.size++;
+      }
       else
         std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
     }
@@ -2515,6 +2558,9 @@ RtMidiIn :: ~RtMidiIn()
 {
   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
   jack_client_close( data->client );
+
+  // Delete the MIDI queue.
+  if ( inputData_.queue.ringSize > 0 ) delete [] inputData_.queue.ring;
 }
 
 void RtMidiIn :: openPort( unsigned int portNumber, const std::string portName )

+ 24 - 17
RtMidi.h

@@ -35,7 +35,7 @@
 */
 /**********************************************************************/
 
-// RtMidi: Version 1.0.14
+// RtMidi: Version 1.0.15
 
 #ifndef RTMIDI_H
 #define RTMIDI_H
@@ -96,7 +96,6 @@ class RtMidi
 /**********************************************************************/
 
 #include <vector>
-#include <queue>
 
 class RtMidiIn : public RtMidi
 {
@@ -105,11 +104,15 @@ class RtMidiIn : public RtMidi
   //! User callback function type definition.
   typedef void (*RtMidiCallback)( double timeStamp, std::vector<unsigned char> *message, void *userData);
 
-  //! Default constructor that allows an optional client name.
+  //! Default constructor that allows an optional client name and queue size.
   /*!
-      An exception will be thrown if a MIDI system initialization error occurs.
+      An exception will be thrown if a MIDI system initialization
+      error occurs.  The queue size defines the maximum number of
+      messages that can be held in the MIDI queue (when not using a
+      callback function).  If the queue size limit is reached,
+      incoming messages will be ignored.
   */
-  RtMidiIn( const std::string clientName = std::string( "RtMidi Input Client") );
+  RtMidiIn( const std::string clientName = std::string( "RtMidi Input Client"), unsigned int queueSizeLimit = 100 );
 
   //! If a MIDI connection is still open, it will be closed by the destructor.
   ~RtMidiIn();
@@ -158,16 +161,9 @@ class RtMidiIn : public RtMidi
   */
   std::string getPortName( unsigned int portNumber = 0 );
 
-  //! Set the maximum number of MIDI messages to be saved in the queue.
-  /*!
-      If the queue size limit is reached, incoming messages will be
-      ignored.  The default limit is 1024.
-  */
-  void setQueueSizeLimit( unsigned int queueSize );
-
   //! Specify whether certain MIDI message types should be queued or ignored during input.
   /*!
-      By default, MIDI timing and active sensing messages are ignored
+o      By default, MIDI timing and active sensing messages are ignored
       during message input because of their relative high data rates.
       MIDI sysex messages are ignored by default as well.  Variable
       values of "true" imply that the respective message type will be
@@ -193,15 +189,26 @@ class RtMidiIn : public RtMidi
 
     // Default constructor.
     MidiMessage()
-      :bytes(3), timeStamp(0.0) {}
+      :bytes(0), timeStamp(0.0) {}
+  };
+
+  struct MidiQueue {
+    unsigned int front;
+    unsigned int back;
+    unsigned int size;
+    unsigned int ringSize;
+		MidiMessage *ring;
+
+    // Default constructor.
+    MidiQueue()
+      :front(0), back(0), size(0), ringSize(0) {}
   };
 
   // The RtMidiInData structure is used to pass private class data to
   // the MIDI input handling function or thread.
   struct RtMidiInData {
-    std::queue<MidiMessage> queue;
+    MidiQueue queue;
     MidiMessage message;
-    unsigned int queueLimit;
     unsigned char ignoreFlags;
     bool doInput;
     bool firstMessage;
@@ -213,7 +220,7 @@ class RtMidiIn : public RtMidi
 
     // Default constructor.
     RtMidiInData()
-      : queueLimit(1024), ignoreFlags(7), doInput(false), firstMessage(true),
+      : ignoreFlags(7), doInput(false), firstMessage(true),
         apiData(0), usingCallback(false), userCallback(0), userData(0),
         continueSysex(false) {}
   };

+ 1 - 1
doc/doxygen/Doxyfile

@@ -31,7 +31,7 @@ PROJECT_NAME           = RtMidi
 # This could be handy for archiving the generated documentation or 
 # if some version control system is used.
 
-PROJECT_NUMBER         = 1.0.14
+PROJECT_NUMBER         = 1.0.15
 
 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
 # base path where the generated documentation will be put. 

+ 1 - 1
doc/doxygen/tutorial.txt

@@ -17,7 +17,7 @@ MIDI input and output functionality are separated into two classes, RtMidiIn and
 
 \section download Download
 
-Latest Release (17 April 2011): <A href="http://www.music.mcgill.ca/~gary/rtmidi/release/rtmidi-1.0.14.tar.gz">Version 1.0.14</A>
+Latest Release (11 August 2011): <A href="http://www.music.mcgill.ca/~gary/rtmidi/release/rtmidi-1.0.15.tar.gz">Version 1.0.15</A>
 
 \section start Getting Started
 

+ 5 - 0
doc/release.txt

@@ -2,6 +2,11 @@ RtMidi - a set of C++ classes that provides a common API for realtime MIDI input
 
 By Gary P. Scavone, 2003-2011.
 
+v1.0.15: (11 August 2011)
+- updates for wide character support in Windows
+- stopped using std::queue and implemented internal MIDI ring buffer (for thread safety ... thanks to Michael Behrman)
+- removal of the setQueueSizeLimit() function ... queue size limit now an optional arguement to constructor
+
 v1.0.14: (17 April 2011)
 - bug fix to Jack MIDI support (thanks to Alexander Svetalkin and Pedro Lopez-Cabanillas)