diff --git a/build/build.cake b/build/build.cake
index 382888b2..d2b8a58b 100644
--- a/build/build.cake
+++ b/build/build.cake
@@ -1,10 +1,9 @@
#tool nuget:?package=NuGet.CommandLine&version=5.10
-#addin nuget:?package=Cake.Compression&version=0.3.0
-
-
+//#addin nuget:?package=Cake.Compression&version=0.3.0
+// ===========================================================================================
string setupVersionName = "Developer Preview 4";
-
+// ===========================================================================================
@@ -163,7 +162,8 @@ Task("SetupEnvironment")
// Copy key output files from VSFiles to staging to allow building installer
var outputDir = System.IO.Path.Combine(apiAndServiceSolutionDir, "VSFiles", plat.ToString(), configuration);
- var apiHeaderDir = System.IO.Path.Combine(apiAndServiceSolutionDir, "VSFiles\\intermediate\\Windows.Devices.Midi2", plat.ToString(), configuration, "GeneratedFiles\\winrt");
+ var generatedFilesDir = System.IO.Path.Combine(apiAndServiceSolutionDir, "VSFiles", "intermediate", "Windows.Devices.Midi2", plat.ToString(), configuration, "GeneratedFiles", "winrt");
+ //var apiHeaderDir = System.IO.Path.Combine(apiAndServiceSolutionDir, "VSFiles\\intermediate\\Windows.Devices.Midi2", plat.ToString(), configuration, "GeneratedFiles\\winrt");
Information("\nCopying service and API for " + plat.ToString());
@@ -186,16 +186,36 @@ Task("SetupEnvironment")
CopyFiles(System.IO.Path.Combine(outputDir, "WinRTActivationEntries.txt"), copyToDir);
// copy the C++ header for the API
- CopyFiles(System.IO.Path.Combine(apiHeaderDir, "Windows.Devices.Midi2.h"), copyToDir);
+ CopyFiles(System.IO.Path.Combine(generatedFilesDir, "Windows.Devices.Midi2.h"), copyToDir);
// copy the API Header and the .winmd to the "API bare" folder
- var apiBareCopyToDir = System.IO.Path.Combine(releaseRootDir, "API");
+ var apiBareCopyToDir = System.IO.Path.Combine(releaseRootDir, "api");
if (!DirectoryExists(apiBareCopyToDir))
CreateDirectory(apiBareCopyToDir);
+ if (!DirectoryExists(System.IO.Path.Combine(apiBareCopyToDir, "winrt")))
+ CreateDirectory(System.IO.Path.Combine(apiBareCopyToDir, "winrt"));
+
+ if (!DirectoryExists(System.IO.Path.Combine(apiBareCopyToDir, "winrt", "impl")))
+ CreateDirectory(System.IO.Path.Combine(apiBareCopyToDir, "winrt", "impl"));
+
+
CopyFiles(System.IO.Path.Combine(copyToDir, "Windows.Devices.Midi2.h"), apiBareCopyToDir);
+
+ CopyFiles(System.IO.Path.Combine(generatedFilesDir, "base.h"), System.IO.Path.Combine(apiBareCopyToDir, "winrt/"));
+ CopyFiles(System.IO.Path.Combine(generatedFilesDir, "Windows.Devices.h"), System.IO.Path.Combine(apiBareCopyToDir, "winrt/"));
+ CopyFiles(System.IO.Path.Combine(generatedFilesDir, "impl/Windows.Devices.Enumeration.2.h"), System.IO.Path.Combine(apiBareCopyToDir, "winrt/impl/"));
+ CopyFiles(System.IO.Path.Combine(generatedFilesDir, "impl/Windows.Devices.Midi.2.h"), System.IO.Path.Combine(apiBareCopyToDir, "winrt/impl/"));
+ CopyFiles(System.IO.Path.Combine(generatedFilesDir, "impl/Windows.Foundation.2.h"), System.IO.Path.Combine(apiBareCopyToDir, "winrt/impl/"));
+ CopyFiles(System.IO.Path.Combine(generatedFilesDir, "impl/Windows.Foundation.Collections.2.h"), System.IO.Path.Combine(apiBareCopyToDir, "winrt/impl/"));
+ CopyFiles(System.IO.Path.Combine(generatedFilesDir, "impl/Windows.Devices.Midi2.2.h"), System.IO.Path.Combine(apiBareCopyToDir, "winrt/impl/"));
+
+
+
+
+
CopyFiles(System.IO.Path.Combine(copyToDir, "Windows.Devices.Midi2.dll"), apiBareCopyToDir);
CopyFiles(System.IO.Path.Combine(copyToDir, "Windows.Devices.Midi2.winmd"), apiBareCopyToDir);
CopyFiles(System.IO.Path.Combine(copyToDir, "Windows.Devices.Midi2.pri"), apiBareCopyToDir);
@@ -455,7 +475,7 @@ Task("PackSDKProjection")
Task("BuildConsoleApp")
.IsDependentOn("PackAPIProjection")
- .IsDependentOn("PackSDKProjection")
+/* .IsDependentOn("PackSDKProjection") */
.DoesForEach(platformTargets, plat =>
{
// TODO: Update nuget ref in console app to the new version
@@ -565,14 +585,14 @@ Task("BuildSettingsApp")
});
-
+ string finalSetupName = string.Empty;
Task("BuildInstaller")
.IsDependentOn("SetupEnvironment")
.IsDependentOn("BuildServiceAndAPI")
.IsDependentOn("BuildApiActivationRegEntriesCSharp")
- .IsDependentOn("BuildSDK")
- .IsDependentOn("BuildSettingsApp")
+/* .IsDependentOn("BuildSDK") */
+/* .IsDependentOn("BuildSettingsApp") */
.IsDependentOn("BuildConsoleApp")
.DoesForEach(platformTargets, plat =>
{
@@ -640,7 +660,7 @@ Task("BuildInstaller")
writer.WriteLine("");
}
- string finalSetupName = $"Windows MIDI Services {setupVersionName} {setupBuildPlatform} {setupBuildFullVersionString}.exe";
+ finalSetupName = $"Windows MIDI Services {setupVersionName} {setupBuildPlatform} {setupBuildFullVersionString}.exe";
var buildSettings = new DotNetBuildSettings
{
@@ -674,6 +694,9 @@ Task("BuildInstaller")
CopyFiles(System.IO.Path.Combine(consoleOnlySetupProjectDir, "bin", plat.ToString(), "Release", "*.msi"), releaseStandAloneInstallerFolder);
CopyFiles(System.IO.Path.Combine(settingsOnlySetupProjectDir, "bin", plat.ToString(), "Release", "*.msi"), releaseStandAloneInstallerFolder);
+
+
+
});
@@ -689,6 +712,14 @@ Task("CopyAPIArtifacts")
CopyFiles(System.IO.Path.Combine(apiStagingDir, "Windows.Devices.Midi2.dll"), apiReleaseArtifactsFolder);
CopyFiles(System.IO.Path.Combine(apiStagingDir, "Windows.Devices.Midi2.pri"), apiReleaseArtifactsFolder);
CopyFiles(System.IO.Path.Combine(apiStagingDir, "Windows.Devices.Midi2.h"), apiReleaseArtifactsFolder);
+ CopyFiles(System.IO.Path.Combine(apiStagingDir, "winrt/base.h"), System.IO.Path.Combine(apiReleaseArtifactsFolder, "winrt/"));
+ CopyFiles(System.IO.Path.Combine(apiStagingDir, "winrt/Windows.Devices.h"), System.IO.Path.Combine(apiReleaseArtifactsFolder, "winrt/"));
+ CopyFiles(System.IO.Path.Combine(apiStagingDir, "winrt/impl/Windows.Devices.Enumeration.2.h"), System.IO.Path.Combine(apiReleaseArtifactsFolder, "winrt/impl/"));
+ CopyFiles(System.IO.Path.Combine(apiStagingDir, "winrt/impl/Windows.Devices.Midi.2.h"), System.IO.Path.Combine(apiReleaseArtifactsFolder, "winrt/impl/"));
+ CopyFiles(System.IO.Path.Combine(apiStagingDir, "winrt/impl/Windows.Foundation.2.h"), System.IO.Path.Combine(apiReleaseArtifactsFolder, "winrt/impl/"));
+ CopyFiles(System.IO.Path.Combine(apiStagingDir, "winrt/impl/Windows.Foundation.Collections.2.h"), System.IO.Path.Combine(apiReleaseArtifactsFolder, "winrt/impl/"));
+ CopyFiles(System.IO.Path.Combine(apiStagingDir, "winrt/impl/Windows.Devices.Midi2.2.h"), System.IO.Path.Combine(apiReleaseArtifactsFolder, "winrt/impl/"));
+
});
@@ -701,7 +732,12 @@ Task("Default")
.IsDependentOn("BuildApiActivationRegEntriesInternal")
.IsDependentOn("BuildInstaller")
.IsDependentOn("CopyAPIArtifacts")
- ;
+ .Does(() =>
+{
+
+ Information("\n\nInstaller >> \"" + finalSetupName + "\"\n\n");
+
+});
diff --git a/build/staging/version/BundleInfo.wxi b/build/staging/version/BundleInfo.wxi
index c4e17050..dfa1ff29 100644
--- a/build/staging/version/BundleInfo.wxi
+++ b/build/staging/version/BundleInfo.wxi
@@ -1,4 +1,4 @@
-
+
diff --git a/diagnostics/trace-logging/TraceCaptureFile.etl b/diagnostics/trace-logging/TraceCaptureFile.etl
new file mode 100644
index 00000000..977cde1e
Binary files /dev/null and b/diagnostics/trace-logging/TraceCaptureFile.etl differ
diff --git a/get-started/midi-developers/app-developers/docs/README.md b/get-started/midi-developers/app-developers/docs/README.md
index 3e9b2a43..3ac0ea17 100644
--- a/get-started/midi-developers/app-developers/docs/README.md
+++ b/get-started/midi-developers/app-developers/docs/README.md
@@ -5,6 +5,7 @@ API and other documentation which will eventually be used in the Microsoft Learn
| Page | Description |
| ------------- | --------------------- |
| [midi-api-types.md](midi-api-types.md) | Overview of all the major types in the API |
+| [timestamps.md](timestamps.md) | Details about Timestamps in Windows MIDI Services |
| [consuming-midi-api.md](consuming-midi-api.md) | How to build against the API |
| [diagnostic-endpoints.md](diagnostic-endpoints.md) | Behavior and use of the diagnostic loopback and ping endpoints |
| [best-practices.md](best-practices-endpoints.md) | Best practices and tips when using the API |
diff --git a/get-started/midi-developers/app-developers/docs/timestamps.md b/get-started/midi-developers/app-developers/docs/timestamps.md
new file mode 100644
index 00000000..7ce08e4c
--- /dev/null
+++ b/get-started/midi-developers/app-developers/docs/timestamps.md
@@ -0,0 +1,16 @@
+# MIDI Clock and Timestamps
+
+## The MidiClock Type
+
+The Windows::Devices::Midi2::MidiClock type provides access to the system-wide MIDI Timestamp system. Timestamps are high-resultion tick counts which can be converted to offsets in seconds or fractions of seconds, but do not represent a real-world time of day without additional tracking with an external reference clock (`GetSystemTimePreciseAsFileTime`, for example).
+
+
+## High-resolution timestamps
+
+Windows MIDI Services currently uses the high-resolution 64 bit QueryPerformanceCounter type.
+
+On most systems, the resolution is 100ns per tick, and so takes around 30,000 years to roll over. You do not need to worry about it wrapping around to zero, instead you can rely on the ticks to increase.
+
+You can learn more about high-resolution timestamps in Windows at [https://aka.ms/miditimestamp](https://aka.ms/miditimestamp).
+
+It's unlikely that we will change from QueryPerformanceCounter to another mechanism in the future. But the contract with applications is the MidiClock type. If you want to ensure your applications continue to work across revisions, always use `MidiClock::Now()` to acquire a timestamp, and use the other `MidiClock` methods for calculating ticks per second
diff --git a/src/api/Abstraction/DiagnosticsAbstraction/Midi2.LoopbackMidiBidi.cpp b/src/api/Abstraction/DiagnosticsAbstraction/Midi2.LoopbackMidiBidi.cpp
index f293f1b9..86f6e520 100644
--- a/src/api/Abstraction/DiagnosticsAbstraction/Midi2.LoopbackMidiBidi.cpp
+++ b/src/api/Abstraction/DiagnosticsAbstraction/Midi2.LoopbackMidiBidi.cpp
@@ -142,21 +142,53 @@ CMidi2LoopbackMidiBiDi::SendMidiMessage(
LONGLONG Timestamp
)
{
+ TraceLoggingWrite(
+ MidiDiagnosticsAbstractionTelemetryProvider::Provider(),
+ __FUNCTION__,
+ TraceLoggingLevel(WINEVENT_LEVEL_INFO),
+ TraceLoggingPointer(this, "this")
+ );
+
+
RETURN_HR_IF_NULL(E_INVALIDARG, Message);
RETURN_HR_IF(E_INVALIDARG, Size < sizeof(uint32_t));
if (m_IsPing)
{
+ TraceLoggingWrite(
+ MidiDiagnosticsAbstractionTelemetryProvider::Provider(),
+ __FUNCTION__,
+ TraceLoggingLevel(WINEVENT_LEVEL_INFO),
+ TraceLoggingPointer(this, "this"),
+ TraceLoggingWideString(L"Sending Ping")
+ );
+
RETURN_HR_IF_NULL(E_POINTER, m_PingMidiDevice);
return m_PingMidiDevice->SendMidiMessage(Message, Size, Timestamp);
}
else if (m_IsEndpointA)
{
+ TraceLoggingWrite(
+ MidiDiagnosticsAbstractionTelemetryProvider::Provider(),
+ __FUNCTION__,
+ TraceLoggingLevel(WINEVENT_LEVEL_INFO),
+ TraceLoggingPointer(this, "this"),
+ TraceLoggingWideString(L"Sending From Loopback A to B")
+ );
+
RETURN_HR_IF_NULL(E_POINTER, m_LoopbackMidiDevice);
return m_LoopbackMidiDevice->SendMidiMessageFromAToB(Message, Size, Timestamp);
}
else
{
+ TraceLoggingWrite(
+ MidiDiagnosticsAbstractionTelemetryProvider::Provider(),
+ __FUNCTION__,
+ TraceLoggingLevel(WINEVENT_LEVEL_INFO),
+ TraceLoggingPointer(this, "this"),
+ TraceLoggingWideString(L"Sending From Loopback B to A")
+ );
+
RETURN_HR_IF_NULL(E_POINTER, m_LoopbackMidiDevice);
return m_LoopbackMidiDevice->SendMidiMessageFromBToA(Message, Size, Timestamp);
}
@@ -171,6 +203,13 @@ CMidi2LoopbackMidiBiDi::Callback(
LONGLONG
)
{
+ TraceLoggingWrite(
+ MidiDiagnosticsAbstractionTelemetryProvider::Provider(),
+ __FUNCTION__,
+ TraceLoggingLevel(WINEVENT_LEVEL_INFO),
+ TraceLoggingPointer(this, "this")
+ );
+
RETURN_HR_IF_NULL(E_INVALIDARG, Message);
RETURN_HR_IF_NULL(E_POINTER, m_Callback);
RETURN_HR_IF(E_INVALIDARG, Size < sizeof(uint32_t));
diff --git a/src/api/Abstraction/DiagnosticsAbstraction/dllmain.cpp b/src/api/Abstraction/DiagnosticsAbstraction/dllmain.cpp
index 13bf8470..22e24c84 100644
--- a/src/api/Abstraction/DiagnosticsAbstraction/dllmain.cpp
+++ b/src/api/Abstraction/DiagnosticsAbstraction/dllmain.cpp
@@ -13,6 +13,7 @@ DllMain(
{
if (Reason == DLL_PROCESS_ATTACH)
{
+ OutputDebugString(__FUNCTION__ L" Setting Diagnostics Abstraction error logging.\n");
wil::SetResultTelemetryFallback(MidiDiagnosticsAbstractionTelemetryProvider::FallbackTelemetryCallback);
}
diff --git a/src/api/Abstraction/MidiSrvAbstraction/Midi2.MidiSrv.cpp b/src/api/Abstraction/MidiSrvAbstraction/Midi2.MidiSrv.cpp
index db89664f..9e1a8ea3 100644
--- a/src/api/Abstraction/MidiSrvAbstraction/Midi2.MidiSrv.cpp
+++ b/src/api/Abstraction/MidiSrvAbstraction/Midi2.MidiSrv.cpp
@@ -54,7 +54,7 @@ CMidi2MidiSrv::Initialize(
//creationParams.BufferSize = PAGE_SIZE; // original
//creationParams.BufferSize = 512; // Set this for debugging see https://github.com/microsoft/MIDI/issues/182 for all the drama :)
- creationParams.BufferSize = PAGE_SIZE * 4;
+ creationParams.BufferSize = PAGE_SIZE * 2;
RETURN_IF_FAILED(GetMidiSrvBindingHandle(&bindingHandle));
diff --git a/src/api/Client/Midi2Client/MidiClock.idl b/src/api/Client/Midi2Client/MidiClock.idl
index 136d1493..0748357b 100644
--- a/src/api/Client/Midi2Client/MidiClock.idl
+++ b/src/api/Client/Midi2Client/MidiClock.idl
@@ -22,9 +22,11 @@ namespace Windows.Devices.Midi2
// returns the units per second for the timestamp
static UInt64 TimestampFrequency{ get; };
- // convenience function
+ // convenience functions
+ //static Double ConvertTimestampToNanoseconds(MIDI_TIMESTAMP timestampValue); // TODO post-NAMM 2024
static Double ConvertTimestampToMicroseconds(MIDI_TIMESTAMP timestampValue);
static Double ConvertTimestampToMilliseconds(MIDI_TIMESTAMP timestampValue);
+ //static Double ConvertTimestampToSeconds(MIDI_TIMESTAMP timestampValue); // TODO post-NAMM 2024
// these can offset to the future or the past, which is why the offset is signed
static MIDI_TIMESTAMP OffsetTimestampByTicks(MIDI_TIMESTAMP timestampValue, Int64 offsetTicks);
@@ -37,6 +39,10 @@ namespace Windows.Devices.Midi2
// synchronizing timestamps to wall clock time, as much as that is possible
+
+
+
+
}
}
diff --git a/src/api/Client/Midi2Client/MidiEndpointConnection.cpp b/src/api/Client/Midi2Client/MidiEndpointConnection.cpp
index 7ab229b5..13b5613e 100644
--- a/src/api/Client/Midi2Client/MidiEndpointConnection.cpp
+++ b/src/api/Client/Midi2Client/MidiEndpointConnection.cpp
@@ -166,7 +166,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
}
catch (winrt::hresult_error const& ex)
{
- internal::LogHresultError(__FUNCTION__, L" hresult exception initializing endpoint.", ex);
+ internal::LogHresultError(__FUNCTION__, L"hresult exception initializing endpoint.", ex);
return false;
}
@@ -214,7 +214,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
}
catch (winrt::hresult_error const& ex)
{
- internal::LogHresultError(__FUNCTION__, L" hresult exception initializing endpoint interface. Service may be unavailable.", ex);
+ internal::LogHresultError(__FUNCTION__, L"hresult exception initializing endpoint interface. Service may be unavailable.", ex);
m_endpointAbstraction = nullptr;
@@ -223,7 +223,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
}
else
{
- internal::LogGeneralError(__FUNCTION__, L" Endpoint interface is nullptr");
+ internal::LogGeneralError(__FUNCTION__, L"Endpoint interface is nullptr");
return false;
}
@@ -239,7 +239,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
void MidiEndpointConnection::Close()
{
- internal::LogInfo(__FUNCTION__, L"Connection Close ");
+ internal::LogInfo(__FUNCTION__, L"Connection Close");
if (m_closeHasBeenCalled) return;
@@ -281,7 +281,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
void MidiEndpointConnection::InitializePlugins() noexcept
{
- internal::LogInfo(__FUNCTION__, L"Initializing message processing plugins ");
+ internal::LogInfo(__FUNCTION__, L"Initializing message processing plugins");
for (const auto& plugin : m_messageProcessingPlugins)
{
@@ -389,7 +389,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
midi2::MidiSendMessageResult MidiEndpointConnection::SendMessageStruct(
internal::MidiTimestamp timestamp,
midi2::MidiMessageStruct const& message,
- uint8_t wordCount)
+ uint8_t wordCount) noexcept
{
internal::LogInfo(__FUNCTION__, L"Sending message struct");
@@ -485,7 +485,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
const internal::MidiTimestamp timestamp,
winrt::Windows::Foundation::IMemoryBuffer const& buffer,
const uint32_t byteOffset,
- const uint8_t byteLength)
+ const uint8_t byteLength) noexcept
{
internal::LogInfo(__FUNCTION__, L"Sending message buffer");
@@ -547,7 +547,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
winrt::array_view words,
uint32_t const startIndex,
uint8_t const wordCount
- )
+ ) noexcept
{
internal::LogInfo(__FUNCTION__, L"Sending message word array");
@@ -604,7 +604,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
_Use_decl_annotations_
midi2::MidiSendMessageResult MidiEndpointConnection::SendMessageWords(
internal::MidiTimestamp const timestamp,
- uint32_t const word0)
+ uint32_t const word0) noexcept
{
internal::LogInfo(__FUNCTION__, L"Sending message words (1)");
@@ -656,7 +656,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
midi2::MidiSendMessageResult MidiEndpointConnection::SendMessageWords(
internal::MidiTimestamp const timestamp,
uint32_t const word0,
- uint32_t const word1)
+ uint32_t const word1) noexcept
{
internal::LogInfo(__FUNCTION__, L"Sending message words (2)");
@@ -712,7 +712,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
internal::MidiTimestamp const timestamp,
uint32_t const word0,
uint32_t const word1,
- uint32_t const word2)
+ uint32_t const word2) noexcept
{
internal::LogInfo(__FUNCTION__, L"Sending message words (3)");
@@ -771,7 +771,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
uint32_t const word0,
uint32_t const word1,
uint32_t const word2,
- uint32_t const word3)
+ uint32_t const word3) noexcept
{
internal::LogInfo(__FUNCTION__, L"Sending message words (4)");
@@ -826,7 +826,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
_Use_decl_annotations_
midi2::MidiSendMessageResult MidiEndpointConnection::SendMessagePacket(
- midi2::IMidiUniversalPacket const& message)
+ midi2::IMidiUniversalPacket const& message) noexcept
{
internal::LogInfo(__FUNCTION__, L"Sending message packet");
diff --git a/src/api/Client/Midi2Client/MidiEndpointConnection.h b/src/api/Client/Midi2Client/MidiEndpointConnection.h
index 12544cb7..294219d3 100644
--- a/src/api/Client/Midi2Client/MidiEndpointConnection.h
+++ b/src/api/Client/Midi2Client/MidiEndpointConnection.h
@@ -56,59 +56,56 @@ namespace winrt::Windows::Devices::Midi2::implementation
_Success_(return == true)
- midi2::MidiSendMessageResult SendMessagePacket(
- _In_ midi2::IMidiUniversalPacket const& ump);
+ midi2::MidiSendMessageResult SendMessagePacket(
+ _In_ midi2::IMidiUniversalPacket const& ump) noexcept;
_Success_(return == true)
- midi2::MidiSendMessageResult SendMessageStruct(
- _In_ internal::MidiTimestamp timestamp,
- _In_ midi2::MidiMessageStruct const& message,
- _In_ uint8_t wordCount);
+ midi2::MidiSendMessageResult SendMessageStruct(
+ _In_ internal::MidiTimestamp timestamp,
+ _In_ midi2::MidiMessageStruct const& message,
+ _In_ uint8_t wordCount) noexcept;
_Success_(return == true)
- midi2::MidiSendMessageResult SendMessageWords(
- _In_ internal::MidiTimestamp const timestamp,
- _In_ uint32_t const word0);
+ midi2::MidiSendMessageResult SendMessageWords(
+ _In_ internal::MidiTimestamp const timestamp,
+ _In_ uint32_t const word0) noexcept;
_Success_(return == true)
- midi2::MidiSendMessageResult SendMessageWords(
- _In_ internal::MidiTimestamp const timestamp,
- _In_ uint32_t const word0,
- _In_ uint32_t const word1);
+ midi2::MidiSendMessageResult SendMessageWords(
+ _In_ internal::MidiTimestamp const timestamp,
+ _In_ uint32_t const word0,
+ _In_ uint32_t const word1) noexcept;
_Success_(return == true)
- midi2::MidiSendMessageResult SendMessageWords(
- _In_ internal::MidiTimestamp const timestamp,
- _In_ uint32_t const word0,
- _In_ uint32_t const word1,
- _In_ uint32_t const word2);
+ midi2::MidiSendMessageResult SendMessageWords(
+ _In_ internal::MidiTimestamp const timestamp,
+ _In_ uint32_t const word0,
+ _In_ uint32_t const word1,
+ _In_ uint32_t const word2) noexcept;
_Success_(return == true)
- midi2::MidiSendMessageResult SendMessageWords(
- _In_ internal::MidiTimestamp const timestamp,
- _In_ uint32_t const word0,
- _In_ uint32_t const word1,
- _In_ uint32_t const word2,
- _In_ uint32_t const word3);
-
+ midi2::MidiSendMessageResult SendMessageWords(
+ _In_ internal::MidiTimestamp const timestamp,
+ _In_ uint32_t const word0,
+ _In_ uint32_t const word1,
+ _In_ uint32_t const word2,
+ _In_ uint32_t const word3) noexcept;
_Success_(return == true)
- midi2::MidiSendMessageResult SendMessageWordArray(
- _In_ internal::MidiTimestamp const timestamp,
- _In_ winrt::array_view words,
- _In_ uint32_t const startIndex,
- _In_ uint8_t const wordCount);
-
-
+ midi2::MidiSendMessageResult SendMessageWordArray(
+ _In_ internal::MidiTimestamp const timestamp,
+ _In_ winrt::array_view words,
+ _In_ uint32_t const startIndex,
+ _In_ uint8_t const wordCount) noexcept;
_Success_(return == true)
- midi2::MidiSendMessageResult SendMessageBuffer(
- _In_ internal::MidiTimestamp timestamp,
- _In_ foundation::IMemoryBuffer const& buffer,
- _In_ uint32_t byteOffset,
- _In_ uint8_t byteLength);
+ midi2::MidiSendMessageResult SendMessageBuffer(
+ _In_ internal::MidiTimestamp timestamp,
+ _In_ foundation::IMemoryBuffer const& buffer,
+ _In_ uint32_t byteOffset,
+ _In_ uint8_t byteLength) noexcept;
diff --git a/src/api/Libs/MidiXProc/MidiXProc.cpp b/src/api/Libs/MidiXProc/MidiXProc.cpp
index 5dd279c9..d499a43e 100644
--- a/src/api/Libs/MidiXProc/MidiXProc.cpp
+++ b/src/api/Libs/MidiXProc/MidiXProc.cpp
@@ -273,10 +273,10 @@ CMidiXProc::SendMidiMessage(
do{
// 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 writePosition = InterlockedCompareExchange((LONG*)Registers->WritePosition, 0, 0);
+ ULONG readPosition = InterlockedCompareExchange((LONG*)Registers->ReadPosition, 0, 0);
ULONG newWritePosition = (writePosition + requiredBufferSize) % Data->BufferSize;
- ULONG bytesAvailable {0};
+ ULONG bytesAvailable{ 0 };
// Calculate the available space in the buffer.
if (readPosition <= writePosition)
@@ -301,10 +301,10 @@ CMidiXProc::SendMidiMessage(
// if there is sufficient space to write the buffer, send it
if (bytesAvailable >= requiredBufferSize)
{
- PLOOPEDDATAFORMAT header = (PLOOPEDDATAFORMAT) (((BYTE *) Data->BufferAddress) + writePosition);
+ PLOOPEDDATAFORMAT header = (PLOOPEDDATAFORMAT)(((BYTE*)Data->BufferAddress) + writePosition);
header->ByteCount = Length;
- CopyMemory((((BYTE *) header) + sizeof(LOOPEDDATAFORMAT)), MidiData, Length);
+ CopyMemory((((BYTE*)header) + sizeof(LOOPEDDATAFORMAT)), MidiData, Length);
// if a position provided is nonzero, use it, otherwise use the current QPC
if (Position)
@@ -313,27 +313,42 @@ CMidiXProc::SendMidiMessage(
}
else if (m_OverwriteZeroTimestamp)
{
- LARGE_INTEGER qpc {0};
+ 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);
+ 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);
+ //}
+
bufferSent = TRUE;
}
else
{
// relinquish the remainder of this processing slice and try again on the next
- Sleep(0);
+ //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);
}
+
}while (!bufferSent && --maxRetries > 0);
// Failed to send the buffer due to insufficient space,
// fail.
if (!bufferSent)
{
+ LOG_IF_FAILED(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
diff --git a/src/api/Test/Midi2.Abstraction.unittests/Midi2.Abstraction.unittests.vcxproj b/src/api/Test/Midi2.Abstraction.unittests/Midi2.Abstraction.unittests.vcxproj
index eeecde69..68b7e4d5 100644
--- a/src/api/Test/Midi2.Abstraction.unittests/Midi2.Abstraction.unittests.vcxproj
+++ b/src/api/Test/Midi2.Abstraction.unittests/Midi2.Abstraction.unittests.vcxproj
@@ -69,23 +69,23 @@
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.abstraction.unittests\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\midiswenum\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midixproc\$(Platform)\$(Configuration)
$(VC_LibraryPath_ARM64);$(WindowsSDK_LibraryPath_ARM64);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\midiswenum\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midixproc\$(Platform)\$(Configuration)
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.abstraction.unittests\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.abstraction.unittests\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\midiswenum\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midixproc\$(Platform)\$(Configuration)
$(VC_LibraryPath_ARM64);$(WindowsSDK_LibraryPath_ARM64);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\midiswenum\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midixproc\$(Platform)\$(Configuration)
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.abstraction.unittests\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
diff --git a/src/api/Test/Midi2.Client.benchmarks/Midi2.Client.benchmarks.vcxproj b/src/api/Test/Midi2.Client.benchmarks/Midi2.Client.benchmarks.vcxproj
index 84c85ca0..4c224806 100644
--- a/src/api/Test/Midi2.Client.benchmarks/Midi2.Client.benchmarks.vcxproj
+++ b/src/api/Test/Midi2.Client.benchmarks/Midi2.Client.benchmarks.vcxproj
@@ -76,28 +76,28 @@
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.client.benchmarks\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
$(SolutionDir)VSFiles\intermediate\$(MSBuildProjectName)\$(Platform)\$(Configuration)\GeneratedFiles\
$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)VSFiles\intermediate\idl\$(Platform)\$(Configuration)
$(VC_LibraryPath_ARM64);$(WindowsSDK_LibraryPath_ARM64);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.client.benchmarks\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
$(SolutionDir)VSFiles\intermediate\$(MSBuildProjectName)\$(Platform)\$(Configuration)\GeneratedFiles\
$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)VSFiles\intermediate\idl\$(Platform)\$(Configuration)
$(VC_LibraryPath_ARM64);$(WindowsSDK_LibraryPath_ARM64);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.client.benchmarks\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
$(SolutionDir)VSFiles\intermediate\$(MSBuildProjectName)\$(Platform)\$(Configuration)\GeneratedFiles\
$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)VSFiles\intermediate\idl\$(Platform)\$(Configuration)
$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.client.benchmarks\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
$(SolutionDir)VSFiles\intermediate\$(MSBuildProjectName)\$(Platform)\$(Configuration)\GeneratedFiles\
$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)VSFiles\intermediate\idl\$(Platform)\$(Configuration)
$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);
diff --git a/src/api/Test/Midi2.Client.unittests/Midi2.Client.unittests.vcxproj b/src/api/Test/Midi2.Client.unittests/Midi2.Client.unittests.vcxproj
index fa2a40f9..6d30d173 100644
--- a/src/api/Test/Midi2.Client.unittests/Midi2.Client.unittests.vcxproj
+++ b/src/api/Test/Midi2.Client.unittests/Midi2.Client.unittests.vcxproj
@@ -76,28 +76,28 @@
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.client.unittests\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
$(SolutionDir)VSFiles\intermediate\$(MSBuildProjectName)\$(Platform)\$(Configuration)\GeneratedFiles\
$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)VSFiles\intermediate\idl\$(Platform)\$(Configuration)
$(VC_LibraryPath_ARM64);$(WindowsSDK_LibraryPath_ARM64);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.client.unittests\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
$(SolutionDir)VSFiles\intermediate\$(MSBuildProjectName)\$(Platform)\$(Configuration)\GeneratedFiles\
$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)VSFiles\intermediate\idl\$(Platform)\$(Configuration)
$(VC_LibraryPath_ARM64);$(WindowsSDK_LibraryPath_ARM64);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.client.unittests\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
$(SolutionDir)VSFiles\intermediate\$(MSBuildProjectName)\$(Platform)\$(Configuration)\GeneratedFiles\
$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)VSFiles\intermediate\idl\$(Platform)\$(Configuration)
$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.client.unittests\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
$(SolutionDir)VSFiles\intermediate\$(MSBuildProjectName)\$(Platform)\$(Configuration)\GeneratedFiles\
$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)VSFiles\intermediate\idl\$(Platform)\$(Configuration)
$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);
diff --git a/src/api/Test/Midi2.Driver.unittests/Midi2.Driver.unittests.vcxproj b/src/api/Test/Midi2.Driver.unittests/Midi2.Driver.unittests.vcxproj
index dc6aa160..88dd5afb 100644
--- a/src/api/Test/Midi2.Driver.unittests/Midi2.Driver.unittests.vcxproj
+++ b/src/api/Test/Midi2.Driver.unittests/Midi2.Driver.unittests.vcxproj
@@ -91,28 +91,28 @@
$(LibraryPath);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midiksenum\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midiks\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midixproc\$(Platform)\$(Configuration);
$(VC_IncludePath);$(WindowsSDK_IncludePath)
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.driver.unittests\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
$(VC_IncludePath);$(WindowsSDK_IncludePath)
$(LibraryPath);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midiksenum\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midiks\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midixproc\$(Platform)\$(Configuration);
$(VC_IncludePath);$(WindowsSDK_IncludePath)
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.driver.unittests\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
$(VC_IncludePath);$(WindowsSDK_IncludePath)
$(LibraryPath);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midiksenum\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midiks\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midixproc\$(Platform)\$(Configuration);
$(VC_IncludePath);$(WindowsSDK_IncludePath)
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.driver.unittests\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
$(VC_IncludePath);$(WindowsSDK_IncludePath)
$(LibraryPath);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midiksenum\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midiks\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midixproc\$(Platform)\$(Configuration);
$(VC_IncludePath);$(WindowsSDK_IncludePath)
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.driver.unittests\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
diff --git a/src/api/Test/Midi2.Service.unittests/Midi2.Service.unittests.vcxproj b/src/api/Test/Midi2.Service.unittests/Midi2.Service.unittests.vcxproj
index ef2502e0..45b65cde 100644
--- a/src/api/Test/Midi2.Service.unittests/Midi2.Service.unittests.vcxproj
+++ b/src/api/Test/Midi2.Service.unittests/Midi2.Service.unittests.vcxproj
@@ -69,22 +69,22 @@
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.service.unittests\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
$(VC_LibraryPath_ARM64);$(WindowsSDK_LibraryPath_ARM64);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);;$(SolutionDir)\VSFiles\intermediate\midixproc\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midiksenum\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\midiswenum\$(Platform)\$(Configuration)
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.service.unittests\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
$(VC_LibraryPath_ARM64);$(WindowsSDK_LibraryPath_ARM64);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);;$(SolutionDir)\VSFiles\intermediate\midixproc\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midiksenum\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\midiswenum\$(Platform)\$(Configuration)
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.service.unittests\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midixproc\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\midiswenum\$(Platform)\$(Configuration)
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.service.unittests\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);;$(SolutionDir)\VSFiles\intermediate\midixproc\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midiksenum\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\midiswenum\$(Platform)\$(Configuration)
diff --git a/src/api/Test/Midi2.Transform.unittests/Midi2.Transform.unittests.vcxproj b/src/api/Test/Midi2.Transform.unittests/Midi2.Transform.unittests.vcxproj
index 6367f39d..e7098bc6 100644
--- a/src/api/Test/Midi2.Transform.unittests/Midi2.Transform.unittests.vcxproj
+++ b/src/api/Test/Midi2.Transform.unittests/Midi2.Transform.unittests.vcxproj
@@ -69,23 +69,23 @@
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.Transform.unittests\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\midiswenum\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midixproc\$(Platform)\$(Configuration)
$(VC_LibraryPath_ARM64);$(WindowsSDK_LibraryPath_ARM64);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\midiswenum\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midixproc\$(Platform)\$(Configuration)
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.Transform.unittests\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.Transform.unittests\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\midiswenum\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midixproc\$(Platform)\$(Configuration)
$(VC_LibraryPath_ARM64);$(WindowsSDK_LibraryPath_ARM64);$(WindowsSdkDir)\Testing\Development\lib\$(Platform);$(SolutionDir)\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\midiswenum\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\test\miditestcommon\$(Platform)\$(Configuration);$(SolutionDir)\VSFiles\intermediate\midixproc\$(Platform)\$(Configuration)
$(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
- $(SolutionDir)VSFiles\intermediate\midi2.Transform.unittests\$(Platform)\$(Configuration)\
+ $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
diff --git a/src/oob-setup/midi-services-setup.sln b/src/oob-setup/midi-services-setup.sln
index 92484d5c..6b940425 100644
--- a/src/oob-setup/midi-services-setup.sln
+++ b/src/oob-setup/midi-services-setup.sln
@@ -15,24 +15,17 @@ Project("{B7DD6F7E-DEF8-4E67-B5B7-07EF123DB6F0}") = "settings-package", "setting
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {E18CC5FC-F028-48A7-9343-E32A85CDF7B3}.Debug|x64.ActiveCfg = Debug|x64
{E18CC5FC-F028-48A7-9343-E32A85CDF7B3}.Release|x64.ActiveCfg = Release|x64
{E18CC5FC-F028-48A7-9343-E32A85CDF7B3}.Release|x64.Build.0 = Release|x64
- {182F17E6-CF91-4D65-B767-6469D523F5AC}.Debug|x64.ActiveCfg = Debug|x64
{182F17E6-CF91-4D65-B767-6469D523F5AC}.Release|x64.ActiveCfg = Release|x64
{182F17E6-CF91-4D65-B767-6469D523F5AC}.Release|x64.Build.0 = Release|x64
- {8049E08D-92F2-4BDE-B07F-BCF7DAD5F134}.Debug|x64.ActiveCfg = Debug|x64
{8049E08D-92F2-4BDE-B07F-BCF7DAD5F134}.Release|x64.ActiveCfg = Release|x64
{8049E08D-92F2-4BDE-B07F-BCF7DAD5F134}.Release|x64.Build.0 = Release|x64
- {6894F024-2ADF-4A9B-87FC-70C8209C6CDE}.Debug|x64.ActiveCfg = Debug|x64
{6894F024-2ADF-4A9B-87FC-70C8209C6CDE}.Release|x64.ActiveCfg = Release|x64
{6894F024-2ADF-4A9B-87FC-70C8209C6CDE}.Release|x64.Build.0 = Release|x64
- {0C3D23A8-A238-4551-BEB4-2912EFA3245C}.Debug|x64.ActiveCfg = Debug|x64
- {0C3D23A8-A238-4551-BEB4-2912EFA3245C}.Debug|x64.Build.0 = Debug|x64
{0C3D23A8-A238-4551-BEB4-2912EFA3245C}.Release|x64.ActiveCfg = Release|x64
{0C3D23A8-A238-4551-BEB4-2912EFA3245C}.Release|x64.Build.0 = Release|x64
EndGlobalSection
diff --git a/src/user-tools/midi-console/Midi/AnsiConsoleOutput.cs b/src/user-tools/midi-console/Midi/AnsiConsoleOutput.cs
index 88d9de88..26b1a7b5 100644
--- a/src/user-tools/midi-console/Midi/AnsiConsoleOutput.cs
+++ b/src/user-tools/midi-console/Midi/AnsiConsoleOutput.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
+using System.Runtime.Intrinsics.X86;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Midi2;
@@ -13,40 +14,103 @@ namespace Microsoft.Devices.Midi2.ConsoleApp
internal class AnsiConsoleOutput
{
- public static void ConvertToFriendlyTimeUnit(double microsecondsToConvert, out double convertedValue, out string convertedUnitLabel)
+ public static void ConvertTicksToFriendlyTimeUnit(UInt64 ticksToConvert, out double convertedValue, out string convertedUnitLabel, bool longLabel = false)
{
// TODO: These should likely be localized
+ string offsetUnitNanoseconds = "ns";
string offsetUnitMicroseconds = "μs";
string offsetUnitMilliseconds = "ms";
string offsetUnitSeconds = "s";
- string offsetUnitMinutes = "MN";
- string offsetUnitHours = "HR";
+ string offsetUnitMinutes = "mn";
+ string offsetUnitHours = "hr";
+ string offsetUnitDays = "dd";
+ string offsetUnitYears = "yy";
+
+ string offsetUnitNanosecondsLong = "nanoseconds";
+ string offsetUnitMicrosecondsLong = "microseconds";
+ string offsetUnitMillisecondsLong = "milliseconds";
+ string offsetUnitSecondsLong = "seconds";
+ string offsetUnitMinutesLong = "minutes";
+ string offsetUnitHoursLong = "hours";
+ string offsetUnitDaysLong = "days";
+ string offsetUnitYearsLong = "years";
+
+
+ const double secondsPerMinute = 60;
+ const double secondsPerHour = secondsPerMinute * 60;
+ const double secondsPerDay = secondsPerHour * 24;
+ const double secondsPerYear = secondsPerDay * 365; // yes, this is approximate, but good enough for where it is used
+
+ // these just make the code much more readible
+ double ticksPerSecond = MidiClock.TimestampFrequency;
+ double ticksPerMinute = MidiClock.TimestampFrequency * secondsPerMinute;
+ double ticksPerHour = MidiClock.TimestampFrequency * secondsPerHour;
+ double ticksPerDay = MidiClock.TimestampFrequency * secondsPerDay;
+ double ticksPerYear = MidiClock.TimestampFrequency * secondsPerYear;
+
+ double ticksPerMillisecond = MidiClock.TimestampFrequency / 1000;
+ double ticksPerMicrosecond = MidiClock.TimestampFrequency / 1000000;
+ double ticksPerNanosecond = MidiClock.TimestampFrequency / 1000000000;
+
+
+ if (ticksToConvert == 0)
+ {
+ convertedValue = 0;
+ convertedUnitLabel = "--";
+ }
+ else if (ticksToConvert > ticksPerYear)
+ {
+ // convert to days
+ convertedUnitLabel = longLabel ? offsetUnitYearsLong : offsetUnitYears;
+ convertedValue = (double)ticksToConvert / ticksPerYear;
+
+ }
+ else if (ticksToConvert > ticksPerDay)
+ {
+ // convert to days
+ convertedUnitLabel = longLabel ? offsetUnitDaysLong : offsetUnitDays;
+ convertedValue = (double)ticksToConvert / ticksPerDay;
- if (Math.Abs(microsecondsToConvert) > (double)(60.0 * 60.0 * 1000000))
+ }
+ else if (ticksToConvert > ticksPerHour)
+ {
+ // convert to hours
+
+ convertedUnitLabel = longLabel ? offsetUnitHoursLong : offsetUnitHours;
+ convertedValue = (double)ticksToConvert / ticksPerHour;
+ }
+ else if (ticksToConvert > ticksPerMinute)
{
- convertedUnitLabel = offsetUnitHours;
- convertedValue = microsecondsToConvert / (double)(60.0 * 60.0 * 1000000);
+ // convert to minutes
+
+ convertedUnitLabel = longLabel ? offsetUnitMinutesLong : offsetUnitMinutes;
+ convertedValue = (double)ticksToConvert / ticksPerMinute;
}
- else if (Math.Abs(microsecondsToConvert) > (60.0 * 1000000))
+ else if (ticksToConvert > ticksPerSecond)
{
- convertedUnitLabel = offsetUnitMinutes;
- convertedValue = microsecondsToConvert / (60* 1000000);
+ // convert to seconds
+
+ convertedUnitLabel = longLabel ? offsetUnitMinutesLong : offsetUnitSeconds;
+ convertedValue = (double)ticksToConvert / ticksPerSecond;
}
- else if (Math.Abs(microsecondsToConvert) > 1000000)
+ else if (ticksToConvert > ticksPerMillisecond)
{
- convertedUnitLabel = offsetUnitSeconds;
- convertedValue = microsecondsToConvert / 1000000;
+ // convert to milliseconds
+ convertedUnitLabel = longLabel ? offsetUnitMillisecondsLong : offsetUnitMilliseconds;
+ convertedValue = (double)ticksToConvert / ticksPerMillisecond;
}
- else if (Math.Abs(microsecondsToConvert) > 1000)
+ else if (ticksToConvert > ticksPerMicrosecond)
{
- convertedUnitLabel = offsetUnitMilliseconds;
- convertedValue = microsecondsToConvert / 1000;
+ // convert to microseconds
+ convertedUnitLabel = longLabel ? offsetUnitMicrosecondsLong : offsetUnitMicroseconds;
+ convertedValue = (double)ticksToConvert / ticksPerMicrosecond;
}
else
{
- convertedUnitLabel = offsetUnitMicroseconds;
- convertedValue = microsecondsToConvert;
+ // convert to nanoseconds
+ convertedUnitLabel = longLabel ? offsetUnitNanosecondsLong : offsetUnitNanoseconds;
+ convertedValue = (double)ticksToConvert / ticksPerNanosecond;
}
}
diff --git a/src/user-tools/midi-console/Midi/Commands/Clock/TimeCommand.cs b/src/user-tools/midi-console/Midi/Commands/Clock/TimeCommand.cs
index 1937490d..9267b745 100644
--- a/src/user-tools/midi-console/Midi/Commands/Clock/TimeCommand.cs
+++ b/src/user-tools/midi-console/Midi/Commands/Clock/TimeCommand.cs
@@ -20,13 +20,48 @@ internal class Settings : CommandSettings
public override int Execute(CommandContext context, Settings settings)
{
+
+ var frequency = MidiClock.TimestampFrequency;
+ double convertedFrequency = 0;
+ string units = string.Empty;
+
+ if (frequency >= 100000)
+ {
+ convertedFrequency = 1.0 / frequency * 1000000000.0;
+ units = "ns";
+ }
+ else if (frequency >= 1000)
+ {
+ convertedFrequency = 1.0 / frequency * 1000000.0;
+ units = "μs";
+ }
+ else
+ {
+ // hope we never see this!
+ convertedFrequency = 1.0 / frequency * 1000.0;
+ units = "ms";
+ }
+
+ AnsiConsole.MarkupLine("The Windows MIDI Services MIDI Clock is a high-resolution 64 bit system timestamp that is reset when the computer is rebooted. See [darkslategray1]https://aka.ms/miditimestamp[/] for more information.");
+ AnsiConsole.WriteLine();
+
+ AnsiConsole.MarkupLine($"Timestamp resolution: [deepskyblue1]{MidiClock.TimestampFrequency.ToString("N0")}[/] ticks per second ([deepskyblue1]{convertedFrequency.ToString("N2")} {units}[/] per tick)");
+ AnsiConsole.WriteLine();
+ AnsiConsole.MarkupLine($"➡️ 10 microseconds: {AnsiMarkupFormatter.FormatTimestamp(MidiClock.OffsetTimestampByMicroseconds(0, 10))} ticks");
+ AnsiConsole.MarkupLine($"➡️ 10 milliseconds: {AnsiMarkupFormatter.FormatTimestamp(MidiClock.OffsetTimestampByMilliseconds(0, 10))} ticks");
+ AnsiConsole.MarkupLine($"➡️ 2 seconds: {AnsiMarkupFormatter.FormatTimestamp(MidiClock.OffsetTimestampByMilliseconds(0, 2000))} ticks");
+ AnsiConsole.WriteLine();
+
var now = MidiClock.Now;
+ var ticksUntilWrap = Int64.MaxValue - now; // turns out, QPC LARGE_INTEGER is signed, not unsigned.
+ double tickWrapTime = 0.0;
+ string tickWrapLabel = string.Empty;
- AnsiConsole.MarkupLine("Current timestamp: " + AnsiMarkupFormatter.FormatTimestamp(now) + " ticks");
- AnsiConsole.MarkupLine("Timestamp resolution: " + AnsiMarkupFormatter.FormatTimestamp(MidiClock.TimestampFrequency) + " ticks per second");
- AnsiConsole.MarkupLine("Two seconds in ticks: " + AnsiMarkupFormatter.FormatTimestamp(MidiClock.OffsetTimestampByMilliseconds(0, 2000)) + " ticks");
+ AnsiConsoleOutput.ConvertTicksToFriendlyTimeUnit(ticksUntilWrap, out tickWrapTime, out tickWrapLabel, true);
- ;
+ AnsiConsole.MarkupLine($"Current timestamp: {AnsiMarkupFormatter.FormatTimestamp(now)} ticks");
+ AnsiConsole.WriteLine();
+ AnsiConsole.MarkupLine($"Time until the MIDI Clock wraps back around to zero is {AnsiMarkupFormatter.FormatTimestamp(ticksUntilWrap)} ticks or [deepskyblue1]{tickWrapTime.ToString("N2")} {tickWrapLabel}[/].");
return (int)MidiConsoleReturnCode.Success;
}
diff --git a/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointMonitorCommand.cs b/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointMonitorCommand.cs
index e11efcaa..7ef7cf51 100644
--- a/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointMonitorCommand.cs
+++ b/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointMonitorCommand.cs
@@ -21,6 +21,7 @@ public struct ReceivedMidiMessage
{
public UInt32 Index;
public UInt64 ReceivedTimestamp;
+ public UInt64 ReceivedOffsetFromLastMessage;
public UInt64 MessageTimestamp;
public byte NumWords;
public UInt32 Word0;
@@ -226,7 +227,7 @@ public override int Execute(CommandContext context, Settings settings)
UInt64 startTimestamp = 0;
- UInt64 lastReceivedTimestamp = 0;
+ //UInt64 lastReceivedEventTimestamp = 0;
UInt32 index = 0;
UInt64 firstMessageReceivedEventTimestamp = 0;
@@ -245,10 +246,11 @@ public override int Execute(CommandContext context, Settings settings)
// open the connection
if (connection.Open())
{
- // Main message listener background thread -----------------------------------------------------
+ // Main message listener background thread ---------------------------------------------------------
var messageListener = new Thread(() =>
{
+
UInt64 lastMessageTimestamp = 0;
UInt32 lastReceivedDebugWord = 0;
@@ -256,59 +258,73 @@ public override int Execute(CommandContext context, Settings settings)
connection.MessageReceived += (s, e) =>
{
- // this captures stats to tell us how long it takes to receive and queue messages
- lastMessageReceivedEventTimestamp = MidiClock.Now;
- if (firstMessageReceivedEventTimestamp == 0) firstMessageReceivedEventTimestamp = lastMessageReceivedEventTimestamp;
countMessagesReceived++;
- // this captures intended timestamps, not actual
- if (startTimestamp == 0) startTimestamp = e.Timestamp;
+ // this captures stats to tell us how long it takes to receive and queue messages
+ UInt64 thisMessageReceivedEventTimestamp = MidiClock.Now;
+
+ if (firstMessageReceivedEventTimestamp == 0)
+ {
+ firstMessageReceivedEventTimestamp = thisMessageReceivedEventTimestamp;
+ lastMessageReceivedEventTimestamp = thisMessageReceivedEventTimestamp;
+ }
+
+ // this captures incoming message timestamps, not actual received event timestamp
+ if (startTimestamp == 0)
+ {
+ startTimestamp = e.Timestamp;
+ lastMessageTimestamp = e.Timestamp;
+ }
// helps prevent any race conditions with main loop and its output
- if (!continueWaiting) return;
+ //if (!continueWaiting) return;
index++;
var receivedMessage = new ReceivedMidiMessage()
{
Index = index,
- ReceivedTimestamp = MidiClock.Now,
+ ReceivedTimestamp = thisMessageReceivedEventTimestamp,
+ ReceivedOffsetFromLastMessage = thisMessageReceivedEventTimestamp - lastMessageReceivedEventTimestamp,
MessageTimestamp = e.Timestamp
};
- if (e.Timestamp < lastMessageTimestamp)
+
+ if (index > 1 && e.Timestamp < lastMessageTimestamp)
{
outOfTimestampOrderMessageCount++;
receivedMessage.HasError = true;
}
-
lastMessageTimestamp = e.Timestamp;
receivedMessage.NumWords = e.FillWords(
- out receivedMessage.Word0,
- out receivedMessage.Word1,
- out receivedMessage.Word2,
+ out receivedMessage.Word0,
+ out receivedMessage.Word1,
+ out receivedMessage.Word2,
out receivedMessage.Word3);
- switch (receivedMessage.NumWords)
+ if (settings.WarnIfSkippedIncrementMessage)
{
- case 1: break; // 1 word messages don't auto-increment
- case 2:
- currentDebugWord = receivedMessage.Word1;
- break;
- case 3:
- currentDebugWord = receivedMessage.Word2;
- break;
- case 4:
- currentDebugWord = receivedMessage.Word3;
- break;
- }
+ switch (receivedMessage.NumWords)
+ {
+ case 1: break; // 1 word messages don't auto-increment
- if (settings.WarnIfSkippedIncrementMessage && index > 1)
- {
- if (currentDebugWord != lastReceivedDebugWord + 1)
+ case 2:
+ currentDebugWord = receivedMessage.Word1;
+ break;
+
+ case 3:
+ currentDebugWord = receivedMessage.Word2;
+ break;
+
+ case 4:
+ currentDebugWord = receivedMessage.Word3;
+ break;
+ }
+
+ if (index > 1 && (currentDebugWord > lastReceivedDebugWord + 1))
{
numberOfSkippedDebugMessages += (currentDebugWord - lastReceivedDebugWord - 1);
receivedMessage.HasError = true;
@@ -317,18 +333,20 @@ public override int Execute(CommandContext context, Settings settings)
lastReceivedDebugWord = currentDebugWord;
}
-
+ // add it to the queue so it can be processed
lock (m_receivedMessagesQueue)
{
m_receivedMessagesQueue.Enqueue(receivedMessage);
}
-
m_messageDispatcherThreadWakeup.Set();
+
if (settings.SingleMessage)
{
continueWaiting = false;
}
+
+ lastMessageReceivedEventTimestamp = thisMessageReceivedEventTimestamp;
};
m_terminateMessageListenerThread.WaitOne();
@@ -336,16 +354,14 @@ public override int Execute(CommandContext context, Settings settings)
messageListener.Start();
- //const UInt32 minMessagesToLagBeforeSkip = 10;
-
- // Console display background thread -----------------------------------------------------
+ // Console display background thread ---------------------------------------------------------------
var messageConsoleDisplay = new Thread(() =>
{
while (continueWaiting)
{
if (m_displayMessageQueue.Count == 0) m_displayMessageThreadWakeup.WaitOne(5000);
- if (m_displayMessageQueue.Count > 0)
+ if (continueWaiting && m_displayMessageQueue.Count > 0)
{
ReceivedMidiMessage message;
@@ -354,34 +370,13 @@ public override int Execute(CommandContext context, Settings settings)
message = m_displayMessageQueue.Dequeue();
}
-
- if (startTimestamp == 0)
- {
- // gets timestamp of first message we receive and uses that so all others are an offset
- startTimestamp = message.ReceivedTimestamp;
- }
-
- if (lastReceivedTimestamp == 0)
- {
- lastReceivedTimestamp = message.ReceivedTimestamp;
- }
-
if (message.Index == 1)
{
displayTable.OutputHeader();
}
- // calculate offset from the last message received
- var offsetMicroseconds = MidiClock.ConvertTimestampToMicroseconds(
- message.ReceivedTimestamp - lastReceivedTimestamp);
-
- // set our last received so we can calculate offsets
- lastReceivedTimestamp = message.ReceivedTimestamp;
-
- displayTable.OutputRow(message, offsetMicroseconds);
+ displayTable.OutputRow(message);
}
-
- //Thread.Sleep(0);
}
});
messageConsoleDisplay.Start();
@@ -405,17 +400,6 @@ public override int Execute(CommandContext context, Settings settings)
message = m_receivedMessagesQueue.Dequeue();
}
-
- //if (settings.SkipToKeepUp && m_displayMessageQueue.Count >= minMessagesToLagBeforeSkip)
- //{
- // // display queue is backed up. Skip displaying if user has specified that.
-
- // lock (m_displayMessageQueue)
- // {
- // m_displayMessageQueue.Clear();
- // }
- //}
-
// add to the display queue
lock (m_displayMessageQueue)
{
@@ -440,7 +424,7 @@ public override int Execute(CommandContext context, Settings settings)
messageDispatcherThread.Start();
- // File writing background thread -----------------------------------------------------
+ // File writing background thread ------------------------------------------------------------------
if (captureWriter != null)
{
var messageFileWriter = new Thread(() =>
@@ -449,7 +433,7 @@ public override int Execute(CommandContext context, Settings settings)
{
if (m_fileWriterMessagesQueue.Count == 0) m_fileMessageThreadWakeup.WaitOne(5000);
- if (m_fileWriterMessagesQueue.Count > 0)
+ if (continueWaiting && m_fileWriterMessagesQueue.Count > 0)
{
ReceivedMidiMessage message;
@@ -480,9 +464,10 @@ public override int Execute(CommandContext context, Settings settings)
}
- // Main UI loop and moving messages to output queues -----------------------------------------
+ // Main UI loop ------------------------------------------------------------------------------------
AnsiConsole.MarkupLine(Strings.MonitorPressEscapeToStopMonitoringMessage);
AnsiConsole.WriteLine();
+
while (continueWaiting)
{
if (Console.KeyAvailable)
@@ -535,77 +520,72 @@ public override int Execute(CommandContext context, Settings settings)
// Summary information ---------------------------------------------------------------------------------
- if (lastMessageReceivedEventTimestamp >= firstMessageReceivedEventTimestamp)
{
string message = "➡️ ";
if (countMessagesReceived == 0)
{
- message += "[red]No[/] messages received";
+ message += "[yellow]No messages received[/]";
}
else if (countMessagesReceived == 1)
{
- message += "[green]One[/] message received";
+ message += "[steelblue1]One message received[/]";
}
else
{
- message += $"[steelblue1]{countMessagesReceived.ToString("N0")}[/] messages received";
+ message += $"[steelblue1]{countMessagesReceived.ToString("N0")} messages received[/]";
}
- // calculate total receive time, not total display time
+ if (countMessagesReceived > 0 && lastMessageReceivedEventTimestamp >= firstMessageReceivedEventTimestamp)
+ {
+ // calculate total receive time, not total display time
- UInt64 totalTicks = lastMessageReceivedEventTimestamp - firstMessageReceivedEventTimestamp;
- double totalSeconds = MidiClock.ConvertTimestampToMilliseconds(totalTicks) / 1000.0;
+ UInt64 totalTicks = lastMessageReceivedEventTimestamp - firstMessageReceivedEventTimestamp;
+ double totalTime = 0.0;
+ string totalTimeLabel = string.Empty;
- message += $" and processed over [steelblue1]{totalSeconds.ToString("N2")}[/] seconds, ";
+ AnsiConsoleOutput.ConvertTicksToFriendlyTimeUnit(totalTicks, out totalTime, out totalTimeLabel);
- UInt64 averageTicksPerMessage = totalTicks / countMessagesReceived;
- double averageMicroseconds = MidiClock.ConvertTimestampToMicroseconds(averageTicksPerMessage);
- double averageMilliseconds = MidiClock.ConvertTimestampToMilliseconds(averageTicksPerMessage);
+ UInt64 averageTicks = totalTicks / countMessagesReceived; // yes, this will truncate. That's ok
+ double averageTime = 0.0;
+ string averageTimeLabel = string.Empty;
+
+ AnsiConsoleOutput.ConvertTicksToFriendlyTimeUnit(averageTicks, out averageTime, out averageTimeLabel);
+
+ message += $" over [steelblue1]{totalTime.ToString("N2")} {totalTimeLabel}[/], ";
+ message += $"averaging [steelblue1]{averageTime.ToString("N2")} {averageTimeLabel}[/] per message. (Total display time may be longer)";
- if (averageMicroseconds > 1000000)
- {
- // display in seconds
- double averageSeconds = averageMicroseconds / 1000000.0;
- message += $"[steelblue1]{averageSeconds.ToString("N4")} s[/] per message.";
- }
- else if (averageMilliseconds > 1)
- {
- // display in milliseconds
- message += $"[steelblue1]{averageMilliseconds.ToString("N2")} ms[/] per message.";
- }
- else
- {
- // display in microseconds
- message += $"[steelblue1]{averageMilliseconds.ToString("N2")} μs[/] per message.";
}
AnsiConsole.MarkupLine(message);
}
- if (outOfTimestampOrderMessageCount > 0)
+ if (countMessagesReceived > 0)
{
- string message = "❎ " + outOfTimestampOrderMessageCount.ToString();
-
- if (outOfTimestampOrderMessageCount > 1)
+ if (outOfTimestampOrderMessageCount > 0)
{
- // multiple messages out of order
- message += " messages received out of sent timestamp order.";
+ string message = "❎ " + outOfTimestampOrderMessageCount.ToString();
+
+ if (outOfTimestampOrderMessageCount > 1)
+ {
+ // multiple messages out of order
+ message += " messages received out of sent timestamp order.";
+ }
+ else
+ {
+ // single message out of order
+ message += " message received out of sent timestamp order.";
+ }
+
+ AnsiConsole.MarkupLine(AnsiMarkupFormatter.FormatError(message));
}
else
{
- // single message out of order
- message += " message received out of sent timestamp order.";
+ AnsiConsole.MarkupLine("✅ No messages received out of expected timestamp order.");
}
-
- AnsiConsole.MarkupLine(AnsiMarkupFormatter.FormatError(message));
- }
- else
- {
- AnsiConsole.MarkupLine("✅ No messages received out of expected timestamp order.");
}
- if (settings.WarnIfSkippedIncrementMessage)
+ if (countMessagesReceived > 0 && settings.WarnIfSkippedIncrementMessage)
{
if (numberOfSkippedDebugMessages > 0)
{
@@ -614,19 +594,21 @@ public override int Execute(CommandContext context, Settings settings)
if (numberOfSkippedDebugMessages > 1)
{
// multiple messages out of order
- message += " in-line messages skipped (assuming they were sent with debug words).";
+ message = AnsiMarkupFormatter.FormatError(message + " debug messages skipped");
}
else
{
// single message out of order
- message += " in-line message skipped (assuming it was sent with debug words).";
+ message = AnsiMarkupFormatter.FormatError(message + " debug message skipped");
}
- AnsiConsole.MarkupLine(AnsiMarkupFormatter.FormatError(message));
+ message += " (assuming ordered debug words). This does not include any missing from the end or beginning.";
+
+ AnsiConsole.MarkupLine(message);
}
else
{
- AnsiConsole.MarkupLine("✅ No messages skipped.");
+ AnsiConsole.MarkupLine("✅ No debug messages skipped. This does not include any missing from the end or beginning.");
}
}
diff --git a/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointSendMessageCommand.cs b/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointSendMessageCommand.cs
index 39d5e50b..a75783cf 100644
--- a/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointSendMessageCommand.cs
+++ b/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointSendMessageCommand.cs
@@ -227,7 +227,7 @@ public override int Execute(CommandContext context, Settings settings)
AnsiConsole.Progress()
.Start(ctx =>
{
- if ((settings.Count * (settings.Words!.Length + 2)) > bufferWarningThreshold && settings.DelayBetweenMessages == 0)
+ if (settings.DelayBetweenMessages == 0 && (settings.Count * (settings.Words!.Length + 2)) > bufferWarningThreshold)
{
AnsiConsole.MarkupLine(AnsiMarkupFormatter.FormatWarning(Strings.SendMessageFloodWarning));
AnsiConsole.WriteLine();
diff --git a/src/user-tools/midi-console/Midi/CustomTable/MidiMessageTable.cs b/src/user-tools/midi-console/Midi/CustomTable/MidiMessageTable.cs
index 4ff17f6d..9e31f206 100644
--- a/src/user-tools/midi-console/Midi/CustomTable/MidiMessageTable.cs
+++ b/src/user-tools/midi-console/Midi/CustomTable/MidiMessageTable.cs
@@ -45,9 +45,13 @@ private void BuildStringFormats()
char horizontalLine = '\u2500';
string cross = "\u253C";
- string errorVerticalLine = "[red]\u2573[/]";
+ //string errorVerticalLine = "[black]\u2573[/]";
+ string errorVerticalLine = "\u2502";
string verticalLine = "\u2502";
+
+
+
foreach (var col in Columns)
{
if (_headerFormat != string.Empty && !col.NoLeftSeparator)
@@ -103,7 +107,9 @@ private void BuildStringFormats()
}
- _errorMessageFormat += "[red] ** possible error **[/]";
+ _errorMessageFormat += "[white] ** possible error **[/] ";
+
+ _errorMessageFormat = $"[default on darkred]{_errorMessageFormat}[/]";
}
@@ -149,7 +155,7 @@ public void OutputHeader()
AnsiConsole.MarkupLine(_separatorLine);
}
- public void OutputRow(ReceivedMidiMessage message, double deltaMicrosecondsFromPreviousMessage)
+ public void OutputRow(ReceivedMidiMessage message)
{
//Console.WriteLine(message.Index);
//return;
@@ -187,7 +193,7 @@ public void OutputRow(ReceivedMidiMessage message, double deltaMicrosecondsFromP
double offsetValue = 0;
string offsetUnitLabel = string.Empty;
- AnsiConsoleOutput.ConvertToFriendlyTimeUnit(deltaMicrosecondsFromPreviousMessage, out offsetValue, out offsetUnitLabel);
+ AnsiConsoleOutput.ConvertTicksToFriendlyTimeUnit(message.ReceivedOffsetFromLastMessage, out offsetValue, out offsetUnitLabel);
double deltaValue = 0;
@@ -195,19 +201,17 @@ public void OutputRow(ReceivedMidiMessage message, double deltaMicrosecondsFromP
if (m_verbose)
{
- double deltaScheduledTimestampMicroseconds = 0.0;
-
if (message.ReceivedTimestamp >= message.MessageTimestamp)
{
- deltaScheduledTimestampMicroseconds = MidiClock.ConvertTimestampToMicroseconds(message.ReceivedTimestamp - message.MessageTimestamp);
+ AnsiConsoleOutput.ConvertTicksToFriendlyTimeUnit((UInt64)(message.ReceivedTimestamp - message.MessageTimestamp), out deltaValue, out deltaUnitLabel);
}
else
{
// we received the message early, so the offset is negative
- deltaScheduledTimestampMicroseconds = -1 * MidiClock.ConvertTimestampToMicroseconds(message.MessageTimestamp - message.ReceivedTimestamp);
+ AnsiConsoleOutput.ConvertTicksToFriendlyTimeUnit((UInt64)(message.ReceivedTimestamp - message.MessageTimestamp), out deltaValue, out deltaUnitLabel);
+ deltaValue = deltaValue * -1;
}
- AnsiConsoleOutput.ConvertToFriendlyTimeUnit(deltaScheduledTimestampMicroseconds, out deltaValue, out deltaUnitLabel);
}