DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/snd_pc98/cbus/amd98.c
00001 #include        "compiler.h"
00002 #include        <math.h>
00003 #include        "pccore.h"
00004 #include        "iocore.h"
00005 #include        "cbuscore.h"
00006 #include        "amd98.h"
00007 #include        "sound.h"
00008 #include        "fmboard.h"
00009 
00010 
00011 // ないよりあったほーが良い程度のリズム…
00012 static struct {
00013         PMIXHDR hdr;
00014         PMIXTRK trk[4];
00015         UINT    rate;
00016         UINT    enable;
00017 } amd98r;
00018 
00019 
00020 static void pcmmake1(PMIXDAT *dat, UINT rate,
00021                                                                                         int vol, double hz, double env) {
00022 
00023         UINT    i;
00024         double  x;
00025         double  y;
00026         double  slast;
00027         double  s;
00028         double  v;
00029         UINT    size;
00030         SINT16  *ptr;
00031 
00032         x = 44100.0 * 2.0 * PI / ((double)rate * hz);
00033         y = 44100.0 / 256.0 / (double)rate;
00034         slast = 0.0;
00035         for (i=0; i<rate; i++) {
00036                 s = sin(x * (double)i);
00037                 v = pow(env, (double)i * y) * (double)vol;
00038                 if ((v < 128.0) && (slast < 0.0) && (s >= 0.0)) {
00039                         break;
00040                 }
00041                 slast = s;
00042         }
00043         size = i;
00044         if (!size) {
00045                 return;
00046         }
00047         ptr = (SINT16 *)_MALLOC(size * sizeof(SINT16), "AMD98");
00048         if (ptr == NULL) {
00049                 return;
00050         }
00051         for (i=0; i<size; i++) {
00052                 s = sin(x * (double)i);
00053                 v = pow(env, (double)i * y) * (double)vol;
00054                 ptr[i] = (SINT16)(s * v);
00055         }
00056         dat->sample = ptr;
00057         dat->samples = size;
00058 }
00059 
00060 static void pcmmake2(PMIXDAT *dat, UINT rate,
00061                                                                 int vol, double hz, double env, double k) {
00062 
00063         UINT    i;
00064         double  x;
00065         double  y;
00066         double  p;
00067         double  s;
00068         double  slast;
00069         double  v;
00070         UINT    size;
00071         SINT16  *ptr;
00072 
00073         x = 2.0 * PI * hz / (double)rate;
00074         y = 44100.0 / 256.0 / (double)rate;
00075         p = 0.0;
00076         slast = 0.0;
00077         for (i=0; i<rate; i++) {
00078                 p += x * pow(k, (double)i * y);
00079                 s = sin(p);
00080                 v = pow(env, (double)i * y) * (double)vol;
00081                 if ((v < 128.0) && (slast < 0.0) && (s >= 0.0)) {
00082                         break;
00083                 }
00084                 slast = s;
00085         }
00086         size = i;
00087         if (!size) {
00088                 return;
00089         }
00090         ptr = (SINT16 *)_MALLOC(size * sizeof(SINT16), "AMD98");
00091         if (ptr == NULL) {
00092                 return;
00093         }
00094         p = 0.0;
00095         for (i=0; i<size; i++) {
00096                 p += x * pow(k, (double)i * y);
00097                 s = sin(p);
00098                 v = pow(env, (double)i * y) * (double)vol;
00099                 ptr[i] = (SINT16)(s * v);
00100         }
00101         dat->sample = ptr;
00102         dat->samples = size;
00103 }
00104 
00105 
00106 void amd98_initialize(UINT rate) {
00107 
00108         ZeroMemory(&amd98r, sizeof(amd98r));
00109         amd98r.rate = rate;
00110 }
00111 
00112 void amd98_deinitialize(void) {
00113 
00114         int             i;
00115         void    *ptr;
00116 
00117         amd98r.hdr.enable = 0;
00118         for (i=0; i<4; i++) {
00119                 ptr = amd98r.trk[i].data.sample;
00120                 amd98r.trk[i].data.sample = NULL;
00121                 if (ptr) {
00122                         _MFREE(ptr);
00123                 }
00124         }
00125 }
00126 
00127 static void amd98_rhythmload(void) {
00128 
00129         UINT    i;
00130 
00131         if (!amd98r.hdr.enable) {
00132                 TRACEOUT(("AMD98 Rhythm load"));
00133                 amd98r.hdr.enable = 0x0f;
00134                 // bd
00135                 pcmmake1(&amd98r.trk[0].data, amd98r.rate,
00136                                                         24000, 889.0476190476, 0.9446717478);
00137                 // lt
00138                 pcmmake2(&amd98r.trk[1].data, amd98r.rate,
00139                                                         6400, 172.9411764706, 0.8665145391, 0.9960000000);
00140                 // ht
00141                 pcmmake2(&amd98r.trk[2].data, amd98r.rate,
00142                                                         9600, 213.0000000000, 0.8665145391, 0.9960000000);
00143                 // sd
00144                 pcmmake1(&amd98r.trk[3].data, amd98r.rate,
00145                                                         12000, 255.4400000000, 0.8538230481);
00146                 for (i=0; i<4; i++) {
00147                         amd98r.trk[i].flag = PMIXFLAG_L | PMIXFLAG_R;
00148                         amd98r.trk[i].volume = 1 << 12;
00149                 }
00150         }
00151 }
00152 
00153 
00154 // ----
00155 
00156 static void amd98_rhythm(UINT map) {
00157 
00158         PMIXTRK *trk;
00159         UINT    bit;
00160 
00161         map &= 0x0f;
00162         if (map == 0) {
00163                 return;
00164         }
00165         sound_sync();
00166         trk = amd98r.trk;
00167         bit = 0x01;
00168         do {
00169                 if ((map & bit) && (trk->data.sample)) {
00170                         trk->pcm = trk->data.sample;
00171                         trk->remain = trk->data.samples;
00172                         amd98r.hdr.playing |= bit;
00173                 }
00174                 trk++;
00175                 bit <<= 1;
00176         } while (bit < 0x10);
00177 }
00178 
00179 
00180 // ----
00181 
00182 static void setamd98event(UINT32 cnt, BOOL absolute) {
00183 
00184         if (cnt > 8) {                                                          // 根拠なし
00185                 cnt *= pccore.multiple;
00186         }
00187         else {
00188                 cnt = pccore.multiple << 16;
00189         }
00190         if (!(pccore.cpumode & CPUMODE_8MHZ)) {
00191                 cnt = cnt * 16 / 13;                                    // cnt * 2457600 / 1996800
00192         }
00193         nevent_set(NEVENT_MUSICGEN, cnt, amd98int, absolute);
00194 }
00195 
00196 void amd98int(NEVENTITEM item) {
00197 
00198         PITCH   pitch;
00199 
00200         if (item->flag & NEVENT_SETEVENT) {
00201                 pitch = pit.ch + 4;
00202                 if ((pitch->ctrl & 0x0c) == 0x04) {
00203                         // レートジェネレータ
00204                         setamd98event(pitch->value, NEVENT_RELATIVE);
00205                 }
00206         }
00207         pic_setirq(0x0d);
00208         (void)item;
00209 }
00210 
00211 
00212 // ----
00213 
00214 static void IOOUTCALL amd_od8(UINT port, REG8 dat) {
00215 
00216         opn.addr = dat;
00217         (void)port;
00218 }
00219 
00220 static void IOOUTCALL amd_od9(UINT port, REG8 dat) {
00221 
00222         opn.addr2 = dat;
00223         (void)port;
00224 }
00225 
00226 static void IOOUTCALL amd_oda(UINT port, REG8 dat) {
00227 
00228         UINT    addr;
00229 
00230         addr = opn.addr;
00231         if (addr < 0x0e) {
00232                 psggen_setreg(&psg1, addr, dat);
00233         }
00234         else if (addr == 0x0f) {
00235                 psg1.reg.io2 = dat;
00236         }
00237         (void)port;
00238 }
00239 
00240 static void IOOUTCALL amd_odb(UINT port, REG8 dat) {
00241 
00242         UINT    addr;
00243 
00244         addr = opn.addr2;
00245         if (addr < 0x0e) {
00246                 psggen_setreg(&psg2, addr, dat);
00247         }
00248         else if (addr == 0x0f) {
00249                 REG8 b;
00250                 b = psg2.reg.io2;
00251                 if ((b & 1) > (dat & 1)) {
00252                         b &= 0xc2;
00253                         if (b == 0x42) {
00254                                 amd98.psg3reg = psg1.reg.io2;
00255                         }
00256                         else if (b == 0x40) {
00257                                 if (amd98.psg3reg < 0x0e) {
00258                                         psggen_setreg(&psg3, amd98.psg3reg, psg1.reg.io2);
00259                                 }
00260                                 else if (amd98.psg3reg == 0x0f) {
00261                                         amd98_rhythm(psg1.reg.io2);
00262                                 }
00263                         }
00264                 }
00265                 psg2.reg.io2 = dat;
00266         }
00267         (void)port;
00268 }
00269 
00270 static void IOOUTCALL amd_odc(UINT port, REG8 dat) {
00271 
00272         PITCH   pitch;
00273 
00274         pitch = pit.ch + 4;
00275         if (pit_setcount(pitch, dat)) {
00276                 return;
00277         }
00278         setamd98event(pitch->value, NEVENT_ABSOLUTE);
00279         (void)port;
00280 }
00281 
00282 static void IOOUTCALL amd_ode(UINT port, REG8 dat) {
00283 
00284         pit_setflag(pit.ch + 4, dat);
00285         (void)port;
00286 }
00287 
00288 static REG8 IOINPCALL amd_ida(UINT port) {
00289 
00290         UINT    addr;
00291 
00292         addr = opn.addr;
00293         if (addr < 0x0e) {
00294                 return(psggen_getreg(&psg1, addr));
00295         }
00296         else if (addr == 0x0f) {
00297                 return(psg1.reg.io2);
00298         }
00299         (void)port;
00300         return(0xff);
00301 }
00302 
00303 static REG8 IOINPCALL amd_idb(UINT port) {
00304 
00305         UINT    addr;
00306 
00307         addr = opn.addr2;
00308         if (addr < 0x0e) {
00309                 return(psggen_getreg(&psg2, addr));
00310         }
00311         else if (addr == 0x0f) {
00312                 return(psg2.reg.io2);
00313         }
00314         (void)port;
00315         return(0xff);
00316 }
00317 
00318 #if defined(TRACE)
00319 static REG8 IOINPCALL amd_inp(UINT port) {
00320 
00321         TRACEOUT(("amd inp - %.4x", port));
00322         return(0xff);
00323 }
00324 #endif
00325 
00326 // ----
00327 
00328 static void psgpanset(PSGGEN psg) {
00329 
00330         psggen_setpan(psg, 0, 1);
00331         psggen_setpan(psg, 1, 0);
00332         psggen_setpan(psg, 2, 2);
00333 }
00334 
00335 void amd98_bind(void) {
00336 
00337         amd98_rhythmload();
00338 
00339         psgpanset(&psg1);
00340         psgpanset(&psg2);
00341         psgpanset(&psg3);
00342         psggen_restore(&psg1);
00343         psggen_restore(&psg2);
00344         psggen_restore(&psg3);
00345         sound_streamregist(&psg1, (SOUNDCB)psggen_getpcm);
00346         sound_streamregist(&psg2, (SOUNDCB)psggen_getpcm);
00347         sound_streamregist(&psg3, (SOUNDCB)psggen_getpcm);
00348         sound_streamregist(&amd98r, (SOUNDCB)pcmmix_getpcm);
00349         iocore_attachout(0xd8, amd_od8);
00350         iocore_attachout(0xd9, amd_od9);
00351         iocore_attachout(0xda, amd_oda);
00352         iocore_attachout(0xdb, amd_odb);
00353         iocore_attachout(0xdc, amd_odc);
00354         iocore_attachout(0xde, amd_ode);
00355 
00356         iocore_attachinp(0xda, amd_ida);
00357         iocore_attachinp(0xdb, amd_idb);
00358 #if defined(TRACE)
00359         iocore_attachinp(0xd8, amd_inp);
00360         iocore_attachinp(0xd9, amd_inp);
00361         iocore_attachinp(0xdc, amd_inp);
00362         iocore_attachinp(0xde, amd_inp);
00363 #endif
00364 }
00365