home *** CD-ROM | disk | FTP | other *** search
/ Frostbyte's 1980s DOS Shareware Collection / floppyshareware.zip / floppyshareware / NWUG / DIG.ZIP / VPMOD.ASM < prev    next >
Assembly Source File  |  1989-06-24  |  19KB  |  840 lines

  1. page 58,132
  2. .286c
  3. .MODEL LARGE
  4.  
  5. ;**********************************************************************
  6. ;*                                                                    *
  7. ;*                             Equates                                *
  8. ;*                                                                    *
  9. ;**********************************************************************
  10.  
  11. tccount        equ    72    ;reload count to produce 16572 Hz
  12. countmax_18hz    equ    910    ;ratio of new timer rate to old rate
  13.  
  14. tcaddrc        equ    43h    ;timer/counter control register address
  15. tcaddrd        equ    40h    ;timer/counter data register zero
  16.  
  17. tcmode        equ    34h    ;mode control byte for timer/counter
  18.  
  19. ppiaddr        equ    61h    ;programmable peripheral interface address
  20.  
  21. ;**********************************************************************
  22. ;*                                                                    *
  23. ;*                             Macros                                 *
  24. ;*                                                                    *
  25. ;**********************************************************************
  26.  
  27. ljz    macro    dest
  28.     local    skip
  29.     jnz    skip
  30.     jmp    dest
  31. skip:
  32.     endm
  33.  
  34. ljb    macro    dest
  35.     local    skip
  36.     jnb    skip
  37.     jmp    dest
  38. skip:
  39.     endm
  40.  
  41. ljbe    macro    dest
  42.     local    skip
  43.     jnbe    skip
  44.     jmp    dest
  45. skip:
  46.     endm
  47.  
  48. ;**********************************************************************
  49. ;*                                                                    *
  50. ;*                         Global variables                           *
  51. ;*                                                                    *
  52. ;**********************************************************************
  53.  
  54. .DATA
  55.         even        ;don't put these on an odd boundary
  56.  
  57. blockaddr    dd    0    ;beginning of memory block
  58. blocksize    dd    0    ;size of memory block
  59. blockend    dd    0    ;last address of memory block + 1
  60. currentaddr    dd    0    ;pointer to current play position in memory
  61. endaddr        dd    0    ;address of last byte to be played + 1
  62. datalength    dd    0    ;total number of data bytes
  63. datacount    dd    0    ;number of data bytes already played
  64. filladdr    dd    0    ;address of next byte to be filled from disk
  65. fillcount    dd    0    ;number of bytes already read from disk
  66.  
  67. goflag        dw    0    ;indicates whether playback is in progress
  68. fdoneflag    dw    0    ;indicates whether unread data remains in file
  69. fileflag    dw    0    ;indicates whether data is read from a file
  70. filehandle    dw    0    ;handle of file containing voice data
  71. hookedflag    dw    0    ;indicates whether the interrupt is hooked
  72. countfor_18hz    dw    0    ;counter to determine when to call BIOS
  73.  
  74. shiftcount    db    0    ;current bit position within byte
  75.  
  76. ;**********************************************************************
  77. ;*                                                                    *
  78. ;*                               Code                                 *
  79. ;*                                                                    *
  80. ;**********************************************************************
  81.  
  82. .CODE
  83.  
  84. bios_timer_routine    dd    0    ;we keep this in the code segment
  85.                     ; for access through the CS register
  86.                     ; since the other segment registers
  87.                     ; will contain unknown values when
  88.                     ; this is needed
  89.  
  90.     assume    ds:DGROUP
  91.  
  92. ;**********************************************************************
  93. ;*             Speed up the timer tick and set "goflag"               *
  94. ;**********************************************************************
  95.  
  96. startvoice    proc    near
  97.  
  98.     pushf
  99.     cli
  100.     mov    al,tcmode
  101.     out    tcaddrc,al
  102.     mov    ax,tccount
  103.     out    tcaddrd,al
  104.     mov    al,ah
  105.     out    tcaddrd,al
  106.     mov    shiftcount,0
  107.     mov    countfor_18hz,countmax_18hz
  108.     mov    goflag,1
  109.     popf
  110.     ret
  111.  
  112. startvoice    endp
  113.  
  114. ;**********************************************************************
  115. ;*         Slow the timer tick to normal and clear "goflag"           *
  116. ;**********************************************************************
  117.  
  118. stopvoice    proc    near
  119.  
  120.     pushf
  121.     cli
  122.     mov    al,tcmode
  123.     out    tcaddrc,al
  124.     mov    al,0
  125.     out    tcaddrd,al
  126.     out    tcaddrd,al
  127.     mov    goflag,0
  128.     mov    fdoneflag,0
  129.     popf
  130.     ret
  131.  
  132. stopvoice    endp
  133.  
  134. ;**********************************************************************
  135. ;*                   Interrupt service routine                        *
  136. ;**********************************************************************
  137.  
  138. timer_tick    proc    far
  139.  
  140.     push    ds
  141.     push    bx
  142.     push    es
  143.     push    ax
  144.     push    cx
  145.  
  146.     mov    ax,DGROUP
  147.     mov    ds,ax
  148.  
  149.     cmp    goflag,0
  150.     je    chain_exit
  151.  
  152.     les    bx,currentaddr
  153.     mov    ah,es:[bx]
  154.     mov    cl,shiftcount
  155.     rol    ah,cl
  156.     rol    ah,2
  157.     and    ah,02h
  158.     in    al,ppiaddr
  159.     and    al,0FCh
  160.     or    al,ah
  161.     out    ppiaddr,al
  162.     inc    cl
  163.     and    cl,07h
  164.     mov    shiftcount,cl
  165.     jnz    exit_decide
  166.  
  167.     mov    ax,es
  168.     inc    bx
  169.     jnz    check_wrap
  170.     add    ax,1000h
  171. check_wrap:
  172.     cmp    bx,word ptr blockend
  173.     jne    check_end
  174.     cmp    ax,word ptr blockend+2
  175.     jne    check_end
  176.     mov    bx,word ptr blockaddr
  177.     mov    ax,word ptr blockaddr+2
  178. check_end:
  179.     cmp    bx,word ptr endaddr
  180.     jne    save_cur_addr
  181.     cmp    ax,word ptr endaddr+2
  182.     jne    save_cur_addr
  183.     call    stopvoice
  184.     jmp    short exit_decide
  185. save_cur_addr:
  186.     mov    word ptr currentaddr,bx
  187.     mov    word ptr currentaddr+2,ax
  188.     add    word ptr datacount,1
  189.     adc    word ptr datacount+2,0
  190.  
  191. exit_decide:
  192.     dec    countfor_18hz
  193.     jnz    nochain_exit
  194.     mov    countfor_18hz,countmax_18hz
  195.  
  196. chain_exit:
  197.     pop    cx
  198.     pop    ax
  199.     pop    es
  200.     pop    bx
  201.     pop    ds
  202.     jmp    cs:bios_timer_routine
  203.  
  204. nochain_exit:
  205.     mov    al,20h
  206.     out    20h,al
  207.     pop    cx
  208.     pop    ax
  209.     pop    es
  210.     pop    bx
  211.     pop    ds
  212.     iret
  213.  
  214. timer_tick    endp
  215.  
  216. ;**********************************************************************
  217. ;*                   Initialization procedure                         *
  218. ;**********************************************************************
  219.  
  220. ;This routine should be called exactly one time before any of the other
  221. ; routines in this package are called. It takes no parameters, but returns
  222. ; a value indicating success or failure as follows:
  223.  
  224. ;Return value        Meaning
  225. ;------------        -------
  226. ;     0              success
  227. ;     1              voice package already initialized
  228. ;     2              wrong CPU, won't run on 8088 or 8086
  229.  
  230.     public    PVOICE_INIT
  231.  
  232. PVOICE_INIT    proc    far
  233.  
  234.     push    sp
  235.     pop    ax
  236.     cmp    ax,sp
  237.     je    vi_test
  238.     mov    ax,2
  239.     ret
  240.  
  241. vi_test:
  242.     cmp    hookedflag,0
  243.     je    vi_hook
  244.     mov    ax,1
  245.     ret
  246.  
  247. vi_hook:
  248.     enter    0,0
  249.     push    si
  250.     push    di
  251.  
  252.     push    ds
  253.     lea    dx,PVOICE_CBREAK
  254.     mov    ax,seg PVOICE_CBREAK
  255.     mov    ds,ax
  256.     mov    ax,2523h
  257.     int    21h
  258.     pop    ds
  259.  
  260.     push    ds
  261.     mov    ax,3508h
  262.     int    21h
  263.     mov    word ptr cs:bios_timer_routine,bx
  264.     mov    word ptr cs:bios_timer_routine+2,es
  265.     lea    dx,timer_tick
  266.     mov    ax,seg timer_tick
  267.     mov    ds,ax
  268.     mov    ax,2508h
  269.     int    21h
  270.     pop    ds
  271.  
  272.     pop    di
  273.     pop    si
  274.     mov    hookedflag,1
  275.     sub    ax,ax
  276.     leave
  277.     ret
  278.  
  279. PVOICE_INIT    endp
  280.  
  281. ;**********************************************************************
  282. ;*                      Cleanup procedure                             *
  283. ;**********************************************************************
  284.  
  285. ;This will restore the interrupt 8 vector to its original state. This
  286. ; routine MUST be called before the main program exits to DOS, unless:
  287. ; (a) the program has never called PVOICE_INIT, or (b) the program is
  288. ; becoming memory-resident.
  289.  
  290. ;There are no parameters. The return values are 0 for success or 1 if
  291. ; the interrupt vector was not in fact hooked.
  292.  
  293.     public    PVOICE_CLEANUP
  294.  
  295. PVOICE_CLEANUP    proc    far
  296.  
  297.     cmp    hookedflag,1
  298.     je    vc_unhook
  299.     mov    ax,1
  300.     ret
  301.  
  302. vc_unhook:
  303.     enter    0,0
  304.     push    si
  305.     push    di
  306.     call    stopvoice
  307.     push    ds
  308.     lds    dx,cs:bios_timer_routine
  309.     mov    ax,2508h
  310.     int    21h
  311.     pop    ds
  312.     pop    di
  313.     pop    si
  314.     mov    hookedflag,0
  315.     sub    ax,ax
  316.     leave
  317.     ret
  318.  
  319. PVOICE_CLEANUP    endp
  320.  
  321. ;**********************************************************************
  322. ;*                Vector restore for Control-Break                    *
  323. ;**********************************************************************
  324.  
  325.     public    PVOICE_CBREAK
  326.  
  327. PVOICE_CBREAK    proc    far
  328.  
  329.     pusha
  330.     push    ds
  331.     push    es
  332.  
  333.     mov    ax,DGROUP
  334.     mov    ds,ax
  335.     call    stopvoice
  336.     call    PVOICE_CLEANUP
  337.  
  338.     pop    es
  339.     pop    ds
  340.     popa
  341.     stc
  342.     ret
  343.  
  344. PVOICE_CBREAK    endp
  345.  
  346. ;**********************************************************************
  347. ;*                "File read catch-up" procedure                      *
  348. ;**********************************************************************
  349.  
  350. ;This must be called frequently from the main program if file reading is
  351. ; being used and the length of the data to be played is longer than the
  352. ; length of the memory block. The routine checks the progress of the
  353. ; address pointer in use by the interrupt service routine and fills in
  354. ; more data from the file if necessary. When all the data has been read,
  355. ; then "endaddr" is set accordingly.
  356.  
  357. ;There are no parameters. The return values are 0 for success or 1 if
  358. ; an error occurred while reading the file.
  359.  
  360. vcat_temp1l        equ    [bp-4]    ;current address from ISR
  361. vcat_temp1h        equ    [bp-2]
  362.  
  363. ;the four stopping points:
  364.  
  365. vcat_temp2l        equ    [bp-8]    ;data length - fill count
  366. vcat_temp2h        equ    [bp-6]
  367. vcat_temp3l        equ    [bp-12]    ;current address - fill address
  368. vcat_temp3h        equ    [bp-10]
  369. vcat_temp4l        equ    [bp-16]    ;block end - fill address
  370. vcat_temp4h        equ    [bp-14]
  371. vcat_temp5l        equ    [bp-20]    ;(boundary) - fill address
  372. vcat_temp5h        equ    [bp-18]
  373.  
  374. vcat_templength        equ    20
  375.  
  376.     public    PVOICE_CATCHUP
  377.  
  378. PVOICE_CATCHUP    proc    far
  379.  
  380.     enter    vcat_templength,0
  381.  
  382. ;should we even be doing this?
  383.  
  384.     cmp    fileflag,0
  385.     ljz    vcat_exit0
  386.     cmp    fdoneflag,0
  387.     ljz    vcat_exit0
  388.  
  389. ;grab a stable value from currentaddr
  390. ; since it is changing all the time
  391.  
  392.     cli
  393.     mov    ax,word ptr currentaddr
  394.     mov    vcat_temp1l,ax
  395.     mov    ax,word ptr currentaddr+2
  396.     mov    vcat_temp1h,ax
  397.     sti
  398.  
  399. ;calculate the forward distance to each of the
  400. ; four possible stopping points
  401.  
  402. vcat_getlengths:
  403.     mov    ax,word ptr datalength
  404.     sub    ax,word ptr fillcount
  405.     mov    vcat_temp2l,ax
  406.     mov    ax,word ptr datalength+2
  407.     sbb    ax,word ptr fillcount+2
  408.     mov    vcat_temp2h,ax
  409.     or    ax,vcat_temp2l
  410.     jnz    vcat_getgap
  411.  
  412.     ;if datalength = fillcount then all
  413.     ; data has been read
  414.  
  415.     cli
  416.     mov    ax,word ptr filladdr
  417.     mov    word ptr endaddr,ax
  418.     mov    ax,word ptr filladdr+2
  419.     mov    word ptr endaddr+2,ax
  420.     sti
  421.     mov    fdoneflag,0
  422.  
  423.     jmp    vcat_exit0
  424.  
  425. vcat_getgap:
  426.     mov    ax,vcat_temp1l
  427.     sub    ax,word ptr filladdr
  428.     mov    vcat_temp3l,ax
  429.     pushf
  430.     mov    ax,vcat_temp1h
  431.     sub    ax,word ptr filladdr+2
  432.     sar    ax,12
  433.     popf
  434.     sbb    ax,0
  435.     mov    vcat_temp3h,ax
  436.     or    ax,vcat_temp3l
  437.     jnz    vcat_getclearance
  438.     mov    vcat_temp3l,0FFFFh
  439.     mov    vcat_temp3h,0FFFFh
  440.  
  441. vcat_getclearance:
  442.     mov    ax,word ptr blockend
  443.     sub    ax,word ptr filladdr
  444.     mov    vcat_temp4l,ax
  445.     pushf
  446.     mov    ax,word ptr blockend+2
  447.     sub    ax,word ptr filladdr+2
  448.     sar    ax,12
  449.     popf
  450.     sbb    ax,0
  451.     mov    vcat_temp4h,ax
  452.  
  453.     mov    ax,word ptr filladdr
  454.     neg    ax
  455.     mov    vcat_temp5l,ax
  456.     mov    word ptr vcat_temp5h,0
  457.     jnz    vcat_cmp1
  458.     inc    word ptr vcat_temp5h
  459.  
  460. ;select the stopping point which will be
  461. ; encountered soonest
  462.  
  463. ;Since we are not interested in the negative
  464. ; values, doing unsigned compares in a search
  465. ; for the smallest number will give the
  466. ; desired result.
  467.  
  468. vcat_cmp1:
  469.     mov    ax,vcat_temp2h
  470.     mov    cx,vcat_temp2l
  471.  
  472.     cmp    ax,vcat_temp3h
  473.     jb    vcat_cmp3
  474.     ja    vcat_cmp2
  475.     cmp    cx,vcat_temp3l
  476.     jb    vcat_cmp3
  477.  
  478. vcat_cmp2:
  479.     mov    ax,vcat_temp3h
  480.     mov    cx,vcat_temp3l
  481.  
  482.  
  483. vcat_cmp3:
  484.     cmp    ax,vcat_temp4h
  485.     jb    vcat_cmp5
  486.     ja    vcat_cmp4
  487.     cmp    cx,vcat_temp4l
  488.     jb    vcat_cmp5
  489.  
  490. vcat_cmp4:
  491.     mov    ax,vcat_temp4h
  492.     mov    cx,vcat_temp4l
  493.  
  494.  
  495. vcat_cmp5:
  496.     cmp    ax,vcat_temp5h
  497.     jb    vcat_cmp7
  498.     ja    vcat_cmp6
  499.     cmp    cx,vcat_temp5l
  500.     jb    vcat_cmp7
  501.  
  502. vcat_cmp6:
  503.     mov    ax,vcat_temp5h
  504.     mov    cx,vcat_temp5l
  505.  
  506.  
  507. vcat_cmp7:
  508.  
  509. ;Now the smallest number is in AX:CX.
  510. ; However, AX:CX may be 65536 or 0FFFFh
  511. ; (illegal), so we must test for these
  512. ; possibilities.
  513.  
  514.     cmp    ax,1
  515.     je    vcat_fixcx
  516.     cmp    cx,0FFFFh
  517.     jne    vcat_readfile
  518.  
  519. vcat_fixcx:
  520.     mov    cx,0FE00h
  521.     sub    ax,ax
  522.  
  523. vcat_readfile:
  524.     mov    bx,filehandle
  525.     push    ds
  526.     lds    dx,filladdr
  527.     mov    ah,3Fh
  528.     int    21h
  529.     pop    ds
  530.     jc    vcat_error1
  531.     cmp    ax,cx
  532.     jne    vcat_error1
  533.  
  534. ;update global varibles to show the current
  535. ; situation
  536.  
  537.     add    word ptr fillcount,cx
  538.     adc    word ptr fillcount+2,0
  539.  
  540.     add    word ptr filladdr,cx
  541.     jnc    vcat_fillwrap
  542.     add    word ptr filladdr+2,1000h
  543.  
  544. vcat_fillwrap:
  545.     mov    bx,word ptr blockend
  546.     cmp    bx,word ptr filladdr
  547.     jne    vcat_exit0
  548.     mov    ax,word ptr blockend+2
  549.     cmp    ax,word ptr filladdr+2
  550.     jne    vcat_exit0
  551.     mov    bx,word ptr blockaddr
  552.     mov    ax,word ptr blockaddr+2
  553.     mov    word ptr filladdr,bx
  554.     mov    word ptr filladdr+2,ax
  555.  
  556.     jmp    short vcat_exit0
  557.  
  558. ;error exit point
  559.  
  560. vcat_error1:
  561.     mov    ax,1
  562.     jmp    short vcat_exit
  563.  
  564. ;normal exit point
  565.  
  566. vcat_exit0:
  567.  
  568.     ;don't leave until at least one bit has been played
  569.     ; or goflag becomes zero
  570.  
  571.     mov    ax,word ptr currentaddr
  572.     cmp    vcat_temp1l,ax
  573.     jne    vcat_exitloop
  574.     cmp    goflag,0
  575.     jne    vcat_exit0
  576. vcat_exitloop:
  577.     sub    ax,ax
  578. vcat_exit:
  579.     leave
  580.     ret
  581.  
  582. PVOICE_CATCHUP    endp
  583.  
  584. ;**********************************************************************
  585. ;*                   "Start playback" procedure                       *
  586. ;**********************************************************************
  587.  
  588. ;Accepts the following parameters with PASCAL parameter-passing convention:
  589.  
  590. ;Position   Size   Description
  591. ;--------   ----   -----------
  592. ;   1         4    A far pointer to the memory block used for voice data.
  593. ;   2         4    A dword indicating the length of the memory block.
  594. ;   3         2    A flag word. If this is 1, then data will be read from
  595. ;                   a file. If it is 0, then the data is assumed to be
  596. ;                   already present in the memory block.
  597. ;   4         2    An open file handle. This is ignored if the flag word
  598. ;                   is 0.
  599. ;   5         4    A dword indicating the number of bytes of voice data
  600. ;                   to be played. If the flag word is 0, then this number
  601. ;                   must not be greater than the length of the memory
  602. ;                   block.
  603. ;   6         4    A dowrd indicating the offset within the memory block
  604. ;                   where playback is to begin. This number must be less
  605. ;                   than the block length.
  606.  
  607. ;Return value        Meaning
  608. ;------------        -------
  609. ;     0              success
  610. ;     1              data length greater than block size but no file read
  611. ;     2              block size is too small (datalength > blocksize and
  612. ;                     blocksize < 8192 and file read = yes)
  613. ;     3              unable to read from file
  614. ;     4              voice playback is already in progress
  615. ;     5              starting offset is not less than block length
  616.  
  617. min_blocksize    equ    8192
  618.  
  619. vs_parm1    equ    [bp+22]    ;length = 4
  620. vs_parm2    equ    [bp+18]    ;length = 4
  621. vs_parm3    equ    [bp+16]    ;length = 2
  622. vs_parm4    equ    [bp+14]    ;length = 2
  623. vs_parm5    equ    [bp+10]    ;length = 4
  624. vs_parm6    equ    [bp+6]    ;length = 4
  625.  
  626. vs_parmlength    equ    20
  627.  
  628.     public    PVOICE_START
  629.  
  630. PVOICE_START    proc    far
  631.  
  632.     cmp    goflag,0
  633.     je    vs_begin
  634.     mov    ax,4
  635.     ret    vs_parmlength
  636.  
  637. vs_begin:
  638.     enter    0,0
  639.     mov    word ptr datacount,0
  640.     mov    word ptr datacount+2,0
  641.     mov    word ptr fillcount,0
  642.     mov    word ptr fillcount+2,0
  643.  
  644.     les    bx,dword ptr vs_parm1
  645.     mov    word ptr blockaddr,bx
  646.     mov    word ptr blockaddr+2,es
  647.     les    bx,dword ptr vs_parm6
  648.     mov    ax,es
  649.     add    bx,word ptr blockaddr
  650.     adc    ax,0
  651.     shl    ax,12
  652.     add    ax,word ptr blockaddr+2
  653.     mov    word ptr currentaddr,bx
  654.     mov    word ptr currentaddr+2,ax
  655.     mov    word ptr filladdr,bx
  656.     mov    word ptr filladdr+2,ax
  657.     les    bx,dword ptr vs_parm2
  658.     mov    word ptr blocksize,bx
  659.     mov    word ptr blocksize+2,es
  660.     mov    ax,es
  661.     add    bx,word ptr blockaddr
  662.     adc    ax,0
  663.     shl    ax,12
  664.     add    ax,word ptr blockaddr+2
  665.     mov    word ptr blockend,bx
  666.     mov    word ptr blockend+2,ax
  667.     cmp    ax,word ptr currentaddr+2
  668.     ljb    vs_error5
  669.     ja    vs_getdatalen
  670.     cmp    bx,word ptr currentaddr
  671.     ljbe    vs_error5
  672.  
  673. vs_getdatalen:
  674.     les    bx,dword ptr vs_parm5
  675.     mov    word ptr datalength,bx
  676.     mov    word ptr datalength+2,es
  677.     mov    ax,vs_parm4
  678.     mov    filehandle,ax
  679.     mov    ax,vs_parm3
  680.     mov    fileflag,ax
  681.  
  682.     or    ax,ax
  683.     jz    vs_check
  684.  
  685.     mov    fdoneflag,1
  686.     mov    word ptr endaddr,0
  687.     mov    word ptr endaddr+2,0
  688.     mov    ax,word ptr blocksize
  689.     sub    ax,word ptr datalength
  690.     mov    ax,word ptr blocksize+2
  691.     sbb    ax,word ptr datalength+2
  692.     jnc    vs_catch
  693.     mov    ax,word ptr blocksize
  694.     sub    ax,min_blocksize
  695.     mov    ax,word ptr blocksize+2
  696.     sbb    ax,0
  697.     jc    vs_error2
  698.  
  699. vs_catch:
  700.     call    PVOICE_CATCHUP
  701.     or    ax,ax
  702.     jnz    vs_error3
  703.     jmp    short vs_exit0
  704.  
  705. vs_check:
  706.     mov    ax,word ptr datalength+2
  707.     cmp    ax,word ptr blocksize+2
  708.     ja    vs_error1
  709.     jb    vs_setend
  710.     mov    ax,word ptr datalength
  711.     cmp    ax,word ptr blocksize
  712.     ja    vs_error1
  713.     jb    vs_setend
  714.  
  715.     mov    ax,word ptr blockaddr
  716.     mov    word ptr endaddr,ax
  717.     mov    ax,word ptr blockaddr+2
  718.     mov    word ptr endaddr+2,ax
  719.     jmp    short vs_exit0
  720.  
  721. vs_setend:
  722.     les    bx,dword ptr vs_parm5
  723.     mov    ax,es
  724.     add    bx,word ptr blockaddr
  725.     adc    ax,0
  726.     shl    ax,12
  727.     add    ax,word ptr blockaddr+2
  728.     mov    word ptr endaddr,bx
  729.     mov    word ptr endaddr+2,ax
  730.     jmp    short vs_exit0
  731.  
  732. vs_error1:
  733.     mov    ax,1
  734.     jmp    short vs_exit
  735.  
  736. vs_error2:
  737.     mov    ax,2
  738.     jmp    short vs_exit
  739.  
  740. vs_error3:
  741.     mov    ax,3
  742.     jmp    short vs_exit
  743.  
  744. vs_error5:
  745.     mov    ax,5
  746.     jmp    short vs_exit
  747.  
  748. vs_exit0:
  749.     call    startvoice
  750.     sub    ax,ax
  751. vs_exit:
  752.     leave
  753.     ret    vs_parmlength
  754.  
  755. PVOICE_START    endp
  756.  
  757. ;**********************************************************************
  758. ;*                   "Stop playback" procedure                        *
  759. ;**********************************************************************
  760.  
  761. ;This is used when it is necessary to stop the playback before all
  762. ; data has been output to the speaker.
  763.  
  764. ;This routine accepts no parameters and has no return information.
  765.  
  766.     public    PVOICE_STOP
  767.  
  768. PVOICE_STOP    proc    far
  769.  
  770.     call    stopvoice
  771.     sub    ax,ax
  772.     ret
  773.  
  774. PVOICE_STOP    endp
  775.  
  776. ;**********************************************************************
  777. ;*                     "Get status" procedure                         *
  778. ;**********************************************************************
  779.  
  780. ;This will supply certain status information about the operation of the
  781. ; voice playback routines.
  782.  
  783. ;The first parameter is a far pointer to a dword which will receive the
  784. ; number of bytes which have already been output to the speaker.
  785.  
  786. ;The second parameter is a far pointer to a dword which will receive the
  787. ; offset within the memory block of the byte that will be played next.
  788.  
  789. ;The return value is a flag word in which the lowest two bits are
  790. ; significant:
  791.  
  792. ;Bit #      Meaning if 1
  793. ;-----      ------------
  794. ;  0        playback is still in progress
  795. ;  1        unread data remains in file
  796.  
  797.  
  798. vst_parm1    equ    [bp+10]    ;length = 4
  799. vst_parm2    equ    [bp+6]    ;length = 4
  800.  
  801. vst_parmlength    equ    8
  802.  
  803.     public    PVOICE_STATUS
  804.  
  805. PVOICE_STATUS    proc    far
  806.  
  807.     enter    0,0
  808.  
  809.     les    bx,vst_parm1
  810.     cli
  811.     mov    ax,word ptr datacount
  812.     mov    dx,word ptr datacount+2
  813.     mov    es:[bx],ax
  814.     mov    es:[bx+2],dx
  815.     les    bx,vst_parm2
  816.     mov    ax,word ptr currentaddr
  817.     mov    dx,word ptr currentaddr+2
  818.     sti
  819.     shr    dx,12    ;we can cheat here because we
  820.             ; know it's incremented by 1000h units
  821.     mov    cx,word ptr blockaddr+2
  822.     shr    cx,12
  823.     sub    ax,word ptr blockaddr
  824.     sbb    dx,cx
  825.     mov    es:[bx],ax
  826.     mov    es:[bx+2],dx
  827.  
  828.     cli
  829.     mov    ax,fdoneflag
  830.     shl    ax,1
  831.     or    ax,goflag
  832.     sti
  833.  
  834.     leave
  835.     ret    vst_parmlength
  836.  
  837. PVOICE_STATUS    endp
  838.  
  839.     end
  840.