Ah, found it!

Now this is very very OLD Delphi produced code. So you'll have to forgive any lax conventions here.

I obviously am rewritting it, but the fact that I was unable to get IT samples to playback made me wonder. The problem quite simply was that Impulse Tracker prodced modules would load and MODPlug would not. Where as, only in IT did I have trouble decoding or playing back samples. S3M played them back just fine. Don't recall getting to the point of trying XM samples though.

I'll also include the S3MData.pas and ITData.pas sources for the load routines. IT had some packing/unpacking routines that I think may have tricked me aswell perhaps someone can point out points about the proper method for the use of these aswell.

[pascal]unit Unit1;

interface

uses
// Standard Libs
SysUtils, Types, Classes, Variants,
// CLX Cross-Platform Libs
Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons, ExtCtrls,
// OpenGL Libs
al, oooal, altypes, alut,
// OpenMod Libs
S3MData, ITData, XMData, ModTools;

type
TForm1 = class(TForm)
SongNameBox: TEdit;
Label1: TLabel;
OrdersList: TListBox;
SamplesBox: TListBox;
SampleAddressBox: TListBox;
ChannelsBox: TEdit;
PatternsBox: TEdit;
SongLengthBox: TEdit;
Label4: TLabel;
Label5: TLabel;
Label2: TLabel;
Label3: TLabel;
Label6: TLabel;
Label7: TLabel;
Button1: TButton;
OpenMODDlg: TOpenDialog;
PlaySample: TSpeedButton;
Timer1: TTimer;
ModTypeBox: TEdit;
Label8: TLabel;
procedure Button1Click(Sender: TObject);
procedure SamplesBoxDblClick(Sender: TObject);
procedure PlaySampleClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure OrdersListDblClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

ModType: Integer;
S3M: S3M_Mixer;
IT: IT_Mixer;
XM: XM_Mixer;

{-------}
// AudioSample: TSDL_AudioSpec;

Sample: TALObject;

// OpenAL Possitioning Settings
listenerpos: array [0..2] of TALfloat= ( 0.0, 0.0, 0.0);
listenervel: array [0..2] of TALfloat= ( 0.0, 0.0, 0.0);
listenerori: array [0..5] of TALfloat= ( 0.0, 0.0, -1.0, 0.0, 1.0, 0.0);
playbuf : array[0..7] of TAluint;
source : array[0..7] of TALuint;

{--------}

implementation

uses Unit2, Unit3;

{$R *.xfm}


procedure TForm1.Button1Click(Sender: TObject);
var i, j: Integer;
TempStr: String;
begin
if (OpenMODDlg.Execute) then
begin
ModType := GetModType(OpenMODDlg.FileName);
ModTypeBox.Text := MODTypeString[ModType];
if (ModType = mtS3M) then
begin
S3M := S3M_Mixer.Create;

S3M.LoadFromFile(OpenMODDlg.FileName);


SongNameBox.Text := GetModString(S3M.Name);
ChannelsBox.Text := IntToStr(S3M.NumberOfChannels);
PatternsBox.Text := IntToStr(S3M.Header.PatNum);
//PatternsBox.Text := IntToStr(S3M.NumberOfPatterns);
SongLengthBox.Text := IntToStr(S3M.SongLength);

OrdersList.Clear;
for i := 0 to S3M.SongLength - 1 do
OrdersList.Items.Add(IntToStr(S3M.Orders[i]));

