/************************************************************************
 *	TITLE:			JAZ.C					*
 *	PROJECT:		JAGUAR/JAZ				*
 *	FUNCTION:		MAIN JAZ MODULE				*
 *	PROGRAMMER:		Hans-Martin Krober, Andreas Binner	*
 *	DATE:			5/95					*
 *									*
 *              COPYRIGHT 1993,1994 Atari U.S. Corporation              *
 *          UNATHORIZED REPRODUCTION, ADAPTATION, DISTRIBUTION,         *
 *          PERFORMANCE OR DISPLAY OF THIS COMPUTER PROGRAM OR          *
 *        THE ASSOCIATED AUDIOVISUAL WORK IS STRICTLY PROHIBITED.       *
 *                            ALL RIGHTS RESERVED.                      *
 *									*
 ************************************************************************/

#include <stdarg.h>
#include "portab.h"
#include "slibc.h"
#include "glib.h"
#include "gemlib.h"
#include "jazobj.h"
#include "ptchptch.h"
#include "jazsyn.h"
#include "dos.h"
#include "jazutil.h"

/*	----------------------------------------------------------------
 *	EXTERNALS
 */

EXTERN WORD scrn_w, scrn_h;
EXTERN struct _pitchpatch pitchpatch[];

EXTERN BYTE filebuf[];

EXTERN BYTE *patchnameslist;
EXTERN BYTE *samplenameslist;

EXTERN BYTE SLASH;

EXTERN WORD sprintf(BYTE *, ...);
EXTERN VOID read_cnf(VOID);
EXTERN VOID init_patches(VOID);
EXTERN VOID pstab_handler(OBJECT *, WORD, WORD, WORD, ULONG);
EXTERN VOID pstab_pload(OBJECT *, WORD, WORD, WORD, ULONG);
EXTERN VOID pstab_pview(OBJECT *, WORD, WORD, WORD, ULONG);
EXTERN WORD build_pedit(VOID);
EXTERN LONG patchtab[];			/* buffer for patches */
EXTERN BYTE patch_names[][16];
EXTERN PATCHINFO patchinfo_table[];
EXTERN WORD patch_cnt;


/*	----------------------------------------------------------------
 *	GLOBALS
 */

OBJECT	maintree[20];		/* Main Screen Objs */
OBJECT	jaztree[20];		/* PMT list Objs */
OBJECT  ptttree[20];		/* PMT Dialog Box */
OBJECT  pstabtree[20];		/* Patch  Tables Dialog Box */


BYTE	*pttlist[LIST_COLS*MAX_PTT];	/* PTT String List for dialog box */
PTT_TAB ptt_table[MAX_PTT];	/* PTT Data */
WORD	ptt_count;		/* # of entries in PTT */
WORD	ptt_id;			/* unique id for each entry */
LONG	*curr_patch;
WORD	curr_pnr;
WORD	curr_ptt;
BYTE	jaz_prf_file[256];

/*	----------------------------------------------------------------
 *	PROTOTYPES
 */
VOID	main(VOID);
VOID	InitGEMObjs(VOID);
VOID	InitPttTable(VOID);
VOID	PttTable2Strings(WORD);
VOID	PttTable2PitchPatch(VOID);
VOID 	pttlist_handler(OBJECT *, WORD, LISTINFO *);
LONG 	pttbttn_handler(OBJECT *, WORD, WORD, WORD, ULONG);
WORD	pttcmp(PTT_TAB *, PTT_TAB *);
VOID	load_handler(OBJECT *, WORD, WORD, WORD, ULONG);
VOID	save_handler(OBJECT *, WORD, WORD, WORD, ULONG);
VOID 	pstab_handler(OBJECT *, WORD, WORD, WORD, ULONG);
LONG	pstab_close(OBJECT *, WORD, WORD, WORD, ULONG);
WORD	write_pmp(BYTE *);
WORD	read_pmp(BYTE *);
VOID	change_tune (OBJECT *,WORD,SLIDEINFO *);
VOID	change_patch (OBJECT *,WORD,SLIDEINFO *);
VOID	change_volume (OBJECT *tree,WORD obj,SLIDEINFO *info);
VOID	change_channel (OBJECT *tree,WORD obj,SLIDEINFO *info);
VOID	midi_onoff (OBJECT *tree,WORD obj,WORD e, WORD, WORD);
VOID	scrn_onoff (OBJECT *tree,WORD obj,WORD e, WORD, WORD);
VOID	timer_speed (OBJECT *tree,WORD obj,POPUPINFO *info);
WORD	return_handler(OBJECT *tree, WORD obj, WORD d1, WORD d2, ULONG d3);
VOID 	handle_pmtlist(VOID);
VOID 	pttlist_bthandler(OBJECT *, WORD, WORD, WORD, ULONG);


/*	----------------------------------------------------------------
 *	FUNCTIONS
 */


/*
 *	C ENTRY POINT
 *	MAIN()
 */

	VOID
main(VOID)
{
	strcpy(jaz_prf_file, "jaz.prf");

	read_cnf();		/* read JAZ.CNF */
	appl_init();		/* init GEM library */
	init_patches();		/* copy default patches to patch table */
	InitPttTable();		/* Init PTT (Map) */
	PttTable2Strings(-1);
	InitGEMObjs();		/* Init GEM Object Trees */
	init_fsel();		/* Init File Selector */
#if 0
	build_pedit();		/* build Patch Edit screens */
#endif
	build_jazalg();		/* build JAZ algorithm page */
	build_jazosc();		/* build JAZ osc page */
	build_jazenv();		/* build JAZ env page */
	
	/* 
 	 * Read default performance file 
	 */
	read_patch(PERF_FILE, jaz_prf_file, 0);	


	objc_draw(maintree, 0, MAXDEPTH, 0, 0, scrn_w, scrn_h);

	form_xdo(maintree, MAIN_BAR);
}

VOID handle_pmtlist(VOID)
{
	objc_draw(jaztree, 0, MAXDEPTH, 0, 0, scrn_w, scrn_h);

	form_xdo(jaztree, JAZ_FILEBAR);

	v_draw_title();
	objc_draw(maintree, 0, MAXDEPTH, 0, 0, scrn_w, scrn_h);
}

WORD return_handler(OBJECT *tree, WORD obj, WORD d1, WORD d2, ULONG d3)
{
	return -1;	
}

/*
 *	Init Patch Translation Table
 */

	VOID
InitPttTable()
{
	REG WORD i;

	ptt_id = 0;
	for (i = 0; i < MIDI_CHANNELS; i++, ptt_id++) {
		ptt_table[i].act = 0;
		ptt_table[i].channel = i+1;
		ptt_table[i].patch = 1;		/* default to patch 1 */
		ptt_table[i].start = 0;
		ptt_table[i].end = 127;
		ptt_table[i].offset = 0;
		ptt_table[i].priority = 7;
		ptt_table[i].volume = 127;
		ptt_table[i].tuning = 0x1000L;
		ptt_table[i].id = ptt_id;
#if 0
		ptt_table[i].ix = i;
		ptt_table[i].iix = 0;
#endif
		pitchpatch[i].translate = TRUE;
		pitchpatch[i].n = 1;
		pitchpatch[i].patch[0] = 0;
		pitchpatch[i].start[0] = 0;
		pitchpatch[i].end[0] = 127;
		pitchpatch[i].offset[0] = 0;
#if 0
		pitchpatch[i].ix[0] = ptt_id;
#endif

	}
#if 0
	ptt_table[14].patch = ptt_table[15].patch = 13; 	/* for now */
	pitchpatch[14].patch[0] = pitchpatch[15].patch[0] = 13;
#endif
	ptt_count = 16;
}

