/*     
(c) Copyright 1988-1994 Microsoft Corporation.

Microsoft Bars&Pipes Professional Source Code License

This License governs use of the accompanying Software.
Microsoft hopes you find this Software useful.

You are licensed to do anything you want with the Software.

In return, we simply require that you agree:

1.      Not to remove any copyright notices from the Software.

2.      That the Software comes "as is", with no warranties.
        None whatsoever. This means no implied warranty of merchantability or
        fitness for a particular purpose or any warranty of non-infringement.
        Also, you must pass this disclaimer on whenever you distribute the Software.

3.      That we will not be liable for any of those types of damages known as indirect,
        special, consequential, or incidental related to the Software or this License,
        to the maximum extent the law permits. Also, you must pass this limitation of
        liability on whenever you distribute the Software.

4.      That if you sue anyone over patents that you think may apply to the Software
        for that person s use of the Software, your license to the Software ends automatically.

5.      That the patent rights Microsoft is licensing only apply to the Software,
        not to any derivatives you make.

6.      That your rights under the License end automatically if you breach this in any way.
*/
#include <exec/types.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#include <proto/rexxsyslib.h>
#include <rexx/errors.h>
#include <exec/memory.h>
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "/v.h"
#include "/CompilerSpecific.h"
#include "/tools.h"
#include "/environ.h"

//void kprintf(char *,...);

#define ID_REXX 0x52455858
#define HOST_PORT_NAME   "Bars&Pipes ARexx"
extern struct Functions *functions;
struct Library *RexxSysBase;   /* this is the rexx library base */
static struct MsgPort *rexxport;
static short shutdown;
static long shutdownbit;
static long unblockbit;
static struct Task *rexxtask;
short waiting;

typedef struct ARexxCommands
{
  char *command;
  short (*function)(char *args,long *primary,char *result);
} ARexxCommands;

struct Preload
{
  struct Preload *next;
  struct Environment environment;
  char filename[150];
};

struct Preload *songlist;

CHIP static UWORD  arexxoff[] = {
/*------ plane # 0: --------*/

  0x180,   0x0,   0x0,   0x0,   0x0,
  0x3c0,   0x0,   0x0,   0x0,   0x0,
  0xfc0,   0x200,   0x0,   0x0,   0x0,
  0x1fe0,   0x1f00,   0x0,   0x0,   0x0,
  0x3fe0,   0x7f80,   0x0,   0x0,   0x0,
  0x3fe1,   0xffc0,   0x0,   0x0,   0x0,
  0x3ff1,   0xffc0,   0x0,   0x0,   0x0,
  0x3ff3,   0xffe0,   0x0,   0x0,   0x0,
  0x3fff,   0xffe0,   0x0,   0x0,   0x0,
  0x3f33,   0xcc00,   0x0,   0x0,   0x0,
  0x3e61,   0xf306,   0x0,   0x0,   0x0,
  0x3e61,   0xf313,   0x0,   0x0,   0x0,
  0x1e60,   0xf319,   0x8000,   0x0,   0x0,
  0xcc8,   0xf319,   0x8000,   0x0,   0x0,
  0xccc,   0x7319,   0x8181,   0x8304,   0x1800,
  0x98c,   0x4313,   0x630,   0xc186,   0xc00,
  0x18c,   0x306,   0x618,   0x6303,   0x1800,
  0x186,   0x300,   0x4c18,   0x6103,   0x800,
  0x306,   0x310,   0xcc00,   0x3001,   0x8000,
  0x300,   0x318,   0xcc7e,   0x181c,   0xc000,
  0x303,   0x30c,   0x4c7e,   0x183c,   0xc000,
  0x603,   0x306,   0xc7f,   0x3039,   0x8000,
  0x603,   0x306,   0xc3e,   0x6213,   0x1000,
  0x601,   0x8313,   0x60c,   0x6313,   0x1800,
  0xc01,   0x8319,   0x8600,   0xc186,   0xc00,
  0x3006,   0x1,   0x8181,   0x8304,   0x1800,
  0x0,   0x0,   0x1fc3,   0xffff,   0x8000,
  0x0,   0x0,   0xf03,   0xffff,   0x8000,
  0x0,   0x0,   0xc01,   0xffff,   0xc000,
  0x0,   0x0,   0x1,   0xfc1f,   0xc000,
  0x0,   0x0,   0x1,   0xc01f,   0xc000,
  0x0,   0x0,   0x0,   0xf,   0xc000,
  0x0,   0x0,   0x0,   0xf,   0xc000,
  0x0,   0x0,   0x0,   0x3,   0xc000,
  0x0,   0x0,   0x0,   0x1,   0xe000,
  0x0,   0x0,   0x0,   0x0,   0xe000,
  0x0,   0x0,   0x0,   0x0,   0x6000,
  0x0,   0x0,   0x0,   0x0,   0x2000,
 /*------ plane # 1: --------*/

  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0xc0,   0x3000,   0x0,   0x0,   0x0,
  0x1a0,   0xd1a,   0x0,   0x0,   0x0,
  0x1a0,   0xd0d,   0x0,   0x0,   0x0,
  0x1a0,   0xd06,   0x8000,   0x0,   0x0,
  0x348,   0xd06,   0x8000,   0x0,   0x0,
  0x344,   0xd06,   0x8682,   0x8104,   0x800,
  0x684,   0xd0d,   0x1a11,   0x468a,   0x3400,
  0x694,   0xd1a,   0x1a68,   0xa10d,   0x800,
  0x69a,   0xd00,   0x3468,   0xa10d,   0x800,
  0xd1a,   0xd10,   0x3400,   0xd006,   0x8000,
  0xd00,   0xd08,   0x3400,   0x6803,   0x4000,
  0xd0d,   0xd14,   0x3400,   0x6803,   0x4000,
  0x1a0d,   0xd1a,   0x3400,   0xd006,   0x8000,
  0x1a0d,   0xd1a,   0x1401,   0xa20d,   0x1000,
  0x1a06,   0x8d1d,   0xa10,   0xa50d,   0x2800,
  0x3406,   0x8d1e,   0x8201,   0x468a,   0x3400,
  0xd01a,   0x6,   0x8202,   0x0,   0x800,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
 /*------ plane # 2: --------*/

  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0xcc,   0x33ff,   0x8000,   0x0,   0x0,
  0x1be,   0xdfb,   0xe000,   0x0,   0x0,
  0x1be,   0xded,   0xe000,   0x0,   0x0,
  0x1bf,   0xde6,   0xf000,   0x0,   0x0,
  0x37f,   0xde6,   0xf000,   0x0,   0x0,
  0x377,   0x8de6,   0xf6fe,   0xfdff,   0xefc0,
  0x6f7,   0x8ded,   0xfbdf,   0x7efb,   0xf780,
  0x6f7,   0x8dfb,   0xfbef,   0xbded,   0xef00,
  0x6fb,   0xcdff,   0xb7ef,   0xbfcd,   0xfe00,
  0xdfb,   0xcdff,   0x37ff,   0xdf86,   0xfc00,
  0xdff,   0xcdef,   0x3780,   0x6f03,   0x7800,
  0xdcd,   0xedf7,   0xb780,   0x6f83,   0x7c00,
  0x1bcd,   0xedfb,   0xf780,   0xdfc6,   0xfe00,
  0x1b8d,   0xedfb,   0xf7c1,   0xbfed,   0xff00,
  0x1b86,   0xfdfd,   0xfbf3,   0xbded,   0xef00,
  0x3786,   0xfdfe,   0xfbff,   0x7efb,   0xf780,
  0xdffb,   0xfffe,   0xfe7e,   0x7cfb,   0xefc0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0,
  0x0,   0x0,   0x0,   0x0,   0x0};
 struct  Image arexxoffimage =
 {
 0,0,
 74 , 38 , 3 ,
 &arexxoff[0],
 0x07,0x00,
 NULL
 };


