/'===============================================================================================
 DSP Plugin Viewer Example
 Copyright (c), Firelight Technologies Pty, Ltd 2004-2011.

 This example ....
==============================================================================================='/

#include "windows.bi"
#include "win/commctrl.bi" 
#include "win/commdlg.bi" 
#include "crt.bi"

#include "fmodex/fmodex.bi"
#include "fmodex/fmod_errors.bi"
#include "dsppluginviewer.bi"

#define TITLE  "DSP Plugin Viewer Example. Copyright (c), Firelight Technologies Pty, Ltd 2004-2011."
#define GRAPHICWINDOW_WIDTH     256
#define GRAPHICWINDOW_HEIGHT    116
#define IDC_ACTIVEBUTTON        &h8801
#define IDC_REMOVEBUTTON        &h8802
#define IDC_CONFIGBUTTON        &h8803

#define Button_GetCheck(hwndCtl) cast(integer,cast(DWORD,SendMessage((hwndCtl),BM_GETCHECK,0,0)))
#define Button_SetCheck(hwndCtl,check) SendMessage((hwndCtl),BM_SETCHECK,cast(WPARAM,cast(integer,(check))),0)

/'
    Structures
'/
type Plugin_ as plugin
type PluginParam
    as Plugin_     ptr plugin
    as integer         index
    as HWND        sliderhwnd
    as HWND        namehwnd
    as HWND        valuehwnd
    as WNDPROC     oldtrackbarproc
    as integer         dragging
    as float       min, max
end type

type Plugin
    as Plugin     ptr next           ' linked list node.
    as Plugin     ptr prev           ' linked list node.
    as FMOD_DSP  ptr dsp
    as HWND        hwnd
    as HWND        activehwnd
    as HWND        removehwnd
    as HWND        confighwnd     ' button
    as HWND        configguihwnd
    as WNDPROC     oldpluginproc
    as integer         numparams
    as  integer         windowwidth
    as integer         windowheight
    as integer         configwidth
    as integer         configheight
    as bool        configactive
    as PluginParam ptr param      ' hopefully there are no more than 64 parameters in a plugin!
end type

#define SLIDERHEIGHT 20

/'
    Globals
'/
dim shared as HWND            gMainHwnd           = 0
dim shared as HWND            gPluginHwnd         = 0
dim shared as HINSTANCE       gHinstance          = 0
dim shared as FMOD_System   ptr gSystem             = 0
dim shared as FMOD_Sound    ptr gSound              = 0
dim shared as FMOD_Channel  ptr gChannel            = 0
dim shared as FMOD_Sound    ptr gSoundRecord        = 0
dim shared as FMOD_Channel  ptr gChannelRecord      = 0
dim shared as integer             gPluginWindowHeight = 5
dim shared as integer             gPluginWindowWidth  = 0
dim shared as WNDPROC         gOldProgressProc    = 0
dim shared as Plugin          gPluginHead
dim shared as BITMAPINFO      gGraphicWindowBitmap
dim shared as RGBQUAD         gGraphicWindowBitmapData(GRAPHICWINDOW_WIDTH * GRAPHICWINDOW_HEIGHT-1)


sub  ERRCHECK(byval result as FMOD_RESULT)
    if (result <> FMOD_OK) then
        dim as zstring * 1024   errstring = any

        sprintf(errstring, "FMOD error! (%d) %s", result, FMOD_ErrorString(result))

        MessageBox( NULL, errstring, "FMOD error!", MB_ICONHAND or MB_OK or MB_SYSTEMMODAL)
    end if
end sub

