Metropoli BBS
VIEWER: x01.bas MODE: TEXT (ASCII)
DECLARE FUNCTION InitDevice% (device%, SIP AS ANY, IP AS ANY)
DECLARE FUNCTION PickDevice% (SIP AS ANY, XMSflag%)

REM $INCLUDE: 'RUCKDAC.BI'

'--------------------------------------
'SEE X01_71.BAS FOR BASIC7/VBDOS EXAMPLE
'--------------------------------------

'X01.BAS - load and play digital data file into DOS memory
'
'        - The SB is always played in DMA mode in this example, this means
'        - that stereo or high-sample rate files will not play correctly;
'        - they will play correctly on an SB PRO or on the other devices.
'        - To play stereo or high-sample rate files on the SB, PBP.Mode
'        - must be set to either 0 or 1 (i.e., non-SB/DMA mode).
'
'31-Jan-93 -chh
'C>bc X01 /o;
'C>link X01,X01.EXE,nul,RUCKDAC.LIB;
ver$ = "[930131]"

DEFINT A-Z

'The packs could be made global but passing them as paramters works

DIM SIP AS SysInfoPackTYPE
DIM IP AS InitPackTYPE
DIM LP AS LoadPackTYPE
DIM SP AS SetPackTYPE
DIM PBP AS PlaybackPackTYPE
DIM GDP AS GetDataPackTYPE
DIM DP AS DeallocPackTYPE
DIM XP AS XitPackTYPE

CLS
PRINT "X01.BAS - RUCKUS-DAC play of VOC or WAVE file example."; ver$

InIDE = -1     'since the IDE needs more than 2K available, use this to
               'flag if operating in QB's ennvironment

'RUCKDAC uses memory from the operating system pool
'since BASIC starts up claiming all memory, instruct it to return excess
'memory back to OS pool

nix& = SETMEM(700000)           'return to QB environment any previous release
nix& = SETMEM(0)                'see how much is available
nix& = nix& - 2100              'release all but 2K to operating system

IF InIDE THEN
   nix& = nix& - 66000          'leave 64K more for IDE
   XP.Func = ExitDac            'and shut down any loose ends
   nix = RUCKDAC(XP)
END IF

nix& = SETMEM(-nix&)            'this call does the actual release

'pick device to use

devID = PickDevice(SIP, XMSflag)'id system and get device to use
IF devID < 0 THEN PRINT "Ended.": END

CLS
LOCATE 5

'initialize the selected device and register ExitDac via AtExitDac