CHIP static UWORD arexxon[] = {
/*------ plane # 0: --------*/

  0x180,   0x0,   0x0,   0x0,   0x0,
  0x3c0,   0x0,   0x0,   0x0,   0x0,
  0xfc0,   0x200,   0x0,   0x0,   0x0,
  0x1fe0,   0x1f00,   0x0,   0x0,   0x0,
  0x3fe0,   0x7f80,   0x0,   0x0,   0x0,
  0x3fe1,   0xffc0,   0x0,   0x0,   0x0,
  0x3ff1,   0xffc0,   0x0,   0x0,   0x0,
  0x3ff3,   0xffe0,   0x0,   0x0,   0x0,
  0x3fff,   0xffe0,   0x0,   0x0,   0x0,
  0x3f33,   0xcc00,   0x0,   0x0,   0x0,
  0x3e61,   0xf306,   0x0,   0x0,   0x0,
  0x3e61,   0xf313,   0x0,   0x0,   0x0,
  0x1e60,   0xf319,   0x8000,   0x0,   0x0,
  0xcc8,   0xf319,   0x8000,   0x0,   0x0,
  0xccc,   0x7319,   0x8181,   0x8304,   0x1800,
  0x98c,   0x4313,   0x630,   0xc186,   0xc00,
  0x18c,   0x306,   0x618,   0x6303,   0x1800,
  0x186,   0x300,   0x4c18,   0x6103,   0x800,
  0x306,   0x310,   0xcc00,   0x3001,   0x8000,
  0x300,   0x318,   0xcc7e,   0x181c,   0xc000,
  0x303,   0x30c,   0x4c7e,   0x183c,   0xc000,
  0x603,   0x306,   0xc7f,   0x3039,   0x8000,
  0x603,   0x306,   0xc3e,   0x6213,   0x1000,
  0x601,   0x8313,   0x60c,   0x6313,   0x1800,
  0xc01,   0x8319,   0x8600,   0xc186,   0xc00,
  0x3006,   0x1,   0x8181,   0x8304,   0x1800,
  0x0,   0x0,   0x1fc3,   0xffff,   0x8000,
  0x0,   0x0,   0xf03,   0xffff,   0x8000,
  0x0,   0x0,   0xc01,   0xffff,   0xc000,
  0x0,   0x0,   0x1,   0xfc1f,   0xc000,
  0x0,   0x0,   0x1,   0xc01f,   0xc000,
  0x0,   0x0,   0x0,   0xf,   0xc000,
  0x0,   0x0,   0x0,   0xf,   0xc000,
  0x0,   0x0,   0x0,   0x3,   0xc000,
  0x0,   0x0,   0x0,   0x1,   0xe000,
  0x0,   0x0,   0x0,   0x0,   0xe000,
  0x0,   0x0,   0x0,   0x0,   0x6000,
  0x0,   0x0,   0x0,   0x0,   0x2000,
 /*------ plane # 1: --------*/

  0x180,   0x0,   0x0,   0x0,   0x0,
  0x3c0,   0x0,   0x0,   0x0,   0x0,
  0xfc0,   0x200,   0x0,   0x0,   0x0,
  0x1fe0,   0x1f00,   0x0,   0x0,   0x0,
  0x3fe0,   0x7f80,   0x0,   0x0,   0x0,
  0x3fe1,   0xffc0,   0x0,   0x0,   0x0,
  0x3ff1,   0xffc0,   0x0,   0x0,   0x0,
  0x3ff3,   0xffe0,   0x0,   0x0,   0x0,
  0x3fff,   0xffe0,   0x0,   0x0,   0x0,
  0x3f1f,   0xc7ff,   0x8000,   0x0,   0x0,
  0x3e3f,   0xf1e3,   0xe000,   0x0,   0x0,
  0x3e3f,   0xf1f1,   0xe000,   0x0,   0x0,
  0x1e3f,   0xf1f8,   0xf000,   0x0,   0x0,
  0xc7f,   0xf1f8,   0xf000,   0x0,   0x0,
  0xc77,   0xf1f8,   0xf0fc,   0xfdff,   0xefc0,
  0x8f7,   0xc1f1,   0xe3de,   0x78f3,   0xc780,
  0xe7,   0x81e3,   0xe38f,   0x3de1,   0xef00,
  0xe3,   0xc1ff,   0xc78f,   0x3fc1,   0xfe00,
  0x1e3,   0xc1ff,   0xc7ff,   0x1f80,   0xfc00,
  0x1ff,   0xc1ef,   0xc7fe,   0xf1c,   0x7800,
  0x1c1,   0xe1e7,   0xc7fe,   0xfbc,   0x7c00,
  0x3c1,   0xe1e3,   0xc7ff,   0x1ff8,   0xfe00,
  0x381,   0xe1e3,   0xe7fe,   0x3ff1,   0xfe00,
  0x380,   0xf1f1,   0xf3e7,   0x39f1,   0xce00,
  0x780,   0xf1f8,   0xfbfe,   0x78f3,   0xc600,
  0x1fe3,   0xfff8,   0xfcfc,   0xfdff,   0xee00,
  0x0,   0x0,   0x1fc3,   0xffff,   0x8000,
  0x0,   0x0,   0xf03,   0xffff,   0x8000,
  0x0,   0x0,   0xc01,   0xffff,   0xc000,
  0x0,   0x0,   0x1,   0xfc1f,   0xc000,
  0x0,   0x0,   0x1,   0xc01f,   0xc000,
  0x0,   0x0,   0x0,   0xf,   0xc000,
  0x0,   0x0,   0x0,   0xf,   0xc000,
  0x0,   0x0,   0x0,   0x3,   0xc000,
  0x0,   0x0,   0x0,   0x1,   0xe000,
  0x0,   0x0,   0x0,   0x0,   0xe000,
  0x0,   0x0,   0x0,   0x0,   0x6000,
  0x0,   0x0,   0x0,   0x0,   0x2000,
 /*------ plane # 2: --------*/

  0x180,   0x0,   0x0,   0x0,   0x0,
  0x3c0,   0x0,   0x0,   0x0,   0x0,
  0xfc0,   0x200,   0x0,   0x0,   0x0,
  0x1fe0,   0x1f00,   0x0,   0x0,   0x0,
  0x3fe0,   0x7f80,   0x0,   0x0,   0x0,
  0x3fe1,   0xffc0,   0x0,   0x0,   0x0,
  0x3ff1,   0xffc0,   0x0,   0x0,   0x0,
  0x3ff3,   0xffe0,   0x0,   0x0,   0x0,
  0x3fff,   0xffe0,   0x0,   0x0,   0x0,
  0x3fdf,   0xf7ff,   0x8000,   0x0,   0x0,
  0x3fbf,   0xfdfb,   0xe000,   0x0,   0x0,
  0x3fbf,   0xfdfd,   0xe000,   0x0,   0x0,
  0x1fbf,   0xfdfe,   0xf000,   0x0,   0x0,
  0xf7f,   0xfdfe,   0xf000,   0x0,   0x0,
  0xf77,   0xfdfe,   0xf6fe,   0xfdff,   0xefc0,
  0xef7,   0xcdfd,   0xfbdf,   0x7efb,   0xf780,
  0x6f7,   0x8dfb,   0xfbef,   0xbded,   0xef00,
  0x6fb,   0xcdff,   0xf7ef,   0xbfcd,   0xfe00,
  0xdfb,   0xcdff,   0xf7ff,   0xdf86,   0xfc00,
  0xdff,   0xcdef,   0xf7fe,   0x6f1f,   0x7800,
  0xdcd,   0xedf7,   0xf7fe,   0x6fbf,   0x7c00,
  0x1bcd,   0xedfb,   0xf7ff,   0xdffe,   0xfe00,
  0x1b8d,   0xedfb,   0xf7ff,   0xbffd,   0xff00,
  0x1b86,   0xfdfd,   0xfbf7,   0xbdfd,   0xef00,
  0x3786,   0xfdfe,   0xfbff,   0x7efb,   0xf780,
  0xdffb,   0xfffe,   0xfefe,   0xfdff,   0xefc0,
  0x0,   0x0,   0x1fc3,   0xffff,   0x8000,
  0x0,   0x0,   0xf03,   0xffff,   0x8000,
  0x0,   0x0,   0xc01,   0xffff,   0xc000,
  0x0,   0x0,   0x1,   0xfc1f,   0xc000,
  0x0,   0x0,   0x1,   0xc01f,   0xc000,
  0x0,   0x0,   0x0,   0xf,   0xc000,
  0x0,   0x0,   0x0,   0xf,   0xc000,
  0x0,   0x0,   0x0,   0x3,   0xc000,
  0x0,   0x0,   0x0,   0x1,   0xe000,
  0x0,   0x0,   0x0,   0x0,   0xe000,
  0x0,   0x0,   0x0,   0x0,   0x6000,
  0x0,   0x0,   0x0,   0x0,   0x2000};
 struct  Image arexxonimage =
 {
 0,0,
 74 , 38 , 3 ,
 &arexxon[0],
 0x07,0x00,
 NULL
 };

