/*	Echo.c

	© 1989 Blue Ribbon Bakery
	
*/

#include "bars.h"
#include <libraries/dos.h>
#include <exec/memory.h>
#include <string.h>
#include <intuition/intuition.h>

/*	Each Tool has a unique ID. */

#define ID_ECHO	0x4543484F

/*	The Tool's image. */

static UWORD echo[] = { 
/*------ plane # 0: --------*/

  0x0,   0x0, 
  0xfff,   0xf000, 
  0x3fff,   0xfc00, 
  0x3bff,   0xfc00, 
  0x3bff,   0xfc00, 
  0x3bff,   0xfc00, 
  0x23ff,   0xfc00, 
  0x23ff,   0xfc00, 
  0x3fff,   0xfc00, 
  0x3fff,   0xfc00, 
  0xfff,   0xf000, 
  0x0,   0x0,
 /*------ plane # 1: --------*/

  0x0,   0x0, 
  0x0,   0x0, 
  0x0,   0x0, 
  0x0,   0x0, 
  0xc000,   0x300, 
  0xc000,   0x300, 
  0xc000,   0x300, 
  0xc000,   0x300, 
  0x0,   0x0, 
  0x0,   0x0, 
  0x0,   0x0, 
  0x0,   0x0,
 /*------ plane # 2: --------*/

  0x0,   0x0, 
  0xfff,   0xf000, 
  0x3fff,   0xfc00, 
  0x3bee,   0xec00, 
  0x3bee,   0xec00, 
  0x3bee,   0xec00, 
  0x2388,   0x8c00, 
  0x2388,   0x8c00, 
  0x3fff,   0xfc00, 
  0x3fff,   0xfc00, 
  0xfff,   0xf000, 
  0x0,   0x0};
 struct  Image echoimage =
 {
 0,0,
 24 , 12 , 3 ,
 &echo[0],
 0x1f,0x00,
 NULL,
 };

/*	The Echo Tool has the standard Tool structure, plus
	parameters that are unique to this Tool.
*/
 
struct EchoTool {
    struct Tool tool;
    short echocount;
    short echodistance;
    char echostyle;
};
 
extern struct Functions *functions;

/*	The user interface window structure.  Complements of Power Windows. */

static struct IntuiText echoIText1 = {
	3,1,COMPLEMENT,
	0,0,
	NULL,
	"Rising",
	NULL
};

static struct MenuItem echoMenuItem3 = {
	NULL,
	0,16,
	56,8,
	ITEMTEXT+ITEMENABLED+HIGHCOMP,
	0,
	(APTR)&echoIText1,
	NULL,
	NULL,
	NULL,
	MENUNULL
};

static struct IntuiText echoIText2 = {
	3,1,COMPLEMENT,
	0,0,
	NULL,
	"Level",
	NULL
};

static struct MenuItem echoMenuItem2 = {
	&echoMenuItem3,
	0,8,
	56,8,
	ITEMTEXT+ITEMENABLED+HIGHCOMP,
	0,
	(APTR)&echoIText2,
	NULL,
	NULL,
	NULL,
	MENUNULL
};

static struct IntuiText echoIText3 = {
	3,1,COMPLEMENT,
	0,0,
	NULL,
	"Falling",
	NULL
};

static struct MenuItem echoMenuItem1 = {
	&echoMenuItem2,
	0,0,
	56,8,
	ITEMTEXT+ITEMENABLED+HIGHCOMP,
	0,
	(APTR)&echoIText3,
	NULL,
	NULL,
	NULL,
	MENUNULL
};

static struct Menu echoMenu1 = {
	NULL,
	0,0,
	7,0,
	MENUENABLED,
	"",
	&echoMenuItem1
};

static SHORT echoBorderVectors1[] = {
	0,0,
	144,0
};
static struct Border echoBorder1 = {
	-48,9,
	4,0,JAM1,
	2,
	echoBorderVectors1,
	NULL
};

static struct IntuiText echoIText4 = {
	7,0,JAM1,
	-48,0,
	NULL,
	"Slope:",
	NULL
};

