















                 UltraSound Software Development Kit (SDK)
                               Revision 2.10

                            December 24th, 1993





                               Documentation





                                    by

                               Kurt Kennett

                                    and

                               Mike Travers








                              Advanced Gravis
                         101-3750 North Fraser Way
                     Burnaby, British Columbia V5J 5E9
                            FAX (604)-431-5155

                            Forte Technologies
                          1555 East Henrietta Rd.
                           Rochester, N.Y. 14526
                            FAX (716)-292-6353







                                  NOTICE


The information contained in  this manual is believed  to be correct.   The
manual is  subject  to change  without  notice  and does  not  represent  a
commitment on the part of FORTE, Advanced Gravis, or Ingenuity Software.

Neither FORTE, Advanced Gravis, nor Ingenuity  Software make a warranty  of
any kind with regard to this  material, including, but not limited to,  the
implied warranties of merchantability and fitness for a particular purpose.
Neither FORTE, Advanced Gravis, nor Ingenuity Software shall be liable  for
errors contained  herein  or for  incidental  or consequential  damages  in
connection with the furnishing, performance or use of this material.

This document  contains  proprietary  information  which  is  protected  by
copyright.    This manual  is Copyright  (C) 1992,1993  by FORTE,  Advanced
Gravis, and Ingenuity Software.   All rights are reserved.  No part of this
document may be reproduced, transmitted, transcribed, stored in a retrieval
system, or translated into any human  or computer language, in any form  or
by any means; electronic,  mechanical, magnetic, optical, chemical,  manual
or otherwise, without the expressed  written permission of FORTE,  Advanced
Gravis, and Ingenuity Software.

Any copying, duplication, selling, or otherwise distributing the program or
support files described in this manual, other than for the limited purposes
of system  backup and  loading the  program into  the computer  as part  of
executing the program, is a violation of the software license agreement and
the law.  Willful violation of the  copyright law of the United States  can
result in statutory damages of up to $50,000 in addition to actual damages,
plus   criminal penalties  of imprisonment  for  up to  one year  and/or  a
$10,000 fine.






                             TABLE OF CONTENTS


Section                                                               Page

Chapter 1 - General Information                                          3
1.0  Introduction                                                        3
1.1  Features of the UltraSound                                          3
1.2  Benefits of supporting the UltraSound                               4
1.3  The GF1 - 32 Voice Sound Synthesizer                                4
1.4  MIDI Interface                                                      7
1.5  Joystick Interface                                                  7


Chapter 2 - Hardware Information                                         8
2.1  I/O Port Map                                                        8
2.2  MIDI Control Port                                                   9
2.3  MIDI Status Port                                                    9
2.4  MIDI Data Port                                                      9
2.5  Page Register                                                      10
2.6  Select Register                                                    10
  2.6.1  Global Registers                                               10
    2.6.1.1  DRAM DMA Control Register                                  11
    2.6.1.2  DMA Start Address                                          11
    2.6.1.3  DRAM I/O Address                                           12
    2.6.1.4  Timer Control                                              12
    2.6.1.5  Timer 1 and Timer 2 Count                                  12
    2.6.1.6  Sampling Frequency                                         12
    2.6.1.7  Sampling Control Register                                  13
    2.6.1.8  Joystick Trim DAC                                          13
    2.6.1.9  Reset Register                                             14
  2.6.2  Voice-specific Registers                                       14
    2.6.2.1  Voice Control Register                                     15
    2.6.2.2  Frequency Control Register                                 16
    2.6.2.3  Starting location HIGH                                     16
    2.6.2.4  Starting location LOW                                      16
    2.6.2.5  End Address HIGH                                           16
    2.6.2.6  End Address LOW                                            16
    2.6.2.7  Volume Ramp Rate                                           17
    2.6.2.8  Volume Ramp Start                                          17
    2.6.2.9  Volume Ramp End                                            17
    2.6.2.10  Current Volume                                            18
    2.6.2.11  Current Location HIGH                                     18
    2.6.2.12  Current Location LOW                                      18
    2.6.2.13  Pan Position                                              18
    2.6.2.14  Volume Ramp Control Register                              19
    2.6.2.15  Active Voices                                             19
    2.6.2.16  IRQ Source Register                                       20
2.7  Global Data Low                                                    20
2.8  Global Data High                                                   20
2.9  IRQ Status                                                         21
2.10  Timer Control Register                                            21
2.11  Timer Data Register                                               21
2.12  DRAM I/O                                                          21






Section                                                               Page

2.13  Mix Control Register                                              22
2.14  IRQ Control Register                                              22
2.15 Register Control                                                   24
2.16 Volume ramping description                                         24


Chapter 3 - Programming the UltraSound                                  26
3.0  Introduction                                                       26
3.1  Sound                                                              26
3.2  The Basics of the UltraSound                                       27
3.3  Using GUS Memory                                                   27
3.4  What are Samples?                                                  28
3.5  Using Voices                                                       29
3.6  Volumes                                                            30
3.7  Using Looping                                                      30
3.8  Clicks and click removal                                           31
3.9  Interrupt Handling Functions                                       32
3.10 Rollover feature                                                   32
3.11 Stereo playback                                                    33
3.12 C-specific information                                             35
3.13 PASCAL-specific information                                        36
  3.13.1 Available constants and variables                              37
  3.13.2 Examples                                                       39
  3.13.3 Management of GUS RAM                                          40
3.14 Coming Attractions                                                 41
3.15 Technical Support                                                  42

Chapter 4 - Reference Guide                                             43
  UltraAllocVoice                                                       81
  UltraAuxHandler                                                       54
  UltraCalcRate                                                         43
  UltraClearVoices                                                      81
  UltraClose                                                            43
  UltraDisableLineIn                                                    46
  UltraDisableMicIn                                                     46
  UltraDisableMIDIXmit                                                  58
  UltraDisableOutput                                                    47
  UltraDownload                                                         44
  UltraDRAMDMABusy                                                      45
  UltraDRAMTcHandler                                                    50
  UltraEnableLineIn                                                     47
  UltraEnableMicIn                                                      47
  UltraEnableMIDIXmit                                                   59
  UltraEnableOutput                                                     48
  UltraFreeVoice                                                        82
  UltraGetLineIn                                                        48
  UltraGetMicIn                                                         49
  UltraGetOutput                                                        48
  UltraGoRecord                                                         45
  UltraGoVoice                                                          46
  UltraMaxAlloc                                                         55
  UltraMaxAvail                                                         55






Section                                                               Page

  UltraMemAlloc                                                         56
  UltraMemAvail                                                         56
  UltraMemFree                                                          57
  UltraMemInit                                                          57
  UltraMIDIDisableRecv                                                  58
  UltraMIDIEnableRecv                                                   58
  UltraMIDIRecv                                                         59
  UltraMIDIRecvHandler                                                  51
  UltraMIDIReset                                                        60
  UltraMIDIStatus                                                       60
  UltraMIDIXmit                                                         60
  UltraMIDIXmitHandler                                                  51
  UltraOpen                                                             61
  UltraPeekData                                                         62
  UltraPing                                                             62
  UltraPokeData                                                         63
  UltraPrimeRecord                                                      64
  UltraPrimeVoice                                                       65
  UltraProbe                                                            66
  UltraRampLinearVolume                                                 84
  UltraRampVolume                                                       67
  UltraReadLinearVolume                                                 84
  UltraReadRecordPosition                                               67
  UltraReadVoice                                                        68
  UltraReadVolume                                                       68
  UltraRecordData                                                       69
  UltraRecordDMABusy                                                    70
  UltraRecordHandler                                                    54
  UltraReset                                                            70
  UltraSetBalance                                                       71
  UltraSetFrequency                                                     71
  UltraSetLinearVolume                                                  83
  UltraSetLoopMode                                                      71
  UltraSetRecordFrequency                                               72
  UltraSetVoice                                                         72
  UltraSetVoiceEnd                                                      72
  UltraSetVolume                                                        73
  UltraSizeDRAM                                                         73
  UltraStartTimer                                                       74
  UltraStartVoice                                                       75
  UltraStopTimer                                                        75
  UltraStopVoice                                                        76
  UltraStopVolume                                                       76
  UltraTimer1Handler                                                    52
  UltraTimer2Handler                                                    52
  UltraTimerStopped                                                     76
  UltraTrimJoystick                                                     77
  UltraUpload                                                           77
  UltraVectorLinearVolume                                               85
  UltraVectorVolume                                                     78
  UltraVersion                                                          78
  UltraVersionStr                                                       79






Section                                                               Page

  UltraVoiceOff                                                         82
  UltraVoiceOn                                                          83
  UltraVoiceStopped                                                     79
  UltraVolumeHandler                                                    53
  UltraVolumeStopped                                                    79
  UltraWaitDRAMDMA                                                      80
  UltraWaitRecordDMA                                                    80
  UltraWaveHandler                                                      53


Chapter 5 - Focal Point 3D Sound                                        86
5.0  Introduction                                                       86
5.1  Creating 3D file                                                   87
5.2  3D Sound Routines                                                  87
    UltraAbsPosition                                                    87
    UltraAngPosition3D                                                  88
    UltraAngFltPosition3D                                               89
    UltraCloseDup3D                                                     89
    UltrDup3D                                                           90
    UltraLoad3DEffect                                                   91
    UltraSetFreq3D                                                      92
    UltraRelease3DInterleave                                            92
    UltraSetup3DInterleave                                              93
    UltraStart3D                                                        93
    UltraStop3D                                                         94
    UltraUnLoad3DEffect                                                 94


Appendix A - Error Codes                                                95

Appendix B - Volume Control                                             96

Appendix C - Voice Control                                              97

Appendix D - DMA Control                                                98

Appendix E - Recording Control                                          99

Appendix F - Patch Files                                               100
  Field descriptions                                                   104

Appendix G - 3D File Header                                            109



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

                      Chapter 1 - General Information

1.0 Introduction

This is version 2.10 of the Software Development Kit (SDK) for the Advanced
Gravis UltraSound card, and is the combined work of Advanced Gravis,  FORTE
Technologies, and Ingenuity  Software.   This kit  is intended  for use  by
programmers of  IBM-compatible  PCs.   After  becoming familiar  with  this
material, you should be able to use  C or Pascal to program the  UltraSound
under MS-DOS.

This is the first version which includes a full Borland Pascal (version  7)
and Turbo-Pascal (versions 6  and 7) interface.   This was written by  Kurt
Kennett of  Ingenuity  Software for  Advanced  Gravis, and  is  the  direct
translation of the routines in the  C interface.  For specific  information
about the Pascal interface, see section 3.13.

For specific  information  about  the  revised  and  updated  C  interface,
including compilers and memory models supported, see section 3.12.

Some of the discussions of the  hardware interface to the card (Chapter  2)
are quite technical, and  go beyond the  level of technical  sophistication
needed to write software.   Therefore, a seperate  section (Chapter 3)  has
been included which is a general overview of how to write software for  the
card.   What  follows in  this  chapter is  a  general description  of  the
UltraSound card  and its  features, the  MIDI functionality,  the  Joystick
interface, and  the  GF1  32-voice  Sound  Synthesizer.    Throughout  this
documentation,  the  words  'lowlevel  toolkit',  'lowlevel  routines'  and
'lowlevel code' are  used.   This refers  to any  and all  of the  routines
described and included in the C and/or Pascal interfaces.



1.1 Features of the UltraSound

- Jumper selectable base port address.
- Software selectable IRQ vectors and DMA channels.
- XT and AT compatibility.
- 8 or 16 bit playback: Stereo and Monophonic.
- 8 bit recording:  Stereo or Monophonic.
- Playback and recording rates up to 44.1 kHz.
- 32 voice wavetable synthesis: all voices mixed on board.
- Simultaneous playback and recording is possible.
- Each voice has its own volume settings, volume enveloping, playback  rate
  and balance.
- Both line level and amplified outputs.
- 6850 compatible MIDI UART on-board.
- Gravis Eliminator joystick interface with jumper enable/disable.
- 256Kb DRAM on board for waveforms.  Expandable to 1Mb.
- Stereo microphone input with automatic level control.
- Line level input.
- CD ROM Drive audio input.
- Stereo mini-jacks for line & amplified outputs and Mic and Line inputs.


___________________________________________________________________________
                                                                          3



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

1.2 Benefits of supporting the UltraSound

The UltraSound has 32 separate  voices, each of which  can be used to  play
back any 8- or 16-bit digital data that is loaded into its DRAM.  This data
can consist  of individual  sound effects,  a whole  sound track,  or  even
single musical  notes  of  a  digitized  instrument.    The  UltraSound  is
completely controlled  by  the  PC,  thus  giving  maximum  flexibility  to
applications which use it.  The main chip which runs the card (the GF1)  is
directly addressable from the PC's CPU via basic I/O instructions.

Here are some of the features that the UltraSound offers:

1) Wavetable synthesis has a much higher sound quality that FM-based cards
   can ever achieve.   This method of audio  synthesis is the same  method
   used in expensive professional keyboards.
2) 32 digital voices can be  independently controlled. This allows  you to
   have up to 32 sound effects or instruments going at once.
3) The card is RAM-based.  Since  the instrument patches are kept  on disk
   and only loaded when they are  needed, they can be changed  or improved
   at will.
4) Focal Point 3D  sound generation.  You can  position your  applications
   sounds anywhere in 3D space around the listener.
5) All mixing is  done on  the card.   There is  no burden  on the CPU  to
   playback multiple channels.
6) Multiple cards can be  installed in the same  PC. With some  relatively
   minor adjustments to the SDK software, multiple cards can be controlled
   in the same PC.
7) Hardware-assisted voice enveloping. A multi-point attack-decay-sustain-
   release  envelope  can  be  implemented  that  uses  virtually  no  CPU
   overhead. Tremelo can also be done in hardware.
8) Sound effects can be pre-loaded into DRAM, using little or no PC memory
   to keep track of them.  This leaves more space for your application and
   it's data.  It also allows you to start or stop any  sound whenever you
   wish.



1.3 The GF1 - 32 Voice Sound Synthesizer

The UltraSound uses  Wave-Table Synthesis to  produce sound  output.   This
means that either sampled data from actual instruments or other synthesized
digital audio is  stored in DRAM  on the UltraSound  Board.   The GF1  chip
which controls the board  is set up to  play back relatively short  digital
audio samples and produce continuous sound closely reproducing the original
instrument.   The  32  voices  are  independently  controlled  and  can  be
producing different sounds concurently.   Output from  all voices is  mixed
into the left or right channels.  Circuitry in the GF1 can be programmed to
perform the  following audio  processing functions  independently for  each
voice:

- Frequency Shifting to produce different notes of the same instrument.




___________________________________________________________________________
                                                                          4



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

- Amplitude Modulation to produce note enveloping (attack, decay,  sustain,
  release), overall  volume control  or special  effects such  as LFO  (low
  frequency amplitude modulation).

- Panning the voice from left to right channel outputs.

Multi-track digital audio recordings can be played through the GF1 by using
one voice per digital audio track.  The GF1 is compatible with 8 and 16 bit
data, stereo  or  mono, signed  or  unsigned data,  and  8 or  16  bit  DMA
channels.

The GF1 is basically a pipeline processor.  It constantly loops from  voice
#0 to the  end of the  active voices (how  to define the  number of  active
voices is shown later). Every 1.6  microseconds, the GF1 performs a  series
of operations on a particular voice.  The more active voices there are, the
longer it takes  between each time  a particular voice  is serviced.   This
puts a limit on  the rate at which  playback can occur.   14 active  voices
will allow a maximum of 44.1  kHz playback.  28  voices will allow 22  kHz.
Faster rates can be achieved by making the frequency constant greater  than
1.  This will cause the GF1 to skip some  data bytes to play a sample  back
at the requested  frequency.  This  is not generally  a problem, but  could
cause some distortion or aliasing.

The formula for calculating the playback rate is:

                           Frequency   Active Voices
                             44100          14
                             41160          15
                             38587          16
                             36317          17
                             34300          18
                             32494          19
                             30870          20
                             29400          21
                             28063          22
                             26843          23
                             25725          24
                             24696          25
                             23746          26
                             22866          27
                             22050          28
                             21289          29
                             20580          30
                             19916          31
                             19293          32

This table is calculated by knowing that 14 active voices will give exactly
44.1 kHz  playback.    Therefore,  the voice  servicing  rate  'X'  can  be
calculated from:

                      1,000,000 / (X * 14) = 44100 Hz
                       X = 1.619695497 microseconds



___________________________________________________________________________
                                                                          5



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

