home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 390.lha / SampLibrary / samplib.doc.pp / samplib.doc
Encoding:
Text File  |  1990-07-01  |  28.1 KB  |  609 lines

  1.     This is the document for the dissidents' samp.library 1.0 © 1989. Set your
  2. editor's TAB width to 3.
  3.  
  4.  
  5.                 «««««««««««««« WHAT THE HELL IS SAMP? »»»»»»»»»»»»
  6.     (or "If it doesn't have anything to do with video, what good is it?")
  7.  
  8.     SAMP is an IFF file format used to store any resolution audio data. This
  9. format is used in dissidents' Midi Sample Wrench, a 16 bit audio waveform
  10. editing program for the Amiga.  The dissidents' samp.library is a library
  11. used to load and save SAMP files.  The samp.library will allow you to write
  12. applications that can save and retrieve audio data saved in the SAMP format.
  13. For a detailed spec of the SAMP format, consult the SAMP.doc file.
  14.     The samp.library is written entirely in 68000 assembly for speed and small
  15. size. Distributed with the library are C and assembly Include files and example
  16. applications, as well as a utility to convert 8SVX files to SAMP, and other
  17. SAMP support libraries.
  18.  
  19.  
  20.                 ««««««««««««««««« COPYRIGHT NOTICE »»»»»»»»»»»»»»»»»»
  21.  
  22.     The samp.library and ToSAMP conversion utility are copyright by dissidents
  23. software. These two files may be used by and freely distributed with any
  24. application, commercial or otherwise, although copyright is retained exclu-
  25. sively by dissidents, and the files must not be modified in any way. In
  26. addition, the following files are copyright by dissidents, and may only be
  27. distributed on disks which are freely-distributable or for which a nominal
  28. charge to cover media and shipping is the only consumer cost:
  29.  
  30.     1).  SAMPlib.doc
  31.     2).  SAMP.doc
  32.     3).  ToSAMP.asm
  33.     4).  Exam.c, Exam.asm
  34.     5).  SAMP.i, SAMP.h
  35.     6).  SAMPInterface.asm
  36.     7).  TestInsType.c, TestInsType.asm
  37.     8).  InsTypeInterface.asm
  38.     9).  instype.library
  39.     10). SAMP_ReadOut.c
  40.     11). SAMP_Writer.c
  41.  
  42.     All copyright notices must remain intact.
  43.  
  44.  
  45.                 «««««««««««««««« CURRENT LIMITATIONS »»»»»»»»»»»»»»»»
  46.  
  47.     The library does not support loading/saving SAMP files inside of a CAT or
  48. LIST, nor does it currently support Continuation files or NumOfChans > 4.
  49.     Due to memory considerations, the library can only be servicing one task
  50. at any given moment (though several tasks may simultaneously open the library).
  51.  
  52.  
  53.                 ««««««««««««««««« DATA STRUCTURES »»»»»»»»»»»»»»»»»
  54.  
  55.     Before you open and use the samp.library, you must create a few structures
  56. and variables from which the library can load/save data. The most important
  57. structure is is the SampleHeader64 structure. It is used to hold information
  58. about 1 waveform such as its size, OneShotStart and LoopStart addresses, Root
  59. Note, and velocity table. Each waveform that is loaded must have its own 64
  60. byte SampleHeader64 structure. Furthermore, all the SampleHeader64 structures
  61. must be contiguous in memory. For this reason, an application should allocate
  62. the proper number of SampleHeader64 structures before actually loading the
  63. waveform data. This can be done by either of the following procedures:
  64.  
  65.     1).    Determine the maximum # of waves that the application can load, and
  66.             declare an array of this many SampleHeader64 structures.
  67.             (The C example takes this approach).
  68.  
  69.     2).    After opening a file (via OpenSampRead) and examining the MHDR's
  70.             NumOfWaves, allocate a block of mem with size = sizeofSampleHeader64
  71.             * NumOfWaves.
  72.  
  73.     The string buffers for the waves' names must also be contiguous in memory.
  74. For this reason, your application must decide upon the maximum length of each
  75. name, and allocate an appropriately sized mem block. On the other hand, you
  76. may forego allocating any string buffers, in which case the library will ignore
  77. loading the waves' names.
  78.  
  79.     Finally, a pointer to a TransposeNode must be declared (and initially set
  80. to zero).  A TransposeNode is a structure that the library will create for
  81. every different sampleRate in a SAMP file. These structures are all linked
  82. into a list to which your variable points. A TransposeNode contains a transpose
  83. table as described in the SAMP doc.
  84.  
  85.     Note that these structures are not part of the SAMP spec itself. They simply
  86. facilitate the playback of SAMP files with minimal processing delays.
  87.  
  88.  
  89.             «««««««««««««««««« LIBRARY STRUCTURES »»»»»»»»»»»»»»»»
  90.  
  91.     When you open a SAMP file to read or write, you gain exclusive access to
  92. the samp.library's structures until you close the file. One structure is a
  93. SAMPInfo structure. This contains an imbedded MHDR chunk. When you open a
  94. SAMP for reading via OpenSampRead(), the SAMP's MHDR is loaded into the library
  95. SAMPInfo's MHDR.  So, you can examine the file's NumOfWaves, NumOfChans,
  96. Format, etc before loading any wave data. The SAMPInfo also contains fields to
  97. store pointers to (addresses of) functions within your application. These
  98. functions will be called at certain times by the library's read/write routines.
  99. For example, you can supply a pointer to a function which will be called by
  100. the library's ReadWaves() for every wave's FATK data handling. The SAMPInfo
  101. also contains fields to specify the maximum allowed length of a wave's name,
  102. the type of mem into which the wave data will be loaded, and Seek() offsets
  103. from the beginning of the file to various chunks.
  104.  
  105.     The library also has a waveHeader structure as described in the SAMP doc.
  106. This structure is used by ReadWaves() and WriteWaves() to hold data per each
  107. wave read/written.
  108.  
  109.  
  110.         «««««««««««««««««««« OPENING THE LIBRARY »»»»»»»»»»»»»»»»»»»
  111.  
  112.     The samp.library file must be copied to the libs drawer of your boot disk.
  113.  
  114. Then, any application may open and use the library via a call to Exec's
  115. OpenLibrary(). The current version of samp is 0. The library is closed via
  116. Exec's CloseLibrary().  C applications must be linked with the module
  117.  
  118.                             SAMPInterface.asm
  119.  
  120. (which itself must be assembled by your C compiler's assembler).
  121.  
  122.  
  123.         ««««««««««««««««««««« THE LIBRARY FUNCTIONS »»»»»»»»»»»»»»»»»»
  124.  
  125.     Here are descriptions and calling procedures for the library functions:
  126.  
  127.  
  128. *************************** OpenSampRead *****************************
  129.  
  130.     This routine must be called first in order to read in a SAMP file and
  131.  perform operations on it via other library routines such as LoadNames,
  132.  LoadPlaymap, MixPlaymap, and ReadWaves. It opens the file, determines
  133.  if it is a SAMP file that the library can read, and prevents other tasks
  134.  from using the library until the file is processed and closed.
  135.  
  136.     This is passed the name of the SAMP file to be opened (a NULL-terminated
  137.  string). Also, you may pass a pointer to a function which the library should
  138.  call for unknown chunks, or instead pass in 0. The library understands
  139.  "BODY", "AUTH", "ANNO", "NAME", "MHDR" and "(c) " chunks. If you pass a 0,
  140.  it will ignore all other chunks. If you pass a pointer to your own function,
  141.  it will call your function as so:
  142.  
  143.  flag = UnknownChunk( ID, ChunkSize, SeekOffset, SAMPInfo );
  144.                             d0            d2            d4                a4
  145.  
  146.  ID                ULONG, IFF-type ID ( eg, 'XYZ0' ).
  147.  ChunkSize        ULONG, Size of this chunk.
  148.  SeekOffset        ULONG, Offset from start of the file.
  149.  SAMPInfo        Pointer to library's SAMPInfo structure.
  150.  
  151.  flag                ULONG, return value.
  152.  
  153.  If you return a 1, then the OpenSampRead terminates and closes the file.
  154.  A 0 allows OpenSampRead to continue.
  155.  For more details, see the section "PROCESSING UNKNOWN CHUNKS".
  156.  
  157.  OpenSampRead() returns the address of the library's SAMPInfo structure
  158.  or 0 if an error. The z-flag is cleared for error (bne Error), set otherwise.
  159.  An error may be caused by some other task already using the library, failure
  160.  to open the requested file, the requested file is not a SAMP file, or the BODY
  161.  for this SAMP file cannot be located within this file (i.e. will not support
  162.  Continuation files). For C programmers, the exact error number is returned
  163.  in a variable called SAMPError (which is a global in the module
  164.  SampInterface.asm). For assembly programmers, the exact error number is
  165.  returned in d1.
  166.  
  167.     SAMPInfo = OpenSampRead( Filename, UnKnownVector );
  168.         d0                                d1                    a0
  169.  
  170.  Filename          Pointer to UBYTE, DOS name of the desired SAMP file.
  171.  UnKnownVector  Pointer to a function ( APTR ) ( use 0 to skip unknown chunks ).
  172.  
  173.  SAMPInfo         Pointer to a SAMPInfo structure.
  174.  
  175. ***************************** CloseSamp *******************************
  176.  
  177.     Closes a SAMP file that was opened for reading or writing, and frees the
  178. library for other tasks to use. This must be called after you have successfully
  179. opened a SAMP file (via OpenSampRead or OpenSampWrite), and are finished
  180. processing it.
  181.  
  182.     CloseSamp();
  183.  
  184.  
  185. ***************************** ReadWaves *********************************
  186.  
  187. #define nameSize 20  /* just for an example */
  188.  
  189.  total = ReadWaves( offsetWave, totalWaves, nameBuffer[offsetWave][nameSize], SampleHeader64[offsetWave] );
  190.     d0                            d6                d7                    a2                                        a3
  191.  
  192.  offsetWave            ULONG, first wave to start loading.
  193.  totalWaves          ULONG, number of waves to load in.
  194.  &nameBuffer[][]    Address of UBYTE buffer array which will hold wave names.
  195.  &SampHead64[]        Address of SampleHeader64 structures array, which will
  196.                          hold the individual waves data.
  197.  
  198.  total                ULONG, total number of waves actually read in.
  199.  
  200.      Loads the specified range of waves within the SAMP file between offsetWave
  201.  and offsetWave+totalWaves. offsetWave is the first wave to start loading
  202.  (with the first wave in the SAMP file being wave #0). Loads them starting at
  203.  the passed SampleHeader64. Also loads the names for these waves starting at
  204.  nameBuffer unless passed a NULL. Before calling ReadWaves, you should
  205.  set the library SAMPInfo's MaxChars variable to the max # of chars each
  206.  nameBuffer can hold. The default is 20 bytes. All names are padded out with
  207.  spaces and NULL-terminated.
  208.  
  209.      Also, you should set the SAMPInfo's ATAKvector, RLSEvector, FATKvector,
  210.  FRLSvector, USERvector, and EXTRAvector to point to any routines you want the
  211.  library to call per wave. If you don't, the default is for the library to
  212.  ignore FATK, FRLS, and USER data, and to read/reformat ATAK and RLSE EGPoints
  213.  into the SampleHeader64's envelope fields.
  214.  
  215.  offsetWave is specified from zero (i.e. a value of zero won't skip any waves
  216.  in the file. A 2 will skip the first 2 waves in the file and start loading the
  217.  3rd wave into SampleHeader1.) For totalWaves = 1, only 1 wave is loaded.
  218.  
  219.      This returns the number of waves actually loaded (0 if none). Sets
  220.  z-flag for success, cleared for error. For C programmers, the exact error
  221.  number is returned in a variable called SAMPError. For assembly programmers,
  222.  the exact error number is returned in d1.
  223.  
  224.     Each wave's SampleHeader64 structure has an TransTable field. ReadWaves()
  225.  places each wave's sampleRate in this field. Later, you can extract the value
  226.  from this field when making the transpose tables, and rewrite the field with
  227.  a pointer to the ORIGINAL pitch of the table. See the C example.
  228.  
  229.     The library calls your ATAK, RLSE, FATK, FRLS, or USER vector only if a
  230.  wave has data. In other words, if a wave doesn't have any FRLS EGPoints,
  231.  then the library skips calling your FRLS vector when loading that wave.
  232.  The library calls your EXTRA vector AFTER each wave's 80 byte waveHeader
  233.  and BEFORE the sample data is read in. This vector is useful for getting the
  234.  library waveHeader's midiSampNum, loopType, and instrumType if you wish to
  235.  use/store this data somewhere. See the section "CONVERTING WAVE DATA".
  236.     Your vectors are passed the lib's SAMPInfo and waveHeader, the current
  237.  SampleHeader64 address (a pointer to a SampleHeader64), and waveNumber
  238.  (minus offsetWave).
  239.     They should return an abort flag (1 = Abort read, 0 = continue). For
  240.  example, the library calls your FATK routine as so:
  241.  
  242.  flag = FATKroutine( waveNumber, SampleHeader, SAMPInfo, waveHeader );
  243.     d0                            d5                a3                a4                a5
  244.  
  245.  waveNumber            ULONG, wave of interest.
  246.  SampleHeader         Pointer to library's SampleHeader64 structure.
  247.  SAMPInfo            Pointer to library's SAMPInfo structure.
  248.  waveHeader            Pointer to library's waveHeader structure.
  249.  
  250.  flag                    ULONG, return value.
  251.  
  252.     When reading a SAMP, you should either read or seek past any data from
  253.  within an ATAK, RLSE, FATK, FRLS, or USER vector. When the library calls your
  254.  ATAK, RLSE, FATK, FRLS, or USER vector, the DOS file position will be at the
  255.  expected data within the SAMP file. In other words, when the library calls
  256.  your FATK vector, the file position will be at the wave's FATK data (if there
  257.  is any). When the library calls your USER vector, the file position will be
  258.  at the wave's USER data (if any). You can find your precise position and the 
  259.  type of USER data via the waveHeader structure. Your vector must either read 
  260.  exactly this many  bytes of data, or Seek() forward this many bytes from the
  261.  current position. In other words, when your vector returns, the new file
  262.  position must be at the next byte AFTER the expected data. If you Seek()
  263.  somewhere else in the file, always Seek() back to the point after the
  264.  expected data (before your vector returns).
  265.  
  266.     By default, the library loads the sample data into MEMF_CHIP, but you can
  267.  change this before calling ReadWaves() by storing the desired AllocMem()
  268.  attributes in the lib's SAMPinfo MemType field.
  269.  
  270.  
  271. *************************** LoadPlayMap ********************************
  272.     Checks each byte of the loaded PlayMap. For every wave number above or below
  273.  the wave range (offsetWave+1 to offsetWave+totalWaves) in the loaded PlayMap,
  274.  the application's destination PlayMap byte is left as is. Otherwise, the wave
  275.  number is set to
  276.  
  277.     (SAMPInfo's NumOfWaves - offsetWave) + startWave
  278.  
  279.  where startWave is the number of the SampleHeader where the first wave
  280.  was loaded in. (startWave and offsetWave both referenced from wave #0)
  281.  numOfChans is the # of channels for each midi note in the destination playMap.
  282.  LoadPlaymap simply zeros out the destination playMap first (i.e. sets all
  283.  bytes to NO WAVE) before loading the new playMap.  The difference is that
  284.  for every byte that is not = NO WAVE in the loaded playmap, MixPlayMap 
  285.  overwrites the respective destination playmap byte.  This is useful for
  286.  combining several SAMP files into one by loading each file into different
  287.  SampleHeader64 structures, and "mixing" each loaded playmap.  LoadPlaymap
  288.  makes the destination playmap an exact copy of the loaded playmap. This is
  289.  useful for an application that loads only one samp file.
  290.      If totalWaves = 0, LoadPlaymap just zeros out the playMap and MixPlaymap
  291.  does nothing. In this case, offsetWave and startWave are ignored. In this
  292.  context LoadPlaymap can be used to initialize ("empty") a playmap.
  293.  
  294.  
  295.  MixPlayMap( totalWaves, numOfChans, offsetWave, startWave, destPlayMap);
  296.                     d0                d1                d6                d7                a0
  297.  
  298.  totalWaves            ULONG, total number of waves read in.
  299.  numOfChans            ULONG, number of play channels.
  300.  offsetWave            ULONG, wave offset position.
  301.  startWave            ULONG, number of first wave read in.
  302.  destPlayMap        Pointer to UBYTE array, a playMap.
  303.  
  304. *************************** MakeTransTable ***************************
  305.     Makes a TransposeNode for the passed sample period. The transpose table
  306.  will have the specified # of steps above and below the ORIGINAL_PITCH as
  307.  described by the upperRange and lowerRange values. This routine will
  308.  allocate and link the TransposeNode into the passed TList only if there
  309.  is not already a table for this sampleRate. Otherwise, returns ORIGPITCH
  310.  of the other table in order to avoid duplication. Returns a zero if not
  311.  enough mem to create a new table, or the passed sampleRate = 0.
  312.  TList holds the address of (is a handle to) the first TransposeNode.
  313.  
  314.     If using the Amiga hardware, you may set the library's SAMPInfo's LowLimit
  315.  and HighLimit fields before calling this. Defaults are 500 and 127 respec-
  316.  tively. These are the limits between which the period values must range within
  317.  the Transpose table. If a period is outside these limits, then the Transpose
  318.  table entry is set to zero to indicate that the period is out of range. When
  319.  playing back the wave, it is then easy to determine if a certain transposition
  320.  of a wave's sample Rate results in a period out of range. The default limits
  321.  are set for normal DMA audio and should not be altered unless your program
  322.  does non-DMA audio output.
  323.  
  324.     Note that this function only supports a Transpose table of +12 to -12 steps
  325.  from the root. All further steps will result in TransposeTable entries of 0.
  326.  
  327.  ORIGPITCHaddr = MakeTransTable( samplePeriod, upperRange, lowerRange, &TList );
  328.         d0                                        d5                d6                d7            a2
  329.  
  330.  
  331.  samplePeriod        ULONG, sample period in nSec.
  332.  upperRange            ULONG, number of entries above original pitch.
  333.  lowerRange            ULONG, number of entries below original pitch.
  334.  &TList                Pointer to a pointer to a TransposeNode ( a handle ).
  335.  
  336.  ORIGPITCH            Pointer to a ULONG, this is the middle of a ULONG array.
  337.                          The array extends outward from this address by the upperRange
  338.                          and lowerRange values.
  339.  
  340.     If you are not using the Amiga's audio hardware, you will probably want to
  341.  calculate the periods differently than MakeTransTable. This function figures
  342.  in the Amiga fudge factor (.279365), a hardware limitation. Hopefully, your
  343.  hardware will be MUCH nicer than the primitive Amiga audio system, and so a
  344.  second function is provided:
  345.  
  346.  ORIGPITCHaddr = CusMakeTransTable( sampleRate, upperRange, lowerRange, Vector, &TList );
  347.         d0                                            d5                d6                d7             a1         a2
  348.  
  349.     This routine has an extra parameter; a pointer to a vector which will be
  350. called for each "step" of the transpose table, starting with the lowest step.
  351. This routine is passed the sample period in nanoseconds and the step offset
  352. from the original pitch address of the table. It should return the new trans-
  353. pose table entry for that step.
  354.  
  355.  
  356.     entry = Vector( period, stepOffset );
  357.  
  358.  For example, if you asked for 6 steps lowerRange with sampleRate = 18000, the
  359. first call to your vector is passed period = 55556 and step = -6*2 (Multiplied
  360. by 2 because each entry in transpose table is a USHORT).  If you were making
  361. a transpose table for a western tempered scale, you could calculate
  362.  
  363.     period/.707106781
  364.  
  365. for the new period in nanoseconds. (.707106781 because we are transposing down
  366. 6 steps. See SAMP doc.)  Actually, since the transpose table expects back a
  367. USHORT, you might choose to return the period in MICROSECONDS. Excepting a
  368. little round-off error, we can use integer division:
  369.  
  370.     period/707  (in microseconds)
  371.  
  372. This assumes that your hardware wants the period in microseconds (like the
  373. Amiga hardware). You should return a zero for a period that is out of range.
  374. In this way, your player program can understand that a TransposeTable entry
  375. of 0 means that the hardware cannot play the wave back at the required speed.
  376.  
  377. With your own vector, there is no limit to the number of steps above or below
  378. the root note. That will be determined by your application and hardware.
  379.  
  380.  
  381. **************************** RemoveTTable() ***************************
  382.  Removes the TransposeNode (and its Table) for the passed sampleHeader64
  383.  structure from the passed TList if there are no other waves using the Table.
  384.  If the passed ptr to ORIGINAL_PITCH is NULL, this function does nothing.
  385.  
  386.  RemoveTable( sampleHeader64, TList );
  387.                         a0                a1
  388.  
  389.  sampleHeader64    Pointer to a sampleHeader64 structure.
  390.  TList                Pointer to a pointer to a TransposeNode ( a handle ).
  391.  
  392. NOTE: Because we only have a pointer to the ORIGINAL_PITCH in our sample-
  393. Header64 structure and the TransposeTable can be any size (i.e. we don't 
  394. really know the address of the TransposeNode), we need to locate the prepended
  395. TransposeNode by inspection. We do this by searching the TList until we find
  396. a Node whose tn_Orig field matches our sampleHeader64's ORIGINAL_PITCH. Then
  397. we know we have the right Node. Before we deAlloc, we need to check if any
  398. other waves are also using this table (one table can be used for many waves)
  399. by checking the tn_Hosts field.  This field counts how many waves have been
  400. given this table from MakeTransTable().
  401.  
  402.  
  403. **************************** FreeTTables() *****************************
  404.  Frees all of the TransposeTables in the passed TList. TList is a handle to
  405.  the first TransposeNode in the list.
  406.  
  407.  FreeTTables( TList );
  408.                     a1
  409.  
  410.  TList                Pointer to a pointer to a TransposeNode ( a handle ).
  411.  
  412. ;*************************** FindTNode() *******************************
  413.  Finds the TransposeNode address given the ptr to the TransposeTable list
  414.  and the ORIGINAL_PITCH address of the table whose node address you want.
  415.  Returns zero if no matching Node found. (Z-flag set accordingly)
  416.  If passed an ORIGINAL_PITCH address of NULL, this function returns 0.
  417.  
  418.  TransposeNode = FindTNode( ORIGPITCHaddr, TList );
  419.         d0                                d0                    a1
  420.  
  421.  TList                Pointer to a pointer to a TransposeNode ( a handle ).
  422.  
  423. ***************************** OpenSampWrite ***************************
  424.  Opens the SAMP filename for writing. Must be called before using WriteMHDR,
  425.  WriteName, WriteChunk, or WriteWaves. Returns the address of the library's
  426.  SAMPInfo if success, or a zero if the file couldn't be created. Upon
  427.  successful return, application should set SAMPInfo's Format, PlayMode,
  428.  NumWaves, and NumOfChans. The defaults for these are 8 bit, INDEPENDENT,
  429.  0 waves, and 4 channels. z-flag cleared for error.
  430.  
  431.  SAMPInfo = OpenSampWrite( fileName );
  432.     d0                                    d1
  433.  
  434.  fileName            Pointer to UBYTE, DOS filename.
  435.  
  436.  SAMPInfo            Pointer to a SAMPInfo structure.
  437.  
  438.  
  439. ******************************* WriteMHDR ******************************
  440.  Writes out the SAMP and MHDR with SAMP header fileSize = 14+sizeOfPlayMap.
  441.  Adjusts your PlayMap bytes so that all wave numbers < startWave and > =
  442.  startWave+numWaves are set to 0. startWave is from 0 being the first wave.
  443.  Returns a 1 if success, 0 if an error.
  444.  
  445.  result = WriteMHDR( startWave, playMap );
  446.  d0                        d0                a0
  447.  
  448.  startWave        ULONG, wave number at which to start.
  449.  playMap            Pointer to a UBYTE array, a playMap.
  450.  
  451.  result            BOOL, success / failure code.
  452.  
  453.  You can save a file without playMaps by setting the NumOfChans field in the
  454.  SAMPInfo structure to 0, and then passing in 0 for the playMap address.
  455.  ( ie, the SAMPInfo you got from OpenSampWrite() )
  456.  
  457. ******************************* WriteSampChunk ***************************
  458.  Writes out the passed ID, size (of data, not including header), and data.
  459.  Returns a 1 if success, 0 if an error.
  460.  
  461.  result = WriteSampChunk( ID, size, data );
  462.     d0                          d0     d1        a0
  463.  
  464.  ID                 ULONG, a standard IFF-type ID ( ie, like 'ILBM' - but don't
  465.                                  use this one :-) 
  466.  size                ULONG, number of bytes.
  467.  data                Pointer to UBYTE of data to be saved.
  468.  
  469.  result            BOOL, success / failure code.
  470.  
  471.  
  472. ****************************** WriteSampData ******************************
  473.  Writes out the data for the passed number of bytes and the passed data ptr.
  474.  This is commonly used by vector routines writing out FATK, FRLS, and USER
  475.  data when saving a wave. Returns a 1 if success, 0 if an error.
  476.  
  477.  result = WriteSampData( numOfBytes, dataPtr );
  478.     d0                                d3            a0
  479.  
  480.  numOfBytes        ULONG, number of bytes.
  481.  dataPtr            Pointer to UBYTE of data to be saved.
  482.  
  483.  result            BOOL, success / failure code.
  484.  
  485. ****************************** WriteNames ********************************
  486.  Writes the NAME chunk. Uses SAMPInfo's NumWaves to determine how many wave
  487.  names to write. Passed the base of the first string buffer. Passed the size
  488.  of a string buffer. Ignores trailing spaces on each name.
  489.  Returns a 1 if success, 0 if an error.
  490.  
  491.  result = WriteNames( bufsize, bufPtr );
  492.     d0                        d0            a0
  493.  
  494.  bufsize            ULONG, number of bytes.
  495.  bufPtr            Pointer to UBYTE of data to be saved.
  496.  
  497.  result            BOOL, success / failure code.
  498.  
  499. ******************************* WriteWaves *****************************
  500.  
  501.  result = WriteWaves( offsetWave, totalWaves, SampleHeader64[0], TList )
  502.  d0                        d0                    d1                a0                    a1
  503.  
  504.  offsetWave                ULONG, offset number.
  505.  totalWaves                ULONG, total number of waves to write.
  506.  &SampleHeader64[]     Pointer to a SampleHeader64 array.
  507.  &TList                    Pointer to a pointer to a TransposeNode.
  508.  
  509.  result                    BOOL, success / failure code.
  510.  
  511.      Writes the specified range of waves between offsetWave and offsetWave +
  512.  totalWaves to the SAMP file. offsetWave is the first wave to start saving
  513.  (with the first SampleHeader64 being wave #0).
  514.  
  515.     offsetWave is specified from zero (i.e. a value of zero won't skip any
  516.  SampleHeader64 structs. A 2 will skip the first 2 SampleHeader64s and start
  517.  saving the 3rd SampleHeader64 as wave #0.) For totalWaves = 1, only 1 wave
  518.  is saved.
  519.  
  520.     totalWaves is the number of waves to save. If totalWaves = 0, it returns 1
  521.  and writes an "empty" BODY chunk.
  522.  
  523.     TList holds the address of the first TransposeNode. (a C handle)
  524.  
  525.     As a side note, if you are not using Transpose Tables you may pass 0
  526. for the TList handle, BUT in order to do this, you MUST also set the
  527. TransTable field of the passed SampleHeader64 structure(s) to 0.
  528.  
  529.      Before calling WriteWaves(), you should set the SAMPInfo's ATAKvector,
  530.  RLSEvector, FATKvector, FRLSvector, USERvector, and EXTRAvector to point to
  531.  any routines you want the library to call per wave. If you don't, the default
  532.  is for the library to write no FATK, FRLS, and USER data, and to write ATAK
  533.  and RLSE EGPoints based upon the SampleHeader64's envelope fields.
  534.  
  535.  WriteWaves() calls your EXTRAvector BEFORE the each wave's 80 byte waveHeader
  536.  and data is written out. This vector is useful for setting the library
  537.  waveHeader's SampNum, LoopType, and InsType per wave.
  538.  
  539.  Calls ATAK, RLSE, FATK, FRLS vectors to write out Amplifier/Filter EGPoints,
  540.  and USERvector to write User Data.
  541.  
  542.  The vectors are passed the lib's SAMPInfo and waveHeader, and the current
  543.  SampleHeader. The vectors should return an abort flag (1 = Abort write, 0 =
  544.  continue). For example, the library calls your FATK routine as so:
  545.  
  546.  flag = FATKroutine( SampleHeader, SAMPinfo, waveHeader );
  547.     d0                            a3                a4                a5
  548.  
  549.  SampleHeader        Pointer to a SampleHeader64 structure ( about to be saved ). 
  550.  SAMPInfo            Pointer to a SAMPInfo structure ( about to be saved ).
  551.  waveHeader            Pointer to a waveHeader structure ( about to be saved ).
  552.  
  553.  flag                    ULONG, success / failure code.
  554.  
  555.     You must set the waveHeader's size fields to the number of bytes in the
  556.  data written out. For example, if your USER vector writes out 40 bytes of
  557.  data, set the waveHeader's USERsize to 40. (You should also set the
  558.  USERtype).
  559.  
  560.  NOTE: In order to write out a SAMP file without a playMap, simply set 
  561.  NumOfChans in the MHDR chunk to zero ( see WriteMHDR() ). You may then pass
  562.  WriteWaves 0's for the TList and SampleHeader64. It is imperative that you
  563.  set all required fields in the waveHeader structure ( via the EXTRAVector )!
  564.  This includes WaveSize, Period, Rate, and the three Loop fields.
  565.  
  566.  
  567. ************************** SAMPErrorMsg ****************************
  568.  
  569.  When passed the error number (as returned by OpenSampRead for example),
  570.  this returns the address of a NULL-terminated string describing the error.
  571.  This is suitable for informing the user of any possible errors. For asm
  572.  programmer's certain lib routines return a error number in d1. For C pro-
  573.  grammer's, the error is stored in a variable called SAMPError.
  574.  
  575.  string = SAMPErrorMsg( SAMPError );
  576.     d0                                d1
  577.  
  578.  SAMPError        ULONG, internal error code.
  579.  
  580.  string            Pointer to UBYTE, a corresponding error code message.
  581.  
  582.  
  583.             «««««««««««««« PROCESSING UNKNOWN CHUNKS »»»»»»»»»»»»
  584.  
  585.     When your UnknownChunk vector is called by OpenSampRead, it passes a
  586. SeekOffset. This value is the number of bytes from the beginning of the file
  587. to this chunk's ID, and can be used by your application to Seek() to this chunk
  588. later. Your vector should store the chunk ID and SeekOffset for later process-
  589. ing after OpenSampRead returns. Do not do any Seek() or Read() from within
  590. this vector!!!  Always wait until you return from OpenSampRead() before you
  591. access the chunk. The idea is to Seek() from the beginning of file to the
  592. chunk and process it, perhaps before or after you ReadWaves(), ReadNames(),
  593. LoadPlaymap(), MixPlaymap(), and certainly before you CloseSamp(). The DOS
  594. fileHandle can be found in the library SAMPInfo's Handle field.
  595.     Note that the ChunkSize passed to your vector does not count the standard, 8
  596. byte IFF chunkID and chunkSize fields with which all IFF chunks must start.
  597.  
  598.  
  599.             «««««««««««««« READING AUTH, ANNO, etc. CHUNKS »»»»»»»»»»»»
  600.  
  601.  In order to grab the data held in the other known chunks ( AUTH, ANNO, (C) ),
  602. you may obtain the FileHandle for the file via the SAMPInfo structure before
  603. calling CloseSamp(). Seek values for each of the known chunks are also found
  604. in this structure. The general idea is to Seek() to the beginning of the
  605. file, and then Seek() to the desired segment. This will place you at the
  606. start of the chunk, and you may then determine the chunk size by reading the
  607. first 8 bytes (the 2nd ULONG is the chunk size). After reading this, you may
  608. read the actual chunk data, and do with it as you will. 
  609.