Watchdog bug in 2.4.0

Please let our ADS show!

This sites offers only FREE software and it's supported by a few advertisement boxes (no intrusive popups).
Please:

  • disable your AdBlocker by adding CoolSoft website to whitelist
  • give the proper cookie consent
  • enable JavaScript for this website

This seconds wait is to let you update your browser configuration...

Ok, I've done the required changes... now show me your content!
!!! Please enable JavaScript !!!

Pages

Posts: 18
Joined: January 1, 2016 - 17:54
Watchdog bug in 2.4.0

After having used 2.1-RC1 for a long time being quite happy. I now updated to 2.4.0.

One reason for using 2.1-RC1 was your statement "Noticeable changes: Virtual MIDI devices can now be shared between clients. ", which worked very well for me.

I believed, this would be included in 2.4.0 too. But I failed. It isn't included. Or - if it is - it does not work. I made a simple test script (in Lua, sorry, but the Workflow should be clear):

for n=-1,10 do
    local caps=MmMidi.OutGetDevCaps(n)
    if caps then
        printf("Port %2d :%-32.32s ",n,caps.szPname)
        local hmo1,err1=MmMidi.OutOpen(n)
        local hmo2,err2=MmMidi.OutOpen(n)
        printf("%-20s [%-10s] %-20s [%-10s]\n",tostring(hmo1),tostring(MmMidi.ErrorText(err1)),tostring(hmo2),tostring(MmMidi.ErrorText(err2)))
        MmMidi.OutClose(hmo1)
        MmMidi.OutClose(hmo2)
    end
end

The output is:

Port -1 :Microsoft MIDI Mapper            userdata: 0x006d2708 [MMSYSERR_NOERROR] nil                  [MMSYSERR_ALLOCATED]
Port  0 :VirtualMIDISynth #1              userdata: 0x006d2708 [MMSYSERR_NOERROR] nil                  [MMSYSERR_ALLOCATED]
Port  1 :Microsoft GS Wavetable Synth     userdata: 0x006d2708 [MMSYSERR_NOERROR] nil                  [MMSYSERR_ALLOCATED]
Port  2 :DMX 6Fire MIDI Out               userdata: 0x006d2708 [MMSYSERR_NOERROR] nil                  [MMSYSERR_ALLOCATED]

At least for "Port 0" I had expected to get MMSYSERR_NOERROR also for the second OutOpen. This worked with 2.1-RC1.

Did I miss something? Please give advice. Do I need to return to 2.1-RC1?

Regards

Posts: 1978
Joined: March 25, 2012 - 01:19
Re: Watchdog bug in 2.4.0
bassklampfe wrote:
At least for "Port 0" I had expected to get MMSYSERR_NOERROR also for the second OutOpen. This worked with 2.1-RC1.

You're right that it "worked" like this in 2.1-RC1, but it was an unexpected behavior, a bad return value that allowed the same device to be opened twice (or more) by the same process.
It worked but could lead to crash in some cases and, most of all, it did not comply with Windows MIDI API specifications.

To make things clear: a (virtual) MIDI device can be shared between clients does not mean it can be used multiple times by the same one ;)
It means that two different MIDI players (or two instances of the same one) can play on the same VirtualMIDISynth device.

In your code sample, the same process (PID) tries to open a MIDI device more than once.
In this case the MMSYSERR_ALLOCATED return value is correct and expected: https://msdn.microsoft.com/it-it/library/windows/desktop/dd798476(v=vs.85).aspx
As you can see all of your other MIDI devices return the same error code...

If you need to open more than one device you should configure VirtualMIDISynth to show more than one device (up to 4) and they behave as separate MIDI devices.

Posts: 18
Joined: January 1, 2016 - 17:54
Re: Watchdog bug in 2.4.0
coolsoft wrote:
It means that two different MIDI players (or two instances of the same one) can play on the same VirtualMIDISynth device.

