.586P
.587
locals
jumps
.model flat,STDCALL
include win32.inc           ; some 32-bit constants and structures

L equ <LARGE>

;
; Define the external functions we will be linking to
;
extrn            BeginPaint:PROC
extrn            CreateWindowExA:PROC
extrn            DefWindowProcA:PROC
extrn            DispatchMessageA:PROC
extrn            EndPaint:PROC
extrn            ExitProcess:PROC
extrn            FindWindowA:PROC
extrn            GetMessageA:PROC
extrn            GetModuleHandleA:PROC
extrn            GetStockObject:PROC
extrn            InvalidateRect:PROC
extrn            LoadCursorA:PROC
extrn            LoadIconA:PROC
extrn            MessageBoxA:PROC
extrn            PostQuitMessage:PROC
extrn            RegisterClassA:PROC
extrn            ShowWindow:PROC
extrn            SetWindowPos:PROC
extrn            TextOutA:PROC
extrn            TranslateMessage:PROC
extrn            UpdateWindow:PROC
extrn            CreateFileA:PROC
extrn            GetFileSize:PROC
extrn            CloseHandle:PROC
extrn            GlobalAlloc:PROC
extrn            GlobalHandle:PROC
extrn            GlobalFree:PROC
extrn            ReadFile:PROC
extrn            WriteFile:PROC
extrn            GlobalMemoryStatus:PROC
extrn            GetWindowTextA:PROC
extrn            MessageBeep:PROC
;
; for Unicode support, Win32 remaps some functions to either the Ansi or
; Wide char versions.  We will assume Ansi for this example.
;
CreateWindowEx   equ <CreateWindowExA>
DefWindowProc    equ <DefWindowProcA>
DispatchMessage  equ <DispatchMessageA>
FindWindow       equ <FindWindowA>
GetMessage       equ <GetMessageA>
GetModuleHandle  equ <GetModuleHandleA>
LoadCursor       equ <LoadCursorA>
LoadIcon         equ <LoadIconA>
MessageBox       equ <MessageBoxA>
RegisterClass    equ <RegisterClassA>
TextOut          equ <TextOutA>

.data
copyright        db 'Ingenieurbro Baumann, Dorsten',0

lppaint          PAINTSTRUCT <?>
msg              MSGSTRUCT   <?>
wc               WNDCLASS    <?>
hInst            dd 0
newhwnd          dd 0                           ;handle of mainwnd
childhwnd1       dd 0                           ;handle of childwindow
childhwnd2       dd 0

szTitleName      db 'Win32 Assembly Program /* complexFFT */'
zero             db 0
szAlternate      db '(Secondary)',0
szClassName      db 'ASMCLASS32',0
szPaint          db '*.flt wird transformiert nach *ft.fft',0
MSG_L            EQU ($-offset szPaint)-1
szTitleName1     db 'e:\<Ordner>\<name>.flt',0
szClassName1     db 'EDIT',0
szTitleName2     db 'START',0
szClassName2     db 'BUTTON',0

Outdat1          db 40 dup (0)                  ;Zieldatei
Indat            db 40 dup (0)                  ;Quelldatei

hIndat           dd 0
hOutdat1         dd 0
lenIndat         dd 0
lpOutdatBuf      dd 0    ;Adresse des beantragten Buffers
lenBuff          dd 0    ;L„nge des Buffers
count            dd 0    ;gelesene oder geschriebene Byte der letzten Operation
defControl       dw 0    ;Koprozessor Kontrollwort original
myControl        dw 0    ;mein privates Kontrollwort des Koprozessors
einhalb          dq 0.5
minus            dq -1.0

.code
;-----------------------------------------------------------------------------
;
; This is where control is received from the loader.
;
start:

        push    L 0
        call    GetModuleHandle         ; get hmod (in eax)
        mov     hInst, eax              ; hInstance is same as HMODULE
                                        ; in the Win32 world
        push    L 0
        push    offset szClassName
        call    FindWindow
        or      eax,eax
        jz      reg_class

        mov     [zero], ' '             ; space to modify title string