static struct Gadget echoGadget3 = {
	NULL,
	68,45,
	96,9,
	GADGHBOX+GADGHIMAGE,
	RELVERIFY+GADGIMMEDIATE,
	BOOLGADGET,
	(APTR)&echoBorder1,
	NULL,
	&echoIText4,
	NULL,
	(APTR)&echoMenu1,
	3,
	NULL
};

static UBYTE echoechoGadget2SIBuff[20];
static struct StringInfo echoechoGadget2SInfo = {
	echoechoGadget2SIBuff,
	NULL,
	0,
	20,
	0,
	0,0,0,0,0,
	0,
	0,
	NULL
};

static SHORT echoBorderVectors2[] = {
	0,0,
	145,0
};
static struct Border echoBorder2 = {
	-72,9,
	4,0,JAM1,
	2,
	echoBorderVectors2,
	NULL
};

static struct IntuiText echoIText5 = {
	7,0,JAM2,
	-72,0,
	NULL,
	"Repeat #:",
	NULL
};

static struct Gadget echoGadget2 = {
	&echoGadget3,
	91,31,
	72,9,
	NULL,
	RELVERIFY+GADGIMMEDIATE+LONGINT,
	STRGADGET,
	(APTR)&echoBorder2,
	NULL,
	&echoIText5,
	NULL,
	(APTR)&echoechoGadget2SInfo,
	2,
	NULL
};

static UBYTE echoechoGadget1SIBuff[20];
static struct StringInfo echoechoGadget1SInfo = {
	echoechoGadget1SIBuff,
	NULL,
	0,
	20,
	0,
	0,0,0,0,0,
	0,
	0,
	NULL
};

static SHORT echoBorderVectors3[] = {
	0,0,
	145,0
};
static struct Border echoBorder3 = {
	-48,9,
	4,0,JAM1,
	2,
	echoBorderVectors3,
	NULL
};

static struct IntuiText echoIText6 = {
	7,0,JAM2,
	-48,0,
	NULL,
	"Delay:",
	NULL
};

static struct Gadget echoGadget1 = {
	&echoGadget2,
	66,17,
	96,9,
	NULL,
	RELVERIFY+GADGIMMEDIATE,
	STRGADGET,
	(APTR)&echoBorder3,
	NULL,
	&echoIText6,
	NULL,
	(APTR)&echoechoGadget1SInfo,
	1,
	NULL
};

#define echoGadgetList1 echoGadget1

static struct NewWindow echoNewWindowStructure1 = {
	158,46,
	184,64,
	6,1,
	GADGETDOWN+GADGETUP+CLOSEWINDOW+INACTIVEWINDOW,
	WINDOWDRAG+WINDOWDEPTH+WINDOWCLOSE+ACTIVATE+NOCAREREFRESH,
	&echoGadget1,
	NULL,
	"Echo",
	NULL,
	NULL,
	5,5,
	-1,-1,
	CUSTOMSCREEN
};

static void fillstring(window,tool,id)

struct Window *window;
struct EchoTool *tool;
short id;

{
    struct StringInfo *stringinfo = (struct StringInfo *) 
	(*functions->GetStringInfo)(window,id);
    if (id == 1) {
	tool->echodistance = 
	    (*functions->stringtolength)(0,0,stringinfo->Buffer,tool->echodistance);
    }
    else if (id == 2) {
	tool->echocount = stringinfo->LongInt;
	if (tool->echocount < 0) tool->echocount = 0;
    }
}

void edittoolcode(tool)

struct EchoTool *tool;

