/************************************************************************
 *	TITLE:			JAZALG.C				*
 *	PROJECT:		JAGUAR/JAZ				*
 *	FUNCTION:	 	JAZ ALGORITHM MODULE			*
 *	PROGRAMMER:		Hans-Martin Krober			*
 *	DATE:			6/96					*
 *									*
 *              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 "algobj.h"
#include "jazenv.h"
#include "jazsyn.h"
#include "jazosc.h"
#include "ptchptch.h"
#include "dos.h"

/*	---------
 *	EXTERNALS
 */
EXTERN WORD 	scrn_w;
EXTERN WORD 	scrn_h;
EXTERN ULONG	patchtab[][PATCH_SIZE];
EXTERN MDTAB	mdtab_table[];
EXTERN PATCHINFO patchinfo_table[];
EXTERN WORD	curr_pnr;
EXTERN ENVTAB	env_table[];
EXTERN ENVTAB	dflt_envtab;
EXTERN SMPTAB	sample_table[];
EXTERN WORD	smpslot_cnt;

EXTERN LONG	*allocMDTAB(VOID);
EXTERN VOID	freeMDTAB(LONG*);
EXTERN VOID	mdtab2dsp(MDTAB *);
EXTERN WORD	find_mdtabSlot(VOID);
EXTERN VOID	free_mdtabSlot(WORD);
EXTERN LONG	*allocENV(WORD, WORD);
EXTERN LONG	adjust_volume(OBJECT *, WORD, POPUPINFO *);
EXTERN WORD	_debug;
EXTERN LONG	reverb_voice[];
EXTERN WORD	dft_env_ix;
/*
 *	Synth Externals
 */

EXTERN LONG 	*_effect_mode;
EXTERN LONG 	*_voice_buffer;
EXTERN LONG 	*_voice_table;
EXTERN LONG 	*_reverb_table;
EXTERN ULONG	_attn;
EXTERN ULONG	_delay;
EXTERN ULONG	_dft_filter;
EXTERN ULONG	_filter_def_1;
EXTERN ULONG	_mixer;
EXTERN ULONG	_reverb;
EXTERN ULONG	_osc_sampler;
EXTERN ULONG	_osc_sampler_loop;
EXTERN ULONG	_osc_nisampler;
EXTERN ULONG	_osc_fixedwave;
EXTERN ULONG	_osc_fixedwave_loop;
EXTERN ULONG	_osc_fm;
EXTERN ULONG	_osc_fm_loop;
EXTERN ULONG	_osc_polywave;
EXTERN ULONG	_osc_noise;
EXTERN ULONG	_osc_fx_pw;
EXTERN ULONG	_osc_fx_dist;
EXTERN ULONG	_osc_fx_pan;
EXTERN ULONG	_osc_fx_pitch;
EXTERN ULONG	_env_fx_pw;
EXTERN ULONG	_env_fx_dist;
EXTERN ULONG	_env_fx_pan;
EXTERN ULONG	_env_fx_pitch;
EXTERN ULONG	_env_slot1;
EXTERN ULONG	_env_slot2;
EXTERN ULONG	_env_slot3;
EXTERN ULONG	_loopenv_slot1;
EXTERN ULONG	_loopenv_slot2;
EXTERN ULONG	_loopenv_slot3;
EXTERN ULONG	_loopenv_skip;
EXTERN ULONG	_lfo_1;
EXTERN ULONG	_lfo_2;
EXTERN ULONG	_dist;
EXTERN ULONG	*_mdtab_reverb;
EXTERN ULONG	_vt_return_loc;
EXTERN ULONG	*_vt_ret_value;


/*	----------
 *	PROTOTYPES
 */
LONG	hndl_alg(OBJECT *, WORD, WORD, WORD, ULONG);
LONG	hndl_alg_clr(OBJECT *, WORD, WORD, WORD, ULONG);
LONG	alg_edit(OBJECT *, WORD, WORD, WORD, ULONG);
LONG	alg_omni(OBJECT *, WORD, WORD, WORD, ULONG);
LONG	process_alg(OBJECT *, WORD, POPUPINFO *);
WORD	get_env_index(WORD);
WORD	proc_lfo(WORD, WORD);
WORD	check_envs(WORD, WORD);
WORD	check_for_waveform(WORD);
WORD	setup_alg_values(WORD);
WORD	curr_mdtab2temp(VOID);
VOID	cancel_temp_mdtab(VOID);
VOID	patchinfo_rm_env(WORD, WORD);
WORD	env_only_used_by(WORD, ENVTAB*);
ENVTAB	*pi_find_envtab(WORD, WORD);
WORD	pi_find_envtab_ix(WORD, WORD);
VOID	replace_sample(WORD, WORD, WORD);
VOID	alg_free_lfo(WORD);
VOID	alg_free_env(WORD);
VOID	show_warning(WORD, WORD, WORD, WORD, BYTE *);
VOID	update_other_patches(VOID);
WORD	get_envstate(WORD);
WORD	check_delay(VOID);
VOID	set_delay(OBJECT *, WORD, POPUPINFO *);

/*	---------
 *	GLOBALS
 */
PATCHINFO patchinfo_bak;
WORD	alg_osc_type;
WORD	alg_old_osc_type;
WORD	alg_in_edit;			/* page in edit mode flag 	 */
WORD	alg_edit_mode;
WORD	alg_omni_mode;
WORD	alg_was_not_active;
WORD	alg_made_inactive_cnt;
WORD	alg_made_inactive[32];
ULONG	alg_mdtab[N_MDMODULES];    /* temp algorithm module tab work buffer */
LONG	overwrite1[9];
ULONG	alg_mdtab_bak[N_MDMODULES];/* bak alg. module tab work buffer */
LONG	overwrite2[9];
LONG	*alg_bak_dsp_addr;
MDTAB	*alg_mdtab_ptr;
MDTAB	*alg_mdtab_bak_ptr;
OBJECT	algtree[40];			/* the object tree for this page  */
OBJECT	warn_tree[10];
ULONG	tmp_patch_buf[PATCH_SIZE];
WORD	org_env_flags[4];
WORD	envnew[4];
WORD	env1_flag;
WORD	env2_flag;
WORD	env3_flag;
WORD	lfo2_flag;
WORD	lfo3_flag;

/*
 *	MODULE POINTER TABLES OBJECT Handling
 */

#define MDTAB_CMD_SET	0x8000
#define MDTAB_CMD_IF	0x4000
#define MDTAB_CMD_PW	0x2000
#define MDTAB_CMD_DIST	0x1000
#define MDTAB_CMD_MASK	0x0fff

#define MD_SET MDTAB_CMD_SET
#define MD_IF MDTAB_CMD_IF
#define MD_PW MDTAB_CMD_PW
#define MD_DIST MDTAB_CMD_DIST

typedef struct _mdtab_obj {
	WORD	slot;		/* parameter slot #  */
	ULONG	*p_mdtab;	/* pointer to reference module */
	WORD	param;		/* number of paramters + cmd flag */
	ULONG	*p_fxtab;	/* pointer to following effects module */
				/* or variable 			       */
	WORD	obj;		/* popup object index in GEM object tree */
	WORD	index;		/* index value for this module in popup */
} MDTAB_OBJ;

ULONG	fm_flag;

MDTAB_OBJ mdtabobj_table[] = {
 /* slot   p_mdtab        		object		index		*/	
 { 0, &_osc_sampler, 	6,	NULL,	ALG_OSCMAIN, 	POP_OSC_SAMPLER },
 { 0, &_osc_nisampler, 	3,	NULL,	ALG_OSCMAIN, 	POP_OSC_NISAMPLER },
 { 0, &_osc_fixedwave, 	3,	NULL,	ALG_OSCMAIN, 	POP_OSC_FIXEDWAVE },
 { 0, &_osc_fm, MD_SET | 6,  &fm_flag, 	ALG_OSCMAIN, 	POP_OSC_FM },
 { 0, &_osc_polywave, 	6, 	NULL, 	ALG_OSCMAIN, 	POP_OSC_POLYWAVE },
/* { 0, &_osc_noise, 	6, 	NULL,	ALG_OSCMAIN, 	POP_OSC_NOISE },*/
 { 3, &_osc_fixedwave_loop, 0,	NULL,	-1,		-1 },
 { 3, &_loopenv_skip,   3,	NULL,	-1,		-1 },
 { 3, &_lfo_1,		3,&_osc_fx_pan,	ALG_MIXERENV,	POP_ENV_LFO },
 { 3, &_lfo_1,	        3,&_osc_fx_pitch,ALG_OSC2ENV,	POP_ENV_LFO },
 { 3, &_lfo_1,	MD_PW | 3,&_osc_fx_pw,	ALG_DISTENV,	POP_ENV_LFO },
 { 3, &_lfo_1,	MD_DIST|3,&_osc_fx_dist,ALG_DISTENV,	POP_ENV_LFO },
 { 6, &_osc_sampler_loop,   0,	NULL,	-1,		-1 },
 { 6, &_loopenv_skip,   3,	NULL,	-1,		-1 },
 { 6, &_loopenv_slot1,	3,&_env_fx_pan, ALG_MIXERENV, 	POP_ENV_1 },
 { 6, &_loopenv_slot1,	3,&_env_fx_pitch, ALG_OSC1ENV, 	POP_ENV_1 },
 { 6, &_loopenv_slot1, MD_PW | 	3,&_env_fx_pw , ALG_DISTENV, 	POP_ENV_1 },
 { 6, &_loopenv_slot1, MD_DIST |3,&_env_fx_dist , ALG_DISTENV, 	POP_ENV_1 },
 { 6, &_loopenv_slot1,	3,	NULL, 	ALG_ATTNENV, 	POP_ENV_1 },
 { 6, &_lfo_1,		3,&_osc_fx_pan,	ALG_MIXERENV,	POP_ENV_LFO },
 { 6, &_lfo_1,		3,&_osc_fx_pitch,ALG_OSC2ENV,	POP_ENV_LFO },
 { 6, &_lfo_1,	MD_PW |	3,&_osc_fx_pw,	ALG_DISTENV,	POP_ENV_LFO },
 { 6, &_lfo_1,	MD_DIST|3,&_osc_fx_dist,ALG_DISTENV,	POP_ENV_LFO },
 { 9, &_loopenv_skip,   3,	NULL,	-1,		-1 },
 { 9, &_loopenv_slot2,	3,&_env_fx_pan, ALG_MIXERENV, 	POP_ENV_2 },
 { 9, &_loopenv_slot2,	3,&_env_fx_pitch , ALG_OSC2ENV, POP_ENV_2 },
 { 9, &_loopenv_slot2,	MD_PW | 3,&_env_fx_pw, ALG_DISTENV, 	POP_ENV_2 },
 { 9, &_loopenv_slot2,	MD_DIST|3,&_env_fx_dist, ALG_DISTENV, 	POP_ENV_2 },
 { 9, &_loopenv_slot2, MD_IF |	3, &fm_flag, 	ALG_OSC1ENV, 	POP_ENV_1 },
 { 9, &_loopenv_slot2,	3,	NULL, 	ALG_FILTERENV, 	POP_ENV_1 },
 { 9, &_lfo_1,		3,&_osc_fx_pan,	ALG_MIXERENV,	POP_ENV_LFO },
 { 9, &_lfo_1,		3,&_osc_fx_pitch,ALG_OSC2ENV,	POP_ENV_LFO },
 { 9, &_lfo_1,	MD_PW | 3,&_osc_fx_pw,	ALG_DISTENV,	POP_ENV_LFO },
 { 9, &_lfo_1,	MD_DIST|3,&_osc_fx_dist,ALG_DISTENV,	POP_ENV_LFO },
 { 12, &_loopenv_slot3,	3,&_env_fx_pan, ALG_MIXERENV, 	POP_ENV_2 },
 { 12, &_loopenv_slot3,	3,&_env_fx_pitch, ALG_OSC2ENV, 	POP_ENV_2 },
 { 12, &_loopenv_slot3,	MD_PW | 3,&_env_fx_pw , ALG_DISTENV, 	POP_ENV_2 },
 { 12, &_lfo_1,		3,&_osc_fx_pan,	ALG_MIXERENV,	POP_ENV_LFO },
 { 12, &_lfo_1,		3,&_osc_fx_pitch,ALG_OSC2ENV,	POP_ENV_LFO },
 { 12, &_lfo_1,	MD_PW | 3,&_osc_fx_pw,	ALG_DISTENV,	POP_ENV_LFO },
 { 12, &_lfo_1,	MD_DIST| 3,&_osc_fx_dist,ALG_DISTENV,	POP_ENV_LFO },
 { 15, &_dist,		0, 	NULL,	ALG_DIST,	POP_DIST }, 
 { 15, &_dft_filter,	3, 	NULL,	ALG_FILTER,	POP_FILTER_ON },
/* where does distortion go ??? */
 {-1, NULL,		0,	NULL,	0,		0 }
};


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

