/*
 * windows.cs
 * Copyright (c) 2009 kbinani
 *
 * This file is part of bocoree.
 *
 * bocoree is free software; you can redistribute it and/or
 * modify it under the terms of the BSD License.
 *
 * bocoree is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 */
using System;
using System.Runtime.InteropServices;

namespace bocoree {

    using MMRESULT = System.UInt32;
    using HMIDIIN = System.Int32;
    using DWORD = System.UInt32;
    using UINT = System.UInt32;
    using WORD = System.UInt16;
    using BYTE = System.Byte;

    public delegate void delegateWaveOutProc( IntPtr hwo, uint uMsg, uint dwInstance, uint dwParam1, uint dwParam2 );

    [StructLayout( LayoutKind.Sequential, Pack = 1 )]
    public struct JOYINFO {
        [MarshalAs( UnmanagedType.U4 )]
        public uint wXpos;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wYpos;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wZpos;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wButtons;
    }

    [StructLayout( LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1 )]
    public struct JOYCAPSW {
        const int MAXPNAMELEN = 32;
        const int MAX_JOYSTICKOEMVXDNAME = 260;
        [MarshalAs( UnmanagedType.U2 )]
        public ushort wMid;
        [MarshalAs( UnmanagedType.U2 )]
        public ushort wPid;
        [MarshalAs( UnmanagedType.ByValTStr, SizeConst = MAXPNAMELEN )]
        public string szPname;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wXmin;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wXmax;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wYmin;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wYmax;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wZmin;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wZmax;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wNumButtons;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wPeriodMin;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wPeriodMax;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wRmin;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wRmax;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wUmin;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wUmax;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wVmin;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wVmax;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wCaps;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wMaxAxes;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wNumAxes;
        [MarshalAs( UnmanagedType.U4 )]
        public uint wMaxButtons;
        [MarshalAs( UnmanagedType.ByValTStr, SizeConst = MAXPNAMELEN )]
        public string szRegKey;
        [MarshalAs( UnmanagedType.ByValTStr, SizeConst = MAX_JOYSTICKOEMVXDNAME )]
        public string szOEMVxD;
    }

    [StructLayout( LayoutKind.Sequential, Pack = 1 )]
    public struct JOYINFOEX {
        public uint dwSize;
        public uint dwFlags;
        public uint dwXpos;
        public uint dwYpos;
        public uint dwZpos;
        public uint dwRpos;
        public uint dwUpos;
        public uint dwVpos;
        public uint dwButtons;
        public uint dwButtonNumber;
        public uint dwPOV;
        public uint dwReserved1;
        public uint dwReserved2;
    }

    [StructLayout( LayoutKind.Sequential, Pack = 1 )]
    public struct WAVEFORMATEX {
        public ushort wFormatTag;
        public ushort nChannels;
        public uint nSamplesPerSec;
        public uint nAvgBytesPerSec;
        public ushort nBlockAlign;
        public ushort wBitsPerSample;
        public ushort cbSize;
    }

    [StructLayout( LayoutKind.Sequential, Pack = 1 )]
    public struct WAVEHDR {
        public IntPtr lpData; // pointer to locked data buffer
        public uint dwBufferLength; // length of data buffer
        public uint dwBytesRecorded; // used for input only
        public IntPtr dwUser; // for client's use
        public uint dwFlags; // assorted flags (see defines)
        public uint dwLoops; // loop control counter
        public IntPtr lpNext; // PWaveHdr, reserved for driver
        public uint reserved; // reserved for driver
    }

    /*typedef struct mmtime_tag
{
    UINT            wType;      // indicates the contents of the union
    union
    {
        DWORD       ms;         // milliseconds
        DWORD       sample;     // samples
        DWORD       cb;         // byte count
        DWORD       ticks;      // ticks in MIDI stream

        // SMPTE 
        struct
        {
            BYTE    hour;       // hours
            BYTE    min;        // minutes
            BYTE    sec;        // seconds
            BYTE    frame;      // frames 
            BYTE    fps;        // frames per second
            BYTE    dummy;      // pad
#ifdef _WIN32
            BYTE    pad[2];
#endif
        } smpte;

        // MIDI
        struct
        {
            DWORD songptrpos;   // song pointer position 
        } midi;
    } u;
}*/
    [StructLayout( LayoutKind.Explicit )]
    public struct MMTIME {
        [FieldOffset( 0 )]
        public UInt32 wType;
        [FieldOffset( 4 )]
        public UInt32 ms;
        [FieldOffset( 4 )]
        public UInt32 sample;
        [FieldOffset( 4 )]
        public UInt32 cb;
        [FieldOffset( 4 )]
        public UInt32 ticks;
        [FieldOffset( 4 )]
        public Byte smpteHour;
        [FieldOffset( 5 )]
        public Byte smpteMin;
        [FieldOffset( 6 )]
        public Byte smpteSec;
        [FieldOffset( 7 )]
        public Byte smpteFrame;
        [FieldOffset( 8 )]
        public Byte smpteFps;
        [FieldOffset( 9 )]
        public Byte smpteDummy;
        [FieldOffset( 10 )]
        public Byte smptePad0;
        [FieldOffset( 11 )]
        public Byte smptePad1;
        [FieldOffset( 4 )]
        public UInt32 midiSongPtrPos;
    }
    
