ECE291 Computer Engineering II Lockwood, Spring 1999
TunaFish GuitarTuner Project

Team Members:

Joshua Berry: Program flow, FFT

David Marshall: Sound, FFT

Joanna Washburn: Command handling

Tim Wilson: Graphics
 


 


 

Introduction

    The Tunafish Music Tuner is a piece of software that allows the user to tune an instrument.  The Music
Tuner has a tone that matches the pitch of each of the twelve notes in an octave.  When the software is in
play back mode and one of the buttons is pressed, the tuner plays a pitch in short segments until the button is
pressed again, or another button is pressed.  The frequency of the pitch is shown on the display, with a bar at
the fundamental frequency, or the frequency with the greatest intensity.  When in read in mode, the user can
play an instrument, and the frequency of the sound will be displayed on the screen.  If a button is first
pressed, a bar displaying the fundamental frequency of that pitch is displayed.  Also, a bar showing the
fundamental pitch of the sound played is displayed, and based on the positions of these bars, the user can
adjust the pitch of the note played to match the target frequency of the note that was pressed.
 

Problem Description

In order for our music tuner to work, we must be able to read in sound from an instrument, and perform a
fourier transform on that sound.  The code for the transform is all original, written by our group, which makes
this project unique.  Once the transform has been computed, we can categorize each frequency range in a
defined number of bins, and then display each bin on the screen, in histogram form, in essence displaying the
wave of that sound.  This software will be mouse based, which will require a mouse handler which will be
called either every time the mouse moves on the screen.  This will be accomplished by using an interrupt, and
setting the interrupt pointer of the mouse to our new procedure.  Next, we must manipulate the DMA to be
able to read in sound.  This will require altering and adding functionality to the sound library provided for us,
and setting up two separate pages in the DMA.  The separate pages will allow us to record sounds of
variable length without the restriction of the page size.  We can accomplish this by writing to one page of the
DMA while outputting from the other page. The ability of our software to read in and analyze sound is
another unique aspect of our project.  Once the sound is read in, it will need to be stored in a wav file, to be
analyzed.  Next, we will perform an fft on the input data, to obtain a range of frequencies, with their
respective intensities, which will be stored in an array of bins.  A somewhat dynamic GUI will be needed,
and for this we will read in a tiled pcx file, and display the graphics for the buttons and borders of the
interface by accessing the current tile to be displayed.  An array of pointers to tiles will indicate which tile
should be printed to what location on the screen, and will be constantly updated, based on the actions of the
mouse.  Over this skin, the display will be drawn, which will be a histogram, using the data from the bins in
the fft structure.  The display will have several features, depending upon the mode we are in.  For instance,
for tuning, a button will be selected indicating the note to be tuned to.  The display will then draw a bar at the
desired frequency, as well as one at the principle frequency of the sound that was played from the
instrument.  Also, the wave form of the sound played will be displayed.  The code for the display has the
ability to zoom in on the data, displaying either 256, 128, 64, 32, 16, or 8 frequency bins, depending on a
variable passed to the procedure.  Then, we will draw the mouse on top of the graphics.  This will be
accomplished by double buffering.  The skin will be read into a 64k buffer, and then the graphics will be
written over the background of the display, and finally, the mouse will be drawn over everything.  Then, the
entire buffer will be dumped onto the screen.  This eliminates flicker on the screen.  The most difficult
portions of this project will be designing an efficient fft algorithm, and reading in sound of variable lengths and
magnitudes from the instrument.  The graphics will require several special cases, for the zooming capabilities,
and also for the skin.  The buttons will show that they are pressed, and need to be depressed once either
they are pressed again, or another button is pressed.  Also, the display will respond differently depending on
what mode the software is in.  Once this project is completed, it will provide a very useful music tuner.
 

Constants
 
STOP equ 0
PLAY equ 1
RECORD equ 2
QUIT equ 3
 _SB_HSvReg_Rec equ 1  
; record at 1 = HS, 0 = reg
 

Structures

