DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/snd_pc98/sound/opngeng.c
00001 #include    "np2glue.h"
00002 //#include      "compiler.h"
00003 //#include      "pccore.h"
00004 //#include      "iocore.h"
00005 #include        "sound.h"
00006 #include        "fmboard.h"
00007 
00008 
00009 #if defined(OPNGENX86)
00010 #error use opngen.x86
00011 #endif
00012 
00013 
00014 extern  OPNCFG  opncfg;
00015 
00016 
00017 #define CALCENV(e, c, s)                                                                                                        \
00018         (c)->slot[(s)].freq_cnt += (c)->slot[(s)].freq_inc;                                             \
00019         (c)->slot[(s)].env_cnt += (c)->slot[(s)].env_inc;                                               \
00020         if ((c)->slot[(s)].env_cnt >= (c)->slot[(s)].env_end) {                                 \
00021                 switch((c)->slot[(s)].env_mode) {                                                                       \
00022                         case EM_ATTACK:                                                                                                 \
00023                                 (c)->slot[(s)].env_mode = EM_DECAY1;                                            \
00024                                 (c)->slot[(s)].env_cnt = EC_DECAY;                                                      \
00025                                 (c)->slot[(s)].env_end = (c)->slot[(s)].decaylevel;                     \
00026                                 (c)->slot[(s)].env_inc = (c)->slot[(s)].env_inc_decay1;         \
00027                                 break;                                                                                                          \
00028                         case EM_DECAY1:                                                                                                 \
00029                                 (c)->slot[(s)].env_mode = EM_DECAY2;                                            \
00030                                 (c)->slot[(s)].env_cnt = (c)->slot[(s)].decaylevel;                     \
00031                                 (c)->slot[(s)].env_end = EC_OFF;                                                        \
00032                                 (c)->slot[(s)].env_inc = (c)->slot[(s)].env_inc_decay2;         \
00033                                 break;                                                                                                          \
00034                         case EM_RELEASE:                                                                                                \
00035                                 (c)->slot[(s)].env_mode = EM_OFF;                                                       \
00036                         case EM_DECAY2:                                                                                                 \
00037                                 (c)->slot[(s)].env_cnt = EC_OFF;                                                        \
00038                                 (c)->slot[(s)].env_end = EC_OFF + 1;                                            \
00039                                 (c)->slot[(s)].env_inc = 0;                                                                     \
00040                                 (c)->playing &= ~(1 << (s));                                                            \
00041                                 break;                                                                                                          \
00042                 }                                                                                                                                       \
00043         }                                                                                                                                               \
00044         (e) = (c)->slot[(s)].totallevel -                                                                               \
00045                                         opncfg.envcurve[(c)->slot[(s)].env_cnt >> ENV_BITS];
00046 
00047 #define SLOTOUT(s, e, c)                                                                                                        \
00048                 ((opncfg.sintable[(((s).freq_cnt + (c)) >>                                                      \
00049                                                         (FREQ_BITS - SIN_BITS)) & (SIN_ENT - 1)] *              \
00050                                 opncfg.envtable[(e)]) >> (ENVTBL_BIT+SINTBL_BIT-TL_BITS))
00051 
00052 
00053 static void calcratechannel(OPNCH *ch) {
00054 
00055         SINT32  envout;
00056         SINT32  opout;
00057 
00058         opngen.feedback2 = 0;
00059         opngen.feedback3 = 0;
00060         opngen.feedback4 = 0;
00061 
00062         /* SLOT 1 */
00063         CALCENV(envout, ch, 0);
00064         if (envout > 0) {
00065                 if (ch->feedback) {
00066                         /* with self feed back */
00067                         opout = ch->op1fb;
00068                         ch->op1fb = SLOTOUT(ch->slot[0], envout,
00069                                                                                         (ch->op1fb >> ch->feedback));
00070                         opout = (opout + ch->op1fb) / 2;
00071                 }
00072                 else {
00073                         /* without self feed back */
00074                         opout = SLOTOUT(ch->slot[0], envout, 0);
00075                 }
00076                 /* output slot1 */
00077                 if (!ch->connect1) {
00078                         opngen.feedback2 = opngen.feedback3 = opngen.feedback4 = opout;
00079                 }
00080                 else {
00081                         *ch->connect1 += opout;
00082                 }
00083         }
00084         /* SLOT 2 */
00085         CALCENV(envout, ch, 1);
00086         if (envout > 0) {
00087                 *ch->connect2 += SLOTOUT(ch->slot[1], envout, opngen.feedback2);
00088         }
00089         /* SLOT 3 */
00090         CALCENV(envout, ch, 2);
00091         if (envout > 0) {
00092                 *ch->connect3 += SLOTOUT(ch->slot[2], envout, opngen.feedback3);
00093         }
00094         /* SLOT 4 */
00095         CALCENV(envout, ch, 3);
00096         if (envout > 0) {
00097                 *ch->connect4 += SLOTOUT(ch->slot[3], envout, opngen.feedback4);
00098         }
00099 }
00100 
00101 void SOUNDCALL opngen_getpcm(void *hdl, SINT32 *pcm, UINT count) {
00102 
00103         OPNCH   *fm;
00104         UINT    i;
00105         UINT    playing;
00106         SINT32  samp_l;
00107         SINT32  samp_r;
00108 
00109         if ((!opngen.playing) || (!count)) {
00110                 return;
00111         }
00112         fm = opnch;
00113         do {
00114                 samp_l = opngen.outdl * (opngen.calcremain * -1);
00115                 samp_r = opngen.outdr * (opngen.calcremain * -1);
00116                 opngen.calcremain += FMDIV_ENT;
00117                 while(1) {
00118                         opngen.outdc = 0;
00119                         opngen.outdl = 0;
00120                         opngen.outdr = 0;
00121                         playing = 0;
00122                         for (i=0; i<opngen.playchannels; i++) {
00123                                 if (fm[i].playing & fm[i].outslot) {
00124                                         calcratechannel(fm + i);
00125                                         playing++;
00126                                 }
00127                         }
00128                         opngen.outdl += opngen.outdc;
00129                         opngen.outdr += opngen.outdc;
00130                         opngen.outdl >>= FMVOL_SFTBIT;
00131                         opngen.outdr >>= FMVOL_SFTBIT;
00132                         if (opngen.calcremain > opncfg.calc1024) {
00133                                 samp_l += opngen.outdl * opncfg.calc1024;
00134                                 samp_r += opngen.outdr * opncfg.calc1024;
00135                                 opngen.calcremain -= opncfg.calc1024;
00136                         }
00137                         else {
00138                                 break;
00139                         }
00140                 }
00141                 samp_l += opngen.outdl * opngen.calcremain;
00142                 samp_l >>= 8;
00143                 samp_l *= opncfg.fmvol;
00144                 samp_l >>= (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8);
00145                 pcm[0] += samp_l;
00146                 samp_r += opngen.outdr * opngen.calcremain;
00147                 samp_r >>= 8;
00148                 samp_r *= opncfg.fmvol;
00149                 samp_r >>= (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8);
00150                 pcm[1] += samp_r;
00151                 opngen.calcremain -= opncfg.calc1024;
00152                 pcm += 2;
00153         } while(--count);
00154         opngen.playing = playing;
00155         (void)hdl;
00156 }
00157 
00158 void SOUNDCALL opngen_getpcmvr(void *hdl, SINT32 *pcm, UINT count) {
00159 
00160         OPNCH   *fm;
00161         UINT    i;
00162         SINT32  samp_l;
00163         SINT32  samp_r;
00164 
00165         fm = opnch;
00166         while(count--) {
00167                 samp_l = opngen.outdl * (opngen.calcremain * -1);
00168                 samp_r = opngen.outdr * (opngen.calcremain * -1);
00169                 opngen.calcremain += FMDIV_ENT;
00170                 while(1) {
00171                         opngen.outdc = 0;
00172                         opngen.outdl = 0;
00173                         opngen.outdr = 0;
00174                         for (i=0; i<opngen.playchannels; i++) {
00175                                 calcratechannel(fm + i);
00176                         }
00177                         if (opncfg.vr_en) {
00178                                 SINT32 tmpl;
00179                                 SINT32 tmpr;
00180                                 tmpl = (opngen.outdl >> 5) * opncfg.vr_l;
00181                                 tmpr = (opngen.outdr >> 5) * opncfg.vr_r;
00182                                 opngen.outdl += tmpr;
00183                                 opngen.outdr += tmpl;
00184                         }
00185                         opngen.outdl += opngen.outdc;
00186                         opngen.outdr += opngen.outdc;
00187                         opngen.outdl >>= FMVOL_SFTBIT;
00188                         opngen.outdr >>= FMVOL_SFTBIT;
00189                         if (opngen.calcremain > opncfg.calc1024) {
00190                                 samp_l += opngen.outdl * opncfg.calc1024;
00191                                 samp_r += opngen.outdr * opncfg.calc1024;
00192                                 opngen.calcremain -= opncfg.calc1024;
00193                         }
00194                         else {
00195                                 break;
00196                         }
00197                 }
00198                 samp_l += opngen.outdl * opngen.calcremain;
00199                 samp_l >>= 8;
00200                 samp_l *= opncfg.fmvol;
00201                 samp_l >>= (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8);
00202                 pcm[0] += samp_l;
00203                 samp_r += opngen.outdr * opngen.calcremain;
00204                 samp_r >>= 8;
00205                 samp_r *= opncfg.fmvol;
00206                 samp_r >>= (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8);
00207                 pcm[1] += samp_r;
00208                 opngen.calcremain -= opncfg.calc1024;
00209                 pcm += 2;
00210         }
00211         (void)hdl;
00212 }
00213