From 8b0a8337d9ef38d588800de6e37cc8f2e3c6b601 Mon Sep 17 00:00:00 2001 From: Pete Brown Date: Thu, 18 Jan 2024 18:33:44 -0500 Subject: [PATCH] Fix (or at least work around) missing messages problem --- build/staging/version/BundleInfo.wxi | 2 +- src/api/Libs/MidiXProc/MidiXProc.cpp | 120 ++++++++++++++------------- 2 files changed, 62 insertions(+), 60 deletions(-) diff --git a/build/staging/version/BundleInfo.wxi b/build/staging/version/BundleInfo.wxi index 398dc077e..dfa1ff296 100644 --- a/build/staging/version/BundleInfo.wxi +++ b/build/staging/version/BundleInfo.wxi @@ -1,4 +1,4 @@ - + diff --git a/src/api/Libs/MidiXProc/MidiXProc.cpp b/src/api/Libs/MidiXProc/MidiXProc.cpp index becd5862d..d499a43e2 100644 --- a/src/api/Libs/MidiXProc/MidiXProc.cpp +++ b/src/api/Libs/MidiXProc/MidiXProc.cpp @@ -271,74 +271,76 @@ CMidiXProc::SendMidiMessage( PMEMORY_MAPPED_DATA Data = &(m_MidiOut->Data); do{ - try + // the write position is the last position we have written, + // the read position is the last position the driver has read from + ULONG writePosition = InterlockedCompareExchange((LONG*)Registers->WritePosition, 0, 0); + ULONG readPosition = InterlockedCompareExchange((LONG*)Registers->ReadPosition, 0, 0); + ULONG newWritePosition = (writePosition + requiredBufferSize) % Data->BufferSize; + ULONG bytesAvailable{ 0 }; + + // Calculate the available space in the buffer. + if (readPosition <= writePosition) { - // the write position is the last position we have written, - // the read position is the last position the driver has read from - ULONG writePosition = InterlockedCompareExchange((LONG*)Registers->WritePosition, 0, 0); - ULONG readPosition = InterlockedCompareExchange((LONG*)Registers->ReadPosition, 0, 0); - ULONG newWritePosition = (writePosition + requiredBufferSize) % Data->BufferSize; - ULONG bytesAvailable{ 0 }; - - // Calculate the available space in the buffer. - if (readPosition <= writePosition) + bytesAvailable = Data->BufferSize - (writePosition - readPosition); + } + else + { + bytesAvailable = (readPosition - writePosition); + } + + // Note, if we fill the buffer up 100%, then write position == read position, + // which is the same as when the buffer is empty and everything in the buffer + // would be lost. + // Reserve 1 byte so that when the buffer is full the write position will trail + // the read position. + // Because of this reserve, and the above calculation, the true bytesAvailable + // count can never be 0. + assert(bytesAvailable != 0); + bytesAvailable--; + + // if there is sufficient space to write the buffer, send it + if (bytesAvailable >= requiredBufferSize) + { + PLOOPEDDATAFORMAT header = (PLOOPEDDATAFORMAT)(((BYTE*)Data->BufferAddress) + writePosition); + + header->ByteCount = Length; + CopyMemory((((BYTE*)header) + sizeof(LOOPEDDATAFORMAT)), MidiData, Length); + + // if a position provided is nonzero, use it, otherwise use the current QPC + if (Position) { - bytesAvailable = Data->BufferSize - (writePosition - readPosition); + header->Position = Position; } - else + else if (m_OverwriteZeroTimestamp) { - bytesAvailable = (readPosition - writePosition); + LARGE_INTEGER qpc{ 0 }; + QueryPerformanceCounter(&qpc); + header->Position = qpc.QuadPart; } - // Note, if we fill the buffer up 100%, then write position == read position, - // which is the same as when the buffer is empty and everything in the buffer - // would be lost. - // Reserve 1 byte so that when the buffer is full the write position will trail - // the read position. - // Because of this reserve, and the above calculation, the true bytesAvailable - // count can never be 0. - assert(bytesAvailable != 0); - bytesAvailable--; - - // if there is sufficient space to write the buffer, send it - if (bytesAvailable >= requiredBufferSize) - { - PLOOPEDDATAFORMAT header = (PLOOPEDDATAFORMAT)(((BYTE*)Data->BufferAddress) + writePosition); - - header->ByteCount = Length; - CopyMemory((((BYTE*)header) + sizeof(LOOPEDDATAFORMAT)), MidiData, Length); - - // if a position provided is nonzero, use it, otherwise use the current QPC - if (Position) - { - header->Position = Position; - } - else if (m_OverwriteZeroTimestamp) - { - LARGE_INTEGER qpc{ 0 }; - QueryPerformanceCounter(&qpc); - header->Position = qpc.QuadPart; - } - - // update the write position and notify the other side that data is available. - InterlockedExchange((LONG*)Registers->WritePosition, newWritePosition); - RETURN_LAST_ERROR_IF(FALSE == SetEvent(m_MidiOut->WriteEvent.get())); + // update the write position and notify the other side that data is available. + InterlockedExchange((LONG*)Registers->WritePosition, newWritePosition); + RETURN_LAST_ERROR_IF(FALSE == SetEvent(m_MidiOut->WriteEvent.get())); - //if (!SetEvent(m_MidiOut->WriteEvent.get())) - //{ - // LOG_LAST_ERROR(); - // RETURN_LAST_ERROR_IF(true); - //} + //if (!SetEvent(m_MidiOut->WriteEvent.get())) + //{ + // LOG_LAST_ERROR(); + // RETURN_LAST_ERROR_IF(true); + //} - bufferSent = TRUE; - } - else - { - // relinquish the remainder of this processing slice and try again on the next - Sleep(0); - } + bufferSent = TRUE; + } + else + { + // relinquish the remainder of this processing slice and try again on the next + //Sleep(0); + + // if you remove this line, you will get additional send *and* receive failures + // if you set it to Sleep(0), you will end up with missing messages if we're + // spammed heavily + // If you set it to Sleep(1), there's more jitter, but all messages arrive. + Sleep(1); } - CATCH_LOG(); }while (!bufferSent && --maxRetries > 0);