Ad Lib, January 1989 -------------------- The .INS instrument files have been grouped together to create a .BNK (bank) file. The purpose of this is to save space. DOS will allocate 1K of space for a file regardless of how small the file actually is. So the bank file saves a significant amount of space. We are currently modifying our software to use the .BNK file instead of .INS files. The new software versions will all be numbered 1.5 and will not support the old .INS files. However, a utility will be provided to convert between the two formats. The default name for the bank file is STANDARD.BNK although any name may be used as long as the file extension is .BNK. The .BNK file a basically a collection of the old .INS file structures (as shown in Appendix C of the Programmer's Manual) with the waveform added to the end. Structure of .BNK files ----------------------- FIELD# SIZE-bytes TYPE DESCRIPTION HEADER 1 1 char file version, major 2 1 char file version, minor 3 6 char signature: "ADLIB-" 4 2 unsigned number of list entries used 5 2 unsigned total number of list entries in file 6 4 long absolute offset in file of start of name list 7 4 long absolute offset in file of start of data 8 8 char filler (set to zero) INSTRUMENT NAME SECTION RECORD 1 2 unsigned index into data section 2 1 char flag: 0 if this record is not used, else 1 3 9 char instrument name (max 8 char + NULL) DATA SECTION RECORD 1 1 char mode (0=melodic, 1=percussive) 2 1 char voice number (if percussive mode) 3 13 char modulator (operator 0) parameters 4 13 char carrier (operator 1) parameters 5 1 char wave form for modulator 6 1 char wave form for carrier There is one header at the very beginning of the file. Field #6 in the header is the absolute offset of the start of the instrument name section. The instrument name section contains a list of records which contain the instrument name, a flag and a pointer to the data section. Header field #5 gives the total number of records in this list, although not all of these records may be in use. Header field #4 gives the number of name records which are actually being used. The records in use will be placed at the beginning of the section and will be arranged alphabetically by instrument name. The data section contains the records of instrument parameters. One of these records is equivalent to the .INS file structure, except that the 2-byte fields are now 1-byte long. Two more bytes have been added for the wave form type for each operator. So, to read an instrument from the new bank file: 1. Read the header. 2. Use header field #6 to do a seek to the start of the instrument name section. 3. Search the name section for the desired name. (The search is delimited by header field #4.) 4. When found, get its index into the data section (name field #1). 5. Calculate the address where the data for this instument will be found: header_field_#7 + (index * sizeof_data_record) 6. Do a seek to the calculated address and read the data. Notes ----- The instrument names are alphabetically arranged so that you are not limited to using a linear search method. A binary search would be appropriate. If you are going to be creating or deleting an instrument, you must preserve the alphabetical order of instrument names. However, the data section is not neccesarily ordered. When adding data, you can find the data record to use from the index pointer from the first unused instrument name record. The unused instrument name records are not empty: the pointers into the data section are valid and are used when adding instruments. When expanding the instrument name section, field #1 must be initialized to a valid value. (In this case, the data section must be shifted down and header field #7 must be adjusted accordingly.) The purpose of having empty name records is to avoid having to rewrite the entire file every time an instrument is added. C Structures ------------ The following are C structures which correspond to the information given above. /* Instrument bank file header */ typedef struct { char majorVersion; char minorVersion; char sig [6]; /* signature: "ADLIB-" */ unsigned nrDefined; /* number of list entries used */ unsigned nrEntry; /* number of total entries in list */ long offsetIndex; /* offset in file of start of name list */ long offsetTimbre; /* offset in file of start of data */ char filler [8]; /* must be zero */ } BankHeader; /* Name of instrument with a pointer to its position in the file */ typedef struct { unsigned nrReference; /* index into data section */ char usedFlag; /* 0 if this entry is not used */ char TimbreName [9]; /* max 8 char's + NULL */ } BankEntry; /* Operator structure */ typedef struct { char ksl; char freqMult; char feedBack; /* used by operator 0 only */ char attack; char sustLevel; char sustain; char decay; char release; char output; char am; char vib; char ksr; char fm; /* used by operator 0 only */ } Operator; typedef struct { char mode; char percVoice; Operator op0; Operator op1; char wave0; /* wave form for operator 0 */ char wave1; /* wave form for operator 1 */ } PackedTimbre;