/*******************************************************************************

  PlaySMF V1.1 - minimal Standard MIDI File type 0 & 1 player
  Written in 1998 by Alastair M. Robinson.

  Just a quick wrapper to try out and demonstrate my SMF PlayRoutines.

  Compiled with the totally brilliant VBCC (Using MinStart.o, which is why
  the dos.library is declared and opened.)

  Run from the shell with the filename as an argument.  You can also supply
  a tempo if you want, but if the file contains a tempo of its own, the tempo
  provided at the command-line will be overridden.
  Example:
  PlaySMF Central6.mid tempo 96

*******************************************************************************/

#include <exec/types.h>
#include <exec/ports.h>
#include <exec/semaphores.h>
#include <dos/dos.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include "Disk.h"
#include "/PlayRoutine/B5MIDI.h"
#include "Main.h"

struct Library *DOSBase;
struct RDArgs *myargs;
unsigned char *MIDIFile;

char *PortName="PlaySMF.rendezvous";
struct MsgPort *RendezvousPort;

void SongEndHandler();  /* This makes SongEndHandler() visible in main(), where
                           it is referenced as &SongEndHandler.  Without this
                           line, the SongEndHandler() function would have to
                           precede main(). */

int main()
{
  ULONG sigs=0,sigswait=0;
  if(Main_Setup())
  {
    sigswait=(1<<RendezvousPort->mp_SigBit)|SIGBREAKF_CTRL_C;
    PlayMIDIFile(&SongEndHandler);  /* Set the song playing */
    do
    {
      sigs=Wait(sigswait);
    }
    while((sigs&sigswait)==0);
  }
  else
    PrintFault(IoErr(),"Failed");

  Main_Cleanup(sigs); /* Cleanup stuff MUST be called even if setup failed! */
  return(0);
}

void SongEndHandler()
{
  Signal(MIDIContext.ParentTask,SIGBREAKF_CTRL_C);
  /* This is about as simple as SongEndHandlers get.  This one will tell the
     main task to quit when the song finishes.  If you want the song to loop
     instead, just put the line:
     PlayMIDIFile(&SongEndHandler);
     in place of the Signal() line.
  */
}

BOOL Main_Setup()
{
  ULONG Arguments[]={0,0,0};
  ULONG bpm=0;
  enum MIDIErrors err;

  if(!(RendezvousPort=CreateMsgPort()))
    return(FALSE);

  RendezvousPort->mp_Node.ln_Name=PortName;

  HandleRendezvous();

  AddPort(RendezvousPort);

  if(!(DOSBase=OpenLibrary("dos.library",0)))
    return(FALSE);

  if(!(myargs=ReadArgs("FILENAME/A,TEMPO/N",Arguments,NULL)))
    return(FALSE);

  if(Arguments[1])
  {
    bpm=*((ULONG*)Arguments[1]);
  }

  if(!(MIDI_Setup()))
    return(FALSE);

  ObtainSemaphore(&MIDIContext.DataSemaphore);

  if(!(MIDIFile=LoadFile((char *)Arguments[0],0)))
    return(FALSE);

  err=InitMIDIFile(MIDIFile,bpm);

  ReleaseSemaphore(&MIDIContext.DataSemaphore);

  switch(err)
  {
    case MIDI_OK:
      return(TRUE); break;
    case MIDI_OutOfMemory:
      PutStr("Not enough memory!\n"); break;
    case MIDI_BadTiming:
      PutStr("Unsupported timing model!\n"); break;
    case MIDI_NotMIDIFile:
      PutStr("Not a Standard Midi File!\n"); break;
        /* N.B. printf() is not available when minstart is used! */
  }
}

void Main_Cleanup(ULONG sigs)
{
  MIDI_Cleanup();

  if(MIDIFile)
    FreeVec(MIDIFile);

  if(RendezvousPort)
  {
    if(sigs&(1<<RendezvousPort->mp_SigBit)) /* Were we stopped by another */
    {                                       /* copy of PlaySMF?           */
      WaitPort(RendezvousPort);
      ReplyMsg(GetMsg(RendezvousPort)); /* Tell other task the coast is clear! */
    }
    RemPort(RendezvousPort);
    DeleteMsgPort(RendezvousPort);
    RendezvousPort=NULL;
  }

  if(myargs)
    FreeArgs(myargs);
}


/* The HandleRendezvous() function checks to see if PlaySMF is already running,
   and if so, it sends a message to the other task's Rendezvous port.  The
   other task will free all its resources before replying to this message.  */

void HandleRendezvous()
{
  static struct Message mes;
  struct MsgPort *otherport;

  mes.mn_ReplyPort=RendezvousPort;

  Forbid();
  if(otherport=FindPort(PortName))
  {
    PutMsg(otherport,&mes);
    Permit();
    WaitPort(RendezvousPort);
    GetMsg(RendezvousPort);
  }
  else
    Permit();
}