Struct   PCXfile 
MANUFACTURER DB 10     ; A ZSoft PCX File
VERSION  DB ?
ENCODING  DB 1
BITS_PER_PIXEL DB ? ; 1,2,4,8,24 (8 for ECE291 images)
XMIN  DW ?
YMIN DW ?
XMAX  DW ?      ; Window
YMAX  DW ?
HORZ_DPI  DW ?      ; Horizontal Dots per inch
VERT_DPI  DW ?      ; Vertical Dots per inch
PALETTE DB 48 DUP (?) ; =< 16 colors
RESERVED  DB ?
COLOR_PLANES  DB ?
BYTES_PER_LINE  DW ?
PALETTE_TYPE  DW ?
HSCR_SIZE  DW ?      ; only supported by
VSCR_SIZE  DW ?      ; PBrush IV or higher
FILLER  DB 54 DUP (?)
IMAGE_DATA DB FileSize DB ? ; RLE-Encoded Data     ; (line-by-line)
PALETTE_MARK DB 12     ; Indicates Trailer Palette
PALETTE_256C DB 256 DUP('RGB') ; 768 Bytes of       ; Palette Data

Struct     FFT 
FFTSEG DW SEG SEGMENT SAMPLEBUFFER ; pointer ; to current part of Samplebuffer to  ; analyze
FFTOFF DW OFFSET OFFSET SAMPLEBUFFER
ENDOFBUFFER DW 0 ; used to determine if not      ; enough data in buffer to performFFT
BINCOUNT DW 128 ; Variable containing the     ; number of bins in the range to be   ; displayed on the screen
BIN DB 128 DUP (0) ; frequency bin array ; with magnitude value
GRAPHICS DB 256X128 DUP (255) ; visual data to ; put to screen use the bin[] data to ; calculate this
FUNFREQ DW ? ; Fundamental Freq identified
FUNBIN DB 35
TARGETFREQ DW 440  ; Target Fundamental Freq
TARGETBIN DB 43

Struct     mousePos 
DW 0 ; X-pos 0 to 319
DW 0 ; Y-pos 0 to 199
LB  DB 1 ; Left button status 0 if down, ; 1 if up.

Struct     SampleType 
INSTR  DB 0 ; index to table that contains  ; Instr names
NOTE  DB 0 ; Pitch to play: 0=A, 1=A#/Bb,   ; 2=B, ... 11=Ab/G#
REQUEST DB STOP ; user request, either PLAY  ; or STOP
STATUS  DB STOP ; actual status of player,   ; PLAY or STOP

Struct     WaveHdr
FORMAT  DB 'RIFF' ; Windows wav PCM format
FILELEN  DD ? ; Filelength
WAVEFMT  DB 'WAVEfmt_'
FMT_LEN  DD ?
FMT_TAG  DW ?
CHANNEL  DW ?
SAMPLES  DD ? ; Number of samples
BYTESPS  DD ?
BKALIGN  DW ?
BITSPS DW ?
DATA  DB 'data'
DATALEN  DD ?

Struct     SkinTile 
tile db 16*10 = 160 bytes per tile

Struct     COMP_STUCT
R REAL8 ?
I REAL8 ?
 
 

Variables
 
