File:  [RetroPC.NET] / xmil / sound / opmgeng.c
Revision 1.3: download - view: text, annotated - select for diffs
Fri Feb 4 15:42:12 2005 JST (20 years, 8 months ago) by yui
Branches: MAIN
CVS tags: HEAD
RetroPC CVS restarting 2005/02/04 (T.Yui)

#include	"compiler.h"

#if defined(SUPPORT_TURBOZ) || defined(SUPPORT_OPM)

#include	"sound.h"
#include	"sndctrl.h"

extern	OPMCFG	opmcfg;

#define	CALCENV(e, c, s)													\
	(c)->slot[(s)].freq_cnt += (c)->slot[(s)].freq_inc;						\
	(c)->slot[(s)].env_cnt += (c)->slot[(s)].env_inc;						\
	if ((c)->slot[(s)].env_cnt >= (c)->slot[(s)].env_end) {					\
		switch((c)->slot[(s)].env_mode) {									\
			case EM_ATTACK:													\
				(c)->slot[(s)].env_mode = EM_DECAY1;						\
				(c)->slot[(s)].env_cnt = EC_DECAY;							\
				(c)->slot[(s)].env_end = (c)->slot[(s)].decaylevel;			\
				(c)->slot[(s)].env_inc = (c)->slot[(s)].env_inc_decay1;		\
				break;														\
			case EM_DECAY1:													\
				(c)->slot[(s)].env_mode = EM_DECAY2;						\
				(c)->slot[(s)].env_cnt = (c)->slot[(s)].decaylevel;			\
				(c)->slot[(s)].env_end = EC_OFF;							\
				(c)->slot[(s)].env_inc = (c)->slot[(s)].env_inc_decay2;		\
				break;														\
			case EM_RELEASE:												\
				(c)->slot[(s)].env_mode = EM_OFF;							\
			case EM_DECAY2:													\
				(c)->slot[(s)].env_cnt = EC_OFF;							\
				(c)->slot[(s)].env_end = EC_OFF + 1;						\
				(c)->slot[(s)].env_inc = 0;									\
				(c)->playing &= ~(1 << (s));								\
				break;														\
		}																	\
	}																		\
	(e) = (c)->slot[(s)].totallevel -										\
					opmcfg.envcurve[(c)->slot[(s)].env_cnt >> ENV_BITS];

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


static void calcratechannel(OPMCH *ch) {

	SINT32	envout;
	SINT32	opout;

	opmgen.feedback2 = 0;
	opmgen.feedback3 = 0;
	opmgen.feedback4 = 0;

	/* SLOT 1 */
	CALCENV(envout, ch, 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) {
			opmgen.feedback2 = opmgen.feedback3 = opmgen.feedback4 = opout;
		}
		else {
			*ch->connect1 += opout;
		}
	}
	/* SLOT 2 */
	CALCENV(envout, ch, 1);
	if (envout > 0) {
		*ch->connect2 += SLOTOUT(ch->slot[1], envout, opmgen.feedback2);
	}
	/* SLOT 3 */
	CALCENV(envout, ch, 2);
	if (envout > 0) {
		*ch->connect3 += SLOTOUT(ch->slot[2], envout, opmgen.feedback3);
	}
	/* SLOT 4 */
	CALCENV(envout, ch, 3);
	if (envout > 0) {
		*ch->connect4 += SLOTOUT(ch->slot[3], envout, opmgen.feedback4);
	}
}

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

	OPMCH	*ch;
	UINT	i;
	UINT	playing;
	SINT32	samp_l;
	SINT32	samp_r;

	if ((!opmgen.playing) || (!count)) {
		return;
	}
	ch = opmch;
	do {
		samp_l = opmgen.outdl * (opmgen.calcremain * -1);
		samp_r = opmgen.outdr * (opmgen.calcremain * -1);
		opmgen.calcremain += FMDIV_ENT;
		while(1) {
			opmgen.outdc = 0;
			opmgen.outdl = 0;
			opmgen.outdr = 0;
			playing = 0;
			for (i=0; i<OPMCH_MAX; i++) {
				if (ch[i].playing & ch[i].outslot) {
					calcratechannel(ch + i);
					playing++;
				}
			}
			opmgen.outdl += opmgen.outdc;
			opmgen.outdr += opmgen.outdc;
			opmgen.outdl >>= FMVOL_SFTBIT;
			opmgen.outdr >>= FMVOL_SFTBIT;
			if (opmgen.calcremain > opmcfg.calc1024) {
				samp_l += opmgen.outdl * opmcfg.calc1024;
				samp_r += opmgen.outdr * opmcfg.calc1024;
				opmgen.calcremain -= opmcfg.calc1024;
			}
			else {
				break;
			}
		}
		samp_l += opmgen.outdl * opmgen.calcremain;
		samp_l >>= 8;
		samp_l *= opmcfg.fmvol;
		samp_l >>= (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8);
		pcm[0] += samp_l;
		samp_r += opmgen.outdr * opmgen.calcremain;
		samp_r >>= 8;
		samp_r *= opmcfg.fmvol;
		samp_r >>= (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8);
		pcm[1] += samp_r;
		opmgen.calcremain -= opmcfg.calc1024;
		pcm += 2;
	} while(--count);
	opmgen.playing = playing;
	(void)hdl;
}

#endif

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