1 // imf2vgm.c - IMF -> VGM Converter
13 static UINT8 OpenIMFFile(const char* FileName);
14 static void WriteVGMFile(const char* FileName);
15 static void ConvertIMF2VGM(void);
32 int main(int argc, char* argv[])
40 printf("IMF to VGM Converter\n--------------------\n\n");
48 while(argbase < argc && argv[argbase][0] == '-')
50 if (! stricmp(argv[argbase], "-help"))
52 printf("Usage: imf2vgm [-Loop] [-Hz###] [-Type#] Input.imf [Output.vgm]\n");
54 printf("Loop: Makes the song loop from beginning to end.\n");
55 printf("Hz: There are 3 known speeds: 280, 560 and 700\n");
56 printf(" 560 is default for .imf, 700 for .wlf files\n");
57 printf("Type: Can be 0 (no header) or 1 (header with 2-byte file size)\n");
60 else if (! stricmp(argv[argbase], "-Loop"))
65 else if (! strnicmp(argv[argbase], "-Hz", 3))
67 ForceHz = (UINT16)strtoul(argv[argbase] + 3, NULL, 0);
70 else if (! strnicmp(argv[argbase], "-Type", 5))
72 ForceType = (UINT8)strtoul(argv[argbase] + 5, NULL, 0);
73 if (ForceType >= 0x02)
75 printf("Error: Type must be either 0 or 1!\n");
86 printf("File Name:\t");
87 if (argc <= argbase + 0)
89 ReadFilename(FileName, sizeof(FileName));
93 strcpy(FileName, argv[argbase + 0]);
94 printf("%s\n", FileName);
96 if (! strlen(FileName))
99 if (OpenIMFFile(FileName))
101 printf("Error opening the file!\n");
109 if (ForceType < 0xFF)
113 if (argc > argbase + 1)
114 strcpy(FileName, argv[argbase + 1]);
116 strcpy(FileName, "");
117 if (FileName[0] == '\0')
119 strcpy(FileName, FileBase);
120 strcat(FileName, ".vgm");
122 WriteVGMFile(FileName);
128 DblClickWait(argv[0]);
133 static UINT8 OpenIMFFile(const char* FileName)
139 hFile = fopen(FileName, "rb");
143 fseek(hFile, 0x00, SEEK_END);
144 IMFDataLen = ftell(hFile);
147 IMFData = (UINT8*)malloc(IMFDataLen);
150 fseek(hFile, 0x00, SEEK_SET);
151 IMFDataLen = fread(IMFData, 0x01, IMFDataLen, hFile);
155 memcpy(&TempSht, &IMFData[0x00], 0x02);
161 strcpy(FileBase, FileName);
162 TempPnt = strrchr(FileBase, '.');
170 TempPnt = FileBase + strlen(FileBase);
172 if (! stricmp(TempPnt, "wlf"))
185 static void WriteVGMFile(const char* FileName)
189 hFile = fopen(FileName, "wb");
190 fwrite(VGMData, 0x01, VGMDataLen, hFile);
193 printf("File written.\n");
198 static void ConvertIMF2VGM(void)
208 VGMDataLen = sizeof(VGM_HEADER) + IMFDataLen * 0x02;
209 VGMData = (UINT8*)malloc(VGMDataLen);
211 printf("IMF Type: %u, IMF Playback Rate: %u Hz\n", IMFType, IMFRate);
213 memcpy(&CurDelay, &IMFData[0x00], 0x02);
216 IMFDataStart = 0x0000;
217 IMFDataEnd = IMFDataLen;
219 else //if (IMFType == 0x01)
221 IMFDataStart = 0x0002;
222 IMFDataEnd = IMFDataStart + CurDelay;
225 // Generate VGM Header
226 memset(&VGMHead, 0x00, sizeof(VGM_HEADER));
227 VGMHead.fccVGM = FCC_VGM;
228 VGMHead.lngVersion = 0x00000151;
229 VGMHead.lngRate = IMFRate;
230 VGMHead.lngDataOffset = 0x80;
231 VGMHead.lngHzYM3812 = 3579545;
234 IMFPos = IMFDataStart;
235 VGMPos = VGMHead.lngDataOffset;
238 HalfRate = IMFRate / 2; // for correct rounding
239 while(IMFPos < IMFDataEnd)
241 if (VGMPos >= VGMDataLen - 0x08)
243 VGMDataLen += 0x8000;
244 VGMData = (UINT8*)realloc(VGMData, VGMDataLen);
246 VGMData[VGMPos + 0x00] = 0x5A;
247 VGMData[VGMPos + 0x01] = IMFData[IMFPos + 0x00]; // register
248 VGMData[VGMPos + 0x02] = IMFData[IMFPos + 0x01]; // data
251 memcpy(&CurDelay, &IMFData[IMFPos + 0x02], 0x02);
253 TempTick = (UINT64)CurTick * 44100 + HalfRate;
254 VGMSmplC = (UINT32)(TempTick / IMFRate);
257 if (VGMSmplL < VGMSmplC)
259 SmplVal = VGMSmplC - VGMSmplL;
262 if (SmplVal <= 0xFFFF)
263 CurDelay = (UINT16)SmplVal;
267 if (VGMPos >= VGMDataLen - 0x08)
269 VGMDataLen += 0x8000;
270 VGMData = (UINT8*)realloc(VGMData, VGMDataLen);
272 VGMData[VGMPos + 0x00] = 0x61;
273 memcpy(&VGMData[VGMPos + 0x01], &CurDelay, 0x02);
280 VGMData[VGMPos] = 0x66;
284 VGMHead.lngEOFOffset = VGMDataLen;
285 VGMHead.lngTotalSamples = VGMSmplL;
288 VGMHead.lngLoopOffset = VGMHead.lngDataOffset;
289 VGMHead.lngLoopSamples = VGMHead.lngTotalSamples;
292 SmplVal = VGMHead.lngDataOffset;
293 if (SmplVal > sizeof(VGM_HEADER))
294 SmplVal = sizeof(VGM_HEADER);
295 VGMHead.lngEOFOffset -= 0x04;
296 if (VGMHead.lngLoopOffset)
297 VGMHead.lngLoopOffset -= 0x1C;
298 VGMHead.lngDataOffset -= 0x34;
299 memcpy(&VGMData[0x00], &VGMHead, SmplVal);