tempbufferdb 64000 dup (?) A buffer large enough to hold the compress data from a PCX file, including the header and trailer. Will use an entire segment
tempbuffer2 db 64000 dup (?) Same as tempbuffer
SkinArray db 200 dup (160) Array that is about 200 elements long, each element is 160 bytes long. This holds all of the tiles that will be printed to the screen.
TileIndex db 200 dup (?) Array 200 bytes long, containing pointers to SkinArray
screenBuffer db 6400 dup (?) Double buffer for mode 13h screen
SampleBuffer db 16384 dup (0) Sound sample buffer. Will get broken into 2 pieces on the same page for smooth DMA transfers to and from SoundBlaster
SkinTile 16X10 bytes of pixel data 
MouseCursor db 400 dup (?) 10X10 array of pixels. Use palette 255 to denote invisible color also, make icon point to the upper left corner
Mode db PLAY Mode will indicate PLAY mode, record mode, or QUIT initialize to PLAY mode
NewCommand db 0  0 if nothing other than mouse or datascreen to update 1 if button pressed, wave file finished, etc.
sbuf_page db ?  Used for sound 
sbuf_offset dw ? Used for sound 
sbuf_length dw 8192  8 k - all that is guaranteed to not cross a page
finalbuffersize dw ? Used for sound
mycounter dw -1  Originally –1, for switching between buffer
needrefill dw 0 Used for sound
wavfile db 'AAA.wav',0 ; 0  
        db 'Asp.wav',0 ;1  
        db 'BBB.wav',0 ; 2  
        db 'CCC.wav',0 ; 3  
        db 'Csp.wav',0 ; 4  
        db 'DDD.wav',0 ; 5  
        db 'Dsp.wav',0 ; 6  
        db 'EEE.wav',0 ; 7  
        db 'FFF.wav',0 ; 8  
        db 'Fsp.wav',0 ; 9  
        db 'GGG.wav',0 ; 10  
        db 'Gsp.wav',0 ; 11 
        db 'vic.wav',0 ; 12
null terminated file names, 8 bytes/file 
0 - 15 is 1st (default) instrument = 128 bytes 

other instruments can be added as 15 - 31, etc.

fileno dw ?  file handle
wavremaining dd 0 Used for sound
wavlength dd 0 Used for sound
wavdone db 0 Used for sound
loadbuf WaveHdr_STRUCT < >  Buffer withWavefile WaveHdr
RecordDone db 0 Flag to indicate when enough recorded samples have been accrued
pitch SampleType < > Pitch is a Sampletype structure
fft FFT_STRUCT < >
Xvar COMP_STRUCT < > Complex FFT variables
Yvar COMP_STRUCT < > Complex FFT variables
Res COMP_STRUCT < > Complex FFT variables
Iteration  db      1 FFT variables
Var1024     Real8   1024.0 FFT variables/constants
Var256      Real8   256.0 FFT variables/constants
Var128      Real8   128.0 FFT variables/constants
Var2        Real8   2.0 FFT variables/constants
Var0        Real8   0.0 FFT variables/constants
ScaleIN     Real8   2.0 FFT variables/constants
ScaleOUT    Real8   4.0 FFT variables/constants
Buffer2Disk seg fft, offset fft.bin, 128 FFT variables
ITempx      qword   ? FFT variables
RTempx      Real8   ? FFT variables
ResultVar   qword   ? FFT variables
mousePos mousePos_STRUCT< >
BugFix db ? For some reason this location in memory gets written into.  So, this byte makes sure nothing important is written over.
 

Macros
 
ReadFile name(zero terminating string), es:di bufferaddr, numbytes,  set carry flag if an error occurred
UpdateScrn  bulk copy of the 64000 byte screenBuff to mode 13h scrn
ChangeButton Author: Joanna Washburn  
Input:cx is how many to write (2 or 4) 
      bx is which tile to start writing 
Output: changes tile index to new tiles 
 
FindLeftCorner Author: Joanna Washburn 
Input: Takes Tile Number from AccessTileIndex  
Output: finds top left corner of 4 tile button in bx 
 
AccessTileIndex Author: Joanna Washburn 
Input: mouse position 
Output: where on screen you are in bx 
  what tile is there in ax 
 
ModeVideo13 set Model13h VGA graphics
ModeTest Set VGA for 80x25 text mode
movQW dst, sr Josh's -- description: performs a Quad word memory to memory copy that is optimized
fof speed. Uses eax and ecx for imtermediate steps
ClearQW add Josh's -- description: resets a QWORD at location addr to zero. Uses eax for intermediate steps
DosExit  exit to dos 
 

External Procedures

SoundLib functions
Code:   Micheal Urman

SB_Init:near
SB_Clean:near
SB_Play:near
SB_Stop:near
SB_SetCallback:near
SB_SingleCycle:near

Procedures

MouseInstall
Author: Joanna Washburn
    Input: None
    Output: None
    Purpose: MouseInstall instructs the mouse driver to call the Mousehandler routine for specified clicks.
        Three calls to Int 33h routines must be made in order to: reset the mouse driver, show the mouse cursor, and set
        MouseHandler to be the user event handler for left-mouse-button (LMB) clicks.

