#include "kmsnddev.h" #include "divfix.h" #include "s_logtbl.h" #include "s_deltat.h" #include #define CPS_SHIFT 16 #define PHASE_SHIFT 16 /* 16(fix) */ typedef struct { KMIF_SOUND_DEVICE kmif; KMIF_LOGTABLE *logtbl; struct YMDELTATPCMSOUND_COMMON_TAG { Int32 mastervolume; Int32 step; Int32 output; Uint32 cnt; Uint32 cps; Uint32 phase; Uint32 deltan; Uint32 scale; Uint32 mem; Uint32 play; Uint32 start; Uint32 stop; Int32 level32; Uint8 key; Uint8 level; Uint8 granuality; Uint8 pad4_3; Uint8 regs[0x10]; } common; Uint8 *romrambuf; Uint32 romrammask; Uint8 *rambuf; Uint32 rammask; Uint8 *rombuf; Uint32 rommask; Uint8 ymdeltatpcm_type; Uint8 memshift; } YMDELTATPCMSOUND; static Uint8 const table_step[8] = { 1, 3, 5, 7, 9, 11, 13, 15, }; static Uint8 const table_scale[16] = { 57, 57, 57, 57, 77, 102, 128, 153, 57, 57, 57, 57, 77, 102, 128, 153, }; __inline static void writeram(YMDELTATPCMSOUND *sndp, Uint32 v) { sndp->rambuf[(sndp->common.mem >> 1) & sndp->rammask] = v; sndp->common.mem += 1 << 1; } __inline static Uint32 readram(YMDELTATPCMSOUND *sndp) { Uint32 v; v = sndp->romrambuf[(sndp->common.play >> 1) & sndp->romrammask]; if (sndp->common.play & 1) v &= 0x0F; else v >>= 4; sndp->common.play += 1; if (sndp->common.play >= sndp->common.stop) { if (sndp->common.regs[0] & 0x10) { sndp->common.play = sndp->common.start; sndp->common.step = 0; sndp->common.scale = 127; } else { sndp->common.key = 0; } } return v; } __inline static void DelrtatStep(YMDELTATPCMSOUND *sndp, Uint32 data) { if (data & 8) sndp->common.step -= (table_step[data & 7] * sndp->common.scale) >> 3; else sndp->common.step += (table_step[data & 7] * sndp->common.scale) >> 3; if (sndp->common.step > ((1 << 15) - 1)) sndp->common.step = ((1 << 15) - 1); if (sndp->common.step < -(1 << 15)) sndp->common.step = -(1 << 15); sndp->common.scale = (sndp->common.scale * table_scale[data]) >> 6; if (sndp->common.scale > 24576) sndp->common.scale = 24576; if (sndp->common.scale < 127) sndp->common.scale = 127; } #if (((-1) >> 1) == -1) #define SSR(x, y) (((Int32)x) >> (y)) #else #define SSR(x, y) (((x) >= 0) ? ((x) >> (y)) : (-((-(x) - 1) >> (y)) - 1)) #endif static int sndsynth(YMDELTATPCMSOUND *sndp ) { if (!sndp->common.key) return 0; { Uint32 step; sndp->common.cnt += sndp->common.cps; step = sndp->common.cnt >> CPS_SHIFT; sndp->common.cnt &= (1 << CPS_SHIFT) - 1; sndp->common.phase += step * sndp->common.deltan; step = sndp->common.phase >> PHASE_SHIFT; sndp->common.phase &= (1 << PHASE_SHIFT) - 1; if (step) { do { DelrtatStep(sndp, readram(sndp)); } while (--step); sndp->common.output = sndp->common.step * sndp->common.level32; sndp->common.output = SSR(sndp->common.output, 8 + 2); } } return sndp->common.output; } static void sndwrite(YMDELTATPCMSOUND *sndp, Uint32 a, Uint32 v) { sndp->common.regs[a] = v; switch (a) { /* START,REC,MEMDATA,REPEAT,SPOFF,--,--,RESET */ case 0x00: /* Control Register 1 */ if ((v & 0x80) && !sndp->common.key) { sndp->common.key = 1; sndp->common.play = sndp->common.start; sndp->common.step = 0; sndp->common.scale = 127; } if (v & 1) sndp->common.key = 0; break; /* L,R,-,-,SAMPLE,DA/AD,RAMTYPE,ROM */ case 0x01: /* Control Register 2 */ sndp->romrambuf = (sndp->common.regs[1] & 1) ? sndp->rombuf : sndp->rambuf; sndp->romrammask = (sndp->common.regs[1] & 1) ? sndp->rommask : sndp->rammask; break; case 0x02: /* Start Address L */ case 0x03: /* Start Address H */ sndp->common.granuality = (v & 2) ? 1 : 4; sndp->common.start = ((sndp->common.regs[3] << 8) + sndp->common.regs[2]) << (sndp->memshift + 1); sndp->common.mem = sndp->common.start; break; case 0x04: /* Stop Address L */ case 0x05: /* Stop Address H */ sndp->common.stop = ((sndp->common.regs[5] << 8) + sndp->common.regs[4]) << (sndp->memshift + 1); break; case 0x06: /* Prescale L */ case 0x07: /* Prescale H */ break; case 0x08: /* Data */ if ((sndp->common.regs[0] & 0x60) == 0x60) writeram(sndp, v); break; case 0x09: /* Delta-N L */ case 0x0A: /* Delta-N H */ sndp->common.deltan = (sndp->common.regs[0xA] << 8) + sndp->common.regs[0x9]; if (sndp->common.deltan < 0x100) sndp->common.deltan = 0x100; break; case 0x0B: /* Level Control */ sndp->common.level = v; sndp->common.level32 = ((Int32)(sndp->common.level * LogToLin(sndp->logtbl, sndp->common.mastervolume, LOG_LIN_BITS - 15))) >> 7; sndp->common.output = sndp->common.step * sndp->common.level32; sndp->common.output = SSR(sndp->common.output, 8 + 2); break; } } static Uint32 sndread(YMDELTATPCMSOUND *sndp, Uint32 a) { return 0; } static void sndreset(YMDELTATPCMSOUND *sndp, Uint32 clock, Uint32 freq) { XMEMSET(&sndp->common, 0, sizeof(sndp->common)); sndp->common.cps = DivFix(clock, 72 * freq, CPS_SHIFT); sndp->romrambuf = (sndp->common.regs[1] & 1) ? sndp->rombuf : sndp->rambuf; sndp->romrammask = (sndp->common.regs[1] & 1) ? sndp->rommask : sndp->rammask; sndp->common.granuality = 4; } static void sndvolume(YMDELTATPCMSOUND *sndp, Int32 volume) { volume = (volume << (LOG_BITS - 8)) << 1; sndp->common.mastervolume = volume; sndp->common.level32 = ((Int32)(sndp->common.level * LogToLin(sndp->logtbl, sndp->common.mastervolume, LOG_LIN_BITS - 15))) >> 7; sndp->common.output = sndp->common.step * sndp->common.level32; sndp->common.output = SSR(sndp->common.output, 8 + 2); } static void sndrelease(YMDELTATPCMSOUND *sndp) { if (sndp->logtbl) sndp->logtbl->release(sndp->logtbl->ctx); XFREE(sndp); } static void setinst(YMDELTATPCMSOUND *sndp, Uint32 n, void *p, Uint32 l) { if (n) return; if (p) { sndp->rombuf = (Uint8*) p; sndp->rommask = l - 1; sndp->romrambuf = (sndp->common.regs[1] & 1) ? sndp->rombuf : sndp->rambuf; sndp->romrammask = (sndp->common.regs[1] & 1) ? sndp->rommask : sndp->rammask; } else { sndp->rombuf = 0; sndp->rommask = 0; } } KMIF_SOUND_DEVICE *YMDELTATPCMSoundAlloc(Uint32 ymdeltatpcm_type) { Uint32 ram_size; YMDELTATPCMSOUND *sndp; switch (ymdeltatpcm_type) { case YMDELTATPCM_TYPE_Y8950: ram_size = 32 * 1024; break; case YMDELTATPCM_TYPE_YM2608: ram_size = 256 * 1024; break; default: ram_size = 0; break; } sndp = (YMDELTATPCMSOUND*) XMALLOC(sizeof(YMDELTATPCMSOUND) + ram_size); if (!sndp) return 0; sndp->ymdeltatpcm_type = ymdeltatpcm_type; switch (ymdeltatpcm_type) { case YMDELTATPCM_TYPE_Y8950: sndp->memshift = 2; break; case YMDELTATPCM_TYPE_YM2608: /* OPNA */ sndp->memshift = 6; break; case YMDELTATPCM_TYPE_YM2610: sndp->memshift = 9; break; } sndp->kmif.ctx = sndp; sndp->kmif.release = (void (*)( void* )) sndrelease; sndp->kmif.synth = (int (*)( void* )) sndsynth; sndp->kmif.volume = (void (*)( void*, int )) sndvolume; sndp->kmif.reset = (void (*)( void*, Uint32, Uint32 )) sndreset; sndp->kmif.write = (void (*)( void*, Uint32, Uint32 )) sndwrite; sndp->kmif.read = (Uint32 (*)( void*, Uint32 )) sndread; sndp->kmif.setinst = (void (*)( void*, Uint32, void*, Uint32 )) setinst; /* RAM */ sndp->rambuf = ram_size ? (Uint8 *)(sndp + 1) : 0; sndp->rammask = ram_size ? (ram_size - 1) : 0; /* ROM */ sndp->rombuf = 0; sndp->rommask = 0; sndp->logtbl = LogTableAddRef(); if (!sndp->logtbl) { sndrelease(sndp); return 0; } return &sndp->kmif; }