| version 1.6, 2003/12/08 00:55:30 | version 1.13, 2004/06/19 14:39:22 | 
| Line 1 | Line 1 | 
 | #include        "compiler.h" | #include        "compiler.h" | 
 |  | #include        <math.h> | 
 | #include        "pccore.h" | #include        "pccore.h" | 
 | #include        "iocore.h" | #include        "iocore.h" | 
 | #include        "cbuscore.h" | #include        "cbuscore.h" | 
| Line 7 | Line 8 | 
 | #include        "fmboard.h" | #include        "fmboard.h" | 
 |  |  | 
 |  |  | 
| static void setamd98event(BOOL absolute) { | // ないよりあったほーが良い程度のリズム… | 
|  | static struct { | 
|  | PMIXHDR hdr; | 
|  | PMIXTRK trk[4]; | 
|  | UINT    rate; | 
|  | UINT    enable; | 
|  | } amd98r; | 
|  |  | 
|  |  | 
|  | static void pcmmake1(PMIXDAT *dat, UINT rate, | 
|  | int vol, double hz, double env) { | 
|  |  | 
|  | UINT    i; | 
|  | double  x; | 
|  | double  y; | 
|  | double  slast; | 
|  | double  s; | 
|  | double  v; | 
|  | UINT    size; | 
|  | SINT16  *ptr; | 
|  |  | 
|  | x = 44100.0 * 2.0 * PI / ((double)rate * hz); | 
|  | y = 44100.0 / 256.0 / (double)rate; | 
|  | slast = 0.0; | 
|  | for (i=0; i<rate; i++) { | 
|  | s = sin(x * (double)i); | 
|  | v = pow(env, (double)i * y) * (double)vol; | 
|  | if ((v < 128.0) && (slast < 0.0) && (s >= 0.0)) { | 
|  | break; | 
|  | } | 
|  | slast = s; | 
|  | } | 
|  | size = i; | 
|  | if (!size) { | 
|  | return; | 
|  | } | 
|  | ptr = (SINT16 *)_MALLOC(size * sizeof(SINT16), "AMD98"); | 
|  | if (ptr == NULL) { | 
|  | return; | 
|  | } | 
|  | for (i=0; i<size; i++) { | 
|  | s = sin(x * (double)i); | 
|  | v = pow(env, (double)i * y) * (double)vol; | 
|  | ptr[i] = (SINT16)(s * v); | 
|  | } | 
|  | dat->sample = ptr; | 
|  | dat->samples = size; | 
|  | } | 
 |  |  | 
| SINT32  cnt; | static void pcmmake2(PMIXDAT *dat, UINT rate, | 
|  | int vol, double hz, double env, double k) { | 
 |  |  | 
| if (pit.value[3] > 8) {                                         // 根拠なし | UINT    i; | 
| cnt = pc.multiple * pit.value[3]; | double  x; | 
|  | double  y; | 
|  | double  p; | 
|  | double  s; | 
|  | double  slast; | 
|  | double  v; | 
|  | UINT    size; | 
|  | SINT16  *ptr; | 
|  |  | 
|  | x = 2.0 * PI * hz / (double)rate; | 
|  | y = 44100.0 / 256.0 / (double)rate; | 
|  | p = 0.0; | 
|  | slast = 0.0; | 
|  | for (i=0; i<rate; i++) { | 
|  | p += x * pow(k, (double)i * y); | 
|  | s = sin(p); | 
|  | v = pow(env, (double)i * y) * (double)vol; | 
|  | if ((v < 128.0) && (slast < 0.0) && (s >= 0.0)) { | 
|  | break; | 
|  | } | 
|  | slast = s; | 
|  | } | 
|  | size = i; | 
|  | if (!size) { | 
|  | return; | 
|  | } | 
|  | ptr = (SINT16 *)_MALLOC(size * sizeof(SINT16), "AMD98"); | 
|  | if (ptr == NULL) { | 
|  | return; | 
|  | } | 
|  | p = 0.0; | 
|  | for (i=0; i<size; i++) { | 
|  | p += x * pow(k, (double)i * y); | 
|  | s = sin(p); | 
|  | v = pow(env, (double)i * y) * (double)vol; | 
|  | ptr[i] = (SINT16)(s * v); | 
|  | } | 
|  | dat->sample = ptr; | 
|  | dat->samples = size; | 
|  | } | 
|  |  | 
|  |  | 
|  | void amd98_initialize(UINT rate) { | 
|  |  | 
|  | ZeroMemory(&amd98r, sizeof(amd98r)); | 
|  | amd98r.rate = rate; | 
|  | } | 
|  |  | 
|  | void amd98_deinitialize(void) { | 
|  |  | 
|  | int             i; | 
|  | void    *ptr; | 
|  |  | 
|  | amd98r.hdr.enable = 0; | 
|  | for (i=0; i<4; i++) { | 
|  | ptr = amd98r.trk[i].data.sample; | 
|  | amd98r.trk[i].data.sample = NULL; | 
|  | if (ptr) { | 
|  | _MFREE(ptr); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void amd98_rhythmload(void) { | 
|  |  | 
|  | UINT    i; | 
|  |  | 
|  | if (!amd98r.hdr.enable) { | 
|  | TRACEOUT(("AMD98 Rhythm load")); | 
|  | amd98r.hdr.enable = 0x0f; | 
|  | // bd | 
|  | pcmmake1(&amd98r.trk[0].data, amd98r.rate, | 
|  | 24000, 889.0476190476, 0.9446717478); | 
|  | // lt | 
|  | pcmmake2(&amd98r.trk[1].data, amd98r.rate, | 
|  | 6400, 172.9411764706, 0.8665145391, 0.9960000000); | 
|  | // ht | 
|  | pcmmake2(&amd98r.trk[2].data, amd98r.rate, | 
|  | 9600, 213.0000000000, 0.8665145391, 0.9960000000); | 
|  | // sd | 
|  | pcmmake1(&amd98r.trk[3].data, amd98r.rate, | 
|  | 12000, 255.4400000000, 0.8538230481); | 
|  | for (i=0; i<4; i++) { | 
|  | amd98r.trk[i].flag = PMIXFLAG_L | PMIXFLAG_R; | 
|  | amd98r.trk[i].volume = 1 << 12; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | // ---- | 
|  |  | 
|  | static void amd98_rhythm(UINT map) { | 
|  |  | 
|  | PMIXTRK *trk; | 
|  | UINT    bit; | 
|  |  | 
|  | map &= 0x0f; | 
|  | if (map == 0) { | 
|  | return; | 
|  | } | 
|  | sound_sync(); | 
|  | trk = amd98r.trk; | 
|  | bit = 0x01; | 
|  | do { | 
|  | if ((map & bit) && (trk->data.sample)) { | 
|  | trk->pcm = trk->data.sample; | 
|  | trk->remain = trk->data.samples; | 
|  | amd98r.hdr.playing |= bit; | 
|  | } | 
|  | trk++; | 
|  | bit <<= 1; | 
|  | } while (bit < 0x10); | 
|  | } | 
|  |  | 
|  |  | 
|  | // ---- | 
|  |  | 
|  | static void setamd98event(UINT32 cnt, BOOL absolute) { | 
|  |  | 
|  | if (cnt > 8) {                                                          // 根拠なし | 
|  | cnt *= pccore.multiple; | 
 | } | } | 
 | else { | else { | 
| cnt = pc.multiple << 16; | cnt = pccore.multiple << 16; | 
 | } | } | 
| if (pc.baseclock == PCBASECLOCK25) { | if (!(pccore.cpumode & CPUMODE_8MHZ)) { | 
 | cnt = cnt * 16 / 13;                                    // cnt * 2457600 / 1996800 | cnt = cnt * 16 / 13;                                    // cnt * 2457600 / 1996800 | 
 | } | } | 
 | nevent_set(NEVENT_MUSICGEN, cnt, amd98int, absolute); | nevent_set(NEVENT_MUSICGEN, cnt, amd98int, absolute); | 
| Line 25  static void setamd98event(BOOL absolute) | Line 195  static void setamd98event(BOOL absolute) | 
 |  |  | 
 | void amd98int(NEVENTITEM item) { | void amd98int(NEVENTITEM item) { | 
 |  |  | 
 |  | PITCH   pitch; | 
 |  |  | 
 | if (item->flag & NEVENT_SETEVENT) { | if (item->flag & NEVENT_SETEVENT) { | 
| if ((pit.mode[3] & 0x0c) == 0x04) { | pitch = pit.ch + 4; | 
|  | if ((pitch->ctrl & 0x0c) == 0x04) { | 
 | // レートジェネレータ | // レートジェネレータ | 
| setamd98event(NEVENT_RELATIVE); | setamd98event(pitch->value, NEVENT_RELATIVE); | 
 | } | } | 
 | } | } | 
 | pic_setirq(0x0d); | pic_setirq(0x0d); | 
| Line 72  static void IOOUTCALL amd_odb(UINT port, | Line 245  static void IOOUTCALL amd_odb(UINT port, | 
 | if ((b & 1) > (dat & 1)) { | if ((b & 1) > (dat & 1)) { | 
 | b &= 0xc2; | b &= 0xc2; | 
 | if (b == 0x42) { | if (b == 0x42) { | 
 | //                              TRACEOUT(0xfff0, psg_1.reg.io2); |  | 
 | amd98.psg3reg = psg1.reg.io2; | amd98.psg3reg = psg1.reg.io2; | 
 | } | } | 
 | else if (b == 0x40) { | else if (b == 0x40) { | 
 | //                              TRACEOUT(0xfff1, psg_1.reg.io2); |  | 
 | if (amd98.psg3reg < 0x0e) { | if (amd98.psg3reg < 0x0e) { | 
| psggen_setreg(&psg3, amd98.psg3reg, | psggen_setreg(&psg3, amd98.psg3reg, psg1.reg.io2); | 
| psg1.reg.io2); |  | 
 | } | } | 
 | else if (amd98.psg3reg == 0x0f) { | else if (amd98.psg3reg == 0x0f) { | 
| int r; | amd98_rhythm(psg1.reg.io2); | 
| static const BYTE amdr[] = {0x01, 0x08, 0x10, 0x20, 0x06, 0x40}; |  | 
| sound_sync(); |  | 
| for (r=0; r<6; r++) { |  | 
| if (psg1.reg.io2 & amdr[r]) { |  | 
| //                                                      rhythm_play(&rhythm, r, 0); |  | 
| } |  | 
| } |  | 
 | } | } | 
 | } | } | 
 | } | } | 
| Line 100  static const BYTE amdr[] = {0x01, 0x08, | Line 263  static const BYTE amdr[] = {0x01, 0x08, | 
 |  |  | 
 | static void IOOUTCALL amd_odc(UINT port, REG8 dat) { | static void IOOUTCALL amd_odc(UINT port, REG8 dat) { | 
 |  |  | 
| pit_setcount(3, dat); | PITCH   pitch; | 
| setamd98event(NEVENT_ABSOLUTE); |  | 
|  | pitch = pit.ch + 4; | 
|  | if (pit_setcount(pitch, dat)) { | 
|  | return; | 
|  | } | 
|  | setamd98event(pitch->value, NEVENT_ABSOLUTE); | 
 | (void)port; | (void)port; | 
 | } | } | 
 |  |  | 
 | static void IOOUTCALL amd_ode(UINT port, REG8 dat) { | static void IOOUTCALL amd_ode(UINT port, REG8 dat) { | 
 |  |  | 
| pit_setflag(3, dat); | pit_setflag(pit.ch + 4, dat); | 
|  | (void)port; | 
|  | } | 
|  |  | 
|  | static REG8 IOINPCALL amd_ida(UINT port) { | 
|  |  | 
|  | if (opn.opnreg < 0x0e) { | 
|  | return(psggen_getreg(&psg1, opn.opnreg)); | 
|  | } | 
|  | else if (opn.opnreg == 0x0f) { | 
|  | return(psg1.reg.io2); | 
|  | } | 
|  | (void)port; | 
|  | return(0xff); | 
|  | } | 
|  |  | 
|  | static REG8 IOINPCALL amd_idb(UINT port) { | 
|  |  | 
|  | if (opn.opnreg < 0x0e) { | 
|  | return(psggen_getreg(&psg2, opn.extreg)); | 
|  | } | 
|  | else if (opn.opnreg == 0x0f) { | 
|  | return(psg2.reg.io2); | 
|  | } | 
 | (void)port; | (void)port; | 
 |  | return(0xff); | 
 | } | } | 
 |  |  | 
 |  | static REG8 IOINPCALL amd_inp(UINT port) { | 
 |  |  | 
 |  | TRACEOUT(("amd inp - %.4x", port)); | 
 |  | return(0xff); | 
 |  | } | 
 |  |  | 
 | // ---- | // ---- | 
 |  |  | 
| Line 123  static void psgpanset(PSGGEN psg) { | Line 320  static void psgpanset(PSGGEN psg) { | 
 |  |  | 
 | void amd98_bind(void) { | void amd98_bind(void) { | 
 |  |  | 
 |  | amd98_rhythmload(); | 
 |  |  | 
 | psgpanset(&psg1); | psgpanset(&psg1); | 
 | psgpanset(&psg2); | psgpanset(&psg2); | 
 | psgpanset(&psg3); | psgpanset(&psg3); | 
 |  | psggen_restore(&psg1); | 
 |  | psggen_restore(&psg2); | 
 |  | psggen_restore(&psg3); | 
 | sound_streamregist(&psg1, (SOUNDCB)psggen_getpcm); | sound_streamregist(&psg1, (SOUNDCB)psggen_getpcm); | 
 | sound_streamregist(&psg2, (SOUNDCB)psggen_getpcm); | sound_streamregist(&psg2, (SOUNDCB)psggen_getpcm); | 
 | sound_streamregist(&psg3, (SOUNDCB)psggen_getpcm); | sound_streamregist(&psg3, (SOUNDCB)psggen_getpcm); | 
| //      sound_streamregist(&rhythm, (SOUNDCB)rhythm_getpcm); | sound_streamregist(&amd98r, (SOUNDCB)pcmmix_getpcm); | 
 | iocore_attachout(0xd8, amd_od8); | iocore_attachout(0xd8, amd_od8); | 
 | iocore_attachout(0xd9, amd_od9); | iocore_attachout(0xd9, amd_od9); | 
 | iocore_attachout(0xda, amd_oda); | iocore_attachout(0xda, amd_oda); | 
 | iocore_attachout(0xdb, amd_odb); | iocore_attachout(0xdb, amd_odb); | 
 | iocore_attachout(0xdc, amd_odc); | iocore_attachout(0xdc, amd_odc); | 
 | iocore_attachout(0xde, amd_ode); | iocore_attachout(0xde, amd_ode); | 
 |  |  | 
 |  | iocore_attachinp(0xda, amd_ida); | 
 |  | iocore_attachinp(0xdb, amd_idb); | 
 |  | #if defined(TRACE) | 
 |  | iocore_attachinp(0xd8, amd_inp); | 
 |  | iocore_attachinp(0xd9, amd_inp); | 
 |  | iocore_attachinp(0xdc, amd_inp); | 
 |  | iocore_attachinp(0xde, amd_inp); | 
 |  | #endif | 
 | } | } | 
 |  |  |