struct Accessory Access;
struct ToolMaster ontimemaster;
struct Tool ontimetool;


SAVEDS long loadsong(char *filename)
{
  long file=functions->fastopen(filename,MODE_OLDFILE);

  if(file)
  {
    functions->openwait();
    functions->clearenvironment((struct Environment *)functions,1);
    functions->loadsong(file,(struct Environment *)functions);
    functions->fastclose(file);
    strcpy(functions->filename,filename);
    functions->display(0x1000000);
    functions->closewait();
  }
  return !file;
}


SAVEDS struct Preload *preloadsong(char *filename)
{
  struct Preload *preload=(struct Preload *)functions->myalloc(sizeof(struct Preload),MEMF_CLEAR);
  long file=functions->fastopen(filename,MODE_OLDFILE);

  if(file && preload)
  {
    functions->openwait();
    functions->loadsong(file,&preload->environment);
    functions->fastclose(file);
    functions->closewait();
    strcpy(preload->filename,filename);
  }
  else if(preload)
  {
    functions->myfree((void *)preload,sizeof(struct Preload));
    preload=NULL;
  }
  return preload;
}


SAVEDS long installsong(char *string)
{
  struct Preload *song;

  for(song=songlist ; song!=NULL ; song=song->next)
  {
    if(!strcmp(string,song->filename))
        break;
  }
  if(song)
  {
    if(functions->running)
        functions->transportcommand(TC_STOP,functions->timenow);
    songlist=(struct Preload *)functions->List_Remove(songlist,song);
    functions->openwait();
    functions->clearenvironment((struct Environment *)functions,1);
    functions->installenvironment(&song->environment);
    strcpy(functions->filename,song->filename);
    functions->display(0x1000000);
    functions->closewait();
    functions->myfree((void *)song,sizeof(struct Preload));
    return 0;
  }
  return 1;
}