/*
 *	Convert Patch translation table values (which we see on the
 *	screen) to PitchPatchTable used by the real-time MIDI parser.
 */

	VOID
PttTable2PitchPatch()
{
	REG PTT_TAB *p;
	REG WORD i, k, j, n;

	p = ptt_table;
	k = ptt_count;

	/*
  	 * Reinitialize Table
	 */
	for (i = 0; i < MIDI_CHANNELS; i++) {
		pitchpatch[i].translate = FALSE;
		pitchpatch[i].n = 0;
	}

	/*
	 * Convert data
	 */
	for (i = 0; i < k; i++, p++) {
		/*
		 *	The following 'if' statement is for us to be
		 *	on the safe side. Because it could be that
		 *	a patch should be active but was refused to 
		 *	being active due to lack of DSP memory!
		 */
		if (patchinfo_table[p->patch - 1].active) {
			j = p->channel - 1;
			pitchpatch[j].translate = TRUE;
			n = pitchpatch[j].n++;
			pitchpatch[j].patch[n] = p->patch - 1;
			pitchpatch[j].start[n] = p->start;
			pitchpatch[j].end[n] = p->end;
			pitchpatch[j].offset[n] = p->offset;
#if 0
			pitchpatch[j].ix[n] = i;
#endif
			pitchpatch[j].cover[n] = FALSE;
		}
	}

	/*
	 * Set the other channels to the first patch, so that we don't
	 * crash!
	 *
 	 * N O T E : We should let it point to a DEFAULT PATCH which
	 * !!!!!!!   is always there!!!!!!
	 */
	p = ptt_table;
#if 0
	for (i = 0; i < MIDI_CHANNELS; i++) {
		if (pitchpatch[i].translate == FALSE) {
			pitchpatch[i].translate = TRUE;
			pitchpatch[i].n = 1;
			pitchpatch[i].patch[0] = p->patch - 1;
			pitchpatch[i].start[0] = 0;
			pitchpatch[i].end[0] = 127;
			pitchpatch[i].offset[0] = 0;
			pitchpatch[i].ix[0] = 0;
		}
	}
#else
	/*
	 * We go even one step father: to cover the whole note range we
	 * add one whole note range pointing to patch # to the end. Since it's
	 * the end, the others have priority
	 */
	for (i = 0; i < MIDI_CHANNELS; i++) {
		pitchpatch[i].translate = TRUE;
		n = pitchpatch[i].n++;
		pitchpatch[i].patch[n] = 0;
		pitchpatch[i].start[n] = 0;
		pitchpatch[i].end[n] = 127;
		pitchpatch[i].offset[n] = 0;
		pitchpatch[i].cover[n] = TRUE;		
	}


#endif

#if DEBUG
	/*
	 * debugging
	 */

	 for (i = 0; i < MIDI_CHANNELS; i++) {
		BYTE dbuf[80];
		for (j = 0; j < pitchpatch[i].n; j++) {
			sprintf(dbuf, "ch=%02d p=%03d s=%03d e=%03d o=%03d",
				i+1, pitchpatch[i].patch[j] + 1,
				pitchpatch[i].start[j],
				pitchpatch[i].end[j],
				pitchpatch[i].offset[j]);
			dos_echo(dbuf);
		}
	}

#endif

}

/*
 *	Convert Patch translation table values to strings
 */

	VOID
PttTable2Strings(x)
	WORD x;		/* either the index or if -1, do all  */
{
	REG BYTE **s;
	REG PTT_TAB *p;
	REG WORD i, k;

	if (x == -1) {
		s = pttlist;
		p = ptt_table;
		k = ptt_count;
	} else {
		s = &pttlist[x * LIST_COLS];
		p = &ptt_table[x];
		k = 1;
	}
	for (i = 0; i < k; i++, p++) {
		sprintf(p->s_act, "%c", (p->act == 0) ? ' ' : 'X');
		*s++ = p->s_act;
		sprintf(p->s_channel, "%02d", p->channel);
		*s++ = p->s_channel;
#if 0
		sprintf(p->s_patch, "%03d", p->patch);
#else
		p->s_patch = patch_names[p->patch-1];

#endif
		*s++ = p->s_patch;
		sprintf(p->s_note, "%03d - %03d", p->start, p->end);
		*s++ = p->s_note;
		sprintf(p->s_offset, "%d", p->offset);
		*s++ = p->s_offset;
		sprintf(p->s_priority, "%d", p->priority);
		*s++ = p->s_priority;
		sprintf(p->s_volume, "%03d", p->volume);
		*s++ = p->s_volume;
		sprintf(p->s_tuning, "$%04lx", p->tuning);
		*s++ = p->s_tuning;
	}
}

/*
 *	Build the GEM object for the main page
 */

	VOID
