MidiFilter template project

Speaking for myself, I hate seeing disorganised or “dodgy” coding. Whether I’m writing code for my self, for my company, for a customer, or for a mate, I always feel compelled to “sort it out”. :slight_smile:

Mind you, my wife wishes that coding tidiness extended to keeping the house tidy, but there you go. We all have our differences. :slight_smile:

Hi folks!

I’m getting the hang of this I think…! :slight_smile:

I’ve created a Juce plugin adaptor for DXi/MFX (similar to the one I did a few days ago for VST Module Architecture SDK MIDI Effect).

I can create the filter, create the Juce UI which diplays nicely within the host property page… but I get an assertion when I shut down Cakewalk within a debug Juce build…

void Thread::stopThread (const int timeOutMilliseconds)
{
    const ScopedLock sl (startStopLock);

    if (isThreadRunning())
    {
        signalThreadShouldExit();
        notify();

        if (timeOutMilliseconds != 0)
            waitForThreadToExit (timeOutMilliseconds);

        if (isThreadRunning())
        {
            // very bad karma if this point is reached, as
            // there are bound to be locks and events left in
            // silly states when a thread is killed by force..
            jassertfalse
            Logger::writeToLog (T("!! killing thread by force !!"));

The above happens within my call to shutdownJuce_GUI, which is called in my DllMain in response to DLL_PROCESS_DETACH.

This is the MessageManager AsyncUpdate InternalTimerThread.
The above assertion is hit before the MessageManager is deleted by Juce. Looks like things might not be getting cleared-up by Juce in the right order, for some reason. :slight_smile:

The only thing that I’m not doing that I can think of that might be relevant, is not calling my equivalent of “doIdleCallback” (c.f. Jules’ VST Plugin adaptor implementation). My filter and the editor have both been created and cleaned up.

Anybody any pointers as to what I’m probably doing wrong?

TIA!!

Pete

The timer thread and message manager both get deleted as DeletedAtShutdown objects, so maybe it’s the creation order that’s wrong? In a normal app the messagemanager gets created first, so that it’ll get deleted last.

Hi Jules,

Turns out that the problem is that the message manager timer thread “wait for exit” times-out… as I think the underyling OS thread behind the Juce thread class instance has already died. I think. :slight_smile:

FWIW, the MessageManager constructor is called within setCurrentModuleInstanceHandle in response to code in the DllMain…:

BOOL APIENTRY DllMain (HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
{
  if (dwReason == DLL_PROCESS_ATTACH)
  {
    g_hModule = hModule;

//im_trace("initialiseJuce_GUI)...\n");

    PlatformUtilities::setCurrentModuleInstanceHandle (hModule);
    initialiseJuce_GUI();
 }

This then, within setTimeBeforeShowingWaitCursor, calls startTimer which creates an InternalTimerThread …

When I close Sonar, this gets called in my DllMain…

  if (dwReason == DLL_PROCESS_DETACH)
  {
//im_trace("shutdownJuce_GUI)...\n");

    shutdownJuce_GUI();
  }

… which calls deleteAll, and deletes first the timer and then the message manager with this code:

            if (okToDelete)
                delete deletee;

The problem here is that this code times out (!) when the timer is deleted!!! in juce_thread.cpp …

        if (timeOutMilliseconds != 0)
            waitForThreadToExit (timeOutMilliseconds);

… raising an exception.

The message manager later gets destructed.

I think what is happening is this: the “underlying” win32 thread represented by the juce::Thread class has actually died already, maybe by some shutdown code in Cakewalk.
In which case, I’d guess that this assertion isn’t very helpful!
The solution would be if the Juce method “waitForThreadToExit” could test the validity of the underlying OS thread handle, and if the thread is already dead then simply mark the thread as not running and return.

??? :slight_smile:

Pete

Yes, it sounds like Cakewalk is zapping the thread itself before giving us the chance to shut down. Very anti-social of it. If the plugin was in the middle of doing something important when its threads got killed, it could cause all sorts of problems.

I reckon the only workaround would be to shift the shutdown code into the close-plugin callback. I do something similar on the mac, keeping a reference count of the number of plugin instances open, and when it hits 0, juce gets shutdown (and obviously re-opened if another one is needed).

Hi Jules,

I’ve tried that, but Juce subquently got in a muddle in juce_win32_windowing.cpp when I resumed …

        if (wCreateWindowExW != 0)
            hwnd = wCreateWindowExW (exstyle, windowClassHolder->windowClassName, L"", type, 0, 0, 0, 0, 0, 0, 0, 0);
        else
            hwnd = CreateWindowEx (exstyle, windowClassHolder->windowClassName, _T(""), type, 0, 0, 0, 0, 0, 0, 0, 0);

        if (hwnd != 0)
        {

Where the value hwnd was NULL.

This was due this declaration in juce_win32_windowing.cpp …

    class WindowClassHolder    : public DeletedAtShutdown

I’ve tried to tidy-up better in WindowClassHolder (setting windowClassHolder to NULL in the destructor), but this just moved the problem elsewhere in the Juce library, where it instead ends-up dying due to (maybe?) the font stuff not being re-initialised properly…

Looks like the win32 stuff in Juce isn’t coded right now to work in the way you suggest. :slight_smile: Makes me wonder if my suggestion wrt threads is an easier way to go?

Toodle pip! :slight_smile:

Pete

… any thoughts? :slight_smile:

Ok, I’ve just had a quick scan through the code and checked in a bunch of tweaks that should sort out some of these re-initialisation problems, so you can see if that helps here…

Sweet! :slight_smile: Is there any way I can get hold of them to try them, or should I wait for a future release? ATBest! Pete

of course - just use SVN to grab the tip build from sourceforge.

Hi Jules, thanks for this, have done.

So that I have some idea what to look for, what is the general area of the change that you think might fix this? I can see lots of files have changed, but these are mainly adding throw() to lots of the methods. :slight_smile:

I presume that the change is one to do with initialisation (i.e. not any change related to host thread termination detection, as that doesn’t seem to have changed…)

TIA! :slight_smile:

Pete

There were a few places where I’d used static objects, and I’ve changed those to singletons that can get re-instantiated correctly. There’s an awful lot of changes, so if I were you I’d just use the tip rather than fishing through it. The tip’s actually pretty stable right now, probably better than the 1.43 release.

Thanks Jules, shall try it out then. Been out of the loop for the past 24 hours changing my own source control archive over from CVS to SVN. That was fun. :slight_smile: Worth the effort though, I never liked CVS…!

yeah, I’d only used cvs before, and loathed it too, but svn is really pretty good.

Jules, you’re too good. :slight_smile: That totally solved the problem. Respect all round. :slight_smile:

Ta very much. Luckily, I wasn’t exactly sure what the problem was, so that made it easier to fix.

Very droll. :slight_smile:

BTW, the Mac juce.xcodeconfig still looks for a really early SDK, and thefore needs to be modified by hand to work on most new Macs (AFAIK) or Juce building stops almost immediately.

Not sure what to suggest you might do to fix that, but just thought I should mention it (as I thought you mentioned you’d fixed that a while back…)

HTH!

Pete

You mean the 10.2 SDK? It does still come with XCode, but you need to tick its box when you install. I’ll probably ditch 10.2 compatibility at some point in the future, but there are still quite a few people using it.