Mercurial > hg > dmlib
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 { |