    [StructLayout(LayoutKind.Sequential, Pack = 1 )]
    public unsafe struct _MMTIME {
        public UINT wType;
        byte b1;
        byte b2;
        byte b3;
        byte b4;
        byte b5;
        byte b6;
        byte b7;
        byte b8;

        public struct SMPTE {
            public BYTE    hour;       // hours
            public BYTE    min;        // minutes
            public BYTE    sec;        // seconds
            public BYTE    frame;      // frames 
            public BYTE    fps;        // frames per second
            public BYTE    dummy;      // pad
            public fixed BYTE    pad[2];
        }

        public SMPTE smpte {
            get {
                SMPTE ret = new SMPTE();
                ret.hour = b1;
                ret.min = b2;
                ret.sec = b3;
                ret.frame = b4;
                ret.fps = b5;
                ret.dummy = b6;
                ret.pad[0] = b7;
                ret.pad[1] = b8;
                return ret;
            }
        }

        public struct MIDI {
            public DWORD songptrpos;   // song pointer position 
        }

        public MIDI midi {
            get {
                MIDI ret = new MIDI();
                ret.songptrpos = ms;
                return ret;
            }
        }

        public uint ms {
            get {
                return (uint)b1 | (uint)(b2 << 8) | (uint)(b3 << 16) | (uint)(b4 << 32);
            }
        }
        public uint sample {
            get {
                return ms;
            }
        }
        public uint cb {
            get {
                return ms;
            }
        }
        public uint ticks {
            get {
                return ms;
            }
        }
    }

    [StructLayout( LayoutKind.Sequential, CharSet = CharSet.Ansi )]
    public struct MIDIINCAPS {
        public ushort wMid;
        public ushort wPid;
        public uint vDriverVersion;
        [MarshalAs( UnmanagedType.ByValTStr, SizeConst = windows.MAXPNAMELEN )]
        public string szPname;
        public uint dwSupport;

        public override string ToString() {
            return szPname;
        }
    }

    public static partial class windows {
        public const uint JOYERR_NOERROR = 0;
        public const ushort JOY_RETURNX = 0x00000001;
        public const ushort JOY_RETURNY = 0x00000002;
        public const ushort JOY_RETURNZ = 0x00000004;
        public const ushort JOY_RETURNR = 0x00000008;
        public const ushort JOY_RETURNU = 0x00000010;
        public const ushort JOY_RETURNV = 0x00000020;
        public const ushort JOY_RETURNPOV = 0x00000040;
        public const ushort JOY_RETURNBUTTONS = 0x00000080;
        public const ushort JOY_RETURNRAWDATA = 0x00000100;
        public const ushort JOY_RETURNPOVCTS = 0x00000200;
        public const ushort JOY_RETURNCENTERED = 0x00000400;
        public const ushort JOY_USEDEADZONE = 0x00000800;
        public const ushort JOY_RETURNALL = (JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ |
                                 JOY_RETURNR | JOY_RETURNU | JOY_RETURNV |
                                 JOY_RETURNPOV | JOY_RETURNBUTTONS);

        public const ushort MM_MCINOTIFY = 0x3B9;          /* MCI */

        public const ushort MM_WOM_OPEN = 0x3BB;         /* waveform output */
        public const ushort MM_WOM_CLOSE = 0x3BC;
        public const ushort MM_WOM_DONE = 0x3BD;

        public const ushort MM_WIM_OPEN = 0x3BE;        /* waveform input */
        public const ushort MM_WIM_CLOSE = 0x3BF;
        public const ushort MM_WIM_DATA = 0x3C0;

        public const ushort MM_MIM_OPEN = 0x3C1;        /* MIDI input */
        public const ushort MM_MIM_CLOSE = 0x3C2;
        public const ushort MM_MIM_DATA = 0x3C3;
        public const ushort MM_MIM_LONGDATA = 0x3C4;
        public const ushort MM_MIM_ERROR = 0x3C5;
        public const ushort MM_MIM_LONGERROR = 0x3C6;

        public const ushort MM_MOM_OPEN = 0x3C7;         /* MIDI output */
        public const ushort MM_MOM_CLOSE = 0x3C8;
        public const ushort MM_MOM_DONE = 0x3C9;

