;fasm wav.asm wav.exe

include 'win32a.inc'
WAVE_FORMAT_PCM = 1
Beat_Bass_Size = 58*2
Beat_Melody_Size = 37*2
struct WAVEFORMATEX
    wFormatTag      dw ?    ;WAVE_FORMAT_PCM=1
    nChannels       dw ?    ;1
    nSamplesPerSec  dd ?    ;44100
    nAvgBytesPerSec dd ?    ;nSamplesPerSec * nBlockAlign=2*44100
    nBlockAlign     dw ?    ;nChannels * wBitsPerSample / 8=2
    wBitsPerSample  dw ?    ;16
    cbSize          dw ?    ;0 ;//sizeof(WaveFormat)
ends

struct WAVEHDR
  lpData            dd      ?   ;[buffer Address]
  dwBufferLength    dd      ?   ;0x00109a00
  dwBytesRecorded   dd      ?   ;0
  dwUser            dd      ?   ;0
  dwFlags           dd      ?   ;0
  dwLoops           dd      ?   ;0
  lpNext            dd      ?   ;0
  Reserved          dd      ?   ;0
ends


virtual at VarTmp
    AddressBass     dd ?
    AddressMelody   dd ?
 end virtual


;======================================
format PE GUI 4.0
entry start
; section '.bss' readable writeable
    ; AddressBass     dd ?
    ; AddressMelody   dd ?
    ; hWaveOut        dd ?

section '.text' code readable writeable executable
;================
; Header Wave
;================
; align 16
; Wave_Header db "RIFF"       ; Header
; Length_File dd 0x00109a24   ; Length File - 8 =4+24+8+0x00109a00
; Wave_ID     db "WAVE"       ; Wave ID
; Chunk_fmt   db "fmt "       ; Chunk fmt
; Length_fmt  dd 0x00000010   ; 16 Byte
; Format_TAG  dw 0x0001       ; Windows PCM
; Channels    dw 0x0001       ; MONO
; Sample_Rate dd 44100        ; 44100
; Avg_Byte    dd 2*44100      ; 44100 * 2 
; Block_Align dw 0x0002       ; Align Word
; Bits_x_Sample   dw 0x0010   ; 16 bit
; Chunk_data  db "data"       ; Chunk data
; Length_data dd 0x00109a00   ; Length data
;==================
; Bass frequency
;==================
align 16
Freq_Bass:	
    dd  82.4, 164.5,  82.4, 164.5, 82.4, 164.5,  82.4, 164.5
    dd 110.0, 220.0, 110.0, 220.0,110.0, 220.0, 110.0, 220.0
    dd 103.82,207.6, 103.82,207.6, 82.4, 164.5,  82.4, 164.5
    dd 110.0, 220.0, 110.0, 220.0,110.0, 110.0, 123.47,130.8
    dd 146.8, 110.0
    dd  65.4, 130.8,  65.4, 130.8, 49.0,  98.0,  49.0 , 98.0
    dd 123.47,246.9, 123.47,246.9, 82.4, 164.5, 103.82, 207.6
    dd 110.0, 220.0, 110.0, 220.0,110.0, 220.0, 110.0, 220.0

align 16
;====================
; Melody frequency
;====================
Freq_Melody:
    dd 659.2, 493.8, 523.2, 587.3, 523.2, 493.8
    dd 440.0, 440.0, 523.2, 659.2, 587.3, 523.2
    dd 493.8, 523.2, 587.3, 659.2
    dd 523.2, 440.0, 440.0
    dd 587.3, 698.5, 880.0, 784.0, 698.5
    dd 659.2, 523.2, 659.2, 587.3, 523.2
    dd 493.8, 493.8, 523.2, 587.3, 659.2
    dd 523.2, 440.0, 440.0
align 16
Beat_Melody:
    dw 17000, 8500, 8500,17000, 8500,8500
    dw 17000, 8500, 8500,17000, 8500,8500
    dw 25500, 8500,17000,17000
    dw 17000,17000,42500
    dw 17000, 8500,17000, 8500, 8500
    dw 25500, 8500,17000, 8500, 8500
    dw 17000, 8500, 8500,17000,17000
    dw 17000,17000,17000

;================
; DATI Waveform
;================
align 16
    PI_x_Rcp        dq 1.4247585730565955729989312395825e-4 ; PI*(44100/2)
    Zero_Cinque     dd 0.5
    Zero_Uno        dd 0.1
    Zero_ZZ_Uno     dd 0.0001
    Due_Punto_Tre   dd 2.3
    DPHIF           dd 0.0
    Amp_Env         dd 1.0
    Zero_Nove       dd 0.9998
    Amp_Sample      dd 12000.0
    Filt_Env        dd 0.0
    Phase           dd 0.0
    Y_0             dd 0.0
    Y_1             dd 0.0
    

    WaveHeader  WAVEHDR  NULL,0x00109a00*3,0,0,0,0,0,0
    WaveFormat  WAVEFORMATEX WAVE_FORMAT_PCM,1,44100,2*44100,2,16,0
    

