// VGMPlay.c: C Source File of the Main Executable // // Line Size: 96 Chars // Tab Size: 4 Spaces /*3456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456 0000000001111111111222222222233333333334444444444555555555566666666667777777777888888888899999*/ // TODO: Callback "ChangeSampleRate" to fix YM2203's AY8910 // Mixer Muting ON: // Mixer's FM Volume is set to 0 or Mute -> absolutely muted // (sometimes it can take some time to get the Mixer Control under Windows) // Mixer Muting OFF: // FM Volume is set to 0 through commands -> very very low volume level ~0.4% // (faster way) //#define MIXER_MUTING // These defines enable additional features. // ADDITIONAL_FORMATS enables CMF and DRO support. // CONSOLE_MODE switches between VGMPlay and in_vgm mode. // in_vgm mode can also be used for custom players. // //#define ADDITIONAL_FORMATS //#define CONSOLE_MODE //#define VGM_BIG_ENDIAN #include #include #include #include #include "stdbool.h" #include // for pow() #ifndef NO_ZLIB #include #endif #include "resampler.h" #include "chips/mamedef.h" // integer types for fast integer calculation // the bit number is unused (it's an orientation) #define FUINT8 unsigned int #define FUINT16 unsigned int #include "VGMPlay.h" //#include "VGMPlay_Intf.h" // Already included by VGMPlay.h now #include "chips/ChipIncl.h" unsigned char OpenPortTalk(void *); void ClosePortTalk(void *); #include "ChipMapper.h" // Function Prototypes (prototypes in comments are defined in VGMPlay_Intf.h) //void VGMPlay_Init(void); //void VGMPlay_Init2(void); //void VGMPlay_Deinit(void); INLINE UINT16 ReadLE16(const UINT8* Data); INLINE UINT16 ReadBE16(const UINT8* Data); INLINE UINT32 ReadLE24(const UINT8* Data); INLINE UINT32 ReadLE32(const UINT8* Data); INLINE int FILE_getLE16(VGM_FILE* hFile, UINT16* RetValue); INLINE int FILE_getLE32(VGM_FILE* hFile, UINT32* RetValue); static UINT32 gcd(UINT32 x, UINT32 y); //void PlayVGM(void); //void StopVGM(void); //void RestartVGM(void); //void PauseVGM(bool Pause); //void SeekVGM(bool Relative, INT32 PlayBkSamples); //void RefreshMuting(void); //void RefreshPanning(void); //void RefreshPlaybackOptions(void); //UINT32 GetGZFileLength(const char* FileName); //UINT32 GetGZFileLengthW(const wchar_t* FileName); static UINT32 GetGZFileLength_Internal(FILE* hFile); //bool OpenVGMFile(const char* FileName); static bool OpenVGMFile_Internal(VGM_PLAYER*, VGM_FILE* hFile, UINT32 FileSize); static void ReadVGMHeader(VGM_FILE* hFile, VGM_HEADER* RetVGMHead); static UINT8 ReadGD3Tag(VGM_FILE* hFile, UINT32 GD3Offset, GD3_TAG* RetGD3Tag); static void ReadChipExtraData32(VGM_PLAYER*, UINT32 StartOffset, VGMX_CHP_EXTRA32* ChpExtra); static void ReadChipExtraData16(VGM_PLAYER*, UINT32 StartOffset, VGMX_CHP_EXTRA16* ChpExtra); //void CloseVGMFile(void); //void FreeGD3Tag(GD3_TAG* TagData); static wchar_t* MakeEmptyWStr(void); static wchar_t* ReadWStrFromFile(VGM_FILE* hFile, UINT32* FilePos, UINT32 EOFPos); //UINT32 GetVGMFileInfo(const char* FileName, VGM_HEADER* RetVGMHead, GD3_TAG* RetGD3Tag); static UINT32 GetVGMFileInfo_Internal(VGM_FILE* hFile, UINT32 FileSize, VGM_HEADER* RetVGMHead, GD3_TAG* RetGD3Tag); INLINE UINT32 MulDivRound(UINT64 Number, UINT64 Numerator, UINT64 Denominator); //UINT32 CalcSampleMSec(VGM_PLAYER* p, UINT64 Value, UINT8 Mode); //UINT32 CalcSampleMSecExt(VGM_PLAYER* p, UINT64 Value, UINT8 Mode, VGM_HEADER* FileHead); //const char* GetChipName(UINT8 ChipID); //const char* GetAccurateChipName(UINT8 ChipID, UINT8 SubType); //UINT32 GetChipClock(void*, UINT8 ChipID, UINT8* RetSubType); static UINT16 GetChipVolume(VGM_PLAYER*, UINT8 ChipID, UINT8 ChipNum, UINT8 ChipCnt); static void RestartPlaying(VGM_PLAYER*); static void Chips_GeneralActions(VGM_PLAYER*, UINT8 Mode); INLINE INT32 SampleVGM2Pbk_I(VGM_PLAYER*, INT32 SampleVal); // inline functions INLINE INT32 SamplePbk2VGM_I(VGM_PLAYER*, INT32 SampleVal); //INT32 SampleVGM2Playback(void*, INT32 SampleVal); // non-inline functions //INT32 SamplePlayback2VGM(void*, INT32 SampleVal); static bool SetMuteControl(VGM_PLAYER*, bool mute); static void InterpretFile(VGM_PLAYER*, UINT32 SampleCount); static void AddPCMData(VGM_PLAYER*, UINT8 Type, UINT32 DataSize, const UINT8* Data); //INLINE FUINT16 ReadBits(UINT8* Data, UINT32* Pos, FUINT8* BitPos, FUINT8 BitsToRead); static bool DecompressDataBlk(VGM_PLAYER* p, VGM_PCM_DATA* Bank, UINT32 DataSize, const UINT8* Data); static UINT8 GetDACFromPCMBank(VGM_PLAYER*); static UINT8* GetPointerFromPCMBank(VGM_PLAYER*, UINT8 Type, UINT32 DataPos); static void ReadPCMTable(VGM_PLAYER*, UINT32 DataSize, const UINT8* Data); static void InterpretVGM(VGM_PLAYER*, UINT32 SampleCount); #ifdef ADDITIONAL_FORMATS extern void InterpretOther(VGM_PLAYER*, UINT32 SampleCount); #endif static void GeneralChipLists(VGM_PLAYER*); static void SetupResampler(VGM_PLAYER*, CAUD_ATTR* CAA); static void ChangeChipSampleRate(void* DataPtr, UINT32 NewSmplRate); INLINE INT16 Limit2Short(INT32 Value); static void null_update(void *param, stream_sample_t **outputs, int samples); struct dual_opl2_info { void * chip; int ChipID; }; static void dual_opl2_stereo(void *param, stream_sample_t **outputs, int samples); static void ResampleChipStream(VGM_PLAYER*, CA_LIST* CLst, WAVE_32BS* RetSample, UINT32 Length); static INT32 RecalcFadeVolume(VGM_PLAYER*); //UINT32 FillBuffer(void *, WAVE_16BS* Buffer, UINT32 BufferSize) // Options and such moved to VGM_PLAYER structure void * VGMPlay_Init(void) { UINT8 CurChip; UINT8 CurCSet; UINT8 CurChn; CHIP_OPTS* TempCOpt; CAUD_ATTR* TempCAud; VGM_PLAYER* p = (VGM_PLAYER*) calloc(1, sizeof(*p)); if (!p) return NULL; p->SampleRate = 44100; p->FadeTime = 5000; p->FadeRAWLog = false; p->VolumeLevel = 1.0f; //p->FullBufFill = false; p->SurroundSound = false; p->VGMMaxLoop = 0x02; p->VGMPbRate = 0; #ifdef ADDITIONAL_FORMATS p->CMFMaxLoop = 0x01; #endif p->ResampleMode = 0x00; p->CHIP_SAMPLING_MODE = 0x00; p->CHIP_SAMPLE_RATE = 0x00000000; p->DoubleSSGVol = false; for (CurCSet = 0x00; CurCSet < 0x02; CurCSet ++) { TempCAud = (CAUD_ATTR*)&p->ChipAudio[CurCSet]; for (CurChip = 0x00; CurChip < CHIP_COUNT; CurChip ++, TempCAud ++) { TempCOpt = (CHIP_OPTS*)&p->ChipOpts[CurCSet] + CurChip; TempCOpt->Disabled = false; TempCOpt->EmuCore = 0x00; TempCOpt->SpecialFlags = 0x00; TempCOpt->ChnCnt = 0x00; TempCOpt->ChnMute1 = 0x00; TempCOpt->ChnMute2 = 0x00; TempCOpt->ChnMute3 = 0x00; TempCOpt->Panning = NULL; // Set up some important fields to prevent in_vgm from crashing // when clicking on Muting checkboxes after init. TempCAud->ChipType = 0xFF; TempCAud->ChipID = CurCSet; TempCAud->Paired = NULL; } p->ChipOpts[CurCSet].GameBoy.SpecialFlags = 0x0003; // default options, 0x8000 skips the option write and keeps NSFPlay's default values p->ChipOpts[CurCSet].NES.SpecialFlags = 0x8000 | (0x00 << 12) | (0x3B << 4) | (0x01 << 2) | (0x03 << 0); TempCAud = p->CA_Paired[CurCSet]; for (CurChip = 0x00; CurChip < 0x03; CurChip ++, TempCAud ++) { TempCAud->ChipType = 0xFF; TempCAud->ChipID = CurCSet; TempCAud->Paired = NULL; } // currently the only chips with Panning support are // SN76496 and YM2413, it should be not a problem that it's hardcoded. TempCOpt = (CHIP_OPTS*)&p->ChipOpts[CurCSet].SN76496; TempCOpt->ChnCnt = 0x04; TempCOpt->Panning = (INT16*)malloc(sizeof(INT16) * TempCOpt->ChnCnt); for (CurChn = 0x00; CurChn < TempCOpt->ChnCnt; CurChn ++) TempCOpt->Panning[CurChn] = 0x00; TempCOpt = (CHIP_OPTS*)&p->ChipOpts[CurCSet].YM2413; TempCOpt->ChnCnt = 0x0E; // 0x09 + 0x05 TempCOpt->Panning = (INT16*)malloc(sizeof(INT16) * TempCOpt->ChnCnt); for (CurChn = 0x00; CurChn < TempCOpt->ChnCnt; CurChn ++) TempCOpt->Panning[CurChn] = 0x00; } p->FileMode = 0xFF; return p; } void VGMPlay_Init2(void *_p) { VGM_PLAYER* p = (VGM_PLAYER*)_p; // has to be called after the configuration is loaded p->StreamBufs[0x00] = (INT32*)malloc(SMPL_BUFSIZE * sizeof(INT32)); p->StreamBufs[0x01] = (INT32*)malloc(SMPL_BUFSIZE * sizeof(INT32)); if (p->CHIP_SAMPLE_RATE <= 0) p->CHIP_SAMPLE_RATE = p->SampleRate; p->PlayingMode = 0xFF; return; } void VGMPlay_Deinit(void *_p) { UINT8 CurChip; UINT8 CurCSet; CHIP_OPTS* TempCOpt; VGM_PLAYER* p = (VGM_PLAYER*)_p; free(p->StreamBufs[0x00]); p->StreamBufs[0x00] = NULL; free(p->StreamBufs[0x01]); p->StreamBufs[0x01] = NULL; for (CurCSet = 0x00; CurCSet < 0x02; CurCSet ++) { for (CurChip = 0x00; CurChip < CHIP_COUNT; CurChip ++) { TempCOpt = (CHIP_OPTS*)&p->ChipOpts[CurCSet] + CurChip; if (TempCOpt->Panning != NULL) { free(TempCOpt->Panning); TempCOpt->Panning = NULL; } } } free(p); return; } INLINE UINT16 ReadLE16(const UINT8* Data) { // read 16-Bit Word (Little Endian/Intel Byte Order) #ifndef VGM_BIG_ENDIAN return *(UINT16*)Data; #else return (Data[0x01] << 8) | (Data[0x00] << 0); #endif } INLINE UINT16 ReadBE16(const UINT8* Data) { // read 16-Bit Word (Big Endian/Motorola Byte Order) #ifndef VGM_BIG_ENDIAN return (Data[0x00] << 8) | (Data[0x01] << 0); #else return *(UINT16*)Data; #endif } INLINE UINT32 ReadLE24(const UINT8* Data) { // read 24-Bit Word (Little Endian/Intel Byte Order) #ifndef VGM_BIG_ENDIAN return (*(UINT32*)Data) & 0x00FFFFFF; #else return (Data[0x02] << 16) | (Data[0x01] << 8) | (Data[0x00] << 0); #endif } INLINE UINT32 ReadLE32(const UINT8* Data) { // read 32-Bit Word (Little Endian/Intel Byte Order) #ifndef VGM_BIG_ENDIAN return *(UINT32*)Data; #else return (Data[0x03] << 24) | (Data[0x02] << 16) | (Data[0x01] << 8) | (Data[0x00] << 0); #endif } INLINE int FILE_getLE16(VGM_FILE* hFile, UINT16* RetValue) { #ifndef VGM_BIG_ENDIAN return hFile->Read(hFile, RetValue, 0x02); #else int RetVal; UINT8 Data[0x02]; RetVal = hFile->Read(hFile, Data, 0x02); *RetValue = (Data[0x01] << 8) | (Data[0x00] << 0); return RetVal; #endif } INLINE int FILE_getLE32(VGM_FILE* hFile, UINT32* RetValue) { #ifndef VGM_BIG_ENDIAN return hFile->Read(hFile, RetValue, 0x04); #else int RetVal; UINT8 Data[0x04]; RetVal = hFime->Read(hFile, Data, 0x04); *RetValue = (Data[0x03] << 24) | (Data[0x02] << 16) | (Data[0x01] << 8) | (Data[0x00] << 0); return RetVal; #endif } static UINT32 gcd(UINT32 x, UINT32 y) { UINT32 shift; UINT32 diff; // Thanks to Wikipedia for this algorithm // http://en.wikipedia.org/wiki/Binary_GCD_algorithm if (! x || ! y) return x | y; for (shift = 0; ((x | y) & 1) == 0; shift ++) { x >>= 1; y >>= 1; } while((x & 1) == 0) x >>= 1; do { while((y & 1) == 0) y >>= 1; if (x < y) { y -= x; } else { diff = x - y; x = y; y = diff; } y >>= 1; } while(y); return x << shift; } void PlayVGM(void *_p) { UINT8 CurChip; UINT8 FMVal; INT32 TempSLng; VGM_PLAYER* p = (VGM_PLAYER*)_p; if (p->PlayingMode != 0xFF) return; p->FadePlay = false; p->MasterVol = 1.0f; p->ForceVGMExec = false; p->FadeStart = 0; p->ForceVGMExec = true; p->PlayingMode = 0x00; // Normal Mode if (p->VGMHead.bytVolumeModifier <= VOLUME_MODIF_WRAP) TempSLng = p->VGMHead.bytVolumeModifier; else if (p->VGMHead.bytVolumeModifier == (VOLUME_MODIF_WRAP + 0x01)) TempSLng = VOLUME_MODIF_WRAP - 0x100; else TempSLng = p->VGMHead.bytVolumeModifier - 0x100; p->VolumeLevelM = (float)(p->VolumeLevel * pow(2.0, TempSLng / (double)0x20)); p->FinalVol = p->VolumeLevelM; if (! p->VGMMaxLoop) { p->VGMMaxLoopM = 0x00; } else { TempSLng = (p->VGMMaxLoop * p->VGMHead.bytLoopModifier + 0x08) / 0x10 - p->VGMHead.bytLoopBase; p->VGMMaxLoopM = (TempSLng >= 0x01) ? TempSLng : 0x01; } if (! p->VGMPbRate || ! p->VGMHead.lngRate) { p->VGMPbRateMul = 1; p->VGMPbRateDiv = 1; } else { // I prefer small Multiplers and Dividers, as they're used very often TempSLng = gcd(p->VGMHead.lngRate, p->VGMPbRate); p->VGMPbRateMul = p->VGMHead.lngRate / TempSLng; p->VGMPbRateDiv = p->VGMPbRate / TempSLng; } p->VGMSmplRateMul = p->SampleRate * p->VGMPbRateMul; p->VGMSmplRateDiv = p->VGMSampleRate * p->VGMPbRateDiv; // same as above - to speed up the VGM <-> Playback calculation TempSLng = gcd(p->VGMSmplRateMul, p->VGMSmplRateDiv); p->VGMSmplRateMul /= TempSLng; p->VGMSmplRateDiv /= TempSLng; p->PlayingTime = 0; p->EndPlay = false; p->VGMPos = p->VGMHead.lngDataOffset; p->VGMSmplPos = 0; p->VGMSmplPlayed = 0; p->VGMEnd = false; p->VGMCurLoop = 0x00; if (p->VGMPos >= p->VGMHead.lngEOFOffset) p->VGMEnd = true; Chips_GeneralActions(p, 0x00); // Start chips // also does Reset (0x01), Muting Mask (0x10) and Panning (0x20) p->Last95Drum = 0xFFFF; p->Last95Freq = 0; p->Last95Max = 0xFFFF; p->IsVGMInit = true; p->ErrorHappened = false; InterpretFile(p, 0); p->IsVGMInit = false; p->ForceVGMExec = false; return; } void StopVGM(void *_p) { VGM_PLAYER* p = (VGM_PLAYER*)_p; if (p->PlayingMode == 0xFF) return; Chips_GeneralActions(p, 0x02); // Stop chips p->PlayingMode = 0xFF; return; } void RestartVGM(void *_p) { VGM_PLAYER* p = (VGM_PLAYER*)_p; if (p->PlayingMode == 0xFF || ! p->VGMSmplPlayed) return; RestartPlaying(p); return; } void SeekVGM(void *_p, bool Relative, INT32 PlayBkSamples) { INT32 Samples; UINT32 LoopSmpls; VGM_PLAYER* p = (VGM_PLAYER*)_p; if (p->PlayingMode == 0xFF || (Relative && ! PlayBkSamples)) return; LoopSmpls = p->VGMCurLoop * SampleVGM2Pbk_I(p, p->VGMHead.lngLoopSamples); if (! Relative) Samples = PlayBkSamples - (LoopSmpls + p->VGMSmplPlayed); else Samples = PlayBkSamples; if (Samples < 0) { Samples = LoopSmpls + p->VGMSmplPlayed + Samples; if (Samples < 0) Samples = 0; RestartPlaying(p); } p->ForceVGMExec = true; InterpretFile(p, Samples); p->ForceVGMExec = false; return; } void RefreshMuting(void *_p) { VGM_PLAYER* p = (VGM_PLAYER*)_p; Chips_GeneralActions(p, 0x10); // set muting mask return; } void RefreshPanning(void *_p) { VGM_PLAYER* p = (VGM_PLAYER*)_p; Chips_GeneralActions(p, 0x20); // set panning return; } void RefreshPlaybackOptions(void *_p) { INT32 TempVol; UINT8 CurChip; CHIP_OPTS* TempCOpt1; CHIP_OPTS* TempCOpt2; VGM_PLAYER* p = (VGM_PLAYER*)_p; if (p->VGMHead.bytVolumeModifier <= VOLUME_MODIF_WRAP) TempVol = p->VGMHead.bytVolumeModifier; else if (p->VGMHead.bytVolumeModifier == (VOLUME_MODIF_WRAP + 0x01)) TempVol = VOLUME_MODIF_WRAP - 0x100; else TempVol = p->VGMHead.bytVolumeModifier - 0x100; p->VolumeLevelM = (float)(p->VolumeLevel * pow(2.0, TempVol / (double)0x20)); p->FinalVol = p->VolumeLevelM * p->MasterVol * p->MasterVol; if (p->PlayingMode == 0xFF) { TempCOpt1 = (CHIP_OPTS*)&p->ChipOpts[0x00]; TempCOpt2 = (CHIP_OPTS*)&p->ChipOpts[0x01]; for (CurChip = 0x00; CurChip < CHIP_COUNT; CurChip ++, TempCOpt1 ++, TempCOpt2 ++) { TempCOpt2->EmuCore = TempCOpt1->EmuCore; TempCOpt2->SpecialFlags = TempCOpt1->SpecialFlags; } } return; } UINT32 GetGZFileLength(const char* FileName) { FILE* hFile; UINT32 FileSize; hFile = fopen(FileName, "rb"); if (hFile == NULL) return 0xFFFFFFFF; FileSize = GetGZFileLength_Internal(hFile); fclose(hFile); return FileSize; } #ifndef NO_WCHAR_FILENAMES UINT32 GetGZFileLengthW(const wchar_t* FileName) { FILE* hFile; UINT32 FileSize; hFile = _wfopen(FileName, L"rb"); if (hFile == NULL) return 0xFFFFFFFF; FileSize = GetGZFileLength_Internal(hFile); fclose(hFile); return FileSize; } #endif static UINT32 GetGZFileLength_Internal(FILE* hFile) { UINT32 FileSize; UINT16 gzHead; size_t RetVal; RetVal = fread(&gzHead, 0x02, 0x01, hFile); if (RetVal >= 1) { gzHead = ReadBE16((UINT8*)&gzHead); if (gzHead != 0x1F8B) { RetVal = 0; // no .gz signature - treat as normal file } else { // .gz File fseek(hFile, -4, SEEK_END); // Note: In the error case it falls back to fseek/ftell. RetVal = fread(&FileSize, 0x04, 0x01, hFile); #ifdef VGM_BIG_ENDIAN FileSize = ReadLE32((UINT8*)&FileSize); #endif } } if (RetVal <= 0) { // normal file fseek(hFile, 0x00, SEEK_END); FileSize = ftell(hFile); } return FileSize; } #ifndef NO_ZLIB typedef struct vgm_file_gz { VGM_FILE vf; gzFile hFile; UINT32 Size; } VGM_FILE_gz; static int VGMF_gzread(VGM_FILE* hFile, void* ptr, UINT32 count) { VGM_FILE_gz* File = (VGM_FILE_gz *)hFile; return gzread(File->hFile, ptr, count); } static int VGMF_gzseek(VGM_FILE* hFile, UINT32 offset) { VGM_FILE_gz* File = (VGM_FILE_gz *)hFile; return gzseek(File->hFile, offset, SEEK_SET); } static UINT32 VGMF_gzgetsize(VGM_FILE* hFile) { VGM_FILE_gz* File = (VGM_FILE_gz *)hFile; return File->Size; } #endif bool OpenVGMFile(void *_p, const char* FileName) { #ifdef NO_ZLIB return false; #else gzFile hFile; UINT32 FileSize; bool RetVal; VGM_PLAYER* p = (VGM_PLAYER*)_p; FileSize = GetGZFileLength(FileName); hFile = gzopen(FileName, "rb"); if (hFile == NULL) return false; VGM_FILE_gz vgmFile; vgmFile.vf.Read = VGMF_gzread; vgmFile.vf.Seek = VGMF_gzseek; vgmFile.vf.GetSize = VGMF_gzgetsize; vgmFile.hFile = hFile; vgmFile.Size = FileSize; RetVal = OpenVGMFile_Internal(p, (VGM_FILE *)&vgmFile, FileSize); gzclose(hFile); return RetVal; #endif } #ifndef NO_WCHAR_FILENAMES bool OpenVGMFileW(void *_p, const wchar_t* FileName) { #ifdef NO_ZLIB return false; #else gzFile hFile; UINT32 FileSize; bool RetVal; VGM_PLAYER* p = (VGM_PLAYER*)_p; #if ZLIB_VERNUM < 0x1270 int fDesc; FileSize = GetGZFileLengthW(FileName); fDesc = _wopen(FileName, _O_RDONLY | _O_BINARY); hFile = gzdopen(fDesc, "rb"); if (hFile == NULL) { _close(fDesc); return false; } #else FileSize = GetGZFileLengthW(FileName); hFile = gzopen_w(FileName, "rb"); if (hFile == NULL) return false; #endif VGM_FILE_gz vgmFile; vgmFile.vf.Read = VGMF_gzread; vgmFile.vf.Seek = VGMF_gzseek; vgmFile.vf.GetSize = VGMF_gzgetsize; vgmFile.hFile = hFile; vgmFile.Size = FileSize; RetVal = OpenVGMFile_Internal(p, (VGM_FILE *)&vgmFile, FileSize); gzclose(hFile); return RetVal; #endif } #endif bool OpenVGMFile_Handle(void* _p, VGM_FILE* hFile) { UINT32 FileSize = hFile->GetSize(hFile); return OpenVGMFile_Internal((VGM_PLAYER*)_p, hFile, FileSize); } static bool OpenVGMFile_Internal(VGM_PLAYER* p, VGM_FILE* hFile, UINT32 FileSize) { UINT32 fccHeader; UINT32 CurPos; UINT32 HdrLimit; hFile->Seek(hFile, 0x00); FILE_getLE32(hFile, &fccHeader); if (fccHeader != FCC_VGM) return false; if (p->FileMode != 0xFF) CloseVGMFile(p); p->FileMode = 0x00; p->VGMDataLen = FileSize; hFile->Seek(hFile, 0x00); ReadVGMHeader(hFile, &p->VGMHead); p->VGMSampleRate = 44100; if (! p->VGMDataLen) p->VGMDataLen = p->VGMHead.lngEOFOffset; if (! p->VGMHead.lngEOFOffset || p->VGMHead.lngEOFOffset > p->VGMDataLen) { p->VGMHead.lngEOFOffset = p->VGMDataLen; } if (p->VGMHead.lngLoopOffset && ! p->VGMHead.lngLoopSamples) { // 0-Sample-Loops causes the program to hangs in the playback routine p->VGMHead.lngLoopOffset = 0x00000000; } if (p->VGMHead.lngDataOffset < 0x00000040) { p->VGMHead.lngDataOffset = 0x00000040; } memset(&p->VGMHeadX, 0x00, sizeof(VGM_HDR_EXTRA)); memset(&p->VGMH_Extra, 0x00, sizeof(VGM_EXTRA)); // Read Data p->VGMDataLen = p->VGMHead.lngEOFOffset; p->VGMData = (UINT8*)malloc(p->VGMDataLen); if (p->VGMData == NULL) return false; hFile->Seek(hFile, 0x00); hFile->Read(hFile, p->VGMData, p->VGMDataLen); // Read Extra Header Data if (p->VGMHead.lngExtraOffset) { UINT32* TempPtr; CurPos = p->VGMHead.lngExtraOffset; TempPtr = (UINT32*)&p->VGMHeadX; // Read Header Size p->VGMHeadX.DataSize = ReadLE32(&p->VGMData[CurPos]); if (p->VGMHeadX.DataSize > sizeof(VGM_HDR_EXTRA)) p->VGMHeadX.DataSize = sizeof(VGM_HDR_EXTRA); HdrLimit = CurPos + p->VGMHeadX.DataSize; CurPos += 0x04; TempPtr ++; // Read all relative offsets of this header and make them absolute. for (; CurPos < HdrLimit; CurPos += 0x04, TempPtr ++) { *TempPtr = ReadLE32(&p->VGMData[CurPos]); if (*TempPtr) *TempPtr += CurPos; } ReadChipExtraData32(p, p->VGMHeadX.Chp2ClkOffset, &p->VGMH_Extra.Clocks); ReadChipExtraData16(p, p->VGMHeadX.ChpVolOffset, &p->VGMH_Extra.Volumes); } // Read GD3 Tag HdrLimit = ReadGD3Tag(hFile, p->VGMHead.lngGD3Offset, &p->VGMTag); if (HdrLimit == 0x10) { p->VGMHead.lngGD3Offset = 0x00000000; //return false; } if (! p->VGMHead.lngGD3Offset) { // replace all NULL pointers with empty strings p->VGMTag.strTrackNameE = MakeEmptyWStr(); p->VGMTag.strTrackNameJ = MakeEmptyWStr(); p->VGMTag.strGameNameE = MakeEmptyWStr(); p->VGMTag.strGameNameJ = MakeEmptyWStr(); p->VGMTag.strSystemNameE = MakeEmptyWStr(); p->VGMTag.strSystemNameJ = MakeEmptyWStr(); p->VGMTag.strAuthorNameE = MakeEmptyWStr(); p->VGMTag.strAuthorNameJ = MakeEmptyWStr(); p->VGMTag.strReleaseDate = MakeEmptyWStr(); p->VGMTag.strCreator = MakeEmptyWStr(); p->VGMTag.strNotes = MakeEmptyWStr(); } return true; } static void ReadVGMHeader(VGM_FILE* hFile, VGM_HEADER* RetVGMHead) { VGM_HEADER CurHead; UINT32 CurPos; UINT32 HdrLimit; hFile->Read(hFile, &CurHead, sizeof(VGM_HEADER)); #ifdef VGM_BIG_ENDIAN { UINT8* TempPtr; // Warning: Lots of pointer casting ahead! for (CurPos = 0x00; CurPos < sizeof(VGM_HEADER); CurPos += 0x04) { TempPtr = (UINT8*)&CurHead + CurPos; switch(CurPos) { case 0x28: // 0x28 [16-bit] SN76496 Feedback Mask // 0x2A [ 8-bit] SN76496 Shift Register Width // 0x2B [ 8-bit] SN76496 Flags *(UINT16*)TempPtr = ReadLE16(TempPtr); break; case 0x78: // 78-7B [8-bit] AY8910 Type/Flags case 0x7C: // 7C-7F [8-bit] Volume/Loop Modifiers case 0x94: // 94-97 [8-bit] various flags break; default: // everything else is 32-bit *(UINT32*)TempPtr = ReadLE32(TempPtr); break; } } } #endif // Header preperations if (CurHead.lngVersion < 0x00000101) { CurHead.lngRate = 0; } if (CurHead.lngVersion < 0x00000110) { CurHead.shtPSG_Feedback = 0x0000; CurHead.bytPSG_SRWidth = 0x00; CurHead.lngHzYM2612 = CurHead.lngHzYM2413; CurHead.lngHzYM2151 = CurHead.lngHzYM2413; } if (CurHead.lngVersion < 0x00000150) { CurHead.lngDataOffset = 0x00000000; // If I would aim to be very strict, I would uncomment these few lines, // but I sometimes use v1.51 Flags with v1.50 for better compatibility. // (Some hyper-strict players refuse to play v1.51 files, even if there's // no new chip used.) //} //if (CurHead.lngVersion < 0x00000151) //{ CurHead.bytPSG_Flags = 0x00; CurHead.lngHzSPCM = 0x0000; CurHead.lngSPCMIntf = 0x00000000; // all others are zeroed by memset } if (CurHead.lngHzPSG) { if (! CurHead.shtPSG_Feedback) CurHead.shtPSG_Feedback = 0x0009; if (! CurHead.bytPSG_SRWidth) CurHead.bytPSG_SRWidth = 0x10; } // relative -> absolute addresses if (CurHead.lngEOFOffset) CurHead.lngEOFOffset += 0x00000004; if (CurHead.lngGD3Offset) CurHead.lngGD3Offset += 0x00000014; if (CurHead.lngLoopOffset) CurHead.lngLoopOffset += 0x0000001C; if (CurHead.lngVersion < 0x00000150) CurHead.lngDataOffset = 0x0000000C; //if (CurHead.lngDataOffset < 0x0000000C) // CurHead.lngDataOffset = 0x0000000C; if (CurHead.lngDataOffset) CurHead.lngDataOffset += 0x00000034; CurPos = CurHead.lngDataOffset; // should actually check v1.51 (first real usage of DataOffset) // v1.50 is checked to support things like the Volume Modifiers in v1.50 files if (CurHead.lngVersion < 0x00000150 /*0x00000151*/) CurPos = 0x40; if (! CurPos) CurPos = 0x40; HdrLimit = sizeof(VGM_HEADER); if (HdrLimit > CurPos) memset((UINT8*)&CurHead + CurPos, 0x00, HdrLimit - CurPos); if (! CurHead.bytLoopModifier) CurHead.bytLoopModifier = 0x10; if (CurHead.lngExtraOffset) { CurHead.lngExtraOffset += 0xBC; CurPos = CurHead.lngExtraOffset; if (CurPos < HdrLimit) memset((UINT8*)&CurHead + CurPos, 0x00, HdrLimit - CurPos); } if (CurHead.lngGD3Offset >= CurHead.lngEOFOffset) CurHead.lngGD3Offset = 0x00; if (CurHead.lngLoopOffset >= CurHead.lngEOFOffset) CurHead.lngLoopOffset = 0x00; if (CurHead.lngDataOffset >= CurHead.lngEOFOffset) CurHead.lngDataOffset = 0x40; if (CurHead.lngExtraOffset >= CurHead.lngEOFOffset) CurHead.lngExtraOffset = 0x00; *RetVGMHead = CurHead; return; } static UINT8 ReadGD3Tag(VGM_FILE* hFile, UINT32 GD3Offset, GD3_TAG* RetGD3Tag) { UINT32 CurPos; UINT32 TempLng; UINT8 ResVal; ResVal = 0x00; // Read GD3 Tag if (GD3Offset) { hFile->Seek(hFile, GD3Offset); FILE_getLE32(hFile, &TempLng); if (TempLng != FCC_GD3) { GD3Offset = 0x00000000; ResVal = 0x10; // invalid GD3 offset } } if (RetGD3Tag == NULL) return ResVal; if (! GD3Offset) { RetGD3Tag->fccGD3 = 0x00000000; RetGD3Tag->lngVersion = 0x00000000; RetGD3Tag->lngTagLength = 0x00000000; RetGD3Tag->strTrackNameE = NULL; RetGD3Tag->strTrackNameJ = NULL; RetGD3Tag->strGameNameE = NULL; RetGD3Tag->strGameNameJ = NULL; RetGD3Tag->strSystemNameE = NULL; RetGD3Tag->strSystemNameJ = NULL; RetGD3Tag->strAuthorNameE = NULL; RetGD3Tag->strAuthorNameJ = NULL; RetGD3Tag->strReleaseDate = NULL; RetGD3Tag->strCreator = NULL; RetGD3Tag->strNotes = NULL; } else { //CurPos = GD3Offset; //hFile->Seek(hFile, CurPos, SEEK_SET); //CurPos += FILE_getLE32(hFile, &RetGD3Tag->fccGD3); CurPos = GD3Offset + 0x04; // Save some back seeking, yay! RetGD3Tag->fccGD3 = TempLng; // (That costs lots of CPU in .gz files.) CurPos += FILE_getLE32(hFile, &RetGD3Tag->lngVersion); CurPos += FILE_getLE32(hFile, &RetGD3Tag->lngTagLength); TempLng = CurPos + RetGD3Tag->lngTagLength; RetGD3Tag->strTrackNameE = ReadWStrFromFile(hFile, &CurPos, TempLng); RetGD3Tag->strTrackNameJ = ReadWStrFromFile(hFile, &CurPos, TempLng); RetGD3Tag->strGameNameE = ReadWStrFromFile(hFile, &CurPos, TempLng); RetGD3Tag->strGameNameJ = ReadWStrFromFile(hFile, &CurPos, TempLng); RetGD3Tag->strSystemNameE = ReadWStrFromFile(hFile, &CurPos, TempLng); RetGD3Tag->strSystemNameJ = ReadWStrFromFile(hFile, &CurPos, TempLng); RetGD3Tag->strAuthorNameE = ReadWStrFromFile(hFile, &CurPos, TempLng); RetGD3Tag->strAuthorNameJ = ReadWStrFromFile(hFile, &CurPos, TempLng); RetGD3Tag->strReleaseDate = ReadWStrFromFile(hFile, &CurPos, TempLng); RetGD3Tag->strCreator = ReadWStrFromFile(hFile, &CurPos, TempLng); RetGD3Tag->strNotes = ReadWStrFromFile(hFile, &CurPos, TempLng); } return ResVal; } static void ReadChipExtraData32(VGM_PLAYER* p, UINT32 StartOffset, VGMX_CHP_EXTRA32* ChpExtra) { UINT32 CurPos; UINT8 CurChp; VGMX_CHIP_DATA32* TempCD; if (! StartOffset || StartOffset >= p->VGMDataLen) { ChpExtra->ChipCnt = 0x00; ChpExtra->CCData = NULL; return; } CurPos = StartOffset; ChpExtra->ChipCnt = p->VGMData[CurPos]; if (ChpExtra->ChipCnt) ChpExtra->CCData = (VGMX_CHIP_DATA32*)malloc(sizeof(VGMX_CHIP_DATA32) * ChpExtra->ChipCnt); else ChpExtra->CCData = NULL; CurPos ++; for (CurChp = 0x00; CurChp < ChpExtra->ChipCnt; CurChp ++) { TempCD = &ChpExtra->CCData[CurChp]; TempCD->Type = p->VGMData[CurPos + 0x00]; TempCD->Data = ReadLE32(&p->VGMData[CurPos + 0x01]); CurPos += 0x05; } return; } static void ReadChipExtraData16(VGM_PLAYER* p, UINT32 StartOffset, VGMX_CHP_EXTRA16* ChpExtra) { UINT32 CurPos; UINT8 CurChp; VGMX_CHIP_DATA16* TempCD; if (! StartOffset || StartOffset >= p->VGMDataLen) { ChpExtra->ChipCnt = 0x00; ChpExtra->CCData = NULL; return; } CurPos = StartOffset; ChpExtra->ChipCnt = p->VGMData[CurPos]; if (ChpExtra->ChipCnt) ChpExtra->CCData = (VGMX_CHIP_DATA16*)malloc(sizeof(VGMX_CHIP_DATA16) * ChpExtra->ChipCnt); else ChpExtra->CCData = NULL; CurPos ++; for (CurChp = 0x00; CurChp < ChpExtra->ChipCnt; CurChp ++) { TempCD = &ChpExtra->CCData[CurChp]; TempCD->Type = p->VGMData[CurPos + 0x00]; TempCD->Flags = p->VGMData[CurPos + 0x01]; TempCD->Data = ReadLE16(&p->VGMData[CurPos + 0x02]); CurPos += 0x04; } return; } void CloseVGMFile(void *_p) { VGM_PLAYER* p = (VGM_PLAYER*)_p; if (p->FileMode == 0xFF) return; p->VGMHead.fccVGM = 0x00; free(p->VGMH_Extra.Clocks.CCData); p->VGMH_Extra.Clocks.CCData = NULL; free(p->VGMH_Extra.Volumes.CCData); p->VGMH_Extra.Volumes.CCData = NULL; free(p->VGMData); p->VGMData = NULL; if (p->FileMode == 0x00) FreeGD3Tag(&p->VGMTag); p->FileMode = 0xFF; return; } void FreeGD3Tag(GD3_TAG* TagData) { if (TagData == NULL) return; TagData->fccGD3 = 0x00; free(TagData->strTrackNameE); TagData->strTrackNameE = NULL; free(TagData->strTrackNameJ); TagData->strTrackNameJ = NULL; free(TagData->strGameNameE); TagData->strGameNameE = NULL; free(TagData->strGameNameJ); TagData->strGameNameJ = NULL; free(TagData->strSystemNameE); TagData->strSystemNameE = NULL; free(TagData->strSystemNameJ); TagData->strSystemNameJ = NULL; free(TagData->strAuthorNameE); TagData->strAuthorNameE = NULL; free(TagData->strAuthorNameJ); TagData->strAuthorNameJ = NULL; free(TagData->strReleaseDate); TagData->strReleaseDate = NULL; free(TagData->strCreator); TagData->strCreator = NULL; free(TagData->strNotes); TagData->strNotes = NULL; return; } static wchar_t* MakeEmptyWStr(void) { wchar_t* Str; Str = (wchar_t*)malloc(0x01 * sizeof(wchar_t)); Str[0x00] = L'\0'; return Str; } static wchar_t* ReadWStrFromFile(VGM_FILE* hFile, UINT32* FilePos, UINT32 EOFPos) { // Note: Works with Windows (16-bit wchar_t) as well as Linux (32-bit wchar_t) UINT32 CurPos; wchar_t* TextStr; wchar_t* TempStr; UINT32 StrLen; UINT16 UnicodeChr; CurPos = *FilePos; if (CurPos >= EOFPos) return NULL; TextStr = (wchar_t*)malloc((EOFPos - CurPos) / 0x02 * sizeof(wchar_t)); if (TextStr == NULL) return NULL; hFile->Seek(hFile, CurPos); TempStr = TextStr - 1; StrLen = 0x00; do { TempStr ++; FILE_getLE16(hFile, &UnicodeChr); *TempStr = (wchar_t)UnicodeChr; CurPos += 0x02; StrLen ++; if (CurPos >= EOFPos) { *TempStr = L'\0'; break; } } while(*TempStr != L'\0'); TextStr = (wchar_t*)realloc(TextStr, StrLen * sizeof(wchar_t)); *FilePos = CurPos; return TextStr; } UINT32 GetVGMFileInfo(const char* FileName, VGM_HEADER* RetVGMHead, GD3_TAG* RetGD3Tag) { #ifdef NO_ZLIB return 0; #else gzFile hFile; UINT32 FileSize; UINT32 RetVal; FileSize = GetGZFileLength(FileName); hFile = gzopen(FileName, "rb"); if (hFile == NULL) return 0x00; VGM_FILE_gz vgmFile; vgmFile.vf.Read = VGMF_gzread; vgmFile.vf.Seek = VGMF_gzseek; vgmFile.vf.GetSize = VGMF_gzgetsize; vgmFile.hFile = hFile; vgmFile.Size = FileSize; RetVal = GetVGMFileInfo_Internal((VGM_FILE *)&vgmFile, FileSize, RetVGMHead, RetGD3Tag); gzclose(hFile); return RetVal; #endif } #ifndef NO_WCHAR_FILENAMES UINT32 GetVGMFileInfoW(const wchar_t* FileName, VGM_HEADER* RetVGMHead, GD3_TAG* RetGD3Tag) { #ifdef NO_ZLIB return 0; #else gzFile hFile; UINT32 FileSize; UINT32 RetVal; #if ZLIB_VERNUM < 0x1270 int fDesc; FileSize = GetGZFileLengthW(FileName); fDesc = _wopen(FileName, _O_RDONLY | _O_BINARY); hFile = gzdopen(fDesc, "rb"); if (hFile == NULL) { _close(fDesc); return 0x00; } #else FileSize = GetGZFileLengthW(FileName); hFile = gzopen_w(FileName, "rb"); if (hFile == NULL) return 0x00; #endif VGM_FILE_gz vgmFile; vgmFile.vf.Read = VGMF_gzread; vgmFile.vf.Seek = VGMF_gzseek; vgmFile.vf.GetSize = VGMF_gzgetsize; vgmFile.hFile = hFile; vgmFile.Size = FileSize; RetVal = GetVGMFileInfo_Internal((VGM_FILE *)&vgmFile, FileSize, RetVGMHead, RetGD3Tag); gzclose(hFile); return RetVal; #endif } #endif UINT32 GetVGMFileInfo_Handle(VGM_FILE* hFile, VGM_HEADER* RetVGMHead, GD3_TAG* RetGD3Tag) { UINT32 FileSize = hFile->GetSize(hFile); return GetVGMFileInfo_Internal(hFile, FileSize, RetVGMHead, RetGD3Tag); } static UINT32 GetVGMFileInfo_Internal(VGM_FILE* hFile, UINT32 FileSize, VGM_HEADER* RetVGMHead, GD3_TAG* RetGD3Tag) { // this is a copy-and-paste from OpenVGM, just a little stripped UINT32 fccHeader; UINT32 TempLng; VGM_HEADER TempHead; hFile->Seek(hFile, 0x00); FILE_getLE32(hFile, &fccHeader); if (fccHeader != FCC_VGM) return 0x00; if (RetVGMHead == NULL && RetGD3Tag == NULL) return FileSize; hFile->Seek(hFile, 0x00); ReadVGMHeader(hFile, &TempHead); if (! TempHead.lngEOFOffset || TempHead.lngEOFOffset > FileSize) TempHead.lngEOFOffset = FileSize; if (TempHead.lngDataOffset < 0x00000040) TempHead.lngDataOffset = 0x00000040; /*if (TempHead.lngGD3Offset) { gzseek(hFile, TempHead.lngGD3Offset, SEEK_SET); gzgetLE32(hFile, &fccHeader); if (fccHeader != FCC_GD3) TempHead.lngGD3Offset = 0x00000000; //return 0x00; }*/ if (RetVGMHead != NULL) *RetVGMHead = TempHead; // Read GD3 Tag if (RetGD3Tag != NULL) TempLng = ReadGD3Tag(hFile, TempHead.lngGD3Offset, RetGD3Tag); return FileSize; } INLINE UINT32 MulDivRound(UINT64 Number, UINT64 Numerator, UINT64 Denominator) { return (UINT32)((Number * Numerator + Denominator / 2) / Denominator); } UINT32 CalcSampleMSec(void* _p, UINT64 Value, UINT8 Mode) { // Mode: // Bit 0 (01): Calculation Mode // 0 - Sample2MSec // 1 - MSec2Sample // Bit 1 (02): Calculation Samlpe Rate // 0 - current playback rate // 1 - 44.1 KHz (VGM native) UINT32 SmplRate; UINT32 PbMul; UINT32 PbDiv; UINT32 RetVal; VGM_PLAYER* p = (VGM_PLAYER *)_p; if (! (Mode & 0x02)) { SmplRate = p->SampleRate; PbMul = 1; PbDiv = 1; } else { SmplRate = p->VGMSampleRate; PbMul = p->VGMPbRateMul; PbDiv = p->VGMPbRateDiv; } switch(Mode & 0x01) { case 0x00: RetVal = MulDivRound(Value, (UINT64)1000 * PbMul, (UINT64)SmplRate * PbDiv); break; case 0x01: RetVal = MulDivRound(Value, (UINT64)SmplRate * PbDiv, (UINT64)1000 * PbMul); break; } return RetVal; } UINT32 CalcSampleMSecExt(void *_p, UINT64 Value, UINT8 Mode, VGM_HEADER* FileHead) { // Note: This function was NOT tested with non-VGM formats! // Mode: see function above UINT32 SmplRate; UINT32 PbMul; UINT32 PbDiv; UINT32 RetVal; VGM_PLAYER* p = (VGM_PLAYER *)_p; if (! (Mode & 0x02)) { SmplRate = p->SampleRate; PbMul = 1; PbDiv = 1; } else { // TODO: make it work for non-VGM formats // (i.e. get VGMSampleRate information from FileHead) // // But currently GetVGMFileInfo doesn't support them, it doesn't matter either way SmplRate = 44100; if (! p->VGMPbRate || ! FileHead->lngRate) { PbMul = 1; PbDiv = 1; } else { PbMul = FileHead->lngRate; PbDiv = p->VGMPbRate; } } switch(Mode & 0x01) { case 0x00: RetVal = MulDivRound(Value, 1000 * PbMul, SmplRate * PbDiv); break; case 0x01: RetVal = MulDivRound(Value, SmplRate * PbDiv, 1000 * PbMul); break; } return RetVal; } static UINT32 EncryptChipName(void* DstBuf, const void* SrcBuf, UINT32 Length) { // using nineko's awesome encryption algorithm // http://forums.sonicretro.org/index.php?showtopic=25300 // based on C code by sasuke const UINT8* SrcPos; UINT8* DstPos; UINT32 CurPos; UINT8 CryptShift; // Src Bit/Dst Byte UINT8 PlainShift; // Src Byte/Dst Bit if (Length & 0x07) return 0x00; // Length MUST be a multiple of 8 SrcPos = (const UINT8*)SrcBuf; DstPos = (UINT8*)DstBuf; for (CurPos = 0; CurPos < Length; CurPos += 8, SrcPos += 8, DstPos += 8) { for (CryptShift = 0; CryptShift < 8; CryptShift ++) { DstPos[CryptShift] = 0x00; for (PlainShift = 0; PlainShift < 8; PlainShift ++) { if (SrcPos[PlainShift] & (1 << CryptShift)) DstPos[CryptShift] |= (1 << PlainShift); } } } return Length; } const char* GetChipName(UINT8 ChipID) { const char* CHIP_STRS[CHIP_COUNT] = { "SN76496", "YM2413", "YM2612", "YM2151", "SegaPCM", "RF5C68", "YM2203", "YM2608", "YM2610", "YM3812", "YM3526", "Y8950", "YMF262", "YMF278B", "YMF271", "YMZ280B", "RF5C164", "PWM", "AY8910", "GameBoy", "NES APU", "MultiPCM", "uPD7759", "OKIM6258", "OKIM6295", "K051649", "K054539", "HuC6280", "C140", "K053260", "Pokey", "QSound", "SCSP", "WSwan", "VSU", "SAA1099", "ES5503", "ES5506", "X1-010", "C352", "GA20"}; /*if (ChipID == 0x21) { static char TempStr[0x08]; UINT32 TempData[2]; //EncryptChipName(TempData, "WSwan", 0x08); TempData[0] = 0x1015170F; TempData[1] = 0x001F1C07; EncryptChipName(TempStr, TempData, 0x08); return TempStr; // "WSwan" }*/ if (ChipID < CHIP_COUNT) return CHIP_STRS[ChipID]; else return NULL; } const char* GetAccurateChipName(UINT8 ChipID, UINT8 SubType) { const char* RetStr; if ((ChipID & 0x7F) >= CHIP_COUNT) return NULL; RetStr = NULL; switch(ChipID & 0x7F) { case 0x00: if (! (ChipID & 0x80)) { switch(SubType) { case 0x01: RetStr = "SN76489"; break; case 0x02: RetStr = "SN76489A"; break; case 0x03: RetStr = "SN76494"; break; case 0x04: RetStr = "SN76496"; break; case 0x05: RetStr = "SN94624"; break; case 0x06: RetStr = "NCR7496"; break; case 0x07: RetStr = "SEGA PSG"; break; default: RetStr = "SN76496"; break; } } else { RetStr = "T6W28"; } break; case 0x01: if (ChipID & 0x80) RetStr = "VRC7"; break; case 0x04: RetStr = "Sega PCM"; break; case 0x08: if (! (ChipID & 0x80)) RetStr = "YM2610"; else RetStr = "YM2610B"; break; case 0x12: // AY8910 switch(SubType) { case 0x00: RetStr = "AY-3-8910"; break; case 0x01: RetStr = "AY-3-8912"; break; case 0x02: RetStr = "AY-3-8913"; break; case 0x03: RetStr = "AY8930"; break; case 0x04: RetStr = "AY-3-8914"; break; case 0x10: RetStr = "YM2149"; break; case 0x11: RetStr = "YM3439"; break; case 0x12: RetStr = "YMZ284"; break; case 0x13: RetStr = "YMZ294"; break; } break; case 0x13: RetStr = "GB DMG"; break; case 0x14: if (! (ChipID & 0x80)) RetStr = "NES APU"; else RetStr = "NES APU + FDS"; break; case 0x1C: switch(SubType) { case 0x00: case 0x01: RetStr = "C140"; break; case 0x02: RetStr = "C140 (219)"; break; } break; case 0x21: RetStr = "WonderSwan"; break; case 0x22: RetStr = "VSU-VUE"; break; case 0x25: if (! (ChipID & 0x80)) RetStr = "ES5505"; else RetStr = "ES5506"; break; case 0x28: RetStr = "Irem GA20"; break; } // catch all default-cases if (RetStr == NULL) RetStr = GetChipName(ChipID & 0x7F); return RetStr; } UINT32 GetChipClock(void* _p, UINT8 ChipID, UINT8* RetSubType) { UINT32 Clock; UINT8 SubType; UINT8 CurChp; bool AllowBit31; VGM_PLAYER* p = (VGM_PLAYER *)_p; VGM_HEADER* FileHead = &p->VGMHead; SubType = 0x00; AllowBit31 = 0x00; switch(ChipID & 0x7F) { case 0x00: Clock = FileHead->lngHzPSG; AllowBit31 = 0x01; // T6W28 Mode if (RetSubType != NULL && ! (Clock & 0x80000000)) // The T6W28 is handles differently. { switch(FileHead->bytPSG_SRWidth) { case 0x0F: // 0x4000 if (FileHead->bytPSG_Flags & 0x08) // Clock Divider == 1? SubType = 0x05; // SN94624 else SubType = 0x01; // SN76489 break; case 0x10: // 0x8000 if (FileHead->shtPSG_Feedback == 0x0009) SubType = 0x07; // SEGA PSG else if (FileHead->shtPSG_Feedback == 0x0022) SubType = 0x06; // NCR7496 break; case 0x11: // 0x10000 if (FileHead->bytPSG_Flags & 0x08) // Clock Divider == 1? SubType = 0x03; // SN76494 else SubType = 0x02; // SN76489A/SN76496 break; } /* FbMask Noise Taps Negate Stereo Dv Freq0 Fb SR Flags 01 SN76489 0x4000, 0x01, 0x02, TRUE, FALSE, 8, TRUE 03 0F 07 (02|04|00|01) [unverified] 02 SN76489A 0x10000, 0x04, 0x08, FALSE, FALSE, 8, TRUE 0C 11 05 (00|04|00|01) 03 SN76494 0x10000, 0x04, 0x08, FALSE, FALSE, 1, TRUE 0C 11 0D (00|04|08|01) 04 SN76496 0x10000, 0x04, 0x08, FALSE, FALSE, 8, TRUE 0C 11 05 (00|04|00|01) [same as SN76489A] 05 SN94624 0x4000, 0x01, 0x02, TRUE, FALSE, 1, TRUE 03 0F 0F (02|04|08|01) [unverified, SN76489A without /8] 06 NCR7496 0x8000, 0x02, 0x20, FALSE, FALSE, 8, TRUE 22 10 05 (00|04|00|01) [unverified] 07 GameGear PSG 0x8000, 0x01, 0x08, TRUE, TRUE, 8, FALSE 09 10 02 (02|00|00|00) 07 SEGA VDP PSG 0x8000, 0x01, 0x08, TRUE, FALSE, 8, FALSE 09 10 06 (02|04|00|00) 01 U8106 0x4000, 0x01, 0x02, TRUE, FALSE, 8, TRUE 03 0F 07 (02|04|00|01) [unverified, same as SN76489] 02 Y2404 0x10000, 0x04, 0x08, FALSE, FALSE; 8, TRUE 0C 11 05 (00|04|00|01) [unverified, same as SN76489A] -- T6W28 0x4000, 0x01, 0x04, ????, FALSE, 8, ???? 05 0F ?? (??|??|00|01) [It IS stereo, but not in GameGear way]. */ } break; case 0x01: Clock = FileHead->lngHzYM2413; AllowBit31 = 0x01; // VRC7 Mode break; case 0x02: Clock = FileHead->lngHzYM2612; break; case 0x03: Clock = FileHead->lngHzYM2151; break; case 0x04: Clock = FileHead->lngHzSPCM; break; case 0x05: if (ChipID & 0x80) return 0; Clock = FileHead->lngHzRF5C68; break; case 0x06: Clock = FileHead->lngHzYM2203; break; case 0x07: Clock = FileHead->lngHzYM2608; break; case 0x08: Clock = FileHead->lngHzYM2610; AllowBit31 = 0x01; // YM2610B Mode break; case 0x09: Clock = FileHead->lngHzYM3812; AllowBit31 = 0x01; // Dual OPL2, panned to the L/R speakers break; case 0x0A: Clock = FileHead->lngHzYM3526; break; case 0x0B: Clock = FileHead->lngHzY8950; break; case 0x0C: Clock = FileHead->lngHzYMF262; break; case 0x0D: Clock = FileHead->lngHzYMF278B; break; case 0x0E: Clock = FileHead->lngHzYMF271; break; case 0x0F: Clock = FileHead->lngHzYMZ280B; break; case 0x10: if (ChipID & 0x80) return 0; Clock = FileHead->lngHzRF5C164; AllowBit31 = 0x01; // hack for Cosmic Fantasy Stories break; case 0x11: if (ChipID & 0x80) return 0; Clock = FileHead->lngHzPWM; break; case 0x12: Clock = FileHead->lngHzAY8910; SubType = FileHead->bytAYType; break; case 0x13: Clock = FileHead->lngHzGBDMG; break; case 0x14: Clock = FileHead->lngHzNESAPU; AllowBit31 = 0x01; // FDS Enable break; case 0x15: Clock = FileHead->lngHzMultiPCM; break; case 0x16: Clock = FileHead->lngHzUPD7759; AllowBit31 = 0x01; // Master/Slave Bit break; case 0x17: Clock = FileHead->lngHzOKIM6258; break; case 0x18: Clock = FileHead->lngHzOKIM6295; AllowBit31 = 0x01; // Pin 7 State break; case 0x19: Clock = FileHead->lngHzK051649; break; case 0x1A: Clock = FileHead->lngHzK054539; break; case 0x1B: Clock = FileHead->lngHzHuC6280; break; case 0x1C: Clock = FileHead->lngHzC140; SubType = FileHead->bytC140Type; break; case 0x1D: Clock = FileHead->lngHzK053260; break; case 0x1E: Clock = FileHead->lngHzPokey; break; case 0x1F: if (ChipID & 0x80) return 0; Clock = FileHead->lngHzQSound; break; case 0x20: Clock = FileHead->lngHzSCSP; break; case 0x21: Clock = FileHead->lngHzWSwan; break; case 0x22: Clock = FileHead->lngHzVSU; break; case 0x23: Clock = FileHead->lngHzSAA1099; break; case 0x24: Clock = FileHead->lngHzES5503; break; case 0x25: Clock = FileHead->lngHzES5506; AllowBit31 = 0x01; // ES5505/5506 switch break; case 0x26: Clock = FileHead->lngHzX1_010; break; case 0x27: Clock = FileHead->lngHzC352; break; case 0x28: Clock = FileHead->lngHzGA20; break; default: return 0; } if (ChipID & 0x80) { VGMX_CHP_EXTRA32* TempCX; if (! (Clock & 0x40000000)) return 0; ChipID &= 0x7F; TempCX = &p->VGMH_Extra.Clocks; for (CurChp = 0x00; CurChp < TempCX->ChipCnt; CurChp ++) { if (TempCX->CCData[CurChp].Type == ChipID) { if (TempCX->CCData[CurChp].Data) Clock = TempCX->CCData[CurChp].Data; break; } } } if (RetSubType != NULL) *RetSubType = SubType; if (AllowBit31) return Clock & 0xBFFFFFFF; else return Clock & 0x3FFFFFFF; } static UINT16 GetChipVolume(VGM_PLAYER* p, UINT8 ChipID, UINT8 ChipNum, UINT8 ChipCnt) { // ChipID: ID of Chip // Bit 7 - Is Paired Chip // ChipNum: chip number (0 - first chip, 1 - second chip) // ChipCnt: chip volume divider (number of used chips) const UINT16 CHIP_VOLS[CHIP_COUNT] = { 0x80, 0x200/*0x155*/, 0x100, 0x100, 0x180, 0xB0, 0x100, 0x80, // 00-07 0x80, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x98, // 08-0F 0x80, 0xE0/*0xCD*/, 0x100, 0xC0, 0x100, 0x40, 0x11E, 0x1C0, // 10-17 0x100/*110*/, 0xA0, 0x100, 0x100, 0x100, 0xB3, 0x100, 0x100, // 18-1F 0x100, 0x100, 0x100, 0x100, 0x40, 0x20, 0x100, 0x40, // 20-27 0x280}; UINT16 Volume; UINT8 CurChp; VGMX_CHP_EXTRA16* TempCX; VGMX_CHIP_DATA16* TempCD; VGM_HEADER* FileHead = &p->VGMHead; Volume = CHIP_VOLS[ChipID & 0x7F]; switch(ChipID) { case 0x00: // SN76496 // if T6W28, set Volume Divider to 01 if (GetChipClock(p, (ChipID << 7) | ChipID, NULL) & 0x80000000) { // The T6W28 consists of 2 "half" chips. ChipNum = 0x01; ChipCnt = 0x01; } break; case 0x18: // OKIM6295 // CP System 1 patch if (p->VGMTag.strSystemNameE != NULL && ! wcsncmp(p->VGMTag.strSystemNameE, L"CP", 0x02)) Volume = 110; break; case 0x86: // YM2203's AY Volume /= 2; break; case 0x87: // YM2608's AY // The YM2608 outputs twice as loud as the YM2203 here. //Volume *= 1; break; case 0x88: // YM2610's AY //Volume *= 1; break; } if (ChipCnt > 1) Volume /= ChipCnt; TempCX = &p->VGMH_Extra.Volumes; TempCD = TempCX->CCData; for (CurChp = 0x00; CurChp < TempCX->ChipCnt; CurChp ++, TempCD ++) { if (TempCD->Type == ChipID && (TempCD->Flags & 0x01) == ChipNum) { // Bit 15 - absolute/relative volume // 0 - absolute // 1 - relative (0x0100 = 1.0, 0x80 = 0.5, etc.) if (TempCD->Data & 0x8000) Volume = (Volume * (TempCD->Data & 0x7FFF) + 0x80) >> 8; else { Volume = TempCD->Data; if ((ChipID & 0x80) && p->DoubleSSGVol) Volume *= 2; } break; } } return Volume; } static void RestartPlaying(VGM_PLAYER* p) { p->VGMPos = p->VGMHead.lngDataOffset; p->VGMSmplPos = 0; p->VGMSmplPlayed = 0; p->VGMEnd = false; p->EndPlay = false; p->VGMCurLoop = 0x00; Chips_GeneralActions(p, 0x01); // Reset Chips // also does Muting Mask (0x10) and Panning (0x20) p->Last95Drum = 0xFFFF; p->Last95Freq = 0; p->ForceVGMExec = true; p->IsVGMInit = true; InterpretFile(p, 0); p->IsVGMInit = false; p->ForceVGMExec = false; return; } static void Chips_GeneralActions(VGM_PLAYER* p, UINT8 Mode) { UINT32 AbsVol; //UINT16 ChipVol; CAUD_ATTR* CAA; CHIP_OPTS* COpt; UINT8 ChipCnt; UINT8 CurChip; UINT8 CurCSet; // Chip Set UINT32 MaskVal; UINT32 ChipClk; switch(Mode) { case 0x00: // Start Chips for (CurCSet = 0x00; CurCSet < 0x02; CurCSet ++) { CAA = (CAUD_ATTR*)&p->ChipAudio[CurCSet]; for (CurChip = 0x00; CurChip < CHIP_COUNT; CurChip ++, CAA ++) { CAA->SmpRate = 0x00; CAA->Volume = 0x00; CAA->ChipType = 0xFF; CAA->ChipID = CurCSet; CAA->Resampler = 0x00; CAA->StreamUpdate = &null_update; CAA->StreamUpdateParam = NULL; CAA->Paired = NULL; } CAA = p->CA_Paired[CurCSet]; for (CurChip = 0x00; CurChip < 0x03; CurChip ++, CAA ++) { CAA->SmpRate = 0x00; CAA->Volume = 0x00; CAA->ChipType = 0xFF; CAA->ChipID = CurCSet; CAA->Resampler = 0x00; CAA->StreamUpdate = &null_update; CAA->StreamUpdateParam = NULL; CAA->Paired = NULL; } } // Initialize Sound Chips AbsVol = 0x00; if (p->VGMHead.lngHzPSG) { //ChipVol = UseFM ? 0x00 : 0x80; p->ChipOpts[0x01].SN76496.EmuCore = p->ChipOpts[0x00].SN76496.EmuCore; ChipCnt = (p->VGMHead.lngHzPSG & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].SN76496; CAA->ChipType = 0x00; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); ChipClk &= ~0x80000000; ChipClk |= p->VGMHead.lngHzPSG & ((CurChip & 0x01) << 31); CAA->SmpRate = device_start_sn764xx(&p->sn764xx[CurChip], p->ChipOpts[CurChip].SN76496.EmuCore, ChipClk, p->SampleRate, p->VGMHead.bytPSG_SRWidth, p->VGMHead.shtPSG_Feedback, (p->VGMHead.bytPSG_Flags & 0x02) >> 1, (p->VGMHead.bytPSG_Flags & 0x04) >> 2, (p->VGMHead.bytPSG_Flags & 0x08) >> 3, (p->VGMHead.bytPSG_Flags & 0x01) >> 0); CAA->StreamUpdate = &sn764xx_stream_update; CAA->StreamUpdateParam = p->sn764xx[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); if (! CurChip || ! (ChipClk & 0x80000000)) AbsVol += CAA->Volume; } if (p->VGMHead.lngHzPSG & 0x80000000) ChipCnt = 0x01; } if (p->VGMHead.lngHzYM2413) { //ChipVol = UseFM ? 0x00 : 0x200/*0x155*/; p->ChipOpts[0x01].YM2413.EmuCore = p->ChipOpts[0x00].YM2413.EmuCore; ChipCnt = (p->VGMHead.lngHzYM2413 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].YM2413; CAA->ChipType = 0x01; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_ym2413(&p->ym2413[CurChip], p->ChipOpts[CurChip].YM2413.EmuCore, ChipClk, p->CHIP_SAMPLING_MODE, p->CHIP_SAMPLE_RATE); CAA->StreamUpdate = &ym2413_stream_update; CAA->StreamUpdateParam = p->ym2413[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); // WHY has this chip such a low volume??? //AbsVol += (CAA->Volume + 1) * 3 / 4; AbsVol += CAA->Volume / 2; } } if (p->VGMHead.lngHzYM2612) { //ChipVol = 0x100; p->ChipOpts[0x01].YM2612.EmuCore = p->ChipOpts[0x00].YM2612.EmuCore; p->ChipOpts[0x01].YM2612.SpecialFlags = p->ChipOpts[0x00].YM2612.SpecialFlags; ChipCnt = (p->VGMHead.lngHzYM2612 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].YM2612; CAA->ChipType = 0x02; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_ym2612(&p->ym2612[CurChip], p->ChipOpts[CurChip].YM2612.EmuCore, p->ChipOpts[CurChip].YM2612.SpecialFlags, ChipClk, p->CHIP_SAMPLING_MODE, p->CHIP_SAMPLE_RATE, &p->IsVGMInit); CAA->StreamUpdate = &ym2612_stream_update; CAA->StreamUpdateParam = p->ym2612[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume; } } if (p->VGMHead.lngHzYM2151) { //ChipVol = 0x100; ChipCnt = (p->VGMHead.lngHzYM2151 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].YM2151; CAA->ChipType = 0x03; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_ym2151(&p->ym2151[CurChip], ChipClk, p->CHIP_SAMPLING_MODE, p->CHIP_SAMPLE_RATE); CAA->StreamUpdate = &ym2151_update; CAA->StreamUpdateParam = p->ym2151[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume; } } if (p->VGMHead.lngHzSPCM) { //ChipVol = 0x180; ChipCnt = (p->VGMHead.lngHzSPCM & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].SegaPCM; CAA->ChipType = 0x04; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_segapcm(&p->segapcm[CurChip], ChipClk, p->VGMHead.lngSPCMIntf); CAA->StreamUpdate = &SEGAPCM_update; CAA->StreamUpdateParam = p->segapcm[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume; } } if (p->VGMHead.lngHzRF5C68) { //ChipVol = 0xB0; // that's right according to MAME, but it's almost too loud ChipCnt = 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].RF5C68; CAA->ChipType = 0x05; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_rf5c68(&p->rf5c68, ChipClk); CAA->StreamUpdate = &rf5c68_update; CAA->StreamUpdateParam = p->rf5c68; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume; } } if (p->VGMHead.lngHzYM2203) { //ChipVol = 0x100; p->ChipOpts[0x01].YM2203.EmuCore = p->ChipOpts[0x00].YM2203.EmuCore; p->ChipOpts[0x01].YM2203.SpecialFlags = p->ChipOpts[0x00].YM2203.SpecialFlags; ChipCnt = (p->VGMHead.lngHzYM2203 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].YM2203; COpt = &p->ChipOpts[CurChip].YM2203; CAA->ChipType = 0x06; CAA->Paired = &p->CA_Paired[CurChip][0x00]; CAA->Paired->ChipType = 0x80 | CAA->ChipType; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_ym2203(&p->ym2203[CurChip], COpt->EmuCore, ChipClk, COpt->SpecialFlags & 0x01, p->VGMHead.bytAYFlagYM2203, (int*) &CAA->Paired->SmpRate, p->CHIP_SAMPLING_MODE, p->CHIP_SAMPLE_RATE); CAA->StreamUpdate = &ym2203_stream_update; CAA->StreamUpdateParam = p->ym2203[CurChip]; CAA->Paired->StreamUpdate = &ym2203_stream_update_ay; CAA->Paired->StreamUpdateParam = p->ym2203[CurChip]; ym2203_set_srchg_cb(p->ym2203[CurChip], &ChangeChipSampleRate, CAA, CAA->Paired); CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); CAA->Paired->Volume = GetChipVolume(p, CAA->Paired->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume + CAA->Paired->Volume; } } if (p->VGMHead.lngHzYM2608) { //ChipVol = 0x80; p->ChipOpts[0x01].YM2608.EmuCore = p->ChipOpts[0x00].YM2608.EmuCore; p->ChipOpts[0x01].YM2608.SpecialFlags = p->ChipOpts[0x00].YM2608.SpecialFlags; ChipCnt = (p->VGMHead.lngHzYM2608 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].YM2608; COpt = &p->ChipOpts[CurChip].YM2608; CAA->ChipType = 0x07; CAA->Paired = &p->CA_Paired[CurChip][0x01]; CAA->Paired->ChipType = 0x80 | CAA->ChipType; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_ym2608(&p->ym2608[CurChip], COpt->EmuCore, ChipClk, COpt->SpecialFlags & 0x01, p->VGMHead.bytAYFlagYM2608, (int*) &CAA->Paired->SmpRate, p->CHIP_SAMPLING_MODE, p->CHIP_SAMPLE_RATE); CAA->StreamUpdate = &ym2608_stream_update; CAA->StreamUpdateParam = p->ym2608[CurChip]; CAA->Paired->StreamUpdate = &ym2608_stream_update_ay; CAA->Paired->StreamUpdateParam = p->ym2608[CurChip]; ym2608_set_srchg_cb(p->ym2608[CurChip], &ChangeChipSampleRate, CAA, CAA->Paired); CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); CAA->Paired->Volume = GetChipVolume(p, CAA->Paired->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume + CAA->Paired->Volume; //CAA->Volume = ChipVol; //CAA->Paired->Volume = ChipVol * 2; } } if (p->VGMHead.lngHzYM2610) { //ChipVol = 0x80; p->ChipOpts[0x01].YM2610.EmuCore = p->ChipOpts[0x00].YM2610.EmuCore; p->ChipOpts[0x01].YM2610.SpecialFlags = p->ChipOpts[0x00].YM2610.SpecialFlags; ChipCnt = (p->VGMHead.lngHzYM2610 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].YM2610; COpt = &p->ChipOpts[CurChip].YM2610; CAA->ChipType = 0x08; CAA->Paired = &p->CA_Paired[CurChip][0x02]; CAA->Paired->ChipType = 0x80 | CAA->ChipType; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_ym2610(&p->ym2610[CurChip], COpt->EmuCore, ChipClk, COpt->SpecialFlags & 0x01, (int*) &CAA->Paired->SmpRate, p->CHIP_SAMPLING_MODE, p->CHIP_SAMPLE_RATE); CAA->StreamUpdate = (ChipClk & 0x80000000) ? ym2610b_stream_update : ym2610_stream_update; CAA->StreamUpdateParam = p->ym2610[CurChip]; CAA->Paired->StreamUpdate = &ym2610_stream_update_ay; CAA->Paired->StreamUpdateParam = p->ym2610[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); CAA->Paired->Volume = GetChipVolume(p, CAA->Paired->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume + CAA->Paired->Volume; //CAA->Volume = ChipVol; //CAA->Paired->Volume = ChipVol * 2; } } if (p->VGMHead.lngHzYM3812) { //ChipVol = UseFM ? 0x00 : 0x100; p->ChipOpts[0x01].YM3812.EmuCore = p->ChipOpts[0x00].YM3812.EmuCore; ChipCnt = (p->VGMHead.lngHzYM3812 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].YM3812; CAA->ChipType = 0x09; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_ym3812(&p->ym3812[CurChip], p->ChipOpts[CurChip].YM3812.EmuCore, ChipClk, p->CHIP_SAMPLING_MODE, p->CHIP_SAMPLE_RATE); if (ChipClk & 0x80000000) { struct dual_opl2_info * info = (struct dual_opl2_info *) malloc(sizeof(struct dual_opl2_info)); CAA->StreamUpdate = dual_opl2_stereo; CAA->StreamUpdateParam = (void *) info; info->chip = p->ym3812[CurChip]; info->ChipID = CurChip; p->ym3812_dual_data[CurChip] = (void *) info; } else { CAA->StreamUpdate = ym3812_stream_update; CAA->StreamUpdateParam = p->ym3812[CurChip]; p->ym3812_dual_data[CurChip] = NULL; } CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); if (! CurChip || ! (ChipClk & 0x80000000)) AbsVol += CAA->Volume * 2; } } if (p->VGMHead.lngHzYM3526) { //ChipVol = UseFM ? 0x00 : 0x100; ChipCnt = (p->VGMHead.lngHzYM3526 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].YM3526; CAA->ChipType = 0x0A; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_ym3526(&p->ym3526[CurChip], ChipClk, p->CHIP_SAMPLING_MODE, p->CHIP_SAMPLE_RATE); CAA->StreamUpdate = &ym3526_stream_update; CAA->StreamUpdateParam = p->ym3526[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume * 2; } } if (p->VGMHead.lngHzY8950) { //ChipVol = UseFM ? 0x00 : 0x100; ChipCnt = (p->VGMHead.lngHzY8950 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].Y8950; CAA->ChipType = 0x0B; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_y8950(&p->y8950[CurChip], ChipClk, p->CHIP_SAMPLING_MODE, p->CHIP_SAMPLE_RATE); CAA->StreamUpdate = &y8950_stream_update; CAA->StreamUpdateParam = p->y8950[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume * 2; } } if (p->VGMHead.lngHzYMF262) { //ChipVol = UseFM ? 0x00 : 0x100; p->ChipOpts[0x01].YMF262.EmuCore = p->ChipOpts[0x00].YMF262.EmuCore; ChipCnt = (p->VGMHead.lngHzYMF262 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].YMF262; CAA->ChipType = 0x0C; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_ymf262(&p->ymf262[CurChip], p->ChipOpts[CurChip].YMF262.EmuCore, ChipClk, p->CHIP_SAMPLING_MODE, p->CHIP_SAMPLE_RATE); CAA->StreamUpdate = &ymf262_stream_update; CAA->StreamUpdateParam = p->ymf262[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume * 2; } } if (p->VGMHead.lngHzYMF278B) { //ChipVol = 0x100; ChipCnt = (p->VGMHead.lngHzYMF278B & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].YMF278B; CAA->ChipType = 0x0D; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_ymf278b(&p->ymf278b[CurChip], ChipClk); CAA->StreamUpdate = &ymf278b_pcm_update; CAA->StreamUpdateParam = p->ymf278b[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume; //good as long as it only uses WaveTable Synth } } if (p->VGMHead.lngHzYMF271) { //ChipVol = 0x100; ChipCnt = (p->VGMHead.lngHzYMF271 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].YMF271; CAA->ChipType = 0x0E; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_ymf271(&p->ymf271[CurChip], ChipClk); CAA->StreamUpdate = &ymf271_update; CAA->StreamUpdateParam = p->ymf271[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume; } } if (p->VGMHead.lngHzYMZ280B) { //ChipVol = 0x98; ChipCnt = (p->VGMHead.lngHzYMZ280B & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].YMZ280B; CAA->ChipType = 0x0F; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_ymz280b(&p->ymz280b[CurChip], ChipClk); CAA->StreamUpdate = &ymz280b_update; CAA->StreamUpdateParam = p->ymz280b[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += (CAA->Volume * 0x20 / 0x13); } } if (p->VGMHead.lngHzRF5C164) { //ChipVol = 0x80; ChipCnt = 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].RF5C164; CAA->ChipType = 0x10; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_rf5c164(&p->rf5c164, ChipClk, p->CHIP_SAMPLING_MODE, p->CHIP_SAMPLE_RATE); CAA->StreamUpdate = &rf5c164_update; CAA->StreamUpdateParam = p->rf5c164; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume * 2; } } if (p->VGMHead.lngHzPWM) { //ChipVol = 0xE0; // 0xCD ChipCnt = 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].PWM; CAA->ChipType = 0x11; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_pwm(&p->pwm, ChipClk, p->CHIP_SAMPLING_MODE, p->CHIP_SAMPLE_RATE); CAA->StreamUpdate = &pwm_update; CAA->StreamUpdateParam = p->pwm; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume; } } if (p->VGMHead.lngHzAY8910) { //ChipVol = 0x100; p->ChipOpts[0x01].AY8910.EmuCore = p->ChipOpts[0x00].AY8910.EmuCore; ChipCnt = (p->VGMHead.lngHzAY8910 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].AY8910; CAA->ChipType = 0x12; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_ayxx(&p->ay8910[CurChip], p->ChipOpts[CurChip].AY8910.EmuCore, ChipClk, p->VGMHead.bytAYType, p->VGMHead.bytAYFlag, p->CHIP_SAMPLING_MODE, p->CHIP_SAMPLE_RATE); CAA->StreamUpdate = &ayxx_stream_update; CAA->StreamUpdateParam = p->ay8910[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume * 2; } } if (p->VGMHead.lngHzGBDMG) { //ChipVol = 0xC0; p->ChipOpts[0x01].GameBoy.SpecialFlags = p->ChipOpts[0x00].GameBoy.SpecialFlags; ChipCnt = (p->VGMHead.lngHzGBDMG & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].GameBoy; CAA->ChipType = 0x13; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_gameboy_sound(&p->gbdmg[CurChip], ChipClk, p->ChipOpts[CurChip].GameBoy.SpecialFlags, p->SampleRate); CAA->StreamUpdate = &gameboy_update; CAA->StreamUpdateParam = p->gbdmg[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume * 2; } } if (p->VGMHead.lngHzNESAPU) { //ChipVol = 0x100; p->ChipOpts[0x01].NES.EmuCore = p->ChipOpts[0x00].NES.EmuCore; p->ChipOpts[0x01].NES.SpecialFlags = p->ChipOpts[0x00].NES.SpecialFlags; ChipCnt = (p->VGMHead.lngHzNESAPU & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].NES; COpt = &p->ChipOpts[CurChip].NES; CAA->ChipType = 0x14; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_nes(&p->nesapu[CurChip], COpt->EmuCore, ChipClk, COpt->SpecialFlags, p->CHIP_SAMPLING_MODE, p->CHIP_SAMPLE_RATE); CAA->StreamUpdate = &nes_stream_update; CAA->StreamUpdateParam = p->nesapu[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume * 2; } } if (p->VGMHead.lngHzMultiPCM) { //ChipVol = 0x40; ChipCnt = (p->VGMHead.lngHzMultiPCM & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].MultiPCM; CAA->ChipType = 0x15; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_multipcm(&p->multipcm[CurChip], ChipClk); CAA->StreamUpdate = &MultiPCM_update; CAA->StreamUpdateParam = p->multipcm[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume * 4; } } if (p->VGMHead.lngHzUPD7759) { //ChipVol = 0x11E; ChipCnt = (p->VGMHead.lngHzUPD7759 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].UPD7759; CAA->ChipType = 0x16; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_upd7759(&p->upd7759[CurChip], ChipClk); CAA->StreamUpdate = &upd7759_update; CAA->StreamUpdateParam = p->upd7759[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume; } } if (p->VGMHead.lngHzOKIM6258) { //ChipVol = 0x1C0; p->ChipOpts[0x01].OKIM6258.SpecialFlags = p->ChipOpts[0x00].OKIM6258.SpecialFlags; ChipCnt = (p->VGMHead.lngHzOKIM6258 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].OKIM6258; CAA->ChipType = 0x17; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_okim6258(&p->okim6258[CurChip], ChipClk, p->ChipOpts[CurChip].OKIM6258.SpecialFlags, (p->VGMHead.bytOKI6258Flags & 0x03) >> 0, (p->VGMHead.bytOKI6258Flags & 0x04) >> 2, (p->VGMHead.bytOKI6258Flags & 0x08) >> 3); CAA->StreamUpdate = &okim6258_update; CAA->StreamUpdateParam = p->okim6258[CurChip]; okim6258_set_srchg_cb(p->okim6258[CurChip], &ChangeChipSampleRate, CAA); CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume * 2; } } if (p->VGMHead.lngHzOKIM6295) { /*// Use the System Tag to decide between normal and CP System volume level. // I know, this is very hackish, but ATM there's no better solution. if (VGMTag.strSystemNameE != NULL && ! wcsncmp(VGMTag.strSystemNameE, L"CP", 0x02)) ChipVol = 110; else ChipVol = 0x100;*/ ChipCnt = (p->VGMHead.lngHzOKIM6295 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].OKIM6295; CAA->ChipType = 0x18; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_okim6295(&p->okim6295[CurChip], ChipClk); CAA->StreamUpdate = &okim6295_update; CAA->StreamUpdateParam = p->okim6295[CurChip]; okim6295_set_srchg_cb(p->okim6295[CurChip], &ChangeChipSampleRate, CAA); CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume * 2; } } if (p->VGMHead.lngHzK051649) { //ChipVol = 0xA0; ChipCnt = (p->VGMHead.lngHzK051649 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].K051649; CAA->ChipType = 0x19; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_k051649(&p->k051649[CurChip], ChipClk); CAA->StreamUpdate = &k051649_update; CAA->StreamUpdateParam = p->k051649[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume; } } if (p->VGMHead.lngHzK054539) { //ChipVol = 0x100; ChipCnt = (p->VGMHead.lngHzK054539 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].K054539; CAA->ChipType = 0x1A; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_k054539(&p->k054539[CurChip], ChipClk); CAA->StreamUpdate = &k054539_update; CAA->StreamUpdateParam = p->k054539[CurChip]; k054539_init_flags(p->k054539[CurChip], p->VGMHead.bytK054539Flags); CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume; } } if (p->VGMHead.lngHzHuC6280) { //ChipVol = 0x100; p->ChipOpts[0x01].HuC6280.EmuCore = p->ChipOpts[0x00].HuC6280.EmuCore; ChipCnt = (p->VGMHead.lngHzHuC6280 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].HuC6280; CAA->ChipType = 0x1B; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_c6280(&p->huc6280[CurChip], p->ChipOpts[CurChip].HuC6280.EmuCore, ChipClk, p->SampleRate, p->CHIP_SAMPLING_MODE, p->CHIP_SAMPLE_RATE); CAA->StreamUpdate = &c6280_update; CAA->StreamUpdateParam = p->huc6280[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume; } } if (p->VGMHead.lngHzC140) { //ChipVol = 0x100; ChipCnt = (p->VGMHead.lngHzC140 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].C140; CAA->ChipType = 0x1C; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_c140(&p->c140[CurChip], ChipClk, p->VGMHead.bytC140Type, p->CHIP_SAMPLING_MODE, p->CHIP_SAMPLE_RATE); CAA->StreamUpdate = &c140_update; CAA->StreamUpdateParam = p->c140[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume; } } if (p->VGMHead.lngHzK053260) { //ChipVol = 0xB3; ChipCnt = (p->VGMHead.lngHzK053260 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].K053260; CAA->ChipType = 0x1D; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_k053260(&p->k053260[CurChip], ChipClk); CAA->StreamUpdate = &k053260_update; CAA->StreamUpdateParam = p->k053260[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume; } } if (p->VGMHead.lngHzPokey) { //ChipVol = 0x100; ChipCnt = (p->VGMHead.lngHzPokey & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].Pokey; CAA->ChipType = 0x1E; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_pokey(&p->pokey[CurChip], ChipClk); CAA->StreamUpdate = &pokey_update; CAA->StreamUpdateParam = p->pokey[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume; } } if (p->VGMHead.lngHzQSound) { //ChipVol = 0x100; ChipCnt = (p->VGMHead.lngHzQSound & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].QSound; CAA->ChipType = 0x1F; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_qsound(&p->qsound[CurChip], ChipClk); CAA->StreamUpdate = &qsound_update; CAA->StreamUpdateParam = p->qsound[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume; } } if (p->VGMHead.lngHzSCSP) { p->ChipOpts[0x01].SCSP.SpecialFlags = p->ChipOpts[0x00].SCSP.SpecialFlags; //ChipVol = 0x100; ChipCnt = (p->VGMHead.lngHzSCSP & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].SCSP; CAA->ChipType = 0x20; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_scsp(&p->scsp[CurChip], ChipClk, p->ChipOpts[CurChip].SCSP.SpecialFlags); CAA->StreamUpdate = &SCSP_Update; CAA->StreamUpdateParam = p->scsp[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume; } } if (p->VGMHead.lngHzWSwan) { //ChipVol = 0x100; ChipCnt = (p->VGMHead.lngHzWSwan & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].WSwan; CAA->ChipType = 0x21; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = ws_audio_init(&p->wswan[CurChip], ChipClk, p->SampleRate, p->CHIP_SAMPLING_MODE, p->CHIP_SAMPLE_RATE); CAA->StreamUpdate = &ws_audio_update; CAA->StreamUpdateParam = p->wswan[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume; } } if (p->VGMHead.lngHzVSU) { //ChipVol = 0x100; ChipCnt = (p->VGMHead.lngHzVSU & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].VSU; CAA->ChipType = 0x22; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_vsu(&p->vsu[CurChip], ChipClk, p->CHIP_SAMPLING_MODE, p->CHIP_SAMPLE_RATE); CAA->StreamUpdate = &vsu_stream_update; CAA->StreamUpdateParam = p->vsu[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume; } } if (p->VGMHead.lngHzSAA1099) { //ChipVol = 0x100; ChipCnt = (p->VGMHead.lngHzSAA1099 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].SAA1099; CAA->ChipType = 0x23; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_saa1099(&p->saa1099[CurChip], ChipClk); CAA->StreamUpdate = &saa1099_update; CAA->StreamUpdateParam = p->saa1099[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume; } } if (p->VGMHead.lngHzES5503) { //ChipVol = 0x40; ChipCnt = (p->VGMHead.lngHzES5503 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].ES5503; CAA->ChipType = 0x24; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_es5503(&p->es5503[CurChip], ChipClk, p->VGMHead.bytES5503Chns); CAA->StreamUpdate = &es5503_pcm_update; CAA->StreamUpdateParam = p->es5503[CurChip]; es5503_set_srchg_cb(p->es5503[CurChip], &ChangeChipSampleRate, CAA); CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume * 8; } } if (p->VGMHead.lngHzES5506) { //ChipVol = 0x20; ChipCnt = (p->VGMHead.lngHzES5506 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].ES5506; CAA->ChipType = 0x25; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_es5506(&p->es550x[CurChip], ChipClk, p->VGMHead.bytES5506Chns); CAA->StreamUpdate = &es5506_update; CAA->StreamUpdateParam = p->es550x[CurChip]; es5506_set_srchg_cb(p->es550x[CurChip], &ChangeChipSampleRate, CAA); CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume * 16; } } if (p->VGMHead.lngHzX1_010) { //ChipVol = 0x100; ChipCnt = (p->VGMHead.lngHzX1_010 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].X1_010; CAA->ChipType = 0x26; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_x1_010(&p->x1_010[CurChip], ChipClk, p->CHIP_SAMPLING_MODE, p->CHIP_SAMPLE_RATE); CAA->StreamUpdate = &seta_update; CAA->StreamUpdateParam = p->x1_010[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume; } } if (p->VGMHead.lngHzC352) { //ChipVol = 0x40; ChipCnt = (p->VGMHead.lngHzC352 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].C352; CAA->ChipType = 0x27; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_c352(&p->c352[CurChip], ChipClk, p->VGMHead.bytC352ClkDiv * 4); CAA->StreamUpdate = &c352_update; CAA->StreamUpdateParam = p->c352[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume * 8; } } if (p->VGMHead.lngHzGA20) { //ChipVol = 0x280; ChipCnt = (p->VGMHead.lngHzGA20 & 0x40000000) ? 0x02 : 0x01; for (CurChip = 0x00; CurChip < ChipCnt; CurChip ++) { CAA = &p->ChipAudio[CurChip].GA20; CAA->ChipType = 0x28; ChipClk = GetChipClock(p, (CurChip << 7) | CAA->ChipType, NULL); CAA->SmpRate = device_start_iremga20(&p->ga20[CurChip], ChipClk); CAA->StreamUpdate = &IremGA20_update; CAA->StreamUpdateParam = p->ga20[CurChip]; CAA->Volume = GetChipVolume(p, CAA->ChipType, CurChip, ChipCnt); AbsVol += CAA->Volume; } } // Initialize DAC Control and PCM Bank p->DacCtrlUsed = 0x00; //memset(DacCtrlUsg, 0x00, 0x01 * 0xFF); for (CurChip = 0x00; CurChip < 0xFF; CurChip ++) { p->DacCtrl[CurChip].Enable = false; } //memset(p->DacCtrl, 0x00, sizeof(DACCTRL_DATA) * 0xFF); memset(p->PCMBank, 0x00, sizeof(VGM_PCM_BANK) * PCM_BANK_COUNT); memset(&p->PCMTbl, 0x00, sizeof(PCMBANK_TBL)); // Reset chips Chips_GeneralActions(p, 0x01); while(AbsVol < 0x200 && AbsVol) { for (CurCSet = 0x00; CurCSet < 0x02; CurCSet ++) { CAA = (CAUD_ATTR*)&p->ChipAudio[CurCSet]; for (CurChip = 0x00; CurChip < CHIP_COUNT; CurChip ++, CAA ++) CAA->Volume *= 2; CAA = p->CA_Paired[CurCSet]; for (CurChip = 0x00; CurChip < 0x03; CurChip ++, CAA ++) CAA->Volume *= 2; } AbsVol *= 2; } while(AbsVol > 0x300) { for (CurCSet = 0x00; CurCSet < 0x02; CurCSet ++) { CAA = (CAUD_ATTR*)&p->ChipAudio[CurCSet]; for (CurChip = 0x00; CurChip < CHIP_COUNT; CurChip ++, CAA ++) CAA->Volume /= 2; CAA = p->CA_Paired[CurCSet]; for (CurChip = 0x00; CurChip < 0x03; CurChip ++, CAA ++) CAA->Volume /= 2; } AbsVol /= 2; } // Initialize Resampler for (CurCSet = 0x00; CurCSet < 0x02; CurCSet ++) { CAA = (CAUD_ATTR*)&p->ChipAudio[CurCSet]; for (CurChip = 0x00; CurChip < CHIP_COUNT; CurChip ++, CAA ++) SetupResampler(p, CAA); CAA = p->CA_Paired[CurCSet]; for (CurChip = 0x00; CurChip < 0x03; CurChip ++, CAA ++) SetupResampler(p, CAA); } GeneralChipLists(p); break; case 0x01: // Reset chips for (CurCSet = 0x00; CurCSet < 0x02; CurCSet ++) { CAA = (CAUD_ATTR*)&p->ChipAudio[CurCSet]; for (CurChip = 0x00; CurChip < CHIP_COUNT; CurChip ++, CAA ++) { if (CAA->ChipType == 0xFF) // chip unused continue; else if (CAA->ChipType == 0x00) device_reset_sn764xx(p->sn764xx[CurCSet]); else if (CAA->ChipType == 0x01) device_reset_ym2413(p->ym2413[CurCSet]); else if (CAA->ChipType == 0x02) device_reset_ym2612(p->ym2612[CurCSet]); else if (CAA->ChipType == 0x03) device_reset_ym2151(p->ym2151[CurCSet]); else if (CAA->ChipType == 0x04) device_reset_segapcm(p->segapcm[CurCSet]); else if (CAA->ChipType == 0x05 && CurCSet == 0x00) device_reset_rf5c68(p->rf5c68); else if (CAA->ChipType == 0x06) device_reset_ym2203(p->ym2203[CurCSet]); else if (CAA->ChipType == 0x07) device_reset_ym2608(p->ym2608[CurCSet]); else if (CAA->ChipType == 0x08) device_reset_ym2610(p->ym2610[CurCSet]); else if (CAA->ChipType == 0x09) device_reset_ym3812(p->ym3812[CurCSet]); else if (CAA->ChipType == 0x0A) device_reset_ym3526(p->ym3526[CurCSet]); else if (CAA->ChipType == 0x0B) device_reset_y8950(p->y8950[CurCSet]); else if (CAA->ChipType == 0x0C) device_reset_ymf262(p->ymf262[CurCSet]); else if (CAA->ChipType == 0x0D) device_reset_ymf278b(p->ymf278b[CurCSet]); else if (CAA->ChipType == 0x0E) device_reset_ymf271(p->ymf271[CurCSet]); else if (CAA->ChipType == 0x0F) device_reset_ymz280b(p->ymz280b[CurCSet]); else if (CAA->ChipType == 0x10 && CurCSet == 0x00) device_reset_rf5c164(p->rf5c164); else if (CAA->ChipType == 0x11 && CurCSet == 0x00) device_reset_pwm(p->pwm); else if (CAA->ChipType == 0x12) device_reset_ayxx(p->ay8910[CurCSet]); else if (CAA->ChipType == 0x13) device_reset_gameboy_sound(p->gbdmg[CurCSet]); else if (CAA->ChipType == 0x14) device_reset_nes(p->nesapu[CurCSet]); else if (CAA->ChipType == 0x15) device_reset_multipcm(p->multipcm[CurCSet]); else if (CAA->ChipType == 0x16) device_reset_upd7759(p->upd7759[CurCSet]); else if (CAA->ChipType == 0x17) device_reset_okim6258(p->okim6258[CurCSet]); else if (CAA->ChipType == 0x18) device_reset_okim6295(p->okim6295[CurCSet]); else if (CAA->ChipType == 0x19) device_reset_k051649(p->k051649[CurCSet]); else if (CAA->ChipType == 0x1A) device_reset_k054539(p->k054539[CurCSet]); else if (CAA->ChipType == 0x1B) device_reset_c6280(p->huc6280[CurCSet]); else if (CAA->ChipType == 0x1C) device_reset_c140(p->c140[CurCSet]); else if (CAA->ChipType == 0x1D) device_reset_k053260(p->k053260[CurCSet]); else if (CAA->ChipType == 0x1E) device_reset_pokey(p->pokey[CurCSet]); else if (CAA->ChipType == 0x1F) device_reset_qsound(p->qsound[CurCSet]); else if (CAA->ChipType == 0x20) device_reset_scsp(p->scsp[CurCSet]); else if (CAA->ChipType == 0x21) ws_audio_reset(p->wswan[CurCSet]); else if (CAA->ChipType == 0x22) device_reset_vsu(p->vsu[CurCSet]); else if (CAA->ChipType == 0x23) device_reset_saa1099(p->saa1099[CurCSet]); else if (CAA->ChipType == 0x24) device_reset_es5503(p->es5503[CurCSet]); else if (CAA->ChipType == 0x25) device_reset_es5506(p->es550x[CurCSet]); else if (CAA->ChipType == 0x26) device_reset_x1_010(p->x1_010[CurCSet]); else if (CAA->ChipType == 0x27) device_reset_c352(p->c352[CurCSet]); else if (CAA->ChipType == 0x28) device_reset_iremga20(p->ga20[CurCSet]); } // end for CurChip } // end for CurCSet Chips_GeneralActions(p, 0x10); // set muting mask Chips_GeneralActions(p, 0x20); // set panning for (CurChip = 0x00; CurChip < p->DacCtrlUsed; CurChip ++) { CurCSet = p->DacCtrlUsg[CurChip]; device_reset_daccontrol(p->daccontrol[CurCSet]); //DacCtrl[CurCSet].Enable = false; } //DacCtrlUsed = 0x00; //memset(DacCtrlUsg, 0x00, 0x01 * 0xFF); for (CurChip = 0x00; CurChip < PCM_BANK_COUNT; CurChip ++) { // reset PCM Bank, but not the data // (this way I don't need to decompress the data again when restarting) p->PCMBank[CurChip].DataPos = 0x00000000; p->PCMBank[CurChip].BnkPos = 0x00000000; } p->PCMTbl.EntryCount = 0x00; break; case 0x02: // Stop chips for (CurCSet = 0x00; CurCSet < 0x02; CurCSet ++) { CAA = (CAUD_ATTR*)&p->ChipAudio[CurCSet]; for (CurChip = 0x00; CurChip < CHIP_COUNT; CurChip ++, CAA ++) { if (CAA->ChipType == 0xFF) // chip unused continue; else if (CAA->ChipType == 0x00) device_stop_sn764xx(p->sn764xx[CurCSet]); else if (CAA->ChipType == 0x01) device_stop_ym2413(p->ym2413[CurCSet]); else if (CAA->ChipType == 0x02) device_stop_ym2612(p->ym2612[CurCSet]); else if (CAA->ChipType == 0x03) device_stop_ym2151(p->ym2151[CurCSet]); else if (CAA->ChipType == 0x04) device_stop_segapcm(p->segapcm[CurCSet]); else if (CAA->ChipType == 0x05 && CurCSet == 0x00) device_stop_rf5c68(p->rf5c68); else if (CAA->ChipType == 0x06) device_stop_ym2203(p->ym2203[CurCSet]); else if (CAA->ChipType == 0x07) device_stop_ym2608(p->ym2608[CurCSet]); else if (CAA->ChipType == 0x08) device_stop_ym2610(p->ym2610[CurCSet]); else if (CAA->ChipType == 0x09) { device_stop_ym3812(p->ym3812[CurCSet]); free(p->ym3812_dual_data[CurCSet]); p->ym3812_dual_data[CurCSet] = NULL; } else if (CAA->ChipType == 0x0A) device_stop_ym3526(p->ym3526[CurCSet]); else if (CAA->ChipType == 0x0B) device_stop_y8950(p->y8950[CurCSet]); else if (CAA->ChipType == 0x0C) device_stop_ymf262(p->ymf262[CurCSet]); else if (CAA->ChipType == 0x0D) device_stop_ymf278b(p->ymf278b[CurCSet]); else if (CAA->ChipType == 0x0E) device_stop_ymf271(p->ymf271[CurCSet]); else if (CAA->ChipType == 0x0F) device_stop_ymz280b(p->ymz280b[CurCSet]); else if (CAA->ChipType == 0x10 && CurCSet == 0x00) device_stop_rf5c164(p->rf5c164); else if (CAA->ChipType == 0x11 && CurCSet == 0x00) device_stop_pwm(p->pwm); else if (CAA->ChipType == 0x12) device_stop_ayxx(p->ay8910[CurCSet]); else if (CAA->ChipType == 0x13) device_stop_gameboy_sound(p->gbdmg[CurCSet]); else if (CAA->ChipType == 0x14) device_stop_nes(p->nesapu[CurCSet]); else if (CAA->ChipType == 0x15) device_stop_multipcm(p->multipcm[CurCSet]); else if (CAA->ChipType == 0x16) device_stop_upd7759(p->upd7759[CurCSet]); else if (CAA->ChipType == 0x17) device_stop_okim6258(p->okim6258[CurCSet]); else if (CAA->ChipType == 0x18) device_stop_okim6295(p->okim6295[CurCSet]); else if (CAA->ChipType == 0x19) device_stop_k051649(p->k051649[CurCSet]); else if (CAA->ChipType == 0x1A) device_stop_k054539(p->k054539[CurCSet]); else if (CAA->ChipType == 0x1B) device_stop_c6280(p->huc6280[CurCSet]); else if (CAA->ChipType == 0x1C) device_stop_c140(p->c140[CurCSet]); else if (CAA->ChipType == 0x1D) device_stop_k053260(p->k053260[CurCSet]); else if (CAA->ChipType == 0x1E) device_stop_pokey(p->pokey[CurCSet]); else if (CAA->ChipType == 0x1F) device_stop_qsound(p->qsound[CurCSet]); else if (CAA->ChipType == 0x20) device_stop_scsp(p->scsp[CurCSet]); else if (CAA->ChipType == 0x21) ws_audio_done(p->wswan[CurCSet]); else if (CAA->ChipType == 0x22) device_stop_vsu(p->vsu[CurCSet]); else if (CAA->ChipType == 0x23) device_stop_saa1099(p->saa1099[CurCSet]); else if (CAA->ChipType == 0x24) device_stop_es5503(p->es5503[CurCSet]); else if (CAA->ChipType == 0x25) device_stop_es5506(p->es550x[CurCSet]); else if (CAA->ChipType == 0x26) device_stop_x1_010(p->x1_010[CurCSet]); else if (CAA->ChipType == 0x27) device_stop_c352(p->c352[CurCSet]); else if (CAA->ChipType == 0x28) device_stop_iremga20(p->ga20[CurCSet]); resampler_destroy(CAA->Resampler); CAA->Resampler = 0x00; CAA->ChipType = 0xFF; // mark as "unused" } // end for CurChip } // end for CurCSet for (CurChip = 0x00; CurChip < p->DacCtrlUsed; CurChip ++) { CurCSet = p->DacCtrlUsg[CurChip]; device_stop_daccontrol(p->daccontrol[CurCSet]); p->DacCtrl[CurCSet].Enable = false; } p->DacCtrlUsed = 0x00; for (CurChip = 0x00; CurChip < PCM_BANK_COUNT; CurChip ++) { free(p->PCMBank[CurChip].Bank); free(p->PCMBank[CurChip].Data); } //memset(PCMBank, 0x00, sizeof(VGM_PCM_BANK) * PCM_BANK_COUNT); free(p->PCMTbl.Entries); //memset(&PCMTbl, 0x00, sizeof(PCMBANK_TBL)); break; case 0x10: // Set Muting Mask for (CurCSet = 0x00; CurCSet < 0x02; CurCSet ++) { CAA = (CAUD_ATTR*)&p->ChipAudio[CurCSet]; for (CurChip = 0x00; CurChip < CHIP_COUNT; CurChip ++, CAA ++) { if (CAA->ChipType == 0xFF) // chip unused continue; else if (CAA->ChipType == 0x00) sn764xx_set_mute_mask(p->sn764xx[CurCSet], p->ChipOpts[CurCSet].SN76496.ChnMute1); else if (CAA->ChipType == 0x01) ym2413_set_mute_mask(p->ym2413[CurCSet], p->ChipOpts[CurCSet].YM2413.ChnMute1); else if (CAA->ChipType == 0x02) ym2612_set_mute_mask(p->ym2612[CurCSet], p->ChipOpts[CurCSet].YM2612.ChnMute1); else if (CAA->ChipType == 0x03) ym2151_set_mute_mask(p->ym2151[CurCSet], p->ChipOpts[CurCSet].YM2151.ChnMute1); else if (CAA->ChipType == 0x04) segapcm_set_mute_mask(p->segapcm[CurCSet], p->ChipOpts[CurCSet].SegaPCM.ChnMute1); else if (CAA->ChipType == 0x05 && CurCSet == 0x00) rf5c68_set_mute_mask(p->rf5c68, p->ChipOpts[CurCSet].RF5C68.ChnMute1); else if (CAA->ChipType == 0x06) ym2203_set_mute_mask(p->ym2203[CurCSet], p->ChipOpts[CurCSet].YM2203.ChnMute1, p->ChipOpts[CurCSet].YM2203.ChnMute3); else if (CAA->ChipType == 0x07) { MaskVal = (p->ChipOpts[CurCSet].YM2608.ChnMute1 & 0x3F) << 0; MaskVal |= (p->ChipOpts[CurCSet].YM2608.ChnMute2 & 0x7F) << 6; ym2608_set_mute_mask(p->ym2608[CurCSet], MaskVal, p->ChipOpts[CurCSet].YM2608.ChnMute3); } else if (CAA->ChipType == 0x08) { MaskVal = (p->ChipOpts[CurCSet].YM2610.ChnMute1 & 0x3F) << 0; MaskVal |= (p->ChipOpts[CurCSet].YM2610.ChnMute2 & 0x7F) << 6; ym2610_set_mute_mask(p->ym2610[CurCSet], MaskVal, p->ChipOpts[CurCSet].YM2610.ChnMute3); } else if (CAA->ChipType == 0x09) ym3812_set_mute_mask(p->ym3812[CurCSet], p->ChipOpts[CurCSet].YM3812.ChnMute1); else if (CAA->ChipType == 0x0A) ym3526_set_mute_mask(p->ym3526[CurCSet], p->ChipOpts[CurCSet].YM3526.ChnMute1); else if (CAA->ChipType == 0x0B) y8950_set_mute_mask(p->y8950[CurCSet], p->ChipOpts[CurCSet].Y8950.ChnMute1); else if (CAA->ChipType == 0x0C) ymf262_set_mute_mask(p->ymf262[CurCSet], p->ChipOpts[CurCSet].YMF262.ChnMute1); else if (CAA->ChipType == 0x0D) ymf278b_set_mute_mask(p->ymf278b[CurCSet], p->ChipOpts[CurCSet].YMF278B.ChnMute1, p->ChipOpts[CurCSet].YMF278B.ChnMute2); else if (CAA->ChipType == 0x0E) ymf271_set_mute_mask(p->ymf271[CurCSet], p->ChipOpts[CurCSet].YMF271.ChnMute1); else if (CAA->ChipType == 0x0F) ymz280b_set_mute_mask(p->ymz280b[CurCSet], p->ChipOpts[CurCSet].YMZ280B.ChnMute1); else if (CAA->ChipType == 0x10 && CurCSet == 0x00) rf5c164_set_mute_mask(p->rf5c164, p->ChipOpts[CurCSet].RF5C164.ChnMute1); else if (CAA->ChipType == 0x11 && CurCSet == 0x00) pwm_mute(p->pwm, p->ChipOpts[CurCSet].PWM.ChnMute1); else if (CAA->ChipType == 0x12) ayxx_set_mute_mask(p->ay8910[CurCSet], p->ChipOpts[CurCSet].AY8910.ChnMute1); else if (CAA->ChipType == 0x13) gameboy_sound_set_mute_mask(p->gbdmg[CurCSet], p->ChipOpts[CurCSet].GameBoy.ChnMute1); else if (CAA->ChipType == 0x14) nes_set_mute_mask(p->nesapu[CurCSet], p->ChipOpts[CurCSet].NES.ChnMute1); else if (CAA->ChipType == 0x15) multipcm_set_mute_mask(p->multipcm[CurCSet], p->ChipOpts[CurCSet].MultiPCM.ChnMute1); else if (CAA->ChipType == 0x16) upd7759_mute(p->upd7759[CurCSet], p->ChipOpts[CurCSet].UPD7759.ChnMute1); else if (CAA->ChipType == 0x17) okim6258_mute(p->okim6258[CurCSet], p->ChipOpts[CurCSet].OKIM6258.ChnMute1); else if (CAA->ChipType == 0x18) okim6295_set_mute_mask(p->okim6295[CurCSet], p->ChipOpts[CurCSet].OKIM6295.ChnMute1); else if (CAA->ChipType == 0x19) k051649_set_mute_mask(p->k051649[CurCSet], p->ChipOpts[CurCSet].K051649.ChnMute1); else if (CAA->ChipType == 0x1A) k054539_set_mute_mask(p->k054539[CurCSet], p->ChipOpts[CurCSet].K054539.ChnMute1); else if (CAA->ChipType == 0x1B) c6280_set_mute_mask(p->huc6280[CurCSet], p->ChipOpts[CurCSet].HuC6280.ChnMute1); else if (CAA->ChipType == 0x1C) c140_set_mute_mask(p->c140[CurCSet], p->ChipOpts[CurCSet].C140.ChnMute1); else if (CAA->ChipType == 0x1D) k053260_set_mute_mask(p->k053260[CurCSet], p->ChipOpts[CurCSet].K053260.ChnMute1); else if (CAA->ChipType == 0x1E) pokey_set_mute_mask(p->pokey[CurCSet], p->ChipOpts[CurCSet].Pokey.ChnMute1); else if (CAA->ChipType == 0x1F) qsound_set_mute_mask(p->qsound[CurCSet], p->ChipOpts[CurCSet].QSound.ChnMute1); else if (CAA->ChipType == 0x20) scsp_set_mute_mask(p->scsp[CurCSet], p->ChipOpts[CurCSet].SCSP.ChnMute1); else if (CAA->ChipType == 0x21) ws_set_mute_mask(p->wswan[CurCSet], p->ChipOpts[CurCSet].WSwan.ChnMute1); else if (CAA->ChipType == 0x22) vsu_set_mute_mask(p->vsu[CurCSet], p->ChipOpts[CurCSet].VSU.ChnMute1); else if (CAA->ChipType == 0x23) saa1099_set_mute_mask(p->saa1099[CurCSet], p->ChipOpts[CurCSet].SAA1099.ChnMute1); else if (CAA->ChipType == 0x24) es5503_set_mute_mask(p->es5503[CurCSet], p->ChipOpts[CurCSet].ES5503.ChnMute1); else if (CAA->ChipType == 0x25) es5506_set_mute_mask(p->es550x[CurCSet], p->ChipOpts[CurCSet].ES5506.ChnMute1); else if (CAA->ChipType == 0x26) x1_010_set_mute_mask(p->x1_010[CurCSet], p->ChipOpts[CurCSet].X1_010.ChnMute1); else if (CAA->ChipType == 0x27) c352_set_mute_mask(p->c352[CurCSet], p->ChipOpts[CurCSet].C352.ChnMute1); else if (CAA->ChipType == 0x28) iremga20_set_mute_mask(p->ga20[CurCSet], p->ChipOpts[CurCSet].GA20.ChnMute1); } // end for CurChip } // end for CurCSet break; case 0x20: // Set Panning for (CurCSet = 0x00; CurCSet < 0x02; CurCSet ++) { CAA = (CAUD_ATTR*)&p->ChipAudio[CurCSet]; for (CurChip = 0x00; CurChip < CHIP_COUNT; CurChip ++, CAA ++) { if (CAA->ChipType == 0xFF) // chip unused continue; else if (CAA->ChipType == 0x00) sn764xx_set_panning(p->sn764xx[CurCSet], p->ChipOpts[CurCSet].SN76496.Panning); else if (CAA->ChipType == 0x01) ym2413_set_panning(p->ym2413[CurCSet], p->ChipOpts[CurCSet].YM2413.Panning); } // end for CurChip } // end for CurCSet break; } return; } INLINE INT32 SampleVGM2Pbk_I(VGM_PLAYER* p, INT32 SampleVal) { return (INT32)((INT64)SampleVal * p->VGMSmplRateMul / p->VGMSmplRateDiv); } INLINE INT32 SamplePbk2VGM_I(VGM_PLAYER* p, INT32 SampleVal) { return (INT32)((INT64)SampleVal * p->VGMSmplRateDiv / p->VGMSmplRateMul); } INT32 SampleVGM2Playback(void* _p, INT32 SampleVal) { VGM_PLAYER* p = (VGM_PLAYER *)_p; return (INT32)((INT64)SampleVal * p->VGMSmplRateMul / p->VGMSmplRateDiv); } INT32 SamplePlayback2VGM(void* _p, INT32 SampleVal) { VGM_PLAYER* p = (VGM_PLAYER *)_p; return (INT32)((INT64)SampleVal * p->VGMSmplRateDiv / p->VGMSmplRateMul); } static void InterpretFile(VGM_PLAYER* p, UINT32 SampleCount) { UINT32 TempLng; UINT8 CurChip; if (p->DacCtrlUsed && SampleCount > 1) // handle skipping { for (CurChip = 0x00; CurChip < p->DacCtrlUsed; CurChip ++) { daccontrol_update(p->daccontrol[p->DacCtrlUsg[CurChip]], SampleCount - 1); } } if (! p->FileMode) InterpretVGM(p, SampleCount); #ifdef ADDITIONAL_FORMATS else InterpretOther(p, SampleCount); #endif if (p->DacCtrlUsed && SampleCount) { // calling this here makes "Emulating while Paused" nicer for (CurChip = 0x00; CurChip < p->DacCtrlUsed; CurChip ++) { daccontrol_update(p->daccontrol[p->DacCtrlUsg[CurChip]], 1); } } p->VGMSmplPlayed += SampleCount; p->PlayingTime += SampleCount; //if (FadePlay && ! FadeTime) // EndPlay = true; return; } static void AddPCMData(VGM_PLAYER* p, UINT8 Type, UINT32 DataSize, const UINT8* Data) { UINT32 CurBnk; VGM_PCM_BANK* TempPCM; VGM_PCM_DATA* TempBnk; UINT32 BankSize; bool RetVal; UINT8 BnkType; UINT8 CurDAC; BnkType = Type & 0x3F; if (BnkType >= PCM_BANK_COUNT || p->VGMCurLoop) return; if (Type == 0x7F) { ReadPCMTable(p, DataSize, Data); return; } TempPCM = &p->PCMBank[BnkType]; TempPCM->BnkPos ++; if (TempPCM->BnkPos <= TempPCM->BankCount) return; // Speed hack for restarting playback (skip already loaded blocks) CurBnk = TempPCM->BankCount; TempPCM->BankCount ++; if (p->Last95Max != 0xFFFF) p->Last95Max = TempPCM->BankCount; TempPCM->Bank = (VGM_PCM_DATA*)realloc(TempPCM->Bank, sizeof(VGM_PCM_DATA) * TempPCM->BankCount); if (! (Type & 0x40)) BankSize = DataSize; else BankSize = ReadLE32(&Data[0x01]); TempPCM->Data = realloc(TempPCM->Data, TempPCM->DataSize + BankSize); TempBnk = &TempPCM->Bank[CurBnk]; TempBnk->DataStart = TempPCM->DataSize; if (! (Type & 0x40)) { TempBnk->DataSize = DataSize; TempBnk->Data = TempPCM->Data + TempBnk->DataStart; memcpy(TempBnk->Data, Data, DataSize); } else { TempBnk->Data = TempPCM->Data + TempBnk->DataStart; RetVal = DecompressDataBlk(p, TempBnk, DataSize, Data); if (! RetVal) { TempBnk->Data = NULL; TempBnk->DataSize = 0x00; //return; goto RefreshDACStrm; // sorry for the goto, but I don't want to copy-paste the code } } if (BankSize != TempBnk->DataSize) printf("Error reading Data Block! Data Size conflict!\n"); TempPCM->DataSize += BankSize; // realloc may've moved the Bank block, so refresh all DAC Streams RefreshDACStrm: for (CurDAC = 0x00; CurDAC < p->DacCtrlUsed; CurDAC ++) { if (p->DacCtrl[p->DacCtrlUsg[CurDAC]].Bank == BnkType) daccontrol_refresh_data(p->daccontrol[p->DacCtrlUsg[CurDAC]], TempPCM->Data, TempPCM->DataSize); } return; } /*INLINE FUINT16 ReadBits(UINT8* Data, UINT32* Pos, FUINT8* BitPos, FUINT8 BitsToRead) { FUINT8 BitReadVal; UINT32 InPos; FUINT8 InVal; FUINT8 BitMask; FUINT8 InShift; FUINT8 OutBit; FUINT16 RetVal; InPos = *Pos; InShift = *BitPos; OutBit = 0x00; RetVal = 0x0000; while(BitsToRead) { BitReadVal = (BitsToRead >= 8) ? 8 : BitsToRead; BitsToRead -= BitReadVal; BitMask = (1 << BitReadVal) - 1; InShift += BitReadVal; InVal = (Data[InPos] << InShift >> 8) & BitMask; if (InShift >= 8) { InShift -= 8; InPos ++; if (InShift) InVal |= (Data[InPos] << InShift >> 8) & BitMask; } RetVal |= InVal << OutBit; OutBit += BitReadVal; } *Pos = InPos; *BitPos = InShift; return RetVal; } static void DecompressDataBlk(VGM_PCM_DATA* Bank, UINT32 DataSize, const UINT8* Data) { UINT8 ComprType; UINT8 BitDec; FUINT8 BitCmp; UINT8 CmpSubType; UINT16 AddVal; UINT32 InPos; UINT32 OutPos; FUINT16 InVal; FUINT16 OutVal; FUINT8 ValSize; FUINT8 InShift; FUINT8 OutShift; UINT8* Ent1B; UINT16* Ent2B; //UINT32 Time; //Time = GetTickCount(); ComprType = Data[0x00]; Bank->DataSize = ReadLE32(&Data[0x01]); BitDec = Data[0x05]; BitCmp = Data[0x06]; CmpSubType = Data[0x07]; AddVal = ReadLE16(&Data[0x08]); switch(ComprType) { case 0x00: // n-Bit compression if (CmpSubType == 0x02) { Ent1B = (UINT8*)PCMTbl.Entries; Ent2B = (UINT16*)PCMTbl.Entries; if (! PCMTbl.EntryCount) { printf("Error loading table-compressed data block! No table loaded!\n"); return; } else if (BitDec != PCMTbl.BitDec || BitCmp != PCMTbl.BitCmp) { printf("Warning! Data block and loaded value table incompatible!\n"); return; } } ValSize = (BitDec + 7) / 8; InPos = 0x0A; InShift = 0; OutShift = BitDec - BitCmp; for (OutPos = 0x00; OutPos < Bank->DataSize; OutPos += ValSize) { if (InPos >= DataSize) break; InVal = ReadBits(Data, &InPos, &InShift, BitCmp); switch(CmpSubType) { case 0x00: // Copy OutVal = InVal + AddVal; break; case 0x01: // Shift Left OutVal = (InVal << OutShift) + AddVal; break; case 0x02: // Table switch(ValSize) { case 0x01: OutVal = Ent1B[InVal]; break; case 0x02: OutVal = Ent2B[InVal]; break; } break; } memcpy(&Bank->Data[OutPos], &OutVal, ValSize); } break; } //Time = GetTickCount() - Time; //printf("Decompression Time: %lu\n", Time); return; }*/ static bool DecompressDataBlk(VGM_PLAYER* p, VGM_PCM_DATA* Bank, UINT32 DataSize, const UINT8* Data) { UINT8 ComprType; UINT8 BitDec; FUINT8 BitCmp; UINT8 CmpSubType; UINT16 AddVal; const UINT8* InPos; const UINT8* InDataEnd; UINT8* OutPos; const UINT8* OutDataEnd; FUINT16 InVal; FUINT16 OutVal; FUINT8 ValSize; FUINT8 InShift; FUINT8 OutShift; UINT8* Ent1B; UINT16* Ent2B; // ReadBits Variables FUINT8 BitsToRead; FUINT8 BitReadVal; FUINT8 InValB; FUINT8 BitMask; FUINT8 OutBit; // Variables for DPCM UINT16 OutMask; ComprType = Data[0x00]; Bank->DataSize = ReadLE32(&Data[0x01]); switch(ComprType) { case 0x00: // n-Bit compression BitDec = Data[0x05]; BitCmp = Data[0x06]; CmpSubType = Data[0x07]; AddVal = ReadLE16(&Data[0x08]); if (CmpSubType == 0x02) { Ent1B = (UINT8*)p->PCMTbl.Entries; // Big Endian note: Those are stored in LE and converted when reading. Ent2B = (UINT16*)p->PCMTbl.Entries; if (! p->PCMTbl.EntryCount) { Bank->DataSize = 0x00; printf("Error loading table-compressed data block! No table loaded!\n"); return false; } else if (BitDec != p->PCMTbl.BitDec || BitCmp != p->PCMTbl.BitCmp) { Bank->DataSize = 0x00; printf("Warning! Data block and loaded value table incompatible!\n"); return false; } } ValSize = (BitDec + 7) / 8; InPos = Data + 0x0A; InDataEnd = Data + DataSize; InShift = 0; OutShift = BitDec - BitCmp; OutDataEnd = Bank->Data + Bank->DataSize; for (OutPos = Bank->Data; OutPos < OutDataEnd && InPos < InDataEnd; OutPos += ValSize) { //InVal = ReadBits(Data, InPos, &InShift, BitCmp); // inlined - is 30% faster OutBit = 0x00; InVal = 0x0000; BitsToRead = BitCmp; while(BitsToRead) { BitReadVal = (BitsToRead >= 8) ? 8 : BitsToRead; BitsToRead -= BitReadVal; BitMask = (1 << BitReadVal) - 1; InShift += BitReadVal; InValB = (*InPos << InShift >> 8) & BitMask; if (InShift >= 8) { InShift -= 8; InPos ++; if (InShift) InValB |= (*InPos << InShift >> 8) & BitMask; } InVal |= InValB << OutBit; OutBit += BitReadVal; } switch(CmpSubType) { case 0x00: // Copy OutVal = InVal + AddVal; break; case 0x01: // Shift Left OutVal = (InVal << OutShift) + AddVal; break; case 0x02: // Table switch(ValSize) { case 0x01: OutVal = Ent1B[InVal]; break; case 0x02: #ifndef VGM_BIG_ENDIAN OutVal = Ent2B[InVal]; #else OutVal = ReadLE16((UINT8*)&Ent2B[InVal]); #endif break; } break; } #ifndef VGM_BIG_ENDIAN //memcpy(OutPos, &OutVal, ValSize); if (ValSize == 0x01) *((UINT8*)OutPos) = (UINT8)OutVal; else //if (ValSize == 0x02) *((UINT16*)OutPos) = (UINT16)OutVal; #else if (ValSize == 0x01) { *OutPos = (UINT8)OutVal; } else //if (ValSize == 0x02) { OutPos[0x00] = (UINT8)((OutVal & 0x00FF) >> 0); OutPos[0x01] = (UINT8)((OutVal & 0xFF00) >> 8); } #endif } break; case 0x01: // Delta-PCM BitDec = Data[0x05]; BitCmp = Data[0x06]; OutVal = ReadLE16(&Data[0x08]); Ent1B = (UINT8*)p->PCMTbl.Entries; Ent2B = (UINT16*)p->PCMTbl.Entries; if (! p->PCMTbl.EntryCount) { Bank->DataSize = 0x00; printf("Error loading table-compressed data block! No table loaded!\n"); return false; } else if (BitDec != p->PCMTbl.BitDec || BitCmp != p->PCMTbl.BitCmp) { Bank->DataSize = 0x00; printf("Warning! Data block and loaded value table incompatible!\n"); return false; } ValSize = (BitDec + 7) / 8; OutMask = (1 << BitDec) - 1; InPos = Data + 0x0A; InDataEnd = Data + DataSize; InShift = 0; OutShift = BitDec - BitCmp; OutDataEnd = Bank->Data + Bank->DataSize; AddVal = 0x0000; for (OutPos = Bank->Data; OutPos < OutDataEnd && InPos < InDataEnd; OutPos += ValSize) { //InVal = ReadBits(Data, InPos, &InShift, BitCmp); // inlined - is 30% faster OutBit = 0x00; InVal = 0x0000; BitsToRead = BitCmp; while(BitsToRead) { BitReadVal = (BitsToRead >= 8) ? 8 : BitsToRead; BitsToRead -= BitReadVal; BitMask = (1 << BitReadVal) - 1; InShift += BitReadVal; InValB = (*InPos << InShift >> 8) & BitMask; if (InShift >= 8) { InShift -= 8; InPos ++; if (InShift) InValB |= (*InPos << InShift >> 8) & BitMask; } InVal |= InValB << OutBit; OutBit += BitReadVal; } switch(ValSize) { case 0x01: AddVal = Ent1B[InVal]; OutVal += AddVal; OutVal &= OutMask; *((UINT8*)OutPos) = (UINT8)OutVal; break; case 0x02: #ifndef VGM_BIG_ENDIAN AddVal = Ent2B[InVal]; #else AddVal = ReadLE16((UINT8*)&Ent2B[InVal]); #endif OutVal += AddVal; OutVal &= OutMask; #ifndef VGM_BIG_ENDIAN *((UINT16*)OutPos) = (UINT16)OutVal; #else OutPos[0x00] = (UINT8)((OutVal & 0x00FF) >> 0); OutPos[0x01] = (UINT8)((OutVal & 0xFF00) >> 8); #endif break; } } break; default: printf("Error: Unknown data block compression!\n"); return false; } return true; } static UINT8 GetDACFromPCMBank(VGM_PLAYER* p) { // for YM2612 DAC data only /*VGM_PCM_BANK* TempPCM; UINT32 CurBnk;*/ UINT32 DataPos; /*TempPCM = &PCMBank[0x00]; DataPos = TempPCM->DataPos; for (CurBnk = 0x00; CurBnk < TempPCM->BankCount; CurBnk ++) { if (DataPos < TempPCM->Bank[CurBnk].DataSize) { if (TempPCM->DataPos < TempPCM->DataSize) TempPCM->DataPos ++; return TempPCM->Bank[CurBnk].Data[DataPos]; } DataPos -= TempPCM->Bank[CurBnk].DataSize; } return 0x80;*/ DataPos = p->PCMBank[0x00].DataPos; if (DataPos >= p->PCMBank[0x00].DataSize) return 0x80; p->PCMBank[0x00].DataPos ++; return p->PCMBank[0x00].Data[DataPos]; } static UINT8* GetPointerFromPCMBank(VGM_PLAYER* p, UINT8 Type, UINT32 DataPos) { if (Type >= PCM_BANK_COUNT) return NULL; if (DataPos >= p->PCMBank[Type].DataSize) return NULL; return &p->PCMBank[Type].Data[DataPos]; } static void ReadPCMTable(VGM_PLAYER* p, UINT32 DataSize, const UINT8* Data) { UINT8 ValSize; UINT32 TblSize; p->PCMTbl.ComprType = Data[0x00]; p->PCMTbl.CmpSubType = Data[0x01]; p->PCMTbl.BitDec = Data[0x02]; p->PCMTbl.BitCmp = Data[0x03]; p->PCMTbl.EntryCount = ReadLE16(&Data[0x04]); ValSize = (p->PCMTbl.BitDec + 7) / 8; TblSize = p->PCMTbl.EntryCount * ValSize; p->PCMTbl.Entries = realloc(p->PCMTbl.Entries, TblSize); memcpy(p->PCMTbl.Entries, &Data[0x06], TblSize); if (DataSize < 0x06 + TblSize) printf("Warning! Bad PCM Table Length!\n"); return; } #define CHIP_CHECK(name) (p->ChipAudio[CurChip].name.ChipType != 0xFF) static void InterpretVGM(VGM_PLAYER* p, UINT32 SampleCount) { INT32 SmplPlayed; UINT8 Command; UINT8 TempByt; UINT16 TempSht; UINT32 TempLng; VGM_PCM_BANK* TempPCM; VGM_PCM_DATA* TempBnk; UINT32 ROMSize; UINT32 DataStart; UINT32 DataLen; const UINT8* ROMData; UINT8 CurChip; const UINT8* VGMPnt; if (p->VGMEnd) return; SmplPlayed = SamplePbk2VGM_I(p, p->VGMSmplPlayed + SampleCount); while(p->VGMSmplPos <= SmplPlayed) { Command = p->VGMData[p->VGMPos + 0x00]; if (Command >= 0x70 && Command <= 0x8F) { switch(Command & 0xF0) { case 0x70: p->VGMSmplPos += (Command & 0x0F) + 0x01; break; case 0x80: TempByt = GetDACFromPCMBank(p); if (p->VGMHead.lngHzYM2612) { chip_reg_write(p, 0x02, 0x00, 0x00, 0x2A, TempByt); } p->VGMSmplPos += (Command & 0x0F); break; } p->VGMPos += 0x01; } else { VGMPnt = &p->VGMData[p->VGMPos]; // Cheat Mode (to use 2 instances of 1 chip) CurChip = 0x00; switch(Command) { case 0x30: if (p->VGMHead.lngHzPSG & 0x40000000) { Command += 0x20; CurChip = 0x01; } break; case 0x3F: if (p->VGMHead.lngHzPSG & 0x40000000) { Command += 0x10; CurChip = 0x01; } break; case 0xA1: if (p->VGMHead.lngHzYM2413 & 0x40000000) { Command -= 0x50; CurChip = 0x01; } break; case 0xA2: case 0xA3: if (p->VGMHead.lngHzYM2612 & 0x40000000) { Command -= 0x50; CurChip = 0x01; } break; case 0xA4: if (p->VGMHead.lngHzYM2151 & 0x40000000) { Command -= 0x50; CurChip = 0x01; } break; case 0xA5: if (p->VGMHead.lngHzYM2203 & 0x40000000) { Command -= 0x50; CurChip = 0x01; } break; case 0xA6: case 0xA7: if (p->VGMHead.lngHzYM2608 & 0x40000000) { Command -= 0x50; CurChip = 0x01; } break; case 0xA8: case 0xA9: if (p->VGMHead.lngHzYM2610 & 0x40000000) { Command -= 0x50; CurChip = 0x01; } break; case 0xAA: if (p->VGMHead.lngHzYM3812 & 0x40000000) { Command -= 0x50; CurChip = 0x01; } break; case 0xAB: if (p->VGMHead.lngHzYM3526 & 0x40000000) { Command -= 0x50; CurChip = 0x01; } break; case 0xAC: if (p->VGMHead.lngHzY8950 & 0x40000000) { Command -= 0x50; CurChip = 0x01; } break; case 0xAE: case 0xAF: if (p->VGMHead.lngHzYMF262 & 0x40000000) { Command -= 0x50; CurChip = 0x01; } break; case 0xAD: if (p->VGMHead.lngHzYMZ280B & 0x40000000) { Command -= 0x50; CurChip = 0x01; } break; } switch(Command) { case 0x66: // End Of File if (p->VGMHead.lngLoopOffset) { p->VGMPos = p->VGMHead.lngLoopOffset; p->VGMSmplPos -= p->VGMHead.lngLoopSamples; p->VGMSmplPlayed -= SampleVGM2Pbk_I(p, p->VGMHead.lngLoopSamples); SmplPlayed = SamplePbk2VGM_I(p, p->VGMSmplPlayed + SampleCount); p->VGMCurLoop ++; if (p->VGMMaxLoopM && p->VGMCurLoop >= p->VGMMaxLoopM) { if (! p->FadePlay) { p->FadeStart = SampleVGM2Pbk_I(p, p->VGMHead.lngTotalSamples + (p->VGMCurLoop - 1) * p->VGMHead.lngLoopSamples); } p->FadePlay = true; } if (p->FadePlay && ! p->FadeTime) p->VGMEnd = true; } else { if (p->VGMHead.lngTotalSamples != (UINT32)p->VGMSmplPos) { #ifdef CONSOLE_MODE printf("Warning! Header Samples: %u\t Counted Samples: %u\n", p->VGMHead.lngTotalSamples, p->VGMSmplPos); p->ErrorHappened = true; #endif p->VGMHead.lngTotalSamples = p->VGMSmplPos; } p->VGMEnd = true; break; } break; case 0x62: // 1/60s delay p->VGMSmplPos += 735; p->VGMPos += 0x01; break; case 0x63: // 1/50s delay p->VGMSmplPos += 882; p->VGMPos += 0x01; break; case 0x61: // xx Sample Delay TempSht = ReadLE16(&VGMPnt[0x01]); p->VGMSmplPos += TempSht; p->VGMPos += 0x03; break; case 0x50: // SN76496 write if (CHIP_CHECK(SN76496)) { chip_reg_write(p, 0x00, CurChip, 0x00, 0x00, VGMPnt[0x01]); } p->VGMPos += 0x02; break; case 0x51: // YM2413 write if (CHIP_CHECK(YM2413)) { chip_reg_write(p, 0x01, CurChip, 0x00, VGMPnt[0x01], VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0x52: // YM2612 write port 0 case 0x53: // YM2612 write port 1 if (CHIP_CHECK(YM2612)) { chip_reg_write(p, 0x02, CurChip, Command & 0x01, VGMPnt[0x01], VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0x67: // PCM Data Stream TempByt = VGMPnt[0x02]; TempLng = ReadLE32(&VGMPnt[0x03]); if (TempLng & 0x80000000) { TempLng &= 0x7FFFFFFF; CurChip = 0x01; } switch(TempByt & 0xC0) { case 0x00: // Database Block case 0x40: AddPCMData(p, TempByt, TempLng, &VGMPnt[0x07]); /*switch(TempByt) { case 0x00: // YM2612 PCM Database break; case 0x01: // RF5C68 PCM Database break; case 0x02: // RF5C164 PCM Database break; }*/ break; case 0x80: // ROM/RAM Dump if (p->VGMCurLoop) break; ROMSize = ReadLE32(&VGMPnt[0x07]); DataStart = ReadLE32(&VGMPnt[0x0B]); DataLen = TempLng - 0x08; ROMData = &VGMPnt[0x0F]; switch(TempByt) { case 0x80: // SegaPCM ROM if (! CHIP_CHECK(SegaPCM)) break; sega_pcm_write_rom(p->segapcm[CurChip], ROMSize, DataStart, DataLen, ROMData); break; case 0x81: // YM2608 DELTA-T ROM Image if (! CHIP_CHECK(YM2608)) break; ym2608_write_data_pcmrom(p->ym2608[CurChip], 0x02, ROMSize, DataStart, DataLen, ROMData); break; case 0x82: // YM2610 ADPCM ROM Image case 0x83: // YM2610 DELTA-T ROM Image if (! CHIP_CHECK(YM2610)) break; TempByt = 0x01 + (TempByt - 0x82); ym2610_write_data_pcmrom(p->ym2610[CurChip], TempByt, ROMSize, DataStart, DataLen, ROMData); break; case 0x84: // YMF278B ROM Image if (! CHIP_CHECK(YMF278B)) break; ymf278b_write_rom(p->ymf278b[CurChip], ROMSize, DataStart, DataLen, ROMData); break; case 0x85: // YMF271 ROM Image if (! CHIP_CHECK(YMF271)) break; ymf271_write_rom(p->ymf271[CurChip], ROMSize, DataStart, DataLen, ROMData); break; case 0x86: // YMZ280B ROM Image if (! CHIP_CHECK(YMZ280B)) break; ymz280b_write_rom(p->ymz280b[CurChip], ROMSize, DataStart, DataLen, ROMData); break; case 0x87: // YMF278B RAM Image if (! CHIP_CHECK(YMF278B)) break; //ymf278b_write_ram(CurChip, ROMSize, DataStart, DataLen, ROMData); break; case 0x88: // Y8950 DELTA-T ROM Image if (! CHIP_CHECK(Y8950) || p->PlayingMode == 0x01) break; y8950_write_data_pcmrom(p->y8950[CurChip], ROMSize, DataStart, DataLen, ROMData); break; case 0x89: // MultiPCM ROM Image if (! CHIP_CHECK(MultiPCM)) break; multipcm_write_rom(p->multipcm[CurChip], ROMSize, DataStart, DataLen, ROMData); break; case 0x8A: // UPD7759 ROM Image if (! CHIP_CHECK(UPD7759)) break; upd7759_write_rom(p->upd7759[CurChip], ROMSize, DataStart, DataLen, ROMData); break; case 0x8B: // OKIM6295 ROM Image if (! CHIP_CHECK(OKIM6295)) break; okim6295_write_rom(p->okim6295[CurChip], ROMSize, DataStart, DataLen, ROMData); break; case 0x8C: // K054539 ROM Image if (! CHIP_CHECK(K054539)) break; k054539_write_rom(p->k054539[CurChip], ROMSize, DataStart, DataLen, ROMData); break; case 0x8D: // C140 ROM Image if (! CHIP_CHECK(C140)) break; c140_write_rom(p->c140[CurChip], ROMSize, DataStart, DataLen, ROMData); break; case 0x8E: // K053260 ROM Image if (! CHIP_CHECK(K053260)) break; k053260_write_rom(p->k053260[CurChip], ROMSize, DataStart, DataLen, ROMData); break; case 0x8F: // QSound ROM Image if (! CHIP_CHECK(QSound)) break; qsound_write_rom(p->qsound[CurChip], ROMSize, DataStart, DataLen, ROMData); break; case 0x90: // ES5506 ROM Image if (! CHIP_CHECK(ES5506)) break; es5506_write_rom(p->es550x[CurChip], ROMSize, DataStart, DataLen, ROMData); break; case 0x91: // X1-010 ROM Image if (! CHIP_CHECK(X1_010)) break; x1_010_write_rom(p->x1_010[CurChip], ROMSize, DataStart, DataLen, ROMData); break; case 0x92: // C352 ROM Image if (! CHIP_CHECK(C352)) break; c352_write_rom(p->c352[CurChip], ROMSize, DataStart, DataLen, ROMData); break; case 0x93: // GA20 ROM Image if (! CHIP_CHECK(GA20)) break; iremga20_write_rom(p->ga20[CurChip], ROMSize, DataStart, DataLen, ROMData); break; // case 0x8C: // OKIM6376 ROM Image // if (! CHIP_CHECK(OKIM6376)) // break; // break; } break; case 0xC0: // RAM Write if (! (TempByt & 0x20)) { DataStart = ReadLE16(&VGMPnt[0x07]); DataLen = TempLng - 0x02; ROMData = &VGMPnt[0x09]; } else { DataStart = ReadLE32(&VGMPnt[0x07]); DataLen = TempLng - 0x04; ROMData = &VGMPnt[0x0B]; } switch(TempByt) { case 0xC0: // RF5C68 RAM Database if (! CHIP_CHECK(RF5C68)) break; rf5c68_write_ram(p->rf5c68, DataStart, DataLen, ROMData); break; case 0xC1: // RF5C164 RAM Database if (! CHIP_CHECK(RF5C164)) break; rf5c164_write_ram(p->rf5c164, DataStart, DataLen, ROMData); break; case 0xC2: // NES APU RAM if (! CHIP_CHECK(NES)) break; nes_write_ram(p->nesapu[CurChip], DataStart, DataLen, ROMData); break; case 0xE0: // SCSP RAM if (! CHIP_CHECK(SCSP)) break; scsp_write_ram(p->scsp[CurChip], DataStart, DataLen, ROMData); break; case 0xE1: // ES5503 RAM if (! CHIP_CHECK(ES5503)) break; es5503_write_ram(p->es5503[CurChip], DataStart, DataLen, ROMData); break; } break; } p->VGMPos += 0x07 + TempLng; break; case 0xE0: // Seek to PCM Data Bank Pos p->PCMBank[0x00].DataPos = ReadLE32(&VGMPnt[0x01]); p->VGMPos += 0x05; break; case 0x4F: // GG Stereo if (CHIP_CHECK(SN76496)) { chip_reg_write(p, 0x00, CurChip, 0x01, 0x00, VGMPnt[0x01]); } p->VGMPos += 0x02; break; case 0x54: // YM2151 write if (CHIP_CHECK(YM2151)) { chip_reg_write(p, 0x03, CurChip, 0x01, VGMPnt[0x01], VGMPnt[0x02]); } //p->VGMSmplPos += 80; p->VGMPos += 0x03; break; case 0xC0: // Sega PCM memory write TempSht = ReadLE16(&VGMPnt[0x01]); CurChip = (TempSht & 0x8000) >> 15; if (CHIP_CHECK(SegaPCM)) { sega_pcm_w(p->segapcm[CurChip], TempSht & 0x7FFF, VGMPnt[0x03]); } p->VGMPos += 0x04; break; case 0xB0: // RF5C68 register write if (CHIP_CHECK(RF5C68)) { chip_reg_write(p, 0x05, CurChip, 0x00, VGMPnt[0x01], VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0xC1: // RF5C68 memory write if (CHIP_CHECK(RF5C68)) { TempSht = ReadLE16(&VGMPnt[0x01]); rf5c68_mem_w(p->rf5c68, TempSht, VGMPnt[0x03]); } p->VGMPos += 0x04; break; case 0x55: // YM2203 if (CHIP_CHECK(YM2203)) { chip_reg_write(p, 0x06, CurChip, 0x00, VGMPnt[0x01], VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0x56: // YM2608 write port 0 case 0x57: // YM2608 write port 1 if (CHIP_CHECK(YM2608)) { chip_reg_write(p, 0x07, CurChip, Command & 0x01, VGMPnt[0x01], VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0x58: // YM2610 write port 0 case 0x59: // YM2610 write port 1 if (CHIP_CHECK(YM2610)) { chip_reg_write(p, 0x08, CurChip, Command & 0x01, VGMPnt[0x01], VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0x5A: // YM3812 write if (CHIP_CHECK(YM3812)) { chip_reg_write(p, 0x09, CurChip, 0x00, VGMPnt[0x01], VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0x5B: // YM3526 write if (CHIP_CHECK(YM3526)) { chip_reg_write(p, 0x0A, CurChip, 0x00, VGMPnt[0x01], VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0x5C: // Y8950 write if (CHIP_CHECK(Y8950)) { chip_reg_write(p, 0x0B, CurChip, 0x00, VGMPnt[0x01], VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0x5E: // YMF262 write port 0 case 0x5F: // YMF262 write port 1 if (CHIP_CHECK(YMF262)) { chip_reg_write(p, 0x0C, CurChip, Command & 0x01, VGMPnt[0x01], VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0x5D: // YMZ280B write if (CHIP_CHECK(YMZ280B)) { chip_reg_write(p, 0x0F, CurChip, 0x00, VGMPnt[0x01], VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0xD0: // YMF278B write if (CHIP_CHECK(YMF278B)) { CurChip = (VGMPnt[0x01] & 0x80) >> 7; chip_reg_write(p, 0x0D, CurChip, VGMPnt[0x01] & 0x7F, VGMPnt[0x02], VGMPnt[0x03]); } p->VGMPos += 0x04; break; case 0xD1: // YMF271 write if (CHIP_CHECK(YMF271)) { CurChip = (VGMPnt[0x01] & 0x80) >> 7; chip_reg_write(p, 0x0E, CurChip, VGMPnt[0x01] & 0x7F, VGMPnt[0x02], VGMPnt[0x03]); } p->VGMPos += 0x04; break; case 0xB1: // RF5C164 register write if (CHIP_CHECK(RF5C164)) { chip_reg_write(p, 0x10, CurChip, 0x00, VGMPnt[0x01], VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0xC2: // RF5C164 memory write if (CHIP_CHECK(RF5C164)) { TempSht = ReadLE16(&VGMPnt[0x01]); rf5c164_mem_w(p->rf5c164, TempSht, VGMPnt[0x03]); } p->VGMPos += 0x04; break; case 0xB2: // PWM channel write if (CHIP_CHECK(PWM)) { chip_reg_write(p, 0x11, CurChip, (VGMPnt[0x01] & 0xF0) >> 4, VGMPnt[0x01] & 0x0F, VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0x68: // PCM RAM write CurChip = (VGMPnt[0x02] & 0x80) >> 7; TempByt = VGMPnt[0x02] & 0x7F; DataStart = ReadLE24(&VGMPnt[0x03]); TempLng = ReadLE24(&VGMPnt[0x06]); DataLen = ReadLE24(&VGMPnt[0x09]); if (! DataLen) DataLen += 0x01000000; ROMData = GetPointerFromPCMBank(p, TempByt, DataStart); if (ROMData == NULL) { p->VGMPos += 0x0C; break; } switch(TempByt) { case 0x01: if (! CHIP_CHECK(RF5C68)) break; rf5c68_write_ram(p->rf5c68, TempLng, DataLen, ROMData); break; case 0x02: if (! CHIP_CHECK(RF5C164)) break; rf5c164_write_ram(p->rf5c164, TempLng, DataLen, ROMData); break; case 0x06: if (! CHIP_CHECK(SCSP)) break; scsp_write_ram(p->scsp[CurChip], TempLng, DataLen, ROMData); break; case 0x07: if (! CHIP_CHECK(NES)) break; p->Last95Drum = DataStart / DataLen - 1; p->Last95Max = p->PCMBank[TempByt].DataSize / DataLen; nes_write_ram(p->nesapu[CurChip], TempLng, DataLen, ROMData); break; } p->VGMPos += 0x0C; break; case 0xA0: // AY8910 write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(AY8910)) { chip_reg_write(p, 0x12, CurChip, 0x00, VGMPnt[0x01] & 0x7F, VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0xB3: // GameBoy DMG write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(GameBoy)) { chip_reg_write(p, 0x13, CurChip, 0x00, VGMPnt[0x01] & 0x7F, VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0xB4: // NES APU write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(NES)) { chip_reg_write(p, 0x14, CurChip, 0x00, VGMPnt[0x01] & 0x7F, VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0xB5: // MultiPCM write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(MultiPCM)) { chip_reg_write(p, 0x15, CurChip, 0x00, VGMPnt[0x01] & 0x7F, VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0xC3: // MultiPCM memory write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(MultiPCM)) { TempSht = ReadLE16(&VGMPnt[0x02]); multipcm_bank_write(p->multipcm[CurChip], VGMPnt[0x01] & 0x7F, TempSht); } p->VGMPos += 0x04; break; case 0xB6: // UPD7759 write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(UPD7759)) { chip_reg_write(p, 0x16, CurChip, 0x00, VGMPnt[0x01] & 0x7F, VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0xB7: // OKIM6258 write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(OKIM6258)) { chip_reg_write(p, 0x17, CurChip, 0x00, VGMPnt[0x01] & 0x7F, VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0xB8: // OKIM6295 write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(OKIM6295)) { chip_reg_write(p, 0x18, CurChip, 0x00, VGMPnt[0x01] & 0x7F, VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0xD2: // SCC1 write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(K051649)) { chip_reg_write(p, 0x19, CurChip, VGMPnt[0x01] & 0x7F, VGMPnt[0x02], VGMPnt[0x03]); } p->VGMPos += 0x04; break; case 0xD3: // K054539 write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(K054539)) { chip_reg_write(p, 0x1A, CurChip, VGMPnt[0x01] & 0x7F, VGMPnt[0x02], VGMPnt[0x03]); } p->VGMPos += 0x04; break; case 0xB9: // HuC6280 write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(HuC6280)) { chip_reg_write(p, 0x1B, CurChip, 0x00, VGMPnt[0x01] & 0x7F, VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0xD4: // C140 write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(C140)) { chip_reg_write(p, 0x1C, CurChip, VGMPnt[0x01] & 0x7F, VGMPnt[0x02], VGMPnt[0x03]); } p->VGMPos += 0x04; break; case 0xBA: // K053260 write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(K053260)) { chip_reg_write(p, 0x1D, CurChip, 0x00, VGMPnt[0x01] & 0x7F, VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0xBB: // Pokey write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(Pokey)) { chip_reg_write(p, 0x1E, CurChip, 0x00, VGMPnt[0x01] & 0x7F, VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0xC4: // QSound write if (CHIP_CHECK(QSound)) { chip_reg_write(p, 0x1F, CurChip, VGMPnt[0x01], VGMPnt[0x02], VGMPnt[0x03]); } p->VGMPos += 0x04; break; case 0xC5: // YMF292/SCSP write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(SCSP)) { chip_reg_write(p, 0x20, CurChip, VGMPnt[0x01] & 0x7F, VGMPnt[0x02], VGMPnt[0x03]); } p->VGMPos += 0x04; break; case 0xBC: // WonderSwan write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(WSwan)) { chip_reg_write(p, 0x21, CurChip, 0x00, VGMPnt[0x01] & 0x7F, VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0xC6: // WonderSwan memory write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(WSwan)) { TempSht = ReadBE16(&VGMPnt[0x01]) & 0x7FFF; ws_write_ram(p->wswan[CurChip], TempSht, VGMPnt[0x03]); } p->VGMPos += 0x04; break; case 0xC7: // VSU write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(VSU)) { chip_reg_write(p, 0x22, CurChip, VGMPnt[0x01] & 0x7F, VGMPnt[0x02], VGMPnt[0x03]); } p->VGMPos += 0x04; break; case 0xBD: // SAA1099 write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(SAA1099)) { chip_reg_write(p, 0x23, CurChip, 0x00, VGMPnt[0x01] & 0x7F, VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0xD5: // ES5503 write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(ES5503)) { chip_reg_write(p, 0x24, CurChip, VGMPnt[0x01] & 0x7F, VGMPnt[0x02], VGMPnt[0x03]); } p->VGMPos += 0x04; break; case 0xBE: // ES5506 write (8-bit data) CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(ES5506)) { chip_reg_write(p, 0x25, CurChip, VGMPnt[0x01] & 0x7F, 0x00, VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0xD6: // ES5506 write (16-bit data) CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(ES5506)) { chip_reg_write(p, 0x25, CurChip, 0x80 | (VGMPnt[0x01] & 0x7F), VGMPnt[0x02], VGMPnt[0x03]); } p->VGMPos += 0x04; break; case 0xC8: // X1-010 write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(X1_010)) { chip_reg_write(p, 0x26, CurChip, VGMPnt[0x01] & 0x7F, VGMPnt[0x02], VGMPnt[0x03]); } p->VGMPos += 0x04; break; #if 0 // for ctr's WIP rips case 0xC9: // C352 write CurChip = 0x00; if (CHIP_CHECK(C352)) { if (VGMPnt[0x01] == 0x03 && VGMPnt[0x02] == 0xFF && VGMPnt[0x03] == 0xFF) c352_w(p->c352[CurChip], 0x202, 0x0020); else chip_reg_write(p, 0x27, CurChip, VGMPnt[0x01], VGMPnt[0x02], VGMPnt[0x03]); } p->VGMPos += 0x04; break; #endif case 0xE1: // C352 write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(C352)) { TempSht = ((VGMPnt[0x01] & 0x7F) << 8) | (VGMPnt[0x02] << 0); c352_w(p->c352[CurChip], TempSht, (VGMPnt[0x03] << 8) | VGMPnt[0x04]); } p->VGMPos += 0x05; break; case 0xBF: // GA20 write CurChip = (VGMPnt[0x01] & 0x80) >> 7; if (CHIP_CHECK(GA20)) { chip_reg_write(p, 0x28, CurChip, 0x00, VGMPnt[0x01] & 0x7F, VGMPnt[0x02]); } p->VGMPos += 0x03; break; case 0x90: // DAC Ctrl: Setup Chip CurChip = VGMPnt[0x01]; if (CurChip == 0xFF) { p->VGMPos += 0x05; break; } if (! p->DacCtrl[CurChip].Enable) { device_start_daccontrol(&p->daccontrol[CurChip], p, p->SampleRate); device_reset_daccontrol(p->daccontrol[CurChip]); p->DacCtrl[CurChip].Enable = true; p->DacCtrlUsg[p->DacCtrlUsed] = CurChip; p->DacCtrlUsed ++; } TempByt = VGMPnt[0x02]; // Chip Type TempSht = ReadBE16(&VGMPnt[0x03]); daccontrol_setup_chip(p->daccontrol[CurChip], TempByt & 0x7F, (TempByt & 0x80) >> 7, TempSht); p->VGMPos += 0x05; break; case 0x91: // DAC Ctrl: Set Data CurChip = VGMPnt[0x01]; if (CurChip == 0xFF || ! p->DacCtrl[CurChip].Enable) { p->VGMPos += 0x05; break; } p->DacCtrl[CurChip].Bank = VGMPnt[0x02]; if (p->DacCtrl[CurChip].Bank >= PCM_BANK_COUNT) p->DacCtrl[CurChip].Bank = 0x00; TempPCM = &p->PCMBank[p->DacCtrl[CurChip].Bank]; p->Last95Max = TempPCM->BankCount; daccontrol_set_data(p->daccontrol[CurChip], TempPCM->Data, TempPCM->DataSize, VGMPnt[0x03], VGMPnt[0x04]); p->VGMPos += 0x05; break; case 0x92: // DAC Ctrl: Set Freq CurChip = VGMPnt[0x01]; if (CurChip == 0xFF || ! p->DacCtrl[CurChip].Enable) { p->VGMPos += 0x06; break; } TempLng = ReadLE32(&VGMPnt[0x02]); p->Last95Freq = TempLng; daccontrol_set_frequency(p->daccontrol[CurChip], TempLng); p->VGMPos += 0x06; break; case 0x93: // DAC Ctrl: Play from Start Pos CurChip = VGMPnt[0x01]; if (CurChip == 0xFF || ! p->DacCtrl[CurChip].Enable || ! p->PCMBank[p->DacCtrl[CurChip].Bank].BankCount) { p->VGMPos += 0x0B; break; } DataStart = ReadLE32(&VGMPnt[0x02]); p->Last95Drum = 0xFFFF; TempByt = VGMPnt[0x06]; DataLen = ReadLE32(&VGMPnt[0x07]); daccontrol_start(p->daccontrol[CurChip], DataStart, TempByt, DataLen); p->VGMPos += 0x0B; break; case 0x94: // DAC Ctrl: Stop immediately CurChip = VGMPnt[0x01]; if (! p->DacCtrl[CurChip].Enable) { p->VGMPos += 0x02; break; } p->Last95Drum = 0xFFFF; if (CurChip < 0xFF) { daccontrol_stop(p->daccontrol[CurChip]); } else { for (CurChip = 0x00; CurChip < 0xFF; CurChip ++) daccontrol_stop(p->daccontrol[CurChip]); } p->VGMPos += 0x02; break; case 0x95: // DAC Ctrl: Play Block (small) CurChip = VGMPnt[0x01]; if (CurChip == 0xFF || ! p->DacCtrl[CurChip].Enable || ! p->PCMBank[p->DacCtrl[CurChip].Bank].BankCount) { p->VGMPos += 0x05; break; } TempPCM = &p->PCMBank[p->DacCtrl[CurChip].Bank]; TempSht = ReadLE16(&VGMPnt[0x02]); p->Last95Drum = TempSht; p->Last95Max = TempPCM->BankCount; if (TempSht >= TempPCM->BankCount) TempSht = 0x00; TempBnk = &TempPCM->Bank[TempSht]; TempByt = DCTRL_LMODE_BYTES | (VGMPnt[0x04] & 0x10) | // Reverse Mode ((VGMPnt[0x04] & 0x01) << 7); // Looping daccontrol_start(p->daccontrol[CurChip], TempBnk->DataStart, TempByt, TempBnk->DataSize); p->VGMPos += 0x05; break; default: switch(Command & 0xF0) { case 0x00: case 0x10: case 0x20: p->VGMPos += 0x01; break; case 0x30: p->VGMPos += 0x02; break; case 0x40: case 0x50: case 0xA0: case 0xB0: p->VGMPos += 0x03; break; case 0xC0: case 0xD0: p->VGMPos += 0x04; break; case 0xE0: case 0xF0: p->VGMPos += 0x05; break; default: p->VGMEnd = true; p->EndPlay = true; break; } break; } } if (p->VGMPos >= p->VGMHead.lngEOFOffset) p->VGMEnd = true; if (p->VGMEnd) break; } return; } static void GeneralChipLists(VGM_PLAYER* p) { // Generate Chip List for playback loop UINT16 CurBufIdx; CA_LIST* CLstOld; CA_LIST* CLst; CA_LIST* CurLst; UINT8 CurChip; UINT8 CurCSet; CAUD_ATTR* CAA; p->ChipListAll = NULL; //ChipListPause = NULL; //ChipListOpt = NULL; // generate list of all chips that are used in the current VGM CurBufIdx = 0x00; CLstOld = NULL; for (CurChip = 0x00; CurChip < CHIP_COUNT; CurChip ++) { for (CurCSet = 0x00; CurCSet < 0x02; CurCSet ++) { CAA = (CAUD_ATTR*)&p->ChipAudio[CurCSet] + CurChip; if (CAA->ChipType != 0xFF) { CLst = &p->ChipListBuffer[CurBufIdx]; CurBufIdx ++; if (CLstOld == NULL) p->ChipListAll = CLst; else CLstOld->next = CLst; CLst->CAud = CAA; CLst->COpts = (CHIP_OPTS*)&p->ChipOpts[CurCSet] + CurChip; CLstOld = CLst; } } } if (CLstOld != NULL) CLstOld->next = NULL; /*// Go through the chip list and copy all chips to a new list, except for a few // selected ones. CLstOld = NULL; CurLst = ChipListAll; while(CurLst != NULL) { // don't emulate the RF5Cxx chips when paused+emulated if (CurLst->CAud->ChipType != 0x05 && CurLst->CAud->ChipType != 0x10) { CLst = &p->ChipListBuffer[CurBufIdx]; CurBufIdx ++; if (CLstOld == NULL) p->ChipListPause = CLst; else CLstOld->next = CLst; *CLst = *CurLst; CLstOld = CLst; } CurLst = CurLst->next; } if (CLstOld != NULL) CLstOld->next = NULL;*/ return; } static void SetupResampler(VGM_PLAYER* p, CAUD_ATTR* CAA) { if (! CAA->SmpRate) { CAA->Resampler = 0x00; return; } CAA->TargetSmpRate = p->SampleRate; CAA->Resampler = resampler_create(); return; } static void ChangeChipSampleRate(void* DataPtr, UINT32 NewSmplRate) { CAUD_ATTR* CAA = (CAUD_ATTR*)DataPtr; if (CAA->SmpRate == NewSmplRate) return; CAA->SmpRate = NewSmplRate; return; } INLINE INT16 Limit2Short(INT32 Value) { INT32 NewValue; NewValue = Value; if (NewValue < -0x8000) NewValue = -0x8000; else if (NewValue > 0x7FFF) NewValue = 0x7FFF; return (INT16)NewValue; } INLINE INT32 LimitScaleAdd(INT32 Target, INT32 Value, UINT16 Scale) { INT64 NewValue; NewValue = (INT64)Value; NewValue *= (INT64)Scale; NewValue += (INT64)Target; if (NewValue < -0x80000000LL) NewValue = -0x80000000LL; else if (NewValue > 0x7FFFFFFFLL) NewValue = 0x7FFFFFFFLL; return (INT32)NewValue; } static void null_update(void *param, stream_sample_t **outputs, int samples) { memset(outputs[0x00], 0x00, sizeof(stream_sample_t) * samples); memset(outputs[0x01], 0x00, sizeof(stream_sample_t) * samples); return; } static void dual_opl2_stereo(void *param, stream_sample_t **outputs, int samples) { struct dual_opl2_info * info = (struct dual_opl2_info *) param; ym3812_stream_update(info->chip, outputs, samples); // Dual-OPL with Stereo if (info->ChipID & 0x01) memset(outputs[0x00], 0x00, sizeof(stream_sample_t) * samples); // Mute Left Chanel else memset(outputs[0x01], 0x00, sizeof(stream_sample_t) * samples); // Mute Right Chanel return; } static void ResampleChipStream(VGM_PLAYER* p, CA_LIST* CLst, WAVE_32BS* RetSample, UINT32 Length) { CAUD_ATTR* CAA; INT32* CurBufL; INT32* CurBufR; INT32 SmpCnt; // must be signed, else I'm getting calculation errors INT32 CurSmpl; UINT32 SampleRate; UINT32 OutPos; sample_t ls, rs; CAA = CLst->CAud; if (!CAA->Resampler) return; CurBufL = p->StreamBufs[0x00]; CurBufR = p->StreamBufs[0x01]; SampleRate = p->SampleRate; OutPos = 0; // This Do-While-Loop gets and resamples the chip output of one or more chips. // It's a loop to support the AY8910 paired with the YM2203/YM2608/YM2610. do { for (OutPos = 0; OutPos < Length; OutPos++) { if (CAA->LastSmpRate != CAA->SmpRate) { resampler_set_rate(CAA->Resampler, (double)CAA->SmpRate / (double)CAA->TargetSmpRate); CAA->LastSmpRate = CAA->SmpRate; } SmpCnt = resampler_get_min_fill(CAA->Resampler) / 2; if (SmpCnt) { CAA->StreamUpdate(CAA->StreamUpdateParam, p->StreamBufs, SmpCnt); for (CurSmpl = 0; CurSmpl < SmpCnt; CurSmpl++) resampler_write_pair(CAA->Resampler, CurBufL[CurSmpl], CurBufR[CurSmpl]); } resampler_read_pair(CAA->Resampler, &ls, &rs); RetSample[OutPos].Left = LimitScaleAdd(RetSample[OutPos].Left, ls, CAA->Volume); RetSample[OutPos].Right = LimitScaleAdd(RetSample[OutPos].Right, rs, CAA->Volume); } CAA = CAA->Paired; } while(CAA != NULL); return; } static INT32 RecalcFadeVolume(VGM_PLAYER* p) { float TempSng; if (p->FadePlay) { if (! p->FadeStart) p->FadeStart = p->PlayingTime; TempSng = (p->PlayingTime - p->FadeStart) / (float)p->SampleRate; p->MasterVol = 1.0f - TempSng / (p->FadeTime * 0.001f); if (p->MasterVol < 0.0f) { p->MasterVol = 0.0f; //EndPlay = true; p->VGMEnd = true; } p->FinalVol = p->VolumeLevelM * p->MasterVol * p->MasterVol; } return (INT32)(0x100 * p->FinalVol + 0.5f); } UINT32 FillBuffer(void *_p, WAVE_16BS* Buffer, UINT32 BufferSize) { UINT32 CurSmpl; WAVE_32BS TempBuf; INT32 CurMstVol; UINT32 RecalcStep; CA_LIST* CurCLst; VGM_PLAYER* p = (VGM_PLAYER *)_p; //memset(Buffer, 0x00, sizeof(WAVE_16BS) * BufferSize); RecalcStep = p->FadePlay ? p->SampleRate / 44100 : 0; CurMstVol = RecalcFadeVolume(p); if (Buffer == NULL) { //for (CurSmpl = 0x00; CurSmpl < BufferSize; CurSmpl ++) // InterpretFile(1); InterpretFile(p, BufferSize); if (p->FadePlay && ! p->FadeStart) { p->FadeStart = p->PlayingTime; RecalcStep = p->FadePlay ? p->SampleRate / 100 : 0; } //if (RecalcStep && ! (CurSmpl % RecalcStep)) if (RecalcStep) CurMstVol = RecalcFadeVolume(p); if (p->VGMEnd) { p->EndPlay = true; } return BufferSize; } for (CurSmpl = 0x00; CurSmpl < BufferSize; CurSmpl ++) { InterpretFile(p, 1); // Sample Structures // 00 - SN76496 // 01 - YM2413 // 02 - YM2612 // 03 - YM2151 // 04 - SegaPCM // 05 - RF5C68 // 06 - YM2203 // 07 - YM2608 // 08 - YM2610/YM2610B // 09 - YM3812 // 0A - YM3526 // 0B - Y8950 // 0C - YMF262 // 0D - YMF278B // 0E - YMF271 // 0F - YMZ280B // 10 - RF5C164 // 11 - PWM // 12 - AY8910 // 13 - GameBoy // 14 - NES APU // 15 - MultiPCM // 16 - UPD7759 // 17 - OKIM6258 // 18 - OKIM6295 // 19 - K051649 // 1A - K054539 // 1B - HuC6280 // 1C - C140 // 1D - K053260 // 1E - Pokey // 1F - QSound // 20 - YMF292/SCSP // 21 - WonderSwan // 22 - VSU // 23 - SAA1099 // 24 - ES5503 // 25 - ES5506 // 26 - X1-010 // 27 - C352 // 28 - GA20 TempBuf.Left = 0x00; TempBuf.Right = 0x00; CurCLst = p->ChipListAll; while(CurCLst != NULL) { if (! CurCLst->COpts->Disabled) { ResampleChipStream(p, CurCLst, &TempBuf, 1); } CurCLst = CurCLst->next; } // ChipData << 9 [ChipVol] >> 5 << 8 [MstVol] >> 11 -> 9-5+8-11 = <<1 TempBuf.Left = ((TempBuf.Left >> 5) * CurMstVol) >> 11; TempBuf.Right = ((TempBuf.Right >> 5) * CurMstVol) >> 11; if (p->SurroundSound) TempBuf.Right *= -1; Buffer[CurSmpl].Left = Limit2Short(TempBuf.Left); Buffer[CurSmpl].Right = Limit2Short(TempBuf.Right); if (p->FadePlay && ! p->FadeStart) { p->FadeStart = p->PlayingTime; RecalcStep = p->FadePlay ? p->SampleRate / 100 : 0; } if (RecalcStep && ! (CurSmpl % RecalcStep)) CurMstVol = RecalcFadeVolume(p); if (p->VGMEnd) { if (! p->EndPlay) { p->EndPlay = true; break; } } } return CurSmpl; } // ChanCount is an array of 3, for the 3 mute masks per chip static void GetChipByChannel(void* vgmp, UINT32 channel, UINT8 *ChipID, UINT8 *ChipType, UINT8 *Channel, UINT8 *ChanCount) { VGM_PLAYER* p = (VGM_PLAYER *)vgmp; *ChipType = 0xFF; if (p->VGMHead.lngHzPSG) { if (channel < 4) { *ChipID = 0x00; *ChipType = 0x00; *Channel = channel; ChanCount[0] = 4; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 4; if (p->VGMHead.lngHzPSG & 0x40000000) { if (channel < 4) { *ChipID = 0x01; *ChipType = 0x00; *Channel = channel; ChanCount[0] = 4; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 4; } } if (p->VGMHead.lngHzYM2413) { if (channel < 14) { *ChipID = 0x00; *ChipType = 0x01; *Channel = channel; ChanCount[0] = 14; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 14; if (p->VGMHead.lngHzYM2413 & 0x40000000) { if (channel < 14) { *ChipID = 0x01; *ChipType = 0x01; *Channel = channel; ChanCount[0] = 14; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 14; } } if (p->VGMHead.lngHzYM2612) { if (channel < 7) { *ChipID = 0x00; *ChipType = 0x02; *Channel = channel; ChanCount[0] = 7; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 7; if (p->VGMHead.lngHzYM2612 & 0x40000000) { if (channel < 7) { *ChipID = 0x01; *ChipType = 0x02; *Channel = channel; ChanCount[0] = 7; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 7; } } if (p->VGMHead.lngHzYM2151) { if (channel < 8) { *ChipID = 0x00; *ChipType = 0x03; *Channel = channel; ChanCount[0] = 8; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 8; if (p->VGMHead.lngHzYM2151 & 0x40000000) { if (channel < 8) { *ChipID = 0x01; *ChipType = 0x03; *Channel = channel; ChanCount[0] = 8; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 8; } } if (p->VGMHead.lngHzSPCM) { if (channel < 16) { *ChipID = 0x00; *ChipType = 0x04; *Channel = channel; ChanCount[0] = 16; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 16; if (p->VGMHead.lngHzSPCM & 0x40000000) { if (channel < 16) { *ChipID = 0x01; *ChipType = 0x04; *Channel = channel; ChanCount[0] = 16; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 16; } } if (p->VGMHead.lngHzRF5C68) { if (channel < 8) { *ChipID = 0x00; *ChipType = 0x05; *Channel = channel; ChanCount[0] = 8; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 8; } if (p->VGMHead.lngHzYM2203) { if (channel < 6) { *ChipID = 0x00; *ChipType = 0x06; *Channel = channel; ChanCount[0] = 3; ChanCount[1] = 0; ChanCount[2] = 3; } channel -= 6; if (p->VGMHead.lngHzYM2203 & 0x40000000) { if (channel < 6) { *ChipID = 0x01; *ChipType = 0x06; *Channel = channel; ChanCount[0] = 3; ChanCount[1] = 0; ChanCount[2] = 3; } channel -= 6; } } if (p->VGMHead.lngHzYM2608) { if (channel < 16) { *ChipID = 0x00; *ChipType = 0x07; *Channel = channel; ChanCount[0] = 6; ChanCount[1] = 7; ChanCount[2] = 3; } channel -= 16; if (p->VGMHead.lngHzYM2608 & 0x40000000) { if (channel < 16) { *ChipID = 0x01; *ChipType = 0x07; *Channel = channel; ChanCount[0] = 6; ChanCount[1] = 7; ChanCount[2] = 3; } channel -= 16; } } if (p->VGMHead.lngHzYM2610) { if (channel < 16) { *ChipID = 0x00; *ChipType = 0x08; *Channel = channel; ChanCount[0] = 6; ChanCount[1] = 7; ChanCount[2] = 3; } channel -= 16; if (p->VGMHead.lngHzYM2610 & 0x40000000) { if (channel < 16) { *ChipID = 0x01; *ChipType = 0x08; *Channel = channel; ChanCount[0] = 6; ChanCount[1] = 7; ChanCount[2] = 3; } channel -= 16; } } if (p->VGMHead.lngHzYM3812) { if (channel < 14) { *ChipID = 0x00; *ChipType = 0x09; *Channel = channel; ChanCount[0] = 14; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 14; if (p->VGMHead.lngHzYM3812 & 0x40000000) { if (channel < 14) { *ChipID = 0x01; *ChipType = 0x09; *Channel = channel; ChanCount[0] = 14; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 14; } } if (p->VGMHead.lngHzYM3526) { if (channel < 15) { *ChipID = 0x00; *ChipType = 0x0A; *Channel = channel; ChanCount[0] = 15; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 15; if (p->VGMHead.lngHzYM3526 & 0x40000000) { if (channel < 15) { *ChipID = 0x01; *ChipType = 0x0B; *Channel = channel; ChanCount[0] = 15; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 15; } } if (p->VGMHead.lngHzY8950) { if (channel < 15) { *ChipID = 0x00; *ChipType = 0x0B; *Channel = channel; ChanCount[0] = 15; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 15; if (p->VGMHead.lngHzY8950 & 0x40000000) { if (channel < 15) { *ChipID = 0x01; *ChipType = 0x0B; *Channel = channel; ChanCount[0] = 15; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 15; } } if (p->VGMHead.lngHzYMF262) { if (channel < 23) { *ChipID = 0x00; *ChipType = 0x0C; *Channel = channel; ChanCount[0] = 23; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 23; if (p->VGMHead.lngHzYMF262 & 0x40000000) { if (channel < 23) { *ChipID = 0x00; *ChipType = 0x0C; *Channel = channel; ChanCount[0] = 23; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 23; } } if (p->VGMHead.lngHzYMF278B) { if (channel < 47) { *ChipID = 0x00; *ChipType = 0x0D; *Channel = channel; ChanCount[0] = 23; ChanCount[1] = 24; ChanCount[2] = 0; } channel -= 47; if (p->VGMHead.lngHzYMF278B & 0x40000000) { if (channel < 47) { *ChipID = 0x01; *ChipType = 0x0D; *Channel = channel; ChanCount[0] = 23; ChanCount[1] = 24; ChanCount[2] = 0; } channel -= 47; } } if (p->VGMHead.lngHzYMF271) { if (channel < 12) { *ChipID = 0x00; *ChipType = 0x0E; *Channel = channel; ChanCount[0] = 12; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 12; if (p->VGMHead.lngHzYMF271 & 0x40000000) { if (channel < 12) { *ChipID = 0x01; *ChipType = 0x0E; *Channel = channel; ChanCount[0] = 12; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 12; } } if (p->VGMHead.lngHzYMZ280B) { if (channel < 8) { *ChipID = 0x00; *ChipType = 0x0F; *Channel = channel; ChanCount[0] = 8; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 8; if (p->VGMHead.lngHzYMZ280B & 0x40000000) { if (channel < 8) { *ChipID = 0x01; *ChipType = 0x0F; *Channel = channel; ChanCount[0] = 8; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 8; } } if (p->VGMHead.lngHzRF5C164) { if (channel < 8) { *ChipID = 0x00; *ChipType = 0x10; *Channel = channel; ChanCount[0] = 8; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 8; } if (p->VGMHead.lngHzPWM) { if (channel < 1) { *ChipID = 0x00; *ChipType = 0x11; *Channel = channel; ChanCount[0] = 1; ChanCount[1] = 0; ChanCount[2] = 0; } channel--; } if (p->VGMHead.lngHzAY8910) { if (channel < 3) { *ChipID = 0x00; *ChipType = 0x12; *Channel = channel; ChanCount[0] = 3; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 3; if (p->VGMHead.lngHzAY8910 & 0x40000000) { if (channel < 3) { *ChipID = 0x01; *ChipType = 0x12; *Channel = channel; ChanCount[0] = 3; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 3; } } if (p->VGMHead.lngHzGBDMG) { if (channel < 4) { *ChipID = 0x00; *ChipType = 0x13; *Channel = channel; ChanCount[0] = 4; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 4; if (p->VGMHead.lngHzGBDMG & 0x40000000) { if (channel < 4) { *ChipID = 0x01; *ChipType = 0x13; *Channel = channel; ChanCount[0] = 4; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 4; } } if (p->VGMHead.lngHzNESAPU) { if (channel < 6) { *ChipID = 0x00; *ChipType = 0x14; *Channel = channel; ChanCount[0] = 6; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 6; if (p->VGMHead.lngHzNESAPU & 0x40000000) { if (channel < 6) { *ChipID = 0x01; *ChipType = 0x14; *Channel = channel; ChanCount[0] = 6; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 6; } } if (p->VGMHead.lngHzMultiPCM) { if (channel < 28) { *ChipID = 0x00; *ChipType = 0x15; *Channel = channel; ChanCount[0] = 28; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 28; if (p->VGMHead.lngHzMultiPCM & 0x40000000) { if (channel < 28) { *ChipID = 0x01; *ChipType = 0x15; *Channel = channel; ChanCount[0] = 28; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 28; } } if (p->VGMHead.lngHzUPD7759) { if (channel < 1) { *ChipID = 0x00; *ChipType = 0x16; *Channel = channel; ChanCount[0] = 1; ChanCount[1] = 0; ChanCount[2] = 0; } channel--; if (p->VGMHead.lngHzUPD7759 & 0x40000000) { if (channel < 1) { *ChipID = 0x01; *ChipType = 0x16; *Channel = channel; ChanCount[0] = 1; ChanCount[1] = 0; ChanCount[2] = 0; } channel--; } } if (p->VGMHead.lngHzOKIM6258) { if (channel < 1) { *ChipID = 0x00; *ChipType = 0x17; *Channel = channel; ChanCount[0] = 1; ChanCount[1] = 0; ChanCount[2] = 0; } channel--; if (p->VGMHead.lngHzOKIM6258 & 0x40000000) { if (channel < 1) { *ChipID = 0x01; *ChipType = 0x17; *Channel = channel; ChanCount[0] = 1; ChanCount[1] = 0; ChanCount[2] = 0; } channel--; } } if (p->VGMHead.lngHzOKIM6295) { if (channel < 4) { *ChipID = 0x00; *ChipType = 0x18; *Channel = channel; ChanCount[0] = 4; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 4; if (p->VGMHead.lngHzOKIM6295 & 0x40000000) { if (channel < 4) { *ChipID = 0x01; *ChipType = 0x18; *Channel = channel; ChanCount[0] = 4; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 4; } } if (p->VGMHead.lngHzK051649) { if (channel < 5) { *ChipID = 0x00; *ChipType = 0x19; *Channel = channel; ChanCount[0] = 5; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 5; if (p->VGMHead.lngHzK051649 & 0x40000000) { if (channel < 5) { *ChipID = 0x01; *ChipType = 0x19; *Channel = channel; ChanCount[0] = 5; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 5; } } if (p->VGMHead.lngHzK054539) { if (channel < 8) { *ChipID = 0x00; *ChipType = 0x1A; *Channel = channel; ChanCount[0] = 8; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 8; if (p->VGMHead.lngHzK054539 & 0x40000000) { if (channel < 8) { *ChipID = 0x01; *ChipType = 0x1A; *Channel = channel; ChanCount[0] = 8; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 8; } } if (p->VGMHead.lngHzHuC6280) { if (channel < 6) { *ChipID = 0x00; *ChipType = 0x1B; *Channel = channel; ChanCount[0] = 6; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 6; if (p->VGMHead.lngHzHuC6280 & 0x40000000) { if (channel < 6) { *ChipID = 0x01; *ChipType = 0x1B; *Channel = channel; ChanCount[0] = 6; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 6; } } if (p->VGMHead.lngHzC140) { if (channel < 24) { *ChipID = 0x00; *ChipType = 0x1C; *Channel = channel; ChanCount[0] = 24; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 24; if (p->VGMHead.lngHzC140 & 0x40000000) { if (channel < 24) { *ChipID = 0x01; *ChipType = 0x1C; *Channel = channel; ChanCount[0] = 24; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 24; } } if (p->VGMHead.lngHzK053260) { if (channel < 4) { *ChipID = 0x00; *ChipType = 0x1D; *Channel = channel; ChanCount[0] = 4; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 4; if (p->VGMHead.lngHzK053260 & 0x40000000) { if (channel < 4) { *ChipID = 0x01; *ChipType = 0x1D; *Channel = channel; ChanCount[0] = 4; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 4; } } if (p->VGMHead.lngHzPokey) { if (channel < 4) { *ChipID = 0x00; *ChipType = 0x1E; *Channel = channel; ChanCount[0] = 4; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 4; if (p->VGMHead.lngHzPokey & 0x40000000) { if (channel < 4) { *ChipID = 0x01; *ChipType = 0x1E; *Channel = channel; ChanCount[0] = 4; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 4; } } if (p->VGMHead.lngHzQSound) { if (channel < 16) { *ChipID = 0x00; *ChipType = 0x1F; *Channel = channel; ChanCount[0] = 16; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 16; if (p->VGMHead.lngHzQSound & 0x40000000) { if (channel < 16) { *ChipID = 0x01; *ChipType = 0x1F; *Channel = channel; ChanCount[0] = 16; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 16; } } if (p->VGMHead.lngHzSCSP) { if (channel < 32) { *ChipID = 0x00; *ChipType = 0x20; *Channel = channel; ChanCount[0] = 32; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 32; if (p->VGMHead.lngHzSCSP & 0x40000000) { if (channel < 32) { *ChipID = 0x01; *ChipType = 0x20; *Channel = channel; ChanCount[0] = 32; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 32; } } if (p->VGMHead.lngHzWSwan) { if (channel < 4) { *ChipID = 0x00; *ChipType = 0x21; *Channel = channel; ChanCount[0] = 4; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 4; if (p->VGMHead.lngHzWSwan & 0x40000000) { if (channel < 4) { *ChipID = 0x01; *ChipType = 0x21; *Channel = channel; ChanCount[0] = 4; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 4; } } if (p->VGMHead.lngHzVSU) { if (channel < 6) { *ChipID = 0x00; *ChipType = 0x22; *Channel = channel; ChanCount[0] = 6; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 6; if (p->VGMHead.lngHzVSU & 0x40000000) { if (channel < 6) { *ChipID = 0x01; *ChipType = 0x22; *Channel = channel; ChanCount[0] = 6; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 6; } } if (p->VGMHead.lngHzSAA1099) { if (channel < 6) { *ChipID = 0x00; *ChipType = 0x23; *Channel = channel; ChanCount[0] = 6; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 6; if (p->VGMHead.lngHzSAA1099 & 0x40000000) { if (channel < 6) { *ChipID = 0x01; *ChipType = 0x23; *Channel = channel; ChanCount[0] = 6; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 6; } } if (p->VGMHead.lngHzES5503) { if (channel < 32) { *ChipID = 0x00; *ChipType = 0x24; *Channel = channel; ChanCount[0] = 32; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 32; if (p->VGMHead.lngHzES5503 & 0x40000000) { if (channel < 32) { *ChipID = 0x01; *ChipType = 0x24; *Channel = channel; ChanCount[0] = 32; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 32; } } if (p->VGMHead.lngHzES5506) { if (channel < 32) { *ChipID = 0x00; *ChipType = 0x25; *Channel = channel; ChanCount[0] = 32; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 32; if (p->VGMHead.lngHzES5506 & 0x40000000) { if (channel < 32) { *ChipID = 0x01; *ChipType = 0x25; *Channel = channel; ChanCount[0] = 32; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 32; } } if (p->VGMHead.lngHzX1_010) { if (channel < 16) { *ChipID = 0x00; *ChipType = 0x26; *Channel = channel; ChanCount[0] = 16; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 16; if (p->VGMHead.lngHzX1_010 & 0x40000000) { if (channel < 16) { *ChipID = 0x01; *ChipType = 0x26; *Channel = channel; ChanCount[0] = 16; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 16; } } if (p->VGMHead.lngHzC352) { if (channel < 32) { *ChipID = 0x00; *ChipType = 0x27; *Channel = channel; ChanCount[0] = 32; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 32; if (p->VGMHead.lngHzC352 & 0x40000000) { if (channel < 32) { *ChipID = 0x01; *ChipType = 0x27; *Channel = channel; ChanCount[0] = 32; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 32; } } if (p->VGMHead.lngHzGA20) { if (channel < 4) { *ChipID = 0x00; *ChipType = 0x28; *Channel = channel; ChanCount[0] = 4; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 4; if (p->VGMHead.lngHzGA20 & 0x40000000) { if (channel < 4) { *ChipID = 0x01; *ChipType = 0x28; *Channel = channel; ChanCount[0] = 4; ChanCount[1] = 0; ChanCount[2] = 0; } channel -= 4; } } } const char* GetAccurateChipNameByChannel(void* vgmp, UINT32 channel, UINT32 *realChannel) { UINT8 ChipID, ChipType, SubType, Channel, ChanCount[3]; GetChipByChannel(vgmp, channel, &ChipID, &ChipType, &Channel, ChanCount); if (ChipType == 0xFF) return NULL; *realChannel = Channel; GetChipClock(vgmp, ChipType, &SubType); return GetAccurateChipName(ChipType, SubType); } void SetChannelMute(void* vgmp, UINT32 channel, UINT8 mute) { VGM_PLAYER *p = (VGM_PLAYER *)vgmp; UINT8 ChipID, ChipType, Channel, ChanCount[3]; CHIP_OPTS *opts; UINT8 FieldNumber; UINT32 *ChnMutes; GetChipByChannel(vgmp, channel, &ChipID, &ChipType, &Channel, ChanCount); if (ChipType == 0xFF) return; opts = (CHIP_OPTS *)(&p->ChipOpts[ChipID]) + ChipType; ChnMutes = (UINT32 *)(&opts->ChnMute1); for (FieldNumber = 0; FieldNumber < 3; FieldNumber++) { if (Channel < ChanCount[FieldNumber]) { if (mute) ChnMutes[FieldNumber] |= 1 << Channel; else ChnMutes[FieldNumber] &= ~(1 << Channel); break; } Channel -= ChanCount[FieldNumber]; } Chips_GeneralActions(p, 0x10); }