InitGEMObjs()
{
	LISTINFO	*list;


	objc_xadd(maintree, NIL, MAIN_BOX, 
		G_IBOX, -1, -1, 
		2, 2, scrn_w - 4, scrn_h - 4,
		IS3DOBJ|NONE, NORMAL,
		0);	

		objc_xadd(maintree, MAIN_BOX, MAIN_BAR, 
			G_XBAR, -1, -1, 
			215, 110, 150, 80,
			IS3DOBJ|JOYPAD|SELECTABLE, NORMAL,
			T_BA_NUM, 5,
			T_BA_FIRST, 1,
			0);
			objc_xadd(maintree, MAIN_BAR, MAIN_EDITPMT, 
				G_XBUTTON, -1, -1, 
				0, 2, 145, 8,
				ABUTTON|IS3DOBJ|SELECTABLE, NORMAL,
				T_BT_TEXT, "EDIT PATCH MAP TABLE",
				T_BT_BGCOLOR, 0,
				T_BT_TXTCOLOR, 1,
				T_BT_FONTID, 0,
				T_BT_SMCHAR, '1',
				T_OB_LATTACH, MAIN_BAR, 1,
				T_OB_UATTACH, MAIN_BAR, 3,
				T_BT_CALLBK, handle_pmtlist,
				0);
			objc_xadd(maintree, MAIN_BAR, MAIN_EDITPATCHES, 
				G_XBUTTON, -1, -1, 
				0, 2, 145, 8,
				ABUTTON|IS3DOBJ|SELECTABLE, NORMAL,
				T_BT_TEXT, "EDIT PATCHES",
				T_BT_BGCOLOR, 0,
				T_BT_TXTCOLOR, 1,
				T_BT_FONTID, 0,
				T_BT_SMCHAR, '2',
				T_OB_LATTACH, MAIN_BAR, 1,
				T_OB_UATTACH, MAIN_EDITPMT, 3,
				T_BT_CALLBK, pstab_handler,
				0);
			objc_xadd(maintree, MAIN_BAR, MAIN_LOADPRF, 
				G_XBUTTON, -1, -1, 
				0, 2, 145, 8,
				ABUTTON|IS3DOBJ|SELECTABLE, NORMAL,
				T_BT_TEXT, "LOAD PERFORMANCE FILE",
				T_BT_BGCOLOR, 0,
				T_BT_TXTCOLOR, 1,
				T_BT_FONTID, 0,
				T_BT_SMCHAR, '3',
				T_BT_CALLBK, load_handler,
				T_OB_LATTACH, MAIN_BAR, 1,
				T_OB_UATTACH, MAIN_EDITPATCHES, 3,
				0);

			objc_xadd(maintree, MAIN_BAR, MAIN_SAVEPRF, 
				G_XBUTTON, -1, -1, 
				0, 2, 145, 8,
				ABUTTON|IS3DOBJ|SELECTABLE, NORMAL,
				T_BT_TEXT, "SAVE PERFORMANCE FILE",
				T_BT_BGCOLOR, 0,
				T_BT_TXTCOLOR, 1,
				T_BT_FONTID, 0,
				T_BT_SMCHAR, '4',
				T_BT_CALLBK, save_handler,
				T_OB_LATTACH, MAIN_BAR, 1,
				T_OB_UATTACH, MAIN_LOADPRF, 3,
				0);

			objc_xadd(maintree, MAIN_BAR, MAIN_BUSHOG, 
				G_XBUTTON, -1, -1, 
				0, 2, 145, 8,
				ABUTTON|IS3DOBJ|SELECTABLE, NORMAL,
				T_BT_TEXT, "BUS HOG",
				T_BT_BGCOLOR, 0,
				T_BT_TXTCOLOR, 1,
				T_BT_FONTID, 0,
				T_BT_SMCHAR, '5',
				T_OB_LATTACH, MAIN_BAR, 1,
				T_OB_UATTACH, MAIN_SAVEPRF, 3,
				0);



	objc_xadd(jaztree, NIL, JAZ_BOX, 
		G_BOX, -1, -1, 
		2, 2, scrn_w - 4, scrn_h - 4,
		IS3DOBJ|NONE, NORMAL,
		0);	


		objc_xadd(jaztree, JAZ_BOX, JAZ_TLBOX,
			G_XBAR, -1, -1, 
			0, 0, 0, 24,
			IS3DOBJ|NONE, NORMAL,
			T_OB_UATTACH, JAZ_BOX, 2,
			T_OB_LATTACH, JAZ_BOX, 4,
			T_OB_RATTACH, JAZ_BOX, 4,
			0);	
			objc_xadd(jaztree, JAZ_TLBOX, JAZ_TLTEXT, 
				G_XTEXT, -1, -1, 
				0, 0, 0, 6, 
				IS3DOBJ|NONE, NORMAL,
				T_OB_UATTACH, JAZ_TLBOX, 0,
				T_OB_LATTACH, JAZ_TLBOX, 4,
				T_OB_RATTACH, JAZ_TLBOX, 4,
				T_BX_TEXT, STR_TIMELEFT,
				T_BX_FONTID, FNT_SMALL,
				T_BX_ALIGN, TE_CNTR,
				0);
			objc_xadd(jaztree, JAZ_TLBOX, JAZ_TL0, 
				G_XTEXT, -1, -1, 
				0, 0, 6, 6, 
				NONE, NORMAL,
				T_OB_UATTACH, JAZ_TLTEXT, 5,
				T_OB_LATTACH, JAZ_TLBOX, 2,
				T_BX_TEXT, "0",
				T_BX_FONTID, FNT_SMALL,
				T_BX_ALIGN, TE_LEFT,
				0);
			objc_xadd(jaztree, JAZ_TLBOX, JAZ_TL100, 
				G_XTEXT, -1, -1, 
				0, 0, 24, 6, 
				NONE, NORMAL,
				T_OB_UATTACH, JAZ_TLTEXT, 5,
				T_OB_RATTACH, JAZ_TLBOX, 2,
				T_BX_TEXT, "100%",
				T_BX_FONTID, FNT_SMALL,
				T_BX_ALIGN, TE_LEFT,
				0);
			objc_xadd(jaztree, JAZ_TLBOX, JAZ_TLSLIDER,
				G_XBAR, -1, -1, 
				0, 0, 80, 8,
				IS3DOBJ|NONE, NORMAL,
				T_OB_UATTACH, JAZ_TLTEXT, 0,
				T_OB_LATTACH, JAZ_TL0, 2,
				T_OB_RATTACH, JAZ_TL100, 2,
				0);

	
		objc_xadd(jaztree, JAZ_BOX, JAZ_PTTBOX, 
			G_XLIST, -1, -1, 
			4, 36, 372, 130,
			JOYPAD|IS3DOBJ|SELECTABLE, NORMAL,
			T_OB_DOWN, JAZ_FILEBAR,
			T_LST_NAME, STR_PTT,
			T_LST_TITLES, STR_ACT,
			T_LST_TITLES, STR_CHANNEL,
			T_LST_TITLES, STR_PATCH,
			T_LST_TITLES, STR_NOTERANGE,
			T_LST_TITLES, STR_OFFSET,
			T_LST_TITLES, STR_PRIORITY,
			T_LST_TITLES, STR_VOL,
			T_LST_TITLES, STR_TUNING,
			T_LST_CALLBK, pttlist_handler,
			0);
		list = jaztree[JAZ_PTTBOX].ob_spec.list;
		list->data = (VOID*) &pttlist;
		list->index = 0;
		list->maxitems = ptt_count;

		objc_xadd(jaztree, JAZ_BOX, JAZ_FILEBAR, 
			G_XBAR, -1, -1, 
			4, 0, 372, 18,
			IS3DOBJ|JOYPAD|SELECTABLE, NORMAL,
			T_OB_UP, JAZ_PTTBOX,
			T_OB_UATTACH, JAZ_PTTBOX, 3,
			T_BA_NUM, 4,
			T_BA_FIRST, 1,
			0);
			objc_xadd(jaztree, JAZ_FILEBAR, JAZ_PAGE, 
				G_XBUTTON, -1, -1, 
				0, 2, 80, 12,
				ABUTTON|IS3DOBJ|SELECTABLE, NORMAL,
				T_BT_TEXT, "Edit",
				T_BT_BGCOLOR, 0,
				T_BT_TXTCOLOR, 1,
				T_BT_FONTID, 1,
				T_BT_SMCHAR, '1',
				T_OB_LATTACH, JAZ_FILEBAR, 6,
				T_OB_UATTACH, JAZ_FILEBAR, 1,
				T_BT_CALLBK, pttlist_bthandler,
				0);
			objc_xadd(jaztree, JAZ_FILEBAR, JAZ_LOAD, 
				G_XBUTTON, -1, -1, 
				0, 2, 80, 12,
				ABUTTON|IS3DOBJ|SELECTABLE, NORMAL,
				T_BT_TEXT, "Load PMT",
				T_BT_BGCOLOR, 0,
				T_BT_TXTCOLOR, 1,
				T_BT_FONTID, 1,
				T_BT_SMCHAR, '2',
/*				T_BT_CALLBK, load_handler,*/
				T_OB_LATTACH, JAZ_PAGE, 6,
				T_OB_UATTACH, JAZ_FILEBAR, 1,
				0);
			objc_xadd(jaztree, JAZ_FILEBAR, JAZ_SAVE, 
				G_XBUTTON, -1, -1, 
				0, 2, 80, 12,
				ABUTTON|IS3DOBJ|SELECTABLE, NORMAL,
				T_BT_TEXT, STR_SAVEPTT,
				T_BT_BGCOLOR, 0,
				T_BT_TXTCOLOR, 1,
				T_BT_FONTID, 1,
				T_BT_SMCHAR, '3',
/*				T_BT_CALLBK, save_handler,*/
				T_OB_LATTACH, JAZ_LOAD, 6,
				T_OB_UATTACH, JAZ_FILEBAR, 1,
				0);
			objc_xadd(jaztree, JAZ_FILEBAR, JAZ_CLOSE, 
				G_XBUTTON, -1, -1, 
				0, 2, 80, 12,
				ABUTTON|IS3DOBJ|SELECTABLE, NORMAL,
				T_BT_TEXT, "Close",
				T_BT_BGCOLOR, 0,
				T_BT_TXTCOLOR, 1,
				T_BT_FONTID, 1,
				T_BT_SMCHAR, '4',
				T_BT_CALLBK, return_handler,
				T_OB_LATTACH, JAZ_SAVE, 6,
				T_OB_UATTACH, JAZ_FILEBAR, 1,
				0);

/************************/
/*  Patch Mapping Tree  */
/************************/

	objc_xadd(ptttree, NIL, PTT_BOX, 
		G_BOX, -1, -1, 
		10, 30, 360, 160,
		IS3DOBJ|NONE, NORMAL,
		0);	
		objc_xadd(ptttree, PTT_BOX, PTT_TITLE, 
			G_XBOXTEXT, -1, -1, 
			0, 0, 
			FNT_MSTRWIDTH(STR_PTTTITLE) + 16, 14, 
			IS3DOBJ|NONE, NORMAL,
			T_OB_LATTACH, PTT_BOX, 6,		
			T_OB_RATTACH, PTT_BOX, 6,		
			T_OB_UATTACH, PTT_BOX, 2,
			T_BX_TEXT, STR_PTTTITLE,
			T_BX_FONTID, FNT_MEDIUM,
			T_BX_ALIGN, TE_CNTR,
			0);

		objc_xadd(ptttree, PTT_BOX, PTT_FRAME1, 
			G_BOX, -1, -1, 
			6, 22, 165, 110, 
			FRAME, NORMAL,
			0);

		objc_xadd(ptttree, PTT_FRAME1, PTT_CHANNEL,
			G_XREALSLIDER, -1, -1,
			8, 6, 25, 96,
			JOYPAD|SELECTABLE, NORMAL,
			T_OB_UP, PTT_BAR,
			T_OB_DOWN, PTT_BAR,
			T_OB_LEFT, PTT_FINE,
			T_OB_RIGHT, PTT_PATCH,
			T_SLIDE_SLNAME, "CHAN",
			T_SLIDE_MIN, 1L,
			T_SLIDE_MAX, 16L,
			T_SLIDE_CALLBK, change_channel,
			0);

		objc_xadd(ptttree, PTT_FRAME1, PTT_PATCH,
			G_XREALSLIDER, -1, -1,
			0, 6, 25, 96,
			JOYPAD|SELECTABLE, NORMAL,
			T_OB_LATTACH, PTT_CHANNEL, 6,
			T_OB_UP, PTT_BAR,
			T_OB_DOWN, PTT_BAR,
			T_OB_LEFT, PTT_CHANNEL,
			T_OB_RIGHT, PTT_START,
			T_SLIDE_SLNAME, STR_PTTPATCH,
			T_SLIDE_MIN, 1L,
			T_SLIDE_MAX, 128L,
			T_SLIDE_CALLBK, change_patch,
			0);

		objc_xadd(ptttree, PTT_FRAME1, PTT_START,
			G_XREALSLIDER, -1, -1,
			0, 6, 25, 96,
			JOYPAD|SELECTABLE, NORMAL,
			T_OB_LATTACH, PTT_PATCH, 6,
			T_OB_UP, PTT_BAR,
			T_OB_DOWN, PTT_BAR,
			T_OB_LEFT, PTT_PATCH,
			T_OB_RIGHT, PTT_END,
			T_SLIDE_SLNAME, STR_PTTSTART,
			T_SLIDE_MAX, 127L,
			0);

		objc_xadd(ptttree, PTT_FRAME1, PTT_END,
			G_XREALSLIDER, -1, -1,
			0, 6, 25, 96,
			JOYPAD|SELECTABLE, NORMAL,
			T_OB_LATTACH, PTT_START, 6,
			T_OB_UP, PTT_BAR,
			T_OB_DOWN, PTT_BAR,
			T_OB_LEFT, PTT_START,
			T_OB_RIGHT, PTT_OFFSET,
			T_SLIDE_SLNAME, STR_PTTEND,
			T_SLIDE_MAX, 127L,
			0);

		objc_xadd(ptttree, PTT_FRAME1, PTT_OFFSET,
			G_XREALSLIDER, -1, -1,
			0, 6, 25, 96,
			JOYPAD|SELECTABLE, NORMAL,
			T_OB_LATTACH, PTT_END, 6,
			T_OB_UP, PTT_BAR,
			T_OB_DOWN, PTT_BAR,
			T_OB_LEFT, PTT_END,
			T_OB_RIGHT, PTT_VOLUME,
			T_SLIDE_SLNAME, STR_PTTOFFSET,
			T_SLIDE_MAX, 127L,
			0);

		objc_xadd(ptttree, PTT_BOX, PTT_FRAME2, 
			G_BOX, -1, -1, 
			177, 22, 175, 110, 
			FRAME, NORMAL,
			0);


		objc_xadd(ptttree, PTT_FRAME2, PTT_VOLUME,
			G_XREALSLIDER, -1, -1,
			8, 6, 25, 96,
			JOYPAD|SELECTABLE, NORMAL,
			T_OB_UP, PTT_BAR,
			T_OB_DOWN, PTT_BAR,
			T_OB_LEFT, PTT_OFFSET,
			T_OB_RIGHT, PTT_PRIORITY,
			T_SLIDE_SLNAME, STR_PTTVOLUME,
			T_SLIDE_MAX, 127L,
			T_SLIDE_CALLBK, change_volume,
			0);

		objc_xadd(ptttree, PTT_FRAME2, PTT_PRIORITY,
			G_XREALSLIDER, -1, -1,
			0, 6, 25, 96,
			JOYPAD|SELECTABLE, NORMAL,
			T_OB_LATTACH, PTT_VOLUME, 6,
			T_OB_UP, PTT_BAR,
			T_OB_DOWN, PTT_BAR,
			T_OB_LEFT, PTT_VOLUME,
			T_OB_RIGHT, PTT_OCTAVE,
			T_SLIDE_SLNAME, STR_PTTPRIORITY,
			T_SLIDE_MAX, 7L,
			0);

		objc_xadd(ptttree, PTT_FRAME2, PTT_OCTAVE,
			G_XREALSLIDER, -1, -1,
			0, 16, 25, 86,
			JOYPAD|SELECTABLE, NORMAL,
			T_OB_LATTACH, PTT_PRIORITY, 6,
			T_OB_UP, PTT_BAR,
			T_OB_DOWN, PTT_BAR,
			T_OB_LEFT, PTT_PRIORITY,
			T_OB_RIGHT, PTT_HALFSTEP,
			T_SLIDE_SLNAME, "OCT",
			T_SLIDE_MAX, 3L,
			T_SLIDE_MIN, -3L,
			T_SLIDE_CALLBK, change_tune,
			0);

		objc_xadd(ptttree, PTT_FRAME2, PTT_HALFSTEP,
			G_XREALSLIDER, -1, -1,
			0, 16, 25, 86,
			JOYPAD|SELECTABLE, NORMAL,
			T_OB_LATTACH, PTT_OCTAVE, 6,
			T_OB_UP, PTT_BAR,
			T_OB_DOWN, PTT_BAR,
			T_OB_LEFT, PTT_OCTAVE,
			T_OB_RIGHT, PTT_FINE,
			T_SLIDE_SLNAME, "HALF",
			T_SLIDE_MAX, 11L,
			T_SLIDE_CALLBK, change_tune,
			0);
		objc_xadd(ptttree, PTT_FRAME2, PTT_FINE,
			G_XREALSLIDER, -1, -1,
			0, 16, 25, 86,
			JOYPAD|SELECTABLE, NORMAL,
			T_OB_LATTACH, PTT_HALFSTEP, 6,
			T_OB_UP, PTT_BAR,
			T_OB_DOWN, PTT_BAR,
			T_OB_LEFT, PTT_HALFSTEP,
			T_OB_RIGHT, PTT_CHANNEL,
			T_SLIDE_SLNAME, "FINE",
			T_SLIDE_MAX, 243L,
			T_SLIDE_CALLBK, change_tune,
			0);

		objc_xadd(ptttree, PTT_FRAME2, PTT_TUNING, 
			G_XBOXTEXT, -1, -1, 
			0, 4, 75, 7, 
			IS3DOBJ|NONE, NORMAL,
			T_OB_LATTACH, PTT_PRIORITY, 6,		
			T_BX_TEXT, "TUNING",
			T_BX_FONTID, FNT_SMALL,
			T_BX_ALIGN, TE_CNTR,
			0);


		objc_xadd(ptttree, PTT_BOX, PTT_BAR, 
			G_XBAR, -1, -1, 
			4, 0, 372, 18,
			IS3DOBJ|JOYPAD|SELECTABLE, NORMAL,
			T_OB_DOWN, PTT_CHANNEL,
			T_OB_UP, PTT_VOLUME,
			T_OB_UATTACH, PTT_FRAME2, 2,
			T_OB_LATTACH, PTT_BOX, 6,
			T_OB_RATTACH, PTT_BOX, 6,
			T_BA_NUM, 4,
			T_BA_FIRST, 1,
			0);
			objc_xadd(ptttree, PTT_BAR, PTT_CHANGE, 
				G_XBUTTON, -1, -1, 
				0, 2, 70, 12,
				ABUTTON|IS3DOBJ|SELECTABLE, NORMAL,
				T_BT_TEXT, STR_CHANGE,
				T_BT_BGCOLOR, 0,
				T_BT_TXTCOLOR, 1,
				T_BT_FONTID, 1,
				T_BT_SMCHAR, '1',
				T_BT_CALLBK, pttbttn_handler,
				T_OB_LATTACH, PTT_BAR, 6,
				T_OB_UATTACH, PTT_BAR, 1,
				0);
			objc_xadd(ptttree, PTT_BAR, PTT_ADD, 
				G_XBUTTON, -1, -1, 
				0, 2, 50, 12,
				ABUTTON|IS3DOBJ|SELECTABLE, NORMAL,
				T_BT_TEXT, STR_ADD,
				T_BT_BGCOLOR, 0,
				T_BT_TXTCOLOR, 1,
				T_BT_FONTID, 1,
				T_BT_SMCHAR, '2',
				T_BT_CALLBK, pttbttn_handler,
				T_OB_LATTACH, PTT_CHANGE, 6,
				T_OB_UATTACH, PTT_BAR, 1,
				0);
			objc_xadd(ptttree, PTT_BAR, PTT_DELETE, 
				G_XBUTTON, -1, -1, 
				0, 2, 70, 12,
				ABUTTON|IS3DOBJ|SELECTABLE, NORMAL,
				T_BT_TEXT, STR_DELETE,
				T_BT_BGCOLOR, 0,
				T_BT_TXTCOLOR, 1,
				T_BT_FONTID, 1,
				T_BT_SMCHAR, '3',
				T_BT_CALLBK, pttbttn_handler,
				T_OB_LATTACH, PTT_ADD, 6,
				T_OB_UATTACH, PTT_BAR, 1,
				0);
			objc_xadd(ptttree, PTT_BAR, PTT_CANCEL, 
				G_XBUTTON, -1, -1, 
				0, 2, 70, 12,
				ABUTTON|IS3DOBJ|SELECTABLE, NORMAL,
				T_BT_TEXT, STR_CANCEL,
				T_BT_BGCOLOR, 0,
				T_BT_TXTCOLOR, 1,
				T_BT_FONTID, 1,
				T_BT_SMCHAR, '4',
				T_BT_CALLBK, pttbttn_handler,
				T_OB_RATTACH, PTT_BAR, 6,
				T_OB_UATTACH, PTT_BAR, 1,
				0);
#if 1
	objc_xadd(pstabtree, NIL, PSTAB_BOX, 
		G_BOX, -1, -1, 
		10, 6, 360, 188,
		IS3DOBJ|NONE, NORMAL,
		0);	
		objc_xadd(pstabtree, PSTAB_BOX, PSTAB_TITLE, 
			G_XBOXTEXT, -1, -1, 
			0, 0, 
			FNT_MSTRWIDTH(STR_PSTABTITLE) + 16, 14, 
			IS3DOBJ|NONE, NORMAL,
			T_OB_LATTACH, PSTAB_BOX, 6,		
			T_OB_RATTACH, PSTAB_BOX, 6,		
			T_OB_UATTACH, PSTAB_BOX, 2,
			T_BX_TEXT, STR_PSTABTITLE,
			T_BX_FONTID, FNT_MEDIUM,
			T_BX_ALIGN, TE_CNTR,
			0);
		objc_xadd(pstabtree, PSTAB_BOX, PSTAB_PLIST, 
			G_XLIST, -1, -1, 
			0, 0, 334, 100,
			JOYPAD|IS3DOBJ|SELECTABLE, NORMAL,
			T_OB_DOWN, PSTAB_PBAR,
			T_OB_UP, PSTAB_MBAR,
			T_OB_UATTACH, PSTAB_TITLE, 6,		
			T_OB_LATTACH, PSTAB_BOX, 12,		
			T_LST_NAME, STR_PSTABPATCHES,
			T_LST_TITLES, STR_PSTABNR,
			T_LST_TITLES, STR_PSTABNAME,
			T_LST_TITLES, STR_PSTABTYPE,
			T_LST_TITLES, STR_PSTABACTI,
			T_LST_CALLBK, pstab_pview,
			0);
		list = pstabtree[PSTAB_PLIST].ob_spec.list;
		list->data = (VOID*) &patchnameslist;
		list->index = 0;
		list->maxitems = 128;

		objc_xadd(pstabtree, PSTAB_BOX, PSTAB_PBAR, 
			G_XBAR, -1, -1, 
			0, 0, 334, 18,
 			IS3DOBJ|JOYPAD|SELECTABLE, NORMAL,
			T_OB_DOWN, PSTAB_MBAR,
			T_OB_UP, PSTAB_PLIST,
			T_OB_UATTACH, PSTAB_PLIST, 3,
			T_OB_LATTACH, PSTAB_BOX, 12,		
			T_BA_NUM, 2,
			T_BA_FIRST, 1,
			0);
			objc_xadd(pstabtree, PSTAB_PBAR, PSTAB_PVIEW, 
				G_XBUTTON, -1, -1, 
				0, 2, 75, 12,
				ABUTTON|IS3DOBJ|SELECTABLE, NORMAL,
				T_OB_LATTACH, PSTAB_PBAR, 2,
				T_OB_UATTACH, PSTAB_PBAR, 1,
				T_BT_TEXT, STR_PSTABVIEW,
				T_BT_BGCOLOR, 0,
				T_BT_TXTCOLOR, 1,
				T_BT_FONTID, 1,
				T_BT_SMCHAR, '1',
				T_BT_CALLBK, pstab_pview,
				0);
			objc_xadd(pstabtree, PSTAB_PBAR, PSTAB_PLOAD, 
				G_XBUTTON, -1, -1, 
				0, 2, 75, 12,
				ABUTTON|IS3DOBJ|SELECTABLE, NORMAL,
				T_OB_LATTACH, PSTAB_PVIEW, 5,
				T_OB_UATTACH, PSTAB_PBAR, 1,
				T_BT_TEXT, STR_PSTABLOAD,
				T_BT_BGCOLOR, 0,
				T_BT_TXTCOLOR, 1,
				T_BT_FONTID, 1,
				T_BT_SMCHAR, '2',
				T_BT_CALLBK, pstab_pload,
				0);

			objc_xadd(pstabtree, PSTAB_PBAR, PSTAB_PSAVE, 
				G_XBUTTON, -1, -1, 
				0, 2, 75, 12,
				ABUTTON|IS3DOBJ|SELECTABLE, NORMAL,
				T_OB_LATTACH, PSTAB_PLOAD, 5,
				T_OB_UATTACH, PSTAB_PBAR, 1,
				T_BT_TEXT, STR_PSTABSAVE,
				T_BT_BGCOLOR, 0,
				T_BT_TXTCOLOR, 1,
				T_BT_FONTID, 1,
				T_BT_SMCHAR, '3',
				0);

			objc_xadd(pstabtree, PSTAB_PBAR, PSTAB_PDELETE, 
				G_XBUTTON, -1, -1, 
				0, 2, 75, 12,
				ABUTTON|IS3DOBJ|SELECTABLE, NORMAL,
				T_OB_LATTACH, PSTAB_PSAVE, 5,
				T_OB_UATTACH, PSTAB_PBAR, 1,
				T_BT_TEXT, STR_PSTABDELETE,
				T_BT_BGCOLOR, 0,
				T_BT_TXTCOLOR, 1,
				T_BT_FONTID, 1,
				T_BT_SMCHAR, '4',
				0);

		objc_xadd(pstabtree, PSTAB_BOX, PSTAB_MBAR, 
			G_XBAR, -1, -1, 
			0, 0, 160, 18,
 			IS3DOBJ|JOYPAD|SELECTABLE, NORMAL,
			T_OB_DOWN, PSTAB_PLIST,
			T_OB_UP, PSTAB_PBAR,
			T_OB_UATTACH, PSTAB_PBAR, 6,
			T_OB_LATTACH, PSTAB_BOX, 6,		
			T_OB_RATTACH, PSTAB_BOX, 6,
			T_BA_NUM, 1,
			T_BA_FIRST, 1,
			0);
			objc_xadd(pstabtree, PSTAB_MBAR, PSTAB_CLOSE, 
				G_XBUTTON, -1, -1, 
				0, 2, 60, 12,
				ABUTTON|IS3DOBJ|SELECTABLE, NORMAL,
				T_OB_UATTACH, PSTAB_MBAR, 1,
				T_OB_LATTACH, PSTAB_MBAR, 100,
				T_OB_RATTACH, PSTAB_MBAR, 100,
				T_BT_TEXT, STR_PSTABCLOSE,
				T_BT_BGCOLOR, 0,
				T_BT_TXTCOLOR, 1,
				T_BT_FONTID, 1,
				T_BT_SMCHAR, '1',
				T_BT_CALLBK, pstab_close,
				0);

#endif
}

