#include "compiler.h"
#include "pccore.h"
#include "iocore.h"
#include "sound.h"
#include "fmboard.h"
#if defined(OPNGENX86)
#error use opngen.x86
#endif
extern OPNCFG opncfg;
#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 - \
opncfg.envcurve[(c)->slot[(s)].env_cnt >> ENV_BITS];
#define SLOTOUT(s, e, c) \
((opncfg.sintable[(((s).freq_cnt + (c)) >> \
(FREQ_BITS - SIN_BITS)) & (SIN_ENT - 1)] * \
opncfg.envtable[(e)]) >> (ENVTBL_BIT+SINTBL_BIT-TL_BITS))
static void calcratechannel(OPNCH *ch) {
SINT32 envout;
SINT32 opout;
opngen.feedback2 = 0;
opngen.feedback3 = 0;
opngen.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) {
opngen.feedback2 = opngen.feedback3 = opngen.feedback4 = opout;
}
else {
*ch->connect1 += opout;
}
}
/* SLOT 2 */
CALCENV(envout, ch, 1);
if (envout > 0) {
*ch->connect2 += SLOTOUT(ch->slot[1], envout, opngen.feedback2);
}
/* SLOT 3 */
CALCENV(envout, ch, 2);
if (envout > 0) {
*ch->connect3 += SLOTOUT(ch->slot[2], envout, opngen.feedback3);
}
/* SLOT 4 */
CALCENV(envout, ch, 3);
if (envout > 0) {
*ch->connect4 += SLOTOUT(ch->slot[3], envout, opngen.feedback4);
}
}
void SOUNDCALL opngen_getpcm(void *hdl, SINT32 *pcm, UINT count) {
OPNCH *fm;
UINT i;
UINT playing;
SINT32 samp_l;
SINT32 samp_r;
if ((!opngen.playing) || (!count)) {
return;
}
fm = opnch;
do {
samp_l = opngen.outdl * (opngen.calcremain * -1);
samp_r = opngen.outdr * (opngen.calcremain * -1);
opngen.calcremain += FMDIV_ENT;
while(1) {
opngen.outdc = 0;
opngen.outdl = 0;
opngen.outdr = 0;
playing = 0;
for (i=0; i<opngen.playchannels; i++) {
if (fm[i].playing & fm[i].outslot) {
calcratechannel(fm + i);
playing++;
}
}
opngen.outdl += opngen.outdc;
opngen.outdr += opngen.outdc;
opngen.outdl >>= FMVOL_SFTBIT;
opngen.outdr >>= FMVOL_SFTBIT;
if (opngen.calcremain > opncfg.calc1024) {
samp_l += opngen.outdl * opncfg.calc1024;
samp_r += opngen.outdr * opncfg.calc1024;
opngen.calcremain -= opncfg.calc1024;
}
else {
break;
}
}
samp_l += opngen.outdl * opngen.calcremain;
samp_l >>= 8;
samp_l *= opncfg.fmvol;
samp_l >>= (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8);
pcm[0] += samp_l;
samp_r += opngen.outdr * opngen.calcremain;
samp_r >>= 8;
samp_r *= opncfg.fmvol;
samp_r >>= (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8);
pcm[1] += samp_r;
opngen.calcremain -= opncfg.calc1024;
pcm += 2;
} while(--count);
opngen.playing = playing;
(void)hdl;
}
void SOUNDCALL opngen_getpcmvr(void *hdl, SINT32 *pcm, UINT count) {
OPNCH *fm;
UINT i;
SINT32 samp_l;
SINT32 samp_r;
fm = opnch;
while(count--) {
samp_l = opngen.outdl * (opngen.calcremain * -1);
samp_r = opngen.outdr * (opngen.calcremain * -1);
opngen.calcremain += FMDIV_ENT;
while(1) {
opngen.outdc = 0;
opngen.outdl = 0;
opngen.outdr = 0;
for (i=0; i<opngen.playchannels; i++) {
calcratechannel(fm + i);
}
if (opncfg.vr_en) {
SINT32 tmpl;
SINT32 tmpr;
tmpl = (opngen.outdl >> 5) * opncfg.vr_l;
tmpr = (opngen.outdr >> 5) * opncfg.vr_r;
opngen.outdl += tmpr;
opngen.outdr += tmpl;
}
opngen.outdl += opngen.outdc;
opngen.outdr += opngen.outdc;
opngen.outdl >>= FMVOL_SFTBIT;
opngen.outdr >>= FMVOL_SFTBIT;
if (opngen.calcremain > opncfg.calc1024) {
samp_l += opngen.outdl * opncfg.calc1024;
samp_r += opngen.outdr * opncfg.calc1024;
opngen.calcremain -= opncfg.calc1024;
}
else {
break;
}
}
samp_l += opngen.outdl * opngen.calcremain;
samp_l >>= 8;
samp_l *= opncfg.fmvol;
samp_l >>= (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8);
pcm[0] += samp_l;
samp_r += opngen.outdr * opngen.calcremain;
samp_r >>= 8;
samp_r *= opncfg.fmvol;
samp_r >>= (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8);
pcm[1] += samp_r;
opngen.calcremain -= opncfg.calc1024;
pcm += 2;
}
(void)hdl;
}
RetroPC.NET-CVS <cvs@retropc.net>