; ------------------------------------------------------
; Custom Sound Mixer
; Copyright (c) 2005-2016, Franck Charlet
; All rights reserved.
; ------------------------------------------------------
; buildblock RELEASE
;       CAPT %5\Release.bat
; buildblockend
; buildblock DEBUG
;       CAPT %5\Debug.bat
; buildblockend

; ------------------------------------------------------
; Constants
SCREEN_WIDTH            equ     800
SCREEN_HEIGHT           equ     600
SCREEN_BPP              equ     32

; ------------------------------------------------------
; Includes
                        include ..\Common_Src\FrameWork.asm
                        include ..\Common_Src\SoundMixer.asm

; ------------------------------------------------------
; Constants
WAVE_SIZE               equ     4096

; Mix at 44khz / Stereo (2) / 16 bits
SAMPLING_RATE           equ     44100
SAMPLING_CHANNELS       equ     2
SAMPLING_RESOLUTION     equ     16

NOTE_LEFT               equ     12 * 5          ; C5
NOTE_RIGHT              equ     12 * 5          ; C5

; ------------------------------------------------------
; Functions
Mixing_Routine          proto   :dword, :dword

; ------------------------------------------------------
; Variables
Sin_Wave                dd      0
Left_Buffer             dd      0
Right_Buffer            dd      0

Left_Phase              real4   0.0
Right_Phase             real4   0.0
Freq_Scale              real4   0.0

; ------------------------------------------------------
; Name: Initialize()
; Desc: Perform the various initializations
Initialize              proc

                        invoke  glClearDepth, CDBL(1.0)
                        invoke  glHint, GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST
                        invoke  glClearColor, 0, 0, 0, CFLT(1.0)
                        invoke  glEnable, GL_NORMALIZE
                        invoke  glEnable, GL_CULL_FACE

                        ; Just a test that plays 2 interpolated sin waves on left & right speakers
                        ; with a cheap surround effect

                        ; Create sin wave datas
                        mov     Sin_Wave, ALLOCMEM(WAVE_SIZE * 4)
                        .if     Sin_Wave == NULL
No_Memory:                      invoke  Set_Error_Msg, CSTR("Not enough memory")
                                mov     eax, FALSE
                                ret
                        .endif

                        mov     edi, Sin_Wave
                        xor     ebx, ebx
                        .while  ebx < WAVE_SIZE
                                fldpi
                                fadd    st(0), st(0)
                                fmul    INT2FLT(ebx)
                                fdiv    INT2FLT(WAVE_SIZE)
                                fsin
                                fstp    dword ptr [edi + ebx * 4]
                                inc     ebx
                        .endw
                        
                        fld     INT2DBL(WAVE_SIZE)
                        fdiv    INT2DBL(SAMPLING_RATE)
                        fstp    Freq_Scale

                        ; Alloc the two floating points buffers
                        mov     Left_Buffer, ALLOCMEM(SAMPLING_RATE * 4)
                        .if     Left_Buffer == NULL
                                jmp     No_Memory
                        .endif
                        
                        mov     Right_Buffer, ALLOCMEM(SAMPLING_RATE * 4)
                        .if     Right_Buffer == NULL
                                jmp     No_Memory
                        .endif

                        ; If the mixing routine is specified we need to fill all others arguments but the last one.
                        invoke  DSound_Mixer_Create, g_window.hWnd, addr Mixing_Routine, SAMPLING_RATE, SAMPLING_CHANNELS, SAMPLING_RESOLUTION, 0
                        .if     eax == FALSE
                                invoke  Set_Error_Msg, CSTR("Can't create sound mixer")
                                mov     eax, FALSE
                                ret
                        .endif
                                                
                        mov     eax, TRUE
                        ret
Initialize              endp

; ------------------------------------------------------
; Name: Deinitialize()
; Desc: Free allocated resources
Deinitialize            proc

                        FREEMEM Right_Buffer
                        FREEMEM Left_Buffer
                        FREEMEM Sin_Wave
                        invoke  DSound_Mixer_Destroy
                        ret
Deinitialize            endp

; ------------------------------------------------------
; Name: Update()
; Desc: Update the scene
Update                  proc    FrameRate:real4

                        ; Update scene here

                        invoke  DInput_Get_Key, DIK_ESCAPE
                        test    eax, eax
                        jz      Esc_Pressed
                        invoke  Terminate_Application
Esc_Pressed:            ret
Update                  endp

; ------------------------------------------------------
; Name: Draw()
; Desc: Draw the scene
Draw                    proc
                        invoke  glClear, GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT or GL_STENCIL_BUFFER_BIT

                        ; Draw scene here

                        ret
Draw                    endp