/*
 *	Handle the PTT List - The 'A' (Select) Button was pressed inside the
 *	list.
 */

	VOID
pttlist_bthandler(tree, obj, d1, d2, d3)
	OBJECT	 *tree;
	WORD	 obj;
	WORD	 d1;
	WORD	 d2;
	ULONG	 d3;
{
	pttlist_handler(tree,obj,jaztree[JAZ_PTTBOX].ob_spec.list);
}

	VOID
pttlist_handler(tree, obj, info)
	OBJECT	 *tree;
	WORD	 obj;
	LISTINFO *info;
{
	LONG tune,o,h,f;
	REG WORD i, ch;
	BYTE temp[255];
	
	PTT_TAB *p = &ptt_table[info->index];

	sprintf(temp,"Patch Mapping: '%s' to #%d",patch_names[p->patch-1],p->channel);
	objc_xupdate(ptttree, PTT_TITLE, T_BX_TEXT, temp, 0);
	objc_xupdate(ptttree, PTT_CHANNEL, T_SLIDE_DEFAULT, (LONG)p->channel, 0);
	objc_xupdate(ptttree, PTT_PATCH, T_SLIDE_DEFAULT, (LONG)p->patch, 0);
	objc_xupdate(ptttree, PTT_PATCH, T_SLIDE_MAX, (LONG)patch_cnt, 0);
	objc_xupdate(ptttree, PTT_START, T_SLIDE_DEFAULT, (LONG)p->start, 0);
	objc_xupdate(ptttree, PTT_END, T_SLIDE_DEFAULT, (LONG)p->end, 0);
	objc_xupdate(ptttree, PTT_OFFSET, T_SLIDE_DEFAULT, (LONG)p->offset, 0);
	objc_xupdate(ptttree, PTT_PRIORITY, T_SLIDE_DEFAULT, (LONG)p->priority, 0);
	objc_xupdate(ptttree, PTT_VOLUME, T_SLIDE_DEFAULT, (LONG)p->volume, 0);
	
	tune=p->tuning;
	tune2ohf(tune,&o,&h,&f);
		
	objc_xupdate(ptttree, PTT_OCTAVE, T_SLIDE_DEFAULT, o, 0);
	objc_xupdate(ptttree, PTT_HALFSTEP, T_SLIDE_DEFAULT, h, 0);
	objc_xupdate(ptttree, PTT_FINE, T_SLIDE_DEFAULT, f, 0);

	/*
 	 * find current line in pitchpatch array
	 */
	ch = p->channel - 1;
	curr_ptt = -1;
	for (i = 0; i < pitchpatch[ch].n; i++) {
		if (pitchpatch[ch].cover[i])
			continue;
		if ((pitchpatch[ch].start[i] == p->start) &&
		    (pitchpatch[ch].end[i] == p->end)) {
			curr_ptt = i;
			break;
		}
	}

	v_dark_tree(tree);
	objc_draw(ptttree, 0, MAXDEPTH, 0, 0, scrn_w, scrn_h);
	form_xdo(ptttree, PTT_BAR);
	objc_draw(jaztree, 0, MAXDEPTH, 0, 0, scrn_w, scrn_h);
	objc_outline(tree, obj, NIL);
}