build_jazalg()
{
	objc_xadd(warn_tree, NIL, ROOT, 
		G_BOX, -1, -1, 
		6, 140, 370, 52,
		IS3DOBJ, NORMAL,
		0);
	objc_xadd(warn_tree, ROOT, 1, 
		G_XTEXT, -1, -1, 
		0, 0, 0, 8,
		IS3DOBJ|NONE, NORMAL,
		T_OB_LATTACH, ROOT, 2,		
		T_OB_RATTACH, ROOT, 2,		
		T_OB_UATTACH, ROOT, 0,
		T_BX_TEXT, "                                                ",
		T_BX_FONTID, FNT_MEDIUM,
		T_BX_ALIGN, TE_LEFT,
		T_BX_TXTCOLOR, LRED,
		0);
	objc_xadd(warn_tree, ROOT, 2, 
		G_XTEXT, -1, -1, 
		0, 0, 0, 8,
		IS3DOBJ|NONE, NORMAL,
		T_OB_LATTACH, ROOT, 2,		
		T_OB_RATTACH, ROOT, 2,		
		T_OB_UATTACH, 1, 0,
		T_BX_TEXT, "                                                ",
		T_BX_FONTID, FNT_MEDIUM,
		T_BX_ALIGN, TE_LEFT,
		0);
	objc_xadd(warn_tree, ROOT, 3, 
		G_XTEXT, -1, -1, 
		0, 0, 0, 8,
		IS3DOBJ|NONE, NORMAL,
		T_OB_LATTACH, ROOT, 2,		
		T_OB_RATTACH, ROOT, 2,		
		T_OB_UATTACH, 2, 0,
		T_BX_TEXT, "                                                ",
		T_BX_FONTID, FNT_MEDIUM,
		T_BX_ALIGN, TE_LEFT,
		0);
	objc_xadd(warn_tree, ROOT, 4, 
		G_XTEXT, -1, -1, 
		0, 0, 0, 8,
		IS3DOBJ|NONE, NORMAL,
		T_OB_LATTACH, ROOT, 2,		
		T_OB_RATTACH, ROOT, 2,		
		T_OB_UATTACH, 3, 0,
		T_BX_TEXT, "                                                ",
		T_BX_FONTID, FNT_MEDIUM,
		T_BX_ALIGN, TE_LEFT,
		0);


	objc_xadd(algtree, NIL, ROOT, 
		G_BOX, -1, -1, 
		0, 0, scrn_w, scrn_h+1,
		NONE, NORMAL,
		0);
	objc_xadd(algtree, ROOT, ALG_TITLE, 
		G_XBOXTEXT, -1, -1, 
		0, 0, 0, 9,
		IS3DOBJ|NONE, NORMAL,
		T_OB_LATTACH, ROOT, 2,		
		T_OB_RATTACH, ROOT, 2,		
		T_OB_UATTACH, ROOT, 0,
		T_BX_TEXT, STR_ALGTITLE,
		T_BX_FONTID, FNT_MEDIUM,
		T_BX_ALIGN, TE_CNTR,
		0);
 	objc_xadd(algtree, ROOT, ALG_OSC1ENV,
		G_XPOPUP, -1, -1,
		0, 0, 70, 24,
		JOYPAD|IS3DOBJ|SELECTABLE, NORMAL,
		T_OB_LATTACH, ROOT, 2,		
		T_OB_UATTACH, ALG_TITLE, 2,
		T_OB_RIGHT, ALG_OSCMAIN,
		T_OB_LEFT, ALG_OSC2ENV,
		T_OB_UP, ALG_BTTNBOX,
		T_OB_DOWN, ALG_OMNI,
		T_POP_SLNAME, STR_ALGMOD1,
		T_POP_DATA, STR_ALGENV2,
		T_POP_FONTID, FNT_MEDIUM,
		T_POP_TYPE, ACTION_BUTTON|LOCKPOP,
		T_POP_LOCK_STR, FMSTR_LOCKPOP,
		T_POP_ACTION,  handle_modifier,
		T_POP_CALLBK,	process_alg,
		0);	
	objc_xadd(algtree, ROOT, ALG_OSC1ENVARROW, 
		G_XARROW, -1, -1,
		0, 0, 32, 4,
		NONE, NORMAL,
		T_OB_LATTACH, ALG_OSC1ENV, 2,		
		T_OB_UATTACH, ALG_TITLE, 20,
		T_OB_SPEC, 0L,
		0);
#if 0
	objc_xadd(algtree, ROOT, ALG_OSC1PITCH, 
		G_XTEXT, -1, -1,
		0, 0, 30, 6,
		NONE, NORMAL,
		T_OB_LATTACH, ALG_OSC1ENV, 4,		
		T_OB_UATTACH, ALG_TITLE, 8,
		T_BT_TEXT, STR_ALGPITCH,
		T_BX_FONTID, FNT_SMALL,
		0);
#endif
	objc_xadd(algtree, ROOT, ALG_OSC1FM, 
		G_XTEXT, -1, -1,
		0, 0, 20, 6,
		NONE, NORMAL,
#if 0
		T_OB_LATTACH, ALG_OSC1ENV, 3,		
		T_OB_UATTACH, ALG_OSC1ENVARROW, 1,
#endif
		T_OB_LATTACH, ALG_OSC1ENV, 4,		
		T_OB_UATTACH, ALG_TITLE, 8,
		T_BT_TEXT, STR_ALGFM,
		T_BX_FONTID, FNT_SMALL,
		0);
	objc_xadd(algtree, ROOT, ALG_OSCBOX,
		G_BOX, -1, -1, 
		0, 0, 166, 40,
		FRAME, NORMAL,
		T_OB_LATTACH, ALG_OSC1ENVARROW, 0,		
		T_OB_UATTACH, ALG_TITLE, 4,
		0);
	objc_xadd(algtree, ALG_OSCBOX, ALG_OSCMAIN,
		G_XPOPUP, -1, -1,
		0, 0, 150, 24,
		JOYPAD|IS3DOBJ|SELECTABLE, NORMAL,
		T_OB_LATTACH, ALG_OSCBOX, 6,		
		T_OB_UATTACH, ALG_OSCBOX, 6,
		T_OB_LEFT, ALG_OSC1ENV,
		T_OB_RIGHT, ALG_OSC2ENV,
		T_OB_DOWN, ALG_DIST,
		T_OB_UP, ALG_MIXERBOX,
		T_POP_SLNAME, STR_ALGOSCMAIN,
		T_POP_DATA, STR_ALGOSCPOPUP,
		T_POP_FONTID, FNT_MEDIUM,
		T_POP_TYPE, ACTION_BUTTON|LOCKPOP,
		T_POP_LOCK_STR, FMSTR_LOCKPOP,
		T_POP_ACTION,  handle_osc,
		T_POP_CALLBK,  process_alg,
		0);	

	objc_xadd(algtree, ROOT, ALG_OSC2PITCH, 
		G_XTEXT, -1, -1,
		0, 0, 30, 6,
		NONE, NORMAL,
		T_OB_LATTACH, ALG_OSCBOX, 2,		
		T_OB_UATTACH, ALG_TITLE, 8,
		T_BT_TEXT, STR_ALGPITCH,
		T_BX_FONTID, FNT_SMALL,
		0);
	objc_xadd(algtree, ROOT, ALG_OSC2ENVARROW, 
		G_XARROW, -1, -1,
		0, 0, 32, 4,
		NONE, NORMAL,
		T_OB_LATTACH, ALG_OSCBOX, 0,		
		T_OB_UATTACH, ALG_TITLE, 20,
		T_OB_SPEC, 1L,
		0);
 	objc_xadd(algtree, ROOT, ALG_OSC2ENV,
		G_XPOPUP, -1, -1,
		0, 0, 70, 24,
		JOYPAD|IS3DOBJ|SELECTABLE, NORMAL,
		T_OB_RATTACH, ROOT, 2,		
		T_OB_UATTACH, ALG_TITLE, 2,
		T_OB_LEFT, ALG_OSCMAIN,
		T_OB_RIGHT, ALG_OSC1ENV,
		T_OB_DOWN, ALG_DISTENV,
		T_OB_UP, ALG_MIXERENV,
		T_POP_SLNAME, STR_ALGMOD2,
		T_POP_DATA, STR_ALGENV3LFO1,
		T_POP_FONTID, FNT_MEDIUM,
		T_POP_TYPE, ACTION_BUTTON|LOCKPOP,
		T_POP_LOCK_STR, FMSTR_LOCKPOP,
		T_POP_ACTION,  handle_modifier,
		T_POP_CALLBK,  process_alg,
		0);	
	objc_xadd(algtree, ROOT, ALG_DISTARROW1, 
		G_XARROW, -1, -1,
		0, 0, 14, 14,
		NONE, NORMAL,
		T_OB_LATTACH, ROOT, 187,		
		T_OB_UATTACH, ALG_OSCBOX, 0,
		T_OB_SPEC, 2L,
		0);
 	objc_xadd(algtree, ROOT, ALG_DIST,
		G_XPOPUP, -1, -1,
		0, 0, 100, 24,
		JOYPAD|IS3DOBJ|SELECTABLE, NORMAL,
		T_OB_LATTACH, ROOT, 142,		
		T_OB_UATTACH, ALG_DISTARROW1, 0,
		T_OB_RIGHT, ALG_DISTENV,
		T_OB_LEFT, ALG_BTTNBOX,
		T_OB_UP, ALG_OSCMAIN,
		T_OB_DOWN, ALG_FILTER,
		T_POP_SLNAME, STR_ALGDIST,
		T_POP_DATA, STR_ALGDISTPOPUP,
		T_POP_FONTID, FNT_MEDIUM,
		T_POP_TYPE, LOCKPOP,
		T_POP_LOCK_STR, FMSTR_LOCKPOP,
/*		T_POP_ACTION,  */
		T_POP_CALLBK,  process_alg,
		0);
 	objc_xadd(algtree, ROOT, ALG_DISTENV,
		G_XPOPUP, -1, -1,
		0, 0, 70, 24,
		JOYPAD|IS3DOBJ|SELECTABLE, NORMAL,
		T_OB_RATTACH, ROOT, 2,		
		T_OB_UATTACH, ALG_DISTARROW1, -2,	
		T_OB_LEFT, ALG_DIST,
		T_OB_RIGHT, ALG_DIST,
		T_OB_UP, ALG_OSC2ENV,
		T_OB_DOWN, ALG_FILTERENV,
		T_POP_SLNAME, STR_ALGMOD,
		T_POP_DATA, STR_ALGENV3LFO1,
		T_POP_FONTID, FNT_MEDIUM,
		T_POP_TYPE, ACTION_BUTTON|LOCKPOP,
		T_POP_LOCK_STR, FMSTR_LOCKPOP,
		T_POP_ACTION,  handle_modifier,
		T_POP_CALLBK,  process_alg,
		0);	
	objc_xadd(algtree, ROOT, ALG_DISTENVARROW, 
		G_XARROW, -1, -1,
		0, 0, 10, 10,
		NONE, NORMAL,
		T_OB_LATTACH, ALG_DIST, 2,
		T_OB_RATTACH, ALG_DISTENV, 2,
		T_OB_UATTACH, ALG_DISTARROW1, 15,	
		T_OB_SPEC, 1L,
		0);	


	objc_xadd(algtree, ROOT, ALG_FILTERARROW, 
		G_XARROW, -1, -1,
		0, 0, 14, 14,
		NONE, NORMAL,
		T_OB_LATTACH, ROOT, 187,		
		T_OB_UATTACH, ALG_DIST, 1,
		T_OB_SPEC, 2L,
		0);
 	objc_xadd(algtree, ROOT, ALG_FILTER,
		G_XPOPUP, -1, -1,
		0, 0, 100, 24,
		JOYPAD|IS3DOBJ|SELECTABLE, NORMAL,
		T_OB_LATTACH, ROOT, 142,		
		T_OB_UATTACH, ALG_FILTERARROW, 0,
		T_OB_UP, ALG_DIST,
		T_OB_RIGHT, ALG_FILTERENV,
		T_OB_LEFT, ALG_BTTNBOX,
		T_OB_DOWN, ALG_MIXERBOX,
		T_POP_SLNAME, STR_ALGFILTER,
		T_POP_DATA, STR_ALGFILTERPOPUP,
		T_POP_FONTID, FNT_MEDIUM,
		T_POP_TYPE, ACTION_BUTTON|LOCKPOP,
		T_POP_LOCK_STR, FMSTR_LOCKPOP,
/*		T_POP_ACTION,  */
		T_POP_CALLBK,  process_alg,
		0);
 	objc_xadd(algtree, ROOT, ALG_FILTERENV,
		G_XPOPUP, -1, -1,
		0, 0, 70, 24,
		JOYPAD|IS3DOBJ|SELECTABLE, NORMAL,
		T_OB_RATTACH, ROOT, 2,		
		T_OB_UATTACH, ALG_FILTERARROW, -2,	
		T_OB_UP, ALG_DISTENV,
		T_OB_LEFT, ALG_FILTER,
		T_OB_DOWN, ALG_ATTNENV,
		T_OB_RIGHT, ALG_BTTNBOX,
		T_POP_SLNAME, STR_ALGMOD,
		T_POP_DATA, STR_ALGENV2,
		T_POP_FONTID, FNT_MEDIUM,
		T_POP_TYPE, ACTION_BUTTON|LOCKPOP,
		T_POP_LOCK_STR, FMSTR_LOCKPOP,
		T_POP_ACTION,  handle_modifier, 
		T_POP_CALLBK,  process_alg,
		0);	
	objc_xadd(algtree, ROOT, ALG_FILTERENVARROW, 
		G_XARROW, -1, -1,
		0, 0, 10, 10,
		NONE, NORMAL,
		T_OB_LATTACH, ALG_FILTER, 2,
		T_OB_RATTACH, ALG_FILTERENV, 2,
		T_OB_UATTACH, ALG_FILTERARROW, 15,	
		T_OB_SPEC, 1L,
		0);	
	objc_xadd(algtree, ROOT, ALG_CORNER, 
		G_XTEXT, -1, -1,
		0, 0, 30, 6,
		NONE, NORMAL,
		T_OB_LATTACH, ALG_FILTER, 18,		
		T_OB_UATTACH, ALG_FILTERARROW, 7,
		T_BT_TEXT, STR_ALGCORNER,
		T_BX_FONTID, FNT_SMALL,
		0);
	objc_xadd(algtree, ROOT, ALG_FREQ, 
		G_XTEXT, -1, -1,
		0, 0, 30, 6,
		NONE, NORMAL,
		T_OB_LATTACH, ALG_FILTER, 18,		
		T_OB_UATTACH, ALG_FILTERENVARROW, -7,
		T_BT_TEXT, STR_ALGFREQ,
		T_BX_FONTID, FNT_SMALL,
		0);

	objc_xadd(algtree, ROOT, ALG_ATTNARROW, 
		G_XARROW, -1, -1,
		0, 0, 12, 12,
		NONE, NORMAL,
		T_OB_LATTACH, ROOT, 187,		
		T_OB_UATTACH, ALG_FILTER, 1,
		T_OB_SPEC, 2L,
		0);
 	objc_xadd(algtree, ROOT, ALG_ATTN,
		G_XBOXTEXT, -1, -1,
		0, 0, 100, 12,
		IS3DOBJ, NORMAL,
		T_OB_LATTACH, ROOT, 142,		
		T_OB_UATTACH, ALG_ATTNARROW, 0,
		T_BX_TEXT, STR_ALGATTN,
		T_BX_FONTID, FNT_MEDIUM,
		T_BX_ALIGN, TE_CNTR,
		0);
 	objc_xadd(algtree, ROOT, ALG_ATTNENV,
		G_XPOPUP, -1, -1,
		0, 0, 70, 24,
		JOYPAD|IS3DOBJ|SELECTABLE, NORMAL,
		T_OB_RATTACH, ROOT, 2,		
		T_OB_UATTACH, ALG_ATTNARROW, -12,	
		T_OB_UP, ALG_FILTERENV,
		T_OB_DOWN, ALG_MIXERENV,
		T_OB_RIGHT, ALG_BTTNBOX,
		T_OB_LEFT, ALG_BTTNBOX,
		T_POP_SLNAME, STR_ALGMOD,
		T_POP_DATA, STR_ALGENV1,
		T_POP_FONTID, FNT_MEDIUM,
		T_POP_TYPE, ACTION_BUTTON|LOCKPOP,
		T_POP_LOCK_STR, FMSTR_LOCKPOP,
		T_POP_ACTION,  handle_modifier,
		T_POP_CALLBK,  process_alg,
		0);
		algtree[ALG_ATTNENV].ob_spec.popup->index=1;
		
	objc_xadd(algtree, ROOT, ALG_ATTNENVARROW, 
		G_XARROW, -1, -1,
		0, 0, 10, 10,
		NONE, NORMAL,
		T_OB_LATTACH, ALG_ATTN, 1,
		T_OB_RATTACH, ALG_ATTNENV, 2,
		T_OB_UATTACH, ALG_ATTNARROW, 8,	
		T_OB_SPEC, 1L,
		0);	

	objc_xadd(algtree, ROOT, ALG_MIXERARROW, 
		G_XARROW, -1, -1,
		0, 0, 12, 12,
		NONE, NORMAL,
		T_OB_LATTACH, ROOT, 187,		
		T_OB_UATTACH, ALG_ATTN, 1,
		T_OB_SPEC, 2L,
		0);
#if 0
 	objc_xadd(algtree, ROOT, ALG_MIXER,
		G_XBOXTEXT, -1, -1,
		0, 0, 100, 12,
		IS3DOBJ, NORMAL,		
		T_OB_LATTACH, ROOT, 142,		
		T_OB_UATTACH, ALG_MIXERARROW, 0,
		T_BX_TEXT, STR_ALGMIXER,
		T_BX_FONTID, FNT_MEDIUM,
		T_BX_ALIGN, TE_CNTR,
		0);


 	objc_xadd(algtree, ROOT, ALG_MIXER,
		G_XPOPUP, -1, -1,
		0, 0, 100, 24,
		JOYPAD|IS3DOBJ|SELECTABLE, NORMAL,
		T_OB_LATTACH, ROOT, 142,		
		T_OB_UATTACH, ALG_ATTN, 2,
		T_OB_UP, ALG_FILTER,
		T_OB_RIGHT, ALG_MIXERENV,
		T_OB_LEFT, ALG_BTTNBOX,
		T_OB_DOWN, ALG_OSCMAIN,
		T_POP_SLNAME, "MIXER",
		T_POP_DATA, STR_ALGREVERB,
		T_POP_FONTID, FNT_MEDIUM,
		T_POP_TYPE, ACTION_BUTTON,
		T_POP_LOCK_STR, FMSTR_LOCKPOP,
		T_POP_ACTION,  adjust_volume,
		T_POP_CALLBK,  process_alg,
		0);	
#endif
	objc_xadd(algtree, ROOT, ALG_MIXERBOX,
		G_XBAR, -1, -1, 
		0, 0, 100, 24,
		IS3DOBJ|JOYPAD|SELECTABLE, NORMAL,
		T_OB_LATTACH, ROOT, 142,		
		T_OB_UATTACH, ALG_ATTN, 2,
		T_OB_UP, ALG_FILTER,
		T_OB_RIGHT, ALG_MIXERENV,
		T_OB_LEFT, ALG_BTTNBOX,
		T_OB_DOWN, ALG_OSCMAIN,
		T_BA_NUM, 1,
		T_BA_FIRST, 1,
		0);

	objc_xadd(algtree, ALG_MIXERBOX, ALG_MIXER, 
		G_XBUTTON, -1, -1, 
		0, 2, 0, 12,
		ABUTTON|IS3DOBJ|SELECTABLE, NORMAL,
		T_BT_TEXT, "Mixer",
		T_BT_BGCOLOR, 0,
		T_BT_TXTCOLOR, 1,
		T_BT_FONTID, 1,
		T_BT_SMCHAR, '1',
		T_OB_LATTACH, ALG_MIXERBOX, 6,
		T_OB_RATTACH, ALG_MIXERBOX, 6,
		T_OB_UATTACH, ALG_MIXERBOX, 6,
		T_BT_CALLBK, adjust_volume,
		0);
 	objc_xadd(algtree, ROOT, ALG_MIXERENV,
		G_XPOPUP, -1, -1,
		0, 0, 70, 24,
		JOYPAD|IS3DOBJ|SELECTABLE, NORMAL,
		T_OB_RATTACH, ROOT, 2,		
		T_OB_UATTACH, ALG_MIXERARROW, -10,	
		T_OB_UP, ALG_ATTNENV,
		T_OB_RIGHT, ALG_BTTNBOX,
		T_OB_LEFT, ALG_MIXERBOX,
		T_OB_DOWN, ALG_OSC2ENV,
		T_POP_SLNAME, "MOD.",
		T_POP_DATA, STR_ALGENV3LFO1,
		T_POP_FONTID, FNT_MEDIUM,
		T_POP_TYPE, ACTION_BUTTON|LOCKPOP,
		T_POP_LOCK_STR, FMSTR_LOCKPOP,
		T_POP_ACTION,  handle_modifier,
		T_POP_CALLBK,  process_alg,
		0);	
	objc_xadd(algtree, ROOT, ALG_MIXERENVARROW, 
		G_XARROW, -1, -1,
		0, 0, 10, 10,
		NONE, NORMAL,
		T_OB_LATTACH, ALG_MIXERBOX, 1,
		T_OB_RATTACH, ALG_MIXERENV, 2,
		T_OB_UATTACH, ALG_MIXERARROW, 8,	
		T_OB_SPEC, 1L,
		0);
 	objc_xadd(algtree, ROOT, ALG_PAN,
		G_XTEXT, -1, -1,
		0, 0, 25, 8,
		IS3DOBJ, NORMAL,
		T_OB_LATTACH, ALG_MIXERBOX, 14,		
		T_OB_UATTACH, ALG_MIXERARROW, -4,
		T_BX_TEXT, STR_ALGPAN,
		T_BX_FONTID, FNT_SMALL,
		T_BX_ALIGN, TE_CNTR,
		0);	



	objc_xadd(algtree, ROOT, ALG_BTTNBOX,
		G_XBAR, -1, -1, 
		0, 0, 80, 80,
		IS3DOBJ|JOYPAD|SELECTABLE, NORMAL,
		T_OB_LATTACH, ROOT, 4,		
		T_OB_DATTACH, ROOT, 2,
		T_OB_RIGHT, ALG_MIXERBOX,
		T_OB_LEFT, ALG_ATTNENV,
		T_OB_UP, ALG_EDIT,
		T_OB_DOWN, ALG_OSC1ENV,
		T_BA_NUM, 2,
		T_BA_FIRST, 1,
		0);

	objc_xadd(algtree, ALG_BTTNBOX, ALG_OK, 
		G_XBUTTON, -1, -1, 
		0, 2, 0, 12,
		ABUTTON|IS3DOBJ|SELECTABLE, NORMAL,
		T_BT_TEXT, STR_ALGOK,
		T_BT_BGCOLOR, 0,
		T_BT_TXTCOLOR, 1,
		T_BT_FONTID, 1,
		T_BT_SMCHAR, '1',
		T_OB_LATTACH, ALG_BTTNBOX, 6,
		T_OB_RATTACH, ALG_BTTNBOX, 6,
		T_OB_UATTACH, ALG_BTTNBOX, 6,
		T_BT_CALLBK, hndl_alg,
		0);
	objc_xadd(algtree, ALG_BTTNBOX, ALG_CANCEL, 
		G_XBUTTON, -1, -1, 
		0, 2, 0, 12,
		ABUTTON|IS3DOBJ|SELECTABLE, NORMAL,
		T_BT_TEXT, STR_ALGCANCEL,
		T_BT_BGCOLOR, 0,
		T_BT_TXTCOLOR, 1,
		T_BT_FONTID, 1,
		T_BT_SMCHAR, '2',
		T_OB_LATTACH, ALG_BTTNBOX, 6,
		T_OB_RATTACH, ALG_BTTNBOX, 6,
		T_OB_UATTACH, ALG_OK, 6,
		T_BT_CALLBK, hndl_alg,
		0);
	objc_xadd(algtree, ALG_BTTNBOX, ALG_CLEAR, 
		G_XBUTTON, -1, -1, 
		0, 2, 0, 12,
		ABUTTON|IS3DOBJ|SELECTABLE, DISABLED|NORMAL,
		T_BT_TEXT, STR_ALGCLEAR,
		T_BT_BGCOLOR, 0,
		T_BT_TXTCOLOR, 1,
		T_BT_FONTID, 1,
		T_BT_SMCHAR, '3',
		T_OB_LATTACH, ALG_BTTNBOX, 6,
		T_OB_RATTACH, ALG_BTTNBOX, 6,
		T_OB_DATTACH, ALG_BTTNBOX, 6,
		T_BT_CALLBK, hndl_alg_clr,
		0);

	objc_xadd(algtree, ROOT, ALG_EDIT, 
		G_XBUTTON, -1, -1, 
		4, 0, 80, 12, 
		IS3DOBJ|JOYPAD|CHECKBOX, NORMAL,
		T_OB_LATTACH, ROOT, 6,		
		T_OB_DATTACH, ALG_BTTNBOX, 8,
		T_OB_UP, ALG_OMNI,
		T_OB_DOWN, ALG_BTTNBOX,
		T_OB_RIGHT, ALG_FILTER,
		T_OB_LEFT, ALG_FILTERENV,
		T_BT_TEXT, STR_EDIT,
		T_BT_TXTCOLOR, LRED,
		T_BT_FONTID, 0,
		T_BT_CALLBK, alg_edit,
		0);
	objc_xadd(algtree, ROOT, ALG_OMNI, 
		G_XBUTTON, -1, -1, 
		4, 0, 80, 12, 
		IS3DOBJ|JOYPAD|CHECKBOX, SELECTED,
		T_OB_LATTACH, ROOT, 6,		
		T_OB_DATTACH, ALG_EDIT, 4,
		T_OB_UP, ALG_OSC1ENV,
		T_OB_DOWN, ALG_EDIT,
		T_OB_RIGHT, ALG_FILTER,
		T_OB_LEFT, ALG_FILTERENV,
		T_BT_TEXT, STR_OMNI,
		T_BT_TXTCOLOR, LRED,
		T_BT_FONTID, 0,
		T_BT_CALLBK, alg_omni,
		0);


	alg_in_edit = FALSE;
	alg_edit_mode = 0;
	alg_omni_mode = 0;

}


	LONG