declare function FMOD_PluginInstanceProc(byval hwnd as HWND, byval msg as uinteger, byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT
declare function FMOD_TrackbarProc(byval hwnd as HWND, byval msg as uinteger, byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT
declare function FMOD_ProgressWindowProc(byval hwnd as HWND, byval msg as uinteger, byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT
declare function FMOD_PluginWindowProc(byval hwnd as HWND, byval msg as uinteger, byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

/'
[
	[DESCRIPTION]

	[PARAMETERS]
 
	[RETURN_VALUE]

	[REMARKS]

	[SEE_ALSO]
]
'/
sub PlotSpectrum(byval hdc as HDC, byval winx as integer, byval winy as integer, byval uselog as bool)
    dim as FMOD_RESULT result = any
    dim as integer count = any, count2 = any, numchannels = any
    dim as float spectrum(8-1,512-1) = any
    dim as float maximum
dim as integer x = any,y = any
    dim as HRESULT hr = any

    #define calcoffset(_x, _y) (GRAPHICWINDOW_WIDTH * (_y)) + (_x)

    result = FMOD_SYSTEM_GetSoftwareFormat(gSystem, 0, 0, @numchannels, 0, 0, 0)
    if (result <> FMOD_OK) then
        return
    end if
    
    /'
        Draw a black square with grey lines through it.
    '/
    clear(gGraphicWindowBitmapData(0), 0, GRAPHICWINDOW_WIDTH * GRAPHICWINDOW_HEIGHT * sizeof(RGBQUAD))

    for x=0  to GRAPHICWINDOW_WIDTH-1
        dim as RGBQUAD ptr pixel = any

        for y = 0 to  30-1
            pixel = @gGraphicWindowBitmapData(calcoffset(x, GRAPHICWINDOW_HEIGHT * y / 30))
            pixel->rgbRed   = &h40
            pixel->rgbGreen = &h40
            pixel->rgbBlue  = &h40
        next
    next

    for x=0 to GRAPHICWINDOW_WIDTH-1 step 64
        dim as RGBQUAD ptr pixel = any

        for y = 0 to GRAPHICWINDOW_HEIGHT-1
            pixel = @gGraphicWindowBitmapData(calcoffset(x, y))
            pixel->rgbRed   = &h40
            pixel->rgbGreen = &h40
            pixel->rgbBlue  = &h40
        next
    next

    for count = 0 to numchannels-1
        result = FMOD_SYSTEM_GetSpectrum(gSystem, @spectrum(count,0), 512, count, FMOD_DSP_FFT_WINDOW_TRIANGLE)    /' returns an array of 512 floats '/
        if (result <> FMOD_OK) then
            return
        end if


        scope    
            for count2=0 to 512-1
                if (spectrum(count,count2) > maximum) then
                    maximum = spectrum(count,count2)
end if
next
                end scope

        if (maximum > 0.0001f) then
            /'
                Spectrum graphic is 256 entries wide, and the spectrum is 512 entries.
                The upper band of frequencies at 44khz is pretty boring (ie 11-22khz), so we are only
                going to display the first 256 frequencies, or (0-11khz)
            '/
            for x = 0 to 512-1
                dim as RGBQUAD ptr pixel = any
                dim as float value = any, db = any

                value = spectrum(count,x)

                if (uselog) then
                    /'
                        1.0   = 0db
                        0.5   = -6db
                        0.25  = -12db
                        0.125 = -24db

                    '/
                    db = 10.0f * log10(value) * 2.0f

                    value = db
                    if (value < -150) then
                        value = -150
                    end if

                    value /= -150.0f
                    value = 1.0f - value

                    y = int(value * GRAPHICWINDOW_HEIGHT)
                                else
                    y = int(value / maximum * GRAPHICWINDOW_HEIGHT)
                end if
        
                if (y >= GRAPHICWINDOW_HEIGHT) then
                    y = GRAPHICWINDOW_HEIGHT - 1
                end if

                for count2 = 0 to y-1
                    dim as integer r = any, g = any, b = any

                    pixel = @gGraphicWindowBitmapData(calcoffset(x * GRAPHICWINDOW_WIDTH / 512, count2))

                    r = (count2 shl 1)
                    g = &hFF - (count2 shl 1)
                    b = &h1F

                    pixel->rgbRed   = iif(r > 255,255,r)
                    pixel->rgbGreen = iif(g > 255,255,g)
                    pixel->rgbBlue  = iif(b > 255,255,b)

                next
            next
        end if
    next

    hr = SetDIBitsToDevice( _
        hdc, _                                   ' Target device HDC
        winx, _
        winy, _
        GRAPHICWINDOW_WIDTH, _                   ' Destination width
        GRAPHICWINDOW_HEIGHT, _                  ' Destination height
        0, _                                     ' X source position
        0, _                                     ' Adjusted Y source position
        0, _                               ' Start scan line
        gGraphicWindowBitmap.bmiHeader.biHeight, _ ' Scan lines present
        @gGraphicWindowBitmapData(0), _               ' Image data
        @gGraphicWindowBitmap, _                  ' DIB header
        DIB_RGB_COLORS)                        ' Type of palette
end sub



/'
[
	[DESCRIPTION]

	[PARAMETERS]
 
	[RETURN_VALUE]

	[REMARKS]

	[SEE_ALSO]
]
'/
sub PlotOscilliscope(byval hdc as HDC, byval winx as integer, byval winy as integer)
    dim as integer channel = any, count = any, count2 = any, numchannels = any
    dim as float xoff = any, step_ = any
    dim as float  ptr src = any
    static as float OscBuffer(GRAPHICWINDOW_WIDTH-1) = any
    
    clear(gGraphicWindowBitmapData(0), 0, GRAPHICWINDOW_WIDTH * GRAPHICWINDOW_HEIGHT * sizeof(RGBQUAD))

    FMOD_System_GetSoftwareFormat(gSystem, 0, 0, @numchannels, 0, 0, 0)

    for channel = 0 to numchannels-1
        FMOD_System_getWaveData(gSystem, @OscBuffer(0), GRAPHICWINDOW_WIDTH, channel)

        /'
            xoff is the x position that is scaled lookup of the dsp block according to the graphical
            window size.
        '/
        xoff = 0
        step_ = 1

        src = @OscBuffer(0)
        for count=0 to GRAPHICWINDOW_WIDTH-1
            dim as RGBQUAD ptr pixel = any
            dim as integer x = any, y = any, y2 = any
    
            #define calcoffset2(_x, _y) (GRAPHICWINDOW_WIDTH * _y) + _x

            x  = xoff
            y  = int((src[x]           + 1.0f) / 2.0f * GRAPHICWINDOW_HEIGHT)
            y2 = int((src[x+step_] + 1.0f) / 2.0f * GRAPHICWINDOW_HEIGHT)

            y  = iif(y  < 0,0,iif(y  >= GRAPHICWINDOW_HEIGHT,GRAPHICWINDOW_HEIGHT-1,y))
            y2 = iif(y2 < 0,0 ,iif(y2 >= GRAPHICWINDOW_HEIGHT,GRAPHICWINDOW_HEIGHT-1,y2))

            if (y > y2) then
                dim as integer tmp = y
                y = y2
                y2 = tmp
            end if

            for count2=y to y2
                pixel = @gGraphicWindowBitmapData(calcoffset2(count, count2))
                pixel->rgbRed   = &hff
                pixel->rgbGreen = &hff
                pixel->rgbBlue  = &haf
            next

            xoff += step_
        next
    next

    SetDIBitsToDevice( _
        hdc, _                                   ' Target device HDC
        winx, _
        winy, _
        GRAPHICWINDOW_WIDTH, _                   ' Destination width
        GRAPHICWINDOW_HEIGHT, _                  ' Destination height
        0, _                                     ' X source position
        0, _                                     ' Adjusted Y source position
        0, _                               ' Start scan line
        gGraphicWindowBitmap.bmiHeader.biHeight, _ ' Scan lines present
        @gGraphicWindowBitmapData(0), _               ' Image data
        @gGraphicWindowBitmap, _                  ' DIB header
        DIB_RGB_COLORS)                        ' Type of palette
end sub



/'
[
	[DESCRIPTION]

	[PARAMETERS]
 
	[RETURN_VALUE]

	[REMARKS]

	[SEE_ALSO]
]
'/
function RefreshPluginList() as FMOD_RESULT
    dim as RECT        rect = any
    dim as SCROLLINFO  scrollinfo
    dim as Plugin     ptr plugin = any

    gPluginWindowWidth = 0
    gPluginWindowHeight = 5

    GetWindowRect(gPluginHwnd, @rect)
    InvalidateRect(gPluginHwnd, @rect, TRUE)

    /'
        Now re-add using new list.
    '/
    plugin = gPluginHead.next
    while (plugin <> @gPluginHead)
        MoveWindow(plugin->hwnd, 5, _
                                 gPluginWindowHeight, _
                                 iif(plugin->configwidth > plugin->windowwidth,plugin->configwidth,plugin->windowwidth), _
                                 plugin->windowheight + (iif(plugin->configactive,plugin->configheight,0)), _
                                 TRUE)

        gPluginWindowHeight += plugin->windowheight
        if (plugin->windowwidth > gPluginWindowWidth) then
            gPluginWindowWidth = plugin->windowwidth
        end if
        
        if (plugin->configactive) then
            gPluginWindowHeight += 5                           /' gap below sliders and gui '/
            gPluginWindowHeight += plugin->configheight
            if (plugin->configwidth + 5 > gPluginWindowWidth) then
                gPluginWindowWidth = plugin->configwidth
            end if
        end if

        gPluginWindowHeight += 5   /' gap below plugin '/

        plugin = plugin->next
    wend

    scrollinfo.cbSize = sizeof(SCROLLINFO)
    scrollinfo.fMask  = SIF_RANGE or SIF_PAGE or SIF_POS
    scrollinfo.nMin   = 0
    scrollinfo.nMax   = gPluginWindowHeight
    scrollinfo.nPage  = rect.bottom / 2
    scrollinfo.nPos   = 0
    SetScrollInfo(gPluginHwnd, SB_VERT, @scrollinfo, TRUE)

    clear(scrollinfo, 0, sizeof(SCROLLINFO))
    scrollinfo.cbSize = sizeof(SCROLLINFO)
    scrollinfo.fMask  = SIF_RANGE or SIF_PAGE or SIF_POS
    scrollinfo.nMin   = 0
    scrollinfo.nMax   = gPluginWindowWidth
    scrollinfo.nPage  = (rect.right - rect.left) - 35
    scrollinfo.nPos   = 0
    SetScrollInfo(gPluginHwnd, SB_HORZ, @scrollinfo, TRUE)

    return FMOD_OK
end function


/'
[
	[DESCRIPTION]

	[PARAMETERS]
 
	[RETURN_VALUE]

	[REMARKS]

	[SEE_ALSO]
]
'/
function RemovePlugin(byval plugin as Plugin ptr) as FMOD_RESULT
    dim as FMOD_RESULT result = any

    if (plugin->hwnd) then
        DestroyWindow(plugin->hwnd)
    end if
    
    plugin->next->prev = plugin->prev
    plugin->prev->next = plugin->next
    
    result = FMOD_DSP_Release(plugin->dsp)
    ERRCHECK(result)

    RefreshPluginList()

    delete [] plugin->param
    delete plugin   

    return FMOD_OK
end function


/'
[
	[DESCRIPTION]

	[PARAMETERS]
 
	[RETURN_VALUE]

	[REMARKS]

	[SEE_ALSO]
]
'/
function AddPlugin(byval pName as zstring ptr, byval displayname as zstring ptr) as FMOD_RESULT
    dim as FMOD_RESULT result = any
    dim as FMOD_PLUGINTYPE plugintype = any
    dim as Plugin ptr plugin = any
    dim as uinteger handle = any
    
    result = FMOD_SYSTEM_LoadPlugin(gSystem, pName, @handle,FMOD_PLUGINTYPE_DSP)
    if (result <> FMOD_OK) then
        return result
    end if

    result = FMOD_SYSTEM_GetPluginInfo(gSystem, handle, @plugintype, 0,0,0)
    if (result <> FMOD_OK) then
       return result
    end if

    if (plugintype <> FMOD_PLUGINTYPE_DSP) then
        FMOD_SYSTEM_UnloadPlugin(gSystem, handle)
        return FMOD_ERR_PLUGIN
     end if

    plugin = new Plugin
    if (plugin = 0) then
        return FMOD_ERR_MEMORY
    end if

    clear(*plugin, 0, sizeof(Plugin))
    
    result = FMOD_SYSTEM_CreateDSPByPlugin(gSystem, handle, @plugin->dsp)
    if (result <> FMOD_OK) then
        return result
    end if

    /'
        Add to end of circular linked list.
    '/
    plugin->prev = gPluginHead.prev
    gPluginHead.prev->next = plugin
    gPluginHead.prev = plugin
    plugin->next = @gPluginHead

    /'
        Add the plugin dialogue to the plugin window
    '/
    scope
        dim as RECT          rect = any
        dim as SCROLLINFO    scrollinfo
        dim as zstring * 256         pName = any, s = any
        dim as uinteger  version = 0
        dim as integer           count2 = any

        GetWindowRect(gPluginHwnd, @rect)

        FMOD_DSP_GetInfo(plugin->dsp, pName, @version, 0, @plugin->configwidth, @plugin->configheight)
        FMOD_DSP_GetNumParameters(plugin->dsp, @plugin->numparams)

        sprintf(s, "%s %1x.%2x", pName, version shr 16, version and &hFFFF)

        plugin->windowheight = ((plugin->numparams + 1) * (SLIDERHEIGHT + 5)) + 10
        plugin->windowwidth  = (rect.right - rect.left) - 35
        plugin->hwnd         = CreateWindow("STATIC",   s,      WS_BORDER or WS_CHILD or WS_CLIPSIBLINGS or WS_VISIBLE, 5,                         gPluginWindowHeight, plugin->windowwidth, plugin->windowheight, gPluginHwnd,  NULL,     0, 0)
        plugin->removehwnd   = CreateWindow("BUTTON", "Remove", WS_CHILD or WS_VISIBLE,                               plugin->windowwidth - 105, 5,                   100,                 20,                   plugin->hwnd, cast(hmenu,IDC_REMOVEBUTTON), 0, 0)
        plugin->confighwnd   = CreateWindow("BUTTON", "Config", WS_CHILD or WS_VISIBLE,                               plugin->windowwidth - 210, 5,                   100,                 20,                   plugin->hwnd, cast(HMENU,IDC_CONFIGBUTTON), 0, 0)
        plugin->activehwnd   = CreateWindow("BUTTON", "Active", WS_CHILD or WS_VISIBLE or BS_AUTOCHECKBOX,             plugin->windowwidth - 315, 5,                   100,                 20,                   plugin->hwnd, cast(HMENU,IDC_ACTIVEBUTTON), 0, 0)
        plugin->configactive = false

        SetWindowLongPtr(plugin->hwnd, GWLP_USERDATA, cast(LONG_PTR,plugin))
        plugin->oldpluginproc = cast(WNDPROC     ,GetWindowLongPtr(plugin->hwnd, GWLP_WNDPROC))
        SetWindowLongPtr(plugin->hwnd, GWLP_WNDPROC, cast(LONG_PTR,@FMOD_PluginInstanceProc))

        plugin->param = new PluginParam[plugin->numparams]
        clear(*plugin->param, 0, sizeof(PluginParam) * plugin->numparams)

        /'
            Now add sliders for each plugin
        '/
        for count2 = 0 to plugin->numparams-1
            dim as PluginParam ptr param = @plugin->param[count2]
            dim as zstring * 32 paramname = any, label = any, valuestr = any
            dim as float value = any, scale = any
            dim as integer x = 0, sliderwidth = any

            FMOD_DSP_GetParameterInfo(plugin->dsp, count2, paramname, label, 0, 0, @param->min, @param->max)
            FMOD_DSP_GetParameter(plugin->dsp, count2, @value, valuestr, 32)

            sliderwidth = (rect.right - rect.left) - 350

            param->plugin = plugin
            param->index  = count2
            scale = sliderwidth / abs(param->max - param->min) 

            sprintf(s, "%s %s", valuestr, label)
            x = 5
            param->namehwnd   = CreateWindow("STATIC",       paramname, WS_CHILD or WS_VISIBLE, x, 30 + (count2 * (SLIDERHEIGHT + 5)), 150-5,       SLIDERHEIGHT, plugin->hwnd, NULL, 0, 0)
            x += 145
            param->sliderhwnd = CreateWindow(TRACKBAR_CLASS, "",        WS_CHILD or WS_VISIBLE, x, 30 + (count2 * (SLIDERHEIGHT + 5)), sliderwidth, SLIDERHEIGHT, plugin->hwnd, NULL, 0, 0)
            x += sliderwidth
            param->valuehwnd  = CreateWindow("STATIC",       s,         WS_CHILD or WS_VISIBLE, x, 30 + (count2 * (SLIDERHEIGHT + 5)), 150-5,       SLIDERHEIGHT, plugin->hwnd, NULL, 0, 0)
            /'
	            Subclass the position slider so we can get the mouse messages and process them there
            '/
            SetWindowLongPtr(param->sliderhwnd, GWLP_USERDATA, cast(LONG_PTR,param))
            param->oldtrackbarproc = cast(WNDPROC     ,GetWindowLongPtr(param->sliderhwnd, GWLP_WNDPROC))
            SetWindowLongPtr(param->sliderhwnd, GWLP_WNDPROC,  cast(LONG_PTR,@FMOD_TrackbarProc))

            SendMessage(param->sliderhwnd, TBM_SETRANGE,    TRUE,   CAST(LPARAM,MAKELONG(0, sliderwidth)))
            SendMessage(param->sliderhwnd, TBM_SETPAGESIZE, 0,      cast(LPARAM,scale))
            SendMessage(param->sliderhwnd, TBM_SETPOS,      TRUE,   cast(LPARAM,( (value - param->min) / (param->max - param->min) * sliderwidth )))  

        next

        gPluginWindowHeight += (plugin->windowheight + 5)

        scrollinfo.cbSize = sizeof(SCROLLINFO)
        scrollinfo.fMask  = SIF_RANGE or SIF_PAGE or SIF_POS
        scrollinfo.nMin   = 0
        scrollinfo.nMax   = gPluginWindowHeight- 30
        scrollinfo.nPage  = rect.bottom / 2
        SetScrollInfo(gPluginHwnd, SB_VERT, @scrollinfo, TRUE)

        clear(scrollinfo, 0, sizeof(SCROLLINFO))
        scrollinfo.cbSize = sizeof(SCROLLINFO)
        scrollinfo.fMask  = SIF_RANGE or SIF_PAGE or SIF_POS
        scrollinfo.nMin   = 0
        scrollinfo.nMax   = gPluginWindowWidth
        scrollinfo.nPage  = (rect.right - rect.left) - 35
        SetScrollInfo(gPluginHwnd, SB_HORZ, @scrollinfo, TRUE)
    end scope

    return FMOD_OK
end function


/'
[
	[DESCRIPTION]

	[PARAMETERS]
 
	[RETURN_VALUE]

	[REMARKS]

	[SEE_ALSO]
]
'/
function FMOD_ProgressWindowProc(byval hwnd as HWND, byval message as uinteger, byval wParam as WPARAM, byval lParam as LPARAM ) as LRESULT
select case message
        case WM_LBUTTONDOWN, WM_MOUSEMOVE:
            dim as FMOD_RESULT  result = any
            dim as RECT         r = any
            dim as integer          width_ = any, xpos = LOWORD(lParam)  ' horizontal position of cursor 
            dim as uinteger length = any

            if (message = WM_MOUSEMOVE and wParam <> MK_LBUTTON) then
                exit select
            end if
        
            GetWindowRect(hwnd, @r)
            width_ = r.right - r.left
            
            result = FMOD_SOUND_GetLength(gSound, @length, FMOD_TIMEUNIT_MODORDER)
            if (result <> FMOD_OK) then
                FMOD_SOUND_GetLength(gSound, @length, FMOD_TIMEUNIT_MS)
            end if

            result = FMOD_CHANNEL_SetPosition(gChannel, length / width_ * xpos, FMOD_TIMEUNIT_MODORDER)
            if (result <> FMOD_OK) then
                FMOD_CHANNEL_SetPosition(gChannel,length / width_ * xpos, FMOD_TIMEUNIT_MS)
            end if
end select
    
	return CallWindowProc(gOldProgressProc, hwnd, message, wParam, lParam)
end function


/'
[
	[DESCRIPTION]

	[PARAMETERS]
 
	[RETURN_VALUE]

	[REMARKS]

	[SEE_ALSO]
]
'/
function FMOD_PluginInstanceProc(byval hwnd as HWND, byval msg as uinteger, byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT
    dim as WNDPROC oldpluginproc = any

    dim as Plugin ptr plugin = cast(Plugin ptr, GetWindowLongPtr(hwnd, GWLP_USERDATA))

    oldpluginproc = plugin->oldpluginproc

select case msg
        case WM_COMMAND:
select case LOWORD(wParam)
                case IDC_ACTIVEBUTTON:
                    if (Button_GetCheck(plugin->activehwnd)) then
                        FMOD_SYSTEM_AddDSP(gSystem, plugin->dsp, 0)
                    elseIf (Button_GetCheck(plugin->activehwnd) = 0) then
                        FMOD_DSP_Remove(plugin->dsp)
                    end if
                case IDC_REMOVEBUTTON:
                    RemovePlugin(plugin)
                case IDC_CONFIGBUTTON:
                    if (plugin->dsp) then
                        if (plugin->configactive) then
                            FMOD_DSP_ShowConfigDialog(plugin->dsp, hwnd, false)
                            DestroyWindow(plugin->configguihwnd)

                            plugin->configactive = false
                            RefreshPluginList()                       

                            plugin->configguihwnd = 0
                        else
                            plugin->configactive = true
                            RefreshPluginList()
                            plugin->configguihwnd = CreateWindow("STATIC", _
                                                                 "", _
                                                                 WS_CHILD or WS_CLIPSIBLINGS or WS_VISIBLE, _
                                                                 5,                         _
                                                                 plugin->windowheight, _
                                                                 plugin->configwidth, _
                                                                 plugin->configheight, _
                                                                 plugin->hwnd,  _
                                                                 NULL,     _
                                                                 0, _
                                                                 0)
                            FMOD_DSP_ShowConfigDialog(plugin->dsp, plugin->configguihwnd, true)
                        end if
                    end if


            end select
    end select

    return CallWindowProc(oldpluginproc, hwnd, msg, wParam, lParam)
end function


/'
[
	[DESCRIPTION]

	[PARAMETERS]
 
	[RETURN_VALUE]

	[REMARKS]

	[SEE_ALSO]
]
'/
function FMOD_TrackbarProc(byval hwnd as HWND, byval msg as uinteger, byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT
    dim as PluginParam ptr param = cast(PluginParam ptr,GetWindowLongPtr(hwnd, GWLP_USERDATA))
    dim as bool update = false

select case msg
        case WM_KEYUP,WM_KEYDOWN:
            update = true
        case WM_LBUTTONDOWN:
            param->dragging = TRUE
            update = true
        case WM_LBUTTONUP:
            param->dragging = FALSE
        case WM_MOUSEMOVE:
            if (param->dragging) then
                update = true
            end if
    end select

    if (update) then
        dim as RECT rect = any
        dim as integer position = SendMessage(hwnd, TBM_GETPOS, 0, 0)
        dim as float value = any
        dim as zstring * 32 valuestr = any
        dim as zstring * 32 label = any
        dim as zstring * 256 s = any
        dim as integer sliderwidth = any

        GetWindowRect(hwnd, @rect)

        sliderwidth = rect.right - rect.left

        value = position + 0.5f
        value /= sliderwidth
        value *= (param->max - param->min)
        value += param->min

        FMOD_DSP_GetParameterInfo(param->plugin->dsp, param->index, 0, label, 0, 0, 0, 0)
        FMOD_DSP_SetParameter(param->plugin->dsp, param->index, value)
        FMOD_DSP_GetParameter(param->plugin->dsp, param->index, 0, valuestr, 32)

        sprintf(s, "%s %s", valuestr, label)

        SendMessage(param->valuehwnd, WM_SETTEXT, 0, cast(LPARAM,@s))
    end if

    return CallWindowProc(param->oldtrackbarproc, hwnd, msg, wParam, lParam)
end function


/'
[
	[DESCRIPTION]

	[PARAMETERS]
 
	[RETURN_VALUE]

	[REMARKS]

	[SEE_ALSO]
]
'/
function FMOD_PluginWindowProc(byval hwnd as HWND, byval msg as uinteger, byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT
select case msg
        case WM_HSCROLL:        
            dim as integer lineWidth = 1

scope
                dim as integer OldPos = any, NewPos = any
select case LOWORD(wParam)
                case SB_PAGEDOWN,SB_LINEDOWN:           
                    OldPos = GetScrollPos (hwnd, SB_HORZ)           
                    SetScrollPos (hwnd, SB_HORZ, (OldPos+1), TRUE)           
                    NewPos = GetScrollPos (hwnd, SB_HORZ)           
                    ScrollWindow (hwnd, (OldPos-NewPos)*lineWidth, 0, NULL, NULL)         
                case SB_PAGEUP,SB_LINEUP:           
                    OldPos = GetScrollPos (hwnd, SB_HORZ)           
                    SetScrollPos (hwnd, SB_HORZ, (OldPos-1), TRUE)           
                    NewPos = GetScrollPos (hwnd, SB_HORZ)           
                    ScrollWindow (hwnd, (OldPos-NewPos)*lineWidth, 0, NULL, NULL)         
                case SB_THUMBPOSITION,SB_THUMBTRACK: 
                    OldPos = GetScrollPos (hwnd, SB_HORZ)           
                    NewPos = HIWORD (wParam)           
                    SetScrollPos (hwnd, SB_HORZ, NewPos, TRUE)           
                    ScrollWindow (hwnd, (OldPos-NewPos)*lineWidth, 0, NULL, NULL)         
end select
end scope
        case WM_VSCROLL:        
            dim as integer lineHeight = 1
scope
                dim as integer OldPos = any, NewPos = any
select case LOWORD(wParam)
                case SB_PAGEDOWN,SB_LINEDOWN:           
                    OldPos = GetScrollPos (hwnd, SB_VERT)           
                    SetScrollPos (hwnd, SB_VERT, (OldPos+1), TRUE)           
                    NewPos = GetScrollPos (hwnd, SB_VERT)           
                    ScrollWindow (hwnd, 0,(OldPos-NewPos)*lineHeight, NULL, NULL)         
                case SB_PAGEUP,SB_LINEUP:           
                    OldPos = GetScrollPos (hwnd, SB_VERT)           
                    SetScrollPos (hwnd, SB_VERT, (OldPos-1), TRUE)           
                    NewPos = GetScrollPos (hwnd, SB_VERT)           
                    ScrollWindow (hwnd, 0,(OldPos-NewPos)*lineHeight, NULL, NULL)         
                case SB_THUMBPOSITION,SB_THUMBTRACK: 
                    OldPos = GetScrollPos (hwnd, SB_VERT)           
                    NewPos = HIWORD (wParam)           
                    SetScrollPos (hwnd, SB_VERT, NewPos, TRUE)           
                    ScrollWindow (hwnd, 0, (OldPos-NewPos)*lineHeight, NULL, NULL)         
end select
end scope
end select

    return DefWindowProc (hwnd, msg, wParam, lParam) 
end function


/'
[
	[DESCRIPTION]

	[PARAMETERS]
 
	[RETURN_VALUE]

	[REMARKS]

	[SEE_ALSO]
]
'/
function FMOD_DlgProc(byval hwnd as HWND, byval msg as uinteger, byval wParam as WPARAM, byval lParam as LPARAM) as BOOL
    static as integer timerid = 0
 
select case msg
		case WM_INITDIALOG:
			/'
			    SET UP A PAINT TIMER FOR INTERFACE
			'/
			timerid = SetTimer(hwnd, 0, 10,0) 
			if (timerid = 0) then
    			MessageBox( NULL, "Too many timers in use", "Error", MB_ICONHAND or MB_OK or MB_SYSTEMMODAL)
    			return FALSE
			end if

            /'
                Set up the child plugin window
            '/
            scope
                dim as RECT        recordrect = any
                dim as RECT        rect = any
                dim as WNDCLASS    wc

                wc.style			= CS_HREDRAW or CS_VREDRAW
                wc.lpfnWndProc		= @FMOD_PluginWindowProc
                wc.hInstance		= gHinstance
                wc.hIcon			= 0
                wc.hCursor			= LoadCursor( NULL, IDC_ARROW )
                wc.hbrBackground	= cast(HBRUSH,GetStockObject(LTGRAY_BRUSH))
                wc.lpszMenuName		= 0
                wc.lpszClassName	= @"Plugin Window"

                RegisterClass(@wc)

                GetWindowRect(hwnd, @rect)
                GetWindowRect(GetDlgItem(hwnd, IDC_STATIC_RECORD), @recordrect)

                gPluginHwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "Plugin Window", "", WS_CHILD or WS_VSCROLL or WS_HSCROLL or WS_CLIPSIBLINGS or WS_VISIBLE, 5, recordrect.bottom, rect.right - rect.left - 25, (rect.bottom - rect.top) - recordrect.bottom - 65, hwnd, 0, 0, 0)
            end scope

            gPluginHead.next = @gPluginHead
            gPluginHead.prev = @gPluginHead

	        gOldProgressProc = cast(WNDPROC,GetWindowLongPtr(GetDlgItem(hwnd, IDC_PROGRESS1), GWLP_WNDPROC))
            SetWindowLongPtr(GetDlgItem(hwnd, IDC_PROGRESS1), GWLP_WNDPROC, cast(long,@FMOD_ProgressWindowProc))
return TRUE
        case WM_COMMAND:
select case LOWORD(wParam)
                case IDC_OPENBUTTON:
	                dim as OPENFILENAME ofn					/' common dialog box structure   '/
	                dim as zstring * MAX_PATH szDirName = any /' directory string              '/
	                dim as zstring * 20481 szFile = any /' filename string               '/
	                dim as zstring * 4096 szFileTitle = any /' filename string               '/

	                /'
                        Obtain the system directory name and store it in szDirName. 
                    '/
	                GetSystemDirectory(szDirName, sizeof(szDirName)) 

	                /'
                        Place the terminating null character in the szFile.
                    '/
	                szFile[0] = 0
                    szFileTitle[0] = 0

	                /'
                        Set the members of the OPENFILENAME structure.
                    '/
	                ofn.lStructSize       = sizeof(OPENFILENAME) 
	                ofn.hwndOwner         = hwnd 
	                ofn.lpstrTitle        = @!"Open\0"
	                ofn.lpstrFilter       = @!"All audio files (*.*)\0*.*\0\0"
	                ofn.lpstrCustomFilter = NULL
	                ofn.nFilterIndex      = 1 
	                ofn.lpstrFile         = @szFile 
	                ofn.nMaxFile          = 20480     /' Huge value allows many files to be multi-selected '/
	                ofn.lpstrFileTitle    = @szFileTitle
	                ofn.nMaxFileTitle     = 2048
	                ofn.lpstrInitialDir   = @!".\0"
	                ofn.Flags             = OFN_EXPLORER or OFN_PATHMUSTEXIST or OFN_FILEMUSTEXIST 

	                /'
                        Display the Open dialog box.
                    '/
	                if (GetOpenFileName(@ofn)) then
                        dim as FMOD_RESULT result

                        if (gSound) then
                            if (gChannel) then
                                FMOD_CHANNEL_Stop(gChannel)
                                gChannel = 0
                                SendMessage(GetDlgItem(hwnd, IDC_PLAY), WM_SETTEXT, 0, cast(LPARAM, @"Play"))
                            end if
                            FMOD_SOUND_Release(gSound)
                        end if
                        result = FMOD_SYSTEM_CreateStream(gSystem, ofn.lpstrFile, FMOD_2D or FMOD_SOFTWARE, 0, @gSound)
                        ERRCHECK(result)

                        SendMessage(GetDlgItem(hwnd, IDC_EDIT1), WM_SETTEXT, 0, cast(LPARAM,ofn.lpstrFile))
                    end if
                case IDC_PLAY:
                    dim as BOOL isplaying = false
    
                    if (gChannel) then
                        FMOD_CHANNEL_IsPlaying(gChannel, @isplaying)
                    end if

                    if (isplaying or  gSound = 0) then
                        if (gChannel) then
                            FMOD_CHANNEL_Stop(gChannel)
                            gChannel = 0
                        end if
                        SendMessage(GetDlgItem(hwnd, IDC_PLAY), WM_SETTEXT, 0, cast(LPARAM, @"Play"))
                                        else
                        FMOD_SYSTEM_PlaySound(gSystem, FMOD_CHANNEL_FREE, gSound, false, @gChannel)
                        SendMessage(GetDlgItem(hwnd, IDC_PLAY), WM_SETTEXT, 0, cast(LPARAM, @"Stop"))
                    end if
                case IDC_PAUSE:
                    if (gChannel) then
                        dim as bool paused = any

                        FMOD_CHANNEL_GetPaused(gChannel,@paused)
                        if (paused) then
                            FMOD_CHANNEL_SetPaused(gChannel, false)
                            SendMessage(GetDlgItem(hwnd, IDC_PAUSE), WM_SETTEXT, 0, cast(LPARAM, @"Pause"))
                        else
                            FMOD_CHANNEL_SetPaused(gChannel, true)
                            SendMessage(GetDlgItem(hwnd, IDC_PAUSE), WM_SETTEXT, 0, cast(LPARAM, @"UnPause"))
                        end if
                    end if
                case IDC_RECORD:
                    if (gSoundRecord = 0) then
                        dim as FMOD_RESULT result = any
                        dim as FMOD_OUTPUTTYPE foutput = any
                        dim as FMOD_CREATESOUNDEXINFO exinfo

                        dim as FMOD_MODE mode = FMOD_2D or FMOD_OPENUSER

                        mode or= FMOD_LOOP_NORMAL
                        mode or= FMOD_SOFTWARE
  
                        #define USERLENGTH (44100 * 5)
             
                        exinfo.cbsize           = sizeof(FMOD_CREATESOUNDEXINFO)
                        exinfo.length           = USERLENGTH * 2 * sizeof(short)
                        exinfo.numchannels      = 2
                        exinfo.defaultfrequency = 44100
                        exinfo.format           = FMOD_SOUND_FORMAT_PCM16

                        result = FMOD_SYSTEM_CreateSound(gSystem, 0, mode, @exinfo, @gSoundRecord)
                        ERRCHECK(result)

                        result = FMOD_SYSTEM_RecordStart(gSystem, 0, gSoundRecord, true)
                        ERRCHECK(result)

                        FMOD_SYSTEM_GetOutput(gSystem, @foutput)
                        if (foutput <> FMOD_OUTPUTTYPE_ASIO) then
                            Sleep(100)
                        end if

                        result = FMOD_SYSTEM_PlaySound(gSystem, FMOD_CHANNEL_FREE, gSoundRecord, false, @gChannelRecord)
                        ERRCHECK(result)

                        SendMessage(GetDlgItem(hwnd, IDC_RECORD), WM_SETTEXT, 0, cast(LPARAM, @"Stop Recording"))
                    else
                        FMOD_SYSTEM_RecordStop(gSystem, 0)

                        FMOD_CHANNEL_Stop(gChannelRecord)
                        gChannelRecord = 0
                        FMOD_SOUND_Release(gSoundRecord)
                        gSoundRecord = 0

                        SendMessage(GetDlgItem(hwnd, IDC_RECORD), WM_SETTEXT, 0, cast(LPARAM, @"Record"))
                    end if
                case IDC_ADDPLUGIN:
	                dim as OPENFILENAME	ofn					/' common dialog box structure   '/
	                dim as zstring * MAX_PATH szDirName = any /' directory string              '/
	                dim as zstring * 20481 szFile = any /' filename string               '/
	                dim as zstring * 4096 szFileTitle = any /' filename string               '/

	                /'
                        Obtain the system directory name and store it in szDirName. 
                    '/
	                GetSystemDirectory(szDirName, sizeof(szDirName)) 

	                /'
                        Place the terminating null character in the szFile.
                    '/
	                szFile[0] = 0
                    szFileTitle[0] = 0

	                /'
                        Set the members of the OPENFILENAME structure.
                    '/
	                ofn.lStructSize       = sizeof(OPENFILENAME) 
	                ofn.hwndOwner         = hwnd 
	                ofn.lpstrTitle        = @!"Open\0"
                    ofn.lpstrFilter       = @!"FMOD Plugins (dsp*.dll)\0dsp*.dll\0VST Plugins (*.dll)\0*.dll\0All files (*.*)\0*.*\0\0"
	                ofn.lpstrCustomFilter = NULL
	                ofn.nFilterIndex      = 1 
	                ofn.lpstrFile         = @szFile 
	                ofn.nMaxFile          = 20480     /' Huge value allows many files to be multi-selected '/
	                ofn.lpstrFileTitle    = @szFileTitle
	                ofn.nMaxFileTitle     = 2048
	                ofn.lpstrInitialDir   = @!"plugins\0"
	                ofn.Flags             = OFN_EXPLORER or OFN_PATHMUSTEXIST or OFN_FILEMUSTEXIST or OFN_ALLOWMULTISELECT 

	                /'
                        Display the Open dialog box.
                    '/
	                if (GetOpenFileName(@ofn)) then
		                dim as zstring ptr path = ofn.lpstrFile
		                dim as zstring ptr fname = ofn.lpstrFile
		                dim as zstring * 256 name_ = any

		                /'
                            Single file
                        '/
		                if (ofn.nFileOffset) then
			                /'
                                Skip to the first filename
                            '/
			                fname +=ofn.nFileOffset
			                *(fname-1) = 0		/' clear the backslash before the filename so the loop below handles it '/
               else /'                             Multiple files '/
			                while (*fname)	/' search to the first filename '/
fname+=1
wend
		                end if

		                do 
                            dim as FMOD_RESULT result = any

			                /'
                                Put path in name
                            '/
                            sprintf(name_, "%s%s%s", path, "\\", fname)

			                /'
                                Open the file.
                            '/
                            result = AddPlugin(name_, fname)
                            ERRCHECK(result)

			                while (*fname)
fname+=1
wend

                            Sleep(1)

		                loop  while (*fname)
                    end if
end select
		case WM_CLOSE:
            dim as FMOD_RESULT result = any

			KillTimer(hwnd, timerid)

            /'
                The timer doesnt die immediately, sleep for a bit to let it die so we dont free streams then the timer tries to access them
            '/
            Sleep(200)

            /'
                Shutdown FMOD
            '/
            if (gSound) then
                result = FMOD_SOUND_Release(gSound)
                ERRCHECK(result)
            end if
            if (gSystem) then
                result = FMOD_SYSTEM_Close(gSystem)
                ERRCHECK(result)

                result = FMOD_SYSTEM_Release(gSystem)
                ERRCHECK(result)
            end if

			EndDialog(hwnd,0)
            PostQuitMessage(0)
return TRUE
		case WM_TIMER :
			dim as HDC hdc = GetDC(hwnd)
            dim as RECT        rect = any
            
            GetWindowRect(GetDlgItem(gMainHwnd,IDC_STATIC_ANALYZER), @rect)

            FMOD_SYSTEM_Update(gSystem)		

            PlotSpectrum(hdc,     (((rect.right  - rect.left) / 4) -      (GRAPHICWINDOW_WIDTH  / 2)), _
                                  (((rect.bottom - rect.top)  / 2) -      (GRAPHICWINDOW_HEIGHT / 2)), true)
            PlotOscilliscope(hdc, ((((rect.right - rect.left) / 4) * 3) - (GRAPHICWINDOW_WIDTH  / 2)), _
                                  (((rect.bottom - rect.top)  / 2) -      (GRAPHICWINDOW_HEIGHT / 2)))
            
            if (gChannel) then
                dim as FMOD_RESULT result = any
                dim as uinteger currtime = any, length = any
                dim as bool playing = any

                result = FMOD_CHANNEL_GetPosition(gChannel, @currtime, FMOD_TIMEUNIT_MODORDER)
                if (result <> FMOD_OK) then
                    FMOD_CHANNEL_GetPosition(gChannel, @currtime, FMOD_TIMEUNIT_MS)
                end if

                result = FMOD_SOUND_GetLength(gSound, @length, FMOD_TIMEUNIT_MODORDER)
                if (result <> FMOD_OK) then
                    FMOD_SOUND_GetLength(gSound, @length, FMOD_TIMEUNIT_MS)
                end if

                SendMessage(GetDlgItem(gMainHwnd,IDC_PROGRESS1), PBM_SETRANGE, 0, MAKELPARAM(0, 1000) )
 			    SendMessage(GetDlgItem(gMainHwnd,IDC_PROGRESS1), PBM_SETPOS, cast(WPARAM,currtime / length * 1000.0f), 0)

                FMOD_CHANNEL_IsPlaying(gChannel, @playing)
                if (playing = 0) then
                    gChannel = 0
                    SendMessage(GetDlgItem(hwnd, IDC_PLAY), WM_SETTEXT, 0, cast(LPARAM,@"Play"))
                end if
            end if

			ReleaseDC(hwnd, hdc)
	end select

return FALSE
end function


/'
[
	[DESCRIPTION]

	[PARAMETERS]
 
	[RETURN_VALUE]

	[REMARKS]

	[SEE_ALSO]
]
'/
function FMOD_OutputSelectProc(byval hwnd as HWND, byval msg as uinteger, byval wParam as WPARAM, byval lParam as LPARAM) as BOOL
    static as integer selected = 0
 
select case msg
		case WM_INITDIALOG:
            Button_SetCheck(GetDlgItem(hwnd,IDC_DSOUND), TRUE)
			return TRUE
        case WM_COMMAND:
select case LOWORD(wParam)
                case IDOK:
                    if (Button_GetCheck(GetDlgItem(hwnd,IDC_DSOUND))) then
                        selected = 0
                    end if
                    if (Button_GetCheck(GetDlgItem(hwnd,IDC_WINMM))) then
                        selected = 1
                    end if
                    if (Button_GetCheck(GetDlgItem(hwnd,IDC_ASIO))) then
                        selected = 2
                    end if

			        EndDialog(hwnd, selected)
                case IDCANCEL:
	        		EndDialog(hwnd, -1)
                    PostQuitMessage(0)
end select
            return TRUE
		case WM_CLOSE:
			EndDialog(hwnd, -1)
            PostQuitMessage(0)
			return TRUE
		end select

	return FALSE
end function


/'
[
	[DESCRIPTION]

	[PARAMETERS]
 
	[RETURN_VALUE]

	[REMARKS]

	[SEE_ALSO]
]
'/
function Initialize(byval hinst as HINSTANCE, byval lpCmdLine as LPSTR) as integer
    dim as FMOD_RESULT result = any
    dim as uinteger version = any
    dim as integer retval = any

    /'
        Initialise FMOD
    '/

    result = FMOD_Memory_Initialize(allocate(10 * 1024*1024), 10 * 1024*1024, 0, 0, 0,0)
    ERRCHECK(result)

    result = FMOD_System_Create(@gSystem)
    ERRCHECK(result)

    result = FMOD_SYSTEM_GetVersion(gSystem, @version)
    ERRCHECK(result)

    if (version < FMOD_VERSION) then
        MessageBox(GetForegroundWindow(), "INCORRECT DLL VERSION!!", "FMOD ERROR", MB_OK)
    end if

    result = FMOD_SYSTEM_SetPluginPath(gSystem, "plugins")
    ERRCHECK(result)
    
    /'
        Display selection dialog
    '/
	retval = DialogBox(hinst, MAKEINTRESOURCE(IDD_OUTPUTSELECT), GetDesktopWindow(), @FMOD_OutputSelectProc)
    if (retval < 0) then
        return FALSE
    end if

select case retval
        case 0: 
            FMOD_SYSTEM_SetOutput(gSystem, FMOD_OUTPUTTYPE_DSOUND) 
        case 1: 
            FMOD_SYSTEM_SetOutput(gSystem, FMOD_OUTPUTTYPE_WINMM) 
        case 2: 
            FMOD_SYSTEM_SetOutput(gSystem, FMOD_OUTPUTTYPE_ASIO) 
    end select

    /'
        Set the output rate to 44100 instead of the default 48000, because some winamp plugins wont work unless they are 44100.
    '/
    result = FMOD_SYSTEM_SetSoftwareFormat(gSystem, 44100, FMOD_SOUND_FORMAT_PCM16, 0, 0, FMOD_DSP_RESAMPLER_LINEAR)
    ERRCHECK(result)

    /'
        Initialize FMOD.
    '/
    result = FMOD_SYSTEM_Init(gSystem, 32, FMOD_INIT_NORMAL, 0)
    ERRCHECK(result)
    if (result <> FMOD_OK) then
        return FALSE
    end if

    /'
        Create window and graphics 
    '/
	gMainHwnd = CreateDialog(hinst, MAKEINTRESOURCE(IDD_DIALOG), GetDesktopWindow(), @FMOD_DlgProc)

	ShowWindow(gMainHwnd, SW_SHOW)

    SetWindowText(gMainHwnd, TITLE)

    ' make the header
    ZeroMemory( @gGraphicWindowBitmap, sizeof( BITMAPINFO ) )
    gGraphicWindowBitmap.bmiHeader.biSize = sizeof( gGraphicWindowBitmap.bmiHeader )
    gGraphicWindowBitmap.bmiHeader.biWidth  = GRAPHICWINDOW_WIDTH
    gGraphicWindowBitmap.bmiHeader.biHeight = GRAPHICWINDOW_HEIGHT
    gGraphicWindowBitmap.bmiHeader.biPlanes = 1
    gGraphicWindowBitmap.bmiHeader.biBitCount = 32
    gGraphicWindowBitmap.bmiHeader.biCompression = BI_RGB
    gGraphicWindowBitmap.bmiHeader.biSizeImage = 0
    gGraphicWindowBitmap.bmiHeader.biXPelsPerMeter = 0
    gGraphicWindowBitmap.bmiHeader.biYPelsPerMeter = 0
    gGraphicWindowBitmap.bmiHeader.biClrUsed = 0
    gGraphicWindowBitmap.bmiHeader.biClrImportant = 0

	return TRUE
end function


' program start
    dim as MSG          msg = any

gHinstance = GetModuleHandle(NULL)

    /'
        Create interface and start message loop
    '/
    if (Initialize(gHinstance, GetCommandLine())= 0) then end FALSE

  	while (GetMessage( @msg, 0, 0, 0 ))
if(IsDialogMessage(gMainHwnd, @msg ) ) then continue while
    	TranslateMessage( @msg )
      	DispatchMessage( @msg )
  	wend

	end msg.wParam