SAVEDS static void roottostring(unsigned short note,unsigned short flats,char *string)
{
  static char *convert[]={"C","C#","D","D#","E","F","F#","G","G#","A","A#","B"};
  static char *flatconvert[]={"C","Db","D","Eb","E","F","Gb","G","Ab","A","Bb","B"};

  note%=12;
  if(flats)
      strcpy(string,flatconvert[note]);
  else
      strcpy(string,convert[note]);
}


SAVEDS static void stripquotes(char *str)
{
  short i=strlen(str)-1;

  if((*str=='"' || *str=='\'') && str[i]==*str)
  {
    str[i]='\0';
    strcpy(str,str+1);
  }
}


SAVEDS long savesong(char *filename)
{
  long file=functions->fastopen(filename,MODE_NEWFILE);

  if(file)
  {
    functions->openwait();
    functions->savesong(file,(struct Environment *)functions);
    functions->fastclose(file);
    functions->closewait();
  }
  return(!file);
}



SAVEDS static char *parsearexx(char *command,char **args)
{
  char *p;

  if(command==NULL)
      return NULL;
  //command=(char *)stpblk(command);    // skip past white space
  p=strchr(command,' ');
  if(p)
  {
    *p++='\0';
    //p=(char *)stpblk(p);
  }
  *args=p;
  return command;
}