alg_edit(tree, curr, found, n, k)
	OBJECT *tree;
	WORD	curr;
	WORD	found;
	WORD	n;
	ULONG	k;
{
	alg_in_edit = !alg_in_edit;
	
	disable_sound();		/* kill all voices / safety action */
	enable_sound();

	if (alg_in_edit) {
		if (alg_edit_mode == 0) {
		  REG WORD i, j, used;

		  disable_sound();

		  for (used = 0, i = 0; i < 4; i++) {
		    for (j = 0; j < 32; j++)
			if ((patchinfo_table[curr_pnr].mdtab->used[i] >> j) & 1)
				used++;
		  }
		  if (used > 1)
			show_warning(-1, -1, -1, -1, "WARNING:|This algorithm is used by more than one|patch. Selecting \'Change\' will effect|all patches using this algorithm.");

		  alg_edit_mode = form_alert(FRM_ALERT, FMSTR_MDTABNEW);
		  if (used > 1)
			objc_draw(algtree, 0, MAXDEPTH, 0, 0, scrn_w, scrn_h);

		  curr_mdtab2temp();
		  enable_sound();
		}
		/*
		 *	Enable all popups
		 */
		algtree[ALG_OSC1ENV].ob_spec.popup->type &= ~LOCKPOP;
		algtree[ALG_OSC2ENV].ob_spec.popup->type &= ~LOCKPOP;
		algtree[ALG_OSCMAIN].ob_spec.popup->type &= ~LOCKPOP;
		algtree[ALG_DIST].ob_spec.popup->type    &= ~LOCKPOP;
		algtree[ALG_DISTENV].ob_spec.popup->type &= ~LOCKPOP;
		algtree[ALG_FILTER].ob_spec.popup->type  &= ~LOCKPOP;
		algtree[ALG_FILTERENV].ob_spec.popup->type &= ~LOCKPOP;
		algtree[ALG_ATTNENV].ob_spec.popup->type  &= ~LOCKPOP;
		algtree[ALG_MIXERENV].ob_spec.popup->type &= ~LOCKPOP;
		/*algtree[ALG_MIXER].ob_spec.popup->type &= ~LOCKPOP;*/

		alg_osc_type = algtree[ALG_OSCMAIN].ob_spec.popup->index;
		alg_old_osc_type = alg_osc_type;				
	} else {
		algtree[ALG_OSC1ENV].ob_spec.popup->type |= LOCKPOP;
		algtree[ALG_OSC2ENV].ob_spec.popup->type |= LOCKPOP;
		algtree[ALG_OSCMAIN].ob_spec.popup->type |= LOCKPOP;
		algtree[ALG_DIST].ob_spec.popup->type    |= LOCKPOP;
		algtree[ALG_DISTENV].ob_spec.popup->type |= LOCKPOP;
		algtree[ALG_FILTER].ob_spec.popup->type  |= LOCKPOP;
		algtree[ALG_FILTERENV].ob_spec.popup->type |= LOCKPOP;
		algtree[ALG_ATTNENV].ob_spec.popup->type   |= LOCKPOP;
		algtree[ALG_MIXERENV].ob_spec.popup->type  |= LOCKPOP;
		/*algtree[ALG_MIXER].ob_spec.popup->type  |= LOCKPOP;*/

	}
	return 0L;
}


	LONG
alg_omni(tree, curr, found, n, k)
	OBJECT *tree;
	WORD	curr;
	WORD	found;
	WORD	n;
	ULONG	k;
{
	if (alg_was_not_active) {
		algtree[ALG_OMNI].ob_state |= SELECTED;
		objc_draw(algtree, ALG_OMNI, MAXDEPTH, 0, 0, scrn_w, scrn_h);
		form_alert(FRM_ALERT, FMSTR_OMNIONLYACTIVE);		
		return 0L;
	}
	alg_omni_mode = !alg_omni_mode;

	return 0L;

}
	
	LONG