align 4
hWaveOut:
imports:
    LoadLibraryA dd 0xE9826FC6  ;hash value
    GlobalAlloc  dd 0xF6156B0A
    Sleep        dd 0xAD924C14
    ExitProcess  dd 0x38A66AE8
    ;------------------------------------
    waveOutOpen  dd 0x43227117
    waveOutPrepareHeader dd 0x9D72D684
    waveOutWrite dd 0xCAADFC96
    waveOutUnprepareHeader dd 0x5DC945D7
    waveOutReset dd 0x9DC4E8D7
    ; waveOutClose dd 0xD4B58C93

VarTmp:
libraries:
        db 4                        ;kernel32 api num
            ; db 'winmm',0,5
        db not 'w',not 'i',not 'n',not 'm',not 'm',0
        db 5                        ;winmm api num
FLAG    db 0                        ;end 

start:
    call    kernel32_base
    stdcall kernel32_func,eax
;==============================================================================
;   *****   main *****
;==============================================================================
    invoke  GlobalAlloc,GMEM_FIXED,0x109a00*3+Beat_Bass_Size+Beat_Melody_Size
    or      eax,eax
    jz      @error
    mov     [WaveHeader.lpData],eax
    add     eax,0x109a00*3
    push    eax                     ;***save AddressBass
    mov     [AddressBass],eax
    add     eax,Beat_Bass_Size
    mov     [AddressMelody],eax
    cld
    mov     ecx,Beat_Melody_Size/2
    mov     esi,Beat_Melody
    mov     edi,eax
    rep     movsw
    ;cpuid
    
    mov     ecx,Beat_Bass_Size/2
    mov     ax,8500
    mov     edi,[AddressBass]
    rep     stosw
    mov     [edi-26*2],dword 0x4268C738   ;51000 17000  38c76842

    
;=============================================    
    finit                   ; init coprocessor
    ; mov     [FLAG],cl
    pop     edi             ; ***offset rhythm [AddressBass]
    lea     ebx,[edi-0x109a00*2]
    push    ebx             ; ***save 
    mov     esi,Freq_Bass   ; offset frequency
    mov     ecx,58          ; number of note
    call    @tetris_wav     ; compute waveform
    
    mov     ecx,0x00109a00/4
    pop     esi             ; ***
    lea     edi,[esi+0x00109a00]
    rep     movsd
;=============================================   
    inc     [FLAG]
    mov     ebx,[WaveHeader.lpData]
    mov     edi,Beat_Melody ; offset rhythm
    
    mov     ecx,2
A01:
    push    ecx
    push    ebx
    finit                   ; init coprocessor
    mov     esi,Freq_Melody ; offset frequency
    mov     ecx,37          ; number of note
    call    @tetris_wav     ; compute waveform
    
    pop     ebx
    add     ebx,0x00109a00*2
    mov     edi,[AddressMelody]  ; offset rhythm
    
    pop     ecx
    loop    A01
    
;================================================
    
    invoke  waveOutOpen,hWaveOut,-1,WaveFormat,0,0,0
    test    eax,eax
    jnz     @error
    invoke  waveOutPrepareHeader,[hWaveOut],WaveHeader,sizeof.WAVEHDR
    test    eax,eax
    jnz     @error

    invoke  waveOutWrite,[hWaveOut],WaveHeader,sizeof.WAVEHDR
    test    eax,eax
    jnz     @error

    invoke  Sleep,40000     ;hang up
    
    invoke  waveOutReset,[hWaveOut]
    ; invoke  waveOutClose,[hWaveOut]
    invoke  waveOutUnprepareHeader,[hWaveOut],WaveHeader,sizeof.WAVEHDR
        
@error:
    invoke  ExitProcess,0

;=================================================================
;       ***** procedures ******
;=================================================================
align 16
@tetris_wav:
    fld     [Zero_Cinque]
    fld     [Zero_Uno]

@change_note:
    fld     dword [esi]
    fld     st
    fmul    [PI_x_Rcp]
    fxch
    fmul    [Zero_ZZ_Uno]
    fld1
    fxch
    fsubp   st1,st0
    fmul    [Due_Punto_Tre]
    fxch    st2
    fxch

@@: 
    fld     st
    fsub    [DPHIF]
    fmul    st0,st2
    fadd    [DPHIF]
    fstp    [DPHIF]
    fld     [Amp_Env]
    fmul    [Zero_Nove]
    fld     st
    fsub    [Filt_Env]
    fmul    st0,st3
    fadd    [Filt_Env]
    fstp    [Filt_Env]
    fstp    [Amp_Env]
    fldpi
    fld     [Phase]
    fadd    [DPHIF]

    fcom    st1
    fnstsw  ax
    test    ah,1
    jnz     @no_zero

    fxch
    fld     st0
    fadd    st0,st1

    fsub    st2,st0
    fstp    st
    fxch