Once X is known, the frequency 'divisor' is calculated by:

          divisor = 1,000,000 / (1.619695497 * # of active voices)

The  lowlevel  code  pre-calculates  this  table  so  that  floating  point
arithmetic doesn't  need to  be done.   A  frequency 'counter'  is used  to
calculate how often  a voice is  updated by the  GF1.  To  calculate an  FC
(frequency counter) for any given frequency  with a particular # of  active
voices, run it through this formula:

C:
   fc = (unsigned int)(((speed_khz<<9L)+(divisor>>1L)) / divisor);
   fc = fc << 1;

PASCAL:
   fc := Word(((Speed_Khz SHL 9)+(Divisor SHR 1)) DIV Divisor);
   fc := fc SHL 1;

The left  shift  is  needed since  the  FC  is in  bits  15-1.    For  more
information about  the  frequency  counter, see  chapter  2,  the  hardware
section.

This value  is  then  put  in  the  frequency  control  register  for  that
particular voice.  If the mantissa portion of  the FC is 1, then each  time
around the loop,  the GF1 uses  each data  point to play.   If  there is  a
fractional portion, the GF1 interpolates the  actual data to play from  the
two data points that it is between.  This makes the sound much  'smoother',
since the GF1 will create  points in between the  actual data points.   For
example, assume an 8 bit recording  at 22 kHz and 14  active voices .   The
frequency control register is set up to  1/2 (exponent = 256).  This  means
that every time  around the loop,  that particular  voice's accumulator  is
adjusted by 1/2.  So the first time the  accumulator is 0 and data point  0
is used.  The second time around the  loop, the accumulator is 0.5.   Since
there obviously is no DRAM location 0.5, the GF1 interpolates what the data
would be by looking at location 0 and location 1 and taking the appropriate
ratio from each.  In this case, it picks a point half-way between the  two.
If the recording rate were 11kHz, it would take 25% from location 0 and 75%
from location 1 the first time  through the loop.   The next time it  would
take 50% from each.  The  next time it would take  25% from location 0  and
75% from location 1.  The fourth time through it uses 100% of location 1.

The interpolation  is done  to a  resolution of  16 bits,  even for  8  bit
playback.  This has the  effect of making an  8 bit recording sound  better
when played back on the GF1 than on a standard 8 bit card.

Remember that the GF1 works on a voice every 1.6 microseconds.  This  means
that the fewer voices, the faster  each voice gets updated.  The  frequency
control register setting for the voice MUST take this into account.  The FC
must get smaller if the  number of active voices  gets smaller.  This  will
increase the number of points created between the actual data points so the
perceived playback speed remains the same.




___________________________________________________________________________
                                                                          6



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

1.4 MIDI Interface

The MIDI 101 interface consists of  standard UART functionality -  Motorola
MC68C50.  An interrupt  to the PC can  be generated for  each byte of  MIDI
data received or transmitted.  This  hardware is independent of any of  the
other hardware.  The main MIDI circuitry is included in the GF1  processor,
but external to the chip is an optical isolator that is used on the  serial
input data and an open collector driver that is used for the serial output.
In addition, external logic is included on board to loop back transmit data
to the receive  data under software  control.  The  serial interface has  a
fixed configuration  with no  programmable options,  as  in the  MC6850.  A
control register is  used to enable  and disable  the interrupt  generation
logic.  A status register is used  to determine if the transmit or  receive
register is interrupting.  A read or write to the data register clears  the
interrupt status.

The specifications for the interface are:

                              31.25 kHz +- 1%
                               asynchronous
                                1 start bit
                                8 data bits
                                1 stop bit

The MIDI signals  are available  on the  15 pin  D connector  used for  the
joystick.  An external cable assembly  containing the optical isolator  and
driver is required to use the MIDI interface.



1.5 Joystick Interface

The joystick  interface is  an Eliminator  Joystick interface  designed  by
Advanced Gravis.   It basically consists  of a single  eight bit  register.
When written to, four  flip-flops are reset  and comparator inputs  (LM339)
begin to charge up based on the  position of the joystick.  The  comparator
threshold is setup in the GF1.   Crossing the threshold of the  comparators
cause the  flip-flops to  be preset  and the  capacitor to  be  discharged.
Reads of the register return the  state of four digital inputs  (internally
pulled up) and the state of the flip-flops.   The rate of discharge of  the
capacitors has a minimum time constant of 1 microsecond.

UltraSound boards with a revision version (printed on the card) of 3.3  and
lower have  a jumper  which is  used  to enable  or disable  the  joystick.
Boards  with  a  revision  version  of  3.4  and  above  have  a   software
enable/disable for the joystick instead of  a jumper.  There is a  joystick
SDK available sperately from Gravis.








___________________________________________________________________________
                                                                          7



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

                     Chapter 2 - Hardware Information

2.1  I/O Port Map

The following  describes I/O  address map  used on  the board.  The 'X'  is
defined by the  jumper settings  on the  UltraSound and  should match  that
specified in the ULTRASND environment variable.

     INTERFACE                         I/O,MEM,  R,W       ADDRESS
                                       INT,DMA             HEX
     ------------------------------------------------------------
     UltraSound Base Port:              ---       --        2X0

     MIDI Interface:
          Control                       I/O       W         3X0
          Status                        I/O       R         3X0
          Transmit Data                 I/O       W         3X1
          Receive Data                  I/O       R         3X1
          Joystick Interface:
            Trigger Timer               I/O       W         201
            Read Data                   I/O       R         201

     GF1 Synthesizer:
          GF1 Page Register             I/O       R/W       3X2
          GF1/Global Register Select    I/O       R/W       3X3
          GF1/Global Data Low Byte      I/O       R,W       3X4
          GF1/Global Data High Byte     I/O       R/W       3X5
          IRQ Status Register 1=ACTIVE  I/O       R         2X6
          Timer Control Reg             I/O       R/W       2X8
          Timer Data                    I/O       W         2X9
          DRAM                          I/O       R,W       3X7
          DRAM                          DMA       R,W       1,3,5,6,7
          Record Digital Audio          DMA       R         1,3,5,6,7
          BOARD ONLY
            Mix Control register        I/O       W         2X0
            IRQ  control register       I/O       W         2XB
            (2X0- bit 6 = 1)
            DMA control register        I/O       W         2XB
            (2X0- bit 6 = 0)
            Register Controls           I/O       R/W       2XF (Rev 3.4+)
            Mixer Control               I/O       W         3X6 (Rev 3.7+)

At power-up the board  has operational Joystick  and MIDI interfaces.  This
allows their direct use with existing software. The GF1 ASIC powers up with
all voices disabled,  not requiring a  software initialization. This  helps
eliminate noise at powerup and allows  the Joystick and MIDI interfaces  to
be used by existing applications. The  IRQ control register MUST be set  up
before  the  MIDI  interface  can  generate  an  IRQ.    This  is  done  in
ULTRINIT.EXE and when an  application sets up the  latches to the  ULTRASND
parameters.





___________________________________________________________________________
                                                                          8



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

2.2  MIDI Control Port - 3X0

Here are the bit definitions  for the MIDI control  byte. It is located  at
address 3X0 hex and is write only.

     =================================
     | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
     =================================
       |   |   |   |   |   |   |   |
       |   |   |   |   |   |   |   +---- 1 \ Master reset (when set)
       |   |   |   |   |   |   +-------- 1 /
       |   |   |   |   |   +------------ Reserved
       |   |   |   |   +---------------- Reserved
       |   |   |   +-------------------- Reserved
       |   |   +------------------------ 1 \ xmit IRQ enabled
       |   +---------------------------- 0 /
       +-------------------------------- 1 = Receive IRQ enabled

Bit 0 & 1 will cause  a master reset when toggled  high and then low.  They
must be  left low  when using  port. This  will normally  cause a  transmit
buffer empty IRQ.



2.3  MIDI Status Port - 3X0

Here are the bit definitions for  the MIDI status byte.   It is located  at
address 3X0 hex and is read-only.

     =================================
     | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
     =================================
       |   |   |   |   |   |   |   |
       |   |   |   |   |   |   |   +---- Receive reg. full
       |   |   |   |   |   |   +-------- Transmit reg. empty
       |   |   |   |   |   +------------ Reserved
       |   |   |   |   +---------------- Reserved
       |   |   |   +-------------------- Framing Error
       |   |   +------------------------ Overrun error
       |   +---------------------------- Reserved
       +-------------------------------- Interrupt pending

The MIDI control interface behaves identically to a 6850 UART.



2.4  MIDI Data Port - 3X1

The transmit and receive registers are at 3X1 hex and are 8 bits wide.






___________________________________________________________________________
                                                                          9



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

2.5  Page Register - 3X2

This could also be called the voice select register. This register is  used
to specify which voice's registers you  want to read/write. This value  can
range from 0 to  the number of active  voices specified (13-31). Once  this
has been specified, you may select the specific register within that voice.
Be careful that  IRQs are  off during  the time  that the  page and  select
registers are  being  modified.  This  will  prevent  the  foreground  from
selecting a voice and having the background change it in the background.



2.6  Select Register - 3X3
2.6.1  Global Registers

These are the global registers. They are not voice-specific.

               Address     Mode    Width   Description

                 41        R/W       8     DRAM DMA Control
                 42        W        16     DMA Start Address
                 43        W        16     DRAM I/O Address (LOW)
                 44        W         8     DRAM I/O Address (HIGH)
                 45        R/W       8     Timer Control
                 46        W         8     Timer 1 Count
                 47        W         8     Timer 2 Count
                 48        W         8     Sampling Frequency
                 49        R/W       8     Sampling Control
                 4B        W         8     Joystick trim DAC
                 4C        R/W       8     RESET

























___________________________________________________________________________
                                                                         10



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

2.6.1.1  DRAM DMA Control Register - (41)

     =================================
     | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
     =================================
       |   |   |   |   |   |   |   |
       |   |   |   |   |   |   |   +---- Enable DMA (1=go)
       |   |   |   |   |   |   +-------- DMA direction (1=read)
       |   |   |   |   |   +------------ DMA channel width
       |   |   |   |   +---------------- \
       |   |   |   +-------------------- / DMA Rate divider
       |   |   +------------------------ DMA IRQ Enable
       |   +---------------------------- (R) DMA IRQ Pending
       |                                 (W) DATA SIZE (0=8bit,1=16bit)
       +-------------------------------- Invert MSB (write only)

Bit 0 -  Enable the  DMA  channel. The  GF1  will begin  sending  DMA  ACK
         protocol. If PC  DMA controller  is programmed,  data will  begin
         being transferred.  If not,  data  will move  as  soon as  it  is
         programmed.
Bit 1 -  DMA  transfer  direction.  Read  is   taking  data  OUT  of   the
         UltraSound, Write sends data to it.
Bit 2 -  0 = if DMA channel is an 8 bit channel (0-3).
         1 = If it is a 16 bit channel (4-7)
           Note: This is INDEPENDENT of the data size.
Bit 3,4 -DMA Rate divisor. The Maximum rate is approx 650 khz.
           00 = divide by 1
           01 = divide by 2
           10 = divide by 3
           11 = divide by 4
Bit 5 -  DMA terminal count interrupt enable
Bit 6 -  Read  - DMA terminal count IRQ pending
         Write - Data size 0 = 8 Bit data
                           1 = 16 bit data
             Note: Data size is independent of channel size
Bit 7 -  1 = Invert High bit to flip data to twos complement form.
             Note: This flips bit 7 for 8 bit data and bit 15 for
                   16 bit data.



2.6.1.2  DMA Start Address - (42)

Bits 15-0 are Address lines 19-4.

This register defines where the DMA will  transfer data to or from.   Since
only the upper 16 address bits are used and the lower 4 bits are set to  0,
a DMA transfer MUST begin on an 16 byte  boundary for an 8 bit DMA  channel
(0-3). If a 16 bit DMA channel is being used, the transfer MUST being on  a
32 byte boundary. An  additional address translation is  necessary if a  16
bit DMA  channel  is used.  For  simple example  code  on how  to  do  this
translation, see the C function convert_to_16().



___________________________________________________________________________
                                                                         11



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

2.6.1.3  DRAM I/O Address (43,44)

These 2 registers allow you to specify an address to peek and poke directly
into UltraSound DRAM. Register 43 is  the lower 16 address lines.  Register
44 is the upper 4 address lines. (bits 0-3). Read or write to register  3X7
to get at the address location.



2.6.1.4  Timer Control - (45)

          =================================
          | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
          =================================
            |   |   |   |   |   |   |   |
            |   |   |   |   |   |   |   +---- Reserved (Set to 0)
            |   |   |   |   |   |   +-------- Reserved (Set to 0)
            |   |   |   |   |   +------------ Enable Timer 1 IRQ
            |   |   |   |   +---------------- Enable Timer 2 IRQ
            |   |   |   +-------------------- Reserved (Set to 0)
            |   |   +------------------------ Reserved (Set to 0)
            |   +---------------------------- Reserved (Set to 0)
            +-------------------------------- Reserved (Set to 0)



2.6.1.5  Timer 1 and Timer 2 Count - (46,47)

These counts are loaded by the application  and then they will count up  to
$FF and generate  and IRQ.  Timer 1 has  a granularity  of 80  microseconds
(0.00008 sec) and Timer  2 has a granularity  of 320 microseconds  (0.00032
sec).



2.6.1.6  Sampling Frequency - (48)

The formula for calculating this value is:
     rate = 9878400/(16*(FREQ+2))
















___________________________________________________________________________
                                                                         12



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

2.6.1.7  Sampling Control Register - (49)

          =================================
          | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
          =================================
            |   |   |   |   |   |   |   |
            |   |   |   |   |   |   |   +---- Start sampling
            |   |   |   |   |   |   +-------- Mode (0=mono, 1=stereo)
            |   |   |   |   |   +------------ DMA width (0=8bit,1=16bit)
            |   |   |   |   +---------------- Reserved (Set to 0)
            |   |   |   +-------------------- Reserved (Set to 0)
            |   |   +------------------------ DMA IRQ enable
            |   +---------------------------- (Read) DMA IRQ pending
            +-------------------------------- Invert MSB

Bit 0 -If PC DMA controller is programmed, it will begin sampling as  soon
       as this is enabled.
Bit 1 -0 = mono
       1 = stereo
       In stereo mode, the order of the  data bytes is left is first,  and
       right is second. If a 16 bit data  channel is used, the left is  in
       the lower byte.
Bit 2 -DMA Channel width (0 = 8 bit, 1 = 16 bit)
Bit 5 -Enable DMA terminal count IRQ
Bit 6 -DMA terminal count IRQ pending
Bit 7 -Flip bit 7 to get non-twos compliment data



2.6.1.8  Joystick Trim DAC - (4B)

This register is initialized to 4.3 volts (value = 29). It only needs to be
modified to  account  for faster/slower  machines.  A utility  is  provided
(ULTRAJOY.EXE) that  sets this  up.   There should  be no  reason for  your
application to modify this register.




















___________________________________________________________________________
                                                                         13



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

2.6.1.9  Reset Register - (4C)

     =================================
     | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
     =================================
       |   |   |   |   |   |   |   |
       |   |   |   |   |   |   |   +---- Master Reset
       |   |   |   |   |   |   +-------- DAC Enable
       |   |   |   |   |   +------------ GF1 Master IRQ Enable
       |   |   |   |   +---------------- Reserved (Set to 0)
       |   |   |   +-------------------- Reserved (Set to 0)
       |   |   +------------------------ Reserved (Set to 0)
       |   +---------------------------- Reserved (Set to 0)
       +-------------------------------- Reserved (Set to 0)

Bit 0 -GF1 Master Reset. 0 = reset,  1 = run. As long as  this is a 0,  it
       will be held in a reset state.
Bit 1 -Enable DAC output. DAC's will not run unless this bit is set.
Bit 2 -Master IRQ enable.  This bit MUST  be set  to get ANY  of the  GF1-
       generated IRQs (wavetable, volume, etc).

This register will normally contain the value $07 while your application is
running.



2.6.2  Voice-specific Registers

The following are the voice-specific registers. Each voice has its own bank
of read and write  registers that alter its  behavior. The write  registers
range from 0 to F and the corresponding read registers range from 80 to 8F.
To convert from the write to the read, just add 80 hex.

          Write    Read     Width   Description
            0       80        8     Voice Control
            1       81       16     Frequency Control
            2       82       16     Starting Address (HIGH)
            3       83       16     Starting Address (LOW)
            4       84       16     End Address (HIGH)
            5       85       16     End Address (LOW)
            6       86        8     Volume Ramp Rate
            7       87        8     Volume Ramp Start
            8       88        8     Volume Ramp End
            9       89       16     Current Volume
            A       8A       16     Current Address (HIGH)
            B       8B       16     Current Address (LOW)
            C       8C        8     Pan Position
            D       8D        8     Volume Control
            E       8E        8     Active Voices (Voice independent)
            -       8F        8     IRQ Status (Voice independent)

There are several 'self-modifying' bits  defined for these registers.  This
means that the GF1 may change them at anytime  on its own. Due to the  fact
that the software must accommodate this phenomena, it is possible that  the

___________________________________________________________________________
                                                                         14



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

GF1 may change something immediately  after your application has  set/reset
one of  the bits.  This is  due to  the GF1's  pipeline processor  type  of
architecture: it does  a read-modify-write cycle,  and if your  application
modifies one of these bits AFTER it has done the read portion and BEFORE it
does the write portion, it's possible for the chip to perform  incorrectly.
To overcome this, you need to do a  double write (with a delay in  between)
when those particular  bits are  involved. This delay  must be  at least  3
times the length of time necessary  to process a voice. (3*1.6  microsecs).
In the lowlevel code,  this is done with  a function called GF1_Delay.  The
self-modifying bits are  designated with an  (*) after  the particular  bit
definition.

Changing the start and  end points of  a voice while  its playing can  have
some strange side  effects. For example,  if you change  end poistion to  a
lower location than it is currently playing, you will get and IRQ (if  they
are enabled). Also, since the high  and low bytes are set individually  and
asynchronously to when the GF1 is working on a voice, it is possible to get
an unexpected IRQ if the current  position and the new end position cross.



2.6.2.1  Voice Control Register - (0,80)

     =================================
     | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
     =================================
       |   |   |   |   |   |   |   |
       |   |   |   |   |   |   |   +---- Voice Stopped
       |   |   |   |   |   |   +-------- Stop Voice
       |   |   |   |   |   +------------ 16 bit data
       |   |   |   |   +---------------- Loop enable
       |   |   |   +-------------------- Bi-directional loop enable
       |   |   +------------------------ Wave table IRQ
       |   +---------------------------- Direction of movement
       +-------------------------------- IRQ pending

* Bit 0- 1 = Voice is  stopped. This gets set  by hitting the end  address
         (not looping) or by setting bit 1 in this reg.
  Bit 1- 1 = Stop Voice. Manually force voice to stop.
  Bit 2- 1 = 16 bit wave data, 0 = 8 bit data
  Bit 3- 1 = Loop to begin address when it hits the end address.
  Bit 4- 1 = Bi-directional looping enabled
  Bit 5- 1 = Enable wavetable IRQ. Generate an IRQ when the voice hits the
         end address. Will generate IRQ even if looping is enabled.
* Bit 6- 1 = Decreasing addresses, 0 =  increasing addresses. It is  self-
         modifying because it might shift directions  when it hits one  of
         the loop boundaries and looping is enabled.
* Bit 7- 1 = Wavetable IRQ  pending. If IRQ's are  enabled and looping  is
         NOT enabled, an IRQ will be constantly generated until  the voice
         is stopped. This means  that you may  get more than  1 IRQ if  it
         isn't handled properly.




___________________________________________________________________________
                                                                         15



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

2.6.2.2  Frequency Control Register - (1,81)

     Bits 15-10 - Integer Portion
     Bits 9-1   - Fractional Portion
     Bit 0      - Not used.

This register  determines the  amount added  to  (or subtracted  from)  the
current position of the voice to determine where the next position will be.
This is how the interpolated data points are determined. If the FC register
is less than 0, the GF1 will interpolate the data point in between the  two
actual data points. Note that the FC can be greater than 1. This allows for
skipping over data bytes.  The actual frequency that  it will play back  is
directly related to the number of active voice specified (register 8E).



2.6.2.3  Starting location HIGH - (2,82)

Bits 12-0  are the HIGH 13 bits of the address of the starting location of
           the waveform (Addr lines 19-7).
Bits 15-13 are not used.



2.6.2.4  Starting location LOW - (3,83)

Bits 15-9  are the low 7 bits of  the address of the starting location  of
           the waveform. (Addr lines 6-0).
Bits 8-5   are the fractional part of the starting address.
Bits 4-0   are not used.



2.6.2.5  End Address HIGH - (4,84)

Bits 12-0  are the high 13 bits of  the address of the ending location  of
           the waveform. (Addr lines 19-7)
Bits 15-13 are not used.



2.6.2.6  End Address LOW - (5,85)

Bits 15-9  are the low 7 bits of the address of the ending location of the
           waveform. (Addr lines 6-0).
Bits 8-5   are the fractional part of the ending address.
Bits 4-0   are not used.








___________________________________________________________________________
                                                                         16



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

2.6.2.7  Volume Ramp Rate - (6,86)

Bits 5-0   is the amount added to (or subtracted from) the  current volume
           to get the next volume. The  range is from 1 to 63.  The larger
           the number, the greater the volume step.
Bits 7-6   defines the rate at which the increment is applied.

Please see section 2.16 for more information on hardware volume ramping.



2.6.2.8  Volume Ramp Start - (7,87)

Bits 7-4   Exponent
Bits 3-0   Mantissa

This register specifies  the starting position  of a volume  ramp. See  the
special section on volume  ramping for a more  complete explanation of  how
this register works.

Please see section 2.16 for more information on hardware volume ramping.



2.6.2.9  Volume Ramp End - (8,88)

Bits 7-4   Exponent
Bits 3-0   Mantissa

This register specifies  the ending  position of a  volume ramp.   See  the
special section on volume  ramping for a more  complete explanation of  how
this register works.

Note:   The starting volume must always be less than the ending volume. If
        you want the volume  to ramp down, turn  on the decreasing  volume
        bit in the Volume Control Register.

Please see section 2.16 for more information on hardware volume ramping.

















___________________________________________________________________________
                                                                         17



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

2.6.2.10  Current Volume - (9,89)

* Bits 15-12   Exponent
* Bits 11-4    Mantissa
  Bits 3-0     Reserved (Set to 0)

Note:   This register has 4 extra bits of precision that is  necessary for
        finer granularity of volume  placement.  The  extra bits are  used
        during a volume ramp.

Note:   This is a self-modifying value. The GF1 will update  this register
        as it ramps.

Note:   You should always  set this  register equal  to the  value of  the
        beginning of the volume ramp (start OR end).

Please see section 2.16 for more information on hardware volume ramping.



2.6.2.11  Current Location HIGH - (A,8A)

Bits 15-13 Reserved (Set to 0)
Bits 12-0  High 13 bits of address (address lines 19-7)



2.6.2.12  Current Location LOW - (B,8B)

Bits 15-9  Low 7 bits of address. (address lines 6-0)
Bits 8-0   9 bit fractional position.



2.6.2.13  Pan Position - (C,8C)

Bits 8-4   Reserved (Set to 0)
Bits 3-0   Pan position. (0=full left, 15=full right)

















___________________________________________________________________________
                                                                         18



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

2.6.2.14  Volume Ramp Control Register - (D,8D)

     =================================
     | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
     =================================
       |   |   |   |   |   |   |   |
       |   |   |   |   |   |   |   +---- Ramp Stopped
       |   |   |   |   |   |   +-------- Stop Ramp
       |   |   |   |   |   +------------ Rollover condition
       |   |   |   |   +---------------- Loop Enable
       |   |   |   +-------------------- Bi-directional loop enable
       |   |   +------------------------ Volume ramp IRQ enable
       |   +---------------------------- Direction
       +-------------------------------- IRQ pending

* Bit 0- Show the ramp has stopped
  Bit 1- Manually stop the ramp.
  Bit 2- Roll over condition. This bit pertains more towards  the location
         of the voice rather than its  volume. Its purpose is to  generate
         an IRQ and NOT stop  (or loop). It will  generate an IRQ and  the
         voice's address  will continue  to move  thru  DRAM in  the  same
         direction. This can  be a  very powerful feature.  It allows  the
         application to get  an interrupt without  having the sound  stop.
         This can be easily used to implement a ping-pong buffer algorithm
         so an application can keep feeding  it data and there will be  no
         pops. Even if looping is enabled, it will not loop.
  Bit 3- Enable looping. Loop from end to start (or start to end).
  Bit 4- Enable bi-directional looping.  When it  hits end  (or start)  it
         will change directions and proceed toward the other limit.
  Bit 5- Enable getting an IRQ when ramp hits end.
* Bit 6- Ramp direction. 0=increasing, 1=decreasing.
* Bit 7- (READ) Volume ramp IRQ pending.

Please see section 2.16 for more information on hardware volume ramping.



2.6.2.15  Active Voices - (E,8E)

Bits 7-6   Must be set to a 1
Bits 5-0   # of voices to enable - 1.

The range is from 14 - 32. Any value less than 14 will be forced to 14.












___________________________________________________________________________
                                                                         19



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

2.6.2.16  IRQ Source Register - (F,8F)

     =================================
     | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
     =================================
       |   |   |   |   |   |   |   |
       |   |   |   |   |   |   |   +----\
       |   |   |   |   |   |   +-------- \
       |   |   |   |   |   +------------  - Interrupting voice #
       |   |   |   |   +---------------- /
       |   |   |   +--------------------/
       |   |   +------------------------ 1
       |   +---------------------------- Volume Ramp IRQ pending
       +-------------------------------- WaveTable IRQ pending

Bit 4-1-Voice # (0-31) of interrupting voice
Bit 5-  ALWAYS a 1
Bit 6-  0 = Volume Ramp IRQ occurred
Bit 7-  0 = Wavetable IRQ occurred

Note:   This is  a global  read only  register. There  is only  1 for  ALL
        voices. You MUST service any indicated IRQ's since a read  of this
        port will clear the associated IRQ bits in the  particular voice's
        control and/or volume control registers.

Note:   It is possible that multiple  voices could interrupt at  virtually
        the same time.  In this  case, this  register will  behave like  a
        fifo. When in your IRQ handler, keep reading (and  servicing) this
        register until you do a read with  both IRQ bits set to a  1. This
        means there are no voice IRQs left to deal with.

Note:   Since it is possible  to get ANOTHER IRQ  from the same voice  for
        the SAME  reason, you  must ignore  any subsequent  IRQ from  that
        voice while in the IRQ handler. For example, when a voice hits its
        end position and  generates an  IRQ back to  your application,  it
        will continue to generate IRQ's until either the voice is stopped,
        the IRQ enable is turned off, or the end location is moved.



2.7  Global Data Low - 3X4

This register can be used to do either a 16 bit transfer for one of the  16
bit wide  GF1 registers  (Start addr  high etc)  when using  a 16  bit  I/O
instruction or the low part of a 16 bit  wide register when using an 8  bit
I/O instruction.



2.8  Global Data High - 3X5

This register is used to do either an 8 bit  transfer for one of the GF1  8
bit registers or to do the high part of a 16 bit wide register.


___________________________________________________________________________
                                                                         20



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

2.9  IRQ Status - 2X6

CAUTION: Note that this is at 2X6 *** NOT 3X6 ***.

     =================================
     | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
     =================================
       |   |   |   |   |   |   |   |
       |   |   |   |   |   |   |   +---- MIDI Transmit IRQ
       |   |   |   |   |   |   +-------- MIDI Receive IRQ
       |   |   |   |   |   +------------ Timer 1 IRQ
       |   |   |   |   +---------------- Timer 2 IRQ
       |   |   |   +-------------------- Reserved (Set to 0)
       |   |   +------------------------ WaveTable IRQ (any voice)
       |   +---------------------------- Volume Ramp IRQ (any voice)
       +-------------------------------- DMA TC IRQ (DRAM or Sample)



2.10  Timer Control Register - 2X8

This register  maps to  the  same location  as  the ADLIB  board's  control
register. Writing a 4 here selects  the timer stuff. Bit  6 will be set  if
timer #1 has expired. Bit 5 will be set it timer #2 has expired.



2.11  Timer Data Register - 2X9

     =================================
     | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
     =================================
       |   |   |   |   |   |   |   |
       |   |   |   |   |   |   |   +---- Timer 1 Start
       |   |   |   |   |   |   +-------- Timer 2 Start
       |   |   |   |   |   +------------ Reserved (Set to 0)
       |   |   |   |   +---------------- Reserved (Set to 0)
       |   |   |   +-------------------- Reserved (Set to 0)
       |   |   +------------------------ Mask Timer 2
       |   +---------------------------- Mask Timer 1
       +-------------------------------- Reset Timer IRQ

     Bit 0 - Start up timer #1
     Bit 1 - Start up timer #2
     Bit 5 - Mask off timer 2
     Bit 6 - Mask off timer 1
     Bit 7 - Clear Timer IRQ


2.12  DRAM I/O - 3X7

This register is used to read or write  data at the location pointed at  by
registers 43 and 44. This is used to peek and poke directly to DRAM.


___________________________________________________________________________
                                                                         21



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

2.13  Mix Control Register - 2X0

     =================================
     | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
     =================================
       |   |   |   |   |   |   |   |
       |   |   |   |   |   |   |   +---- 0=Enable Line IN
       |   |   |   |   |   |   +-------- 0=Enable Line OUT
       |   |   |   |   |   +------------ 1=Enable MIC IN
       |   |   |   |   +---------------- Enable latches
       |   |   |   +-------------------- Combine chan1 IRQ with Chan2
       |   |   +------------------------ Enable MIDI loopback TxD to RxD
       |   +---------------------------- Control Reg Select
       +-------------------------------- Reserved (Set to 0)

Bit 0 -Enable UltraSound line Input
Bit 1 -Enable UltraSound Line output
Bit 2 -Enable Stereo Mic Input
Bit 3 -Enable latches.This  provides power  to the  DMA/IRQ latches.  Once
       these are enabled, NEVER disable them.   Disabling them will  cause
       random IRQ's in the PC  since the DMA and  IRQ lines are not  being
       driven any more.
Bit 4 -Combine Channel 1 (GF1) IRQ's with Channel 2 (MIDI)
Bit 5 -Enable MIDI  loopback. Any  data sent  out  Transmit port  will  be
       looped back into the input port.
Bit 6 -Control Register Select. When this is set to a 1, the next IO write
       to 2XB will be to the IRQ control latches. When this is set to a 0,
       the next IO write to  2XB will be to  the DMA channel latches.  The
       write to 2XB for either of these MUST occur as the NEXT IOW or else
       the write to  2XB will  be locked  out and  not occur.  This is  to
       prevent an application  that is  probing for  cards to  accidentaly
       corrupt the latches.



2.14  IRQ Control Register - 2XB

     IRQ  control register         I/O       W         2XB
     (2X0- bit 6 = 1)

     Bits 2-0 Channel 1 (GF1) IRQ Selector
         0=No Interrupt
         1=IRQ2
         2=IRQ5
         3=IRQ3
         4=IRQ7
         5=IRQ11
         6=IRQ12
         7=IRQ15






___________________________________________________________________________
                                                                         22



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

     Bits 5-3 Channel 2 (MIDI) IRQ selector
         0=No Interrupt
         1=IRQ2
         2=IRQ5
         3=IRQ3
         4=IRQ7
         5=IRQ11
         6=IRQ12
         7=IRQ15

    Bit 6 1 = Combine Both IRQS using Channel 1's IRQ
    Bit 7 Reserved (Set to 0)

Note:   If the channels are sharing an IRQ, channel 2's IRQ must be set to
        0 and turn on bit 6. A bus conflict will occur if both latches are
        programmed with the same IRQ #.


     DMA control register          I/O       W         2XB
     (2X0- bit 6 = 0)

     Bits 2-0 DMA Select Register 1
        0=NO DMA
        1=DMA1
        2=DMA3
        3=DMA5
        4=DMA6
        5=DMA7

     Bits 5-3 DMA Select Register 2
        0=NO DMA
        1=DMA1
        2=DMA3
        3=DMA5
        4=DMA6
        5=DMA7

    Bit 6 - Combine Both on the same DMA channel.
    Bit 7 - Reserved (Set to 0).

Note:   If the channels are sharing an DMA, channel 2's DMA must be set to
        0 and turn on bit 6. A bus conflict will occur if both latches are
        programmed with the same DMA #.

C programmers can refer to the  UltraSetInterface routine in INIT.C of  the
lowlevel source code for the proper sequence for programming these latches.
If the order is not right, unpredictable things may happen.

Changing the IRQ settings will usually cause an IRQ on the OLD IRQ  because
it is no longer being driven low by the  latches and it will tend to  float
up. That low to high transition causes an IRQ on the PC. Normally, this  is
not a problem, but it is something to be aware of.



___________________________________________________________________________
                                                                         23



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

2.15 Register Control - 2XF

This register is  only valid  for UltraSound boards  that are  at or  above
revision 3.4.  It is  not valid  for  boards which  have a  prior  revision
number.

On 3.4 and  above boards,  there is a  bank of  6 registers  that exist  at
location 2XB. Register 2XF is used to select which one is being talked to.

Register #     Use

     0         Same as pre-3.4 boards
     1-4       Unused - Reserved
     5         Write a 0 to clear IRQs on power-up
     6         'Jumper register'


   Jumper register definition:

     =================================
     | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
     =================================
       |   |   |   |   |   |   |   |
       |   |   |   |   |   |   |   +---- Reserved (Set to 0)
       |   |   |   |   |   |   +-------- 1=Enable MIDI port addr decode
       |   |   |   |   |   +------------ 1=Enable joystick port decode
       |   |   |   |   +---------------- Reserved (Set to 0)
       |   |   |   +-------------------- Reserved (Set to 0)
       |   |   +------------------------ Reserved (Set to 0)
       |   +---------------------------- Reserved (Set to 0)
       +-------------------------------- Reserved (Set to 0)



2.16 Volume ramping description

The UltraSound has built-in volume ramping to facilitate the implementation
of the attack decay sustain release envelopes.  This ramping uses the  same
principle as the voices for updating the  volume values.  A section of  the
envelope can be programmed such  that the PC does  not need to be  burdened
with the task of changing each volume  at specified intervals.  At the  end
of that  particular section,  an IRQ  can  be generated  so that  the  next
section can be programmed in.

This continues until the entire envelope has been completed.  The start and
end points as well as the increment rate are fully programmable.

The hardware volume registers and bit definitions are:

      Current Volume (9,89)    EEEEMMMMMMMM    (Bits 15-4)

      Volume Start   (7,87)    EEEEMMMM        (Bits 7-0)

      Volume End     (8,88)    EEEEMMMM        (Bits 7-0)

___________________________________________________________________________
                                                                         24



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________


      Volume Incr    (6,86)    RRMMMMMM        (Bits 7-0)

Once the current  volume, start and  end volumes are  programmed, the  only
thing left  is to  set up  the volume  increment register.   This  register
determines how fast the  ramp takes place and  with what granularity.   The
finer the granularity, the smoother (but  slower) the ramp.  The  increment
register has 2 fields.   The first  is the amount  added to (or  subtracted
from) the current volume to get to the next one.  These are the low 6  bits
and can range from 1 to  63.  A 1  is a long, slow  ramp compared to a  63.
The upper  2 bits  determine how  often  the increment  is applied  to  the
current volume.  The rate bits are defined as:

 Rate Bits       Volume Update Rate
     00                FUR    (FUR = 1/(1.6*#active voices))
     01                FUR/8
     10                FUR/64
     11                FUR/512

Each rate increment is 8 times longer  than the preceding one.  This  means
that the value to store for the fastest possible ramp is 1Fh (63), and  the
value for the slowest  possible ramp is 1Ch  (193).  The approximate  times
for a full scale volume ramp (0-4095) are:

                Rate    Vol Inc    14 Voices     32 Voices
                ----    -------    ---------     ---------
                  0       63         1.4 ms        3.3 ms
                  0        1        91.7 ms      209.7 ms
                  1       63        11.5 ms       26.2 ms
                  1        1       733.8 ms        1.7 sec
                  2       63        91.8 ms      209.7 ms
                  3        1         5.9 sec      13.4 sec
                  3       63       734.0 ms        1.7 sec
                  3        1        47.0 sec     107.3 sec

Note that these  times are for  full sweep ramping.   Since  a volume  ramp
usually goes between points  in between the limits,  the actual ramp  times
will be much smaller.

Allowing to let the volume ramps to go  to the extremes can cause a  random
oscillation of the volume when it reaches the limits.  This is caused by an
overshoot past  the limit  due to  a large  step size.   The  SDK  routines
protect against this by limiting how close to the rails you can get.












___________________________________________________________________________
                                                                         25



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

                  Chapter 3 - Programming the UltraSound

3.0 Introduction

The UltraSound is frequently referred to as 'GUS', for Gravis'  UltraSound.
The card has  a very good  reputation among programmers,  since it is  very
easy to program using a high level language, and provides incredible sound.
However, there are some things that you need to be aware of to successfully
program  the  board.    Users  of  either  language  should  consult  their
respective example programs  before attempting to  use the card.   Also,  C
users should  consult  section  3.12, while  Pascal  users  should  consult
section 3.13.



3.1 Sound

A sound is something that you hear. It is produced by a source and received
by the ears of the listener.  There are several mediums for the storage  of
sound, including vinyl, magnetic surfaces, and more recently optical disks.

When something makes a sound, it creates waves of different air  intensity.
These waves are registered as 'sound',  and the amplitude and frequency  of
these waves determine the 'type' of sound.

Amplitude is determined by the highest  and lowest points of the wave,  and
is registered by  your ear  as the  volume of  the sound.   Therefore,  the
loudness of a  sound is  changed by varying  the amplitude  of the  sound's
wave.  Frequency is determined by the number of pulses (passes of a  single
wave peak and trough)  which pass a  certain point in  a certain amount  of
time.  The measure  of sound frequency is  done using the standard  measure
for frequency - Hertz (Hz).  The higher the frequency, the higher the pitch
of the sound that is heard.

Normal sound  like speech  and sound  that comes  from mixes  of  different
instruments  is  a  very  complex  pattern  of  changes  in  amplitude  and
frequency.  To record the wave's  pattern, a computer takes a large  number
of 'samples' of the wave produced by the sound.  Then when it goes  through
the individual  'samples' at  the  same rate  they  were recorded,  it  can
reconstruct the original  wave and produce  a sound which  is close to  the
original sound.  If the  sample rate is not  high enough, the computer  can
miss changes in the amplitude and frequency, and the sound reproduced  will
not sound exactly like the original sound.

The number of  samples taken each  second is referred  to as the  'sampling
rate', and the number of samples played back each second is referred to  as
the 'playback rate'.   When a rock  band plays a  song, the combined  sound
wave produced by the singers and  instruments is produced.  To record  this
wave at CD-quality on a computer medium  (like memory or a hard disk),  the
wave is 'sampled' 44100 times each second.  Since the number of samples per
second is a frequency, this rate is measured again in Hertz.  Therefore, we
say that the recording frequency is 44.1 kHz.



___________________________________________________________________________
                                                                         26



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

If I  record a  sound  at 44.1  kHz  for two  seconds,  I will  have  88200
individual 'samples'.  The data that comprises these 'samples' is typically
referred to as a 'sample' itself.

When a recording made at 44.1 kHz is played back at 44.1 kHz, the  original
sound is reproduced almost exactly.   Note that the recording and  playback
frequency are different from the frequency of the sound itself.

Most other sound cards do not have any  RAM on them, and therefore have  to
use the PC's RAM to store the sounds  they produce.  This leaves less  room
for application programs,  and is just  another thing that  the CPU has  to
track and process - slowing down the machine.

On the UltraSound,  samples are  stored on  the card  in it's  DRAM.   This
leaves more  space in  PC RAM  for programs.   Also,  the GF1  chip in  the
UltraSound can play  32 independent sounds  at once without  using any  CPU
time - so the machine doesn't slow down at all!



3.2 The Basics of the UltraSound

The only things  you need  to know to  set up  the card  when your  program
starts is the maximum  # of voices you  are going to  need and the  maximum
playback frequency you're going to need for any sample.

Consult the  frequency table  in section  1.3 to  see how  many voices  you
should initialize the  card with.   If  you don't  need a  large number  of
voices,  initializing  the  card  to  use  fewer  voices  means  that  some
'oversampling' will occur, making the sound better in quality.  You  cannot
initialize for fewer than 14 voices or larger than 32.

To open the card, you call  the UltraOpen function.   This will set up  the
interrupt vectors and control procedures for  the card, and then reset  the
card to use the number of voices you  specify.  When you are finished  with
the card, you need  to close it so  that the interrupt procedures,  voices,
and volumes  get stopped  and reset  to 'normal'.   To  do this,  call  the
UltraClose function.  Please see chapter  4, the reference guide, for  more
information on the syntax and usage of these routines.


3.3 Using GUS Memory

The UltraSound has a default amount of 256K of memory on the card that  can
be upgraded in 256K increments up to 1 MB.   If you are developing for  the
card, you may  want to upgrade  to a full  megabyte.  Also,  you should  be
aware that many users of the  card do NOT have 1  MB of RAM installed,  and
that if you are going to load samples  into the card's memory, you need  to
check to  make sure  you  have enough  room.   The  function  UltraMaxAlloc
(additionally  for   Pascal   users   the   functions   UltraMemAvail   and
UltraMaxAvail) will  tell  you  how much  RAM  you  still  have  available.
Because of the  way the  GUS memory  is structured  physically, you  cannot
allocate chunks larger than 256k at one time.


___________________________________________________________________________
                                                                         27



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

The C and  Pascal versions  of the SDK  use different  methods for  keeping
track of blocks of memory that  have been allocated and blocks that  remain
free.  The C version uses a small portion of  GUS RAM to keep track of  the
blocks, whereas  the Pascal  version uses  a small  amount of  normal  heap
space.  In any event, you do not have to worry about the internal operation
of these routines.  To see  how the Pascal version  uses a small amount  of
heap space to manage GUS memory, see section 3.13.3.

The memory allocation routines will ONLY return 32 byte aligned  addresses,
so if your application uses them, this will not be a problem. If you  chose
not to  use the  allocation routines  provided, be  sure and  follow  these
rules.  To obtain a legal block of UltraSound RAM that is guaranteed to  be
aligned on a 32-byte boundary, use the UltraMemAlloc function.  To free  up
the memory after  you have used  it, use the  UltraMemFree function.   Once
again, see chapter  4, the  reference guide,  for more  information on  the
syntax and usage of these routines.

You DO NOT necessarily need to  use the memory allocation and  deallocation
routines to program the card.  You DO have  to be careful if you choose  to
do without them.  The DMA can only begin on a 16 or 32 byte boundary. An  8
bit DMA channel (0-3) must start on a 16  byte boundary while a 16 bit  DMA
channel (4-7) must start on a 32  byte boundary. If an improper address  is
supplied, the address will be truncated down when the DMA occurs.  A DMA to
or from the card cannot cross a 256K boundary.

To send data from  PC memory to the  card, use the UltraDownload  function.
To read data from  the card into PC  memory, use the UltraUpload  function.
If you download data to the card, ensure that  if the data is not in  two's
compliment form you convert it to two's compliment on the download.  To  do
this, use the DMA control bits (see Appendix D).  Any data you Upload  from
the card that is playable will be in two's compliment format.



3.4 What are Samples?

As mentioned above, a 'sample' is raw data that has been recorded using the
GUS or another digital  sound recording device.   Most of these files  will
have extensions of .SND or .WAV.  There are other extensions available, but
these are the most common.

A technique  known as  'frequency shifting'  is sometimes  used to  produce
alternate 'notes' of a specified instrument.  Amiga '.MOD' file players use
this technique to  make a single  instrument sample  sound differently  for
each note played over 3 octaves.   Essentially, the technique utilizes  the
12-note scale with  the principle  that each half-step  is 1/12  root of  2
times the  value of  its predecessor  in frequency  (working from  left  to
right).  For  instance,  if  we  take  C  as  (1*frequency),  C#  would  be
(1.05946*frequency).  Since there are 12 notes in an octave, when you reach
B (the end of the octave), the next note is (2*frequency) - so doubling the
original frequency means you raise the note one octave.




___________________________________________________________________________
                                                                         28



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

There is a  drawback to the  technique mentioned above.   If  a sample  was
recorded at 11kHz for two seconds, and  then played back at 22kHz to  raise
the note one  octave, it would  only play for  one second  instead of  two.
This is because you have (11025 * 2 seconds) = 22050 bytes of data.  If you
play this at  22050 Hz,  or 22050 bytes  per second,  you will  have one  1
second of sound.  Thus, if you raise or lower the frequency in this manner,
the sound will  respectively take  a shorter or  longer amount  of time  to
play.

A common problem with samples is that the start and/or end of them is at  a
reasonably high amplitude.  When the sample starts and/or stops, the values
flowing through the DACs on the card change suddenly.  This usually results
in an audible 'click' or 'pop' through the speakers.  Section 3.8 looks  at
the removal of this and other types of clicks and pops than can occur.



3.5 Using Voices

Depending on the number you choose when opening (or initializing) the card,
you can use anywhere  from 14 to 32  voices at once.   You can look at  the
voices as those of the people in a choir.  You can tell the voices to start
or stop  singing (UltraStartVoice,  UltraStopVoice),  sing at  a  specified
pitch or frequency (UltraSetFrequency),  loudly or softly  (UltraSetVolume,
UltraSetLinearVolume), and at a specified balance (UltraSetBalance).

The exciting thing  about the  voices is  that any  number of  them can  be
played at once, and there is no extra drain on the CPU if you are playing a
larger number of voices as  opposed to a smaller  one.  Also, these  voices
can play any type of sampled sound, 8- or 16-bit, at frequencies up to 44.1
kHz.  Any number of voices can even play the same sample at the same time.

To start  up  a voice,  you  use the  UltraStartVoice  or  UltraPrimeVoice/
UltraGoVoice combination.  Either one of these two routines will ask for  a
voice number, as  well as a  begin, start, and  end location.   The  reason
begin and start locations are both asked for is in case you wish to play  a
sample backwards or  loop at a  specific position which  is not the  start.
The following diagram may make this clearer:

                             Forward playing:
                             ================
                     -------->------->-------->------|
                                  ^---------<------<-|
                 Begin ...... Start Loop......... End Loop
                 location ... location  ......... location

                             Backward playing:
                             =================
                  |------<-----<------<------<----------
                              |--------->----->---->---^
               End Loop.... Start Loop............... Begin
               location .... location ................location



___________________________________________________________________________
                                                                         29



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

A voice starts at the 'begin' location, and continues playing until it hits
the 'end' location.  If the 'begin'  is a greater location than the  'end',
the sample will be played backwards.  The 'start' location is the start  of
the loop if looping is  enabled for the voice  begin played.  Depending  on
whether and how you wish  to loop the voice,  you can make various  effects
occur.  Looping of the voices is discussed in the next section.

When you have finished with a  voice, You should stop it  (UltraStopVoice),
and deallocate  it  (UltraFreeVoice).   Please  see section  3.8  on  click
removal for information on problems with stopping a voice abruptly.


3.6 Volumes

A volume is available for each voice.  If the volume for a voice is not set
to zero, the data at the position of the voice's accumulator will be summed
into the final  output.  Therefore,  it is important  that if  you are  not
using a voice you should set it's volume to zero.

The UltraSound uses logarithmic volumes using  an exponent and a  mantissa.
For detailed information  about how the  volumes work,  please see  section
2.16.  As an alternative to using  the logarithmic units, a table has  been
provided in the lowlevel  code which gives linear  equivalents of the  full
volume range.  You can therefore use the logarithmic volume routines or the
linear volume routines - whichever your application requires.

Volumes for each voice may be 'ramped'.  This means that you can specify  a
start and end volume, and the card will smoothly change the volume from the
beginning level to the end level.  In ramping the volumes, a 'rate' must be
specified which assigns how fast the volume is changed.  Please see section
2.16 for detailed information on how to set up a volume ramp rate.



3.7 Using Looping

You can loop both voices  and volumes on the  UltraSound.  Looping a  voice
can result in  sustaining a  particular note,  the generation  of a  unique
sound, or any number  of other 'special effects'.   Looping the volume  can
result in a tremelo effect at various intervals.

Looping a sample is a simple task of setting the mode bits when  specifying
the start of  a voice (through  UltraPrimeVoice, UltraStartVoice), or  when
using UltraSetLoopMode.  See appendix C  for a definition of which bits  in
the mode byte control looping.  Also,  Pascal users should be aware of  the
constants that are available for use instead (see section 3.13).

Looping the  volume is  essentially as  simple as  looping a  voice.   When
specifying the  volume  for a  particular  voice (using  UltraSetVolume  or
UltraSetLinearVolume), you set the  volume mode byte  depending on how  you
wish to loop the volume.  See appendix B for a definition of which bits  in
the mode byte control looping.



___________________________________________________________________________
                                                                         30



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

3.8 Clicks and click removal

As was mentioned in  a few of the  preceding sections, 'clicks' and  'pops'
can occur when the output of  the DAC changes suddenly.   This is the  most
frequent type of click, since there  may not be a  way to control the  data
values the voices are trying to play.

In general, it is necessary to remember that all voices are being summed in
to the  final output,  even if  they  are not  running.   This  means  that
whatever data value that  the voice is pointing  at is contributing to  the
summation.  It is important that a voice be  pointed to a known value at  a
known location after it is  stopped so that some  control is kept over  it.
For instance, if a voice  were left at whereever  the end position was  for
the last time it played, a pop could  occur if new data were either  DMA'ed
or poked over the  top of it.   For this reason, it  is recommended that  a
voice be pointed to a location containing a 0 and that its volume be set to
0.  At  that point,  the voice  will have  no contribution  to the  output.
There are some particular cases where clicks most frequently occur:

During Reset
- Because of  the way  the card  is  reset, a  pop  can occur  through  the
  speakers when a reset occurs.  The way  to remove this pop is to  disable
  the output, reset the card, and then enable the output again.

During a balance sweep
- Since there are  only 16 pan  positions and there  is such  a large  jump
  between individual positions,  a relatively fast  balance sweep from  one
  side to another may produce  clicks.  You can  get a very smooth  balance
  sweep using 2 voices and volume  ramping.  Set one  voice up to one  side
  and one to the other, and ramp one down from volume X to zero at the same
  rate as you ramp the other from 0 up to volume  X.  The result is a  very
  smooth balance sweep.

When starting and stopping a voice
- By setting up fairly fast rates when  a sample start or ends and  ramping
  up or down appropriately, any pop created  by a sudden change in the  DAC
  value will be summed in at such a low volume, it will never be heard.

End points not set properly
- Make sure your end points are at the ends  of your samples. It is a  very
  common mistake  to set  an end  point to  1 sample  beyond the  end.  For
  example, if a sample is 100 bytes long an starts at location 100, the end
  point is at position 199,  NOT position 200.   Also, it is possible  that
  the GF1 will interpolate data at points beyond the end point.  To  ensure
  that this does not cause  'clicks', use a few  extra bytes after the  end
  point of the sample to maintain it.

Loop points not set properly
- The same problem as  stated above (end points)  is common for loop  start
  and end points.   Be sure that the  data at the end  of the loop and  the
  beginning of the  loop are  practically identical,  since if  there is  a
  large step between them  a click will result  because the DAC value  will
  change suddenly.


___________________________________________________________________________
                                                                         31



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

3.9 Interrupt Handling Functions

There are 9 functions  (procedures for Pascal users)  which can be used  to
define a handler for events that happen under interrupt on the  UltraSound.
These are  NOT interrupt  handlers but  are  callbacks from  the  interrupt
handler.  This  means that  they should not  be defined  as interrupt  type
functions but must adhere to the general  rules of interrupt code.  No  DOS
calls should be made and care must be taken not to cause problems with code
running in the foreground.

              UltraDramTcHandler          UltraRecordHandler
              UltraMIDIXmitHandler        UltraMIDIRecvHandler
              UltraTimer1Handler          UltraTimer2Handler
              UltraWaveHandler            UltraVolumeHandler
                              UltraAuxHandler

All these routines  return the old  callback address so  chaining could  be
done if desired.  This not usually necessary.  It is also not necessary  to
restore the handler  back to  the old  one when  exiting your  application.
However, the  UltraClose function  MUST be  called  to restore  the  actual
interrupt handler.

These will only be CALLED if  the interrupt for the particular function  is
enabled in the mode parameter (see the Appendices for the bit definitions.)
It is  also not  necessary to  set up  a callback  since it  has a  default
associated with it.

You should be able to make any SDK library calls from within the  interrupt
handlers.    All  the  library  functions  protect  themselves  from  being
interrupted while doing critical operations.



3.10 Rollover feature

Each voice  has a  'rollover'  feature that  allows  an application  to  be
notified when a voice's playback position passes over a particular place in
DRAM.  This  is very useful  for getting seamless  digital audio  playback.
Basically, the GF1 will generate an IRQ when a voice's current position  is
equal to the end position.  However, instead of stopping or looping back to
the start position, the voice will continue playing in the same  direction.
This means that there will be no pause (or gap) in the playback.  Note that
this feature is enabled/disabled thru  the voice's VOLUME control  register
(since there are no more bits available in the voice control registers).  A
voice's loop enable  bit takes precedence  over the rollover.   This  means
that if a  voice's loop enable  is on, it  will loop when  it hits the  end
position, regardless of the state of the rollover enable.

A simple example of this technique is:

1)   Allocate a chunk of DRAM: 20K, for example.
2)   Load the entire 20K with wave data.
3)   Start up a voice with looping disabled and rollover enabled.  Set  its
     end position to the MIDDLE of the buffer.