hndl_alg(tree, curr, found, n, k)
	OBJECT *tree;
	WORD	curr;
	WORD	found;
	WORD	n;
	ULONG	k;
{
	REG LONG *p, *q;
	REG WORD i;

	if (alg_was_not_active) {
		mk_one_patch_inactive(curr_pnr);
		for (i = 0; i < alg_made_inactive_cnt; i++)
			mk_one_patch_active(alg_made_inactive[i]);
	}

	if (found == ALG_CANCEL)
		cancel_temp_mdtab();

	algtree[ALG_OSC1ENV].ob_spec.popup->type |= LOCKPOP;
	algtree[ALG_OSC2ENV].ob_spec.popup->type |= LOCKPOP;
	algtree[ALG_OSCMAIN].ob_spec.popup->type |= LOCKPOP;
	algtree[ALG_DIST].ob_spec.popup->type    |= LOCKPOP;
	algtree[ALG_DISTENV].ob_spec.popup->type |= LOCKPOP;
	algtree[ALG_FILTER].ob_spec.popup->type  |= LOCKPOP;
	algtree[ALG_FILTERENV].ob_spec.popup->type |= LOCKPOP;
	algtree[ALG_ATTNENV].ob_spec.popup->type   |= LOCKPOP;
	/* algtree[ALG_MIXERENV].ob_spec.popup->type  |= LOCKPOP;*/
	/*algtree[ALG_MIXER].ob_spec.popup->type  |= LOCKPOP;*/


	garbage_collection();
	if (alg_edit_mode == 1) /* change */
		update_other_patches();
	update_patchnameslist();


	alg_in_edit = 0;
	alg_edit_mode = 0;
	alg_omni_mode = 0;
	algtree[ALG_EDIT].ob_state &= ~SELECTED;

	return -1L;
}

	LONG
hndl_alg_clr(tree, curr, found, n, k)
	OBJECT *tree;
	WORD	curr;
	WORD	found;
	WORD	n;
	ULONG	k;
{
	if (alg_in_edit) {
		/*
		 * Reset popup values
		 */
		algtree[ALG_OSC1ENV].ob_spec.popup->index = 0;
		algtree[ALG_OSC2ENV].ob_spec.popup->index = 0;
		algtree[ALG_OSCMAIN].ob_spec.popup->index = 0;
		algtree[ALG_DIST].ob_spec.popup->index = 0;
		algtree[ALG_DISTENV].ob_spec.popup->index = 0;
		algtree[ALG_FILTER].ob_spec.popup->index = 0;
		algtree[ALG_FILTERENV].ob_spec.popup->index = 0;
		algtree[ALG_ATTNENV].ob_spec.popup->index = 0;
		algtree[ALG_MIXERENV].ob_spec.popup->index = 0;
		/*algtree[ALG_MIXER].ob_spec.popup->index = 0;*/
		objc_draw(algtree, 0, MAXDEPTH, 0, 0, scrn_w, scrn_h);
		process_alg(algtree, ALG_OSC1ENV, 
			algtree[ALG_OSC1ENV].ob_spec.popup);
	} else
		form_alert(FRM_ALERT, FMSTR_LOCKPOP);

	return 0L;
}

#define MDTAB_MAX_SLOTS	7

WORD	mod_popups[] = {
	ALG_OSC1ENV, ALG_OSC2ENV, ALG_DISTENV, ALG_FILTERENV, ALG_ATTNENV, 
	ALG_MIXERENV, -1
};

#define MOD_PITCH1	0
#define MOD_PITCH2	1
#define MOD_PW		2
#define MOD_DIST	2
#define MOD_FILTER	3
#define MOD_ATTN	4
#define MOD_PAN		5

	WORD
setup_alg_values(patch_no)
	WORD	patch_no;
{
	REG ULONG *pt = patchtab[patch_no];
	REG ULONG *p;
	REG MDTAB_OBJ *mdtabobj_p;
	REG WORD  i;
	WORD pw_flag, dist_flag, flag, found, x;
	ULONG *mdtab;

	/*
	 * see if patch is active, if not make hime temporaly acctive..
	 */
	if (patchinfo_table[patch_no].active == FALSE) {
		alg_was_not_active = TRUE;
		alg_made_inactive_cnt = 0;
		if (mk_one_patch_active(patch_no) == FAILURE) {
			for (i = 0, x = 0; i < NR_PATCHES; i++) {
				if (i == patch_no)
					continue;
				if (patchinfo_table[patch_no].active) {
					mk_one_patch_inactive(i);
					alg_made_inactive[x++] = i;

					if (mk_one_patch_active(patch_no) 
					== SUCCESS) {
						break;
					}
				}
			}
			alg_made_inactive_cnt = x;
		}
	} else
		alg_was_not_active = FALSE;

	mdtab = (ULONG *) pt[0];
	/*
	 * Reset popup values
	 */
	algtree[ALG_OSC1ENV].ob_spec.popup->index = 0;
	algtree[ALG_OSC2ENV].ob_spec.popup->index = 0;
	algtree[ALG_OSCMAIN].ob_spec.popup->index = 0;
	algtree[ALG_DIST].ob_spec.popup->index = 0;
	algtree[ALG_DISTENV].ob_spec.popup->index = 0;
	algtree[ALG_FILTER].ob_spec.popup->index = 0;
	algtree[ALG_FILTERENV].ob_spec.popup->index = 0;
	algtree[ALG_ATTNENV].ob_spec.popup->index = 0;
	algtree[ALG_MIXERENV].ob_spec.popup->index = 0;

	fm_flag = 0;

	if (mdtab == NULL) {
		form_alert(FRM_ALERT, "[New synth module!][ OK ]");
		return -1;	/* FOR NOW !!! */
	}
	mdtabobj_p = mdtabobj_table;

/*
 * -> are all popups being reset????
 * -> are flags like fm_flag being reset???
 */

	/*
	 * Analyse the MDTAB
	 * - - - - - - - - -
	 * p is our MDTAB pinter
	 * i is our Synth Patch parameter index counter
 	 *   most unit generators have 3 parameters, some have 6, others none
	 *
	 * mdtabobj_p points into our nice table which contains the popup
	 *	      settings for the various unit generatots (UG).
 	 *
	 * Here's how it works:
		We compare the current table's paremeter slot number with 'i',
		the parameter index count. As long as they are equal, we
		compare the UG in the table with 'p', the UG in the MDTAB.
		If they are not equal, we go to the next entry in the table.
		If the slot # is not equal to 'i' anymore, it means we haven't
		found anything matching and advance i by 3 to get to the next
		roup in the table. 

		If a UG is matching, we check if the table entry contains 
		special commands for flag setting and checking (IF & SET). 
		After those have been taken care of, we check if this table 
		entry requires an effect module. If it does, we compare the 
		next enrty in the MDTAB with the required effect
		in the table. If it matches we go on, if not, we go on to the
		next table entry.
		
		Now that we matched a table entry with 'p', we set the
		corrrosponding values in the popup menu which are specified
		in the table entry. We then take the number of parameters of
		the UG and add them to 'i'. We advance in the table until
		we find an entry with an equal or greater slot #. We set
		the 'found' flag to true, so that 'i' doesn't get advanced at
		the end of loop by three and break out of the loop.

	 */
	for (p = mdtab, i = 0; i < 21; ) {
		if (*p == _attn)
			break;	 /* we stop when we reached the attenuator */
		found = FALSE;
		while (mdtabobj_p->slot == i) {	/* while in same group */
			if (*(mdtabobj_p->p_mdtab) == *p) {
				/*	Found one!
				 */
				/*
				 * Do the special command handling
				 */
				flag = TRUE;	
				pw_flag = FALSE;		
				dist_flag = FALSE;		
				if (mdtabobj_p->param & MDTAB_CMD_PW) {
					pw_flag = TRUE;
				}
				if (mdtabobj_p->param & MDTAB_CMD_DIST) {
					dist_flag = TRUE;
				}
				if (mdtabobj_p->param & MDTAB_CMD_IF) {
					if (*mdtabobj_p->p_fxtab)
						flag = TRUE;
					else {
						flag = FALSE;
						goto x_next; /* ???? */
					}
				} else if (mdtabobj_p->param & MDTAB_CMD_SET)
					*mdtabobj_p->p_fxtab = TRUE;
				/*
				 * Do we require an effect UG?
				 */

				else if (mdtabobj_p->p_fxtab != NULL) {
					if (*(p + 1L) != *(mdtabobj_p->p_fxtab)) {
						goto x_next;
						 /* right one, go on */
					} else
						p++; 
						/* ok, prepare for next MDTAB */
				}
				/*
				 * Set the popup menu index
				 */
				if (pw_flag) {
					algtree[ALG_DIST].ob_spec.popup->index
					 = POP_PW;
				} 
				if (dist_flag) {
					algtree[ALG_DIST].ob_spec.popup->index
					 = POP_DIST;
				}
				if (flag && (mdtabobj_p->obj != -1)) {
					algtree[mdtabobj_p->obj].ob_spec.popup->index =
						mdtabobj_p->index;
					x =  i / 3;
					if (mdtabobj_p->index == POP_ENV_LFO)
						x |= 0x8000;

					algtree[mdtabobj_p->obj].ob_spec.popup->user_defined 
						= x;			
				}
				/*
				 * Advance to the next group
				 */
				x = mdtabobj_p->param & MDTAB_CMD_MASK; 
				if (x != 0) {
					i += x; /* add # of paramters */
					do {
						mdtabobj_p++;
					} while (mdtabobj_p->slot < i);
					p++;
					found = TRUE; /* we found something */
					break;
				} else {
					/*
					 * Special case of UG with 0 parameters,
					 * like osc_sampler_loop. They don't
					 * have parameters, so we still want
					 * to look in the same group. But p has
					 * to get advanced to look at the
					 * next MDTAB UG.
					 */
					p++; 	/* skip */
				}
			}
x_next:
			mdtabobj_p++;	/* next entry in table */
		}
		if (!found)
			i += 3;		

	}

	if (fm_flag)
		algtree[ALG_OSC1ENV].ob_state = NORMAL;
	else
		algtree[ALG_OSC1ENV].ob_state = DISABLED;

        org_env_flags[0] = 0;
        org_env_flags[1] = 0;
        org_env_flags[2] = 0;
        org_env_flags[3] = 0;

	env1_flag = env2_flag = env3_flag = FALSE;

        for (i = 0; mod_popups[i] != -1; i++) {
                if ((x = algtree[mod_popups[i]].ob_spec.popup->index > 0) &&
                (x < 4)){
                        org_env_flags[x] = TRUE;
			switch (x) {
			case 1:
				env1_flag = TRUE;
				break;
			case 2:
				env2_flag = TRUE;
				break;
			case 3:
				env3_flag = TRUE;
				break;
			}
		}
        }


	alg_omni_mode = 1;

	return 0;

}


/*
 *	don't change order, corrosponds to object index for modifiers
 */

#define N_POPUPS 		9
#define POPFLAG_OSC		0
#define POPFLAG_MOD1		1
#define POPFLAG_MOD2		2
#define POPFLAG_DISTENV		3
#define POPFLAG_FILTERENV	4
#define POPFLAG_ATTNENV		5
#define POPFLAG_MIXERENV	6
#define POPFLAG_DIST		7
#define POPFLAG_FILTER		8


WORD	alg_pop_flags[N_POPUPS];
WORD	env_lfo_flags[5];

#define LFO_FLAG	0x8000



LONG *rom_osc_fx_table[] = { 
	NULL, &_osc_fx_pitch, &_osc_fx_pw, NULL, NULL, &_osc_fx_pan,
	(LONG*) -1L
};

LONG *rom_env_fx_table[] = { 
	NULL, &_env_fx_pitch, &_env_fx_pw, NULL, NULL, &_env_fx_pan,
	(LONG*) -1L
};

LONG *osc_fx_table[10];
LONG *env_fx_table[10];


struct	envlfofx {
	WORD	n;
	WORD	x;
	WORD	mod_pop[6];
	WORD	done[6];
} envlfo_fx[5];

struct _dt {
	LONG	*addr;
	BYTE	*label;
} dbtable[] = {
	{ &_osc_sampler, "osc_sampler" }, 
	{ &_osc_sampler_loop, "osc_sampler_loop" },
	{ &_osc_nisampler, "osc_nisampler" }, 
	{ &_osc_fixedwave, "osc_fixedwave" }, 
	{ &_osc_fixedwave_loop, "osc_fixedwave_loop" }, 
	{ &_osc_fm, "osc_fm" }, 
	{ &_osc_polywave, "osc_polywave" },
	{ &_osc_fx_pan, "osc_fx_pan" },
	{ &_osc_fx_pw, "osc_fx_pw" },
	{ &_osc_fx_dist, "osc_fx_dist" },
	{ &_osc_fx_pitch, "osc_fx_pitch" },
	{ &_env_fx_pan, "env_fx_pan" },
	{ &_env_fx_pw, "env_fx_pw" },
	{ &_env_fx_dist, "env_fx_dist" },
	{ &_env_fx_pitch, "env_fx_pitch" },
	{ &_loopenv_slot1, "loopenv_slot1" },
	{ &_loopenv_slot2, "loopenv_slot2" },
	{ &_loopenv_slot3, "loopenv_slot3" },
	{ &_loopenv_skip, "loopenv_skip" },
	{ &_lfo_1, "lfo_1" },
	{ &_dist, "dist" },
	{ &_dft_filter, "dft_filter" },
	{ &_attn, "attn" },
	{ NULL, NULL }
};

WORD offset2obj[PATCH_SIZE]; /* only used for lfos right. So that we find */
			     /* the lfo object we have to turn of when    */
			     /* someone changes the ocillator from fixed  */
			     /* wave to something else...		  */

/*
 *	prcoess_alg()
 *	Build a module tab from an algorithm page.
 */

	LONG