reg_class:
;
; initialize the WndClass structure
;
        mov     [wc.clsStyle], CS_HREDRAW + CS_VREDRAW + CS_GLOBALCLASS
        mov     [wc.clsLpfnWndProc], offset WndProc
        mov     [wc.clsCbClsExtra], 0
        mov     [wc.clsCbWndExtra], 0

        mov     eax, hInst
        mov     wc.clsHInstance, eax

        push    L IDI_APPLICATION
        push    L 0
        call    LoadIcon
        mov     wc.clsHIcon, eax

        push    L IDC_ARROW
        push    L 0
        call    LoadCursor
        mov     wc.clsHCursor, eax

        mov     wc.clsHbrBackground, COLOR_WINDOW + 1
        mov     dword ptr wc.clsLpszMenuName, 0
        mov     dword ptr wc.clsLpszClassName, offset szClassName

        push    offset wc
        call    RegisterClass
        
        push    L 0                      ; lpParam
        push    hInst                    ; hInstance
        push    L 0                      ; menu
        push    L 0                      ; parent hwnd
        push    L 100                    ; height
        push    L 600                    ; width
        push    L CW_USEDEFAULT          ; y
        push    L CW_USEDEFAULT          ; x
        push    L WS_OVERLAPPEDWINDOW    ; Style
        push    offset szTitleName       ; Title string
        push    offset szClassName       ; Class name
        push    L 0                      ; extra style
        call    CreateWindowEx
        mov     newhwnd, eax

        push    L SW_SHOWNORMAL
        push    newhwnd
        call    ShowWindow

        push    newhwnd
        call    UpdateWindow

        ;EDIT-Child
        push    L 0
        push    hInst
        push    L 0
        push    newhwnd
        push    L 20
        push    L 256
        push    L 26
        push    L 5
        push    L (WS_CHILD or WS_CAPTION or WS_VISIBLE)
        push    offset szTitleName1
        push    offset szClassName1
        push    L 0
        call    CreateWindowEx
        mov     childhwnd1,eax

        ;BUTTON-Child
        push    L 0
        push    hInst
        push    L 0
        push    newhwnd
        push    L 50
        push    L 100
        push    L 10
        push    L 420
        push    L (WS_CHILD or 00000000h or WS_VISIBLE)
        push    offset szTitleName2
        push    offset szClassName2
        push    L 0
        call    CreateWindowEx
        mov     childhwnd2,eax

msg_loop:
        push    L 0
        push    L 0
        push    L 0
        push    offset msg
        call    GetMessage

        cmp     ax, 0
        je      end_loop

        push    offset msg
        call    TranslateMessage

        push    offset msg
        call    DispatchMessage

        jmp     msg_loop

end_loop:
        push    msg.msWPARAM
        call    ExitProcess

        ; we never get to here

;-----------------------------------------------------------------------------
WndProc          proc uses ebx edi esi, hwnd:DWORD, wmsg:DWORD, wparam:DWORD, lparam:DWORD
;
; WARNING: Win32 requires that EBX, EDI, and ESI be preserved!  We comply
; with this by listing those regs after the 'uses' statement in the 'proc'
; line.  This allows the Assembler to save them for us.
;
        LOCAL   theDC:DWORD

        cmp     wmsg, WM_DESTROY
        je      wmdestroy
        cmp     wmsg, WM_RBUTTONDOWN
        je      wmrbuttondown
        cmp     wmsg, WM_SIZE
        je      wmsize
        cmp     wmsg, WM_CREATE
        je      wmcreate
        cmp     wmsg, WM_LBUTTONDOWN
        je      wmlbuttondown
        cmp     wmsg, WM_PAINT
        je      wmpaint
        cmp     wmsg, WM_GETMINMAXINFO
        je      wmgetminmaxinfo
        cmp     wmsg, WM_CHAR
        je      wm_char
        cmp     wmsg, WM_COMMAND
        je      wmcommand

        jmp     defwndproc

wmcommand:
        ;EDIT-FELD
        mov     eax,lparam              ;handle of sending element
        cmp     eax,childhwnd1          ;handle of my element
        jne     wmcommand1              ;was it not
        mov     eax,wparam              ;HI:message, LO:ID
        sar     eax,16                  ;ax message
        cmp     ax,0300h                ;EN_CHANGE
        jne     wmcommand1              ;not EN_CHANGE
        jmp     finish                  ;ready

wmcommand1:
        ;BUTTON mit START
        mov     eax,lparam              ;handle of sending element
        cmp     eax,childhwnd2          ;my ?
        jne     defwndproc              ;nein

        ;Dateinamen nach Indat bernehmen
        push    L 32                    ;count asciis
        push    offset Indat            ;to buffer
        push    childhwnd1              ;from element with this handle
        call    GetWindowTextA          ;copy text

        ;Dateinamen fr Ausgabedatei kopieren
        cld
        mov     ecx,L 40
        mov     esi,offset Indat
        mov     edi,offset Outdat1
        rep     movsb

        ;*.flt „ndern in *ft.fft
        mov     esi,offset Outdat1
        mov     ecx,L 40
