File:  [RetroPC.NET] / np2 / sound / opngeng.c
Revision 1.1: download - view: text, annotated - select for diffs
Fri Oct 17 02:58:04 2003 JST (22 years ago) by yui
Branches: MAIN
CVS tags: HEAD
Initial revision

#include	"compiler.h"
#include	"sound.h"
#include	"opngen.h"


extern	SINT32	env_curve[];				// ver0.27
extern	SINT32	envtable[];
extern	SINT32	sintable[];					// ver0.27

// opn work
extern	UINT	playchannels;
extern	SINT32	feedback2;
extern	SINT32	feedback3;
extern	SINT32	feedback4;
extern	SINT32	outdl;
extern	SINT32	outdc;
extern	SINT32	outdr;
extern	SINT32	calc1024;
extern	SINT32	calcremain;
extern	SINT32	fmvolforasm;
extern	SINT32	fmvolforc;


#define SLOTOUT(s, e, c)													\
		((sintable[(((s).freq_cnt + (c)) >> (FREQ_BITS - SIN_BITS)) &		\
			(SIN_ENT-1)] * envtable[(e)]) >> (ENVTBL_BIT+SINTBL_BIT-TL_BITS))

static SINT32 calcrateenvlope(OPNSLOT *slot) {

	/* calcrate phage generator */
	slot->freq_cnt += slot->freq_inc;
	/* calcrate envelope generator */
	slot->env_cnt += slot->env_inc;
	if (slot->env_cnt >= slot->env_end) {
		switch(slot->env_mode) {
			case EM_ATTACK:						// DECAY1 start
				slot->env_mode = EM_DECAY1;
				slot->env_cnt = EC_DECAY;
				slot->env_end = slot->decaylevel;
				slot->env_inc = slot->env_inc_decay1;
				break;

			case EM_DECAY1:						// DECAY2 start
				slot->env_mode = EM_DECAY2;
				slot->env_cnt = slot->decaylevel;
				slot->env_end = EC_OFF;
				slot->env_inc = slot->env_inc_decay2;
				break;

			case EM_RELEASE:					// OFF timing
				slot->env_mode = EM_OFF;

			case EM_DECAY2: 					// DECAY end
				slot->env_cnt = EC_OFF;
				slot->env_end = EC_OFF + 1;
				slot->env_inc = 0;
				break;
		}
	}
	return(slot->totallevel - env_curve[slot->env_cnt >> ENV_BITS]);
}

static void calcratechannel(OPNCH *ch) {

	SINT32	envout;
	SINT32	opout;

	feedback2 = 0;
	feedback3 = 0;
	feedback4 = 0;

	/* SLOT 1 */
	envout = calcrateenvlope(ch->slot + 0);
	if (envout > 0) {
		if (ch->feedback) {
			/* with self feed back */
			opout = ch->op1fb;
			ch->op1fb = SLOTOUT(ch->slot[0], envout,
											(ch->op1fb >> ch->feedback));
			opout = (opout + ch->op1fb) / 2;
		}
		else {
			/* without self feed back */
			opout = SLOTOUT(ch->slot[0], envout, 0);
		}
		/* output slot1 */
		if (!ch->connect1) {
			feedback2 = feedback3 = feedback4 = opout;
		}
		else {
			*ch->connect1 += opout;
		}
	}
	/* SLOT 2 */
	envout = calcrateenvlope(ch->slot + 1);
	if (envout > 0) {
		*ch->connect2 += SLOTOUT(ch->slot[1], envout, feedback2);
	}
	/* SLOT 3 */
	envout = calcrateenvlope(ch->slot + 2);
	if (envout > 0) {
		*ch->connect3 += SLOTOUT(ch->slot[2], envout, feedback3);
	}
	/* SLOT 4 */
	envout = calcrateenvlope(ch->slot + 3);
	if (envout > 0) {
		*ch->connect4 += SLOTOUT(ch->slot[3], envout, feedback4);
	}
}

void SOUNDCALL opngen_getpcm(void *hdl, SINT32 *pcm, UINT count) {

	OPNCH	*opn;
	UINT	i;
	SINT32	samp_l;
	SINT32	samp_r;

	opn = opnch;
	while(count--) {
		samp_l = outdl * (calcremain * -1);
		samp_r = outdr * (calcremain * -1);
		calcremain += FMDIV_ENT;
		while(1) {
			outdc = 0;
			outdl = 0;
			outdr = 0;
			for (i=0; i<playchannels; i++) {
				calcratechannel(opn + i);
			}
			outdl += outdc;
			outdr += outdc;
			outdl >>= FMVOL_SFTBIT;
			outdr >>= FMVOL_SFTBIT;
			if (calcremain > calc1024) {
				samp_l += outdl * calc1024;
				samp_r += outdr * calc1024;
				calcremain -= calc1024;
			}
			else {
				break;
			}
		}
		samp_l += outdl * calcremain;
		samp_l >>= 8;
		samp_l *= fmvolforc;
		samp_l >>= (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8);
		pcm[0] += samp_l;
		samp_r += outdr * calcremain;
		samp_r >>= FMDIV_BITS;
		samp_r *= fmvolforc;
		samp_r >>= (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8);
		pcm[1] += samp_r;
		calcremain -= calc1024;
		pcm += 2;
	}
	(void)hdl;
}


RetroPC.NET-CVS <cvs@retropc.net>