___________________________________________________________________________
                                                                         32



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

4)   When the voice hits  the middle, you  will get an  IRQ, but the  voice
     will continue to play.
5)   At this point, enable looping and disable the rollover.  Also, set the
     end position to the end of the  buffer. This will make the voice  loop
     back to the beginning without stopping.
6)   Now load the FIRST 10K with more  wave data. This will make sure  that
     there is correct data to play when the voice loops.
7)   When the voice loops, you will get and IRQ.
8)   At this  point,  disable looping,  enable  rollover and  set  the  end
     position back to the middle of the buffer.
9)   Now load the SECOND 10K with more wave data. This will make sure  that
     there is corect data to play when the rollover occurs.
10)  Continue in a loop, starting at step #4.

Note:This algorithm does not take care  of an initial condition where  not
     enough data  exists to  fill one  complete  buffer. It  also  doesn't
     address how  to finish  playing the  last incomplete  buffer.   These
     points are left up to your implementation to resolve.



3.11 Stereo playback

Stereo data is represented in an interleaved format, meaning that the  data
alternates between a sample for the left channel and a sample for the right
channel.  It is either the  responsibility of the hardware or the  software
to ensure that the data gets used properly. Stereo data can be played  back
two completely different  ways, either under  software control or  hardware
control:

Software Control
================

This is  the most  flexible method,  since it  allows for  playback at  any
frequency.  The basic  algorithm is to de-interleave  the data into a  left
channel buffer  and a  right channel  buffer,  then send  the data  to  two
independent voices  on  the card.    Here is  a  brief description  of  the
algorithm that would be used:

1)   Allocate 2 voices. One for left and one for right.
2)   Set the left voice pan position all the way left.
3)   Set the right voice pan position all the way right.
4)   Set both voice volumes to the same value.
5)   Allocate 2 chunks of UltraSound DRAM of the same size, say 20K apiece.
6)   Read in 40K of stereo data.
7)   De-interleave data into 20K of left data and 20K of right data.
8)   DMA left buffer into DRAM buffer #1.
9)   DMA right buffer into DRAM buffer #2.
10)  Prime right voice to loop on all 20K of data forever. No IRQ.
11)  Prime left voice  to play 10K  of its data  with the rollover  feature
     enabled (See discussion on seamless digital playback above).
12)  Start both channels  up as close  together as possible  so they  track
     together. The right  channel will not  be touched, except  to DMA  new
     data into its buffer.

___________________________________________________________________________
                                                                         33



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

13)  At this point the software will loop on the following steps until  the
     data is exhausted. The rollover will  allow the software to play  half
     the buffer and  get notified when  it has finished,  but the  playback
     will continue uninterrupted. When the  rollover IRQ happens, the  left
     voice will be changed to loop at  the 20K position. At this point  the
     software will be able to load the  next 10K of left channel data  into
     the FIRST 10K of the left channel DRAM. The right channel is also sent
     10K of data into its FIRST 10K.
14)  Now each channel  has the data  to play when  they loop  at their  20K
     marks.
15)  When the left  channel's loop  IRQ happens,  both the  left and  right
     channel can be sent more data into their SECOND 10K buffer. Also,  the
     left channel's  looping will  be turned  off and  it will  be told  to
     rollover at its 10K mark again.  Now both channel's are ready to  play
     thru their 10K marks with no interruption.
16)  Go back to step 13 and loop

The above algorithm does not detail the startup conditions or the  shutdown
conditions.

Things that you will need to accomodate are:

1) Less than 1 buffer full of data.
2) How to terminate when data ends in  first buffer. You must allow it  to
   loop back from the end and then stop at the end of the data  instead of
   rolling over at the middle. Both right and left must be taken care of.
3) How to terminate when data ends in the second buffer.  After filling in
   the data in the second buffer, you can turn off the rolling over at the
   middle and tell it to stop at the end of the data in the second buffer.

Be sure you understand all the starting and ending possibilties when coding
you application.

The basic idea is to let the right voice  loop forever on a buffer of  data
and feed it data  based on IRQ  generated from the  left channel. The  left
channel can be monitored  via the rollover feature  to generate and IRQ  at
the halfway point and an IRQ at the loop point at the end of the buffer  to
know when the second buffer finishes. Data will then be sent to BOTH voices
for the portion of data that it just finished playing.


Hardware Control
================

This method has  the advantage  of not  needing to  de-interleave the  data
before DMAing it into  UltraSound DRAM: the data  is  sent  to DRAM in  the
interleaved format. This  means that  a voice must  be able  to play  every
other sample  to correctly  separate  the right  and  left channel.  It  is
possible to set up the GF1  and the 2 voices to  do this, however, it  will
only work for 2 usable freqencies. (44100 and 22050). Any other frequencies
must be done using the software control de-interleaving method.




___________________________________________________________________________
                                                                         34



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

The theory behind how to achieve  this is quite complex. It involves  using
the # of active voices and the voice's frequency control register to get it
to grab the correct  samples at the  proper frequency.   Here is the  setup
necessary to playback 44100 Hz stereo and 22050 Hz stereo data:

44100 Hz:Set the #  of active voices  to 14 and  set both voices  playback
         rate to 88200 hz.

22050 Hz:Set the #  of active voices  to 28 and  set both voices  playback
         rate to 44100 hz

These two configurations  will make both  voices have  a frequency  control
register equal to 2. The frequency control register holds the amount  added
to the current voice playback location to get the next playback location.

Normally, this number is  a fraction so interpolation  is done to  generate
intermediate points between successive locations. With interleaved data, we
don't want to interpolate since the  neighboring data points belong to  the
other channel.  We want to completely skip over the point after the current
one, and go to our current position plus 2.

The number of active  voices selected will determine  the update rate.  The
more voices that are active, the longer time between updates, thus  slowing
down the frequency.  14 active voices  will give and  update rate of  about
22.5 microseconds (44100 hz), whereas 28  voices will give and update  rate
of about 45 microseconds (22050 hz).

The intialization of the voices in  this mode will obviously be  different.
Essenntially, the voices must be  set up to play  the same data but  offset
their start and end points by one or two bytes, depending on whether it  is
an 8- or 16-bit sample.


3.12 C-specific information

Currently,  10  different  C   memory  model/compiler  configurations   are
supplied.  Large, medium, small and  tiny models for Borland and  Microsoft
compilers are available,  as well  as flat  model for  WatCom and  MetaWare
compilers.  The level  0 library contains the  lowest level function  calls
that talk directly to the hardware.  The level 1 library is a little higher
and contains  functions that  call level  0 functions.   The  3D  libraries
contain the functions necessary for implementing the Focal Point 3D sounds.
Borland C++ 2.0  and 3.1, Microsoft  C 6.0, Watcom  C9.0/386, and  Metaware
High C/C++ were used to  test the library routines.   These are the  naming
conventions for the C libraries:

     ultra0lb.lib Level 0, large model,  Borland C
     ultra1lb.lib Level 1, large model,  Borland C
     ult3D_lb.lib      3D, large model,  Borland C

     ultra0mb.lib Level 0, medium model, Borland C
     ultra1mb.lib Level 1, medium model, Borland C
     ult3D_mb.lib      3D, medium model, Borland C


___________________________________________________________________________
                                                                         35



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

     ultra0sb.lib Level 0, small model,  Borland C
     ultra1sb.lib Level 1, small model,  Borland C
     ult3D_sb.lib      3D, small model,  Borland C

     ultra0tb.lib Level 0, tiny model,   Borland C
     ultra1tb.lib Level 1, tiny model,   Borland C
     ult3D_tb.lib      3D, tiny model,   Borland C

     ultra0lm.lib Level 0, large model,  Microsoft C
     ultra1lm.lib Level 1, large model,  Microsoft C
     ult3D_lm.lib      3D, large model,  Microsoft C

     ultra0mm.lib Level 0, medium model, Microsoft C
     ultra1mm.lib Level 1, medium model, Microsoft C
     ult3D_mm.lib      3D, medium model, Microsoft C

     ultra0sm.lib Level 0, small model,  Microsoft C
     ultra1sm.lib Level 1, small model,  Microsoft C
     ult3D_sm.lib      3D, small model,  Microsoft C

     ultra0tm.lib Level 0, tiny model,   Microsoft C
     ultra1tm.lib Level 1, tiny model,   Microsoft C
     ult3D_tm.lib      3D, tiny model,   Microsoft C

     ultra0wc.lib Level 0, Flat model,   Watcom C
     ultra1wc.lib Level 1, Flat model,   Watcom C
     ult3D_wc.lib      3D, Flat model,   Watcom C

     ultra0mw.lib Level 0, Flat model,   Metaware High C/C++
     ultra1mw.lib Level 1, Flat model,   Metaware High C/C++
     ult3D_mw.lib      3D, Flat model,   Metaware High C/C++

Several example applications are supplied on the toolkit disks to show  you
how to interface to the libraries.   Please look them over carefully.  They
are the best way to get a handle on the way the card operates.



3.13 PASCAL-specific information

Version 2.10 of  the UltraSound  SDK is the  first version  which has  full
support for Turbo Pascal 6.0  and 7.0, as well  as Borland Pascal 7.0.  For
those of  you who  are  curious, Borland  Pascal  7.0 is  the  professional
version of Turbo Pascal 7.0.   It costs more, but  includes a lot of  bells
and whistles that are not included in the regular 'Turbo' version (for more
information, contact Borland).

The translation was done  entirely by Kurt  Kennett of Ingenuity  Software,
and is a  direct translation of  the C toolkit.   The code  was written  in
Borland Pascal 7 and  then minor adjustments were  made to make it  compile
under Turbo 6 and 7.




___________________________________________________________________________
                                                                         36



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

Due to the fact that the Pascal translation  was done after the C code  was
finished, some of  the naming  conventions for  some of  the functions  and
record types reflects  a 'C-like'  syntax and  style.   Some conversion  of
function  result  types  has  been  done  to  reflect  a  more  Pascal-like
structure.

After installation of the  SDK, there will be  two units and one  interface
file available in the PASCAL subdirectory:

     ULTRADRV.V60  Turbo Pascal 6.0 version
     ULTRADRV.V70  Turbo/Borland Pascal 7.0 version
     ULTRADRV.INT  This is the interface section for all units.

You should copy the unit you wish to  use to one of your unit  directories,
and then rename the unit to  'ULTRADRV.TPU'.  You may experience  compiling
problems if you  do not rename  the file.   You may also  wish to copy  the
interface file to use as a quick-reference.

For users of Turbo and Borland Pascal 7.0, a help file has been provided to
allow quick context-sensitive  help from inside  the IDE editor.   Also,  a
MAKEHELP.TXT version of this  help file has been  provided for those  users
who employ TurboPower's context-sensitive help system.

To install the IDE help file, load Turbo or Borland Pascal 7 and select the
'Help' menu from the  menu bar.  Choose  the 'Files...' option, and  select
the 'Add'  button.   Choose the  file  'ULTRADRV.TPH' from  the  UltraSound
PASCAL subdirectory.  After you have done this, you may use the F1 key  and
it's derivatives to access reference information  for any of the  functions
and procedures in the SDK reference manual (chapter 3).

For  example,   after   installing   the   help   file,   type   the   word
'UltraSetFrequency' into the IDE, move the  cursor on top of the word,  and
press CTRL-F1.  You will be given an explanation of the syntax and usage of
the Procedure, as  well as  information on  related procedures,  functions,
constants, and variables.

A short section  detailing specific information  about types and  constants
available follows.   For more information,  please see  the interface  file
ULTRADRV.INT.



3.13.1 Available constants and variables

The SDK TPU (or  'driver') has some predefined  constants to assist you  in
programming  various  aspects  of  the  card.    There  are  three   common
frequencies that sampled sounds are played at: 11, 22, and 44 KHz:

     Khz_11 = 11025;
     Khz_22 = 22050;
     Khz_44 = 44100;




___________________________________________________________________________
                                                                         37



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

Whenever volume is specified, there is a volume control byte.  The bits  in
this byte control several important functions.  OR the following  constants
together with zero if you need  them.  If you  don't, just specify zero  as
the volume control byte:

     Loop_Volume           = 08;
     Bi_Directional_Volume = 16;
     Enable_Volume_Handler = 32;

Whenever a voice is started or changed, there is a voice control byte.  The
bits in this byte control several  important functions for each voice.   OR
the following constants together with zero if you need them.  If you don't,
just specify zero as the voice control byte:

   Voice_Data_16Bit        = 04;
   Loop_Voice              = 08;
   Bi_Directional_Voice    = 16;
   Enable_VoiceEnd_Handler = 32;

When a DMA transfer is  started, you need to  tell the DMA controller  what
type of  data  you  are sending  to  the  UltraSound, as  well  as  if  the
controller should  convert  the  data  to  2's  complement.    If  you  are
downloading ram .SND  files to the  card, you need  to OR the  Convert_Data
constant to 0 as the control byte.  If you are downloading 16 Bit data, you
need to OR the control byte with DMA_Data_16Bit.

   DMA_Data_16Bit = 64;
   Convert_Data   = 128;

There are several predefined  variables to help  you manage the  UltraSound
card as you  use it.   These variables determine  the Configuration,  error
codes, and whether or not the card is installed:

Ultra_Installed : BOOLEAN;
If the driver cannot  read the environment variable  'ULTRASND' when it  is
initialized (i.e.  when  your program  starts),  this BOOLEAN  will  remain
false.  Otherwise,  the variable Ultra_Config  (see below) will  be set  up
with the values found in the environment variable.

Ultra_Config  : Ultra_CFG;
If the  driver  was  able  to read  a  configuration  from  the  'ULTRASND'
environment variable,  this variable  record will  be  filled in  with  the
appropriate information  found  in the  environment.   If  the  environment
string is not  found, this variable  will assume  a default  configuration.
All of the functions and procedures in the driver use this configuration to
initialize and use the  card.  Be  careful if you're  going to go  sticking
values into this record.  The main use  of this variable is to display  the
active configuration to the user.







___________________________________________________________________________
                                                                         38



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

The driver predefines three variables to help you with error control:

UltraOk       : Boolean;
This boolean always maintains the status  of the last UltraSound  procedure
or function.  If there was a  problem with the routine, this variable  will
be FALSE.  Otherwise, it will be TRUE (indicating no error).

UltraError    : Integer;
This is the "Error  Code" of the Error.   This variable is  set to 0 if  no
error has occurred, and is only set when UltraOk becomes FALSE.

UltraErrorStr : String;
This is the "description"  of the error  which has occurred.   As an  added
bonus to you, the programmer, this string is set with a (descriptive) error
message whenever a card-related error occurs.



3.13.2 Examples

There are several example programs included with the units described in the
previous section:

GUSINIT.PAS
This example file is a small  unit that you may  want to use to  initialize
the GUS before you use it.  The important thing about this unit is that  it
installs an  'Exit  Procedure' which  is  called upon  program  termination
(normal or crash-out).   The  exit procedure  closes down  the card  before
returning to DOS (or the IDE, depending upon where you are).  In TP and  BP
7, you can type 'ExitProc' into the IDE, move the cursor on top of it,  and
hit CTRL-F1 for a detailed explanation of what an exit procedure is.  After
including this unit in  your 'uses' clause, your  main program can just  go
ahead and start using it.  You don't need to call UltraOpen, UltraReset, or
even UltraClose when you're finished.

GUS1.PAS
This is the primitive example program for the card which loads three sounds
(a laser blast, a photon  torpedo, and a missile)  into the card's RAM  and
then allows you to press the '1'..'3' keys to play them.  This example uses
the GUSINIT unit - showing you how easy it is to use.

LOADMOD.PAS
This is a unit which provides services to load Amiga '.MOD' files into  GUS
RAM and main memory.  After calling  a single function, the file will  have
been loaded and the samples contained in it set up to play.  It is left  up
to you to supply playback routines or trivial sample-playing routines.









___________________________________________________________________________
                                                                         39



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

3.13.3 Management of GUS RAM.

The Pascal  version of  the  SDK employs  a  different approach  to  memory
control than the C toolkit.  In the C SDK, a small amount of the GUS RAM is
used to keep track of allocated  blocks.  In the  Pascal SDK, a very  small
amount of heap space is used to keep track of the blocks.

Because of the way  the UltraSound RAM is  structured, any particular  card
has a total  amount of installed  RAM that is  a multiple of  256k.   Since
samples cannot be played across these  boundaries, the driver unit  divides
the total RAM by 256k into 1 to 4 'pools'.

        |--------------------------------------|
        |                                      | 256k (a single 'pool')
        |--------------------------------------|

Each of these pools is seen as a single unit which can be subdivided.   For
the purposes of this example, we will  use a GUS which has 512k  installed.
If this is the case, there will be two pools of RAM available:

        |--------------------------------------|
        |                                      | Pool 1
        |--------------------------------------|
        |                                      | Pool 2
        |--------------------------------------|

Once the card has been  initialized, there will be  a small amount of  heap
space being  used to  keep track  of  these pools  (usually less  than  100
bytes).  At this point, the  UltraMaxFree function will return 256k,  since
the size of the  largest block that  can be allocated  is one entire  pool.
The UlraMemAvail function  will return 512k  however, reflecting the  total
amount of memory still available.

If a user were to allocate a 128k chunk of memory, the allocation  routines
would look in each pool sequentially until a pool is found with enough room
for the new block.  At this point in our example, it would use Pool 1.

        |----------------------------------------|
        |XXXXXXXXXXXXXXXXXXXX                    | Pool 1
        |----------------------------------------|
        |                                        | Pool 2
        |----------------------------------------|

The X's in the diagram above reflect used space.  If the size of the  block
being allocated is not  divisible by 32,  the actual size  of the block  in
memory is increased to the next multiple of 32.  For example, if I were  to
ask for a 50  byte chunk of  RAM, the actual  size of ram  that I would  be
using would be  64 bytes in  size.  This  is so that  all memory  locations
returned will  be  aligned on  a  32-byte boundary.    At this  point,  the
UltraMaxFree function will return 256k, since the size of the largest block
that can be allocated is still one entire pool (Pool 2).  The UltraMemAvail
function will  return 384k,  reflecting the  total amount  of memory  still
available.


___________________________________________________________________________
                                                                         40



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

If a user  were to  now allocate  a 200k  chunk of  memory, the  allocation
routines would once again  look in each pool  sequentially until a pool  is
found with enough room for the new block.  At this point in our example, it
would have to use Pool 2, since there is not enough room left in Pool 1.

        |----------------------------------------|
        |XXXXXXXXXXXXXXXXXXXX                    | Pool 1
        |----------------------------------------|
        |YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY         | Pool 2
        |----------------------------------------|

At this  point, the  UltraMaxFree function  would  return 128k,  since  the
largest block free is in Pool 1.   UltraMemFree would now return 184k.   If
we were to allocate a third block of 70k, the diagram would look like:

        |----------------------------------------|
        |XXXXXXXXXXXXXXXXXXXXZZZZZZZZZZ          | Pool 1
        |----------------------------------------|
        |YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY         | Pool 2
        |----------------------------------------|

If we were to now DEallocate the first  block (the X's in the diagram),  we
would be left  with a 'hole'  in the ram.   This is  reminiscent of a  hard
disk's free space fragmentation.

        |----------------------------------------|
        |                    ZZZZZZZZZZ          | Pool 1
        |----------------------------------------|
        |YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY         | Pool 2
        |----------------------------------------|

Note that the SDK's memory allocation  routines do NOT relocate samples  to
fend off fragmentation.  Note also that the memory routines are set up  and
are ready to be  used as soon as  you call UltraOpen,  and are closed  down
automatically (and  the heap  space they  use  deallocated) when  you  call
UltraClose.



3.14 Coming Attractions

There are a couple of addendums  to the SDK that  will be released as  they
are completed.  They  deal with hardware  that is in  the process of  being
implemented.  Code and documentation necessary to make them operate will be
made available as soon as possible.

1) New mixer.  All UltraSounds  that are made  that have  a board  revision
number greater than  3.6 will  incorporate a  new mixer.   Basically,  this
mixer allows  software control  over the  levels of  the input  and  output
signals.  This is a 1 chip mixer: Gravis will make specs and block diagrams
available as soon as we can.




___________________________________________________________________________
                                                                         41



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

2) 16 bit recording  support. This falls into  2 categories: daughter  card
support and UltraMax  support.  Both  of these use  the same chip  (Crystal
Semiconductors CS4231 CODEC).   Contact  Crystal to  get a  data sheet  for
specs on how to program it:  their telephone number is (512) 445-7222.  The
only difference in the 16 bit recording  capabilities of the 2 cards is  in
how it interfaces to the rest of  the UltraSound card.  Block diagrams  for
both of these boards will be made available when the toolkit for the  codec
is released.



3.15 Technical Support

                Questions regarding the SDK can be sent to:

                           SDK Technical Support
                              Advanced Gravis
                         101-3750 North Fraser Way
                     Burnaby, British Columbia V5J 5E9
                            FAX (604) 431-5155

      If you have access to a modem, you can contact Gravis' BBS at:
                              (604) 431-5927

    If you have access to internet mail services, you can send mail to
'john.smith@gravis.com' for general questions, or 'kurt.kennett@gravis.com'
          for questions regarding the Pascal version of the SDK.

 Please make sure you have consulted this documentation before contacting
                        Technical support. (RTFM!)

























___________________________________________________________________________
                                                                         42



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

                        Chapter 4 - Reference Guide

This chapter is a reference guide for the routines that compromise both the
C and Pascal versions of the SDK.  Please see the table of contents to look
up a particular routine quickly by name.


UltraCalcRate
_________________________________

Purpose:   To calculate the rate for a volume ramp.

C:         unsigned char UltraCalcRate(start,end,mil_secs);
           unsigned int start;
           unsigned int end;
           unsigned long mil_secs;

PASCAL:    FUNCTION UltraCalcRate(StartV   : WORD;
                                  EndV     : WORD;
                                  Mil_Secs : LONGINT) : BYTE;

Remarks:   This routine calculates the  rate necessary to  ramp the volume
           from StartV volume  (logarithmic) to  EndV volume (logarithmic)
           in a desired # of milliseconds.  This value should be passed to
           UltraRampVolume.  This  is only  an approximation.   The longer
           the time span, the less precise the result is likely to be.

Returns:   A  value   which   can   be   passed   to  UltraRampVolume   or
           UltraRampLinearVolume.

See also:  UltraRampVolume, UltraRampLinearVolume



UltraClose
_________________________________

Purpose:   To close out the UltraSound card.

C:         int UltraClose(void);

PASCAL:    FUNCTION UltraClose : BOOLEAN;

Remarks:   This routine should  be called  before your  application exits.
           It shuts down all  audio and puts  the card in  a stable state.
           It also puts  the PC back  to the  state prior  to running your
           application (resets interrupt vectors etc).

Returns:   TRUE if Close was successful, FALSE otherwise.

See also:  UltraOpen, UltraReset




___________________________________________________________________________
                                                                         43



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraDownload
_________________________________

Purpose:   Download a chunk of data into UltraSound DRAM.

C:         int UltraDownload(dataptr,control,dram_loc,len,wait);
           void *dataptr;
           unsigned char control;
           unsigned long dram_loc;
           unsigned int len;
           int wait;

PASCAL:    FUNCTION UltraDownLoad(DataPtr  : POINTER;
                                  Control  : BYTE;
                                  DRAM_Loc : LONGINT;
                                  Len      : WORD;
                                  Wait     : BOOLEAN) : BOOLEAN;

Remarks:   This routine will transfer a chunk of data from the PC's RAM to
           the UltraSound's DRAM.  It will  transfer 'Len' # of bytes from
           DataPtr (in  PC) to  DRAM_Loc (in  UltraSound).   If  'Wait' is
           TRUE, then it  will wait  until the transfer  is complete.   If
           'Wait' is FALSE, it will return as soon as transfer is started.
           In some cases  where you  need to get  output quickly,  you can
           start the download and  then immediately start  a voice playing
           the data.   The  DMA transfer  is  MUCH faster  than  the voice
           playback, so  it will  be able  to download  data ahead  of the
           playback.  For obvious reasons, this  will not work if you want
           to play the data backwards.  See Appendix D for a definition of
           the control  bits.    They  specify  the  type  of  data  being
           transferred.

Returns:   C:      ULTRA_OK if no problem.
                   DMA_BUSY if DMA Channel is busy.

           PASCAL: TRUE if transfer was successful.   FALSE otherwise.
                   If unsuccessful, check UltraErrorStr for the reason.

See also:  UltraUpload, UltraDRAMDMABusy
















___________________________________________________________________________
                                                                         44



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraDRAMDMABusy
_________________________________

Purpose:   Test to see if the DMA channel is busy.

C:         int UltraDramDMABusy(void);

PASCAL:    FUNCTION UltraDRAMDMABusy : BOOLEAN;

Remarks:   This routine will check to see  if the to/from DRAM DMA channel
           is busy.  It  might be useful so  your application doesn't hang
           around while waiting for a DMA transfer to complete.

Returns:   TRUE if the channel is still busy.   FALSE if it's free.

See also:  UltraWaitDRAMDMA, UltraDownload, UltraUpload



UltraGoRecord
_________________________________

Purpose:   To start up a pre-set record.

C:         int UltraGoRecord(control);
           unsigned char control;

PASCAL:    FUNCTION UltraGoRecord(Control : BYTE) : BOOLEAN;