/*
 *	Handle the buttons in the PTT box (Add, Delete, Change, Cancel)
 */


	LONG
pttbttn_handler(tree, obj, bttn, n, k)
	OBJECT	*tree;
	WORD	obj, bttn, n;
	ULONG	k;
{
	PTT_TAB *p;
	WORD x, ch;
	LONG lvalue,o,h,f;
	WORD sort;
	REG WORD i, j, l;
	WORD ix, iix;
	WORD channel, start, end, patch;
	LISTINFO *list = jaztree[JAZ_PTTBOX].ob_spec.list;
	WORD over_start[32], over_end[32];



	objc_xget(ptttree, PTT_PATCH, T_SLIDE_DEFAULT, &lvalue, 0);
	patch = (WORD) (lvalue - 1L);

	if ((bttn == PTT_ADD) || (bttn == PTT_CHANGE)) {
		objc_xget(ptttree, PTT_CHANNEL, T_SLIDE_DEFAULT, &lvalue, 0);
		channel = (WORD) lvalue;
		objc_xget(ptttree, PTT_START, T_SLIDE_DEFAULT, &lvalue, 0);
		start = (WORD) lvalue;
		objc_xget(ptttree, PTT_END, T_SLIDE_DEFAULT, &lvalue, 0);
		end = (WORD) lvalue;

		if (start > end) {
			form_alert(FRM_ALERT, FMSTR_LESSTHAN) ;
			return 0L;	/* Don't close, continue with dialog */
		}
		ch = channel - 1;

		for (i = 0, j = 0, l = 0; i < pitchpatch[ch].n; i++) {
			if (pitchpatch[ch].cover[i] == TRUE)
				continue;
			if (i == curr_ptt)	/* don't check current line */
				continue;
			if 
			 ((pitchpatch[ch].start[i] == start) ||
			  (pitchpatch[ch].end[i]   == start) ||
			  ((pitchpatch[ch].start[i] <= start) &&
			   (start < pitchpatch[ch].end[i])))
				over_start[j++] = i;
			if 
			 ((pitchpatch[ch].start[i] == end) ||
			  (pitchpatch[ch].end[i]   == end) ||
			  ((pitchpatch[ch].start[i] < end) &&
			   (end <= pitchpatch[ch].end[i])))
				over_end[l++] = i;
		}

		if ((j > 0) || (l > 0)) {
			form_alert(FRM_ALERT, FMSTR_OVERLAP) ;
			return 0L;	/* Don't close, continue with dialog */
		}
	}
	switch (bttn) {
	case PTT_ADD:
		if (ptt_count >= MAX_PTT) {
			form_alert(FRM_ALERT, FMSTR_TOOMANYPTT);
			return -1L;
		}
		x = ptt_count++;
		p = &ptt_table[x];
		sort = TRUE;
		break;
	case PTT_CHANGE:
		p = &ptt_table[x = list->index];
		sort = FALSE;
		break;
	case PTT_DELETE:
		if (ptt_count <= 1) {
			form_alert(FRM_ALERT, FMSTR_CANTDELLASTPTT);
			return 0L;
		}

		x = list->index;
#if 0
		ix = ptt_table[x].ix;	
		iix = ptt_table[x].iix;	
#endif
		for (i = x; i < (ptt_count - 1); i++) {
			ptt_table[i] = ptt_table[i+1];
		}
		list->maxitems = --ptt_count;
		if (list->index >= list->maxitems)
			list->index = list->maxitems -1;
		if (list->index < 0)
			list->index = 0;

		PttTable2Strings(-1);
		PttTable2PitchPatch();	/* update also MIDI parser table!!*/

		patchinfo_table[patch].active = FALSE;
			/* have to call a function here ... */
		update_patchnameslist();

		return -1L;
		break;
	case PTT_CANCEL:
		return -1L;
		break;
	default:
		return 0L;
	}

	patchinfo_table[patch].active = TRUE;
			/* have to call a function here ... */
	p->act = 0;

	p->start   = start;
	p->end     = end;
	p->channel = channel;

	objc_xget(ptttree, PTT_PATCH, T_SLIDE_DEFAULT, &lvalue, 0);
	p->patch = (WORD) lvalue;
	objc_xget(ptttree, PTT_OFFSET, T_SLIDE_DEFAULT, &lvalue, 0);
	p->offset = (WORD) lvalue;
	objc_xget(ptttree, PTT_PRIORITY, T_SLIDE_DEFAULT, &lvalue, 0);
	p->priority = (WORD) lvalue;
	objc_xget(ptttree, PTT_VOLUME, T_SLIDE_DEFAULT, &lvalue, 0);
	p->volume = (WORD) lvalue;
	objc_xget(ptttree, PTT_OCTAVE, T_SLIDE_DEFAULT, &o, 0);
	objc_xget(ptttree, PTT_HALFSTEP, T_SLIDE_DEFAULT, &h, 0);
	objc_xget(ptttree, PTT_FINE, T_SLIDE_DEFAULT, &f, 0);
	
	p->tuning = ohf2tune(o, h, f);
	patchtab[21 * (p->patch - 1) + 3L] = p->tuning;
		
	if (sort) {
		qsort((BYTE*)ptt_table, ptt_count, (WORD)sizeof(PTT_TAB), &pttcmp);
		list->maxitems = ptt_count;
		PttTable2Strings(-1);
	} else
		PttTable2Strings(x);

	PttTable2PitchPatch();	/* also, update the MIDI table */
	update_patchnameslist();
	return -1L;
}