Ok, maybe my sample script was not correct. Indeed, running a play-midi script multiple times on the same device works. But what I observe

Running multiple instances of PriMus worked flawless in 2.1-RC1. In 2.4.0, they more or less loose the focus on VMS.

All instances have "VirtualMIDISynth #1" as output device, but it's more or less random, which will catch a Midi-Handle. I will discuss this with the developer of PriMus and come back to you.
If you want to make some tests by yourself, a free "PriMus Reader" version is available at Columbus Soft Download Page.

Posts: 18
Joined: January 1, 2016 - 17:54
Re: Watchdog bug in 2.4.0

Further investigation revealed an issue in VMS, I think. When I open a device and do not start at once playing notes, then VMS (sometimes) returns to "free" and any output on the - still opened - handle is impossible.

The following script playes three notes

hmo=MmMidi.OutOpen(0)
MmMidi.OutShortMsg3(hmo,NOTE_ON,64,100)    MmMidi.Sleep(500)
MmMidi.OutShortMsg3(hmo,NOTE_ON,68,100)    MmMidi.Sleep(500)
MmMidi.OutShortMsg3(hmo,NOTE_ON,71,100)    MmMidi.Sleep(1000)
MmMidi.OutShortMsg3(hmo,NOTE_OFF,64,0)
MmMidi.OutShortMsg3(hmo,NOTE_OFF,68,0)
MmMidi.OutShortMsg3(hmo,NOTE_OFF,71,0)
MmMidi.OutClose(hmo)

and always runs perfect.

Changed to the following:

hmo=MmMidi.OutOpen(0)
MmMidi.Sleep(1000)
mmMidi.OutShortMsg3(hmo,NOTE_ON,64,100)    MmMidi.Sleep(500)
MmMidi.OutShortMsg3(hmo,NOTE_ON,68,100)    MmMidi.Sleep(500)
MmMidi.OutShortMsg3(hmo,NOTE_ON,71,100)    MmMidi.Sleep(1000)
MmMidi.OutShortMsg3(hmo,NOTE_OFF,64,0)
MmMidi.OutShortMsg3(hmo,NOTE_OFF,68,0)
MmMidi.OutShortMsg3(hmo,NOTE_OFF,71,0)
MmMidi.OutClose(hmo)

Sometimes VMS returns to "free" before the first note is played and then there is only silence. The time, VMS returns to "free" is random, I cannot see any pattern. I have also tried shorter delays or longer delays.

It's not stable. Sometimes I get 20 runs without any error. Sometimes only 1/10 succeeds.

If you need more information or testing, please let me know.

Regards

Posts: 1978
Joined: March 25, 2012 - 01:19
Re: Watchdog bug in 2.4.0

There's a "watchdog" between VMS-Driver (the DLL loaded in your process space) and VMS-Synth (the VirtualMIDISynth.exe process that's automatically started when needed).
Its purpose is to detect clients that crashed unexpectedly leaving the connection open and, worst, any note playing.
The driver starts a secondary thread to send a NOP message each 4000ms (by defaut) and the synth waits the double of that time before considering the client as dead (to avoid aliasing).

This watchdog thread is (or it should be) independent from your application main thread, so your sleeps should not interfere with it.
The only exception is when you place a breakpoint somewhere in your code to debug it: once the process breaks on a breakpoint all of its threads are suspended, so VMS-Synth waits for at most 8000ms then closes connection.

If this is not the case, then I'd like to test it on my side.
Sadly I don't know LUA and also I don't have any build environment for it.
Is there a way to compile your sample to an .exe?
If yes, then attach it here (zipped) and I'll have a look...

Posts: 18
Joined: January 1, 2016 - 17:54
Re: Watchdog bug in 2.4.0
coolsoft wrote:
Is there a way to compile your sample to an .exe?
If yes, then attach it here (zipped) and I'll have a look...

It may take some time, but I will try to build a standalong commandline programm to verify. I'll come back to you

