/*
	MIDI Mixer
	Fichier: MIDIMIXR.C
	par Raymond Hill
	xxxxxx88
	Console MIDI permettant de simuler une console de mixage.
*/

#include <gemdefs.h>
#include <obdefs.h>
#include <osbind.h>

#define	STATUS		0
#define	CONTROLEUR	1
#define	VOLUME		2
#define CONSOLE 	0
#define FSLIDER 	1
#define FUP 		2
#define FDOWN 		3
#define FSLID 		4
#define FBUTTON 	5

long _stksize = 1024;

/* Declaration des types propres a MIDIMIXR */

typedef struct {
	int		handle;
	char	*title;
	GRECT	box;
	OBJECT	*tree;
} WINDOW;

/* Declarations des variables globales */

extern int gl_apid;
static int menu_id;

int	contrl[12],
	intin[16],
	ptsin[16],
	intout[16],
	ptsout[16];

int	phys_handle,handle;
int canal;

GRECT	deskxywh;

WINDOW	thewindow = {
	-1,
	0L,
	0,0,0,0,
	0L };

char volume[16][3] = {
	176,7,0,
	177,7,0,
	178,7,0,
	179,7,0,
	180,7,0,
	181,7,0,
	182,7,0,
	183,7,0,
	184,7,0,
	185,7,0,
	186,7,0,
	187,7,0,
	188,7,0,
	189,7,0,
	190,7,0,
	191,7,0 };

init_mixer()
{
	int dummy;

	appl_init();
	rsrc_load("midimixr.rsc");
	phys_handle = graf_handle(&dummy,&dummy,&dummy,&dummy);
	menu_id = menu_register(gl_apid,"  Mixeur MIDI");
	rsrc_gaddr(R_TREE,CONSOLE,&thewindow.tree);
	if ( Getrez() == 2 )
		thewindow.tree->ob_height -= 9;
	form_center(thewindow.tree,&dummy,&dummy,&dummy,&dummy);
	thewindow.title = " Mixeur MIDI - Raymond Hill pour OKTAL\277 ",
	wind_get(0,WF_CURRXYWH,&deskxywh.g_x,&deskxywh.g_y,&deskxywh.g_w,&deskxywh.g_h);
}

do_mixer()
{
	register int which;
	int mx,my;
	int dummy;
	int msgbuff[16];

	for (;;) {
		which = evnt_multi( MU_MESAG|MU_BUTTON,
							1,1,1,
							0,0L,0L,
							0,0L,0L,
							msgbuff,
							0L,
							&mx,&my,&dummy,
							&dummy,&dummy,
							&dummy );
	
		wind_update(BEG_UPDATE);
		if ( which & MU_MESAG )		hndl_mesag(msgbuff);
		if ( which & MU_BUTTON )	hndl_button(mx,my);
		wind_update(END_UPDATE);
		}
}

hndl_mesag(msgbuff)
	int *msgbuff;
{
	int dummy;
	static int workin[] = {1,1,1,1,1,1,1,1,1,1,2};
	int workout[57];
	register WINDOW *windptr = &thewindow;

	switch ( msgbuff[0] ) {

		case AC_OPEN:
			if ( windptr->handle < 0 ) {
				handle = phys_handle;
				v_opnvwk(workin,&handle,workout);
				open_window();
				for ( dummy = 0; dummy < 16; dummy++ )
					Midiws(2,&volume[dummy][0]);
				}
			else
				wind_set(windptr->handle,WF_TOP);
			break;

		case AC_CLOSE:
			if ( windptr->handle > 0 ) {
				v_clsvwk(handle);
				windptr->handle = -1;
				}

		case WM_CLOSED:
			if ( windptr->handle > 0 ) {
				close_window();
				v_clsvwk(handle);
				}
			break;

		case WM_MOVED:
			windptr->box = *(GRECT *)&msgbuff[4];
			wind_calc(1,0xB,windptr->box,&windptr->tree->ob_x,&windptr->tree->ob_y,&dummy,&dummy);
			wind_set(windptr->handle,WF_CURRXYWH,windptr->box);
			break;

		case WM_NEWTOP:
		case WM_TOPPED:
			wind_set(windptr->handle,WF_TOP);
			break;

		case WM_REDRAW:
			draw_tree(windptr->tree,0,&msgbuff[4]);
			break;
		}
}