SAVEDS static short af_areyousure(char *args,long *primary,char *result)
{
  sprintf(result,"%ld",functions->areyousure(args));
  return 0;
}


SAVEDS static short af_chord(char *args,long *primary,char *result)
{
  struct ChordEvent *chord;
  long time;

  if(functions->running)
      time=functions->timenow;
  else
      time=functions->starttime;
  chord=functions->timetochord(NULL,time);
  if(chord)
  {
    roottostring(chord->root,chord->flats,result);
    strcat(result," ");
    strcat(result,chord->chord->name->string);
  }
  else
      strcpy(result,"No Chord");
  return 0;
}


SAVEDS static short af_closewait(char *args,long *primary,char *result)
{
  functions->closewait();
  return 0;
}


SAVEDS static short af_dynamics(char *args,long *primary,char *result)
{
  long time;
  unsigned short dyn;

  if(functions->running)
      time=functions->timenow;
  else
      time=functions->starttime;
  dyn=functions->timetodynamics(NULL,time);
  sprintf(result,"%ld",dyn);
  return 0;
}


SAVEDS static short af_frame(char *args,long *primary,char *result)
{
  static char *framestr[]={"24","25","29","30"};

  strcpy(result,framestr[functions->smptetype]);
  if(*args)
  {
    switch(atol(args))
    {
    case 24:
      functions->smptetype=0;
      break;
    case 25:
      functions->smptetype=1;
      break;
    case 29:
      functions->smptetype=2;
      break;
    case 30:
      functions->smptetype=3;
      break;
    default:
      *primary=RC_WARN;
      break;
    }
  }
  return 0;
}


SAVEDS static short af_getflag(char *args,long *primary,char *result)
{
  long time;
  char *c;

  c=parsearexx(args,&args);
  if(c==NULL)
  {
    *primary=RC_WARN;
    return 0;
  }
  if(stricmp(c,"m1")==0)
      time=functions->markone;
  else if(stricmp(c,"m2")==0)
      time=functions->marktwo;
  else if(stricmp(c,"m3")==0)
      time=functions->markthree;
  else if(stricmp(c,"m4")==0)
      time=functions->markfour;
  else if(stricmp(c,"punchin")==0)
      time=functions->punchin;
  else if(stricmp(c,"punchout")==0)
      time=functions->punchout;
  else if(stricmp(c,"loopin")==0)
      time=functions->loopin;
  else if(stricmp(c,"loopout")==0)
      time=functions->loopout;
  else if(stricmp(c,"cutin")==0)
      time=functions->cutin;
  else if(stricmp(c,"cutout")==0)
      time=functions->cutout;
  else if(stricmp(c,"stop")==0)
      time=functions->stoptime;
  else
  {
    *primary=RC_WARN;
    return 0;
  }
  if(stricmp(args,"beat")==0)
      functions->timetostring(NULL,time,result);
  else if(stricmp(args,"smpte")==0)
      functions->frametostring(functions->timetoframe(time),result);
  else if(stricmp(c,"clock")==0)
      sprintf(result,"%ld",time>>3);
  else
      functions->timetostring(NULL,time,result);
  return 0;
}


SAVEDS static short af_install(char *args,long *primary,char *result)
{
  stripquotes(args);
  if(functions->doscall(installsong,args))
      *primary=RC_WARN;
  return 0;
}


SAVEDS static short af_key(char *args,long *primary,char *result)
{
  struct KeyEvent *key;
  long time;

  if(functions->running)
      time=functions->timenow;
  else
      time=functions->starttime;
  key=functions->timetokey(NULL,time);
  if(key)
  {
    roottostring(key->root,key->flats,result);
    strcat(result," ");
    strcat(result,key->scale->name->string);
  }
  else
      strcpy(result,"C Major");
  return 0;
}


SAVEDS static short af_locate(char *args,long *primary,char *result)
{
  long time;
  char *c,buf[40];

  c=parsearexx(args,&args);
  if(c==NULL)
  {
    *primary=RC_WARN;
    return 0;
  }
  if(functions->running)
      functions->timetostring(NULL,functions->timenow,result);
  else
      functions->timetostring(NULL,functions->starttime,result);
  if(stricmp(c,"beginning")==0 || stricmp(c,"begin")==0 || stricmp(c,"beg")==0)
      time=0;
  else if(stricmp(c,"beat")==0)
  {
    strcpy(buf,args);
    strcat(buf,".0");
    time=functions->stringtotime(NULL,buf,0);
  }
  else if(stricmp(c,"smpte")==0)
  {
    if(functions->running)
        functions->frametostring(functions->timetoframe(functions->timenow),result);
    else
        functions->frametostring(functions->timetoframe(functions->starttime),result);
    time=functions->frametohires(functions->stringtoframe(args,0));
  }
  else if(stricmp(c,"clock")==0)
  {
    if(functions->running)
        sprintf(result,"%ld",functions->timenow>>3);
    else
        sprintf(result,"%ld",functions->starttime>>3);
    time=atol(args)<<3;
  }
  else
  {
    *primary=RC_WARN;
    return 0;
  }
  if(functions->running)
  {
    functions->transportcommand(TC_STOP,functions->timenow);
    functions->transportcommand(TC_POSITION,time);
    functions->starttime=time;
    functions->transportcommand(TC_PLAY,time);
  }
  else
      functions->transportcommand(TC_POSITION,time);
  functions->doscall(functions->display,0x400);  // DRAW_MARKERS
  return 0;
}