Remarks:   This routine  will  start  up a  pre-primed  record  (done with
           UltraPrimeRecord).  It can also be used to restart a indefinite
           recording process from the recording handler callback.

Returns:   C:      ULTRA_OK if no error
                   DMA_BUSY if the channel is busy

           PASCAL: TRUE if Record started ok.  FALSE otherwise.
                   If FALSE check the UltraErrorStr for the reason.

See also:  UltraRecordData, UltraPrimeRecord, UltraRecordHandler















___________________________________________________________________________
                                                                         45



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraGoVoice
_________________________________

Purpose:   To start a voice that has already been primed.

C:         void UltraGoVoice(voice,mode);
           int voice;
           unsigned char mode;

PASCAL:    PROCEDURE UltraGoVoice(Voice : INTEGER;
                                  VMode : BYTE);

Remarks:   This routine will start up a voice that has already been primed
           with set-up values by  UltraPrimeVoice.  This can  be useful if
           you  need  to  start  multiple  voices  as  close  together  as
           possible.  See Appendix C for the mode bit definitions.

See also:  UltraPrimeVoice, UltraStartVoice



UltraDisableLineIn
_________________________________

Purpose:   To disable line level input.

C:         void UltraDisableLineIn(void);

PASCAL:    PROCEDURE UltraDisableLineIn;

Remarks:   If line level input is enabled and output is enabled, the input
           is routed directly to the  output and audio will  be heard.  If
           this is not desired, use this to disable line in.

See also:  UltraEnableLineIn, UltraGetLineIn



UltraDisableMicIn
_________________________________

Purpose:   To disable microphone input.

C:         void UltraDisableMicIn(void);

PASCAL:    PROCEDURE UltraDisableMicIn;

Remarks:   If microphone input is enabled and output is enabled, the input
           is routed directly to the  output and audio will  be heard.  If
           this is not desired, use this to disable microphone in.

See also:  UltraEnableMicIn, UltraGetMicIn



___________________________________________________________________________
                                                                         46



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraDisableOutput
_________________________________

Purpose:   To turn off all output from the UltraSound.

C:         void UltraDisableOutput(void);

PASCAL:    PROCEDURE UltraDisableOutput;

Remarks:   This routine will disable all output from the UltraSound.  This
           can be  used during  recording so  that the  input will  not be
           looped back to the output.  It is also useful to disable output
           during resets  since  that will  help  eliminate  'pops' during
           initialization.

See also:  UltraEnableOutput, UltraGetOutput



UltraEnableLineIn
_________________________________

Purpose:   To enable line level input.

C:         void UltraEnableLineIn(void);

PASCAL:    PROCEDURE UltraEnableLineIn;

Remarks:   Turns on the line level  input.  If you  are not recording from
           the line  input,  it is  probably  not desirable  to  have this
           enabled since it will  be looped back to  the output (if output
           is enabled).

See also:  UltraDisableLineIn, UltraGetLineIn



UltraEnableMicIn
_________________________________

Purpose:   To turn on the microphone input.

C:         void UltraEnableMicIn(void);

PASCAL:    PROCEDURE UltraEnableMicIn;

Remarks:   This routine should be called when  you want to record from the
           microphone.  It is  possible to have both  the microphone input
           enabled and line level input enabled.  If you are not recording
           from the  microphone, it  is recommended  that it  be disabled,
           since it will reduce noise on the output.

See also:  UltraDisableMicIn, UltraGetMicIn


___________________________________________________________________________
                                                                         47



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraEnableOutput
_________________________________

Purpose:   To enable output from the UltraSound.

C:         void UltraEnableOutput(void);

PASCAL:    PROCEDURE UltraEnableOutput;

Remarks:   This routine  must  be called  to  enable any  output  from the
           UltraSound.  This can be used to turn on output after muting it
           with UltraDisableOutput.

See also:  UltraDisableOutput, UltraGetOutput



UltraGetLineIn
_________________________________

Purpose:   To return the current state of line level input

C:         int UltraGetLineIn(void);

PASCAL:    FUNCTION UltraGetLineIn : BOOLEAN;

Remarks:   This can be useful if you want to  change the state of the line
           level input and then restore it back to the original state.

Returns:   TRUE if LineIn is Enabled, FALSE otherwise.

See also:  UltraEnableLineIn, UltraDisableLineIn



UltraGetOutput
_________________________________

Purpose:   To return the current output enabled state.

C:         int UltraGetOutput(void);

PASCAL:    FUNCTION UltraGetOutput;

Remarks:   This can  be useful  if you  want to  change  the state  of the
           output and then restore it back to the original state.

Returns:   TRUE if Output is Enabled, FALSE otherwise.

See also:  UltraEnableOutput, UltraDisableOutput





___________________________________________________________________________
                                                                         48



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraGetMicIn
_________________________________

Purpose:   To return the current state of the microphone input.

C:         int UltraGetMicIn(void);

PASCAL:    FUNCTION UltraGetMicIn;

Remarks:   This can  be useful  if you  want to  change  the state  of the
           microphone input  and  then  restore it  back  to  the original
           state.

Returns:   TRUE if Output is Enabled, FALSE otherwise.

See also:  UltraEnableMicIn, UltraDisableMicIn







































___________________________________________________________________________
                                                                         49



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraDRAMTcHandler
_________________________________

Purpose:   To define a callback for a DMA transfer completion.

C:         PFV *(UltraDramTcHandler(handler));
           PFV *handler;

PASCAL:    PROCEDURE UltraDRAMTcHandler(VAR Handler : PFV);

Remarks:   This procedure defines a  callback for whenever  a DMA transfer
           to the  UltraSound has  been  completed.   The  routine address
           passed as a parameter is set as the new handler.  No parameters
           are passed to your new handler.

Returns:   For C  users,  this  routine returns  the  address  of  the old
           handler.

PASCAL
Example:   Since PASCAL cannot  return function  or procedure  type values
           from  functions,  the  equivalent  routine   was  made  into  a
           procedure which took  a single VAR  parameter.   Thus, when you
           are going to change the address  of a callback routine, you put
           the new address into a variable,  run it through the procedure,
           and what will then be in the variable is the address of the old
           handler:

           VAR
             OldProc : PFV;

           Procedure MyNewProc;
             { The new handler - defined as a normal procedure }
             begin
               ...
             end;

           ...
           { Set OldProc to address of new handler }
           OldProc := MyNewProc;
           { Now set the new handler and return the old one }
           UltraDRAMTcHandler(OldProc);
           ...

           At this point,  OldProc holds the  address of  the old routine.
           Therefore, to chain to  the old routine, you  would simply have
           to call OldProc from your handler.









___________________________________________________________________________
                                                                         50



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraMIDIXmitHandler
_________________________________

Purpose:   To define a callback for MIDI transmit interrupt.

C:         PFV *(UltraMIDIXmitHandler(handler));
           PFV *handler;

PASCAL:    PROCEDURE UltraMIDIXMitHandler(VAR Handler : WORD_PROC);

Remarks:   This procedure defines a callback for  whenever a MIDI transmit
           empty interrupt occurs.  This can be used to send out MIDI data
           under interrupt  control.    The routine  address  passed  as a
           parameter is set as the  new handler.  The  MIDI Status Byte is
           passed to the new handler defined.

Returns:   For C  users,  this  routine returns  the  address  of  the old
           handler.

PASCAL
Example:   See the example for UltraDRAMTcHandler.

See also:  UltraMIDIRecvHandler



UltraMIDIRecvHandler
_________________________________

Purpose:   To define a callback for a MIDI receive interrupt.

C:         PFV *(UltraMIDIRecvHandler(handler));
           PFV *handler;

PASCAL:    PROCEDURE UltraMIDIRecvHandler(VAR Handler : TWOWORD_PROC);

Remarks:   This procedure  defines  a  callback  for  whenever  a byte  is
           received in the MIDI input port.  This  can be used to get data
           from the MIDI port under interrupt contol.  The routine address
           passed as a parameter is set as the new handler.  The MIDI port
           status and MIDI  data are passed  to your handler.   The status
           bits are defined in Appendix D.

Returns:   For C  users,  this  routine returns  the  address  of  the old
           handler.

PASCAL
Example:   See the example for UltraDRAMTcHandler.

See also:  UltraMIDIXmitHandler





___________________________________________________________________________
                                                                         51



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraTimer1Handler
_________________________________

Purpose:   To define a callback from Timer #1.

C:         PFV *(UltraTimer1Handler(handler));
           PFV *handler;

PASCAL:    PROCEDURE UltraTimer1Handler(VAR Handler : PFV);

Remarks:   This procedure defines a callback for whenever the UltraSound's
           Timer 1 'Ticks'.  The routine  address passed as a parameter is
           set as  the new  handler.   No  parameters are  passed  to this
           handler.

Returns:   For C  users,  this  routine returns  the  address  of  the old
           handler.

PASCAL
Example:   See the example for UltraDRAMTcHandler.

See also:  UltraTimer2Handler, UltraStartTimer



UltraTimer2Handler
_________________________________

Purpose:   To define a callback for Timer #2.

C:         PFV *(UltraTimer2Handler(handler));
           PFV *handler;

PASCAL:    PROCEDURE UltraTimer2Handler(VAR Handler : PFV);

Remarks:   This procedure defines a callback for whenever the UltraSound's
           Timer 2 'Ticks'.  The routine  address passed as a parameter is
           set as  the new  handler.   No  parameters are  passed  to this
           handler.

Returns:   For C  users,  this  routine returns  the  address  of  the old
           handler.

PASCAL
Example:   See the example for UltraDRAMTcHandler.

See also:  UltraTimer1Handler, UltraStartTimer








___________________________________________________________________________
                                                                         52



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraWaveHandler
_________________________________

Purpose:   To define a callback for an end-of-wave interrupt.

C:         PFV *(UltraWaveHandler(handler));
           PFV *handler;

PASCAL:    PROCEDURE UltraWaveHandler(VAR Handler : INT_PROC);

Remarks:   This  procedure  defines  a  callback   for  whenever  a  voice
           generates a  wavetable interrupt.   This  happens when  a voice
           hits it's end and interrupts are  enabled.  It will happen even
           if looping is on (i.e.  the  voice keeps playing).  The routine
           address passed as a parameter is set as the new handler.
           Normally, This procedure  is used  to signify  that a  voice is
           done playing.  This handler can  be useful for starting another
           voice or counting the  # of times  that a voice  goes through a
           loop.  The voice # that  generated the interrupt is passed back
           to your handler.

Returns:   For C  users,  this  routine returns  the  address  of  the old
           handler.

PASCAL
Example:   See the example for UltraDRAMTcHandler.



UltraVolumeHandler
_________________________________

Purpose:   To define a callback for volume ramp complete interrupt.

C:         PFV *(UltraVolumeHandler(handler));
           PFV *handler;

PASCAL:    PROCEDURE UltraVolumeHandler(VAR Handler : INT_PROC);

Remarks:   This procedure defines  a callback  for whenever a  volume ramp
           ends.  The routine address passed as  a parameter is set as the
           new handler.   This routine  can be used  to generate  a volume
           envelope (attack, decay,  sustain, release).   This is  done by
           changing to  the appropriate  volume  ramps in  the  handler to
           handle the next part of the envelope.   The voice # causing the
           interrupt will be passed back to your handler.

Returns:   For C  users,  this  routine returns  the  address  of  the old
           handler.

PASCAL
Example:   See the example for UltraDRAMTcHandler.



___________________________________________________________________________
                                                                         53



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraRecordHandler
_________________________________

Purpose:   To define a callback for a DMA record complete interrupt.

C:         PFV *(UltraUltraRecordHandler(handler));
           PFV *handler;

PASCAL:    PROCEDURE UltraRecordHandler(VAR Handler : PFV);

Remarks:   This routine is  called when a  buffer that  was being recorded
           into is full.  The routine address passed as a parameter is set
           as the new handler.  Normally,  this procedure would be used to
           let  the  application  start  up  another  record.    A  double
           buffering scheme could be used to record data continuously.  No
           parameters are passed to this handler.
           As long  as the  DMA channels  for  recording and  playback are
           different,  the   UltraSound  is   capable   of  simultaneously
           recording and playback.   At  high data rates  your application
           may have a problem with throughput.

Returns:   For C  users,  this  routine returns  the  address  of  the old
           handler.

PASCAL
Example:   See the example for UltraDRAMTcHandler.



UltraAuxHandler
_________________________________

Purpose:   To define a callback for an auxiliary interrupt.

C:         PFV *(UltraUltraAuxHandler(handler));
           PFV *handler;

PASCAL:    PROCEDURE UltraAuxHandler(VAR Handler : PFV);

Remarks:   This handler will be  called at the end  of ALL interrupts that
           happen on the UltraSound.  Its  primary purpose is for use with
           the new UltraMax card since its shares its IRQ with the GF1.

Returns:   For C  users,  this  routine returns  the  address  of  the old
           handler.

PASCAL
Example:   See the example for UltraDRAMTcHandler.







___________________________________________________________________________
                                                                         54



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraMaxAlloc
_________________________________

Purpose:   To find the size of the largest allocatable block of UltraSound
           DRAM.

C:         unsigned long UltraMaxAlloc(void);

PASCAL:    FUNCTION UltraMaxAlloc : LONGINT;

Remarks:   This routine will return  the largest block of  DRAM (in bytes)
           that  can  still  be  allocated.     This  can  be  useful  for
           determining whether or  not a  patch or  sample can  be loaded.
           The maximum size of a block is 256K.

Returns:   # of bytes in largest available block.

See also:  UltraMemAlloc, UltraMemFree,
           for C users UltraMemInit
           and for PASCAL users UltraMemAvail and UltraMaxAvail




UltraMaxAvail
_________________________________

Purpose:   To find the size of the largest allocatable block of UltraSound
           DRAM.

C:         Use the UltraMaxAlloc function.

PASCAL:    FUNCTION UltraMaxAvail : LONGINT;

Remarks:   This routine will return  the largest block of  DRAM (in bytes)
           that  can  still  be  allocated.     This  can  be  useful  for
           determining whether or  not a  patch or  sample can  be loaded.
           The maximum size of a block is  256K.  This routine is included
           to provide consistency of naming for PASCAL Programmers.

Returns:   # of bytes in largest available block.

See also:  UltraMemAlloc, UltraMemFree,
           for C users UltraMemInit
           and for PASCAL users UltraMemAvail










___________________________________________________________________________
                                                                         55



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraMemAvail
_________________________________

Purpose:   To find the total amount of free UltraSound DRAM.

C:         This function is not available.

PASCAL:    FUNCTION UltraMemAvail : LONGINT;

Remarks:   For PASCAL users,  this will  return the  total amount  of DRAM
           still available for use on the UltraSound.

Returns:   # of bytes in left available.

See also:  UltraMemAlloc, UltraMemFree, UltraMaxAlloc
           for C users UltraMemInit
           and for PASCAL users UltraMaxAvail



UltraMemAlloc
_________________________________

Purpose:   To safely allocate a chunk of UltraSound DRAM.

C:         int UltraMemAlloc(size, location);
           unsigned long size;
           unsigned long *location;

PASCAL:    FUNCTION UltraMemAlloc(    Size     : LONGINT;
                                  VAR Location : LONGINT) : BOOLEAN;

Remarks:   This routine allocates a chunk of DRAM of 'Size' bytes from the
           UltraSound's DRAM.  The memory allocation structures are set up
           by UltraOpen.  'Location'  is filled in with  the DRAM location
           of the  start  of the  chunk  of memory.    The  memory address
           returned will ALWAYS be  aligned on a 32  byte boundary so that
           the DRAM can be DMA'ed into without error.  Also, the size will
           be rounded UP to the  next 32 byte boundary.   PASCAL users can
           reference section 1.8.3 for  a detailed look at  how the memory
           is managed.

Returns:   C:      ULTRA_OK if no problem.
                   NO_MEMORY if there is no chunk of DRAM large enough.

           PASCAL: TRUE if the allocation was successful.
                   If FALSE, check UltraErrorStr for the reason.

See also:  UltraMemFree, UltraMaxAlloc,
           for C users UltraMemInit
           and for PASCAL users UltraMaxAvail and UltraMemAvail




___________________________________________________________________________
                                                                         56



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraMemFree
_________________________________

Purpose:   To  free   a   chunk   of   DRAM   previously  allocated   with
           UltraMemAlloc.

C:         int UltraMemFree(size,location);
           unsigned long size;
           unsigned long location;

PASCAL:    FUNCTION  UltraMemFree(Size     : LONGINT;
                                  Location : LONGINT) : BOOLEAN;

Remarks:   Frees a previously allocated  chunk of UltraSound  memory.  The
           size will  automatically  be rounded  UP  to the  next  32 byte
           boundary.

Returns:   C:      ULTRA_OK if no problem.
                   CORRUPT_MEM if the memory structures are corrupted.

           PASCAL: TRUE if deallocation was successful.
                   If FALSE, check UltraErrorStr for the reason.

See also:  UltraMemInit, UltraMemAlloc
           for C users UltraMemInit
           and for PASCAL users UltraMaxAvail and UltraMemAvail



UltraMemInit
_________________________________

Purpose:   To initialize or re-initialize the memory pool structures.

C:         unsigned long UltraMemInit(void);

PASCAL:    This routine is not  used.  The unit  automatically calls these
           routines when your program starts.

Remarks:   This routine sets up the UltraSound  DRAM so that UltraMemAlloc
           and UltraMemFree will work.  It is called in UltraOpen.  It can
           be called at any time  if an application wants  to clean up all
           its allocated or corrupted memory structures.

Returns:   Number of K of DRAM found on the UltraSound.  If an application
           wishes to reserve a chunk of DRAM outside of the memory pool, a
           variable called _ultra_reserved_dram must be set  up with the #
           of bytes  to  reserve  BEFORE  UltraMemInit  is  called.   This
           reserved chunk will  start at  0.  The  reserved chunk  must be
           greater than 32 bytes and less than 256K in size.

See also:  UltraMemAlloc, UltraMemFree, and UltraMaxAlloc



___________________________________________________________________________
                                                                         57



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraMIDIDisableRecv
_________________________________

Purpose:   To disable the MIDI receive data interrupt.

C:         void UltraMIDIDisableRecv(void);

PASCAL:    PROCEDURE UltraMIDIDisableRecv;

Remarks:   This routine will disable the receive  data interrupts from the
           MIDI.   If  the interrupt  is  enabled, it  should  be disabled
           before leaving your application.

See also:  UltraMIDIEnableRecv, UltraMIDIRecvHandler



UltraDisableMIDIXmit
_________________________________

Purpose:   To disable MIDI transmit interrupts.

C:         void UltraDisableMIDIXmit(void);

PASCAL:    PROCEDURE UltraDisableMIDIXmit;

Remarks:   This routine will turn  off MIDI transmit interrupts.   It MUST
           be called when you are through sending data.

See also:  UltraMIDIXmitHandler, UltraMIDIEnableXmit



UltraMIDIEnableRecv
_________________________________

Purpose:   To enable receive data interrupts for MIDI port.

C:         void UltraMIDIEnableRecv(void);

PASCAL:    PROCEDURE UltraMIDIEnableRecv;

Remarks:   This routine will enable receive data  interrupts from the MIDI
           port.  It is  necessary to set  up a callback  routine for your
           application to process the data.

See also:  UltraMIDIRecvhandler, UltraMIDIDisableRecv








___________________________________________________________________________
                                                                         58



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraEnableMIDIXmit
_________________________________

Purpose:   To enable transmit interrupts from MIDI.

C:         void UltraEnableMIDIXmit(void);

PASCAL:    PROCEDURE UltraEnableMIDIXmit;

Remarks:   This  routine  will  enable  transmit  data  interrupts  to  be
           generated as each byte is transmitted  out the MIDI port.  Note
           that a transmit interrupt will be  generated as soon as the IRQ
           is enabled  unless  a byte  is  sent out  immediately  prior to
           enabling it.   This  is because  the  xmit buffer  is initially
           empty (unless primed) so  it will pop an  interrupt.  Also note
           that you MUST disable  this interrupt when you  are not sending
           any more  data or  else you  will be  hung up  getting transmit
           ready interrupts.

See also:  UltraMIDIXmitHandler, UltraMIDIDisableXmit



UltraMIDIRecv
_________________________________

Purpose:   To read a byte from the MIDI port.

C:         unsigned char UltraMIDIRecv(void);

PASCAL:    FUNCTION UltraMIDIRecv : BYTE;

Remarks:   This routine is  used to read  a byte from  the MIDI  port.  It
           assumes that the byte is waiting.  The  Byte is there if it got
           to the MIDI receive  interrupt callback routine or  if you have
           polled the status and determined the receive buffer is full.

Returns:   MIDI data byte

See also:  UltraMIDIRecvHandler, UltraMIDIStatus















___________________________________________________________________________
                                                                         59



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraMIDIReset
_________________________________

Purpose:   To reset the MIDI port.

C:         void UltraMIDIReset(void);

PASCAL:    PROCEDURE UltraMIDIReset;

Remarks:   This routine should  be used  to ensure that  the MIDI  port is
           ready to use.   All  MIDI interrupts will  be disabled  by this
           call.

See also:  UltraEnableMIDIXmit, UltraEnableMIDIRecv



UltraMIDIStatus
_________________________________

Purpose:   To read the MIDI status byte.

C:         unsigned char UltraMIDIStatus(void);

PASCAL:    FUNCTION UltraMIDIStatus : BYTE;

Remarks:   This routine returns the  current MIDI port status  bits.  This
           can be used  to determine if  an error  has occurred  or if the
           port is ready to be read or written.

Returns:   The MIDI status byte.  See chapter 2.

See also:  UltraMIDIXmit, UltraMIDIRecv




UltraMIDIXmit
_________________________________

Purpose:   To send a byte out the MIDI port.

C:         void UltraMIDIXmit(data);
           unsigned char data;

PASCAL:    PROCEDURE UltraMIDIXmit(Data : BYTE);

Remarks:   This routine will send the 'Data'  byte out the MIDI data port.
           If interrupts are enabled, an interrupt  will be generated when
           the Byte has been transmitted.

See also:  UltraMIDIXmitHandler



___________________________________________________________________________
                                                                         60



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraOpen
_________________________________

Purpose:   To open and initialize the UltraSound card and the SDK code.

C:         int UltraOpen(config,voices);
           ULTRA_CFG *config;
           int voices;

PASCAL:    FUNCTION  UltraOpen(VAR Config : Ultra_CFG;
                                   Voices : INTEGER) : BOOLEAN;

Remarks:   This  routine  should  ALWAYS  be   called  to  initialize  the
           UltraSound.  It will probe for the card and program the IRQ and
           DMA latches.   It will then  disable line  and microphone input
           and enable output.  It also  initializes the memory structures.
           The #  of  active  voices  is  an  important  parameter to  the
           UltraSound: the fewer  the #  of voices, the  more oversampling
           that occurs  on  playback.    This  will  make  the sound  much
           'cleaner'.  If you specify a number of voices less than 14, the
           card will still be initialized to  use 14 voices.  Likewise, if
           you select larger than 32 voices, you will still only have 32.

Returns:   C:      ULTRA_OK if no problem.
                   NO_ULTRA if no UltraSound card found.
                   BAD_NUM_OF_VOICES if # of active voices out of range

           PASCAL: TRUE if the card was successfully opened.
                   If FALSE, check UltraErrorStr for the reason.

See also:  UltraClose, UltraProbe
























___________________________________________________________________________
                                                                         61



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraPeekData
_________________________________

Purpose:   To examine any DRAM location on the UltraSound.

C:         unsigned char UltraPeekData(baseport,location);
           unsigned int baseport;
           unsigned long location;

PASCAL:    FUNCTION UltraPeekData(PPort   : INTEGER;
                                  Address : LONGINT) : BYTE;

Remarks:   This routine is  used to  allow an application  to look  at any
           location in UltraSound's DRAM.  This can be handy for obtaining
           VU information or any other time it is  nice to know what is in
           DRAM.  Be aware that if the data is playable it will be in twos
           compliment form.  If the data that you want is 16 bit data, you
           will need  to  peek  both  locations  and  do  any  appropriate
           conversions.  The data will be  in low/high format.  That means
           that the low byte of the data will be  in the even byte and the
           high byte will be in the odd byte.