VOID	timer_speed (OBJECT *tree,WORD obj,POPUPINFO *info)
{
	int *timer;
	
	timer=0xf00050;
	*timer=8000-info->index*1000;
}


VOID	midi_onoff(OBJECT *tree,WORD obj,WORD e, WORD d1, WORD d2)
{
	if (IsSelected(obj))
		midi_on();
	else
		midi_off();
}

VOID	scrn_onoff(OBJECT *tree,WORD obj,WORD e, WORD d1, WORD d2)
{
	if (IsSelected(obj))
		video_on();
	else
		video_off();
}

VOID	change_patch (OBJECT *tree,WORD obj,SLIDEINFO *info)
{
	LONG o,h,f,v;
	BYTE temp[255];
	
	tune2ohf(patchtab[21*(info->curr-1)+3L],&o,&h,&f);
	v=(patchtab[21*(info->curr-1)+20L]>>8)&0xff;
	
	sprintf(temp,"Patch Mapping: '%s' to #%d",patch_names[info->curr-1],(WORD)ptttree[PTT_CHANNEL].ob_spec.slider->curr);
	objc_xupdate(ptttree, PTT_TITLE, T_BX_TEXT, temp, 0);
	objc_xupdate(ptttree, PTT_OCTAVE, T_SLIDE_DEFAULT, o, 0);
	objc_xupdate(ptttree, PTT_HALFSTEP, T_SLIDE_DEFAULT, h, 0);
	objc_xupdate(ptttree, PTT_FINE, T_SLIDE_DEFAULT, f, 0);
	objc_xupdate(ptttree, PTT_VOLUME, T_SLIDE_DEFAULT, v, 0);
	ob_draw(ptttree, PTT_TITLE,0);
	ob_draw(ptttree, PTT_OCTAVE,0);
	ob_draw(ptttree, PTT_HALFSTEP,0);
	ob_draw(ptttree, PTT_FINE,0);
	ob_draw(ptttree, PTT_VOLUME,0);
}

