diff --git a/src/midi.cpp b/src/midi.cpp index 83cba6a2..92a71617 100644 --- a/src/midi.cpp +++ b/src/midi.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include @@ -288,30 +288,13 @@ std::vector Input::getChannels() { static const size_t InputQueue_maxSize = 8192; -struct InputQueue_Compare { - bool operator()(const Message& a, const Message& b) { - return a.getFrame() > b.getFrame(); - } -}; - -struct InputQueue_Queue : std::priority_queue, InputQueue_Compare> { - void reserve(size_t capacity) { - c.reserve(capacity); - } - void clear() { - // Messing with the protected container is dangerous, but completely clearing it should be fine. - c.clear(); - } -}; - struct InputQueue::Internal { - InputQueue_Queue queue; + std::deque queue; std::mutex mutex; }; InputQueue::InputQueue() { internal = new Internal; - internal->queue.reserve(InputQueue_maxSize); } InputQueue::~InputQueue() { @@ -323,19 +306,28 @@ void InputQueue::onMessage(const Message& message) { // Reject MIDI message if queue is full if (internal->queue.size() >= InputQueue_maxSize) return; + // Message timestamp must be monotonically increasing, otherwise clear the queue. + if (!internal->queue.empty() && message.getFrame() < internal->queue.back().getFrame()) { + internal->queue.clear(); + } // Push to queue - internal->queue.push(message); + internal->queue.push_back(message); } bool InputQueue::tryPop(Message* messageOut, int64_t maxFrame) { + // Check if queue is empty before locking, to avoid frequent unnecessary locking if (internal->queue.empty()) return false; std::lock_guard lock(internal->mutex); - const Message& msg = internal->queue.top(); - if (msg.getFrame() <= maxFrame) { - *messageOut = msg; - internal->queue.pop(); + + if (internal->queue.empty()) + return false; + + const Message& message = internal->queue.front(); + if (message.getFrame() <= maxFrame) { + *messageOut = message; + internal->queue.pop_front(); return true; }