Hi,

This is a summary of everything to show how I would like an event-driven
sound server would work on Windows. Anything I have said before may have
been wrong, but everything I say below I have verified as being correct. :)

You haven't yet said if you are happy with this idea, but I would like
messages posted from wherever sound events, commands, and data first
originate from in FreeSCI.

We would use PostMessage() for a number of reasons. Firstly, messages are
guaranteed to get through since they go into a queue. It also works
correctly with the message-loop-in-server model below, which processes
messages when we want, not when Windows wants. It also posts messages to
where you tell them to go (unlike SendNotifyMessage()!). The problem I
previously mentioned about passing pointers and losing references to them
can occur with any of the message functions we would want to use
(PostMessage(), SendNotifyMessage()) as we want to use ones that return
immediately. We must keep this in mind.

Timing will be sweet with no need for another thread (on Windows). The
function SetTimer() will cause Windows to send a WM_TIMER message to a
specified thread every XXX milliseconds. However if this is not high enough
resolution, we can use a separate thread and alternative timing functions
quite simply. At the moment, I would have the timer rounded up to go off
every 17 milliseconds since I can only use integers. Is this a problem?
Would 16 ms be better?

The current model I'm using does not use a message callback function but
processes everything in the main thread. The example you gave is what I
would have suggested as well and detail below. While you said that it wasn't
particularly elegant, it is pre-emptive multi-tasking and you can't get more
efficient than that on Windows. It would definitely be an advance on how
things are working at the moment on this platform - both in CPU-usage and
timing.

So here's roughly what the code would look like:

win32_sound_init()
{
    DWORD dwSoundTId;
    WNDCLASS wc;

    /* register window class */
    memset (&wc, 0, sizeof(WNDCLASS));
    wc.lpfnWndProc = SoundWndProc;
    sound_wnd_inst = GetModuleHandle(NULL);
    wc.hInstance = sound_wnd_inst;    /* thread instance */
    wc.lpszClassName = g_szSoundWndClass;
    RegisterClass(&wc);

    sound_thread = CreateThread(NULL, /* handle not inheritable */
                                0,    /* use default stack size */
                                win32_sound_server, /* thread start function
*/
                                0,    /* cb function parameter */
                                0,   /* thread runs immediately */
                                &dwSoundTId); /* pointer to id of thread */
}

/* unused message callback function */
LRESULT CALLBACK
SoundWndProc (HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
    printf("warning: message processed incorrectly\n");
    return DefWindowProc (hWnd, nMsg, wParam, lParam);
}

/* sound server thread begins here */
DWORD WINAPI
win32_sound_server(LPVOID lpP)
{
    MSG msg;    /* temp msg storage */
    BOOL bRet;  /* stores return value of GetMessage() */
    DECLARE_MESSAGES();

    /* create our 'window' so can receive messages */
    sound_wnd = CreateWindow(g_szSoundWndClass,
                             "Sound Thread",
                             ( WS_DISABLED | WS_POPUP ),
                             CW_USEDEFAULT,
                             CW_USEDEFAULT,
                             CW_USEDEFAULT,
                             CW_USEDEFAULT,
                             NULL,
                             NULL,
                             NULL,
                             NULL);

    /* create timer */
    SetTimer(sound_wnd,   /* send timer messages here */
             sound_timer, /* timer identifier (ptr to uint) */
             17,          /* time-out value in milliseconds (uint) */
             NULL);       /* post WM_TIMER msg when done */

    /* start the message loop... */
    /* only wakes up when gets a message */
    while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
    {
        if (bRet == -1)
        {
            /* handle the error and possibly exit */
        }
        else if (&msg.message == WM_TIMER)
        {
            /* do standard sound processing */
        }
        else if (&msg.message == UWM_SOUND_COMMAND_SET_VOLUME)
        {
            master_volume = &msg.wParam * 100 / 15; /* scale to % */
            midi_volume(master_volume);
        }

        /* ... */

        else if ( (&msg.message == UWM_SOUND_COMMAND_SHUTDOWN) ||
                  (&msg.message == WM_DESTROY) )
        {
            /* clean up and quit */
            /* ... */
            CloseHandle(...);
            KillTimer(...);
            PostQuitMessage(0);    /* thread terminates */
        }
        else
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    /* On finish, return the exit code to the system. */
    return msg.wParam;
}


How's all that look? I can code this up in prototype form to test it out if
you're happy with it. I still need to know where messages would be
posted/sent from though.

Cheers!

Alex.



Reply via email to