Regards

Posts: 18
Joined: January 1, 2016 - 17:54
Re: Watchdog bug in 2.4.0
coolsoft wrote:
Is there a way to compile your sample to an .exe?
If yes, then attach it here (zipped) and I'll have a look...

Ok, here it is. Attached you'll find a VisualStudio-2005 Project and the resulting Exe. The code is simple:

#include 
#include 
#include 
#pragma comment(lib, "Winmm")
 
int main(int argc,char*argv[])
{
    int sleep=0;
    if(argc>1)
        sleep=atoi(argv[1]);
 
    const unsigned NOTE_OFF=0x80;
    const unsigned NOTE_ON=0x90;
 
    HMIDIOUT hmo;
    MMRESULT result=midiOutOpen(&hmo,0,0,0,0);
 
    if(sleep)
        Sleep(sleep);
 
#define OutShortMsg3(hmo,a,b,c) midiOutShortMsg(hmo,(c*256+b)*256+a)
    OutShortMsg3(hmo,NOTE_ON,64,100);    Sleep(500);
    OutShortMsg3(hmo,NOTE_ON,68,100);    Sleep(500);
    OutShortMsg3(hmo,NOTE_ON,71,100);    Sleep(1000);
    OutShortMsg3(hmo,NOTE_OFF,64,0);
    OutShortMsg3(hmo,NOTE_OFF,68,0);
    OutShortMsg3(hmo,NOTE_OFF,71,0);
    midiOutClose(hmo);
    return 0;
}

Use as following:

Open VMS/Settings/About page to view state of VMS

Play without delay: MidiCommandline.exe

Play with delay: MidiCommandline.exe 5000

Using your description, I could enforce the problem quite reliable with the following sequence

MidiCommandline.exe 5000
- wait for about 4..6 seconds
MidiCommandline.exe 5000

Almost any try if not the first, then the second will not play because VMS gos to "free" before.

Hope, this will help you

Regards

Attachments (Only registered users)
MidiCommandline.zip
Posts: 18
Joined: January 1, 2016 - 17:54
Re: Watchdog bug in 2.4.0
bassklampfe wrote:
MidiCommandline.exe 5000

Even more simple.

MidiCommandline.exe 10000

will reliable always fail. But this is a perfect legal usecase. Assume the following:

  • Start a program
  • Programm will open the configured midi device
  • In Program do "File/Open" and navigate to some folder to load a midi file or a score
    (This will surely take more than 8 seconds)
  • In Program press Play => Nothing. Silence.

I think, the concept of a watchdog must be reviewed. I'm willing to discuss

Regards

Posts: 1978
Joined: March 25, 2012 - 01:19
Re: Watchdog bug in 2.4.0

Good and bad news: the good is that I'm able to reproduce it on my side, the bad is that the bug happens only if I run both the test program and VMS without the debugger attached.
I suppose there's a race condition somewhere and running it with the debugger will hide it.
It should take longer to find what's wrong... I need to fill code with log traces ;)

bassklampfe wrote:
I think, the concept of a watchdog must be reviewed. I'm willing to discuss

Feel free to post your suggestions

Posts: 18
Joined: January 1, 2016 - 17:54
Re: Watchdog bug in 2.4.0
coolsoft wrote:
...the bad is that the bug happens only if I run both the test program and VMS without the debugger attached....

Oh, one of these ugly bugs. I know them, being a software developer too. Good luck :-)

bassklampfe wrote:
I think, the concept of a watchdog must be reviewed. I'm willing to discuss
coolsoft wrote:
Feel free to post your suggestions

Is there a reason to use a watchdog? On midiOutOpen you sample the process id of the caller (you show it in the VMS/About status info). Wouldn't it be sufficient to monitor, if the process still exists? In which situation is an "IsWatchDogTriggered()" better than a "DoesProcessStillExist()" ? I just try to understand what you're doing and why.

Pages