SAVEDS static short af_open(char *args,long *primary,char *result)
{
  char *c;

  c=parsearexx(args,&args);
  if(c==NULL || stricmp(c,"song") || *args=='\0')
  {
    *primary=RC_WARN;
    return 0;
  }
  stripquotes(args);
  if(functions->doscall(loadsong,args))
  {
    *primary=RC_WARN;
    strcpy(result,"No Such File");
  }
  return 0;
}


SAVEDS static short af_openwait(char *args,long *primary,char *result)
{
  functions->openwait();
  return 0;
}


SAVEDS static short af_playing(char *args,long *primary,char *result)
{
  sprintf(result,"%ld",functions->running);
  return 0;
}


SAVEDS static short af_preload(char *args,long *primary,char *result)
{
  struct Preload *song;

  stripquotes(args);
  song=(struct Preload *)functions->doscall(preloadsong,args);
  if(song!=NULL)
  {
    song->next=songlist;
    songlist=song;
  }
  else
      *primary=RC_WARN;
  return 0;
}


SAVEDS static short af_punchin(char *args,long *primary,char *result)
{
  functions->transportcommand(TC_RECORDON,functions->timenow);
  return 0;
}


SAVEDS static short af_punchout(char *args,long *primary,char *result)
{
  functions->transportcommand(TC_RECORDOFF,functions->timenow);
  return 0;
}


SAVEDS static short af_record(char *args,long *primary,char *result)
{
  long time;
  char *c,buf[40];

  if(functions->running)
      functions->transportcommand(TC_STOP,functions->timenow);
  c=parsearexx(args,&args);
  if(c==NULL)
      time=functions->starttime;
  else if(stricmp(c,"beginning")==0 || stricmp(c,"begin")==0 || stricmp(c,"beg")==0)
      time=0;
  else if(stricmp(c,"beat")==0)
  {
    strcpy(buf,args);
    strcat(buf,".0");
    time=functions->stringtotime(NULL,buf,0);
  }
  else if(stricmp(c,"smpte")==0)
      time=functions->frametohires(functions->stringtoframe(args,0));
  else if(stricmp(c,"clock")==0)
      time=atol(args)<<3;
  else
  {
    *primary=RC_WARN;
    time=functions->starttime;
  }
  functions->transportcommand(TC_RECORDON,time);
  if(time==0)
      functions->transportcommand(TC_START,0);
  else
  {
    functions->transportcommand(TC_POSITION,time);
    functions->starttime=time;
    functions->transportcommand(TC_PLAY,time);
  }
  return 0;
}


/* SAVEDS static short af_remove(char *args,long *primary,char *result)
{
  struct Preload *song;

  stripquotes(args);
  for(song=songlist ; song!=NULL ; song=song->next)
  {
    if(stricmp(args,song->filename)==0)
        break;
  }
  if(song)
  {
    songlist=(struct Preload *)functions->List_Remove(songlist,song);
    song->environment.lock=0;
    functions->openwait();
    functions->clearenvironment(&song->environment,1);
    functions->myfree((void *)song,sizeof(struct Preload));
    functions->closewait();
  }
  else
      *primary=RC_WARN;
  return 0;
} */


SAVEDS static short af_save(char *args,long *primary,char *result)
{
  char *c;

  c=parsearexx(args,&args);
  if(c==NULL || stricmp(c,"song") || *args=='\0')
  {
    *primary=RC_WARN;
    return 0;
  }
  stripquotes(args);
  if(functions->doscall(savesong,args))
      *primary=RC_WARN;
  return 0;
}


SAVEDS static short af_screentoback(char *args,long *primary,char *result)
{
  ScreenToBack(functions->screen);
  return 0;
}


SAVEDS static short af_screentofront(char *args,long *primary,char *result)
{
  ScreenToFront(functions->screen);
  return 0;
}


SAVEDS static short af_signature(char *args,long *primary,char *result)
{
  struct TimeSigEvent *ts;
  long time;

  if(functions->running)
      time=functions->timenow;
  else
      time=functions->starttime;
  for(ts=functions->masterclip.timesig.first ; ts!=NULL && ts->next!=NULL ; ts=ts->next)
  {
    if(ts->next && ts->next->time>time)
        break;
  }
  if(ts)
      sprintf(result,"%ld/%ld",ts->beatcount,ts->beat);
  else
      strcpy(result,"4/4");
  return 0;
}


