Mercurial > hg > dmlib
diff minijss/jloadjss.c @ 2278:40ccc09f09be
Implement empty channel removal in xm2jss and make JSSMOD format support
channel remapping for this.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 18 Jun 2019 12:12:51 +0300 |
parents | ca9fe688ab6b |
children | fc58f62f100c |
line wrap: on
line diff
--- a/minijss/jloadjss.c Tue Jun 18 12:11:16 2019 +0300 +++ b/minijss/jloadjss.c Tue Jun 18 12:12:51 2019 +0300 @@ -16,13 +16,19 @@ #endif +static inline JSSNote * jssGetNotePtr(JSSPattern *pattern, const int channel, const int row) +{ + return pattern->data + (pattern->nchannels * row) + pattern->map[channel]; +} + + // Short helper macros for reading data #define JSGETBYTE(XV) \ if (!dmf_read_byte(inFile, XV)) \ return DMERR_OUT_OF_DATA -static int jssDoGetConvertedNote(DMResource *inFile, JSSNote *pnote, Uint8 note) +static int jssDoGetConvertedNote(DMResource *inFile, JSSNote *pnote, const Uint8 note) { Uint8 tmp; @@ -50,18 +56,29 @@ } -static inline int jssGetConvertedNote(DMResource *inFile, JSSNote *pnote) +static inline int jssGetConvertedNote(DMResource *inFile, + JSSPattern *pattern, const int channel, const int row) { Uint8 tmp; + int res; + JSGETBYTE(&tmp); - return jssDoGetConvertedNote(inFile, pnote, tmp); + if ((res = jssDoGetConvertedNote(inFile, + jssGetNotePtr(pattern, channel, row), tmp)) != DMERR_OK) + JSSERROR(res, res, "Error converting note on row=%d, chn=%d\n", + row, channel); + + return res; } #if defined(JM_SUP_PATMODE_2) || defined(JM_SUP_PATMODE_4) -static int jssGetCompressedNote(DMResource *inFile, JSSNote *pnote) +static int jssGetCompressedNoteDo(DMResource *inFile, + JSSPattern *pattern, const int channel, const int row) { + JSSNote *pnote = jssGetNotePtr(pattern, channel, row); Uint8 packb, tmp; + int res = DMERR_OK; JSGETBYTE(&packb); if (packb & 0x80) @@ -102,12 +119,23 @@ } else { - int ret; - if ((ret = jssDoGetConvertedNote(inFile, pnote, packb)) != DMERR_OK) - return ret; + res = jssDoGetConvertedNote(inFile, pnote, packb); } - return DMERR_OK; + return res; +} + + +static int jssGetCompressedNote(DMResource *inFile, + JSSPattern *pattern, const int channel, const int row) +{ + int res = jssGetCompressedNoteDo(inFile, pattern, channel, row); + + if (res != DMERR_OK) + JSSERROR(res, res, "Error uncompressing note on row=%d, chn=%d\n", + row, channel); + + return res; } #endif @@ -115,19 +143,12 @@ #ifdef JM_SUP_PATMODE_2 static int jssGetPatternCompHoriz(DMResource *inFile, JSSPattern *pattern) { - int row, channel; - - assert(buf != NULL); - assert(pattern != NULL); - - for (row = 0; row < pattern->nrows; row++) - for (channel = 0; channel < pattern->nchannels; channel++) + for (int row = 0; row < pattern->nrows; row++) + for (int channel = 0; channel < pattern->nmap; channel++) { - JSSNote *pnote = &pattern->data[(pattern->nchannels * row) + channel]; - int res = jssGetCompressedNote(inFile, pnote); + int res = jssGetCompressedNote(inFile, pattern, channel, row); if (res != DMERR_OK) - JSSERROR(res, res, "Error uncompressing note on row=%d, chn=%d\n", - row, channel); + return res; } return DMERR_OK; @@ -138,19 +159,12 @@ #ifdef JM_SUP_PATMODE_4 static int jssGetPatternCompVert(DMResource *inFile, JSSPattern *pattern) { - int row, channel; - - assert(buf != NULL); - assert(pattern != NULL); - - for (channel = 0; channel < pattern->nchannels; channel++) - for (row = 0; row < pattern->nrows; row++) + for (int channel = 0; channel < pattern->nmap; channel++) + for (int row = 0; row < pattern->nrows; row++) { - JSSNote *pnote = &pattern->data[(pattern->nchannels * row) + channel]; - int res = jssGetCompressedNote(inFile, pnote); + int res = jssGetCompressedNote(inFile, pattern, channel, row); if (res != DMERR_OK) - JSSERROR(res, res, "Error uncompressing note on row=%d, chn=%d\n", - row, channel); + return res; } return DMERR_OK; @@ -161,19 +175,12 @@ #ifdef JM_SUP_PATMODE_1 static int jssGetPatternRawHoriz(DMResource *inFile, JSSPattern *pattern) { - int row, channel; - - assert(buf != NULL); - assert(pattern != NULL); - - for (row = 0; row < pattern->nrows; row++) - for (channel = 0; channel < pattern->nchannels; channel++) + for (int row = 0; row < pattern->nrows; row++) + for (int channel = 0; channel < pattern->nmap; channel++) { - JSSNote *pnote = &pattern->data[(pattern->nchannels * row) + channel]; - int res = jssGetConvertedNote(inFile, pnote); + int res = jssGetConvertedNote(inFile, pattern, channel, row); if (res != DMERR_OK) - JSSERROR(res, res, "Error converting note on row=%d, chn=%d\n", - row, channel); + return res; } return DMERR_OK; @@ -184,19 +191,12 @@ #ifdef JM_SUP_PATMODE_3 static int jssGetPatternRawVert(DMResource *inFile, JSSPattern *pattern) { - int row, channel; - - assert(buf != NULL); - assert(pattern != NULL); - - for (channel = 0; channel < pattern->nchannels; channel++) - for (row = 0; row < pattern->nrows; row++) + for (int channel = 0; channel < pattern->nmap; channel++) + for (int row = 0; row < pattern->nrows; row++) { - JSSNote *pnote = &pattern->data[(pattern->nchannels * row) + channel]; - int res = jssGetConvertedNote(inFile, pnote); + int res = jssGetConvertedNote(inFile, pattern, channel, row); if (res != DMERR_OK) - JSSERROR(res, res, "Error converting note on row=%d, chn=%d\n", - row, channel); + return res; } return DMERR_OK; @@ -209,21 +209,18 @@ #undef JSGETBYTE #define JSGETBYTE(XV) if (!dmf_read_byte(inFile, XV)) return DMERR_OUT_OF_DATA -#define JSFOREACHNOTE1 \ - for (channel = 0; channel < pattern->nchannels; channel++) \ - for (row = 0; row < pattern->nrows; row++) { \ - JSSNote *pnote = pattern->data + (pattern->nchannels * row) + channel; +#define JSFOREACHNOTE1 \ + for (int channel = 0; channel < pattern->nmap; channel++) \ + for (int row = 0; row < pattern->nrows; row++) { \ + JSSNote *pnote = pattern->data + (pattern->nchannels * row) + pattern->map[channel]; #define JSFOREACHNOTE2 } + static int jssGetPatternRawVertElem(DMResource *inFile, JSSPattern *pattern) { - int row, channel; Uint8 tmp; - assert(buf != NULL); - assert(pattern != NULL); - JSFOREACHNOTE1 JSGETBYTE(&tmp); if (tmp == 0) @@ -433,7 +430,8 @@ // Read pattern header if (!dmf_read_le32(inFile, &jssP.size) || - !dmf_read_le16(inFile, &jssP.nrows)) + !dmf_read_le16(inFile, &jssP.nrows) || + !dmf_read_le16(inFile, &jssP.nchannels)) JSSERROR(DMERR_FREAD, DMERR_FREAD, "Failed to read JSSMOD pattern header #%d.\n", index); @@ -444,6 +442,11 @@ "Invalid number of rows in pattern #%d: %d.\n", index, jssP.nrows); + if (jssP.nchannels == 0 || jssP.nchannels > module->nchannels) + JSSERROR(DMERR_INVALID_DATA, DMERR_INVALID_DATA, + "Invalid number of channels in pattern #%d: %d.\n", + index, jssP.nchannels); + // Allocate pattern pattern = module->patterns[index] = jssAllocatePattern(jssP.nrows, module->nchannels); if (pattern == NULL) @@ -453,6 +456,28 @@ index); } + // Read channel mappings, if any + pattern->nmap = jssP.nchannels; + if (jssP.nchannels != module->nchannels) + { + if (!dmf_read_str(inFile, pattern->map, + sizeof(pattern->map[0]) * jssP.nchannels)) + JSSERROR(DMERR_FREAD, DMERR_FREAD, + "Failed to read JSSMOD channel mapping data for pattern #%d.\n", + index); + + // Check mapping + for (int nch = 0; nch < jssP.nchannels; nch++) + { + if (pattern->map[nch] >= module->nchannels) + { + JSSERROR(DMERR_INVALID_DATA, DMERR_INVALID_DATA, + "Invalid channel mapping in pattern #%d: chn %d -> %d.\n", + index, nch, pattern->map[nch]); + } + } + } + // Get pattern data switch (jssH.patMode) {