VOID	change_channel (OBJECT *tree,WORD obj,SLIDEINFO *info)
{
	BYTE temp[255];
	
	
	sprintf(temp,"Patch Mapping: '%s' to #%d",patch_names[(WORD)ptttree[PTT_PATCH].ob_spec.slider->curr-1],(WORD)ptttree[PTT_CHANNEL].ob_spec.slider->curr);
	objc_xupdate(ptttree, PTT_TITLE, T_BX_TEXT, temp, 0);
	ob_draw(ptttree, PTT_TITLE,0);
}


VOID	change_tune (OBJECT *tree,WORD obj,SLIDEINFO *info)
{
	LONG o,h,f;
	
	o=tree[PTT_OCTAVE].ob_spec.slider->curr;
	h=tree[PTT_HALFSTEP].ob_spec.slider->curr;
	f=tree[PTT_FINE].ob_spec.slider->curr;
	patchtab[21*(tree[PTT_PATCH].ob_spec.slider->curr-1)+3L]=ohf2tune(o,h,f);
}

VOID	change_volume (OBJECT *tree,WORD obj,SLIDEINFO *info)
{
	LONG v;
	
	v=tree[PTT_VOLUME].ob_spec.slider->curr;
	patchtab[21*(tree[PTT_PATCH].ob_spec.slider->curr-1)+20L]=v<<8;
}