SAVEDS static short af_setflag(char *args,long *primary,char *result)
{
  long time;
  char *flag,*c,buf[40];

  flag=parsearexx(args,&args);
  if(flag==NULL)
  {
    *primary=RC_WARN;
    return 0;
  }
  c=parsearexx(args,&args);
  if(c==NULL)
  {
    if(functions->running)
        time=functions->timenow;
    else
        time=functions->starttime;
  }
  else if(stricmp(c,"beginning")==0 || stricmp(c,"begin")==0 || stricmp(c,"beg")==0)
      time=0;
  else if(stricmp(c,"beat")==0)
  {
    strcpy(buf,args);
    strcat(buf,".0");
    time=functions->stringtotime(NULL,buf,0);
  }
  else if(stricmp(c,"smpte")==0)
      time=functions->frametohires(functions->stringtoframe(args,0));
  else if(stricmp(c,"clock")==0)
      time=atol(args)<<3;
  else
  {
    *primary=RC_WARN;
    return 0;
  }
  if(stricmp(flag,"m1")==0)
      functions->markone=time;
  else if(stricmp(flag,"m2")==0)
      functions->marktwo=time;
  else if(stricmp(flag,"m3")==0)
      functions->markthree=time;
  else if(stricmp(flag,"m4")==0)
      functions->markfour=time;
  else if(stricmp(flag,"punchin")==0)
      functions->punchin=time;
  else if(stricmp(flag,"punchout")==0)
      functions->punchout=time;
  else if(stricmp(flag,"loopin")==0)
      functions->loopin=time;
  else if(stricmp(flag,"loopout")==0)
      functions->loopout=time;
  else if(stricmp(flag,"cutin")==0)
      functions->cutin=time;
  else if(stricmp(flag,"cutout")==0)
      functions->cutout=time;
  else if(stricmp(flag,"stop")==0)
      functions->savestop=functions->stoptime=time;
  else
  {
    *primary=RC_WARN;
    return 0;
  }
  functions->doscall(functions->display,0x400);  // DRAW_MARKERS
  return 0;
}


SAVEDS static short af_start(char *args,long *primary,char *result)
{
  long time;
  char *c,buf[40];

  if(functions->running)
      functions->transportcommand(TC_STOP,functions->timenow);
  c=parsearexx(args,&args);
  if(c==NULL)
      time=functions->starttime;
  else if(stricmp(c,"beginning")==0 || stricmp(c,"begin")==0 || stricmp(c,"beg")==0)
      time=0;
  else if(stricmp(c,"beat")==0)
  {
    strcpy(buf,args);
    strcat(buf,".0");
    time=functions->stringtotime(NULL,buf,0);
  }
  else if(stricmp(c,"smpte")==0)
      time=functions->frametohires(functions->stringtoframe(args,0));
  else if(stricmp(c,"clock")==0)
      time=atol(args)<<3;
  else
  {
    *primary=RC_WARN;
    time=functions->starttime;
  }
  if(time==0)
      functions->transportcommand(TC_START,0);
  else
  {
    functions->transportcommand(TC_POSITION,time);
    functions->starttime=time;
    functions->transportcommand(TC_PLAY,time);
  }
  return 0;
}


SAVEDS static short af_stop(char *args,long *primary,char *result)
{
  if(functions->running)
      functions->transportcommand(TC_STOP,functions->timenow);
  else
      *primary=RC_WARN;
  return 0;
}


SAVEDS static short af_tempo(char *args,long *primary,char *result)
{
  long t;

  sprintf(result,"%ld",functions->inittempo);
  if(*args)
  {
    t=atol(args);
    if(t>=10 && t<=350)
        functions->settempo(t);
    else
        *primary=RC_WARN;
  }
  return 0;
}


SAVEDS static short af_wait(char *args,long *primary,char *result)
{
  long time;
  char *c,buf[40];
  struct Event *ev;

  c=parsearexx(args,&args);
  if(c==NULL)
  {
    *primary=RC_WARN;
    return 0;
  }
  else if(stricmp(c,"beat")==0)
  {
    if(functions->running==0)
    {
      *primary=RC_WARN;
      return 0;
    }
    strcpy(buf,args);
    strcat(buf,".0");
    time=functions->stringtotime(NULL,buf,0);
  }
  else if(stricmp(c,"smpte")==0)
  {
    if(functions->running==0)
    {
      *primary=RC_WARN;
      return 0;
    }
    time=functions->frametohires(functions->stringtoframe(args,0));
  }
  else if(stricmp(c,"clock")==0)
  {
    if(functions->running==0)
    {
      *primary=RC_WARN;
      return 0;
    }
    time=atol(args)<<3;
  }
  else if(stricmp(c,"stop")==0)
  {
    waiting=1;
    Wait(unblockbit);
    waiting=0;
    return 0;
  }
  else if(stricmp(c,"start")==0)
  {
    waiting=2;
    Wait(unblockbit);
    waiting=0;
    return 0;
  }
  else
  {
    *primary=RC_WARN;
    return 0;
  }
  ev=functions->allocevent();
  if(ev)
  {
    ev->time=time;
    ev->tool=&ontimetool;
    waiting=1;
    functions->qevent(ev);
    Wait(unblockbit);
    waiting=0;
  }
  return 0;
}