hndl_button(mx,my)
	int mx,my;
{
	int button;
	int dummy;
	register int obfind,obslider;
	register int n;
	register char *pmidi;
	register OBJECT *pobj;
	register WINDOW *windptr = &thewindow;

	extern chg_volume();

	if ( wind_find(mx,my) == windptr->handle ) {

		if ( (obfind = objc_find(windptr->tree,0,MAX_DEPTH,mx,my)) <= 0 )
			return;

		canal = (obfind - FSLIDER) / 5;
		pmidi = &volume[canal][0];
		obslider = canal * 5 + FSLIDER;

		switch ( obfind - obslider ) {

			/* Up & Down */
			case 1:
			case 2:
				v_hide_c(handle);
				pobj = &windptr->tree[obslider+3];
				do {
					if ( (obfind - obslider) == 1 ) {
						if ( ++*(pmidi+2) < 0 )
							*(pmidi+2) = 127;
						}
					else {
						if ( --*(pmidi+2) < 0 )
							*(pmidi+2) = 0;
						}
					Midiws(2,pmidi);
					asm {
							move.b	2(pmidi),D0
							ext.w	D0
							muls	#99,D0
							divs	#127,D0
							move	D0,n
						}
					itoda(((TEDINFO *)(pobj+1)->ob_spec)->te_ptext,n);
					asm {
							moveq	#99,D0
							sub		n,D0
							move	22(pobj),D1
							sub		46(pobj),D1
							ext.l	D1
							muls	D1,D0
							divs	#99,D0
							move	D0,n
						}
					do_arrow(windptr->tree,obslider+3,n,1);
					evnt_button(0,0,0,&dummy,&dummy,&button,&dummy);
				} while ( button & 1 );
				v_show_c(handle,1);
				break;
			/* Slider */
			case 4:
				xslid_box(windptr->tree,obslider+3,chg_volume);
				break;
			}
		}
}

chg_volume(pobj)
	register OBJECT *pobj;
{
	register int n;
	register char *pmidi = &volume[canal][0];

	asm {
			move	22(pobj),D0
			sub		46(pobj),D0
			move	42(pobj),D1
			muls	#127,D1
			divs	D0,D1
			moveq	#127,D0
			sub		D1,D0
			move.b	D0,2(pmidi)
			muls	#99,D0
			divs	#127,D0
			move	D0,n
		}
	itoda(((TEDINFO *)(pobj+1)->ob_spec)->te_ptext,n);
	Midiws(2,pmidi);
}

open_window()
{
	register WINDOW *windptr = &thewindow;

	if ( windptr->handle < 0 ) {
		windptr->handle = wind_create(0xB,deskxywh);
		wind_calc(0,0xB,*(GRECT *)&windptr->tree->ob_x,&windptr->box.g_x,&windptr->box.g_y,&windptr->box.g_w,&windptr->box.g_h);
		wind_set(windptr->handle,WF_NAME,windptr->title);
		wind_open(windptr->handle,windptr->box);
		}
}

close_window()
{
	if ( thewindow.handle > 0 ) {
		wind_close(thewindow.handle);
		wind_delete(thewindow.handle);
		thewindow.handle = -1;
		}
}

draw_tree(treeptr,obindex,pclipbox)
	OBJECT *treeptr;
	int obindex;
	register GRECT *pclipbox;
{
	GRECT windbox,drawbox;

	wind_get(thewindow.handle,WF_FIRSTXYWH,&windbox.g_x,&windbox.g_y,&windbox.g_w,&windbox.g_h);
	while ( windbox.g_w && windbox.g_h ) {
		if ( rect_intersect(*pclipbox,windbox,&drawbox) )
			objc_draw(treeptr,obindex,MAX_DEPTH,drawbox);
		wind_get(thewindow.handle,WF_NEXTXYWH,&windbox.g_x,&windbox.g_y,&windbox.g_w,&windbox.g_h);
		}
}