MouseUninstall
Author: Joanna Washburn
    Input: None
    Output: None
    Purpose: MouseUninstall will restore the mouse driver to it's original state by first hiding the mouse cursor, then resetting the driver.

MouseHandler
Author: Joanna Washburn
    Input: AX = event mask (same format as described in MouseInstall above)
                BX = mouse button status
                    Bit 0: LMB activated
                    Bit 1: RMB activated
                    Bit 2: MMB activated
                CX = horizontal mouse position
                DX = vertical mouse position
                DS = data segment of the mouse driver
    Output: MousePos.X = horizontal position of mouse
                  MousePos.Y = vertical position of mouse
                  MousePos.LB = status of the left button (pressed or released)
                  NewCommand = whether or not left mouse button is pressed.
    Description: MouseHandler will be called by the mouse driver. It updates the MousePos structure which includes the horizontal
        position (X), the vertical postion (Y), and the status of the left mouse button (LB).  NewCommand also gets updated.

PerformCommand
Author: Joanna Washburn
    Input:  NewCommand = variable indicating whether or not the left mouse button is pressed
               MousePos structure
                Mode  = variable giving status of software (Play, Record, or Quit)
    Output:  Sample.inst  = the instrument chosen
                   Sample.note  = the pitch to be played
                   Fft.lowFreq  = low frequency to center around desired pitch
                   Fft.hiFreq  = high frequency to center around desired pitch
                   Mode = updated
                 tileIndex = updated
    Description:  PerformCommand will take inputs from the mouse handler and determine the mode, pitch, instrument, etc. that was
        selected by determining which tile was chosen.

DecompressPCX
Author: Tim Wilson
    Input: PCX file containing all of the default tiles that will be used in the GUI skin
    Output: The PCX file is stored in a temporary variable called tempbuffer
    Purpose: DecompressPCX uses several interrupt calls to open a specified PCX file and read the data into tempbuffer so that the file
        can be later stored as an array of tiles.
 

SetPalette
Author: Tim Wilson
    Input: tempbuffer = buffer of length 64000 which holds the data from the pcx file
    Output: Adjusts the palette settings to correspond to the ones used in the PCX file
    Purpose: SetPalette reads the palette information from either the header or trailer of the PCX file and sets the computer’s palette
        to match.
 

FillSkinArray
Auhtor: Tim Wilson
    Input: tempbuffer
    Output: SkinArray = an array containing the image data from the PCX file
    Purpose: FillSkinArray takes the image data from the PCX file and stores it in tiles; these tiles make up the array called SkinArray.
        Each tile is 160 bytes, or 16x10 pixels in dimension. The array has its own segment, and uses it all.
 

GenerateCurSkin
Author: Tim Wilson
    Input:  SkinArray = an array containing the image data from the PCX file
                tileIndex = an array containing pointers to tiles in SkinArray
    Output: Writes to the screen the current image of the GUI
    Purpose: GenerateCurSkin writes to the screen 200 tiles from SkinArray to the screen, as specified by tileIndex. TileIndex is an array
        200 bytes long, which specifies which tiles from SkinArray will be printed to which portions of the screen. TileIndex is updated
        each time the mouse interrupt updates detail and this function constantly redraws the screen based upon this base skinarray.

GenerateFFTGFX
Author: Tim Wilson
    Input: fft structure
    Output: Writes to the screen a graphic representation of the input sound wave
    Purpose: GenerateFFTGFX reads information from the fft structure, such as lowFreq, hiFreq, binCount, bin, and graphics, and creates
        a set of bars to indicate the strength of the signal at a given frequency. The greater the strength, the taller the bar at that frequency
        bin, and thus a set of bars, similar to a graphics equalizer, except with many more bars, will be displayed on the screen.

LoadMouse
Autor: Tim Wilson
   Found in graphics.inc file
   Input: Mouse.pcx = pcx file containing mouse cursor
   Output: MouseCursor = array containing decompressed image of mouse cursor
   Purpose:
      LoadMouse opens Mouse.pcx and stores the image data in the array
      MouseCursor.
 

