1 /* OpenCP Module Player
2  * copyright (c) 2019-'21 Stian Skjelstad <stian.skjelstad@gmail.com>
3  *
4  * GMDPlay loader for ScreamTracker ][ modules
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 #include "config.h"
22 #include <errno.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include "types.h"
27 #include "boot/plinkman.h"
28 #include "dev/mcp.h"
29 #include "filesel/filesystem.h"
30 #include "gmdplay.h"
31 #include "stuff/err.h"
32 
33 /*
34   Commands are tested against Scream Tracker v2.3 (stores files as v2.21)
35   A Tempo/Speed                     - OK (cmdFineSpeed, cmdSpeed, cmdTempo - OCP has Speed and Tempo in reverse)
36   B Break Pattern and Jump to order - OK (Goto, PreConfigures which order next break will jump to)
37   C Break Pattern                   - OK (cmdBreak)
38   D Volume Slide                    - OK (our wave-device makes ramps, instead of instant volume changes)
39   E Portamento down                 - TODO
40   F Portamento up                   - TODO
41   G Portomento to                   - TODO
42   H Vibrato                         - TODO
43   I Tremor                          - OK (our wave-device makes ramps, instead of instant volume changes
44   J Arpieggo                        - N/A
45   K Portamento + volume slide       - N/A
46   L Vibrato + volume slide          - N/A
47  */
48 
49 static uint16_t tempo_table[256] =
50 {
51 	  10, 1053,  826,  600,  375,  175,    4,    4,    4,    4,    4,    4,    4,    4,    4,    4,
52 	1256, 1176, 1100, 1025,  951,  876,  801,  726,  625,  550,  475,  400,  325,  250,  175,  100,
53 	1255, 1231, 1178, 1151, 1105, 1076, 1027, 1001,  952,  901,  875,  826,  802,  751,  727,  676,
54 	1256, 1256, 1230, 1201, 1178, 1151, 1130, 1101, 1076, 1053, 1027, 1002,  979,  952,  928,  901,
55 	1255, 1255, 1231, 1231, 1201, 1177, 1178, 1152, 1130, 1130, 1105, 1105, 1076, 1053, 1053, 1027,
56 	1255, 1255, 1255, 1231, 1231, 1201, 1201, 1178, 1178, 1178, 1151, 1151, 1130, 1130, 1105, 1105,
57 	1255, 1251, 1251, 1231, 1231, 1225, 1201, 1200, 1178, 1178, 1178, 1151, 1151, 1151, 1130, 1130,
58 	1255, 1255, 1255, 1255, 1231, 1231, 1231, 1231, 1201, 1201, 1201, 1201, 1178, 1177, 1177, 1178,
59 	1256, 1255, 1255, 1255, 1256, 1255, 1231, 1231, 1231, 1231, 1231, 1201, 1201, 1201, 1201, 1201,
60 	1255, 1255, 1255, 1255, 1255, 1255, 1231, 1231, 1231, 1231, 1231, 1201, 1201, 1201, 1201, 1201,
61 	1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231,
62 	1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231,
63 	1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231,
64 	1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231,
65 	1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255,
66 	1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255, 1255,
67 };
68 
69 struct STMPattern
70 {
71 	uint8_t note;
72 	uint8_t instrument;
73 	uint8_t volume;
74 	uint8_t command;
75 	uint8_t parameters;
76 };
77 
putcmd(uint8_t ** p,uint8_t c,uint8_t d)78 static inline void putcmd(uint8_t **p, uint8_t c, uint8_t d)
79 {
80 	*(*p)++=c;
81 	*(*p)++=d;
82 }
83 
_mpLoadSTM(struct gmdmodule * m,struct ocpfilehandle_t * file)84 static int _mpLoadSTM(struct gmdmodule *m, struct ocpfilehandle_t *file)
85 {
86 	unsigned int t,t2,i;
87 	uint8_t orders[128];
88 	int ordersn;
89 	uint32_t smppara[31];
90 	struct gmdpattern *pp;
91 	uint8_t temptrack[2000];
92 
93 	struct __attribute__((packed))
94 	{
95 		char name[20];
96 		char tracker[8];
97 		uint8_t sig, type, maj, min, tempo, pats, gv;
98 		uint8_t reserved[13];
99 	} hdr;
100 
101 	mpReset(m);
102 
103 #ifdef STM_LOAD_DEBUG
104 	fprintf(stderr, "Reading header: %d bytes\n", (int)sizeof(hdr));
105 #endif
106 
107 	if (file->read (file, &hdr, sizeof (hdr)) != sizeof (hdr))
108 	{
109 		fprintf (stderr, "STM: reading header failed: %s\n", strerror (errno));
110 		return errFormStruc;
111 	}
112 
113 	if (hdr.type != 2)
114 	{
115 		fprintf (stderr, "STM: Not a module\n");
116 		return errFormStruc;
117 	}
118 
119 	if (hdr.min <= 10)
120 	{
121 		hdr.gv = 64;
122 	} else if (hdr.gv > 64)
123 	{
124 		hdr.gv = 64;
125 	}
126 
127 	if (hdr.pats>99)
128 	{
129 		fprintf(stderr, "STM: too many patterns\n");
130 		return errFormStruc;
131 	}
132 
133 	if (hdr.pats==0)
134 	{
135 		fprintf(stderr, "STM: no patterns\n");
136 		return errFormStruc;
137 	}
138 
139 	m->patnum=hdr.pats;
140 
141 	memcpy(m->name, hdr.name, 20);
142 	m->name[20]=0;
143 
144 	m->channum = 4;
145 
146 	m->modsampnum=m->sampnum=m->instnum=31;
147 	if (hdr.min < 21)
148 	{
149 		ordersn = 64;
150 	} else {
151 		ordersn = 128;
152 	}
153 	m->tracknum=hdr.pats*(4+1)+1;
154 	m->options=MOD_S3M; /* we have Tremor with 00 parameters etc. */
155 	m->loopord=0;
156 
157 	/* m->options|=MOD_MODPAN; */
158 
159 	if (!mpAllocInstruments(m, m->instnum)||!mpAllocSamples(m, m->sampnum)||!mpAllocModSamples(m, m->modsampnum))
160 	{
161 		fprintf(stderr, "STM: Out of mem?\n");
162 		return errAllocMem;
163 	}
164 
165 	for (i=0; i<31; i++)
166 	{
167 		struct gmdinstrument *ip;
168 		struct gmdsample *sp;
169 		struct sampleinfo *sip;
170 		unsigned int j;
171 
172 		struct __attribute__((packed))
173 		{
174 			char dosname[12];
175 			uint8_t  type;
176 			uint8_t  disk;
177 			uint16_t sampptr;
178 			uint16_t length;
179 			uint16_t loopstart;
180 			uint16_t loopend;
181 			uint8_t volume;
182 			char d1[1];
183 			uint16_t c3spd;
184 			char d2[6];
185 		} sins;
186 
187 #ifdef STM_LOAD_DEBUG
188 		fprintf(stderr, "Reading %d bytes of instrument %02d header (@0x%08x)\n", (int)sizeof(sins), i + 1, (int)file->getpos (file));
189 #endif
190 		if (file->read (file, &sins, sizeof (sins)) != sizeof (sins))
191 		{
192 			fprintf (stderr, "STM: reading instrument %02d header failed: %s\n", i+1, strerror (errno));
193 			return errFileRead;
194 		}
195 
196 		sins.sampptr   = uint16_little (sins.sampptr);
197 		sins.length    = uint16_little (sins.length);
198 		sins.loopstart = uint16_little (sins.loopstart);
199 		sins.loopend   = uint16_little (sins.loopend);
200 		sins.c3spd     = uint16_little (sins.c3spd);
201 
202 		smppara[i]=sins.sampptr<<4;
203 
204 		ip=&m->instruments[i];
205 		sp=&m->modsamples[i];
206 		sip=&m->samples[i];
207 
208 		ip->name[0]=0;
209 		if (!sins.length)
210 			continue;
211 		if (sins.length > 64000)
212 		{ /* limitiation of Scream Tracker series */
213 			sins.length = 64000;
214 		}
215 		if (sins.type!=0)
216 		{
217 			fprintf (stderr, "STM: warning, non-PCM type sample\n");
218 		}
219 
220 		sp->handle=i;
221 		for (j=0; j<128; j++)
222 			ip->samples[j]=i;
223 		memcpy(sp->name, sins.dosname, 12);
224 		sp->name[12]=0;
225 		sp->normnote=-mcpGetNote8363(sins.c3spd); // TODO, this seems off
226 		sp->stdvol=(sins.volume>0x3F)?0xFF:(sins.volume<<2);
227 		sp->stdpan=-1;
228 		sp->opt=0;
229 
230 		if ((sins.loopstart >= sins.loopend) || (sins.loopstart >= sins.length))
231 		{
232 			sins.loopstart = 0;
233 			sins.loopend = 65535;
234 		} else if ((sins.loopend > sins.length) && (sins.loopend != 65535))
235 		{
236 			sins.loopend = sins.length;
237 		}
238 
239 		sip->length=sins.length;
240 		sip->loopstart=sins.loopstart;
241 		sip->loopend=sins.loopend;
242 		sip->samprate=8363; // TODO, this seems off
243 		sip->type=0; //mcpSampUnsigned;
244 
245 		if (sins.loopstart || (sins.loopend != 65535))
246 		{
247 			sip->type |= mcpSampLoop;
248 		}
249 	}
250 
251 
252 #ifdef STM_LOAD_DEBUG
253 	fprintf(stderr, "Reading pattern orders, %d bytes\n", (int)m->patnum);
254 #endif
255 	if (file->read (file, orders, ordersn) != ordersn)
256 	{
257 		fprintf (stderr, "STM: reading orders failed: %s\n", strerror (errno));
258 		return errFileRead;
259 	}
260 
261 #if 0
262 	for (t=m->patnum-1; (signed)t>=0; t--)
263 	{
264 		if (orders[t]<254)
265 			break;
266 		m->patnum--;
267 	}
268 #endif
269 
270 	t2=0;
271 	for (t=0; t<ordersn; t++)
272 	{
273 		if (orders[t] == 255) /* End of song */
274 		{
275 			break;
276 		}
277 		if (orders[t]<hdr.pats) /* 99 = Ignore this entry */
278 		{
279 			t2 = t+1;
280 		}
281 	}
282 
283 	m->endord = m->ordnum = t2;
284 	if (!m->ordnum)
285 	{
286 		fprintf(stderr, "STM: No orders\n");
287 		return errFormMiss;
288 	}
289 
290 	if (!mpAllocTracks(m, m->tracknum)||!mpAllocPatterns(m, m->patnum)||!mpAllocOrders(m, m->ordnum))
291 	{
292 		fprintf(stderr, "STM: Out of mem?\n");
293 		return errAllocMem;
294 	}
295 
296 	for (t=0; t<t2; t++)
297 	{
298 		if (orders[t] == 255) /* End of song */
299 		{
300 			break;
301 		}
302 		if (orders[t]<hdr.pats) /* 99 = Ignore this entry */
303 		{
304 			/* does jump hit correct, if we have a hole in the series now? */
305 			m->orders[t]=orders[t];
306 		} else {
307 			m->orders[t]=0xffff;
308 		}
309 	}
310 
311 	for (pp=m->patterns, t=0; t<m->patnum; pp++, t++)
312 	{
313 		pp->patlen=64;
314 		for (i=0; i<m->channum; i++)
315 		{
316 			pp->tracks[i]=t*(m->channum+1)+i;
317 			pp->gtrack=t*(m->channum+1)+m->channum;
318 		}
319 	}
320 
321 	for (t=0; t<hdr.pats; t++)
322 	{
323 		unsigned int row;
324 		unsigned int j;
325 		/* we need to load the full-pattern, since we need to have data sorted by [channel][row], not [row][channel] */
326 		struct STMPattern pat[64][4];
327 
328 		for (row=0; row < 64; row++)
329 		{
330 			for (j=0; j<4; j++)
331 			{
332 				if (ocpfilehandle_read_uint8 (file, &pat[row][j].note))
333 				{
334 					fprintf (stderr, "STM: reading pattern data failed: %s\n", strerror (errno));
335 					return errFileRead;
336 				}
337 				switch (pat[row][j].note)
338 				{
339 					case 0xfb:
340 						pat[row][j].note = 0;    pat[row][j].instrument =  0; pat[row][j].volume =  0; pat[row][j].command = 0; pat[row][j].parameters = 0; break;
341 					case 0xfc:
342 						pat[row][j].note = 255;  pat[row][j].instrument = 32; pat[row][j].volume = 65; pat[row][j].command = 0; pat[row][j].parameters = 0; break;
343 					case 0xfd:
344 						pat[row][j].note = 0xfe; pat[row][j].instrument = 32; pat[row][j].volume = 65; pat[row][j].command = 0; pat[row][j].parameters = 0; break;
345 					default:
346 					{
347 						uint8_t insvol, volcmd;
348 						if (ocpfilehandle_read_uint8 (file, &insvol))
349 						{
350 							fprintf (stderr, "STM: reading pattern data failed: %s\n", strerror (errno));
351 							return errFileRead;
352 						}
353 
354 						if (ocpfilehandle_read_uint8 (file, &volcmd))
355 						{
356 							fprintf (stderr, "STM: reading pattern data failed: %s\n", strerror (errno));
357 							return errFileRead;
358 						}
359 
360 						if (ocpfilehandle_read_uint8 (file, &pat[row][j].parameters))
361 						{
362 							fprintf (stderr, "STM: reading pattern data failed: %s\n", strerror (errno));
363 							return errFileRead;
364 						}
365 
366 						pat[row][j].instrument = insvol >> 3;
367 						pat[row][j].volume = (insvol & 0x07) | ((volcmd & 0xf0) >> 1);
368 						pat[row][j].command = volcmd & 0x0f;
369 					}
370 				}
371 			}
372 		}
373 
374 		for (j=0; j<m->channum; j++)
375 		{
376 			//char setorgpan=t==orders[0];
377 			struct gmdtrack *trk;
378 			uint16_t len;
379 			uint8_t *tp, *cp;
380 
381 			tp=temptrack;
382 			cp=tp+2;
383 
384 			for (row = 0; row < 64; row++)
385 			{
386 				int nte=-1, vol=-1, ins=-1;
387 
388 				if (!row&&(t==orders[0]))
389 				{
390 					putcmd(&cp, cmdVolVibratoSetWave, 0x10);
391 					putcmd(&cp, cmdPitchVibratoSetWave, 0x10);
392 				}
393 
394 				if (pat[row][j].note < 254)
395 				{
396 					// TonePortemento behaves differently on STM....
397 					//if (pat[row][j].command != 7)
398 					nte=(pat[row][j].note>>4)*12+(pat[row][j].note&0x0F)+36;
399 				} else if (pat[row][j].note == 254)
400 				{
401 					putcmd(&cp, cmdNoteCut, 0);
402 				}
403 
404 				if (pat[row][j].volume <= 64)
405 				{
406 					vol = (pat[row][j].volume > 0x3f)?0xFF:(pat[row][j].volume<<2);
407 				}
408 				if (pat[row][j].instrument)
409 				{
410 					ins = pat[row][j].instrument - 1;
411 				}
412 
413 				if (pat[row][j].command == 7) /* cmdPitchSlideToNote, so flag this note as a portamento-target instead of a note-on event */
414 				{
415 					nte |= 0x80;
416 				}
417 
418 				if ((ins!=-1)||(nte!=-1)||(vol!=-1))
419 				{
420 					uint8_t *act=cp;
421 					*cp++=cmdPlayNote;
422 					if (ins!=-1)
423 					{
424 						*act|=cmdPlayIns;
425 						*cp++=ins;
426 					}
427 					if (nte!=-1)
428 					{
429 						*act|=cmdPlayNte;
430 						*cp++=nte;
431 					}
432 					if (vol!=-1)
433 					{
434 						*act|=cmdPlayVol;
435 						*cp++=vol;
436 					}
437 				}
438 
439 				switch (pat[row][j].command)
440 				{
441 					case 0: /* . */
442 					case 1: /* A - Speed, global */
443 					case 2: /* B - Position Jump, global */
444 					case 3: /* C - Pattern Break, global */
445 						break;
446 					case 4: /* D - VolumeSlide */
447 						if (pat[row][j].parameters & 0x0f)
448 						{
449 							putcmd(&cp, cmdVolSlideDown, (pat[row][j].parameters&0x0f)<<2);
450 						} else {
451 							putcmd(&cp, cmdVolSlideUp, (pat[row][j].parameters>>4)<<2);
452 						}
453 						break;
454 					case 5: /* E - PortamentoDown */
455 						putcmd(&cp, cmdRowPitchSlideDown, pat[row][j].parameters);
456 						break;
457 					case 6: /* F - PortamentoUp */
458 						putcmd(&cp, cmdRowPitchSlideUp, pat[row][j].parameters);
459 						break;
460 					case 7: /* G - TonePortamento */
461 						putcmd(&cp, cmdPitchSlideToNote, pat[row][j].parameters);
462 						break;
463 					case 8: /* H - Vibrato */
464 						putcmd(&cp, cmdPitchVibrato, pat[row][j].parameters);
465 						break;
466 					case 9: /* I - Tremor */
467 						putcmd(&cp, cmdTremor, pat[row][j].parameters);
468 						break;
469 					case 10: /* J - Arpeggio, not implemented in Scream Tracker 2 */
470 					case 11: /* K - Vibra, VolumeSlide, not implemented in Scream Tracker 2 */
471 					case 12: /* L - */
472 					case 13: /* M - */
473 					case 14: /* N - */
474 					case 15: /* O - Tone, VolumeSlide, not implemented in Scream Tracker 2*/
475 						break;
476 				}
477 
478 				if (cp!=(tp+2))
479 				{
480 					tp[0]=row;
481 					tp[1]=cp-tp-2;
482 					tp=cp;
483 					cp=tp+2;
484 				}
485 			}
486 
487 			trk=&m->tracks[t*(m->channum+1)+j];
488 			len=tp-temptrack;
489 
490 			if (!len)
491 			{
492 				trk->ptr=trk->end=0;
493 			} else {
494 				trk->ptr=malloc(sizeof(uint8_t)*len);
495 				trk->end=trk->ptr+len;
496 				if (!trk->ptr)
497 				{
498 					fprintf(stderr, "STM: Out of mem (4) ?\n");
499 					return errAllocMem;
500 				}
501 				memcpy(trk->ptr, temptrack, len);
502 			}
503 		}
504 
505 		do {
506 			uint8_t *cp, *tp;
507 			struct gmdtrack *trk;
508 			uint16_t len;
509 
510 			tp=temptrack;
511 			cp=tp+2;
512 
513 			if (t==orders[0])
514 			{
515 				int p = hdr.tempo;
516 
517 				if (hdr.min < 21)
518 				{
519 					p = ((p/10)<<4) | (p % 10);
520 				}
521 
522 				if (!p)
523 				{
524 					p = 0x60;
525 				}
526 
527 				putcmd(&cp, cmdTempo, p>>4);
528 
529 				putcmd(&cp, cmdSpeed, tempo_table[p] / 10);
530 				putcmd(&cp, cmdFineSpeed, tempo_table[p]%10);
531 
532 				if (hdr.gv!=0x40)
533 				{
534 					putcmd(&cp, cmdGlobVol, hdr.gv<<2);
535 				}
536 			}
537 
538 			for (row=0; row < 64; row++)
539 			{
540 				for (j=0; j<m->channum; j++)
541 				{
542 					switch (pat[row][j].command)
543 					{
544 						case 0: /* . */
545 							break;
546 						case 1: /* A - Speed, global */
547 							{
548 								int p = pat[row][j].parameters;
549 								if (hdr.min < 21)
550 								{
551 									p = ((p/10)<<4) | (p % 10);
552 								}
553 
554 								if (p)
555 								{
556 									putcmd(&cp, cmdTempo, p>>4);
557 
558 									putcmd(&cp, cmdSpeed, tempo_table[p] / 10);
559 									putcmd(&cp, cmdFineSpeed, tempo_table[p]%10);
560 								}
561 							}
562 							break;
563 						case 2: /* B - Position Jump, global */
564 							putcmd(&cp, cmdGoto, pat[row][j].parameters);
565 							break;
566 						case 3: /* C - Pattern Break, global */
567 							putcmd(&cp, cmdBreak, pat[row][j].parameters);
568 							break;
569 						case 4: /* D - VolumeSlide */
570 						case 5: /* E - PortamentoDown */
571 						case 6: /* F - PortamentoUp */
572 						case 7: /* G - TonePortamento */
573 						case 8: /* H - Vibrato */
574 						case 9: /* I - Tremor */
575 						case 10: /* J - Arpeggio, not implemented in Scream Tracker 2 */
576 						case 11: /* K - Vibra, VolumeSlide, not implemented in Scream Tracker 2 */
577 						case 12: /* L - */
578 						case 13: /* M - */
579 						case 14: /* N - */
580 						case 15: /* O - Tone, VolumeSlide, not implemented in Scream Tracker 2*/
581 							break;
582 					}
583 				}
584 
585 				if (cp!=(tp+2))
586 				{
587 					tp[0]=row;
588 					tp[1]=cp-tp-2;
589 					tp=cp;
590 					cp=tp+2;
591 				}
592 			}
593 
594 			trk=&m->tracks[t*(m->channum+1)+m->channum];
595 			len=tp-temptrack;
596 
597 			if (!len)
598 			{
599 				trk->ptr=trk->end=0;
600 			} else {
601 				trk->ptr=malloc(sizeof(uint8_t)*len);
602 				trk->end=trk->ptr+len;
603 				if (!trk->ptr)
604 				{
605 					fprintf(stderr, "STM: Out of mem (6)?\n");
606 					return errAllocMem;
607 				}
608 				memcpy(trk->ptr, temptrack, len);
609 			}
610 		} while (0);
611 	}
612 
613 	for (i=0; i<m->instnum; i++)
614 	{
615 		struct gmdsample *sp=&m->modsamples[i];
616 		struct sampleinfo *sip=&m->samples[i];
617 		int l;
618 		if (sp->handle==0xFFFF)
619 			continue;
620 
621 		l=sip->length;
622 #ifdef STM_LOAD_DEBUG
623 		fprintf (stderr, "Instrument %d sample, seeking to 0x%08x\n", i+1, smppara[i]);
624 #endif
625 		file->seek_set (file, smppara[i]);
626 
627 		sip->ptr=malloc(sizeof(int8_t)*(l+16));
628 		if (!sip->ptr)
629 		{
630 			fprintf(stderr, "STM: Out of mem (7)?\n");
631 			return errAllocMem;
632 		}
633 		if (file->read (file, sip->ptr, l) != l)
634 		{
635 			fprintf(stderr, __FILE__ ": warning, read failed #8\n");
636 		}
637 	}
638 
639 	return errOk;
640 }
641 
642 struct gmdloadstruct mpLoadSTM = { _mpLoadSTM };
643 
644 struct linkinfostruct dllextinfo = {.name = "gmdlstm", .desc = "OpenCP Module Loader: *.STM (c) 2019-'21, Stian Skjelstad", .ver = DLLVERSION, .size = 0};
645