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

REM $INCLUDE: 'RUCKDAC.BI'

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

'X02.BAS - load and play mod data file from DOS memory
'
'31-Jan-93 -chh
'C>bc X02 /o;
'C>link X02,X02.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 SMP AS SetModPackTYPE
DIM PBP AS PlaybackPackTYPE
DIM XP AS XitPackTYPE

CLS
PRINT "X02.BAS - RUCKUS-DAC play of MOD 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 = ExitMod            '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, HighRate)'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 " MOD filename: ", filename$
   PRINT "Playback rate:              ( 5000 to "; HighRate; ")";
   LOCATE , 16
   INPUT "", SampleRate
   IF SampleRate < 5000 THEN SampleRate = 5000
   IF SampleRate > HighRate THEN SampleRate = HighRate

   filename$ = filename$ + CHR$(0)        'DOS requires ASCIIZ name
   LP.Func = LoadMod

   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 = 0       'load into DOS
   stat = RUCKDAC(LP)

   IF stat = 0 THEN
   
      'data is loaded, set up play parameters

      IF devID = 5 THEN         'just a quick bump of the Pro's out volumes
         SPP.Func = SetVolMainSBP
         SPP.Volume = &HF0F
         stat = RUCKDAC(SPP)

         SPP.Func = SetVolVocSBP
         SPP.VolVoc = &HF0F
         stat = RUCKDAC(SPP)   'see RUCKUS-MIDI for AdLib/FM volume adjust
      END IF

      SMP.VolCh1 = 255
      SMP.VolCh2 = 255
      SMP.VolCh3 = 255
      SMP.VolCh4 = 255
      SMP.Func = SetVolumeMod
      stat = RUCKDAC(SMP)
   
      IF devID < 5 THEN SMP.Stereo = 0 ELSE SMP.Stereo = 1
      SMP.Func = SetStereoMod
      stat = RUCKDAC(SMP)

      SMP.IntRate = SampleRate  'IntRate and SliceAdj set with SetIntRateMod

      'The SBPro doubles the sample rate when doing stereo output so
      'here we double the requested rate to rate needed by SBPRO. This
      'should be done _AFTER_ the SetStereoMod call above.

      IF SMP.Stereo THEN        'this routine converts sample rates >32K
         t& = 2& * SampleRate   'to a signed integer value
         IF t& > 32767 THEN t& = t& - 65536
         SMP.IntRate = t&
      END IF

      SMP.Func = SetIntRateMod  'error checking typically should always
      stat = RUCKDAC(SMP)       'be performed but not here for clarity


      SMP.FastMode = 0         'on slow CPUs (XTs) set this to 1
      SMP.SliceAdj = 1         'fill DMA buffer 1 byte at a time (to 4K)
      SMP.Func = SetFastMod    'and call SetFastMod function
      stat = RUCKDAC(SMP)

      'if device is a Sound Blaster, use DMA+FG, else timer-0 FG

      PBP.Func = PlayMod
      IF devID < 4 THEN PBP.Mode = 0 ELSE PBP.Mode = 2

      'for timer-0 background play set PBP.Mode = 1 and for DMA background
      'play set PBP.Mode = 3 -- you must also poll dac@endmod in the
      'RUCKUS-DAC data area (offset +14) and wait until it is non-zero
      'to determine if mod playback has completed

      'for complete compatibilty mod play is done as a foreground task
      'in this example

      PRINT "Playing as a foreground ";
      IF devID >= 4 THEN PRINT "DMA";  ELSE PRINT "TIMER-0";
      PRINT " task ";
      IF devID = 5 THEN PRINT "in ((STEREO)) ";
      PRINT "at"; SampleRate; "Hz mix rate"
      PRINT
      PRINT "Press CTRL-ALT to end or wait until tune is over."

      'note that the PC speaker playback may sound better if the
      'keyboard pause button is activated, try it

      PBP.XMMhandle = 0
      'Note that PBP.LoadPtrOff/Seg is not used with mod playback since
      'only one mod can be in memory at a time
      PBP.BufferSize = 4096           'each DMA buffer (2) is this size
      stat = RUCKDAC(PBP)             'and allocated for SBs only (2048-64K)

      IF stat = 0 THEN

         'Playing in the foreground, wait until done or Ctrl-Alt pressed.
         'Won't get here until CTRL-ALT is pressed or end of tune

         'end play

         XP.Func = EndMod
         stat = RUCKDAC(XP)

         'to release memory used by LoadMod use ExitMod

      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 = ExitMod
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 ExitMod with _atexit

DIM XP AS XitPackTYPE   'local use for AtExitMod

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 ExitMod and notify if failure occured, non-fatal and unlikely

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

END IF

InitDevice = stat

END FUNCTION

FUNCTION PickDevice (SIP AS SysInfoPackTYPE, HighRate)

'RUCKDAC SysInfoDac lib routine called to find available devices
'user prompted which device to use (0-5), -1 means no valid selection
'HighRate returned which is effective top-end of device

DIM device AS INTEGER

device = -1
HighRate = 5000

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 ((STEREO)), port "; HEX$(SIP.D5port); "h, IRQ"; SIP.D5IRQ; "and DMA"; SIP.D5DMA

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

   'ensure device selected is available

   SELECT CASE device
   CASE 0: HighRate = 18000
   CASE 1: IF SIP.Device1 = 0 THEN device = -1 ELSE HighRate = 23000
   CASE 2: IF SIP.Device2 = 0 THEN device = -1 ELSE HighRate = 7000
   CASE 3: IF SIP.Device3 = 0 THEN device = -1 ELSE HighRate = 12000
   CASE 4: IF SIP.Device4 = 0 THEN device = -1 ELSE HighRate = 23000
   CASE 5: IF SIP.Device5 = 0 THEN device = -1 ELSE HighRate = 22750 'stereo
   CASE ELSE
      device = -1
   END SELECT

END IF

PickDevice = device

END FUNCTION

[ RETURN TO DIRECTORY ]