/*
	eXtended SLID BOX.
*/
xslid_box(ptree,obindex,theproc)
	OBJECT *ptree;
	int obindex;
	int (*theproc)();
{
	int mx,my;
	int button;
	int dummy;
	register int deltay;
	register int yoffset;
	GRECT thebox;
	GRECT childbox;
	GRECT parentbox;
	register OBJECT *pobj = (ptree + obindex);
	register GRECT *pbox  = &thebox;
	register GRECT *pcbox = &childbox;
	register GRECT *ppbox = &parentbox;

	objc_xywh(ptree,obindex,ppbox);
	objc_xywh(ptree,obindex+1,pcbox);

	vq_mouse(handle,&button,&mx,&my);
	yoffset = my - pcbox->g_y;

	v_hide_c(handle);
	while ( button & 1 ) {
		my -= yoffset;
		if ( my < ppbox->g_y )
			my = ppbox->g_y;
		else
			if ( (my + pcbox->g_h) > (ppbox->g_y + ppbox->g_h) )
				my = ppbox->g_y + ppbox->g_h - pcbox->g_h;
		if ( deltay = my - pcbox->g_y ) {
			pcbox->g_y += deltay;
			(pobj+1)->ob_y += deltay;
			if ( theproc )
				(*theproc)(pobj);
			draw_tree(ptree,obindex+1,pcbox);
			*pbox = *pcbox;
			if ( deltay ) {
				if ( deltay < 0 ) {
					pbox->g_y += pbox->g_h;
					pbox->g_h = -deltay;
					}
				else {
					pbox->g_y -= deltay;
					pbox->g_h = deltay;
					}
				}
			draw_tree(ptree,obindex,pbox);
			}
		evnt_button(0,0,0,&mx,&my,&button,&dummy);
		}
	v_show_c(handle,1);
}

do_arrow(dialog,obslider,newpos,dir)
	register OBJECT *dialog;
	register int obslider;
	register int newpos;
	int dir;
{
	GRECT thebox;
	register OBJECT *pobj = (dialog + obslider);
	register GRECT *pbox = &thebox;

	(int *)pobj += dir;
	(int *)pbox += dir;
	(pobj+1)->ob_x += (newpos -= (pobj+1)->ob_x);
	objc_xywh(dialog,obslider+1,&thebox);
	draw_tree(dialog,obslider+1,&thebox);
	pbox->g_w = (newpos < 0) ? -newpos : newpos;
	if ( newpos < 0 )
		pbox->g_x += (pobj+1)->ob_width;
	else
		pbox->g_x -= newpos;
	draw_tree(dialog,obslider,&thebox);
}

/*
	Calcule la position absolue de l'objet.
*/
objc_xywh(tree,obindex,thebox)
	register OBJECT *tree;
	register int obindex;
	register GRECT *thebox;
{
	objc_offset(tree,obindex,&thebox->g_x,&thebox->g_y);
	thebox->g_w = (tree + obindex)->ob_width;
	thebox->g_h = (tree + obindex)->ob_height;
}

main()
{
	init_mixer();
	do_mixer();
}

/*
	Integer TO Decimal Ascii.
*/
itoda(s,v)
	char *s;
	int v;
{
	asm {
			move.l	s(A6),A0
			move	v(A6),D0
			ext.l	D0
			divu	#10,D0
			beq.s	L1
			add		#'0',D0
			move.b	D0,(A0)+
			bra.s	L2
		L1:	move.b	#32,(A0)+
		L2:	swap	D0
			add		#'0',D0
			move.b	D0,(A0)+
			clr.b	(A0)
	}
}
