Mercurial > hg > dmlib
annotate xm2jss.c @ 202:85614db5f577
Warn about invalid instruments.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sun, 07 Oct 2012 08:53:51 +0300 |
parents | 50f55def91e5 |
children | 245b15cd1919 |
rev | line source |
---|---|
0 | 1 /* |
2 * xm2jss - Convert XM module to JSSMOD | |
3 * Programmed and designed by Matti 'ccr' Hamalainen | |
4 * (C) Copyright 2006-2009 Tecnic Software productions (TNSP) | |
5 * | |
6 * Please read file 'COPYING' for information on license and distribution. | |
7 */ | |
8 #include <stdio.h> | |
9 #include <errno.h> | |
10 #include "jss.h" | |
11 #include "jssmod.h" | |
184
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
12 #include "jssplr.h" |
0 | 13 #include "dmlib.h" |
14 #include "dmargs.h" | |
15 #include "dmres.h" | |
16 | |
184
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
17 #define jmpNMODEffectTable (36) |
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
18 static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
19 |
0 | 20 |
21 char *srcFilename = NULL, *destFilename = NULL; | |
22 BOOL optIgnoreErrors = FALSE, | |
23 optStripExtInstr = FALSE, | |
24 optStripInstr = FALSE, | |
25 optStripSamples = FALSE, | |
26 optOptimize = FALSE; | |
27 | |
28 int optPatternMode = PATMODE_COMP_HORIZ, | |
29 optSampMode16 = jsampDelta, | |
30 optSampMode8 = jsampFlipSign | jsampDelta; | |
31 | |
32 #define SAMPMODE_MASK (jsampFlipSign | jsampSwapEndianess | jsampSplit | jsampDelta) | |
33 | |
34 | |
35 static const char* patModeTable[PATMODE_LAST] = | |
36 { | |
37 "Raw horizontal", | |
38 "Compressed horizontal (similar to XM modules)", | |
39 "Raw vertical", | |
40 "Compressed vertical", | |
41 "Raw vertical for each element", | |
42 }; | |
43 | |
44 | |
45 DMOptArg optList[] = { | |
46 { 0, '?', "help", "Show this help", OPT_NONE }, | |
47 { 5, 'v', "verbose", "Be more verbose", OPT_NONE }, | |
48 { 6, 'o', "output", "Output file", OPT_ARGREQ }, | |
49 { 1, 'i', "ignore", "Ignore errors", OPT_NONE }, | |
50 { 2, 'p', "patterns", "Pattern storage mode", OPT_ARGREQ }, | |
51 { 3, 'E', "strip-ext-instr","Strip ext. instruments (implies -I -S)", OPT_NONE }, | |
52 { 9, 'I', "strip-instr", "Strip instruments (implies -S)", OPT_NONE }, | |
53 { 4, 'S', "strip-samples", "Strip instr. sampledata", OPT_NONE }, | |
54 { 7, '8', "smode8", "8-bit sample conversion flags", OPT_ARGREQ }, | |
55 { 8, '1', "smode16", "16-bit sample conversion flags", OPT_ARGREQ }, | |
56 {10, 'O', "optimize", "Optimize module", OPT_NONE }, | |
57 }; | |
58 | |
59 const int optListN = sizeof(optList) / sizeof(optList[0]); | |
60 | |
61 | |
62 void argShowHelp() | |
63 { | |
64 int i; | |
65 | |
66 dmPrintBanner(stdout, dmProgName, "[options] <module.xm>"); | |
67 dmArgsPrintHelp(stdout, optList, optListN); | |
68 | |
69 printf("\n" | |
70 "Pattern storage modes:\n"); | |
71 | |
72 for (i = 1; i < PATMODE_LAST; i++) | |
73 printf(" %d = %s\n", i, patModeTable[i-1]); | |
74 | |
75 printf( | |
76 "\n" | |
77 "Sample data conversion flags (summative):\n" | |
78 " 1 = Delta encoding (DEF 8 & 16)\n" | |
79 " 2 = Flip signedness (DEF 8)\n" | |
80 " 4 = Swap endianess (affects 16-bit only)\n" | |
81 " 8 = Split and de-interleave hi/lo bytes (affects 16-bit only)\n" | |
82 "\n" | |
83 ); | |
84 } | |
85 | |
86 BOOL argHandleOpt(const int optN, char *optArg, char *currArg) | |
87 { | |
88 (void) optArg; | |
89 | |
90 switch (optN) | |
91 { | |
92 case 0: | |
93 argShowHelp(); | |
94 exit(0); | |
95 break; | |
96 | |
97 case 1: | |
98 optIgnoreErrors = TRUE; | |
99 break; | |
100 | |
101 case 2: | |
102 optPatternMode = atoi(optArg); | |
103 if (optPatternMode <= 0 || optPatternMode >= PATMODE_LAST) | |
104 { | |
105 dmError("Unknown pattern conversion mode %d\n", optPatternMode); | |
106 return FALSE; | |
107 } | |
108 break; | |
109 | |
110 case 7: optSampMode8 = atoi(optArg) & SAMPMODE_MASK; break; | |
111 case 8: optSampMode16 = atoi(optArg) & SAMPMODE_MASK; break; | |
112 | |
113 case 4: optStripSamples = TRUE; break; | |
114 case 3: optStripExtInstr = TRUE; break; | |
115 case 9: optStripInstr = TRUE; break; | |
116 case 10: optOptimize = TRUE; break; | |
117 | |
118 case 5: | |
119 dmVerbosity++; | |
120 break; | |
121 | |
122 case 6: | |
123 destFilename = optArg; | |
124 break; | |
125 | |
126 default: | |
127 dmError("Unknown argument '%s'.\n", currArg); | |
128 return FALSE; | |
129 } | |
130 | |
131 return TRUE; | |
132 } | |
133 | |
134 | |
135 BOOL argHandleFile(char *currArg) | |
136 { | |
137 // Was not option argument | |
138 if (!srcFilename) | |
139 srcFilename = currArg; | |
140 else | |
141 { | |
142 dmError("Gay error '%s'.\n", currArg); | |
143 return FALSE; | |
144 } | |
145 | |
146 return TRUE; | |
147 } | |
148 | |
149 | |
150 /* These functions and the macro mess are meant to make the | |
151 * conversion routines themselves clearer and simpler. | |
152 */ | |
153 BOOL jsPutByte(Uint8 *patBuf, size_t patBufSize, size_t *npatBuf, Uint8 val) | |
154 { | |
155 if (*npatBuf >= patBufSize) | |
156 return FALSE; | |
157 else | |
158 { | |
159 patBuf[*npatBuf] = val; | |
160 (*npatBuf)++; | |
161 return TRUE; | |
162 } | |
163 } | |
164 | |
165 #define JSPUTBYTE(x) do { if (!jsPutByte(patBuf, patBufSize, patSize, x)) return DMERR_BOUNDS; } while (0) | |
166 | |
167 #define JSCOMP(x,z) do { if ((x) != jsetNotSet) { qflags |= (z); qcomp++; } } while (0) | |
168 | |
169 #define JSCOMPPUT(xf,xv,qv) do { \ | |
170 if (qflags & (xf)) { \ | |
171 if ((xv) < 0 || (xv) > 255) \ | |
172 JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, \ | |
173 "%s value out of bounds %d.\n", qv, (xv)); \ | |
174 JSPUTBYTE(xv); \ | |
175 } \ | |
176 } while (0) | |
177 | |
178 #define JSCONVPUT(xv,qv) do { \ | |
179 if ((xv) != jsetNotSet) { \ | |
180 if ((xv) < 0 || (xv) > 254) \ | |
181 JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, \ | |
182 "%s value out of bounds %d.\n", qv, (xv)); \ | |
183 JSPUTBYTE((xv) + 1); \ | |
184 } else { \ | |
185 JSPUTBYTE(0); \ | |
186 } \ | |
187 } while (0) | |
188 | |
189 | |
190 /* Convert a note | |
191 */ | |
192 static int jssConvertNote(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSNote *note) | |
193 { | |
194 Uint8 tmp; | |
195 if (note->note == jsetNotSet) | |
196 tmp = 0; | |
197 else if (note->note == jsetNoteOff) | |
198 tmp = 127; | |
199 else | |
200 tmp = note->note + 1; | |
201 | |
202 if (tmp > 0x7f) | |
203 JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, "Note value out of bounds %d > 0x7f.\n", tmp); | |
204 | |
205 JSPUTBYTE(tmp & 0x7f); | |
206 | |
207 JSCONVPUT(note->instrument, "Instrument"); | |
208 JSCONVPUT(note->volume, "Volume"); | |
209 JSCONVPUT(note->effect, "Effect"); | |
210 | |
211 tmp = (note->param != jsetNotSet) ? note->param : 0; | |
212 JSPUTBYTE(tmp); | |
213 | |
214 return DMERR_OK; | |
215 } | |
216 | |
217 | |
218 /* Compress a note | |
219 */ | |
220 static int jssCompressNote(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSNote *note) | |
221 { | |
222 Uint8 qflags = 0; | |
223 int qcomp = 0; | |
224 | |
225 JSCOMP(note->note, COMP_NOTE); | |
226 JSCOMP(note->instrument, COMP_INSTRUMENT); | |
227 JSCOMP(note->volume, COMP_VOLUME); | |
228 JSCOMP(note->effect, COMP_EFFECT); | |
229 if (note->param != jsetNotSet && note->param != 0) | |
230 { | |
231 qflags |= COMP_PARAM; | |
232 qcomp++; | |
233 } | |
234 | |
235 if (qcomp < 4) | |
236 { | |
237 JSPUTBYTE(qflags | 0x80); | |
238 | |
239 if (note->note != jsetNotSet) | |
240 { | |
241 Uint8 tmp = (note->note != jsetNoteOff) ? note->note : 127; | |
242 if (tmp > 0x7f) | |
243 JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, "Note value out of bounds %d > 0x7f.\n", tmp); | |
244 JSPUTBYTE(tmp); | |
245 } | |
246 | |
247 JSCOMPPUT(COMP_INSTRUMENT, note->instrument, "Instrument"); | |
248 JSCOMPPUT(COMP_VOLUME, note->volume, "Volume"); | |
249 JSCOMPPUT(COMP_EFFECT, note->effect, "Effect"); | |
250 JSCOMPPUT(COMP_PARAM, note->param, "Param"); | |
251 } else | |
252 return jssConvertNote(patBuf, patBufSize, patSize, note); | |
253 | |
254 return DMERR_OK; | |
255 } | |
256 | |
257 | |
258 /* Compress pattern | |
259 */ | |
260 static int jssConvertPatternCompHoriz(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) | |
261 { | |
262 int row, channel; | |
263 *patSize = 0; | |
264 | |
265 for (row = 0; row < pattern->nrows; row++) | |
266 for (channel = 0; channel < pattern->nchannels; channel++) | |
267 { | |
268 const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; | |
269 const int res = jssCompressNote(patBuf, patBufSize, patSize, note); | |
270 if (res != DMERR_OK) | |
271 { | |
272 JSSERROR(res, res, "Note compression failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", | |
273 patBuf, patBufSize, *patSize, row, channel); | |
274 return res; | |
275 } | |
276 } | |
277 | |
278 return DMERR_OK; | |
279 } | |
280 | |
281 | |
282 static int jssConvertPatternCompVert(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) | |
283 { | |
284 int row, channel; | |
285 *patSize = 0; | |
286 | |
287 for (channel = 0; channel < pattern->nchannels; channel++) | |
288 for (row = 0; row < pattern->nrows; row++) | |
289 { | |
290 const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; | |
291 const int res = jssCompressNote(patBuf, patBufSize, patSize, note); | |
292 if (res != DMERR_OK) | |
293 { | |
294 JSSERROR(res, res, "Note compression failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", | |
295 patBuf, patBufSize, *patSize, row, channel); | |
296 return res; | |
297 } | |
298 } | |
299 | |
300 return DMERR_OK; | |
301 } | |
302 | |
303 | |
304 /* Convert a pattern | |
305 */ | |
306 static int jssConvertPatternRawHoriz(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) | |
307 { | |
308 int row, channel; | |
309 *patSize = 0; | |
310 | |
311 for (row = 0; row < pattern->nrows; row++) | |
312 for (channel = 0; channel < pattern->nchannels; channel++) | |
313 { | |
314 const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; | |
315 const int res = jssConvertNote(patBuf, patBufSize, patSize, note); | |
316 if (res != DMERR_OK) | |
317 { | |
318 JSSERROR(res, res, "Note conversion failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", | |
319 patBuf, patBufSize, *patSize, row, channel); | |
320 return res; | |
321 } | |
322 } | |
323 | |
324 return DMERR_OK; | |
325 } | |
326 | |
327 | |
328 static int jssConvertPatternRawVert(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) | |
329 { | |
330 int row, channel; | |
331 *patSize = 0; | |
332 | |
333 for (channel = 0; channel < pattern->nchannels; channel++) | |
334 for (row = 0; row < pattern->nrows; row++) | |
335 { | |
336 const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; | |
337 const int res = jssConvertNote(patBuf, patBufSize, patSize, note); | |
338 if (res != DMERR_OK) | |
339 { | |
340 JSSERROR(res, res, "Note conversion failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", | |
341 patBuf, patBufSize, *patSize, row, channel); | |
342 return res; | |
343 } | |
344 } | |
345 | |
346 return DMERR_OK; | |
347 } | |
348 | |
349 | |
350 #define JSFOREACHNOTE1 \ | |
351 for (channel = 0; channel < pattern->nchannels; channel++) \ | |
352 for (row = 0; row < pattern->nrows; row++) { \ | |
353 const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; | |
354 | |
355 #define JSFOREACHNOTE2 } | |
356 | |
357 static int jssConvertPatternRawElem(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) | |
358 { | |
359 Uint8 tmp; | |
360 int row, channel; | |
361 *patSize = 0; | |
362 | |
363 JSFOREACHNOTE1; | |
364 if (note->note == jsetNotSet) | |
365 tmp = 0; | |
366 else if (note->note == jsetNoteOff) | |
367 tmp = 127; | |
368 else | |
369 tmp = note->note + 1; | |
370 if (tmp > 0x7f) | |
371 JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, "Note value out of bounds %d > 0x7f.\n", tmp); | |
372 JSPUTBYTE(tmp); | |
373 JSFOREACHNOTE2; | |
374 | |
375 JSFOREACHNOTE1; | |
376 JSCONVPUT(note->instrument, "Instrument"); | |
377 JSFOREACHNOTE2; | |
378 | |
379 JSFOREACHNOTE1; | |
380 JSCONVPUT(note->volume, "Volume"); | |
381 JSFOREACHNOTE2; | |
382 | |
383 JSFOREACHNOTE1; | |
384 JSCONVPUT(note->effect, "Effect"); | |
385 JSFOREACHNOTE2; | |
386 | |
387 JSFOREACHNOTE1; | |
388 JSCONVPUT(note->param, "Param"); | |
389 JSFOREACHNOTE2; | |
390 | |
391 return DMERR_OK; | |
392 } | |
393 | |
394 #undef JSFOREACHNOTE1 | |
395 #undef JSFOREACHNOTE2 | |
396 | |
397 | |
398 static void jssCopyEnvelope(JSSMODEnvelope *je, JSSEnvelope *e) | |
399 { | |
400 int i; | |
401 | |
402 je->flags = e->flags; | |
403 je->npoints = e->npoints; | |
404 je->sustain = e->sustain; | |
405 je->loopS = e->loopS; | |
406 je->loopE = e->loopE; | |
407 | |
408 for (i = 0; i < e->npoints; i++) | |
409 { | |
410 je->points[i].frame = e->points[i].frame; | |
411 je->points[i].value = e->points[i].value; | |
412 } | |
413 } | |
414 | |
415 | |
416 /* Save a JSSMOD file | |
417 */ | |
418 int jssSaveJSSMOD(FILE *outFile, JSSModule *m, int patMode, int flags8, int flags16) | |
419 { | |
420 JSSMODHeader jssH; | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
421 int i, pattern, order, instr, totalSize; |
0 | 422 const size_t patBufSize = 64*1024; // 64kB pattern buffer |
423 Uint8 *patBuf; | |
424 | |
425 // Check the module | |
426 if (m == NULL) | |
427 JSSERROR(DMERR_NULLPTR, DMERR_NULLPTR, "Module pointer was NULL\n"); | |
428 | |
429 if ((m->nchannels < 1) || (m->npatterns < 1) || (m->norders < 1)) | |
430 JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, | |
431 "Module had invalid values (nchannels=%i, npatterns=%i, norders=%i)\n", | |
432 m->nchannels, m->npatterns, m->norders); | |
433 | |
434 // Create the JSSMOD header | |
435 jssH.idMagic[0] = 'J'; | |
436 jssH.idMagic[1] = 'M'; | |
437 jssH.idVersion = JSSMOD_VERSION; | |
438 jssH.norders = m->norders; | |
439 jssH.npatterns = m->npatterns; | |
440 jssH.nchannels = m->nchannels; | |
441 jssH.nextInstruments = m->nextInstruments; | |
442 jssH.ninstruments = m->ninstruments; | |
443 jssH.defFlags = m->defFlags; | |
444 jssH.intVersion = m->intVersion; | |
445 jssH.defRestartPos = m->defRestartPos; | |
446 jssH.defSpeed = m->defSpeed; | |
447 jssH.defTempo = m->defTempo; | |
448 jssH.patMode = patMode; | |
449 | |
450 // Write header | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
451 totalSize = sizeof(jssH); |
0 | 452 if (fwrite(&jssH, sizeof(jssH), 1, outFile) != 1) |
453 JSSERROR(DMERR_FWRITE, DMERR_FWRITE, "Could not write JSSMOD header!\n"); | |
454 | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
455 dmMsg(1," * JSSMOD-header 0x%04x, %d bytes.\n", JSSMOD_VERSION, totalSize); |
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
456 |
0 | 457 // Write orders list |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
458 for (totalSize = order = 0; order < m->norders; order++) |
0 | 459 { |
460 Uint16 tmp = m->orderList[order]; | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
461 totalSize += sizeof(tmp); |
0 | 462 if (fwrite(&tmp, sizeof(tmp), 1, outFile) != 1) |
463 JSSERROR(DMERR_FWRITE, DMERR_FWRITE, "Could not write JSSMOD orders list.\n"); | |
464 } | |
465 | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
466 dmMsg(1," * %d item orders list, %d bytes.\n", |
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
467 m->norders, totalSize); |
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
468 |
0 | 469 // Allocate pattern compression buffer |
470 if ((patBuf = dmMalloc(patBufSize)) == NULL) | |
471 JSSERROR(DMERR_MALLOC, DMERR_MALLOC, | |
472 "Error allocating memory for pattern compression buffer.\n"); | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
473 |
0 | 474 |
475 // Write patterns | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
476 for (totalSize = pattern = 0; pattern < m->npatterns; pattern++) |
0 | 477 { |
478 JSSMODPattern patHead; | |
479 size_t finalSize = 0; | |
480 | |
481 switch (patMode) | |
482 { | |
483 case PATMODE_RAW_HORIZ: | |
484 i = jssConvertPatternRawHoriz(patBuf, patBufSize, &finalSize, m->patterns[pattern]); | |
485 break; | |
486 case PATMODE_COMP_HORIZ: | |
487 i = jssConvertPatternCompHoriz(patBuf, patBufSize, &finalSize, m->patterns[pattern]); | |
488 break; | |
489 case PATMODE_RAW_VERT: | |
490 i = jssConvertPatternRawVert(patBuf, patBufSize, &finalSize, m->patterns[pattern]); | |
491 break; | |
492 case PATMODE_COMP_VERT: | |
493 i = jssConvertPatternCompVert(patBuf, patBufSize, &finalSize, m->patterns[pattern]); | |
494 break; | |
495 case PATMODE_RAW_ELEM: | |
496 i = jssConvertPatternRawElem(patBuf, patBufSize, &finalSize, m->patterns[pattern]); | |
497 break; | |
498 default: | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
499 i = DMERR_INVALID_DATA; |
0 | 500 dmFree(patBuf); |
501 JSSERROR(DMERR_INVALID_DATA, DMERR_INVALID_DATA, | |
502 "Unsupported pattern conversion mode %d.\n", patMode); | |
503 break; | |
504 } | |
505 | |
506 if (i != DMERR_OK) | |
507 { | |
508 dmFree(patBuf); | |
509 JSSERROR(i, i, "Error converting pattern data #%i\n", pattern); | |
510 } | |
511 else | |
512 { | |
513 dmMsg(3, " - Pattern %d size %d bytes\n", pattern, finalSize); | |
514 patHead.nrows = m->patterns[pattern]->nrows; | |
515 patHead.size = finalSize; | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
516 totalSize += finalSize + sizeof(patHead); |
0 | 517 |
518 if (fwrite(&patHead, sizeof(patHead), 1, outFile) != 1) | |
519 { | |
520 dmFree(patBuf); | |
521 JSSERROR(DMERR_FWRITE, DMERR_FWRITE, | |
522 "Error writing pattern #%d header\n", pattern); | |
523 } | |
524 | |
525 if (fwrite(patBuf, sizeof(Uint8), finalSize, outFile) != finalSize) | |
526 { | |
527 dmFree(patBuf); | |
528 JSSERROR(DMERR_FWRITE, DMERR_FWRITE, | |
529 "Error writing pattern #%d data\n", pattern); | |
530 } | |
531 } | |
532 } | |
533 dmFree(patBuf); | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
534 dmMsg(1," * %d patterns, %d bytes.\n", m->npatterns, totalSize); |
0 | 535 |
536 // Write extended instruments | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
537 for (totalSize = instr = 0; instr < m->nextInstruments; instr++) |
0 | 538 { |
539 JSSMODExtInstrument jssE; | |
540 JSSExtInstrument *einst = m->extInstruments[instr]; | |
541 | |
542 memset(&jssE, 0, sizeof(jssE)); | |
543 | |
544 if (einst) | |
545 { | |
546 // Create header | |
547 jssE.nsamples = einst->nsamples; | |
548 for (i = 0; i < jsetNNotes; i++) | |
549 { | |
550 int snum = einst->sNumForNotes[i]; | |
551 jssE.sNumForNotes[i] = (snum != jsetNotSet) ? snum : 0; | |
552 } | |
553 | |
554 jssCopyEnvelope(&jssE.volumeEnv, &(einst->volumeEnv)); | |
555 jssCopyEnvelope(&jssE.panningEnv, &(einst->panningEnv)); | |
556 jssE.vibratoType = einst->vibratoType; | |
557 jssE.vibratoSweep = einst->vibratoSweep; | |
558 jssE.vibratoDepth = einst->vibratoDepth; | |
559 jssE.fadeOut = einst->fadeOut; | |
560 } else | |
561 JSSWARNING(DMERR_NULLPTR, DMERR_NULLPTR, "Extended instrument #%i NULL!\n", instr); | |
562 | |
563 // Write to file | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
564 totalSize += sizeof(jssE); |
0 | 565 if (fwrite(&jssE, sizeof(jssE), 1, outFile) != 1) |
566 JSSERROR(DMERR_FWRITE, DMERR_FWRITE, | |
567 "Could not write JSSMOD extended instrument #%i to file!\n", instr); | |
568 } | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
569 dmMsg(1," * %d Extended Instruments, %d bytes.\n", m->nextInstruments, totalSize); |
0 | 570 |
571 | |
572 // Write sample instrument headers | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
573 for (totalSize = instr = 0; instr < m->ninstruments; instr++) |
0 | 574 { |
575 JSSMODInstrument jssI; | |
576 JSSInstrument *pInst = m->instruments[instr]; | |
577 | |
578 memset(&jssI, 0, sizeof(jssI)); | |
579 | |
580 // Create header | |
581 if (pInst) | |
582 { | |
583 jssI.size = pInst->size; | |
584 jssI.loopS = pInst->loopS; | |
585 jssI.loopE = pInst->loopE; | |
586 jssI.volume = pInst->volume; | |
587 jssI.flags = pInst->flags; | |
588 jssI.C4BaseSpeed = pInst->C4BaseSpeed; | |
589 jssI.ERelNote = pInst->ERelNote; | |
590 jssI.EFineTune = pInst->EFineTune; | |
591 jssI.EPanning = pInst->EPanning; | |
592 jssI.hasData = (pInst->data != NULL) ? TRUE : FALSE; | |
593 jssI.convFlags = (pInst->flags & jsf16bit) ? flags16 : flags8; | |
594 } | |
595 else | |
596 JSSWARNING(DMERR_NULLPTR, DMERR_NULLPTR, "Instrument #%i NULL!\n", instr); | |
597 | |
598 // Write to file | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
599 totalSize += sizeof(jssI); |
0 | 600 if (fwrite(&jssI, sizeof(jssI), 1, outFile) != 1) |
601 JSSERROR(DMERR_FWRITE, DMERR_FWRITE, | |
602 "Could not write JSSMOD instrument #%i to file!\n", instr); | |
603 } | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
604 dmMsg(1," * %d Instrument headers, %d bytes.\n", m->ninstruments, totalSize); |
0 | 605 |
606 // Write sample data | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
607 for (totalSize = instr = 0; instr < m->ninstruments; instr++) |
0 | 608 if (m->instruments[instr]) |
609 { | |
610 JSSInstrument *inst = m->instruments[instr]; | |
611 if (inst->data != NULL) | |
612 { | |
613 size_t res; | |
614 if (inst->flags & jsf16bit) | |
615 { | |
616 jssEncodeSample16(inst->data, inst->size, flags16); | |
617 res = fwrite(inst->data, sizeof(Uint16), inst->size, outFile); | |
618 } | |
619 else | |
620 { | |
621 jssEncodeSample8(inst->data, inst->size, flags8); | |
622 res = fwrite(inst->data, sizeof(Uint8), inst->size, outFile); | |
623 } | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
624 |
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
625 totalSize += inst->size; |
86 | 626 if (res != (size_t) inst->size) |
0 | 627 JSSERROR(DMERR_FWRITE, DMERR_FWRITE, |
628 "Could not write JSSMOD sample #%i to file!\n", instr); | |
629 } | |
630 } | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
631 dmMsg(1," * %d samples, %d bytes.\n", m->ninstruments, totalSize); |
0 | 632 |
633 return DMERR_OK; | |
634 } | |
635 | |
636 | |
637 /* Optimize a given module | |
638 */ | |
639 JSSModule *optimizeModule(JSSModule *m) | |
640 { | |
641 BOOL usedPatterns[jsetMaxPatterns + 1], | |
642 usedInstruments[jsetMaxInstruments + 1], | |
643 usedExtInstruments[jsetMaxInstruments + 1]; | |
644 int mapExtInstruments[jsetMaxInstruments + 1], | |
645 mapInstruments[jsetMaxInstruments + 1], | |
646 mapPatterns[jsetMaxPatterns + 1]; | |
647 JSSModule *r = NULL; | |
648 int i, n8, n16; | |
649 | |
650 // Allocate a new module | |
651 if ((r = jssAllocateModule()) == NULL) | |
652 return NULL; | |
653 | |
654 // Allocate tables | |
655 | |
656 // Copy things | |
657 r->moduleType = m->moduleType; | |
658 r->moduleName = dm_strdup(m->moduleName); | |
659 r->trackerName = dm_strdup(m->trackerName); | |
660 r->defSpeed = m->defSpeed; | |
661 r->defTempo = m->defTempo; | |
662 r->defFlags = m->defFlags; | |
663 r->defRestartPos = m->defRestartPos; | |
664 r->intVersion = m->intVersion; | |
665 r->nchannels = m->nchannels; | |
666 r->norders = m->norders; | |
667 for (i = 0; i < jsetNChannels; i++) | |
668 r->defPanning[i] = m->defPanning[i]; | |
669 | |
670 // Initialize values | |
671 for (i = 0; i <= jsetMaxInstruments; i++) | |
672 { | |
673 usedExtInstruments[i] = FALSE; | |
674 usedInstruments[i] = FALSE; | |
675 mapExtInstruments[i] = jsetNotSet; | |
676 mapInstruments[i] = jsetNotSet; | |
677 } | |
678 | |
679 for (i = 0; i <= jsetMaxPatterns; i++) | |
680 { | |
681 usedPatterns[i] = FALSE; | |
682 mapPatterns[i] = jsetNotSet; | |
683 } | |
684 | |
685 // Find out all used patterns and ext.instruments | |
686 for (i = 0; i < m->norders; i++) | |
687 { | |
688 int pattern = m->orderList[i]; | |
689 if (pattern >= 0 && pattern < m->npatterns) | |
690 { | |
691 JSSPattern *p = m->patterns[pattern]; | |
692 if (p != NULL) | |
693 { | |
694 int row, channel; | |
695 JSSNote *n = p->data; | |
696 | |
697 // Mark pattern as used | |
698 usedPatterns[pattern] = TRUE; | |
699 | |
700 // Check all notes | |
701 for (row = 0; row < p->nrows; row++) | |
702 for (channel = 0; channel < p->nchannels; channel++, n++) | |
703 { | |
704 if (n->instrument != jsetNotSet) | |
705 { | |
706 if (n->instrument >= 0 && n->instrument < m->nextInstruments) | |
707 usedExtInstruments[n->instrument] = TRUE; | |
708 else | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
709 dmMsg(2, "Pattern 0x%x, row=0x%x, chn=%d has invalid instrument 0x%x\n", |
0 | 710 pattern, row, channel, n->instrument); |
711 } | |
712 } | |
713 } | |
714 else | |
715 { | |
716 dmError("Pattern 0x%x is used on order 0x%x, but has no data!\n", | |
717 pattern, i); | |
718 } | |
719 } | |
720 else | |
721 if (pattern != jsetMaxPatterns) | |
722 { | |
723 dmError("Order 0x%x has invalid pattern number 0x%x!\n", | |
724 i, pattern); | |
725 } | |
726 } | |
727 | |
728 // Find out used instruments | |
729 for (i = 0; i <= jsetMaxInstruments; i++) | |
730 if (usedExtInstruments[i] && m->extInstruments[i] != NULL) | |
731 { | |
732 int note; | |
733 JSSExtInstrument *e = m->extInstruments[i]; | |
734 | |
735 for (note = 0; note < jsetNNotes; note++) | |
736 if (e->sNumForNotes[note] != jsetNotSet) | |
737 { | |
738 int q = e->sNumForNotes[note]; | |
739 if (q >= 0 && q < m->ninstruments) | |
740 { | |
741 usedInstruments[q] = TRUE; | |
742 } | |
743 else | |
744 { | |
745 dmError("Ext.instrument #%d sNumForNotes[%d] value out range (%d < %d).\n", | |
746 i, m->ninstruments, q); | |
747 } | |
748 } | |
749 } | |
750 | |
751 // Create pattern mappings | |
752 r->npatterns = 0; | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
753 dmMsg(1, "Unused patterns: "); |
0 | 754 |
755 for (i = 0; i <= jsetMaxPatterns; i++) | |
756 if (m->patterns[i] != NULL) | |
757 { | |
758 if (!usedPatterns[i]) | |
759 { | |
760 dmPrint(2, "0x%x, ", i); | |
761 } | |
762 else | |
763 { | |
764 if (i >= m->npatterns) | |
765 dmError("Pattern 0x%x >= 0x%x, but used!\n", i, m->npatterns); | |
766 | |
767 mapPatterns[i] = r->npatterns; | |
768 r->patterns[r->npatterns] = m->patterns[i]; | |
769 (r->npatterns)++; | |
770 } | |
771 } | |
772 dmPrint(2, "\n"); | |
773 | |
774 dmMsg(1, "%d used patterns, %d unused.\n", | |
775 r->npatterns, m->npatterns - r->npatterns); | |
776 | |
777 | |
778 // Re-map instruments | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
779 dmMsg(1, "Unused instruments: "); |
0 | 780 for (n8 = n16 = i = 0; i <= jsetMaxInstruments; i++) |
781 if (m->instruments[i] != NULL) | |
782 { | |
783 if (!usedInstruments[i]) | |
784 { | |
785 dmPrint(2, "0x%x, ", i); | |
786 } | |
787 else | |
788 { | |
789 JSSInstrument *ip = m->instruments[i]; | |
790 if (i >= m->ninstruments) | |
791 dmError("Instrument 0x%x >= 0x%x, but used!\n", i, m->ninstruments); | |
792 | |
793 mapInstruments[i] = r->ninstruments; | |
794 r->instruments[r->ninstruments] = ip; | |
795 (r->ninstruments)++; | |
796 | |
797 if (ip->flags & jsf16bit) | |
798 n16++; | |
799 else | |
800 n8++; | |
801 } | |
802 } | |
803 dmPrint(2, "\n"); | |
804 dmMsg(1, "Total of (%d) 16-bit, (%d) 8-bit samples, (%d) instruments.\n", | |
805 n16, n8, r->ninstruments); | |
806 | |
807 // Re-map ext.instruments | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
808 dmMsg(1, "Unused ext.instruments: "); |
0 | 809 for (i = 0; i < jsetMaxInstruments; i++) |
810 if (usedExtInstruments[i]) | |
811 { | |
812 if (i >= m->nextInstruments) | |
813 { | |
814 dmError("Ext.instrument 0x%x >= 0x%x, but used!\n", | |
815 i, m->nextInstruments); | |
816 } | |
817 else | |
818 if (m->extInstruments[i] != NULL) | |
819 { | |
820 JSSExtInstrument *e = m->extInstruments[i]; | |
821 int note; | |
822 | |
823 mapExtInstruments[i] = r->nextInstruments; | |
824 r->extInstruments[r->nextInstruments] = e; | |
825 (r->nextInstruments)++; | |
826 | |
827 // Re-map sNumForNotes | |
828 for (note = 0; note < jsetNNotes; note++) | |
829 { | |
830 int q = e->sNumForNotes[note]; | |
831 if (q != jsetNotSet) | |
832 { | |
833 int map; | |
834 if (q >= 0 && q <= jsetMaxInstruments) | |
835 { | |
836 map = mapInstruments[q]; | |
837 } | |
838 else | |
839 { | |
840 map = jsetNotSet; | |
841 dmError("e=%d, note=%d, q=%d/%d\n", i, note, q, r->ninstruments); | |
842 } | |
843 e->sNumForNotes[note] = map; | |
844 } | |
845 } | |
846 } | |
847 else | |
848 { | |
849 dmPrint(2, "[0x%x==NULL], ", i); | |
850 mapExtInstruments[i] = jsetNotSet; | |
851 } | |
852 } | |
853 else | |
854 { | |
855 if (i < m->nextInstruments && m->extInstruments[i] != NULL) | |
856 { | |
857 dmPrint(2, "0x%x, ", i); | |
858 } | |
859 } | |
860 dmPrint(2, "\n"); | |
861 dmMsg(1, "%d extended instruments.\n", r->nextInstruments); | |
862 | |
863 | |
864 // Remap pattern instrument data | |
865 for (i = 0; i < r->npatterns; i++) | |
866 { | |
867 int row, channel; | |
868 JSSPattern *p = r->patterns[i]; | |
869 JSSNote *n = p->data; | |
870 | |
871 for (row = 0; row < p->nrows; row++) | |
872 for (channel = 0; channel < p->nchannels; channel++, n++) | |
873 { | |
184
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
874 char effect; |
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
875 |
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
876 if (n->instrument >= 0 && n->instrument <= jsetMaxInstruments) |
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
877 n->instrument = mapExtInstruments[n->instrument]; |
202
85614db5f577
Warn about invalid instruments.
Matti Hamalainen <ccr@tnsp.org>
parents:
184
diff
changeset
|
878 |
85614db5f577
Warn about invalid instruments.
Matti Hamalainen <ccr@tnsp.org>
parents:
184
diff
changeset
|
879 if (n->instrument != jsetNotSet && r->extInstruments[n->instrument] == NULL) |
85614db5f577
Warn about invalid instruments.
Matti Hamalainen <ccr@tnsp.org>
parents:
184
diff
changeset
|
880 dmError("Non-existing instrument used #%d.\n", n->instrument); |
184
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
881 |
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
882 JMPGETEFFECT(effect, n->effect); |
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
883 |
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
884 switch (effect) |
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
885 { |
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
886 case 'C': // Cxx = Set volume |
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
887 if (n->volume == jsetNotSet) |
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
888 { |
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
889 n->volume = n->param; |
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
890 n->effect = jsetNotSet; |
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
891 n->param = jsetNotSet; |
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
892 } |
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
893 break; |
50f55def91e5
Add a minor optimization in the conversion.
Matti Hamalainen <ccr@tnsp.org>
parents:
86
diff
changeset
|
894 } |
0 | 895 } |
896 } | |
897 | |
898 // Remap orders list | |
899 for (i = 0; i < m->norders; i++) | |
900 { | |
901 r->orderList[i] = mapPatterns[m->orderList[i]]; | |
902 } | |
903 | |
904 return r; | |
905 } | |
906 | |
907 | |
908 int main(int argc, char *argv[]) | |
909 { | |
910 DMResource *sfile = NULL; | |
911 FILE *dfile = NULL; | |
912 JSSModule *sm, *dm; | |
913 int result; | |
914 | |
915 dmInitProg("xm2jss", "XM to JSSMOD converter", "0.6", NULL, NULL); | |
916 dmVerbosity = 0; | |
917 | |
918 // Parse arguments | |
919 if (!dmArgsProcess(argc, argv, optList, optListN, | |
920 argHandleOpt, argHandleFile, TRUE)) | |
921 exit(1); | |
922 | |
923 | |
924 // Read the source file | |
925 if (srcFilename == NULL) | |
926 sfile = dmf_create_stdio_stream(stdin); | |
927 else | |
84
35db15881923
Oops, another fix for dmf_create_stdio() changes.
Matti Hamalainen <ccr@tnsp.org>
parents:
9
diff
changeset
|
928 if ((sfile = dmf_create_stdio(srcFilename, "rb")) == NULL) |
0 | 929 { |
84
35db15881923
Oops, another fix for dmf_create_stdio() changes.
Matti Hamalainen <ccr@tnsp.org>
parents:
9
diff
changeset
|
930 dmError("Error opening input file '%s', %d: %s\n", |
35db15881923
Oops, another fix for dmf_create_stdio() changes.
Matti Hamalainen <ccr@tnsp.org>
parents:
9
diff
changeset
|
931 srcFilename, errno, strerror(errno)); |
0 | 932 return 1; |
933 } | |
934 | |
935 // Initialize miniJSS | |
936 jssInit(); | |
937 | |
938 // Read file | |
939 dmMsg(1, "Reading XM-format file ...\n"); | |
940 result = jssLoadXM(sfile, &sm); | |
941 dmf_close(sfile); | |
942 if (result != 0) | |
943 { | |
944 dmError("Error while loading XM file (%i), ", result); | |
945 if (optIgnoreErrors) | |
946 fprintf(stderr, "ignoring. This may cause problems.\n"); | |
947 else | |
948 { | |
949 fprintf(stderr, "giving up. Use --ignore if you want to try to convert anyway.\n"); | |
950 return 2; | |
951 } | |
952 } | |
953 | |
954 // Check stripping settings | |
955 if (optStripExtInstr) optStripInstr = TRUE; | |
956 if (optStripInstr) optStripSamples = TRUE; | |
957 | |
958 // Remove samples | |
959 if (optStripSamples) | |
960 { | |
961 int i; | |
962 | |
963 dmMsg(1, "Stripping samples...\n"); | |
964 for (i = 0; i < sm->ninstruments; i++) | |
965 { | |
966 dmFree(sm->instruments[i]->data); | |
967 sm->instruments[i]->data = NULL; | |
968 } | |
969 } | |
970 | |
971 // Remove instruments | |
972 if (optStripInstr) | |
973 { | |
974 int i; | |
975 | |
976 dmMsg(1, "Stripping instruments...\n"); | |
977 for (i = 0; i < sm->ninstruments; i++) | |
978 { | |
979 dmFree(sm->instruments[i]); | |
980 sm->instruments[i] = NULL; | |
981 } | |
982 sm->ninstruments = 0; | |
983 } | |
984 | |
985 // Remove ext.instruments | |
986 if (optStripExtInstr) | |
987 { | |
988 int i; | |
989 | |
990 dmMsg(1, "Stripping ext.instruments...\n"); | |
991 for (i = 0; i < sm->nextInstruments; i++) | |
992 { | |
993 dmFree(sm->extInstruments[i]); | |
994 sm->extInstruments[i] = NULL; | |
995 } | |
996 sm->nextInstruments = 0; | |
997 } | |
998 // Run the optimization procedure | |
999 if (optOptimize) | |
1000 { | |
1001 dmMsg(1, "Optimizing module data...\n"); | |
1002 dm = optimizeModule(sm); | |
1003 } else | |
1004 dm = sm; | |
1005 | |
1006 // Write output file | |
1007 if (destFilename == NULL) | |
1008 dfile = stdout; | |
1009 else if ((dfile = fopen(destFilename, "wb")) == NULL) | |
1010 { | |
1011 dmError("Error creating output file '%s'. (%s)\n", destFilename, strerror(errno)); | |
1012 return 1; | |
1013 } | |
1014 | |
9
c42ee907de9c
Various improvements in xm2jss output.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
1015 dmMsg(1, "Writing JSSMOD-format file [patMode=0x%04x, samp8=0x%02x, samp16=0x%02x]\n", |
0 | 1016 optPatternMode, optSampMode8, optSampMode16); |
1017 | |
1018 result = jssSaveJSSMOD(dfile, dm, optPatternMode, optSampMode8, optSampMode16); | |
1019 | |
1020 fclose(dfile); | |
1021 | |
1022 if (result != 0) | |
1023 { | |
1024 dmError("Error while saving JSSMOD file (%i), the resulting file may be broken!\n", result); | |
1025 } | |
1026 | |
1027 dmMsg(1, "Conversion complete.\n"); | |
1028 return 0; | |
1029 } |