/************************************************************************
 *	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 *);
/*
 *	Synth Externals
 */

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_pan;
EXTERN ULONG	_osc_fx_pitch;
EXTERN ULONG	_env_fx_pw;
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;


/*	----------
 *	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);

/*	---------
 *	GLOBALS
 */
WORD	alg_osc_type;
WORD	alg_in_edit;			/* page in edit mode flag 	 */
WORD	alg_edit_mode;
WORD	alg_omni_mode;
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  */
ULONG	tmp_patch_buf[PATCH_SIZE];
WORD	org_env_flags[4];

/*
 *	MODULE POINTER TABLES OBJECT Handling
 */

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

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

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 },
 { 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,	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 },
 { 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_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 },
 { 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 },
 { 15, &_dft_filter,	3, 	NULL,	ALG_FILTER,	POP_FILTER_ON },
/* where does distortion go ??? */
/* { 15, &_dist,		0, 	NULL,	ALG_DIST,	POP_DIST }, */
 {-1, NULL,		0,	NULL,	0,		0 }
};


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

build_jazalg()
{
	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_BTTNBOX,
		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_ATTNENV,
		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);
#endif
 	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|LOCKPOP,
		T_POP_LOCK_STR, FMSTR_LOCKPOP,
		T_POP_ACTION,  adjust_volume,
		T_POP_CALLBK,  process_alg,
		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_BTTNBOX,
		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_MIXER, 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_MIXER, 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_ATTNENV,
		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, 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;

	if (alg_in_edit) {
		if (alg_edit_mode == 0) {
			alg_edit_mode = form_alert(FRM_ALERT, FMSTR_MDTABNEW);
			curr_mdtab2temp();
		}
		/*
		 *	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;
				
	} 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;
{
	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 (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;

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

	update_patchnameslist();

	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, flag, found, x;
	ULONG *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;		
				if (mdtabobj_p->param & MDTAB_CMD_PW) {
					pw_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 (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;

        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;
		}
        }

	/*
	 * check for reverb and delay...
	 */
	if (*(ULONG*)(_mdtab_reverb+1L) == _reverb)
		algtree[ALG_MIXER].ob_spec.popup->index = 2;
	else if (*_mdtab_reverb == _delay)
		algtree[ALG_MIXER].ob_spec.popup->index = 1;
	else
		algtree[ALG_MIXER].ob_spec.popup->index = 0;


	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_pitch, "osc_fx_pitch" },
	{ &_env_fx_pan, "env_fx_pan" },
	{ &_env_fx_pw, "env_fx_pw" },
	{ &_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; 
{
	REG WORD i, k;
	REG LONG *p, *q;
	WORD 	 ix;
	WORD 	 osc;
	WORD 	 n;
	WORD	 x;
	WORD	 env1_flag;
	WORD	 env2_flag;
	WORD	 env3_flag;
	WORD	 lfo2_flag;
	WORD	 lfo3_flag;



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

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

	/*
	 * 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] = NULL;
		osc_fx_table[2] = NULL;
	}

	switch (obj) {
	case ALG_MIXER:
		if (tree[ALG_MIXER].ob_spec.popup->index == 0) {
			*_mdtab_reverb = _vt_return_loc;
		} else if (tree[ALG_MIXER].ob_spec.popup->index == 1) {
			ULONG *p = _mdtab_reverb;

			*p++ = _delay;
			*p   = _vt_return_loc;
		} else if (tree[ALG_MIXER].ob_spec.popup->index == 2) {
			ULONG *p = _mdtab_reverb;


			form_alert(FRM_ALERT, "[Reverb not included in|the synth right now][ OK ]");
			tree[ALG_MIXER].ob_spec.popup->index = 0;
			objc_draw(algtree, ALG_MIXER, MAXDEPTH, 
				0, 0, scrn_w, scrn_h);
#if 0
			*p++ = _delay;
			*p++ = _reverb;
			*p   = _vt_return_loc;
#endif
		}

		break;	
	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)) {
			form_alert(FRM_ALERT, FMSTR_PWNEEDSENV);
			tree[ALG_DISTENV].ob_spec.popup->index = POP_ENV_2;
		 	if (check_envs(ALG_DISTENV, osc) == FAILURE)
				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);
		}
		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)) {
			n = form_alert(FRM_ALERT, FMSTR_FILTERNOENV);
			if (n == 2) {
				tree[ALG_FILTERENV].ob_spec.popup->index = 1;
		 		if (check_envs(ALG_FILTERENV, osc) == FAILURE)
					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);
				form_alert(FRM_ALERT, FMSTR_WRNFILTERNOENV);
				/* TO DO: ...specify defalut value */
			}
		} 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 0
	case ALG_OSC1ENV:
 		if (check_envs(obj, osc) == FAILURE)
			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)
			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)
			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 ((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;
		}
		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)
			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)
			return 0L;
		break;
	case ALG_MIXERENV:
 		if (check_envs(obj, osc) == FAILURE)
			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

		/*
		 * Was is fixed wave? If yes, check if we used an lfo &
		 * turn it off.
		 */
		if (alg_osc_type == POP_OSC_FIXEDWAVE) {
			WORD n = patchinfo_table[curr_pnr].env_cnt;

			for (i = 0; i < n; i++) {
			     if (patchinfo_table[curr_pnr].env_offset[i] == 5) {
				algtree[offset2obj[5]].ob_spec.popup->index = 0;
				objc_draw(algtree,offset2obj[5], 
					MAXDEPTH, 0, 0, scrn_w, scrn_h);
			     }
			}
		}

		switch (osc) {
		case POP_OSC_SAMPLER:
		case POP_OSC_NISAMPLER:
		case POP_OSC_CSAMPLER:
		case POP_OSC_CNISAMPLER:
			patchtab[curr_pnr][1] = 0xE80FFFE4;
			patchtab[curr_pnr][2] = (ULONG)sample_table[8].addr;
							; /* 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[8].size << 12L;
					break;
				}
				patchtab[curr_pnr][5] = size;
				patchtab[curr_pnr][6] = size;
				patchtab[curr_pnr][7] = size;
			}


			replace_sample(curr_pnr, 2, 8);
			replace_sample(curr_pnr, 5, -1);

			if (smpslot_cnt >= 8)
				break;
			else
				form_alert(FRM_ALERT, FMSTR_NOSAMP);

		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);
			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 (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; 
			
	} 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;
	}

	/*
	 * 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 if anything else is out there
		 */
		for (i = 1; i < N_POPUPS; i++) {
			if (alg_pop_flags[i] > 0) {
				flag = TRUE;
				break;
			}
		}
		patchtab[curr_pnr][8] = 0x0L;
#if 0
		patchtab[curr_pnr][9] = 0x3ff80000L; /* for some volume */
#endif
		patchtab[curr_pnr][10] = 0x0L;
		if (flag) {
			alg_mdtab[ix++] = _loopenv_skip;

		} else {
			/*
			 * since nothing else is there, we go to the attn
			 * right away
			 */
			goto at_attn;
		}
	} else {
		WORD slot;

		alg_mdtab[ix++] = _loopenv_slot1;
		/*
		 * make sure envelope is there..
		 */
		slot = 1;
		k = patchinfo_table[curr_pnr].env_cnt;
		for (i = 0; i < k; i++) {
			if (patchinfo_table[curr_pnr].env_offset[i] == 
			(5 + slot * 3)) {
				break;
			}
		}
		env1_flag = TRUE;
		if (i == k) { /* 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_offset[k] = d;
			patchinfo_table[curr_pnr].env[k] = 
				&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;
			patchinfo_table[curr_pnr].env_cnt++;
			if (patchinfo_table[curr_pnr].env_cnt > 4)
				form_alert(FRM_ALERT, 
"[XX process_alg():| Too many envelopes in|patch_info.][ OK ]");
		} else {
			ENVTAB *env;

			env = pi_find_envtab(curr_pnr, 1);
			patchtab[curr_pnr][8] = (LONG) env->dsp_addr;
			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]]);
			  }
			}

		}
		env = pi_find_envtab(curr_pnr, 2);
		patchtab[curr_pnr][11] = (LONG) env->dsp_addr;
		patchtab[curr_pnr][12] = env->start_value;
		patchtab[curr_pnr][13] = env->release_slope;
		env2_flag = TRUE;
	} else {
		patchtab[curr_pnr][11] = 0x0L;
#if 0
		patchtab[curr_pnr][12] = 0x0L;
#endif
		patchtab[curr_pnr][13] = 0x0L;
	}
	/*
	 * put an lfo here? but only if there is no filter
	 */
	if (!env2_flag && 
	(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;
	}

	/*
	 * 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 */;
		}
	}

	/*
	 * 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) {
				alg_mdtab[ix++] = 
				*(env_fx_table[envlfo_fx[POP_ENV_3].mod_pop[i]]);
			  }
			}

		}
		env = pi_find_envtab(curr_pnr, 3);
		patchtab[curr_pnr][14] = (LONG) env->dsp_addr;
		patchtab[curr_pnr][15] = env->start_value;
		patchtab[curr_pnr][16] = env->release_slope;
		env3_flag = TRUE;
	} else {
		patchtab[curr_pnr][14] = 0x0L;
#if 0
		patchtab[curr_pnr][15] = 0x0L;
#endif
		patchtab[curr_pnr][16] = 0x0L;
	}
	/*
	 * put an lfo here? but only if there is no dist.
	 */
	if (!env3_flag &&
	(algtree[ALG_DIST].ob_spec.popup->index != POP_DIST)) {
		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 */
	}

	/*
	 * is there distortion?
	 */
	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 ? */
		}
	} 



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);
		return 0L;
	}

	/*
	 * copy into DSP RAM
	 */
	p = alg_mdtab;
	q = (LONG*) patchtab[curr_pnr][0];
	for (i = 0; i < 8; 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....
 */
	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");	
	}

	return 0L;
}
	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 (((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)) {
				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) {
			n = patchinfo_table[curr_pnr].smp_cnt;
			patchinfo_table[curr_pnr].smp_offset[n] = x;
			patchinfo_table[curr_pnr].sample[n] = 
				&sample_table[1]; /* SINE */
			patchinfo_table[curr_pnr].smplist_ix[n] = 1;
			patchinfo_table[curr_pnr].smp_cnt++;

			patchtab[curr_pnr][x++] = 0xf1d200L; /* ROM SINE */
			patchtab[curr_pnr][x++] = 0x1000L;
			patchtab[curr_pnr][x]   = 0x0L;
		}
	}

	return ix;
}

	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;

	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..
		 */
		k = patchinfo_table[curr_pnr].env_cnt;
		for (i = 0; i < k; i++) {
			if (patchinfo_table[curr_pnr].env_offset[i] == 
			(5 + slot * 3)) {
				break;
			}
		}
		if (i == k) { /* 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_offset[k] = d;
			patchinfo_table[curr_pnr].env[k] = 
				&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;
			patchinfo_table[curr_pnr].env_cnt++;
			if (patchinfo_table[curr_pnr].env_cnt > 4)
				form_alert(FRM_ALERT, 
"[XX check_envs():| Too many envelopes in|patch_info.][ OK ]");
		}
		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];

	/*
	 * 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, org_env_flags, k = 8; j < 4; j++, k += 3) {
		if (org_env_flags[j] == FALSE) {
			n = patchinfo_table[curr_pnr].env_cnt;
			for (i = 0; i < n; i++) {
			   if (patchinfo_table[curr_pnr].env_offset[i] == k) {
				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_rm_env(curr_pnr, i);
			   }
			}
		}
	}

}

	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;
{
	REG WORD i, n;
	
	n = patchinfo_table[pnr].env_cnt;
	for (i = envnr; i < (n-1); i++) {
		patchinfo_table[pnr].env[i] = patchinfo_table[pnr].env[i+1];
		patchinfo_table[pnr].env_offset[i] = 
			patchinfo_table[pnr].env_offset[i+1];
	}
	patchinfo_table[pnr].env_cnt--;
}

	ENVTAB
*pi_find_envtab(pnr, slot)
	WORD pnr, slot;
{
	REG WORD i, n;
	
	n = patchinfo_table[pnr].env_cnt;

	slot = 5 + slot * 3;

	for (i = 0; i < n; i++) {
		if (patchinfo_table[pnr].env_offset[i] == slot)
			return patchinfo_table[pnr].env[i];
	}

	/*
	 * We should never get here:
	 */
	form_alert(FRM_ALERT, 
"[XX find_envtab():|Envelope not found.][ OK ]");

	return NULL;
}

	WORD