        public const int WAVE_MAPPER = -1;

        public const int WAVE_FORMAT_PCM = 1;

        public const int CALLBACK_TYPEMASK = 0x00070000;    /* callback type mask */
        public const int CALLBACK_NULL = 0x00000000;    /* no callback */
        public const int CALLBACK_WINDOW = 0x00010000;    /* dwCallback is a HWND */
        public const int CALLBACK_TASK = 0x00020000;    /* dwCallback is a HTASK */
        public const int CALLBACK_FUNCTION = 0x00030000;    /* dwCallback is a FARPROC */
        public const int CALLBACK_THREAD = (CALLBACK_TASK);/* thread ID replaces 16 bit task */
        public const int CALLBACK_EVENT = 0x00050000;    /* dwCallback is an EVENT Handle */

        public const int WHDR_DONE = 0x00000001;  /* done bit */
        public const int WHDR_PREPARED = 0x00000002;  /* set if this header has been prepared */
        public const int WHDR_BEGINLOOP = 0x00000004;  /* loop start block */
        public const int WHDR_ENDLOOP = 0x00000008;  /* loop end block */
        public const int WHDR_INQUEUE = 0x00000010;  /* reserved for driver */

        public const int TIME_MS    =     0x0001;  /* time in milliseconds */
        public const int TIME_SAMPLES=    0x0002;  /* number of wave samples */
        public const int TIME_BYTES=      0x0004;  /* current byte offset */
        public const int TIME_SMPTE =     0x0008;  /* SMPTE time */
        public const int TIME_MIDI   =    0x0010;  /* MIDI time */
        public const int TIME_TICKS = 0x0020;  /* Ticks within MIDI stream */

        public const int MAXPNAMELEN = 32;
        public const int MAX_JOYSTICKOEMVXDNAME = 260;

        #region midi
        [DllImport( "winmm.dll" )]
        public static extern UINT midiInGetNumDevs();
        [DllImport( "winmm.dll" )]
        public static unsafe extern MMRESULT midiInOpen( HMIDIIN* lphMidiIn,
                                                         UINT uDeviceID,
                                                         DWORD dwCallback,
                                                         DWORD dwCallbackInstance,
                                                         DWORD dwFlags );
        #endregion

        #region joy
        [DllImport( "winmm.dll" )]
        [return: MarshalAs( UnmanagedType.U4 )]
        public static extern uint joyGetNumDevs();

        [DllImport( "winmm.dll" )]
        public static extern uint joyGetPos( uint uJoyID, ref JOYINFO pji );

        [DllImport( "winmm.dll" )]
        public static extern uint joyGetDevCapsW( uint uJoyID, ref JOYCAPSW pjc, uint cbjc );

        [DllImport( "winmm.dll" )]
        public static extern uint joyGetPosEx( uint uJoyID, ref JOYINFOEX pji );
        #endregion

        #region wave
        [DllImport( "winmm.dll" )]
        public static extern uint waveOutWrite( IntPtr hwo, ref WAVEHDR pwh, uint cbwh );
        [DllImport( "winmm.dll" )]
        //[return: MarshalAs(UnmanagedType.U4)]
        public static extern uint waveOutOpen( ref IntPtr hWaveOut,
                                               int uDeviceID,
                                               ref WAVEFORMATEX lpFormat,
                                               delegateWaveOutProc dwCallback,
                                               IntPtr dwInstance,
                                               uint dwFlags );
        //public static extern uint waveOutOpen( ref IntPtr phwo, UINT uDeviceID, ref WAVEFORMATEX pwfx, delegateWaveOutProc dwCallback, IntPtr dwInstance, uint fdwOpen );
        [DllImport("winmm.dll")]
        public static extern uint waveOutPrepareHeader( IntPtr hwo, ref WAVEHDR pwh, UINT cbwh);
        [DllImport( "winmm.dll")]
        public static extern uint waveOutGetPosition( IntPtr hwo, ref MMTIME pmmt, UINT cbmmt);
        [DllImport("winmm.dll")]
        public static extern uint waveOutReset( IntPtr hwo);
        [DllImport("winmm.dll")]
        public static extern  uint  waveOutUnprepareHeader( IntPtr hwo, ref WAVEHDR pwh, UINT cbwh);
        [DllImport("winmm.dll")]
        public static extern uint waveOutClose( IntPtr hwo);
        #endregion

        #region mci
        [DllImport( "winmm.dll", CharSet = CharSet.Ansi )]
        public static extern bool mciGetErrorStringA( uint mcierr, [MarshalAs( UnmanagedType.LPStr )] string pszText, UINT cchText );
        #endregion
    }

}