search: mov     al,[esi]
        cmp     al,'.'
        je      change
        inc     esi
        loop    search

change: mov     edx,dword ptr[esi]
        mov     ax,'tf'
        mov     [esi],ax
        add     esi,L 2
        mov     dword ptr[esi],edx
        cmp     edx,'tlf.'
        jne     doit
        mov     edx,'tff.'
        mov     dword ptr[esi],edx

        jmp     doit                    ;Start

wmpaint:
        push    offset lppaint
        push    hwnd
        call    BeginPaint
        mov     theDC, eax

        push    L MSG_L           ; length of string
        push    offset szPaint    ; string
        push    L 5               ; y
        push    L 5               ; x
        push    theDC             ; the DC
        call    TextOut

        push    offset lppaint
        push    hwnd
        call    EndPaint

        mov     eax, 0
        jmp     finish

wmcreate:
        mov     eax, 0
        jmp     finish

defwndproc:
        push    lparam
        push    wparam
        push    wmsg
        push    hwnd
        call    DefWindowProc
        jmp     finish

wmdestroy:
        push    L 0
        call    PostQuitMessage
        mov     eax, 0
        jmp     finish

wmlbuttondown:

        jmp     finish

wmrbuttondown:

        ;Fenster berholen
        push    L 0
        push    L 0
        push    hwnd
        call    InvalidateRect          

        jmp     finish

wmsize:
        mov     eax, 0
        jmp     finish

wmgetminmaxinfo:
        mov     ebx, lparam  ; ptr to minmaxinfo struct
        mov     [(MINMAXINFO ptr ebx).mintrackposition_x] , 350
        mov     [(MINMAXINFO ptr ebx).mintrackposition_y] , 60
        mov     eax, 0
        jmp     finish

wm_char:
        jmp finish

doit:   ;Koprozessor Kontrollwort setzen
        fstcw   defControl
        mov     ax,defControl
        or      ax,0001001110111111b
        mov     myControl,ax
        fldcw   myControl
        feni

        ;Eingangsdatendatei ”ffnen
        push    L 0                     ;hTemplateFile
        push    L 020h                  ;dwAttrsAndFlag
        push    L 04h                   ;dwCreate
        push    L 0                     ;lpSecurityAttributes
        push    L 0                     ;dwShareMode
        push    L 080000000h            ;Generic_Read
        push    offset Indat            ;Dateinamenadresse
        call    CreateFileA             ;”ffnen
        mov     hIndat,eax              ;Handle

        ;L„nge der Datei erfragen
        push    L 0                     ;lpdwFileSizeHigh
        push    eax                     ;Handle
        call    GetFileSize
        mov     lenIndat,eax            ;L„nge in Byte
        mov     lenBuff,eax

        ;Speicher fr Eingangsdaten beantragen
        push    eax
        push    L 0
        call    GlobalAlloc             ;Speicher beantragen
        cmp     eax,L 0                 ;erfolgreich ?
        je      Fehler                  ;nein

        ;Anfangsadressen zuweisen
        mov     lpOutdatBuf,eax         ;zugewiesene Anfangsadresse*


        ;Real-Data einlesen
        push    L 0                     ;keine overlapped-Struktur
        push    offset count            ;gelesene Byte
        push    lenIndat                ;zu lesende Byte
        push    lpOutdatBuf             ;Adresse des Buffers
        push    hIndat                  ;Handle der Datei
        call    ReadFile                ;lesen

        ;Indat schlieáen
        push    hIndat
        call    CloseHandle

        ;Ausgangsdatendatei ”ffnen
        push    L 0                     ;hTemplateFile
        push    L 020h                  ;dwAttrsAndFlag
        push    L 04h                   ;dwCreate
        push    L 0                     ;lpSecurityAttributes
        push    L 0                     ;dwShareMode
        push    L 040000000h            ;Generic_Write
        push    offset Outdat1          ;Dateinamenadresse
        call    CreateFileA             ;”ffnen
        mov     hOutdat1,eax            ;Handle

        call    imagFFT                 ;Tranformation

        ;Outdat1 schlieáen
        push    hOutdat1
        call    CloseHandle

        push    lpOutdatBuf             ;Handle erfragen fr OutdatBuf
        call    GlobalHandle
        push    eax
        call    GlobalFree              ;Speicher freigeben

finish: ret
        
WndProc          endp
;-----------------------------------------------------------------------------
imagFFT   proc

        LOCAL   cntn:DWORD,cntn2:DWORD,bits:DWORD,maxIndex:DWORD,\
