Mercurial > hg > dmlib
diff tools/xm2jss.c @ 2285:25398f2eba64
Merge.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 18 Jun 2019 14:23:02 +0300 |
parents | 6c3c3355007d |
children | dcf1016f3d27 |
line wrap: on
line diff
--- a/tools/xm2jss.c Tue Jun 18 07:38:05 2019 +0300 +++ b/tools/xm2jss.c Tue Jun 18 14:23:02 2019 +0300 @@ -1,7 +1,7 @@ /* * xm2jss - Convert XM module to JSSMOD * Programmed and designed by Matti 'ccr' Hamalainen - * (C) Copyright 2006-2017 Tecnic Software productions (TNSP) + * (C) Copyright 2006-2019 Tecnic Software productions (TNSP) * * Please read file 'COPYING' for information on license and distribution. */ @@ -147,6 +147,15 @@ } +static inline const JSSNote * jssGetNotePtr(const JSSPattern *pattern, const int channel, const int row) +{ + if (!pattern->used[channel]) + return NULL; + else + return pattern->data + (pattern->nchannels * row) + channel; +} + + /* These functions and the macro mess are meant to make the * conversion routines themselves clearer and simpler. */ @@ -189,7 +198,7 @@ /* Convert a note */ -static int jssConvertNote( +static int jssDoConvertNote( Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSNote *pnote) { @@ -220,7 +229,7 @@ /* Compress a note */ -static int jssCompressNote( +static int jssDoCompressNote( Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSNote *pnote) { @@ -256,13 +265,33 @@ JSCOMPPUT(JM_COMP_VOLUME, pnote->volume, "Volume"); JSCOMPPUT(JM_COMP_EFFECT, pnote->effect, "Effect"); JSCOMPPUT(JM_COMP_PARAM, pnote->param, "Param"); + + return DMERR_OK; } else { // Was 4 bytes or more, just dump it all in .. - return jssConvertNote(patBuf, patBufSize, patSize, pnote); + return jssDoConvertNote(patBuf, patBufSize, patSize, pnote); } +} + +static int jssCompressNote( + Uint8 *patBuf, const size_t patBufSize, + size_t *patSize, const JSSPattern *pattern, + const int channel, const int row) +{ + const JSSNote *pnote = jssGetNotePtr(pattern, channel, row); + if (pnote != NULL) + { + int res = jssDoCompressNote(patBuf, patBufSize, patSize, pnote); + if (res != DMERR_OK) + { + JSSERROR(res, res, "Note compression failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", + patBuf, patBufSize, *patSize, row, channel); + return res; + } + } return DMERR_OK; } @@ -278,14 +307,9 @@ for (int row = 0; row < pattern->nrows; row++) for (int channel = 0; channel < pattern->nchannels; channel++) { - const JSSNote *pnote = &pattern->data[(pattern->nchannels * row) + channel]; - const int res = jssCompressNote(patBuf, patBufSize, patSize, pnote); + int res = jssCompressNote(patBuf, patBufSize, patSize, pattern, channel, row); if (res != DMERR_OK) - { - JSSERROR(res, res, "Note compression failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", - patBuf, patBufSize, *patSize, row, channel); return res; - } } return DMERR_OK; @@ -301,14 +325,9 @@ for (int channel = 0; channel < pattern->nchannels; channel++) for (int row = 0; row < pattern->nrows; row++) { - const JSSNote *pnote = &pattern->data[(pattern->nchannels * row) + channel]; - const int res = jssCompressNote(patBuf, patBufSize, patSize, pnote); + int res = jssCompressNote(patBuf, patBufSize, patSize, pattern, channel, row); if (res != DMERR_OK) - { - JSSERROR(res, res, "Note compression failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", - patBuf, patBufSize, *patSize, row, channel); return res; - } } return DMERR_OK; @@ -317,6 +336,26 @@ /* Convert a pattern */ +static int jssConvertNote( + Uint8 *patBuf, const size_t patBufSize, + size_t *patSize, const JSSPattern *pattern, + const int channel, const int row) +{ + const JSSNote *pnote = jssGetNotePtr(pattern, channel, row); + if (pnote != NULL) + { + int res = jssDoConvertNote(patBuf, patBufSize, patSize, pnote); + if (res != DMERR_OK) + { + JSSERROR(res, res, "Note conversion failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", + patBuf, patBufSize, *patSize, row, channel); + return res; + } + } + return DMERR_OK; +} + + static int jssConvertPatternRawHoriz( Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) @@ -326,14 +365,9 @@ for (int row = 0; row < pattern->nrows; row++) for (int channel = 0; channel < pattern->nchannels; channel++) { - const JSSNote *pnote = &pattern->data[(pattern->nchannels * row) + channel]; - const int res = jssConvertNote(patBuf, patBufSize, patSize, pnote); + int res = jssConvertNote(patBuf, patBufSize, patSize, pattern, channel, row); if (res != DMERR_OK) - { - JSSERROR(res, res, "Note conversion failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", - patBuf, patBufSize, *patSize, row, channel); return res; - } } return DMERR_OK; @@ -349,14 +383,9 @@ for (int channel = 0; channel < pattern->nchannels; channel++) for (int row = 0; row < pattern->nrows; row++) { - const JSSNote *pnote = &pattern->data[(pattern->nchannels * row) + channel]; - const int res = jssConvertNote(patBuf, patBufSize, patSize, pnote); + int res = jssConvertNote(patBuf, patBufSize, patSize, pattern, channel, row); if (res != DMERR_OK) - { - JSSERROR(res, res, "Note conversion failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", - patBuf, patBufSize, *patSize, row, channel); return res; - } } return DMERR_OK; @@ -366,9 +395,11 @@ #define JSFOREACHNOTE1 \ for (channel = 0; channel < pattern->nchannels; channel++) \ for (row = 0; row < pattern->nrows; row++) { \ - const JSSNote *pnote = &pattern->data[(pattern->nchannels * row) + channel]; + const JSSNote *pnote = jssGetNotePtr(pattern, channel, row); \ + if (pnote != NULL) { -#define JSFOREACHNOTE2 } +#define JSFOREACHNOTE2 } } + static int jssConvertPatternRawElem( Uint8 *patBuf, const size_t patBufSize, @@ -546,12 +577,18 @@ // Convert and write patterns for (totalSize = index = 0; index < module->npatterns; index++) - if (module->patterns[index] != NULL) { JSSPattern *pattern = module->patterns[index]; size_t dataSize = 0; int ret; + if (pattern == NULL) + { + dmMsg(1, + "Pattern #%d is NULL.\n", index); + pattern = module->patterns[module->npatterns]; + } + if (pattern->nrows > jsetMaxRows) { JSSERROR(DMERR_INVALID_DATA, DMERR_INVALID_DATA, @@ -593,17 +630,30 @@ if (!dm_fwrite_le32(outFile, dataSize) || !dm_fwrite_le16(outFile, pattern->nrows) || - !dm_fwrite_str(outFile, patBuf, dataSize)) + !dm_fwrite_le16(outFile, pattern->nmap)) { JSSERROR(DMERR_FWRITE, DMERR_FWRITE, - "Error writing JSSMOD pattern #%d.\n", + "Error writing JSSMOD pattern header #%d.\n", index); } - } - else - { - JSSERROR(DMERR_NULLPTR, DMERR_NULLPTR, - "Pattern #%d was NULL.\n", index); + + if (pattern->nmap != pattern->nchannels) + { + if (!dm_fwrite_str(outFile, pattern->map, + sizeof(pattern->map[0]) * pattern->nmap)) + { + JSSERROR(DMERR_FWRITE, DMERR_FWRITE, + "Error writing JSSMOD channel map for pattern #%d.\n", + index); + } + } + + if (!dm_fwrite_str(outFile, patBuf, dataSize)) + { + JSSERROR(DMERR_FWRITE, DMERR_FWRITE, + "Error writing JSSMOD pattern data #%d.\n", + index); + } } dmFree(patBuf); @@ -620,8 +670,8 @@ { einst = &tmpEInst; memset(&tmpEInst, 0, sizeof(tmpEInst)); - JSSWARNING(DMERR_NULLPTR, DMERR_NULLPTR, - "Extended instrument #%d NULL!\n", + dmMsg(1, + "Extended instrument #%d is NULL!\n", index); } @@ -744,18 +794,19 @@ /* Scan given pattern for used instruments and channels. * Also checks if the pattern is empty. */ -void scanPattern(const JSSModule *module, const JSSPattern *pattern, - const int npattern, BOOL *usedExtInstruments, BOOL *usedChannels, BOOL *empty) +BOOL jssScanPattern(const JSSModule *module, const JSSPattern *pattern, + const int npattern, BOOL *usedExtInstruments, BOOL *usedChannels) { JSSNote *n = pattern->data; - *empty = FALSE; + BOOL empty = TRUE; // Check all notes in this pattern for (int row = 0; row < pattern->nrows; row++) for (int channel = 0; channel < pattern->nchannels; channel++, n++) { // Is the instrument set? - if (n->instrument != jsetNotSet) + if (usedExtInstruments != NULL && + n->instrument != jsetNotSet) { // Is it valid? if (n->instrument >= 0 && n->instrument < module->nextInstruments) @@ -774,16 +825,20 @@ n->effect != jsetNotSet || n->param != jsetNotSet) { - usedChannels[channel] = TRUE; - *empty = FALSE; + if (usedChannels != NULL) + usedChannels[channel] = TRUE; + + empty = FALSE; } } + + return empty; } /* Check if two given patterns are dupes */ -BOOL comparePattern(const JSSPattern *pat1, const JSSPattern *pat2) +BOOL jssComparePattern(const JSSPattern *pat1, const JSSPattern *pat2) { return pat1->nrows == pat2->nrows && @@ -794,12 +849,11 @@ /* Optimize a given module */ -JSSModule *optimizeModule(JSSModule *m) +JSSModule *jssOptimizeModule(JSSModule *m) { BOOL usedPatterns[jsetMaxPatterns + 1], usedInstruments[jsetMaxInstruments + 1], - usedExtInstruments[jsetMaxInstruments + 1], - usedChannels[jsetMaxChannels]; + usedExtInstruments[jsetMaxInstruments + 1]; int mapExtInstruments[jsetMaxInstruments + 1], mapInstruments[jsetMaxInstruments + 1], mapPatterns[jsetMaxPatterns + 1], @@ -827,7 +881,6 @@ for (int i = 0; i < jsetNChannels; i++) { r->defPanning[i] = m->defPanning[i]; - usedChannels[i] = FALSE; } // Initialize values @@ -859,13 +912,8 @@ JSSPattern *pattern = m->patterns[npat]; if (pattern != NULL) { - BOOL empty; - - // Mark this pattern as used - usedPatterns[npat] = TRUE; - - // Scan for used instruments and channels - scanPattern(m, pattern, npat, usedExtInstruments, usedChannels, &empty); + // Scan for used instruments etc + BOOL empty = jssScanPattern(m, pattern, npat, usedExtInstruments, NULL); // Empty patterns with known number of rows are "removed" if (empty && pattern->nrows == jsetDefaultRows) @@ -873,6 +921,8 @@ m->orderList[norder] = jsetNotSet; usedPatterns[npat] = FALSE; } + else + usedPatterns[npat] = TRUE; } else { @@ -951,7 +1001,7 @@ for (int pat2 = 0; pat2 < m->npatterns; pat2++) if (pat1 != pat2 && m->patterns[pat2] != NULL && dupPatterns[pat2] == jsetNotSet && - comparePattern(m->patterns[pat1], m->patterns[pat2])) + jssComparePattern(m->patterns[pat1], m->patterns[pat2])) { dmPrint(1, " * %d and %d are dupes.\n", pat1, pat2); dupPatterns[pat2] = pat1; @@ -1077,19 +1127,6 @@ r->nextInstruments, nunused); // - // Check for actually used channels - // XXX TODO: Actually remove the unused channels. - // - nunused = 0; - for (int i = 0; i < r->nchannels; i++) - { - if(!usedChannels[i]) - nunused++; - } - dmMsg(1, "%d channels (%d unused).\n", - r->nchannels - nunused, nunused); - - // // Remap pattern data with remapped instrument data // for (int i = 0; i < r->npatterns; i++) @@ -1150,6 +1187,29 @@ if (nunused) dmPrint(2, "\n"); + // + // Do final pass on patterns to remove unused channels + // + for (int i = 0; i < r->npatterns; i++) + { + JSSPattern *p = r->patterns[i]; + + jssScanPattern(r, p, i, NULL, p->used); + + p->nmap = 0; + for (int i = 0; i < r->nchannels; i++) + { + if (p->used[i]) + p->map[p->nmap++] = i; + } + + if (p->nmap != p->nchannels) + { + dmMsg(2, "Pattern %d: %d/%d used channels (%d unused).\n", + i, p->nchannels - p->nmap, p->nchannels, p->nmap); + } + } + return r; } @@ -1161,7 +1221,7 @@ JSSModule *sm, *dm; int result; - dmInitProg("xm2jss", "XM to JSSMOD converter", "0.7", NULL, NULL); + dmInitProg("xm2jss", "XM to JSSMOD converter", "0.8", NULL, NULL); dmVerbosity = 0; // Parse arguments @@ -1252,7 +1312,7 @@ if (optOptimize) { dmMsg(1, "Optimizing module data...\n"); - dm = optimizeModule(sm); + dm = jssOptimizeModule(sm); } else dm = sm;