PROGRAM SDSLoad;



{ Written By Sid (SJones@hort.cri.nz) Any comments on the  }

{ following code!? are appreciated, even if they are insulting. }

{ It's the only way I'll learn                                  }

{                                                               }

{ Written with reference to EMUs SYS-EX documentation, and SDS  }





USES    Midi, crt;



TYPE    NameOfFile   = STRING[60];



CONST   { ID's }

        Emu          = $18;

        Emax         = $02;  { emax 1 only ?}



        { System Exclusive Commands }

        SysExStart   = $F0;

        EOX          = $F7;

        ReqReady     = $08;

        SendReady    = $38;



        { Values for Emax status, Follows SDS protocol}

        EmaxACK      = $7F;

        EmaxNAK      = $7E;

        EmaxCAN      = $7D;

        EmaxWAIT     = $7C;



        { Sizes and Positions in SDS Data }

        HeaderSize   =  21;  { as per SDS }

        PacketSize   = 127;  {     "      }

        PacketNoPos  =   5;  {     "      }

        CheckSumPos  = 126;  {     "      }



VAR     MidiData      : INTEGER;

        TheName       : NameOfFile;

        FromF         : FILE;

        NumRead       : WORD;

        HeaderBuffer  : ARRAY[1..HeaderSize] OF BYTE;

        PacketBuffer  : ARRAY[1..PacketSize] OF BYTE;

        EmaxStatus    : INTEGER;





PROCEDURE Welcome;

BEGIN

  ClrScr;

  WriteLn('Written By Sid (SJones@hort.cri.nz) with reference to Emax 1 ');

  WriteLn('SYS-EX manual, midi port routines were modified from a listing in ');

  WriteLn('Inside Turbo Pascal, Source compiled with Turbo Pascal 6.0 However ');

  WriteLn('I think the program could also be compiled with lower versions.');

  WriteLn;

  WriteLn('Source will be available from the EMAX ftp site');

  WriteLn;

  WriteLn('       sweaty.palm.cri.nz  (161.66.1.11)  in emax/sds ');

  WriteLn;

  WriteLn('Please report any bugs to me at the above email address');

  WriteLn;

END;



PROCEDURE ClearBit;

{ Clear a bit of the screen }

BEGIN

  GotoXY(1,23);ClrEol;

  GotoXY(1,24);ClrEol;

END;





PROCEDURE MyHALT;

{ Halts the program and closes the one open file }

BEGIN

  Close(fromF);

  HALT;

END;





FUNCTION FileExists(FileName: NameOfFile) : BOOLEAN;

{ Check if file is present }

VAR

  f: FILE;

BEGIN

  {$I-}  Assign(f, FileName);

         Reset(f);  Close(f);

  {$I+}  FileExists := IOResult = 0;

END;





PROCEDURE Init;

{ Set up MIDI interface, may be specific for MPU-401     }

{ type interface I have no way to check other interfaces }

BEGIN

  Write('Resetting MPU INTERFACE');

  ResetMIDIInterface;             { reset }

  SendMIDICommand (UARTMode);     { set to UART mode }

  WriteLn('.......Reset Successful!');

  WriteLn;

END;





PROCEDURE CheckReady;

{ ask the Emax if it's ready to recieve data, a bit of dumbness      }

{ as suits the Emax i.e. writes e's to the screen until emax replies }

VAR

  junk : INTEGER;

BEGIN

  Write('Wh');

  SendMidiData(SysExStart);   { these 5 statements are the }

  SendMidiData(Emu);          { request to send            }

  SendMidiData(Emax);

  SendMidiData(ReqReady);

  SendMidiData(EOX);

  REPEAT

    junk := GetMidiData;    { loop until Emax is Ready }

    Write('e');

  UNTIL junk = SendReady;

  WriteLn('re''s EMAX.............      Emax is ready');

  WriteLn;

END;





PROCEDURE GetfileNameAndOpen (VAR TheName : NameOfFile);

{ Opens file and sets record size to 1, Blockreads can then be set to }

{ the header size and packet size                                     }

BEGIN

  ClearBit;

  Write('Name of the Sample Dump File :- ');

  ReadLn(TheName);ClrEol;

  IF NOT FileExists(TheName) THEN

    REPEAT

      ClearBit;

      Write('Can''t find the file ', TheName, ' enter again : ');

      ReadLn(TheName);

      ClrEol;

    UNTIL FileExists(TheName);

  Assign(FromF, TheName);

  Reset(FromF, 1); { Record size = 1 }

END;





FUNCTION GetEmaxStatus : INTEGER;

{ Handshaking Messages from SDS protocol }

VAR

  Junk : INTEGER;

BEGIN

  Junk := GetMidiData;          { Should be F0 }

  Junk := GetMidiData;          {     "     7E }

  Junk := GetMidiData;          {     "     channel number }



  GetEmaxStatus := GetMidiData; {     "     essential byte of message }



  Junk := GetMidiData;          {     "     packet number byte }

  Junk := GetMidiData;          {     "     F7 }

END;





PROCEDURE ReadHeader;

{ read the 21 bytes of header into buffer }

BEGIN

  WriteLn('Reading Header from ', FileSize(FromF), ' bytes...');

  BlockRead(FromF, HeaderBuffer, SizeOf(HeaderBuffer), NumRead);

END;





FUNCTION ReplyToHeader: BOOLEAN; FORWARD;

{ forward declaration of ReplyToHeader so that }

{ it is visible to SendHeader                  }





PROCEDURE SendHeader;

{ send the header information to Emax, emax should reply }

{ Check the messages coming back using ReplyToHeader     }

VAR

  i : BYTE;

BEGIN

  WriteLn('Sending, Emax clock thing should be revolving on front panel');

  FOR i := 1 TO HeaderSize DO

    BEGIN

      SendMidiData(HeaderBuffer[i]);

      Delay(5); { may not be necessary EMU think so }

    END;

  REPEAT UNTIL ReplyToHeader;

END;





FUNCTION ReplyToHeader: BOOLEAN;

{ a bit of a cludge but it seems to work! read the midiport and look for }

{ the status byte corresponding to EmaxACK, EmaxNAK, EmaxCAN or EmaxWAIT }

VAR

  Status : INTEGER;

BEGIN

  ReplyToHeader := FALSE;

  Status := EmaxWAIT;

  WHILE Status = EmaxWAIT DO

    BEGIN

      Status := GetEmaxStatus;

      CASE Status OF

        EmaxACK  : BEGIN

                     WriteLn('Header Accepted, Sample will start to load');

                     ReplyToHeader := TRUE;

                     EXIT;

                   END;

        EmaxNAK  : BEGIN

                     WriteLn('Emax did''t acknowledge :- retrying');

                     EXIT;

                   END;

        EmaxWAIT : WriteLn('waiting for Emax ');

      END;{case}

    END; {while}

  IF Status = EmaxCAN THEN

    BEGIN

      Write('Emax has cancelled after receiving the header  ');

      Write('There is probably not enough available ');

      WriteLn('memory in EMAX.......       Exiting');

      MyHALT;

   END;

END;





PROCEDURE ReadDataPacket;

{ Read the data packet into buffer no checks are made of checksum }

BEGIN

  BlockRead(FromF, PacketBuffer, SizeOf(PacketBuffer), NumRead);

END;





FUNCTION ReplyToPacket : BOOLEAN; FORWARD;

{ Forward declaration so it's visible to SendDataPacket }





PROCEDURE SendDataPacket;

{  send the packets to Emax, Emax should send reply   }

{ Check the messages coming back using ReplyToHeader  }

VAR

  i : BYTE;

BEGIN

  FOR i := 1 TO PacketSize DO

    SendMidiData(PacketBuffer[i]);

  REPEAT UNTIL ReplyToPacket;

END;





FUNCTION ReplyToPacket : BOOLEAN;

{ a bit of a cludge but it seems to work! read the midiport and look for }

{ the status byte corresponding to EmaxACK, EmaxNAK, EmaxCAN or EmaxWAIT }

VAR

  Status : INTEGER;

BEGIN

  ReplyToPacket := FALSE;

  Status := EmaxWAIT;

  WHILE Status = EmaxWAIT DO

    BEGIN

      Status := GetEmaxStatus;

      CASE Status OF

        EmaxACK  : BEGIN

                     ReplyToPacket := TRUE;

                     EXIT;

                   END;

        EmaxNAK  : BEGIN

                     WriteLn('Got a NAK retrying');

                     EXIT;

                   END;

        EmaxWAIT : WriteLn('waiting for Emax');

      END;

    END;

  IF Status = EmaxCAN  THEN

    BEGIN

      WriteLn('Emax has Cancelled the dump ..... Exiting');

      MyHALT;

    END;

  END;



PROCEDURE ReadAndSendPackets;

{ Reads and sends the blocks read, provides some indication  }

{ loading, approx 45 seconds for 100Kbytes, writing the dots }

{ causes no appreciable increse in the net loading time      }

{ Closes file when finished                                  }

VAR

  Count : WORD;

BEGIN

  Count := 1;

  REPEAT

    ReadDataPacket;

    SendDataPacket;

    Count := Count + 1;

    IF Count MOD 20 = 0 THEN Write('.');

  UNTIL Eof(FromF) OR (NumRead = 0);

  Close(FromF);

END;





PROCEDURE ByeBye;

BEGIN

  WriteLn;

  WriteLn('All Done press a key');

  REPEAT UNTIL KeyPressed;

  ClrScr;

  WriteLn('If you got to here then the SDS sample MAY have loaded correctly it ');

  WriteLn('should be on key A1.  You will have to go to PRESET DEFINITION');

  WriteLn('EDIT ASSIGMENT to move it onto the keyboard.');

END;





BEGIN

  Welcome;

  Init;

  CheckReady;

  GetFileNameAndOpen(TheName);

  ReadHeader;

  SendHeader;

  ReadAndSendPackets;

  ByeBye;

END.

