home *** CD-ROM | disk | FTP | other *** search
/ Collection of Hack-Phreak Scene Programs / cleanhpvac.zip / cleanhpvac / ASMCODE.ZIP / GUSUTIL.ASM < prev    next >
Assembly Source File  |  1994-11-02  |  87KB  |  3,565 lines

  1. ;══════════════════════════════════════════════════════════════════════
  2. ;
  3. ; Gravis Utilities for Borland\Turbo Pascal.
  4. ;
  5. ; Copyright (c) 1994 by Jonathan E. Wright and AmoebaSoft.
  6. ;
  7. ;══════════════════════════════════════════════════════════════════════
  8. ;
  9. ; NOTES:
  10. ;
  11. ;══════════════════════════════════════════════════════════════════════
  12. ;
  13. ; If the IRQ handler is enabled, you must be sure to set the voice's
  14. ; Start, End and Current Locations before setting the IRQAtEnd bit with
  15. ; a call to VoiceMode or GUS_VoiceMode.  If you set the IRQ bit while
  16. ; the Current voice location is pointing to the end location, i.e. the
  17. ; voice has been played once, the voice can be turned off immediately by
  18. ; the IRQ handler and never get a chance to be heard.
  19. ;
  20. ; The IRQ handler doesn't appear to be necessary for normal sample
  21. ; playback, especially if the samples are high quality and have been
  22. ; modified to have ramps at the beginning and end to stop clicking (i.e.
  23. ; the sample fades in from 0 very quickly at the beginning and fades out
  24. ; to zero very quickly at the end).
  25. ;
  26. ; A voice with Looping set and IRQ's enabled will be cut off be the IRQ
  27. ; handler when the end of the sample is reached and will not loop.  To
  28. ; loop a voice, start it without the IRQAtEnd bit set.
  29. ;
  30. ; This file contains 80386 specific instructions and won't work on lamer
  31. ; processors.
  32. ;
  33. ; The MOD player interprets Set Volume (0Fh) commands with a value > 64
  34. ; as Set Flag commands.  If a Set Volume command with an argument of 65
  35. ; is given, then the variable MODFlag will be set to 65 - 65 = 0.  If a
  36. ; Set Volume command with an argument of 66 is given, the flag will be
  37. ; set to 66 - 65 = 1.  This allows a program to synchronize itself with
  38. ; events in the music, based on the value of MODFlag.
  39. ;
  40. ;══════════════════════════════════════════════════════════════════════
  41.  
  42. ;follwing registers are GUS_Base + value
  43. ;
  44. ;GUS_Status      EQU     06h
  45. ;GUS_TimerCon    EQU     08h
  46. ;GUS_TimerData   EQU     09h
  47. ;GUS_IRQDMACon   EQU     0Bh
  48. ;GUS_MidiCon     EQU     100h
  49. ;GUS_MidiData    EQU     101h
  50. ;GUS_Voice       EQU     102h
  51. ;GUS_Command     EQU     103h
  52. ;GUS_DataLo      EQU     104h
  53. ;GUS_DataHi      EQU     105h
  54. ;GUS_DRAMIO      EQU     107h
  55.  
  56. GUS_SetVoiceMode EQU     00h
  57. GUS_SetVoiceFreq EQU     01h
  58. GUS_RampVolIncr  EQU     06h
  59. GUS_RampVolStart EQU     07h
  60. GUS_RampVolEnd   EQU     08h
  61. GUS_CurVolume    EQU     09h
  62. GUS_VolControl   EQU     0Dh
  63.  
  64. GUS_Stop         EQU 3
  65. GUS_Bit16        EQU 4
  66. GUS_Loop         EQU 8
  67. GUS_Bidirec      EQU 16
  68. GUS_IRQAtEnd     EQU 32
  69. GUS_Backward     EQU 64
  70.  
  71. GUS_Scale0       EQU 0
  72. GUS_Scale8       EQU 1
  73. GUS_Scale64      EQU 2
  74. GUS_Scale512     EQU 3
  75.  
  76. GUS_RampStop     EQU 3
  77. GUS_RampRoll     EQU 4
  78. GUS_RampLoop     EQU 8
  79. GUS_RampBidir    EQU 16
  80. GUS_RampIRQ      EQU 32
  81. GUS_RampDec      EQU 64
  82.  
  83. NoteSize         EQU     6
  84. PatLineSize      EQU     8 * NoteSize   ; maxtracks * notetype size
  85. InstrTypeSize    EQU     44
  86. ChannelInfoSize  EQU     83
  87.  
  88. PatternOfs       EQU     1364
  89. ScriptOfs        EQU     1876
  90. NumPatsOfs       EQU     ScriptOfs + 128
  91. EndJumpOfs       EQU     NumPatsOfs + 1
  92.  
  93.         .386
  94.  
  95. DATA    SEGMENT WORD    PUBLIC   USE16
  96.  
  97.         EXTRN   GUS_Base      : WORD
  98.         EXTRN   GUS_IRQ       : WORD
  99.  
  100.         EXTRN   GUS_Status    : WORD
  101.         EXTRN   GUS_TimerCon  : WORD
  102.         EXTRN   GUS_TimerData : WORD
  103.         EXTRN   GUS_IRQDMACon : WORD
  104.         EXTRN   GUS_MidiCon   : WORD
  105.         EXTRN   GUS_MidiData  : WORD
  106.         EXTRN   GUS_Voice     : WORD
  107.         EXTRN   GUS_Command   : WORD
  108.         EXTRN   GUS_DataLo    : WORD
  109.         EXTRN   GUS_DataHi    : WORD
  110.         EXTRN   GUS_DRAMIO    : WORD
  111.  
  112.         EXTRN   GUS_Mixer     : BYTE
  113.  
  114.         EXTRN   ActiveVoices  : BYTE
  115.         EXTRN   CurVoice      : BYTE
  116.         EXTRN   OrigRate      : WORD
  117.         EXTRN   MODSpeed      : WORD
  118.         EXTRN   CurLine       : WORD
  119.         EXTRN   CurPattern    : WORD
  120.         EXTRN   ScriptPos     : WORD
  121.         EXTRN   MODPlaying    : BYTE
  122.         EXTRN   PreMODInt8    : DWORD
  123.         EXTRN   MODData       : DWORD
  124.         EXTRN   Channels      : BYTE
  125.         EXTRN   ChannelInfo   : BYTE
  126.         EXTRN   MODFlag       : BYTE
  127.         EXTRN   MODVolume     : WORD
  128.  
  129.         EXTRN   UpdateChannelWaves : BYTE
  130.         EXTRN   UpdateChannelRecs  : BYTE
  131.  
  132.         EXTRN   VoiceModes    : BYTE
  133.  
  134. DATA    ENDS
  135.  
  136. CODE    SEGMENT WORD    PUBLIC    USE16
  137.         ASSUME  CS:CODE,DS:DATA
  138.  
  139.         PUBLIC  GUS_TestBaseAddress
  140.         PUBLIC  GUS_ReadVoicePos
  141.         PUBLIC  GUS_Peek, GUS_Poke
  142.         PUBLIC  GUS_Mem
  143.         PUBLIC  GUS_SetActiveVoices
  144.         PUBLIC  GUS_VoiceFreq
  145.         PUBLIC  GUS_VoiceAddr
  146.         PUBLIC  GUS_VoiceVolume
  147.         PUBLIC  GUS_VoiceMode
  148.         PUBLIC  GUS_ReadVoiceMode
  149.         PUBLIC  GUS_StartVoice
  150.         PUBLIC  GUS_StopVoice
  151.         PUBLIC  GUS_SpeakerOn
  152.         PUBLIC  GUS_SpeakerOff
  153.         PUBLIC  GUS_Reset
  154.         PUBLIC  GUS_VoiceBalance
  155.         PUBLIC  GUS_RampRate
  156.         PUBLIC  GUS_RampVolume
  157.         PUBLIC  GUS_VolumeControl
  158.         PUBLIC  GUS_MoveSample
  159.         PUBLIC  GUS_SetClockRate
  160.         PUBLIC  GUS_SetTimer
  161.         PUBLIC  GUS_ResetTimer
  162.         PUBLIC  GUS_SetIRQ
  163.         PUBLIC  GUS_RestoreIRQ
  164.         PUBLIC  MODInt8
  165.         PUBLIC  GUS_StartMOD
  166.         PUBLIC  GUS_ContinueMOD
  167.         PUBLIC  GUS_StopMOD
  168.  
  169.         PUBLIC  FreqTable
  170.         PUBLIC  FreqDivisors
  171.  
  172. SelectVoice     MACRO
  173.         cli
  174.  
  175.         mov     dx,GUS_Voice
  176.         out     dx,al
  177.         mov     CurVoice,al
  178.  
  179.         sti
  180.  
  181.         ENDM
  182.  
  183. ;══════════════════════════════════════════════════════════════════════
  184. ; Code segment variables local to the assembly unit
  185.  
  186.  
  187.         OldInt08     DD    ?
  188.         OldIRQInt    DD    ?
  189.  
  190.         OldIntFlag   DW    ?
  191.         OldIntCount  DW    ?
  192.  
  193. ;══════════════════════════════════════════════════════════════════════
  194. ; Code segment tables local to the assembly unit
  195.  
  196. NoteTable  DW 856,808,762,720,678,640,604,570,538,508,480,453 ; C-1 to B-1
  197.            DW 428,404,381,360,339,320,302,285,269,254,240,226 ; C-2 to B-2
  198.            DW 214,202,190,180,170,160,151,143,135,127,120,113 ; C-3 to B-3
  199.  
  200.            DW 850,802,757,715,674,637,601,567,535,505,477,450 ; Finetune +1.
  201.            DW 425,401,379,357,337,318,300,284,268,253,239,225 ;
  202.            DW 213,201,189,179,169,159,150,142,134,126,119,113 ;
  203.  
  204.            DW 844,796,752,709,670,632,597,563,532,502,474,447 ; Finetune +2.
  205.            DW 422,398,376,355,335,316,298,282,266,251,237,224 ;
  206.            DW 211,199,188,177,167,158,149,141,133,125,118,112 ;
  207.  
  208.            DW 838,791,746,704,665,628,592,559,528,498,470,444 ; Finetune +3.
  209.            DW 419,395,373,352,332,314,296,280,264,249,235,222 ;
  210.            DW 209,198,187,176,166,157,148,140,132,125,118,111 ;
  211.  
  212.            DW 832,785,741,699,660,623,588,555,524,495,467,441 ; Finetune +4.
  213.            DW 416,392,370,350,330,312,294,278,262,247,233,220 ;
  214.            DW 208,196,185,175,165,156,147,139,131,124,117,110 ;
  215.  
  216.            DW 826,779,736,694,655,619,584,551,520,491,463,437 ; Finetune +5.
  217.            DW 413,390,368,347,328,309,292,276,260,245,232,219 ;
  218.            DW 206,195,184,174,164,155,146,138,130,123,116,109 ;
  219.  
  220.            DW 820,774,730,689,651,614,580,547,516,487,460,434 ; Finetune +6.
  221.            DW 410,387,365,345,325,307,290,274,258,244,230,217 ;
  222.            DW 205,193,183,172,163,154,145,137,129,122,115,109 ;
  223.  
  224.            DW 814,768,725,684,646,610,575,543,513,484,457,431 ; Finetune +7.
  225.            DW 407,384,363,342,323,305,288,272,256,242,228,216 ;
  226.            DW 204,192,181,171,161,152,144,136,128,121,114,108 ;
  227.  
  228.            DW 907,856,808,762,720,678,640,604,570,538,504,480 ; Finetune -8.
  229.            DW 453,428,404,381,360,339,320,302,285,269,254,240 ;
  230.            DW 226,214,202,190,180,170,160,151,143,135,127,120 ;
  231.  
  232.            DW 900,850,802,757,715,675,636,601,567,535,505,477 ; Finetune -7.
  233.            DW 450,425,401,379,357,337,318,300,284,268,253,238 ;
  234.            DW 225,212,200,189,179,169,159,150,142,134,126,119 ;
  235.  
  236.            DW 894,844,796,752,709,670,632,597,563,532,502,474 ; Finetune -6.
  237.            DW 447,422,398,376,355,335,316,298,282,266,251,237 ;
  238.            DW 223,211,199,188,177,167,158,149,141,133,125,118 ;
  239.  
  240.            DW 887,838,791,746,704,665,628,592,559,528,498,470 ; Finetune -5.
  241.            DW 444,419,395,373,352,332,314,296,280,264,249,235 ;
  242.            DW 222,209,198,187,176,166,157,148,140,132,125,118 ;
  243.  
  244.            DW 881,832,785,741,699,660,623,588,555,524,494,467 ; Finetune -4.
  245.            DW 441,416,392,370,350,330,312,294,278,262,247,233 ;
  246.            DW 220,208,196,185,175,165,156,147,139,131,123,117 ;
  247.  
  248.            DW 875,826,779,736,694,655,619,584,551,520,491,463 ; Finetune -3.
  249.            DW 437,413,390,368,347,338,309,292,276,260,245,232 ;
  250.            DW 219,206,195,184,174,164,155,146,138,130,123,116 ;
  251.  
  252.            DW 868,820,774,730,689,651,614,580,547,516,487,460 ; Finetune -2.
  253.            DW 434,410,387,365,345,325,307,290,274,258,244,230 ;
  254.            DW 217,205,193,183,172,163,154,145,137,129,122,115 ;
  255.  
  256.            DW 862,814,768,725,684,646,610,575,543,513,484,457 ; Finetune -1.
  257.            DW 431,407,384,363,342,323,305,288,272,256,242,228 ;
  258.            DW 216,203,192,181,171,161,152,144,136,128,121,114 ;
  259.  
  260. VolTable   DW 00000h, 0B000h, 0B800h, 0BC00h, 0BE00h, 0C000h, 0C400h
  261.            DW 0C800h, 0CC00h, 0D000h, 0D200h, 0D400h, 0D600h, 0D800h
  262.            DW 0DA00h, 0DC00h, 0DE00h, 0E000h, 0E100h, 0E200h, 0E300h
  263.            DW 0E400h, 0E500h, 0E600h, 0E700h, 0E800h, 0E900h, 0EA00h
  264.            DW 0EB00h, 0EC00h, 0ED00h, 0EE00h, 0EF00h, 0F080h, 0F100h
  265.            DW 0F180h, 0F200h, 0F280h, 0F300h, 0F380h, 0F400h, 0F480h
  266.            DW 0F500h, 0F580h, 0F600h, 0F680h, 0F700h, 0F780h, 0F800h
  267.            DW 0F880h, 0F900h, 0F980h, 0FA00h, 0FA80h, 0FB00h, 0FB80h
  268.            DW 0FC00h, 0FC80h, 0FD00h, 0FD80h, 0FE00h, 0FE80h, 0FF00h
  269.            DW 0FF80h, 0FFF0h
  270.  
  271. ; frequency divisors are used in building the frequency table and are
  272. ; for MaxVoices = 14 to MaxVoices = 32
  273.  
  274. VoiceVolumes DB 32 DUP (0)
  275.  
  276. ;VoiceModes   DB 32 DUP (0)
  277.  
  278. FreqDivisors DB 43, 40, 37, 35, 33, 31, 30, 28, 27, 26, 25, 24
  279.              DB 23, 22, 21, 20, 20, 19, 18
  280.  
  281. FreqTable    DW 1713 DUP (0)
  282.  
  283. EffectJumps  DW OFFSET DoAppregio
  284.              DW OFFSET DoSlideUp
  285.              DW OFFSET DoSlideDown
  286.              DW OFFSET DoTonePortamento
  287.              DW OFFSET DoVibrato
  288.              DW OFFSET DoToneVolSlide
  289.              DW OFFSET DoVibVolSlide
  290.              DW OFFSET DoTremolo
  291.              DW OFFSET DoNotUsed
  292.              DW OFFSET DoSetSampleOffs
  293.              DW OFFSET DoVolumeSlide
  294.              DW OFFSET DoPositionJump
  295.              DW OFFSET DoSetVolume
  296.              DW OFFSET DoPatternBreak
  297.              DW OFFSET DoExtended
  298.              DW OFFSET DoSetSpeed
  299.  
  300.  
  301. ; this table is set and reset during a GF1 IRQ to tell us if we've already
  302. ; serviced a voice for either a Wave Table IRQ or a Ramp IRQ
  303.  
  304. EndIRQ     DB 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
  305.            DB 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
  306. RampIRQ    DB 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
  307.            DB 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
  308.  
  309. ;══════════════════════════════════════════════════════════════════════
  310. GUS_Delay       PROC
  311.  
  312.         push    ax
  313.         push    dx
  314.  
  315.         mov     dx,300h
  316.  
  317.         in      al,dx
  318.         in      al,dx
  319.         in      al,dx
  320.         in      al,dx
  321.         in      al,dx
  322.         in      al,dx
  323.         in      al,dx
  324.  
  325.         pop     dx
  326.         pop     ax
  327.  
  328.         ret
  329.  
  330. GUS_Delay       ENDP
  331.  
  332. ;══════════════════════════════════════════════════════════════════════
  333. ; bx = rate
  334.  
  335. ClockRate       PROC
  336.  
  337.         push    ax
  338.         push    dx
  339.  
  340.     cmp    bx,0
  341.     jg    DoDivide
  342.  
  343.         xor     ax,ax
  344.         jmp     SetRate
  345.  
  346. DoDivide:
  347.     mov     ax,65535
  348.     xor     dx,dx
  349.     div     bx
  350.  
  351. SetRate:
  352.         push    ax
  353.  
  354.     mov     al,36h
  355.     out    43h,al
  356.  
  357.         pop     ax
  358.  
  359.     out    40h,al
  360.     xchg    ah,al
  361.     out    40h,al
  362.  
  363.         mov     cs:OldIntFlag,bx          ; when this is 0, the old int is called
  364.         mov     cs:OldIntCount,bx         ; set oldintflag to this when reset
  365.  
  366.         pop     dx
  367.         pop     ax
  368.  
  369.         ret
  370.  
  371. ClockRate       ENDP
  372.  
  373. ;══════════════════════════════════════════════════════════════════════
  374. ;AX = interrupt number
  375. ;BX = offset of new interrupt handler
  376.  
  377. SetIRQInt       PROC
  378.  
  379.         push    cx
  380.         push    bx
  381.         push    es
  382.         push    di
  383.  
  384.         cli
  385.  
  386.         xor     ah,ah
  387.         mov     cl,al           ; preserve interrupt number for use
  388.         cmp     al,7
  389.         jg      HighIRQ
  390.  
  391.         mov     di,ax           ; calculate IRQ interrupt vector addx
  392.         add     di,8            ; irq 0-7 = ints 8 - 0Fh
  393.         shl     di,2
  394.         jmp     SetIRQ
  395.  
  396. HighIRQ:
  397.         mov     di,ax           ; irq 8-15 = ints 70h - 77h
  398.         add     di,68h          ; calculate high IRQ addx - IRQ 10 = int 72h
  399.         shl     di,2            ; * 4 = offset in vector table
  400.  
  401. SetIRQ:
  402.         xor     ax,ax
  403.         mov     es,ax
  404.         mov     ax,es:[di]      ; save offset of old irq handler
  405.         mov     word ptr OldIRQInt,ax
  406.         mov     es:[di],bx      ; store offset of new irq handler
  407.  
  408.         mov     ax,es:[di+2]    ; save segment of old irq handler
  409.         mov     word ptr OldIRQInt[2],ax
  410.         mov     es:[di+2],cs    ; store segment of new irq handler
  411.  
  412.         cmp     cl,7
  413.         jle     LowIRQ
  414.  
  415.         sub     cl,8            ; subtract 8 for the bit shift
  416.         mov     dx,0A1h
  417.         jmp     Enable
  418.  
  419. LowIRQ:
  420.         mov     dx,21h
  421.  
  422. Enable:
  423.         mov     ah,1            ; enable interrupt control mask-bit
  424.         shl     ah,cl
  425.         not     ah              ; make the mask
  426.  
  427.         in      al,dx           ; enable the IRQ
  428.         and     al,ah
  429.         out     dx,al
  430.  
  431.         sti
  432.  
  433.         pop     di
  434.         pop     es
  435.         pop     bx
  436.         pop     cx
  437.  
  438.         ret
  439.  
  440. SetIRQInt       ENDP
  441.  
  442. ;════════════════════════════════════════════════════════
  443. ;al = interrupt number
  444.  
  445. RestoreIRQInt   PROC
  446.  
  447.         push    cx
  448.         cli
  449.  
  450.         mov     cl,al
  451.  
  452.         add     al,8                   ; calculate interrupt vector addx
  453.         cbw
  454.         shl     al,1
  455.         shl     al,1
  456.         mov     di,ax
  457.  
  458.         push    es                     ; restore interrupt vector
  459.         xor     ax,ax
  460.         mov     es,ax
  461.         mov     ax,word ptr OldIRQInt
  462.         mov     es:[di],ax
  463.  
  464.         mov     ax,word ptr OldIRQInt[2]
  465.         mov     es:[di+2],ax
  466.  
  467.         pop     es
  468.  
  469.         mov     ah,1
  470.         shl     ah,cl
  471.  
  472.         in      al,21h
  473.         or      al,ah
  474.         out     21h,al
  475.  
  476.         sti
  477.         pop     cx
  478.  
  479.         ret
  480.  
  481. RestoreIRQInt   ENDP
  482.  
  483. ;══════════════════════════════════════════════════════════════════════
  484.  
  485. SetTimer        PROC
  486.  
  487.         push    ax
  488.         push    es
  489.  
  490.         xor     ax,ax
  491.         mov     es,ax
  492.  
  493.         cli
  494.  
  495.         ; save the old interrupt
  496.  
  497.         mov     ax,es:[0020h]
  498.         mov     word ptr cs:OldInt08 [0],ax
  499.         mov     ax,es:[0022h]
  500.         mov     word ptr cs:OldInt08 [2],ax
  501.  
  502.         ; set the new interrupt
  503.  
  504.         mov     ax,OFFSET NewInt08
  505.         mov     es:[0020h],ax
  506.         mov     ax,cs
  507.         mov     es:[0022h],ax
  508.  
  509.         sti
  510.  
  511.         pop     es
  512.         pop     ax
  513.  
  514.         ret
  515.  
  516. SetTimer        ENDP
  517.  
  518. ;══════════════════════════════════════════════════════════════════════
  519.  
  520. ResetTimer      PROC
  521.  
  522.         push    ax
  523.         push    es
  524.  
  525.         xor     ax,ax
  526.         mov     es,ax
  527.  
  528.         cli
  529.  
  530.         ; restore the old interrupt
  531.  
  532.         mov     ax,word ptr cs:OldInt08 [0]
  533.         mov     es:[0020h],ax
  534.         mov     ax,word ptr cs:OldInt08 [2]
  535.         mov     es:[0022h],ax
  536.  
  537.         sti
  538.  
  539.         pop     es
  540.         pop     ax
  541.  
  542.         ret
  543.  
  544. ResetTimer      ENDP
  545.  
  546. ;══════════════════════════════════════════════════════════════════════
  547. ; BX - high byte of address, CX - low word of address
  548. ; AL - byte returned
  549.  
  550. Peek    PROC
  551.  
  552.         push    dx
  553.  
  554.         mov     dx,GUS_Command
  555.         mov     al,43h
  556.         out     dx,al
  557.  
  558.         mov     dx,GUS_DataLo
  559.         mov     ax,cx
  560.         out     dx,ax
  561.  
  562.         mov     dx,GUS_Command
  563.         mov     al,44h
  564.         out     dx,al
  565.  
  566.         mov     dx,GUS_DataHi
  567.         mov     al,bl
  568.         out     dx,al
  569.  
  570.         mov     dx,GUS_DRAMIO
  571.         in      al,dx
  572.  
  573.         pop     dx
  574.  
  575.         ret
  576.  
  577. Peek    ENDP
  578.  
  579. ;══════════════════════════════════════════════════════════════════════
  580. ; BX - high byte of address, CX - low word of address
  581. ; AX - byte to poke
  582.  
  583. Poke    PROC
  584.  
  585.         push    dx
  586.         push    ax
  587.  
  588.         mov     dx,GUS_Command
  589.         mov     al,43h
  590.         out     dx,al
  591.  
  592.         mov     dx,GUS_DataLo
  593.         mov     ax,cx
  594.         out     dx,ax
  595.  
  596.         mov     dx,GUS_Command
  597.         mov     al,44h
  598.         out     dx,al
  599.  
  600.         mov     dx,GUS_DataHi
  601.         mov     al,bl
  602.         out     dx,al
  603.  
  604.         mov     dx,GUS_DRAMIO
  605.         pop     ax
  606.         out     dx,al
  607.  
  608.         pop     dx
  609.  
  610.         ret
  611.  
  612. Poke    ENDP
  613.  
  614. ;══════════════════════════════════════════════════════════════════════
  615. ; al = number voices Ultrasound will mix (this effects playback rate)
  616.  
  617. SetActive       PROC
  618.  
  619.         push    dx
  620.  
  621.         cmp     al,0Dh
  622.         jge     EnoughVoices
  623.  
  624.         mov     al,0Dh                 ; minimum of 14 voices, (14 - 1)!
  625.  
  626. EnoughVoices:
  627.         cmp     al,31
  628.         jle     NotTooMany
  629.  
  630.         mov     al,31
  631.  
  632. NotTooMany:
  633.         mov     ActiveVoices,al        ; ActiveVoices = number active - 1
  634.         or      al,0C0h                ; must be OR'ed with C0h
  635.  
  636.         push    ax                     ; save the number of voices
  637.         mov     dx,GUS_Command
  638.         mov     al,0Eh
  639.         out     dx,al                  ; select highest active voice function
  640.         pop     ax                     ; pop the number of voices wanted
  641.  
  642.         mov     dx,GUS_DataHi
  643.         out     dx,al                  ; now send the number of voices
  644.  
  645.         pop     dx
  646.  
  647.         ret
  648.  
  649. SetActive       ENDP
  650.  
  651. ;══════════════════════════════════════════════════════════════════════
  652. ; bx = Frequency - sets for current voice (i.e. last voice selected)
  653.  
  654. VoiceFreq       PROC
  655.  
  656.         push    ax
  657.         push    bx
  658.         push    cx
  659.         push    dx
  660.  
  661.         mov     ax,bx                  ; put frequency in ax
  662.  
  663.         movzx   bx,ActiveVoices        ; get frequency divisor according
  664.         sub     bx,13                  ; to number of voices
  665.         xor     dx,dx
  666.         movzx   cx,byte ptr cs:[bx + OFFSET FreqDivisors]
  667.  
  668.         div     cx                     ; divide freq in dx:ax by cx
  669.  
  670.         mov     bx,ax
  671.  
  672.         mov     dx,GUS_Command
  673.         mov     al,1
  674.         out     dx,al
  675.  
  676.         mov     dx,GUS_DataLo
  677.         mov     ax,bx
  678.         out     dx,ax                  ; send the freq number to Ultrasound
  679.  
  680.         call    GUS_Delay
  681.         call    GUS_Delay
  682.  
  683.         mov     dx,GUS_Command
  684.         mov     al,1
  685.         out     dx,al
  686.  
  687.         mov     dx,GUS_DataLo
  688.         mov     ax,bx
  689.         out     dx,ax                  ; send the freq number to Ultrasound
  690.  
  691.         pop     dx
  692.         pop     cx
  693.         pop     bx
  694.         pop     ax
  695.  
  696.         ret
  697.  
  698. VoiceFreq       ENDP
  699.  
  700. ;══════════════════════════════════════════════════════════════════════
  701. ; bx = Frequency - sets for current voice (i.e. last voice selected)
  702.  
  703. NoteFreq        PROC
  704.  
  705.         push    ax
  706.         push    bx
  707.         push    dx
  708.  
  709.         mov     dx,GUS_Command
  710.         mov     al,1
  711.         out     dx,al
  712.  
  713.         inc     dx
  714.         mov     ax,bx
  715.         out     dx,ax                  ; send the freq number to Ultrasound
  716.  
  717.         pop     dx
  718.         pop     bx
  719.         pop     ax
  720.  
  721.         ret
  722.  
  723. NoteFreq        ENDP
  724.  
  725.  
  726. ;══════════════════════════════════════════════════════════════════════
  727. ; bx:cx = start location - sets for current voice (i.e. last voice selected)
  728.  
  729. LoopStartAddr   PROC
  730.  
  731.         push    ax
  732.         push    bx
  733.         push    cx
  734.         push    dx
  735.  
  736.         mov     dx,GUS_Command
  737.         mov     al,02                  ; select low address of start location
  738.         out     dx,al
  739.  
  740.         mov     ax,cx
  741.         mov     dx,bx
  742.         shrd    ax,dx,7
  743.         shr     dx,7
  744.  
  745.         mov     dx,GUS_DataLo
  746.         out     dx,ax
  747.  
  748.         mov     dx,GUS_Command
  749.         mov     al,03                  ; select hi address of start location
  750.         out     dx,al
  751.  
  752.         mov     ax,cx
  753.         mov     dx,bx
  754.         shld    dx,ax,9
  755.         shl     ax,9
  756.  
  757.         mov     dx,GUS_DataLo
  758.         out     dx,ax
  759.  
  760.         pop     dx
  761.         pop     cx
  762.         pop     bx
  763.         pop     ax
  764.  
  765.         ret
  766.  
  767. LoopStartAddr   ENDP
  768.  
  769. ;══════════════════════════════════════════════════════════════════════
  770. ; bx:cx = end location - sets for current voice (i.e. last voice selected)
  771.  
  772. LoopEndAddr     PROC
  773.  
  774.         push    ax
  775.         push    bx
  776.         push    cx
  777.         push    dx
  778.  
  779.         mov     dx,GUS_Command
  780.         mov     al,04                  ; select low address of end location
  781.         out     dx,al
  782.  
  783.         mov     ax,cx
  784.         mov     dx,bx
  785.         shrd    ax,dx,7
  786.         shr     dx,7
  787.  
  788.         mov     dx,GUS_DataLo
  789.         out     dx,ax
  790.  
  791.         mov     dx,GUS_Command
  792.         mov     al,05                  ; select hi address of start location
  793.         out     dx,al
  794.  
  795.         mov     ax,cx
  796.         mov     dx,bx
  797.         shld    dx,ax,9
  798.         shl     ax,9
  799.  
  800.         mov     dx,GUS_DataLo
  801.         out     dx,ax
  802.  
  803.         pop     dx
  804.         pop     cx
  805.         pop     bx
  806.         pop     ax
  807.  
  808.         ret
  809.  
  810. LoopEndAddr     ENDP
  811.  
  812. ;══════════════════════════════════════════════════════════════════════
  813. ; bx:cx = current location in sample - sets for current voice (i.e. last voice selected)
  814.  
  815. VoiceStartAddr  PROC
  816.  
  817.         push    ax
  818.         push    bx
  819.         push    cx
  820.         push    dx
  821.  
  822.         mov     dx,GUS_Command
  823.         mov     al,0Ah                 ; select low address of ptr location
  824.         out     dx,al
  825.  
  826.         mov     ax,cx
  827.         mov     dx,bx
  828.         shrd    ax,dx,7
  829.         shr     dx,7
  830.  
  831.         mov     dx,GUS_DataLo
  832.         out     dx,ax
  833.  
  834.         mov     dx,GUS_Command
  835.         mov     al,0Bh                 ; select hi address of start location
  836.         out     dx,al
  837.  
  838.         mov     ax,cx
  839.         mov     dx,bx
  840.         shld    dx,ax,9
  841.         shl     ax,9
  842.  
  843.         mov     dx,GUS_DataLo
  844.         out     dx,ax
  845.  
  846.         pop     dx
  847.         pop     cx
  848.         pop     bx
  849.         pop     ax
  850.  
  851.         ret
  852.  
  853. VoiceStartAddr  ENDP
  854.  
  855. ;══════════════════════════════════════════════════════════════════════
  856. ; bl = volume (0 thru 64) - sets for current voice (i.e. last voice selected)
  857. ; bh = 1 - save volume, bh = 0 don't save volume
  858.  
  859. TempVol DW      0
  860.  
  861. SetVol  PROC    FAR
  862.  
  863.         push    ax
  864.         push    bx
  865.         push    cx
  866.         push    dx
  867.  
  868.         mov     TempVol,bx
  869.  
  870.         xor     bh,bh
  871.         shl     bx,1                   ; * 2 to address words
  872.         mov     cx,cs:[bx + OFFSET VolTable]
  873.  
  874.         mov     dx,GUS_Command
  875.         mov     al,GUS_CurVolume       ; select set volume
  876.         out     dx,al
  877.  
  878.         mov     dx,GUS_DataLo
  879.         mov     ax,cx
  880.         out     dx,ax                  ; and send it to the Ultrasound
  881.  
  882.         mov     cx,TempVol
  883.         cmp     ch,0
  884.         je      NoStoreVol
  885.  
  886.         movzx   bx,CurVoice
  887.         mov     cs:[bx + OFFSET VoiceVolumes],cl
  888.  
  889. NoStoreVol:
  890.         pop     dx
  891.         pop     cx
  892.         pop     bx
  893.         pop     ax
  894.  
  895.         ret
  896.  
  897. SetVol  ENDP
  898.  
  899. ;══════════════════════════════════════════════════════════════════════
  900. ; bl = volume (0 thru 64) - sets for current voice (i.e. last voice selected)
  901. ; bh = 1 - save volume, bh = 0 don't save volume
  902.  
  903. MODSetVol       PROC    FAR
  904.  
  905.         push    ax
  906.         push    bx
  907.         push    cx
  908.         push    dx
  909.  
  910.         mov     TempVol,bx
  911.  
  912.         cmp     MODVolume,0            ; avoid a divide by zero error
  913.         je      NoVolume
  914.  
  915.         xor     bh,bh
  916.         shl     bx,1                   ; * 2 to address words
  917.         sub     dx,dx                  ; volume in dx:ax
  918.         mov     ax,cs:[bx + OFFSET VolTable]
  919.         mov     cx,MODVolume           ; volume * MODVolume
  920.         mul     cx
  921.  
  922.         mov     cx,100                 ; (volume * MODVolume) DIV 100 = %
  923.         div     cx
  924.         mov     cx,ax
  925.         jmp     SetTheVolumeNow
  926.  
  927. NoVolume:
  928.         mov     cx,0
  929.  
  930. SetTheVolumeNow:
  931.         mov     dx,GUS_Command
  932.         mov     al,GUS_CurVolume       ; select set volume
  933.         out     dx,al
  934.  
  935.         mov     dx,GUS_DataLo
  936.         mov     ax,cx
  937.         out     dx,ax                  ; and send it to the Ultrasound
  938.  
  939.         mov     cx,TempVol
  940.         cmp     ch,0
  941.         je      DontStoreVol
  942.  
  943.         movzx   bx,CurVoice
  944.         mov     cs:[bx + OFFSET VoiceVolumes],cl
  945.  
  946. DontStoreVol:
  947.         pop     dx
  948.         pop     cx
  949.         pop     bx
  950.         pop     ax
  951.  
  952.         ret
  953.  
  954. MODSetVol       ENDP
  955.  
  956. ;══════════════════════════════════════════════════════════════════════
  957. ;ah = mode - sets for current voice (i.e. last voice selected)
  958.  
  959. VoiceMode       PROC
  960.  
  961.         push    ax
  962.         push    bx
  963.         push    cx
  964.         push    dx
  965.  
  966.         mov     dx,GUS_Command
  967.         mov     al,GUS_SetVoiceMode     ; select set voice mode
  968.         out     dx,al
  969.  
  970.         mov     dx,GUS_DataHi
  971.         mov     al,ah
  972.         out     dx,al
  973.  
  974.         call    GUS_Delay
  975.         call    GUS_Delay
  976.  
  977.         mov     dx,GUS_Command
  978.         mov     al,GUS_SetVoiceMode     ; select set voice mode
  979.         out     dx,al
  980.  
  981.         mov     dx,GUS_DataLo
  982.         mov     al,ah
  983.         out     dx,al
  984.  
  985.         ; store the voice mode
  986.  
  987.         call    ReadVoiceMode
  988.  
  989.         movzx   bx,CurVoice
  990.         mov     ds:[OFFSET VoiceModes + bx],ah
  991.  
  992.         pop     dx
  993.         pop     cx
  994.         pop     bx
  995.         pop     ax
  996.  
  997.         ret
  998.  
  999. VoiceMode       ENDP
  1000.  
  1001. ;══════════════════════════════════════════════════════════════════════
  1002. ; returns the voice mode byte in ah and al
  1003.  
  1004. ReadVoiceMode   PROC
  1005.  
  1006.         push    dx
  1007.  
  1008.         mov     dx,GUS_Command
  1009.         mov     al,80h
  1010.         out     dx,al
  1011.  
  1012.         xor     ax,ax
  1013.         mov     dx,GUS_DataHi
  1014.         in      al,dx
  1015.  
  1016.         mov     ah,al
  1017.  
  1018.         pop     dx
  1019.  
  1020. ReadVoiceMode   ENDP
  1021.  
  1022. ;══════════════════════════════════════════════════════════════════════
  1023. ; - sets for current voice (i.e. last voice selected)
  1024.  
  1025. StopRamp        PROC
  1026.  
  1027.         push    dx
  1028.         push    ax
  1029.  
  1030.         mov     dx,GUS_Command
  1031.         mov     al,8Dh
  1032.         out     dx,al
  1033.  
  1034.         mov     dx,GUS_DataHi           ; read volume control
  1035.         in      al,dx
  1036.  
  1037.         or      al,00000011b            ; turn on ramp bits
  1038.         and     al,11011111b            ; turn of ramp IRQ
  1039.         push    ax
  1040.  
  1041.         mov     dx,GUS_Command
  1042.         mov     al,0Dh
  1043.         out     dx,al
  1044.  
  1045.         mov     dx,GUS_DataHi           ; set volume control
  1046.         pop     ax
  1047.         out     dx,al
  1048.  
  1049.         pop     ax
  1050.         pop     dx
  1051.  
  1052.         ret
  1053.  
  1054. StopRamp        ENDP
  1055.  
  1056. ;══════════════════════════════════════════════════════════════════════
  1057. ; - sets for current voice (i.e. last voice selected)
  1058.  
  1059. StartRamp       PROC
  1060.  
  1061.         push    dx
  1062.         push    ax
  1063.  
  1064.         mov     dx,GUS_Command
  1065.         mov     al,8Dh
  1066.         out     dx,al
  1067.  
  1068.         mov     dx,GUS_DataHi           ; read volume control
  1069.         in      al,dx
  1070.  
  1071.         and     al,11111100b            ; turn off ramp bits
  1072.         push    ax
  1073.  
  1074.         mov     dx,GUS_Command
  1075.         mov     al,0Dh
  1076.         out     dx,al
  1077.  
  1078.         mov     dx,GUS_DataHi           ; set volume control
  1079.         pop     ax
  1080.         out     dx,al
  1081.  
  1082.         pop     ax
  1083.         pop     dx
  1084.  
  1085.         ret
  1086.  
  1087. StartRamp       ENDP
  1088.  
  1089. ;══════════════════════════════════════════════════════════════════════
  1090. ; - sets for current voice (i.e. last voice selected)
  1091.  
  1092. StopVoice       PROC
  1093.  
  1094.         push    ax
  1095.         push    bx
  1096.         push    dx
  1097.  
  1098.         mov     bx,0                   ; set volume to zero to stop
  1099.                                        ; GF1 from summing
  1100.         call    SetVol                 ; & don't save voice volume
  1101.  
  1102.         call    ReadVoiceMode
  1103.  
  1104.         or      ah,00000010b           ; turn on the stop voice bits
  1105.         and     ah,11011111b           ; turn of the damn IRQ bit
  1106.  
  1107.         call    VoiceMode
  1108.  
  1109.         pop     dx
  1110.         pop     bx
  1111.         pop     ax
  1112.  
  1113.         ret
  1114.  
  1115. StopVoice       ENDP
  1116.  
  1117. ;══════════════════════════════════════════════════════════════════════
  1118. ; - sets for current voice (i.e. last voice selected)
  1119.  
  1120. StartVoice      PROC
  1121.  
  1122.         push    ax
  1123.         push    bx
  1124.         push    cx
  1125.         push    dx
  1126.  
  1127.         call    ReadVoiceMode
  1128.  
  1129.         and     ah,11111100b
  1130.  
  1131.         call    VoiceMode
  1132.  
  1133.         mov     bx,0
  1134.         mov     bl,CurVoice
  1135.         mov     cl,cs:[OFFSET VoiceVolumes + bx]
  1136.  
  1137.         ; get the last set voice volume in bx
  1138.         mov     bh,0                   ; bl = volume, bh = don't save
  1139.         mov     bl,cl
  1140.         call    SetVol                 ; reset the volume to last set vol
  1141.  
  1142.         pop     dx
  1143.         pop     cx
  1144.         pop     bx
  1145.         pop     ax
  1146.  
  1147.         ret
  1148.  
  1149. StartVoice      ENDP
  1150.  
  1151. ;══════════════════════════════════════════════════════════════════════
  1152. ; - sets for current voice (i.e. last voice selected)
  1153.  
  1154. MODStartVoice      PROC
  1155.  
  1156.         push    ax
  1157.         push    bx
  1158.         push    cx
  1159.         push    dx
  1160.  
  1161.         call    ReadVoiceMode
  1162.  
  1163.         and     ah,11111100b
  1164.  
  1165.         call    VoiceMode
  1166.  
  1167.         mov     bx,0
  1168.         mov     bl,CurVoice
  1169.         mov     cl,cs:[OFFSET VoiceVolumes + bx]
  1170.  
  1171.         ; get the last set voice volume in bx
  1172.         mov     bh,0                   ; bl = volume, bh = don't save
  1173.         mov     bl,cl
  1174.         call    MODSetVol              ; reset the volume to last set vol
  1175.  
  1176.         pop     dx
  1177.         pop     cx
  1178.         pop     bx
  1179.         pop     ax
  1180.  
  1181.         ret
  1182.  
  1183. MODStartVoice      ENDP
  1184.  
  1185. ;══════════════════════════════════════════════════════════════════════
  1186. ;bx = pan value - sets for current voice (i.e. last voice selected)
  1187.  
  1188. VoiceBalance    PROC
  1189.  
  1190.         push    ax
  1191.         push    dx
  1192.  
  1193.         mov     dx,GUS_Command
  1194.         mov     al,0Ch                  ; voice balance register
  1195.         out     dx,al
  1196.  
  1197.         mov     dx,GUS_DataHi
  1198.         mov     ax,bx
  1199.         out     dx,al
  1200.  
  1201.         pop     dx
  1202.         pop     ax
  1203.  
  1204.         ret
  1205.  
  1206. VoiceBalance    ENDP
  1207.  
  1208. ;══════════════════════════════════════════════════════════════════════
  1209. ;bl = Increment, bh = scale - sets for current voice (i.e. last voice selected)
  1210.  
  1211. RampRate        PROC
  1212.  
  1213.         push    ax
  1214.         push    bx
  1215.         push    dx
  1216.  
  1217.         mov     dx,GUS_Command
  1218.         mov     al,GUS_RampVolIncr      ; volume ramp rate
  1219.         out     dx,al
  1220.  
  1221.         shl     bh,6                    ; combine the scale and
  1222.         add     bl,bh                   ; increment
  1223.  
  1224.         mov     dx,GUS_DataHi
  1225.         mov     al,bl
  1226.         out     dx,al
  1227.  
  1228.         call    GUS_Delay
  1229.         call    GUS_Delay
  1230.  
  1231.         mov     dx,GUS_Command
  1232.         mov     al,GUS_RampVolIncr      ; volume ramp rate
  1233.         out     dx,al
  1234.  
  1235.         mov     dx,GUS_DataHi
  1236.         mov     al,bl
  1237.         out     dx,al
  1238.  
  1239.         pop     dx
  1240.         pop     bx
  1241.         pop     ax
  1242.  
  1243.         ret
  1244.  
  1245. RampRate        ENDP
  1246.  
  1247. ;══════════════════════════════════════════════════════════════════════
  1248. ;bx = volume start, cx = volume end - sets for current voice (i.e. last voice selected)
  1249.  
  1250. RampVolume      PROC
  1251.  
  1252.         push    ax
  1253.         push    bx
  1254.         push    cx
  1255.         push    dx
  1256.  
  1257.         mov     dx,GUS_Command
  1258.         mov     al,GUS_RampvolStart     ; volume ramp start
  1259.         out     dx,al
  1260.         shr     bx,4                    ; clip off 4 bits
  1261.         mov     dx,GUS_DataHi
  1262.         mov     al,bl
  1263.         out     dx,al
  1264.  
  1265.         mov     dx,GUS_Command
  1266.         mov     al,GUS_RampVolEnd       ; volume ramp end
  1267.         out     dx,al
  1268.         shr     cx,4                    ; clip off 4 bits
  1269.         mov     dx,GUS_DataHi
  1270.         mov     al,cl
  1271.         out     dx,al
  1272.  
  1273.         pop     dx
  1274.         pop     cx
  1275.         pop     bx
  1276.         pop     ax
  1277.  
  1278.         ret
  1279.  
  1280. RampVolume      ENDP
  1281.  
  1282. ;══════════════════════════════════════════════════════════════════════
  1283. ;bl = control byte - sets for current voice (i.e. last voice selected)
  1284.  
  1285. VolControl      PROC
  1286.  
  1287.         push    ax
  1288.         push    dx
  1289.  
  1290.         mov     dx,GUS_Command
  1291.         mov     al,GUS_VolControl       ; volume control register
  1292.         out     dx,al
  1293.  
  1294.         mov     dx,GUS_DataHi
  1295.         mov     ax,bx
  1296.         out     dx,al
  1297.  
  1298.         call    GUS_Delay
  1299.         call    GUS_Delay
  1300.  
  1301.         mov     dx,GUS_Command
  1302.         mov     al,GUS_VolControl       ; volume control register
  1303.         out     dx,al
  1304.  
  1305.         mov     dx,GUS_DataHi
  1306.         mov     ax,bx
  1307.         out     dx,al
  1308.  
  1309.         pop     dx
  1310.         pop     ax
  1311.  
  1312.         ret
  1313.  
  1314. VolControl      ENDP
  1315.  
  1316. ;══════════════════════════════════════════════════════════════════════
  1317. ; returns linear voice position in dx:ax
  1318.  
  1319. ReadVoicePos PROC
  1320.  
  1321.         push    bx
  1322.         push    cx
  1323.  
  1324.         mov     dx,GUS_Command
  1325.         mov     al,8Ah                  ; read voice position
  1326.         out     dx,al
  1327.  
  1328.         mov     dx,GUS_DataLo
  1329.         in      ax,dx                   ; Low voice position
  1330.         mov     cx,ax                   ; save it
  1331.  
  1332.         mov     dx,GUS_Command
  1333.         mov     al,8Bh
  1334.         out     dx,al
  1335.  
  1336.         mov     dx,GUS_DataLo
  1337.         in      ax,dx
  1338.  
  1339.         ; convert the position to a linear address
  1340.  
  1341.         xor     dx,dx
  1342.         mov     bx,cx
  1343.         shl     cx,7
  1344.         shl     dx,7
  1345.         shr     bx,9
  1346.         or      dx,bx
  1347.         shr     ax,9
  1348.         and     ax,7Fh
  1349.         or      cx,ax
  1350.         mov     ax,cx
  1351.  
  1352.         pop     cx
  1353.         pop     bx
  1354.  
  1355.         ret
  1356.  
  1357. ReadVoicePos ENDP
  1358.  
  1359. ;══════════════════════════════════════════════════════════════════════
  1360.  
  1361. Reset   PROC
  1362.  
  1363.         push    ax
  1364.         push    bx
  1365.         push    cx
  1366.         push    dx
  1367.  
  1368.         mov     dx,GUS_Base
  1369.         mov     al,01001010b            ; turn off speaker and enable IRQs
  1370.         out     dx,al
  1371.  
  1372.         mov     dx,GUS_Command
  1373.         mov     al,04Ch
  1374.         out     dx,al
  1375.         mov     dx,GUS_DataHi
  1376.         mov     al,0
  1377.         out     dx,al
  1378.  
  1379.         call    GUS_Delay
  1380.         call    GUS_Delay
  1381.  
  1382.         mov     dx,GUS_Command
  1383.         mov     al,4Ch                  ; initialization register
  1384.         out     dx,al
  1385.         mov     dx,GUS_DataHi
  1386.         mov     al,00000111b            ; turn initialization off so
  1387.         out     dx,al                   ; that we can write to the card
  1388.  
  1389.         call    GUS_Delay
  1390.         call    GUS_Delay
  1391.  
  1392.         mov     dx,GUS_Command
  1393.         mov     al,41h                  ; DMA control register
  1394.         out     dx,al
  1395.         mov     dx,GUS_DataHi
  1396.         xor     al,al                   ; turn off all pending DMA IRQs
  1397.         out     dx,al
  1398.  
  1399.         mov     dx,GUS_Command
  1400.         mov     al,45h                  ; Timer control register
  1401.         out     dx,al
  1402.         mov     dx,GUS_DataHi
  1403.         xor     al,al                   ; clear all pending timer IRQs
  1404.         out     dx,al
  1405.  
  1406.         mov     dx,GUS_Command
  1407.         mov     al,49h                  ; Sample control IRQs
  1408.         out     dx,al
  1409.         mov     dx,GUS_DataHi
  1410.         xor     al,al                   ; clear all pending sample control IRQs
  1411.         out     dx,al
  1412.  
  1413.         mov     dx,GUS_Command
  1414.         mov     al,0Eh                  ; active voices register
  1415.         out     dx,al
  1416.         mov     dx,GUS_DataHi
  1417.         mov     al,31
  1418.         mov     ActiveVoices,31
  1419.         or      al,0Ch                  ; select number of active voices
  1420.         out     dx,al
  1421.  
  1422.         ; read a few ports (anyone know why?  I don't.)
  1423.  
  1424.         mov     dx,GUS_Status
  1425.         in      al,dx
  1426.  
  1427.         mov     dx,GUS_Command
  1428.         mov     al,41h                  ; DMA control register
  1429.         out     dx,al
  1430.         mov     dx,GUS_DataHi           ; read DMA control register
  1431.         in      al,dx
  1432.  
  1433.         mov     dx,GUS_Command
  1434.         mov     al,49h                  ; Sample Control IRQ register
  1435.         out     dx,al
  1436.         mov     dx,GUS_DataHi
  1437.         in      al,dx                   ; read Sample Control register
  1438.  
  1439.         mov     dx,GUS_Command
  1440.         mov     al,8Fh                  ; IRQ status register
  1441.         out     dx,al
  1442.         mov     dx,GUS_DataHi
  1443.         in      al,dx
  1444.  
  1445.         ; turn all voices and ramps off
  1446.  
  1447.         mov     cx,0
  1448. VoiceClearLoop:
  1449.         mov     al,cl
  1450.         SelectVoice
  1451.  
  1452. ;        mov     dx,GUS_Voice
  1453. ;        mov     al,cl                   ; select voice
  1454. ;        out     dx,al
  1455.  
  1456. ;        inc     dx                      ; GUS_Command
  1457. ;        mov     al,0                    ; select Voice Mode register
  1458. ;        out     dx,al
  1459. ;        add     dx,2                    ; GUS_DataHi
  1460. ;        mov     al,3                    ; voice off, no IRQs enabled
  1461. ;        out     dx,al
  1462.  
  1463. ;        xor     bx,bx
  1464. ;        mov     bl,cl
  1465. ;        mov     ds:[OFFSET VoiceModes + bx],3
  1466.  
  1467.         mov     ah,3                     ; voice off, no IRQs, no Loop
  1468.         call    VoiceMode                ; set the voice mode register
  1469.                                          ; and store the value
  1470.  
  1471.         mov     bx,0100h                 ; set voice volume register
  1472.         call    SetVol                   ; and store the value
  1473.  
  1474.         inc     dx
  1475.         sub     dx,2                    ; GUS_Command
  1476.         mov     al,0Dh                  ; volume control register
  1477.         out     dx,al
  1478.         add     dx,2                    ; GUS_DataHi
  1479.         mov     al,3                    ; ramp off
  1480.         out     dx,al
  1481.  
  1482.         sub     dx,2                    ; GUS_Command
  1483.         mov     al,0Ch                  ; voice balance control
  1484.         out     dx,al
  1485.         add     dx,2                    ; GUS_DataHi
  1486.         mov     al,7                    ; center balance
  1487.         out     dx,al
  1488.  
  1489.         inc     cx                      ; next voice
  1490.         cmp     cx,32
  1491.         jne     VoiceClearLoop
  1492.  
  1493.         ; read a few ports again (still dont know why.)
  1494.  
  1495.         mov     dx,GUS_Command
  1496.         mov     al,41h                  ; DMA control register
  1497.         out     dx,al
  1498.         mov     dx,GUS_DataHi           ; read DMA control register
  1499.         in      al,dx
  1500.  
  1501.         mov     dx,GUS_Command
  1502.         mov     al,49h                  ; Sample Control IRQ register
  1503.         out     dx,al
  1504.         mov     dx,GUS_DataHi
  1505.         in      al,dx                   ; read Sample Control register
  1506.  
  1507.         mov     dx,GUS_Command
  1508.         mov     al,8Fh                  ; IRQ status register
  1509.         out     dx,al
  1510.         mov     dx,GUS_DataHi
  1511.         in      al,dx
  1512.  
  1513.         mov     dx,GUS_Command
  1514.         mov     al,4Ch                  ; init mode register
  1515.         out     dx,al
  1516.         mov     dx,GUS_DataHi
  1517.         mov     al,7                    ; set first 3 bits
  1518.         out     dx,al                   ; return to init mode
  1519.  
  1520.         mov     dx,GUS_Base
  1521.         mov     al,01001101b            ; turn on speaker and enable IRQs
  1522.                                         ; line in and mic in = off
  1523.         out     dx,al
  1524.         mov     GUS_Mixer,al            ; save the mixer val since we can't
  1525.                                         ; read it ever
  1526.  
  1527.         pop     dx
  1528.         pop     cx
  1529.         pop     bx
  1530.         pop     ax
  1531.  
  1532.         ret
  1533.  
  1534. Reset   ENDP
  1535.  
  1536. ;══════════════════════════════════════════════════════════════════════
  1537.  
  1538. GUS_ReadVoicePos     PROC    FAR
  1539.  
  1540. VoiceNum EQU    byte ptr [bp+06]
  1541.  
  1542.          push   bp
  1543.          mov    bp,sp
  1544.  
  1545.          mov    al,VoiceNum
  1546.          SelectVoice
  1547.  
  1548.          call   ReadVoicePos
  1549.  
  1550.          mov    sp,bp
  1551.          pop    bp
  1552.  
  1553.          ret    2
  1554.  
  1555. GUS_ReadVoicePos     ENDP
  1556.  
  1557. ;══════════════════════════════════════════════════════════════════════
  1558.  
  1559. GUS_Peek        PROC    FAR
  1560.  
  1561. HiAddr1 EQU     word ptr [bp+08]
  1562. LoAddr1 EQU     word ptr [bp+06]
  1563.  
  1564.         push    bp
  1565.         mov     bp,sp
  1566.  
  1567.         cmp     GUS_Base,210
  1568.         jl      ExitPeek
  1569.  
  1570.         mov     cx,LoAddr1
  1571.         mov     bx,HiAddr1
  1572.  
  1573.         call    Peek
  1574.  
  1575. ExitPeek:
  1576.         mov     bp,sp
  1577.         pop     bp
  1578.  
  1579.         ret     4
  1580.  
  1581. GUS_Peek        ENDP
  1582.  
  1583. ;══════════════════════════════════════════════════════════════════════
  1584.  
  1585. GUS_Poke        PROC    FAR
  1586.  
  1587. HiAddr2 EQU     word ptr [bp+10]
  1588. LoAddr2 EQU     word ptr [bp+08]
  1589. Value   EQU     byte ptr [bp+06]
  1590.  
  1591.         push    bp
  1592.         mov     bp,sp
  1593.  
  1594.         cmp     GUS_Base,210
  1595.         jl      ExitPoke
  1596.  
  1597.         mov     cx,LoAddr2
  1598.         mov     bx,HiAddr2
  1599.         movzx   ax,Value
  1600.  
  1601.         call    Poke
  1602.  
  1603. ExitPoke:
  1604.         mov     sp,bp
  1605.         pop     bp
  1606.  
  1607.         ret     6
  1608.  
  1609. GUS_Poke        ENDP
  1610.  
  1611. ;══════════════════════════════════════════════════════════════════════
  1612.  
  1613. GUS_TestBaseAddress PROC FAR
  1614.  
  1615.         push    bp
  1616.         mov     bp,sp
  1617.  
  1618.         mov     dx,GUS_Command
  1619.         mov     al,4Ch
  1620.         out     dx,al
  1621.  
  1622.         mov     dx,GUS_DataHi
  1623.         mov     al,01
  1624.         out     dx,al                  ; turn OFF Ultrasound reset state
  1625.  
  1626.         call    GUS_Delay
  1627.         call    GUS_Delay
  1628.  
  1629.         mov     ax,0AAh
  1630.         mov     bx,0
  1631.         mov     cx,0
  1632.         call    Poke
  1633.  
  1634.         mov     al,055h
  1635.         mov     bx,01h
  1636.         call    Poke
  1637.  
  1638.         mov     bx,0
  1639.         call    Peek
  1640.  
  1641.         push    ax                     ; save the peeked value
  1642.  
  1643.         mov     dx,GUS_Command
  1644.         mov     al,4Ch
  1645.         out     dx,al                  ; turn Ultrasound init state ON
  1646.  
  1647.         mov     dx,GUS_DataHi
  1648.         mov     al,00
  1649.         out     dx,al
  1650.  
  1651.         pop     ax                     ; restore the peeked value
  1652.         cmp     al,0AAh
  1653.         jne     GUS_NotFound
  1654.  
  1655.         mov     ax,1
  1656.         jmp     GUS_TestExit
  1657.  
  1658. GUS_NotFound:
  1659.         xor     ax,ax
  1660.  
  1661. GUS_TestExit:
  1662.         mov     dx,GUS_Command
  1663.         mov     al,4Ch
  1664.         out     dx,al                  ; turn Ultrasound init state OFF
  1665.  
  1666.         mov     dx,GUS_DataHi
  1667.         mov     al,01
  1668.         out     dx,al
  1669.  
  1670.         mov     sp,bp
  1671.         pop     bp
  1672.  
  1673.         ret
  1674.  
  1675. GUS_TestBaseAddress ENDP
  1676.  
  1677. ;══════════════════════════════════════════════════════════════════════
  1678.  
  1679. GUS_Mem         PROC FAR
  1680.  
  1681.         push    bp
  1682.         mov     bp,sp
  1683.  
  1684.         xor     dx,dx
  1685.  
  1686.         cmp     GUS_Base,210
  1687.         jl      ExitMem
  1688.  
  1689.         xor     cx,cx
  1690.         mov     bx,4
  1691.         mov     ax,0AAh
  1692.  
  1693.         call    Poke
  1694.  
  1695.         xor     cx,cx
  1696.         mov     bx,4
  1697.  
  1698.         call    Peek
  1699.  
  1700.         mov     dx,0100h
  1701.         cmp     al,0AAh
  1702.         jne     ExitMem
  1703.  
  1704.         xor     cx,cx
  1705.         mov     bx,8
  1706.         mov     ax,0AAh
  1707.  
  1708.         call    Poke
  1709.  
  1710.         xor     cx,cx
  1711.         mov     bx,8
  1712.  
  1713.         call    Peek
  1714.         mov     dx,0200h
  1715.         cmp     al,0AAh
  1716.         jne     ExitMem
  1717.  
  1718.         xor     cx,cx
  1719.         mov     bx,0Ch
  1720.         mov     al,0AAh
  1721.  
  1722.         call    Poke
  1723.  
  1724.         xor     cx,cx
  1725.         mov     bx,0Ch
  1726.  
  1727.         call    Peek
  1728.         mov     dx,0300h
  1729.         cmp     al,0AAh
  1730.         jne     ExitMem
  1731.  
  1732.         mov     dx,0400h
  1733.  
  1734. ExitMem:
  1735.         mov     ax,dx
  1736.  
  1737.         mov     sp,bp
  1738.         pop     bp
  1739.  
  1740.         ret
  1741.  
  1742. GUS_Mem         ENDP
  1743.  
  1744. ;══════════════════════════════════════════════════════════════════════
  1745. ;moves the sample to GUS memory
  1746. ;es:di - address of sample in DOS memory
  1747. ;bx:cx = address in GUS memory to store sample
  1748. ;dx = sample length
  1749.  
  1750. MoveSample      PROC
  1751.  
  1752. StoreLoop:
  1753.         push    dx                     ; save the sample length counter
  1754.  
  1755.         mov     dx,GUS_Command
  1756.         mov     al,43h
  1757.         out     dx,al
  1758.  
  1759.         inc     dx                     ; GUS_DataLo
  1760.         mov     ax,cx
  1761.         out     dx,ax
  1762.  
  1763.         dec     dx                     ; GUS_Command
  1764.         mov     al,44h
  1765.         out     dx,al
  1766.  
  1767.         add     dx,2                   ; GUS_DataHi
  1768.         mov     al,bl
  1769.         out     dx,al
  1770.  
  1771.         add     dx,2                   ; GUS_DRAMIO
  1772.  
  1773.         mov     al,es:[di]             ; load the byte to send
  1774.         inc     di
  1775.         out     dx,al
  1776.  
  1777.         add     cx,1
  1778.         adc     bx,0                   ; increment the GUS memory ptr
  1779.  
  1780.         pop     dx
  1781.         dec     dx
  1782.         jnz     StoreLoop              ; do it again if we're not at the end
  1783.  
  1784.         ret
  1785.  
  1786. MoveSample      ENDP
  1787.  
  1788. ;══════════════════════════════════════════════════════════════════════
  1789. ; PROCEDURE GUS_VoiceFreq (VoiceNum : BYTE; Hertz : WORD);
  1790.  
  1791. GUS_VoiceFreq   PROC FAR
  1792.  
  1793. Voice1  EQU     byte ptr [bp+08]
  1794. Freq1   EQU     word ptr [bp+06]
  1795.  
  1796.         push    bp
  1797.         mov     bp,sp
  1798.  
  1799.         cmp     GUS_Base,210
  1800.         jl      ExitVoiceFreq
  1801.  
  1802.         mov     al,Voice1
  1803.         SelectVoice
  1804.  
  1805.         mov     bx,Freq1
  1806.  
  1807.         call    VoiceFreq
  1808.  
  1809. ExitVoiceFreq:
  1810.         mov     sp,bp
  1811.         pop     bp
  1812.  
  1813.         ret     4
  1814.  
  1815. GUS_VoiceFreq   ENDP
  1816.  
  1817. ;══════════════════════════════════════════════════════════════════════
  1818. ;PROCEDURE GUS_ActiveVoices (Voices : BYTE);
  1819.  
  1820. GUS_SetActiveVoices PROC FAR
  1821.  
  1822. Voice2  EQU     byte ptr [bp+06]
  1823.  
  1824.         push    bp
  1825.         mov     bp,sp
  1826.  
  1827.         cmp     GUS_Base,210
  1828.         jl      ExitActive
  1829.  
  1830.         movzx   ax,Voice2
  1831.         call    SetActive
  1832.  
  1833. ExitActive:
  1834.         mov     sp,bp
  1835.         pop     bp
  1836.  
  1837.         ret     2
  1838.  
  1839. GUS_SetActiveVoices ENDP
  1840.  
  1841. ;══════════════════════════════════════════════════════════════════════
  1842. ;PROCEDURE GUS_VoiceAddr (Voice : BYTE; Start, CurPtr, End : LONGINT);
  1843.  
  1844. GUS_VoiceAddr   PROC    FAR
  1845.  
  1846. Voice3  EQU     byte ptr [bp+18]
  1847. PtrHi   EQU     word ptr [bp+16]
  1848. PtrLo   EQU     word ptr [bp+14]
  1849. StartHi EQU     word ptr [bp+12]
  1850. StartLo EQU     word ptr [bp+10]
  1851. EndHi   EQU     word ptr [bp+08]
  1852. EndLo   EQU     word ptr [bp+06]
  1853.  
  1854.         push    bp
  1855.         mov     bp,sp
  1856.  
  1857.         cmp     GUS_Base,210
  1858.         jl      ExitVoiceAddr
  1859.  
  1860.         mov     al,Voice3
  1861.         SelectVoice
  1862.  
  1863.         ;mov     ax,Voice3
  1864.         mov     bx,PtrHi
  1865.         mov     cx,PtrLo
  1866.         call    VoiceStartAddr
  1867.  
  1868.         ;mov     ax,Voice3
  1869.         mov     bx,StartHi
  1870.         mov     cx,StartLo
  1871.         call    LoopStartAddr
  1872.  
  1873.         ;mov     ax,Voice3
  1874.         mov     bx,EndHi
  1875.         mov     cx,EndLo
  1876.         call    LoopEndAddr
  1877.  
  1878. ExitVoiceAddr:
  1879.         mov     sp,bp
  1880.         pop     bp
  1881.  
  1882.         ret     14
  1883.  
  1884. GUS_VoiceAddr   ENDP
  1885.  
  1886. ;══════════════════════════════════════════════════════════════════════
  1887. ;PROCEDURE GUS_VoiceVolume (Voice : BYTE; Volume : WORD);
  1888.  
  1889. GUS_VoiceVolume PROC    FAR
  1890.  
  1891. Voice4  EQU     byte ptr [bp+08]
  1892. Volume  EQU     word ptr [bp+06]
  1893.  
  1894.         push    bp
  1895.         mov     bp,sp
  1896.  
  1897.         cmp     GUS_Base,210
  1898.         jl      ExitVoiceVol
  1899.  
  1900.         mov     al,Voice4
  1901.         SelectVoice
  1902.  
  1903.         mov     bx,Volume
  1904.         mov     bh,1                    ; save volume!
  1905.         call    SetVol
  1906.  
  1907. ExitVoiceVol:
  1908.         mov     sp,bp
  1909.         pop     bp
  1910.  
  1911.         ret     4
  1912.  
  1913. GUS_VoiceVolume ENDP
  1914.  
  1915. ;══════════════════════════════════════════════════════════════════════
  1916. ;PROCEDURE GUS_VoiceMode (Voice : BYTE; Mode : BYTE);
  1917.  
  1918. GUS_VoiceMode   PROC    FAR
  1919.  
  1920. Voice5  EQU     byte ptr [bp+08]
  1921. Mode    EQU     byte ptr [bp+06]
  1922.  
  1923.         push    bp
  1924.         mov     bp,sp
  1925.  
  1926.         cmp     GUS_Base,210
  1927.         jl      ExitVoiceMode
  1928.  
  1929.         mov     al,Voice5
  1930.         SelectVoice
  1931.  
  1932.         mov     ah,Mode
  1933.         call    VoiceMode
  1934.  
  1935. ExitVoiceMode:
  1936.         mov     sp,bp
  1937.         pop     bp
  1938.  
  1939.         ret     4
  1940.  
  1941. GUS_VoiceMode   ENDP
  1942.  
  1943. ;══════════════════════════════════════════════════════════════════════
  1944. ;FUNCTION GUS_ReadVoiceMode (Voice : BYTE): BYTE;
  1945.  
  1946. GUS_ReadVoiceMode PROC FAR
  1947.  
  1948. Voice12 EQU     byte ptr [bp+06]
  1949.  
  1950.         push    bp
  1951.         mov     bp,sp
  1952.  
  1953.         mov     al,Voice12
  1954.         SelectVoice
  1955.  
  1956.         call    ReadVoiceMode
  1957.  
  1958.         mov     sp,bp
  1959.         pop     bp
  1960.  
  1961.         ret     2
  1962.  
  1963. GUS_ReadVoiceMode ENDP
  1964.  
  1965. ;══════════════════════════════════════════════════════════════════════
  1966. ;PROCEDURE GUS_StopVoice (Voice : BYTE);
  1967.  
  1968. GUS_StopVoice   PROC    FAR
  1969.  
  1970. Voice6  EQU     byte ptr [bp+06]
  1971.  
  1972.          push    bp
  1973.         mov     bp,sp
  1974.  
  1975.         cmp     GUS_Base,210
  1976.         jl      ExitStopVoice
  1977.  
  1978.         mov     al,Voice6
  1979.         SelectVoice
  1980.  
  1981.         call    StopVoice
  1982.  
  1983. ExitStopVoice:
  1984.         mov     sp,bp
  1985.         pop     bp
  1986.  
  1987.         ret     2
  1988.  
  1989. GUS_StopVoice   ENDP
  1990.  
  1991. ;══════════════════════════════════════════════════════════════════════
  1992. ;PROCEDURE GUS_StartVoice (Voice : BYTE);
  1993.  
  1994. GUS_StartVoice  PROC    FAR
  1995.  
  1996. Voice7  EQU     byte ptr [bp+06]
  1997.  
  1998.         push    bp
  1999.         mov     bp,sp
  2000.  
  2001.         cmp     GUS_Base,210
  2002.         jl      ExitStartVoice
  2003.  
  2004.         mov     al,Voice7
  2005.         SelectVoice
  2006.  
  2007.         call    StartVoice
  2008.  
  2009. ExitStartVoice:
  2010.         mov     sp,bp
  2011.         pop     bp
  2012.  
  2013.         ret     2
  2014.  
  2015. GUS_StartVoice  ENDP
  2016.  
  2017. ;══════════════════════════════════════════════════════════════════════
  2018.  
  2019. GUS_SpeakerOn   PROC    FAR
  2020.  
  2021.         push    bp
  2022.         mov     bp,sp
  2023.  
  2024.         cmp     GUS_Base,210
  2025.         jl      ExitSpeakerOn
  2026.  
  2027.         mov     dx,GUS_Base
  2028.         mov     al,GUS_Mixer
  2029.         or      al,00001000b           ; make sure latches are on!
  2030.         and     al,11111101b           ; turn speaker on
  2031.         mov     GUS_Mixer,al           ; store the current value
  2032.         out     dx,al
  2033.  
  2034. ExitSpeakerOn:
  2035.         mov     sp,bp
  2036.         pop     bp
  2037.  
  2038.         ret
  2039.  
  2040. GUS_SpeakerOn   ENDP
  2041.  
  2042. ;══════════════════════════════════════════════════════════════════════
  2043.  
  2044. GUS_SpeakerOff  PROC    FAR
  2045.  
  2046.         push    bp
  2047.         mov     bp,sp
  2048.  
  2049.         cmp     GUS_Base,210
  2050.         jl      ExitSpeakerOff
  2051.  
  2052.         mov     dx,GUS_Base
  2053.         mov     al,GUS_Mixer
  2054.         or      al,00001010b           ; turn on latches and turn speaker off
  2055.         mov     GUS_Mixer,al           ; store the current value
  2056.         out     dx,al
  2057.  
  2058. ExitSpeakerOff:
  2059.         mov     sp,bp
  2060.         pop     bp
  2061.  
  2062.         ret
  2063.  
  2064. GUS_SpeakerOff  ENDP
  2065.  
  2066. ;══════════════════════════════════════════════════════════════════════
  2067.  
  2068. GUS_Reset       PROC    FAR
  2069.  
  2070.         cmp     GUS_Base,210
  2071.         jl      ExitReset
  2072.  
  2073.         call    Reset
  2074.  
  2075. ExitReset:
  2076.         ret
  2077.  
  2078. GUS_Reset       ENDP
  2079.  
  2080. ;══════════════════════════════════════════════════════════════════════
  2081.  
  2082. GUS_VoiceBalance PROC   FAR
  2083.  
  2084. Voice8  EQU     byte ptr [bp+08]
  2085. Balance EQU     byte ptr [bp+06]
  2086.  
  2087.         push    bp
  2088.         mov     bp,sp
  2089.  
  2090.         cmp     GUS_Base,210
  2091.         jl      ExitVoiceBalance
  2092.  
  2093.         mov     al,Voice8
  2094.         SelectVoice
  2095.  
  2096.         movzx   bx,Balance
  2097.         call    VoiceBalance
  2098.  
  2099. ExitVoiceBalance:
  2100.         mov     sp,bp
  2101.         pop     bp
  2102.  
  2103.         ret     4
  2104.  
  2105. GUS_VoiceBalance ENDP
  2106.  
  2107. ;══════════════════════════════════════════════════════════════════════
  2108. ;PROCEDURE GUS_RampRate (Voice, Increment, Scale : BYTE);
  2109.  
  2110. GUS_RampRate    PROC    FAR
  2111.  
  2112. Voice9  EQU     byte ptr [bp+10]
  2113. Incr    EQU     byte ptr [bp+08]
  2114. Scale   EQU     byte ptr [bp+06]
  2115.  
  2116.         push    bp
  2117.         mov     bp,sp
  2118.  
  2119.         cmp     GUS_Base,210
  2120.         jl      ExitRampRate
  2121.  
  2122.         mov     al,Voice9
  2123.         SelectVoice
  2124.  
  2125.         mov     bl,Incr
  2126.         mov     bh,Scale
  2127.         call    RampRate
  2128.  
  2129. ExitRampRate:
  2130.         mov     sp,bp
  2131.         pop     bp
  2132.  
  2133.         ret     6
  2134.  
  2135. GUS_RampRate    ENDP
  2136.  
  2137. ;══════════════════════════════════════════════════════════════════════
  2138. ;PROCEDURE GUS_RampVolume (Voice, StartVol, EndVol : BYTE);
  2139.  
  2140. GUS_RampVolume  PROC    FAR
  2141.  
  2142. Voice10 EQU     byte ptr [bp+10]
  2143. SVol    EQU     byte ptr [bp+08]
  2144. EVol    EQU     byte ptr [bp+06]
  2145.  
  2146.         push    bp
  2147.         mov     bp,sp
  2148.  
  2149.         cmp     GUS_Base,210
  2150.         jl      ExitRampVol
  2151.  
  2152.         mov     al,Voice10
  2153.         SelectVoice
  2154.  
  2155.         xor     bx,bx
  2156.  
  2157.         mov     bl,EVol
  2158.         shl     bx,1
  2159.         mov     cx,cs:[bx + OFFSET VolTable]
  2160.  
  2161.         movzx   bx,SVol
  2162.         shl     bx,1
  2163.         mov     ax,cs:[bx + OFFSET VolTable]
  2164.         mov     bx,ax
  2165.  
  2166.         call    RampVolume
  2167.  
  2168. ExitRampVol:
  2169.         mov     sp,bp
  2170.         pop     bp
  2171.  
  2172.         ret     6
  2173.  
  2174. GUS_RampVolume  ENDP
  2175.  
  2176. ;══════════════════════════════════════════════════════════════════════
  2177. ;PROCEDURE GUS_VolumeControl (Voice, Control : BYTE);
  2178.  
  2179. GUS_VolumeControl PROC  FAR
  2180.  
  2181. Voice11 EQU     byte ptr [bp+08]
  2182. Control EQU     byte ptr [bp+06]
  2183.  
  2184.         push    bp
  2185.         mov     bp,sp
  2186.  
  2187.         cmp     GUS_Base,210
  2188.         jl      ExitVolumeCon
  2189.  
  2190.         mov     al,Voice11
  2191.         SelectVoice
  2192.  
  2193.         movzx   bx,Control
  2194.         call    VolControl
  2195.  
  2196. ExitVolumeCon:
  2197.         mov     sp,bp
  2198.         pop     bp
  2199.  
  2200.         ret     4
  2201.  
  2202. GUS_VolumeControl ENDP
  2203.  
  2204. ;══════════════════════════════════════════════════════════════════════
  2205. ;PROCEDURE GUS_StoreSample (DOSAddr, GUSAddr : LONGINT; Len : WORD);
  2206.  
  2207. GUS_MoveSample  PROC    FAR
  2208.  
  2209. DOSAddrHi       EQU     word   ptr [bp+14]
  2210. DOSAddrLo       EQU     word   ptr [bp+12]
  2211. GUSAddrHi       EQU     word   ptr [bp+10]
  2212. GUSAddrLo       EQU     word   ptr [bp+08]
  2213. Len             EQU     word   ptr [bp+06]
  2214.  
  2215.         push    bp
  2216.         mov     bp,sp
  2217.  
  2218.         mov     ax,DOSAddrHi
  2219.         mov     es,ax
  2220.         mov     di,DOSAddrLo
  2221.  
  2222.         mov     bx,GUSAddrHi
  2223.         mov     cx,GUSAddrLo
  2224.  
  2225.         mov     dx,Len
  2226.  
  2227.         call    MoveSample
  2228.  
  2229.         mov     sp,bp
  2230.         pop     bp
  2231.  
  2232.         ret     10
  2233.  
  2234. GUS_MoveSample  ENDP
  2235.  
  2236. ;══════════════════════════════════════════════════════════════════════
  2237. ;PROCEDURE GUS_SetClockRate (rate : WORD);
  2238.  
  2239. GUS_SetClockRate PROC   FAR
  2240.  
  2241. Rate    EQU    word ptr [BP+06]
  2242.  
  2243.     push    bp
  2244.     mov     bp,sp
  2245.  
  2246.     mov     bx,Rate
  2247.         call    ClockRate
  2248.  
  2249.     mov     sp,bp
  2250.     pop     bp
  2251.  
  2252.     ret    2
  2253.  
  2254. GUS_SetClockRate ENDP
  2255.  
  2256. ;══════════════════════════════════════════════════════════════════════
  2257.  
  2258. GUS_SetTimer    PROC    FAR
  2259.  
  2260.         push    bp
  2261.         mov     bp,sp
  2262.  
  2263.         call    SetTimer
  2264.  
  2265.         mov     sp,bp
  2266.         pop     bp
  2267.  
  2268.         ret
  2269.  
  2270. GUS_SetTimer    ENDP
  2271.  
  2272. ;══════════════════════════════════════════════════════════════════════
  2273.  
  2274. GUS_ResetTimer  PROC    FAR
  2275.  
  2276.         push    bp
  2277.         mov     bp,sp
  2278.  
  2279.         call    ResetTimer
  2280.  
  2281.         mov     sp,bp
  2282.         pop     bp
  2283.  
  2284.         ret
  2285.  
  2286. GUS_ResetTimer  ENDP
  2287.  
  2288. ;══════════════════════════════════════════════════════════════════════
  2289.  
  2290. GUS_SetIRQ      PROC    FAR
  2291.  
  2292.         push    bp
  2293.         mov     bp,sp
  2294.  
  2295.         mov     ax,GUS_IRQ
  2296.         mov     bx,OFFSET IRQInt
  2297.         call    SetIRQInt
  2298.  
  2299.         ; al will store the GF1 IRQ number in bits 0-2
  2300.  
  2301.         cmp     GUS_IRQ,2
  2302.         jne     TestIRQ5
  2303.  
  2304.         mov     al,1
  2305.         jmp     SetIRQCon
  2306.  
  2307. TestIRQ5:
  2308.         cmp     GUS_IRQ,5
  2309.         jne     TestIRQ3
  2310.  
  2311.         mov     al,2
  2312.         jmp     SetIRQCon
  2313.  
  2314. TestIRQ3:
  2315.         cmp     GUS_IRQ,3
  2316.         jne     TestIRQ7
  2317.  
  2318.         mov     al,3
  2319.         jmp     SetIRQCon
  2320.  
  2321. TestIRQ7:
  2322.         cmp     GUS_IRQ,7
  2323.         jne     TestIRQ11
  2324.  
  2325.         mov     al,4
  2326.         jmp     SetIRQCon
  2327.  
  2328. TestIRQ11:
  2329.         cmp     GUS_IRQ,11
  2330.         jne     TestIRQ12
  2331.  
  2332.         mov     al,5
  2333.         jmp     SetIRQCon
  2334.  
  2335. TestIRQ12:
  2336.         cmp     GUS_IRQ,12
  2337.         jne     TestIRQ15
  2338.  
  2339.         mov     al,6
  2340.         jmp     SetIRQCon
  2341.  
  2342. TestIRQ15:
  2343.         cmp     GUS_IRQ,15
  2344.         jne     NoIRQ
  2345.  
  2346.         mov     al,7
  2347.         jmp     SetIRQCon
  2348.  
  2349. NoIRQ:
  2350.         xor     al,al
  2351.  
  2352. SetIRQCon:
  2353.         push    ax                     ; save the IRQ bit
  2354.  
  2355. ;        mov     dx,GUS_Base
  2356. ;        mov     al,GUS_Mixer
  2357. ;        or      al,01000000b           ; select IRQ Control Register
  2358. ;        mov     GUS_Mixer,al
  2359. ;        out     dx,al
  2360.  
  2361.         pop     ax                     ; restore the IRQ bit
  2362. ;        mov     dx,GUS_IRQDMACon       ; IRQ/DMA Control register
  2363. ;        out     dx,al                  ; send the IRQ control bits
  2364.  
  2365.         mov     sp,bp
  2366.         pop     bp
  2367.  
  2368.         ret
  2369.  
  2370. GUS_SetIRQ      ENDP
  2371.  
  2372. ;══════════════════════════════════════════════════════════════════════
  2373.  
  2374. GUS_RestoreIRQ  PROC    FAR
  2375.  
  2376.         push    bp
  2377.         mov     bp,sp
  2378.  
  2379.         mov     ax,GUS_IRQ
  2380.         call    RestoreIRQInt
  2381.  
  2382.         mov     sp,bp
  2383.         pop     bp
  2384.  
  2385.         ret
  2386.  
  2387. GUS_RestoreIRQ  ENDP
  2388.  
  2389. ;══════════════════════════════════════════════════════════════════════
  2390.  
  2391. NewInt08        PROC    FAR
  2392.  
  2393.         push    ax
  2394.         pushf
  2395.  
  2396.     mov    al,20h                 ; enable interrupts
  2397.     out    20h,al
  2398.     sti
  2399.  
  2400.         dec     cs:OldIntFlag
  2401.         cmp     cs:OldIntFlag,0
  2402.         jne     ExitNewInt
  2403.  
  2404.         mov     ax,cs:OldIntCount      ; reset the counter
  2405.         mov     cs:OldIntFlag,ax
  2406.  
  2407.         popf
  2408.         pop     ax
  2409.  
  2410.         pushf
  2411.         call    OldInt08
  2412.  
  2413.         iret
  2414.  
  2415. ExitNewInt:
  2416.         popf
  2417.         pop     ax
  2418.  
  2419.         iret
  2420.  
  2421. NewInt08        ENDP
  2422.  
  2423. ;══════════════════════════════════════════════════════════════════════
  2424.  
  2425. Mess1   DB      'WTirq ',0
  2426. Mess2   DB      'Rirq ',0
  2427. Mess3   DB      'CurVoice = ',0
  2428.  
  2429. IRQInt  PROC    FAR
  2430.  
  2431.         push    ax
  2432.         push    bx
  2433.         push    cx
  2434.         push    dx
  2435.         push    ds
  2436.         push    es
  2437.         push    si
  2438.         push    di
  2439.         pushf
  2440.  
  2441.         mov     ax,SEG Data            ; set DS to TP's DS
  2442.         mov     ds,ax
  2443.         mov     di,OFFSET EndIRQ
  2444.         mov     si,OFFSET RampIRQ
  2445.  
  2446.         mov     al,CurVoice
  2447.         push    ax
  2448.  
  2449. CheckForIRQ:
  2450.         mov     dx,GUS_Command
  2451.         mov     al,08Fh                ; select read IRQ source register
  2452.         out     dx,al
  2453.  
  2454.         add     dx,2                   ; GUS_DataLow
  2455.         in      al,dx                  ; get the number of voice sending IRQ
  2456.                                        ; plus the type of IRQ
  2457.         mov     cl,al
  2458.         mov     ch,cl
  2459.         movzx   bx,al                  ; IRQ status in cl and bl
  2460.  
  2461. ;        call    PrintHexByte           ; print register contents
  2462.  
  2463.         and     cl,10000000b           ; isolate WaveIRQ bit
  2464.         and     ch,01000000b           ; isolate RampIRQ bit
  2465.         and     bl,00011111b           ; remove bits 7-5 to get voice #
  2466.  
  2467.         or      cl,cl
  2468.         jnz     NextTest               ; if set, no wavetable IRQ
  2469.         jmp     WaveTableIRQ
  2470.  
  2471. NextTest:
  2472.         or      ch,ch
  2473.         jnz     IRQExit                ; if set then no Ramp IRQ either, exit
  2474.         jmp     FixRampIRQ             ; not set, so fix Ramp IRQ
  2475.  
  2476. WaveTableIRQ:
  2477.         cmp     byte ptr cs:[di + bx],0; check table to see if we've
  2478.         jne     AlreadyServiced        ; serviced this voice already
  2479.                                        ; if yes then check for Ramp IRQs
  2480.         mov     byte ptr cs:[di + bx],1; put 1 in table so we'll know
  2481.                                        ; we've already serviced it
  2482.  
  2483. ;        mov     al,0FFh
  2484. ;        call    PrintHexByte           ; print register contents
  2485.  
  2486.         mov     al,bl                  ; get voice number in al
  2487.         SelectVoice                    ; change to voice #
  2488.  
  2489.         ; turn the voice off so it will stop generating IRQs
  2490.  
  2491.         call    StopVoice
  2492.  
  2493.         ; set the voice pointer to start location
  2494.  
  2495.          jmp     TestForRamp
  2496.  
  2497. AlreadyServiced:
  2498. ;        mov     al,0FDh
  2499. ;        call    PrintHexByte           ; print register contents
  2500.  
  2501.         ; test to see if there is a ramp IRQ
  2502.  
  2503. TestForRamp:
  2504.         or      ch,ch
  2505.         jnz     CheckForIRQ             ; no ramp IRQ so check for another
  2506.                                         ; IRQ
  2507. FixRampIRQ:
  2508.         ; stop the ramp from generating an IRQ
  2509.  
  2510.         cmp     byte ptr cs:[si + bx],0; check table to see if we've
  2511.         jne     CheckForIRQ            ; serviced this voice already
  2512.                                        ; if yes then check for other IRQs
  2513.         mov     byte ptr cs:[si + bx],1; put 1 in table so we'll know
  2514.                                        ; we've already serviced it
  2515.         mov     al,0FEh
  2516.         call    PrintHexByte           ; print register contents
  2517.  
  2518.         mov     al,bl
  2519.         SelectVoice
  2520.  
  2521.         call    StopRamp
  2522.         jmp     CheckForIRQ            ; check for IRQ's on other voices
  2523.  
  2524. IRQExit:
  2525. ;        mov     al,07Fh
  2526. ;        call    PrintHexByte           ; print register contents
  2527.  
  2528.         mov     ax,cs
  2529.         mov     es,ax
  2530.         mov     di,OFFSET EndIRQ       ; zero tables before leaving int
  2531.         mov     cx,32                  ; 64 bytes / 2 = 32
  2532.         xor     ax,ax                  ; store a zero
  2533.         rep     stosw
  2534.  
  2535.         mov     ax,GUS_IRQ
  2536.         cmp     ax,07
  2537.         jg      HiIRQ
  2538.  
  2539.         mov     al,20h                 ; clear primary PIC
  2540.         out     20h,al
  2541.  
  2542.       HiIRQ:
  2543.         mov     al,20h
  2544.         out     0A0h,al                ; clear secondary PIC
  2545.  
  2546.         pop     ax                     ; restore old current voice
  2547.         SelectVoice
  2548.  
  2549.       IRQDone:
  2550.         popf
  2551.         pop     di
  2552.         pop     si
  2553.         pop     es
  2554.         pop     ds
  2555.         pop     dx
  2556.         pop     cx
  2557.         pop     bx
  2558.         pop     ax
  2559.  
  2560.         pushf
  2561.         call    OldIRQInt
  2562.  
  2563.         iret
  2564.  
  2565. IRQInt  ENDP
  2566.  
  2567. ;══════════════════════════════════════════════════════════════════════
  2568. ; al = bits 0-3 nibble to print
  2569.  
  2570. CurX    DB      0
  2571. CurY    DB      0
  2572. CurAttr DB      1Fh
  2573. OldX    DB      0
  2574. OldY    DB      0
  2575.  
  2576. PrintNibble     PROC
  2577.  
  2578.         push    ax
  2579.         push    bx
  2580.         push    cx
  2581.         push    dx
  2582.  
  2583.         cmp     cs:[CurX],72
  2584.         jle     NoChangeX
  2585.         mov     cs:[CurX],0
  2586.  
  2587.       NoChangeX:
  2588.         push    ax
  2589.         mov     ah,02h
  2590.         xor     bh,bh
  2591.         mov     dh,cs:[CurY]
  2592.         mov     dl,cs:[CurX]
  2593.         int     10h
  2594.         pop     ax
  2595.  
  2596.         and     al,00001111b           ; clear the top four bits of byte
  2597.  
  2598.         cmp     al,0Ah
  2599.         jge     IsLetter
  2600.  
  2601.         add     al,30h                 ; add 48d to get ASCII digit
  2602.         jmp     PrintIt
  2603.  
  2604. IsLetter:
  2605.         add     al,37h                 ; add 55d to get ASCII character
  2606.  
  2607. PrintIt:
  2608.         mov     ah,0Eh
  2609.         xor     bx,bx
  2610.  
  2611.         int     10h                    ; output one hex digit
  2612.         inc     cs:[CurX]
  2613.  
  2614.         pop     dx
  2615.         pop     cx
  2616.         pop     bx
  2617.         pop     ax
  2618.  
  2619.         ret
  2620.  
  2621. PrintNibble     ENDP
  2622.  
  2623. ;══════════════════════════════════════════════════════════════════════
  2624. ; al = byte to print in hex
  2625.  
  2626. PrintHexByte    PROC
  2627.  
  2628.         push    ax
  2629.         push    bx
  2630.         push    cx
  2631.  
  2632.         mov     ah,al
  2633.         shr     al,4
  2634.         call    PrintNibble
  2635.  
  2636.         mov     al,ah
  2637.         call    PrintNibble
  2638.  
  2639.         mov     ax,0E20h
  2640.         xor     bx,bx
  2641.         int     10h                    ; output a space
  2642.         inc     cs:[CurX]
  2643.  
  2644.         pop     cx
  2645.         pop     bx
  2646.         pop     ax
  2647.  
  2648.         ret
  2649.  
  2650. PrintHexByte    ENDP
  2651.  
  2652. ;══════════════════════════════════════════════════════════════════════
  2653. ; al = byte to print in binary
  2654.  
  2655. PrintBinByte    PROC
  2656.  
  2657.         push    ax
  2658.         push    bx
  2659.         push    cx
  2660.         push    dx
  2661.  
  2662.         cmp     cs:[CurX],72
  2663.         jle     LeaveX
  2664.         mov     cs:[CurX],0
  2665.  
  2666.       LeaveX:
  2667.         mov     ah,03h                  ; get cursor position
  2668.         xor     bh,bh
  2669.         int     10h
  2670.  
  2671.         mov     OldX,dl            ; save cursor position
  2672.         mov     OldY,dh
  2673.  
  2674.         mov     dx,ax
  2675.  
  2676.         mov     cx,9
  2677.  
  2678. BinLoop1:
  2679.         rcl     dl,1
  2680.         jc      Print1
  2681.  
  2682.         mov     al,30h
  2683.         jmp     PrintOneBit
  2684.  
  2685. Print1:
  2686.         mov     al,31h
  2687.  
  2688. PrintOneBit:
  2689.         push    ax
  2690.         mov     ah,02h
  2691.         xor     bh,bh
  2692.         mov     dh,cs:[CurY]
  2693.         mov     dl,cs:[CurX]
  2694.         int     10h
  2695.         inc     cs:[CurX]
  2696.         pop     ax
  2697.  
  2698.         push    cx
  2699.         mov     ah,09h
  2700.         movzx   bx,CurAttr
  2701.         mov     cx,1
  2702.         int     10h
  2703.         pop     cx
  2704.  
  2705.         loop    BinLoop1
  2706.  
  2707.         mov     ax,0E20h
  2708.         mov     bx,16
  2709.         int     10h                    ; output a space
  2710.         inc     cs:[CurX]
  2711.  
  2712.         mov     ah,02h                 ; restore old cursor position
  2713.         xor     bh,bh
  2714.         mov     dh,OldY
  2715.         mov     dl,OldX
  2716.         int     10h
  2717.  
  2718.         add     CurAttr,10h
  2719.         cmp     CurAttr,08Fh
  2720.         jne     NoReset
  2721.  
  2722.         mov     CurAttr,1Fh
  2723.  
  2724.       NoReset:
  2725.         pop     dx
  2726.         pop     cx
  2727.         pop     bx
  2728.         pop     ax
  2729.  
  2730.         ret
  2731.  
  2732. PrintBinByte    ENDP
  2733.  
  2734. ;══════════════════════════════════════════════════════════════════════
  2735. ;si = offset of string
  2736.  
  2737. Write   PROC
  2738.  
  2739.         push    ax
  2740.         push    bx
  2741.         push    dx
  2742.         push    si
  2743.  
  2744. CheckCursor:
  2745.         cmp     cs:[CurX],60
  2746.         jle     MoveCursor
  2747.         mov     cs:[CurX],0
  2748.  
  2749. MoveCursor:
  2750.         mov     ah,02h
  2751.         xor     bh,bh
  2752.         mov     dh,cs:[CurY]
  2753.         mov     dl,cs:[CurX]
  2754.         int     10h
  2755.  
  2756. WriteLoop:
  2757.         mov     al,cs:[si]
  2758.         cmp     al,0
  2759.         je      ExitWrite
  2760.  
  2761.         mov     ah,0Eh
  2762.         mov     bx,16
  2763.         int     10h
  2764.         inc     si
  2765.         inc     cs:[CurX]
  2766.         jmp     WriteLoop
  2767.  
  2768. ExitWrite:
  2769.         pop     si
  2770.         pop     dx
  2771.         pop     bx
  2772.         pop     ax
  2773.  
  2774.         ret
  2775.  
  2776. Write   ENDP
  2777.  
  2778. ;══════════════════════════════════════════════════════════════════════
  2779.  
  2780. MaxTrax DB      0
  2781. DataPos DD      0
  2782. RecCnt  DB      0
  2783.  
  2784. UpdateChanRecs  PROC
  2785.  
  2786.         inc     RecCnt
  2787.         cmp     RecCnt,2
  2788.         jge     DoUpdate
  2789.  
  2790.         ret
  2791.  
  2792. DoUpdate:
  2793.         mov     RecCnt,0
  2794.  
  2795.         les     di,[MODData]            ; segment:offset of MOD data
  2796.         mov     al,es:[di + 2011]       ; number of channels
  2797.         mov     MaxTrax,al
  2798.  
  2799.         mov     cl,0
  2800.         mov     bx,OFFSET ChannelInfo
  2801.  
  2802. UpdateLoop0:
  2803.         mov     al,cl
  2804.         SelectVoice
  2805.  
  2806.         cmp     byte ptr ds:[bx],0
  2807.         je      VoiceIsOff
  2808.  
  2809.         mov     al,cl
  2810.         call    ReadVoiceMode           ; get the voice mode byte in ah and al
  2811.  
  2812.         test    al,1                    ; if voice is stopped don't jump
  2813.         jz      VoiceIsPlaying
  2814.  
  2815. VoiceIsOff:
  2816.         ; store 0 in Channel Volume
  2817.         inc     bx
  2818.         mov     byte ptr ds:[bx],0
  2819.  
  2820.         ; store   0 in Channel Hit
  2821.         inc     bx
  2822.         mov     byte ptr ds:[bx],0
  2823.  
  2824.         add     bx,81                   ; move bx to next channel record
  2825.  
  2826.         inc     cl
  2827.         cmp     cl,MaxTrax
  2828.         jl      UpdateLoop0
  2829.  
  2830.         ret
  2831.  
  2832. VoiceIsPlaying:
  2833. ;        call    ReadVoicePos
  2834.  
  2835. ;        push    bx
  2836. ;        push    cx
  2837.  
  2838. ;        mov     bx,dx
  2839. ;        mov     cx,ax
  2840. ;        mov     word ptr cs:[DataPos],cx
  2841. ;        mov     word ptr cs:[DataPos + 2],bx
  2842.  
  2843. ;        call    Peek
  2844.  
  2845. ;        pop     cx
  2846. ;        pop     bx
  2847.  
  2848.         inc     bx
  2849.         mov     byte ptr ds:[bx],0      ; put "volume" in ChannelVolume
  2850.  
  2851.         inc     bx
  2852.         cmp     byte ptr ds:[bx],0
  2853.         je      HitIsZero
  2854.  
  2855.         dec     byte ptr ds:[bx]        ; decrement ChannelHit counter
  2856.  
  2857. HitIsZero:
  2858.         add     bx,81                   ; point to Wave array
  2859.  
  2860.         inc     cl
  2861.         cmp     cl,MaxTrax
  2862.         jl      UpdateLoop0
  2863.  
  2864.         ret
  2865.  
  2866. UpdateChanRecs  ENDP
  2867.  
  2868. ;══════════════════════════════════════════════════════════════════════
  2869.  
  2870. UpdateWaves     PROC
  2871.  
  2872.         mov     cl,0
  2873.         mov     bx,OFFSET ChannelInfo
  2874.  
  2875. UpdateLoop1:
  2876.         mov     al,cl
  2877.         SelectVoice
  2878.  
  2879.         cmp     byte ptr ds:[bx],0
  2880.         je      WaveVoiceIsOff
  2881.  
  2882.         mov     al,cl
  2883.         call    ReadVoiceMode           ; get the voice mode byte in ah and al
  2884.  
  2885.         test    al,1                    ; if voice is stopped don't jump
  2886.         jz      WaveVoiceIsPlaying
  2887.  
  2888. WaveVoiceIsOff:
  2889.         add     bx,3
  2890.  
  2891.         push    cx                      ; store a flat line in this voice's
  2892.                                         ; wave or we'll see data that's after
  2893.                                         ; the end of the current instrument
  2894.         cld
  2895.  
  2896.         mov     ax,ds
  2897.         mov     es,ax
  2898.         mov     di,bx
  2899.  
  2900.         mov     eax,0
  2901.         mov     cx,20
  2902.         rep     stosd
  2903.  
  2904.         pop     cx
  2905.  
  2906.         add     bx,80                   ; move bx to next channel record
  2907.  
  2908.         inc     cl
  2909.         cmp     cl,4
  2910.         jl      UpdateLoop1
  2911.  
  2912.         ret
  2913.  
  2914. WaveVoiceIsPlaying:
  2915.         call    ReadVoicePos
  2916.  
  2917.         push    bx
  2918.         push    cx
  2919.  
  2920.         mov     bx,dx
  2921.         mov     cx,ax
  2922.         mov     word ptr cs:[DataPos],cx
  2923.         mov     word ptr cs:[DataPos + 2],bx
  2924.  
  2925.         pop     cx
  2926.         pop     bx
  2927.  
  2928.         add     bx,3                    ; point to Wave array
  2929.  
  2930.         push    cx
  2931.  
  2932.         mov     cx,80
  2933.  
  2934. WaveLoop:
  2935.         mov     dx,GUS_Command
  2936.         mov     al,43h
  2937.         out     dx,al
  2938.  
  2939.         mov     dx,GUS_DataLo
  2940.         mov     ax,word ptr cs:[DataPos]
  2941.         out     dx,ax
  2942.  
  2943.         mov     dx,GUS_Command
  2944.         mov     al,44h
  2945.         out     dx,al
  2946.  
  2947.         mov     dx,GUS_DataHi
  2948.         mov     al,byte ptr cs:[DataPos + 2]
  2949.         out     dx,al
  2950.  
  2951.         mov     dx,GUS_DRAMIO
  2952.         in      al,dx
  2953.  
  2954.         inc     DataPos
  2955.  
  2956.         mov     byte ptr ds:[bx],al
  2957.         inc     bx
  2958.  
  2959.         dec     cx
  2960.         jnz     WaveLoop
  2961.  
  2962.         pop     cx
  2963.  
  2964.         inc     cl
  2965.         cmp     cl,4
  2966.         jl      UpdateLoop1
  2967.  
  2968.         ret
  2969.  
  2970. UpdateWaves     ENDP
  2971.  
  2972. ;══════════════════════════════════════════════════════════════════════
  2973.  
  2974. MajorTick       DW      0               ; tick occurs every 20 of these
  2975. TickCnt         DW      0               ; tracks the time till next pat line
  2976. WaveTick        DW      0               ; tracks occurance of wave updates
  2977. OldCnt          DW      0               ; keeps the original int 08 interrupt time
  2978. LineOfs         DW      0
  2979. CurChannel      DB      0               ; current channel being processed
  2980. LastVoice       DB      0               ; save variable for CurVoice
  2981. NumPats         DW      0
  2982. EndJumpPos      DW      0
  2983. JumpToPat       DW      0FFh            ; pattern to jump to after cur line
  2984. JumpToLine      DW      0FFh            ; line to jump to in pattern
  2985. ChannelVol      DB      41h
  2986.  
  2987. ;══════════════════════════════════════════════════════════════════════
  2988. ; handles all the timing for playing the current MOD file
  2989. ; expects the int 08 interrupt rate to be 1001 times per second (55 * 18.2)
  2990. ; OrigRate is the rate that the old interrupt 8 was called
  2991. ;══════════════════════════════════════════════════════════════════════
  2992.  
  2993. MODInt8 PROC    FAR
  2994.  
  2995.         push    ax                      ; save original registers
  2996.         push    bx
  2997.         push    cx
  2998.         push    dx
  2999.         push    ds
  3000.         push    es
  3001.         push    si
  3002.         push    di
  3003.         push    gs
  3004.         pushf                           ; save original flags
  3005.  
  3006.         mov     ax,DATA
  3007.         mov     ds,ax
  3008.  
  3009.         mov     al,CurVoice
  3010.         mov     LastVoice,al
  3011.  
  3012.         cmp     MODPlaying,0
  3013.         jne     CheckTick               ; if mod is playing then jump
  3014.         jmp     NoMODTick
  3015.  
  3016. ; mod player stuff starts here
  3017.  
  3018. CheckTick:
  3019.         call    UpdateChanRecs
  3020.  
  3021.         inc     MajorTick               ; this makes sure a 'tick' happens
  3022.         cmp     MajorTick,19            ; only 50 times per second
  3023.         jge     TickOccurred
  3024.         jmp     NoMODTick
  3025.  
  3026. TickOccurred:
  3027.         cmp     UpdateChannelWaves,0
  3028.         je      NoWaveUpdate
  3029.  
  3030.         inc     WaveTick
  3031.         cmp     WaveTick,3              ; wave updates only 16 time / sec
  3032.         jl      NoWaveUpdate            ; cause Gravis I/O is slow
  3033.  
  3034.         mov     WaveTick,0
  3035.  
  3036.         call    UpdateWaves
  3037.  
  3038. NoWaveUpdate:
  3039.         mov     MajorTick,0
  3040.  
  3041.         inc     TickCnt
  3042.         mov     ax,TickCnt
  3043.         cmp     ax,MODSpeed             ; if TickCount = MODSpeed then
  3044.         jge     DoSomething
  3045.         jmp     NoMODTick
  3046.  
  3047. DoSomething:
  3048.         mov     TickCnt,0
  3049.  
  3050. ; begin processing the current line of the mod
  3051.  
  3052.         mov     CurChannel,0
  3053.         les     di,[MODData]            ; segment:offset of MOD data
  3054.  
  3055.         mov     bx,CurPattern
  3056.         shl     bx,2                    ; curpattern * 4
  3057.         add     bx,di                   ; offset to PatternPtr
  3058.         add     bx,PatternOfs           ; skip over instrument info
  3059.         mov     si,word ptr es:[bx]     ; offset of current pattern data
  3060.         mov     ax,es:[bx + 2]          ; segment of current pattern data
  3061.         mov     gs,ax                   ; gs:si seg:ofs of cur pattern data
  3062.         mov     ax,PatLineSize
  3063.         mul     CurLine
  3064.         add     si,ax                   ; si = offset of current pattern line
  3065.         mov     LineOfs,si
  3066.  
  3067. ProcessChannel:
  3068.         mov     al,CurChannel           ; al = voice number
  3069.         SelectVoice                     ; select voice number 0-maxtracks - 1
  3070.  
  3071. ProcessEffect:
  3072.         mov     si,LineOfs              ; restore offset to cur channel's note
  3073.         mov     ChannelVol,65           ; flag\var for volume changes
  3074.         mov     bx,gs:[si + 3]          ; effect number in bl, arg in bh
  3075.         mov     cl,bh                   ; effect arg in cl
  3076.         xor     bh,bh                   ; now bx will address jump table
  3077.  
  3078.         cmp     bl,0
  3079.         jne     GoToEffect
  3080.  
  3081. CheckAppregio:
  3082.         cmp     cl,0                    ; appregio only if arg is <> 0
  3083.         jne     GoToEffect
  3084.         jmp     PlayNote
  3085.  
  3086.         ; come here ONLY if there is an effect to be played
  3087. GoToEffect:
  3088.         shl     bx,1
  3089.         jmp     word ptr EffectJumps [bx]
  3090.  
  3091. DoAppregio:
  3092.         jmp     PlayNote
  3093.  
  3094. DoSlideUp:
  3095.         jmp     PlayNote
  3096.  
  3097. DoSlideDown:
  3098.         jmp     PlayNote
  3099.  
  3100. DoTonePortamento:
  3101.         jmp     PlayNote
  3102.  
  3103. DoVibrato:
  3104.         jmp     PlayNote
  3105.  
  3106. DoToneVolSlide:
  3107.         jmp     PlayNote
  3108.  
  3109. DoVibVolSlide:
  3110.         jmp     PlayNote
  3111.  
  3112. DoTremolo:
  3113.         jmp     PlayNote
  3114.  
  3115. DoNotUsed:
  3116.         jmp     PlayNote
  3117.  
  3118. DoSetSampleOffs:
  3119.         jmp     PlayNote
  3120.  
  3121. DoVolumeSlide:
  3122.         jmp     PlayNote
  3123.  
  3124. DoPositionJump:
  3125.         xor     ch,ch
  3126.         mov     JumpToPat,cx
  3127.         mov     CurLine,63             ; forces a pattern change after line
  3128.  
  3129.         jmp     PlayNote
  3130.  
  3131. DoSetVolume:
  3132.         cmp     cl,64
  3133.         ja      DoSetFlag
  3134.  
  3135.         mov     ChannelVol,cl
  3136.         mov     bh,01
  3137.         mov     bl,cl
  3138.         call    MODSetVol
  3139.  
  3140. ; set ChannelHit in channel Record, this variable is used to do spectrum
  3141. ; analyzer bar stuff, basically
  3142.         shl     cl,1
  3143.         mov     bl,CurChannel
  3144.         mov     ax,ChannelInfoSize
  3145.         mul     bl
  3146.         mov     bx,ax
  3147.         mov     byte ptr ds:[OFFSET ChannelInfo + 2 + bx],cl
  3148.  
  3149.         jmp     PlayNote
  3150.  
  3151. DoSetFlag:
  3152.         sub     cl,65                   ; subtract 65 from effect arg
  3153.         mov     MODFlag,cl              ; and store it in MODFlag
  3154.  
  3155.         jmp     PlayNote
  3156.  
  3157. DoPatternBreak:
  3158.         mov     bl,cl
  3159.         shr     bl,4
  3160.         mov     ax,10
  3161.         mul     bl                      ; ax = 10 * upper nibble of effect arg
  3162.  
  3163.         and     cl,00001111b            ; cx = zeroed upper nibble of effect arg
  3164.         xor     ch,ch
  3165.         add     cl,al                   ; cl = (10 * upper nibble) + (lower nibble)
  3166.         mov     JumpToLine,cx           ; line to jump to in next pattern
  3167.         mov     CurLine,63              ; forces a pattern change after line
  3168.  
  3169.         jmp     PlayNote
  3170.  
  3171. DoExtended:
  3172.         jmp     PlayNote
  3173.  
  3174. DoSetSpeed:
  3175.         xor     ch,ch
  3176.         mov     MODSpeed,cx
  3177.  
  3178. PlayNote:
  3179. ; determine if this channel is on or off
  3180.  
  3181.         movzx   bx,CurChannel
  3182.         mov     ax,ChannelInfoSize
  3183.         mul     bl
  3184.         mov     bx,ax
  3185.         cmp     byte ptr ds:[OFFSET ChannelInfo + bx],0
  3186.         jne     ChannelIsOn
  3187.         jmp     NextChannel
  3188.  
  3189. ChannelIsOn:
  3190.         mov     si,LineOfs              ; restore offset to cur channel's note
  3191.         mov     dl, byte ptr gs:[si]
  3192.         cmp     dl,0                    ; dl = instrument number + 1
  3193.         je      NextChannel
  3194.  
  3195. ; determine voice frequency
  3196.         call    StopVoice
  3197.  
  3198.         mov     bx,gs:[si + 1] ; voice period in bx
  3199.         shl     bx,1
  3200.         mov     ax,cs:[OFFSET FreqTable + bx]
  3201.         mov     bx,ax
  3202.         call    NoteFreq
  3203.  
  3204.         movzx   cx, byte ptr gs:[si]
  3205.         dec     cl                      ; cl = instrument #
  3206.         mov     ax,44
  3207.         mul     cl
  3208.         mov     si,ax                   ; offset to instrument record
  3209.         add     si,di                   ; is now in si
  3210.  
  3211.         mov     ebx,es:[si]             ; eax = location of sample in GUS RAM
  3212.  
  3213.         mov     cx,bx
  3214.         shr     ebx,16                  ; bx:cx = longint sample location
  3215.         call    VoiceStartAddr          ; set current address of voice
  3216.  
  3217.         mov     dx,word ptr es:[si + 19]; repeat length
  3218.         cmp     dx,2
  3219.         jg      LoopInstr
  3220.  
  3221. ; set up the voice for no looping (i.e. play entire sample only once)
  3222.         call    LoopStartAddr
  3223.  
  3224.         mov     eax,es:[si + 9]         ; eax = length of sample
  3225.         mov     ebx,es:[si]             ; ebx = location of sample in GUS RAM
  3226.         dec     eax                     ; subtract one from length
  3227.         add     ebx,eax                 ; add length to location
  3228.  
  3229.         mov     cx,bx
  3230.         shr     ebx,16                  ; bx:cx = end address of voice
  3231.  
  3232.         call    LoopEndAddr             ; set end address of voice
  3233.  
  3234.         jmp     StartSample
  3235.  
  3236. LoopInstr:
  3237.         mov     eax,es:[si]             ; eax = location of sample in GUS RAM
  3238.         movzx   ebx,word ptr es:[si + 17]; bx = loop start addres DIV 2
  3239.         shl     ebx,1                   ; * 2 for loop start
  3240.         add     ebx,eax                 ; ebx = loop start in GUS RAM
  3241.  
  3242.         push    ebx
  3243.  
  3244.         mov     cx,bx                   ; put lower offset in cx
  3245.         shr     ebx,16                  ; shift upper into bx
  3246.         call    LoopStartAddr           ; set start address of voice
  3247.  
  3248.         movzx   ebx,word ptr es:[si + 19]; bx = length of loop DIV 2
  3249.         shl     ebx,1                   ; * 2 for loop length
  3250.         dec     ebx                     ;
  3251.  
  3252.         pop     eax
  3253.         add     ebx,eax                 ; eax = loop start + loop length
  3254.  
  3255.         mov     cx,bx
  3256.         shr     ebx,16                  ; bx:cx = loop end location
  3257.         call    LoopEndAddr             ; set end address of voice
  3258.  
  3259. StartSample:
  3260.         ; is this sample's data length = 0 bytes?
  3261.         cmp     dword ptr es:[si + 9],0
  3262.         jne     InstrumentNotDummy
  3263.  
  3264.         ; sample is 0 bytes, so set volume to 0 and stop the voice
  3265.         call    StopVoice
  3266.  
  3267.         jmp     NextChannel
  3268.  
  3269. InstrumentNotDummy:
  3270. ; set ChannelHit in channel Record, this variable is used to do spectrum
  3271. ; analyzer bar stuff, basically
  3272. ;        mov     bl,CurChannel
  3273. ;        mov     ax,83
  3274. ;        mul     bl
  3275. ;        mov     bx,ax
  3276. ;        mov     byte ptr ds:[OFFSET ChannelInfo + 2 + bx],127
  3277.  
  3278. ; set voice mode, start playing
  3279.         mov     ah,00000000b
  3280.  
  3281.         mov     bx,word ptr es:[si + 19]; repeat length
  3282.         cmp     bx,2
  3283.         jle     IRQBitSet               ; if no looping then jump
  3284.  
  3285.         mov     ah,GUS_Loop             ; if looping, then turn off IRQs
  3286.                                         ; for this channel
  3287.  
  3288. IRQBitSet:
  3289.         call    VoiceMode
  3290.  
  3291.         cmp     ChannelVol,65
  3292.         jne     VolumeAlreadySet        ; volume was already set by an
  3293.                                         ; effect so skip volume set here
  3294.         mov     bh,1
  3295.         mov     bl,byte ptr es:[si + 16]; bl = sample's default volume
  3296.  
  3297.         call    MODSetVol
  3298.  
  3299. ; set ChannelHit in channel Record, this variable is used to do spectrum
  3300. ; analyzer bar stuff, basically
  3301.         mov     cl,bl
  3302.         shl     cl,1
  3303.         mov     bl,CurChannel
  3304.         mov     ax,83
  3305.         mul     bl
  3306.         mov     bx,ax
  3307.         mov     byte ptr ds:[OFFSET ChannelInfo + 2 + bx],cl
  3308.  
  3309. VolumeAlreadySet:
  3310.         ; start the voice playing
  3311.         call    MODStartVoice
  3312.  
  3313. NextChannel:
  3314.         inc     CurChannel
  3315.         mov     al,CurChannel
  3316.         cmp     al,Channels
  3317.         jge     FinishedLine
  3318.  
  3319.         add     LineOfs,NoteSize        ; go to next channel note
  3320.         jmp     ProcessChannel
  3321.  
  3322. FinishedLine:
  3323. ; finished processing current line of the mod
  3324.  
  3325.         inc     CurLine                 ; finished # of ticks so go to
  3326.         cmp     CurLine,64              ; the next line in the pattern
  3327.         jl      SkipPatternChange
  3328.  
  3329.         ; finished 64 lines so go to the next pattern
  3330.  
  3331.         cmp     JumpToLine,0FFh         ; if not 0FFh then a pattern break
  3332.         je      NoPatternBreak          ; was specified
  3333.  
  3334.         mov     ax,JumpToLine
  3335.         mov     CurLine,ax
  3336.         mov     JumpToLine,0FFh
  3337.         jmp     PatternBreak
  3338.  
  3339. NoPatternBreak:
  3340.         mov     CurLine,0
  3341.  
  3342. PatternBreak:
  3343.         mov     ax,NumPats
  3344.  
  3345.         cmp     JumpToPat,0FFh          ; if not 0FFh then a position jump
  3346.         je      NoPositionJump          ; was specified
  3347.  
  3348.         mov     bx,JumpToPat
  3349.         mov     ScriptPos,bx
  3350.         mov     JumpToPat,0FFh          ; reset so pattern jumps don't keep
  3351.         jmp     SongNotOver             ; occurring
  3352.  
  3353. NoPositionJump:
  3354.         inc     ScriptPos
  3355.         cmp     ScriptPos,ax
  3356.         jl      SongNotOver
  3357.  
  3358.         mov     ax,EndJumpPos
  3359.         cmp     ax,127
  3360.         jne     RestartSong
  3361.  
  3362.         mov     MODPlaying,0
  3363.         call    SetUpMOD
  3364.         jmp     SkipPatternChange
  3365.  
  3366. RestartSong:
  3367.         mov     ScriptPos,ax
  3368.  
  3369. SongNotOver:
  3370.         mov     bx,ScriptOfs
  3371.         add     bx,ScriptPos
  3372.         movzx   ax,byte ptr es:[di + bx]
  3373.         mov     CurPattern,ax
  3374.  
  3375. SkipPatternChange:
  3376.  
  3377. NoMODTick:
  3378.         inc     OldCnt
  3379.         mov     ax,OldCnt
  3380.         cmp     ax,OrigRate
  3381.         jl      SkipOrigInt
  3382.  
  3383.         mov     OldCnt,0
  3384.  
  3385.         pushf
  3386.         call    dword ptr ds:[PreMODInt8]
  3387.  
  3388. SkipOrigInt:
  3389.         mov     al,LastVoice            ; set the Current Voice back to what
  3390.         SelectVoice                     ; it was so other routines aren't
  3391.                                         ; screwed up
  3392.  
  3393.         mov     al,20h                  ; reset PIC
  3394.         out     20h,al
  3395.  
  3396.         popf                            ; restore original flags
  3397.         pop     gs
  3398.         pop     di                      ; restore original registers
  3399.         pop     si
  3400.         pop     es
  3401.         pop     ds
  3402.         pop     dx
  3403.         pop     cx
  3404.         pop     bx
  3405.         pop     ax
  3406.  
  3407.         iret
  3408.  
  3409. MODInt8 ENDP
  3410.  
  3411. ;══════════════════════════════════════════════════════════════════════
  3412.  
  3413. TempBal DB      0
  3414.  
  3415. SetUpMOD        PROC
  3416.  
  3417.         mov     CurLine,0
  3418.         mov     ScriptPos,0
  3419.         mov     TickCnt,0
  3420.         mov     MODSpeed,6
  3421.  
  3422.         ; get first pattern # from script
  3423.         les     di,[MODData]
  3424.         mov     bx,ScriptOfs
  3425.         movzx   ax,byte ptr es:[di + bx]
  3426.         mov     CurPattern,ax
  3427.  
  3428.         add     bx,128                  ; NumPats
  3429.         mov     al,es:[di + bx]
  3430.         xor     ah,ah
  3431.         mov     cs:[NumPats],ax
  3432.  
  3433.         inc     bx
  3434.         mov     al,es:[di + bx]
  3435.         mov     cs:[EndJumpPos],ax
  3436.  
  3437.         ; turn all the channels on
  3438.         mov     ds:[OFFSET ChannelInfo],1
  3439.         mov     ds:[OFFSET ChannelInfo + 83],1
  3440.         mov     ds:[OFFSET ChannelInfo + 166],1
  3441.         mov     ds:[OFFSET ChannelInfo + 249],1
  3442.  
  3443.         mov     TempBal,2
  3444.  
  3445.         les     di,[MODData]            ; segment:offset of MOD data
  3446.         mov     al,es:[di + 2011]       ; number of channels
  3447.         mov     MaxTrax,al
  3448.         mov     bx,OFFSET ChannelInfo
  3449.         mov     cl,0
  3450.  
  3451. SetUpVoiceLoop:
  3452.         mov     al,cl
  3453.         SelectVoice
  3454.  
  3455.         push    cx
  3456.         push    bx
  3457.  
  3458.         mov     cx,0FFF0h
  3459.         mov     bx,0FFF0h
  3460.         call    RampVolume
  3461.  
  3462.         xor     bx,bx
  3463.         call    RampRate
  3464.  
  3465.         mov     bl,3
  3466.         call    VolControl
  3467.  
  3468.         mov     bx,0140h
  3469.         call    MODSetVol
  3470.  
  3471.         movzx   bx,TempBal
  3472.         call    VoiceBalance
  3473.         cmp     TempBal,13
  3474.         jne     SetBalRight
  3475.  
  3476.         mov     TempBal,2
  3477.         jmp     SetBalLeft
  3478.  
  3479. SetBalRight:
  3480.         mov     TempBal,13
  3481.  
  3482. SetBalLeft:
  3483.         pop     bx
  3484.         mov     byte ptr ds:[bx],01h    ; channel on
  3485.         mov     byte ptr ds:[bx + 1],00h; channel volume = 0
  3486.         mov     byte ptr ds:[bx + 2],00h; channel hit = 0
  3487.         add     bx,ChannelInfoSize
  3488.  
  3489.         pop     cx
  3490.  
  3491.         inc     cl
  3492.         cmp     cl,MaxTrax
  3493.         jl      SetUpVoiceLoop
  3494.  
  3495.         ret
  3496.  
  3497. SetUpMOD        ENDP
  3498.  
  3499. ;══════════════════════════════════════════════════════════════════════
  3500.  
  3501. GUS_StartMOD    PROC    FAR
  3502.  
  3503.         push    bp
  3504.         mov     bp,sp
  3505.  
  3506.         call    SetUpMOD
  3507.  
  3508.         mov     MODPlaying,1
  3509.  
  3510.         mov     sp,bp
  3511.         pop     bp
  3512.         ret
  3513.  
  3514. GUS_StartMOD    ENDP
  3515.  
  3516. ;══════════════════════════════════════════════════════════════════════
  3517.  
  3518. GUS_ContinueMOD PROC    FAR
  3519.  
  3520.         push    bp
  3521.         mov     bp,sp
  3522.  
  3523.         mov     MODPlaying,1
  3524.  
  3525.         mov     sp,bp
  3526.         pop     bp
  3527.  
  3528.         ret
  3529.  
  3530. GUS_ContinueMOD ENDP
  3531.  
  3532. ;══════════════════════════════════════════════════════════════════════
  3533.  
  3534. GUS_StopMOD     PROC    FAR
  3535.  
  3536.         push    bp
  3537.         mov     bp,sp
  3538.  
  3539.         mov     MODPlaying,0
  3540.  
  3541.         les     di,[MODData]            ; segment:offset of MOD data
  3542.         mov     al,es:[di + 2011]       ; number of channels
  3543.         mov     MaxTrax,al
  3544.         mov     al,0
  3545.  
  3546. StopVoices:
  3547.         SelectVoice
  3548.         call    StopVoice
  3549.  
  3550.         inc     al
  3551.         cmp     al,MaxTrax
  3552.         jne     StopVoices
  3553.  
  3554.         mov     sp,bp
  3555.         pop     bp
  3556.  
  3557.         ret
  3558.  
  3559. GUS_StopMOD     ENDP
  3560.  
  3561. ;══════════════════════════════════════════════════════════════════════
  3562.  
  3563. CODE    ENDS
  3564.  
  3565. END