OpenWav
 Author: David Marshall
 Derived from : Mike Urman's code
 Found in play.inc file
 Purpose:
    Open a .wav file and advances to the beginning of the data
 Input:
    Pitch SampleType < >
    SampleType_STRUCT STRUC
    INSTRU    DB 0 ; index to table that contains Instr names
    NOTE      DB 0 ; Pitch to play: 0=A, 1=A#/Bb, 2=B, ... 11=Ab/G#
    REQUEST   DB STOP ; user request, either PLAY or STOP
    STATUS    DB STOP ; actual status of player, PLAY or STOP
    SampleType_STRUCT ENDS
 Output:
    wavlength : gets size of total .wav
    wavremaining : gets size of total .wav because that is how much is left
 Description:
    Use INT 21h, Open File (3Dh) and Read File (3Fh)
 

MainPlayWav
 Author: David Marshall
 Derived from : Mike Urman's code
 Found in play.inc file
 Purpose:
    The control function that orchestrates the playing of a specified .wav file
 Input:
     Pitch SampleType<>
    SampleType_STRUCT STRUC
     INSTRU    DB 0 ; index to table that contains Instr names
     NOTE      DB 0 ; Pitch to play: 0=A, 1=A#/Bb, 2=B, ... 11=Ab/G#
     REQUEST   DB STOP ; user request, either PLAY or STOP
     STATUS    DB STOP ; actual status of player, PLAY or STOP
    SampleType_STRUCT ENDS
 Output:
    Sound of .wav
    Sample.status updated
 Description:
    1. Calculates linear address of buffer
    2. Set sbuf_length to 8192
    3. Determines 2 4K buffer that lie on same page
    4. initialize soundcard and install ISR
    5. Set up SoundHandler a fn of ISR
    6. Open .wav
    7. Play the .wav with all of the single cycle complexities
 

LoadHalfBuffer
 Author: David Marshall
 Derived from : Mike Urman's code
 Found in play.inc file
 Purpose:
    Takes a 1 or 0 in ax, and reads from the file into the
     appropriate half of sndbuf.
 Input:
    AX = identifies which half of sndbuf to write to
    sbuf_page =      db      ?
    sbuf_offset =    dw      ?
    sbuf_length =    dw      8192
 Output:
    finalbuffersize = how much data is in this final buffer
    wavdone = inc to 1 if done,
              inc to 2 on end case = interupt is called and says it needs
              refill so LoadHalfBuffer is called and loads nothing
              while other half buffer is being played
    wavremaining = wavremaining - bytes read in this load
 Description:
    each page is 64k
    our sndbuf is 16k
    we define our sbuf_length to be 8k
    we only write to 1/2 buffers or 4k pieces
 

SoundHandler
 Author: David Marshall
 Derived from : Mike Urman's code
 Found in play.inc file
 Purpose:
    SoundHandler is called whenever the DSP generates an interrupt
 Input:
    None
 Output:
    mycounter = increments it
    needrefill = increments it to 1 everytime
 Description:
    Installed by SB_SetCallback in library; called in MainPlayWav.
 

MainRecordWav
 Author: David Marshall
 Derived from : Mike Urman's code
 Found in record.inc file
 Purpose: Record a 1K sample
 Input:
      None
 Output:
      1024 samples in the sndbuf and the location of it via
       FFT_STRUCT STRUC
         FFTSEG       DW ?
         FFTOFF       DW ?
          ...
       FFT_STRUCT ENDS
 Description:
    1. Calculates linear address of buffer
    2. Set sbuf_length to 1024
    3. Determines 1 1K buffer of our 16K buffer that lies on one page
    4. Tell fft variable where buffer is
    5. initialize soundcard, turn off speakers, and install ISR
    6. Selects RecordSoundHandler far procedure to call from
        the SoundBlaster interrupt.
    7. Calls SB_Record