; ------------------------------------------------------
; Name: Mixing_Routine()
; Desc: Sound buffer mixing
Mixing_Routine          proc    uses ebx edi esi Buffer:dword, Buffer_Length:dword
                        local   dwBuffer_Length:dword
                        local   iLeft_Phase:dword
                        local   iRight_Phase:dword
                        local   Switch:dword
                        local   Interp_Len:dword
                        
                        mov     eax, Buffer_Length
                        shr     eax, 2
                        mov     dwBuffer_Length, eax
                        
                        mov     esi, Left_Buffer
                        mov     edi, Right_Buffer
                        mov     ecx, Sin_Wave
                        lea     edx, Midi_Freq_Table                    ; Created in SoundMixer.asm
                        
                        mov     Switch, FALSE
                        mov     eax, dwBuffer_Length
                        add     eax, 2                                  ; Make sure the interpolated sample is complete
                        mov     Interp_Len, eax

                        xor     ebx, ebx
                        .while  ebx < Interp_Len
                                ; Only one sample out of 2
                                .if     Switch == TRUE
                                        ; Store the samples in the floating point buffer
                                        fld     Left_Phase
                                        fistp   iLeft_Phase
        
                                        mov     eax, iLeft_Phase
                                        fld     dword ptr [ecx + eax * 4]
                                        fstp    dword ptr [esi]
                                        add     esi, 4
        
                                        fld     Right_Phase
                                        fistp   iRight_Phase
        
                                        mov     eax, iRight_Phase
                                        fld     dword ptr [ecx + eax * 4]
                                        fchs                            ; Inverting it gives a simple surround fx
                                        fstp    dword ptr [edi]
                                        add     edi, 4
                                .endif

                                mov     eax, dwBuffer_Length            ; The last sample will be re-used the next time
                                .if     ebx < eax                       ; so we'll 
                                        mov     eax, NOTE_LEFT
                                        fld     dword ptr [edx + eax * 4]
                                        fmul    Freq_Scale
                                        fadd    Left_Phase
                                        FCMP    st(0), INT2FLT(WAVE_SIZE - 1)
                                        jb      Reset_Left_Phase
                                        fsub    INT2FLT(WAVE_SIZE - 1)
Reset_Left_Phase:                       fstp    Left_Phase

                                        mov     eax, NOTE_RIGHT
                                        fld     dword ptr [edx + eax * 4]
                                        fmul    Freq_Scale
                                        fadd    Right_Phase
                                        FCMP    st(0), INT2FLT(WAVE_SIZE - 1)
                                        jb      Reset_Right_Phase
                                        fsub    INT2FLT(WAVE_SIZE - 1)
Reset_Right_Phase:                      fstp    Right_Phase
                                .endif
                                xor     Switch, TRUE
                                inc     ebx
                        .endw
                
                        ; Mix the final buffer with the interpolation
                        mov     edi, Buffer
                        mov     eax, dwBuffer_Length
                        cdq
                        mov     ebx, 2
                        idiv    ebx
                        push    edx
                        mov     Interp_Len, eax
                        mov     ecx, Left_Buffer
                        mov     edx, Right_Buffer
                        xor     ebx, ebx
                        .while  ebx < Interp_Len
                                fld     dword ptr [ecx]
                                fmul    CFLT(32767.0)                   ; Defined in soundMixer.asm
                                push    eax
                                fistp   dword ptr [esp]
                                pop     eax
                                mov     [edi], ax
                                add     edi, 2

                                fld     dword ptr [edx]
                                fmul    CFLT(32767.0)
                                push    eax
                                fistp   dword ptr [esp]
                                pop     eax
                                mov     [edi], ax
                                add     edi, 2

                                fld     dword ptr [ecx]
                                add     ecx, 4
                                fld     dword ptr [ecx]                 ; Take the next sample to create a new middle one
                                fsub    st(0), st(1)
                                fmul    CFLT(0.5)
                                faddp   st(1), st(0)
                                fmul    CFLT(32767.0)
                                push    eax
                                fistp   dword ptr [esp]
                                pop     eax
                                mov     [edi], ax
                                add     edi, 2

                                fld     dword ptr [edx]
                                add     edx, 4
                                fld     dword ptr [edx]
                                fsub    st(0), st(1)
                                fmul    CFLT(0.5)
                                faddp   st(1), st(0)
                                fmul    CFLT(32767.0)
                                push    eax
                                fistp   dword ptr [esp]
                                pop     eax
                                mov     [edi], ax
                                add     edi, 2

                                inc     ebx
                        .endw
                        ; Fill the remainding sample if necessary
                        pop     eax
                        .if     eax != 0
                                fld     dword ptr [ecx]
                                fmul    CFLT(32767.0)
                                push    eax
                                fistp   dword ptr [esp]
                                pop     eax
                                mov     [edi], ax
                                add     edi, 2

                                fld     dword ptr [edx]
                                fmul    CFLT(32767.0)
                                push    eax
                                fistp   dword ptr [esp]
                                pop     eax
                                mov     [edi], ax
                        .endif

                        ret
Mixing_Routine          endp

end start
