1 /*************************************************************************/
2 /* cp_loader_xm.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30
31 #include "cp_loader_xm.h"
32 #include "cp_tables.h"
33
34 #define ABORT_LOAD \
35 { \
36 file->close(); \
37 return FILE_CORRUPTED; \
38 }
39
load_song(const char * p_file,CPSong * p_song,bool p_sampleset)40 CPLoader::Error CPLoader_XM::load_song(const char *p_file, CPSong *p_song, bool p_sampleset) {
41
42 song = p_song;
43
44 if (file->open(p_file, CPFileAccessWrapper::READ)) {
45
46 return FILE_CANNOT_OPEN;
47 };
48
49 /**************************************
50 LOAD HEADER
51 ***************************************/
52
53 file->get_byte_array(header.idtext, 17);
54 header.idtext[17] = 0;
55
56 file->get_byte_array(header.songname, 20);
57
58 header.songname[20] = 0;
59 header.hex1a = file->get_byte();
60 if (header.hex1a != 0x1A) { //XM "magic" byte.. this sucks :)
61
62 file->close();
63 return FILE_UNRECOGNIZED;
64 }
65
66 //magic byte sucks, but can't do much about it..
67
68 song->reset(); //must reset the song
69
70 song->set_name((const char *)header.songname);
71
72 file->get_byte_array(header.trackername, 20);
73 header.trackername[20] = 0;
74
75 header.version = file->get_word();
76
77 header.headersize = file->get_dword();
78
79 header.songlength = file->get_word();
80
81 header.restart_pos = file->get_word();
82
83 header.channels_used = file->get_word();
84
85 header.patterns_used = file->get_word();
86
87 header.instruments_used = file->get_word();
88
89 song->set_linear_slides(file->get_word());
90
91 song->set_speed(file->get_word());
92
93 song->set_tempo(file->get_word());
94 song->set_instruments(true);
95
96 file->get_byte_array(header.orderlist, 256);
97
98 for (int i = 0; i < header.songlength; i++) {
99
100 if (i > 199)
101 break;
102 song->set_order(i, header.orderlist[i]);
103 }
104
105 /**************************************
106 LOAD PATTERNS
107 ***************************************/
108
109 for (int i = 0; i < header.patterns_used; i++) {
110
111 uint32_t aux, rows;
112
113 aux = file->get_dword(); //length
114 aux = file->get_byte(); //packing type
115 rows = aux = file->get_word(); //rows!
116
117 song->get_pattern(i)->set_length(aux);
118
119 aux = file->get_word(); //packed size
120 if (aux == 0)
121 continue;
122 //unpaaack!
123 for (int j = 0; j < (int)rows; j++)
124 for (int k = 0; k < header.channels_used; k++) {
125
126 CPNote aux_note;
127 uint8_t aux_byte;
128 //uint8_t field;
129 aux_byte = file->get_byte(); //packing type
130 if (!(aux_byte & 0x80)) {
131
132 aux_note.note = aux_byte;
133 aux_byte = 0xFE; //if bit 7 not set, read all of them except the note
134 }
135
136 if (aux_byte & 1) aux_note.note = file->get_byte();
137 if (aux_byte & 2) aux_note.instrument = file->get_byte();
138 if (aux_byte & 4) aux_note.volume = file->get_byte();
139 if (aux_byte & 8) aux_note.command = file->get_byte();
140 if (aux_byte & 16) aux_note.parameter = file->get_byte();
141
142 if (aux_note.note != CPNote::EMPTY) {
143
144 if (aux_note.note == 97)
145 aux_note.note = CPNote::OFF;
146 else {
147 aux_note.note += 11; //octave minus one (XM C-0 is 1, not zero )
148 }
149 }
150 if (aux_note.instrument != CPNote::EMPTY) {
151
152 if ((aux_note.instrument > 0) && (aux_note.instrument < 100))
153 aux_note.instrument--;
154 else
155 aux_note.instrument = CPNote::EMPTY;
156 }
157 if (aux_note.volume != CPNote::EMPTY) {
158
159 if (aux_note.volume < 0x10) {
160 } else if (aux_note.volume < 0x50) {
161
162 aux_note.volume -= 0x10;
163
164 } else if (aux_note.volume < 0x60) {
165 //
166 aux_note.volume = CPNote::EMPTY;
167
168 } else if (aux_note.volume < 0x70) {
169 //60 -- volume slide down
170 aux_note.volume -= 0x60;
171 if (aux_note.volume > 9) aux_note.volume = 9;
172 aux_note.volume += 95;
173
174 } else if (aux_note.volume < 0x80) {
175 //70 -- volume slide up
176 aux_note.volume -= 0x70;
177 if (aux_note.volume > 9) aux_note.volume = 9;
178 aux_note.volume += 85;
179
180 } else if (aux_note.volume < 0x90) {
181 //80 -- fine volume slide down
182 aux_note.volume -= 0x80;
183 if (aux_note.volume > 9) aux_note.volume = 9;
184 aux_note.volume += 75;
185
186 } else if (aux_note.volume < 0xA0) {
187 //9 -- fine volume slide up
188
189 aux_note.volume -= 0x90;
190 if (aux_note.volume > 9) aux_note.volume = 9;
191
192 aux_note.volume += 65;
193
194 } else if (aux_note.volume < 0xB0) {
195 //A -- set vibrato speed
196 aux_note.volume = CPNote::EMPTY;
197
198 } else if (aux_note.volume < 0xC0) {
199 //B -- vibrato
200 aux_note.volume -= 0xB0;
201 if (aux_note.volume > 9) aux_note.volume = 9;
202 aux_note.volume += 203;
203
204 } else if (aux_note.volume < 0xD0) {
205 //C -- set panning
206 int aux = aux_note.volume -= 0xC0;
207 aux = aux * 65 / 0xF;
208 aux_note.volume = 128 + aux;
209
210 } else if (aux_note.volume < 0xE0) {
211 aux_note.volume = CPNote::EMPTY;
212
213 } else if (aux_note.volume < 0xF0) {
214 aux_note.volume = CPNote::EMPTY;
215
216 } else {
217 //F -- tone porta
218 aux_note.volume -= 0xF0;
219 aux_note.volume *= 9;
220 aux_note.volume /= 0xF;
221 aux_note.volume += 193;
222 }
223 }
224 if (aux_note.command != CPNote::EMPTY) {
225
226 switch (aux_note.command) {
227
228 case 0x0:
229 aux_note.command = 'J' - 'A';
230 break;
231 case 0x1:
232 aux_note.command = 'F' - 'A';
233 break;
234 case 0x2:
235 aux_note.command = 'E' - 'A';
236 break;
237 case 0x3:
238 aux_note.command = 'G' - 'A';
239 break;
240 case 0x4:
241 aux_note.command = 'H' - 'A';
242 break;
243 case 0x5:
244 aux_note.command = 'L' - 'A';
245 break;
246 case 0x6:
247 aux_note.command = 'K' - 'A';
248 break;
249 case 0x7:
250 aux_note.command = 'R' - 'A';
251 break;
252 case 0x8:
253 aux_note.command = 'X' - 'A';
254 break;
255 case 0x9:
256 aux_note.command = 'O' - 'A';
257 break;
258 case 0xa:
259 aux_note.command = 'D' - 'A';
260 break;
261 case 0xb:
262 aux_note.command = 'B' - 'A';
263 break;
264 case 0xc:
265 //printf("XM Import: Warning! effect C (set volume) not implemented!\n");
266 break;
267 case 0xd:
268 aux_note.command = 'C' - 'A';
269 break;
270
271 case 0xe: /* Extended effects */
272
273 aux_note.command = 'S' - 'A';
274 switch (aux_note.parameter >> 4) {
275 case 0x1: /* XM fine porta up */
276 if (!(aux_note.parameter & 0xF)) {
277 aux_note.command = CPNote::EMPTY;
278 aux_note.parameter = 0;
279 break;
280 }
281 aux_note.command = 'F' - 'A';
282 aux_note.parameter = 0xF0 | (aux_note.parameter & 0xF);
283 break;
284 case 0x2: /* XM fine porta down */
285 if (!(aux_note.parameter & 0xF)) {
286 aux_note.command = CPNote::EMPTY;
287 aux_note.parameter = 0;
288 break;
289 }
290 aux_note.command = 'E' - 'A';
291 aux_note.parameter = 0xF0 | (aux_note.parameter & 0xF);
292 break;
293 case 0xa: /* XM fine volume up */
294 if (!(aux_note.parameter & 0xF)) {
295 aux_note.command = CPNote::EMPTY;
296 aux_note.parameter = 0;
297 break;
298 }
299 aux_note.command = 'D' - 'A';
300 aux_note.parameter = 0x0F | ((aux_note.parameter & 0xF) << 4);
301
302 break;
303 case 0xb: /* XM fine volume down */
304 if (!(aux_note.parameter & 0xF)) {
305 aux_note.command = CPNote::EMPTY;
306 aux_note.parameter = 0;
307 break;
308 }
309 aux_note.command = 'D' - 'A';
310 aux_note.parameter = 0xF0 | (aux_note.parameter & 0xF);
311
312 break;
313 case 0x9: /* XM fine volume down */
314 if (!(aux_note.parameter & 0xF)) {
315 aux_note.command = CPNote::EMPTY;
316 aux_note.parameter = 0;
317 break;
318 }
319 aux_note.command = 'Q' - 'A';
320 aux_note.parameter = 0x00 | (aux_note.parameter & 0xF);
321 break;
322
323 case 0xc: //notecut
324
325 aux_note.parameter = 0xC0 | (aux_note.parameter & 0xF);
326 break;
327
328 case 0xd: //notedelay
329
330 aux_note.parameter = 0xD0 | (aux_note.parameter & 0xF);
331 break;
332
333 case 0xe: //patterndelay
334
335 aux_note.parameter = 0xE0 | (aux_note.parameter & 0xF);
336 break;
337 }
338
339 break;
340 case 0xf:
341 if (aux_note.parameter < 32) {
342 aux_note.command = 'A' - 'A';
343 } else {
344 aux_note.command = 'T' - 'A';
345 }
346 break;
347 case 'G' - 55:
348 aux_note.command = 'V' - 'A';
349 break;
350 case 'H' - 55:
351 aux_note.command = 'W' - 'A';
352 break;
353 case 'K' - 55:
354 if (aux_note.note != CPNote::EMPTY) break;
355 aux_note.note = CPNote::OFF;
356 break;
357 case 'P' - 55:
358 aux_note.command = 'P' - 'A';
359 break;
360 case 'R' - 55:
361 aux_note.command = 'Q' - 'A';
362 break;
363 case 'T' - 55:
364 aux_note.command = 'I' - 'A';
365 break;
366 default: {
367
368 aux_note.command = CPNote::EMPTY;
369 }
370 }
371 }
372
373 song->get_pattern(i)->set_note(k, j, aux_note);
374 }
375 }
376
377 /**************************************
378 LOAD INSTRUMENTS!
379 ***************************************/
380
381 for (int i = 0; i < header.instruments_used; i++) {
382
383 uint32_t aux;
384 int sampnum;
385
386 CPInstrument &instrument = *song->get_instrument(i);
387 uint32_t cpos = file->get_pos();
388 //printf("pos is %i\n",cpos);
389
390 /* +4 */ uint32_t hsize = file->get_dword(); //header length
391
392 char instrname[23];
393 instrname[22] = 0;
394
395 file->get_byte_array((uint8_t *)instrname, 22);
396 //XM_LOAD_DEBUG printf("name is %s\n",instrname);
397
398 /* +27 */ aux = file->get_byte(); //byte that must be ignored
399 //XM_LOAD_DEBUG printf("header size is %i\n",hsize);
400
401 /* +29 */ sampnum = file->get_word();
402
403 //XM_LOAD_DEBUG printf("samples %i\n",sampnum);
404
405 instrument.set_name(instrname);
406 // printf("Header Len: %i, CPInstrument %i, %i samples , name: s,\n",hsize,i,sampnum,instrname);
407
408 if (sampnum == 0) {
409 //aux=file->get_dword(); //Why is this for? -- for nothing, skipped
410 if (hsize) {
411
412 file->seek(cpos + hsize); //skip header if size has been specified
413 }
414 continue;
415 }
416
417 /* +33 */ file->get_dword();
418
419 if (Error result = load_instrument_internal(&instrument, false, cpos, hsize, sampnum)) {
420
421 CP_PRINTERR("Error loading instrument");
422 file->close();
423 return result;
424 }
425 }
426 //
427 file->close();
428 return FILE_OK;
429 }
430
load_instrument_internal(CPInstrument * p_instr,bool p_xi,int p_cpos,int p_hsize,int p_sampnum)431 CPLoader::Error CPLoader_XM::load_instrument_internal(CPInstrument *p_instr, bool p_xi, int p_cpos, int p_hsize, int p_sampnum) {
432
433 int sampnum;
434 uint32_t aux;
435 uint8_t notenumb[96];
436 uint16_t panenv[24], volenv[24];
437 int volpoints, panpoints;
438 int vol_loop_begin, vol_loop_end, vol_sustain_loop;
439 int pan_loop_begin, pan_loop_end, pan_sustain_loop;
440 char instrname[23];
441 int sample_index[16] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; //-1 means no index!
442
443 instrname[22] = 0;
444
445 /* +129 */ file->get_byte_array((uint8_t *)notenumb, 96);
446 for (int j = 0; j < 24; j++) {
447 volenv[j] = file->get_word();
448 }
449 for (int j = 0; j < 24; j++) {
450 panenv[j] = file->get_word();
451 }
452
453 /* +177 */
454 /* +225 */
455 /* +226 */ volpoints = file->get_byte();
456 /* +227 */ panpoints = file->get_byte();
457 /* +230 */ vol_sustain_loop = file->get_byte();
458 /* +228 */ vol_loop_begin = file->get_byte();
459 /* +229 */ vol_loop_end = file->get_byte();
460
461 //XM_LOAD_DEBUG printf("1- volpoints: %i, panpoints: %i, susloop: %i, loop begin: %i, loop end %i\n",volpoints,panpoints,vol_sustain_loop,vol_loop_begin,vol_loop_end);
462 pan_sustain_loop = file->get_byte();
463 /* +231 */ pan_loop_begin = file->get_byte();
464 /* +232 */ pan_loop_end = file->get_byte();
465
466 /* +234 */ aux = file->get_byte();
467 p_instr->get_volume_envelope()->reset();
468 p_instr->get_volume_envelope()->set_enabled(aux & 1);
469 p_instr->get_volume_envelope()->set_sustain_loop_enabled((aux & 2) ? true : false);
470 p_instr->get_volume_envelope()->set_loop_enabled((aux & 4) ? true : false);
471 /* +235 */ aux = file->get_byte();
472 p_instr->get_pan_envelope()->reset();
473 p_instr->get_pan_envelope()->set_enabled(aux & 1);
474 p_instr->get_pan_envelope()->set_sustain_loop_enabled((aux & 2) ? true : false);
475 p_instr->get_pan_envelope()->set_loop_enabled((aux & 4) ? true : false);
476
477 /* +239 */ aux = file->get_dword(); // sadly, cant use those
478 /* +241 */ p_instr->set_volume_fadeout(file->get_word() >> 4);
479 /* +243 */ aux = file->get_word(); // reserved!
480
481 for (int j = 0; j < volpoints; j++) {
482 int ofs = volenv[j * 2];
483 int val = volenv[j * 2 + 1];
484 p_instr->get_volume_envelope()->add_position(ofs, val);
485 }
486
487 //make sure minimum is 2
488 while (p_instr->get_volume_envelope()->get_node_count() < 2) {
489
490 p_instr->get_volume_envelope()->add_position(p_instr->get_volume_envelope()->get_node_count() * 20, 64);
491 }
492
493 for (int j = 0; j < panpoints; j++) {
494 int ofs = panenv[j * 2];
495 int val = panenv[j * 2 + 1];
496 p_instr->get_pan_envelope()->add_position(ofs, val - 32);
497 }
498
499 //make sure minimum is 2
500 while (p_instr->get_pan_envelope()->get_node_count() < 2) {
501
502 p_instr->get_pan_envelope()->add_position(p_instr->get_pan_envelope()->get_node_count() * 20, 0);
503 }
504
505 p_instr->get_volume_envelope()->set_loop_begin(vol_loop_begin);
506 p_instr->get_volume_envelope()->set_loop_end(vol_loop_end);
507 p_instr->get_volume_envelope()->set_sustain_loop_end(vol_sustain_loop);
508 p_instr->get_volume_envelope()->set_sustain_loop_begin(vol_sustain_loop);
509 p_instr->get_pan_envelope()->set_loop_begin(pan_loop_begin);
510 p_instr->get_pan_envelope()->set_loop_end(pan_loop_end);
511 p_instr->get_pan_envelope()->set_sustain_loop_end(pan_sustain_loop);
512 p_instr->get_pan_envelope()->set_sustain_loop_begin(pan_sustain_loop);
513
514 if (!p_xi) {
515
516 if ((file->get_pos() - p_cpos) < p_hsize) {
517
518 uint8_t junkbuster[500];
519
520 //printf("extra junk XM instrument in header! hsize is %i, extra junk: %i\n",p_hsize,(file->get_pos()-p_cpos));
521 //printf("extra: %i\n",p_hsize-(file->get_pos()-p_cpos));
522 file->get_byte_array((uint8_t *)junkbuster, p_hsize - (file->get_pos() - p_cpos));
523 }
524
525 sampnum = p_sampnum;
526 } else {
527
528 uint8_t junkbuster[500];
529 file->get_byte_array((uint8_t *)junkbuster, 20); //14 bytes?
530
531 sampnum = file->get_word();
532 }
533
534 CPSampleManager *sm = CPSampleManager::get_singleton();
535
536 /*SAMPLE!!*/
537
538 for (int j = 0; j < sampnum; j++) {
539
540 if (j > 16) ABORT_LOAD;
541
542 int s_idx = -1;
543 for (int s = 0; s < CPSong::MAX_SAMPLES; s++) {
544
545 if (song->get_sample(s)->get_sample_data().is_null()) {
546 //empty sample!
547 s_idx = s;
548 break;
549 }
550 }
551
552 if (s_idx == -1) ABORT_LOAD;
553 //printf("free sample: %i\n",s_idx);
554
555 CPSample &sample = *song->get_sample(s_idx);
556
557 int sample_size = file->get_dword();
558 int tmp_loop_begin = file->get_dword();
559
560 int tmp_loop_end = file->get_dword();
561
562 sample.set_default_volume(file->get_byte());
563
564 uint8_t ftb = file->get_byte();
565 int8_t *fts = (int8_t *)&ftb;
566 int finetune = *fts;
567 uint32_t flags = file->get_byte();
568
569 if (flags & 16) { // is 16 bits.. at flag 16.. fun :)
570
571 tmp_loop_end /= 2;
572 tmp_loop_begin /= 2;
573 sample_size /= 2;
574 }
575
576 CPSample_ID sample_data = sm->create(flags & 16, false, sample_size);
577
578 sample.set_sample_data(sample_data);
579 sm->set_loop_begin(sample_data, tmp_loop_begin);
580 sm->set_loop_end(sample_data, tmp_loop_end + tmp_loop_begin);
581
582 sm->set_loop_type(sample_data, (flags & 3) ? ((flags & 2) ? CP_LOOP_BIDI : CP_LOOP_FORWARD) : CP_LOOP_NONE);
583
584 sample.set_pan_enabled(true);
585 sample.set_pan(file->get_byte() * 64 / 255);
586 uint8_t noteb = file->get_byte();
587 int8_t *notes = (int8_t *)¬eb;
588 int note_offset = *notes;
589 note_offset += 48;
590 //note_offset+=60;
591
592 //int linear_period=10*12*16*4 - (note_offset)*16*4 - finetune/2;
593 //int freq=(int)(8363*pow(2.0,(double)(6*12*16*4 - linear_period) / (double)(12*16*4)));
594
595 //sm->set_c5_freq( sample_data, freq);
596 sm->set_c5_freq(sample_data, CPTables::get_linear_frequency(CPTables::get_linear_period(note_offset << 1, finetune)));
597 //printf("NOTE %i,fine %i\n",note_offset,finetune);
598
599 char auxb;
600 auxb = file->get_byte(); //reserved?
601 file->get_byte_array((uint8_t *)instrname, 22);
602 sample.set_name(instrname);
603
604 sample_index[j] = s_idx;
605 }
606
607 /*SAMPLE __DATA__!!*/
608
609 for (int j = 0; j < sampnum; j++) {
610
611 if (sample_index[j] == -1) continue;
612
613 CPSample *sample = song->get_sample(sample_index[j]);
614 CPSample_ID sid = sample->get_sample_data();
615
616 sm->lock_data(sid);
617
618 void *dataptr = sm->get_data(sid);
619
620 if (sm->is_16bits(sid)) {
621
622 int16_t old = 0;
623
624 for (int k = 0; k < sm->get_size(sid); k++) {
625
626 int16_t newsample;
627 int16_t sampleval = file->get_word();
628 newsample = sampleval + old;
629 old = newsample;
630
631 ((int16_t *)dataptr)[k] = newsample;
632 //sm->set_data( sid, k, newsample );
633 }
634 } else {
635
636 int8_t old = 0;
637
638 for (int k = 0; k < sm->get_size(sid); k++) {
639
640 int8_t newsample;
641 int8_t sampleval = file->get_byte();
642 newsample = sampleval + old;
643 old = newsample;
644
645 ((int8_t *)dataptr)[k] = newsample;
646
647 //sm->set_data( sid, k, (int16_t)newsample << 8 );
648 }
649 }
650
651 sm->unlock_data(sid);
652 }
653
654 for (int j = 0; j < 96; j++) {
655
656 int val = notenumb[j];
657 if ((val < 0) || (val > 15))
658 continue;
659 else
660 val = sample_index[val];
661 if (val == -1) continue;
662 p_instr->set_sample_number(12 + j, val);
663 }
664
665 return FILE_OK;
666 }
667
load_sample(const char * p_file,CPSample * p_sample)668 CPLoader::Error CPLoader_XM::load_sample(const char *p_file, CPSample *p_sample) {
669
670 return FILE_UNRECOGNIZED;
671 }
672
673 /* Compute CPInstrument Info */
load_instrument(const char * p_file,CPSong * p_song,int p_instr_idx)674 CPLoader::Error CPLoader_XM::load_instrument(const char *p_file, CPSong *p_song, int p_instr_idx) {
675
676 if (file->open(p_file, CPFileAccessWrapper::READ)) return FILE_CANNOT_OPEN;
677 //int i;
678 song = p_song;
679 CPInstrument &instr = *p_song->get_instrument(p_instr_idx);
680 int aux;
681
682 char buffer[500];
683 file->get_byte_array((uint8_t *)buffer, 0x15);
684 buffer[8] = 0;
685 if (buffer[0] != 'E' ||
686 buffer[1] != 'x' ||
687 buffer[2] != 't' ||
688 buffer[3] != 'e' ||
689 buffer[4] != 'n' ||
690 buffer[5] != 'd' ||
691 buffer[6] != 'e' ||
692 buffer[7] != 'd') {
693 file->close();
694 return FILE_UNRECOGNIZED;
695 }
696
697 file->get_byte_array((uint8_t *)buffer, 0x16);
698 buffer[0x16] = 0;
699 instr.set_name(buffer);
700 aux = file->get_byte(); //says ignore ti
701 /*if(aux!=0x1a) { I'm not sure. this is supposed to be ignored...
702
703 file->close();
704 return FILE_UNRECOGNIZED;
705 } */
706
707 file->get_byte_array((uint8_t *)buffer, 0x14); //somethingaboutthename
708 aux = file->get_word(); //version or blahblah
709
710 if (load_instrument_internal(&instr, true, 0, 0)) {
711
712 file->close();
713 return FILE_CORRUPTED;
714 }
715
716 file->close(); //ook, we got it..
717
718 return FILE_OK;
719 }
720
CPLoader_XM(CPFileAccessWrapper * p_file)721 CPLoader_XM::CPLoader_XM(CPFileAccessWrapper *p_file) {
722
723 file = p_file;
724 }
~CPLoader_XM()725 CPLoader_XM::~CPLoader_XM() {
726 }
727