RecordSoundHandler
 Author: David Marshall
 Derived from : Mike Urman's code
 Found in record.inc file
 Purpose:
    SoundHandler is called whenever the DSP generates an interrupt
 Input:
    None
 Output:
    RecordDone = increments it to one when done
 Description:
    Installed by SB_SetCallback in library; called in MainPlayWav

WriteRecording
 Author:   David Marshall
 Found in record.inc file
 Purpose:  Mostly debugging uses, but it also would allow us to store our
                recorded sound for later uses

SB_Record
 Author: David Marshall
 Derived from : Mike Urman's code
 Found in Sblib291.asm file
 Description:
    Set up DMA (channel 0) to transfer to the memroy from SB
    Program the DSP for 8-bit cycle DMA mode transfer
    Programs DMA and DSP to record to specified buffer.
 Input :
    ax = offset of the sound buffer (relatve to page)
    bh = 0 for regular 8-bit Mono Single-cycle Transfer
       = 1 for 8-bit Mono High Speed Single-cycle Transfer).
    bl = page of the sound buffer
    cx = length of the sound buffer
 Output:
    a 1024 buffer of data in from mic

_ProgramDMA_Record
 Author: David Marshall
 Derived from : Mike Urman's code
 Found in Sblib291.asm file
 Description:
    Set up DMA (channel 0) to transfer to the memroy from SB
 Input:
    ax = page offset of the sound buffer
    bl = page # of the sound buffer
    cx = length of the sound buffer
 Output:
    none

_ProgramDSP_Record
 Author: David Marshall
 Derived from : Mike Urman's code
 Found in Sblib291.asm file
 Description:
     Set up SB DSP to record an 8-bit Mono Single-cycle transfer
     1. Set the DSP transfer Time Constant
     For reg
        2. Send an I/O command folowed by data transfer count
     For HS
        2. Set the DSP block size
        3. Send an I/O command to start HS SC DMA mode transfer.
 Input:
     cx = length of the sound (transfer count value will be one byte less than
             actual length of sound)
     bh = 0 for regular 8-bit Mono Single-cycle Transfer
          = 1 for 8-bit Mono High Speed Single-cycle Transfer
            (maybe we need high speed for real time action)
 Output:
     none

_TurnOffSpeakers
 Author: David Marshall
 Found in Sblib291.asm file
 Description:
     Turns off speakers
 Input: none
 Output: none

SB_Init_Record
 Author: David Marshall
 Derived from : Mike Urman's code
 Found in Sblib291.asm file
 Description:
    Attempts Initialization the sound card and reports on success/failure
 Input: none
 Output:
    carry flag: set on installation failure
    SB_BaseAddr, SB_IRQ, SB_DMA_Low set appropriately
    ISR installed
 

ComplexMul
 Author: Joshua Berry
 Found in fft.inc file
 Purpose:
     Peform necessary multiplication using complex numbers on FP stack.
     Complex multiplication = 4 real multiplications, 1 real add, and 1 read sub.
  Input:
     Xvar COMP_STRUCT < >
     Yvar COMP_STRUCT < >
  Ouput:
     Res COMP_STRUCT < >

PerformFFT
 Author: David Marshall and Joshua Berry
 Found in fft.inc file
 Purpose:
     Implement the FFT algorithm (decimation in frequency) (Fast DFT)
 Input:
     1st half of tempBuffer (serves as 2 buffer dividing tempBuffer in 2)
     Samples are in a+jb fashion, where a and b are Real 8
 Output:
     1st quarter of tempBuffer.  1024 results in bit reversal order.
     Results are of same complex convention

ConvIntFL
 Author: David Marshall and Joshua Berry
 Found in fft.inc file
 Purpose:
     Convert an integer to REAL 8 format.  Then subtract 128 and divide by 128.
     Then result is complex Real8 samples valued between 1 and -1, which is
     the required format for the Perform FFT function.
 Input:
     fft = var of type
       FFT_STRUCT STRUC
         FFTSEG       DW ?
         FFTOFF       DW ?
         ....
       FFT_STRUCT ENDS
 Output:
      tempBuffer <-- 0...16k (1024 of FFT_STRUCT)