process_alg(tree, obj, info)
	OBJECT    *tree;
	WORD	  obj;
	POPUPINFO *info; 
{ /* begin process_alg() */
	REG WORD i, k;
	REG LONG *p, *q;
	WORD 	 ix;
	WORD 	 osc;
	WORD 	 n;
	WORD	 x;
	WORD 	 dist_flag = FALSE;

	disable_sound();

	for (i = 0; i < 4; i++)
		envnew[i] = FALSE;

	/* -------------------------------------------------------------------
	 * Do some checking of combinations!
	 */
	osc = algtree[ALG_OSCMAIN].ob_spec.popup->index; /* get oscillator */

	x = algtree[ALG_OSC1ENV].ob_state;
	if (osc == POP_OSC_FM)
		algtree[ALG_OSC1ENV].ob_state = NORMAL;
	else
		algtree[ALG_OSC1ENV].ob_state = DISABLED;

	if (x != algtree[ALG_OSC1ENV].ob_state) {
		objc_draw(algtree, ALG_OSC1ENV, MAXDEPTH, 0, 0, scrn_w, scrn_h);
	}

	/*
	 * depending on fm or dist/pw we have to use a differnt fx table
	 */
	for (i = 0; rom_env_fx_table[i] != (LONG*) -1L; i++) {
		env_fx_table[i] = rom_env_fx_table[i];
		osc_fx_table[i] = rom_osc_fx_table[i];
	}
	if (osc == POP_OSC_FM) {
		env_fx_table[0] = NULL;
		osc_fx_table[0] = NULL;
	}
	
	if (tree[ALG_DIST].ob_spec.popup->index == POP_DIST) {
		env_fx_table[2] = &_env_fx_dist;
		osc_fx_table[2] = &_osc_fx_dist;
	}

	switch (obj) {
	case ALG_DIST:
		/*
		 * Pulse Width needs an envelope/lfo!
		 */
		if ((tree[ALG_DIST].ob_spec.popup->index == POP_PW) && 
		(tree[ALG_DISTENV].ob_spec.popup->index == POP_ENV_NONE)) {
			WORD x;

			x = form_alert(FRM_ALERT, FMSTR_PWNEEDSENV);

			switch (x) {
			case 1:
			    tree[ALG_DISTENV].ob_spec.popup->index = POP_ENV_2;
			    break;
			case 2:
			    tree[ALG_DISTENV].ob_spec.popup->index = POP_ENV_3;
			    break;
			case 3:
			    tree[ALG_DISTENV].ob_spec.popup->index = POP_ENV_LFO;
			    break;
			}
		 	if (check_envs(ALG_DISTENV, osc) == FAILURE) {
				enable_sound();
				return 0L;
			}
			objc_draw(algtree, ALG_DISTENV, MAXDEPTH, 
				0, 0, scrn_w, scrn_h);
		}

		if ((tree[ALG_DIST].ob_spec.popup->index == 0) && 
		(tree[ALG_DISTENV].ob_spec.popup->index != POP_ENV_NONE)) {
			tree[ALG_DISTENV].ob_spec.popup->index = POP_ENV_NONE;
			objc_draw(algtree, ALG_DISTENV, MAXDEPTH, 
				0, 0, scrn_w, scrn_h);
		}
		if ((tree[ALG_DIST].ob_spec.popup->index == POP_DIST) &&
		(tree[ALG_DISTENV].ob_spec.popup->index == POP_ENV_NONE))
			dist_flag = TRUE;
		break;
	case ALG_FILTER:
		/*
		 * If filter and no modifier, than ask user...
		 */
		if ((osc == POP_OSC_FM) &&
		(tree[ALG_FILTER].ob_spec.popup->index > 0)) {
			form_alert(FRM_ALERT, FMSTR_FMNOFILTER);
			tree[ALG_FILTER].ob_spec.popup->index = 0;
			objc_draw(algtree, ALG_FILTER, MAXDEPTH, 
					0, 0, scrn_w, scrn_h);
		} else
		if ((tree[ALG_FILTER].ob_spec.popup->index == POP_FILTER_ON) && 
		(tree[ALG_FILTERENV].ob_spec.popup->index == POP_ENV_NONE)) {
			show_warning(-1,-1,-1,-1, "NOTE:|Filter will only be driven by a|constant if you\'re not using|envelope #2 at all.");
			n = form_alert(FRM_ALERT, FMSTR_FILTERNOENV);
			objc_draw(algtree, ROOT, MAXDEPTH, 0, 0, scrn_w, scrn_h);
			if (n == 2) {
				tree[ALG_FILTERENV].ob_spec.popup->index = 1;
		 		if (check_envs(ALG_FILTERENV, osc) == FAILURE) {
					enable_sound();
					return 0L;
				}
				objc_draw(algtree, ALG_FILTERENV, MAXDEPTH, 
					0, 0, scrn_w, scrn_h);
			} else {
				tree[ALG_FILTERENV].ob_spec.popup->index = 0;
				objc_draw(algtree, ALG_FILTERENV, MAXDEPTH, 
					0, 0, scrn_w, scrn_h);

			}
		} else
		if ((tree[ALG_FILTER].ob_spec.popup->index == 0) && 
		(tree[ALG_FILTERENV].ob_spec.popup->index != POP_ENV_NONE)) {
			tree[ALG_FILTERENV].ob_spec.popup->index = POP_ENV_NONE;
			objc_draw(algtree, ALG_FILTERENV, MAXDEPTH, 
				0, 0, scrn_w, scrn_h);
		}
		break;
#if 1
	case ALG_OSC1ENV:
 		if (check_envs(obj, osc) == FAILURE) {
			enable_sound();
			return 0L;
		}
		/*
		 * FM always has to use envelope #2
		 */
		if ((osc == POP_OSC_FM) && 
		(tree[ALG_OSC1ENV].ob_spec.popup->index > 0) &&
		(tree[ALG_OSC1ENV].ob_spec.popup->index != POP_ENV_1)) {
			tree[ALG_OSC1ENV].ob_spec.popup->index = POP_ENV_1;
			objc_draw(algtree, ALG_OSC1ENV, MAXDEPTH, 
					0, 0, scrn_w, scrn_h);
			form_alert(FRM_ALERT, FMSTR_FMUSEENV2);
		}
		break;
#endif
	case ALG_OSC2ENV:
 		if (check_envs(obj, osc) == FAILURE) {
			enable_sound();
			return 0L;
		}
		if ((osc == POP_OSC_FM) && 
		(tree[ALG_OSC2ENV].ob_spec.popup->index == POP_ENV_2)) {
			tree[ALG_OSC1ENV].ob_spec.popup->index = POP_ENV_1;
			objc_draw(algtree, ALG_OSC1ENV, MAXDEPTH,  /* is env2 */
					0, 0, scrn_w, scrn_h);
		}
		if ((tree[ALG_FILTER].ob_spec.popup->index > 0) &&
		(tree[ALG_OSC2ENV].ob_spec.popup->index == POP_ENV_2)) {
			tree[ALG_FILTERENV].ob_spec.popup->index = POP_ENV_1;
			objc_draw(algtree, ALG_FILTERENV, MAXDEPTH,  /* is env2 */
					0, 0, scrn_w, scrn_h);
		}
		break;
	case ALG_DISTENV:
		if (check_envs(obj, osc) == FAILURE) {
			enable_sound();
			return 0L;
		}
		if ((osc == POP_OSC_FM) && 
		(tree[ALG_DISTENV].ob_spec.popup->index == POP_ENV_2)) {
			tree[ALG_OSC1ENV].ob_spec.popup->index = POP_ENV_1;
			objc_draw(algtree, ALG_OSC1ENV, MAXDEPTH,  /* is env2 */
					0, 0, scrn_w, scrn_h);
		}
		/*
		 * Dist always has to use envelope #3/lfo
		 */
#if 0 /* not anymore */
		if ((tree[ALG_DIST].ob_spec.popup->index == POP_DIST) && 
		(tree[ALG_DISTENV].ob_spec.popup->index > 0) &&
		((tree[ALG_DISTENV].ob_spec.popup->index != POP_ENV_3) &&
		(tree[ALG_DISTENV].ob_spec.popup->index != POP_ENV_LFO))) {
			tree[ALG_DISTENV].ob_spec.popup->index = POP_ENV_3;
			objc_draw(algtree, ALG_DISTENV, MAXDEPTH, 
					0, 0, scrn_w, scrn_h);
			form_alert(FRM_ALERT, FMSTR_DISTUSEENV3);
			break;
		}
#endif
		if ((tree[ALG_DIST].ob_spec.popup->index == 0) && 
		(tree[ALG_DISTENV].ob_spec.popup->index > 0) &&
		(tree[ALG_DISTENV].ob_spec.popup->index != 3)) {
			tree[ALG_DIST].ob_spec.popup->index = POP_PW;
			objc_draw(algtree, ALG_DIST, MAXDEPTH, 
					0, 0, scrn_w, scrn_h);
			break;
		} 
		if ((tree[ALG_DIST].ob_spec.popup->index == 0) && 
		(tree[ALG_DISTENV].ob_spec.popup->index > 0) &&
		(tree[ALG_DISTENV].ob_spec.popup->index == 3)) {
			tree[ALG_DIST].ob_spec.popup->index = POP_DIST;
			objc_draw(algtree, ALG_DIST, MAXDEPTH, 
					0, 0, scrn_w, scrn_h);
			break;
		}
		if ((tree[ALG_FILTER].ob_spec.popup->index > 0) &&
		(tree[ALG_DISTENV].ob_spec.popup->index == POP_ENV_2)) {
			tree[ALG_FILTERENV].ob_spec.popup->index = POP_ENV_1;
			objc_draw(algtree, ALG_FILTERENV, MAXDEPTH,  /* is env2 */
					0, 0, scrn_w, scrn_h);
		} 
		break;
	case ALG_FILTERENV:
 		if (check_envs(obj, osc) == FAILURE) {
			enable_sound();
			return 0L;
		}
		if ((osc == POP_OSC_FM) &&
		(tree[ALG_FILTERENV].ob_spec.popup->index > 0)) {
			form_alert(FRM_ALERT, FMSTR_FMNOFILTER);
			tree[ALG_FILTERENV].ob_spec.popup->index = 0;
			objc_draw(algtree, ALG_FILTERENV, MAXDEPTH, 
					0, 0, scrn_w, scrn_h);
		} else 
		if ((tree[ALG_FILTER].ob_spec.popup->index == 0) && 
		(tree[ALG_FILTERENV].ob_spec.popup->index > 0)) {
			tree[ALG_FILTER].ob_spec.popup->index = POP_FILTER_ON;
			objc_draw(algtree, ALG_FILTER, MAXDEPTH, 
					0, 0, scrn_w, scrn_h);
		}
		break;
	case ALG_ATTNENV:
 		if (check_envs(obj, osc) == FAILURE) {
			enable_sound();
			return 0L;
		}
		break;
	case ALG_MIXERENV:
 		if (check_envs(obj, osc) == FAILURE) {
			enable_sound();
			return 0L;
		}
		if ((osc == POP_OSC_FM) && 
		(tree[ALG_MIXERENV].ob_spec.popup->index == POP_ENV_2)) {
			tree[ALG_OSC1ENV].ob_spec.popup->index = POP_ENV_1;
			objc_draw(algtree, ALG_OSC1ENV, MAXDEPTH,  /* is env2 */
					0, 0, scrn_w, scrn_h);
		}
		if ((tree[ALG_FILTER].ob_spec.popup->index > 0) &&
		(tree[ALG_MIXERENV].ob_spec.popup->index == POP_ENV_2)) {
			tree[ALG_FILTERENV].ob_spec.popup->index = POP_ENV_1;
			objc_draw(algtree, ALG_FILTERENV, MAXDEPTH,  /* is env2 */
					0, 0, scrn_w, scrn_h);
		}
		break;
	}

	/* -------------------------------------------------------------------
	 * Init 
	 */
	ix = 0;
	for (i = 0; i < 5; i++) {
		envlfo_fx[i].n = 0;
		envlfo_fx[i].x = 0;
	}
	for (i = 0; i < N_POPUPS; i++) {
		alg_pop_flags[i] = 0;
	}
	/* -------------------------------------------------------------------
	 * Get the oscillator first
	 */

	switch (osc) {
	case POP_OSC_SAMPLER:
		alg_mdtab[ix++] = _osc_sampler;
		alg_mdtab[ix++] = _osc_sampler_loop;
		break;
	case POP_OSC_NISAMPLER:
		alg_mdtab[ix++] = _osc_nisampler;
		break;
	case POP_OSC_CSAMPLER:
		alg_mdtab[ix++] = _osc_sampler;
		alg_mdtab[ix++] = _osc_sampler_loop;
		break;
	case POP_OSC_CNISAMPLER:
		alg_mdtab[ix++] = _osc_nisampler;
		break;
	case POP_OSC_FIXEDWAVE:
		alg_mdtab[ix++] = _osc_fixedwave;
		alg_mdtab[ix++] = _osc_fixedwave_loop;
		break;
	case POP_OSC_FM:
		alg_mdtab[ix++] = _osc_fm;
		break;
	case POP_OSC_POLYWAVE:
		alg_mdtab[ix++] = _osc_polywave;
		break;
	}
	if ((obj == ALG_OSCMAIN) && (osc != alg_osc_type)) {
#if 0 
		algtree[ALG_OSC1ENV].ob_spec.popup->index = 0;
		algtree[ALG_OSC2ENV].ob_spec.popup->index = 0;
		algtree[ALG_OSCMAIN].ob_spec.popup->index = 0;
		algtree[ALG_DIST].ob_spec.popup->index = 0;
		algtree[ALG_DISTENV].ob_spec.popup->index = 0;
		algtree[ALG_FILTER].ob_spec.popup->index = 0;
		algtree[ALG_FILTERENV].ob_spec.popup->index = 0;
		algtree[ALG_ATTNENV].ob_spec.popup->index = 0;
		algtree[ALG_MIXERENV].ob_spec.popup->index = 0;
		algtree[ALG_MIXER].ob_spec.popup->index = 0;

		objc_draw(algtree,ROOT, MAXDEPTH, 0, 0, scrn_w, scrn_h);
#endif
		/*
		 * always turn on ATTN ENV so we don't get note off problems..
		 */
		if (algtree[ALG_ATTNENV].ob_spec.popup->index == 0) {
			WORD d, r;
			d = curr_pnr / 32;
			r = curr_pnr % 32;

			algtree[ALG_ATTNENV].ob_spec.popup->index = 1;
			objc_draw(algtree, ALG_ATTNENV, MAXDEPTH, 
				0, 0, scrn_w, scrn_h);

			env_table[0].used[d] |= (LONG)(1L << r);
			env_table[0].free = FALSE;
			patchtab[curr_pnr][8]  = (LONG) env_table[0].dsp_addr;
			patchtab[curr_pnr][9]  = env_table[0].start_value;
			patchtab[curr_pnr][10] = env_table[0].release_slope;

			
		}


		/*
		 * Was it fixed wave? If yes, check if we used an lfo &
		 * turn it off.
		 */
		if (alg_osc_type == POP_OSC_FIXEDWAVE) {

			if (patchinfo_table[curr_pnr].env[1] != NULL) {
				algtree[offset2obj[5]].ob_spec.popup->index = 0;
				objc_draw(algtree,offset2obj[5], 
					MAXDEPTH, 0, 0, scrn_w, scrn_h);
			}
		}
		if (alg_osc_type == POP_OSC_FM) { /* was it FM? */
			algtree[ALG_OSC1ENV].ob_state |= DISABLED;
			algtree[ALG_OSC1ENV].ob_spec.popup->index = POP_ENV_NONE;
			objc_draw(algtree, ALG_OSC1ENV, MAXDEPTH, 
					0, 0, scrn_w, scrn_h);

		}
		switch (osc) {
		case POP_OSC_SAMPLER:
		case POP_OSC_NISAMPLER:
			patchtab[curr_pnr][1] = 0xE80FFFE4;
			patchtab[curr_pnr][2] = (ULONG)sample_table[8].addr;
 			replace_sample(curr_pnr, 2, 8);
			replace_sample(curr_pnr, 5, -1);

			goto sampler_go;
		case POP_OSC_CSAMPLER:
		case POP_OSC_CNISAMPLER:		/* compressed flag */
			patchtab[curr_pnr][1] = 0xE80FFFE4 | 0x200000L;
			patchtab[curr_pnr][2] = (ULONG)sample_table[9].addr;
 			replace_sample(curr_pnr, 2, 9);
			replace_sample(curr_pnr, 5, -1);

		sampler_go:
			/*if (alg_osc_type < 4)
				break;
			*/
						/* don't change if we had */
						/* already a sampler */
				

							; /* default sample */
			patchtab[curr_pnr][3] = 0x1000L;
			patchtab[curr_pnr][4] = 0x0L;
			{
				LONG size;
				switch (sample_table[8].type) {
				case SMPTYPE_RAW:
					size = (sample_table[8].size /2L)<< 12L;
					break;
				case SMPTYPE_COMPRESSED:
					size = sample_table[9].size << 12L;
					break;
				}
				patchtab[curr_pnr][5] = size - 1L;
				patchtab[curr_pnr][6] = size - 1L;
				patchtab[curr_pnr][7] = size - 1L;
			}


			if (smpslot_cnt >= 8)
				break;
			else
				form_alert(FRM_ALERT, FMSTR_NOSAMP);
			break;
		case POP_OSC_FIXEDWAVE:
			patchtab[curr_pnr][1] = 0xFFEFFFE5L;
			patchtab[curr_pnr][2] = 0xf1d200L; /* ROM SINE */
			patchtab[curr_pnr][3] = 0x1000L;
			patchtab[curr_pnr][4] = 0x0L;
			patchtab[curr_pnr][5] = 0x0L;
			patchtab[curr_pnr][6] = 0x0L;
			patchtab[curr_pnr][7] = 0x0L;
			replace_sample(curr_pnr, 2, 1);
			replace_sample(curr_pnr, 5, -1);
			break;
		case POP_OSC_FM:
			patchtab[curr_pnr][1] = 0xffefffe5L;
			patchtab[curr_pnr][2] = 0xf1d200L; /* ROM SINE */
			patchtab[curr_pnr][3] = 0x1000L;
			patchtab[curr_pnr][4] = 0x0L;
			patchtab[curr_pnr][5] = 0xf1d200L; /* ROM SINE */
			patchtab[curr_pnr][6] = 0x1000L;
			patchtab[curr_pnr][7] = 0x0L;
			replace_sample(curr_pnr, 2, 1);
			replace_sample(curr_pnr, 5, 1);
			algtree[ALG_OSC1ENV].ob_state = NORMAL;
			objc_draw(algtree, ALG_OSC1ENV, MAXDEPTH, 
					0, 0, scrn_w, scrn_h);
			algtree[ALG_FILTER].ob_spec.popup->index = 0;
			objc_draw(algtree, ALG_FILTER, MAXDEPTH, 
					0, 0, scrn_w, scrn_h);
			algtree[ALG_FILTERENV].ob_spec.popup->index = 0;
			objc_draw(algtree, ALG_FILTERENV, MAXDEPTH, 
					0, 0, scrn_w, scrn_h);
			break;
		case POP_OSC_POLYWAVE:
			patchtab[curr_pnr][1] = 0xFFFFFFF3L;
			patchtab[curr_pnr][2] = 0x00820082;
			patchtab[curr_pnr][3] = 0x1000L;
			patchtab[curr_pnr][4] = 0x0L;
			patchtab[curr_pnr][5] = 0x13L;
			patchtab[curr_pnr][6] = 0x1000L;
			patchtab[curr_pnr][7] = 0x0L;
			replace_sample(curr_pnr, 5, -1);
			replace_sample(curr_pnr, 2, -1);
			break;
		}
#if 0
		patchtab[curr_pnr][8] = 0x0L;
		patchtab[curr_pnr][9] = 0x0L;
		patchtab[curr_pnr][10] = 0x0L;

		patchtab[curr_pnr][11] = 0x0L;
		patchtab[curr_pnr][12] = 0x0L;
		patchtab[curr_pnr][13] = 0x0L;

		patchtab[curr_pnr][14] = 0x0L;
		patchtab[curr_pnr][15] = 0x0L;
		patchtab[curr_pnr][17] = 0x0L;
#endif
		alg_osc_type = osc;
	}

	alg_pop_flags[POPFLAG_OSC] = TRUE;

	/* -------------------------------------------------------------------
	 * look for envelopes/lfos in popups
	 */
	for (k = 1; k < 5; k++) { /* for all envelope indexes: 1, 2, 3, lfo */
		for (i = 0; mod_popups[i] != -1; i++) { /* for modifier popups */
			if (get_env_index(mod_popups[i]) == k) {
				/*
				 * the modifier popup is set to an env/lfo
				 */
				alg_pop_flags[i+1] = k; 

				/*
				 * one more env/lfo, store modifier number
				 */
				n = envlfo_fx[k].n;	
				envlfo_fx[k].mod_pop[n] = i;
				envlfo_fx[k].done[n] = FALSE;
				envlfo_fx[k].n = ++n;
			}
		}
	}
	if ((tree[ALG_DIST].ob_spec.popup->index == POP_DIST) &&
	(tree[ALG_DISTENV].ob_spec.popup->index == POP_ENV_NONE))
			dist_flag = TRUE;

	if (algtree[ALG_FILTERENV].ob_spec.popup->index == 1) { 
			/* filter env pop -> special case */
		alg_pop_flags[POPFLAG_FILTERENV] = 2;
		n = envlfo_fx[2].n;
		envlfo_fx[2].mod_pop[n] = 4; /* filter location in mod_pop */
		envlfo_fx[2].done[n] = FALSE;
		envlfo_fx[2].n = ++n;		
	}
	if (algtree[ALG_OSC1ENV].ob_spec.popup->index == 1) { 
			/* osc1 (FM) env pop -> special case */
		alg_pop_flags[POPFLAG_MOD1] = 2;
		n = envlfo_fx[2].n;
		envlfo_fx[2].mod_pop[n] = 0; /* filter location in mod_pop */
		envlfo_fx[2].done[n] = FALSE;
		envlfo_fx[2].n = ++n;		
	}

	if (algtree[ALG_FILTER].ob_spec.popup->index == 1) 
		alg_pop_flags[POPFLAG_FILTER] = 1;
	if (algtree[ALG_DIST].ob_spec.popup->index == 1) 
		alg_pop_flags[POPFLAG_DIST] = 1;

	/*
	 * look for lfo, if fixed wave
	 */
	if ((osc == POP_OSC_FIXEDWAVE) && (envlfo_fx[POP_ENV_LFO].n > 0)) {
		WORD old_ix;

		old_ix = ix;
		ix = proc_lfo(ix, 0);
		if (old_ix == ix) {
			alg_mdtab[ix++] = _loopenv_skip; 
			alg_free_lfo(0);
		}			
	} else if (osc == POP_OSC_FIXEDWAVE) {
		/*
		 * if we use fixed wave, but no lfo, we have to do a skip
		 * to get to the nextr block!
		 */
		alg_mdtab[ix++] = _loopenv_skip; 

		patchtab[curr_pnr][5] = 0x0L;
		patchtab[curr_pnr][6] = 0x0L;
		patchtab[curr_pnr][7] = 0x0L;
		alg_free_lfo(0);
	} else 
		/*alg_free_lfo(0); - leave it alone FM for example has two ROMSs*/

	/*
	 * do we have to do a skip for envelope #1?
	 */
	env1_flag = FALSE;
	if (envlfo_fx[POP_ENV_1].n == 0) {
		WORD flag = FALSE;
		/*
		 *	let's see if anything else is out there
		 */
		for (i = 1; i < N_POPUPS; i++) {
			if (alg_pop_flags[i] > 0) {
				flag = TRUE;
				break;
			}
		}

#if 0
		patchtab[curr_pnr][9] = 0x3ff80000L; /* for some volume */
#endif
		if (flag) {
			alg_mdtab[ix++] = _loopenv_skip;
			alg_free_env(1);
		} else {
			/*
			 * since nothing else is there, we go to the attn
			 * right away
			 */
			for (i = 1; i <= 3; i++) {
				alg_free_lfo(i);
				alg_free_env(i);
			}
			goto at_attn;
		}
	} else {
		WORD slot;

		alg_mdtab[ix++] = _loopenv_slot1;
		/*
		 * make sure envelope is there..
		 */
		slot = 1;

		env1_flag = TRUE;
		if (patchinfo_table[curr_pnr].env[2] == NULL) { /* not found */
			WORD ix;
			WORD d, r;

			ix = 0; /* use the default envelope */
			d = curr_pnr / 32;
			r = curr_pnr % 32;
			env_table[ix].used[d] |= (LONG)(1L << r);
			env_table[ix].free = FALSE;
			d = 5 + slot * 3;

			patchinfo_table[curr_pnr].env[slot+1] = 
				&env_table[ix];		
			patchtab[curr_pnr][d] = 
				(LONG) env_table[ix].dsp_addr;
			patchtab[curr_pnr][d + 1] = 
				env_table[ix].start_value;
			patchtab[curr_pnr][d + 2] = 
				env_table[ix].release_slope;

		} else {
			ENVTAB *env;

			if ((env = pi_find_envtab(curr_pnr, 1)) != NULL) {
				patchtab[curr_pnr][8] = (LONG) env->dsp_addr;
				if (envnew[1]) {
					patchtab[curr_pnr][9] = env->start_value;
					patchtab[curr_pnr][10] = env->release_slope;
				}
			}

		}
		if ((n = envlfo_fx[POP_ENV_1].n) > 1) {
			for (i = 0; i < n; i++) {
			  if (env_fx_table[envlfo_fx[POP_ENV_1].mod_pop[i]]
			   != NULL) {
				alg_mdtab[ix++] = 
				*(env_fx_table[envlfo_fx[POP_ENV_1].mod_pop[i]]);

				switch (obj) {
				case ALG_OSC1ENV:
				case ALG_OSC2ENV:
				case ALG_DISTENV:
				case ALG_FILTERENV:
				case ALG_ATTNENV:
				case ALG_MIXERENV:
				  algtree[obj].ob_spec.popup->user_defined = 
					algtree[obj].ob_spec.popup->index + 1;
					break;
				}

			  }
			}

		}
	}

	/*
	 * is there an envelope 2?
	 */
	env2_flag = FALSE;
	if (envlfo_fx[POP_ENV_2].n > 0) {
		ENVTAB *env;

		alg_mdtab[ix++] = _loopenv_slot2;
		if ((n = envlfo_fx[POP_ENV_2].n) >= 1) {
			for (i = 0; i < n; i++) {
			  if (env_fx_table[envlfo_fx[POP_ENV_2].mod_pop[i]]
			   != NULL) {
				alg_mdtab[ix++] = 
				*(env_fx_table[envlfo_fx[POP_ENV_2].mod_pop[i]]);
			  }
			}

		}
		if ((env = pi_find_envtab(curr_pnr, 2)) != NULL) {
			patchtab[curr_pnr][11] = (LONG) env->dsp_addr;
			if (envnew[2]) {
				patchtab[curr_pnr][12] = env->start_value;
				patchtab[curr_pnr][13] = env->release_slope;
			}
		
			env2_flag = TRUE;
		}
	} else {

#if 0
		patchtab[curr_pnr][12] = 0x0L;
#endif
		alg_free_env(2);
	}
	/*
	 * put an lfo here? but only if there is no filter
	 */
	if (!env2_flag && (osc != POP_OSC_FM) &&
	(algtree[ALG_FILTER].ob_spec.popup->index == POP_FILTER_OFF)) {
		WORD old_ix;

		old_ix = ix;
		ix = proc_lfo(ix, 2);
		if (old_ix != ix)
			env2_flag = TRUE | LFO_FLAG;
		else
			alg_free_lfo(2);
	} else	
			alg_free_lfo(2);


	/*
	 * is there an envelope 3?
	 */
	env3_flag = FALSE;
	if (envlfo_fx[POP_ENV_3].n > 0) {
		ENVTAB *env;

		if (!env2_flag)
			alg_mdtab[ix++] = _loopenv_skip;
		alg_mdtab[ix++] = _loopenv_slot3;
		if ((n = envlfo_fx[POP_ENV_3].n) >= 1) {
			for (i = 0; i < n; i++) {
			  if (env_fx_table[envlfo_fx[POP_ENV_3].mod_pop[i]]
			   != NULL) {
			       if (env_fx_table[envlfo_fx[POP_ENV_3].mod_pop[i]]
				== (LONG*) &_env_fx_dist)
					dist_flag = TRUE;
				else 
				  alg_mdtab[ix++] = 
				  *(env_fx_table[envlfo_fx[POP_ENV_3].mod_pop[i]]);
			  }
			}
/*
			if ((envlfo_fx[POP_ENV_3].n == 1) && dist_flag) {
				ix--;
			}
*/
		}
		if ((env = pi_find_envtab(curr_pnr, 3)) != NULL) {
				patchtab[curr_pnr][14] = (LONG) env->dsp_addr;
			if (envnew[3]) {
				patchtab[curr_pnr][15] = env->start_value;
				patchtab[curr_pnr][16] = env->release_slope;
			}
			env3_flag = TRUE;
		}
	} else {
#if 0
		patchtab[curr_pnr][15] = 0x0L;
#endif
		alg_free_env(3);
	}
	/*
	 * put an lfo here? but only if there is no dist.
	 */
	if (!env3_flag && !dist_flag) {
#if 0
	(algtree[ALG_DIST].ob_spec.popup->index != POP_DIST)) {
#endif
		WORD old_ix;

		if (!env2_flag)
			alg_mdtab[ix++] = _loopenv_skip;
		old_ix = ix;
		ix = proc_lfo(ix, 3);
		if (old_ix != ix)
			env3_flag = TRUE | LFO_FLAG;
		else if (!env2_flag) {
			ix--;		/* hack: take out the skip again */
			alg_free_lfo(3);
		} else
			alg_free_lfo(3);

	} else
		alg_free_lfo(3);
	/*
	 * is there distortion?
	 */
#if 0
	if (algtree[ALG_DIST].ob_spec.popup->index == POP_DIST) {
		alg_mdtab[ix++] = _dist;
		if (!env3_flag) { 
#if 0
			patchtab[curr_pnr][14] = 0x0L;
#endif
			/* enter dummy value, 0 for now */;
			/* really, also for distortion ? */
		}
	} 
#else
	if (dist_flag) {
		alg_mdtab[ix++] = _dist;
	}
#endif


	/*
	 * is there a filter?
	 */
	if (algtree[ALG_FILTER].ob_spec.popup->index == POP_FILTER_ON) {
		alg_mdtab[ix++] = _dft_filter;
		patchtab[curr_pnr][17] = _filter_def_1;
		if (!env2_flag) {
#if 0
			patchtab[curr_pnr][11] = 0x0L;
#endif
			/* enter dummy value, 0 for now */;
		}
	}


at_attn:
	alg_mdtab[ix++] = _attn;


	/*
	 * Even if he said he doesn't want an envelope for the filter,
	 * if env #2 is used, it's also used for the filter!
	 */
	if ((tree[ALG_FILTER].ob_spec.popup->index == POP_FILTER_ON) && 
	(tree[ALG_FILTERENV].ob_spec.popup->index == POP_ENV_NONE)) {
		if (env2_flag & 0x7fff) {
			tree[ALG_FILTERENV].ob_spec.popup->index = 1;
			objc_draw(algtree, ALG_FILTERENV, MAXDEPTH, 
				0, 0, scrn_w, scrn_h);
		}
	}

	/*
	 * Even if he said he doesn't want an envelope for the distortion,
	 * if env #3 is used, it's also used for the filter!
	 */
	if ((tree[ALG_DIST].ob_spec.popup->index == POP_DIST) && 
	(tree[ALG_DISTENV].ob_spec.popup->index == POP_ENV_NONE)) {
		if (env3_flag & 0x7fff) {
			if (env3_flag & LFO_FLAG)
			tree[ALG_DISTENV].ob_spec.popup->index = 
					POP_ENV_LFO;
			else
				tree[ALG_DISTENV].ob_spec.popup->index = 
					POP_ENV_3;
			objc_draw(algtree, ALG_DISTENV, MAXDEPTH, 
				0, 0, scrn_w, scrn_h);
		}
	}

	/*
	 * did we have space for all envelopess
	 */
	n = envlfo_fx[POP_ENV_LFO].n;
	for (i = 0; i < n; i++) {
		if (envlfo_fx[POP_ENV_LFO].done[i] == FALSE)
			break;
	}
	if (i != n)
		form_alert(FRM_ALERT, FMSTR_NOROOMFORLFO);

	/*
	 * check for number of modules before we write anything back
	 */

	if (ix > N_MDMODULES) {
		form_alert(FRM_ALERT, FMSTR_TOOMANYMDS);
		algtree[obj].ob_spec.popup->index = 0;
			objc_draw(algtree, obj, MAXDEPTH, 
				0, 0, scrn_w, scrn_h);
		enable_sound();
		return 0L;
	}

	if (!env2_flag) {
		patchtab[curr_pnr][11] = 0x0L;
		patchtab[curr_pnr][13] = 0x0L;
	}
	if (!env3_flag) {
		patchtab[curr_pnr][14] = 0x0L;
		patchtab[curr_pnr][16] = 0x0L;
	}
		

	/*
	 * copy into DSP RAM
	 */
	p = alg_mdtab;
	q = (LONG*) patchtab[curr_pnr][0];
	for (i = 0; i < N_MDMODULES; i++, p++, q++) {
		*q = *p; 
		if (*p == _attn)
			break;
	}
	/*
	 * and update patchinfo
	 */
	memcpy((BYTE*)patchinfo_table[curr_pnr].mdtab->modules, 
		(BYTE*)alg_mdtab, 32L);

/*
 * Debugging....
 */
	if (_debug) {
		dos_echo("------------ mdtab:");
		for (i = 0; i < ix; i++) {
			WORD f;
			struct _dt *p;

			for (f = 0, p = dbtable; p->addr; p++) {
				if (*p->addr == alg_mdtab[i]) {
					dos_echo(p->label);
					f=1;
				}
			}
			if (!f)
				dos_echo("not found");	
		}
		{
			BYTE buf[128];
			WORD env_cnt = 0, smp_cnt = 0;

			for (i = 0; i < 5; i++) {
				if (patchinfo_table[i].sample[i] != NULL)
					smp_cnt++;
				if (patchinfo_table[i].env[i] != NULL)
					env_cnt++;
			}

			dos_echo("------------ patchinfo:");
			sprintf(buf, "env #: %d\tsmp #:%d", 
				env_cnt,
				smp_cnt);
			dos_echo(buf);
			dos_echo("------------ envinfo:");
			for (i = 0; i < 5; i++) {
				if (patchinfo_table[curr_pnr].env[i] == NULL)
					continue;
				sprintf(buf, "offset[%d] = %d, entries = %d", i,
				 i*3+2,
				 patchinfo_table[curr_pnr].env[i]->n_entries);
				dos_echo(buf);
			}
			dos_echo("------------ smpinfo:");
			for (i = 0; i < 5; i++) {
				if (patchinfo_table[curr_pnr].sample[i] == NULL)
					continue;
				sprintf(buf, "offset[%d] = %d, index = %d", i,
				 i*3+2,
				 (WORD)(patchinfo_table[curr_pnr].sample[i] - sample_table));
				dos_echo(buf);
			}

			dos_echo("------------ general:");
			jaz_debug();
			dos_echo("------------------------");
		}
	}
	enable_sound();

	return 0L;
} /* end process_alg() */

	WORD
