new file: 16/vgmsnd/common.h
modified: 16/vgmsnd/stdtype.h
modified: 16/vgmsnd/vgmSndDrv.c
modified: 16/vgmsnd/vgmSndDrv.h
--- /dev/null
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#include "stdtype.h"
+#include "stdbool.h"
+
+#ifndef INLINE
+#if defined(_MSC_VER)
+#define INLINE static __inline // __forceinline
+#elif defined(__GNUC__)
+#define INLINE static __inline__
+#else
+#define INLINE static inline
+#endif
+#endif // INLINE
+
+#endif // __COMMON_H__
\r
// 64-bit values\r
#ifdef _MSC_VER\r
\r
// 64-bit values\r
#ifdef _MSC_VER\r
-typedef unsigned __int64 UINT64;\r
-typedef signed __int64 INT64;\r
+//typedef unsigned __int64 UINT64;\r
+//typedef signed __int64 INT64;\r
-__extension__ typedef unsigned long long UINT64;\r
-__extension__ typedef signed long long INT64;\r
+//__extension__ typedef unsigned long long UINT64;\r
+//__extension__ typedef signed long long INT64;\r
#endif\r
#endif // _WINDOWS_H\r
\r
#endif\r
#endif // _WINDOWS_H\r
\r
#include <stdlib.h>\r
#include <string.h>\r
\r
#include <stdlib.h>\r
#include <string.h>\r
\r
#include "vgmSndDrv.h"\r
\r
\r
#include "vgmSndDrv.h"\r
\r
\r
UINT32 vgmSmplPos;\r
UINT32 pbSmplPos;\r
VGM_FILE* file;\r
UINT32 vgmSmplPos;\r
UINT32 pbSmplPos;\r
VGM_FILE* file;\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
// 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
VGM_BASE_HDR vgmBaseHdr;\r
FILE* hFile;\r
UINT32 CurPos;\r
memset(vgmFile, 0x00, sizeof(VGM_FILE));\r
memset(vgmFile, 0x00, sizeof(VGM_FILE));\r
hFile = fopen(FileName, "rb");\r
if (hFile == NULL)\r
return 0xFF;\r
hFile = fopen(FileName, "rb");\r
if (hFile == NULL)\r
return 0xFF;\r
hdrSize = sizeof(VGM_BASE_HDR);\r
readEl = fread(&vgmBaseHdr, hdrSize, 0x01, hFile);\r
hdrSize = sizeof(VGM_BASE_HDR);\r
readEl = fread(&vgmBaseHdr, hdrSize, 0x01, hFile);\r
{\r
fclose(hFile);\r
return 0xFE; // read error\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
fclose(hFile);\r
return 0x81; // We don't support VGM v1.10 and earlier\r
}\r
vgmFile->dataLen = vgmBaseHdr.lngEOFOffset + 0x04;\r
vgmFile->data = (UINT8*)malloc(vgmFile->dataLen);\r
if (vgmFile->data == NULL)\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
//return 0xFE; // read error\r
vgmFile->dataLen = hdrSize + readEl;\r
}\r
memcpy(&vgmFile->header, vgmFile->data, sizeof(VGM_HEADER));\r
memcpy(&vgmFile->header, vgmFile->data, sizeof(VGM_HEADER));\r
// relative -> absolute addresses\r
vgmFile->header.lngEOFOffset += 0x04;\r
if (vgmFile->header.lngGD3Offset)\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
if (! vgmFile->header.lngDataOffset)\r
vgmFile->header.lngDataOffset = 0x0C;\r
vgmFile->header.lngDataOffset += 0x34;\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
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
fclose(hFile);\r
return 0x00;\r
}\r
fclose(hFile);\r
return 0x00;\r
}\r
{\r
free(vgmFile->data); vgmFile->data = NULL;\r
vgmFile->dataLen = 0;\r
{\r
free(vgmFile->data); vgmFile->data = NULL;\r
vgmFile->dataLen = 0;\r
static bool DoVgmLoop(VGM_PBK* vgmPlay)\r
{\r
const VGM_HEADER* vgmHdr = &vgmPlay->file->header;\r
static bool DoVgmLoop(VGM_PBK* vgmPlay)\r
{\r
const VGM_HEADER* vgmHdr = &vgmPlay->file->header;\r
if (! vgmHdr->lngLoopOffset)\r
return false;\r
if (! vgmHdr->lngLoopOffset)\r
return false;\r
vgmPlay->curLoopCnt ++;\r
vgmPlay->curLoopCnt ++;\r
vgmPlay->vgmPos = vgmHdr->lngLoopOffset;\r
vgmPlay->vgmSmplPos -= vgmHdr->lngLoopSamples;\r
vgmPlay->pbSmplPos -= vgmHdr->lngLoopSamples;\r
vgmPlay->vgmPos = vgmHdr->lngLoopOffset;\r
vgmPlay->vgmSmplPos -= vgmHdr->lngLoopSamples;\r
vgmPlay->pbSmplPos -= vgmHdr->lngLoopSamples;\r
UINT8 Command;\r
UINT8 blockType;\r
UINT32 blockLen;\r
UINT8 Command;\r
UINT8 blockType;\r
UINT32 blockLen;\r
vgmPlay->pbSmplPos += Samples;\r
VGMPos = vgmPlay->vgmPos;\r
VGMSmplPos = vgmPlay->vgmSmplPos;\r
vgmPlay->pbSmplPos += Samples;\r
VGMPos = vgmPlay->vgmPos;\r
VGMSmplPos = vgmPlay->vgmSmplPos;\r
vgmPlay->vgmEnd = 0x01;\r
return;\r
}\r
vgmPlay->vgmEnd = 0x01;\r
return;\r
}\r
if (VGMPos >= vgmLen)\r
vgmPlay->vgmEnd = 0x01;\r
}\r
if (VGMPos >= vgmLen)\r
vgmPlay->vgmEnd = 0x01;\r
}\r
vgmPlay->vgmSmplPos = VGMSmplPos;\r
if (vgmPlay->vgmEnd)\r
StopPlayback(vgmPlay);\r
vgmPlay->vgmSmplPos = VGMSmplPos;\r
if (vgmPlay->vgmEnd)\r
StopPlayback(vgmPlay);\r
{\r
UINT8 curSFX;\r
UINT8 curReg;\r
{\r
UINT8 curSFX;\r
UINT8 curReg;\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
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
for (curSFX = 0; curSFX < SFX_CHN_COUNT; curSFX ++)\r
{\r
memset(&oplRegs_SFX[curSFX], 0x00, sizeof(VGM_PBK));\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
vgmPbSFX[curSFX].oplChnMask = curSFX;\r
vgmPbSFX[curSFX].oplRegCache = oplRegs_SFX[curSFX];\r
}\r
// reset OPL2 chip\r
curReg = 0x00;\r
do\r
// reset OPL2 chip\r
curReg = 0x00;\r
do\r
curReg --;\r
OPL2_Write(curReg, 0x00);\r
} while(curReg > 0x20);\r
curReg --;\r
OPL2_Write(curReg, 0x00);\r
} while(curReg > 0x20);\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
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
OPL2_Write(0x01, 0x20); // Waveform Select: Enable\r
OPL2_Write(0x01, 0x20); // Waveform Select: Enable\r
return;\r
}\r
\r
void DeinitEngine(void)\r
{\r
UINT8 curSFX;\r
return;\r
}\r
\r
void DeinitEngine(void)\r
{\r
UINT8 curSFX;\r
StopPlayback(&vgmPbMusic);\r
for (curSFX = 0; curSFX < SFX_CHN_COUNT; curSFX ++)\r
StopPlayback(&vgmPbSFX[curSFX]);\r
StopPlayback(&vgmPbMusic);\r
for (curSFX = 0; curSFX < SFX_CHN_COUNT; curSFX ++)\r
StopPlayback(&vgmPbSFX[curSFX]);\r
OPL2_Write(0x04, 0x00); // disable all timers\r
OPL2_Write(0x04, 0x00); // disable all timers\r
UINT8 PlayMusic(VGM_FILE* vgmFile)\r
{\r
VGM_PBK* vgmPb = &vgmPbMusic;\r
UINT8 PlayMusic(VGM_FILE* vgmFile)\r
{\r
VGM_PBK* vgmPb = &vgmPbMusic;\r
if (! vgmPb->vgmEnd)\r
StopPlayback(vgmPb);\r
if (! vgmPb->vgmEnd)\r
StopPlayback(vgmPb);\r
return 0x00;\r
}\r
\r
UINT8 PlaySFX(VGM_FILE* vgmFile, UINT8 sfxChnID)\r
{\r
VGM_PBK* vgmPb;\r
return 0x00;\r
}\r
\r
UINT8 PlaySFX(VGM_FILE* vgmFile, UINT8 sfxChnID)\r
{\r
VGM_PBK* vgmPb;\r
if (sfxChnID >= SFX_CHN_COUNT)\r
return 0xFF;\r
if (sfxChnID >= SFX_CHN_COUNT)\r
return 0xFF;\r
vgmPb = &vgmPbSFX[sfxChnID];\r
vgmPb = &vgmPbSFX[sfxChnID];\r
if (! vgmPb->vgmEnd)\r
StopPlayback(vgmPb);\r
if (! vgmPb->vgmEnd)\r
StopPlayback(vgmPb);\r
StopPlayback(&vgmPbSFX[sfxChnID]);\r
return 0x00;\r
}\r
StopPlayback(&vgmPbSFX[sfxChnID]);\r
return 0x00;\r
}\r
if (sfxChnID >= SFX_CHN_COUNT)\r
return 0xFF;\r
if (sfxChnID >= SFX_CHN_COUNT)\r
return 0xFF;\r
StopPlayback(&vgmPbSFX[sfxChnID]);\r
return 0x00;\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
return 0x80; // finished playing already\r
if (vgmPbMusic.vgmEnd == 0x02)\r
return 0x01; // is already paused\r
StopPlayback(&vgmPbMusic);\r
vgmPbMusic.vgmEnd = 0x02;\r
StopPlayback(&vgmPbMusic);\r
vgmPbMusic.vgmEnd = 0x02;\r
return 0x80; // finished playing already\r
if (! (vgmPbMusic.vgmEnd & 0x02))\r
return 0x01; // is not paused\r
return 0x80; // finished playing already\r
if (! (vgmPbMusic.vgmEnd & 0x02))\r
return 0x01; // is not paused\r
vgmPbMusic.vgmEnd &= ~0x02;\r
vgmPbMusic.vgmEnd &= ~0x02;\r
vgmPb->vgmEnd = 0xFF;\r
return;\r
}\r
vgmPb->vgmEnd = 0xFF;\r
return;\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
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
if (vgmPb->pbMode == PBMODE_SFX)\r
{\r
UINT8 curReg;\r
if (vgmPb->pbMode == PBMODE_SFX)\r
{\r
UINT8 curReg;\r
curReg = 0xB0 | vgmPb->oplChnMask;\r
if (oplRegs_Music[curReg] & 0x20)\r
OPL2_Write(curReg, oplRegs_Music[curReg] & ~0x20); // send Key Off\r
curReg = 0xB0 | vgmPb->oplChnMask;\r
if (oplRegs_Music[curReg] & 0x20)\r
OPL2_Write(curReg, oplRegs_Music[curReg] & ~0x20); // send Key Off\r
vgmPbMusic.oplChnMask |= (1 << vgmPb->oplChnMask); // mask out music channel\r
}\r
vgmPbMusic.oplChnMask |= (1 << vgmPb->oplChnMask); // mask out music channel\r
}\r
{\r
if (vgmPb->vgmEnd & 0x80)\r
return;\r
{\r
if (vgmPb->vgmEnd & 0x80)\r
return;\r
if (vgmPb->pbMode == PBMODE_MUSIC)\r
{\r
UINT8 curReg;\r
UINT16 chnMask;\r
if (vgmPb->pbMode == PBMODE_MUSIC)\r
{\r
UINT8 curReg;\r
UINT16 chnMask;\r
chnMask = 0x0001;\r
for (curReg = 0xB0; curReg < 0xB9; curReg ++, chnMask <<= 1)\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
vgmPb->oplRegCache[curReg] &= ~0x1F;\r
OPL2_Write(curReg, vgmPb->oplRegCache[curReg]); // send Key Off\r
}\r
vgmPb->vgmEnd = 0x01;\r
}\r
else //if (vgmPb->pbMode == PBMODE_SFX)\r
vgmPb->vgmEnd = 0x01;\r
}\r
else //if (vgmPb->pbMode == PBMODE_SFX)\r
UINT8 regID;\r
UINT8 curReg;\r
UINT8 opMask;\r
UINT8 regID;\r
UINT8 curReg;\r
UINT8 opMask;\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
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
if (! vgmPbMusic.vgmEnd) // if (music is playing)\r
{\r
opMask = CHN_OPMASK[vgmPb->oplChnMask];\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
curReg = SFX_REGS[regID] | vgmPb->oplChnMask;\r
OPL2_Write(curReg, oplRegs_Music[curReg]); // restore Music register\r
}\r
vgmPbMusic.oplChnMask &= ~(1 << vgmPb->oplChnMask);\r
}\r
}\r
vgmPbMusic.oplChnMask &= ~(1 << vgmPb->oplChnMask);\r
}\r
}\r
{\r
UINT8 regChn;\r
UINT8 ramOfs;\r
{\r
UINT8 regChn;\r
UINT8 ramOfs;\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
if (vgmPb->pbMode == PBMODE_MUSIC)\r
{\r
if (reg == 0x01)\r
data |= 0x20; // enforce "Waveform Select Enable" bit\r
vgmPb->oplRegCache[reg] = data;\r
ramOfs = SFX_REGS_REV[reg >> 4];\r
if (ramOfs < 0x0A) // Operator 20/40/60/80/E0\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
if (reg == 0xBD)\r
return; // no rhythm register for SFX\r
ramOfs = SFX_REGS_REV[reg >> 4];\r
if (ramOfs == 0xFF)\r
return;\r
ramOfs = SFX_REGS_REV[reg >> 4];\r
if (ramOfs == 0xFF)\r
return;\r
if (ramOfs < 0x0A) // Operator 20/40/60/80/E0\r
{\r
regChn = CHN_OPMASK_REV[reg & 0x1F];\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
ramOfs += (regChn & 0x80) >> 7;\r
regChn &= 0x7F;\r
vgmPb->oplRegCache[ramOfs] = data;\r
if (regChn != vgmPb->oplChnMask)\r
{\r
// force command to current channel\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
if (regChn >= 0x09)\r
return; // ignore writes to invalid channels\r
vgmPb->oplRegCache[ramOfs] = data;\r
reg = (reg & 0xF0) | vgmPb->oplChnMask;\r
}\r
}\r
reg = (reg & 0xF0) | vgmPb->oplChnMask;\r
}\r
}\r
OPL2_Write(reg, data);\r
return;\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
if (! vgmPb->workRAM[0x00]) // "Wave Select Enable" off?\r
data = 0x00; // disable waveforms\r
}\r
OPL_CachedWrite(vgmPb, reg, data);\r
return;\r
}\r
OPL_CachedWrite(vgmPb, reg, data);\r
return;\r
}\r
else\r
return; // ignore Y8950 DeltaT writes\r
}\r
else\r
return; // ignore Y8950 DeltaT writes\r
}\r
OPL_CachedWrite(vgmPb, reg, data);\r
return;\r
}\r
OPL_CachedWrite(vgmPb, reg, data);\r
return;\r
}\r
{\r
UINT8 tmrMask;\r
UINT8 curSFX;\r
{\r
UINT8 tmrMask;\r
UINT8 curSFX;\r
tmrMask = OPL2_ReadStatus();\r
if (! (tmrMask & 0x40))\r
return; // wait for overflow\r
OPL2_Write(0x04, 0x80); // Reset Timer/IRQ Status Flags\r
tmrMask = OPL2_ReadStatus();\r
if (! (tmrMask & 0x40))\r
return; // wait for overflow\r
OPL2_Write(0x04, 0x80); // Reset Timer/IRQ Status Flags\r
if (! vgmPbMusic.vgmEnd)\r
UpdateVGM(&vgmPbMusic, VGM_UPD_RATE);\r
for (curSFX = 0; curSFX < SFX_CHN_COUNT; curSFX ++)\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
if (! vgmPbSFX[curSFX].vgmEnd)\r
UpdateVGM(&vgmPbSFX[curSFX], VGM_UPD_RATE);\r
}\r
\r
typedef struct _vgm_file_header\r
{\r
\r
typedef struct _vgm_file_header\r
{\r