/*
 * Compare fct for PTT list
 */
	WORD
pttcmp(a, b)
	PTT_TAB *a, *b;
{
	WORD d;

	if ((d = (a->channel - b->channel)) == 0) {
		d = a->start - b->start;
	} 
	return d;
}




/* ==========================================================================
 * Main Screen Button Bar	
 */


/* 
 * Loading & Saving Patch Mab Tables
 * ---------------------------------
 */

#define PMP_EXT		".pmp"
#define PRF_EXT		".prf"
#define CURR_DIR	"."

/*
 *	Load Button
 */
EXTERN BYTE pathbuf[];

	VOID
load_handler(tree, curr, found, n, k)
	OBJECT *tree;
	WORD	curr;
	WORD	found;
	WORD	n;
	ULONG	k;
{
	BYTE path[256];
	BYTE fname[16];
	WORD x;

	objc_outline(tree, NIL, curr);
	v_dark_tree(tree);
	x = fsel_input(STR_LOADPRF, CURR_DIR, PRF_EXT, path, &fname[1]);

	if (x) {
		BYTE bbuf[28];
		BYTE dbuf[324];

		fname[0] = SLASH;
		strcat(path, fname);
		strrncpy(bbuf, path, 24);
		sprintf(dbuf, FMSTR_LOADPTT, path);
		form_alert(FRM_MSGSHOW, dbuf);
		/*read_pmp(path); */
		free_allSamples();
		init_patches();
		read_patch(PERF_FILE, path, 0); 	/* read perf. file */
		form_alert(FRM_MSGCLOSE, NULL);
	}

	v_draw_title();
	objc_draw(maintree, 0, MAXDEPTH, 0, 0, scrn_w, scrn_h);
	objc_outline(tree, curr, NIL);
}


	VOID
save_handler(tree, curr, found, n, k)
	OBJECT *tree;
	WORD	curr;
	WORD	found;
	WORD	n;
	ULONG	k;
{
	BYTE path[256];
	BYTE fname[16];
	WORD x;

	objc_outline(tree, NIL, curr);
	v_dark_tree(tree);
	x = fsel_input(STR_SAVEPRF, CURR_DIR, PRF_EXT, path, &fname[1]);

	if (x) {
		BYTE bbuf[28];
		BYTE dbuf[324];

		fname[0] = SLASH;
		strcat(path, fname);
		strrncpy(bbuf, path, 24);
		sprintf(dbuf, FMSTR_SAVEPTT, path);
		form_alert(FRM_MSGSHOW, dbuf);
/*		write_pmp(path);*/
		write_patch(PERF_FILE, path, 0); /* write perf. file */
		form_alert(FRM_MSGCLOSE, NULL);
	}

	v_draw_title();
	objc_draw(maintree, 0, MAXDEPTH, 0, 0, scrn_w, scrn_h);
	objc_outline(tree, curr, NIL);
}



/*
 *	Write Patch map
 */

	WORD
write_pmp(fname)
	BYTE *fname;
{
	BYTE		buf[256];
	REG WORD	i;
	REG BYTE	*s = filebuf;
	MFILE 		*fp;

	if ((fp = mfopen(filebuf, "wa")) == NULL)
		return -1;

	mfputs("#ATPMAP - DO NOT REMOVE THIS LINE", fp);
	mfputs("#", fp);
	mfputs("# JAZ - JAGUAR AUDIO SYSTEM - PATCH MAP TABLE", fp);
	mfputs("#", fp);
	sprintf(buf, "# CH\tPATCH\tNOTE RANGE\tOFFSET\tPRI\tVOL\tTUNE", fp);
	mfputs(buf, fp);
	mfputs("#", fp);

	for (i = 0; i < ptt_count; i++) {
		sprintf(buf, "%s\t%s\t%s\t%s\t%s\t%s\t%s", 
			ptt_table[i].s_channel,
			ptt_table[i].s_patch,
			ptt_table[i].s_note,
			ptt_table[i].s_offset,
			ptt_table[i].s_priority,
			ptt_table[i].s_volume,
			ptt_table[i].s_tuning);
			mfputs(buf, fp);
	}
	dos_write(fname, (LONG) fp->_cnt);
	mfclose(fp);
	return 0;
}


	WORD
read_pmp(fname)
	BYTE *fname;
{
	BYTE		buf[256];
	REG WORD	i = 0;
	WORD		n;
	REG BYTE	*s;
	MFILE 		*fp;
	WORD		ch, patch, note_b, note_e, offset, pri, vol;
	LONG		tune;
	LISTINFO *list = jaztree[JAZ_PTTBOX].ob_spec.list;

	dos_read(fname);		
	if ((fp = mfopen(filebuf, "ra")) == NULL)
		return -1;
	while (mfgets(buf, 256, fp) != NULL) {
		s = buf;
		for (; *s && (*s == ' ') && (*s == '\t'); )
			s++;
		if (!*s)
			continue;

		if (*s == '#' || *s == ';' || *s == '*')
			continue;
		n = sscanf(s, "%d %d %d - %d %d %d %d $%lx", &ch, &patch,
			&note_b, &note_e, &offset, &pri, &vol, &tune);
		if (n == 8) {
			ptt_table[i].act      = 0;
			ptt_table[i].channel  = ch;
			ptt_table[i].patch    = patch;
			ptt_table[i].start    = note_b;
			ptt_table[i].end      = note_e;
			ptt_table[i].offset   = offset;
			ptt_table[i].priority = pri;
			ptt_table[i].volume   = vol;
			ptt_table[i].tuning   = tune;
			i++;
		}

	}
	list->maxitems = ptt_count = i;
	PttTable2Strings(-1);
	PttTable2PitchPatch();
	mfclose(fp);
}


	VOID
pstab_handler(tree, curr, found, n, k)
	OBJECT *tree;
	WORD	curr;
	WORD	found;
	WORD	n;
	ULONG	k;
{

	v_dark_tree(tree);
	objc_outline(tree, NIL, curr);

	objc_draw(pstabtree, 0, MAXDEPTH, 0, 0, scrn_w, scrn_h);
	form_xdo(pstabtree, PSTAB_PLIST);

	v_draw_title();
	objc_draw(maintree, 0, MAXDEPTH, 0, 0, scrn_w, scrn_h);
	objc_outline(tree, curr, NIL);
}

	LONG
pstab_close(tree, curr, found, n, k)
	OBJECT *tree;
	WORD	curr;
	WORD	found;
	WORD	n;
	ULONG	k;
{
	return -1L;
}
