/*---------------------------------------------------
   BACHTOCC.o2bas -- Bach Toccata in D Minor (First Bar)
                 (c) Charles Petzold, 1998
  ---------------------------------------------------*/
'Ported to Oxygenbasic

$ filename "BACHTOCC.exe"

'uses rtl32
'uses rtl64

uses corewin

'uses minmidi
'octave 0..10
extern lib "Winmm.dll"

sys midiOutOpen(sys *phmo, uDeviceID,dwCallback, dwInstance,fdwOpen)
sys midiOutShortMsg( sys hmo, dwMsg)
sys midiOutClose( sys hmo)
sys midiOutReset(sys hmo)

% COLOR_WINDOW = 5
% MIDIMAPPER = 0xFFFFFFFF

'=======================
'MAIN CODE
'=======================

sys hInstance = GetModuleHandle(0)
'========================================'


string szClassName = "BachTocc"
string WindowTitle = "Bach Toccata in D Minor (First Bar)"


% ID_TIMER = 1


function MidiOutMsg(sys hMidi, int iStatus, iChannel, iData1,  iData2) as dword
   dword dwMessage = iStatus + iChannel + (iData1 * 0x100) + (iData2 * 0x10000)
   return midiOutShortMsg(hMidi, dwMessage)
end function


int iDur = 1
int iNote = 2

int noteseq[] =
                {110, 69, 81, 
                 110, 67, 79,
                 990, 69, 81,
                 220, -1, -1,
                 110, 67, 79,
                 110, 65, 77,
                 110, 64, 76,
                 110, 62, 74,
                 220, 61, 73,
                 440, 62, 74,
                 1980,-1, -1,
                 110, 57, 69,
                 110, 55, 67,
                 990, 57, 69,
                 220, -1, -1,
                 220, 52, 64,
                 220, 53, 65,
                 220, 49, 61,
                 440, 50, 62,
                 1980, -1, -1}

sys hMidiOut
int iIndex = 1


function WndProc(sys hwnd, Message, wParam, lParam) as sys callback
   int i

   switch Message

   case WM_CREATE

     // Open MIDIMAPPER device                                                           
     if midiOutOpen(hMidiOut, MIDIMAPPER, 0, 0, 0) then
        MessageBeep(MB_ICONEXCLAMATION)
        MessageBox(hwnd, "Cannot open MIDI output device!",
                   szClassname, MB_ICONEXCLAMATION or MB_OK)
        return -1
     end if

     // Send Program Change messages for "Church Organ"         
     'MidiOutMsg(hMidiOut, 0xC0,  0, 19, 0)
     'Send Program Change messages for "Piccolo"         
     MidiOutMsg(hMidiOut, 0xC0,  0, 72, 0)
     SetTimer(hwnd, ID_TIMER, 1000, NULL)

   case WM_TIMER

     // Loop for 2-note polyphony         
     for i = 1 to 2                         
        // Note Off messages for previous note
        if iIndex <> 1 and noteseq[iIndex-iDur-iNote + i] <> -1 then
           MidiOutMsg(hMidiOut, 0x80,  0,
                      noteseq[iIndex-iDur-iNote +i], 0)
        end if
        // Note On messages for new note
        if iIndex <= 20*(iDur+iNote)  and
                     noteseq[iIndex +i] <> -1 then
           MidiOutMsg(hMidiOut, 0x90,  0,
                      noteseq[iIndex +i], 127)
        end if                             
     next i

     if iIndex <= 20*(iDur+iNote) then
       SetTimer(hwnd, ID_TIMER, noteseq[iIndex] - 1, NULL)
       iIndex = iIndex + iDur + iNote
     else
       KillTimer(hwnd, ID_TIMER)
       DestroyWindow (hwnd)   
     end if

   case WM_DESTROY
       midiOutReset(hMidiOut)
       midiOutClose(hMidiOut)
       PostQuitMessage(0)

   case else
       return DefWindowProc(hwnd, Message, wParam, lParam)

   end switch

   return 0
end function


function WinMain(sys nCmdShow) as sys

   WNDCLASSEX wc
   MSG Msg

   sys hwnd

   wc.cbSize        = sizeof(WNDCLASSEX)
   wc.style         = 0
   wc.lpfnWndProc   = @WndProc
   wc.cbClsExtra    = 0
   wc.cbWndExtra    = 0
   wc.hInstance     = hInstance
   wc.hIcon         = LoadIcon (NULL, IDI_APPLICATION)
   wc.hCursor       = LoadCursor(NULL, IDC_ARROW)
   wc.hbrBackground = COLOR_WINDOW+1
   wc.lpszMenuName  = NULL
   wc.lpszClassName = strptr(szClassName)
   wc.hIconSm       = LoadIcon (NULL, IDI_APPLICATION)

   if not RegisterClassEx(&wc) then
      MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONERROR)
      return 0
   end if

   hwnd = CreateWindowEx(
              WS_EX_CLIENTEDGE,
              szClassName,
              WindowTitle,
              WS_OVERLAPPEDWINDOW,
              CW_USEDEFAULT, CW_USEDEFAULT, // x, y positon
                       500,           300,  // x size, y size
              NULL,
              NULL,   // window menu handle
              hInstance, NULL)

   if hwnd = NULL then
     MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONERROR)
     return 0
   end if

   ShowWindow(hwnd, nCmdShow)
   UpdateWindow(hwnd)

   sys bRet
   do while (bRet := GetMessage(&Msg, NULL, 0, 0))
       TranslateMessage(&Msg)
       DispatchMessage(&Msg)
   wend
   
   return Msg.wParam
end function

'WINDOWS START
'=============

WinMain(SW_NORMAL)