Returns:   Data byte at location specified.

See also:  UltraPokeData, UltraUpload



UltraPing
_________________________________

Purpose:   To quickly  check  to see  if  an UltraSound  is  present  at a
           specified port.

C:         int UltraPing(baseport);
           int baseport;

PASCAL:    FUNCTION UltraPing(PPort : WORD) : BOOLEAN;

Remarks:   This routine  will determine  if  an UltraSound  is  present by
           attempting to read and write to its DRAM.  This routine assumes
           that at least  a simple reset  has been done  since power-up so
           that the board is  no longer in a  reset state.  If  it is on a
           reset state, this routine will ALWAYS fail.  UltraProbe pulls a
           quick reset and then calls UltraPing.

Returns:   C:      ULTRA_OK if no problem.
                   NO_ULTRA if no board is found at specified I/O port.

           PASCAL: TRUE if the card was found.   FALSE otherwise.
                   If unsuccessful, check UltraErrorStr for the reason.

See also:  UltraProbe


___________________________________________________________________________
                                                                         62



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraPokeData
_________________________________

Purpose:   To poke a byte into the UltraSound's DRAM.

C:         void UltraPokeData(baseport,location,data);
           unsigned int baseport;
           unsigned long location;
           unsigned char data;

PASCAL:    PROCEDURE UltraPokeData(PPort   : INTEGER;
                                   Address : LONGINT;
                                   Data    : BYTE);

Remarks:   Poke an 8 bit value directly into UltraSound DRAM.  This can be
           useful to  set  the  value of  the  location  that  a  voice is
           pointing to.  It is often desirable to point a voice to a known
           value since its output  is ALWAYS summed in  to the output even
           if the  voice  is not  running.    Be aware  that  there  is no
           automatic conversion  of  data  poked  into  DRAM.   Since  the
           UltraSound can only play  twos compliment data,  make sure that
           the data you  are poking is  in that  format.   Also be careful
           with 16 bit data.

See also:  UltraPeekData, UltraDownload






























___________________________________________________________________________
                                                                         63



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraPrimeRecord
_________________________________

Purpose:   To prime the record DMA channel for use.

C:         int UltraPrimeRecord(pc_ptr,size,repeat);
           void far *pc_ptr;
           unsigned int size;
           int repeat;

PASCAL:    FUNCTION UltraPrimeRecord(PC_Ptr  : POINTER;
                                     Size    : WORD;
                                     RRepeat : BOOLEAN) : BOOLEAN;

Remarks:   This routine will  setup the  DMA channel to  do a  record, but
           does not  start  it.   This  can be  used  to  help synchronize
           events.  Programming  the DMA channel  can take  enough time so
           that a few  samples may be  lost.  (Depending  on sample rate).
           This routine  will help  alleviate  this problem  by  doing the
           programming ahead of time.

Returns:   C:      ULTRA_OK if no problem.
                   DMA_BUSY if DMA Channel is busy.

           PASCAL: TRUE if setup was successful.   FALSE otherwise.
                   If unsuccessful, check UltraErrorStr for the reason.

See also:  UltraGoRecord



























___________________________________________________________________________
                                                                         64



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraPrimeVoice
_________________________________

Purpose:   To prime a voice with values but NOT start it.

C:         unsigned char UltraPrimeVoice(voice,begin,start,end,mode);
           int voice;
           unsigned long begin;
           unsigned long start;
           unsigned long end;
           unsigned char mode;

PASCAL:    FUNCTION UltraPrimeVoice(Voice    : INTEGER;
                                    VBegin   : LONGINT;
                                    VStart   : LONGINT;
                                    VEnd     : LONGINT;
                                    VMode    : BYTE) : BYTE;

Remarks:   This routine is used to  do all the setup  necessary to start a
           voice but does NOT start it up.  This can be useful if you want
           to  start  more   than  1  voice   at  the  same   time.    Use
           UltraPrimeVoice to  do all  the  necessary setup  and  then use
           UltraGoVoice  to  start  the  voices.    UltraStartVoice  calls
           UltraPrimeVoice and then immediately UltraGoVoice.

Returns:   An updated mode value.   The mode may be  modified on the basis
           of the location parameters.   This altered value  should be the
           one passed to UltraGoVoice.

See also:  UltraStartVoice, UltraGoVoice

























___________________________________________________________________________
                                                                         65



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraProbe
_________________________________

Purpose:   To probe  for the  existence of  an  UltraSound at  a specified
           port.

C:         int UltraProbe(base_port);
           unsigned int base_port;

PASCAL:    FUNCTION UltraProbe(PPort : WORD) : BOOLEAN;

Remarks:   This routine probes for the existence  of an UltraSound card at
           the specified base port.  An application could call this before
           calling UltraOpen to see if a card is present.  UltraOpen calls
           this routine  also.    The  difference  between UltraProbe  and
           UltraPing is that UltraProbe will pull a reset to make sure the
           board is  running.   UltraPing  assumes this  has  already been
           done.

Returns:   C:      ULTRA_OK if no problem.
                   NO_ULTRA if no card was found at the port specified.

           PASCAL: TRUE if the card is found.   FALSE otherwise.
                   If unsuccessful, check UltraErrorStr for the reason.

See also:  UltraOpen, UltraPing





























___________________________________________________________________________
                                                                         66



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraRampVolume
_________________________________

Purpose:   To ramp a voice's volume up or down.

C:         void UltraRampVolume(voice,start,end,rate,mode);
           int voice;
           unsigned int start;
           unsigned int end;
           unsigned char rate;
           unsigned char mode;

PASCAL:    PROCEDURE UltraRampVolume(Voice  : INTEGER;
                                     StartV : WORD;
                                     EndV   : WORD;
                                     VRate  : BYTE;
                                     VMode  : BYTE);

Remarks:   Start a  volume  ramp  from a  starting  volume  to  the ending
           volume.  The  rate at which  the ramp occurs  can be calculated
           using UltraCalcRate.    The  mode  determines  the looping  and
           interrupting characteristics  of the  ramp.   If you  choose to
           have it interrupt at the end of the  ramp, you should set up an
           routine to call for a volume interrupt.   This is done with the
           routine UltraVolumeHandler.   The volume mode  bits are defined
           in Appendix B.

See also:  UltraCalcRate, UltraVolumeHandler



UltraReadRecordPosition
_________________________________

Purpose:   To return the # of bytes recorded so far in a record.

C:         unsigned int UltraReadRecordPosition(void);

PASCAL:    FUNCTION UltraReadRecordPosition : WORD;

Remarks:   This routine can be used to monitor the amount data recorded.

Returns:   Number of BYTES recorded so far.

See also:  UltraRecordData










___________________________________________________________________________
                                                                         67



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraReadVoice
_________________________________

Purpose:   To read a voice's current location.

C:         unsigned long UltraReadVoice(voice);
           int voice;

PASCAL:    FUNCTION UltraReadVoice(Voice : INTEGER) : LONGINT;

Remarks:   This routine can be used to monitor a voice's progress.

Returns:   The voice's current position in DRAM.

See also:  UltraSetVoice



UltraReadVolume
_________________________________

Purpose:   To read a voice's current volume.

C:         unsigned int UltraReadVolume(voice);
           int voice;

PASCAL:    FUNCTION UltraReadVolume(Voice : INTEGER) : WORD;

Remarks:   This routine returns the  current volume of a  voice.  This can
           be useful  when used  in conjunction  with  volume ramps.   The
           value returned is  logarithmic, not  linear.  PASCAL  users can
           use UltraReadLinearVolume.

Returns:   0-4095 value, the current logarithmic volume.

See also:  UltraSetVolume, UltraRampVolume



















___________________________________________________________________________
                                                                         68



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraRecordData
_________________________________

Purpose:   To record some  data with the  UltraSound from  the active 'In'
           ports.

C:         int UltraRecordData(pc_ptr,control,size,wait,repeat);
           void far *pc_ptr;
           unsigned char control;
           unsigned int size;
           int wait;
           int repeat;

PASCAL:    FUNCTION UltraRecordData(PC_Ptr  : POINTER;
                                    Control : BYTE;
                                    Size    : WORD;
                                    Wait    : BOOLEAN;
                                    RRepeat : BOOLEAN) : BOOLEAN;

Remarks:   This routine will record a buffer  of data from UltraSound.  It
           can be in either  8-bit mono or  stereo.  In  stereo, there are
           two bytes and the left byte  is first.  If  mono is being used,
           the left channel is  the one that  is sampled.   See Appendix E
           for the a description of the recording control bits.  If 'wait'
           is set to a  non-zero value, then this  routine will not return
           until the buffer  has been filled.   If 'repeat'  is TRUE, then
           the DMA channel will  be set up  in auto-init mode  so that the
           recording is  done indefinitely.   If  this  is done,  then the
           buffer MUST reside completely in  1 64K page of  PC RAM.  Also,
           it is  probably necessary  that your  application hooks  to the
           record handler so that  the control register  on the UltraSound
           can be hit  to restart  the recording  process (UltraGoRecord).
           This will be very quick since the PC DMA controller will not be
           re-programmed.

Returns:   C:      ULTRA_OK if no problem.
                   DMA_BUSY if sampling DMA Channel is busy.
                   BAD_DMA_ADDR if autoinit buffer crosses 64k page.

           PASCAL: TRUE if successful.   FALSE otherwise.
                   If unsuccessful, check UltraErrorStr for the reason.

See also:  UltraWaitRecordDMA, UltraSetRecordFrequency
           UltraGoRecord











___________________________________________________________________________
                                                                         69



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraRecordDMABusy
_________________________________

Purpose:   To see if the record DMA channel is busy.

C:         int UltraRecordDMABusy(void);

PASCAL:    FUNCTION UltraRecordDMABusy : BOOLEAN;

Remarks:   This routine checks to  see if the record  DMA channel is busy.
           It might be busy  doing a record  (or playback if  the record &
           playback channels are the same).

Returns:   C:      0 = Channel not Busy
                   2 = Channel Busy

           PASCAL: TRUE if the channel is not available. FALSE if it is.

See also:  UltraRecordData



UltraReset
_________________________________

Purpose:   To reset the UltraSound.

C:         int UltraReset(voices);
           int voices;

PASCAL:    FUNCTION UltraReset(Voices : INTEGER) : BOOLEAN;

Remarks:   This routine is called by UltraOpen to make sure the card is in
           a known state.  UltraClose also calls this routine.

Returns:   C:      ULTRA_OK if no problem.
                   BAD_NUM_OF_VOICES if # of voices not in range.

           PASCAL: TRUE if card is successfully reset.
                   If FALSE, check UltraErrorStr for the reason.

See also:  UltraOpen, UltraClose













___________________________________________________________________________
                                                                         70



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraSetBalance
_________________________________

Purpose:   To set a voice's pan position.

C:         void UltraSetBalance(voice,data);
           int voice;
           int data;

PASCAL:    PROCEDURE UltraSetBalance(Voice : INTEGER;
                                     Data  : BYTE);

Remarks:   This routine sets the  voice's position between  right and left
           speakers.  A  0 will place  the audio all  the way  to the left
           whereas a  15 will  put the  sound all  the  way to  the right.
           Values that  are out  of range  will  move the  balance  to the
           nearest extreme.



UltraSetFrequency
_________________________________

Purpose:   To set a voice's playback frequency.

C:         void UltraSetFrequency(voice,speed_hz);
           int voice;
           unsigned long speed_hz;

PASCAL:    PROCEDURE UltraSetFrequency(Voice     : INTEGER;
                                       Speed_Khz : LONGINT);

Remarks:   This routine sets  the voice's  playback rate to  the specified
           absolute frequency.  The number of  active voices is taken into
           account when making the appropriate calculations.



UltraSetLoopMode
_________________________________

Purpose:   To set a voice's loop mode.

C:         void UltraSetLoopMode(voice,mode);
           int voice;
           unsigned char mode;

PASCAL:    PROCEDURE UltraSetLoopMode(Voice : INTEGER;
                                      VMode : BYTE);

Remarks:   This  routine  will  set  this  voice's  looping  mode  to  the
           specified mode.   See Appendix  C for  the definition  of these
           bits.


___________________________________________________________________________
                                                                         71



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraSetRecordFrequency
_________________________________

Purpose:   To set the recording rate.

C:         void UltraSetRecordFrequency(rate);
           unsigned long rate;

PASCAL:    PROCEDURE UltraSetRecordFrequency(Rate : LONGINT);

Remarks:   This routine sets the  record rate to  the specified frequency.
           Since the UltraSound uses the PC DMA channel to do the sampling
           directly into PC RAM, no voice specification is necessary.



UltraSetVoice
_________________________________

Purpose:   To set a voice to an absolute position in DRAM.

C:         void UltraSetVoice(voice,location);
           int voice;
           unsigned long location;

PASCAL:    PROCEDURE UltraSetVoice(Voice    : INTEGER;
                                   Location : LONGINT);

Remarks:   This routine  sets a  voice's current  position to  an absolute
           location.  This can be useful to set a voice to a location with
           a known value since all voices' current locations are summed in
           to the output even if the voice is  not running.  'Pops' in the
           audio may result if a voice is  set to a location that contains
           a significant value.


UltraSetVoiceEnd
_________________________________

Purpose:   To set a voice's end position.

C:         void UltraSetVoiceEnd(voice,end);
           int voice;
           unsigned long end;

PASCAL:    PROCEDURE UltraSetVoiceEnd(Voice    : INTEGER;
                                      VEnd     : LONGINT);

Remarks:   This routine sets a new endpoint for the specified voice.  Used
           in conjunction  with UltraSetLoopMode  to turn  looping  off, a
           sampled decay can be implemented.

See also:  UltraSetLoopMode


___________________________________________________________________________
                                                                         72



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraSetVolume
_________________________________

Purpose:   To set a voice's current logarithmic volume.

C:         void UltraSetVolume(voice,volume);
           int voice;
           unsigned int volume;

PASCAL:    PROCEDURE UltraSetVolume(Voice  : INTEGER;
                                    Volume : WORD);

Remarks:   This routine  sets  the  volume  of  the  voice  to a  specific
           logarithmic value.    The  range  is  from  0  to  4095.    Use
           UltraSetLinearVolume to do linear volumes.

See also:  UltraSetLinearVolume



UltraSizeDRAM
_________________________________

Purpose:   To Find the amount of DRAM available on the UltraSound.

C:         int UltraSizeDram(void);

PASCAL:    FUNCTION UltraSizeDRAM : INTEGER;
           Note:  This routine will always return the same value, which is
           the amount of DRAM  that has been  installed on the  card.  Use
           UltraMemAvail to see how much DRAM is still free.

Remarks:   For C users,  this routine could  be used by  an application to
           determine  how   much  it   can  load   into   the  UltraSound.
           UltraMemInit calls this to  determine how much can  be used for
           its memory pool.

Returns:   # of kilobytes found on the UltraSound.

See also:  UltraMemInit















___________________________________________________________________________
                                                                         73



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraStartTimer
_________________________________

Purpose:   To set up and start either Timer 1 or Timer 2.

C:         void UltraStartTimer(timer,duration);
           int timer;
           unsigned char duration;

PASCAL:    PROCEDURE UltraStartTimer(Timer    : INTEGER;
                                     Duration : BYTE);

Remarks:   This routine  can be  used to  start  up one  of  two available
           hardware timers.    Timer  #1 is  an  80  microsecond (.00008s)
           timer.  Timer  #2 is a  320 microsecond (.00032s)  timer.  When
           starting either timer,  you supply the  # of  counts before the
           timer 'ticks'.   When the  timer 'ticks',  it ALWAYS  calls the
           callback routine defined  for it.   If you don't  supply one, a
           default is used.
           These timers can be  used to trigger various  real time events.
           They are  used  extensively  in  music  compostition  programs.
           Please remember that  the callback  routine is  called directly
           from the interrupt handler, so you  must be careful what you do
           in the callback routine.
           Note that the specified timer  is automatically restarted after
           it ticks.  Your application must explicitly call UltraStopTimer
           to shut it off.

See also:  UltraStopTimer, UltraTimerStopped
           UltraTimer1Handler, UltraTimer2Handler.

Example:   Giving Timer 1  a duration  of 10 counts  would make  the timer
           tick every  800 microseconds  (.0008s).   This would  mean your
           callback routine is called 1250 times a second.





















___________________________________________________________________________
                                                                         74



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraStartVoice
_________________________________

Purpose:   To set up and start a voice playing.

C:         void UltraStartVoice(voice,begin,start,end,mode);
           int voice;
           unsigned long begin;
           unsigned long start;
           unsigned long end;
           unsigned char mode;

PASCAL:    PROCEDURE UltraStartVoice(Voice  : INTEGER;
                                     VBegin : LONGINT;
                                     VStart : LONGINT;
                                     VEnd   : LONGINT;
                                     VMode  : BYTE);

Remarks:   This routine will set up and start up  a voice.  The voice will
           begin playback  at  the  'begin' and  continue  to  'end'.   If
           looping is enabled  for this voice,  then it will  then jump to
           'start' and then continue  to 'end'.  The  method of looping is
           determined by 'mode'.   See  Appendix C  for the  definition of
           these bits.

See also:  UltraSetVoiceEnd, UltraSetLoopMode



UltraStopTimer
_________________________________

Purpose:   To stop a timer which has been previously activated.

C:         void UltraStopTimer(timer);
           int timer;

PASCAL:    PROCEDURE UltraStopTimer(Timer : INTEGER);

Remarks:   If you  have started  a  timer with  UltraStartTimer,  you will
           probably  want  to  shut  it  off  before  shutting  down  your
           application.  If you forget,  UltraClose automatically shuts it
           down.

See also:  UltraStartTimer










___________________________________________________________________________
                                                                         75



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraStopVoice
_________________________________

Purpose:   To stop a voice which is playing.

C:         void UltraStopVoice(voice);
           int voice;

PASCAL:    PROCEDURE UltraStopVoice(Voice : INTEGER);

Remarks:   This routine will stop a voice which is playing at it's current
           position.  Don't forget that  if a voice is  left at an unknown
           position, the  data  that is  at  that position  will  still be
           summed into the final output.

See also:  UltraStartVoice, UltraSetVoiceEnd



UltraStopVolume
_________________________________

Purpose:   To stop a currently active volume ramp.

C:         void UltraStopVolume(voice);
           int voice;

PASCAL:    PROCEDURE UltraStopVolume(Voice : INTEGER);

Remarks:   You can use  this routine if  you wish  to stop  an volume ramp
           after a specified period of time, or you wish to make sure that
           a volume ramp has stopped.

See also:  UltraRampVolume, UltraRampLinearVolume



UltraTimerStopped
_________________________________

Purpose:   To check to see if a timer is running.

C:         int UltraTimerStopped(timer);
           int timer;

PASCAL:    FUNCTION UltraTimerStopped(Timer : INTEGER) : BOOLEAN;

Remarks:   This routine can be used  to see if a  timer is currently being
           used.

Returns:   FALSE if still running, TRUE if stopped.

See also:  UltraStartTimer, UltraStopTimer


___________________________________________________________________________
                                                                         76



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraTrimJoystick
_________________________________

Purpose:   To set the trim voltage on the joystick port.

C:         void UltraTrimJoystick(value);
           unsigned char value;

PASCAL:    PROCEDURE UltraTrimJoystick(JoyVal : BYTE);

Remarks:   This routine is used to set the speed compensation value on the
           joystick port on the UltraSound.   The faster the computer, the
           smaller this value  should be.   This allows  all software that
           reads the  joystick  to  return  consistent  joystick positions
           regardless of the speed  of the machine.   This is normally not
           needed and probably should  never be used  in your application.
           The utility ULTRAJOY.EXE which is  included with all UltraSound
           stock software is used to set this value.


UltraUpload
_________________________________

Purpose:   To transfer the contents of a block of DRAM to PC RAM.

C:         int UltraUpload(dataptr,control,dram_loc,len,wait);
           void *dataptr;
           unsigned char control;
           unsigned long dram_loc;
           unsigned int len;
           int wait;

PASCAL:    FUNCTION UltraUpload(DataPtr  : POINTER;
                                Control  : BYTE;
                                DRAM_Loc : LONGINT;
                                Len      : WORD;
                                Wait     : BOOLEAN) : BOOLEAN;

Remarks:   This  routine  will   retrieve  a   chunk  of  data   from  the
           UltraSound's DRAM.    It  will transfer  'len'  #  of  bytes to
           DataPtr (in PC)  from DRAM_loc (in  UltraSound).   If 'Wait' is
           TRUE, then it  will wait  until the transfer  is complete.   If
           'Wait' is FALSE, it will return as soon as transfer is started.
           See Appendix  D for  a definition  of the  control bits.   They
           specify the type of data being retrieved.

Returns:   C:      ULTRA_OK if no problem.
                   DMA_BUSY if DMA Channel is busy.

           PASCAL: TRUE if transfer was successful.   FALSE otherwise.
                   If unsuccessful, check UltraErrorStr for the reason.

See also:  UltraDownload, UltraDRAMDMAWait


___________________________________________________________________________
                                                                         77



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraVectorVolume
_________________________________

Purpose:   To ramp a volume from it's current position to a new value.

C:         void UltraVectorVolume(voice,end_idx,rate,mode);
           int voice;
           unsigned int end;
           unsigned char rate;
           unsigned char mode;

PASCAL:    PROCEDURE UltraVectorVolume(Voice : INTEGER;
                                       VEnd  : WORD;
                                       VRate : BYTE;
                                       VMode : BYTE);

Remarks:   This routine can be  used to ramp from  an unknown volume value
           to a new value.  It is useful if you are doing volume envelopes
           and need to restart the attack/decay sequence at any time.

See also:  UltraRampVolume, UltraStopVolume



UltraVersion
_________________________________

Purpose:   To return the version of the SDK code being used.

C:         void UltraVersion(major,minor);
           int *major;
           int *minor;

PASCAL:    PROCEDURE UltraVersion(VAR Major : BYTE;
                                  VAR Minor : BYTE);

Remarks:   This routine can be useful to track the version of the SDK that
           was used in compiling your source code.

Returns:   Major (1 digit) and minor (2 digits) version of the unit.

See also:  UltraVersionStr













___________________________________________________________________________
                                                                         78



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraVersionStr
_________________________________

Purpose:   To return the version of the SDK code being used in a string.

C:         This function is not available.

PASCAL:    FUNCTION UltraVersionStr : String;

Remarks:   This routine can be useful to track the version of the SDK that
           was used in compiling your source code.

Returns:   Major and minor version of the unit, in string format.

See also:  UltraVersion



UltraVoiceStopped
_________________________________

Purpose:   To return whether a voice is playing.

C:         int UltraVoiceStopped(voice);
           int voice;

PASCAL:    FUNCTION UltraVoiceStopped(Voice : INTEGER) : BOOLEAN;

Remarks:   This routine  can  be used  to  see if  a  sample  has finished
           playing .

Returns:   TRUE if the voice is stopped, FALSE otherwise.



UltraVolumeStopped
_________________________________

Purpose:   To determine  if  a volume  ramp  is running  for  a particular
           voice.

C:         int UltraVolumeStopped(voice);
           int voice;

PASCAL:    FUNCTION UltraVolumeStopped(Voice : INTEGER) : BOOLEAN;

Remarks:   This routine  is used  to determine  the  current state  of the
           volume of the voice.  It can be used to see if a volume ramp is
           still running.

Returns:   TRUE if no volume ramp is running, FALSE otherwise.

See also:  UltraRampVolume, UltraRampLinearVolume


___________________________________________________________________________
                                                                         79



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraWaitDRAMDMA
_________________________________

Purpose:   To wait for a DRAM DMA transfer to complete.

C:         void UltraWaitDramDMA(void);

PASCAL:    PROCEDURE UltraWaitDRAMDMA;

