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 *)&noteb;
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