home *** CD-ROM | disk | FTP | other *** search
- This is the document for the dissidents' samp.library 1.0 © 1989. Set your
- editor's TAB width to 3.
-
-
- «««««««««««««« WHAT THE HELL IS SAMP? »»»»»»»»»»»»
- (or "If it doesn't have anything to do with video, what good is it?")
-
- The dissidents' samp.library is a library used to load and save SAMP files.
- SAMP is an IFF file format used to store any resolution audio data. This format
- is used in dissidents' Midi Sample Wrench, a 16 bit audio waveform editing
- program for the Amiga, and is currently under consideration for adoption by
- CATS. The samp.library will allow you to write applications that can save
- and retrieve audio data saved in the SAMP format. For a detailed spec of the
- SAMP format, consult the SAMP.doc file.
- The samp.library is written entirely in 68000 assembly for speed and small
- size. Distributed with the library are C and assembly Include files and example
- applications, as well as a utility to convert 8SVX files to SAMP.
-
-
- ««««««««««««««««« COPYRIGHT NOTICE »»»»»»»»»»»»»»»»»»
-
- The samp.library and ToSAMP conversion utility are copyright by dissidents
- software. These two files may be used by and freely distributed with any
- application, commercial or otherwise, although copyright is retained exclu-
- sively by dissidents, and the files must not be modified in any way. In
- addition, the following files are copyright by dissidents, and may only be
- distributed on disks which are freely-distributable or for which a nominal
- charge to cover media and shipping is the only consumer cost:
-
- 1). SAMPlib.doc
- 2). SAMP.doc
- 3). ToSAMP.asm
- 4). Exam.c
- 5). Exam.asm
- 6). SAMP.i
- 7). SAMP.h
- 8). SAMPInterface.asm
-
- All copyright notices must remain intact.
-
-
- «««««««««««««««« CURRENT LIMITATIONS »»»»»»»»»»»»»»»»
-
- The library does not support loading/saving SAMP files inside of a CAT or
- LIST, nor does it currently support Continuation files or NumOfChans > 4.
- Due to memory considerations, the library can only be servicing one task
- at any given moment (though several tasks may simultaneously open the library).
-
-
- ««««««««««««««««« DATA STRUCTURES »»»»»»»»»»»»»»»»»
-
- Before you open and use the samp.library, you must create a few structures
- and variables from which the library can load/save data. The most important
- structure is is the SampleHeader64 structure. It is used to hold information
- about 1 waveform such as its size, OneShotStart and LoopStart addresses, Root
- Note, and velocity table. Each waveform that is loaded must have its own 64
- byte SampleHeader64 structure. Furthermore, all the SampleHeader64 structures
- must be contiguous in memory. For this reason, an application should allocate
- the proper number of SampleHeader64 structures before actually loading the
- waveform data. This can be done by either of the following procedures:
-
- 1). Determine the maximum # of waves that the application can load, and
- declare an array of this many SampleHeader64 structures.
- (The C example takes this approach).
-
- 2). After opening a file (via OpenSampRead) and examining the MHDR's
- NumOfWaves, allocate a block of mem with size = sizeofSampleHeader64
- * NumOfWaves.
-
- The string buffers for the waves' names must also be contiguous in memory.
- For this reason, your application must decide upon the maximum length of each
- name, and allocate an appropriately sized mem block. On the other hand, you
- may forego allocating any string buffers, in which case the library will ignore
- loading the waves' names.
-
- Finally, a pointer to a TransposeNode must be declared (and initially set
- to zero). A TransposeNode is a structure that the library will create for
- every different sampleRate in a SAMP file. These structures are all linked
- into a list to which your variable points. A TransposeNode contains a transpose
- table as described in the SAMP doc.
-
-
- «««««««««««««««««« LIBRARY STRUCTURES »»»»»»»»»»»»»»»»
-
- When you open a SAMP file to read or write, you gain exclusive access to
- the samp.library's structures until you close the file. One structure is a
- SAMPInfo structure. This contains an imbedded MHDR chunk. When you open a
- SAMP for reading via OpenSampRead(), the SAMP's MHDR is loaded into the library
- SAMPInfo's MHDR. So, you can examine the file's NumOfWaves, NumOfChans,
- Format, etc before loading any wave data. The SAMPInfo also contains fields to
- store pointers to (addresses of) functions within your application. These
- functions will be called at certain times by the library's read/write routines.
- For example, you can supply a pointer to a function which will be called by
- the library's ReadWaves() for every wave's FATK data handling. The SAMPInfo
- also contains fields to specify the maximum allowed length of a wave's name,
- the type of mem into which the wave data will be loaded, and Seek() offsets
- from the beginning of the file to various chunks.
-
- The library also has a waveHeader structure as described in the SAMP doc.
- This structure is used by ReadWaves() and WriteWaves() to hold data per each
- wave read/written.
-
-
- «««««««««««««««««««« OPENING THE LIBRARY »»»»»»»»»»»»»»»»»»»
-
- The samp.library file must be copied to the libs drawer of your boot disk.
-
- Then, any application may open and use the library via a call to Exec's
- OpenLibrary(). The current version of samp is 0. The library is closed via
- Exec's CloseLibrary(). C applications must be linked with the module
-
- SAMPInterface.asm
-
- (which itself must be assembled by your C compiler's assembler).
-
-
- ««««««««««««««««««««« THE LIBRARY FUNCTIONS »»»»»»»»»»»»»»»»»»
-
- Here are descriptions and calling procedures for the library functions:
-
-
- *************************** OpenSampRead *****************************
-
- This routine must be called first in order to read in a SAMP file and
- perform operations on it via other library routines such as LoadNames,
- LoadPlaymap, MixPlaymap, and ReadWaves. It opens the file, determines
- if it is a SAMP file that the library can read, and prevents other tasks
- from using the library until the file is processed and closed.
-
- This is passed the name of the SAMP file to be opened (a NULL-terminated
- string). Also, you may pass a pointer to a function which the library should
- call for unknown chunks, or instead pass in 0. The library understands
- "BODY", "AUTH", "ANNO", "NAME", "MHDR" and "(c) " chunks. If you pass a 0,
- it will ignore all other chunks. If you pass a pointer to your own function,
- it will call your function as so:
-
- flag = UnknownChunk(SAMPInfo, SeekOffset, ChunkSize ID);
- a4 d4 d2 d0
-
- If you return a 1, then the OpenSampRead terminates and closes the file.
- A 0 allows OpenSampRead to continue.
- For more details, see the section "PROCESSING UNKNOWN CHUNKS".
-
- OpenSampRead() returns the address of the library's SAMPInfo structure
- or 0 if an error. The z-flag is cleared for error (bne Error), set otherwise.
- An error may be caused by some other task already using the library, failure
- to open the requested file, the requested file is not a SAMP file, or the BODY
- for this SAMP file cannot be located within this file (i.e. will not support
- Continuation files). For C programmers, the exact error number is returned
- in a variable called SAMPError (which is a global in the module
- SampInterface.asm). For assembly programmers, the exact error number is
- returned in d1.
-
- SAMPInfo = OpenSampRead( Filename, UnKnownVector );
- d0 d1 a0
-
-
- ***************************** CloseSamp *******************************
-
- Closes a SAMP file that was opened for reading or writing, and frees the
- library for other tasks to use. This must be called after you have successfully
- opened a SAMP file (via OpenSampRead or OpenSampWrite), and are finished
- processing it.
-
- CloseSamp();
-
-
- ***************************** ReadWaves *********************************
-
- #define nameSize 20
-
- total = ReadWaves(offsetWave,totalWaves,nameBuffer[offsetWave][nameSize],SampleHeader64[offsetWave]);
- d0 d6 d7 a2 a3
-
- Loads the specified range of waves within the SAMP file between offsetWave
- and offsetWave+totalWaves. offsetWave is the first wave to start loading
- (with the first wave in the SAMP file being wave #0). Loads them starting at
- the passed SampleHeader64. Also loads the names for these waves starting at
- nameBuffer unless passed a NULL. Before calling ReadWaves, you should
- set the library SAMPInfo's MaxChars variable to the max # of chars each
- nameBuffer can hold. The default is 20 bytes. All names are padded out with
- spaces and NULL-terminated.
-
- Also, you should set the SAMPInfo's ATAKvector, RLSEvector, FATKvector,
- FRLSvector, USERvector, and EXTRAvector to point to any routines you want the
- library to call per wave. If you don't, the default is for the library to
- ignore FATK, FRLS, and USER data, and to read/reformat ATAK and RLSE EGPoints
- into the SampleHeader64's envelope fields.
-
- offsetWave is specified from zero (i.e. a value of zero won't skip any waves
- in the file. A 2 will skip the first 2 waves in the file and start loading the
- 3rd wave into SampleHeader1.) For totalWaves = 1, only 1 wave is loaded.
-
- This returns the number of waves actually loaded (0 if none). Sets
- z-flag for success, cleared for error. For C programmers, the exact error
- number is returned in a variable called SAMPError. For assembly programmers,
- the exact error number is returned in d1.
-
- Each wave's SampleHeader64 structure has an TransTable field. ReadWaves()
- places each wave's sampleRate in this field. Later, you can extract the value
- from this field when making the transpose tables, and rewrite the field with
- a pointer to the ORIGINAL pitch of the table. See the C example.
-
- The library calls your ATAK, RLSE, FATK, FRLS, or USER vector only if a
- wave has data. In other words, if a wave doesn't have any FRLS EGPoints,
- then the library skips calling your FRLS vector when loading that wave.
- The library calls your EXTRA vector AFTER each wave's 80 byte waveHeader
- and sample data are read in. This vector is useful for getting the library
- waveHeader's midiSampNum, loopType, and instrumType if you wish to use/store
- this data.
- Your vectors are passed the lib's SAMPInfo and waveHeader, the current
- SampleHeader64 address (a pointer to a SampleHeader64), and waveNumber
- (minus offsetWave).
- They should return an abort flag (1 = Abort read, 0 = continue). For
- example, the library calls your FATK routine as so:
-
- flag = FATKroutine(waveHeader, SAMPInfo, SampleHeader, waveNumber);
- d0 a5 a4 a3 d5
-
- When reading a SAMP, you should either read or seek past any data from
- within an ATAK, RLSE, FATK, FRLS, or USER vector. When the library calls your
- ATAK, RLSE, FATK, FRLS, or USER vector, the DOS file position will be at the
- expected data within the SAMP file. In other words, when the library calls
- your FATK vector, the file position will be at the wave's FATK data (if there
- is any). When the library calls your USER vector, the file position will be
- at the wave's USER data (if any). The library passes your vector the size of
- the data (in bytes). Your vector must either read exactly this many bytes of
- data, or Seek() forward this many bytes from the current position. In other
- words, when your vector returns, the new file position must be at the next
- byte AFTER the expected data. If you Seek() somewhere else in the file, always
- Seek() back to the point after the expected data before your vector returns.
-
-
- *************************** LoadPlayMap ********************************
- Checks each byte of the loaded PlayMap. For every wave number above or below
- the wave range (offsetWave+1 to offsetWave+totalWaves) in the loaded PlayMap,
- the application's destination PlayMap byte is left as is. Otherwise, the wave
- number is set to
-
- (SAMPInfo's NumOfWaves - offsetWave) + startWave
-
- where startWave is the number of the SampleHeader where the first wave
- was loaded in. (startWave and offsetWave both referenced from wave #0)
- numOfChans is the # of channels for each midi note in the destination playMap.
- LoadPlaymap simply zeros out the destination playMap first.
- If totalWaves = 0, LoadPlaymap just zeros out the playMap and MixPlaymap
- does nothing. In this case, offsetWave and startWave are ignored.
-
- MixPlayMap(totalWaves,numOfChans,offsetWave,startWave,destPlayMap);
- d0 d1 d6 d7 a0
-
-
- *************************** MakeTransTable ***************************
- Makes a TransposeNode for the passed sampleRate (in hz). The transpose table
- will have the specified # of steps above and below the ORIGINAL_PITCH as
- described by the upperRange and lowerRange values. This routine will
- allocate and link the TransposeNode into the passed TList only if there
- is not already a table for this sampleRate. Otherwise, returns ORIGPITCH
- of the other table in order to avoid duplication. Returns a zero if not
- enough mem to create a new table, or the passed sampleRate = 0.
- TList holds the address of the first TransposeNode.
-
- You may set the library's SAMPInfo's LowLimit and HighLimit fields
- before calling this. Defaults are 500 and 127 respectively. These are the
- limits between which the period values must range within the Transpose table.
- If a period is outside these limits, then the Transpose table entry is set
- to zero to indicate that the period is out of range. When playing back the
- wave, it is then easy to determine if a certain transposition of a wave's
- sample Rate results in a period out of range. The default limits are set for
- normal DMA audio and should not be altered unless your program does non-DMA
- audio output.
-
- ORIGPITCHaddress = MakeTransTable(sampleRate,upperRange,lowerRange,&TList);
- d0 d5 d6 d7 a2
-
-
- ***************************** OpenSampWrite ***************************
- Opens the SAMP filename for writing. Must be called before using WriteMHDR,
- WriteName, WriteChunk, or WriteWaves. Returns the address of the library's
- SAMPInfo if success, or a zero if the file couldn't be created. Upon
- successful return, application should set SAMPInfo's Format, PlayMode,
- NumWaves, and NumOfChans. The defaults for these are 8 bit, INDEPENDENT,
- 0 waves, and 4 channels. z-flag cleared for error.
-
- SAMPInfo=OpenSampWrite(fileName);
- d0 d1
-
-
- ******************************* WriteMHDR ******************************
- Writes out the SAMP and MHDR with SAMP header fileSize = 14+sizeOfPlayMap.
- Adjusts your PlayMap bytes so that all wave numbers < startWave and > =
- startWave+numWaves are set to 0. startWave is from 0 being the first wave.
- Returns a 1 if success, 0 if an error.
-
- BOOL WriteMHDR(startWave,playMap);
- d0 d0 a0
-
-
- ******************************* WriteSampChunk ***************************
- Writes out the passed ID, size (of data, not including header), and data.
- Returns a 1 if success, 0 if an error.
-
- BOOL = WriteSampChunk(ID,size,data);
- d0 d0 d1 a0
-
-
- ****************************** WriteSampData ******************************
- Writes out the data for the passed number of bytes and the passed data ptr.
- This is commonly used by vector routines writing out FATK, FRLS, and USER
- data when saving a wave. Returns a 1 if success, 0 if an error.
-
- BOOL = WriteSampData(numOfBytes, dataPtr);
- d0 d3 a0
-
-
- ****************************** WriteNames ********************************
- Writes the NAME chunk. Uses SAMPInfo's NumWaves to determine how many wave
- names to write. Passed the base of the first string buffer. Passed the size
- of a string buffer. Ignores trailing spaces on each name.
- Returns a 1 if success, 0 if an error.
-
- BOOL WriteNames(bufsize, bufPtr);
- d0 d0 a0
-
-
- ******************************* WriteWaves *****************************
-
- BOOL WriteWaves(offsetWave,totalWaves,SampleHeader64[0],TList)
- d0 d0 d1 a0 a1
-
- Writes the specified range of waves between offsetWave and offsetWave +
- totalWaves to the SAMP file. offsetWave is the first wave to start saving
- (with the first SampleHeader64 being wave #0).
-
- offsetWave is specified from zero (i.e. a value of zero won't skip any
- SampleHeader64 structs. A 2 will skip the first 2 SampleHeader64s and start
- saving the 3rd SampleHeader64 as wave #0.) For totalWaves = 1, only 1 wave
- is saved.
-
- totalWaves is the number of waves to save. If totalWaves = 0, it returns 1
- and writes an "empty" BODY chunk.
-
- TList holds the address of the first TTNode. (a C handle)
-
- Before calling WriteWaves(), you should set the SAMPInfo's ATAKvector,
- RLSEvector, FATKvector, FRLSvector, USERvector, and EXTRAvector to point to
- any routines you want the library to call per wave. If you don't, the default
- is for the library to write no FATK, FRLS, and USER data, and to write ATAK
- and RLSE EGPoints based upon the SampleHeader64's envelope fields.
-
- WriteWaves() calls your EXTRAvector BEFORE the each wave's 80 byte waveHeader
- and data is written out. This vector is useful for setting the library
- waveHeader's SampNum, LoopType, and InsType per wave.
-
- Calls ATAK, RLSE, FATK, FRLS vectors to write out Amplifier/Filter EGPoints,
- and USERvector to write User Data.
-
- The vectors are passed the lib's SAMPInfo and waveHeader, and the current
- SampleHeader. The vectors should return an abort flag (1 = Abort write, 0 =
- continue). For example, the library calls your FATK routine as so:
-
- flag = FATKroutine(waveHeader, SAMPinfo, SampleHeader);
- d0 a5 a4 a3
-
- You must set the waveHeader's size fields to the number of bytes in the
- data written out. For example, if your USER vector writes out 40 bytes of
- data, set the waveHeader's USERsize to 40. (You should also set the USERtype).
-
-
- ************************** SAMPErrorMsg ****************************
-
- When passed the error number (as returned by OpenSampRead for example),
- this returns the address of a NULL-terminated string describing the error.
- This is suitable for informing the user of any possible errors. For asm
- programmer's certain lib routines return a error number in d1. For C pro-
- grammer's, the error is stored in a variable called SAMPError.
-
- string = SAMPErrorMsg(SAMPError);
- d0 d1
-
-
- «««««««««««««« PROCESSING UNKNOWN CHUNKS »»»»»»»»»»»»
-
- When your UnknownChunk vector is called by OpenSampRead, it passes a
- SeekOffset. This value is the number of bytes from the beginning of the file
- to this chunk's ID, and can be used by your application to Seek() to this chunk
- later. Your vector should store the chunk ID and SeekOffset for later process-
- ing after OpenSampRead returns. The idea is to Seek() to the chunk and process
- it, perhaps before or after you ReadWaves(), ReadNames(), LoadPlaymap(),
- MixPlaymap(), and certainly before you CloseSamp(). The DOS fileHandle can be
- found in the library SAMPInfo's Handle field. Do not do any Seek() or Read()
- from within this vector!!! The ChunkSize passed to your vector does not
- count the standard, 8 byte IFF chunkID and chunkSize fields that all IFF
- chunks must start with.
-