home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 19 / CD_ASCQ_19_010295.iso / dos / prg / midas / gus.asm < prev    next >
Assembly Source File  |  1994-08-06  |  60KB  |  3,072 lines

  1. ;*    GUS.ASM
  2. ;*
  3. ;* Gravis Ultrasound Sound Device, v3.34
  4. ;*
  5. ;* Copyright 1994 Petteri Kangaslampi and Jarno Paananen
  6. ;*
  7. ;* This file is part of the MIDAS Sound System, and may only be
  8. ;* used, modified and distributed under the terms of the MIDAS
  9. ;* Sound System license, LICENSE.TXT. By continuing to use,
  10. ;* modify or distribute this file you indicate that you have
  11. ;* read the license and understand and accept it fully.
  12. ;*
  13.  
  14.  
  15. IDEAL
  16. P386
  17. JUMPS
  18.  
  19. INCLUDE "lang.inc"
  20. INCLUDE "errors.inc"
  21. INCLUDE "sdevice.inc"
  22. INCLUDE "mmem.inc"
  23. INCLUDE "mglobals.inc"
  24.  
  25.  
  26. ;/***************************************************************************\
  27. ;*     enum gusFunctIDs
  28. ;*     ----------------
  29. ;* Description:  ID numbers for GUS Sound Device functions
  30. ;\***************************************************************************/
  31.  
  32. enum    gusFunctIDs \
  33.     ID_gusDetect = ID_gus, \
  34.     ID_gusInit, \
  35.     ID_gusClose, \
  36.     ID_gusGetMixRate, \
  37.     ID_gusGetMode, \
  38.     ID_gusOpenChans, \
  39.     ID_gusCloseChans, \
  40.     ID_gusClearChans, \
  41.     ID_gusMute, \
  42.     ID_gusPause, \
  43.     ID_gusSetMaster, \
  44.     ID_gusPlaySound, \
  45.     ID_gusStopSound, \
  46.     ID_gusSetRate, \
  47.     ID_gusGetRate, \
  48.     ID_gusSetVol, \
  49.     ID_gusSetInst, \
  50.     ID_gusSetPos, \
  51.     ID_gusGetPos, \
  52.     ID_gusSetPanning, \
  53.     ID_gusGetPanning, \
  54.     ID_gusMuteChannel, \
  55.     ID_gusAddInst, \
  56.     ID_gusRemInst, \
  57.     ID_gusSetUpdRate, \
  58.     ID_gusPlay,\
  59.     ID_gusInitHeap,\
  60.     ID_gusFreeHeap,\
  61.     ID_gusMalloc,\
  62.     ID_gusFree,\
  63.     ID_gusCoreFree,\
  64.     ID_gusAllocBlock
  65.  
  66.  
  67. DATASEG
  68.  
  69. STRUC    gusInstrument
  70.     sample        dd    ?        ; ptr to sample in GUS mem
  71.     surround    dd    ?        ; ptr to surround sample in GUS mem / 0
  72.     length        dw    ?        ; length in bytes
  73.     loopStart    dw    ?        ; Offset from beg.
  74.     loopEnd     dw    ?        ; Offset from beg.
  75.     volume        dw    ?        ; Range 0-64
  76.     flags        dw    ?        ; See below
  77. ENDS
  78.  
  79. ; Flag bits:
  80. ; 0 = Used
  81. ; 2 = Looped
  82.  
  83.  
  84. ; STATUS BITS:
  85. ; 0 = stop voice
  86. ; 1 = retrig note
  87. ; 2 = set volume
  88. ; 3 = set fc
  89. ; 4 = sample changed
  90. ; 5 = sample on/off (used for pause)
  91. ; 8 = muted
  92.  
  93.  
  94. STRUC    gusChannel
  95.     status        db    ?        ; See above
  96.     inst        db    ?        ; Number
  97.     fc        dw    ?        ; In FC-format
  98.     frequency    dd    ?        ; In Hz
  99.     volume        dw    ?        ; 0-64
  100.     surround    db    ?        ; Surround flag
  101.     looped        db    ?        ; 0 / 8 (for GUS)
  102.     scurrent    dd    ?        ; Current position for GUS
  103.     sstart        dd    ?        ; Sample start for GUS
  104.     send        dd    ?        ; Sample end for GUS
  105.     panning     dw    ?        ; Panning position (see enum)
  106. ENDS
  107.  
  108.  
  109. STRUC    ghb                    ; GUS Heap Block
  110.     next        dd    ?        ; Pointer to next block
  111.     gusmem        dd    ?        ; Pointer to GUS memory
  112.     length        dd    ?        ; Length of this block (Rounded to 32 byte border)
  113. ENDS
  114.  
  115. ; lengthFlags:
  116. ;        0 free / allocated
  117.  
  118.  
  119.  
  120. chancount    dw    ?            ; Amount of channels
  121. voicesel    dw    ?            ; Voice Select register
  122. selreg        dw    ?            ; Select Register
  123.  
  124. mixfreq     dw    ?            ; Mixing frequency
  125. updRate     dw    ?            ; SD update rate
  126.  
  127. instpos     dw    ?            ; Instrument to be filled next
  128.  
  129. muted        dw    ?            ; 0 = unmuted, 1 = muted
  130. paused        dw    ?            ; 0 = not, 1 = paused
  131. mastervol    dw    ?            ; Oletus = maksimi
  132. masterchanged    dw    ?            ; Overrides channel set volume
  133. numInsts    dw    ?            ; Max instrument.
  134.  
  135. memamount    dd    ?            ; Amount of memory on GUS
  136. memavail    dd    ?            ; Memory available on GUS
  137. largestblock    dd    ?            ; Largest block of memory on GUS
  138. gusHeapStart    dd    ?            ; First block of GUS heap
  139. gusHeap     DD    ?            ; pointer to GUS heap
  140. monoFlag    dw    ?            ; Force mono output
  141. temp        dd    ?            ; Temporary storage
  142.  
  143.  
  144. label channels gusChannel
  145.     rept    32
  146.     gusChannel    ?
  147.     endm
  148.  
  149. Instruments    dd    ?            ; Pointer to GUS instruments
  150.  
  151.  
  152.  
  153. IDATASEG
  154.  
  155.  
  156. GLOBAL    GUS : SoundDevice
  157.  
  158. IFNDEF    __TP__
  159. PUBLIC    gusHeapStart
  160. ENDIF
  161.  
  162. GUS SoundDevice       < 1,\            ; Called according to tempo
  163.             220h,\            ; Default base I/O port
  164.             0,\            ; No IRQ
  165.             0,\            ; No DMA
  166.             sdUnInitialized,\    ; Status
  167.             sdMono or sdStereo or sd16bit or sdHighQ,\ ; Modes
  168.             far ptr gusID,\     ; ID string
  169.             far ptr gusDetect,\
  170.             far ptr gusInit,\
  171.             far ptr gusClose,\
  172.             far ptr gusGetMixRate,\
  173.             far ptr gusGetMode, \
  174.             far ptr gusOpenChans,\
  175.             far ptr gusCloseChans,\
  176.             far ptr gusClearChans,\
  177.             far ptr gusMute,\
  178.             far ptr gusPause,\
  179.             far ptr gusSetMaster,\
  180.             far ptr gusPlaySound,\
  181.             far ptr gusStopSound,\
  182.             far ptr gusSetRate,\
  183.             far ptr gusGetRate,\
  184.             far ptr gusSetVol,\
  185.             far ptr gusSetInst,\
  186.             far ptr gusSetPos,\
  187.             far ptr gusGetPos,\
  188.             far ptr gusSetPanning,\
  189.             far ptr gusGetPanning,\
  190.             far ptr gusMuteChannel,\
  191.             far ptr gusAddInst,\
  192.             far ptr gusRemInst,\
  193.             far ptr gusSetUpdRate,\
  194.             far ptr gusPlay >
  195.  
  196.  
  197. ; Mixing frequencies for channel amounts 14-32
  198.  
  199. chantab dw    44100,41160,38587,36317,34300,32494,30870,29400,28063,26843
  200.     dw    25725,24696,23746,22866,22050,21289,20580,19916,19293
  201.  
  202.  
  203.  
  204. LABEL    voltable    WORD
  205.     dw    01100h
  206.     dw    09300h,0A900h,0B400h,0BC00h,0C180h,0C580h,0C980h,0CD80h
  207.     dw    0CF40h,0D240h,0D440h,0D640h,0D840h,0DA40h,0DC40h,0DE40h
  208.     dw    0DEF0h,0DFA0h,0E1A0h,0E2A0h,0E3A0h,0E4A0h,0E5A0h,0E6A0h
  209.     dw    0E7A0h,0E8A0h,0E9A0h,0EAA0h,0EBA0h,0ECA0h,0EDA0h,0EEA0h
  210.     dw    0EEF0h,0EFE0h,0EF60h,0F1E0h,0F160h,0F1E0h,0F260h,0F2E0h
  211.     dw    0F360h,0F3E0h,0F460h,0F4E0h,0F560h,0F5E0h,0F660h,0F6E0h
  212.     dw    0F760h,0F7E0h,0F860h,0F8E0h,0F960h,0F9E0h,0FA60h,0FAF0h
  213.     dw    0FB70h,0FBF0h,0FC70h,0FCF0h,0FD70h,0FD90h,0FDB0h,0FDD0h
  214.  
  215. gusID    db    "Gravis Ultrasound Sound Device v3.34",0
  216.  
  217.  
  218.  
  219. CODESEG
  220.  
  221. ;******* GUS Register Select - Macro ************
  222.  
  223. MACRO    regsel    register
  224.     mov    dx,[selreg]
  225.     mov    al,register
  226.     out    dx,al
  227. ENDM
  228.  
  229.  
  230.  
  231. ;/***************************************************************************\
  232. ;*
  233. ;* Function:    int gusDetect(int *result)
  234. ;*
  235. ;* Description: Detects Gravis UltraSound and fills in GUS SoundDevice
  236. ;*        structure with appropriate values for port, DMA and IRQ
  237. ;*
  238. ;* Returns:    MIDAS error code.
  239. ;*        1 stored to *result if GUS was detected, 0 if not.
  240. ;*
  241. ;\***************************************************************************/
  242.  
  243. PROC    gusDetect FAR    result : far ptr
  244. USES    si
  245.  
  246.     mov    [GUS.port],210h         ; Base address
  247.     les    si,[result]
  248.  
  249. @@detectloop:
  250.     mov    ax,[GUS.port]            ; Base address (Set before!)
  251.     add    ax,103h
  252.     mov    [selreg],ax            ; Register select (2x0h+103h)
  253.     dec    ax
  254.     mov    [voicesel],ax            ; Voice select (2x0h+102h)
  255.  
  256.     call    gusReset
  257.  
  258.     regsel    44h
  259.     add    dx,2
  260.     xor    ax,ax
  261.     out    dx,al                ; upper bits of address
  262.  
  263.     regsel    43h
  264.     inc    dx
  265.     xor    ax,ax                ; Address 0
  266.     out    dx,ax
  267.     add    dx,3
  268.     mov    al,055h
  269.     out    dx,al                ; Poke data 1 (55h)
  270.  
  271.     regsel    43h
  272.     inc    dx
  273.     mov    ax,1                ; Address 1
  274.     out    dx,ax
  275.     add    dx,3
  276.     mov    al,0AAh
  277.     out    dx,al                ; Poke data 2 (AAh)
  278.  
  279.     regsel    43h
  280.     inc    dx
  281.     xor    ax,ax                ; Address 0
  282.     out    dx,ax
  283.     add    dx,3
  284.     in    al,dx                ; Peek data 1
  285.     cmp    al,055h
  286.     jne    @@nogusinthisaddress
  287.  
  288.     regsel    43h
  289.     inc    dx
  290.     mov    ax,1                ; Address 1
  291.     out    dx,ax
  292.     add    dx,3
  293.     in    al,dx                ; Peek data 2
  294.     cmp    al,0AAh
  295.     je    @@found
  296.  
  297. @@nogusinthisaddress:
  298.     add    [GUS.port],10h
  299.     cmp    [GUS.port],270h         ; GUS port range is 210h-260h
  300.     jne    @@detectloop
  301.  
  302.     mov    [GUS.port],0
  303.     mov    [word es:si],0
  304.     jmp    @@quit
  305.  
  306. @@found:
  307.     mov    [word es:si],1
  308. @@quit: xor    ax,ax
  309.     ret
  310.  
  311. ENDP
  312.  
  313. ;/***************************************************************************\
  314. ;*
  315. ;* Function:    int gusInit(ushort rate, ushort mode)
  316. ;*
  317. ;* Description: Initializes the GUS for playing
  318. ;*
  319. ;* Input:    ushort rate        Mixing rate (no effect on GUS)
  320. ;*        ushort mode        Mode (see enum) (mono flag only)
  321. ;*
  322. ;* Returns:    MIDAS error code.
  323. ;*
  324. ;\***************************************************************************/
  325. PROC    gusInit FAR    rate : word, mode : word
  326. USES    di
  327.  
  328.     mov    [instpos],1            ; First instrument to be filled
  329.     mov    [numInsts],0            ; No instruments
  330.     mov    [mastervol],64            ; Default master volume
  331.     mov    [masterchanged],0
  332.  
  333.     mov    ax,[mode]
  334.     and    ax,sdMono            ; AND mono bit
  335.     mov    [monoFlag],ax            ; 1 if mono, 0 otherwise
  336.  
  337.     mov    ax,[GUS.port]            ; Base address (Set before!)
  338.     add    ax,103h
  339.     mov    [selreg],ax            ; Register select (2x0h+103h)
  340.     dec    ax
  341.     mov    [voicesel],ax            ; Voice select (2x0h+102h)
  342.  
  343.     call    gusReset            ; Reset GUS
  344.  
  345.     mov    [memamount],0            ; Initial memory amount
  346.     mov    cx,4                ; Max amount of 256k chunks
  347.     xor    bx,bx                ; Start from 00000h
  348.  
  349. @@memloop:
  350.     regsel    44h
  351.     add    dx,2
  352.     mov    ax,bx
  353.     out    dx,al                ; upper bits of address
  354.  
  355.     regsel    43h
  356.     inc    dx
  357.     xor    ax,ax                ; Address 0
  358.     out    dx,ax
  359.     add    dx,3
  360.     mov    al,055h
  361.     out    dx,al                ; Poke data 1 (55h)
  362.  
  363.     regsel    43h
  364.     inc    dx
  365.     mov    ax,1                ; Address 1
  366.     out    dx,ax
  367.     add    dx,3
  368.     mov    al,0AAh
  369.     out    dx,al                ; Poke data 2 (AAh)
  370.  
  371.     regsel    43h
  372.     inc    dx
  373.     xor    ax,ax                ; Address 0
  374.     out    dx,ax
  375.     add    dx,3
  376.     in    al,dx                ; Peek data 1
  377.     cmp    al,055h
  378.     jne    @@poiss
  379.  
  380.     regsel    43h
  381.     inc    dx
  382.     mov    ax,1                ; Address 1
  383.     out    dx,ax
  384.     add    dx,3
  385.     in    al,dx                ; Peek data 2
  386.     cmp    al,0AAh
  387.     jne    @@poiss
  388.  
  389.     add    [memamount],256*1024        ; Add amount of memory by 256k
  390.     add    bx,4                ; Next 256k chunk
  391.     loop    @@memloop
  392.  
  393. @@poiss:                    ; No more memory
  394.     cmp    [memamount],0
  395.     jne    @@memok             ; NO MEMORY!
  396.  
  397.     mov    ax,errSDFailure         ; NO GUS
  398.     jmp    @@err
  399.  
  400. @@memok:
  401.     mov    eax,[memamount]         ; Initialize mem variables
  402.     mov    [memavail],eax
  403.     mov    [largestblock],eax
  404.  
  405.  
  406. ; Clear the all 32 channels
  407.  
  408.     mov    dx,[GUS.port]            ; Mixer
  409.     mov    al,3
  410.     out    dx,al                ; Disable Line in & out
  411.  
  412.     regsel    0eh
  413.     add    dx,2
  414.     mov    al,31 OR 0c0h
  415.     out    dx,al                ; Set number of active
  416.                         ; voices to 32 just for
  417.                         ; sure
  418.  
  419.     mov    cx,32                ; Number of voices
  420. @@resetloop:
  421.     mov    dx,[voicesel]            ; Voice Select
  422.     mov    ax,cx
  423.     out    dx,al
  424.  
  425.     regsel    0                ; Voice control
  426.     add    dx,2                ; data low
  427.     mov    al,3                ; Stop voice
  428.     out    dx,al
  429.  
  430.     regsel    9                ; Current Volume
  431.     inc    dx                ; data high
  432.     mov    ax,0500h            ; Zero volume
  433.     out    dx,ax
  434.  
  435.     regsel    12                ; Pan Position
  436.     add    dx,2                ; data low
  437.     mov    al,8                ; Center
  438.     out    dx,al
  439.  
  440.     regsel    13                ; Volume Ramping
  441.     add    dx,2                ; data low
  442.     mov    al,3                ; disable
  443.     out    dx,al
  444.  
  445.     regsel    6                ; Ramp Rate
  446.     add    dx,2
  447.     mov    al,1fh                ; Rate
  448.     out    dx,al
  449.     loop    @@resetloop
  450.  
  451.     regsel    4ch                ; RESET
  452.     add    dx,2
  453.     mov    al,3
  454.     out    dx,al                ; Enable GF1 and DACs
  455.  
  456.     call    initHeap            ; Initialize GUS-heap
  457.     test    ax,ax
  458.     jne    @@err
  459.  
  460.     call    memAlloc LANG, MAXINSTS * SIZE gusInstrument,\
  461.         seg temp offset temp
  462.                         ; Alloc room for instruments
  463.     test    ax,ax
  464.     jne    @@err
  465.  
  466.     mov    ebx,[temp]
  467.     mov    [Instruments],ebx
  468.  
  469.     mov    di,bx
  470.     shr    ebx,16
  471.     mov    es,bx
  472.     xor    eax,eax
  473.     mov    cx,MAXINSTS * SIZE gusInstrument
  474.     cld
  475.     rep    stosb                ; Clear instrument datas
  476.  
  477.     mov    [GUS.status],sdOK        ; SD initialized
  478.     xor    ax,ax
  479.     ret
  480.  
  481. @@err:    ERROR    ID_gusInit            ; Heap error
  482.     ret
  483. ENDP
  484.  
  485.  
  486.  
  487. ;/***************************************************************************\
  488. ;*
  489. ;* Function:    gusReset
  490. ;*
  491. ;* Description: Resets the GUS card
  492. ;*
  493. ;* Destroys:    ax, dx
  494. ;*
  495. ;\***************************************************************************/
  496. PROC    gusReset NEAR
  497.  
  498.     regsel    4ch                ; RESET
  499.     add    dx,2
  500.     mov    al,0
  501.     out    dx,al                ; RESET!
  502.  
  503.     call    gusdelay
  504.     call    gusdelay
  505.  
  506.     regsel    4ch                ; RESET
  507.     add    dx,2
  508.     mov    al,1
  509.     out    dx,al                ; Enable GF1
  510.  
  511.     call    gusdelay
  512.     call    gusdelay
  513.     ret
  514. ENDP
  515.  
  516. ;/***************************************************************************\
  517. ;*
  518. ;* Function:    int gusClose()
  519. ;*
  520. ;* Description: Closes up the GUS.
  521. ;*
  522. ;* Returns:    MIDAS error code.
  523. ;*
  524. ;\***************************************************************************/
  525. PROC    gusClose FAR
  526.  
  527.     call    gusReset
  528.  
  529.     mov    dx,[GUS.port]            ; Mixer
  530.     xor    al,al
  531.     out    dx,al                ; Enable Line in & out
  532.  
  533.     call    freeHeap
  534.     test    ax,ax
  535.     jnz    @@err
  536.  
  537.     call    memFree LANG, [Instruments]    ; Free instruments
  538.     test    ax,ax
  539.     jnz    @@err
  540.  
  541.     mov    [instpos],1            ; Flush instruments
  542.     mov    [GUS.status],sdUnInitialized
  543.     ret                    ; ax already 0
  544.  
  545. @@err:    ERROR    ID_gusClose
  546.     ret
  547. ENDP
  548.  
  549.  
  550. ;/***************************************************************************\
  551. ;*
  552. ;* Function:    int gusGetMixRate(ushort *rate)
  553. ;*
  554. ;* Description: Returns the mixing rate of the SD
  555. ;*
  556. ;* Returns:    MIDAS error code.
  557. ;*
  558. ;\***************************************************************************/
  559. PROC    gusGetMixRate FAR    rate:far ptr
  560.     mov    ax,[mixfreq]            ; Get mixing rate
  561.     les    bx,[rate]
  562.     mov    [es:bx],ax
  563.     xor    ax,ax                ; Can't fail
  564.     ret
  565. ENDP
  566.  
  567.  
  568.  
  569. ;/***************************************************************************\
  570. ;*
  571. ;* Function:    int gusGetMode(ushort *mode)
  572. ;*
  573. ;* Description: Returns the output mode
  574. ;*
  575. ;* Returns:    MIDAS error code.
  576. ;*
  577. ;\***************************************************************************/
  578. PROC    gusGetMode    FAR    mode:far ptr
  579.  
  580.     mov    ax,sd16bit or sdHighQ
  581.     mov    bx,2
  582.     sub    bx,[monoFlag]            ; 1 if mono (=sdMono)
  583.                         ; 2 if not (=sdStereo)
  584.     or    ax,bx
  585.     les    bx,[mode]
  586.     mov    [es:bx],ax
  587.     xor    ax,ax                ; Can't fail
  588.     ret
  589. ENDP
  590.  
  591.  
  592. ;/***************************************************************************\
  593. ;*
  594. ;* Function:    int gusOpenChans(ushort chans)
  595. ;*
  596. ;* Description: Open channels from the GUS
  597. ;*
  598. ;* Input:    ushort chans        Number of channels to open
  599. ;*
  600. ;* Returns:    MIDAS error code.
  601. ;*
  602. ;\***************************************************************************/
  603.  
  604. PROC    gusOpenChans    FAR    chans:word
  605. USES    si,di
  606.  
  607.     cld
  608.  
  609.     mov    bx,[chans]
  610.     mov    [chancount],bx
  611.  
  612.     mov    [muted],0
  613.     mov    [paused],0
  614.  
  615.     cmp    [surround],0
  616.     je    @@nsurr
  617.     add    bx,bx
  618.     cmp    bx,32
  619.     ja    @@err
  620. @@nsurr:
  621.     cmp    bx,14
  622.     jae    @@okei
  623.     mov    bx,14
  624. @@okei:
  625.     mov    cx,bx
  626.  
  627.     sub    bx,14
  628.     add    bx,bx
  629.     mov    bx,[chantab+bx]         ; Take the mixing rate
  630.     mov    [mixfreq],bx
  631.  
  632.     regsel    0eh
  633.     add    dx,2
  634.     mov    ax,cx
  635.     dec    ax                ; Amount-1
  636.     or    al,0c0h
  637.     out    dx,al
  638.  
  639.     mov    ax,ds
  640.     mov    es,ax
  641.     mov    di,offset channels
  642.  
  643.     xor    al,al
  644.     mov    cx,size gusChannel*32
  645.     rep    stosb                ; Clear channel blocks
  646.  
  647.     mov    cx,[chans]            ; to the table
  648.     xor    bx,bx                ; Start from channel 0
  649.  
  650. @@panloop:
  651.     mov    dx,[voicesel]            ; Voice Select
  652.     mov    ax,[chans]
  653.     sub    ax,cx
  654.     out    dx,al
  655.  
  656.     regsel    12                ; Pan Position
  657.     add    dx,2                ; data low
  658.  
  659.     mov    [bx+channels.panning],panMiddle ; Panning position
  660.  
  661.     mov    al,8                ; Middle
  662.     out    dx,al
  663.  
  664.     mov    [bx+channels.status],1        ; Stop sound
  665.     cmp    [surround],0
  666.     je    @@nss
  667.  
  668.     mov    ax,[chancount]
  669.     imul    ax,ax,size gusChannel        ; Get surround chan
  670.     mov    si,ax
  671.     add    si,bx
  672.     mov    [si+channels.status],81h    ; Stop sound and mute
  673.  
  674. @@nss:    add    bx,SIZE gusChannel
  675.  
  676.     loop    @@panloop
  677.  
  678.     mov    dx,[GUS.port]
  679.     xor    ax,ax
  680.         out     dx,al                           ; Enable line in and out
  681.  
  682.         call    gusMute LANG, 0
  683.         test    ax,ax
  684.         jnz     @@err2
  685.         ret
  686.  
  687. @@err:    mov    ax,errNoChannels        ; Too much channels
  688. @@err2: ERROR   ID_gusOpenChans
  689.     ret
  690. ENDP
  691.  
  692.  
  693. ;/***************************************************************************\
  694. ;*
  695. ;* Function:    int gusCloseChans()
  696. ;*
  697. ;* Description: Closes channels from the GUS
  698. ;*
  699. ;* Returns:    MIDAS error code.
  700. ;*
  701. ;\***************************************************************************/
  702.  
  703. PROC    gusCloseChans     FAR
  704.     call    gusClearChans LANG
  705.     mov    [chancount],0
  706.     xor    ax,ax                ; Can't fail
  707.     ret
  708. ENDP
  709.  
  710.  
  711. ;/***************************************************************************\
  712. ;*
  713. ;* Function:    int gusClearChans()
  714. ;*
  715. ;* Description: Clears channels from the GUS
  716. ;*
  717. ;* Returns:    MIDAS error code.
  718. ;*
  719. ;\***************************************************************************/
  720.  
  721. PROC    gusClearChans     FAR
  722. USES    si
  723.  
  724.     xor    bx,bx
  725.     mov    cx,[chancount]
  726. @@clloop:
  727.     mov    dx,[voicesel]            ; Voice Select
  728.     mov    ax,[chancount]
  729.     sub    ax,cx
  730.     out    dx,al
  731.  
  732.     regsel    12                ; Pan Position
  733.     add    dx,2                ; data low
  734.  
  735.     mov    [bx+channels.panning],panMiddle ; Panning position
  736.     mov    [bx+channels.inst],0        ; No instrument
  737.     and    [bx+channels.status], NOT 80h    ; Not muted
  738.  
  739.     mov    al,8                ; Middle
  740.     out    dx,al
  741.  
  742.     or    [bx+channels.status],1        ; Stop sound
  743.     cmp    [surround],0
  744.     je    @@nss
  745.  
  746.     mov    ax,[chancount]
  747.     imul    ax,ax,size gusChannel        ; Get surround chan
  748.     mov    si,ax
  749.     add    si,bx
  750.     or    [si+channels.status],81h    ; Stop sound and mute
  751.  
  752. @@nss:    add    bx,SIZE gusChannel
  753.     loop    @@clloop
  754.     xor    ax,ax                ; Can't fail
  755.     ret
  756. ENDP
  757.  
  758.  
  759. ;/***************************************************************************\
  760. ;*
  761. ;* Function:    int gusMute(ushort mute)
  762. ;*
  763. ;* Description: Mutes/unmutes GUS channels
  764. ;*
  765. ;* Input:    ushort mute        UnMute = 0 / Mute = 1
  766. ;*
  767. ;* Returns:    MIDAS error code.
  768. ;*
  769. ;\***************************************************************************/
  770.  
  771. PROC    gusMute FAR    mute:word
  772.     mov    ax,[mute]
  773.     mov    [muted],ax
  774.     mov    bl,1                ; Enable GF1 (Disable DACs)
  775.     test    ax,ax
  776.     jnz    @@mute
  777.     mov    bl,3                ; Enable DACs (Unmute)
  778. @@mute:
  779.     regsel    4ch                ; RESET
  780.     add    dx,2
  781.     mov    al,bl
  782.     out    dx,al
  783.     xor    ax,ax                ; Can't fail
  784.     ret
  785. ENDP
  786.  
  787.  
  788.  
  789. ;/***************************************************************************\
  790. ;*
  791. ;* Function:    int gusPause(ushort pause)
  792. ;*
  793. ;* Description: Pauses/unpauses GUS SD
  794. ;*
  795. ;* Input:    ushort pause        Unpause = 0 / Pause = 1
  796. ;*
  797. ;* Returns:    MIDAS error code.
  798. ;*
  799. ;\***************************************************************************/
  800.  
  801. PROC    gusPause FAR     pause:word
  802.     mov    ax,[pause]
  803.     mov    [paused],ax
  804.     test    ax,ax
  805.     jnz    @@pause
  806.  
  807.     xor    cx,cx
  808.     xor    bx,bx
  809. @@chloop:
  810.     test    [si+channels.status],20h
  811.     jz    @@off
  812.  
  813.     mov    dx,[voicesel]            ; Select voice
  814.     mov    ax,cx
  815.     out    dx,al
  816.  
  817.     regsel    0
  818.     add    dx,2
  819.     mov    al,[si+channels.looped]
  820.     out    dx,al
  821.  
  822. @@off:    add    si,SIZE gusChannel
  823.     inc    cx
  824.     cmp    cx,32
  825.     jne    @@chloop
  826.     jmp    @@done
  827.  
  828. @@pause:
  829.     xor    cx,cx
  830.     xor    si,si
  831. @@chloop2:
  832.     mov    dx,[voicesel]            ; Select voice
  833.     mov    ax,cx
  834.     out    dx,al
  835.  
  836.     regsel    80h
  837.     add    dx,2
  838.     in    al,dx
  839.  
  840.     and    al,1                ; Voice on / off
  841.     xor    al,1                ; To active high
  842.     shl    al,5                ; to bit 5
  843.     and    [si+channels.status],NOT 20h
  844.     or    [si+channels.status],al
  845.  
  846.     regsel    0
  847.     add    dx,2
  848.     mov    al,3
  849.     out    dx,al                ; Stop
  850.  
  851.     add    si,SIZE gusChannel
  852.     inc    cx
  853.     cmp    cx,32
  854.     jne    @@chloop2
  855.  
  856. @@done: xor    ax,ax
  857.     ret
  858. ENDP
  859.  
  860.  
  861.  
  862. ;/***************************************************************************\
  863. ;*
  864. ;* Function:    int gusSetMaster(uchar master)
  865. ;*
  866. ;* Description: Sets the master volume for the GUS
  867. ;*
  868. ;* Input:    uchar master        New master volume (0-64)
  869. ;*
  870. ;* Returns:    MIDAS error code.
  871. ;*
  872. ;\***************************************************************************/
  873.  
  874. PROC    gusSetMaster    FAR    master:word
  875.  
  876.     mov    ax,[master]
  877.     mov    [mastervol],ax
  878.     mov    [masterchanged],1
  879.     xor    ax,ax                ; Can't fail
  880.     ret
  881. ENDP
  882.  
  883. ;/***************************************************************************\
  884. ;*
  885. ;* Function:    int gusPlaySound(ushort chan, ulong freq)
  886. ;*
  887. ;* Description: Starts a sound with a frequency
  888. ;*
  889. ;* Input:    ushort chan        Channel number
  890. ;*        ulong freq        Playing frequency
  891. ;*
  892. ;* Returns:    MIDAS error code.
  893. ;*
  894. ;\***************************************************************************/
  895. PROC    gusPlaySound    FAR    chan:word, freq:dword
  896. USES    si
  897. LOCAL    fc:word
  898.  
  899.     mov    bx,[chan]
  900.     cmp    [chancount],bx
  901.     jle    @@errchan
  902.  
  903.     imul    bx,bx,size gusChannel        ; Get channel block
  904.  
  905.     mov    eax,[freq]
  906.     mov    [bx+channels.frequency],eax
  907.  
  908.     shl    eax,10
  909.     xor    edx,edx
  910.     movzx    ecx,[mixfreq]            ; GUS freq = frequency / mixing rate
  911.     idiv    ecx
  912.     and    ax,0fffeh            ; Bit 0 unused
  913.     mov    [bx+channels.fc],ax
  914.     mov    [fc],ax
  915.     or    [bx+channels.status],8        ; FC changed
  916.  
  917.     movzx    dx,[bx+channels.inst]        ; Instrument number
  918.     test    dx,dx
  919.     jz    @@errinst            ; No instrument?
  920.     cmp    dx,[numInsts]
  921.     ja    @@errinst
  922.  
  923.     dec    dx                ; Table starts from 1
  924.     imul    dx,dx,SIZE gusInstrument
  925.  
  926.     les    si,[Instruments]
  927.     add    si,dx
  928.     cmp    [es:si+gusInstrument.length],0
  929.     je    @@quit
  930.  
  931.     mov    ecx,[es:si+gusInstrument.sample] ; Start address
  932.     mov    [bx+channels.scurrent],ecx    ; Tell start position to GUS
  933.     and    [bx+channels.status],NOT 17    ; AND stop sound and sample changed off
  934.     or    [bx+channels.status],2        ; Retrig
  935.  
  936.     cmp    [surround],0
  937.     je    @@quit
  938.  
  939.     mov    bx,[chan]
  940.     add    bx,[chancount]
  941.     imul    bx,bx,size gusChannel        ; Get channel block
  942.  
  943.     mov    eax,[freq]
  944.     mov    [bx+channels.frequency],eax
  945.  
  946.     mov    ax,[fc]
  947.     mov    [bx+channels.fc],ax
  948.     or    [bx+channels.status],8        ; FC changed
  949.  
  950.     mov    ecx,[es:si+gusInstrument.surround] ; Start address
  951.     mov    [bx+channels.scurrent],ecx    ; Tell start position to GUS
  952.     and    [bx+channels.status],NOT 17    ; AND stop sound and sample changed off
  953.     or    [bx+channels.status],2        ; Retrig
  954.  
  955. @@quit:
  956.     xor    ax,ax
  957.     ret
  958.  
  959. @@errchan:
  960.     mov    ax,errInvalidChanNumber
  961.     jmp    @@err
  962. @@errinst:
  963.     mov    ax,errInvalidInstHandle
  964. @@err:    ERROR    ID_gusPlaySound
  965.     ret
  966.  
  967. ENDP
  968.  
  969.  
  970. ;/***************************************************************************\
  971. ;*
  972. ;* Function:    int gusStopSound(ushort chan)
  973. ;*
  974. ;* Description: Stops sound on a channel
  975. ;*
  976. ;* Input:    ushort chan        Channel number
  977. ;*
  978. ;* Returns:    MIDAS error code.
  979. ;*
  980. ;\***************************************************************************/
  981. PROC    gusStopSound    FAR    chan:word
  982.  
  983.     mov    bx,[chan]
  984.     cmp    [chancount],bx
  985.     jle    @@err
  986.  
  987.     imul    bx,bx,size gusChannel        ; Channel block
  988.  
  989.     and    [bx+channels.status], NOT 18    ; AND Retrig and sample change off
  990.     or    [bx+channels.status],1        ; Stop sound
  991.  
  992.     cmp    [surround],0
  993.     je    @@quit
  994.  
  995.     mov    bx,[chan]
  996.     add    bx,[chancount]
  997.     imul    bx,bx,size gusChannel        ; Channel block
  998.  
  999.     and    [bx+channels.status], NOT 18    ; AND Retrig and sample change off
  1000.     or    [bx+channels.status],1        ; Stop sound
  1001.  
  1002. @@quit: xor    ax,ax
  1003.     ret
  1004.  
  1005. @@err:    mov    ax,errInvalidChanNumber
  1006.     ERROR    ID_gusStopSound
  1007.     ret
  1008. ENDP
  1009.  
  1010.  
  1011. ;/***************************************************************************\
  1012. ;*
  1013. ;* Function:    int gusSetRate(ushort chan, ulong freq)
  1014. ;*
  1015. ;* Description: Sets the playing rate for a channel
  1016. ;*
  1017. ;* Input:    ushort chan        Channel number
  1018. ;*        ulong freq        New playing frequency
  1019. ;*
  1020. ;* Returns:    MIDAS error code.
  1021. ;*
  1022. ;\***************************************************************************/
  1023. PROC    gusSetRate    FAR    chan:word, freq:dword
  1024.  
  1025.     mov    bx,[chan]
  1026.     cmp    [chancount],bx
  1027.     jle    @@err
  1028.  
  1029.     imul    bx,bx,size gusChannel
  1030.  
  1031.     mov    eax,[freq]
  1032.     mov    [bx+channels.frequency],eax
  1033.  
  1034.     shl    eax,10
  1035.     xor    edx,edx
  1036.     movzx    ecx,[mixfreq]            ; GUS freq = frequency / mixing rate
  1037.     idiv    ecx
  1038.     and    ax,0fffeh            ; bit 0 unused
  1039.     mov    [bx+channels.fc],ax
  1040.     or    [bx+channels.status],8
  1041.  
  1042.     cmp    [surround],0
  1043.     je    @@quit
  1044.  
  1045.     mov    bx,[chan]
  1046.     add    bx,[chancount]
  1047.     imul    bx,bx,size gusChannel
  1048.  
  1049.     mov    [bx+channels.fc],ax
  1050.     mov    eax,[freq]
  1051.     mov    [bx+channels.frequency],eax
  1052.     or    [bx+channels.status],8
  1053.  
  1054. @@quit: xor    ax,ax
  1055.     ret
  1056.  
  1057. @@err:    mov    ax,errInvalidChanNumber
  1058.     ERROR    ID_gusSetRate
  1059.     ret
  1060. ENDP
  1061.  
  1062.  
  1063. ;/***************************************************************************\
  1064. ;*
  1065. ;* Function:    int gusGetRate(ushort chan, ulong *freq)
  1066. ;*
  1067. ;* Description: Returns the playing rate for a channel
  1068. ;*
  1069. ;* Input:    ushort chan        Channel number
  1070. ;*
  1071. ;* Returns:    MIDAS error code.
  1072. ;*
  1073. ;\***************************************************************************/
  1074.  
  1075. PROC    gusGetRate    FAR    chan : word, freq:far ptr
  1076.  
  1077.     mov    bx,[chan]
  1078.     cmp    [chancount],bx
  1079.     jle    @@err
  1080.  
  1081.     mov    dx,[voicesel]            ; Select voice
  1082.     mov    ax,bx
  1083.     out    dx,al
  1084.  
  1085.     regsel    80h                ; Voice control
  1086.     add    dx,2
  1087.     in    al,dx
  1088.     test    al,1
  1089.     jnz    @@stopped            ; Is sound on?
  1090.  
  1091.     mov    bx,[chan]
  1092.     imul    bx,bx,size gusChannel
  1093.  
  1094.     mov    eax,[bx+channels.frequency]
  1095.     les    bx,[freq]
  1096.     mov    [es:bx],eax
  1097.     xor    ax,ax
  1098.     ret
  1099.  
  1100. @@stopped:
  1101.     les    bx,[freq]
  1102.     mov    [dword es:bx],0
  1103.     xor    ax,ax
  1104.     ret
  1105.  
  1106. @@err:    mov    ax,errInvalidChanNumber
  1107.     ERROR    ID_gusGetRate
  1108.     ret
  1109. ENDP
  1110.  
  1111.  
  1112.  
  1113. ;/***************************************************************************\
  1114. ;*
  1115. ;* Function:    int gusSetVol(ushort chan, uchar volume)
  1116. ;*
  1117. ;* Description: Sets the volume for a channel
  1118. ;*
  1119. ;* Input:    ushort chan        Channel number
  1120. ;*        uchar  volume        New playing volume
  1121. ;*
  1122. ;* Returns:    MIDAS error code.
  1123. ;*
  1124. ;\***************************************************************************/
  1125. PROC    gusSetVol    FAR    chan:word, vol:word
  1126.  
  1127.     mov    ax,[vol]
  1128.     cmp    ax,64
  1129.     jbe    @@not64             ; Max volume = 64
  1130.     mov    ax,64
  1131. @@not64:
  1132.     mov    bx,[chan]
  1133.     cmp    [chancount],bx
  1134.     jle    @@err
  1135.  
  1136.     imul    bx,bx,size gusChannel
  1137.  
  1138.     mov    [bx+channels.volume],ax
  1139.     or    [bx+channels.status],4
  1140.  
  1141.     cmp    [surround],0
  1142.     je    @@quit
  1143.  
  1144.     mov    bx,[chan]
  1145.     add    bx,[chancount]
  1146.     imul    bx,bx,size gusChannel
  1147.  
  1148.     mov    [bx+channels.volume],ax
  1149.     or    [bx+channels.status],4
  1150.  
  1151. @@quit: xor    ax,ax
  1152.     ret
  1153.  
  1154. @@err:    mov    ax,errInvalidChanNumber
  1155.     ERROR    ID_gusSetVol
  1156.     ret
  1157.  
  1158. ENDP
  1159.  
  1160. ;/***************************************************************************\
  1161. ;*
  1162. ;* Function:    int gusSetInst(ushort chan, ushort inst)
  1163. ;*
  1164. ;* Description: Sets up an instrument for playing
  1165. ;*
  1166. ;* Input:    ushort chan        Channel number
  1167. ;*        ushort inst        Instrument number from AddInstrument
  1168. ;*
  1169. ;* Returns:    MIDAS error code.
  1170. ;*
  1171. ;\***************************************************************************/
  1172.  
  1173. PROC    gusSetInst    FAR    chan:word, inst:word
  1174. USES    edi, si
  1175.  
  1176.     mov    bx,[chan]
  1177.     cmp    [chancount],bx
  1178.     jle    @@errchn
  1179.     imul    bx,bx,size gusChannel        ; Channel block
  1180.  
  1181.     mov    ax,[inst]
  1182.     test    ax,ax
  1183.     jz    @@errinst            ; No instrument at all?
  1184.     cmp    ax,[numInsts]
  1185.     ja    @@errinst
  1186.  
  1187.     mov    dx,ax
  1188.     dec    dx                ; Table starts from 1
  1189.     imul    dx,dx,SIZE gusInstrument
  1190.     les    si,[Instruments]
  1191.     add    si,dx
  1192.  
  1193.     cmp    [bx+channels.inst],al
  1194.     je    @@nochange
  1195.  
  1196.     mov    [bx+channels.inst],al        ; Set instrument
  1197.  
  1198.     cmp    [es:si+gusInstrument.length],0
  1199.     je    @@stop
  1200.  
  1201.     mov    ecx,[es:si+gusInstrument.sample] ; Start address
  1202.     mov    [bx+channels.scurrent],ecx    ; Tell start position to GUS
  1203.  
  1204.     test    [es:si+gusInstrument.flags],2 ; Is sample looped?
  1205.     jz    @@noloop
  1206.  
  1207.     mov    edi,ecx
  1208.     movzx    eax,[es:si+gusInstrument.loopEnd]
  1209.     add    edi,eax             ; Loop end address
  1210.     movzx    eax,[es:si+gusInstrument.loopStart]
  1211.     add    ecx,eax             ; Loop start address
  1212.     mov    al,8                ; Enable loop
  1213.     jmp    @@duu
  1214.  
  1215. @@noloop:
  1216.     movzx    eax,[es:si+gusInstrument.length]
  1217.     mov    edi,ecx
  1218.     add    edi,eax             ; Sample end address
  1219.     xor    al,al                ; No loop
  1220. @@duu:
  1221.     mov    [bx+channels.looped],al     ; Put loop flag
  1222.     mov    [bx+channels.sstart],ecx    ; Tell loop start to GUS
  1223.     mov    [bx+channels.send],edi        ; And loop end
  1224.     or    [bx+channels.status],16     ; Sample changed
  1225.  
  1226. @@nochange:
  1227.     mov    ax,[es:si+gusInstrument.volume] ; Set volume
  1228.  
  1229.     mov    [bx+channels.volume],ax
  1230.     or    [bx+channels.status],4
  1231.  
  1232. @@poiss:
  1233.     cmp    [surround],0
  1234.     je    @@quit
  1235.  
  1236.     mov    bx,[chan]
  1237.     add    bx,[chancount]
  1238.     imul    bx,bx,size gusChannel        ; Channel block
  1239.  
  1240.     mov    ax,[inst]
  1241.  
  1242.     cmp    [bx+channels.inst],al
  1243.     je    @@nochange2
  1244.  
  1245.     mov    [bx+channels.inst],al        ; Set instrument
  1246.  
  1247.     mov    ecx,[es:si+gusInstrument.surround] ; Start address
  1248.     mov    [bx+channels.scurrent],ecx    ; Tell start position to GUS
  1249.  
  1250.     test    [es:si+gusInstrument.flags],2    ; Is sample looped?
  1251.     jz    @@noloop2
  1252.  
  1253.     mov    edi,ecx
  1254.     movzx    eax,[es:si+gusInstrument.loopEnd]
  1255.     add    edi,eax             ; Loop end address
  1256.     movzx    eax,[es:si+gusInstrument.loopStart]
  1257.     add    ecx,eax             ; Loop start address
  1258.     mov    al,8                ; Enable loop
  1259.     jmp    @@duu2
  1260.  
  1261. @@noloop2:
  1262.     movzx    eax,[es:si+gusInstrument.length]
  1263.     mov    edi,ecx
  1264.     add    edi,eax             ; Sample end address
  1265.     xor    al,al                ; No loop
  1266. @@duu2:
  1267.     mov    [bx+channels.looped],al     ; Put loop flag
  1268.     mov    [bx+channels.sstart],ecx    ; Tell loop start to GUS
  1269.     mov    [bx+channels.send],edi        ; And loop end
  1270.     or    [bx+channels.status],16     ; Sample changed
  1271.  
  1272. @@nochange2:
  1273.     mov    ax,[es:si+gusInstrument.volume]      ; Set volume
  1274.     mov    [bx+channels.volume],ax
  1275.     or    [bx+channels.status],4
  1276.  
  1277. @@quit:
  1278.     xor    ax,ax
  1279.     ret
  1280.  
  1281. @@stop: call    gusStopSound LANG, [chan]
  1282.     ret
  1283.  
  1284. @@errinst:
  1285.     mov    ax,errInvalidInstHandle
  1286.     jmp    @@err
  1287. @@errchn:
  1288.     mov    ax,errInvalidChanNumber
  1289. @@err:    ERROR    ID_gusSetInst
  1290.     ret
  1291. ENDP
  1292.  
  1293. ;/***************************************************************************\
  1294. ;*
  1295. ;* Function:    int gusSetPos(ushort chan, ushort pos)
  1296. ;*
  1297. ;* Description: Sets the playing position for a channel
  1298. ;*
  1299. ;* Input:    ushort chan        Channel number
  1300. ;*        ushort pos        New playing position
  1301. ;*
  1302. ;* Returns:    MIDAS error code.
  1303. ;*
  1304. ;\***************************************************************************/
  1305. PROC    gusSetPos    FAR    chan:word, pos:word
  1306. USES    si
  1307.  
  1308.     mov    bx,[chan]
  1309.     cmp    [chancount],bx
  1310.     jle    @@err
  1311.     imul    bx,bx,size gusChannel        ; Channel block
  1312.  
  1313.     movzx    dx,[bx+channels.inst]
  1314.     test    dx,dx
  1315.     jz    @@quit                ; No instrument?
  1316.  
  1317.     dec    dx                ; Table starts from 1
  1318.     imul    dx,dx,SIZE gusInstrument
  1319.     les    si,[Instruments]
  1320.     add    si,dx
  1321.  
  1322.     movzx    ecx,[pos]
  1323.     cmp    [es:si+gusInstrument.length],cx ; Over from end?
  1324.     jae    @@ok
  1325.  
  1326.     movzx    ecx,[es:si+gusInstrument.loopStart] ; Yep. Start from loop
  1327.     test    [es:si+gusInstrument.flags],2
  1328.     jnz    @@ok
  1329.  
  1330.     call    gusStopSound LANG, [chan]
  1331.     ret
  1332.  
  1333. @@ok:    add    ecx,[es:si+gusInstrument.sample] ; Add sample start to position
  1334.     mov    [bx+channels.scurrent],ecx    ; Set start position
  1335.     and    [bx+channels.status],NOT 17    ; AND stop sound and sample changed off
  1336.     or    [bx+channels.status],2        ; Retrig
  1337.  
  1338.     cmp    [surround],0
  1339.     je    @@quit
  1340.  
  1341.     mov    bx,[chan]
  1342.     add    bx,[chancount]
  1343.     imul    bx,bx,size gusChannel        ; Channel block
  1344.  
  1345.     movzx    ecx,[pos]
  1346.     add    ecx,[es:si+gusInstrument.surround] ; Add sample start to position
  1347.     mov    [bx+channels.scurrent],ecx    ; Set start position
  1348.     and    [bx+channels.status],NOT 17    ; AND stop sound and sample changed off
  1349.     or    [bx+channels.status],2        ; Retrig
  1350.  
  1351. @@quit:
  1352.     xor    ax,ax
  1353.     ret
  1354.  
  1355. @@err:    mov    ax,errInvalidChanNumber
  1356.     ERROR    ID_gusSetPos
  1357.     ret
  1358. ENDP
  1359.  
  1360.  
  1361. ;/***************************************************************************\
  1362. ;*
  1363. ;* Function:    int gusGetPos(ushort chan, ushort *pos)
  1364. ;*
  1365. ;* Description: Gets the playing position of a channel
  1366. ;*
  1367. ;* Input:    ushort chan        Channel number
  1368. ;*
  1369. ;* Returns:    MIDAS error code.
  1370. ;*
  1371. ;\***************************************************************************/
  1372.  
  1373. PROC    gusGetPos    FAR    chan:word, pos:far ptr
  1374. USES    si
  1375.  
  1376.     mov    bx,[chan]
  1377.     cmp    [chancount],bx
  1378.     jle    @@err
  1379.  
  1380.     mov    dx,[voicesel]            ; Select voice
  1381.     mov    ax,bx
  1382.     out    dx,al
  1383.  
  1384.     regsel    80h                ; Voice control
  1385.     add    dx,2
  1386.     in    al,dx
  1387.     test    al,1
  1388.     jnz    @@stopped            ; Is sound on?
  1389.  
  1390.     imul    bx,bx,size gusChannel        ; Channel block
  1391.  
  1392.     regsel    8ah                ; Current position high
  1393.     inc    dx
  1394.     in    ax,dx
  1395.     xor    ecx,ecx
  1396.     mov    cx,ax
  1397.     and    cx,01fffh
  1398.     shl    ecx,7
  1399.  
  1400.     regsel    8bh                ; Current position low
  1401.     inc    dx
  1402.     in    ax,dx
  1403.     shr    ax,9
  1404.     or    cx,ax
  1405.  
  1406.     movzx    bx,[bx+channels.inst]
  1407.     dec    bx
  1408.     imul    bx,bx,SIZE gusInstrument
  1409.  
  1410.     les    si,[Instruments]
  1411.     sub    ecx,[es:si+bx+gusInstrument.sample]
  1412.  
  1413.     mov    ax,cx
  1414.     test    ax,ax
  1415.     jnz    @@oke
  1416.     inc    ax
  1417. @@oke:
  1418.     les    bx,[pos]
  1419.     mov    [es:bx],ax
  1420.     xor    ax,ax
  1421.     ret
  1422.  
  1423. @@stopped:                    ; No sound is being played
  1424.     les    bx,[pos]
  1425.     mov    [word es:bx],0
  1426.     xor    ax,ax
  1427.     ret
  1428.  
  1429. @@err:    mov    ax,errInvalidChanNumber
  1430.     ERROR    ID_gusGetPos
  1431.     ret
  1432.  
  1433. ENDP
  1434.  
  1435.  
  1436. ;/***************************************************************************\
  1437. ;*
  1438. ;* Function:    int gusSetPanning(ushort chan, short panning)
  1439. ;*
  1440. ;* Description: Sets the panning position for a channel
  1441. ;*
  1442. ;* Input:    ushort channel        Channel number
  1443. ;*        short panning        Panning info (See enum)
  1444. ;*
  1445. ;* Returns:    MIDAS error code.
  1446. ;*
  1447. ;\***************************************************************************/
  1448. PROC    gusSetPanning    FAR    chan:word, panning:word
  1449.  
  1450.     mov    dx,[voicesel]            ; Voice Select
  1451.     mov    ax,[chan]
  1452.     cmp    [chancount],ax
  1453.     jle    @@err
  1454.     out    dx,al
  1455.  
  1456.     mov    bx,[chan]
  1457.     imul    bx,bx,size gusChannel        ; Channel block
  1458.  
  1459.     regsel    12                ; Pan Position
  1460.     add    dx,2                ; data low
  1461.     mov    ax,[panning]
  1462.  
  1463.     mov    [bx+channels.panning],ax    ; Panning position
  1464.  
  1465.     cmp    [monoFlag],1
  1466.     je    @@jatkuu            ; Skip if forced mono
  1467.  
  1468.     cmp    ax,panSurround
  1469.     jne    @@juuh
  1470.  
  1471.     cmp    [surround],0
  1472.     jne    @@huu
  1473.     xor    ax,ax
  1474.     jmp    @@juuh
  1475.  
  1476. @@huu:    xor    al,al                ; To extreme left
  1477.     out    dx,al
  1478.  
  1479.     mov    dx,[voicesel]            ; Voice Select
  1480.     mov    ax,[chan]
  1481.     add    ax,[chancount]            ; Surround channel
  1482.     out    dx,al
  1483.  
  1484.     regsel    12                ; Pan Position
  1485.     add    dx,2                ; data low
  1486.     mov    al,15                ; To extreme right
  1487.     out    dx,al
  1488.  
  1489.     mov    [bx+channels.surround],1    ; This is a surround channel
  1490.     mov    al,[bx+channels.status]     ; Copy status (mute)
  1491.  
  1492.     mov    cx,[chancount]
  1493.     imul    cx,cx,size gusChannel        ; Channel block
  1494.     add    bx,cx
  1495.  
  1496.     mov    [bx+channels.surround],1    ; This is a surround, too
  1497.     mov    [bx+channels.status],al
  1498.     jmp    @@jatkuu
  1499.  
  1500. @@juuh: mov    [bx+channels.surround],0    ; Normal channel
  1501.  
  1502.     mov    bx,[chan]
  1503.     add    bx,[chancount]
  1504.     cmp    bx,32
  1505.     jae    @@skib
  1506.     imul    bx,bx,size gusChannel        ; Channel block
  1507.     mov    [bx+channels.surround],0    ; No longer surround channel (?)
  1508.     or    [bx+channels.status],80h    ; Mute channel
  1509.  
  1510. @@skib: sar    ax,3
  1511.     or    ax,ax                ; Sign
  1512.     jns    @@pos
  1513.     inc    ax
  1514. @@pos:    add    ax,7
  1515.     out    dx,al
  1516.  
  1517. @@jatkuu:
  1518.     mov    [masterchanged],1        ; Force reset of volume
  1519. @@quit: xor    ax,ax
  1520.     ret
  1521.  
  1522. @@err:    mov    ax,errInvalidChanNumber
  1523.     ERROR    ID_gusSetPanning
  1524.     ret
  1525. ENDP
  1526.  
  1527.  
  1528.  
  1529. ;/***************************************************************************\
  1530. ;*
  1531. ;* Function:    int gusGetPanning(ushort chan, short *panning)
  1532. ;*
  1533. ;* Description: Gets the panning position for a channel
  1534. ;*
  1535. ;* Input:    ushort channel        Channel number
  1536. ;*
  1537. ;* Returns:    MIDAS error code.
  1538. ;*
  1539. ;\***************************************************************************/
  1540.  
  1541. PROC    gusGetPanning    FAR    channel : word, panning : far ptr
  1542.  
  1543.     mov    bx,[channel]
  1544.     cmp    [chancount],bx
  1545.     jle    @@err
  1546.     imul    bx,bx,size gusChannel        ; Channel block
  1547.     mov    ax,[bx+channels.panning]    ; Panning position
  1548.     les    bx,[panning]
  1549.     mov    [es:bx],ax
  1550.     xor    ax,ax
  1551.     ret
  1552.  
  1553. @@err:    mov    ax,errInvalidChanNumber
  1554.     ERROR    ID_gusGetPanning
  1555.     ret
  1556. ENDP
  1557.  
  1558.  
  1559.  
  1560. ;/***************************************************************************\
  1561. ;*
  1562. ;* Function:    int gusMuteChannel(ushort chan, ushort mute)
  1563. ;*
  1564. ;* Description: Mutes or unmutes a channel
  1565. ;*
  1566. ;* Input:    ushort chan        Channel number
  1567. ;*        ushort mute        UnMute = 0 / Mute = 1
  1568. ;*
  1569. ;* Returns:    MIDAS error code.
  1570. ;*
  1571. ;\***************************************************************************/
  1572. PROC    gusMuteChannel    FAR    chan:word, mute:word
  1573.  
  1574.     mov    bx,[chan]
  1575.     cmp    [chancount],bx
  1576.     jle    @@err
  1577.     imul    bx,bx,SIZE gusChannel
  1578.  
  1579.     mov    [masterchanged],1
  1580.  
  1581.     mov    ax,[mute]
  1582.     cmp    ax,1
  1583.     je    @@mute
  1584.     and    [bx+channels.status],07fh
  1585.     jmp    @@guu
  1586. @@mute:
  1587.     or     [bx+channels.status],80h
  1588.  
  1589. @@guu:    cmp    [bx+channels.surround],0
  1590.     je    @@pois
  1591.  
  1592.     mov    bx,[chan]
  1593.     add    bx,[chancount]
  1594.     imul    bx,bx,SIZE gusChannel
  1595.  
  1596.     mov    ax,[mute]
  1597.     cmp    ax,1
  1598.     je    @@mute2
  1599.     and    [bx+channels.status],07fh
  1600.     jmp    @@pois
  1601. @@mute2:
  1602.     or     [bx+channels.status],80h
  1603.  
  1604. @@pois: xor    ax,ax
  1605.     ret
  1606.  
  1607. @@err:    mov    ax,errInvalidChanNumber
  1608.     ERROR    ID_gusMuteChannel
  1609.     ret
  1610.  
  1611. ENDP
  1612.  
  1613.  
  1614.  
  1615. ;/***************************************************************************\
  1616. ;*
  1617. ;* Function:    int gusAddInst(uchar *sample, ushort smpType, ushort length,\
  1618. ;*                   ushort loopStart, ushort loopEnd,\
  1619. ;*                   ushort volume, ushort loop, ushort *sdInstNum)
  1620. ;*
  1621. ;* Description: Adds an instrument to the GUS SD internal tables for
  1622. ;*        use and moves it to GUS memory
  1623. ;*
  1624. ;* Input:    uchar  *sample        pointer to sample
  1625. ;*        ushort smpType        sample type
  1626. ;*        ushort length        sample length
  1627. ;*        ushort loopStart    loop start offset
  1628. ;*        ushort loopEnd        loop end offset
  1629. ;*        ushort volume        sample default volume
  1630. ;*        ushort loop        sample loop flag
  1631. ;*
  1632. ;* Returns:    MIDAS error code.
  1633. ;*
  1634. ;\***************************************************************************/
  1635.  
  1636. PROC    gusAddInst    FAR    inst:far ptr, stype:word, length:word, loopStart:word,\
  1637.                 loopEnd:word, volume:word, loop:word, sdNum:far ptr
  1638. USES    si,di
  1639. LOCAL    gusmem:dword, gusmem2:dword
  1640.  
  1641.     cmp    [stype],smp8bit
  1642.     jne    @@errinst
  1643.  
  1644.     mov    ax,[instpos]
  1645.     dec    ax                ; Table starts from 1
  1646.     imul    ax,ax,SIZE gusInstrument
  1647.     les    di,[Instruments]
  1648.     add    di,ax
  1649.  
  1650.     cmp    [length],0
  1651.     je    @@nsurr
  1652.  
  1653.     push    es
  1654.     call    gusMalloc LANG, [length], seg temp offset temp
  1655.     pop    es
  1656.     test    ax,ax
  1657.     jnz    @@err
  1658.  
  1659.     mov    eax,[temp]
  1660.     mov    [gusmem],eax
  1661.  
  1662.     mov    [es:di+gusInstrument.sample],eax   ; Sample start
  1663.     mov    [es:di+gusInstrument.surround],0
  1664.  
  1665.     cmp    [surround],0
  1666.     je    @@nsurr
  1667.  
  1668.     push    es
  1669.     call    gusMalloc LANG, [length], seg temp offset temp
  1670.     pop    es
  1671.     test    ax,ax
  1672.     jnz    @@err
  1673.  
  1674.     mov    eax,[temp]
  1675.     mov    [gusmem2],eax
  1676.     mov    [es:di+gusInstrument.surround],eax ; Surround sample start
  1677.  
  1678. @@nsurr:
  1679.     mov    ax,[length]
  1680.     mov    [es:di+gusInstrument.length],ax ; Sample length
  1681.  
  1682.     mov    ax,[loopStart]
  1683.     mov    [es:di+gusInstrument.loopStart],ax ; Loop start offset
  1684.  
  1685.     mov    ax,[loopEnd]
  1686.     mov    [es:di+gusInstrument.loopEnd],ax  ; Loop end offset
  1687.  
  1688.     mov    ax,[volume]
  1689.     cmp    ax,64
  1690.     jbe    @@oke
  1691.     mov    ax,64
  1692. @@oke:    mov    [es:di+gusInstrument.volume],ax ; Default volume
  1693.  
  1694.     mov    ax,[loop]            ; Loop flag
  1695.     and    ax,1
  1696.     add    ax,ax
  1697.     or    ax,1                ; Used flag
  1698.     mov    [es:di+gusInstrument.flags],ax
  1699.  
  1700.  
  1701.     les    si,[inst]            ; Pointer to sample
  1702.  
  1703.     mov    cx,[length]
  1704.     test    cx,cx
  1705.     jz    @@qwit
  1706.  
  1707.     mov    ebx,[gusmem]            ; Start in GUS memory
  1708.     mov    di,bx
  1709.     shr    ebx,16
  1710.  
  1711. @@dumploop2:
  1712.     regsel    44h                ; Addr hi
  1713.     add    dx,2                ; 3x5
  1714.     mov    ax,bx
  1715.     out    dx,al                ; upper bits of address
  1716.  
  1717.     regsel    43h                ; Addr lo
  1718. @@dumploop:
  1719.     mov    dx,[selreg]
  1720.     inc    dx                ; 3x4
  1721.     mov    ax,di
  1722.     out    dx,ax
  1723.     add    dx,3                ; 3x7
  1724.     mov    al,[es:si]            ; Get data
  1725.     inc    si
  1726.     xor    al,80h                ; Unsigned (MUUTA!)
  1727.     out    dx,al
  1728.  
  1729.     add    di,1                ; Inc ei aseta carryä
  1730.     jc    @@yli64
  1731.     loop    @@dumploop            ; Dump the whole sample
  1732.     jmp    @@quit
  1733.  
  1734. @@yli64:
  1735.     inc    bx                ; Crossed 64kb border
  1736.     loop    @@dumploop2            ; Dump the whole sample
  1737.  
  1738.  
  1739. @@quit: test    [loop],1
  1740.     jz    @@noloob            ; Looped?
  1741.  
  1742. @@loobed:                    ; Copy loop to next 32 byte border
  1743.     les    si,[inst]
  1744.     add    si,[loopStart]
  1745.  
  1746.     mov    dx,di
  1747.     and    dx,01fh             ; Alimmat pois
  1748.     mov    cx,64
  1749.     sub    cx,dx
  1750.  
  1751. @@dumploop3:
  1752.     regsel    44h                ; Addr hi
  1753.     add    dx,2                ; 3x5
  1754.     mov    ax,bx
  1755.     out    dx,al                ;upper bits of address
  1756.  
  1757.     regsel    43h                ; Addr lo
  1758. @@dumploop4:
  1759.     mov    dx,[selreg]
  1760.     inc    dx                ; 3x4
  1761.     mov    ax,di
  1762.  
  1763.     out    dx,ax
  1764.     add    dx,3                ; 3x7
  1765.     mov    al,[es:si]            ; Get data
  1766.     inc    si
  1767.     xor    al,80h                ; Unsigned (MUUTA!)
  1768.     out    dx,al
  1769.  
  1770.     add    di,1                ; Inc ei aseta carryä
  1771.     jc    @@yli642
  1772.     loop    @@dumploop3            ; Do whole loop
  1773.     jmp    @@qwti
  1774.  
  1775. @@yli642:
  1776.     inc    bx                ; Crossed 64kb border
  1777.     loop    @@dumploop4            ; Do whole loop
  1778.     jmp    @@qwti
  1779.  
  1780.  
  1781. @@noloob:                    ; Copy the last byte
  1782.     dec    si
  1783.     mov    dx,di
  1784.     and    dx,01fh             ; Alimmat pois
  1785.     mov    cx,64
  1786.     sub    cx,dx
  1787.  
  1788. @@dumploop5:
  1789.     regsel    44h                ; addr hi
  1790.     add    dx,2                ; 3x5
  1791.     mov    ax,bx
  1792.     out    dx,al                ; upper bits of address
  1793.  
  1794.     regsel    43h                ; addr lo
  1795. @@dumploop6:
  1796.     mov    dx,[selreg]
  1797.     inc    dx                ; 3x4
  1798.     mov    ax,di
  1799.  
  1800.     out    dx,ax
  1801.     add    dx,3                ; 3x7
  1802.     mov    al,[es:si]            ; Get data
  1803.     xor    al,80h                ; Unsigned (MUUTA!)
  1804.     out    dx,al
  1805.  
  1806.     add    di,1                ; Inc ei aseta carryä
  1807.     jc    @@yli643
  1808.     loop    @@dumploop6
  1809.     jmp    @@qwti
  1810. @@yli643:
  1811.     inc    bx                ; Crossed 64kb border
  1812.     loop    @@dumploop5
  1813.  
  1814. @@qwti: cmp    [surround],0
  1815.     je    @@qwit
  1816.  
  1817.     call    CopySurroundSample LANG, [inst], [length], [loopStart],\
  1818.                      [loop], [gusmem2]
  1819.  
  1820.  
  1821. @@qwit: push    [instpos]            ; Return instrument number
  1822.  
  1823.     mov    ax,[instpos]
  1824.     mov    bx,ax
  1825.     dec    bx
  1826.     imul    bx,bx,SIZE gusInstrument
  1827.     les    si,[Instruments]
  1828.     add    si,bx
  1829. @@search:                    ; Search next free instrument
  1830.     test    [es:si+gusInstrument.flags],1
  1831.     jz    @@found
  1832.     add    si,SIZE gusInstrument
  1833.     inc    ax
  1834.     jmp    @@search
  1835.  
  1836. @@found:
  1837.     mov    [instpos],ax
  1838.     pop    ax
  1839.     les    bx,[sdNum]
  1840.     mov    [es:bx],ax
  1841.  
  1842.     cmp    ax,[numInsts]
  1843.     jbe    @@huu
  1844.     mov    [numInsts],ax
  1845. @@huu:
  1846.     xor    ax,ax
  1847.     ret
  1848.  
  1849.  
  1850. @@errinst:
  1851.     mov    ax,errInvalidInst
  1852. @@err:    ERROR    ID_gusAddInst
  1853.     ret
  1854. ENDP
  1855.  
  1856.  
  1857.  
  1858. PROC    CopySurroundSample NEAR inst:far ptr, length:word, loopStart:word,\
  1859.                 loop:word, gusmem:dword
  1860. USES    si,di
  1861.  
  1862.     les    si,[inst]            ; Pointer to sample
  1863.  
  1864.     mov    cx,[length]
  1865.  
  1866.     mov    ebx,[gusmem]            ; Start in GUS memory
  1867.     mov    di,bx
  1868.     shr    ebx,16
  1869.  
  1870. @@dumploop2:
  1871.     regsel    44h
  1872.     add    dx,2                ;3x5
  1873.     mov    ax,bx
  1874.     out    dx,al                ;upper bits of address
  1875.  
  1876.     regsel    43h
  1877. @@dumploop:
  1878.     mov    dx,[selreg]
  1879.     inc    dx                ; 3x4
  1880.     mov    ax,di
  1881.     out    dx,ax
  1882.     add    dx,3                ; 3x7
  1883.     mov    al,[es:si]            ; Get data
  1884.     inc    si
  1885.     xor    al,80h                ; Unsigned (MUUTA!)
  1886.     not    al                ; 180 degree phase transformation
  1887.     out    dx,al
  1888.  
  1889.     add    di,1                ; Inc ei aseta carryä
  1890.     jc    @@yli64
  1891.     loop    @@dumploop            ; Dump the whole sample
  1892.     jmp    @@quit
  1893.  
  1894. @@yli64:
  1895.     inc    bx                ; Crossed 64kb border
  1896.     loop    @@dumploop2            ; Dump the whole sample
  1897.  
  1898. @@quit: test    [loop],1
  1899.     jz    @@noloob            ; Looped?
  1900.  
  1901. @@loobed:                    ; Copy loop to next 32 byte border
  1902.     les    si,[inst]
  1903.     add    si,[loopStart]
  1904.  
  1905.     mov    dx,di
  1906.     and    dx,01fh             ; Alimmat pois
  1907.     mov    cx,64
  1908.     sub    cx,dx
  1909.  
  1910. @@dumploop3:
  1911.     regsel    44h
  1912.     add    dx,2                ;3x5
  1913.     mov    ax,bx
  1914.     out    dx,al                ;upper bits of address
  1915.  
  1916.     regsel    43h
  1917. @@dumploop4:
  1918.     mov    dx,[selreg]
  1919.     inc    dx                ; 3x4
  1920.     mov    ax,di
  1921.  
  1922.     out    dx,ax
  1923.     add    dx,3                ; 3x7
  1924.     mov    al,[es:si]            ; Get data
  1925.     inc    si
  1926.     xor    al,80h                ; Unsigned (MUUTA!)
  1927.     not    al                ; 180 degree phase transformation
  1928.     out    dx,al
  1929.  
  1930.     add    di,1                ; Inc ei aseta carryä
  1931.     jc    @@yli642
  1932.     loop    @@dumploop3            ; Do whole loop
  1933.     jmp    @@qwit
  1934.  
  1935. @@yli642:
  1936.     inc    bx                ; Crossed 64kb border
  1937.     loop    @@dumploop4            ; Do whole loop
  1938.     jmp    @@qwit
  1939.  
  1940.  
  1941.  
  1942. @@noloob:                    ; Copy the last byte
  1943.     dec    si
  1944.     mov    dx,di
  1945.     and    dx,01fh             ; Alimmat pois
  1946.     mov    cx,64
  1947.     sub    cx,dx
  1948.  
  1949. @@dumploop5:
  1950.     regsel    44h
  1951.     add    dx,2                ;3x5
  1952.     mov    ax,bx
  1953.     out    dx,al                ;upper bits of address
  1954.  
  1955.     regsel    43h
  1956. @@dumploop6:
  1957.     mov    dx,[selreg]
  1958.     inc    dx                ; 3x4
  1959.     mov    ax,di
  1960.  
  1961.     out    dx,ax
  1962.     add    dx,3                ; 3x7
  1963.     mov    al,[es:si]            ; Get data
  1964.     xor    al,80h                ; Unsigned (MUUTA!)
  1965.     not    al                ; 180 degree phase transformation
  1966.     out    dx,al
  1967.  
  1968.     add    di,1                ; Inc ei aseta carryä
  1969.     jc    @@yli643
  1970.     loop    @@dumploop6
  1971.     jmp    @@qwit
  1972. @@yli643:
  1973.     inc    bx                ; Crossed 64kb border
  1974.     loop    @@dumploop5
  1975. @@qwit:
  1976.     ret
  1977. ENDP
  1978.  
  1979.  
  1980. ;/***************************************************************************\
  1981. ;*
  1982. ;* Function:    int gusRemInst(ushort inst)
  1983. ;*
  1984. ;* Description: Removes an instrument from the GUS SD internal tables
  1985. ;*        and frees it from GUS memory
  1986. ;*
  1987. ;* Input:    ushort    inst        Instrument number from AddInstrument
  1988. ;*
  1989. ;* Returns:    MIDAS error code.
  1990. ;*
  1991. ;\***************************************************************************/
  1992.  
  1993. PROC    gusRemInst    FAR    inst:word
  1994. USES    si
  1995.  
  1996.     mov    bx,[inst]
  1997.     dec    bx
  1998.     imul    bx,bx,SIZE gusInstrument
  1999.     les    si,[Instruments]
  2000.     add    si,bx
  2001.  
  2002.     test    [es:si+gusInstrument.flags],1
  2003.     jz    @@nothing
  2004.  
  2005.     mov    [es:si+gusInstrument.flags],0    ; Free instrument
  2006.  
  2007.     cmp    [es:si+gusInstrument.length],0
  2008.     je    @@nsurround
  2009.  
  2010.     push    es
  2011.     call    gusFree LANG, [es:si+gusInstrument.sample]
  2012.     pop    es
  2013.     test    ax,ax
  2014.     jnz    @@err
  2015.  
  2016.     cmp    [es:si+gusInstrument.surround],0
  2017.     je    @@nsurround
  2018.  
  2019.     call    gusFree LANG, [es:si+gusInstrument.surround]
  2020.     test    ax,ax
  2021.     jnz    @@err
  2022.  
  2023. @@nsurround:
  2024.     mov    ax,[inst]
  2025.     cmp    ax,[instpos]
  2026.     jae    @@nothing
  2027.  
  2028.     mov    [instpos],ax            ; Lowest instrument number
  2029. @@nothing:
  2030.     cmp    [numInsts],ax
  2031.     jne    @@juu
  2032.  
  2033.     les    si,[Instruments]
  2034.     mov    cx,ax
  2035.     mov    bx,1
  2036.     mov    ax,bx
  2037. @@search:                    ; Search next free instrument
  2038.     test    [es:si+gusInstrument.flags],1
  2039.     jz    @@nop
  2040.     mov    ax,bx
  2041.  
  2042. @@nop:    add    si,SIZE gusInstrument
  2043.     inc    bx
  2044.     loop    @@search
  2045.     mov    [numInsts],ax
  2046. @@juu:    xor    ax,ax
  2047.     ret
  2048.  
  2049. @@err:    ERROR    ID_gusRemInst
  2050.     ret
  2051. ENDP
  2052.  
  2053.  
  2054.  
  2055. ;/***************************************************************************\
  2056. ;*
  2057. ;* Function:    int gusSetUpdRate(ushort rate)
  2058. ;*
  2059. ;* Description: Sets the update rate of SD.
  2060. ;*
  2061. ;* Input:    ushort    rate            Rate in Hz*100
  2062. ;*
  2063. ;* Returns:    MIDAS error code.
  2064. ;*
  2065. ;\***************************************************************************/
  2066.  
  2067. PROC    gusSetUpdRate    FAR    rate:word
  2068.  
  2069.     mov    ax,[rate]
  2070.     mov    [updRate],ax
  2071.     xor    ax,ax
  2072.     ret
  2073. ENDP
  2074.  
  2075.  
  2076. ;/***************************************************************************\
  2077. ;*
  2078. ;* Function:    int gusPlay(int *callMP)
  2079. ;*
  2080. ;* Description: Updates the GUS registers according to the Sound Device
  2081. ;*        internal datas
  2082. ;*
  2083. ;* Returns:    MIDAS error code.
  2084. ;*
  2085. ;\***************************************************************************/
  2086. PROC    gusPlay FAR    callMP : far ptr
  2087. LOCAL    chanc:word
  2088.  
  2089. USES    si
  2090.     cmp    [paused],0
  2091.     jne    @@paused
  2092.  
  2093.     mov    [chanc],0            ; Start from channel 0
  2094.     mov    si,offset channels        ; Channel data
  2095. @@loop:
  2096.     mov    dx,[voicesel]            ; Select voice
  2097.     mov    ax,[chanc]
  2098.     out    dx,al
  2099.  
  2100.     test    [si+gusChannel.status],3    ; Retrig / stop sound?
  2101.     jz    @@nothing
  2102.  
  2103.     and    [si+gusChannel.status],NOT 1    ; And stop sound off
  2104.  
  2105.     regsel    0                ; Voice control
  2106.     add    dx,2
  2107.     mov    al,3                ; Stop voice
  2108.     out    dx,al
  2109.  
  2110.     regsel    9                ; Current volume
  2111.     inc    dx
  2112.     mov    ax,1100h            ; To zero
  2113.     out    dx,ax
  2114.  
  2115.     regsel    0dh                ; Ramp control
  2116.     add    dx,2
  2117.     mov    al,3                ; Stop
  2118.     out    dx,al
  2119.  
  2120.     call    gusdelay
  2121.  
  2122.     regsel    0                ; Voice control
  2123.     add    dx,2
  2124.     mov    al,3                ; Stop voice
  2125.     out    dx,al
  2126.  
  2127.     regsel    0dh                ; Ramp control
  2128.     add    dx,2
  2129.     mov    al,3                ; Stop
  2130.     out    dx,al
  2131.  
  2132.     regsel    9                ; Current volume
  2133.     inc    dx
  2134.     mov    ax,1100h            ; To zero
  2135.     out    dx,ax
  2136.  
  2137.     test    [si+gusChannel.status],2
  2138.     jz    @@stopped            ; Only stop
  2139.  
  2140.     mov    ecx,[si+gusChannel.send]    ; Set sample end
  2141.  
  2142.     regsel    4                ; End position high
  2143.     inc    dx
  2144.     mov    eax,ecx
  2145.     shr    eax,7
  2146.     out    dx,ax
  2147.     regsel    5                ; End position low
  2148.     inc    dx
  2149.     mov    eax,ecx
  2150.     shl    ax,9
  2151.     out    dx,ax
  2152.  
  2153.     mov    ecx,[si+gusChannel.sstart]    ; Set loop start
  2154.  
  2155.     regsel    2                ; Start position high
  2156.     inc    dx
  2157.     mov    eax,ecx
  2158.     shr    eax,7
  2159.     out    dx,ax
  2160.     regsel    3                ; Start position low
  2161.     inc    dx
  2162.     mov    eax,ecx
  2163.     shl    ax,9
  2164.     out    dx,ax
  2165.  
  2166.     mov    ecx,[si+gusChannel.scurrent]    ; Set starting address
  2167.  
  2168.     regsel    10                ; Current position high
  2169.     inc    dx
  2170.     mov    eax,ecx
  2171.     shr    eax,7
  2172.     out    dx,ax
  2173.     regsel    11                ; Current position low
  2174.     inc    dx
  2175.     mov    eax,ecx
  2176.     shl    ax,9
  2177.     out    dx,ax
  2178.  
  2179.     call    gusdelay            ; Delay
  2180.  
  2181.     regsel    10                ; Current position high
  2182.     inc    dx
  2183.     mov    eax,ecx
  2184.     shr    eax,7
  2185.     out    dx,ax
  2186.     regsel    11                ; Current position low
  2187.     inc    dx
  2188.     mov    eax,ecx
  2189.     shl    ax,9
  2190.     out    dx,ax
  2191.  
  2192.     regsel    7                ; Ramp start
  2193.     add    dx,2
  2194.     mov    al,11h                ; From 0
  2195.     out    dx,al
  2196.  
  2197.     regsel    8                ; Ramp end
  2198.     add    dx,2
  2199.     mov    ax,[si+gusChannel.volume]    ; To set volume
  2200.  
  2201.     test    [si+gusChannel.status],80h
  2202.     jz    @@oek
  2203.     xor    ax,ax
  2204. @@oek:
  2205.     mov    bx,[mastervol]
  2206.     mul    bl
  2207.     shr    ax,6
  2208.     mov    bx,ax
  2209.     add    bx,bx
  2210.     mov    ax,[voltable+bx]
  2211.     mov    al,ah
  2212.  
  2213.     cmp    [si+gusChannel.surround],0
  2214.     je    @@hu
  2215.     sub    al,10h                ; Halve the volume
  2216. @@hu:    out    dx,al
  2217.  
  2218.     regsel    6                ; Ramp Rate
  2219.     add    dx,2
  2220.     mov    al,0fh                ; Rate
  2221.     out    dx,al
  2222.     jmp    @@setfc
  2223.  
  2224. @@nothing:
  2225.     cmp    [masterchanged],0
  2226.     jnz    @@set
  2227.     test    [si+gusChannel.status],4
  2228.     jz    @@setfc
  2229. @@set:    and    [si+gusChannel.status],NOT 4
  2230.     regsel    89h
  2231.     inc    dx
  2232.     in    ax,dx
  2233.     mov    cx,ax
  2234.     xor    cl,cl
  2235.  
  2236.     mov    ax,[si+gusChannel.volume]    ; To set volume
  2237.     test    [si+gusChannel.status],80h
  2238.     jz    @@oek2
  2239.     xor    ax,ax
  2240. @@oek2: mov    bx,[mastervol]
  2241.     mul    bl
  2242.     shr    ax,6
  2243.     mov    bx,ax
  2244.     add    bx,bx
  2245.     mov    bx,[voltable+bx]
  2246.  
  2247.     cmp    [si+gusChannel.surround],0
  2248.     je    @@hu2
  2249.     sub    bh,10h                ; Halve the volume
  2250. @@hu2:    xor    bl,bl
  2251.     cmp    cx,bx
  2252.     je    @@setfc
  2253.     cmp    cx,bx
  2254.     jb    @@yli
  2255.     xchg    cx,bx
  2256.     mov    cl,40h
  2257. @@yli:
  2258.     regsel    0dh                ; Ramp Control
  2259.     add    dx,2
  2260.     mov    al,3
  2261.     out    dx,al                ; Stop Ramp
  2262.  
  2263.     call    gusdelay
  2264.  
  2265.     regsel    0dh                ; Ramp Control
  2266.     add    dx,2
  2267.     mov    al,3
  2268.     out    dx,al                ; Stop Ramp
  2269.  
  2270.     regsel    7                ; Ramp start
  2271.     add    dx,2
  2272.     mov    al,ch                ; From lower
  2273.     out    dx,al
  2274.  
  2275.     regsel    8                ; Ramp end
  2276.     add    dx,2
  2277.     mov    al,bh                ; To higher volume
  2278.     out    dx,al
  2279.  
  2280.     regsel    6                ; Ramp Rate
  2281.     add    dx,2
  2282.     mov    al,2fh                ; Rate
  2283.     out    dx,al
  2284.  
  2285.     regsel    0dh                ; Ramp Control
  2286.     add    dx,2
  2287.     mov    al,cl
  2288.     out    dx,al                ; GO!
  2289.  
  2290.     call    gusdelay
  2291.  
  2292.     regsel    0dh                ; Ramp Control
  2293.     add    dx,2
  2294.     mov    al,cl
  2295.     out    dx,al                ; GO!
  2296.  
  2297.  
  2298. @@setfc:
  2299.     test    [si+gusChannel.status],8
  2300.     jz    @@stopped
  2301.  
  2302.     and    [si+gusChannel.status],NOT 8
  2303.     regsel    1                ; Frequency control
  2304.     inc    dx
  2305.     mov    ax,[si+gusChannel.fc]
  2306.     out    dx,ax
  2307.  
  2308. @@stopped:
  2309.     add    si,size gusChannel        ; Do all channels in order
  2310.     inc    [chanc]
  2311.     mov    ax,[chancount]
  2312.     cmp    [surround],0
  2313.     je    @@ij
  2314.     add    ax,ax                ; Plus Surround channels
  2315. @@ij:
  2316.     cmp    [chanc],ax
  2317.     jb    @@loop
  2318.  
  2319. ; ▒▒ PART 2 ▒▒
  2320.  
  2321.  
  2322.     mov    [chanc],0            ; Start over
  2323.     mov    si,offset channels
  2324. @@loop2:
  2325.     test    [si+gusChannel.status],2
  2326.     jz    @@no                ; No retrig
  2327.  
  2328.     mov    dx,[voicesel]            ; Select voice
  2329.     mov    ax,[chanc]
  2330.     out    dx,al
  2331.  
  2332.     regsel    0                ; Voice control
  2333.     mov    al,[si+gusChannel.looped]    ; Enable voice and possible loop
  2334.     add    dx,2
  2335.     out    dx,al
  2336.  
  2337.     regsel    0dh                ; Ramp Control
  2338.     add    dx,2
  2339.     xor    al,al
  2340.     out    dx,al                ; GO!
  2341.  
  2342.     call    gusdelay            ; Delay
  2343.  
  2344.     regsel    0                ; Write it again
  2345.     mov    al,[si+gusChannel.looped]
  2346.     add    dx,2
  2347.     out    dx,al
  2348.  
  2349.     regsel    0dh                ; Ramp Control
  2350.     add    dx,2
  2351.     xor    al,al
  2352.     out    dx,al                ; GO!
  2353.  
  2354.     and    [si+gusChannel.status],NOT 2    ; Retrig done
  2355.     jmp    @@retrigged
  2356. @@no:
  2357.     test    [si+gusChannel.status],16
  2358.     jz    @@retrigged            ; No sample changed
  2359.  
  2360.     cmp    [ALE],1
  2361.     jne    @@noALE
  2362.  
  2363.  
  2364. ;▒▒ GUS-AMIGA-LOOP-EMULATOR (GALE) (TM) V1.1!!! ▒▒
  2365.  
  2366.  
  2367.     mov    dx,[voicesel]            ; Select voice
  2368.     mov    ax,[chanc]
  2369.     out    dx,al
  2370.  
  2371.     regsel    80h                ; Voice control
  2372.     add    dx,2
  2373.     in    al,dx
  2374.  
  2375.     xor    ebx,ebx             ; Offset from loop start
  2376.     test    al,1
  2377.     jz    @@soundon
  2378.  
  2379.     test    [si+gusChannel.looped],8    ; Next sample looped?
  2380.     jz    @@stopsound            ; No
  2381.  
  2382.     mov    ebx,[si+gusChannel.sstart]
  2383.     jmp    @@startfromloop         ; Start from loop start
  2384.  
  2385. @@soundon:
  2386.     regsel    8ah                ; Current position high
  2387.     inc    dx
  2388.     in    ax,dx
  2389.     xor    ecx,ecx
  2390.     mov    cx,ax
  2391.     and    cx,01fffh
  2392.     shl    ecx,7
  2393.  
  2394.     regsel    8bh                ; Current position low
  2395.     inc    dx
  2396.     in    ax,dx
  2397.     shr    ax,9
  2398.     or    cx,ax
  2399.  
  2400.     regsel    84h                ; Sample end position high
  2401.     inc    dx
  2402.     in    ax,dx
  2403.     xor    ebx,ebx
  2404.     mov    bx,ax
  2405.     and    bx,01fffh
  2406.     shl    ebx,7
  2407.  
  2408.     regsel    85h                ; Sample end position low
  2409.     inc    dx
  2410.     in    ax,dx
  2411.     shr    ax,9
  2412.     or    bx,ax
  2413.  
  2414.     sub    ebx,ecx             ; Bytes to sample / loop end
  2415.  
  2416.     mov    eax,[si+gusChannel.frequency]
  2417.     imul    eax,eax,100            ; updRate is Hz*100
  2418.     xor    edx,edx
  2419.     push    ebx
  2420.     movzx    ebx,[updRate]
  2421.     idiv    ebx                ; eax = bytes to play until next update
  2422.     pop    ebx
  2423.  
  2424.     cmp    ebx,eax
  2425.     jge    @@retrigged            ; Some sample still to go
  2426.  
  2427.     test    [si+gusChannel.looped],8    ; Looped?
  2428.     jz    @@stopsound
  2429.  
  2430.     mov    ecx,[si+gusChannel.send]
  2431.     sub    ecx,ebx
  2432.     mov    ebx,ecx
  2433.  
  2434. @@startfromloop:
  2435. ; EBX = Starting position
  2436.  
  2437.     mov    ecx,[si+gusChannel.send]    ; Set sample end
  2438.  
  2439.     regsel    4                ; End position high
  2440.     inc    dx
  2441.     mov    eax,ecx
  2442.     shr    eax,7
  2443.     out    dx,ax
  2444.     regsel    5                ; End position low
  2445.     inc    dx
  2446.     mov    eax,ecx
  2447.     shl    ax,9
  2448.     out    dx,ax
  2449.  
  2450.     mov    ecx,[si+gusChannel.sstart]    ; Set loop start
  2451.  
  2452.     regsel    2                ; Start position high
  2453.     inc    dx
  2454.     mov    eax,ecx
  2455.     shr    eax,7
  2456.     out    dx,ax
  2457.     regsel    3                ; Start position low
  2458.     inc    dx
  2459.     mov    eax,ecx
  2460.     shl    ax,9
  2461.     out    dx,ax
  2462.  
  2463.     regsel    10                ; Current position high
  2464.     inc    dx
  2465.     mov    eax,ebx
  2466.     shr    eax,7
  2467.     out    dx,ax
  2468.     regsel    11                ; Current position low
  2469.     inc    dx
  2470.     mov    eax,ecx
  2471.     shl    ax,9
  2472.     out    dx,ax
  2473.  
  2474.     regsel    0                ; Voice control
  2475.     mov    al,[si+gusChannel.looped]    ; Enable voice and possible loop
  2476.     add    dx,2
  2477.     out    dx,al
  2478.  
  2479.     call    gusdelay            ; Delay
  2480.  
  2481.     regsel    10                ; Current position high
  2482.     inc    dx
  2483.     mov    eax,ebx
  2484.     shr    eax,7
  2485.     out    dx,ax
  2486.     regsel    11                ; Current position low
  2487.     inc    dx
  2488.     mov    eax,ecx
  2489.     shl    ax,9
  2490.     out    dx,ax
  2491.  
  2492.     regsel    0                ; Write it again
  2493.     mov    al,[si+gusChannel.looped]
  2494.     add    dx,2
  2495.     out    dx,al
  2496.  
  2497.     and    [si+gusChannel.status],NOT 16    ; Change done
  2498.     jmp    @@retrigged
  2499.  
  2500.  
  2501. @@stopsound:
  2502.     regsel    0                ; Voice control
  2503.     add    dx,2
  2504.     mov    al,3                ; Stop voice
  2505.     out    dx,al
  2506.  
  2507.     regsel    9                ; Current volume
  2508.     inc    dx
  2509.     mov    ax,1100h            ; To zero
  2510.     out    dx,ax
  2511.  
  2512.     regsel    0dh                ; Ramp control
  2513.     add    dx,2
  2514.     mov    al,3                ; Stop
  2515.     out    dx,al
  2516.  
  2517.     call    gusdelay
  2518.  
  2519.     regsel    0                ; Voice control
  2520.     add    dx,2
  2521.     mov    al,3                ; Stop voice
  2522.     out    dx,al
  2523.  
  2524.     regsel    0dh                ; Ramp control
  2525.     add    dx,2
  2526.     mov    al,3                ; Stop
  2527.     out    dx,al
  2528.  
  2529.     regsel    9                ; Current volume
  2530.     inc    dx
  2531.     mov    ax,1100h            ; To zero
  2532.     out    dx,ax
  2533.  
  2534. @@noALE:
  2535.     and    [si+gusChannel.status],NOT 16    ; Change done
  2536.  
  2537. @@retrigged:
  2538.     add    si,size gusChannel        ; Do all channels
  2539.     inc    [chanc]
  2540.     mov    ax,[chancount]
  2541.  
  2542.     cmp    [surround],0
  2543.     je    @@ij2
  2544.     add    ax,ax                ; Plus Surround channels
  2545. @@ij2:
  2546.     cmp    [chanc],ax
  2547.     jb    @@loop2
  2548.  
  2549.     mov    [masterchanged],0
  2550.  
  2551.     les    bx,[callMP]
  2552.     mov    [word es:bx],1            ; Call mp.Play!
  2553. @@done: xor    ax,ax
  2554.     ret
  2555.  
  2556. @@paused:
  2557.     les    bx,[callMP]
  2558.     mov    [word es:bx],0            ; Don't call mp.Play!
  2559.     jmp    @@done
  2560. ENDP
  2561.  
  2562. PROC    gusdelay NEAR
  2563.     push    dx ax
  2564.     mov    dx,300h
  2565.     rept    8
  2566.     in    al,dx
  2567.     endm
  2568.     pop    ax dx
  2569.     ret
  2570. ENDP
  2571.  
  2572.  
  2573.  
  2574. ;/***************************************************************************\
  2575. ;*
  2576. ;* Function:    int initHeap()
  2577. ;*
  2578. ;* Description: Initializes the GUS heap
  2579. ;*
  2580. ;* Returns:    MIDAS error code.
  2581. ;*
  2582. ;\***************************************************************************/
  2583.  
  2584.  
  2585. PROC    initHeap NEAR
  2586. USES    di
  2587.  
  2588.     mov    ax,MAXINSTS * SIZE ghb
  2589.     cmp    [surround],0
  2590.     je    @@kool
  2591.  
  2592.     add    ax,ax                ; Room for surround
  2593.                         ; blocks, too
  2594.  
  2595. @@kool:
  2596.     push    ax
  2597.     call    memAlloc LANG, ax, seg temp offset temp
  2598.                         ; Alloc room for heap blocks
  2599.  
  2600.     pop    cx                ; Size to CX
  2601.     test    ax,ax
  2602.     jne    @@err
  2603.  
  2604.     mov    ebx,[temp]
  2605.     mov    [gusHeapStart],ebx
  2606.     mov    [gusHeap],ebx
  2607.  
  2608.     les    di,[temp]
  2609.     xor    eax,eax
  2610.                         ; Size already in CX
  2611.     cld
  2612.     rep    stosb                ; Clear instrument datas
  2613.  
  2614.     les    bx,[temp]
  2615.     mov    eax,[memamount]
  2616.     mov    [es:bx+ghb.next],0        ; First block
  2617.     mov    [es:bx+ghb.gusmem],0        ; From start of GUS mem
  2618.     mov    [es:bx+ghb.length],eax        ; Whole GUS memory
  2619.     xor    ax,ax
  2620.     ret
  2621.  
  2622. @@err:    ERROR    ID_gusInitHeap
  2623.     ret
  2624. ENDP
  2625.  
  2626.  
  2627. ;/***************************************************************************\
  2628. ;*
  2629. ;* Function:    int freeHeap()
  2630. ;*
  2631. ;* Description: Uninitializes the GUS heap
  2632. ;*
  2633. ;* Returns:    MIDAS error code.
  2634. ;*
  2635. ;\***************************************************************************/
  2636.  
  2637.  
  2638. PROC    freeHeap NEAR
  2639.     call    memFree LANG, [gusHeap]
  2640.     test    ax,ax
  2641.     jnz    @@err
  2642.     xor    ax,ax
  2643.     ret
  2644.  
  2645. @@err:    ERROR    ID_gusFreeHeap
  2646.     ret
  2647. ENDP
  2648.  
  2649.  
  2650. ;/***************************************************************************\
  2651. ;*
  2652. ;* Function:    int gusMalloc(ushort length, ulong *mem)
  2653. ;*
  2654. ;* Description: Allocates GUS memory (with best fit alcorithm)
  2655. ;*
  2656. ;* Input:    ushort length        Length of the block to be allocated (Rounded up to next 32 bytes)
  2657. ;*
  2658. ;* Returns:    MIDAS error code.
  2659. ;*
  2660. ;\***************************************************************************/
  2661. PROC    gusMalloc FAR    length:word, mem:far ptr
  2662. USES    si,di
  2663. LOCAL    bestfitoff:word, bestfitseg:word, leastslack:dword
  2664.  
  2665.     movzx    eax,[length]
  2666.     test    eax,eax
  2667.     jz    @@done
  2668.  
  2669.     mov    ebx,eax             ; Round up to next 64 byte border (possible 32 bytes extra)
  2670.     and    ebx,1fh
  2671.     mov    ecx,64
  2672.     sub    ecx,ebx
  2673.     add    eax,ecx
  2674.  
  2675.     mov    [bestfitseg],0
  2676.     mov    [leastslack],7ffffffh
  2677.  
  2678.     cmp    [memavail],eax            ; Is there that much memory left
  2679.     jl    @@notenoughmem
  2680.  
  2681.     cmp    [largestblock],eax        ; Do we have to defragment?
  2682.     jg    @@noneedtodefragment
  2683.  
  2684.     push    eax
  2685.     call    gusDefragment
  2686.     pop    eax
  2687.  
  2688.     cmp    [largestblock],eax
  2689.     jl    @@notenoughmem
  2690.  
  2691. @@noneedtodefragment:
  2692.     les    si,[gusHeapStart]
  2693.  
  2694. @@findbest:
  2695.     push    eax
  2696.     call    findFreeBlock
  2697.     pop    eax
  2698.     jc    @@notanymore
  2699.  
  2700.     mov    ebx,[es:si+ghb.length]
  2701.     and    ebx, NOT 1fh            ; And flags off
  2702.     sub    ebx,eax
  2703.     js    @@nxt                ; Too small
  2704.  
  2705.     cmp    [leastslack],ebx
  2706.     jl    @@nxt                ; Not the best
  2707.  
  2708.     mov    [leastslack],ebx        ; Set to be the best
  2709.     mov    bx,es
  2710.     mov    [bestfitseg],bx
  2711.     mov    [bestfitoff],si
  2712.  
  2713. @@nxt:
  2714.     mov    ecx,[es:si+ghb.next]        ; Advance to next block
  2715.     test    ecx,ecx
  2716.     jz    @@notanymore
  2717.     mov    si,cx
  2718.     shr    ecx,16
  2719.     mov    es,cx
  2720.     jmp    @@findbest
  2721.  
  2722. @@notanymore:
  2723.     cmp    [bestfitseg],0            ; Was there any free blocks big enough?
  2724.     je    @@notenoughmem
  2725.     cmp    [leastslack],0
  2726.     je    @@justalloc
  2727.  
  2728.     push    eax
  2729.     call    allocBlock LANG, seg temp offset temp ; Allocate new block
  2730.     test    ax,ax
  2731.     jnz    @@memerr
  2732.  
  2733.     pop    eax
  2734.     lgs    di,[temp]
  2735.  
  2736.     mov    si,[bestfitoff]
  2737.     mov    bx,[bestfitseg]
  2738.     mov    es,bx
  2739.  
  2740.     mov    ebx,[es:si+ghb.gusmem]        ; Copy pointer
  2741.     mov    [gs:di+ghb.gusmem],ebx
  2742.     mov    [gs:di+ghb.length],eax        ; Set block length
  2743.     or    [gs:di+ghb.length],1        ; Mark as allocated
  2744.  
  2745.     add    [es:si+ghb.gusmem],eax        ; Move free block "upwards"
  2746.     sub    [es:si+ghb.length],eax        ; Sub free block length
  2747.  
  2748.     mov    bx,es
  2749.     shl    ebx,16
  2750.     mov    bx,si
  2751.  
  2752.     mov    [gs:di+ghb.next],ebx        ; Link blocks
  2753.     cmp    [gusHeapStart],ebx
  2754.     jne    @@notfirst            ; The first block?
  2755.  
  2756.     mov    bx,gs                ; Set this block to HeapStart
  2757.     shl    ebx,16
  2758.     mov    bx,di
  2759.     mov    [gusHeapStart],ebx
  2760.     jmp    @@donee
  2761.  
  2762. @@notfirst:
  2763.     push    eax
  2764.     mov    eax,ebx
  2765.     call    findPrevBlock            ; Find block linked to the free block
  2766.     pop    eax
  2767.     jc    @@heapcorr            ; No such block!
  2768.  
  2769.     mov    bx,gs
  2770.     shl    ebx,16
  2771.     mov    bx,di
  2772.     mov    [es:si+ghb.next],ebx        ; Link to previous block
  2773.  
  2774.  
  2775. @@donee:
  2776.     sub    [memavail],eax
  2777.     push    gs
  2778.     call    checkCoreFree            ; Update biggest block
  2779.     pop    gs
  2780.     test    ax,ax
  2781.     jnz    @@err
  2782.     mov    eax,[gs:di+ghb.gusmem]        ; Return pointer
  2783.     les    bx,[mem]
  2784.     mov    [es:bx],eax
  2785.     xor    ax,ax
  2786.     ret
  2787.  
  2788. @@justalloc:                    ; Realloc?
  2789.     or    [es:si+ghb.length],1
  2790.     sub    [memavail],eax
  2791.     push    es
  2792.     call    checkCoreFree
  2793.     pop    es
  2794.     test    ax,ax
  2795.     jnz    @@err
  2796.     mov    eax,[es:si+ghb.gusmem]
  2797. @@done: les    bx,[mem]
  2798.     mov    [es:bx],eax
  2799.     xor    ax,ax
  2800.     ret
  2801.  
  2802. @@memerr:
  2803.     pop    ebx                ; pop saved pointer
  2804.     jmp    @@err
  2805.  
  2806. @@heapcorr:
  2807.     mov    ax,errCardHeapCorrupted
  2808.     jmp    @@err
  2809.  
  2810. @@notenoughmem:
  2811.     mov    ax,errOutOfCardMemory
  2812. @@err:    ERROR    ID_gusMalloc
  2813.     ret
  2814. ENDP
  2815.  
  2816.  
  2817.  
  2818. ;/***************************************************************************\
  2819. ;*
  2820. ;* Function:    int gusFree(ulong mem)
  2821. ;*
  2822. ;* Description: Deallocates GUS memory
  2823. ;*
  2824. ;* Input:    ulong block        Pointer to allocated GUS mem
  2825. ;*
  2826. ;* Returns:    1 if success, 0 if not
  2827. ;*
  2828. ;* Destroys:    ax, bx, cx, dx
  2829. ;*
  2830. ;\***************************************************************************/
  2831. PROC    gusFree FAR   block:dword
  2832. USES    si,di
  2833. LOCAL    freed:dword
  2834.  
  2835.     mov    eax,[block]
  2836.  
  2837.     lgs    di,[gusHeapStart]
  2838. @@sloop:
  2839.     cmp    [gs:di+ghb.gusmem],eax
  2840.     je    @@found
  2841.  
  2842.     mov    ebx,[gs:di+ghb.next]
  2843.     test    ebx,ebx
  2844.     jz    @@invalid
  2845.     mov    di,bx
  2846.     shr    ebx,16
  2847.     mov    gs,bx
  2848.     jmp    @@sloop
  2849.  
  2850. @@found:
  2851.     test    [gs:di+ghb.length],1
  2852.     jz    @@heapcorr            ; Not even allocated
  2853.  
  2854.     and    [gs:di+ghb.length],NOT 1    ; Free this block
  2855.  
  2856.     mov    ebx,[gs:di+ghb.length]
  2857.     mov    [freed],ebx
  2858.  
  2859.     mov    ebx,[gs:di+ghb.next]
  2860.     test    ebx,ebx
  2861.     jz    @@nonextblock            ; Last block
  2862.  
  2863.     mov    si,bx
  2864.     shr    ebx,16
  2865.     mov    es,bx
  2866.  
  2867.     test    [es:si+ghb.length],1
  2868.     jnz    @@nonextblock            ; Next allocated -> Can't merge blocks
  2869.  
  2870.     mov    edx,[es:si+ghb.next]
  2871.     mov    [gs:di+ghb.next],edx
  2872.     mov    edx,[es:si+ghb.length]        ; Merge blocks
  2873.     add    [gs:di+ghb.length],edx
  2874.  
  2875.     push    gs
  2876.     call    freeBlock LANG, es si        ; Free block
  2877.     pop    gs
  2878.     test    ax,ax
  2879.     jnz    @@err
  2880.  
  2881. @@nonextblock:
  2882.     mov    bx,gs
  2883.     shl    ebx,16
  2884.     mov    bx,di
  2885.     cmp    [gusHeapStart],ebx
  2886.     je    @@firstblock            ; First block
  2887.  
  2888.     mov    eax,ebx
  2889.     call    findPrevBlock
  2890.     jc    @@heapcorr            ; No such block! (Heap corrupt?)
  2891.  
  2892.     test    [es:si+ghb.length],1
  2893.     jnz    @@firstblock            ; previous allocated -> can't merge blocks
  2894.  
  2895.     mov    edx,[gs:di+ghb.next]
  2896.     mov    [es:si+ghb.next],edx
  2897.     mov    edx,[gs:di+ghb.length]        ; Merge blocks
  2898.     add    [es:si+ghb.length],edx
  2899.  
  2900.     call    freeBlock LANG, gs di        ; Free block
  2901.     test    ax,ax
  2902.     jnz    @@err
  2903.  
  2904. @@firstblock:
  2905.     mov    eax,[freed]
  2906.     add    [memavail],eax
  2907.     call    checkCoreFree
  2908.     test    ax,ax
  2909.     jnz    @@err
  2910.     xor    ax,ax
  2911.     ret
  2912.  
  2913. @@heapcorr:
  2914.     mov    ax,errCardHeapCorrupted
  2915.     jmp    @@err
  2916.  
  2917. @@invalid:
  2918.     mov    ax,errInvalidBlock
  2919. @@err:    ERROR    ID_gusFree
  2920.     ret
  2921. ENDP
  2922.  
  2923.  
  2924. PROC    allocBlock NEAR block:far ptr
  2925.     les    bx,[gusHeapStart]
  2926.     mov    cx,MAXINSTS
  2927.     cmp    [surround],0
  2928.     je    @@findloop
  2929.     add    cx,cx                ; Include surround blocks
  2930. @@findloop:
  2931.     cmp    [es:bx+ghb.length],0
  2932.     je    @@found
  2933.     add    bx,size ghb
  2934.     loop    @@findloop
  2935.     jmp    @@err
  2936. @@found:
  2937.     mov    ax,es
  2938.     shl    eax,16
  2939.     mov    ax,bx
  2940.     les    bx,[block]
  2941.     mov    [es:bx],eax
  2942.     xor    ax,ax
  2943.     ret
  2944.  
  2945. @@err:    mov    ax,errInvalidBlock
  2946.     ERROR    ID_gusAllocBlock
  2947.     ret
  2948. ENDP
  2949.  
  2950. PROC    freeBlock NEAR block:far ptr
  2951.     les    bx,[block]
  2952.     mov    [es:bx+ghb.next],0
  2953.     mov    [es:bx+ghb.gusmem],0
  2954.     mov    [es:bx+ghb.length],0
  2955.     xor    ax,ax
  2956.     ret
  2957. ENDP
  2958.  
  2959. ; es:si = far ptr to current block
  2960. ; Returns: es:si = next free block
  2961. ; Carry set if not found
  2962.  
  2963. PROC    findFreeBlock NEAR
  2964.  
  2965. @@sloop:
  2966.     test    [es:si+ghb.length],1
  2967.     jz    @@found
  2968.  
  2969.     mov    eax,[es:si+ghb.next]   ; Advance to next block
  2970.     test    eax,eax
  2971.     jz    @@nofree
  2972.     mov    si,ax
  2973.     shr    eax,16
  2974.     mov    es,ax
  2975.     jmp    @@sloop
  2976.  
  2977. @@found:
  2978.     clc
  2979.     ret
  2980. @@nofree:
  2981.     stc
  2982.     ret
  2983. ENDP
  2984.  
  2985.  
  2986.  
  2987. ; eax = far ptr to current block
  2988. ; Returns: es:si = prev block
  2989. ; Carry set if not found
  2990.  
  2991. PROC    findPrevBlock NEAR
  2992.  
  2993.     les    si,[gusHeapStart]
  2994. @@sloop:
  2995.     cmp    [es:si+ghb.next],eax
  2996.     je    @@found
  2997.  
  2998.     mov    ebx,[es:si+ghb.next]
  2999.     test    ebx,ebx
  3000.     jz    @@done
  3001.     mov    si,bx
  3002.     shr    ebx,16
  3003.     mov    es,bx
  3004.     jmp    @@sloop
  3005.  
  3006. @@found:
  3007.     clc
  3008.     ret
  3009. @@done:
  3010.     stc
  3011.     ret
  3012. ENDP
  3013.  
  3014.  
  3015.  
  3016. ; No parameters, also checks heap integrity
  3017. ; Returns MIDAS error code
  3018.  
  3019. PROC    checkCoreFree    NEAR
  3020. USES    si
  3021.  
  3022.     les    si,[gusHeapStart]
  3023.     xor    edx,edx             ; Start from size 0
  3024.     xor    ecx,ecx             ; Total mem size
  3025. @@findloop:
  3026.     mov    eax,[es:si+ghb.length]
  3027.     mov    ebx,eax
  3028.     and    ebx,NOT 31            ; ebx = size
  3029.     add    ecx,ebx             ; Add to total
  3030.     test    eax,1                ; Allocated flag
  3031.     jnz    @@findnext            ; Allocated
  3032.     cmp    ebx,edx             ; Largest?
  3033.     jle    @@findnext
  3034.     mov    edx,ebx
  3035. @@findnext:
  3036.     mov    eax,[es:si+ghb.next]   ; Advance to next block
  3037.     test    eax,eax
  3038.     jz    @@done
  3039.     mov    si,ax
  3040.     shr    eax,16
  3041.     mov    es,ax
  3042.     jmp    @@findloop
  3043.  
  3044. @@done:
  3045.     mov    [largestblock],edx
  3046.     cmp    [memamount],ecx         ; All memory in heap?
  3047.     jne    @@heapcorr            ; heap corrupt!
  3048.     xor    ax,ax
  3049.     ret
  3050.  
  3051. @@heapcorr:
  3052.     mov    ax,errCardHeapCorrupted
  3053.     ERROR    ID_gusCoreFree
  3054.     ret
  3055. ENDP
  3056.  
  3057. ;/***************************************************************************\
  3058. ;*
  3059. ;* Function:    gusDefragment
  3060. ;*
  3061. ;* Description: Defragments the GUS memory
  3062. ;*
  3063. ;* Destroys:    ax, bx, cx, dx
  3064. ;*
  3065. ;\***************************************************************************/
  3066. PROC    gusDefragment FAR   length:word
  3067.     ret
  3068. ENDP
  3069.  
  3070. END
  3071.  
  3072.