1 /* OpenCP Module Player
2  * copyright (c) '94-'10 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
3  * copyright (c) '04-'20 Stian Skjelstad <stian.skjelstad@gmail.com>
4  *
5  * ITPlayer interface routines
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  * revision history: (please note changes here)
22  *  -nb980510   Niklas Beisert <nbeisert@physik.tu-muenchen.de>
23  *    -first release
24  *  -kb980717   Tammo Hinrichs <kb@nwn.de>
25  *    -added many many things to provide channel display and stuff
26  *    -removed some bugs which caused crashing in some situations
27  *  -ss040709   Stian Skjelstad <stian@nixia.no>
28  *    -use compatible timing instead of cputime/clock()
29  */
30 
31 #include "config.h"
32 #include <time.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include "types.h"
37 #include "boot/plinkman.h"
38 #include "boot/psetting.h"
39 #include "cpiface/cpiface.h"
40 #include "dev/deviwave.h"
41 #include "dev/mcp.h"
42 #include "filesel/filesystem.h"
43 #include "filesel/mdb.h"
44 #include "filesel/pfilesel.h"
45 #include "itplay.h"
46 #include "stuff/compat.h"
47 #include "stuff/err.h"
48 #include "stuff/poutput.h"
49 
50 #define _MAX_FNAME 8
51 #define _MAX_EXT 4
52 
53 __attribute__ ((visibility ("internal"))) struct itplayer itplayer = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
54 static struct it_module mod = {{0},0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,{0},{0},0,0,0,0,0};
55 
56 static struct it_instrument *insts;
57 static struct it_sample *samps;
58 
59 
60 static const char *modname;
61 static const char *composer;
62 
63 static char currentmodname[_MAX_FNAME+1];
64 static char currentmodext[_MAX_EXT+1];
65 static time_t starttime;
66 static time_t pausetime;
67 
68 
69 void itpInstClear();
70 
itpProcessKey(uint16_t key)71 static int itpProcessKey(uint16_t key)
72 {
73 	int row;
74 	int pat, p;
75 
76 	switch (key)
77 	{
78 		case KEY_ALT_K:
79 			cpiKeyHelp('p', "Start/stop pause with fade");
80 			cpiKeyHelp('P', "Start/stop pause with fade");
81 			cpiKeyHelp(KEY_CTRL_P, "Start/stop pause");
82 			cpiKeyHelp('<', "Jump back (big)");
83 			cpiKeyHelp(KEY_CTRL_LEFT, "Jump back (big)");
84 			cpiKeyHelp('>', "Jump forward (big)");
85 			cpiKeyHelp(KEY_CTRL_RIGHT, "Jump forward (big)");
86 			cpiKeyHelp(KEY_CTRL_UP, "Jump back (small)");
87 			cpiKeyHelp(KEY_CTRL_DOWN, "Jump forward (small)");
88 			mcpSetProcessKey(key);
89 			if (mcpProcessKey)
90 				mcpProcessKey(key);
91 			return 0;
92 		case 'p': case 'P': case KEY_CTRL_P:
93 			if (plPause)
94 				starttime=starttime+dos_clock()-pausetime;
95 			else
96 				pausetime=dos_clock();
97 			mcpSet(-1, mcpMasterPause, plPause^=1);
98 			plChanChanged=1;
99 			break;
100 /*
101 		case 0x7700: //ctrl-home TODO keys
102 			itpInstClear();
103 			itplayer.setpos(0, 0);
104 			if (plPause)
105 				starttime=pausetime;
106 			else
107 				starttime=dos_clock();
108 			break;
109 */
110 		case '<':
111 		case KEY_CTRL_LEFT:
112 		/* case 0x7300: //ctrl-left */
113 			p=getpos(&itplayer);
114 			pat=p>>16;
115 			setpos(&itplayer, pat-1, 0);
116 			break;
117 		case '>':
118 		case KEY_CTRL_RIGHT:
119 		/* case 0x7400: //ctrl-right */
120 			p=getpos(&itplayer);
121 			pat=p>>16;
122 			setpos(&itplayer, pat+1, 0);
123 			break;
124 		case KEY_CTRL_UP:
125 		/* case 0x8D00: //ctrl-up */
126 			p=getpos(&itplayer);
127 			pat=p>>16;
128 			row=(p>>8)&0xFF;
129 			setpos(&itplayer, pat, row-8);
130 			break;
131 		case KEY_CTRL_DOWN:
132 		/* case 0x9100: //ctrl-down */
133 			p=getpos(&itplayer);
134 			pat=p>>16;
135 			row=(p>>8)&0xFF;
136 			setpos(&itplayer, pat, row+8);
137 			break;
138 		default:
139 			if (mcpSetProcessKey(key))
140 				return 1;
141 			if (mcpProcessKey)
142 			{
143 				int ret=mcpProcessKey(key);
144 				if (ret==2)
145 					cpiResetScreen();
146 				if (ret)
147 					return 1;
148 			}
149 	}
150 	return 1;
151 }
152 
itpLooped(void)153 static int itpLooped(void)
154 {
155 	return !fsLoopMods&&getloop(&itplayer);
156 }
157 
itpIdle(void)158 static void itpIdle(void)
159 {
160 	setloop(&itplayer, fsLoopMods);
161 	if (mcpIdle)
162 		mcpIdle();
163 }
164 
itpDrawGStrings(uint16_t (* buf)[CONSOLE_MAX_X])165 static void itpDrawGStrings(uint16_t (*buf)[CONSOLE_MAX_X])
166 {
167 	int pos=getrealpos(&itplayer)>>8;
168 	int gvol, bpm, tmp, gs;
169 	long tim;
170 
171 	mcpDrawGStrings(buf);
172 
173 	getglobinfo(&itplayer, &tmp, &bpm, &gvol, &gs);
174 
175 	if (plPause)
176 		tim=(pausetime-starttime)/DOS_CLK_TCK;
177 	else
178 		tim=(dos_clock()-starttime)/DOS_CLK_TCK;
179 
180 	if (plScrWidth<128)
181 	{
182 		memset(buf[0]+80, 0, (plScrWidth-80)*sizeof(uint16_t));
183 		memset(buf[1]+80, 0, (plScrWidth-80)*sizeof(uint16_t));
184 		memset(buf[2]+80, 0, (plScrWidth-80)*sizeof(uint16_t));
185 
186 		writestring(buf[1],  0, 0x09, " row: ../..  ord: .../...  speed: ..  bpm: ...  gvol: ..\xfa ", 58);
187 		writenum(buf[1],  6, 0x0F, pos&0xFF, 16, 2, 0);
188 		writenum(buf[1],  9, 0x0F, mod.patlens[mod.orders[pos>>8]]-1, 16, 2, 0);
189 		writenum(buf[1], 18, 0x0F, pos>>8, 16, 3, 0);
190 		writenum(buf[1], 22, 0x0F, mod.nord-1, 16, 3, 0);
191 		writenum(buf[1], 34, 0x0F, tmp, 16, 2, 1);
192 		writenum(buf[1], 43, 0x0F, bpm, 10, 3, 1);
193 		writenum(buf[1], 54, 0x0F, gvol, 16, 2, 0);
194 		writestring(buf[1], 56, 0x0F, (gs==ifxGVSUp)?"\x18":(gs==ifxGVSDown)?"\x19":" ", 1);
195 		writestring(buf[2],  0, 0x09, " module \xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa.\xfa\xfa\xfa: ...............................               time: ..:.. ", 80);
196 		writestring(buf[2],  8, 0x0F, currentmodname, _MAX_FNAME);
197 		writestring(buf[2], 16, 0x0F, currentmodext, _MAX_EXT);
198 		writestring(buf[2], 22, 0x0F, modname, 31);
199 		if (plPause)
200 			writestring(buf[2], 58, 0x0C, "paused", 6);
201 		writenum(buf[2], 74, 0x0F, (tim/60)%60, 10, 2, 1);
202 		writestring(buf[2], 76, 0x0F, ":", 1);
203 		writenum(buf[2], 77, 0x0F, tim%60, 10, 2, 0);
204 	} else {
205 		int i;
206 		int nch=0;
207 
208 		memset(buf[0]+128, 0, (plScrWidth-128)*sizeof(uint16_t));
209 		memset(buf[1]+128, 0, (plScrWidth-128)*sizeof(uint16_t));
210 		memset(buf[2]+128, 0, (plScrWidth-128)*sizeof(uint16_t));
211 
212 		writestring(buf[1],  0, 0x09, "    row: ../..  order: .../...   speed: ..  tempo: ...   gvol: ..\xfa  chan: ../..", 81);
213 		writenum(buf[1],  9, 0x0F, pos&0xFF, 16, 2, 0);
214 		writenum(buf[1], 12, 0x0F, mod.patlens[mod.orders[pos>>8]]-1, 16, 2, 0);
215 		writenum(buf[1], 23, 0x0F, pos>>8, 16, 3, 0);
216 		writenum(buf[1], 27, 0x0F, mod.nord-1, 16, 3, 0);
217 		writenum(buf[1], 40, 0x0F, tmp, 16, 2, 1);
218 		writenum(buf[1], 51, 0x0F, bpm, 10, 3, 1);
219 		writenum(buf[1], 63, 0x0F, gvol, 16, 2, 0);
220 		writestring(buf[1], 65, 0x0F, (gs==ifxGVSUp)?"\x18":(gs==ifxGVSDown)?"\x19":" ", 1);
221 		for (i=0; i<plNPChan; i++)
222 			if (mcpGet(i, mcpCStatus))
223 				nch++;
224 		writenum(buf[1], 74, 0x0F, nch, 16, 2, 0);
225 		writenum(buf[1], 77, 0x0F, plNPChan, 16, 2, 0);
226 		writestring(buf[2],  0, 0x09, "    module \xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa.\xfa\xfa\xfa: ...............................  composer: ...............................                  time: ..:..    ", 132);
227 		writestring(buf[2], 11, 0x0F, currentmodname, _MAX_FNAME);
228 		writestring(buf[2], 19, 0x0F, currentmodext, 4);
229 		writestring(buf[2], 25, 0x0F, modname, 31);
230 		writestring(buf[2], 68, 0x0F, composer, 31);
231 		if (plPause)
232 			writestring(buf[2], 100, 0x0C, "playback paused", 15);
233 		writenum(buf[2], 123, 0x0F, (tim/60)%60, 10, 2, 1);
234 		writestring(buf[2], 125, 0x0F, ":", 1);
235 		writenum(buf[2], 126, 0x0F, tim%60, 10, 2, 0);
236 	}
237 }
238 
itpCloseFile(void)239 static void itpCloseFile(void)
240 {
241 	stop(&itplayer);
242 	mcpSet(-1, mcpGRestrict, 0);
243 	it_free(&mod);
244 }
245 
246 /**********************************************************************/
247 
itpMarkInsSamp(uint8_t * ins,uint8_t * smp)248 static void itpMarkInsSamp(uint8_t *ins, uint8_t *smp)
249 {
250 	int i;
251 	for (i=0; i<plNLChan; i++)
252 	{
253 		int j;
254 		if (plMuteCh[i])
255 			continue;
256 		for (j=0; j<plNLChan; j++)
257 		{
258 			int lc, in, sm;
259 			if (!chanactive(&itplayer, j, &lc))
260 				continue;
261 			if (lc!=i) /* unrolled if() since left<->right order varies - stian */
262 				continue;
263 			in=getchanins(&itplayer, j);
264 			sm=getchansamp(&itplayer, j);
265 			ins[in-1]=((plSelCh==i)||(ins[in-1]==3))?3:2;
266 			smp[sm]=((plSelCh==i)||(smp[sm]==3))?3:2;
267 		}
268 	}
269 }
270 
271 /************************************************************************/
272 
logvolbar(int * l,int * r)273 static void logvolbar(int *l, int *r)
274 {
275 	(*l)*=2;
276 	(*r)*=2;
277 	if ((*l)>32)
278 		(*l)=32+(((*l)-32)>>1);
279 	if ((*l)>48)
280 		(*l)=48+(((*l)-48)>>1);
281 	if ((*l)>56)
282 		(*l)=56+(((*l)-56)>>1);
283 	if ((*l)>64)
284 		(*l)=64;
285 	if ((*r)>32)
286 		(*r)=32+(((*r)-32)>>1);
287 	if ((*r)>48)
288 		(*r)=48+(((*r)-48)>>1);
289 	if ((*r)>56)
290 		(*r)=56+(((*r)-56)>>1);
291 	if ((*r)>64)
292 		(*r)=64;
293 }
294 
drawvolbar(uint16_t * buf,int i,uint8_t st)295 static void drawvolbar(uint16_t *buf, int i, uint8_t st)
296 {
297 	int l,r;
298 	itplayer_getrealvol(&itplayer, i, &l, &r);
299 	logvolbar(&l, &r);
300 
301 	l=(l+4)>>3;
302 	r=(r+4)>>3;
303 	if (plPause)
304 		l=r=0;
305 	if (st)
306 	{
307 		writestring(buf, 8-l, 0x08, "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe", l);
308 		writestring(buf, 9, 0x08, "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe", r);
309 	} else {
310 		uint16_t left[] =  {0x0ffe, 0x0bfe, 0x0bfe, 0x09fe, 0x09fe, 0x01fe, 0x01fe, 0x01fe};
311 		uint16_t right[] = {0x01fe, 0x01fe, 0x01fe, 0x09fe, 0x09fe, 0x0bfe, 0x0bfe, 0x0ffe};
312 		writestringattr(buf, 8-l, left+8-l, l);
313 		writestringattr(buf, 9, right, r);
314 	}
315 }
316 
drawlongvolbar(uint16_t * buf,int i,uint8_t st)317 static void drawlongvolbar(uint16_t *buf, int i, uint8_t st)
318 {
319 	int l,r;
320 	itplayer_getrealvol(&itplayer, i, &l, &r);
321 	logvolbar(&l, &r);
322 	l=(l+2)>>2;
323 	r=(r+2)>>2;
324 	if (plPause)
325 		l=r=0;
326 	if (st)
327 	{
328 		writestring(buf, 16-l, 0x08, "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe", l);
329 		writestring(buf, 17, 0x08, "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe", r);
330 	} else {
331 		uint16_t left[] =  {0x0ffe, 0x0ffe, 0x0bfe, 0x0bfe, 0x0bfe, 0x0bfe, 0x09fe, 0x09fe, 0x09fe, 0x09fe, 0x01fe, 0x01fe, 0x01fe, 0x01fe, 0x01fe, 0x01fe};
332 		uint16_t right[] = {0x01fe, 0x01fe, 0x01fe, 0x01fe, 0x01fe, 0x01fe, 0x09fe, 0x09fe, 0x09fe, 0x09fe, 0x0bfe, 0x0bfe, 0x0bfe, 0x0bfe, 0x0ffe, 0x0ffe};
333 		writestringattr(buf, 16-l, left+16-l, l);
334 		writestringattr(buf, 17, right, r);
335 	}
336 }
337 
338 static char *fxstr3[]={0,"vl\x18","vl\x19","fv\x18","fv\x19","pt\x18",
339                        "pt\x19","pt\x0d","fp\x18","fp\x19","pn\x1a","pn\x1b",
340                        "tre", "trr","vib","arp","cut","ret","ofs","eps",
341                        "del", "cv\x18", "cv\x19", "fc\x18", "fc\x19","p-c",
342                        "p-o", "p-f", "ve0", "ve1", "pe0", "pe1", "fe0",
343                        "fe1", "pbr"
344                       };
345 
346 static char *fxstr6[]={0, "volsl\x18","volsl\x19","fvols\x18","fvols\x19",
347                        "porta\x18","porta\x19","porta\x0d","fport\x18",
348                        "fport\x19","pansl\x1a","pansl\x1b","tremol","tremor",
349                        "vibrat","arpegg"," \x0e""cut ","retrig","offset",
350                        "envpos","delay\x0d", "chvol\x18", "chvol\x19",
351                        "fchvl\x18", "fchvl\x19", "past-C", "past-O",
352                        "past-F", "venv:0", "venv:1", "penv:0", "penv:1",
353                        "fenv:0", "fenv:1", "panbrl"
354                       };
355 
356 static char *fxstr12[]={0, "volumeslide\x18","volumeslide\x19",
357                         "finevolslid\x18","finevolslid\x19","portamento \x18",
358                         "portamento \x19","porta to \x0d  ","fine porta \x18",
359                         "fine porta \x19","pan slide \x1a ","pan slide \x1b ",
360                         "tremolo     ","tremor      ","vibrato     ",
361                         "arpeggio    ","note cut    ","note retrig ",
362                         "sampleoffset","set env pos ","note delay  ",
363                         "chanvolslid\x18","chanvolslid\x19",
364                         "finechvolsl\x18","finechvolsl\x19", "past cut",
365                         "past off","past fade","vol env off","vol env on",
366                         "pan env off", "pan env on", "pitchenv off",
367                         "pitchenv on", "panbrello"
368                        };
369 
370 
drawchannel(uint16_t * buf,int len,int i)371 static void drawchannel(uint16_t *buf, int len, int i)
372 {
373 	uint8_t st=plMuteCh[i];
374 
375 	uint8_t tcol=st?0x08:0x0F;
376 	uint8_t tcold=st?0x08:0x07;
377 	uint8_t tcolr=st?0x08:0x0B;
378 
379 	int av;
380 
381 	struct it_chaninfo ci;
382 
383 	char *fxstr;
384 
385 	switch (len)
386 	{
387 		case 36:
388 			writestring(buf, 0, tcold, " \xfa\xfa -- --- -- --- \xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa \xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa ", 36);
389 			break;
390 		case 62:
391 			writestring(buf, 0, tcold, " \xfa\xfa                      ---\xfa --\xfa -\xfa ------ \xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa \xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa ", 62);
392 			break;
393 		case 128:
394 			writestring(buf,  0, tcold, " \xfa\xfa                             \xb3                   \xb3    \xb3   \xb3  \xb3            \xb3  \xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa \xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa", 128);
395 			break;
396 		case 76:
397 			writestring(buf,  0, tcold, " \xfa\xfa                             \xb3    \xb3   \xb3  \xb3            \xb3 \xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa \xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa", 76);
398 			break;
399 		case 44:
400 			writestring(buf, 0, tcold, " \xfa\xfa -- ---\xfa --\xfa -\xfa ------ \xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa \xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa ", 44);
401 			break;
402 	}
403 
404 	av=getchanalloc(&itplayer, i);
405 	if (av)
406 		writenum(buf, 1, tcold, av, 16, 2, 0);
407 
408 	if (!lchanactive(&itplayer, i))
409 		return;
410 
411 	getchaninfo(&itplayer, i, &ci);
412 
413 	switch (len)
414 	{
415 		case 36:
416 			writenum(buf,  4, tcol, ci.ins, 16, 2, 0);
417 			writestring(buf,  7, ci.notehit?tcolr:tcol, plNoteStr[ci.note], 3);
418 			writenum(buf, 11, tcol, ci.vol, 16, 2, 0);
419 			fxstr=fxstr3[ci.fx];
420 			if (fxstr)
421 				writestring(buf, 14, tcol, fxstr, 3);
422 			drawvolbar(buf+18, i, st);
423 			break;
424 		case 62:
425 			if (ci.ins)
426 			{
427 				if (*insts[ci.ins-1].name)
428 					writestring(buf,  4, tcol, insts[ci.ins-1].name, 19);
429 				else
430 				{
431 					writestring(buf,  4, 0x08, "(  )", 4);
432 					writenum(buf,  5, 0x08, ci.ins, 16, 2, 0);
433 				}
434 			}
435 			writestring(buf, 25, ci.notehit?tcolr:tcol, plNoteStr[ci.note], 3);
436 			writestring(buf, 28, tcol, ci.pitchslide ? &" \x18\x19\x0D\x18\x19\x0D"[ci.pitchslide] : &" ~\xf0"[ci.pitchfx], 1);
437 			writenum(buf, 30, tcol, ci.vol, 16, 2, 0);
438 			writestring(buf, 32, tcol, ci.volslide ? &" \x18\x19\x18\x19"[ci.volslide] : &" ~"[ci.volfx], 1);
439 			writestring(buf, 34, tcol, &"L123456MM9ABCDERS"[ci.pan], 1);
440 			writestring(buf, 35, tcol, &" \x1A\x1B"[ci.panslide], 1);
441 			fxstr=fxstr6[ci.fx];
442 			if (fxstr)
443 				writestring(buf, 37, tcol, fxstr, 6);
444 			drawvolbar(buf+44, i, st);
445 			break;
446 		case 76:
447 			if (ci.ins)
448 			{
449 				if (*insts[ci.ins-1].name)
450 					writestring(buf,  4, tcol, insts[ci.ins-1].name, 28);
451 				else
452 				{
453 					writestring(buf,  4, 0x08, "(  )", 4);
454 					writenum(buf,  5, 0x08, ci.ins, 16, 2, 0);
455 				}
456 			}
457 			writestring(buf, 33, ci.notehit?tcolr:tcol, plNoteStr[ci.note], 3);
458 			writestring(buf, 36, tcol, ci.pitchslide ? &" \x18\x19\x0D\x18\x19\x0D"[ci.pitchslide] : &" ~\xf0"[ci.pitchfx], 1);
459 			writenum(buf, 38, tcol, ci.vol, 16, 2, 0);
460 			writestring(buf, 40, tcol, ci.volslide ? &" \x18\x19\x18\x19"[ci.volslide] : &" ~"[ci.volfx], 1);
461 			writestring(buf, 42, tcol, &"L123456MM9ABCDERS"[ci.pan], 1);
462 			writestring(buf, 43, tcol, &" \x1A\x1B"[ci.panslide], 1);
463 
464 			fxstr=fxstr12[ci.fx];
465 			if (fxstr)
466 				writestring(buf, 45, tcol, fxstr, 12);
467 
468 			drawvolbar(buf+59, i, st);
469 			break;
470 		case 128:
471 			if (ci.ins)
472 			{
473 				if (*insts[ci.ins-1].name)
474 					writestring(buf,  4, tcol, insts[ci.ins-1].name, 28);
475 				else
476 				{
477 					writestring(buf,  4, 0x08, "(  )", 4);
478 					writenum(buf,  5, 0x08, ci.ins, 16, 2, 0);
479 				}
480 			}
481 			if (ci.smp!=0xFFFF)
482 			{
483 				if (*samps[ci.smp].name)
484 					writestring(buf, 34, tcol, samps[ci.smp].name, 17);
485 				else
486 				{
487 					writestring(buf, 34, 0x08, "(    )", 6);
488 					writenum(buf, 35, 0x08, ci.smp, 16, 4, 0);
489 				}
490 			}
491 			writestring(buf, 53, ci.notehit?tcolr:tcol, plNoteStr[ci.note], 3);
492 			writestring(buf, 56, tcol, ci.pitchslide ? &" \x18\x19\x0D\x18\x19\x0D"[ci.pitchslide] : &" ~\xf0"[ci.pitchfx], 1);
493 			writenum(buf, 58, tcol, ci.vol, 16, 2, 0);
494 			writestring(buf, 60, tcol, ci.volslide ? &" \x18\x19\x18\x19"[ci.volslide] : &" ~"[ci.volfx], 1);
495 			writestring(buf, 62, tcol, &"L123456MM9ABCDERS"[ci.pan], 1);
496 			writestring(buf, 63, tcol, &" \x1A\x1B"[ci.panslide], 1);
497 
498 			fxstr=fxstr12[ci.fx];
499 			if (fxstr)
500 				writestring(buf, 65, tcol, fxstr, 12);
501 			drawlongvolbar(buf+80, i, st);
502 			break;
503 		case 44:
504 			writenum(buf,  4, tcol, ci.ins, 16, 2, 0);
505 			writestring(buf,  7, ci.notehit?tcolr:tcol, plNoteStr[ci.note], 3);
506 			writestring(buf, 10, tcol, ci.pitchslide ? &" \x18\x19\x0D\x18\x19\x0D"[ci.pitchslide] : &" ~\xf0"[ci.pitchfx], 1);
507 			writenum(buf, 12, tcol, ci.vol, 16, 2, 0);
508 			writestring(buf, 14, tcol, ci.volslide ? &" \x18\x19\x18\x19"[ci.volslide] : &" ~"[ci.volfx], 1);
509 			writestring(buf, 16, tcol, &"L123456MM9ABCDERS"[ci.pan], 1);
510 			writestring(buf, 17, tcol, &" \x1A\x1B"[ci.panslide], 1);
511 
512 			fxstr=fxstr6[ci.fx];
513 			if (fxstr)
514 				writestring(buf, 19, tcol, fxstr, 6);
515 			drawvolbar(buf+26, i, st);
516 			break;
517 	}
518 }
519 
520 /************************************************************************/
521 
itpGetDots(struct notedotsdata * d,int max)522 static int itpGetDots(struct notedotsdata *d, int max)
523 {
524 	int i,j;
525 	int pos=0;
526 	for (i=0; i<plNLChan; i++)
527 	{
528 		if (pos>=max)
529 			break;
530 		j=0;
531 		while (pos<max)
532 		{
533 			int smp, voll, volr, note, sus;
534 			j=getdotsdata(&itplayer, i, j, &smp, &note, &voll, &volr, &sus);
535 			if (j==-1)
536 				break;
537 			d[pos].voll=voll;
538 			d[pos].volr=volr;
539 			d[pos].chan=i;
540 			d[pos].note=note;
541 			d[pos].col=(smp&15)+(sus?32:16);
542 			pos++;
543 		}
544 	}
545   return pos;
546 }
547 
itpMute(int i,int m)548 static void itpMute(int i, int m)
549 {
550 	mutechan(&itplayer, i, m);
551 }
552 
itpGetLChanSample(unsigned int ch,int16_t * buf,unsigned int len,uint32_t rate,int opt)553 static int itpGetLChanSample(unsigned int ch, int16_t *buf, unsigned int len, uint32_t rate, int opt)
554 {
555 	return getchansample(&itplayer, ch, buf, len, rate, opt);
556 }
557 
itpOpenFile(struct moduleinfostruct * info,struct ocpfilehandle_t * file)558 static int itpOpenFile(struct moduleinfostruct *info, struct ocpfilehandle_t *file)
559 {
560 	int retval;
561 
562 	int nch;
563 
564 	if (!mcpOpenPlayer)
565 		return errGen;
566 
567 	if (!file)
568 		return errFileOpen;
569 
570 	strncpy(currentmodname, info->name, _MAX_FNAME);
571 	strncpy(currentmodext, info->name + _MAX_FNAME, _MAX_EXT);
572 
573 	fprintf(stderr, "loading %s%s (%uk)...\n", currentmodname, currentmodext, (unsigned int)(file->filesize(file)>>10));
574 
575 	if (!(retval=it_load(&mod, file)))
576 		if (!loadsamples(&mod))
577 			retval=-1;
578 
579 	if (retval)
580 	{
581 		it_free(&mod);
582 		return -1;
583 	}
584 
585 	it_optimizepatlens(&mod);
586 
587 	mcpNormalize(1);
588 	nch=cfGetProfileInt2(cfSoundSec, "sound", "itchan", 64, 10);
589 	mcpSet(-1, mcpGRestrict, 0);  /* oops... */
590 	if (!play(&itplayer, &mod, nch, file))
591 		retval=errPlay;
592 
593 	if (retval)
594 	{
595 		it_free(&mod);
596 		return retval;
597 	}
598 
599 	insts=mod.instruments;
600 	samps=mod.samples;
601 	plNLChan=mod.nchan;
602 	plIsEnd=itpLooped;
603 	plIdle=itpIdle;
604 	plProcessKey=itpProcessKey;
605 	plDrawGStrings=itpDrawGStrings;
606 	plSetMute=itpMute;
607 	plGetLChanSample=itpGetLChanSample;
608 	plUseDots(itpGetDots);
609 	plUseChannels(drawchannel);
610 	itpInstSetup(mod.instruments, mod.ninst, mod.samples, mod.nsamp, mod.sampleinfos, /*mod.nsampi,*/ 0, itpMarkInsSamp);
611 	itTrkSetup(&mod);
612 	if (mod.message)
613 		plUseMessage(mod.message);
614 	plNPChan=mcpNChan;
615 
616 	modname=mod.name;
617 	composer="";
618 	if (!plCompoMode)
619 	{
620 		if (!*modname)
621 			modname=info->modname;
622 		composer=info->composer;
623 	} else
624 		modname=info->comment;
625 
626 	plGetRealMasterVolume=mcpGetRealMasterVolume;
627 	plGetMasterSample=mcpGetMasterSample;
628 	plGetPChanSample=mcpGetChanSample;
629 
630 	starttime=dos_clock();
631 	plPause=0;
632 	mcpSet(-1, mcpMasterPause, 0);
633 
634 	return errOk;
635 }
636 
637 struct cpifaceplayerstruct itpPlayer = {itpOpenFile, itpCloseFile};
638 struct linkinfostruct dllextinfo = {.name = "playit", .desc = "OpenCP IT Player (c) 1997-10 Tammo Hinrichs, Niklas Beisert, Stian Skjelstad", .ver = DLLVERSION, .size = 0};
639