/***************************************************************************
*	NAME:  IWNOTE1.C $Revision: 1.2 $
**	COPYRIGHT:
**	"Copyright (c) 1994,1995 by e-Tek Labs"
**
**       "This software is furnished under a license and may be used,
**       copied, or disclosed only in accordance with the terms of such
**       license and with the inclusion of the above copyright notice.
**       This software or any other copies thereof may not be provided or
**       otherwise made available to any other person. No title to and
**       ownership of the software is hereby transfered."
****************************************************************************
* $Log: iwnote1.c $
* Revision 1.2  1995/05/25 18:17:13  mleibow
* Revision 1.1  1995/02/23 11:07:16  unknown
* Initial revision
***************************************************************************/

#include <dos.h>
#include <string.h>

#include "iw.h"
#include "iwl.h"
#include "globals.h"
#include "iwatten.h"
#include "iwllist.h"
#include "iwnote.h"

void iw_change_patch(iw_patch_t RFAR *op, iw_patch_t RFAR *np)
{
    struct iw_layer RFAR *ol, RFAR *nl;
    struct iw_envp RFAR *ovep, RFAR *opep, RFAR *nvep, RFAR *npep;
    struct iw_envp_record RFAR *over, RFAR *oper, RFAR *nver, RFAR *nper;
    struct note_status RFAR *ns;
    struct voice_status RFAR *vs;
    unsigned short RFAR *osp, RFAR *nsp;
    short pan;
    int no_real_time = 0, i, layer;
    int j;

    /* check for params which are different which cannot be done in */
    /* real time. If there are any, then silence any notes which are */
    /* playing */
    if (op->layer_mode != np->layer_mode ||
        op->exclusion_mode != np->exclusion_mode ||
	op->exclusion_group != np->exclusion_group ||
	op->effect1 != np->effect1 ||
	op->effect2 != np->effect2) {
	no_real_time = 1;
    }
    ol = op->layers;
    nl = np->layers;
    for (layer=0; !no_real_time && layer < op->nlayers; layer++, ol=ol->id.p, nl=nl->id.p) {
	if (ol->high_range != nl->high_range ||
	    ol->low_range != nl->low_range ||
	    ol->velocity_mode != nl->velocity_mode ||
	    ol->freq_scale != nl->freq_scale ||
	    ol->freq_center != nl->freq_center ||
	    ol->layer_event != nl->layer_event ||
	    ol->flags != nl->flags ||
	    _fmemcmp(&ol->tremolo, &nl->tremolo, sizeof(ol->tremolo)) != 0 ||
	    _fmemcmp(&ol->vibrato, &nl->vibrato, sizeof(ol->vibrato)) != 0) {
	    no_real_time = 1;
	    break;
	}
	/* check to see if envelopes have changed */
	/* volume envelope */
	ovep = (struct iw_envp RFAR *)ol->venv.p;
	nvep = (struct iw_envp RFAR *)nl->venv.p;
	if (ovep && nvep) {
	    if (_fmemcmp(&ovep->h, &nvep->h, sizeof(ovep->h)) != 0) {
		no_real_time = 1;
		break;
	    }
	    over = (struct iw_envp_record RFAR *)(ovep+1);
	    nver = (struct iw_envp_record RFAR *)(nvep+1);
	    for (i=0; i < ovep->h.num_envelopes; i++) {
		if (_fmemcmp(over, nver, sizeof(*over)) != 0) {
		    no_real_time = 1;
		    break;
		}
		osp = (unsigned short RFAR *)(over+1);
		nsp = (unsigned short RFAR *)(nver+1);
		for (j=0; j < (over->nattack+over->nrelease)*2; j++) {
		    if (osp[j] != nsp[j]) {
			no_real_time = 1;
			break;
		    }
		}
		if (no_real_time) break;
		over = (struct iw_envp_record RFAR *)(&osp[j]);
		nver = (struct iw_envp_record RFAR *)(&nsp[j]);
	    }
	}
	/* pitch envelope */
	opep = (struct iw_envp RFAR *)ol->penv.p;
	npep = (struct iw_envp RFAR *)nl->penv.p;
	if (opep && npep) {
	    if (_fmemcmp(&opep->h,&npep->h,sizeof(opep->h))) {
		no_real_time = 1;
		break;
	    }
	    oper = (struct iw_envp_record RFAR *)(opep+1);
	    nper = (struct iw_envp_record RFAR *)(npep+1);
	    for (i=0; i < opep->h.num_envelopes; i++) {
		if (_fmemcmp(oper,nper,sizeof(*oper)) != 0) {
		    no_real_time = 1;
		    break;
		}
		osp = (unsigned short RFAR *)(oper+1);
		nsp = (unsigned short RFAR *)(nper+1);
		for (j=0; j < (oper->nattack+oper->nrelease)*2; j++) {
		    if (osp[j] != nsp[j]) {
			no_real_time = 1;
			break;
		    }
		}
		if (no_real_time) break;
		oper = (struct iw_envp_record RFAR *)(&osp[j]);
		nper = (struct iw_envp_record RFAR *)(&nsp[j]);
	    }
	}
    }
    if (!no_real_time) {
	/* check if any notes are playing, if none, then skip real time */
	/* modifications */
	ENTER;
	for (ns=NS_START; ns != 0; ns = NS_NEXT(ns)) {
	    if (ns->patch == op) break;
	}
	if (ns == 0) no_real_time = 1;
	LEAVE;
    }
    if (no_real_time) {
	/* something changed which can't be modified in real time. */
	ENTER;
	iw_midi_silence_patch_notes(op);
	op->layer_mode = np->layer_mode;
	op->exclusion_mode = np->exclusion_mode;
	op->effect1 = np->effect1;
	op->effect1_depth = np->effect1_depth;
	op->effect2 = np->effect2;
	op->effect2_depth = np->effect2_depth;
	op->bank = np->bank;
	op->program = np->program;
	ol = op->layers;
	nl = np->layers;
	for (layer=0; layer < op->nlayers; layer++, ol=ol->id.p, nl=nl->id.p) {
	    ol->high_range = nl->high_range;
	    ol->low_range = nl->low_range;
	    ol->pan = nl->pan;
	    ol->pan_freq_scale = nl->pan_freq_scale;
	    ol->tremolo = nl->tremolo;
	    ol->vibrato = nl->vibrato;
	    ol->velocity_mode = nl->velocity_mode;
	    ol->attenuation = nl->attenuation;
	    ol->freq_scale = nl->freq_scale;
	    ol->freq_center = nl->freq_center;
	    ol->layer_event = nl->layer_event;
	    ol->flags = nl->flags;
	    /* volume envelope */
	    ovep = (struct iw_envp RFAR *)ol->venv.p;
	    nvep = (struct iw_envp RFAR *)nl->venv.p;
	    if (ovep && nvep) {
		ovep->h = nvep->h;
		over = (struct iw_envp_record RFAR *)(ovep+1);
		nver = (struct iw_envp_record RFAR *)(nvep+1);
		for (i=0; i < nvep->h.num_envelopes; i++) {
	 	    *over = *nver;
		    osp = (unsigned short RFAR *)(over+1);
		    nsp = (unsigned short RFAR *)(nver+1);
		    for (j=0; j < (nver->nattack+nver->nrelease)*2; j++) {
			osp[j] = nsp[j];
		    }
		    over = (struct iw_envp_record RFAR *)(&osp[j]);
		    nver = (struct iw_envp_record RFAR *)(&nsp[j]);
		}
	    }
	    /* pitch envelope */
	    opep = (struct iw_envp RFAR *)ol->penv.p;
	    npep = (struct iw_envp RFAR *)nl->penv.p;
	    if (opep && npep) {
		opep->h = npep->h;
		oper = (struct iw_envp_record RFAR *)(opep+1);
		nper = (struct iw_envp_record RFAR *)(npep+1);
		for (i=0; i < npep->h.num_envelopes; i++) {
		    *oper = *nper;
		    osp = (unsigned short RFAR *)(oper+1);
		    nsp = (unsigned short RFAR *)(nper+1);
		    for (j=0; j < (nper->nattack+nper->nrelease)*2; j++) {
			osp[j] = nsp[j];
		    }
		    oper = (struct iw_envp_record RFAR *)(&osp[j]);
		    nper = (struct iw_envp_record RFAR *)(&nsp[j]);
		}
	    }
	    /* waves not implemented - use digital music interface */
	}
	LEAVE;
	return;
    }
    /* real time change */
    ENTER;
    if (op->effect1_depth != np->effect1_depth ||
	op->effect2_depth != np->effect2_depth) {
	op->effect1_depth = np->effect1_depth;
	op->effect2_depth = np->effect2_depth;
	for (ns=NS_START; ns != 0; ns = NS_NEXT(ns)) {
	    if (ns->patch == op) {
		for (vs=VS_START; vs != 0; vs = VS_NEXT(vs)) {
		    if (vs->note == ns) {
			iwl_change_voice_volume(vs->voice);
		    }
		}
	    }
	}
    }
    ol = op->layers;
    nl = np->layers;
    for (layer=0; layer < op->nlayers; layer++, ol=ol->id.p, nl=nl->id.p) {
	if (ol->pan != nl->pan || ol->pan_freq_scale != nl->pan_freq_scale) {
	    ol->pan = nl->pan;
	    ol->pan_freq_scale = nl->pan_freq_scale;
	    for (vs=VS_START; vs != 0; vs = VS_NEXT(vs)) {
		if (vs->layer == ol) {
		    if (nl->pan_freq_scale) {
			pan = (((vs->note->note-64) * nl->pan_freq_scale)>>7)+nl->pan;
		    } else {
			pan = nl->pan;
		    }
		    pan = pan + iwl_channel_status[vs->channel].pan;
		    if (pan < 0) pan = 0;
		    if (pan > 127) pan = 127;
		    vs->pan = (char)pan;
		    iwl_change_voice_volume(vs->voice);
		    break;
		}
	    }
	}
	if (ol->attenuation != nl->attenuation) {
	    ol->attenuation = nl->attenuation;
	    for (vs=VS_START; vs != 0; vs = VS_NEXT(vs)) {
		if (vs->layer == ol) {
		    vs->layer_atten = nl->attenuation<<5;
		    iwl_change_voice_volume(vs->voice);
		    break;
		}
	    }
	}
	/* check tremolo */
	/* check vibrato */
    }
    LEAVE;
}