Remarks:   If a DMA transfer to/from DRAM is  started but told not to wait
           for it to complete, this  routine can be used  to wait until it
           has completed.

See also:  UltraDownload, UltraUpload



UltraWaitRecordDMA
_________________________________

Purpose:   To wait for a recording DMA transfer to complete.

C:         void UltraWaitRecordDMA(void);

PASCAL:    PROCEDURE UltraWaitRecordDMA;

Remarks:   This can be  used to let  an application wait  until a complete
           sample is finished being acquired.

See also:  UltraRecordData

























___________________________________________________________________________
                                                                         80



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraAllocVoice
_________________________________

Purpose:   To allocate a new voice not currently being used.

C:         int UltraAllocVoice(voice_num,new_num);
           int voice_num;
           int *new_num;

PASCAL:    FUNCTION UltraAllocVoice(VAR Voice_Num : INTEGER) : BOOLEAN;

Remarks:   This routine will return  a voice for your  application to use.
           If you supply a voice number,  it will attempt to allocate that
           particular voice. If  you pass  a -1 for  the voice  number, it
           will return  the  next  free  voice.  This  routine  will  only
           allocate voices up to  the # of active  voices specified in the
           UltraOpen function.

Returns:   C: ULTRA_OK             Got a voice ok
              VOICE_NOT_FREE       Can't get the voice or none left.
              VOICE_OUT_OF_RANGE   Specified voice out of range.

           PASCAL: TRUE if there was no problem allocating the voice.
                   If FALSE, check UltraErrorStr for the reason.

See also:  UltraClearVoices, UltraFreeVoices



UltraClearVoices
_________________________________

Purpose:   To reset all voices to an un-allocated state.

C:         void UltraClearVoices(void);

PASCAL:    PROCEDURE UltraClearVoices;

Remarks:   This routine will  deallocate all  previously allocated voices.
           It  would  be  advisable  to  call  this  before  using  either
           UltraAllocVoice or UltraFreeVoice.

See also:  UltraAllocVoice, UltraFreeVoice.












___________________________________________________________________________
                                                                         81



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraFreeVoice
_________________________________

Purpose:   To free up an allocated voice.

C:         void UltraFreeVoice(voice_num);
           int voice_num;

PASCAL:    PROCEDURE UltraFreeVoice(Voice_Num : INTEGER);

Remarks:   This routine will  free up  a previously allocated  voice. This
           should be used when your application  no longer needs the voice
           so it can be re-allocated at another time.

See also:  UltraClearVoices, UltraAllocVoice.



UltraVoiceOff
_________________________________

Purpose:   To allow flexibility in stopping a voice.

C:         void UltraVoiceOff(voice,end);
           int voice;
           int end;

PASCAL:    PROCEDURE UltraVoiceOff(Voice : INTEGER;
                                   VEnd  : BOOLEAN);

Remarks:   This routine will  either stop  a voice  immediately or  let it
           finish its current loop.  If 'VEnd'  is FALSE then it will stop
           abruptly,  otherwise   it   will  finish   the   current  loop.
           UltraReadVoice could be called  afterwards if you  need to know
           where the loop finished.
           If used with  UltraSetVoiceEnd, you  could implement  a sampled
           decay on the end of your sample.  This would occur if your loop
           point was not at the end of your  data, and you changed the end
           point to the real end  point of your data  and then called this
           routine with VEnd set to TRUE.

See also:  UltraReadVoice, UltraSetVoiceEnd













___________________________________________________________________________
                                                                         82



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraVoiceOn
_________________________________

Purpose:   To turn a voice on at a given frequency.

C:         void UltraVoiceOn(voice,begin,s_loop,e_loop,control,freq);
           int voice;
           unsigned long begin;
           unsigned long s_loop;
           unsigned long e_loop;
           unsigned char control;
           unsigned long freq;

PASCAL:    PROCEDURE UltraVoiceOn(Voice      : INTEGER;
                                  VBegin     : LONGINT;
                                  Start_Loop : LONGINT;
                                  End_Loop   : LONGINT;
                                  Control    : BYTE;
                                  Freq       : LONGINT);

Remarks:   This routine just sets the frequency with UltraSetFrequency and
           then calls UltraStartVoice.

See also:  UltraSetFrequency, UltraStartVoice



UltraSetLinearVolume
_________________________________

Purpose:   To set a voice's volume to a linearized value.

C:         void UltraSetLinearVolume(voice,index);
           int voice;
           int index;

PASCAL:    PROCEDURE UltraSetLinearVolume(Voice : INTEGER;
                                          Index : INTEGER);

Remarks:   This routine indexes into a table  to translate a linear volume
           (0-511)  to  a   logarithmic  one  (0-4095),   and  then  calls
           UltraSetVolume.

See also:  UltraSetVolume











___________________________________________________________________________
                                                                         83



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraReadLinearVolume
_________________________________

Purpose:   To read a voice's volume as a linear value.

C:         This function is not available.

PASCAL:    FUNCTION UltraReadLinearVolume(Voice : INTEGER) : INTEGER;

Remarks:   This routine  indexes  into  a  table  to  translate  a  0-4095
           logarithmic volume to a 0-511 linear volume.

Returns:   Linear Volume Value (0-511).

See also:  UltraSetVolume, UltraSetLinearVolume



UltraRampLinearVolume
_________________________________

Purpose:   To ramp a voice's volume between linear volume values.

C:         void UltraRampLinearVolume(voice,start,end,msecs,mode);
           int voice;
           unsigned int start;
           unsigned int end;
           unsigned long msecs;
           unsigned char mode;

PASCAL:    PROCEDURE UltraRampLinearVolume(Voice     : INTEGER;
                                           Start_Idx : WORD;
                                           End_Idx   : WORD;
                                           Msecs     : LONGINT;
                                           VMode     : BYTE);

Remarks:   This routine is  used to  ramp between linear  volume settings.
           It uses the  same method  as UltraSetLinearVolume  to determine
           the  actual   volume   settings   to   use,   and  then   calls
           UltraRampVolume.

See also:  UltraRampVolume, UltraSetLinearVolume













___________________________________________________________________________
                                                                         84



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraVectorLinearVolume
_________________________________

Purpose:   To ramp a linear  volume from it's current  position to a known
           end point.

C:         void UltraVectorLinearVolume(voice,end,rate,mode)
           int voice;
           unsigned int end;
           unsigned char rate;
           unsigned char mode;

PASCAL:    PROCEDURE UltraVectorLinearVolume(Voice   : INTEGER;
                                             End_Idx : WORD;
                                             VRate   : BYTE;
                                             VMode   : BYTE);

Remarks:   This routine can be  used to ramp  from an unknown  volume to a
           new linear  volume.   It  is  useful if  you  are  doing volume
           envelopes and need to restart the  attack/decay sequence at any
           time.  It can also  produce a smoother ramp  from one volume to
           another, since arbitrarily  setting a  volume that is  far away
           from the current volume can cause 'pops'.

See also:  UltraSetLinearVolume, UltraReadLinearVolume






























___________________________________________________________________________
                                                                         85



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

                     Chapter 5 - Focal Point 3D Sound

5.0 Introduction

Three dimensional audio on the UltraSound is achieved by a technique called
binaural representation.    Basically, this  means  that a  mono  sound  is
'shaped' in such a way that when it is presented to the right and left ears
properly, the sound seems  to come from  the proper place  in space.   This
technique is  also  called  convolution.   This  is  done  thru  algorithms
developed by Focal Point(tm) 3D Audio.  Focal Point has provided a  utility
(called FP3D.EXE) to  convert a mono  sound file to  a 3D  file capable  of
being played on an UltraSound.  The basic concept is that the mono sound is
processed in such  a way  that the file  that is  output contains  up to  6
tracks of sound.  When the sound  is played back, the volumes and  balances
are adjusted to make the sound appear to originate from anywhere in the  3D
space.  It  is possible to  create files that  only have 4  tracks and  can
therefore only be  positioned in 2  dimensions.  This  may be adequate  for
many applications and it will make the resultant file smaller.

There are 2 types of 3D sound that an  application might want to use.   The
first is a sound  effect.  This is  a sound that  can be completely  loaded
into DRAM and played  and positioned at any  time.  It  is used for  things
like gunshots, cars etc.   These can  be looped or  non-looped.  The  other
type of sound is a sound track.  This is for a very long sound that  cannot
be loaded in DRAM all at once.  The implementation of each of these methods
is very different.   A  sound effect is  implemented using  a blocked  data
format.  This means  that each track's data  is in a block  of its own.   A
sound track uses interleaved data.  This means that all the track's data is
interleaved together.  For example, a blocked file would look like this:

HEADER FFFFFRRRRRBBBBBLLLLLUUUUUDDDDD....

whereas an interleaved file would look like this:

HEADER FRBLUDFRBLUDFRBLUDFRBLUDFRBLUD...

where

F = Front Track     L = Left Track
R = Right Track   U = Up Track
B = Behind Track   D = Down Track

Both of these methods have  their individual advantages and  disadvantages.
First, the interleaved method makes it very easy  to read in the data in  a
continuous stream since it will look the same all the way through the file.
It is also faster to read 60K of data once  rather than 6 10K reads.   This
makes it very useful for a sound track.   However, one drawback is that  it
has a very limited number of frequencies that  it will run at.  The  reason
for this is  rather difficult to  explain, but it  pertains to getting  the
UltraSound's voices to play every 4th (or 5th, etc) sample.  The UltraSound
normally would interpolate between  data points but it  can't do that  here
because the adjacent data points are not in the same track.



___________________________________________________________________________
                                                                         86



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

