module external.directx.xaudio2;

import std.math;

import external.directx.com;

version = XAUDIO2_HELPER_FUNCTIONS;

version (DXSDK_2010_6)
{
    mixin(uuid!(XAudio2, "5a508685", "a254", "4fba", ["9b", "82", "9a", "24", "b0", "03", "06", "af"]));
    mixin(uuid!(XAudio2_Debug, "db05ea35", "0329", "4d4b", ["a5", "3a", "6d", "ea", "d0", "3d", "38", "52"]));
    mixin(uuid!(IXAudio2, "8bcf1f58", "9fe7", "4583", ["8a", "c6", "e2", "ad", "c4", "65", "c8", "bb"]));
}

version (XAUDIO_2_8)
{
    mixin(uuid!(IXAudio2, "60d8dac8", "5aa1", "4e8e", ["b5", "97", "2f", "5e", "28", "83", "d4", "84"]));
}

version (GUID_DEFS_ONLY)
{
}
else
{

    interface XAudio2 : IUnknown
    {
    }

    interface XAudio2_Debug : IUnknown
    {
    }

    version (XBOX)
        import xbox.xobjbase;
    else
        import external.directx.com;

align(1):
    enum XAUDIO2_MAX_BUFFER_BYTES = 0x80000000;
    enum XAUDIO2_MAX_QUEUED_BUFFERS = 64;
    enum XAUDIO2_MAX_BUFFERS_SYSTEM = 2;
    enum XAUDIO2_MAX_AUDIO_CHANNELS = 64;
    enum XAUDIO2_MIN_SAMPLE_RATE = 1000;
    enum XAUDIO2_MAX_SAMPLE_RATE = 200000;
    enum XAUDIO2_MAX_VOLUME_LEVEL = 16777216.0f;
    enum XAUDIO2_MIN_FREQ_RATIO = (1 / 1024.0f);
    enum XAUDIO2_MAX_FREQ_RATIO = 1024.0f;
    enum XAUDIO2_DEFAULT_FREQ_RATIO = 2.0f;
    enum XAUDIO2_MAX_FILTER_ONEOVERQ = 1.5f;
    enum XAUDIO2_MAX_FILTER_FREQUENCY = 1.0f;
    enum XAUDIO2_MAX_LOOP_COUNT = 254;
    enum XAUDIO2_MAX_INSTANCES = 8;
    enum XAUDIO2_MAX_RATIO_TIMES_RATE_XMA_MONO = 600000;
    enum XAUDIO2_MAX_RATIO_TIMES_RATE_XMA_MULTICHANNEL = 300000;
    enum XAUDIO2_COMMIT_NOW = 0;
    enum XAUDIO2_COMMIT_ALL = 0;
    enum XAUDIO2_INVALID_OPSET = cast(uint)(-1);
    enum XAUDIO2_NO_LOOP_REGION = 0;
    enum XAUDIO2_LOOP_INFINITE = 255;
    enum XAUDIO2_DEFAULT_CHANNELS = 0;
    enum XAUDIO2_DEFAULT_SAMPLERATE = 0;
    enum XAUDIO2_DEBUG_ENGINE = 0x0001;
    enum XAUDIO2_VOICE_NOPITCH = 0x0002;
    enum XAUDIO2_VOICE_NOSRC = 0x0004;
    enum XAUDIO2_VOICE_USEFILTER = 0x0008;
    enum XAUDIO2_VOICE_MUSIC = 0x0010;
    enum XAUDIO2_PLAY_TAILS = 0x0020;
    enum XAUDIO2_END_OF_STREAM = 0x0040;
    enum XAUDIO2_SEND_USEFILTER = 0x0080;
    enum XAUDIO2_DEFAULT_FILTER_TYPE = LowPassFilter;
    enum XAUDIO2_DEFAULT_FILTER_FREQUENCY = XAUDIO2_MAX_FILTER_FREQUENCY;
    enum XAUDIO2_DEFAULT_FILTER_ONEOVERQ = 1.0f;

    version (XBOX)
    {
        enum XAUDIO2_QUANTUM_NUMERATOR = 2;
        enum XAUDIO2_QUANTUM_DENOMINATOR = 375;
    }
    else
    {
        enum XAUDIO2_QUANTUM_NUMERATOR = 1;
        enum XAUDIO2_QUANTUM_DENOMINATOR = 100;
    }
    enum XAUDIO2_QUANTUM_MS = (1000.0f * XAUDIO2_QUANTUM_NUMERATOR / XAUDIO2_QUANTUM_DENOMINATOR);

    enum FACILITY_XAUDIO2 = 0x896;
    enum XAUDIO2_E_INVALID_CALL = 0x88960001;
    enum XAUDIO2_E_XMA_DECODER_ERROR = 0x88960002;
    enum XAUDIO2_E_XAPO_CREATION_FAILED = 0x88960003;
    enum XAUDIO2_E_DEVICE_INVALIDATED = 0x88960004;

    version (XBOX)
    {
        enum XAUDIO2_XBOX_HWTHREAD_SPECIFIER
        {
            XboxThread0 = 0x01,
            XboxThread1 = 0x02,
            XboxThread2 = 0x04,
            XboxThread3 = 0x08,
            XboxThread4 = 0x10,
            XboxThread5 = 0x20,
            XAUDIO2_ANY_PROCESSOR = XboxThread4,
            XAUDIO2_DEFAULT_PROCESSOR = XAUDIO2_ANY_PROCESSOR
        }

        alias XAUDIO2_PROCESSOR = XAUDIO2_XBOX_HWTHREAD_SPECIFIER;
    }
    else
    {
        alias XAUDIO2_WINDOWS_PROCESSOR_SPECIFIER = int;
        enum : XAUDIO2_WINDOWS_PROCESSOR_SPECIFIER
        {
            Processor1 = 0x00000001,
            Processor2 = 0x00000002,
            Processor3 = 0x00000004,
            Processor4 = 0x00000008,
            Processor5 = 0x00000010,
            Processor6 = 0x00000020,
            Processor7 = 0x00000040,
            Processor8 = 0x00000080,
            Processor9 = 0x00000100,
            Processor10 = 0x00000200,
            Processor11 = 0x00000400,
            Processor12 = 0x00000800,
            Processor13 = 0x00001000,
            Processor14 = 0x00002000,
            Processor15 = 0x00004000,
            Processor16 = 0x00008000,
            Processor17 = 0x00010000,
            Processor18 = 0x00020000,
            Processor19 = 0x00040000,
            Processor20 = 0x00080000,
            Processor21 = 0x00100000,
            Processor22 = 0x00200000,
            Processor23 = 0x00400000,
            Processor24 = 0x00800000,
            Processor25 = 0x01000000,
            Processor26 = 0x02000000,
            Processor27 = 0x04000000,
            Processor28 = 0x08000000,
            Processor29 = 0x10000000,
            Processor30 = 0x20000000,
            Processor31 = 0x40000000,
            Processor32 = 0x80000000,
            XAUDIO2_ANY_PROCESSOR = 0xffffffff,
            XAUDIO2_DEFAULT_PROCESSOR = XAUDIO2_ANY_PROCESSOR
        }
        alias XAUDIO2_PROCESSOR = XAUDIO2_WINDOWS_PROCESSOR_SPECIFIER;
    }

    alias XAUDIO2_DEVICE_ROLE = DWORD;
    enum : XAUDIO2_DEVICE_ROLE
    {
        NotDefaultDevice = 0x0,
        DefaultConsoleDevice = 0x1,
        DefaultMultimediaDevice = 0x2,
        DefaultCommunicationsDevice = 0x4,
        DefaultGameDevice = 0x8,
        GlobalDefaultDevice = 0xf,
        InvalidDeviceRole = ~GlobalDefaultDevice
    }

    struct XAUDIO2_DEVICE_DETAILS
    {
        WCHAR[256] DeviceID;
        WCHAR[256] DisplayName;
        XAUDIO2_DEVICE_ROLE Role;
        WAVEFORMATEXTENSIBLE OutputFormat;
    }

    struct XAUDIO2_VOICE_DETAILS
    {
        uint CreationFlags;
        uint InputChannels;
        uint InputSampleRate;
    }

    struct XAUDIO2_SEND_DESCRIPTOR
    {
        uint Flags;
        IXAudio2Voice pOutputVoice;
    }

    struct XAUDIO2_VOICE_SENDS
    {
        uint SendCount;
        XAUDIO2_SEND_DESCRIPTOR* pSends;
    }

    struct XAUDIO2_EFFECT_DESCRIPTOR
    {
        IUnknown pEffect;
        bool InitialState;
        uint OutputChannels;
    }

    struct XAUDIO2_EFFECT_CHAIN
    {
        uint EffectCount;
        XAUDIO2_EFFECT_DESCRIPTOR* pEffectDescriptors;
    }

    alias XAUDIO2_FILTER_TYPE = uint;
    enum : XAUDIO2_FILTER_TYPE
    {
        LowPassFilter,
        BandPassFilter,
        HighPassFilter,
        NotchFilter
    }

    struct XAUDIO2_FILTER_PARAMETERS
    {
        XAUDIO2_FILTER_TYPE Type;
        float Frequency;

        float OneOverQ;

    }

    struct XAUDIO2_BUFFER
    {
        uint Flags;
        uint AudioBytes;
        const(ubyte)* pAudioData;
        uint PlayBegin;
        uint PlayLength;
        uint LoopBegin;
        uint LoopLength;
        uint LoopCount;
        void* pContext;
    }

    struct XAUDIO2_BUFFER_WMA
    {
        const(uint)* pDecodedPacketCumulativeBytes;
        uint PacketCount;
    }

    struct XAUDIO2_VOICE_STATE
    {
        void* pCurrentBufferContext;
        uint BuffersQueued;
        ulong SamplesPlayed;
    }

    struct XAUDIO2_PERFORMANCE_DATA
    {
        ulong AudioCyclesSinceLastQuery;
        ulong TotalCyclesSinceLastQuery;
        uint MinimumCyclesPerQuantum;
        uint MaximumCyclesPerQuantum;
        uint MemoryUsageInBytes;
        uint CurrentLatencyInSamples;
        uint GlitchesSinceEngineStarted;
        uint ActiveSourceVoiceCount;
        uint TotalSourceVoiceCount;
        uint ActiveSubmixVoiceCount;
        uint ActiveResamplerCount;
        uint ActiveMatrixMixCount;
        uint ActiveXmaSourceVoices;
        uint ActiveXmaStreams;
    }

    struct XAUDIO2_DEBUG_CONFIGURATION
    {
        uint TraceMask;
        uint BreakMask;
        bool LogThreadID;
        bool LogFileline;
        bool LogFunctionName;
        bool LogTiming;
    }

    enum XAUDIO2_LOG_ERRORS = 0x0001;
    enum XAUDIO2_LOG_WARNINGS = 0x0002;
    enum XAUDIO2_LOG_INFO = 0x0004;
    enum XAUDIO2_LOG_DETAIL = 0x0008;
    enum XAUDIO2_LOG_API_CALLS = 0x0010;
    enum XAUDIO2_LOG_FUNC_CALLS = 0x0020;
    enum XAUDIO2_LOG_TIMING = 0x0040;
    enum XAUDIO2_LOG_LOCKS = 0x0080;
    enum XAUDIO2_LOG_MEMORY = 0x0100;
    enum XAUDIO2_LOG_STREAMING = 0x1000;

    interface IXAudio2 : IUnknown
    {
    extern (Windows):
        version (DXSDK_2010_6)
        {
            HRESULT GetDeviceCount(uint* pCount);
            HRESULT GetDeviceDetails(uint Index, XAUDIO2_DEVICE_DETAILS* pDeviceDetails);
            HRESULT Initialize(uint Flags = 0, XAUDIO2_PROCESSOR XAudio2Processor = XAUDIO2_DEFAULT_PROCESSOR);
        }

        HRESULT RegisterForCallbacks(IXAudio2EngineCallback pCallback);
        void UnregisterForCallbacks(IXAudio2EngineCallback pCallback);
        HRESULT CreateSourceVoice(IXAudio2SourceVoice** ppSourceVoice, const(WAVEFORMATEX)* pSourceFormat, uint Flags = 0, float MaxFrequencyRatio = XAUDIO2_DEFAULT_FREQ_RATIO, IXAudio2VoiceCallback pCallback = null, const(XAUDIO2_VOICE_SENDS)* pSendList = null, const(XAUDIO2_EFFECT_CHAIN)* pEffectChain = null);
        HRESULT CreateSubmixVoice(IXAudio2SubmixVoice** ppSubmixVoice, uint InputChannels, uint InputSampleRate, uint Flags = 0, uint ProcessingStage = 0, const(XAUDIO2_VOICE_SENDS)* pSendList = null, const(XAUDIO2_EFFECT_CHAIN)* pEffectChain = null);
        HRESULT CreateMasteringVoice(IXAudio2MasteringVoice** ppMasteringVoice, uint InputChannels = XAUDIO2_DEFAULT_CHANNELS, uint InputSampleRate = XAUDIO2_DEFAULT_SAMPLERATE, uint Flags = 0, uint DeviceIndex = 0, const(XAUDIO2_EFFECT_CHAIN)* pEffectChain = null);
        HRESULT StartEngine();
        void StopEngine();
        HRESULT CommitChanges(uint OperationSet);
        void GetPerformanceData(XAUDIO2_PERFORMANCE_DATA* pPerfData);
        void SetDebugConfiguration(const(XAUDIO2_DEBUG_CONFIGURATION)* pDebugConfiguration, void* pReserved = null);
    }

    extern (C++) interface IXAudio2Voice
    {
    extern (Windows):
        void GetVoiceDetails(XAUDIO2_VOICE_DETAILS* pVoiceDetails);
        HRESULT SetOutputVoices(const(XAUDIO2_VOICE_SENDS)* pSendList);
        HRESULT SetEffectChain(const(XAUDIO2_EFFECT_CHAIN)* pEffectChain);
        HRESULT EnableEffect(uint EffectIndex, uint OperationSet = XAUDIO2_COMMIT_NOW);
        HRESULT DisableEffect(uint EffectIndex, uint OperationSet = XAUDIO2_COMMIT_NOW);
        void GetEffectState(uint EffectIndex, bool* pEnabled);
        HRESULT SetEffectParameters(uint EffectIndex, const(void)* pParameters, uint ParametersByteSize, uint OperationSet = XAUDIO2_COMMIT_NOW);
        HRESULT GetEffectParameters(uint EffectIndex, void* pParameters, uint ParametersByteSize);
        HRESULT SetFilterParameters(const(XAUDIO2_FILTER_PARAMETERS)* pParameters, uint OperationSet = XAUDIO2_COMMIT_NOW);
        void GetFilterParameters(XAUDIO2_FILTER_PARAMETERS* pParameters);
        HRESULT SetOutputFilterParameters(IXAudio2Voice pDestinationVoice, const(XAUDIO2_FILTER_PARAMETERS)* pParameters, uint OperationSet = XAUDIO2_COMMIT_NOW);
        void GetOutputFilterParameters(IXAudio2Voice pDestinationVoice, XAUDIO2_FILTER_PARAMETERS* pParameters);
        HRESULT SetVolume(float Volume, uint OperationSet = XAUDIO2_COMMIT_NOW);
        void GetVolume(float* pVolume);
        HRESULT SetChannelVolumes(uint Channels, const(float)* pVolumes, uint OperationSet = XAUDIO2_COMMIT_NOW);
        void GetChannelVolumes(uint Channels, float* pVolumes);
        HRESULT SetOutputMatrix(IXAudio2Voice pDestinationVoice, uint SourceChannels, uint DestinationChannels, const(float)* pLevelMatrix, uint OperationSet = XAUDIO2_COMMIT_NOW);
        void GetOutputMatrix(IXAudio2Voice pDestinationVoice, uint SourceChannels, uint DestinationChannels, float* pLevelMatrix);
        void DestroyVoice();
    }

    extern (C++) interface IXAudio2SourceVoice : IXAudio2Voice
    {
    extern (Windows):
        HRESULT Start(uint Flags = 0, uint OperationSet = XAUDIO2_COMMIT_NOW);
        HRESULT Stop(uint Flags = 0, uint OperationSet = XAUDIO2_COMMIT_NOW);
        HRESULT SubmitSourceBuffer(const(XAUDIO2_BUFFER)* pBuffer, const(XAUDIO2_BUFFER_WMA)* pBufferWMA = null);
        HRESULT FlushSourceBuffers();
        HRESULT Discontinuity();
        HRESULT ExitLoop(uint OperationSet = XAUDIO2_COMMIT_NOW);
        void GetState(XAUDIO2_VOICE_STATE* pVoiceState);
        HRESULT SetFrequencyRatio(float Ratio, uint OperationSet = XAUDIO2_COMMIT_NOW);
        void GetFrequencyRatio(float* pRatio);
        HRESULT SetSourceSampleRate(uint NewSourceSampleRate);
    }

    interface IXAudio2SubmixVoice : IXAudio2Voice
    {

    }

    interface IXAudio2MasteringVoice : IXAudio2Voice
    {
        version (XAUDIO_2_8) HRESULT GetChannelMask(DWORD* pChannelmask);
    }

    extern (C++) interface IXAudio2EngineCallback
    {
    extern (Windows):
        void OnProcessingPassStart();
        void OnProcessingPassEnd();
        void OnCriticalError(HRESULT Error);
    }

    extern (C++) interface IXAudio2VoiceCallback
    {
        void OnVoiceProcessingPassStart(uint BytesRequired);
        void OnVoiceProcessingPassEnd();
        void OnStreamEnd();
        void OnBufferStart(void* pBufferContext);
        void OnBufferEnd(void* pBufferContext);
        void OnLoopEnd(void* pBufferContext);
        void OnVoiceError(void* pBufferContext, HRESULT Error);
    }

    version (XAUDIO2_HELPER_FUNCTIONS)
    {
        float XAudio2DecibelsToAmplitudeRatio(float Decibels)
        {
            return pow(10.0f, Decibels / 20.0f);
        }

        float XAudio2AmplitudeRatioToDecibels(float Volume)
        {
            if (Volume == 0)
            {
                return -3.402823466e+38f;
            }
            return 20.0f * log10(Volume);
        }

        float XAudio2SemitonesToFrequencyRatio(float Semitones)
        {

            return pow(2.0f, Semitones / 12.0f);
        }

        float XAudio2FrequencyRatioToSemitones(float FrequencyRatio)
        {

            return 39.86313713864835f * log10(FrequencyRatio);
        }

        float XAudio2CutoffFrequencyToRadians(float CutoffFrequency, uint SampleRate)
        {
            if (cast(uint)(CutoffFrequency * 6.0f) >= SampleRate)
            {
                return XAUDIO2_MAX_FILTER_FREQUENCY;
            }
            return 2.0f * sin(cast(float) PI * CutoffFrequency / SampleRate);
        }

        float XAudio2RadiansToCutoffFrequency(float Radians, float SampleRate)
        {
            return SampleRate * asin(Radians / 2.0f) / cast(float) PI;
        }

    }

    version (XBOX)
    {
        STDAPI XAudio2Create(IXAudio2** ppXAudio2, uint Flags = 0, XAUDIO2_PROCESSOR XAudio2Processor = XAUDIO2_DEFAULT_PROCESSOR);
    }
    else
    {
    extern (Windows):
        version (DXSDK_2010_6)
            HRESULT XAudio2Create(out IXAudio2 ppXAudio2, uint Flags = 0, XAUDIO2_PROCESSOR XAudio2Processor = XAUDIO2_DEFAULT_PROCESSOR)
        {
            IXAudio2 pXAudio2;
            HRESULT hr = CoCreateInstance((Flags & XAUDIO2_DEBUG_ENGINE) ? &IID_XAudio2_Debug : &IID_XAudio2, null, CLSCTX_INPROC_SERVER, &IID_IXAudio2, cast(void**)&pXAudio2);
            if (SUCCEEDED(hr))
            {
                hr = pXAudio2.Initialize(Flags, XAudio2Processor);
                if (SUCCEEDED(hr))
                {
                    ppXAudio2 = pXAudio2;
                }
                else
                {
                    pXAudio2.Release();
                }
            }
            return hr;
        }
        else version (XAUDIO_2_8)
        {
            HRESULT XAudio2Create(out IXAudio2 ppXAudio2, uint Flags = 0, XAUDIO2_PROCESSOR XAudio2Processor = XAUDIO2_DEFAULT_PROCESSOR);
        }
    }
}