{
    struct IntuiMessage *message;
    struct Window *window;
    long class, code;
    short stringid = 0;
    char string[30];
    short refresh = 1;
    struct Gadget *gadget;
    struct NewWindow *newwindow;
    static struct IntuiText itext = { 1,0,JAM2,0,0,NULL,0,0 };
    static char *style[3] = { "Falling","Level   ","Rising "};
    echoNewWindowStructure1.Screen = functions->screen;
    if (tool->tool.touched & TOUCH_EDIT) {
	echoNewWindowStructure1.LeftEdge = tool->tool.left;
	echoNewWindowStructure1.TopEdge = tool->tool.top;
    }
    if (!tool->tool.touched) {
	tool->echodistance = 192;
	tool->echocount = 4;
	tool->tool.touched = TOUCH_INIT;
    }
    newwindow = (struct NewWindow *) 
	(*functions->DupeNewWindow)(&echoNewWindowStructure1);
    if (!newwindow) return;
    window = (struct Window *) 
	(*functions->FlashyOpenWindow)(newwindow);
    if (!window) return;
    tool->tool.window = window;
    for (;;) {
	if (refresh) {
	    (*functions->lengthtostring)(0,0,tool->echodistance,string);
	    (*functions->SetStringInfo)(window,1,string);
	    (*functions->SetStringInfoNumber)(window,2,tool->echocount,10);
	    itext.IText = style[tool->echostyle];
	    PrintIText(window->RPort,&itext,68,45);
	}
	refresh = 0;
	message = (struct IntuiMessage *) (*functions->GetIntuiMessage)(window);
	class = message->Class;
	code = message->Code;
	gadget = (struct Gadget *) message->IAddress;
	ReplyMsg((struct Message *)message);
	if (stringid) {
	    if ((class == CLOSEWINDOW) || (class == GADGETDOWN)) {
		fillstring(window,tool,stringid);
		stringid = 0;
	    }
	}
	if (class == CLOSEWINDOW) break;
	else if (class == GADGETDOWN) {
	    switch (gadget->GadgetID) {
		case 1 :
		case 2 :
		    stringid = gadget->GadgetID;
		    break;
		case 3 :
		    code = (*functions->PopUpMenu)(window,(struct Menu *)
			gadget->SpecialInfo);
		    code = ITEMNUM(code);
		    if (code < 3) tool->echostyle = code;
		    refresh = 1;
		    break;
	    }
	}
	else if (class == GADGETUP) {
	    if (gadget->GadgetID < 3) {
		fillstring(window,tool,gadget->GadgetID);
		refresh = 1;
	    }
	}
    }
    tool->tool.window = 0;
    tool->tool.left = window->LeftEdge;
    tool->tool.top = window->TopEdge;
    tool->tool.touched = TOUCH_INIT | TOUCH_EDIT;
    (*functions->FlashyCloseWindow)(window);
    (*functions->DeleteNewWindow)(newwindow);
}

/*	Note processing code.  If the event is a note, create echoes,
	otherwise just pass it on.
*/

static struct Event *processeventcode(event)

struct NoteEvent *event;

{
    struct EchoTool *tool = (struct EchoTool *) event->tool;
    struct NoteEvent *new;
    short count;
    short velocity, inc;
    long time;
    if (!tool->tool.touched) {
	tool->echocount = 4;
	tool->echodistance = 192;
	tool->tool.touched = TOUCH_INIT;
    }
    count = tool->echocount;
    event->tool = event->tool->next;
    if ((event->status == MIDI_NOTEON) || (event->status == MIDI_NOTEOFF) ||
	(event->status == MIDI_PTOUCH)) {
	if (tool->echostyle == 1) {
	    inc = 0;
	    velocity = event->velocity;
	}
	else if (tool->echostyle == 2) {
	    inc = IDivS(event->velocity,count+1);
	    velocity = event->velocity;
	    event->velocity = inc;
	    inc = -inc;
	}
	else {
	    inc = IDivS(event->velocity,count+1);
	    velocity = inc;
	}
	time = event->time + (tool->echodistance * count);
	for (;count;count--) {
	    new = (struct NoteEvent *) (*functions->allocevent)();
	    if (new) {
		new->tool = event->tool;
		new->status = event->status;
		new->value = event->value;
		new->type = event->type;
		new->duration = event->duration;
		new->time = time;
		time -= tool->echodistance;
		new->velocity = velocity;
		velocity += inc;
		new->next = event;
		event = new;
	    }
	}
    }
    return((struct Event *)event);
}

static struct ToolMaster master;

struct ToolMaster *inittoolmaster()

{
    memset((char *)&master,0,sizeof(struct ToolMaster));
    master.toolsize = sizeof(struct EchoTool);
    master.toolid = ID_ECHO;
    master.edittool = edittoolcode;
    master.image = &echoimage;
    strcpy(master.name,"Echo");
    master.processevent = processeventcode;
    master.tooltype = TOOL_NORMAL;
    return(&master);
}
