DOSBox-X
|
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