k:DWORD,istep:DWORD,wr:DWORD,wi:DWORD,j:DWORD,jk:DWORD,\
ik:DWORD,tr:DWORD,ti:DWORD,help:DWORD,cntErg:DWORD,\
a1:DWORD,a2:DWORD,a3:DWORD,a4:DWORD,a5:DWORD,a6:DWORD,i:DWORD,m:DWORD,\
jadr:DWORD,jkadr:DWORD,ikadr:DWORD,iadr:DWORD,ImagOff:DWORD

        ;make fft
        ;einige Vorbereitungen
        mov     eax,lenIndat            ;Anzahl der Byte in Indat
        sar     eax,1                   ;/2=Offset Imag
        mov     ImagOff,eax
        sar     eax,2                   ;/2/4=/8=Anzahl der Abtastwerte
        mov     cntn,eax                ;lokal merken
        mov     ebx,eax
        sar     eax,1                   ;/2=halbe Anzahl
        mov     cntn2,eax               ;lokal merken
        dec     ebx                     ;maxIndex=Anzahl - 1
        mov     maxIndex,ebx            ;merken

        ;Bit-Breite des Index bestimmen falls weniger als 32 Bit Anzahl
        fld1
        fild    cntn                    ;1
        fyl2x                           ;logarithmus dualis cnt
        fistp   bits                    ;h”chtes Bit der L„nge  z.B. 1000b=3
        dec     bits                    ;h”chstes Bit im Index0 dann 0111b=2

        ;in-place bit reverse shuffling
        mov     edx,L 0                 ;Z„hler
rodel1: mov     esi,edx                 ;Index Eingangsfeld
        mov     edi,edx                 ;clear
        mov     ecx,bits                ;Bitbreite Index
mir1:   mov     ebx,bits
        sub     ebx,ecx                 ;Offset des gesp. Bit
        bt      esi,ecx                 ;in esi teste Bit Nr. ecx
        jnc     noset                   ;dieses Bit ist nicht gesetzt
        bts     edi,ebx                 ;set mirrored
        jmp     set
noset:  btr     edi,ebx
set:    dec     ecx                     ;next bit
        cmp     ecx,L 0                 ;alle?
        jge     mir1                    ;nein        
        cmp     esi,edi                 ;Zielindex < Quellindex ?
        jge     letitbe                 ;ja
        sal     esi,2                   ;Index0 * 4 = Offset
        add     esi,lpOutdatBuf         ;Basis Source
        sal     edi,2                   ;Index0 * 4 = Offset
        add     edi,lpOutdatBuf         ;Basis Dest
        mov     eax,dword ptr [esi]     ;source word real
        push    eax                     ;zwischenspeichern
        mov     eax,dword ptr [edi]
        mov     dword ptr [esi],eax
        pop     eax
        mov     dword ptr [edi],eax
        add     esi,ImagOff
        add     edi,ImagOff
        mov     eax,dword ptr [esi]     ;source word imag
        push    eax
        mov     eax,dword ptr [edi]
        mov     dword ptr [esi],eax
        pop     eax
        mov     dword ptr [edi],eax
letitbe:inc     edx                     ;Index + 1
        cmp     edx,maxIndex            ;bis maxIndex
        jle     rodel1                  ;next

;***************************checkedcheckedchecked*****************************

        ;jetzt die eigentliche Transformation, in-place, Format 4 Byte Short-Real
trans:  mov     eax,cntn
        mov     k,eax
        mov     edx,L 1         ;Variable l