SamplesBox.Clear;
SampleAddressBox.Clear;
for i := 0 to S3M.Header.InsNum - 1 do
begin
SamplesBox.Items.Add(GetModString(S3M.Instruments[i].SampleName));
SampleAddressBox.Items.Add(IntToHex(S3M.InsPtr[i] * 16, );
end;
S3M.Free;
end;
if (ModType = mtIT) then
begin
IT := IT_Mixer.Create;

IT.LoadFromFile(OpenMODDlg.FileName);


SongNameBox.Text := GetModString(IT.Name);
ChannelsBox.Text := IntToStr(IT.NumberOfChannels);
PatternsBox.Text := IntToStr(IT.Header.PatternNumber);

SamplesBox.Clear;
SampleAddressBox.Clear;
for i := 0 to IT.Header.SampleNumber - 1 do
begin
SamplesBox.Items.Add(GetModString(IT.Samples[i].SampleName));
SampleAddressBox.Items.Add(IntToHex(IT.SamPtr[i], );
end;
IT.Free;
end;
if (ModType = mtXM) then
begin
XM := XM_Mixer.Create;

XM.LoadFromFile(OpenMODDlg.FileName);

SongNameBox.Text := GetModString(XM.Name);
ChannelsBox.Text := IntToStr(XM.Header.NumOfChannels);
PatternsBox.Text := IntToStr(XM.Header.NumOfPatterns);

XM.Free;
end;
end;
end;

procedure TForm1.SamplesBoxDblClick(Sender: TObject);
type
TSample = Array[0..65528] of Byte; { One sample }
TFixedSample = Array[0..65528] of SmallInt; { One sample }
var
i: Integer;
Samp: TSample;
FixedSamp: TFixedSample;
Sample_Data: ^TSample; { Pointers to actual sample data }
Sample_Size: Word;
FixedSample_Data: ^TFixedSample; { Pointers to actual sample data }
FixedSample_Size: Word;
AudioFormat: Integer;
begin
SamplePreview.Show;

if (ModType = mtS3M) then
DrawSample(S3M.Instruments[SamplesBox.ItemIndex].SampleData,
S3M.Instruments[SamplesBox.ItemIndex].SampleLength, False);
{ if (ModType = mtIT) then
DrawSample(IT.Samples[SamplesBox.ItemIndex].SampleData,
IT.Samples[SamplesBox.ItemIndex].Length);}


if (Sample <> nil) then
Sample.Free;

Sample := TALObject.Create;

// Retrive Sample Data
if (ModType = mtS3M) then
Sample.LoadFromBuffer2(S3M.Instruments[SamplesBox.ItemIndex].SampleData,
S3M.Instruments[SamplesBox.ItemIndex].SampleLength,
8392, AL_FORMAT_MONO;

if (ModType = mtIT) then
begin
if (IT.Samples[SamplesBox.ItemIndex].isStereo) then
if (IT.Samples[SamplesBox.ItemIndex].is16Bit) then
AudioFormat := AL_FORMAT_STEREO16
else
AudioFormat := AL_FORMAT_STEREO8
else
if (IT.Samples[SamplesBox.ItemIndex].is16Bit) then
AudioFormat := AL_FORMAT_MONO16
else
AudioFormat := AL_FORMAT_MONO8;

Sample.LoadFromBuffer2(IT.Samples[SamplesBox.ItemIndex].SampleData,
IT.Samples[SamplesBox.ItemIndex].Length,
// IT.Samples[SamplesBox.ItemIndex].C5Speed,
8392,
AudioFormat);
end;

Sample.Update;
Sample.Play;
end;

procedure TForm1.PlaySampleClick(Sender: TObject);
//var AquiredSample: TSDL_AudioSpec;
// AudioPtr, AquiredPtr: PSDL_AudioSpec;
// err: Integer;
begin
// AudioSample.freq := 22050;
// AudioSample.format := AUDIO_U8;
// if (S3M.isMono) then
// AudioSample.channels := 1
// else
// AudioSample.channels := 2;
// AudioSample.silence
// AudioSample.samples := S3M.Instruments[SamplesBox.ItemIndex].SampleLength;
// AudioSample.size := S3M.Instruments[SamplesBox.ItemIndex].SampleLength;
// AudioSample.userdata := S3M.Instruments[SamplesBox.ItemIndex].SampleData;

// AudioSample.callback :=
// AudioPtr := Addr(AudioSample);
// AquiredPtr := Addr(AquiredSample);
// err := SDL_OpenAudio(AudioPtr, AquiredPtr);
// if (err <> 0) then
// ShowMessage('Error Opening Audio!');
end;

procedure TForm1.FormCreate(Sender: TObject);
var
argv: array of PChar;
loop: integer;
begin
AlutInit(nil, argv);

AlGenSources(8, @source);
AlGenBuffers(8, @playbuf);

//set up listener
AlListenerfv(AL_POSITION, @listenerpos);
AlListenerfv(AL_VELOCITY, @listenervel);
AlListenerfv(AL_ORIENTATION, @listenerori);

end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
AlDeleteSources(8, @source);
AlDeleteBuffers(8, @playbuf);

if (Sample <> nil) then
begin
if (Sample.playing) then
Sample.Stop;
Sample.Destroy;
end;

AlutExit();
end;

end.[/pascal]

[pascal]unit S3MData;

interface

uses
CommonData, ModTools;

type
S3M_Header = Record
SongName : Array[1 .. 28] of Char;
Unknown1 : Byte;{should be '1A' in hex}
Typ : Byte;{File type: 16=module,17=song}
Unknown2 : Word;{Unknown! For Expansion Useless}
OrdNum : Word;{Number of orders in file}
InsNum : Word;{Number of instruments in file}
PatNum : Word;{Number of patterns in file}
Flags : Word;
TrackerVersion : Word;{Created with tracker / version}
FileFormatVersion : Word;
SCRM : Array[1 .. 4] of Char;
GlobalVolume : Byte;
InitialSpeed : Byte;
InitialTempo : Byte;
MasterVolume : Byte;
UltraClickRemoval : Byte;
DefaultPanning : Byte;
Unknown3 : Array[1 .. 8] of Byte;{For expansion, ignore}
Special1 : Word;
end;
S3M_Instrument = Record
InsType : Byte;
FileName : Array[1 .. 12] of Char;
MemSeg : Integer;
SampleLength : Word;
LoopBegin : Word;
LoopEnd : Word;
Volume : Byte;
PackingScheme : Byte; {0 = unpacked, 1 = DP30ADPCM packing}
Flags : Byte; {BYTE AND 1 = Loop on,BYTE AND 2 = Stereo sample (not supported),
BYTE AND 4 = 16 Bit sample (not supported)}
C2SPD : Word;
SampleName : Array[1 .. 28] of Char;
SCRS : Array[1 .. 4] of Char;{'SCRS'}

{Flags}
isLoop : Boolean;
isStereo : Boolean;
is16Bit : Boolean;

SampleData : Pointer;
end;
{ TODO 1 : Add field to indicate END OF ROW }
S3M_Note = Record
Channel : Byte;
Note : Byte;
Instrument : Byte;
Volume : Byte;
Effect : Byte;
EffectParameter : Byte;

SetVolume : Boolean;
LastNote : Boolean;
end;
S3M_Pattern = class(TObject)
NumberOfNotes: Integer;
Notes: Array of S3M_Note;
end;
S3M_Mixer = class(TObject)
Name: String;
NumberOfChannels: Integer;
NumberOfPatterns: Integer;
SongLength: Integer;
Header: S3M_Header;
// Channel Settings: Disabled >= 16 > Right(Enabled) > 7 >= Left(Enabled)
ChannelSettings: Array[0 .. 31] of Byte;

Panning: Array[0 .. 31] of Byte;
isMono: Boolean;

ReMap: Array[0 .. 31] of Byte;
PanValue: Array[0 .. 31] of Pan_Type;

Orders: Array[0 .. 255] of Byte;

Instruments: Array[0 .. 99] of S3M_Instrument;

Patterns: Array[0 .. 253] of S3M_Pattern;

// To be moved after development debugging!!!
InsPtr: Array[0..99] of Word;
PatPtr: Array[0..255] of Word;
// To be moved after development debugging!!!

procedure LoadFromFile(FileName: String);
end;


implementation


{S3M_Mixer Functions}
procedure S3M_Mixer.LoadFromFile(FileName: String);
var FileStream: File;
OldByteBuffer,
ByteBuffer, ByteBuffer2: Byte;
WordBuffer, WordBuffer2: Word;
i, j: Integer;
NoteIndex, RowIndex: Integer;
DumpNote : Boolean;
RecordBlankRow: Boolean;
begin
{Read Header From File}
AssignFile(FileStream, FileName);
Reset(FileStream, 1);

BlockRead(FileStream, Header, SizeOf(Header));

{Display S3M Information}
if (Header.SCRM = 'SCRM') then
begin
{SongName}
Name := Header.SongName;
end;

{Read Channel Settings}
// Channel Settings: Disabled >= 16 > Right(Enabled) > 7 >= Left(Enabled)
NumberOfChannels := 0;
for i := 0 to 31 do
ReMap[i] := 255;
for i := 0 to 31 do
begin
BlockRead(FileStream, ChannelSettings[i], SizeOf(ChannelSettings[i]));
if (ChannelSettings[i] < 16) then
begin
ReMap[i] := NumberOfChannels;
if (ChannelSettings[i] <= 7) then
PanValue[NumberOfChannels] := Left
else
PanValue[NumberOfChannels] := Right;
inc(NumberOfChannels);
end;
end;

{Read Orders}
SongLength := 0;
NumberOfPatterns := 0;
for i := 0 to Header.OrdNum - 1 do
begin
BlockRead(FileStream, ByteBuffer, SizeOf(ByteBuffer));
if (ByteBuffer = 255) then
Break;
if (ByteBuffer < 254) then
begin
Orders[SongLength] := ByteBuffer;

if (Orders[SongLength] > NumberOfPatterns) then
NumberOfPatterns := Orders[SongLength];
inc(SongLength);
end;
end;

{ParaPointers}
for i := 0 to Header.InsNum - 1 do
BlockRead(FileStream, InsPtr[i], SizeOf(InsPtr[i]));
for i := 0 to Header.PatNum do
BlockRead(FileStream, PatPtr[i], SizeOf(PatPtr[i]));

{Default Pan Positions}
if (Header.DefaultPanning = 252) then
for i := 0 to 31 do
begin
BlockRead(FileStream, ByteBuffer, SizeOf(ByteBuffer));
Panning[i] := ByteBuffer AND $0F;
end;

{Mono}
isMono := False;
if ((Header.MasterVolume AND 12 > 0) then
isMono := True;

{Instruments}
for i := 0 to Header.InsNum - 1 do
begin
Seek(FileStream, InsPtr[i] * 16);
BlockRead(FileStream, Instruments[i].InsType, SizeOf(Instruments[i].InsType));
j := 1;
repeat
BlockRead(FileStream, Instruments[i].FileName[j], SizeOf(Instruments[i].FileName[j]));
inc(j);
until (j = 13);

BlockRead(FileStream, ByteBuffer, SizeOf(ByteBuffer));
BlockRead(FileStream, WordBuffer, SizeOf(WordBuffer));

Instruments[i].MemSeg := (ByteBuffer shl 16) + WordBuffer;

BlockRead(FileStream, Instruments[i].SampleLength, SizeOf(Instruments[i].SampleLength));
BlockRead(FileStream, WordBuffer, SizeOf(WordBuffer));
Instruments[i].SampleLength := Instruments[i].SampleLength + (WordBuffer shl ;

BlockRead(FileStream, Instruments[i].LoopBegin, SizeOf(Instruments[i].LoopBegin));
BlockRead(FileStream, WordBuffer, SizeOf(WordBuffer));
Instruments[i].LoopBegin := Instruments[i].LoopBegin + (WordBuffer shl ;

BlockRead(FileStream, Instruments[i].LoopEnd, SizeOf(Instruments[i].LoopEnd));
BlockRead(FileStream, WordBuffer, SizeOf(WordBuffer));
Instruments[i].LoopEnd := Instruments[i].LoopEnd + (WordBuffer shl ;

BlockRead(FileStream, Instruments[i].Volume, SizeOf(Instruments[i].Volume));
BlockRead(FileStream, ByteBuffer, SizeOf(ByteBuffer));

{0 = unpacked, 1 = DP30ADPCM packing}
BlockRead(FileStream, Instruments[i].PackingScheme, SizeOf(Instruments[i].PackingScheme));

BlockRead(FileStream, Instruments[i].Flags, SizeOf(Instruments[i].Flags));
if (Instruments[i].Flags AND 1 = 1) then
Instruments[i].isLoop := True
else
Instruments[i].isLoop := False;
if (Instruments[i].Flags AND 2 = 1) then
Instruments[i].isStereo := True
else
Instruments[i].isStereo := False;
if (Instruments[i].Flags AND 4 = 1) then
Instruments[i].is16Bit := True
else
Instruments[i].is16Bit := False;

BlockRead(FileStream, Instruments[i].C2SPD, SizeOf(Instruments[i].C2SPD));
BlockRead(FileStream, WordBuffer, SizeOf(WordBuffer));
Instruments[i].C2SPD := Instruments[i].C2SPD + (WordBuffer shl ;

for j := 1 to 6 do
BlockRead(FileStream, WordBuffer, SizeOf(WordBuffer));

BlockRead(FileStream, Instruments[i].SampleName, SizeOf(Instruments[i].SampleName));
BlockRead(FileStream, Instruments[i].SCRS, SizeOf(Instruments[i].SCRS));
end;

{Patterns}
for i := 0 to Header.PatNum - 1 do
begin
Seek(FileStream, PatPtr[i] * 16);
// This is the length of the packed pattern data - No need to store this data
BlockRead(FileStream, WordBuffer, SizeOf(WordBuffer));

// Init next Pattern
Patterns[i] := S3M_Pattern.Create;

Patterns[i].NumberOfNotes := NumberOfChannels * 64;
SetLength(Patterns[i].Notes, Patterns[i].NumberOfNotes);

RowIndex := 1;
NoteIndex := 0;
DumpNote := False;
RecordBlankRow := False;
OldByteBuffer := 1; // Init to something other than 0 so no blank rows will be recorded.
repeat
// for j := 0 to (Patterns[i].NumberOfNotes) - 1 do
begin
repeat
begin
DumpNote := False;
BlockRead(FileStream, ByteBuffer, SizeOf(ByteBuffer));

if (OldByteBuffer = 0) and (ByteBuffer = 0) and (not RecordBlankRow) then
RecordBlankRow := True
else
RecordBlankRow := False;

OldByteBuffer := ByteBuffer;

// if byte = 0 then end of row! if previous Byte read was an end of Row marker and LastNote was recorded mark new note
if (ByteBuffer > 0) or (RecordBlankRow) then
begin
// Check to make sure that Note is on a valid channel!
if (ReMap[ByteBuffer AND 31] > NumberOfChannels) then
begin
DumpNote := True;

if (ByteBuffer AND 32 > 0) then
BlockRead(FileStream, WordBuffer2, SizeOf(ByteBuffer2));
if (ByteBuffer AND 64 > 0) then
BlockRead(FileStream, ByteBuffer2, SizeOf(ByteBuffer2));
if (ByteBuffer AND 128 > 0) then
BlockRead(FileStream, WordBuffer2, SizeOf(ByteBuffer2));
end
else
begin
Patterns[i].Notes[NoteIndex].Channel := ReMap[ByteBuffer AND 31];

if (ByteBuffer AND 32 > 0) then
begin
BlockRead(FileStream, ByteBuffer2, SizeOf(ByteBuffer2));
Patterns[i].Notes[NoteIndex].Note := ByteBuffer2;
BlockRead(FileStream, ByteBuffer2, SizeOf(ByteBuffer2));
Patterns[i].Notes[NoteIndex].Instrument := ByteBuffer2;
end;
if (ByteBuffer AND 64 > 0) then
begin
BlockRead(FileStream, ByteBuffer2, SizeOf(ByteBuffer2));
Patterns[i].Notes[NoteIndex].Volume := ByteBuffer2;
Patterns[i].Notes[NoteIndex].SetVolume := True;
end
else
Patterns[i].Notes[NoteIndex].SetVolume := False;
if (ByteBuffer AND 128 > 0) then
begin
BlockRead(FileStream, ByteBuffer2, SizeOf(ByteBuffer2));
Patterns[i].Notes[NoteIndex].Effect := ByteBuffer2;
BlockRead(FileStream, ByteBuffer2, SizeOf(ByteBuffer2));
Patterns[i].Notes[NoteIndex].EffectParameter := ByteBuffer2;
end;

inc(NoteIndex);
end;

// if End of Row marker was set and new blank row is recorded
if (RecordBlankRow) then
Patterns[i].Notes[NoteIndex - 1].LastNote := True;
end
else
begin
inc(RowIndex);
Patterns[i].Notes[NoteIndex - 1].LastNote := True;
end;
end;
until (DumpNote = False);
if (RowIndex > 64) then
Break;
end;
until (NoteIndex > Patterns[i].NumberOfNotes - 1);

// Real NumberOfNotes
Patterns[i].NumberOfNotes := NoteIndex;
end;

{Samples}
for i := 0 to Header.InsNum - 1 do
begin
Seek(FileStream, Instruments[i].MemSeg * 16);
GetMem(Instruments[i].SampleData, Instruments[i].SampleLength);

BlockRead(FileStream, Instruments[i].SampleData^, Instruments[i].SampleLength);
end;

CloseFile(FileStream);
end;

end.[/pascal]

[pascal]unit ITData;
interface

uses
CommonData, ModTools;


type
IT_Header = Record
IMPM : Array[1 .. 4] of Char;
SongName : Array[1 .. 26] of Char;
PatternHilight : Word;{Useless for playback}
OrderNumber : Word;
InstrumentNumber : Word;
SampleNumber : Word;
PatternNumber : Word;
CreatedWith : Word;
CompatableWith : Word;
Flags : Word;
Special : Word;
GlobalVolume : Byte;
MixingVolume : Byte;
InitialSpeed : Byte;
InitialTempo : Byte;
PanningSeparation : Byte;{Panning separation between channels (0->128, 128 is max sep.)}
PitchWheelDepth : Byte;
MessageLength : Word;
MessageOffset : LongWord;
Reservered1 : LongWord;
end;
IT_Instrument_Old = Record {cmwt < $200}
IMPI : Array[1 .. 4] of Char;
DOSFileName : Array[1 .. 12] of Char;
Reserved1 : Byte; {should be $00}
Flag : Byte; {Bit#0: ON = Use volume envelope
Bit#1: ON = Use volume loop
Bit#2: ON = Use sustain volume loop}
VolumeLoopStart : Byte; {Volume loop start (node number)}
VolumeLoopEnd : Byte; {Volume loop end (node number)}
SustainLoopStart : Byte; {Sustain loop start (node number)}
SustainLoopEnd : Byte; {Sustain loop end (node number)}
Unknown1 : Word;
FadeOut : Word;
NewNoteAction : Byte; {New note action:
0 = Note cut
1 = Note continue
2 = Note off
3 = Note fade}
DuplicateNoteCheck : Byte; {Duplicate note check (0 = Off, 1 = On)}
TrackerVersion : Word; {Tracker version used to save the instrument. This is only
used in the instrument files.}
NumberOfSamples : Byte; {Number of samples associated with instrument. This is only
used in the instrument files.}
Reserved2 : Byte;
InstrumentName : Array[1 .. 26] of Char;
Reserved3 : Array[1 .. 6] of Byte;
NoteSampleKeyboardTable : Array[1 .. 240] of Byte;
VolumeEnvelope : Array[1 .. 200] of Byte;
NodePoints : Array[1 .. 25, 1 .. 2] of Byte;{Node points (25x2 bytes)
Node data: Tick THEN magnitude}
end;
IT_Envelope_Node = Record
Value : Integer; {0->64 for vol, -32->+32 for panning or pitch}
Tick : Word; {for tick number (0->9999)}
end;
IT_Envelope = Record
Flag : Byte;
NumberOfNodePoints : Byte;
LoopBegin : Byte;
LoopEnd : Byte;
SustainLoopBegin : Byte;
SustainLoopEnd : Byte;
Nodes : Array[0 .. 24] of IT_Envelope_Node;
end;
IT_Instrument = Record
IMPI : Array[1 .. 4] of Char;
DOSFileName : Array[1 .. 12] of Char;
Reserved1 : Byte; {should be $00}
NewNoteAction : Byte; {New Note Action
0 = Cut
1 = Continue
2 = Note off
3 = Note fade}
DuplicateCheckType : Byte; {Duplicate Check Type
0 = Off
1 = Note
2 = Sample
3 = Instrument}
DuplicateCheckAction : Byte; {Duplicate Check Action
0 = Cut
1 = Note Off
2 = Note fade}
FadeOut : Word;
PitchPanSeparation : Byte; {Pitch-Pan separation, range -32 -> +32}
PitchPanCenter : Byte; {Pitch-Pan center: C-0 to B-9 represented as 0->119 inclusive}
GlobalVolume : Byte; {Global Volume, 0->128}
DefaultPan : Byte; {Default Pan, 0->64, &128 => Don't use}
RandomVolume : Byte; {Random volume variation (percentage)}
RandomPanning : Byte; {Random panning variation (panning change - not implemented yet)}
TrackerVersion : Word; {Tracker version used to save the instrument. This is only
used in the instrument files.}
NumberOfSamples : Byte; {Number of samples associated with instrument. This is only
used in the instrument files.}
Reserved2 : Byte;
InstrumentName : Array[1 .. 26] of Char;
Reserved3 : Word;
MIDIChannel : Byte; {MIDI Channel}
MIDIProgram : Byte; {MIDI Program (Instrument)}
Reserved4 : Word;
NoteSampleKeyboardTable : Array[0 ..119, 0 .. 1] of Byte;
{Each note of the instrument is first converted to a sample number
and a note (C-0 -> B-9). These are stored as note/sample byte pairs
(note first, range 0->119 for C-0 to B-9, sample ranges from
1-99, 0=no sample)}
Envelopes : Array[0 .. 2] of IT_Envelope;
end;
IT_Sample = Record
IMPS : Array[1 .. 4] of Char;
DOSFileName : Array[1 .. 12] of Char;
Reserved1 : Byte; {should be $00}
GlobalVolume : Byte; {Global volume for instrument, ranges from 0->64}
Flags : Byte; {Bit#0: ON = Sample associated with header.
OFF= No sample. (No sampledata either!)
Bit#1: ON = 16-bit, OFF = 8-bit.
Bit#2: ON = Stereo, OFF = Mono.
(Stereo samples are not supported yet.)
Bit#3: RESERVED
Bit#4: ON = Use looping
Bit#5: ON = Use sustain loop
Bit#6: ON = Ping Pong (bi-directional) loop,
OFF= Forwards loop
Bit#7: ON = Ping Pong Sustain loop,
OFF= Forwards Sustain loop}
Volume : Byte; {Default volume for instrument}
SampleName : Array[1 .. 26] of Char;
CreatedWith : Byte; {Created with tracker version.}
DefaultPanning : Byte; {Default panning.
Bits 0->6 = Pan value,
Bit 7. ON to USE (opposite of inst)}
Length : LongWord; {Length of sample in SAMPLES, NOT bytes!}
LoopStart : LongWord; {Start of loop (no of samples in, not bytes)}
LoopEnd : LongWord; {Sample no. AFTER end of loop}
C5Speed : LongWord; {Number of bytes a second for C-5 (ranges from 0->9999999)}
SustainLoopStart : LongWord; {Start of sustain loop}
SustainLoopEnd : LongWord; {Sample no. AFTER end of sustain loop}
SamplePointer : Integer; {'Long' Offset of sample in file. 32-bit signed}
VibratoSpeed : Byte; {Vibrato Speed, ranges from 0->64}
VibratoDepth : Byte; {Vibrato Depth, ranges from 0->64}
VibratoRate : Byte; {Vibrato Rate, rate at which vibrato is applied (0->64)}
VibratoType : Byte; {Vibrato waveform type.
0 = Sine wave
1 = Ramp down
2 = Square wave
3 = Random (speed is irrelevant)}

{Flags}
isSample : Boolean;
is16Bit : Boolean;
isStereo : Boolean;
isLoop : Boolean;
isSustainLoop : Boolean;
isPingPongLoop : Boolean;
isPingPongSustainLoop : Boolean;

SampleLength : Integer; // Length in Bytes!
SampleData : Pointer; // Pointer To Sample Data
end;
IT_Note = Record
Channel : Byte;
Note : Byte;
Instrument : Byte;
VolumePan : Byte;
Effect : Byte;
EffectParameter : Byte;
lastNote : Boolean;
lastInstrument : Boolean;
lastVolumePan : Boolean;
lastEffect : Boolean;
end;
IT_Pattern = class(TObject)
NumberOfRows : Word; {Ranges from 32->200}
NumberOfNotes : Integer;
Notes: Array of IT_Note;
end;
IT_Mixer = class(TObject)
Name : String;
NumberOfChannels : Integer;
NumberOfInstruments : Integer;
NumberOfSamples : Integer;
NumberOfPatterns : Integer;
SongLength : Integer;

Header: IT_Header;

ChannelPan : Array[0 .. 63] of Byte;
{Each byte contains a panning value for a channel. Ranges from
0 (absolute left) to 64 (absolute right). 32 = central pan,
100 = Surround sound.
+128 = disabled channel}
ChannelVolume : Array[0 .. 63] of Byte; {0 to 64}

NumberOfOrders: Word;
Orders: Array[0 .. 255] of Byte;

InsPtr: Array[0 .. 255] of LongWord;
SamPtr: Array[0 .. 255] of LongWord;
PatPtr: Array[0 .. 255] of LongWord;

Instruments: Array[0 .. 255] of IT_Instrument;

Samples: Array[0 .. 255] of IT_Sample;

Patterns: Array[0 .. 253] of IT_Pattern;

procedure LoadFromFile(FileName: String);
end;


implementation

(*
function ITReadBits(bitbuf: Cardinal; bitnum: Integer; ibuf, n: Byte): Cardinal;
//-----------------------------------------------------------------
var
retval: Cardinal;
i: Integer;
begin
retval := 0;
i := n;

if (n > 0) then
begin
repeat
begin
if (bitnum = 0) then
begin
bitbuf := *ibuf++;
bitnum := 8;
end;
retval := retval shr 1;
retval := retval OR (bitbuf shl 31);
bitbuf := bitbuf shr 1;
bitnum := bitnum - 1;
dec(i);
end;
until (i = 0);
i := n;
end;
Result := (retval shr (32-i));
end;


// Unpack 8 Bit IT Sample
procedure ITUnpack8Bit(Sample: Pointer; dwLen: Integer; MemFile: Integer; MemLength: Integer; b215: Boolean);
//-------------------------------------------------------------------------------------------
var
// FileStream: File;
pDst: Pointer;
pSrc: Integer;
wHdr: Integer;
wCount: Integer;
bitbuf: Integer;
bitnum:Integer;
bLeft, bTemp, bTemp2: Byte;
{---}
d,
dwPos: Integer;
wBits: Word;
begin
pDst := pSample;
pSrc := MemFile;
wHdr := 0;
wCount := 0;
bitbuf := 0;
bitnum := 0;
bLeft := 0;
bTemp := 0;
bTemp2 := 0;

while (dwLen > 0) do
begin
if (wCount = 0) then
begin
wCount := $8000;
BlockRead(FileStream, wHdr, 2); // wHdr = *((LPWORD)pSrc);
pSrc := pSrc + 2;
bLeft := 9;
bTemp := 0;
bTemp2 := 0;
bitbuf := 0;
bitnum := 0;
end;
d := wCount;
if (d > dwLen) then
d := dwLen;
// Unpacking
dwPos := 0;
repeat
begin
wBits := (WORD)ITReadBits(bitbuf, bitnum, pSrc, bLeft);
if (bLeft < 7) then
begin
DWORD i = 1 << (bLeft-1);
DWORD j = wBits & 0xFFFF;
if (i != j) then
goto UnpackByte;
wBits = (WORD)(ITReadBits(bitbuf, bitnum, pSrc, 3) + 1) & 0xFF;
bLeft = ((BYTE)wBits < bLeft) ? (BYTE)wBits : (BYTE)((wBits+1) & 0xFF);
goto Next;
end;
if (bLeft < 9) then
begin
WORD i = (0xFF >> (9 - bLeft)) + 4;
WORD j = i - 8;
if ((wBits <= j) || (wBits > i))
goto UnpackByte;
wBits -= j;
bLeft = ((BYTE)(wBits & 0xFF) < bLeft) ? (BYTE)(wBits & 0xFF) : (BYTE)((wBits+1) & 0xFF);
goto Next;
end;
if (bLeft >= 10) then
goto SkipByte;
if (wBits >= 256) then
begin
bLeft = (BYTE)(wBits + 1) & 0xFF;
goto Next;
end;
UnpackByte:
if (bLeft < then
begin
BYTE shift = 8 - bLeft;
char c = (char)(wBits << shift);
c >>= shift;
wBits = (WORD)c;
end;
wBits += bTemp;
bTemp = (BYTE)wBits;
bTemp2 += bTemp;
//#ifdef IT215_SUPPORT
pDst[dwPos] = (b215) ? bTemp2 : bTemp;
//#else
pDst[dwPos] = bTemp;
//#endif
SkipByte:
dwPos++;
Next:
if (pSrc >= lpMemFile+dwMemLength+1) then
return;
end;
until (dwPos >= d);
// Move On
wCount -= d;
dwLen -= d;
pDst += d;
end;
end;
*)

{IT_Mixer Functions}
procedure IT_Mixer.LoadFromFile(FileName: String);
var FileStream: File;
ByteBuffer, ByteBuffer2, ByteBuffer3: Byte;
ShortIntBuffer: ShortInt;
WordBuffer, WordBuffer2: Word;
i, j, k: Integer;
RowIndex: Integer;
DumpNote : Boolean;
HeaderSize: Integer;
HighestChannel: Integer;
NumberOfRows: Integer;
FileLength: Integer;
Flags: Integer;
Len: Integer;
begin
{Check that file Exists}
// if (FileExists(FileName)) then
// begin
{Open File}
AssignFile(FileStream, FileName);
Reset(FileStream, 1);

{Read File Length}
FileLength := FileSize(FileStream);

{Read Header From File}
BlockRead(FileStream, Header, SizeOf(Header));


{Get IT Song Name}
if (Header.IMPM = 'IMPM') then
begin
{SongName}
Name := Header.SongName;
end;

{Read Channel Panning}
for i := 0 to 63 do
BlockRead(FileStream, ChannelPan[i], SizeOf(ChannelPan[i]));

{Read Channel Volumes}
for i := 0 to 63 do
BlockRead(FileStream, ChannelVolume[i], SizeOf(ChannelVolume[i]));

{Read Orders}
for i := 0 to Header.OrderNumber - 1 do
BlockRead(FileStream, Orders[i], SizeOf(Orders[i]));

{Read Instrument ParaPointers}
for i := 0 to Header.InstrumentNumber - 1 do
BlockRead(FileStream, InsPtr[i], SizeOf(InsPtr[i]));

{Read Sample ParaPointers}
for i := 0 to Header.SampleNumber - 1 do
BlockRead(FileStream, SamPtr[i], SizeOf(SamPtr[i]));

{Read Pattern ParaPointers}
for i := 0 to Header.PatternNumber - 1 do
BlockRead(FileStream, PatPtr[i], SizeOf(PatPtr[i]));


{Read Instruments} // Only Reads New Instrument Type!!!
if (Header.CompatableWith >= $200) then
for i := 0 to Header.InstrumentNumber - 1 do
begin
Seek(FileStream, InsPtr[i]);

BlockRead(FileStream, Instruments[i].IMPI, SizeOf(Instruments[i].IMPI));
BlockRead(FileStream, Instruments[i].DOSFileName, SizeOf(Instruments[i].DOSFileName));
BlockRead(FileStream, Instruments[i].Reserved1, SizeOf(Instruments[i].Reserved1));
BlockRead(FileStream, Instruments[i].NewNoteAction, SizeOf(Instruments[i].NewNoteAction));
BlockRead(FileStream, Instruments[i].DuplicateCheckType, SizeOf(Instruments[i].DuplicateCheckType));
BlockRead(FileStream, Instruments[i].DuplicateCheckAction, SizeOf(Instruments[i].DuplicateCheckAction));
BlockRead(FileStream, Instruments[i].FadeOut, SizeOf(Instruments[i].FadeOut));
BlockRead(FileStream, Instruments[i].PitchPanSeparation, SizeOf(Instruments[i].PitchPanSeparation));
BlockRead(FileStream, Instruments[i].PitchPanCenter, SizeOf(Instruments[i].PitchPanCenter));
BlockRead(FileStream, Instruments[i].GlobalVolume, SizeOf(Instruments[i].GlobalVolume));
BlockRead(FileStream, Instruments[i].DefaultPan, SizeOf(Instruments[i].DefaultPan));
BlockRead(FileStream, Instruments[i].RandomVolume, SizeOf(Instruments[i].RandomVolume));
BlockRead(FileStream, Instruments[i].RandomPanning, SizeOf(Instruments[i].RandomPanning));
BlockRead(FileStream, Instruments[i].TrackerVersion, SizeOf(Instruments[i].TrackerVersion));
BlockRead(FileStream, Instruments[i].NumberOfSamples, SizeOf(Instruments[i].NumberOfSamples));
BlockRead(FileStream, Instruments[i].Reserved2, SizeOf(Instruments[i].Reserved2));
BlockRead(FileStream, Instruments[i].InstrumentName, SizeOf(Instruments[i].InstrumentName));
BlockRead(FileStream, Instruments[i].Reserved3, SizeOf(Instruments[i].Reserved3));
BlockRead(FileStream, Instruments[i].MIDIChannel, SizeOf(Instruments[i].MIDIChannel));
BlockRead(FileStream, Instruments[i].MIDIProgram, SizeOf(Instruments[i].MIDIProgram));
BlockRead(FileStream, Instruments[i].Reserved4, SizeOf(Instruments[i].Reserved4));

// Read Note/Sample Keyboard Table
for j := 0 to 119 do
for k := 0 to 1 do
BlockRead(FileStream, Instruments[i].NoteSampleKeyboardTable[j][k], SizeOf(Instruments[i].NoteSampleKeyboardTable[j][k]));

// Read Envelopes
for j := 0 to 2 do
begin
BlockRead(FileStream, Instruments[i].Envelopes[j].Flag, SizeOf(Instruments[i].Envelopes[j].Flag));
BlockRead(FileStream, Instruments[i].Envelopes[j].NumberOfNodePoints, SizeOf(Instruments[i].Envelopes[j].NumberOfNodePoints));
BlockRead(FileStream, Instruments[i].Envelopes[j].LoopBegin, SizeOf(Instruments[i].Envelopes[j].LoopBegin));
BlockRead(FileStream, Instruments[i].Envelopes[j].LoopEnd, SizeOf(Instruments[i].Envelopes[j].LoopEnd));
BlockRead(FileStream, Instruments[i].Envelopes[j].SustainLoopBegin, SizeOf(Instruments[i].Envelopes[j].SustainLoopBegin));
BlockRead(FileStream, Instruments[i].Envelopes[j].SustainLoopEnd, SizeOf(Instruments[i].Envelopes[j].SustainLoopEnd));

// Read Envelope Nodes
for k := 0 to 24 do
begin
if (j = 0) then // First Envelope for Volume(0 to 64)
begin
BlockRead(FileStream, ByteBuffer, 1);
Instruments[i].Envelopes[j].Nodes[k].Value := ByteBuffer;
end
else // Second & Third Envelopes for Panning & Pitch, respectively(-32 to +32)
begin
BlockRead(FileStream, ShortIntBuffer, 1);
Instruments[i].Envelopes[j].Nodes[k].Value := ShortIntBuffer;
end;
BlockRead(FileStream, Instruments[i].Envelopes[j].Nodes[k].Tick, SizeOf(Instruments[i].Envelopes[j].Nodes[k].Tick));
end;

// Skip 1 Byte
BlockRead(FileStream, ByteBuffer, SizeOf(ByteBuffer));
end;

// Skip 7 Wasted Bytes
for j := 0 to 6 do
BlockRead(FileStream, ByteBuffer, SizeOf(ByteBuffer));
end;

{Read Sample Headers}
for i := 0 to Header.SampleNumber - 1 do
begin
Seek(FileStream, SamPtr[i]);

BlockRead(FileStream, Samples[i].IMPS, SizeOf(Samples[i].IMPS));
BlockRead(FileStream, Samples[i].DOSFileName, SizeOf(Samples[i].DOSFileName));
BlockRead(FileStream, Samples[i].Reserved1, SizeOf(Samples[i].Reserved1));
BlockRead(FileStream, Samples[i].GlobalVolume, SizeOf(Samples[i].GlobalVolume));

// Sample Flags
BlockRead(FileStream, Samples[i].Flags, SizeOf(Samples[i].Flags));
//Bit#0: ON = Sample associated with header.
// OFF= No sample. (No sampledata either!)
if (Samples[i].Flags AND 1 > 0) then
Samples[i].isSample := True
else
Samples[i].isSample := False;
//Bit#1: ON = 16-bit, OFF = 8-bit.
if (Samples[i].Flags AND 2 > 0) then
Samples[i].is16Bit := True
else
Samples[i].is16Bit := False;
//Bit#2: ON = Stereo, OFF = Mono.
//(Stereo samples are not supported yet.)
if (Samples[i].Flags AND 4 > 0) then
Samples[i].isStereo := True
else
Samples[i].isStereo := False;
//Bit#4: ON = Use looping
if (Samples[i].Flags AND 16 > 0) then
Samples[i].isLoop := True
else
Samples[i].isLoop := False;
//Bit#5: ON = Use sustain loop
if (Samples[i].Flags AND 32 > 0) then
Samples[i].isSustainLoop := True
else
Samples[i].isSustainLoop := False;
//Bit#6: ON = Ping Pong (bi-directional) loop,
// OFF= Forwards loop
if (Samples[i].Flags AND 64 > 0) then
Samples[i].isPingPongLoop := True
else
Samples[i].isPingPongLoop := False;
//Bit#7: ON = Ping Pong Sustain loop,
// OFF= Forwards Sustain loop
if (Samples[i].Flags AND 128 > 0) then
Samples[i].isPingPongSustainLoop := True
else
Samples[i].isPingPongSustainLoop := False;

BlockRead(FileStream, Samples[i].Volume, SizeOf(Samples[i].Volume));
BlockRead(FileStream, Samples[i].SampleName, SizeOf(Samples[i].SampleName));
BlockRead(FileStream, Samples[i].CreatedWith, SizeOf(Samples[i].CreatedWith));
BlockRead(FileStream, Samples[i].DefaultPanning, SizeOf(Samples[i].DefaultPanning));
BlockRead(FileStream, Samples[i].Length, SizeOf(Samples[i].Length));
BlockRead(FileStream, Samples[i].LoopStart, SizeOf(Samples[i].LoopStart));
BlockRead(FileStream, Samples[i].LoopEnd, SizeOf(Samples[i].LoopEnd));
BlockRead(FileStream, Samples[i].C5Speed, SizeOf(Samples[i].C5Speed));
BlockRead(FileStream, Samples[i].SustainLoopStart, SizeOf(Samples[i].SustainLoopStart));
BlockRead(FileStream, Samples[i].SustainLoopEnd, SizeOf(Samples[i].SustainLoopEnd));
BlockRead(FileStream, Samples[i].SamplePointer, SizeOf(Samples[i].SamplePointer));

BlockRead(FileStream, Samples[i].VibratoSpeed, SizeOf(Samples[i].VibratoSpeed));
BlockRead(FileStream, Samples[i].VibratoDepth, SizeOf(Samples[i].VibratoDepth));
BlockRead(FileStream, Samples[i].VibratoRate, SizeOf(Samples[i].VibratoRate));
BlockRead(FileStream, Samples[i].VibratoType, SizeOf(Samples[i].VibratoType));
end;

{Determine Number Of Channels from Pattern Data}
HighestChannel := -1;
for i := 0 to Header.PatternNumber - 1 do
begin
Seek(FileStream, PatPtr[i]);
// This is the length of the packed pattern data - No need to store this data
BlockRead(FileStream, WordBuffer, SizeOf(WordBuffer));
// Read Number Of Rows for Pattern
BlockRead(FileStream, WordBuffer, SizeOf(WordBuffer));
NumberOfRows := WordBuffer;
// 4 Wasted Bytes!
for j := 0 to 1 do
BlockRead(FileStream, WordBuffer, SizeOf(WordBuffer));
// Read Notes
j := 0;
repeat
begin
// Get Next Channel Marker
BlockRead(FileStream, ByteBuffer, SizeOf(ByteBuffer));
if (ByteBuffer > 0) then
begin
if ((ByteBuffer - 1) AND 63 > HighestChannel) then
HighestChannel := (ByteBuffer - 1) AND 63;
// IF note has a mask
if (ByteBuffer AND 128 > 0) then
begin
BlockRead(FileStream, ByteBuffer2, SizeOf(ByteBuffer2));
// Has Note
if (ByteBuffer2 AND 1 > 0) then
BlockRead(FileStream, ByteBuffer3, SizeOf(ByteBuffer3));
// Has Instrument
if (ByteBuffer2 AND 2 > 0) then
BlockRead(FileStream, ByteBuffer3, SizeOf(ByteBuffer3));
// Has Volume/Pan
if (ByteBuffer2 AND 4 > 0) then
BlockRead(FileStream, ByteBuffer3, SizeOf(ByteBuffer3));
// Has Effect & Parameter
if (ByteBuffer2 AND 8 > 0) then
begin
BlockRead(FileStream, ByteBuffer3, SizeOf(ByteBuffer3));
BlockRead(FileStream, ByteBuffer3, SizeOf(ByteBuffer3));
end;
end;
end;
inc(j);
end;
until (j > NumberOfRows);
end;
NumberOfChannels := HighestChannel + 1;

{Read Patterns}
for i := 0 to Header.PatternNumber - 1 do
begin
Seek(FileStream, PatPtr[i]);
// This is the length of the packed pattern data - No need to store this data
BlockRead(FileStream, WordBuffer, SizeOf(WordBuffer));

// Init next Pattern
Patterns[i] := IT_Pattern.Create;

BlockRead(FileStream, Patterns[i].NumberOfRows, SizeOf(Patterns[i].NumberOfRows));

// 4 Wasted Bytes!
for j := 0 to 1 do
BlockRead(FileStream, WordBuffer, SizeOf(WordBuffer));

Patterns[i].NumberOfNotes := NumberOfChannels * Patterns[i].NumberOfRows;
SetLength(Patterns[i].Notes, Patterns[i].NumberOfNotes);

// Read Notes
j := 0;
repeat
begin
BlockRead(FileStream, ByteBuffer, SizeOf(ByteBuffer));
if (ByteBuffer > 0) then
begin
Patterns[i].Notes[j].Channel := (ByteBuffer - 1) AND 63;

// IF note has a mask
if (ByteBuffer AND 128 > 0) then
begin
BlockRead(FileStream, ByteBuffer2, SizeOf(ByteBuffer2));

// Has Note
if (ByteBuffer2 AND 1 > 0) then
BlockRead(FileStream, Patterns[i].Notes[j].Note, SizeOf(Patterns[i].Notes[j].Note));

// Has Instrument
if (ByteBuffer2 AND 2 > 0) then
BlockRead(FileStream, Patterns[i].Notes[j].Instrument, SizeOf(Patterns[i].Notes[j].Instrument));

// Has Volume/Pan
if (ByteBuffer2 AND 4 > 0) then
BlockRead(FileStream, Patterns[i].Notes[j].VolumePan, SizeOf(Patterns[i].Notes[j].VolumePan));

// Has Effect & Parameter
if (ByteBuffer2 AND 8 > 0) then
begin
BlockRead(FileStream, Patterns[i].Notes[j].Effect, SizeOf(Patterns[i].Notes[j].Effect));
BlockRead(FileStream, Patterns[i].Notes[j].EffectParameter, SizeOf(Patterns[i].Notes[j].EffectParameter));
end;

// Last Note
if (ByteBuffer2 AND 16 > 0) then
Patterns[i].Notes[j].lastNote := True
else
Patterns[i].Notes[j].lastNote := False;

// Last Instrument
if (ByteBuffer2 AND 32 > 0) then
Patterns[i].Notes[j].lastInstrument := True
else
Patterns[i].Notes[j].lastInstrument := False;

// Last Volume/Pan
if (ByteBuffer2 AND 64 > 0) then
Patterns[i].Notes[j].lastVolumePan := True
else
Patterns[i].Notes[j].lastVolumePan := False;

// Last Effect & Parameter
if (ByteBuffer2 AND 128 > 0) then
Patterns[i].Notes[j].lastEffect := True
else
Patterns[i].Notes[j].lastEffect := False;
end;
end;
inc(j);
end;
until (j > Patterns[i].NumberOfRows);
end;

{Read Samples}
for i := 0 to Header.SampleNumber - 1 do
if (Samples[i].SamplePointer > 0) and
(Samples[i].SamplePointer < FileLength) and
(Samples[i].Length > 0) then
begin
// //
// Determine Audio Compression //
// //
if (Samples[i].Length > MAX_SAMPLE_LENGTH) then
Samples[i].Length := MAX_SAMPLE_LENGTH;
if (Samples[i].CreatedWith AND 1 > 0) then
flags := RS_PCM8S
else
flags := RS_PCM8U;
if (Samples[i].Flags AND 2 > 0) then
begin
flags := flags + 5;
if (Samples[i].Flags AND 4 > 0) then
flags := flags OR RSF_STEREO;
Samples[i].is16Bit := True;
// IT 2.14 16-bit packed sample ?
if (Samples[i].Flags AND 8 > 0) then
if (Header.CompatableWith >= $215) and
(Samples[i].CreatedWith AND 4 > 0) then
flags := RS_IT21516
else
flags := RS_IT21416;
end
else
begin
if (Samples[i].Flags AND 4 > 0) then
flags := flags OR RSF_STEREO;
if (Samples[i].CreatedWith = $FF) then
flags := RS_ADPCM4
else
// IT 2.14 8-bit packed sample ?
if (Samples[i].Flags AND 8 > 0) then
if (Header.CompatableWith >= $215) and
(Samples[i].CreatedWith AND 4 > 0) then
flags := RS_IT2158
else
flags := RS_IT2148;
end;
// ReadSample(&Ins[nsmp + 1], flags, (LPSTR)(lpStream + Samples[i].SamplePointer),
// FileLength - Samples[i].SamplePointer);
// //
// Decompress Sample Data //
// //
Len := 0;
Samples[i].SampleLength := Samples[i].Length + 6;
if (flags AND RSF_16BIT > 0) then
begin
Samples[i].SampleLength := Samples[i].SampleLength * 2;
Samples[i].is16Bit := True;
end;
if (flags AND RSF_STEREO > 0) then
begin
Samples[i].SampleLength := Samples[i].SampleLength * 2;
Samples[i].isStereo := True;
end;

// IT 2.14 compressed samples
case (flags) of
RS_IT2148, RS_IT21416, RS_IT2158, RS_IT21516:
begin
Len := FileLength - Samples[i].SamplePointer;
if (Len < 4) then
Continue;
if (flags = RS_IT214 or (flags = RS_IT215 then
begin
//ITUnpack8Bit(Samples[i].SampleData, Samples[i].Length, Samples[i].SamplePointer,
// Len, (flags = RS_IT215)
end
else
begin
//ITUnpack16Bit(Samples[i].SampleData, Samples[i].Length, Samples[i].SamplePointer,
// Len, (flags = RS_IT21516));
end;
Continue;
end;
end;
end;

for i := 0 to Header.SampleNumber - 1 do
if (Samples[i].isSample) and (Samples[i].Length > 0) and
(Samples[i].SamplePointer + Samples[i].Length <= FileSize(FileStream)) then
begin
{Allocate Memory for Sample Data And assign SampleData pointer to it}
// HeaderSize := 192 + Header.OrderNumber + Header.InstrumentNumber * 4 +
// Header.SampleNumber * 4 + Header.PatternNumber * 4;
HeaderSize := 0;
Seek(FileStream, Samples[i].SamplePointer - HeaderSize);
GetMem(Samples[i].SampleData, Samples[i].SampleLength);

BlockRead(FileStream, Samples[i].SampleData^, Samples[i].SampleLength);
end;

CloseFile(FileStream);
end;

end.[/pascal]