If you want to run at 22050 Hz, then you need to have only 28 active voices
to accomplish this.  If you want to play a track at 44100 Hz, you must have
only 14 active voices.  Blocked data doesn't have this problem.  Since  the
data is NOT interleaved, but in  a block of contiguous DRAM, its  frequency
can be  adjusted to  any value.   This  is usually  very useful  for  sound
effects (rev'ing  engines etc).   Also,  since the  data is  blocked,  each
track's data can be allocated separately  and can therefore be up to  256K.
An interleaved file must fit  into 1 256K bank  since we cannot play  16bit
data across a 256K bank.  See the two example 3D programs provided  (PLAY3D
and PLAY3DI) for ideas on how to implement 3D sound into you applications.


5.1  Creating 3D file

Please read the readme.3D file for information on creating a 3D file.


5.2  3D Sound Routines

UltraAbsPosition
_________________________________

Purpose:   To place a sound using integer Cartesian coordinates.

C:         void UltraAbsPosition3D(sound,xpos,ypos,zpos);
           SOUND_3D *sound;
           int xpos;
           int ypos;
           int zpos;

PASCAL:    PROCEDURE UltraAbsPosition3D(VAR Sound : SOUND_3D;
                                            XPos  : INTEGER;
                                            YPos  : INTEGER;
                                            ZPos  : INTEGER);

Remarks:   This routine  will position  a sound  using  standard cartesian
           coordinates. The X position  range is from -511  (left) to +511
           (right). The Y position  is from -511 (below)  to +511 (above).
           The Z position is from -511 (behind) to +511 (ahead). The X and
           Z positions determine the azimuth position and Y determines the
           elevation. The distance  away from  the listener  is determined
           using    trigonometry.     Once    these     are    determined,
           UltraAngPosition3D is called.

           If the distance  is calculated  to be greater  than 511,  it is
           clipped to 511. Also, if the distance is calculated to be 0, no
           positioning is  done since  the  origin is  undefined.  (i.e. A
           sound cannot be generated INSIDE your head (origin)).

           C users should  be careful when  using this  routine, since the
           trig functions will be needed from the C libraries.

See also:  UltraAngPosition3D


___________________________________________________________________________
                                                                         87



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraAngPosition3D
_________________________________

Purpose:   To position a sound using integer polar coordinates.

C:         void UltraAngPosition3D(sound,azimuth,elevation,volume);
           SOUND_3D *sound;
           int azimuth;
           int elevation;
           int volume;

PASCAL:    PROCEDURE UltraAngPosition3D(VAR Sound     : SOUND_3D;
                                            AZIMuth   : INTEGER;
                                            Elevation : INTEGER;
                                            Vol_Dist  : INTEGER);

Remarks:   This routine will position a 3D  sound using polar coordinates.
           The azimuth and elevation are specified  in degrees. Azimuth is
           the angle in the horizontal plane. Straight ahead is 0 degrees,
           90 degrees is to the right, -90 degrees  is to the left and 180
           (or -180) is directly  behind you. If an  angle larger than 180
           or smaller that -180 is specified,  it is converted to its -180
           to 180 equivalent. For example, 270  degrees is equivalent to -
           90 degrees. Elevation is the angle  of elevation above or below
           the horizontal plane. 0 degrees is  no elevation, 90 degrees is
           straight up, and -90 is straight down. Any angle larger than 90
           or smaller that -90 is ignored.

           If more precision is needed,  use UltraAngFltPosition3D so that
           floating point  arithmetic is  used.   Since that  routine uses
           floating point functions (slow), your  application may not want
           to use it.

See also:  UltraAbsPosition3D





















___________________________________________________________________________
                                                                         88



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraAngFltPosition3D
_________________________________

Purpose:   To position a sound using floating point polar coordinates.

C:         void UltraAngFltPosition3D(sound,azimuth,elevation,volume);
           SOUND_3D *sound;
           double azimuth;
           double elevation;
           int volume;

PASCAL:    PROCEDURE UltraAngFltPosition3D(VAR Sound     : SOUND_3D;
                                               AZIMuth   : DOUBLE;
                                               Elevation : DOUBLE;
                                               Vol_Dist  : INTEGER);

Remarks:   This routine will position a 3D  sound using polar coordinates.
           The azimuth  and elevation  are  specified as    floating point
           numbers in degrees. For example, 45  and one half degrees would
           be specified as  45.5. Azimuth is  the angle  in the horizontal
           plane. Straight ahead is 0 degrees, 90 degrees is to the right,
           -90 degrees is to the left and 180 (or -180) is directly behind
           you. If  an  angle larger  than  180 or  smaller  that  -180 is
           specified, it is converted  to its -180 to  180 equivalent. For
           example, 270 degrees is equivalent to -90 degrees. Elevation is
           the angle above or below the  horizontal plane. 0 degrees is no
           elevation, 90 degrees is straight up, and -90 is straight down.
           Any angle larger than 90 or smaller that -90 is ignored.

           If your application  does not  need to  use the  floating point
           routine, it  is advisable  to use  UltraAngPosition  because it
           avoids using some floating-point functions (which are slow).



UltraCloseDup3D
_________________________________

Purpose:   To close a duplicated 3D sound effect.

C:         void UltraCloseDup3D(sound);
           SOUND_3D *sound;

PASCAL:    PROCEDURE UltraCloseDup3D(VAR Sound : SOUND_3D);

Remarks:   This routine must be  used to free up  the resources associated
           with a duplicated 3D effect. This routine will only release the
           voices used by the duplicated effect, not the DRAM allocated by
           the original effect. The original effect  should be closed with
           UltraUnLoad3DEffect.

See also:  UltraDup3D, UltraUnLoad3DEffect.



___________________________________________________________________________
                                                                         89



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltrDup3D
_________________________________

Purpose:   To copy a 3D sound effect.

C:         int UltraDup3D(old,new);
           SOUND_3D *old;
           SOUND_3D *new;

PASCAL:    FUNCTION  UltraDup3D(VAR Current : SOUND_3D;
                                VAR Sound   : SOUND_3D) : BOOLEAN;

Remarks:   This routine is very useful  if you want to  use the same sound
           effect in multiple places  at once. This allows  you to use the
           same DRAM data and  just allocate some more  voices to move the
           sound. This helps  to save DRAM  space. Make sure  that you use
           UltraCloseDup3D to  free the  voices,  NOT UltraUnLoad3DEffect.
           UltraUnLoad3DEffect will release  all the  DRAM for  the sound.
           This new effect  can be passed  to any other  routines the same
           way the original effect is.

Returns:   C:  ULTRA_OK        No Error
               NO_FREE_VOICES  Not enough voices to make new handle

           PASCAL: TRUE if duplication successful.
                   If FALSE, check UltraErrorStr for the reason.

See also:  UltraCloseDup3D



























___________________________________________________________________________
                                                                         90



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraLoad3DEffect
_________________________________

Purpose:   To load a 3D effect from the disk into DRAM.

C:         int UltraLoad3DEffect(sound,filename,pc_buffer,size);
           SOUND_3D *sound;
           char *filename;
           void far *pc_buffer;
           unsigned int size;

PASCAL:    FUNCTION  UltraLoad3DEffect(VAR Sound     : SOUND_3D;
                                       VAR FileName  : STRING;
                                           PC_Buffer : POINTER;
                                           Size      : WORD) : BOOLEAN;

Remarks:   This routine is used  to load a 3D  sound into the  DRAM on the
           UltraSound. It will  allocate all  necessary resources  so that
           UltraStart3D can be  called later. As  many buffers  of DRAM as
           needed will  be  allocated  along  with  the  proper number  of
           voices.  These  resources  will  be  freed  up  when  you  call
           UltraUnLoad3DEffect. The  file  specified  MUST  be  a properly
           formatted or the  routine will  fail. This  means that  it must
           have the proper header and 3D data  in it. The 'pc_buffer' is a
           buffer supplied by your  application for this  routine's use to
           download data into the UltraSound. The  'size' parameter is the
           size of the 'pc_buffer'. The larger  this buffer is, the faster
           it will download.

Returns:   C: ULTRA_OK         No error
              NO_3D_FILE       3D file not found
              BAD_3D_HDR       3D header is bad
              NO_3D_HDR        File doesn't have a valid header
              NOT_BLOCK_DATA   File is not in blocked format
              NO_FREE_VOICES   Not enough free voices
              BAD_FILE_DATA    Not enough data or bad file
              CORRUPT_MEM      Memory structs have been corrupted
              DMA_BUSY         DMA channel busy

           PASCAL: TRUE if the file could be loaded.
                   If FALSE check UltraErrorStr for the reason.

See also:  UltraMemAlloc, UltraVoiceAlloc, UltraDownload












___________________________________________________________________________
                                                                         91



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraSetFreq3D
_________________________________

Purpose:   To set the frequency of a 3D sound effect.

C:         void UltraSetFreq3D(sound,frequency);
           SOUND_3D *sound;
           unsigned long frequency;

PASCAL:    FUNCTION  UltraSetFreq3D(VAR Sound     : SOUND_3D;
                                        Frequency : LONGINT) : BOOLEAN;

Remarks:   This routine will allow you to  alter the frequency that the 3D
           sound is using. This allows  you to do pitch  shifting to get a
           doppler shift type  effect. This  routine can  only be  done on
           blocked data.

Returns:   C: ULTRA_OK          No problem
              NOT_BLOCKED_DATA  Can't change freq of interleaved data

           PASCAL: TRUE if the frequency was changed ok.
                   If FALSE, check UltraErrorStr for the reason.



UltraRelease3DInterleave
_________________________________

Purpose:   To release 3D resources for an interleaved effect.

C:         void UltraRelease3DInterleave(sound)
           SOUND_3D *sound;

PASCAL:    PROCEDURE UltraRelease3DInterleave(VAR Sound : SOUND_3D);

Remarks:   This routines will release the DRAM and voices allocated for an
           interleaved sound track.

See also:  UltraSetup3DInterleave
















___________________________________________________________________________
                                                                         92



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraSetup3DInterleave
_________________________________

Purpose:   To set up for an interleaved 3D sound effect.

C:         int UltraSetup3DInterleave(sound,filename,size);
           SOUND_3D *sound;
           char *filename;
           unsigned long size;

PASCAL:    FUNCTION UltraSetup3DInterleave(VAR Sound    : SOUND_3D;
                                           VAR FileName : STRING;
                                           Size : LONGINT) : BOOLEAN;

Remarks:   This routine will allocate  the voices and  memory necessary to
           play back an interleaved 3D sound. It  will NOT load any of the
           file data into DRAM. Your application  is responsible for that.
           It  will  open  the   file,  read  the   header,  allocate  the
           appropriate resources, and set up the begin, start and end loop
           points for each  voice. Since  the sound  is   interleaved, the
           loop points are staggared appropriately.

Returns:   C: ULTRA_OK             No error
              NO_3D_FILE           3D file not found
              BAD_3D_HDR           3D header is bad
              NO_3D_HDR            File doesn't have a valid header
              NOT_INTERLEAVED_DATA File in blocked format
              NO_FREE_VOICES       Not enough free voices
              BAD_FILE_DATA        Not enough data or bad file
              CORRUPT_MEM          Memory structs have been corrupted

           PASCAL: TRUE if the file could be read successfully.
                   If FALSE, check UltraErrorStr for the reason.

See also:  UltraLoad3DEffect



UltraStart3D
_________________________________

Purpose:   To start a 3D sound which has been loaded.

C:         void UltraStart3D(sound);
           SOUND_3D *sound;

PASCAL:    PROCEDURE UltraStart3D(VAR Sound : SOUND_3D);

Remarks:   This routine will start a 3D sound. If  you want it to begin at
           a specific point in space, be  sure that you position it first.
           It is not necessary to stop the sound before starting it again.

See also:  UltraStart3D


___________________________________________________________________________
                                                                         93



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

UltraStop3D
_________________________________

Purpose:   To stop a 3D sound which is playing.

C:         void UltraStop3D(sound,abruptly);
           SOUND_3D *sound;
           int abruptly;

PASCAL:    PROCEDURE UltraStop3D(VAR Sound    : SOUND_3D;
                                     Abruptly : BOOLEAN);

Remarks:   This routine will stop a 3D sound. There are two ways to stop a
           sound: if the 'abruptly' flag is TRUE, then the sound will shut
           off immediately; if it is FALSE,  then the sound will be ramped
           down very  quickly.  The  second method  will  give  a smoother
           transition.



UltraUnLoad3DEffect
_________________________________

Purpose:   To free resources used by a 3D effect.

C:         void UltraUnLoad3DEffect(sound);
           SOUND_3D *sound;

PASCAL:    PROCEDURE UltraUnLoad3DEffect(VAR Sound : SOUND_3D);

Remarks:   This routine is  used to  free up all  the resources  (voices &
           DRAM) that a 3D  sound   uses.  Since a 3D  sound can use a lot
           of  the   voices   & DRAM,  you should  free up  the  resources
           whenever you can.

See also:  UltraLoad3DEffect



















___________________________________________________________________________
                                                                         94



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

                         Appendix A - Error Codes

======
  C:
======

Main routines: (these are defined in ULTRAERR.H)

  ULTRA_OK           1   No error
  BAD_NUM_OF_VOICES  2   must be 14-32
  NO_MEMORY          3   Not enough free DRAM left
  CORRUPT_MEM        4   memory structures are corrupt
  NO_ULTRA           5   Can't find an UltraSound
  DMA_BUSY           6   This DMA channel is still busy
  BAD_DMA_ADDR       7   auto init across page boundaries
  VOICE_OUT_OF_RANGE 8   allocate a voice past # active
  VOICE_NOT_FREE     9   voice has already been allocated
  NO_FREE_VOICES     10   not any voices free

3D functions: (these are defined in THREED.H)

  NO_3D_FILE             101   Can't open file
  BAD_3D_HDR             102   Header for file is corrupt/non-existent
  NO_DRAM_3D             103   Not enough room for this sound
  NO_3D_HDR              104   No header on this file
  NOT_BLOCK_DATA         105   data not in block format
  BAD_FILE_DATA          106   not enough data as header says
  NOT_INTERLEAVED_DATA   107  data not in interleaved format
  BAD_3D_FREQ            108  invalid freq. for interleaved 3D data



=========
 PASCAL:
=========

Please see the discussion of the PASCAL error handling techniques at the
end of section 1.8.1.

















___________________________________________________________________________
                                                                         95



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

                        Appendix B - Volume Control

Here are the volume ramp control bit definitions:

   =================================
   | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
   =================================
     |   |   |   |   |   |   |   |
     |   |   |   |   |   |   |   +---- Reserved
     |   |   |   |   |   |   +-------- Reserved
     |   |   |   |   |   +------------ Reserved
     |   |   |   |   +---------------- loop enable (0=no loop, 1=loop)
     |   |   |   +-------------------- bi-direction. loop (1=enable)
     |   |   +------------------------ Enable volume ramp IRQ
     |   +---------------------------- Reserved
     +-------------------------------- Reserved

The bits that should be set by the application to get a particular type  of
volume ramp. The completed value should be supplied to UltraRampVolume  and
UltraRampLinearVolume. If volume interrupts are enabled, make sure that you
have set up a volume interrupt  handler (see UltraVolumeHandler). This  can
be used to create your own multi-point volume envelopes.

Bi-directional looping can be used to create a tremelo effect.































___________________________________________________________________________
                                                                         96



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

                        Appendix C - Voice Control

Here are the voice control bit definitions:

   =================================
   | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
   =================================
     |   |   |   |   |   |   |   |
     |   |   |   |   |   |   |   +---- Rollover when hit ending addr
     |   |   |   |   |   |   +-------- Reserved
     |   |   |   |   |   +------------ data type (0=8 bit 1=16 bit)
     |   |   |   |   +---------------- loop enable (0=no loop, 1=loop)
     |   |   |   +-------------------- bi-direction. loop (1=enable)
     |   |   +------------------------ Enable wavetable IRQ
     |   +---------------------------- Direction (0=inc, 1=dec)
     +-------------------------------- Reserved

The UltraSound is capable of playing  back 8 or 16  bit data. (It can  only
record 8 bit). Stereo is handled by using 2 voices. It can loop on the data
in either a uni-directional or bi-directional mode. If you have asked  that
a particular voice generate a wavetable  interrupt when it hits the end  of
the data  (or  loop point,  if  looping is  specified),  be sure  you  have
specified a  wavetable interrupt  hander (UltraWaveHander).  The mode  bits
would be constructed  and passed to  UltraStartVoice and  UltraSetLoopMode.
The rollover bit  is used  to tell the  software to  program the  hardware:
generate an interrupt when the voice  hits the end address, but don't  stop
playing the voice (or loop if looping  is enabled). This allows a voice  to
continue to play but gives the  software a 'marker point' in the  playback.
This can be very powerfull to  allow a seamless playback. The hardware  bit
for turning rollover on is acutally in the voice's volume control  register
(there were no spare bits in the  voice control register). One of the  bits
is shared to tell the toolkit software to enable the rollover in the volume
control register.






















___________________________________________________________________________
                                                                         97



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

                         Appendix D - DMA Control

Here are the dma to/from DRAM control bit definitions:

   =================================
   | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
   =================================
     |   |   |   |   |   |   |   |
     |   |   |   |   |   |   |   +---- Reserved
     |   |   |   |   |   |   +-------- 0=write,1=Read
     |   |   |   |   |   +------------ Reserved
     |   |   |   |   +---------------- Reserved
     |   |   |   +-------------------- Reserved
     |   |   +------------------------ Reserved
     |   +---------------------------- Data size (0=8 bit, 1=16 bit)
     +-------------------------------- (1=convert to 2's comp.)

Note:   The UltraSound  DRAM  location MUST  be  on a  32  byte  boundary.
        UltraMemAlloc enforces this stipulation.

You define the  byte to be  passed to UltraUpload  and UltraDownload  using
these bits. To DMA the data out of DRAM, use UltraUpload.  To send data  to
the DRAM, use UltraDownload. Be sure to specify the sample size and whether
or not the data is in two's  compliment form. The UltraSound can only  play
data back that  is in two's  compliment form. If  your sample  is in  one's
compliment form,  turn on  bit 7  when specifying  the mode  when you  call
UltraDownload - the data  will be translated to  two's compliment as it  is
being DMA'ed.

Note:   If you are poking data  into DRAM, you MUST  put the data in  twos
        compliment yourself. This is accomplished by exclusive  or-ing the
        high bit with a 1.























___________________________________________________________________________
                                                                         98



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

                      Appendix E - Recording Control

Here are the recording control bit definitions:

   =================================
   | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
   =================================
     |   |   |   |   |   |   |   |
     |   |   |   |   |   |   |   +---- Reserved
     |   |   |   |   |   |   +-------- mode (0=mono,1=stereo)
     |   |   |   |   |   +------------ Reserved
     |   |   |   |   +---------------- Reserved
     |   |   |   +-------------------- Reserved
     |   |   +------------------------ Reserved
     |   +---------------------------- Reserved
     +-------------------------------- (1=Convert to 2's comp.)







































___________________________________________________________________________
                                                                         99



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

                         Appendix F - Patch Files

This appendix contains  information about the  the patch file  format.   It
assumes the reader is familiar with wave table synthesis, music, sound,
and the GF1 ASIC chip that is the heart of the UltraSound audio card.

The UltraSound patch file is a collection of data structures and sound data
in the following format:

    patch header (# instruments)
        instrument header 1 (#layers)
            layer 1 header (# waves)
             wave 1 header
             wave 1 data
                wave 2 header
                wave 2 data
                ...
                wave n header
                wave n data
            layer 2 header (# waves)
                wave 1 header
                wave 1 data
                wave 2 header
                wave 2 data
                ...
                wave n header
                wave n data
        instrument header 2 (#layers)
    etc.

All of the Advanced Gravis UltraSound patches contain one instrument at the
current time.  Except for the main patch header, each of the headers has  a
size field which can be used to seek past unwanted data.  For example, if a
patch has two instruments  and you want to  skip the first instrument,  you
would read  the  first instrument  header,  and then  skip  INSTRUMENT_SIZE
bytes.  What follows is the patch header definitions given in C and Pascal.
After the definitions, a field-by-field breakdown of the headers is given.

======
  C:
======

#define ENVELOPES                       6
#define HEADER_SIZE                     12
#define ID_SIZE                         10
#define DESC_SIZE                       60
#define RESERVED_SIZE                   40
#define PATCH_HEADER_RESERVED_SIZE      36
#define LAYER_RESERVED_SIZE             40
#define PATCH_DATA_RESERVED_SIZE        36
#define GF1_HEADER_TEXT                 "GF1PATCH110"
#define MAX_LAYERS                      4
#define INST_NAME_SIZE                  16


___________________________________________________________________________
                                                                        100



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

typedef struct
{
   char             header[ HEADER_SIZE ];
   char             gravis_id[ ID_SIZE ];   /* Id = "ID#000002" */
   char             description[ DESC_SIZE ];
   unsigned char    instruments;
   char             voices;
   char             channels;
   unsigned int     wave_forms;
   unsigned int     master_volume;
   unsigned long    data_size;
   char             reserved[ PATCH_HEADER_RESERVED_SIZE ];
} PATCHHEADER;

typedef struct
{
   unsigned int     instrument;
   char             instrument_name[ 16 ];
   long             instrument_size;
   char             layers;
   char             reserved[ RESERVED_SIZE ];
} INSTRUMENTDATA;

typedef struct
{
   char             layer_duplicate;
   char             layer;
   long             layer_size;
   char             samples;
   char             reserved[ LAYER_RESERVED_SIZE ];
} LAYERDATA;



... continued on the next page ...




















___________________________________________________________________________
                                                                        101



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

typedef struct
{
   char             wave_name[7];

   unsigned char    fractions;
   long             wave_size;
   long             start_loop;
   long             end_loop;

   unsigned int     sample_rate;
   long             low_frequency;
   long             high_frequency;
   long             root_frequency;
   int              tune;

   unsigned char    balance;

   unsigned char    envelope_rate[ ENVELOPES ];
   unsigned char    envelope_offset[ ENVELOPES ];

   unsigned char    tremolo_sweep;
   unsigned char    tremolo_rate;
   unsigned char    tremolo_depth;

   unsigned char    vibrato_sweep;
   unsigned char    vibrato_rate;
   unsigned char    vibrato_depth;

   /* bit 0 = 8 or 16 bit wave data. */
   /* bit 1 = Signed - Unsigned data. */
   /* bit 2 = looping enabled-1. */
   /* bit 3 = Set is bidirectional looping. */
   /* bit 4 = Set is looping backward. */
   /* bit 5 = Turn sustaining on. (Env. pts. 3)*/
   /* bit 6 = Enable envelopes - 1 */
   char             modes;

   int              scale_frequency;
   unsigned int     scale_factor;    /* from 0 to 2048 or 0 to 2 */

   char             reserved[ PATCH_DATA_RESERVED_SIZE ];
} PATCHDATA;



...end of the C section.  Please see the next page for the PASCAL
section...








___________________________________________________________________________
                                                                        102



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

=========
 PASCAL:
=========

CONST
  ENVELOPES                  = 6;
  HEADER_SIZE                = 12;
  ID_SIZE                    = 10;
  DESC_SIZE                  = 60;
  RESERVED_SIZE              = 40;
  PATCH_HEADER_RESERVED_SIZE = 36;
  LAYER_RESERVED_SIZE        = 40;
  PATCH_DATA_RESERVED_SIZE   = 36;
  GF1_HEADER_TEXT            : ARRAY[1..12] OF CHAR = 'GF1PATCH110';

TYPE
  PATCHHEADER = RECORD
    Header        : ARRAY[1..HEADER_SIZE] OF CHAR;
    Gravis_ID     : ARRAY[1..ID_SIZE] OF CHAR;  { Id = 'ID#000002' }
    Description   : ARRAY[1..DESC_SIZE] OF CHAR;
    Instruments   : SHORTINT;
    Voices        : SHORTINT;
    Channels      : SHORTINT;
    Wave_Forms    : WORD;
    Master_Volume : WORD;
    Data_Size     : LONGINT;
    Reserved      : ARRAY[1..PATCH_HEADER_RESERVED_SIZE] OF BYTE;
   END;

  INSTRUMENTDATA = RECORD
    Instrument      : WORD;
    Instrument_Name : ARRAY[1..16] OF CHAR;
    Instrument_Size : LONGINT;
    Layers          : SHORTINT;
    Reserved        : ARRAY[1..RESERVED_SIZE] OF BYTE;
   END;

  LAYERDATA = RECORD
    Layer_Duplicate : SHORTINT;
    Layer           : SHORTINT;
    Layer_Size      : LONGINT;
    Samples         : SHORTINT;
    Reserved        : ARRAY[1..RESERVED_SIZE] OF BYTE;
   END;


...continued on the next page...








___________________________________________________________________________
                                                                        103



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

  PATCHDATA = RECORD
    Wave_Name       : ARRAY[1..7] OF CHAR;
    Fractions       : BYTE;
    Wave_Size       : LONGINT;
    Start_Loop      : LONGINT;
    End_Loop        : LONGINT;
    Sample_Rate     : WORD;
    Low_Frequency   : LONGINT;
    High_Frequency  : LONGINT;
    Root_Frequency  : LONGINT;
    Tune            : INTEGER;
    Balance         : BYTE;
    Envelope_Rate   : ARRAY[1..ENVELOPES] OF BYTE;
    Envelope_Offset : ARRAY[1..ENVELOPES] OF BYTE;
    Tremolo_Sweep   : BYTE;
    Tremolo_Rate    : BYTE;
    Tremolo_Depth   : BYTE;
    Vibrato_Sweep   : BYTE;
    Vibrato_Rate    : BYTE;
    Vibrato_Depth   : BYTE;

    { bit 0 = 8 or 16 bit wave data.            }
    { bit 1 = Signed - Unsigned data.           }
    { bit 2 = looping enabled-1.                }
    { bit 3 = Set is bidirectional looping.     }
    { bit 4 = Set is looping backward.          }
    { bit 5 = Turn sustaining on. (Env. pts. 3) }
    { bit 6 = Enable envelopes - 1              }
    Modes           : SHORTINT;

    Scale_Frequency : INTEGER;
    Scale_Factor    : WORD; { From 0 to 2048 or 0 to 2 }
    Reserved        : ARRAY[1..PATCH_DATA_RESERVED_SIZE] OF BYTE;
   END;


File Header
_________________________________

'Header'
     The header field should contain the  text "GF1PATCH110."  The first  8
     bytes will always be GF1PATCH.   The next three bytes are the  version
     number of the patch  format.  As  fields are added  to the patch,  the
     number will  be  incremented.   All  of  the  UltraSound  patches  are
     currently at version  110.   The older  100 patches  are obsolete  and
     should no longer be in use.

'Description'
     This description field is usually for copyright information.

'Instruments'
     The number of  instruments in the  patch.  All  of the gravis  patches
     contain only one instrument.


___________________________________________________________________________
                                                                        104



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

'Voices'
     The GF1 synth  can update  14 voices  at 44.1Khz.   As  the number  of
     voices increases, the  actual output rate  of each  voice drops.  This
     field should contain the number of voices that were used when creating
     the patch. This field could be used by  a MIDI engine to try and  make
     the patch sound the  same regardless of the  number of active  voices.
     Currently this feature is not implemented in the gravis MIDI engine.

'Channels'
     This field is unused.  Only mono data  can be played out a voice  with
     the GF1.

'Wave_Forms'
     The total number of  waveforms in the  patch.  This  field is used  by
     programs which need to preallocate space for wave form headers  before
     the patch is loaded.

'Master_Volume'
     This field is currently unused.

'Data_Size'
     The size of the  patch data after it  is loaded into  GF1 dram.   This
     number includes the space needed to align each of the waveforms on  32
     byte boundaries.    If  you patch  loader  maintains  linked  list  of
     waveforms in dram, and you need to use an extra 32 bytes per waveform,
     then you can use  the wave_forms field to  figure out how much  memory
     you will need to load the patch.  i.e.  data_size + (32 * wave_forms).



Instrument Header
_________________________________

'Instrument'
     This field is currently unused.

'Instrument_Name'
     This field is currently unused.

'Instrument_Size'
     The size of the instrument.  The number  of bytes to skip in order  to
     read the next instrument header.

'Layers'
     The number of layers in this instrument.  Multiple layers are  usually
     used in patches where  more than one sound  is required with a  single
     MIDI event  (note on).   For  example, a  piano would  could have  two
     layers. The first would be the actual tone from the hammer hitting the
     strings, and the second would be  the (thunk) of the key being  struck
     and all of  the mechanisms moving  inside the piano.   The  mechanisms
     would probably be frequency independant,  and also independant of  the
     length of the tone.



___________________________________________________________________________
                                                                        105



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

Layer Header
__________________________

'Layer_Duplicate'
     Currently unused.  If the layer duplicate  is nonzero, then this layer
     should use the  data from the  previous layer. Only  the headers  will
     follow.

'Layer'
     The current layer number for this instrument

'Layer_Size'
     The size of this layer.   Can be used to seek  past this layer in  the
     file.

'Samples'
     The number  of waveforms  in this  layer.   This field  is ignored  if
     layer_duplicate is true.



Wave Header
_________________________________

'Wave_Name'
     This field is currently unused

'Fractions'
     The start_loop and end_loop are the integer portions of the  wavetable
     address.  The GF1 can interpolate between sample points and  therefore
     meore resolution than just  the integer address is  needed.  The  most
     significant four bits are the  fractional address for the  start_loop,
     and the least significant four bits are the fractional address for the
     end_loop.

'Wave_Size'
     The number  of bytes  of wave  table data  that follows  -- not  #  of
     samples.

'Start_Loop'
     The integer  portion of  the starting  loop  address relative  to  the
     beginning of the wave.  This address is the relative number of  bytes,
     and not the number of samples.

'End_Loop'
     The integer  portion  of  the ending  loop  address  relative  to  the
     beginning of the wave.  This address is the relative number of  bytes,
     and not the number of samples.

'Sample_Rate'
     This is the  sample rate of  the recorded data.   This  number is  not
     related to the actual pitch of the recorded tone.



___________________________________________________________________________
                                                                        106



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

'Low_Frequency'
     Each wave  covers a  specific frequency  range.   This is  the  lowest
     frequency that this wave can be used to play.  This field is scaled be
     1000 for accuracy.

'High_Frequency'
     Each wave covers  a specific  frequency range.   This  is the  highest
     frequency that this wave can be used to play.  This field is scaled by
     1000 for accuracy.  If there is another wave adjacent to this one  and
     its range overlaps this range, then  the next waveform will always  be
     chosen.

'Root_Frequency'
     If this wave  is played back  at the original  sample_rate, then  this
     number should  be the  pitch of  the  original tone.   This  field  is
     modified to tune the wave to a particular pitch.  This field is scaled
     by 1000 for accuracy.

'Tune'
     This field is unused.   Tuning is accomplished  by modifying the  root
     frequency.

'Balance'
     0 is 100% to the right, and 15 is 100% to the left.  As the balance is
     shifted from left to right, the total output power of both channels is
     constant.

'Envelope_Rate'
     An array of 6 rates to  implement a 6-point envelope. The first  three
     rates can be used for attack and decay.   If the sustain flag is  set,
     than the third  envelope point  will be  the sustain  point. The  last
     three envelope  points are  for the  release, and  an optional  "echo"
     effect.  If the last envelope point is left at an audible level,  then
     a sampled release can  heard after the last  envelope point. The  rate
     values are sent directly to the GF1 hardware, and are described in the
     volume ramping section.

'Envelope_Offset'
     An array of 6 offsets to implement a 6-point envelope. The first three
     offsets can be used for attack and decay.  If the sustain flag is set,
     than the third  envelope point will  be the sustain  point.  The  last
     three envelope  points are  for the  release, and  an optional  "echo"
     effect.  If the last envelope point is left at an audible level,  then
     a sampled release can heard after the last envelope point.  The offset
     values are sent directly to the GF1 hardware, and are described in the
     volume ramping section.

'Tremolo_Sweep'
     Not implemented.  Tremolo starts automatically when the note sustains.
     This will be  changed in  future software  to gradually  sweep in  the
     tremolo depth from 0 at the rate of tremolo_sweep / 45 seconds.




___________________________________________________________________________
                                                                        107



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

'Tremolo_Rate'
     The rate of amplitude modulation.  0 is 0.05 Hz,  and 255 is 6 Hz.   A
     complete table is listed below.

'Tremolo_Depth'
     0 means  turn tremolo  off.   255  provides a  16  dB modulation.    A
     complete table is listed below.

'Vibrato_Sweep'
     Gradually  sweep  in  the  vibrato  depth  from  0  at  the  rate   of
     vibrato_sweep / 45 seconds.

'Vibrato_Rate'
     The rate of frequency modulation.  0 is 0.05 Hz, and 255 is 6 Hz.

'Vibrato_Depth'
     0 means turn vibrato off.  255 is a one octave modulation.

'Modes'
     A set of bit fields describing modes and data type:
     BIT 0- 16 bit data
     BIT 1- unsigned data
     BIT 2- looping enabled
     BIT 3- bidirectional loop
     BIT 4- play patch backwards.   start at end address,  loop backwards,
            and then end at beginning address.
     BIT 5- sustain - enveloping  stops at third  envelope point.   a note
            off will continue enveloping.
     BIT 6- currently means enveloping enabled.   All gravis  patches have
            this bit set.  This field will be modified  in the near future
            to implement a sampled release  at note off instead  of at the
            last envelope point.   If this bit  is on, the  sample release
            occurs after the last envelope point.  If this bit is off, the
            sampled release occurs at the note off.
     BIT 7- fast release.  The last three envelope points are ignored.

'Scale_Frequency'
     Keyboard frequency scaling.  Normally, MIDI note 64 plays a middle  C.
     A 65 plays a C#.  frequency  scaling changes the distance in pitch  of
     each MIDI note.   The scale_frequency is the MIDI note number which is
     the pivot point for scaling.  If scale_frequency is 64, then MIDI note
     64 will sound like a C4 regardless of scale factor.

'Scale_Factor'
     1024 means normal scaling.  Each MIDI note is  one semitone away  from
     its neighbor.  512 would be 1/2 semitone apart.  2048 is two semitones
     apart.








___________________________________________________________________________
                                                                        108



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

                        Appendix G - 3D File Header

Here is a definition for the data found in Focal-Point 3D files. All .F3D
files will have this format.  Both C and PASCAL versions of the definition
are listed below.

======
  C:
======

/* Bit definitions for tracks that are in a 3D file ... */
#define FRONT_TRACK      0x01
#define RIGHT_TRACK      0x02
#define REAR_TRACK       0x04
#define LEFT_TRACK       0x08
#define ABOVE_TRACK      0x10
#define BELOW_TRACK      0x20

#define FBLOCK_3D        0x01    /* File data is blocked */
#define F16BIT_3D        0x02    /* 16 bit data */
#define FTWOS_CMP_3D     0x04    /* sound is in twos complement form */
#define FLOOPED_3D       0x08    /* sound is looped , not one shot*/
#define FBI_LOOP_3D      0x10    /* sound is bi-directional */
#define F3D_TYPE         0x60    /* Type of 3D sound */

/* types (F3D_TYPE) of 3D sound (only binaural currently supported) */
#define F_BINAURAL       0x20    /* Binaural representation */
#define F_SURROUND       0x40    /* Surround sound (???) */
#define F_QSOUND         0x60    /* Q sound (???) */

/* the following structure is exactly 256 bytes long ... */
typedef struct {
   char id[10];                /* 3D FILE tag */
   int major;                  /* major version # */
   int minor;                  /* minor version # */
   char description[80];
   unsigned int type;          /* See above .... */
   int tracks;                 /* tracks included in this file ... */
   int reserve1[24];           /* for expansion */
   int maxvol;                 /* volume can range from 0 to maxvol */
   int reserve2[10];           /* for expansion */
   unsigned long blocksize;    /* # of bytes in block data */
   unsigned long loop_offset;  /* byte offset to where loop begins */
   unsigned long reserve3[9];  /* for expansion */
   unsigned long frequency;    /* initial playback frequency */
   unsigned long reserve4[10]; /* for expansion */
} FILEHDR_3D;


...end of the C section.  Please see the next page for the PASCAL
section...




___________________________________________________________________________
                                                                        109



Ultrasound Software Development Kit (SDK)                      Version 2.10
___________________________________________________________________________

========
 PASCAL
========

CONST
  { Bit definitions FOR tracks that are in a 3D FILE ... }
  FRONT_TRACK  = $01;
  RIGHT_TRACK  = $02;
  REAR_TRACK   = $04;
  LEFT_TRACK   = $08;
  ABOVE_TRACK  = $10;
  BELOW_TRACK  = $20;

  FBLOCK_3D    = $01; { FILE data is blocked, NOT interleaved }
  F16BIT_3D    = $02; { 16 bit data }
  FTWOS_CMP_3D = $04; { sound is in twos complement form }
  FLOOPED_3D   = $08; { sound is looped , NOT one shot }
  FBI_LOOP_3D  = $10; { sound is bi-directional }
  F3D_TYPE     = $60; { TYPE OF 3D sound }

  { types (F3D_TYPE) OF 3D sound (only binaural currently supported) }
  F_BINAURAL   = $20; { Binaural representation }
  F_SURROUND   = $40; { Surround sound (???) }
  F_QSOUND     = $60; { Q sound (???) }

TYPE
  FILEHDR_3D = RECORD
    ID          : ARRAY[0..9] OF CHAR;     { 3D FILE tag }
    Major       : INTEGER;                 { Major version # }
    Minor       : INTEGER;                 { Minor version # }
    Description : ARRAY[0..79] OF CHAR;
    SType       : WORD;                    { See above }
    Tracks      : INTEGER;                 { Tracks included }
    Reserve1    : ARRAY[0..23] OF INTEGER; { for expansion }
    MaxVol      : INTEGER;                 { volume range 0-maxvol }
    Reserve2    : ARRAY[0..9] OF INTEGER;  { for expansion }
    BlockSize   : LONGINT;                 { # of bytes in block data }
    Loop_Offset : LONGINT;                 { byte offset of loop begin}
    Reserve3    : ARRAY[0..8] OF LONGINT;  { for expansion }
    Frequency   : LONGINT;                 { playback frequency }
    Reserve4    : ARRAY[0..9] OF LONGINT;  { for expansion }
   END;
  { the file header is exactly 256 bytes long }












___________________________________________________________________________
                                                                        110