while:  cmp     edx,k                   ;while l<k
        jge     readyfft

                mov     eax,edx
                sal     eax,1
                mov     istep,eax

                mov     ecx,L 1                 ;for m=1 to l step 1
                mov     m,ecx
                for1:   mov     eax,L 1         ;eins
                        sub     eax,ecx         ;1-m
                        mov     help,eax        ;zwischenspeichern
                        fild    help            ;laden
                        mov     help,edx        ;l
                        fidiv   help            ;(1-m)/l
                        fldpi                   ;pi
                        fmul    minus
                        fmulp   st(1)           ;(1-m)/l*pi
                        fld     st(0)
                        fcos                    ;cos((1-m)/l*pi)
                        fstp    wr              ;=wr
                        fsin                    ;sin((1-m)/l*pi)
                        fstp    wi              ;=wi   ;checked, seems o.k.                                
                        mov     m,ecx           ;Schleifenvariable „uáere Schleife retten            

                        for2:   mov     i,ecx                   ;for i=m to k step istep
                                ;Indizes
                                add     ecx,edx                 ;i + l
                                mov     j,ecx                   ;=j
                                add     ecx,k                   ;j + k
                                mov     jk,ecx                  ;= jk
                                mov     ecx,i                   ;i
                                add     ecx,k                   ;i + k
                                mov     ik,ecx                  ;= ik
                                ;Adresse Index j
                                mov     ebx,lpOutdatBuf
                                mov     eax,j
                                dec     eax
                                sal     eax,2
                                add     eax,ebx
                                mov     jadr,eax
                                ;Adresse Index jk
                                mov     eax,jk
                                dec     eax
                                sal     eax,2
                                add     eax,ebx
                                mov     jkadr,eax
                                ;Adresse Index i
                                mov     eax,i
                                dec     eax
                                sal     eax,2
                                add     eax,ebx
                                mov     iadr,eax
                                ;Adresse Index ik
                                mov     eax,ik
                                dec     eax
                                sal     eax,2
                                add     eax,ebx
                                mov     ikadr,eax
                                ;tr ausrechnen
                                fld     wr                      ;wr laden
                                mov     eax,jadr
                                fmul    dword ptr [eax]         ;Abtastwert laden                               
                                fld     wi                      ;wi laden
                                mov     eax,jkadr
                                fmul    dword ptr [eax]         ;Abtastwert laden                                
                                fsubp   st(1),st                ;Differenz tr
                                fstp    tr                      ;merken
                                ;ti ausrechnen
                                mov     eax,jkadr
                                fld     dword ptr [eax]         ;Abtastwert                               
                                fmul    wr                      ;wr * fk(j+k)
                                fld     wi
                                mov     eax,jadr                ;Adresse Abtastwert fk(j)
                                fmul    dword ptr [eax]         ;Abtastwert                                
                                faddp   st(1),st                ;Summe ti
                                fstp    ti                      ;merken
                                ;fk(j) ausrechnen checked
                                mov     eax,iadr
                                fld     dword ptr [eax]         ;Abtastwert fk(i)                                
                                fsub    tr                      ;neuer fk(j)                                                                
                                mov     eax,jadr                               
                                fstp    dword ptr [eax]         ;ablegen Ergebnis
                                ;fk(j+k) ausrechnen
                                mov     eax,ikadr
                                fld     dword ptr [eax]         ;Abtastwert fk(i+k)                                
                                fsub    ti                      ;-ti=neuer fk(j+k)
                                mov     eax,jkadr               ;Index jk
                                fstp    dword ptr [eax]         ;Ergebnis ablegen
                                ;fk(i) ausrechnen
                                mov     ebx,iadr
                                fld     dword ptr [ebx]         ;fk(i)                               
                                fadd    tr                      ;+tr=neuer fk(i)                               
                                fstp    dword ptr [ebx]         ;Ergebnis ablegen
                                ;fk(i+k) ausrechnen
                                mov     ebx,ikadr               ;Index ik
                                fld     dword ptr [ebx]         ;Wert                               
                                fadd    ti                      ;+ti                                
                                fstp    dword ptr [ebx]         ;Ergebnis ablegen
                        ;innere Schleife                                      
                        mov     ecx,i           ;Schleifenvariable
                        add     ecx,istep       ;Step
                        cmp     ecx,k           ;Abbruch
                        jle     for2            ;next i

                inc     m               ;Schleifenvariable m
                mov     ecx,m           
                cmp     ecx,edx         ;Abbruch
                jle     for1            ;next m
 
        mov     edx,istep               ;l=istep
        jmp     while                   ;wend

readyfft:
        
        ;Normieren der Spektralwerte
        mov     ecx,cntn                ;N
        sal     ecx,1                   ;2N
div:    mov     ebx,ecx
        dec     ebx                     ;-1=Index
        sal     ebx,2                   ;*4=Offset
        add     ebx,lpOutdatBuf       
        fld     dword ptr [ebx]
        fidiv   cntn2                   ;/(N/2)        
        fstp    dword ptr [ebx]
        loop    div

        ;Buffer leerschreiben
        push    L 0
        push    offset count
        mov     ebx,cntn
        sal     ebx,3
        push    ebx                     ;Anzahl zu schreibende Byte
        push    lpOutdatBuf             ;Adresse Buffer
        push    hOutdat1                ;Handle der Datei
        call    WriteFile               ;schreiben

        push    L 0
        call    MessageBeep

        ret

imagFFT   endp
;-----------------------------------------------------------------------------

Fehler: push    L 0
        call    MessageBeep
        jmp     finish

;-----------------------------------------------------------------------------
public WndProc
ends
end start
