home *** CD-ROM | disk | FTP | other *** search
/ modiromppu / modiromppu.iso / PROGRAMS / ORGPACKS / RADV1_0A.ZIP / PLAYER.ASM < prev    next >
Assembly Source File  |  1995-02-01  |  20KB  |  796 lines

  1. ;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  2. ;          ·
  3. ;          . ███▀▀█▄  ▄██▀▀▀▀  ▄█▀▀▄  ███     ███ █████▄  ██  ███ ·
  4. ;          : ███▄▄█▀  ███▄▄   ▐██▄▄█▌ ███     ███    ▀██▌ ▀█▄▄███ :
  5. ;          │ ███ ▀██▄ ███     ███  ██ ▐██▄    ███     ███     ███ |
  6. ;  ┌ ─ ─═─═╝ ▀▀▀   ▀▀▀ ▀▀▀▀▀▀ ▀▀▀  ▀▀  ▀▀▀▀▀▀ ▀▀▀     ▀▀▀ ▀▀▀▀▀▀  └── ─ -───┐
  7. ;  │ ▄█▀▀▄ ██▀▀▄ ██    ██ ██▀▀▄   ▀▀▀█▄ ██▀▀▄ ▄█▀▀▄ ▄█▀▀▄ ██  █ ▄█▀▀▀ ██▀▀▄ :
  8. ;  | ██▀▀█ ██  █ ██    ██ ██▀▀▄      ██ ██▀▀▄ ██▀▀█ ██  ▄ ██▀▀▄ ██▀   ██▀▀▄ .
  9. ;  : ▀▀  ▀ ▀▀▀▀   ▀▀▀▀ ▀▀ ▀▀▀▀       ▀▀ ▀▀  ▀ ▀▀  ▀  ▀▀▀  ▀▀  ▀  ▀▀▀▀ ▀▀  ▀ ·
  10. ;                                version 1.0a
  11. ;
  12. ;                        Code by SHAYDE/REALITY Feb 95
  13. ;
  14. ;                                    - * -
  15. ;
  16. ; Feel free to use/hack this code about as much as you like.  In the good old
  17. ; dayz of Amiga, ALL tracker writers gave away player source-code so that the
  18. ; coder could do what he/she wanted with it.  On PC every tracker writer thinks
  19. ; their player code should be protected and they either don't release a player
  20. ; or they release it in .OBJ format which means if you need to make changes to
  21. ; the code to fit in with your demo/intro you're fucked!!!  So message to all
  22. ; tracker writers out there:
  23. ; FOR THE SAKE OF CODER SANITY, ALWAYS RELEASE PLAYER CODE FOR YOUR TRACKERS!!
  24. ; OTHERWISE WOT'S THE POINT OF WRITING A TRACKER?!?!??!?!  And release it in
  25. ; source-code form to reduce head-aches!
  26. ;
  27. ;                     - * -
  28. ;
  29. ; This source-code doesn't contain any segment directives so it is only
  30. ; INCLUDEable in other source-code.  Also it requires a minimum of a 286
  31. ; to run.  I avoided using ASSUMEs so that the code that INCLUDEs this code
  32. ; doesn't lose it's ASSUMEs, hence variables are accessed via CS:.  You can
  33. ; save a few bytes by dropping them (which you'll need to do if you want to
  34. ; use this player in protected-mode), although I use DS: to reference the
  35. ; tune segment.
  36. ;
  37. ;                     - * -
  38. ;
  39. ; INSTRUCTIONS FOR USE:
  40. ;
  41. ;    To initialise the player, call "InitPlayer".
  42. ;    To stop play, call "EndPlayer".
  43. ;    To play music, call "PlayMusic" 50 times a second (18.2/sec for a
  44. ;                    "slow-timer" tune).
  45. ;
  46. ;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  47.  
  48.         locals
  49.         jumps
  50.  
  51.  
  52.  
  53. ; Tracker commands
  54. cmPortamentoUp    =    1        ; Portamento up
  55. cmPortamentoDwn    =    2        ; Portamento down
  56. cmToneSlide    =    3        ; Tone Slide: xx is speed of slide
  57. cmToneVolSlide    =    5        ; Tone slide of 00 + Vol. Slide
  58. cmVolSlide    =    10        ; Volume Slide: <50=down, >50=up
  59. cmSetVol    =    12        ; set volume
  60. cmJumpToLine    =    13        ; Jump to line in next track
  61. cmSetSpeed    =    15        ; set speed
  62.  
  63. FreqStart    =    156h        ; low end of frequency in each octave
  64. FreqEnd        =    2aeh        ; high end of frequency in each octave
  65. FreqRange    =    FreqEnd-FreqStart
  66.  
  67.  
  68.  
  69.  
  70. ;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  71. ; This routine initialises the player.
  72. ; IN:
  73. ;    ES:    - points to .RAD module to play
  74. ; OUT:
  75. ;    Carry    - set on error (such as invalid module)
  76. ;──────────────────────────────────────────────────────────────────────────────
  77. InitPlayer:    pusha
  78.  
  79.         call    EndPlayer    ; clear Adlib ready for tune
  80.  
  81.     ; initialise certain Adlib registers that aren't changed
  82.         mov    ax,0120h    ; allow waveforms
  83.         call    Adlib
  84.         mov    ax,0800h
  85.         call    Adlib
  86.         mov    ah,0bdh        ; no drums, etc.
  87.         call    Adlib
  88.  
  89.     ; check to see if it is a RAD file first
  90.         cmp    word ptr es:[0],'AR'
  91.         jnz    @@err
  92.         cmp    word ptr es:[2],' D'
  93.         jnz    @@err
  94.         cmp    byte ptr es:[16],10h        ; correct version?
  95.         jnz    @@err
  96.  
  97.         mov    cs:ModSeg,es        ; keep the segment of module
  98.  
  99.     ; read initial speed
  100.         mov    al,es:[17]
  101.         mov    ah,al
  102.         and    al,1fh
  103.         mov    cs:Speed,al
  104.  
  105.     ; see if there's a description to skip
  106.         mov    si,18
  107.         test    ah,80h            ; description flag
  108.         jz    @@lc            ; no description
  109.  
  110.         xor    al,al
  111.         jmp    @@le
  112.  
  113.     @@ld:    inc    si
  114.     @@le:    cmp    es:[si],al        ; look for null-termination
  115.         jnz    @@ld
  116.         inc    si            ; move past null
  117.  
  118.     ; create table of instrument pointers
  119.     @@lc:    xor    bx,bx
  120.  
  121.     @@la:    mov    bl,es:[si]        ; instrument no.
  122.         inc    si
  123.         add    bx,bx
  124.         jz    @@lb            ; no more instruments
  125.  
  126.         mov    cs:InstPtrs-2[bx],si    ; record pointer to instrument
  127.         add    si,11
  128.         jmp    @@la
  129.  
  130.     ; record offset of order list
  131.     @@lb:    xor    ax,ax
  132.         mov    al,es:[si]        ; no. of orders in order-list
  133.         mov    cs:OrderSize,ax
  134.         inc    si
  135.         mov    cs:OrderList,si
  136.         xor    bx,bx
  137.         mov    bl,es:[si]        ; first pattern to play
  138.         add    bx,bx
  139.         add    si,ax            ; move to end of list
  140.  
  141.     ; record table of pattern offsets
  142.         mov    cs:PatternList,si
  143.         mov    ax,es:[si+bx]        ; first pattern offset
  144.         mov    cs:PatternPos,ax    ; pointer to first pattern
  145.  
  146.     ; initial pointers
  147.         xor    ax,ax
  148.         mov    cs:OrderPos,ax        ; start at position 0.
  149.         mov    cs:SpeedCnt,al
  150.         mov    cs:Line,al        ; start at line 0
  151.  
  152.         clc
  153.         jmp    @@lx            ; successful initialisation
  154.  
  155.     @@err:    stc
  156.     @@lx:    popa
  157.         ret
  158.  
  159.  
  160.  
  161.  
  162.  
  163. ;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  164. ; This stops music playback (stops sound channels).
  165. ;──────────────────────────────────────────────────────────────────────────────
  166. EndPlayer:    push    ax
  167.         mov    ax,020h shl 8
  168.     @@la:    call    Adlib
  169.         inc    ah
  170.         cmp    ah,00f6h
  171.         jb    @@la
  172.         pop    ax
  173.         ret
  174.  
  175.  
  176.  
  177.  
  178.  
  179. ;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  180. ; This routine does the actual playing.  It MUST be called 50 times a second
  181. ; to maintain accurate music playback.  Refer to accompanying timer source-code
  182. ; for ways of providing a 50/sec timer service.
  183. ;──────────────────────────────────────────────────────────────────────────────
  184. PlayMusic:    pusha
  185.         push    ds
  186.  
  187.         mov    ds,cs:ModSeg    ; segment of module
  188.  
  189.         cmp    cs:SpeedCnt,0
  190.         jz    @@la        ; play a line of music
  191.         dec    cs:SpeedCnt
  192.  
  193.     ; no new line, so just update any effects
  194.         call    UpdateNotes
  195.         jmp    @@lx
  196.  
  197.     ; switch off any effects that are in operation
  198.     @@la:    mov    si,8
  199.         xor    al,al
  200.  
  201.     @@laa:    mov    cs:PortSlide[si],al    ; reset any slides
  202.         mov    cs:VolSlide[si],al    ; reset any slides
  203.         mov    cs:ToneSlide[si],al    ; reset any slides
  204.         dec    si
  205.         jns    @@laa
  206.  
  207.     ; playing a new line, PatternPos should have been set-up already
  208.         mov    si,cs:PatternPos
  209.         or    si,si
  210.         jz    @@lb        ; rest of this pattern is blank
  211.  
  212.         mov    al,[si]        ; line indicator
  213.         and    al,7fh        ; eliminate bit 7
  214.         cmp    al,cs:Line    ; is this current line?
  215.         jnz    @@lb        ; haven't reached it yet
  216.  
  217.         test    byte ptr [si],80h    ; last line?
  218.         jz    @@lc        ; no, still more to check
  219.         mov    cs:PatternPos,0    ; mark rest of pattern as blank
  220.  
  221.     @@lc:    inc    si        ; move to first channel
  222.  
  223.     ; play channels
  224.     @@lf:    mov    cl,[si]        ; channel we are processing
  225.         push    cx
  226.         and    cl,7fh        ; get rid of bit 7
  227.         mov    ax,1[si]    ; AL=octave/note, AH=inst/command
  228.         add    si,3
  229.  
  230.         test    ah,15        ; if there's a cmd, there'll be a param.
  231.         jz    @@le        ; no parameter byte
  232.         mov    ch,[si]        ; read parameter
  233.         inc    si
  234.  
  235.     @@le:    call    PlayNote    ; play the note
  236.  
  237.         pop    cx
  238.         jc    @@lg        ; skip rest of line, AX has new line
  239.  
  240.         test    cl,80h        ; last channel to play?
  241.         jz    @@lf        ; not yet
  242.  
  243.         mov    cs:PatternPos,si; keep position in crunched track
  244.  
  245.     ; update pointers
  246.     @@lb:    mov    al,cs:Speed    ; needs to be set AFTER note playing
  247.         dec    al
  248.         mov    cs:SpeedCnt,al    ;    for new speeds to take effect!
  249.  
  250.         inc    cs:Line
  251.         cmp    cs:Line,64    ; end of pattern?
  252.         jb    @@lx        ; nope
  253.  
  254.         mov    cs:Line,0    ; top of next pattern
  255.         call    NextPattern
  256.  
  257.     @@lx:    pop    ds
  258.         popa
  259.         ret
  260.  
  261.     ; jump to line AX
  262.     @@lg:    mov    bl,cs:Speed    ; needs to be set AFTER note playing
  263.         mov    cs:SpeedCnt,bl    ;    for new speeds to take effect!
  264.  
  265.         mov    cs:Line,al
  266.  
  267.         ; find start of next pattern
  268.         call    NextPattern
  269.         jz    @@lx        ; there isn't any data in next pattern
  270.  
  271.         ; find line that is greater or equal to the current line
  272.     @@ll:    mov    cl,[si]        ; line id.
  273.         and    cl,7fh        ; ignore bit 7
  274.         cmp    cl,al
  275.         jae    @@lh        ; found line
  276.  
  277.         test    byte ptr [si],80h
  278.         jz    @@li        ; not last line
  279.         xor    si,si
  280.         jmp    @@lh        ; ignore rest of pattern as it's last
  281.  
  282.         ; skip to next line definition
  283.     @@li:    inc    si
  284.     @@lj:    mov    cl,[si]
  285.         add    si,3
  286.         test    byte ptr cs:[si-1],15    ; is there a valid command?
  287.         jz    @@lk
  288.         inc    si        ; skip parameter
  289.  
  290.     @@lk:    add    cl,cl
  291.         jnc    @@lj        ; wasn't last channel spec.
  292.         jmp    @@ll        ; check next line
  293.  
  294.     @@lh:    mov    cs:PatternPos,si
  295.         jmp    @@lx
  296.  
  297.  
  298.  
  299.  
  300.  
  301. ;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  302. ; Advances pointers to next pattern in order list.
  303. ;──────────────────────────────────────────────────────────────────────────────
  304. NextPattern:    mov    bx,cs:OrderPos
  305.         inc    bx
  306.         cmp    bx,cs:OrderSize
  307.         jb    @@ld
  308.         xor    bx,bx        ; end of tune, move back to start
  309.  
  310.     @@ld:    mov    cs:OrderPos,bx
  311.         mov    si,cs:OrderList
  312.         mov    bl,[si+bx]    ; no. of next pattern
  313.  
  314.         test    bl,80h
  315.         jz    @@lda
  316.         and    bl,7fh
  317.         jmp    @@ld        ; bit 7 = jump to new order
  318.  
  319.     @@lda:    mov    si,cs:PatternList
  320.         add    bx,bx
  321.         mov    si,[si+bx]    ; offset of next pattern
  322.         mov    cs:PatternPos,si
  323.         or    si,si
  324.         ret
  325.  
  326.  
  327.  
  328.  
  329.  
  330. ;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  331. ; Plays a note on a channel.
  332. ; IN:
  333. ;    AL    - Octave (high nibble), Note (low nibble)
  334. ;    AH    - instrument (high nibble), command (low nibble)
  335. ;    CL    - channel to play note on (0..8)
  336. ;    CH    - parameter byte if command is non-zero
  337. ; OUT:
  338. ;    CARRY    - set if a line is to be jumped to
  339. ;    AX    - line to jump to if CARRY set
  340. ; Note: don't use SI or segment regs., otherwise registers do not need saving.
  341. ;──────────────────────────────────────────────────────────────────────────────
  342. PlayNote:    mov    di,cx
  343.         and    di,15
  344.         mov    dh,ah
  345.         and    dh,15        ; command
  346.  
  347.         or    al,al
  348.         jz    @@lb        ; no note playing, process command
  349.  
  350.     ; check to see if we are actually performing a tone slide
  351.         cmp    dh,cmToneSlide
  352.         jnz    @@lt        ; nope, play note
  353.  
  354.         ; note/octave are used as parameters then (instrument ignored)
  355.         mov    bx,ax
  356.         and    bx,15        ; note
  357.         shr    al,4
  358.         and    ax,7        ; octave
  359.         dec    bx        ; we want 1..12
  360.         cmp    bx,12
  361.         jae    @@lx        ; not a valid note (probably KEY-OFF)
  362.  
  363.         imul    ax,FreqRange    ; scale octave
  364.         add    bx,bx
  365.         add    ax,cs:NoteFreq[bx]    ; add frequency of this note
  366.         sub    ax,FreqStart    ; so range starts from zero
  367.         mov    cs:ToneSlideFreqL[di],al    ; destination frequency
  368.         mov    cs:ToneSlideFreqH[di],ah
  369.  
  370.         ; set tone slide speed
  371.         mov    byte ptr cs:ToneSlide[di],1    ; switch tone slide on
  372.         or    ch,ch
  373.         jz    @@lx        ; use last speed setting
  374.         mov    cs:ToneSlideSpeed[di],ch
  375.         jmp    @@lx
  376.  
  377.     ; KEY-OFF the previous note
  378.     @@lt:    push    ax
  379.         mov    al,cs:OldB0[di]    ; old register value
  380.         and    al, not 20h    ; clear KEY-ON bit
  381.         mov    cs:OldB0[di],al    ; so slides after KEYOFF work correctly
  382.         mov    ah,cl
  383.         add    ah,0b0h
  384.         call    Adlib
  385.         pop    ax
  386.  
  387.     ; load instrument (if any)
  388.         mov    dl,ah
  389.         add    al,al
  390.         rcr    dl,1
  391.         shr    dl,3        ; instrument no.
  392.         jz    @@la        ; no instrument to load
  393.         call    LoadInst
  394.  
  395.     ; load note into channel
  396.     @@la:    mov    bl,al
  397.         and    bx,15*2        ; note * 2
  398.         cmp    bx,15*2
  399.         jz    @@lb        ; just a KEY-OFF so we're done
  400.  
  401.         mov    bx,cs:NoteFreq-2[bx]    ; frequency of note (BX-1)
  402.         shr    al,3        ; octave
  403.         and    al,7*4
  404.         or    al,20h        ; KEY-ON
  405.         or    al,bh        ; Frequency high byte
  406.         mov    ah,0b0h
  407.         add    ah,cl
  408.         mov    cs:OldB0[di],al    ; record the register value
  409.         push    ax
  410.  
  411.         sub    ah,10h
  412.         mov    al,bl        ; Frequency low byte
  413.         mov    cs:OldA0[di],al
  414.         call    Adlib
  415.  
  416.         pop    ax
  417.         call    Adlib
  418.  
  419.     ; process command (if any), DH has command, CH has parameter
  420.     @@lb:    xor    bx,bx
  421.         mov    bl,dh        ; command
  422.         add    bx,bx
  423.         jmp    cs:Effects[bx]
  424.  
  425.     @@lx:    clc
  426.     @@lxx:    ret
  427. ;──────────────────────────────────────────────────────────────────────────────
  428. ; Portamento up
  429. @@PortUp:    mov    cs:PortSlide[di],ch
  430.         jmp    @@lx
  431. ;──────────────────────────────────────────────────────────────────────────────
  432. ; Portamento down
  433. @@PortDown:    neg    ch
  434.         mov    cs:PortSlide[di],ch
  435.         jmp    @@lx
  436. ;──────────────────────────────────────────────────────────────────────────────
  437. ; Tone slide to note (no note supplied)
  438. @@ToneSlide:    or    ch,ch        ; parameter has speed of tone slide
  439.         jz    @@lja        ; keep last tone slide speed
  440.         mov    cs:ToneSlideSpeed[di],ch
  441.  
  442.     @@lja:    mov    byte ptr cs:ToneSlide[di],1    ; tone slide on
  443.         jmp    @@lx
  444. ;──────────────────────────────────────────────────────────────────────────────
  445. ; Volume slide & Volume + Tone Slide
  446. @@ToneVolSlide:
  447. @@VolSlide:    cmp    ch,50        ; <50 = slide down, >50 = slide up
  448.         jb    @@lga
  449.         sub    ch,50
  450.         neg    ch
  451.  
  452.     @@lga:    mov    cs:VolSlide[di],ch
  453.  
  454.         cmp    dh,cmToneVolSlide    ; just plain volume slide
  455.         jnz    @@lx
  456.         mov    byte ptr cs:ToneSlide[di],1    ; tone slide on
  457.         jmp    @@lx
  458. ;──────────────────────────────────────────────────────────────────────────────
  459. ; Set volume
  460. @@SetVolume:    call    SetVolume    ; CH has volume, CL has channel
  461.         jmp    @@lx
  462. ;──────────────────────────────────────────────────────────────────────────────
  463. ; jump to line in next pattern
  464. @@JumpToLine:    cmp    ch,64
  465.         jae    @@lx        ; ignore as it is invalid
  466.         xor    ax,ax
  467.         mov    al,ch
  468.         stc
  469.         ret            ; skip rest of channels
  470. ;──────────────────────────────────────────────────────────────────────────────
  471. ; Set speed
  472. @@SetSpeed:    mov    cs:Speed,ch
  473.         jmp    @@lx
  474. ;──────────────────────────────────────────────────────────────────────────────
  475. Effects        dw    @@lx
  476.         dw    @@PortUp
  477.         dw    @@PortDown
  478.         dw    @@ToneSlide
  479.         dw    @@lx
  480.         dw    @@ToneVolSlide
  481.         dw    @@lx
  482.         dw    @@lx
  483.         dw    @@lx
  484.         dw    @@lx
  485.         dw    @@VolSlide
  486.         dw    @@lx
  487.         dw    @@SetVolume
  488.         dw    @@JumpToLine
  489.         dw    @@lx
  490.         dw    @@SetSpeed
  491.  
  492. NoteFreq    dw    16bh,181h,198h,1b0h,1cah,1e5h    ; 156h = C
  493.         dw    202h,220h,241h,263h,287h,2aeh
  494.  
  495.  
  496.  
  497.  
  498.  
  499.  
  500. ;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  501. ; Check each channel for ongoing effects to update.
  502. ;──────────────────────────────────────────────────────────────────────────────
  503. UpdateNotes:    xor    bh,bh        ; channel index
  504.         xor    si,si
  505.  
  506.     ; process portamentos
  507.     @@la:    mov    bl,cs:PortSlide[si]
  508.         or    bl,bl
  509.         jz    @@lb        ; no slide for this channel
  510.         call    GetFreq
  511.         mov    ch,bl
  512.         sar    cx,8        ; sign extend 8bit->16bit
  513.         add    ax,cx
  514.         call    SetFreq
  515.  
  516.     ; process volume slides
  517.     @@lb:    mov    ch,cs:VolSlide[si]
  518.         mov    cl,cs:Old43[si]    ; contains current volume
  519.         and    cl,3fh
  520.         xor    cl,3fh
  521.         or    ch,ch
  522.         jz    @@lc
  523.         jns    @@lba
  524.  
  525.         ; slide volume up
  526.         sub    cl,ch
  527.         cmp    cl,64
  528.         jb    @@lbb
  529.         mov    cl,63
  530.         jmp    @@lbb
  531.  
  532.         ; slide volume down
  533.     @@lba:    sub    cl,ch
  534.         jns    @@lbb
  535.         xor    cl,cl
  536.  
  537.     @@lbb:    mov    ch,cl
  538.         mov    cl,bh        ; channel to set
  539.         call    SetVolume
  540.  
  541.     ; process tone slides
  542.     @@lc:    cmp    cs:ToneSlide[si],0
  543.         jz    @@lx        ; no tone slide
  544.         mov    bl,cs:ToneSlideSpeed[si]    ; shouldn't get wiped uc
  545.  
  546.         ; get current absolute frequency
  547.         call    GetFreq
  548.  
  549.         ; sign extend speed/direction
  550.         mov    dh,bl
  551.         sar    dx,8
  552.  
  553.         ; get destination frequency
  554.         mov    cl,cs:ToneSlideFreqL[si]
  555.         mov    ch,cs:ToneSlideFreqH[si]
  556.         cmp    ax,cx
  557.         jz    @@le        ; already at destination?!
  558.         ja    @@ld        ; tone slide down (source > dest)
  559.  
  560.         ; doing a tone slide up
  561.         add    ax,dx
  562.         cmp    ax,cx
  563.         jb    @@lg        ; still under destination
  564.         jmp    @@le        ; reached destination
  565.  
  566.         ; doing a tone slide down
  567.     @@ld:    sub    ax,dx
  568.         cmp    ax,cx
  569.         ja    @@lg        ; still over destination
  570.  
  571.         ; reached destination so stop tone slide
  572.     @@le:    mov    ax,cx        ; clip it onto destination
  573.         mov    cs:ToneSlide[si],0    ; disables tone slide
  574.  
  575.         ; write new frequency back to channel
  576.     @@lg:    call    SetFreq
  577.  
  578.     @@lx:    inc    bh
  579.         inc    si
  580.         cmp    si,9
  581.         jb    @@la
  582.         ret
  583.  
  584.  
  585.  
  586.  
  587.  
  588. ;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  589. ; Returns the current absolute frequency of channel
  590. ; IN:
  591. ;    SI    - channel
  592. ; OUT:
  593. ;    AX    - frequency
  594. ; USES:
  595. ;    CX, DX
  596. ;──────────────────────────────────────────────────────────────────────────────
  597. GetFreq:    mov    cl,cs:OldA0[si]
  598.         mov    ch,cs:OldB0[si]
  599.         and    ch,3        ; mask to get high frequency
  600.         sub    cx,FreqStart
  601.         mov    al,cs:OldB0[si]
  602.         shr    al,2
  603.         and    ax,7        ; mask to get octave
  604.         mov    dx,FreqRange
  605.         mul    dx
  606.         add    ax,cx
  607.         ret
  608.  
  609.  
  610.  
  611.  
  612.  
  613. ;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  614. ; Sets the channel's frequency
  615. ; IN:
  616. ;    AX    - absolute frequency
  617. ;    SI    - channel
  618. ; USES:
  619. ;    CX, DX
  620. ;──────────────────────────────────────────────────────────────────────────────
  621. SetFreq:    mov    cx,FreqRange
  622.         xor    dx,dx
  623.         div    cx        ; extracts octave in AX and freq. in DX
  624.         add    dx,FreqStart
  625.  
  626.         mov    ah,cs:OldB0[si]
  627.         and    ah,11100000b    ; keep old toggles
  628.         shl    al,2        ; move octave to correct bit position
  629.         or    al,ah        ; insert octave
  630.         or    al,dh        ; insert high frequency
  631.         mov    ah,bh
  632.         add    ah,0b0h
  633.         mov    cs:OldB0[si],al
  634.         call    Adlib
  635.  
  636.         sub    ah,10h
  637.         mov    al,dl        ; low frequency
  638.         mov    cs:OldA0[si],al
  639.         jmp    Adlib
  640.  
  641.  
  642.  
  643.  
  644.  
  645. ;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  646. ; Load in instrument data into a given channel.
  647. ; IN:
  648. ;    CL    - channel to load instrument into (0..8)
  649. ;    DL    - instrument no. (1..31)
  650. ;──────────────────────────────────────────────────────────────────────────────
  651. LoadInst:    push    ax bx si
  652.  
  653.         mov    si,cx
  654.         and    si,0ffh
  655.         mov    ah,cs:ChannelOffs[si]    ; Adlib register offsets
  656.  
  657.         xor    bx,bx
  658.         mov    bl,dl
  659.         dec    bx
  660.         add    bx,bx
  661.         mov    bx,cs:InstPtrs[bx]    ; get instrument offset
  662.         or    bx,bx
  663.         jz    @@lx        ; no instrument data ?!
  664.  
  665.         mov    al,2[bx]
  666.         mov    cs:Old43[si],al    ; old 43.. value
  667.  
  668.         mov    dl,4
  669.  
  670.     @@la:    mov    al,1[bx]
  671.         call    Adlib        ; load carrier
  672.         add    ah,3
  673.         mov    al,[bx]
  674.         call    Adlib        ; load modulator
  675.         add    bx,2
  676.  
  677.         add    ah,20h-3
  678.         dec    dl
  679.         jnz    @@la
  680.  
  681.         add    ah,40h        ; do E0 range now
  682.         mov    al,2[bx]
  683.         call    Adlib
  684.         add    ah,3
  685.         mov    al,1[bx]
  686.         call    Adlib
  687.  
  688.         mov    ah,0c0h
  689.         add    ah,cl
  690.         mov    al,[bx]
  691.         call    Adlib
  692.  
  693.     @@lx:    pop    si bx ax
  694.         ret
  695.  
  696. ChannelOffs    db    20h,21h,22h,28h,29h,2ah,30h,31h,32h
  697.  
  698.  
  699.  
  700.  
  701.  
  702.  
  703. ;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  704. ; Outputs a value to an ADLIB register.
  705. ; IN:
  706. ;    CL    - channel to set volume on
  707. ;    CH    - new volume
  708. ;──────────────────────────────────────────────────────────────────────────────
  709. SetVolume:    push    ax bx
  710.  
  711.         xor    bx,bx
  712.         mov    bl,cl
  713.  
  714.     ; ensure volume is within range
  715.         cmp    ch,64
  716.         jb    @@la
  717.         mov    ch,63
  718.  
  719.     ; get old 43.. value
  720.     @@la:    mov    al,cs:Old43[bx]
  721.         and    al,0c0h        ; mask out volume bits
  722.         xor    ch,3fh
  723.         or    al,ch        ; insert volume
  724.         mov    cs:Old43[bx],al    ; keep new 43.. value
  725.  
  726.     ; write new volume into Adlib
  727.         mov    ah,cs:ChannelOffs[bx]
  728.         add    ah,23h
  729.         call    Adlib
  730.  
  731.         pop    bx ax
  732.         ret
  733.  
  734.  
  735.  
  736.  
  737.  
  738. ;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  739. ; Outputs a value to an ADLIB register.
  740. ; IN:
  741. ;    AH    - register no.
  742. ;    AL    - value
  743. ;──────────────────────────────────────────────────────────────────────────────
  744. Adlib:        push    ax dx
  745.  
  746.         mov    dx,cs:AdlibPort
  747.         xchg    ah,al
  748.         out    dx,al
  749.         rept    6
  750.         in    al,dx
  751.         endm
  752.  
  753.         inc    dx
  754.         mov    al,ah
  755.         out    dx,al
  756.         dec    dx
  757.         mov    ah,22
  758.     @@la:    in    al,dx
  759.         dec    ah
  760.         jnz    @@la
  761.  
  762.         pop    dx ax
  763.         ret
  764.  
  765.  
  766.  
  767.  
  768.  
  769.  
  770. AdlibPort    dw    388h        ; default Adlib base port
  771.  
  772. InstPtrs    dw    31 dup (0)    ; offsets of instrument data
  773. Old43        db    9 dup (0)    ; record of 43..   register values
  774. OldA0        db    9 dup (0)    ; record of A0..A8 register values
  775. OldB0        db    9 dup (0)    ; record of B0..B8 register values
  776.  
  777. ToneSlideSpeed    db    9 dup (1)    ; speed of tone slide
  778. ToneSlideFreqL    db    9 dup (?)    ; destination frequency of tone slide
  779. ToneSlideFreqH    db    9 dup (?)
  780.  
  781. ToneSlide    db    9 dup (?)    ; tone slide flag
  782. PortSlide    db    9 dup (?)    ; portamento slide
  783. VolSlide    db    9 dup (?)    ; volume slide
  784.  
  785. ModSeg        dw    ?    ; segment of module (starts at offset 0)
  786. Speed        db    ?    ; speed (n/50Hz) of tune
  787. SpeedCnt    db    ?    ; counter used for deriving speed
  788.  
  789. OrderSize    dw    ?    ; no. of entries in Order List
  790. OrderList    dw    ?    ; offset in module of Order List
  791. OrderPos    dw    ?    ; current playing position in Order List
  792.  
  793. PatternList    dw    ?    ; offset of pattern offset table in module
  794. PatternPos    dw    ?    ; offset to current line in current pattern
  795. Line        db    ?    ; current line being played (usually +1)
  796.