]> 4ch.mooo.com Git - 16.git/blob - src/lib/vgmsnd/imf2vgm.c
worked on SD abit so the irq0 is not needed in imfplay anymore. I will need to merge...
[16.git] / src / lib / vgmsnd / imf2vgm.c
1 // imf2vgm.c - IMF -> VGM Converter
2 //
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include "stdtype.h"
9 #include "VGMFile.h"
10 #include "common.h"
11
12
13 static UINT8 OpenIMFFile(const char* FileName);
14 static void WriteVGMFile(const char* FileName);
15 static void ConvertIMF2VGM(void);
16
17
18 UINT8 IMFType;
19 UINT16 IMFRate;
20 VGM_HEADER VGMHead;
21 UINT32 IMFDataLen;
22 UINT8* IMFData;
23 UINT32 IMFPos;
24 UINT32 IMFDataStart;
25 UINT32 IMFDataEnd;
26 UINT32 VGMDataLen;
27 UINT8* VGMData;
28 UINT32 VGMPos;
29 char FileBase[0x100];
30 UINT8 LoopOn;
31
32 int main(int argc, char* argv[])
33 {
34         int argbase;
35         int ErrVal;
36         char FileName[0x100];
37         UINT16 ForceHz;
38         UINT8 ForceType;
39         
40         printf("IMF to VGM Converter\n--------------------\n\n");
41         
42         ErrVal = 0;
43         argbase = 1;
44         ForceHz = 0;
45         ForceType = 0xFF;
46         LoopOn = 0x00;
47         
48         while(argbase < argc && argv[argbase][0] == '-')
49         {
50                 if (! stricmp(argv[argbase], "-help"))
51                 {
52                         printf("Usage: imf2vgm [-Loop] [-Hz###] [-Type#] Input.imf [Output.vgm]\n");
53                         printf("\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");
58                         return 0;
59                 }
60                 else if (! stricmp(argv[argbase], "-Loop"))
61                 {
62                         LoopOn = 0x01;
63                         argbase ++;
64                 }
65                 else if (! strnicmp(argv[argbase], "-Hz", 3))
66                 {
67                         ForceHz = (UINT16)strtoul(argv[argbase] + 3, NULL, 0);
68                         argbase ++;
69                 }
70                 else if (! strnicmp(argv[argbase], "-Type", 5))
71                 {
72                         ForceType = (UINT8)strtoul(argv[argbase] + 5, NULL, 0);
73                         if (ForceType >= 0x02)
74                         {
75                                 printf("Error: Type must be either 0 or 1!\n");
76                                 return 2;
77                         }
78                         argbase ++;
79                 }
80                 else
81                 {
82                         break;
83                 }
84         }
85         
86         printf("File Name:\t");
87         if (argc <= argbase + 0)
88         {
89                 ReadFilename(FileName, sizeof(FileName));
90         }
91         else
92         {
93                 strcpy(FileName, argv[argbase + 0]);
94                 printf("%s\n", FileName);
95         }
96         if (! strlen(FileName))
97                 return 0;
98         
99         if (OpenIMFFile(FileName))
100         {
101                 printf("Error opening the file!\n");
102                 ErrVal = 1;
103                 goto EndProgram;
104         }
105         printf("\n");
106         
107         if (ForceHz)
108                 IMFRate = ForceHz;
109         if (ForceType < 0xFF)
110                 IMFType = ForceType;
111         ConvertIMF2VGM();
112         
113         if (argc > argbase + 1)
114                 strcpy(FileName, argv[argbase + 1]);
115         else
116                 strcpy(FileName, "");
117         if (FileName[0] == '\0')
118         {
119                 strcpy(FileName, FileBase);
120                 strcat(FileName, ".vgm");
121         }
122         WriteVGMFile(FileName);
123         
124         free(IMFData);
125         free(VGMData);
126         
127 EndProgram:
128         DblClickWait(argv[0]);
129         
130         return ErrVal;
131 }
132
133 static UINT8 OpenIMFFile(const char* FileName)
134 {
135         FILE* hFile;
136         UINT16 TempSht;
137         char* TempPnt;
138         
139         hFile = fopen(FileName, "rb");
140         if (hFile == NULL)
141                 return 0xFF;
142         
143         fseek(hFile, 0x00, SEEK_END);
144         IMFDataLen = ftell(hFile);
145         
146         // Read Data
147         IMFData = (UINT8*)malloc(IMFDataLen);
148         if (IMFData == NULL)
149                 goto OpenErr;
150         fseek(hFile, 0x00, SEEK_SET);
151         IMFDataLen = fread(IMFData, 0x01, IMFDataLen, hFile);
152         
153         fclose(hFile);
154         
155         memcpy(&TempSht, &IMFData[0x00], 0x02);
156         if (! TempSht)
157                 IMFType = 0x00;
158         else
159                 IMFType = 0x01;
160         
161         strcpy(FileBase, FileName);
162         TempPnt = strrchr(FileBase, '.');
163         if (TempPnt != NULL)
164         {
165                 *TempPnt = 0x00;
166                 TempPnt ++;
167         }
168         else
169         {
170                 TempPnt = FileBase + strlen(FileBase);
171         }
172         if (! stricmp(TempPnt, "wlf"))
173                 IMFRate = 700;
174         else
175                 IMFRate = 560;
176         
177         return 0x00;
178
179 OpenErr:
180
181         fclose(hFile);
182         return 0x80;
183 }
184
185 static void WriteVGMFile(const char* FileName)
186 {
187         FILE* hFile;
188         
189         hFile = fopen(FileName, "wb");
190         fwrite(VGMData, 0x01, VGMDataLen, hFile);
191         fclose(hFile);
192         
193         printf("File written.\n");
194         
195         return;
196 }
197
198 static void ConvertIMF2VGM(void)
199 {
200         UINT16 CurDelay;
201         UINT32 CurTick;
202         UINT16 HalfRate;
203         UINT64 TempTick;
204         UINT32 VGMSmplL;
205         UINT32 VGMSmplC;
206         UINT32 SmplVal;
207         
208         VGMDataLen = sizeof(VGM_HEADER) + IMFDataLen * 0x02;
209         VGMData = (UINT8*)malloc(VGMDataLen);
210         
211         printf("IMF Type: %u, IMF Playback Rate: %u Hz\n", IMFType, IMFRate);
212         
213         memcpy(&CurDelay, &IMFData[0x00], 0x02);
214         if (IMFType == 0x00)
215         {
216                 IMFDataStart = 0x0000;
217                 IMFDataEnd = IMFDataLen;
218         }
219         else //if (IMFType == 0x01)
220         {
221                 IMFDataStart = 0x0002;
222                 IMFDataEnd = IMFDataStart + CurDelay;
223         }
224         
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;
232         
233         // Convert data
234         IMFPos = IMFDataStart;
235         VGMPos = VGMHead.lngDataOffset;
236         CurTick = 0;
237         VGMSmplL = 0;
238         HalfRate = IMFRate / 2; // for correct rounding
239         while(IMFPos < IMFDataEnd)
240         {
241                 if (VGMPos >= VGMDataLen - 0x08)
242                 {
243                         VGMDataLen += 0x8000;
244                         VGMData = (UINT8*)realloc(VGMData, VGMDataLen);
245                 }
246                 VGMData[VGMPos + 0x00] = 0x5A;
247                 VGMData[VGMPos + 0x01] = IMFData[IMFPos + 0x00];        // register
248                 VGMData[VGMPos + 0x02] = IMFData[IMFPos + 0x01];        // data
249                 VGMPos += 0x03;
250                 
251                 memcpy(&CurDelay, &IMFData[IMFPos + 0x02], 0x02);
252                 CurTick += CurDelay;
253                 TempTick = (UINT64)CurTick * 44100 + HalfRate;
254                 VGMSmplC = (UINT32)(TempTick / IMFRate);
255                 IMFPos += 0x04;
256                 
257                 if (VGMSmplL < VGMSmplC)
258                 {
259                         SmplVal = VGMSmplC - VGMSmplL;
260                         while(SmplVal)
261                         {
262                                 if (SmplVal <= 0xFFFF)
263                                         CurDelay = (UINT16)SmplVal;
264                                 else
265                                         CurDelay = 0xFFFF;
266                                 
267                                 if (VGMPos >= VGMDataLen - 0x08)
268                                 {
269                                         VGMDataLen += 0x8000;
270                                         VGMData = (UINT8*)realloc(VGMData, VGMDataLen);
271                                 }
272                                 VGMData[VGMPos + 0x00] = 0x61;
273                                 memcpy(&VGMData[VGMPos + 0x01], &CurDelay, 0x02);
274                                 VGMPos += 0x03;
275                                 SmplVal -= CurDelay;
276                         }
277                         VGMSmplL = VGMSmplC;
278                 }
279         }
280         VGMData[VGMPos] = 0x66;
281         VGMPos += 0x01;
282         
283         VGMDataLen = VGMPos;
284         VGMHead.lngEOFOffset = VGMDataLen;
285         VGMHead.lngTotalSamples = VGMSmplL;
286         if (LoopOn)
287         {
288                 VGMHead.lngLoopOffset = VGMHead.lngDataOffset;
289                 VGMHead.lngLoopSamples = VGMHead.lngTotalSamples;
290         }
291         
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);
300         
301         return;
302 }