comparison 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
comparison
equal deleted inserted replaced
2277:026c3aa0e48f 2278:40ccc09f09be
14 # define JM_SUP_PATMODE_4 1 14 # define JM_SUP_PATMODE_4 1
15 # define JM_SUP_PATMODE_5 1 15 # define JM_SUP_PATMODE_5 1
16 #endif 16 #endif
17 17
18 18
19 static inline JSSNote * jssGetNotePtr(JSSPattern *pattern, const int channel, const int row)
20 {
21 return pattern->data + (pattern->nchannels * row) + pattern->map[channel];
22 }
23
24
19 // Short helper macros for reading data 25 // Short helper macros for reading data
20 #define JSGETBYTE(XV) \ 26 #define JSGETBYTE(XV) \
21 if (!dmf_read_byte(inFile, XV)) \ 27 if (!dmf_read_byte(inFile, XV)) \
22 return DMERR_OUT_OF_DATA 28 return DMERR_OUT_OF_DATA
23 29
24 30
25 static int jssDoGetConvertedNote(DMResource *inFile, JSSNote *pnote, Uint8 note) 31 static int jssDoGetConvertedNote(DMResource *inFile, JSSNote *pnote, const Uint8 note)
26 { 32 {
27 Uint8 tmp; 33 Uint8 tmp;
28 34
29 if (note == 127) 35 if (note == 127)
30 pnote->note = jsetNoteOff; 36 pnote->note = jsetNoteOff;
48 54
49 return DMERR_OK; 55 return DMERR_OK;
50 } 56 }
51 57
52 58
53 static inline int jssGetConvertedNote(DMResource *inFile, JSSNote *pnote) 59 static inline int jssGetConvertedNote(DMResource *inFile,
60 JSSPattern *pattern, const int channel, const int row)
54 { 61 {
55 Uint8 tmp; 62 Uint8 tmp;
56 JSGETBYTE(&tmp); 63 int res;
57 return jssDoGetConvertedNote(inFile, pnote, tmp); 64
65 JSGETBYTE(&tmp);
66 if ((res = jssDoGetConvertedNote(inFile,
67 jssGetNotePtr(pattern, channel, row), tmp)) != DMERR_OK)
68 JSSERROR(res, res, "Error converting note on row=%d, chn=%d\n",
69 row, channel);
70
71 return res;
58 } 72 }
59 73
60 74
61 #if defined(JM_SUP_PATMODE_2) || defined(JM_SUP_PATMODE_4) 75 #if defined(JM_SUP_PATMODE_2) || defined(JM_SUP_PATMODE_4)
62 static int jssGetCompressedNote(DMResource *inFile, JSSNote *pnote) 76 static int jssGetCompressedNoteDo(DMResource *inFile,
63 { 77 JSSPattern *pattern, const int channel, const int row)
78 {
79 JSSNote *pnote = jssGetNotePtr(pattern, channel, row);
64 Uint8 packb, tmp; 80 Uint8 packb, tmp;
81 int res = DMERR_OK;
65 82
66 JSGETBYTE(&packb); 83 JSGETBYTE(&packb);
67 if (packb & 0x80) 84 if (packb & 0x80)
68 { 85 {
69 if (packb & JM_COMP_NOTE) 86 if (packb & JM_COMP_NOTE)
100 pnote->param = tmp; 117 pnote->param = tmp;
101 } 118 }
102 } 119 }
103 else 120 else
104 { 121 {
105 int ret; 122 res = jssDoGetConvertedNote(inFile, pnote, packb);
106 if ((ret = jssDoGetConvertedNote(inFile, pnote, packb)) != DMERR_OK) 123 }
107 return ret; 124
108 } 125 return res;
109 126 }
110 return DMERR_OK; 127
128
129 static int jssGetCompressedNote(DMResource *inFile,
130 JSSPattern *pattern, const int channel, const int row)
131 {
132 int res = jssGetCompressedNoteDo(inFile, pattern, channel, row);
133
134 if (res != DMERR_OK)
135 JSSERROR(res, res, "Error uncompressing note on row=%d, chn=%d\n",
136 row, channel);
137
138 return res;
111 } 139 }
112 #endif 140 #endif
113 141
114 142
115 #ifdef JM_SUP_PATMODE_2 143 #ifdef JM_SUP_PATMODE_2
116 static int jssGetPatternCompHoriz(DMResource *inFile, JSSPattern *pattern) 144 static int jssGetPatternCompHoriz(DMResource *inFile, JSSPattern *pattern)
117 { 145 {
118 int row, channel; 146 for (int row = 0; row < pattern->nrows; row++)
119 147 for (int channel = 0; channel < pattern->nmap; channel++)
120 assert(buf != NULL); 148 {
121 assert(pattern != NULL); 149 int res = jssGetCompressedNote(inFile, pattern, channel, row);
122
123 for (row = 0; row < pattern->nrows; row++)
124 for (channel = 0; channel < pattern->nchannels; channel++)
125 {
126 JSSNote *pnote = &pattern->data[(pattern->nchannels * row) + channel];
127 int res = jssGetCompressedNote(inFile, pnote);
128 if (res != DMERR_OK) 150 if (res != DMERR_OK)
129 JSSERROR(res, res, "Error uncompressing note on row=%d, chn=%d\n", 151 return res;
130 row, channel);
131 } 152 }
132 153
133 return DMERR_OK; 154 return DMERR_OK;
134 } 155 }
135 #endif 156 #endif
136 157
137 158
138 #ifdef JM_SUP_PATMODE_4 159 #ifdef JM_SUP_PATMODE_4
139 static int jssGetPatternCompVert(DMResource *inFile, JSSPattern *pattern) 160 static int jssGetPatternCompVert(DMResource *inFile, JSSPattern *pattern)
140 { 161 {
141 int row, channel; 162 for (int channel = 0; channel < pattern->nmap; channel++)
142 163 for (int row = 0; row < pattern->nrows; row++)
143 assert(buf != NULL); 164 {
144 assert(pattern != NULL); 165 int res = jssGetCompressedNote(inFile, pattern, channel, row);
145
146 for (channel = 0; channel < pattern->nchannels; channel++)
147 for (row = 0; row < pattern->nrows; row++)
148 {
149 JSSNote *pnote = &pattern->data[(pattern->nchannels * row) + channel];
150 int res = jssGetCompressedNote(inFile, pnote);
151 if (res != DMERR_OK) 166 if (res != DMERR_OK)
152 JSSERROR(res, res, "Error uncompressing note on row=%d, chn=%d\n", 167 return res;
153 row, channel);
154 } 168 }
155 169
156 return DMERR_OK; 170 return DMERR_OK;
157 } 171 }
158 #endif 172 #endif
159 173
160 174
161 #ifdef JM_SUP_PATMODE_1 175 #ifdef JM_SUP_PATMODE_1
162 static int jssGetPatternRawHoriz(DMResource *inFile, JSSPattern *pattern) 176 static int jssGetPatternRawHoriz(DMResource *inFile, JSSPattern *pattern)
163 { 177 {
164 int row, channel; 178 for (int row = 0; row < pattern->nrows; row++)
165 179 for (int channel = 0; channel < pattern->nmap; channel++)
166 assert(buf != NULL); 180 {
167 assert(pattern != NULL); 181 int res = jssGetConvertedNote(inFile, pattern, channel, row);
168
169 for (row = 0; row < pattern->nrows; row++)
170 for (channel = 0; channel < pattern->nchannels; channel++)
171 {
172 JSSNote *pnote = &pattern->data[(pattern->nchannels * row) + channel];
173 int res = jssGetConvertedNote(inFile, pnote);
174 if (res != DMERR_OK) 182 if (res != DMERR_OK)
175 JSSERROR(res, res, "Error converting note on row=%d, chn=%d\n", 183 return res;
176 row, channel);
177 } 184 }
178 185
179 return DMERR_OK; 186 return DMERR_OK;
180 } 187 }
181 #endif 188 #endif
182 189
183 190
184 #ifdef JM_SUP_PATMODE_3 191 #ifdef JM_SUP_PATMODE_3
185 static int jssGetPatternRawVert(DMResource *inFile, JSSPattern *pattern) 192 static int jssGetPatternRawVert(DMResource *inFile, JSSPattern *pattern)
186 { 193 {
187 int row, channel; 194 for (int channel = 0; channel < pattern->nmap; channel++)
188 195 for (int row = 0; row < pattern->nrows; row++)
189 assert(buf != NULL); 196 {
190 assert(pattern != NULL); 197 int res = jssGetConvertedNote(inFile, pattern, channel, row);
191
192 for (channel = 0; channel < pattern->nchannels; channel++)
193 for (row = 0; row < pattern->nrows; row++)
194 {
195 JSSNote *pnote = &pattern->data[(pattern->nchannels * row) + channel];
196 int res = jssGetConvertedNote(inFile, pnote);
197 if (res != DMERR_OK) 198 if (res != DMERR_OK)
198 JSSERROR(res, res, "Error converting note on row=%d, chn=%d\n", 199 return res;
199 row, channel);
200 } 200 }
201 201
202 return DMERR_OK; 202 return DMERR_OK;
203 } 203 }
204 #endif 204 #endif
207 #ifdef JM_SUP_PATMODE_5 207 #ifdef JM_SUP_PATMODE_5
208 208
209 #undef JSGETBYTE 209 #undef JSGETBYTE
210 #define JSGETBYTE(XV) if (!dmf_read_byte(inFile, XV)) return DMERR_OUT_OF_DATA 210 #define JSGETBYTE(XV) if (!dmf_read_byte(inFile, XV)) return DMERR_OUT_OF_DATA
211 211
212 #define JSFOREACHNOTE1 \ 212 #define JSFOREACHNOTE1 \
213 for (channel = 0; channel < pattern->nchannels; channel++) \ 213 for (int channel = 0; channel < pattern->nmap; channel++) \
214 for (row = 0; row < pattern->nrows; row++) { \ 214 for (int row = 0; row < pattern->nrows; row++) { \
215 JSSNote *pnote = pattern->data + (pattern->nchannels * row) + channel; 215 JSSNote *pnote = pattern->data + (pattern->nchannels * row) + pattern->map[channel];
216 216
217 #define JSFOREACHNOTE2 } 217 #define JSFOREACHNOTE2 }
218 218
219
219 static int jssGetPatternRawVertElem(DMResource *inFile, JSSPattern *pattern) 220 static int jssGetPatternRawVertElem(DMResource *inFile, JSSPattern *pattern)
220 { 221 {
221 int row, channel;
222 Uint8 tmp; 222 Uint8 tmp;
223
224 assert(buf != NULL);
225 assert(pattern != NULL);
226 223
227 JSFOREACHNOTE1 224 JSFOREACHNOTE1
228 JSGETBYTE(&tmp); 225 JSGETBYTE(&tmp);
229 if (tmp == 0) 226 if (tmp == 0)
230 pnote->note = jsetNotSet; 227 pnote->note = jsetNotSet;
431 JSSPattern *pattern; 428 JSSPattern *pattern;
432 JSSMODPattern jssP; 429 JSSMODPattern jssP;
433 430
434 // Read pattern header 431 // Read pattern header
435 if (!dmf_read_le32(inFile, &jssP.size) || 432 if (!dmf_read_le32(inFile, &jssP.size) ||
436 !dmf_read_le16(inFile, &jssP.nrows)) 433 !dmf_read_le16(inFile, &jssP.nrows) ||
434 !dmf_read_le16(inFile, &jssP.nchannels))
437 JSSERROR(DMERR_FREAD, DMERR_FREAD, 435 JSSERROR(DMERR_FREAD, DMERR_FREAD,
438 "Failed to read JSSMOD pattern header #%d.\n", 436 "Failed to read JSSMOD pattern header #%d.\n",
439 index); 437 index);
440 438
441 // Validate 439 // Validate
442 if (jssP.nrows == 0 || jssP.nrows > jsetMaxRows) 440 if (jssP.nrows == 0 || jssP.nrows > jsetMaxRows)
443 JSSERROR(DMERR_INVALID_DATA, DMERR_INVALID_DATA, 441 JSSERROR(DMERR_INVALID_DATA, DMERR_INVALID_DATA,
444 "Invalid number of rows in pattern #%d: %d.\n", 442 "Invalid number of rows in pattern #%d: %d.\n",
445 index, jssP.nrows); 443 index, jssP.nrows);
446 444
445 if (jssP.nchannels == 0 || jssP.nchannels > module->nchannels)
446 JSSERROR(DMERR_INVALID_DATA, DMERR_INVALID_DATA,
447 "Invalid number of channels in pattern #%d: %d.\n",
448 index, jssP.nchannels);
449
447 // Allocate pattern 450 // Allocate pattern
448 pattern = module->patterns[index] = jssAllocatePattern(jssP.nrows, module->nchannels); 451 pattern = module->patterns[index] = jssAllocatePattern(jssP.nrows, module->nchannels);
449 if (pattern == NULL) 452 if (pattern == NULL)
450 { 453 {
451 JSSERROR(DMERR_MALLOC, DMERR_MALLOC, 454 JSSERROR(DMERR_MALLOC, DMERR_MALLOC,
452 "Could not allocate memory for pattern #%d.\n", 455 "Could not allocate memory for pattern #%d.\n",
453 index); 456 index);
457 }
458
459 // Read channel mappings, if any
460 pattern->nmap = jssP.nchannels;
461 if (jssP.nchannels != module->nchannels)
462 {
463 if (!dmf_read_str(inFile, pattern->map,
464 sizeof(pattern->map[0]) * jssP.nchannels))
465 JSSERROR(DMERR_FREAD, DMERR_FREAD,
466 "Failed to read JSSMOD channel mapping data for pattern #%d.\n",
467 index);
468
469 // Check mapping
470 for (int nch = 0; nch < jssP.nchannels; nch++)
471 {
472 if (pattern->map[nch] >= module->nchannels)
473 {
474 JSSERROR(DMERR_INVALID_DATA, DMERR_INVALID_DATA,
475 "Invalid channel mapping in pattern #%d: chn %d -> %d.\n",
476 index, nch, pattern->map[nch]);
477 }
478 }
454 } 479 }
455 480
456 // Get pattern data 481 // Get pattern data
457 switch (jssH.patMode) 482 switch (jssH.patMode)
458 { 483 {