stat = InitDevice(devID, SIP, IP)
IF stat = 0 THEN
   
   'The following load and play example source is coded inline here
   'to simplify readability -- but it's so easy to add things I just
   'kept adding stuff, so take it slow if you don't follow at first

   'load file and setup playback parameters

   INPUT "VOC/WAVE filename: ", filename$
   filename$ = filename$ + CHR$(0)        'DOS requires ASCIIZ name
   LP.Func = LoadDac

   LP.FilenamePtrOff = SADD(filename$)    'QB format
   LP.FilenamePtrSeg = VARSEG(filename$)
   'LP.FilenamePtrOff = SADD(filename$)    'BASIC7 format
   'LP.FilenamePtrSeg = SSEG(filename$)

   LP.StartPos = 0&     'start load at byte 0 of filename$
   LP.LoadSize = 0&     'load entire file
   LP.XMMflag = XMSflag 'load into DOS or XMS memory (selected in PickDevice)
   stat = RUCKDAC(LP)

   IF stat = 0 THEN
   
      'immediately after load, but before play if non-DMA, we can peek
      'into the DAC data to get the file's recorded sample rate, in case
      'of SR > 32767, we just add 65536 to get unsigned value

      DEF SEG = IP.InfoPtrSeg
      bp = IP.InfoPtrOff
      fileSR& = 256 * PEEK(bp + 25) + PEEK(bp + 24)
      IF fileSR& < 0 THEN fileSR& = fileSR& + 65536
      PRINT " Sample rate:"; fileSR&; "Hz (at load time)"
      PRINT " File format: ";
      IsStereo = PEEK(bp + 26)
      FormatIs = PEEK(bp + 20)
      IF IsStereo THEN PRINT "Stereo";  ELSE PRINT "Mono";
      IF FormatIs = 1 THEN PRINT " voc" ELSE PRINT " wave"
      DEF SEG

      'data is loaded, if device is a Sound Blaster, use DMA at
      'file sample rate else set rate to either file sample rate, or
      'if > 11025 (most ATs can handle 11kHz in non-DMA mode), set to 8000

      PBP.Func = PlayDac
      IF devID >= 4 THEN
         PBP.Mode = 2
      ELSE
         SP.Func = SetIntRateDac

         'to play hal.voc using PCSPKR1 (the hi-rez mode) set
         'SP.IntRate=8463. This results in an upsample rate of 17045Hz

         IF fileSR& < 11025 THEN     'if the recorded sample rate is <11025
            SP.IntRate = fileSR&     'according to the VOC or WAVE file hdr
         ELSE                        'then just go ahead and use that, else
            SP.IntRate = 8000        'down sample to 8000 (or closest fit)
         END IF

         stat = RUCKDAC(SP)

         IF stat THEN
            PRINT "Unexpected error at SetIntRateDac, stat:"; stat
            END
         END IF

         PBP.Mode = 1
      END IF

      IF LP.XMMflag = 0 THEN
         PBP.XMMhandle = 0
         PBP.LoadPtrOff = LP.LoadPtrOff
         PBP.LoadPtrSeg = LP.LoadPtrSeg
      ELSE
         PBP.XMMhandle = LP.XMMhandle
         PBP.LoadPtrOff = 0
         PBP.LoadPtrSeg = 0
         IF PBP.Mode < 2 THEN PRINT "Loading into XMS requires DMA mode.": END
      END IF
      stat = RUCKDAC(PBP)

      IF stat = 0 THEN

         'Playing in the background, wait until done or key pressed.
         'To check if data done playing, read directly into DAC data segment
         'and check to word at offset +10. Checking just the byte will do.

         DEF SEG = IP.InfoPtrSeg
         bp = IP.InfoPtrOff

         actualSR& = 256& * PEEK(bp + 25) + PEEK(bp + 24)
         IF actualSR& < 0 THEN actualSR& = actualSR& + 65536

         usedK = 256 * PEEK(bp + 23) + PEEK(bp + 22)
         DOSleftK = 256 * PEEK(bp + 17) + PEEK(bp + 16)
         XMSleftK = 256 * PEEK(bp + 19) + PEEK(bp + 18)

         PRINT "   Device ID:"; devID
         PRINT "   Play rate:"; actualSR&; "Hz"

         IF LP.XMMflag = 0 THEN
            PRINT " Memory type: DOS"
            PRINT "K bytes left:"; DOSleftK
            PRINT "K bytes used:"; usedK
            PRINT "Load address: "; RIGHT$("000" + HEX$(LP.LoadPtrSeg), 4) + ":" + RIGHT$("000" + HEX$(LP.LoadPtrOff), 4)
         ELSE
            PRINT " Memory type: XMS"
            PRINT "K bytes left:"; XMSleftK
            PRINT "K bytes used:"; usedK
            PRINT "  XMS handle:"; LP.XMMhandle
         END IF

         PRINT "Current byte: ";
         CurrRow = CSRLIN
         CurrCol = POS(0)

         byte& = 0&
         DO
            DacIsDone = PEEK(bp + 10)

            'do something to demonstate playback is a background operation
            'here we just get the current byte position and print if not 0

            LOCATE CurrRow, CurrCol
            GDP.Func = GetBytePosDac
            nix = RUCKDAC(GDP)

            IF GDP.BytePos <> 0 THEN byte& = GDP.BytePos
            PRINT RIGHT$("000000" + HEX$(byte&), 7)

         LOOP UNTIL (DacIsDone <> 0) OR LEN(INKEY$)
         DEF SEG

         'end play

         XP.Func = EndDac
         stat = RUCKDAC(XP)

         'release memory used by LoadDac (ExitDac would do that, too)

         DP.Func = DeallocDac
         IF LP.XMMflag = 0 THEN
            DP.HandSeg = LP.LoadPtrSeg
            DP.TypeFlag = 0
         ELSE
            DP.HandSeg = LP.XMMhandle
            DP.TypeFlag = 1
         END IF
         stat = RUCKDAC(DP)

      ELSE
         PRINT "Play of "; filename$; "failed, stat:"; stat
      END IF

   ELSE
      PRINT "Load of "; filename$; "failed, stat:"; stat
   END IF

ELSE
   PRINT "InitDevice failed, stat:"; stat
END IF

'shut down RUCKDAC and end program