static ARexxCommands commands[]=
{
  "areyousure",     af_areyousure,
  "chord",          af_chord,
  "closewait",      af_closewait,
  "dynamics",       af_dynamics,
  "frame",          af_frame,
  "getflag",        af_getflag,
  "install",        af_install,
  "key",            af_key,
  "load",           af_open,
  "locate",         af_locate,
  "open",           af_open,
  "openwait",       af_openwait,
  "playing",        af_playing,
  "preload",        af_preload,
  "punchin",        af_punchin,
  "punchout",       af_punchout,
  "record",         af_record,
  "running",        af_playing,
  "save",           af_save,
  "screentoback",   af_screentoback,
  "screentofront",  af_screentofront,
  "setflag",        af_setflag,
  "signature",      af_signature,
  "start",          af_start,
  "stop",           af_stop,
  "tempo",          af_tempo,
  "time",           af_locate,
  "timesig",        af_signature,
  "toback",         af_screentoback,
  "tofront",        af_screentofront,
  "wait",           af_wait,
  NULL,             NULL
};


SAVEDS short handlerexxmessage(struct RexxMsg *rmsg)
{
  short i,ret;
  char *command,*args,buf[512],result[128];
  long primary;

  strcpy(buf,rmsg->rm_Args[0]);
  command=parsearexx(buf,&args);
  primary=0;
  result[0]='\0';
  for(i=ret=0 ; commands[i].command!=NULL ; ++i)
  {
    if(stricmp(commands[i].command,command)==0)
    {
      ret=commands[i].function(args,&primary,result);
      break;
    }
  }
  rmsg->rm_Result1=primary;
  rmsg->rm_Result2=0;
  if(rmsg->rm_Action & (1<<RXFB_NONRET))
  {
    DeleteArgstring(rmsg->rm_Args[0]);
    DeleteRexxMsg(rmsg);
    return ret;
  }
  if((primary==0) && (rmsg->rm_Action & (1<<RXFB_RESULT)))
  {
    if(result[0])
        rmsg->rm_Result2=(long)CreateArgstring(result,strlen(result));
    else
        rmsg->rm_Result2=NULL;
  }
  ReplyMsg((struct Message *)rmsg);
  return ret;
}


SAVEDS static void rexxcode(void)
{
  struct RexxMsg *rexxmessage;   /* incoming rexx messages */
  struct Preload *song;

  rexxport=(struct MsgPort *)CreatePort(HOST_PORT_NAME,0L);
  if(!rexxport)
      return;
  rexxtask=FindTask(NULL);
  shutdownbit=1<<AllocSignal(-1);
  unblockbit =1<<AllocSignal(-1);
  while(!shutdown)
  {
    Wait((1<<rexxport->mp_SigBit) | shutdownbit);
    while(rexxmessage=(struct RexxMsg *)GetMsg(rexxport))
        handlerexxmessage(rexxmessage);
  }
  DeletePort(rexxport);
  while(songlist!=NULL)
  {
    song=songlist;
    songlist=song->next;
    functions->clearenvironment(&song->environment,1);
    functions->myfree((void *)song,sizeof(struct Preload));
  }
  rexxtask=NULL;
}


SAVEDS static struct Event *processontimecode(struct Event *ev)
{
  Signal(rexxtask,unblockbit);
  ev->tool=NULL;
  return ev;
}


SAVEDS static void transportcode(long command,long time,long end)
{
  if(command==TC_STOP)
  {
    if(waiting==1)
        Signal(rexxtask,unblockbit);
  }
  else if(command==TC_START || command==TC_PLAY)
  {
    if(waiting==2)
        Signal(rexxtask,unblockbit);
  }
}


SAVEDS void removecode(void)
{
  shutdown=1;
  if(rexxtask)
      Signal(rexxtask,shutdownbit);
  functions->removetransport((void *)transportcode);
  while(rexxtask!=NULL)
      WaitTOF();
  CloseLibrary(RexxSysBase);
  RexxSysBase = NULL;
}



SAVEDS struct Accessory *inittoolmaster(void)
{
  short i;
  if(FindPort(HOST_PORT_NAME))
      return NULL;
  RexxSysBase=OpenLibrary(RXSNAME,0L);
  if(RexxSysBase==NULL)
      return NULL;
  Access.id=ID_REXX;
  Access.image=&arexxoffimage;
  Access.onimage=&arexxonimage;
  Access.remove=(long_cast)removecode;
  strcpy(Access.name,"ARexx");

  ontimemaster.processevent = (event_cast)processontimecode;
  ontimemaster.tooltype = TOOL_NORMAL | TOOL_ONTIME;
  ontimetool.toolmaster = &ontimemaster;
  ontimetool.tooltype = TOOL_ONTIME | TOOL_NORMAL;

  CreateTask("Bars&Pipes ARexx In",0,(void_cast)rexxcode,10000);
  for(i=0 ; i<100 && rexxtask==NULL ; ++i)
      WaitTOF();
  if(rexxtask==NULL)
  {
    CloseLibrary(RexxSysBase);
    return NULL;
  }
  functions->installtransport((void *)transportcode);
  return &Access;
}