get_env_index(obj)
	WORD obj;
{
	switch (obj) {
	case ALG_FILTERENV:
		if (algtree[obj].ob_spec.popup->index == 1)
			return 2;
		break;
	case ALG_ATTNENV:
		if (algtree[obj].ob_spec.popup->index == 1)
			return 1;
		break;
	default:
		return algtree[obj].ob_spec.popup->index;
		break;
	}
	return 0;
}


	WORD
proc_lfo(ix, spot)
	REG WORD ix;
	WORD     spot;
{
	REG WORD i, n;
	WORD flag = FALSE;


	n = envlfo_fx[POP_ENV_LFO].n;

	for (i = 0; !flag && (i < n); i++) {
		if (envlfo_fx[POP_ENV_LFO].done[i] == TRUE)
			continue;
		switch (spot) {
		case 0:
#if 0
			if (((envlfo_fx[POP_ENV_LFO].mod_pop[i] != MOD_DIST) ||
			  (algtree[ALG_DIST].ob_spec.popup->index == POP_PW)) &&
			  (envlfo_fx[POP_ENV_LFO].mod_pop[i] != MOD_FILTER) &&
			  (osc_fx_table[envlfo_fx[POP_ENV_LFO].mod_pop[i]]
			   != NULL)) {
#else
			if (
			  (envlfo_fx[POP_ENV_LFO].mod_pop[i] != MOD_FILTER) &&
			  (osc_fx_table[envlfo_fx[POP_ENV_LFO].mod_pop[i]]
			   != NULL)) {

#endif
				alg_mdtab[ix++] = _lfo_1;
				alg_mdtab[ix++] = 
				*(osc_fx_table[envlfo_fx[POP_ENV_LFO].mod_pop[i]]);
				envlfo_fx[POP_ENV_LFO].done[i] = TRUE;
				
algtree[mod_popups[envlfo_fx[POP_ENV_LFO].mod_pop[i]]].ob_spec.popup->user_defined = 
			1 | 0x8000;
				flag = TRUE;
			}
			break;
		case 2:
#if 0	/* don't remember why this is here 6/23/95 */
			if (envlfo_fx[POP_ENV_LFO].mod_pop[i] == MOD_DIST)
				break;
#endif
			if (osc_fx_table[envlfo_fx[POP_ENV_LFO].mod_pop[i]]
			 != NULL) {
				alg_mdtab[ix++] = _lfo_1;
				alg_mdtab[ix++] = 
				*(osc_fx_table[envlfo_fx[POP_ENV_LFO].mod_pop[i]]);
			} else if (envlfo_fx[POP_ENV_LFO].mod_pop[i] == MOD_FILTER)
				alg_mdtab[ix++] = _lfo_1;
			envlfo_fx[POP_ENV_LFO].done[i] = TRUE;
algtree[mod_popups[envlfo_fx[POP_ENV_LFO].mod_pop[i]]].ob_spec.popup->user_defined = 
			3 | 0x8000;
			flag = TRUE;
			break;
		case 3:
			if (envlfo_fx[POP_ENV_LFO].mod_pop[i] == MOD_FILTER)
				break;

			if (osc_fx_table[envlfo_fx[POP_ENV_LFO].mod_pop[i]]
			 != NULL) {
				alg_mdtab[ix++] = _lfo_1;
				alg_mdtab[ix++] = 
				*(osc_fx_table[envlfo_fx[POP_ENV_LFO].mod_pop[i]]);
			} else if (envlfo_fx[POP_ENV_LFO].mod_pop[i] == MOD_DIST)
				alg_mdtab[ix++] = _lfo_1;

			envlfo_fx[POP_ENV_LFO].done[i] = TRUE;
algtree[mod_popups[envlfo_fx[POP_ENV_LFO].mod_pop[i]]].ob_spec.popup->user_defined = 
			4 | 0x8000;
			flag = TRUE;
			break;
		}
	}
	
	if (flag) {
		WORD x = 5 + spot * 3;

		offset2obj[x] = mod_popups[envlfo_fx[POP_ENV_LFO].mod_pop[i]];

		if (check_for_waveform(spot) == FALSE) {
			if (patchinfo_table[curr_pnr].sample[spot+1] == NULL) {
				patchinfo_table[curr_pnr].sample[spot+1] = 
					&sample_table[1]; /* SINE */

				patchtab[curr_pnr][x++] = 0xf1d200L; /* ROM SINE */
				patchtab[curr_pnr][x++] = 0x1000L;
				patchtab[curr_pnr][x]   = 0x0L;
			} else {
				patchtab[curr_pnr][x] = (LONG)
				 patchinfo_table[curr_pnr].sample[i]->addr;
			}
		}
	}

	return ix;
}

	VOID
alg_free_lfo(spot)
	WORD spot;
{
	REG PATCHINFO *p = &patchinfo_table[curr_pnr]; 
	WORD d, r;
	WORD x = 5 + spot * 3;
	
	d = curr_pnr / 32;
	r = curr_pnr % 32;

	if (p->sample[spot+1] != NULL) {
		patchinfo_table[curr_pnr].sample[spot+1]->used[d] &= 
			(ULONG)~(1L << (ULONG)r);
		p->sample[spot+1] = NULL;
	}

}


	VOID
alg_free_env(spot)
	WORD spot;
{
	REG PATCHINFO *p = &patchinfo_table[curr_pnr]; 
	WORD d, r;
	WORD x = 5 + spot * 3;

	d = curr_pnr / 32;
	r = curr_pnr % 32;
	if (patchinfo_table[curr_pnr].env[spot+1] != NULL) {
		patchinfo_table[curr_pnr].env[spot+1]->used[d] &= 
			(ULONG)~(1L << (ULONG)r);
		patchinfo_table[curr_pnr].env[spot+1] = NULL;
	}
}
	WORD
check_envs(obj, osc)
	WORD obj, osc;
{
	REG WORD i, k;
	WORD max, slot;
	WORD flag[5];

	if (algtree[obj].ob_spec.popup->index == POP_ENV_NONE)
		return SUCCESS;
	if (algtree[obj].ob_spec.popup->index == POP_ENV_LFO)
		return SUCCESS;	/* hey, we don't care about LFOs here */

	for (k = 1; k < 5; k++) {
		flag[k] = 0;
	}
	switch (obj) {
	case ALG_OSC2ENV:
	case ALG_DISTENV:
	case ALG_MIXERENV:
		slot = algtree[obj].ob_spec.popup->index;
		break;
	case ALG_ATTNENV:
		slot = POP_ENV_1;
		break;
	case ALG_OSC1ENV:
	case ALG_FILTERENV:
		slot = POP_ENV_2;
		break;
	}

	for (k = 1; k < 5; k++) { /* for all envelope indexes: 1, 2, 3, lfo */
		for (i = 0; mod_popups[i] != -1; i++) { /* for modifier popups */
			if (mod_popups[i] == obj)
				continue;
			if ((mod_popups[i] == ALG_FILTERENV) &&
			(algtree[mod_popups[i]].ob_spec.popup->index != 0)) {
				flag[2] = TRUE;
				continue;
			} else if ((mod_popups[i] == ALG_ATTNENV) &&
			(algtree[mod_popups[i]].ob_spec.popup->index != 0)) {
				flag[1] = TRUE;
				continue;
			} else 
			if (algtree[mod_popups[i]].ob_spec.popup->index == k) {
				flag[k] = TRUE;
			}
		}
	}
	if (flag[slot] == TRUE)
		return SUCCESS;		/* already in use anyway */

	for (k = 1, i = 0; k < 5; k++) {
		if (flag[k])
			i++;
	}

	max = (osc == POP_OSC_FIXEDWAVE) ? 4 : 3;

	if (i >= max) {
		form_alert(FRM_ALERT, FMSTR_TOOMANYENVS);
		algtree[obj].ob_spec.popup->index = 0;
		algtree[obj].ob_spec.popup->user_defined = 0;
		objc_draw(algtree, obj, MAXDEPTH, 0, 0, scrn_w, scrn_h);
		return FAILURE;
	} else  {

		/*
		 * make sure envelope is there..
		 */

		if (patchinfo_table[curr_pnr].env[1+slot] == NULL) { /* not found */
			WORD ix;
			WORD d, r;

			ix = dft_env_ix ; /* use the default envelope */
			envnew[slot] = TRUE; /* process_alg knows we used */
					     /* a new env and will copy the */
					     /* start value & rel. slope */
			d = curr_pnr / 32;
			r = curr_pnr % 32;
			env_table[ix].used[d] |= (LONG)(1L << r);
			env_table[ix].free = FALSE;
			d = 5 + slot * 3;

			patchinfo_table[curr_pnr].env[slot+1] = 
				&env_table[ix];		
			patchtab[curr_pnr][d] = 
				(LONG) env_table[ix].dsp_addr;
			patchtab[curr_pnr][d + 1] = 
				env_table[ix].start_value;
			patchtab[curr_pnr][d + 2] = 
				env_table[ix].release_slope;

		}
		algtree[obj].ob_spec.popup->user_defined = 
			1 + get_env_index(obj);
		
		return SUCCESS;
	}
}

	WORD
check_for_waveform(spot)
	WORD spot;
{
	LONG lvalue;

	lvalue = patchtab[curr_pnr][5 + spot * 3];

		/*      ROM TRI                   ROM NOISE */
	if (((lvalue >= 0xf1d000L) && (lvalue <= (0xf1de00L+512L))) || 
	 0 /* LATER: CHECK for DSP RAM WAVEFORMS!!!! */) 
		return TRUE;
	else 
		return FALSE;
}


	WORD
curr_mdtab2temp()
{
	REG LONG *p, *q;
	REG WORD i;	
	MDTAB *md;
	WORD x;


	alg_bak_dsp_addr = (LONG*) patchtab[curr_pnr][0];
	patchinfo_bak = patchinfo_table[curr_pnr];
	/*
	 * make backup of patch
	 */
	memcpy((BYTE*)tmp_patch_buf, (BYTE*) patchtab[curr_pnr], 
		(LONG)PATCH_SIZE*4L);

	if (alg_edit_mode == 2) {
		if ((x = find_mdtabSlot()) == -1) {
			form_alert(FRM_ALERT, FMSTR_NOMDTABSLOT);
			alg_edit_mode = 1;
		} else {
			WORD d, r;
			LONG *addr;

			/*
			 * Create new MDTAB, bot in DRAM + DSP RAM
			 */


			addr = (LONG*) allocMDTAB();
				
			if (addr == NULL) {
				form_alert(FRM_ALERT, FMSTR_NODSPMDTABSPACE);
				alg_edit_mode = 1;
				goto edit_out;
			}
			md = patchinfo_table[curr_pnr].mdtab;

			mdtab_table[x] = *md;

			mdtab_table[x].dsp_addr = addr;
			mdtab2dsp(&mdtab_table[x]);
			d = curr_pnr / 32;
			r = curr_pnr % 32;

			mdtab_table[x].type = 0;	
			mdtab_table[x].used[0] = 0L;
			mdtab_table[x].used[1] = 0L;
			mdtab_table[x].used[2] = 0L;
			mdtab_table[x].used[3] = 0L;

			mdtab_table[x].used[d] |= (LONG)(1L << r);
			mdtab_table[x].name[0] = '\0';

			alg_mdtab_bak_ptr = patchinfo_table[curr_pnr].mdtab;

			alg_mdtab_ptr = &mdtab_table[x];
			patchinfo_table[curr_pnr].mdtab = &mdtab_table[x];
			patchtab[curr_pnr][0] = (LONG)addr;
			alg_edit_mode = 2;
		}
	}
edit_out:
	if (alg_edit_mode == 1) {
			alg_mdtab_ptr = patchinfo_table[curr_pnr].mdtab;
		}			

	/*
	 * copy old mdtab to backup buffer
	 */
	q = alg_mdtab_bak;
	p = alg_bak_dsp_addr;
	for (i = 0; i < N_MDMODULES; i++, p++, q++) {
		if ((*q = *p) == _attn)
			break;
	}		

	/*
	 * and into temp work buffer
	 */
	q = alg_mdtab;
	p = alg_bak_dsp_addr;
	for (i = 0; i < N_MDMODULES; i++, p++, q++) {
		if ((*q = *p) == _attn)
			break;
	}		

	return 0;
}


	VOID
cancel_temp_mdtab()
{
	REG LONG *p, *q, *r;
	REG WORD i, j, k;	
	WORD n;
	MDTAB *md;

	if (alg_edit_mode == 0)	/* nothing was changed at all */
		return;

	/*
	 * restore patch
	 */
	memcpy((BYTE*) patchtab[curr_pnr],
		 (BYTE*)tmp_patch_buf, (LONG)PATCH_SIZE * 4L);


	if (alg_edit_mode == 1) {
		r = (LONG*) &patchinfo_table[curr_pnr].mdtab->modules[0];
		q = (LONG*) alg_bak_dsp_addr;
		p = alg_mdtab_bak;
		for (i = 0; i < N_MDMODULES; i++, p++, q++, r++) {
			if ((*r = *q = *p) == _attn)
				break;
		}			
		patchinfo_table[curr_pnr].mdtab->n_entries = i;

		
	} else {
		md = patchinfo_table[curr_pnr].mdtab;
		md->used[0] = 0L;
		md->used[1] = 0L;	/* this should go into free() */
		md->used[2] = 0L;
		md->used[3] = 0L;

		patchinfo_table[curr_pnr].mdtab = alg_mdtab_bak_ptr;
		freeMDTAB((LONG*)patchtab[curr_pnr][0]);
		patchtab[curr_pnr][0] = (LONG) alg_bak_dsp_addr;
		free_mdtabSlot((WORD) (alg_mdtab_ptr - mdtab_table));
	}



	/*
	 * Throw out the unused envelopes
	 */




	for (j = 1, k = 8; j < 4; j++, k += 3) {
		if (org_env_flags[j] == FALSE) {
			   i = j + 1;
			   if (patchinfo_table[curr_pnr].env[i] != NULL) {
				ENVTAB *env = patchinfo_table[curr_pnr].env[i];
				if (env_only_used_by(curr_pnr, env)) {
					freeENV(env->dsp_addr);
					free_envSlot((WORD)(env-env_table));
				}
				patchinfo_table[curr_pnr].env[i] = NULL;
			   }
		}
	}
	patchinfo_table[curr_pnr] = patchinfo_bak;
}

	WORD
env_only_used_by(pnr, env)
	WORD pnr;
	ENVTAB *env;
{
	WORD d;
	WORD r;
	WORD f;

	d = pnr / 32;
	r = pnr % 32;

	env->used[d] &= ~(LONG)(1L << r);
	
	if ((env->used[0] == 0L) && (env->used[1] == 0L) && 
	(env->used[2] == 0L) && (env->used[3] == 0L))
		f = TRUE;
	else 
		f = FALSE;
	env->used[d] |= (LONG)(1L << r);

	return f;
}

	VOID
patchinfo_rm_env(pnr, envnr)
	WORD pnr;
	WORD envnr;
{
	
	patchinfo_table[pnr].env[envnr] = NULL;


}

	ENVTAB
*pi_find_envtab(pnr, slot)
	WORD pnr, slot;
{


	slot += 1;
	return patchinfo_table[pnr].env[slot];

}

	WORD
pi_find_envtab_ix(pnr, slot)
	WORD pnr, slot;
{
	

	return slot+1;

}
	VOID
replace_sample(pnr, offset, sample)
	WORD pnr;
	WORD offset;
	WORD sample;
{
	WORD d, r;

	d = pnr / 32;
	r = pnr % 32;
	offset = (offset - 2) / 3;
	if (sample == -1) {
		if (patchinfo_table[pnr].sample[offset] != NULL) {
			patchinfo_table[pnr].sample[offset]->used[d] &= 
				(ULONG)~(1L << (ULONG)r);
			patchinfo_table[pnr].sample[offset] = NULL;
		}
	} else {
		if (patchinfo_table[pnr].sample[offset] != NULL) {
			patchinfo_table[pnr].sample[offset]->used[d] &= 
				(ULONG)~(1L << (ULONG)r);
			patchinfo_table[pnr].sample[offset] = 
				&sample_table[sample];
			patchinfo_table[pnr].sample[offset]->used[d] |= 
				(ULONG)(1L << r);

		} else {
			patchinfo_table[pnr].sample[offset] = 
				&sample_table[sample];
			patchinfo_table[pnr].sample[offset]->used[d] |= 
					(ULONG)(1L << r);
		}
	}

}
	VOID
show_warning(x, y, w, h, msg)
	WORD x, y, w, h;
	BYTE *msg;
{
	REG WORD i;
	REG BYTE *s, *s0;
	BYTE buf[384];

	strcpy(buf, msg);

	if (x != -1)
		warn_tree[0].ob_x = x;
	if (y != -1)
		warn_tree[0].ob_y = y;
	if (w != -1)
		warn_tree[0].ob_width = w;
	if (h != -1)
		warn_tree[0].ob_height = h;

	for (i = 1, s0 = s = buf; i <= 4; i++) {
		for (; *s && (*s != '|'); s++)
			;
		*s++ = '\0';
		strcpy(warn_tree[i].ob_spec.boxtext->bx_text, s0);
		s0 = s;
	}
	objc_draw(warn_tree, 0, MAXDEPTH, 0, 0, scrn_w, scrn_h);
} 

	VOID
update_other_patches()
{
	REG WORD i, j, l;
	REG PATCHINFO *p, *q;
	MDTAB *md;
	WORD x, k;


	p = &patchinfo_table[curr_pnr];
	md = p->mdtab;
	for (i = 0; i < 4; i++) {
	  for (j = 0; j < 32; j++) {
		x = i * 32 + j;
		if (x == curr_pnr)
			continue;
		if ((md->used[i] >> j) & 1) {
			q = &patchinfo_table[x];
			/*
			 *	insert missing envelopes
			 */ 
			for (k = 0; k < 5; k++) {
				if (!p->env[k])
					continue;
				if (!q->env[k]) { /* not found */
					l = 2+k*3;
					q->env[k] = p->env[k];
					patchtab[x][l] = patchtab[curr_pnr][l++];
					patchtab[x][l] = patchtab[curr_pnr][l++];
					patchtab[x][l] = patchtab[curr_pnr][l];
				}
			}
			/*
			 *	 now get rid of extra ones
			 */ 
			for (k = 0; k < 5; k++) {
				if (p->env[k])
					continue;
				else
					q->env[k] = NULL; /* update used */
							  /* flags ????  */

			}
			/*
			 *	insert missing samples
			 */ 

			for (k = 0; k < 5; k++) {
				if (!p->sample[k])
					continue;
				if (!q->sample[k]) { /* not found */
					l = 2+k*3;
					q->sample[k] = p->sample[k];
					patchtab[x][l] = patchtab[curr_pnr][l++];
					patchtab[x][l] = patchtab[curr_pnr][l++];
					patchtab[x][l] = patchtab[curr_pnr][l++];
					if ((l == 5) && (alg_osc_type <=4)) {
						patchtab[x][l] = patchtab[curr_pnr][l++];
						patchtab[x][l] = patchtab[curr_pnr][l++];
						patchtab[x][l] = patchtab[curr_pnr][l++];
					}
				}
			}
			/*
			 *	 now get rid of extra ones
			 */ 
			for (k = 0; k < 5; k++) {
				if (p->sample[k])
					continue;
				else
					q->sample[k] = NULL; /* update used */
							     /* flags?????  */

			}

			if (alg_osc_type != alg_old_osc_type) {
				patchtab[x][1] = patchtab[curr_pnr][1];
			}	
			
		}
	  }
	}
}

	WORD
get_envstate(envnr)
	WORD envnr;
{
	WORD r;

	switch (envnr) {
	case 0:
		if ((env1_flag & LFO_FLAG) || !env1_flag)
			r = FALSE;
		else
			r = TRUE;		
		break;
	case 1:
		if ((env2_flag & LFO_FLAG) || !env2_flag)
			r = FALSE;
		else
			r = TRUE;		
		break;
	case 2:
		if ((env3_flag & LFO_FLAG) || !env3_flag)
			r = FALSE;
		else
			r = TRUE;		
		break;
	}
	return r;
}




/*
 * check for reverb and delay ...
 */
	WORD
check_delay()
{
	LONG l = *_effect_mode;

	if (*(ULONG*)(_mdtab_reverb+1L) == _reverb)
		return 2;
	else if (*_mdtab_reverb == _delay)
		return 1;
	else if ((l & 0xffffL) == 2)
		return 3;
	else
		return 0;
}

	VOID
set_delay(tree, obj, info)
	OBJECT    *tree;
	WORD	  obj;
	POPUPINFO *info;	
{
	ULONG *p = _mdtab_reverb;
	ULONG *q, *r, *v;
	WORD x, i;

	x = info->index;
	disable_sound();

	switch (x) {
	case 0:
		*_mdtab_reverb = _vt_return_loc;
		*_effect_mode=0xffff0000L;		
		break;
	case 1:
		v = q = _voice_table + 13 * PATCH_SIZE;	/* restore delay voice */
		v[0] = (LONG) _vt_ret_value;

		r = &reverb_voice[1];
		for (q++, i = 0; i < (PATCH_SIZE-1); i++)
			*q++ = *r++;
		v[0] = (LONG) _mdtab_reverb;
		v[3] = (LONG) _voice_buffer;
		v[4] = (LONG) _reverb_table;		

		*p++ = _delay;
		*p   = _vt_return_loc;
		*_effect_mode=0xffff0001L;		

		
		break;
	case 2:
#if 0
		*p++ = _delay;
		*p++ = _reverb;
		*p   = _vt_return_loc;
		*_effect_mode=0xffff0001;		
#endif
		break;
	case 3:
		*_mdtab_reverb = _vt_return_loc;
		*_effect_mode=0xffff0002L;		
		break;
	
	}
	enable_sound();
}
