home *** CD-ROM | disk | FTP | other *** search
- UNIT OktLoader;
-
- INTERFACE
-
- USES Objects, SongUnit;
-
-
-
-
- PROCEDURE LoadOktFileFormat (VAR Song: TSong; VAR St: TStream; VAR Header: TSongHeader);
-
-
-
-
- IMPLEMENTATION
-
- USES SongUtils, SongElements, IFF, AsciiZ;
-
-
-
-
- TYPE
- TModOktIdString = ARRAY[1..8] OF CHAR; { Oktalizer Id string (at the start of the file). }
-
- CONST
- ModOktIdString : TModOktIdString = ('O', 'K', 'T', 'A', 'S', 'O', 'N', 'G');
-
- TYPE
-
- { Note in the file. 4 bytes. }
-
- POktFileNote = ^TOktFileNote;
- TOktFileNote = RECORD
- CASE INTEGER OF
- 1: (l : LONGINT);
- 2: (w1, w2 : WORD);
- 3: (b1, b2, b3, b4 : BYTE);
- END;
-
- POktFilePattern = ^TOktFilePattern;
- TOktFilePattern =
- RECORD
- CASE BYTE OF
- 4 : ( Patt4 : ARRAY [0..63] OF ARRAY [1..4] OF TOktFileNote );
- 5 : ( Patt5 : ARRAY [0..63] OF ARRAY [1..5] OF TOktFileNote );
- 6 : ( Patt6 : ARRAY [0..63] OF ARRAY [1..6] OF TOktFileNote );
- 7 : ( Patt7 : ARRAY [0..63] OF ARRAY [1..7] OF TOktFileNote );
- 8 : ( Patt8 : ARRAY [0..63] OF ARRAY [1..8] OF TOktFileNote );
- END;
-
-
-
-
-
- TYPE
- TOktFile =
- OBJECT(TIffFile)
- Song : PSong;
- OktPBODCount : WORD;
- OktSBODCount : WORD;
- OktTrackCount : WORD;
- OktMaxChannels : WORD;
-
- CONSTRUCTOR Init(VAR MySong: TSong);
- DESTRUCTOR Done; VIRTUAL;
-
- FUNCTION DoBlock(VAR St: TStream;
- Id: TIffBlockIdent; Size: LONGINT) : BOOLEAN; VIRTUAL;
-
- FUNCTION OktProcCMOD(VAR St: TStream; Size: LONGINT) : BOOLEAN;
- FUNCTION OktProcSAMP(VAR St: TStream; Size: LONGINT) : BOOLEAN;
- FUNCTION OktProcSPEE(VAR St: TStream; Size: LONGINT) : BOOLEAN;
- FUNCTION OktProcSLEN(VAR St: TStream; Size: LONGINT) : BOOLEAN;
- FUNCTION OktProcPLEN(VAR St: TStream; Size: LONGINT) : BOOLEAN;
- FUNCTION OktProcPATT(VAR St: TStream; Size: LONGINT) : BOOLEAN;
- FUNCTION OktProcPBOD(VAR St: TStream; Size: LONGINT) : BOOLEAN;
- FUNCTION OktProcSBOD(VAR St: TStream; Size: LONGINT) : BOOLEAN;
- END;
-
-
-
-
-
-
-
-
-
-
- FUNCTION TOktFile.OktProcCMOD(VAR St: TStream; Size: LONGINT) : BOOLEAN;
- VAR
- MyBuff :
- RECORD
- w1 : WORD;
- w2 : WORD;
- w3 : WORD;
- w4 : WORD;
- END;
- BEGIN
- OktProcCMOD := FALSE;
- IF Size <> 8 THEN EXIT;
-
- St.Read(MyBuff, Size);
-
- { Ignore the words until we know what they mean. I just know they are "channel modes". }
-
- OktProcCMOD := TRUE;
- END;
-
-
- FUNCTION TOktFile.OktProcSAMP(VAR St: TStream; Size: LONGINT) : BOOLEAN;
- TYPE
- TOktFileInstrument = RECORD
- Name : ARRAY [1..20] OF CHAR; { AsciiZ string, name of the instrument. }
- Len : LONGINT; { Length of the sample DIV. }
- RepS : WORD;
- RepL : WORD;
- fill1 : BYTE;
- Vol : BYTE; { Default volume. }
- fill2 : WORD;
- END;
- VAR
- MyBuff : TOktFileInstrument;
- Instr : TInstrumentRec;
- Instrument : PInstrument;
- r : WORD;
- i : WORD;
- Rest : LONGINT;
- BEGIN
- OktProcSAMP := FALSE;
- IF Size MOD 32 <> 0 THEN EXIT;
-
- FillChar(Instr, SizeOf(Instr), 0);
-
- Instr.Data := NIL;
- Instr.Xtra := NIL;
- Instr.FTune := 0;
- Instr.Prop := 0;
-
- i := 1;
- WHILE Size >= 32 DO
- BEGIN
- St.Read(MyBuff, 32);
- Instr.len := SwapLong(MyBuff.Len);
- Instr.reps := SWAP(MyBuff.RepS) SHL 1;
- Instr.repl := SWAP(MyBuff.RepL) SHL 1;
- Instr.vol := MyBuff.Vol;
-
- Instrument := Song^.GetInstrument(i);
- IF Instr.Len > 0 THEN
- Instrument^.Change(@Instr)
- ELSE
- Instrument^.Change(NIL);
- Instrument^.SetName(StrASCIIZ(MyBuff.Name, 20) + ' ');
-
- INC(i);
- DEC(Size, 32);
- END;
-
- OktProcSAMP := TRUE;
- END;
-
-
- FUNCTION TOktFile.OktProcSPEE(VAR St: TStream; Size: LONGINT) : BOOLEAN;
- VAR
- Spee : WORD;
- BEGIN
- OktProcSPEE := FALSE;
- IF Size <> 2 THEN EXIT;
-
- St.Read(Spee, 2);
-
- Song^.InitialTempo := SWAP(Spee);
-
- OktProcSPEE := TRUE;
- END;
-
-
- FUNCTION TOktFile.OktProcSLEN(VAR St: TStream; Size: LONGINT) : BOOLEAN;
- BEGIN
- OktProcSLEN := TRUE;
- END;
-
-
- FUNCTION TOktFile.OktProcPLEN(VAR St: TStream; Size: LONGINT) : BOOLEAN;
- VAR
- Len : WORD;
- BEGIN
- OktProcPLEN := FALSE;
- IF Size <> 2 THEN EXIT;
-
- St.Read(Len, 2);
-
- Song^.SequenceLength := SWAP(Len);
-
- OktProcPLEN := TRUE;
- END;
-
-
- FUNCTION TOktFile.OktProcPATT(VAR St: TStream; Size: LONGINT) : BOOLEAN;
- VAR
- i : WORD;
- BEGIN
- IF Size > MaxSequence THEN
- Size := MaxSequence;
-
- St.Read(Song^.PatternSequence^, Size);
-
- FOR i := 1 TO SizeOf(Song^.PatternSequence^) DO
- INC(Song^.PatternSequence^[i]);
-
- OktProcPATT := TRUE;
- END;
-
-
- FUNCTION TOktFile.OktProcPBOD(VAR St: TStream; Size: LONGINT) : BOOLEAN;
- CONST
- FreqTable : ARRAY[0..35] OF WORD =
- (
- $0358,$0328,$02FB,$02D0,$02A7,$0281,$025D,$023B,$021B,$01FD,$01E0,$01C5,
- $01AC,$0194,$017D,$0168,$0154,$0141,$012F,$011E,$010E,$00FE,$00F0,$00E3,
- $00D6,$00CA,$00BF,$00B4,$00AA,$00A0,$0097,$008F,$0087,$007F,$0078,$0071
- );
- VAR
- i, j : WORD;
- Length : WORD;
- NumChannels : WORD;
- Patt : TOktFilePattern;
- Pattern : PPattern;
- FullTrack : TFullTrack;
- Track : PTrack;
- BEGIN
- OktProcPBOD := FALSE;
- IF Size < 6 THEN EXIT;
- IF Size > SizeOf(TOktFilePattern) + 2 THEN EXIT;
-
- St.Read(Length, 2);
- Length := SWAP(Length);
- IF Length > 64 THEN EXIT;
- NumChannels := (Size - 2) DIV (Length * 4);
- IF NumChannels > 8 THEN EXIT;
- IF NumChannels > OktMaxChannels THEN
- OktMaxChannels := NumChannels;
-
- Pattern := Song^.GetPattern(OktPBODCount);
- WITH Pattern^.Patt^ DO
- BEGIN
- NNotes := Length;
- Tempo := 0;
- BPM := 0;
- END;
-
- St.Read(Patt, Size-2);
-
- CASE NumChannels OF
- 4 : FOR i := 63 DOWNTO 0 DO
- FOR j := NumChannels DOWNTO 1 DO
- Patt.Patt8[i][j] := Patt.Patt4[i][j];
- 5 : FOR i := 63 DOWNTO 0 DO
- FOR j := NumChannels DOWNTO 1 DO
- Patt.Patt8[i][j] := Patt.Patt5[i][j];
- 6 : FOR i := 63 DOWNTO 0 DO
- FOR j := NumChannels DOWNTO 1 DO
- Patt.Patt8[i][j] := Patt.Patt6[i][j];
- 7 : FOR i := 63 DOWNTO 0 DO
- FOR j := NumChannels DOWNTO 1 DO
- Patt.Patt8[i][j] := Patt.Patt7[i][j];
- END;
-
- FillChar(FullTrack, SizeOf(FullTrack), 0);
-
- FOR j := 1 TO NumChannels DO
- BEGIN
- FOR i := 0 TO Length - 1 DO
- WITH FullTrack[i], Patt.Patt8[i][j] DO
- BEGIN
- Command := mcNone;
- Parameter := b4;
-
- CASE b3 OF
- { rs_portd-p } $1 : Command := mcTPortDown;
- { rs_portu-p } $2 : Command := mcTPortUp;
- { rs_arp-p } $A : Command := mcOktArp;
- { rs_arp2-p } $B : Command := mcOktArp2;
- $D : Command := mcNone; { rs_slided-p }
- { p-rs_filt } $F : Command := mcSetFilter;
- $11 : Command := mcNone; { p-rs_slideu }
- $15 : Command := mcNone; { p-rs_slided }
- { p-rs_posjmp }$19 : BEGIN
- Command := mcJumpPattern;
- Parameter := (Parameter AND $F) + (Parameter SHR 4)*10 + 1;
- END;
- { p-rs_release }$1B : Command := mcRetrigNote;
- { p-rs_cspeed }$1C : Command := mcSetTempo;
- $1E : Command := mcNone; { rs_slideu-p }
- { rs_volume-p }$1F : BEGIN
- IF Parameter <= 64 THEN
- BEGIN
- Command := mcSetVolume;
- END
- ELSE IF Parameter < $50 THEN
- BEGIN
- Command := mcVolSlide;
- Parameter := Parameter - $40;
- END
- ELSE IF Parameter < $60 THEN
- BEGIN
- Command := mcVolFineDown;
- Parameter := Parameter - $50;
- END
- ELSE IF Parameter < $70 THEN
- BEGIN
- Command := mcVolSlide;
- Parameter := (Parameter - $60) SHL 4;
- END
- ELSE IF Parameter < $80 THEN
- BEGIN
- Command := mcVolFineUp;
- Parameter := Parameter - $70;
- END
- END;
- ELSE Command := mcNone;
- END;
-
- IF b1 = 0 THEN
- BEGIN
- Period := 0;
- Instrument := 0;
- END
- ELSE
- BEGIN
- Period := FreqTable[b1-1];
- Instrument := b2 + 1;
- END;
-
- IF ((Command = mcEndPattern) OR (Command = mcJumpPattern)) AND
- (Pattern^.Patt^.NNotes > i + 1) THEN
- Pattern^.Patt^.NNotes := i + 1;
- END;
-
- Track := Song^.GetTrack(OktTrackCount);
- IF Track = NIL THEN
- BEGIN
- Song^.Status := msOutOfMemory;
- EXIT;
- END;
-
- Track^.SetFullTrack(FullTrack);
-
- Pattern^.Patt^.Channels[j] := OktTrackCount;
-
- INC(OktTrackCount);
- END;
-
- INC(OktPBODCount);
- OktProcPBOD := TRUE;
- END;
-
-
- FUNCTION TOktFile.OktProcSBOD(VAR St: TStream; Size: LONGINT) : BOOLEAN;
- VAR
- Instrument : PInstrumentRec;
- BEGIN
- OktProcSBOD := FALSE;
-
- WHILE (OktSBODCount <= 256) AND
- ((Song^.GetInstrument(OktSBODCount)^.Instr = NIL) OR
- (Song^.GetInstrument(OktSBODCount)^.Instr^.Len = 0) ) DO
- INC(OktSBODCount);
-
- Instrument := Song^.GetInstrument(OktSBODCount)^.Instr;
- IF Instrument = NIL THEN EXIT;
-
- Instrument^.Len := Size;
-
- GetMem(Instrument^.Data, Size);
-
- St.Read(Instrument^.Data^, Size);
-
- INC(OktSBODCount);
- OktProcSBOD := TRUE;
- END;
-
-
-
-
- FUNCTION TOktFile.DoBlock(VAR St: TStream;
- Id: TIffBlockIdent; Size: LONGINT) : BOOLEAN;
- BEGIN
- DoBlock := FALSE;
-
- IF (Id = 'CMOD') AND NOT OktProcCMOD(St, Size) THEN EXIT
- ELSE IF (Id = 'SAMP') AND NOT OktProcSAMP(St, Size) THEN EXIT
- ELSE IF (Id = 'SPEE') AND NOT OktProcSPEE(St, Size) THEN EXIT
- ELSE IF (Id = 'SLEN') AND NOT OktProcSLEN(St, Size) THEN EXIT
- ELSE IF (Id = 'PLEN') AND NOT OktProcPLEN(St, Size) THEN EXIT
- ELSE IF (Id = 'PATT') AND NOT OktProcPATT(St, Size) THEN EXIT
- ELSE IF (Id = 'PBOD') AND NOT OktProcPBOD(St, Size) THEN EXIT
- ELSE IF (Id = 'SBOD') AND NOT OktProcSBOD(St, Size) THEN EXIT;
-
- DoBlock := TRUE;
- END;
-
-
-
-
- CONSTRUCTOR TOktFile.Init(VAR MySong: TSong);
- BEGIN
- TIffFile.Init;
-
- OktPBODCount := 1;
- OktSBODCount := 1;
- OktTrackCount := 1;
- OktMaxChannels := 0;
-
- MySong.SetName(MySong.FileName);
- MySong.InitialTempo := 6;
- MySong.InitialBPM := 125;
- MySong.Volume := 255;
- MySong.NumChannels := 8;
-
- Song := @MySong;
- END;
-
-
-
-
- DESTRUCTOR TOktFile.Done;
- BEGIN
- Song^.NumChannels := OktMaxChannels;
- TIffFile.Done;
- END;
-
-
-
-
- PROCEDURE LoadOktFileFormat (VAR Song: TSong; VAR St: TStream; VAR Header: TSongHeader);
- VAR
- f : TOktFile;
- ModOkt : TModOktIdString ABSOLUTE Header;
- BEGIN
- Song.FileFormat := mffOktalizer;
-
- IF ModOkt <> ModOktIdString THEN
- BEGIN
- Song.Status := msNotLoaded;
- EXIT;
- END;
-
- Song.Status := msFileDamaged;
-
- St.Seek(St.GetPos + SizeOf(TModOktIdString));
-
- f.Init(Song);
- f.Parse(St);
- f.Done;
-
- IF Song.Status = msFileDamaged THEN
- Song.Status := msOk;
- END;
-
-
-
-
- END.
-