--- /dev/null
+#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__
--- /dev/null
+// imf2vgm.c - IMF -> VGM Converter
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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;
+}