#include <stdlib.h>\r
#include <string.h>\r
\r
-#include <common.h>\r
+#include "common.h"\r
#include "vgmSndDrv.h"\r
\r
\r
UINT32 vgmSmplPos;\r
UINT32 pbSmplPos;\r
VGM_FILE* file;\r
- \r
+\r
// oplChnMask:\r
// Music: mask of channels used/overridden by SFX\r
// SFX: ID of channel used by SFX (all commands are forces to it)\r
VGM_BASE_HDR vgmBaseHdr;\r
FILE* hFile;\r
UINT32 CurPos;\r
- \r
+\r
memset(vgmFile, 0x00, sizeof(VGM_FILE));\r
- \r
+\r
hFile = fopen(FileName, "rb");\r
if (hFile == NULL)\r
return 0xFF;\r
- \r
+\r
hdrSize = sizeof(VGM_BASE_HDR);\r
readEl = fread(&vgmBaseHdr, hdrSize, 0x01, hFile);\r
- if (readEl <= 0)\r
+ if (readEl == 0)\r
{\r
fclose(hFile);\r
return 0xFE; // read error\r
fclose(hFile);\r
return 0x81; // We don't support VGM v1.10 and earlier\r
}\r
- \r
+\r
vgmFile->dataLen = vgmBaseHdr.lngEOFOffset + 0x04;\r
vgmFile->data = (UINT8*)malloc(vgmFile->dataLen);\r
if (vgmFile->data == NULL)\r
//return 0xFE; // read error\r
vgmFile->dataLen = hdrSize + readEl;\r
}\r
- \r
+\r
fclose(hFile);\r
- \r
+\r
memcpy(&vgmFile->header, vgmFile->data, sizeof(VGM_HEADER));\r
- \r
+\r
// relative -> absolute addresses\r
vgmFile->header.lngEOFOffset += 0x04;\r
if (vgmFile->header.lngGD3Offset)\r
if (! vgmFile->header.lngDataOffset)\r
vgmFile->header.lngDataOffset = 0x0C;\r
vgmFile->header.lngDataOffset += 0x34;\r
- \r
+\r
CurPos = vgmFile->header.lngDataOffset;\r
if (vgmFile->header.lngVersion < 0x0150)\r
CurPos = 0x40;\r
hdrSize = sizeof(VGM_HEADER);\r
if (hdrSize > CurPos)\r
memset((UINT8*)&vgmFile->header + CurPos, 0x00, hdrSize - CurPos);\r
- \r
+\r
fclose(hFile);\r
return 0x00;\r
}\r
{\r
free(vgmFile->data); vgmFile->data = NULL;\r
vgmFile->dataLen = 0;\r
- \r
+\r
return;\r
}\r
\r
static bool DoVgmLoop(VGM_PBK* vgmPlay)\r
{\r
const VGM_HEADER* vgmHdr = &vgmPlay->file->header;\r
- \r
+\r
if (! vgmHdr->lngLoopOffset)\r
return false;\r
- \r
+\r
vgmPlay->curLoopCnt ++;\r
- \r
+\r
vgmPlay->vgmPos = vgmHdr->lngLoopOffset;\r
vgmPlay->vgmSmplPos -= vgmHdr->lngLoopSamples;\r
vgmPlay->pbSmplPos -= vgmHdr->lngLoopSamples;\r
- \r
+\r
return true;\r
}\r
\r
UINT8 Command;\r
UINT8 blockType;\r
UINT32 blockLen;\r
- \r
+\r
vgmPlay->pbSmplPos += Samples;\r
VGMPos = vgmPlay->vgmPos;\r
VGMSmplPos = vgmPlay->vgmSmplPos;\r
vgmPlay->vgmEnd = 0x01;\r
return;\r
}\r
- \r
+\r
if (VGMPos >= vgmLen)\r
vgmPlay->vgmEnd = 0x01;\r
}\r
vgmPlay->vgmSmplPos = VGMSmplPos;\r
if (vgmPlay->vgmEnd)\r
StopPlayback(vgmPlay);\r
- \r
+\r
return;\r
}\r
\r
{\r
UINT8 curSFX;\r
UINT8 curReg;\r
- \r
+\r
memset(oplRegs_Music, 0x00, 0x100);\r
memset(&vgmPbMusic, 0x00, sizeof(VGM_PBK));\r
vgmPbMusic.pbMode = PBMODE_MUSIC;\r
vgmPbMusic.vgmEnd = 0xFF;\r
vgmPbMusic.oplChnMask = 0x0000;\r
vgmPbMusic.oplRegCache = oplRegs_Music;\r
- \r
+\r
for (curSFX = 0; curSFX < SFX_CHN_COUNT; curSFX ++)\r
{\r
memset(&oplRegs_SFX[curSFX], 0x00, sizeof(VGM_PBK));\r
vgmPbSFX[curSFX].oplChnMask = curSFX;\r
vgmPbSFX[curSFX].oplRegCache = oplRegs_SFX[curSFX];\r
}\r
- \r
+\r
// reset OPL2 chip\r
curReg = 0x00;\r
do\r
curReg --;\r
OPL2_Write(curReg, 0x00);\r
} while(curReg > 0x20);\r
- \r
+\r
OPL2_Write(0x02, TIMER1_RATE); // set Timer 1 Period\r
OPL2_Write(0x04, 0x01); // Timer 1 on/unmasked, Timer 2 off\r
OPL2_Write(0x04, 0x80); // Reset Timer/IRQ Status Flags\r
- \r
+\r
OPL2_Write(0x01, 0x20); // Waveform Select: Enable\r
- \r
+\r
return;\r
}\r
\r
void DeinitEngine(void)\r
{\r
UINT8 curSFX;\r
- \r
+\r
StopPlayback(&vgmPbMusic);\r
for (curSFX = 0; curSFX < SFX_CHN_COUNT; curSFX ++)\r
StopPlayback(&vgmPbSFX[curSFX]);\r
- \r
+\r
OPL2_Write(0x04, 0x00); // disable all timers\r
- \r
+\r
return;\r
}\r
\r
UINT8 PlayMusic(VGM_FILE* vgmFile)\r
{\r
VGM_PBK* vgmPb = &vgmPbMusic;\r
- \r
+\r
if (! vgmPb->vgmEnd)\r
StopPlayback(vgmPb);\r
- \r
+\r
vgmPb->file = vgmFile;\r
- \r
+\r
StartPlayback(vgmPb);\r
- \r
+\r
return 0x00;\r
}\r
\r
UINT8 PlaySFX(VGM_FILE* vgmFile, UINT8 sfxChnID)\r
{\r
VGM_PBK* vgmPb;\r
- \r
+\r
if (sfxChnID >= SFX_CHN_COUNT)\r
return 0xFF;\r
- \r
+\r
vgmPb = &vgmPbSFX[sfxChnID];\r
- \r
+\r
if (! vgmPb->vgmEnd)\r
StopPlayback(vgmPb);\r
- \r
+\r
vgmPb->file = vgmFile;\r
- \r
+\r
StartPlayback(vgmPb);\r
- \r
+\r
return 0x00;\r
}\r
\r
StopPlayback(&vgmPbSFX[sfxChnID]);\r
return 0x00;\r
}\r
- \r
+\r
if (sfxChnID >= SFX_CHN_COUNT)\r
return 0xFF;\r
- \r
+\r
StopPlayback(&vgmPbSFX[sfxChnID]);\r
return 0x00;\r
}\r
return 0x80; // finished playing already\r
if (vgmPbMusic.vgmEnd == 0x02)\r
return 0x01; // is already paused\r
- \r
+\r
StopPlayback(&vgmPbMusic);\r
vgmPbMusic.vgmEnd = 0x02;\r
- \r
+\r
return 0x00;\r
}\r
\r
return 0x80; // finished playing already\r
if (! (vgmPbMusic.vgmEnd & 0x02))\r
return 0x01; // is not paused\r
- \r
+\r
vgmPbMusic.vgmEnd &= ~0x02;\r
- \r
+\r
return 0x00;\r
}\r
\r
vgmPb->vgmEnd = 0xFF;\r
return;\r
}\r
- \r
+\r
vgmPb->vgmEnd = 0x00; // set to 'running'\r
vgmPb->vgmPos = vgmPb->file->header.lngDataOffset;\r
vgmPb->vgmSmplPos = 0;\r
vgmPb->pbSmplPos = 0;\r
vgmPb->curLoopCnt = 0;\r
memset(vgmPb->workRAM, 0x00, 0x04);\r
- \r
+\r
if (vgmPb->pbMode == PBMODE_SFX)\r
{\r
UINT8 curReg;\r
- \r
+\r
curReg = 0xB0 | vgmPb->oplChnMask;\r
if (oplRegs_Music[curReg] & 0x20)\r
OPL2_Write(curReg, oplRegs_Music[curReg] & ~0x20); // send Key Off\r
- \r
+\r
vgmPbMusic.oplChnMask |= (1 << vgmPb->oplChnMask); // mask out music channel\r
}\r
- \r
+\r
return;\r
}\r
\r
{\r
if (vgmPb->vgmEnd & 0x80)\r
return;\r
- \r
+\r
if (vgmPb->pbMode == PBMODE_MUSIC)\r
{\r
UINT8 curReg;\r
UINT16 chnMask;\r
- \r
+\r
chnMask = 0x0001;\r
for (curReg = 0xB0; curReg < 0xB9; curReg ++, chnMask <<= 1)\r
{\r
vgmPb->oplRegCache[curReg] &= ~0x1F;\r
OPL2_Write(curReg, vgmPb->oplRegCache[curReg]); // send Key Off\r
}\r
- \r
+\r
vgmPb->vgmEnd = 0x01;\r
}\r
else //if (vgmPb->pbMode == PBMODE_SFX)\r
UINT8 regID;\r
UINT8 curReg;\r
UINT8 opMask;\r
- \r
+\r
curReg = 0xB0 | vgmPb->oplChnMask;\r
if (vgmPb->oplRegCache[0x0C] & 0x20)\r
{\r
vgmPb->oplRegCache[0x0C] &= ~0x20;\r
OPL2_Write(curReg, vgmPb->oplRegCache[0x0C]); // send Key Off\r
}\r
- \r
+\r
vgmPb->vgmEnd = 0x01;\r
- \r
+\r
if (! vgmPbMusic.vgmEnd) // if (music is playing)\r
{\r
opMask = CHN_OPMASK[vgmPb->oplChnMask];\r
curReg = SFX_REGS[regID] | vgmPb->oplChnMask;\r
OPL2_Write(curReg, oplRegs_Music[curReg]); // restore Music register\r
}\r
- \r
+\r
vgmPbMusic.oplChnMask &= ~(1 << vgmPb->oplChnMask);\r
}\r
}\r
- \r
+\r
return;\r
}\r
\r
{\r
UINT8 regChn;\r
UINT8 ramOfs;\r
- \r
+\r
if (vgmPb->pbMode == PBMODE_MUSIC)\r
{\r
if (reg == 0x01)\r
data |= 0x20; // enforce "Waveform Select Enable" bit\r
vgmPb->oplRegCache[reg] = data;\r
- \r
+\r
ramOfs = SFX_REGS_REV[reg >> 4];\r
if (ramOfs < 0x0A) // Operator 20/40/60/80/E0\r
{\r
{\r
if (reg == 0xBD)\r
return; // no rhythm register for SFX\r
- \r
+\r
ramOfs = SFX_REGS_REV[reg >> 4];\r
if (ramOfs == 0xFF)\r
return;\r
- \r
+\r
if (ramOfs < 0x0A) // Operator 20/40/60/80/E0\r
{\r
regChn = CHN_OPMASK_REV[reg & 0x1F];\r
ramOfs += (regChn & 0x80) >> 7;\r
regChn &= 0x7F;\r
vgmPb->oplRegCache[ramOfs] = data;\r
- \r
+\r
if (regChn != vgmPb->oplChnMask)\r
{\r
// force command to current channel\r
if (regChn >= 0x09)\r
return; // ignore writes to invalid channels\r
vgmPb->oplRegCache[ramOfs] = data;\r
- \r
+\r
reg = (reg & 0xF0) | vgmPb->oplChnMask;\r
}\r
}\r
- \r
+\r
OPL2_Write(reg, data);\r
return;\r
}\r
if (! vgmPb->workRAM[0x00]) // "Wave Select Enable" off?\r
data = 0x00; // disable waveforms\r
}\r
- \r
+\r
OPL_CachedWrite(vgmPb, reg, data);\r
return;\r
}\r
else\r
return; // ignore Y8950 DeltaT writes\r
}\r
- \r
+\r
OPL_CachedWrite(vgmPb, reg, data);\r
return;\r
}\r
{\r
UINT8 tmrMask;\r
UINT8 curSFX;\r
- \r
+\r
tmrMask = OPL2_ReadStatus();\r
if (! (tmrMask & 0x40))\r
return; // wait for overflow\r
OPL2_Write(0x04, 0x80); // Reset Timer/IRQ Status Flags\r
- \r
+\r
if (! vgmPbMusic.vgmEnd)\r
UpdateVGM(&vgmPbMusic, VGM_UPD_RATE);\r
for (curSFX = 0; curSFX < SFX_CHN_COUNT; curSFX ++)\r
if (! vgmPbSFX[curSFX].vgmEnd)\r
UpdateVGM(&vgmPbSFX[curSFX], VGM_UPD_RATE);\r
}\r
- \r
+\r
return;\r
}\r