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 
00057         opngen.feedback2 = 0;
00058         opngen.feedback3 = 0;
00059         opngen.feedback4 = 0;
00060 
00061         /* SLOT 1 */
00062         CALCENV(envout, ch, 0);
00063         if (envout > 0) {
00064                 SINT32  opout;
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 
00107         if ((!opngen.playing) || (!count)) {
00108                 return;
00109         }
00110         fm = opnch;
00111         do {
00112                 SINT32 samp_l = opngen.outdl * (opngen.calcremain * -1);
00113                 SINT32 samp_r = opngen.outdr * (opngen.calcremain * -1);
00114                 opngen.calcremain += FMDIV_ENT;
00115                 while(1) {
00116                         opngen.outdc = 0;
00117                         opngen.outdl = 0;
00118                         opngen.outdr = 0;
00119                         playing = 0;
00120                         for (i=0; i<opngen.playchannels; i++) {
00121                                 if (fm[i].playing & fm[i].outslot) {
00122                                         calcratechannel(fm + i);
00123                                         playing++;
00124                                 }
00125                         }
00126                         opngen.outdl += opngen.outdc;
00127                         opngen.outdr += opngen.outdc;
00128                         opngen.outdl >>= FMVOL_SFTBIT;
00129                         opngen.outdr >>= FMVOL_SFTBIT;
00130                         if (opngen.calcremain > opncfg.calc1024) {
00131                                 samp_l += opngen.outdl * opncfg.calc1024;
00132                                 samp_r += opngen.outdr * opncfg.calc1024;
00133                                 opngen.calcremain -= opncfg.calc1024;
00134                         }
00135                         else {
00136                                 break;
00137                         }
00138                 }
00139                 samp_l += opngen.outdl * opngen.calcremain;
00140                 samp_l >>= 8;
00141                 samp_l *= opncfg.fmvol;
00142                 samp_l >>= (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8);
00143                 pcm[0] += samp_l;
00144                 samp_r += opngen.outdr * opngen.calcremain;
00145                 samp_r >>= 8;
00146                 samp_r *= opncfg.fmvol;
00147                 samp_r >>= (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8);
00148                 pcm[1] += samp_r;
00149                 opngen.calcremain -= opncfg.calc1024;
00150                 pcm += 2;
00151         } while(--count);
00152         opngen.playing = playing;
00153         (void)hdl;
00154 }
00155 
00156 void SOUNDCALL opngen_getpcmvr(void *hdl, SINT32 *pcm, UINT count) {
00157 
00158         OPNCH   *fm;
00159         UINT    i;
00160 
00161         fm = opnch;
00162         while(count--) {
00163                 SINT32 samp_l = opngen.outdl * (opngen.calcremain * -1);
00164                 SINT32 samp_r = opngen.outdr * (opngen.calcremain * -1);
00165                 opngen.calcremain += FMDIV_ENT;
00166                 while(1) {
00167                         opngen.outdc = 0;
00168                         opngen.outdl = 0;
00169                         opngen.outdr = 0;
00170                         for (i=0; i<opngen.playchannels; i++) {
00171                                 calcratechannel(fm + i);
00172                         }
00173                         if (opncfg.vr_en) {
00174                                 SINT32 tmpl;
00175                                 SINT32 tmpr;
00176                                 tmpl = (opngen.outdl >> 5) * opncfg.vr_l;
00177                                 tmpr = (opngen.outdr >> 5) * opncfg.vr_r;
00178                                 opngen.outdl += tmpr;
00179                                 opngen.outdr += tmpl;
00180                         }
00181                         opngen.outdl += opngen.outdc;
00182                         opngen.outdr += opngen.outdc;
00183                         opngen.outdl >>= FMVOL_SFTBIT;
00184                         opngen.outdr >>= FMVOL_SFTBIT;
00185                         if (opngen.calcremain > opncfg.calc1024) {
00186                                 samp_l += opngen.outdl * opncfg.calc1024;
00187                                 samp_r += opngen.outdr * opncfg.calc1024;
00188                                 opngen.calcremain -= opncfg.calc1024;
00189                         }
00190                         else {
00191                                 break;
00192                         }
00193                 }
00194                 samp_l += opngen.outdl * opngen.calcremain;
00195                 samp_l >>= 8;
00196                 samp_l *= opncfg.fmvol;
00197                 samp_l >>= (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8);
00198                 pcm[0] += samp_l;
00199                 samp_r += opngen.outdr * opngen.calcremain;
00200                 samp_r >>= 8;
00201                 samp_r *= opncfg.fmvol;
00202                 samp_r >>= (OPM_OUTSB + FMDIV_BITS + 1 + 6 - FMVOL_SFTBIT - 8);
00203                 pcm[1] += samp_r;
00204                 opngen.calcremain -= opncfg.calc1024;
00205                 pcm += 2;
00206         }
00207         (void)hdl;
00208 }
00209