mirror of https://github.com/x64dbg/btparser
561 lines
15 KiB
Plaintext
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;
|
|
}
|
|
}
|