diff --git a/RtMidi.cpp b/RtMidi.cpp index dd3f5792..221e2c85 100644 --- a/RtMidi.cpp +++ b/RtMidi.cpp @@ -654,15 +654,21 @@ double MidiInApi :: getMessage( std::vector *message ) return 0.0; } + RtMidiError::Type err = RtMidiError::NO_ERROR; + std::string err_msg; double timeStamp; - if ( !inputData_.queue.pop( message, &timeStamp ) ) + if ( !inputData_.queue.pop( message, &timeStamp, &err, &err_msg ) ) return 0.0; + if ( err != RtMidiError::NO_ERROR ) + error( err, err_msg ); + return timeStamp; } +// structure should be locked before using this method unsigned int MidiInApi::MidiQueue::size( unsigned int *__back, - unsigned int *__front ) + unsigned int *__front) { // Access back/front members exactly once and make stack copies for // size calculation @@ -676,6 +682,7 @@ unsigned int MidiInApi::MidiQueue::size( unsigned int *__back, // to member variables are needed. if ( __back ) *__back = _back; if ( __front ) *__front = _front; + return _size; } @@ -685,6 +692,8 @@ bool MidiInApi::MidiQueue::push( const MidiInApi::MidiMessage& msg ) // Local stack copies of front/back unsigned int _back, _front, _size; + lock.lock(); + // Get back/front indexes exactly once and calculate current size _size = size( &_back, &_front ); @@ -692,29 +701,41 @@ bool MidiInApi::MidiQueue::push( const MidiInApi::MidiMessage& msg ) { ring[_back] = msg; back = (back+1)%ringSize; + lock.unlock(); return true; } + lock.unlock(); + return false; } -bool MidiInApi::MidiQueue::pop( std::vector *msg, double* timeStamp ) +bool MidiInApi::MidiQueue::pop( std::vector *msg, double* timeStamp, RtMidiError::Type *err, std::string *err_msg ) { // Local stack copies of front/back unsigned int _back, _front, _size; + lock.lock(); + // Get back/front indexes exactly once and calculate current size _size = size( &_back, &_front ); - if ( _size == 0 ) + if ( _size == 0 ) { + lock.unlock(); return false; + } // Copy queued message to the vector pointer argument and then "pop" it. msg->assign( ring[_front].bytes.begin(), ring[_front].bytes.end() ); *timeStamp = ring[_front].timeStamp; + *err = ring[_front].err; + *err_msg = ring[_front].err_msg; // Update front front = (front+1)%ringSize; + + lock.unlock(); + return true; } @@ -1658,6 +1679,17 @@ static void *alsaMidiHandler( void *ptr ) << (int) ev->data.connect.dest.port << std::endl; #endif + if ( data->usingCallback ) { + std::cerr << "\nPort connection has closed!\n\n"; + data->this_->error( RtMidiError::SYSTEM_ERROR, "Port connection has closed!" ); + } + else { + MidiInApi::MidiMessage err_message; + err_message.err = RtMidiError::SYSTEM_ERROR; + err_message.err_msg = "Port connection has closed"; + if ( !data->queue.push( err_message ) ) + std::cerr << "\nMidiInCore: message queue limit reached!!\n\n"; + } break; case SND_SEQ_EVENT_QFRAME: // MIDI time code @@ -1840,6 +1872,7 @@ void MidiInAlsa :: initialize( const std::string& clientName ) data->trigger_fds[1] = -1; apiData_ = (void *) data; inputData_.apiData = (void *) data; + inputData_.this_ = this; if ( pipe(data->trigger_fds) == -1 ) { errorString_ = "MidiInAlsa::initialize: error creating pipe objects."; diff --git a/RtMidi.h b/RtMidi.h index 4a38c8aa..952e7834 100644 --- a/RtMidi.h +++ b/RtMidi.h @@ -62,6 +62,7 @@ #include #include +#include #include #include @@ -81,6 +82,7 @@ class RTMIDI_DLL_PUBLIC RtMidiError : public std::exception public: //! Defined RtMidiError types. enum Type { + NO_ERROR = 0, WARNING, /*!< A non-critical error. */ DEBUG_WARNING, /*!< A non-critical error which might be useful for debugging. */ UNSPECIFIED, /*!< The default, unspecified error type. */ @@ -555,9 +557,13 @@ class RTMIDI_DLL_PUBLIC MidiInApi : public MidiApi //! Time in seconds elapsed since the previous message double timeStamp; + // Can also contain an error (when bytes.size() == 0) + RtMidiError::Type err; + std::string err_msg; + // Default constructor. MidiMessage() - : bytes(0), timeStamp(0.0) {} + : bytes(0), timeStamp(0.0), err(RtMidiError::NO_ERROR) {} }; struct MidiQueue { @@ -565,12 +571,13 @@ class RTMIDI_DLL_PUBLIC MidiInApi : public MidiApi unsigned int back; unsigned int ringSize; MidiMessage *ring; + std::mutex lock; // Default constructor. MidiQueue() : front(0), back(0), ringSize(0), ring(0) {} bool push( const MidiMessage& ); - bool pop( std::vector*, double* ); + bool pop( std::vector*, double*, RtMidiError::Type*, std::string* ); unsigned int size( unsigned int *back=0, unsigned int *front=0 ); }; @@ -587,6 +594,7 @@ class RTMIDI_DLL_PUBLIC MidiInApi : public MidiApi RtMidiIn::RtMidiCallback userCallback; void *userData; bool continueSysex; + MidiInApi *this_; // Default constructor. RtMidiInData()