/[projet1]/public/pc/tools/osdk/main/Ym2Mym/sources/Ym2Mym.cpp
Defence Force logotype

Contents of /public/pc/tools/osdk/main/Ym2Mym/sources/Ym2Mym.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1040 - (show annotations)
Wed Dec 18 15:56:07 2013 UTC (6 years, 1 month ago) by dbug
File size: 11060 byte(s)
Ym2Mym 1.0
- Added command line parameters for enabling/disabling retuning of frequency
1 /*
2 ym2mym.cpp
3
4 Converts _unpacked_ YM tunes to a format better suitable for
5 MSX1. Supports YM2 and YM3 types well plus YM5 somehow.
6
7 30.1.2000 Marq/Lieves!Tuore & Fit (marq@iki.fi)
8
9 3.2.2000 - Added a rude YM5 loader. Skips most of the header.
10
11 Output format:
12
13 Rows in the tune, 16 bits (lobyte first)
14 For each register, 0 - fragment contains only unchanged data
15 1 - fragment contains packed data
16
17 In a packed fragment, 0 - register value is the same as before
18 11 - raw register data follows. Only regbits[i]
19 bits, not full 8
20 10 - offset + number of bytes from preceding
21 data. As many bits as are required to hold
22 fragment offset & counter data (OFFNUM).
23 */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "infos.h"
30 #include "common.h"
31
32 #define REGS 14
33 #define FRAG 128 // Number of rows to compress at a time
34 #define OFFNUM 14 // Bits needed to store off+num of FRAG
35
36
37
38 void writebits(unsigned data,int bits,FILE *f);
39
40 int main(int argc,char *argv[])
41 {
42 //
43 // Some initialization for the common library
44 //
45 SetApplicationParameters(
46 "Ym2Mym",
47 TOOL_VERSION_MAJOR,
48 TOOL_VERSION_MINOR,
49 "{ApplicationName} - Version {ApplicationVersion} - This program is a part of the OSDK\r\n"
50 "\r\n"
51 "Author:\r\n"
52 " First version by Marq/Lieves!Tuore & Fit (marq@iki.fi) \r\n"
53 " More recent updates by Pointier Mickael \r\n"
54 "\r\n"
55 "Purpose:\r\n"
56 " Convert Atari ST/Amstrad musics from the YM to MYM format.\r\n"
57 "\r\n"
58 "Usage:\r\n"
59 " {ApplicationName} source.ym destination.mym\r\n"
60 "\r\n"
61 "Switches:\r\n"
62 " -tn Tuning\r\n"
63 " -t0 => No retune\r\n"
64 " -t1 => Double frequency [default]\r\n"
65 "\r\n"
66 );
67
68 int retune_music=1;
69
70 ArgumentParser argumentParser(argc,argv);
71
72 while (argumentParser.ProcessNextArgument())
73 {
74 if (argumentParser.IsSwitch("-t"))
75 {
76 //format: [-t]
77 // 0 => No retune
78 // 1 => Double frequency [default]
79 retune_music=argumentParser.GetIntegerValue(0);
80 }
81 }
82
83 if (argumentParser.GetParameterCount()!=2)
84 {
85 ShowError(0);
86 }
87
88 unsigned char*data[REGS]; // The unpacked YM data
89
90 unsigned current[REGS];
91
92 char id[5]={0,0,0,0,0};
93 char ym_new=0;
94 char LeOnArD[8]; // Check string
95
96 FILE *f;
97
98 long n,i,row,change,pack,biggest=0,hits,oldrow,remain,offi;
99 long regbits[REGS]={8,4,8,4, 8,4,5,8, 5,5,5,8, 8,8}; // Bits per PSG reg
100 long regand[REGS]={255,15,255,15, 255,15,31,255, 31,31,31,255, 255,255}; // AND values to mask out extra bits from register data
101
102 unsigned long length; // Song length
103 unsigned long ldata; // Needed in the loader
104
105 if ((f=fopen(argumentParser.GetParameter(0),"rb"))==NULL)
106 {
107 ShowError("Can't open '%s'",argumentParser.GetParameter(0));
108 }
109
110 fseek(f,0,SEEK_END);
111 length=ftell(f)-4;
112 fseek(f,0,SEEK_SET);
113
114 fread(id,1,4,f);
115 if (!strcmp(id,"YM2!")) // YM2 is ok
116 {
117 // YM2!
118 // First four bytes is the ASCII identifier "YM2!".
119 }
120 else
121 if (!strcmp(id,"YM3!")) // YM3 is ok
122 {
123 // YM3!
124 // First four bytes is again the ASCII identifier "YM3!".
125 // ------------------------------------------------------
126 // Offset Size Name Value Contents
127 // ------------------------------------------------------
128 // 0 4 ID "YM3!" File type Identificator
129 // The next bytes are the data block of AY chip registers values.
130 //
131 // Registers are updates one time per VBL interrupt. If music length is N interrupts,
132 // then block consist first N bytes for register 0, further N bytes for register 1
133 // and so on. In total: N*14 bytes. The number of used VBL for music can be computed
134 // as follow: nvbl = (ymfile_size-4)/14;
135 //
136 // VBL1:
137 // store reg0,reg1,reg2,...,reg12,reg13 (14 regs)
138 // VBL2:
139 // store reg0,reg1,reg2,...,reg12,reg13 (14 regs)
140 // ..........
141 // VBLn:
142 // store reg0,reg1,reg2,...,reg12,reg13 (14 regs)
143 //
144 // If the current interrupt features no output to register 13 then the byte of the
145 // data block for this interrupt and for this register has the value 255 ($FF).
146 }
147 else
148 if (!strcmp(id,"YM3b")) // YM3b is ok
149 {
150 // YM3b!
151 //
152 // This format is nearly identical with YM3. It adds only the ability to use loops.
153 //
154 // First four bytes is the ASCII identifier "YM3b".
155 // The following bytes are the data block (see YM3 description).
156 // Last four bytes is a DWORD (32bits integers) data and contains the frame number
157 // at wich the loop restart. That's all.
158 fread(id,1,4,f); // Skip restart for YM3b
159 length-=4;
160 }
161 else
162 if (!strcmp(id,"YM4!")) // YM4 is not yet ok
163 {
164 // YM4!
165 // (note, should be similar to YM5, without extra infos)
166 printf("YM4! format is not yet supported.\n");
167 exit(EXIT_FAILURE);
168 }
169 else
170 if ( (!strcmp(id,"YM5!")) || (!strcmp(id,"YM6!")) ) // YM5 is ok but needs a different loader
171 {
172 // YM5!
173 // This is the actual and most common used format and consist consists of additional information:
174 // chip frequency, player frequency, title, author name, comment and specific Atari ST data (Digi-Drum and SID effects).
175
176 // YM6!
177 // This format is equivalent to YM5! but can use yet another special Atari effect.
178 ym_new=1;
179 }
180 else
181 {
182 printf("Unknown file format '%s'.\n",id);
183 exit(EXIT_FAILURE);
184 }
185
186 if (ym_new) // New YM5 format loader
187 {
188 fread(LeOnArD,1,8,f); // Skip checkstring
189 for (n=length=0;n<4;n++) // Number of VBL's
190 {
191 length<<=8;
192 length+=fgetc(f);
193 }
194 length*=REGS;
195
196 fread(&ldata,1,3,f); // Skip first 3 bytes of info
197 if (!(fgetc(f)&1))
198 {
199 printf("Only interleaved data supported.\n");
200 return(EXIT_FAILURE);
201 }
202
203 if (fgetc(f) || fgetc(f)) // Number of digidrums
204 {
205 printf("Digidrums not supported.\n");
206 return(EXIT_FAILURE);
207 }
208
209 fread(&ldata,1,4,f); /* Skip external freq */
210 fread(&ldata,1,2,f); /* Skip VBL freq */
211 fread(&ldata,1,4,f); /* Skip loop position */
212 fread(&ldata,1,2,f); /* Skip additional data */
213
214 while(fgetc(f)) /* Skip song name */
215 ;
216 while(fgetc(f)) /* Skip author name */
217 ;
218 while(fgetc(f)) /* Skip comments */
219 ;
220 }
221
222 /* Old YM2/YM3 format loader */
223 for (n=0;n<REGS;n++) /* Allocate memory & read data */
224 {
225 /* Allocate extra fragment to make packing easier */
226 if ((data[n]=(unsigned char*)malloc(length/REGS+FRAG))==NULL)
227 {
228 printf("Out of memory.\n");
229 return(EXIT_FAILURE);
230 }
231 memset(data[n],0,length/REGS+FRAG);
232 fread(data[n],1,length/REGS,f);
233 }
234
235 if (retune_music)
236 {
237 unsigned int frame;
238 printf("Retuning the frequency.\n");
239 for (frame=0;frame<=length/REGS;frame++)
240 {
241 int freqA= ( ((data[1][frame])<<8) | (data[0][frame]) )>>1;
242 int freqB= ( ((data[3][frame])<<8) | (data[2][frame]) )>>1;
243 int freqC= ( ((data[5][frame])<<8) | (data[4][frame]) )>>1;
244 int freqEnv= ( ((data[12][frame])<<8) | (data[11][frame]) )>>1;
245 int freqNoise= data[6][frame]>>1;
246
247 data[0][frame]=freqA & 255;
248 data[1][frame]=(freqA>>8);
249
250 data[2][frame]=freqB & 255;
251 data[3][frame]=(freqB>>8);
252
253 data[4][frame]=freqC & 255;
254 data[5][frame]=(freqC>>8);
255
256 data[6][frame]=freqNoise;
257
258 data[11][frame]=freqEnv & 255;
259 data[12][frame]=(freqEnv>>8);
260 }
261 }
262
263
264 if (ym_new) // Let's mask the extra YM5 data out
265 {
266 for (n=0;n<REGS;n++)
267 {
268 for (row=0;row<length/REGS;row++)
269 {
270 data[n][row]&=regand[n];
271 }
272 }
273 }
274
275 fclose(f);
276
277 if ((f=fopen(argumentParser.GetParameter(1),"wb"))==NULL)
278 {
279 printf("Cannot open destination file.\n");
280 return(EXIT_FAILURE);
281 }
282
283 // Set current values to impossible
284 for (n=0;n<REGS;n++)
285 {
286 current[n]=0xffff;
287 }
288
289 fputc(length/REGS&0xff,f); // Write tune length
290 fputc(length/REGS>>8,f);
291
292 for (n=0;n<length/REGS;n+=FRAG) // Go through fragments...
293 {
294 for (i=0;i<REGS;i++) // ... for each register
295 {
296 for (row=change=0;row<FRAG;row++)
297 if (data[i][n+row]!=current[i])
298 change=1;
299
300 if (!change) // No changes in the whole fragment
301 {
302 writebits(0,1,f);
303 continue; // Skip the next pass
304 }
305 else
306 {
307 writebits(1,1,f);
308 }
309
310 for (row=0;row<FRAG;row++)
311 {
312 if (data[i][n+row]!=current[i])
313 {
314 change=1;
315 current[i]=data[i][n+row];
316
317 biggest=0;
318 if (n) // Skip first fragment
319 {
320 offi=0;
321 remain=FRAG-row;
322
323 // Go through the preceding data and try to find similar data
324 for (oldrow=0;oldrow<FRAG;oldrow++)
325 {
326 hits=0;
327 for (pack=0;pack<remain;pack++)
328 {
329 if (data[i][n+row+pack]==data[i][n-FRAG+row+oldrow+pack]
330 && oldrow+pack<FRAG)
331 hits++;
332 else
333 break;
334 }
335 if (hits>biggest) // Bigger sequence found
336 {
337 biggest=hits;
338 offi=oldrow;
339 }
340 }
341 }
342
343 if (biggest>1) // Could we pack data?
344 {
345 row+=biggest-1;
346 current[i]=data[i][n+row];
347 writebits(2,2,f);
348 writebits((offi<<OFFNUM/2)+(biggest-1),OFFNUM,f);
349 }
350 else // Nope, write raw bits
351 {
352 writebits(3,2,f);
353 writebits(data[i][n+row],regbits[i],f);
354 }
355 }
356 else // Same as former value, write 0
357 {
358 writebits(0,1,f);
359 }
360 }
361 }
362 }
363
364 writebits(0,0,f); // Pad to byte size
365 fclose(f);
366 return(EXIT_SUCCESS);
367 }
368
369 // Writes bits to a file. If bits is 0, pads to byte size.
370 void writebits(unsigned data,int bits,FILE *f)
371 {
372 static unsigned char byte=0;
373
374 static int off=0;
375
376 int n;
377
378 if (!bits && off)
379 {
380 off=byte=0;
381 fputc(byte,f);
382 return;
383 }
384
385 // Go through the bits and write a whole byte if needed
386 for (n=0;n<bits;n++)
387 {
388 if (data&(1<<bits-1-n))
389 byte|=0x80>>off;
390
391 if (++off==8)
392 {
393 fputc(byte,f);
394 off=byte=0;
395 }
396 }
397 }
398

  ViewVC Help
Powered by ViewVC 1.1.26