XP.Func = ExitDac
nix = RUCKDAC(XP)
PRINT "  Done, stat:"; stat
nix& = SETMEM(700000)   'return to QB environment any previous release
END

FUNCTION InitDevice (device, SIP AS SysInfoPackTYPE, IP AS InitPackTYPE)

'Initialize RUCKDAC and device and register ExitDac with _atexit
'The IP.port for devices 0 and 3 are set to 0 for low-rez mode, or their
'repective actual ports for hi-rez mode (&H42 and &H388)

DIM XP AS XitPackTYPE   'local use for AtExitDac

IP.Func = InitDac
IP.DeviceID = device
SELECT CASE device
CASE 0: IP.IOport = 0:          IP.IRQline = SIP.D0IRQ: IP.DMAch = SIP.D0DMA
CASE 1: IP.IOport = SIP.D1port: IP.IRQline = SIP.D1IRQ: IP.DMAch = SIP.D1DMA
CASE 2: IP.IOport = SIP.D2port: IP.IRQline = SIP.D2IRQ: IP.DMAch = SIP.D2DMA
CASE 3: IP.IOport = 0:          IP.IRQline = SIP.D3IRQ: IP.DMAch = SIP.D3DMA
CASE 4: IP.IOport = SIP.D4port: IP.IRQline = SIP.D4IRQ: IP.DMAch = SIP.D4DMA
CASE 5: IP.IOport = SIP.D5port: IP.IRQline = SIP.D5IRQ: IP.DMAch = SIP.D5DMA
END SELECT
stat = RUCKDAC(IP)

IF stat = 0 THEN

   'register ExitDac and notify if failure occured, non-fatal and unlikely

   XP.Func = AtExitDac
   stat2 = RUCKDAC(XP)
   IF stat2 THEN INPUT "AtExitDac failed, press ENTER to continue", a$
END IF

InitDevice = stat

END FUNCTION

FUNCTION PickDevice (SIP AS SysInfoPackTYPE, XMSflag)

'RUCKDAC SysInfoDac lib routine called to find available devices
'user prompted which device to use (0-5), -1 means no valid selection
'if XMSflag = 1 on return, user selected XMS load of data

DIM device AS INTEGER

device = -1
XMSflag = 0

SIP.Func = SysInfoDac
stat = RUCKDAC(SIP)
IF stat = 0 THEN

   'list devices that are available
   PRINT
   PRINT "0. End program"
   PRINT "1. PC speaker at port 42h"
   IF SIP.Device1 THEN PRINT "2. LPT-DAC on LPT1, port "; HEX$(SIP.D1port); "h"
   IF SIP.Device2 THEN PRINT "3. Disney Sound System port "; HEX$(SIP.D2port); "h"
   PRINT
   IF SIP.Device3 THEN PRINT "4. AdLib Music Synthesizer Card, port 388h"
   IF SIP.Device4 THEN PRINT "5. Sound Blaster, port "; HEX$(SIP.D4port); "h, IRQ"; SIP.D4IRQ; "and DMA 1"
   IF SIP.Device5 THEN PRINT "6. Sound Blaster Pro, port "; HEX$(SIP.D5port); "h, IRQ"; SIP.D5IRQ; "and DMA"; SIP.D5DMA
   PRINT
   IF SIP.Device4 THEN PRINT "7. Sound Blaster as 5 but use XMS (if applicable)"
   IF SIP.Device5 THEN PRINT "8. Sound Blaster Pro as 6 but use XMS (if applicable)"

   PRINT
   INPUT "Selection: ", device
   device = device - 1

   'ensure device selected is available

   SELECT CASE device
   CASE 0
   CASE 1: IF SIP.Device1 = 0 THEN device = -1
   CASE 2: IF SIP.Device2 = 0 THEN device = -1
   CASE 3: IF SIP.Device3 = 0 THEN device = -1
   CASE 4: IF SIP.Device4 = 0 THEN device = -1
   CASE 5: IF SIP.Device5 = 0 THEN device = -1
   CASE 6: IF SIP.Device4 = 0 THEN device = -1 ELSE device = 4: XMSflag = 1
   CASE 7: IF SIP.Device5 = 0 THEN device = -1 ELSE device = 5: XMSflag = 1
   CASE ELSE
      device = -1
   END SELECT

END IF

PickDevice = device

END FUNCTION

[ RETURN TO DIRECTORY ]