btparser/cparser/WAVTemplateAdv.bt

561 lines
15 KiB
Plaintext

//-----------------------------------
//--- 010 Editor v2.0 Binary Template
//
// File: WAVTemplateAdv.bt
// Author: SweetScape Software plus submissions
// Revision: 1.1
// Purpose: Defines a template for
// parsing WAV audio files. Includes SMPL chunk
// parsing (Parsing wav files that contains
// Sustain Loops. Useful for Game Developers).
// Tested with: CoolEdit and Sound Forge.
//-----------------------------------
// Typedefs for the wave file
typedef char ID[4];
// Record whether we have found a format chunk yet
local int haveValidFormat = false;
//-----------------------------------
// Define structures used in WAV files
// Stores the file header information
typedef struct
{
ID groupID;
long size;
ID riffType;
} WAVRIFFHEADER;
// Stores the format information for the file
typedef struct {
ID chunkID;
long chunkSize;
local int pos = FTell();
short wFormatTag;
unsigned short wChannels;
unsigned long dwSamplesPerSec;
unsigned long dwAvgBytesPerSec;
unsigned short wBlockAlign;
unsigned short wBitsPerSample;
// Mark that we have found a valid format chunk
haveValidFormat = true;
// Unknown data at the end of the chunk
if( chunkSize > (FTell() - pos) )
uchar unknown[ chunkSize - (FTell() - pos) ];
// Padding so the next chunk starts on an even byte
if( chunkSize & 1 )
uchar padding;
} FORMATCHUNK;
// Stores the actual wave data
typedef struct
{
ID chunkID;
long chunkSize;
// Test if we have a valid format
if( !haveValidFormat )
{
Warning( "File contains no valid WAVE format chunk." );
return -1;
}
// Parse the samples of the data
if( ((format.wBitsPerSample != 8) && (format.wBitsPerSample != 16) && (format.wBitsPerSample != 32))
|| (chunkSize % (int)format.wBlockAlign != 0) )
{
// Unsupported storage method used
unsigned char waveformData[chunkSize];
}
else if( (format.wChannels == 1) && (format.wBitsPerSample == 8) )
{
// Define an array of 8-bit samples - common case
uchar samples[ chunkSize ];
}
else if( (format.wChannels == 1) && (format.wBitsPerSample == 16) )
{
// Define an array of 16-bit samples - common case
short samples[ chunkSize/2 ];
}
else if( (format.wChannels == 1) && (format.wBitsPerSample == 32) )
{
// Define an array of 32-bit samples - common case
int samples[ chunkSize/4 ];
}
else
{
// Define general case sample
struct SAMPLES {
if( format.wBitsPerSample == 8 )
uchar channels[ format.wChannels ];
else if( format.wBitsPerSample == 16 )
short channels[ format.wChannels ];
else if( format.wBitsPerSample == 32 )
int channels[ format.wChannels ];
} samples[ chunkSize / (int)format.wBlockAlign ];
}
// Padding so the next chunk starts on an even byte
if( (chunkSize & 1) && (FTell() < FileSize()) )
uchar padding;
} DATACHUNK;
// Stores the size of the wave after decompression
typedef struct
{
ID chunkID;
long chunkSize;
unsigned long uncompressedSize;
} FACTCHUNK;
// Stores a list of cue points or markers to points in the data
typedef struct {
long dwIdentifier;
long dwPosition;
ID fccChunk;
long dwChunkStart;
long dwBlockStart;
long dwSampleOffset;
} CUEPOINT;
typedef struct {
ID chunkID;
long chunkSize;
local int pos = FTell();
long dwCuePoints;
CUEPOINT points[dwCuePoints];
// Unknown data at the end of the chunk
if( chunkSize > (FTell() - pos) )
uchar unknown[ chunkSize - (FTell() - pos) ];
} CUECHUNK;
// Define a list chunk with a set of subchunks
typedef struct {
ID chunkID;
long chunkSize;
char listData[chunkSize];
// Padding so the next chunk starts on an even byte
if( (chunkSize & 1) && (FTell() < FileSize()) )
uchar padding;
} LISTSUBCHUNK;
typedef struct {
ID chunkID;
long chunkSize;
local quad pos = FTell();
ID chunkType;
// Read the subchunks
while( FTell() - pos < chunkSize )
LISTSUBCHUNK subchunk;
// Padding so the next chunk starts on an even byte
if( (chunkSize & 1) && (FTell() < FileSize()) )
uchar padding;
} LISTCHUNK;
// A chunk which could not be identified
typedef struct {
ID chunkID;
long chunkSize;
uchar unknownData[chunkSize];
// Padding so the next chunk starts on an even byte
if( (chunkSize & 1) && (FTell() < FileSize()) )
uchar padding;
} UNKNOWNCHUNK;
//---------------------------------------------
// SMPL / SMPL Loop
//---------------------------------------------
typedef long SMPLLOOPS_Cue_ID <read=WAV_SMPLLOOPS_Cue_ID>;
string
WAV_SMPLLOOPS_Cue_ID( SMPLLOOPS_Cue_ID cid )
{
string sret;
SPrintf( sret, "Cue Point ID: %u", cid );
return sret;
}
//---------------------------------------------
typedef long SMPLLOOPS_Play_Count <read=WAV_SMPLLOOPS_Play_Count>;
string
WAV_SMPLLOOPS_Play_Count( SMPLLOOPS_Play_Count pc )
{
string sret;
if (pc==0)
{
SPrintf( sret, " Infinite Sustain Loop (%u)", pc );
}
else
{
SPrintf( sret, "Play Count: %u", pc );
}
return sret;
}
//---------------------------------------------
typedef long SMPLLOOPS_Start <read=WAV_SMPLLOOPS_Start>;
string
WAV_SMPLLOOPS_Start( SMPLLOOPS_Start st )
{
string sret;
SPrintf( sret, "Loop Start at %u byte offset", st );
return sret;
}
//---------------------------------------------
typedef long SMPLLOOPS_End <read=WAV_SMPLLOOPS_End>;
string
WAV_SMPLLOOPS_End( SMPLLOOPS_End end )
{
string sret;
SPrintf( sret, "Loop End at %u byte offset", end );
return sret;
}
//---------------------------------------------
typedef long SMPLLOOPS_Fraction <read=WAV_SMPLLOOPS_Fraction>;
string
WAV_SMPLLOOPS_Fraction( SMPLLOOPS_Fraction f )
{
string sret;
SPrintf( sret, "Fraction: %u", f );
return sret;
}
//---------------------------------------------
typedef long SMPL_SL <read=WAV_SMPL_SL>;
string
WAV_SMPL_SL( SMPL_SL sl )
{
string sret;
SPrintf( sret, "Number of Samples Loops (Sustain Loops): %u", sl );
return sret;
}
//---------------------------------------------
typedef long SMPL_SD <read=WAV_SMPL_SD>;
string
WAV_SMPL_SD( SMPL_SD sd )
{
string sret;
SPrintf( sret, "Sample Data (number of bytes): %u", sd );
return sret;
}
//---------------------------------------------
typedef long SMPL_SMPTE_Offset <read=WAV_SMPL_SMPTE_Offset>;
string
WAV_SMPL_SMPTE_Offset( SMPL_SMPTE_Offset so )
{
string sret;
SPrintf( sret, "SMPTE Offset (for synchronization): %u", so );
return sret;
}
//---------------------------------------------
typedef long SMPL_MIDI_Pitch_Fraction <read=WAV_SMPL_MIDI_Pitch_Fraction>;
string
WAV_SMPL_MIDI_Pitch_Fraction( SMPL_MIDI_Pitch_Fraction pf )
{
string sret;
SPrintf( sret, "MIDI Pitch Fraction: %u", pf );
return sret;
}
//---------------------------------------------
typedef long SMPL_MIDI_Unity_Note <read=WAV_SMPL_MIDI_Unity_Note>;
string
WAV_SMPL_MIDI_Unity_Note( SMPL_MIDI_Unity_Note un )
{
string sret;
SPrintf( sret, "MIDI unity note value: %u", un );
return sret;
}
//---------------------------------------------
typedef long SMPL_Product <read=WAV_SMPL_Product>;
string
WAV_SMPL_Product( SMPL_Product product )
{
string sret;
SPrintf( sret, "MIDI model ID (defined by the manufacturer): %u", product );
return sret;
}
//---------------------------------------------
typedef long SMPL_Sample_Period <read=WAV_SMPL_Sample_Period>;
string
WAV_SMPL_Sample_Period( SMPL_Sample_Period sp )
{
string sret;
// The sample period specifies the duration of time that passes during the playback of one sample in nanoseconds (normally equal to 1 / Samplers Per Second, where Samples Per Second is the value found in the format chunk).
SPrintf( sret, "Sample Period: %u", sp );
return sret;
}
//---------------------------------------------
typedef long SMPL_SMPTE <read=WAV_SMPL_SMPTE>;
string
WAV_SMPL_SMPTE( SMPL_SMPTE smptef )
{
string s;
string sret;
switch( smptef )
{
case 0: SPrintf( s, "No SMPTE offset" ); break;
case 24: SPrintf( s, "24 frames per second" ); break;
case 25: SPrintf( s, "25 frames per second" ); break;
case 29: SPrintf( s, "30 frames per second with frame dropping (30 drop)" ); break;
case 30: SPrintf( s, "30 frames per second" ); break;
default: SPrintf( s, "unknown (%u)", smptef ); break;
}
SPrintf( sret, "SMPTE Format: %s", s );
return sret;
}
//---------------------------------------------
typedef long SMPL_Manufacturer <read=WAV_SMPL_Manufacturer>;
string
WAV_SMPL_Manufacturer( SMPL_Manufacturer manufacture )
{
string s;
string sret;
switch( manufacture )
{
case 0: SPrintf( s, "Unknown" ); break;
case 1: SPrintf( s, "Sequential Circuits"); break;
case 2: SPrintf( s, "Big Briar"); break;
case 3: SPrintf( s, "Octave / Plateau"); break;
case 4: SPrintf( s, "Moog"); break;
case 5: SPrintf( s, "Passport Designs"); break;
case 6: SPrintf( s, "Lexicon"); break;
case 7: SPrintf( s, "Kurzweil"); break;
case 8: SPrintf( s, "Fender"); break;
case 9: SPrintf( s, "Gulbransen"); break;
case 10: SPrintf( s, "Delta Labs"); break;
case 11: SPrintf( s, "Sound Comp."); break;
case 12: SPrintf( s, "General Electro"); break;
case 13: SPrintf( s, "Techmar"); break;
case 14: SPrintf( s, "Matthews Research"); break;
case 16: SPrintf( s, "Oberheim"); break;
case 17: SPrintf( s, "PAIA"); break;
case 18: SPrintf( s, "Simmons"); break;
case 19: SPrintf( s, "DigiDesign"); break;
case 20: SPrintf( s, "Fairlight"); break;
case 21: SPrintf( s, "JL Cooper"); break;
case 22: SPrintf( s, "Lowery"); break;
case 23: SPrintf( s, "Lin"); break;
case 24: SPrintf( s, "Emu"); break;
case 27: SPrintf( s, "Peavey"); break;
case 32: SPrintf( s, "Bon Tempi"); break;
case 33: SPrintf( s, "S.I.E.L."); break;
case 35: SPrintf( s, "SyntheAxe"); break;
case 36: SPrintf( s, "Hohner"); break;
case 37: SPrintf( s, "Crumar"); break;
case 38: SPrintf( s, "Solton"); break;
case 39: SPrintf( s, "Jellinghaus Ms"); break;
case 40: SPrintf( s, "CTS"); break;
case 41: SPrintf( s, "PPG"); break;
case 47: SPrintf( s, "Elka"); break;
case 54: SPrintf( s, "Cheetah"); break;
case 62: SPrintf( s, "Waldorf"); break;
case 64: SPrintf( s, "Kawai"); break;
case 65: SPrintf( s, "Roland"); break;
case 66: SPrintf( s, "Korg"); break;
case 67: SPrintf( s, "Yamaha"); break;
case 68: SPrintf( s, "Casio"); break;
case 70: SPrintf( s, "Kamiya Studio"); break;
case 71: SPrintf( s, "Akai"); break;
case 72: SPrintf( s, "Victor"); break;
case 75: SPrintf( s, "Fujitsu"); break;
case 76: SPrintf( s, "Sony"); break;
case 78: SPrintf( s, "Teac"); break;
case 80: SPrintf( s, "Matsushita"); break;
case 81: SPrintf( s, "Fostex"); break;
case 82: SPrintf( s, "Zoom"); break;
case 84: SPrintf( s, "Matsushita"); break;
case 85: SPrintf( s, "Suzuki"); break;
case 86: SPrintf( s, "Fuji Sound"); break;
case 87: SPrintf( s, "Acoustic Technical Laboratory"); break;
default: SPrintf( s, "Unknown"); break;
}
SPrintf( sret, "Manufacturer: %s", s);
return sret;
}
//----------------------------------------------------------------------
typedef long SMPLLOOPS_Type <read=WAV_SMPL_Loop_Type>;
string
WAV_SMPL_Loop_Type( SMPLLOOPS_Type loop )
{
string s;
switch( loop )
{
case 0 :
SPrintf( s, "Loop: Forward (%u)", loop );
break;
case 1 :
SPrintf( s, "Loop: Ping Pong (%u)", loop );
break;
case 2 :
SPrintf( s, "Loop: Reverse (%u)", loop );
break;
case 3 :
SPrintf( s, "Loop [reserved for future standard types] (%u)", loop );
break;
default:
s = "Loop: <unknown>";
}
return s;
}
//----------------------------------------------------------------------
// SMPL Loop
typedef struct {
SMPLLOOPS_Cue_ID Cue_Point;
SMPLLOOPS_Type Type;
SMPLLOOPS_Start Start;
SMPLLOOPS_End End;
SMPLLOOPS_Fraction Fraction;
SMPLLOOPS_Play_Count Play_Count;
} SMPLLOOPS;
//----------------------------------------------------------------------
// Chunk SMPL
typedef struct {
ID chunkID;
long chunkSize;
SMPL_Manufacturer Manufacturer;
SMPL_Product Product; // Product code (Manufacture)
SMPL_Sample_Period Sample_Period;
SMPL_MIDI_Unity_Note MIDI_Unity_Note;
SMPL_MIDI_Pitch_Fraction MIDI_Pitch_Fraction;
SMPL_SMPTE SMPTE;
SMPL_SMPTE_Offset SMPTE_Offset;
SMPL_SL Num_Sample_Loops;
SMPL_SD Sampler_Data;
SMPLLOOPS loops[Num_Sample_Loops];
//Padding so the next chunk starts on an even byte
if( (chunkSize & 1) && (FTell() < FileSize()) )
uchar padding;
} SMPLCHUNK;
//---------------------------------------------
// Define the headers
LittleEndian();
SetBackColor( cLtPurple );
WAVRIFFHEADER header;
// Check for valid header
if( header.groupID != "RIFF" || header.riffType != "WAVE" )
{
Warning( "File is not a valid wave file. Template stopped." );
return -1;
}
// Read the file as a set of chunks
local char tag[5];
local uint size;
while( !FEof() )
{
// Read the chunk tag
ReadBytes( tag, FTell(), 4 );
tag[4] = 0;
// See which chunk this is
switch( tag )
{
case "fmt ":
SetBackColor( cLtGray );
FORMATCHUNK format;
break;
case "data":
SetBackColor( cNone );
DATACHUNK data;
break;
case "fact":
SetBackColor( cLtBlue );
FACTCHUNK fact;
break;
case "cue ":
SetBackColor( cLtGray );
CUECHUNK cue;
break;
case "smpl":
SetBackColor( cLtGray );
SMPLCHUNK smpl;
break;
case "LIST":
SetBackColor( cLtYellow );
LISTCHUNK list;
break;
default:
// Unknown chunk
size = ReadUInt( FTell()+4 );
Printf( "Encountered unknown chunk '%s' of size %d at position %Ld.\n",
tag, size, FTell() );
SetBackColor( cNone );
UNKNOWNCHUNK unknown;
break;
}
}