FinalizeResult
 Author: David Marshall and Joshua Berry
 Found in fft.inc file
  Description:
     Get the 1st 128 bins (the lower frequencies) by
     feeding index we want through bit reversal, indexing memory with it
     to get the value (a Complex number).
     Calculate the Magnitude (Real8 between 0 and 1) (Net whole signal = 1).
     Scale by 256.  (so value fits in a byte).
     Then store in corresponding bin.
 Input:
     1st half of tempBuffer
 Output:
     fft = a var of type
        FFT_STRUCT STRUC
         ....
         BINCOUNT     DW 128
         BIN          DB 128 DUP (0)
         ....
        FFT_STRUCT ENDS

BitReverseMap
 Author: David Marshall
 Found in fft.inc file
 Purpose:
     To Return the bit reversal of an index so we can retrieve the value
     of the original index from memory; assuming 0 to 1023 <-- important
 Input:
     ax: the index you want
 Output:
     bx: the bit reversal value (10 bits only) of that value
 Description:
     Bit 9 <-> Bit 0
     Bit 8 <-> Bit 1
     Bit 7 <-> Bit 2
     Bit 6 <-> Bit 3
     Bit 5 <-> Bit 4

FindFunFreq
 Author: Joanna Washburn and David Marshall
 Found in fft.inc file
 Pupose:
      Find the lowest bin with the highest magintude
      Then convert to freq <-- Didn't use in final
 Input:
      none
 Output:
      none
 
 

MAIN ....

Main PROC far

        mov     ax, cseg
        mov     ds, ax

        ModeVideo13

        Call    MouseInstall
        mov     dx,offset mouse
        Call    LoadMouse

        mov     dx,offset tunerSkin      ; Load tunerSkin into pcx variable, transfer
        Call    DecompressPCX     ; image data to tempbuffer, set palette
        Call    FillSkinArray     ; convert tempbuffer to tiles in SkinArray
        Call    GenerateFFTGFX
        Call    GenerateCurSkin
        UpdateScrn
 
        ;play intro wav
        mov     pitch.note, 12
        mov     pitch.request, PLAY
        CALL    MainPlayWav
        mov     pitch.request, STOP
        ;set the bins to 0
        mov     cx, 128
        xor     bx, bx
BinsTo0:
        mov     fft.bin[bx], 0
        inc     bx
        Loop BinsTo0;
 
 MainLoop:

        cmp     Mode, QUIT
        je      ExitTuner
        cmp     Mode, REC
        je      RecordLoop
 
PlayLoop:
        CALL    PerformCommand                ;if command present, perform it
        ; Push ax
        ; mov ax, offset pitch
        ; Pop ax
        CALL    MainPlayWav
        CALL    SwitchWave
 
        CALL    GenerateCurSkin
        CALL    GenerateFFTGFX
        UpdateScrn
 
        CALL    GenerateCurSkin
        CALL    GenerateFFTGFX
        UpdateScrn                         ;macro, copy dub-buff to scrn
        jmp     MainLoop
 
RecordLoop:
        CALL    PerformCommand             ;if command present, perform it
        CALL    GenerateCurSkin
        CALL    GenerateFFTGFX
        UpdateScrn                         ;macro, copy dub-buff to scrn
        CALL    MainRecordWav
 
        mov     fft.FFTSEG, seg sndbuf
        mov     fft.FFTOFF, offset sndbuf
 
        CALL    ConvIntFL
        CALL    PerformFFT
        CALL    FinalizeResult
        CALL    FindFunFreq
 
        CALL    GenerateCurSkin
        CALL    GenerateFFTGFX
        UpdateScrn
 
        mov     cx, 5
GIVEITTIME:
        CALL    GenerateCurSkin
        CALL    GenerateFFTGFX
        UpdateScrn                         ;macro, copy dub-buff to scrn
        LOOP    GIVEITTIME
 
        jmp     MainLoop

ExitTuner:
        CALL    MouseUninstall
        ModeText    ;macro to switch to textmode
        Exit2Dos    ;macro that makes int 21 exit to dos call
 
main endp

cseg    ends
end main