home *** CD-ROM | disk | FTP | other *** search
/ Dave Lowe: Intro 1 of 2 Adlib / Lowe_Intro1of2Adlib.img / DRIVERS / ADLIB.ASM < prev    next >
Encoding:
Assembly Source File  |  1993-01-22  |  19.0 KB  |  1,129 lines

  1. ;--------------------------------------------------------------------------------
  2. ;
  3. ;AdLib specific routines
  4. ;--------------------------------------------------------------------------------
  5.  
  6. ;--------------------------------------------------------------------------------
  7. ;PlaySongAdLib
  8. ;
  9. ;plays a song from the list
  10. ;after setting up all voices
  11. ;
  12. ;Inputs:
  13. ;
  14. ;ax:    Song No.
  15. ;
  16. ;--------------------------------------------------------------------------------
  17.  
  18. PlaySongAdLib proc near
  19.     sub    al,15        ;seventeen roland files in front
  20.     mov    currentSong,ax
  21.     mov    bx,ax
  22.     shl    bx,1
  23.  
  24. ;transfer song parameters
  25. ;to AdLib driver
  26.     mov    ax,ds
  27.     mov    es,ax
  28.  
  29.     mov    si,SongAdNVoices[bx]
  30.     mov    di,offset ChanNVoices
  31.     mov    cx,8
  32.     rep movsb
  33.  
  34.     mov    si,SongAdCVoices[bx]
  35.     mov    di,offset ChanVoices
  36.     mov    cx,8*4
  37.     rep movsb
  38.     
  39.     mov    si,SongAdPatches[bx]
  40.     mov    di,offset SongV0
  41.     mov    cx,8
  42.     rep movsb
  43.  
  44.     mov    si,SongAdTransp[bx]
  45.     mov    di,offset AdTransposes
  46.     mov    cx,9
  47.     rep movsb
  48.  
  49.     shr    bx,1
  50.     mov    al,SongAdPercs[bx]
  51.     mov    Percussion,al
  52.  
  53. ;initialise AdLib
  54.  
  55.     call    InitAdLib
  56.     call    WriteGlobals
  57.     call    InitAllVoices
  58.  
  59. ;Set up voices for this song
  60.  
  61.     mov    si,offset SongV0
  62.     call    SetUpSongVoices
  63.  
  64.     mov    MusicPlayFlg,0
  65.     call    InstallTimer
  66.  
  67.  
  68.     mov    ax,csongseg1
  69.     mov    es,ax
  70.     mov    si,offset MIDIPlayBuffer1
  71.     mov    bx,CurrentSong
  72.     mov    al,SongTempos[bx]
  73.     xor    ah,ah
  74.     call    PlayMIDIFileAdLib
  75.  
  76.     ret
  77. PlaySongAdLib endp
  78.  
  79. ;--------------------------------------------------------------------------------
  80. ;routines for playing MIDI files on AdLib
  81. ;--------------------------------------------------------------------------------
  82.  
  83. ;--------------------------------------------------------------------------------
  84. ;PlayMIDIFileAdLib
  85. ;
  86. ;Inputs:
  87. ;
  88. ;es:si    pointer to MIDI file start
  89. ;ax    temp beats per min.
  90. ;
  91. ;plays until end of file or 
  92. ;until StopMIDIPlayAdLib is called
  93. ;
  94. ;--------------------------------------------------------------------------------
  95.  
  96. PlayMIDIFileAdLib proc near
  97.     mov    PlaySeg,es
  98.     mov    PlayPtr,si
  99.  
  100.     mov    Tempo,ax
  101.     call    SetTimerTempo
  102.  
  103.     call    ReadMIDIHeader    ;get all header info
  104.  
  105.     mov    si,PlayPtr
  106.     call    GetVarLength    ;get first delay
  107.     mov    ax,10
  108.     mov    PlayPtr,si
  109.  
  110.     mov    cs:EventDelay,1
  111.     mov    MusicPlayFlg,-1
  112.  
  113.     ret
  114. PlayMIDIFileAdLib endp
  115.  
  116. StopMIDIPlayAdLib proc near
  117.     mov    MusicPlayFlg,0
  118.     call    RemoveTimer
  119.     call    AllNotesOff
  120.     call    InitAdLib
  121.     ret
  122. StopMIDIPlayAdLib endp
  123.  
  124. SetTimerTempo proc near
  125.     mul    TicksPQ        ;ticks per min.
  126.     mov    bx,60
  127.     div    bx        ;ticks per second
  128.     mov    bx,ax
  129.     mov    ax,13089    ;1192737Hz basic freq.
  130.     mov    dx,18          
  131.     div    bx
  132.     or     ax,1          
  133.     call    TimerRate    ;set up interrupt rate
  134.     ret
  135. SetTimerTempo endp
  136.  
  137. ;--------------------------------------------------------------------------------
  138. ;EventRoutine:
  139. ;
  140. ;This routine is called after (EventDelay) interrupts
  141. ;
  142. ;returns:
  143. ;
  144. ;ax:    new EventDelay
  145. ;
  146. ;--------------------------------------------------------------------------------
  147.  
  148. EventRoutine proc near
  149.     cmp    MusicPlayFlg,0
  150.     jne    DoEvents
  151.     mov    ax,1        ;not playing yet
  152.     ret
  153. DoEvents:
  154.     cmp    BoardFlg,0
  155.     jne    ContEvents        ;play music on ADLIB BOARD
  156. ;    
  157. ;        must be music or fx on ROLAND                   
  158. ;
  159.     cmp    fx_flag,0
  160.     je    rol_music    
  161.     jmp    rol_fx_driver
  162. rol_music:
  163.     jmp    RolEventRoutine        ;play music on ROLAND BOARD
  164. ContEvents:
  165.  
  166. ;do current event
  167.  
  168.     cld
  169.     mov    es,PlaySeg
  170.     mov    si,PlayPtr
  171.  
  172.     cmp    byte ptr es:[si],080h
  173.     jb    ProcessMIDIEvent    ;using running status
  174.  
  175.     mov    al,es:[si]
  176.     inc    si
  177.  
  178.     cmp    al,0FFh
  179.     jne    NotAMeta
  180.     mov    al,es:[si]    ;Meta event type
  181.     inc    si
  182.     call    ProcessMetaEvent
  183.     cmp    ax,0
  184.     je    JND
  185.     jmp    DoneAMPlay    ;end of track
  186. JND:    jmp    NextDelay
  187. NotAMeta:
  188.  
  189.     cmp    al,0F0h
  190.     jb    NotASE
  191.     call    ProcessSysEx0
  192.     jmp    NextDelay
  193. NotASE:
  194.  
  195.     mov    MIDIStatus,al
  196.  
  197. ProcessMIDIEvent:
  198.     mov    al,MIDIStatus
  199.     mov    bl,al
  200.     and    al,1111b    ;channel
  201.     mov    MIDIChannel,al
  202.     xor    bh,bh
  203.     mov    cl,4
  204.     shr    bx,cl        ;form index
  205.     mov    cl,MIDIDataSizes[bx]
  206.     xor    ch,ch
  207.     mov    MIDIDataSiz,cx
  208.  
  209. ;handle different midi events
  210.  
  211. voff:    cmp    bx,8h    ;note off
  212.     jne    NMidi8
  213.  
  214.     mov    bl,MidiChannel
  215.     xor    bh,bh
  216.  
  217.     cmp    Percussion,0
  218.     je    NoOffPerc
  219.     cmp    bx,9
  220.     jne    NoOffPerc
  221.     jmp    NMidiE    ;no note off for percussion voices
  222. NoOffPerc:
  223.  
  224. ;find which voice carries the note to turn off
  225.  
  226.     mov    cl,ChanNVoices[bx]
  227.     xor    ch,ch
  228.  
  229.     shl    bx,1
  230.     shl    bx,1
  231.     shl    bx,1    ;index into ChanVoices
  232.  
  233.     cmp    cx,0
  234.     jne    VAllocd
  235.     jmp    NMidiE        ;no voices allocated
  236. VAllocd:
  237.     cmp    cx,1
  238.     je    NoOChoice
  239. PolyNOL:
  240.     mov    dl,ChanVoices[bx]
  241.     xor    dh,dh
  242.     mov    di,dx
  243.     mov    dl,VoiceNotes[di]
  244.     cmp    dl,es:[si]    ;is it this note?
  245.     je    GotOffVoice    ;yes it is
  246.     inc    bx
  247.     loop    PolyNOL        ;keep trying
  248. GotOffVoice:
  249.     mov    ax,di        ;this voice
  250.  
  251. UseNoteOff:
  252.     mov    bl,es:[si]
  253.     mov    cl,es:[si+1]
  254.     call    NoteOff
  255.     jmp    NMidiE
  256. NoOChoice:
  257.     mov    al,ChanVoices[bx]    ;the only one
  258.     jmp    UseNoteOff
  259.  
  260.  
  261. NMidi8:
  262. ;**********************
  263.     push ax
  264.     push bx
  265.     inc si
  266.     mov al,es:[si]
  267.     cmp al,0
  268.     jne isnoteon
  269. bkp:    pop bx
  270.     pop ax
  271.     mov bx,8h
  272.     dec si
  273.     jmp voff
  274. isnoteon:
  275.     dec si
  276.     pop bx    
  277.     pop ax
  278.  
  279.     cmp    bx,9h    ;note on
  280.     je    HNoteOn
  281.     jmp    NMidi9
  282. HNoteOn:
  283.  
  284. ;handle polyphony
  285. ;- scan available voices
  286. ;- if none free use earliest played
  287.  
  288.     mov    bl,MidiChannel
  289.     xor    bh,bh
  290.  
  291.     mov    di,bx
  292.     shl    di,1
  293.     inc    MIDIChanCount[di]
  294.  
  295.     cmp    Percussion,0
  296.     je    NoPercMidi
  297.     cmp    bx,9        ;midi channel 10 is percussion channel
  298.     je    HandlePerc
  299. NoPercMidi:
  300.     mov    cl,ChanNVoices[bx]
  301.     xor    ch,ch
  302.  
  303.     shl    bx,1
  304.     shl    bx,1
  305.     shl    bx,1    ;index into ChanVoices
  306.  
  307.     cmp    cx,0
  308.     jne    VNAllocd
  309.     jmp    NMidiE        ;no voices allocated
  310. VNAllocd:
  311.     cmp    cx,1
  312.     je    NoPChoice
  313.     mov    bp,0FFFFh    ;this will contain earliest voice
  314.     xor    ax,ax        ;voice to use
  315. PolyVL:
  316.     mov    dl,ChanVoices[bx]    ;is this voice free?
  317.     xor    dh,dh
  318.     mov    di,dx
  319.     shl    di,1
  320.     mov    dx,VoiceStatus[di]
  321.     cmp    dx,0
  322.     je    GotVoice        ;yes, it's free
  323.     cmp    dx,bp
  324.     jae    NotEarlV
  325.     mov    bp,dx        ;this is earlier
  326.     mov    ax,di
  327. NotEarlV:
  328.     inc    bx
  329.     loop    PolyVL        ;keep trying
  330.     shr    ax,1
  331.     jmp    UseVoice    ;use earliest
  332.  
  333. GotVoice:
  334.     mov    ax,di
  335.     shr    ax,1
  336. UseVoice:
  337. ;    mov    bx,ax
  338. ;    xor    bh,bh
  339. ;    mov    bl,AdTransposes[bx]    ;use transpose
  340.     mov    bl,es:[si]
  341.     mov    cl,es:[si+1]
  342.     push    ax
  343.     push    bx
  344.     push    cx
  345.     call    NoteOff
  346.     pop    cx
  347.     pop    bx
  348.     pop    ax
  349.     call    NoteOn
  350.     jmp    NMidiE
  351.  
  352. NoPChoice:
  353.     mov    al,ChanVoices[bx]    ;the only one
  354.     jmp    UseVoice
  355.  
  356. HandlePerc:
  357. ;deal with percussion sounds
  358.     mov    bl,es:[si]    ;note no.
  359.     sub    bl,35        ;form index
  360.     mov    al,DrumSounds[bx]
  361.     mov    bl,24
  362.     jmp    UseVoice
  363.  
  364. NMidi9:         
  365.     cmp    bx,0Ah    ;note aftertouch
  366.     jne    NMidiA
  367.     jmp    NMidiE
  368. NMidiA:
  369.     cmp    bx,0Bh    ;control change
  370.     jne    NMidiB
  371.     jmp    NMidiE
  372. NMidiB:
  373.     cmp    bx,0Ch    ;program change
  374.     jne    NMidiC
  375.     jmp    NMidiE
  376. NMidiC:
  377.     cmp    bx,0Dh    ;chan. aftertouch
  378.     jne    NMidiD
  379.     jmp    NMidiE
  380. NMidiD:
  381.     cmp    bx,0Eh    ;pitch wheel
  382.     jne    NMidiE
  383.     jmp    NMidiE
  384. NMidiE:
  385.  
  386.     add    si,MIDIDataSiz
  387.  
  388. NextDelay:
  389.  
  390. ;check for end of tune
  391.  
  392.     mov    bx,si
  393.     sub    bx,StartPtr
  394.     cmp    bx,PlayLength
  395.     jae    DoneAMPlay
  396. play_aagain:
  397.     call    GetVarLength    ;get delay to next event
  398.     mov    PlayPtr,si
  399.     ret
  400.  
  401. DoneAMPlay:
  402.     mov    si,startptr
  403.     jmp    play_aagain
  404.  
  405.  
  406.     mov    MusicPlayFlg,0
  407.     mov    ax,1
  408.     ret
  409.  
  410. EventRoutine endp
  411.  
  412. ;--------------------------------------------------------------------------------
  413. ;routines for playing notes on AdLib
  414. ;--------------------------------------------------------------------------------
  415.  
  416. ;--------------------------------------------------------------------------------
  417. ;NoteOn
  418. ;
  419. ;inputs:
  420. ;
  421. ;al:    voice    0-8 in melodic 0-10 in percussion mode
  422. ;bl:    pitch    0-127 midi notes: 60 is Middle C (48 is AdLib mid C)
  423. ;cl:    volume    0-127
  424. ;--------------------------------------------------------------------------------
  425.  
  426. NoteOn proc near
  427.     push    si
  428.     push    es
  429.     xor    ah,ah
  430.     xor    bh,bh
  431.     mov    si,ax
  432.     mov    VoiceVolumes[si],cl
  433.     mov    VoiceNotes[si],bl
  434.     add    bl,AdTransposes[si]
  435.     shl    si,1
  436.     mov    dx,PlayPtr
  437.     mov    VoiceStatus[si],dx    ;flag it on
  438.  
  439.     sub    bx,12    ;adlib pitch = midi pitch-12    
  440.     jge    NoteOK
  441.     xor    bx,bx
  442. NoteOK:
  443.     mov    cx,2000h
  444.     cmp    Percussion,0
  445.     jne    PercNoteOn
  446. NormNoteOn:
  447.     mov    dx,1    ;note on
  448.     call    WriteAdLibFreq
  449.     pop    es
  450.     pop    si
  451.     ret
  452.  
  453. ;deal with percussion voices
  454.  
  455. PercNoteOn:
  456.     cmp    ax,5
  457.     jle    NormNoteOn    ;not a perc
  458.     push    ax
  459.     
  460.     cmp    ax,BD        ;change bass drum freq.
  461.     je    BFreq
  462.  
  463.     cmp    ax,TC        ;can't change TC and HH freq
  464.     je    WrBits
  465.     cmp    ax,HH
  466.     je    WrBits
  467.     cmp    ax,SD        ;influenced by TOM
  468.     je    WrBits
  469.  
  470.     push    ax
  471.     push    bx
  472.     push    cx
  473.     mov    ax,SD
  474.     add    bx,7        ;pitch SD = pitch TOM+7
  475.     mov    dx,0
  476.     call    WriteAdLibFreq
  477.     pop    cx
  478.     pop    bx
  479.     pop    ax
  480.  
  481. BFreq:
  482.     mov    dx,0        ;must be 0 for percussion
  483.     call    WriteAdLibFreq
  484.  
  485. WrBits:    pop    bx
  486.     sub    bx,6        ;get offset
  487.     mov    al,PerckeyOns[bx]    ;bit to set
  488.     or    PercBits,al
  489.     call    WriteAmVibPerc    ;set perc bit
  490.     pop    es
  491.     pop    si
  492.     ret
  493. NoteOn endp
  494.  
  495. ;--------------------------------------------------------------------------------
  496. ;NoteOff
  497. ;
  498. ;inputs:
  499. ;
  500. ;ax:    voice    0-8 in melodic 0-10 in percussion mode
  501. ;bl:    pitch    0-127 midi notes: 60 is Middle C (48 is AdLib mid C)
  502. ;cl:    volume    0-127
  503. ;--------------------------------------------------------------------------------
  504.  
  505. NoteOff proc near
  506.     push    si
  507.     push    es
  508.     xor    ah,ah
  509.     xor    bh,bh
  510.     mov    si,ax
  511.     mov    VoiceVolumes[si],cl
  512.     mov    VoiceNotes[si],bl
  513.     add    bl,AdTransposes[si]
  514.     shl    si,1
  515.     mov    VoiceStatus[si],0    ;flag it off
  516.  
  517.     sub    bx,12    ;adlib pitch = midi pitch-12    
  518.     jge    NoteOKO
  519.     xor    bx,bx
  520. NoteOKO:
  521.     mov    cx,2000h
  522.     xor    dx,dx    ;voice off
  523.     cmp    Percussion,0
  524.     jne    PercNoteOff
  525. NormNoteOff:
  526.     call    WriteAdLibFreq
  527.     pop    es
  528.     pop    si
  529.     ret
  530. PercNoteOff:
  531.     cmp    ax,5
  532.     jle    NormNoteOff    ;not a perc
  533.     mov    bx,ax
  534.     sub    bx,6        ;get offset
  535.     mov    al,PerckeyOns[bx]    ;bit to clear
  536.     not    al
  537.     and    PercBits,al
  538.     call    WriteAmVibPerc    ;clear perc bit
  539.     pop    es
  540.     pop    si
  541.     ret
  542. NoteOff endp
  543.  
  544. ;--------------------------------------------------------------------------------
  545. ;AllNotesOff
  546. ;
  547. ;turns off all voices
  548. ;
  549. ;--------------------------------------------------------------------------------
  550.  
  551. AllNotesOff proc near
  552.     mov    bp,8
  553.     xor    ax,ax
  554.     cmp    Percussion,0
  555.     je    NoteOLp
  556.     mov    bp,10
  557. NoteOLp:
  558.     push    ax
  559.     push     bp
  560.     call    NoteOff
  561.     pop    bp
  562.     pop    ax
  563.     inc    ax
  564.     cmp    ax,bp
  565.     jle    NoteOLp
  566.     ret
  567. AllNotesOff endp
  568.  
  569. ;--------------------------------------------------------------------------------
  570. ;routines for setting parameters in AdLib
  571. ;--------------------------------------------------------------------------------
  572.  
  573. ;--------------------------------------------------------------------------------
  574. ;
  575. ;InitAdLib:
  576. ;
  577. ;clear all AdLib registers
  578. ;
  579. ;--------------------------------------------------------------------------------
  580.  
  581. InitAdLib proc near
  582.     mov    ax,1
  583. IAdLp:    push    ax
  584.     call    AdLibWrite    ;clear all reg.s
  585.     pop    ax
  586.     inc    al
  587.     cmp    al,0F5h
  588.     jle    IAdLp
  589.  
  590.     mov    al,4
  591.     mov    ah,60h        ;reset Timer-1 & 2
  592.     call    AdLibWrite
  593.     mov    al,4
  594.     mov    ah,80h        ;reset Timer-1 & 2
  595.     call    AdLibWrite
  596.  
  597.     mov    al,1
  598.     mov    ah,00100000b    ;enable wave-select
  599.     call    AdLibWrite
  600.  
  601.     ret
  602. InitAdLib endp
  603.  
  604. ;--------------------------------------------------------------------------------
  605. ;
  606. ;InitAllVoices:
  607. ;
  608. ;set up all slots to default
  609. ;
  610. ;--------------------------------------------------------------------------------
  611.  
  612. InitAllVoices proc near
  613.     mov    si,offset pianoOpr0
  614.     mov    di,offset pianoOpr1
  615.     mov    ax,0
  616.  
  617.     mov    bp,8    ;last voice
  618.     cmp    Percussion,0
  619.     je    LoopIS
  620.     mov    bp,5    ;last voice
  621.  
  622. LoopIS:    push    ax
  623.     push    bp
  624.     call    WriteVoice        ;set up voices 0-8
  625.     pop    bp
  626.     pop    ax
  627.     inc    ax
  628.     cmp    ax,bp
  629.     jle    LoopIS
  630.  
  631.     cmp    Percussion,0
  632.     je    QuitIS
  633. SetUpPerc:
  634.     mov    si,offset bdOpr0    ;set up percussion voices
  635.     mov    di,offset bdOpr1
  636.     mov    ax,6
  637.     call    WriteVoice
  638.     mov    si,offset sdOpr
  639.     mov    ax,7
  640.     call    WriteVoice
  641.     mov    si,offset tomOpr
  642.     mov    ax,8
  643.     call    WriteVoice
  644.     mov    si,offset cymbOpr
  645.     mov    ax,9
  646.     call    WriteVoice
  647.     mov    si,offset hhOpr
  648.     mov    ax,10
  649.     call    WriteVoice
  650. QuitIS:
  651.     ret
  652. InitAllVoices endp
  653.  
  654. ;--------------------------------------------------------------------------------
  655. ;SetUpSongVoices
  656. ;
  657. ;set up all voices for a song
  658. ;
  659. ;si:    array of patch no.s for voices
  660. ;
  661. ;--------------------------------------------------------------------------------
  662.  
  663. SetUpSongVoices proc near
  664.     mov    ax,0
  665.  
  666.     mov    bp,8    ;last voice
  667.     cmp    Percussion,0
  668.     je    LoopSV
  669.     mov    bp,5    ;last voice
  670.  
  671. LoopSV:    push    ax
  672.     push    bp
  673.     push    si
  674.     mov    bl,[si]    ;patch
  675.     xor    bh,bh
  676.     shl    bx,1
  677.     mov    si,AdLibPatches[bx]
  678.     mov    di,si
  679.     add    di,14        ;operator 1
  680.     call    WriteVoice
  681.     pop    si
  682.     pop    bp
  683.     pop    ax
  684.  
  685.     inc    si
  686.     inc    ax
  687.     cmp    ax,bp
  688.     jle    LoopSV
  689.  
  690.     cmp    Percussion,0
  691.     je    NoSPerc
  692.     call    SetUpPerc
  693. NoSPerc:
  694.     ret
  695.  
  696. SetUpSongVoices endp
  697.  
  698. ;--------------------------------------------------------------------------------
  699. ;WriteVoice:
  700. ;
  701. ;sets up a voice for a patch
  702. ;
  703. ;ax: voice
  704. ;si: patch operator0
  705. ;di: patch operator1
  706. ;
  707. ;--------------------------------------------------------------------------------
  708.  
  709. WriteVoice proc near
  710.     push    si
  711.     mov    bx,offset VoiceSlots
  712.     cmp    Percussion,0
  713.     je    VNPerc
  714.     mov    bx,offset VoiceSlotsPerc    ;for percussion mode
  715. VNPerc:
  716.     mov    dx,ax        ;voice
  717.     shl    ax,1
  718.     add    bx,ax
  719.     mov    al,[bx]        ;first slot (modulator)
  720.     push    bx
  721.     push    dx
  722.     push    di
  723.     mov    bx,dx        ;voice
  724.     call    WriteSlot
  725.     pop    di
  726.     pop    dx
  727.     pop    bx
  728.     
  729.     cmp    byte ptr [bx+1],0    ;no second slot (carrier) if <0
  730.     jl    NoWriS
  731.  
  732.     push    bx
  733.     push    dx
  734.     push    di
  735.     call    WriteFeedFM    ;only once per voice
  736.     pop    di
  737.     pop    dx
  738.     pop    bx
  739.  
  740.     mov    si,di        ;operator1
  741.     mov    al,[bx+1]    ;second slot (carrier)
  742.     mov    bx,dx        ;voice
  743.     call    WriteSlot
  744.  
  745. NoWriS:
  746.     pop    si
  747.     ret
  748. WriteVoice endp
  749.  
  750. ;--------------------------------------------------------------------------------
  751. ;WriteSlot:
  752. ;
  753. ;sets the AdLib up for:
  754. ;
  755. ;ax: slot
  756. ;bx: voice
  757. ;si: operator
  758. ;
  759. ;--------------------------------------------------------------------------------
  760.  
  761. WriteSlot proc near
  762.     mov    Voice,bl
  763.     mov    bx,ax
  764.     xor    bh,bh
  765.     mov    bl,SlotOffsets[bx]    ;offset within chip
  766.  
  767. ;make sure all params within range
  768.  
  769.     and    byte ptr KSL[si],3
  770.     and    byte ptr MULTI[si],15
  771.     and    byte ptr FB[si],7
  772.     and    byte ptr AR[si],15
  773.     and    byte ptr SL[si],15
  774.     and    byte ptr EG[si],1
  775.     and    byte ptr DR[si],15
  776.     and    byte ptr RR[si],15
  777.     and    byte ptr TL[si],63
  778.     and    byte ptr AM[si],1
  779.     and    byte ptr VIB[si],1
  780.     and    byte ptr KSR[si],1
  781.     and    byte ptr C[si],1
  782.     and    byte ptr WS[si],3
  783.  
  784. ;set Ksl,Level
  785.  
  786.      mov    ah,KSL[si]
  787.     mov    cl,6
  788.     shl    ah,cl
  789.     mov    al,TL[si]
  790.     or    ah,al
  791.     mov    al,40h
  792.     add    al,bl
  793.     call    AdLibWrite
  794.  
  795. ;set Attack,Decay
  796.  
  797.     mov    ah,AR[si]
  798.     mov    cl,4
  799.     shl    ah,cl
  800.     or    ah,DR[si]
  801.     mov    al,60h
  802.     add    al,bl
  803.     call    AdLibWrite
  804.  
  805. ;set Sustain,Release
  806.  
  807.     mov    ah,SL[si]
  808.     mov    cl,4
  809.     shl    ah,cl
  810.     or    ah,RR[si]
  811.     mov    al,80h
  812.     add    al,bl
  813.     call    AdLibWrite
  814.  
  815. ;AM, VIB, EG-TYP (Sustaining), KSR, MULTI
  816.  
  817.     mov    ah,AM[si]
  818.     mov    cl,7
  819.     shl    ah,cl
  820.     mov    al,VIB[si]
  821.     mov    cl,6
  822.     shl    al,cl
  823.     or    ah,al
  824.     mov    al,EG[si]
  825.     mov    cl,5
  826.     shl    al,cl
  827.     or    ah,al
  828.     mov    al,KSR[si]
  829.     mov    cl,4
  830.     shl    al,cl
  831.     or    ah,al
  832.     or    ah,MULTI[si]
  833.     mov    al,20h
  834.     add    al,bl
  835.     call    AdLibWrite
  836.  
  837. ;Wave Select
  838.  
  839.     mov    ah,WS[si]
  840.     mov    al,0E0h
  841.     add    al,bl
  842.     call    AdLibWrite
  843.  
  844.     ret
  845. WriteSlot endp
  846.  
  847.  
  848. ;set Feedback,Fm
  849. ;-only once per voice
  850.  
  851. WriteFeedFM proc near
  852.     mov    ah,FB[si]
  853.     shl    ah,1
  854.     mov    al,C[si]
  855.     xor    al,1
  856.     or    ah,al
  857. ;    or    ah,C[si]
  858.     mov    al,0C0h
  859.     add    al,Voice
  860.     call    AdLibWrite
  861.     ret
  862. WriteFeedFM endp
  863.  
  864. ;-------------------------------------------------------------------------------
  865. ;WriteGlobals:
  866. ;
  867. ;sets up AdLib global parameters
  868. ;
  869. ;WriteAmVibPerc:
  870. ;
  871. ;sets the values: amplitude depth,vibrato depth,percussion and percussion keyons
  872. ;
  873. ;-------------------------------------------------------------------------------
  874.  
  875. WriteGlobals proc near
  876.     call    WriteAmVibPerc
  877.     mov    ah,NoteSel
  878.     mov    cl,6
  879.     shl    ah,cl
  880.     mov    al,08h
  881.     call    AdLibWrite
  882.     ret
  883. WriteGlobals endp
  884.  
  885. WriteAmVibPerc proc near
  886.     mov    ah,AmDepth
  887.     mov    cl,7
  888.     shl    ah,cl
  889.     mov    al,VibDepth
  890.     mov    cl,6
  891.     shl    al,cl
  892.     or    ah,al
  893.     mov    al,Percussion
  894.     mov    cl,5
  895.     shl    al,cl
  896.     or    ah,al
  897.     or    ah,PercBits
  898.     mov    al,0BDh
  899.     call    AdLibWrite
  900.     ret
  901. WriteAmVibPerc endp
  902.  
  903. ;------------------------------------------------------------
  904. ;WriteAdLibFreq
  905. ;
  906. ;set a voice's frequency
  907. ;
  908. ;inputs:
  909. ;    ax:    voice        (0-8)
  910. ;    bx:    note        (0-95)
  911. ;    cx:    pitchbend    (0-4000h, 2000h no bend)
  912. ;    dx:    keyOn        (0 disable 1 enable)
  913. ;
  914. ;sets volume to VoiceVolumes[voice] if keyOn=1
  915. ;
  916. ;------------------------------------------------------------
  917.  
  918. WriteAdLibFreq proc near
  919.     mov    Voice,al
  920.     mov    Note,bl
  921.     mov    PitchBend,cx
  922.  
  923.     mov    ax,cx
  924.  
  925.     mov    cl,5
  926.     shl    dl,cl        ;shift KON to correct location
  927.     mov    keyOn,dl
  928.  
  929.     push    ax
  930.     cmp    dl,0
  931.     je    NoVV        ;not if keyon=0
  932. ;set voice volume
  933.     jmp    NoVV
  934.  
  935.     mov    bx,offset VoiceSlots
  936.     cmp    Percussion,0
  937.     je    NoVVPerc
  938.     mov    bx,offset VoiceSlotsPerc
  939.     cmp    Voice,6
  940.     jle    NoVVPerc
  941.     dec    bx        ;for single op. percussion
  942. NoVVPerc:
  943.     mov    al,Voice
  944.     xor    ah,ah
  945.     shl    ax,1
  946.     add    bx,ax
  947.     mov    bl,[bx+1]    ;carrier slot
  948.     xor    bh,bh
  949.     mov    al,SlotOffsets[bx]
  950.     mov    bl,Voice
  951.     mov    ah,VoiceVolumes[bx]
  952.     shr    ah,1        ;0-63 volume
  953.     shr    ah,1        ;0-31
  954.     shr    ah,1        ;0-15
  955.     neg    ah
  956.     add    ah,15        ;attenuation
  957.     add    al,40h
  958.     call    AdLibWrite
  959.     
  960. NoVV:    pop    ax
  961.  
  962.     sub    ax,2000h    ;convert pitch bend to signed no.
  963.     je    NoMul        ;no mul if =0
  964.  
  965.     sar    ax,1        ;scale to 0-255
  966.     sar    ax,1
  967.     sar    ax,1
  968.     sar    ax,1
  969.     sar    ax,1
  970.  
  971.     imul    PitchBendRange    ;* by pitch bend range
  972.  
  973. NoMul:    add    ah,Note        ;add on note no.
  974.  
  975.     add    ax,8        ;round to nearest 1/16
  976.  
  977.     sar    ax,1        ;scale to 4 bit fix point
  978.     sar    ax,1
  979.     sar    ax,1
  980.     sar    ax,1
  981.  
  982.     jge    Not0    ;<0?
  983.  
  984.     xor    ax,ax        ;=0
  985.     jmp    Not95
  986.  
  987. Not0:    cmp    ax,(96*16)-1    ;note <=95?
  988.     jl    Not95
  989.  
  990.     mov    ax,(96*16)-1    ;=95
  991. Not95:
  992.     mov    di,ax        ;get half-tone value within 1 octave
  993.     shr    di,1        ;use integer part of note MOD 12
  994.     shr    di,1
  995.     shr    di,1
  996.     shr    di,1
  997.     mov    dx,di
  998.     mov    bl,MOD12Tab[di]
  999.     xor    bh,bh
  1000.     mov    di,bx
  1001.  
  1002.     shl    di,1        ;get offset in frequency table
  1003.     shl    di,1
  1004.     shl    di,1
  1005.     shl    di,1
  1006.     shl    di,1
  1007.  
  1008.     shl    ax,1
  1009.     and    ax,31
  1010.     add    di,ax        ;add in fractional part (lower 4 bits)
  1011.  
  1012.     mov    ax,FNumTable[di]    ;get frequency
  1013.  
  1014.     mov    di,dx            ;get octave number
  1015.     mov    bl,DIV12Tab[di]    ;DIV 12
  1016.     dec    bl
  1017.  
  1018.     or    ax,ax        ;if high bit set must inc octave
  1019.     jge    NoIncO
  1020.     inc    bl
  1021. NoIncO:
  1022.     or    bl,bl        ;check for <0
  1023.     jge    BlokOK
  1024.     inc    bl
  1025.     sar    ax,1        ;must /2
  1026. BlokOK:
  1027.  
  1028. ;finally write frequency info to AdLib
  1029.  
  1030.     push    bx        ;save block
  1031.     push    ax        ;save freq value
  1032.     mov    ah,al
  1033.     mov    al,FNUM_LOW
  1034.     add    al,Voice
  1035.     call    AdLibWrite
  1036.     pop    ax
  1037.     pop    bx
  1038.  
  1039.     mov    al,ah        ;set up for register
  1040.     and    al,3
  1041.     shl    bl,1
  1042.     shl    bl,1
  1043.     add    al,bl
  1044.     add    al,keyOn
  1045.     mov    ah,al
  1046.     mov    al,KEYON_BLOCK_FNUM
  1047.     add    al,Voice
  1048.     call    AdLibWrite
  1049.     ret
  1050.  
  1051. WriteAdLibFreq endp
  1052.  
  1053. ;------------------------------------------------------------
  1054. ;AdLibWrite
  1055. ;
  1056. ;write to AdLib board
  1057. ;
  1058. ;input:    al - Register No.
  1059. ;    ah - Data
  1060. ;
  1061. ;delays an appropriate amount of
  1062. ;time for AdLib hardware to catch up:
  1063. ;
  1064. ;  3.3 æsec after a register select write
  1065. ; 23.0 æsec after a data write
  1066. ;
  1067. ;------------------------------------------------------------
  1068.  
  1069. AdLibWrite proc near
  1070.  
  1071.     mov    dx,ADLIB_ADDR    ;AdLib output port
  1072.     out    dx,al
  1073.                 ;at least 12 cycles delay (3.3 æsec at 3.6 Mhz)
  1074.     in    al,dx
  1075.     in    al,dx
  1076.     in    al,dx
  1077.     in    al,dx
  1078.     in    al,dx
  1079.     in    al,dx
  1080.  
  1081.     inc    dx        ;data reg
  1082.     mov    al,ah
  1083.     out    dx,al
  1084.     dec    dx
  1085.                 ;84 cycles delay (23 æsec at 3.6 Mhz)
  1086.     in    al,dx
  1087.     in    al,dx
  1088.     in    al,dx
  1089.     in    al,dx
  1090.     in    al,dx
  1091.     in    al,dx
  1092.     in    al,dx
  1093.     in    al,dx
  1094.     in    al,dx
  1095.     in    al,dx
  1096.  
  1097.     in    al,dx
  1098.     in    al,dx
  1099.     in    al,dx
  1100.     in    al,dx
  1101.     in    al,dx
  1102.     in    al,dx
  1103.     in    al,dx
  1104.     in    al,dx
  1105.     in    al,dx
  1106.     in    al,dx
  1107.  
  1108.     in    al,dx
  1109.     in    al,dx
  1110.     in    al,dx
  1111.     in    al,dx
  1112.     in    al,dx
  1113.     in    al,dx
  1114.     in    al,dx
  1115.     in    al,dx
  1116.     in    al,dx
  1117.     in    al,dx
  1118.  
  1119.     in    al,dx
  1120.     in    al,dx
  1121.     in    al,dx
  1122.     in    al,dx
  1123.     in    al,dx
  1124.  
  1125.     ret
  1126.  
  1127. AdLibWrite endp
  1128.  
  1129.