From 8a50d2e6dffd07e0ba149e70ae79cc81e1748d39 Mon Sep 17 00:00:00 2001 From: sparky4 Date: Fri, 18 Aug 2017 19:43:36 -0500 Subject: [PATCH 1/1] imfplay and vgmtest are both broken ><. but bcexmmtest.exe works! --- src/imfplay.c | 2 +- src/lib/vgmsnd/VGMFile.h | 152 ++++++++++++++++++++ src/lib/vgmsnd/imf2vgm.c | 302 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 455 insertions(+), 1 deletion(-) create mode 100755 src/lib/vgmsnd/VGMFile.h create mode 100755 src/lib/vgmsnd/imf2vgm.c diff --git a/src/imfplay.c b/src/imfplay.c index 1895d77d..697b6d36 100755 --- a/src/imfplay.c +++ b/src/imfplay.c @@ -19,7 +19,7 @@ #include "src/lib/16_mm.h" #include "src/lib/16_hc.h" #include "src/lib/16_dbg.h" -//#include "src/lib/16_sd.h" +#include "src/lib/16_sd.h" // #include // #include /* this is where Open Watcom hides the outp() etc. functions */ diff --git a/src/lib/vgmsnd/VGMFile.h b/src/lib/vgmsnd/VGMFile.h new file mode 100755 index 00000000..29c4ad4c --- /dev/null +++ b/src/lib/vgmsnd/VGMFile.h @@ -0,0 +1,152 @@ +#ifndef __VGMFILE_H__ +#define __VGMFILE_H__ + +// Header file for VGM file handling + +typedef struct _vgm_file_header +{ + UINT32 fccVGM; + UINT32 lngEOFOffset; + UINT32 lngVersion; + UINT32 lngHzPSG; + UINT32 lngHzYM2413; + UINT32 lngGD3Offset; + UINT32 lngTotalSamples; + UINT32 lngLoopOffset; + UINT32 lngLoopSamples; + UINT32 lngRate; + UINT16 shtPSG_Feedback; + UINT8 bytPSG_SRWidth; + UINT8 bytPSG_Flags; + UINT32 lngHzYM2612; + UINT32 lngHzYM2151; + UINT32 lngDataOffset; + UINT32 lngHzSPCM; + UINT32 lngSPCMIntf; + UINT32 lngHzRF5C68; + UINT32 lngHzYM2203; + UINT32 lngHzYM2608; + UINT32 lngHzYM2610; + UINT32 lngHzYM3812; + UINT32 lngHzYM3526; + UINT32 lngHzY8950; + UINT32 lngHzYMF262; + UINT32 lngHzYMF278B; + UINT32 lngHzYMF271; + UINT32 lngHzYMZ280B; + UINT32 lngHzRF5C164; + UINT32 lngHzPWM; + UINT32 lngHzAY8910; + UINT8 bytAYType; + UINT8 bytAYFlag; + UINT8 bytAYFlagYM2203; + UINT8 bytAYFlagYM2608; + UINT8 bytVolumeModifier; + UINT8 bytReserved2; + INT8 bytLoopBase; + UINT8 bytLoopModifier; + UINT32 lngHzGBDMG; + UINT32 lngHzNESAPU; + UINT32 lngHzMultiPCM; + UINT32 lngHzUPD7759; + UINT32 lngHzOKIM6258; + UINT8 bytOKI6258Flags; + UINT8 bytK054539Flags; + UINT8 bytC140Type; + UINT8 bytReservedFlags; + UINT32 lngHzOKIM6295; + UINT32 lngHzK051649; + UINT32 lngHzK054539; + UINT32 lngHzHuC6280; + UINT32 lngHzC140; + UINT32 lngHzK053260; + UINT32 lngHzPokey; + UINT32 lngHzQSound; + UINT32 lngHzSCSP; +// UINT32 lngHzOKIM6376; + //UINT8 bytReserved[0x04]; + UINT32 lngExtraOffset; + UINT32 lngHzWSwan; + UINT32 lngHzVSU; + UINT32 lngHzSAA1099; + UINT32 lngHzES5503; + UINT32 lngHzES5506; + UINT8 bytES5503Chns; + UINT8 bytES5506Chns; + UINT8 bytC352ClkDiv; + UINT8 bytESReserved; + UINT32 lngHzX1_010; + UINT32 lngHzC352; + UINT32 lngHzGA20; +} VGM_HEADER; +typedef struct _vgm_header_extra +{ + UINT32 DataSize; + UINT32 Chp2ClkOffset; + UINT32 ChpVolOffset; +} VGM_HDR_EXTRA; +typedef struct _vgm_extra_chip_data32 +{ + UINT8 Type; + UINT32 Data; +} VGMX_CHIP_DATA32; +typedef struct _vgm_extra_chip_data16 +{ + UINT8 Type; + UINT8 Flags; + UINT16 Data; +} VGMX_CHIP_DATA16; +typedef struct _vgm_extra_chip_extra32 +{ + UINT8 ChipCnt; + VGMX_CHIP_DATA32* CCData; +} VGMX_CHP_EXTRA32; +typedef struct _vgm_extra_chip_extra16 +{ + UINT8 ChipCnt; + VGMX_CHIP_DATA16* CCData; +} VGMX_CHP_EXTRA16; +typedef struct _vgm_header_extra_data +{ + VGMX_CHP_EXTRA32 Clocks; + VGMX_CHP_EXTRA16 Volumes; +} VGM_EXTRA; + +#define VOLUME_MODIF_WRAP 0xC0 +typedef struct _vgm_gd3_tag +{ + UINT32 fccGD3; + UINT32 lngVersion; + UINT32 lngTagLength; + wchar_t* strTrackNameE; + wchar_t* strTrackNameJ; + wchar_t* strGameNameE; + wchar_t* strGameNameJ; + wchar_t* strSystemNameE; + wchar_t* strSystemNameJ; + wchar_t* strAuthorNameE; + wchar_t* strAuthorNameJ; + wchar_t* strReleaseDate; + wchar_t* strCreator; + wchar_t* strNotes; +} GD3_TAG; +typedef struct _vgm_pcm_bank_data +{ + UINT32 DataSize; + UINT8* Data; + UINT32 DataStart; +} VGM_PCM_DATA; +typedef struct _vgm_pcm_bank +{ + UINT32 BankCount; + VGM_PCM_DATA* Bank; + UINT32 DataSize; + UINT8* Data; + UINT32 DataPos; + UINT32 BnkPos; +} VGM_PCM_BANK; + +#define FCC_VGM 0x206D6756 // 'Vgm ' +#define FCC_GD3 0x20336447 // 'Gd3 ' + +#endif // __VGMFILE_H__ diff --git a/src/lib/vgmsnd/imf2vgm.c b/src/lib/vgmsnd/imf2vgm.c new file mode 100755 index 00000000..7d7c6834 --- /dev/null +++ b/src/lib/vgmsnd/imf2vgm.c @@ -0,0 +1,302 @@ +// imf2vgm.c - IMF -> VGM Converter +// + +#include +#include +#include + +#include "stdtype.h" +#include "VGMFile.h" +#include "common.h" + + +static UINT8 OpenIMFFile(const char* FileName); +static void WriteVGMFile(const char* FileName); +static void ConvertIMF2VGM(void); + + +UINT8 IMFType; +UINT16 IMFRate; +VGM_HEADER VGMHead; +UINT32 IMFDataLen; +UINT8* IMFData; +UINT32 IMFPos; +UINT32 IMFDataStart; +UINT32 IMFDataEnd; +UINT32 VGMDataLen; +UINT8* VGMData; +UINT32 VGMPos; +char FileBase[0x100]; +UINT8 LoopOn; + +int main(int argc, char* argv[]) +{ + int argbase; + int ErrVal; + char FileName[0x100]; + UINT16 ForceHz; + UINT8 ForceType; + + printf("IMF to VGM Converter\n--------------------\n\n"); + + ErrVal = 0; + argbase = 1; + ForceHz = 0; + ForceType = 0xFF; + LoopOn = 0x00; + + while(argbase < argc && argv[argbase][0] == '-') + { + if (! stricmp(argv[argbase], "-help")) + { + printf("Usage: imf2vgm [-Loop] [-Hz###] [-Type#] Input.imf [Output.vgm]\n"); + printf("\n"); + printf("Loop: Makes the song loop from beginning to end.\n"); + printf("Hz: There are 3 known speeds: 280, 560 and 700\n"); + printf(" 560 is default for .imf, 700 for .wlf files\n"); + printf("Type: Can be 0 (no header) or 1 (header with 2-byte file size)\n"); + return 0; + } + else if (! stricmp(argv[argbase], "-Loop")) + { + LoopOn = 0x01; + argbase ++; + } + else if (! strnicmp(argv[argbase], "-Hz", 3)) + { + ForceHz = (UINT16)strtoul(argv[argbase] + 3, NULL, 0); + argbase ++; + } + else if (! strnicmp(argv[argbase], "-Type", 5)) + { + ForceType = (UINT8)strtoul(argv[argbase] + 5, NULL, 0); + if (ForceType >= 0x02) + { + printf("Error: Type must be either 0 or 1!\n"); + return 2; + } + argbase ++; + } + else + { + break; + } + } + + printf("File Name:\t"); + if (argc <= argbase + 0) + { + ReadFilename(FileName, sizeof(FileName)); + } + else + { + strcpy(FileName, argv[argbase + 0]); + printf("%s\n", FileName); + } + if (! strlen(FileName)) + return 0; + + if (OpenIMFFile(FileName)) + { + printf("Error opening the file!\n"); + ErrVal = 1; + goto EndProgram; + } + printf("\n"); + + if (ForceHz) + IMFRate = ForceHz; + if (ForceType < 0xFF) + IMFType = ForceType; + ConvertIMF2VGM(); + + if (argc > argbase + 1) + strcpy(FileName, argv[argbase + 1]); + else + strcpy(FileName, ""); + if (FileName[0] == '\0') + { + strcpy(FileName, FileBase); + strcat(FileName, ".vgm"); + } + WriteVGMFile(FileName); + + free(IMFData); + free(VGMData); + +EndProgram: + DblClickWait(argv[0]); + + return ErrVal; +} + +static UINT8 OpenIMFFile(const char* FileName) +{ + FILE* hFile; + UINT16 TempSht; + char* TempPnt; + + hFile = fopen(FileName, "rb"); + if (hFile == NULL) + return 0xFF; + + fseek(hFile, 0x00, SEEK_END); + IMFDataLen = ftell(hFile); + + // Read Data + IMFData = (UINT8*)malloc(IMFDataLen); + if (IMFData == NULL) + goto OpenErr; + fseek(hFile, 0x00, SEEK_SET); + IMFDataLen = fread(IMFData, 0x01, IMFDataLen, hFile); + + fclose(hFile); + + memcpy(&TempSht, &IMFData[0x00], 0x02); + if (! TempSht) + IMFType = 0x00; + else + IMFType = 0x01; + + strcpy(FileBase, FileName); + TempPnt = strrchr(FileBase, '.'); + if (TempPnt != NULL) + { + *TempPnt = 0x00; + TempPnt ++; + } + else + { + TempPnt = FileBase + strlen(FileBase); + } + if (! stricmp(TempPnt, "wlf")) + IMFRate = 700; + else + IMFRate = 560; + + return 0x00; + +OpenErr: + + fclose(hFile); + return 0x80; +} + +static void WriteVGMFile(const char* FileName) +{ + FILE* hFile; + + hFile = fopen(FileName, "wb"); + fwrite(VGMData, 0x01, VGMDataLen, hFile); + fclose(hFile); + + printf("File written.\n"); + + return; +} + +static void ConvertIMF2VGM(void) +{ + UINT16 CurDelay; + UINT32 CurTick; + UINT16 HalfRate; + UINT64 TempTick; + UINT32 VGMSmplL; + UINT32 VGMSmplC; + UINT32 SmplVal; + + VGMDataLen = sizeof(VGM_HEADER) + IMFDataLen * 0x02; + VGMData = (UINT8*)malloc(VGMDataLen); + + printf("IMF Type: %u, IMF Playback Rate: %u Hz\n", IMFType, IMFRate); + + memcpy(&CurDelay, &IMFData[0x00], 0x02); + if (IMFType == 0x00) + { + IMFDataStart = 0x0000; + IMFDataEnd = IMFDataLen; + } + else //if (IMFType == 0x01) + { + IMFDataStart = 0x0002; + IMFDataEnd = IMFDataStart + CurDelay; + } + + // Generate VGM Header + memset(&VGMHead, 0x00, sizeof(VGM_HEADER)); + VGMHead.fccVGM = FCC_VGM; + VGMHead.lngVersion = 0x00000151; + VGMHead.lngRate = IMFRate; + VGMHead.lngDataOffset = 0x80; + VGMHead.lngHzYM3812 = 3579545; + + // Convert data + IMFPos = IMFDataStart; + VGMPos = VGMHead.lngDataOffset; + CurTick = 0; + VGMSmplL = 0; + HalfRate = IMFRate / 2; // for correct rounding + while(IMFPos < IMFDataEnd) + { + if (VGMPos >= VGMDataLen - 0x08) + { + VGMDataLen += 0x8000; + VGMData = (UINT8*)realloc(VGMData, VGMDataLen); + } + VGMData[VGMPos + 0x00] = 0x5A; + VGMData[VGMPos + 0x01] = IMFData[IMFPos + 0x00]; // register + VGMData[VGMPos + 0x02] = IMFData[IMFPos + 0x01]; // data + VGMPos += 0x03; + + memcpy(&CurDelay, &IMFData[IMFPos + 0x02], 0x02); + CurTick += CurDelay; + TempTick = (UINT64)CurTick * 44100 + HalfRate; + VGMSmplC = (UINT32)(TempTick / IMFRate); + IMFPos += 0x04; + + if (VGMSmplL < VGMSmplC) + { + SmplVal = VGMSmplC - VGMSmplL; + while(SmplVal) + { + if (SmplVal <= 0xFFFF) + CurDelay = (UINT16)SmplVal; + else + CurDelay = 0xFFFF; + + if (VGMPos >= VGMDataLen - 0x08) + { + VGMDataLen += 0x8000; + VGMData = (UINT8*)realloc(VGMData, VGMDataLen); + } + VGMData[VGMPos + 0x00] = 0x61; + memcpy(&VGMData[VGMPos + 0x01], &CurDelay, 0x02); + VGMPos += 0x03; + SmplVal -= CurDelay; + } + VGMSmplL = VGMSmplC; + } + } + VGMData[VGMPos] = 0x66; + VGMPos += 0x01; + + VGMDataLen = VGMPos; + VGMHead.lngEOFOffset = VGMDataLen; + VGMHead.lngTotalSamples = VGMSmplL; + if (LoopOn) + { + VGMHead.lngLoopOffset = VGMHead.lngDataOffset; + VGMHead.lngLoopSamples = VGMHead.lngTotalSamples; + } + + SmplVal = VGMHead.lngDataOffset; + if (SmplVal > sizeof(VGM_HEADER)) + SmplVal = sizeof(VGM_HEADER); + VGMHead.lngEOFOffset -= 0x04; + if (VGMHead.lngLoopOffset) + VGMHead.lngLoopOffset -= 0x1C; + VGMHead.lngDataOffset -= 0x34; + memcpy(&VGMData[0x00], &VGMHead, SmplVal); + + return; +} -- 2.39.2