pi_find_envtab_ix(pnr, slot)
	WORD pnr, slot;
{
	REG WORD i, n;
	
	n = patchinfo_table[pnr].env_cnt;

	slot = 5 + slot * 3;

	for (i = 0; i < n; i++) {
		if (patchinfo_table[pnr].env_offset[i] == slot)
			return i;
	}

	/*
	 * We should never get here:
	 */
	form_alert(FRM_ALERT, 
"[XX find_envtab():|Envelope not found.][ OK ]");

	return -1;
}
	VOID
replace_sample(pnr, offset, sample)
	WORD pnr;
	WORD offset;
	WORD sample;
{
	REG WORD i, j, n;
	WORD d, r;

	d = pnr / 32;
	r = pnr % 32;
	n = patchinfo_table[pnr].smp_cnt;
	if (sample == -1) {
		for (i = 0; i < n; i++) {
			if (patchinfo_table[pnr].smp_offset[i] == offset) {
				patchinfo_table[pnr].sample[i]->used[d] &= ~r;
				for (j = i; j < (n - 1); j++) {
					patchinfo_table[pnr].smp_offset[j] =
					  patchinfo_table[pnr].smp_offset[j+1];
 					patchinfo_table[pnr].smplist_ix[j] =
					  patchinfo_table[pnr].smplist_ix[j+1];
 					patchinfo_table[pnr].sample[j] =
					  patchinfo_table[pnr].sample[j+1];
				}	
				patchinfo_table[pnr].smp_cnt--;
			}
		}

	} else {
		for (i = 0; i < n; i++) {
			if (patchinfo_table[pnr].smp_offset[i] == offset) {
				patchinfo_table[pnr].sample[i]->used[d] &= ~r;
				patchinfo_table[pnr].smplist_ix[i] = sample;
				patchinfo_table[pnr].sample[i] = 
					&sample_table[i];
				patchinfo_table[pnr].sample[i]->used[d] |= r;
			}
		}
		if (i == n) {
			patchinfo_table[pnr].smplist_ix[i] = sample;
			patchinfo_table[pnr].sample[i] = &sample_table[i];
			patchinfo_table[pnr].smp_offset[i] = offset;
			patchinfo_table[pnr].smp_cnt++;
			patchinfo_table[pnr].sample[i]->used[d] |= r;
		}
	}

}