@no_zero:
    fst     [Phase]
    fxch    st4
    fld     st0
    fmul    [Y_0]
    fadd    st0,st5
    fcos
    fld     st0
    fadd    [Y_0]
    fmul    st0,st7
    fstp    [Y_0]
    fxch
    fld     st0
    fmul    [Y_1]
    fxch    st1
    fxch    st3
    faddp   st1,st0
    fadd    st0,st5
    fcos
    fld     st0
    fadd    [Y_1]
    fmul    st0,st7
    fstp    [Y_1]
    fsubp   st1,st0
    fmul    [Filt_Env]
    fmul    [Amp_Sample]

    cmp     [FLAG],1
    jnc     @add_melody

    fistp   word [ebx]
    fxch    st3
    fstp    st0

    add     ebx,2
    sub     word [edi],1
    jnz     @b

    fstp    st0
    fxch
    fstp    st0

    mov     [Amp_Env],0x3f800000
    add     edi,2
    add     esi,4
    sub     ecx,1
    jnz     @change_note

    ret

@add_melody:
    fild    word [ebx]
    faddp   st1,st0

    fistp   word [ebx]
    fxch    st3
    fstp    st0

    add     ebx,2
    sub     word [edi],1
    jnz     @b

    fstp    st0
    fxch
    fstp    st0

    mov     [Amp_Env],0x3f800000
    add     edi,2
    add     esi,4
    sub     ecx,1
    jnz     @change_note

    ret
;=============================================
;以下通用于得到基址和api
align 4
kernel32_base:
    push    ebp
    push    0x30
    pop     edx
    mov     eax,[fs: edx]
    mov     eax,[eax+0x0C]
    mov     eax,[eax+0x1C]
.find_kernel32_base:
    mov     edx,[eax+0x20]
    mov     ebp,[eax+0x08]
    xor     ecx,ecx
    cmp     [edx+0x18],cl
    mov     eax,[eax]
    jnz     .find_kernel32_base
    mov     eax,ebp
    pop     ebp
    retn    0
;=============================================    
kernel32_func:
label .base dword at esp+4*4+4
    push    ebp
    push    ebx
    push    esi
    push    edi
;-----------------------------
    mov     ebp,[.base]
    mov     esi,libraries
    mov     edi,imports   
.prep:
    lodsb                       ;Load byte at address DS:(E)SI into AL
    movzx   ecx,al
.func:    
    mov     eax,[ebp+0x3C]      ;e_lfanew RVA NT Header
    mov     edx,[ebp+eax+0x78]  ;edx = RVA Data Directory
    add     edx,ebp             ;edx = RVA -> VA
.hash:
    ;----------------------------
    push    esi
    push    ecx
    
    mov     ecx,[edx+0x18]      ;以名称导出函数的总数 NumberOfNames
.srch: 
    jecxz   .done               ;ecx = 0 No More Exports
    dec     ecx
    mov     esi,[edx+0x20]      ;指向函数名地址表的RVA
    add     esi,ebp             ;RVA-> VA
    mov     esi,[esi+ecx*0x04]  ;esi = RVA Export Asciiz Index
    add     esi,ebp             ;esi = RVA -> VA 指向Ascii 串首
    xor     ebx,ebx             ;Null hash value
;--------------------------------
.calc: 
    lodsb                       ;al  = Char Export Asciiz
    rol     ebx,0x06            ;ebx = Hash Preparation
    xor     bl ,al              ;ebx = Hash Complete
    test    al ,al              ;al  = 0 Only For End of Asciiz
    jnz     .calc
;--------------------------------    
    cmp     ebx,[edi]           ;比较hash值
    jnz     .srch               ;不等，则比较下一个api串
    mov     ebx,[edx+0x24]      ;RVA AddressOfNameOrdinals 
    add     ebx,ebp             ;VA
    movzx   ecx,word [ebx+ecx*2]
    mov     ebx,[edx+0x1C]      ;RVA AddressOfFunctions
    add     ebx,ebp             ;VA
    mov     eax,[ebx+ecx*4]     ;Function RVA
    add     eax,ebp             ;VA
.done:
    pop     ecx
    pop     esi
    ;----------------------------
    stosd
    loop    .func               ;For All Functions
    cmp     [esi],cl            ;[esi] = 0 When We're Done
    jz      .exit               ;Exit When Done all
    push    edi
    mov     edi,esi
    push    esi                 ;szLibName
.skip: 
    lodsb
    test    al, al
    jz      .ok
    not     al
    stosb
    jmp     .skip
.ok:
    call    dword [LoadLibraryA];Get lpDLL
    mov     ebp,eax             ;ebp = lpDLL
    pop     edi
    jmp     .prep               ;For Num DLLs
    
.exit:
    pop edi
    pop esi
    pop ebx
    pop ebp

    retn 4