/*
 * $Header: dx7.c,v 1.3 88/07/20 21:40:04 glenn Exp $
 */
#include "dx7.h"

/*
 * Expand a bank voice, indexed by "index" into a single voice.
 */
VoiceExpand(c, v, index)
struct Cdx7voice *c;
struct dx7voice *v;
int index;
{
	struct dx7operator *o;
	struct Cdx7operator *co;
	int i, j;

	/*
	 * Do 6 operators
	 */
	for (i = 0; i < 6; i++) {
		co = (struct Cdx7operator *) c->cv_operator[i];
		o = (struct dx7operator *) v->v_operator[i];

		for (j = 0; j < 4; j++) { /* Envelope rate and levels */
			o->o_rate[j] = co->co_rate[j]; /* EG Rate */
			o->o_level[j] = co->co_level[j]; /* EG Level */
		}
		o->o_breakP = co->co_breakP; /* Keyboard Breakpoint */
		o->o_lDepth = co->co_lDepth; /* Keyboard Depth Left */
		o->o_rDepth = co->co_rDepth; /* Keyboard Depth Right */
		o->o_lCurve = co->co_rlCurves & 0x03; /* Keyboard Curve Left */
		o->o_rCurve = (co->co_rlCurves >> 2) & 0x03; /* Keyboard Curve Right */
		o->o_rates = co->co_dtr & 0x07;	/* Keyboard Rate Scale */
		o->o_sens = co->co_velsams & 0x03; /* Modulation Sensitivity */
		o->o_velocity = (co->co_velsams >> 2) & 0x07; /* Velocity Sensitivity */
		o->o_output = co->co_output; /* Output Level */
		o->o_oscMode = co->co_mc & 0x01; /* Oscillator Mode */
		o->o_Cfreq = (co->co_mc >> 1) & 0x1F; /* Coarse Frequency */
		if (co->co_fine > 63)
			co->co_fine = 63;
		o->o_Ffreq = co->co_fine; /* Fine Frequency */
		o->o_detune = (co->co_dtr >> 3) & 0x0F;	/* Oscillator Detune */
	}

	for (j = 0; j < 4; j++) {
		v->v_pRate[j] = c->cv_pRate[j];	/* Pitch EG Rate */
		v->v_pLevel[j] = c->cv_pLevel[j]; /* Pitch EG Level */
	}
	v->v_algorithm = c->cv_algorithm; /* Algorithm */
	v->v_feedback = c->cv_opSyncFeedback & 0x07; /* Feedback */
	v->v_sync = (c->cv_opSyncFeedback >> 3) & 0x01;	/* Oscillator Sync */
	v->v_lfoSpeed = c->cv_lfoSpeed;	/* LFO Speed */
	v->v_lfoDelay = c->cv_lfoDelay;	/* LFO Delay */
	v->v_lfoPmd = c->cv_lfoPmd;	/* LFO PMD */
	v->v_lfoAmd = c->cv_lfoAmd;	/* LFO AMD */
	v->v_lfoSync = c->cv_PLL & 0x01; /* LFO SYNC */
	v->v_lfoWave = (c->cv_PLL >> 1) & 0x07;	/* LFO Waveform */
	v->v_pSens = (c->cv_PLL >> 4) & 0x07; /* Pitch Mod Sensitivity */
	v->v_transpose = c->cv_transpose; /* Voice Transpose */
	strncpy(v->v_name, c->cv_name, 10);	/* Voice Name */
	v->v_checksum = CheckSum(v, sizeof(*v) - sizeof(v->v_checksum)); /* Voice MIDI Checksum */

}

/*
 * Given a single voice, transform it into the structure used in banks.
 */
VoiceCompress(v, cv)
struct dx7voice *v;
struct Cdx7voice *cv;
{
	struct dx7operator *o;
	struct Cdx7operator *co;
	int i, j;

	/*
	 * Do 6 operators
	 */
	for (i = 0; i < 6; i++) {
		o = (struct dx7operator *) v->v_operator[i];
		co = (struct Cdx7operator *) cv->cv_operator[i];

		for (j = 0; j < 4; j++) { /* Envelope rate and levels */
			co->co_rate[j] = o->o_rate[j]; /* EG Rate */
			co->co_level[j] = o->o_level[j]; /* EG Level */
		}
		co->co_breakP = o->o_breakP; /* Keyboard Breakpoint */
		co->co_lDepth = o->o_lDepth; /* Keyboard Depth Left */
		co->co_rDepth = o->o_rDepth; /* Keyboard Depth Right */
		co->co_rlCurves = (o->o_lCurve & 0x03) | (o->o_rCurve << 2);
		co->co_dtr = (o->o_rates & 0x07) | (o->o_detune << 3);
		co->co_velsams = (o->o_sens & 0x03) | (o->o_velocity << 2);
		co->co_output = o->o_output; /* Output Level */
		co->co_mc = (o->o_oscMode & 0x01) | (o->o_Cfreq << 1);
		co->co_fine = o->o_Ffreq; /* Fine Frequency */
	}

	for (j = 0; j < 4; j++) {
		cv->cv_pRate[j] = v->v_pRate[j];	/* Pitch EG Rate */
		cv->cv_pLevel[j] = v->v_pLevel[j]; /* Pitch EG Level */
	}

	cv->cv_algorithm = v->v_algorithm; /* Algorithm */
	cv->cv_opSyncFeedback = (v->v_sync << 3) | (v->v_feedback & 0x07);
	cv->cv_lfoSpeed = v->v_lfoSpeed;	/* LFO Speed */
	cv->cv_lfoDelay = v->v_lfoDelay;	/* LFO Delay */
	cv->cv_lfoPmd = v->v_lfoPmd;	/* LFO PMD */
	cv->cv_lfoAmd = v->v_lfoAmd;	/* LFO AMD */
	cv->cv_PLL = (v->v_lfoSync & 0x01) | (v->v_lfoWave << 1)| (v->v_pSens << 4);

	cv->cv_transpose = v->v_transpose; /* Voice Transpose */
	strncpy(cv->cv_name, v->v_name, 10);	/* Voice Name */
}

/*
 * Calculate a DX7 checksum of a string of bytes "len" bytes long.
 */
CheckSum(p, len)
register char *p;
register int len;
{
	register int b = 0;

	while (len--)
		b += *p++;

	b = (0x80 - (0x7F & b));

	return (b);
}



