1 /* OpenCP Module Player
2  * copyright (c) '94-'10 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
3  * copyright (c) '04-'21 Stian Skjelstad <stian.skjelstad@gmail.com>
4  *
5  * WAVPlay 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  *  -ryg981219 Fabian Giesen  <fabian@jdcs.su.nw.schule.de>
25  *    -made max amplification 793% (as in module players)
26  */
27 
28 #include "config.h"
29 #include <ctype.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <time.h>
33 #include <unistd.h>
34 #include "types.h"
35 #include "boot/plinkman.h"
36 #include "boot/psetting.h"
37 #include "cpiface/cpiface.h"
38 #include "dev/deviplay.h"
39 #include "dev/player.h"
40 #include "filesel/filesystem.h"
41 #include "filesel/mdb.h"
42 #include "filesel/pfilesel.h"
43 #include "stuff/compat.h"
44 #include "stuff/err.h"
45 #include "stuff/poutput.h"
46 #include "stuff/sets.h"
47 #include "wave.h"
48 
49 #define _MAX_FNAME 8
50 #define _MAX_EXT 4
51 
52 extern char plPause;
53 
54 static unsigned long wavelen;
55 static unsigned long waverate;
56 
57 static time_t starttime;
58 static time_t pausetime;
59 static char currentmodname[_MAX_FNAME+1];
60 static char currentmodext[_MAX_EXT+1];
61 static char *modname;
62 static char *composer;
63 static short vol;
64 static short bal;
65 static short pan;
66 static char srnd;
67 static long amp;
68 static short speed;
69 static short reverb;
70 static short chorus;
71 static char finespeed=8;
72 static time_t pausefadestart;
73 static uint8_t pausefaderelspeed;
74 static int8_t pausefadedirect;
75 
startpausefade(void)76 static void startpausefade(void)
77 {
78 	if (plPause)
79 		starttime=starttime+dos_clock()-pausetime;
80 
81 	if (pausefadedirect)
82 	{
83 		if (pausefadedirect<0)
84 			plPause=1;
85 		pausefadestart=2*dos_clock()-DOS_CLK_TCK-pausefadestart;
86 	} else
87 		pausefadestart=dos_clock();
88 
89 	if (plPause)
90 	{
91 		plChanChanged=1;
92 		wpPause(plPause=0);
93 		pausefadedirect=1;
94 	} else
95 		pausefadedirect=-1;
96 }
97 
dopausefade(void)98 static void dopausefade(void)
99 {
100 	int16_t i;
101 	if (pausefadedirect>0)
102 	{
103 		i=(dos_clock()-pausefadestart)*64/DOS_CLK_TCK;
104 		if (i<0)
105 			i=0;
106 		if (i>=64)
107 		{
108 			i=64;
109 			pausefadedirect=0;
110 		}
111 	} else {
112 		i=64-(dos_clock()-pausefadestart)*64/DOS_CLK_TCK;
113 		if (i>=64)
114 			i=64;
115 		if (i<=0)
116 		{
117 			i=0;
118 			pausefadedirect=0;
119 			pausetime=dos_clock();
120 			wpPause(plPause=1);
121 			plChanChanged=1;
122 			wpSetSpeed(speed);
123 			return;
124 		}
125 	}
126 	pausefaderelspeed=i;
127 	wpSetSpeed(speed*i/64);
128 }
wavDrawGStrings(unsigned short (* buf)[CONSOLE_MAX_X])129 static void wavDrawGStrings(unsigned short (*buf)[CONSOLE_MAX_X])
130 {
131 	struct waveinfo inf;
132 	long tim;
133 	int l;
134 	int p;
135 
136 	wpGetInfo(&inf);
137 	tim=inf.len/inf.rate;
138 
139 	if (plScrWidth<128)
140 	{
141 		memset(buf[0]+80, 0, (plScrWidth-80)*sizeof(uint16_t));
142 		memset(buf[1]+80, 0, (plScrWidth-80)*sizeof(uint16_t));
143 		memset(buf[2]+80, 0, (plScrWidth-80)*sizeof(uint16_t));
144 
145 		writestring(buf[0], 0, 0x09, " vol: \xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa ", 15);
146 		writestring(buf[0], 15, 0x09, " srnd: \xfa  pan: l\xfa\xfa\xfam\xfa\xfa\xfar  bal: l\xfa\xfa\xfam\xfa\xfa\xfar ", 41);
147 		writestring(buf[0], 56, 0x09, " spd: ---% \x1D ptch: ---% ", 24);
148 		writestring(buf[0], 6, 0x0F, "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe", (vol+4)>>3);
149 		writestring(buf[0], 22, 0x0F, srnd?"x":"o", 1);
150 		if (((pan+70)>>4)==4)
151 			writestring(buf[0], 34, 0x0F, "m", 1);
152 		else {
153 			writestring(buf[0], 30+((pan+70)>>4), 0x0F, "r", 1);
154 			writestring(buf[0], 38-((pan+70)>>4), 0x0F, "l", 1);
155 		}
156 		writestring(buf[0], 46+((bal+70)>>4), 0x0F, "I", 1);
157 		_writenum(buf[0], 62, 0x0F, speed*100/256, 10, 3);
158 		_writenum(buf[0], 75, 0x0F, speed*100/256, 10, 3);
159 
160 		writestring(buf[1], 57, 0x09, "amp: ...% filter: ...  ", 23);
161 		_writenum(buf[1], 62, 0x0F, amp*100/64, 10, 3);
162 		writestring(buf[1], 75, 0x0F, "off", 3);
163 
164 		l=(inf.len>>(10-inf.stereo-inf.bit16));
165 		p=(inf.pos>>(10-inf.stereo-inf.bit16));
166 		writestring(buf[1], 0, 0x09, "  pos: ...% / ......k  size: ......k  len: ..:..", 57);
167 		_writenum(buf[1], 7, 0x0F, p*100/l, 10, 3);
168 		writenum(buf[1], 43, 0x0F, (tim/60)%60, 10, 2, 1);
169 		writestring(buf[1], 45, 0x0F, ":", 1);
170 		writenum(buf[1], 46, 0x0F, tim%60, 10, 2, 0);
171 		writenum(buf[1], 29, 0x0F, l, 10, 6, 1);
172 		writenum(buf[1], 14, 0x0F, p, 10, 6, 1);
173 
174 		if (plPause)
175 			tim=(pausetime-starttime);
176 		else
177 			 tim=(time(NULL)-starttime);
178 
179 		writestring(buf[2],  0, 0x09, "   wave \xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa.\xfa\xfa\xfa: ...............................               time: ..:.. ", 80);
180 		writestring(buf[2],  8, 0x0F, currentmodname, _MAX_FNAME);
181 		writestring(buf[2], 16, 0x0F, currentmodext, _MAX_EXT);
182 		writestring(buf[2], 22, 0x0F, modname, 31);
183 		if (plPause)
184 			writestring(buf[2], 58, 0x0C, "paused", 6);
185 		writenum(buf[2], 74, 0x0F, (tim/60)%60, 10, 2, 1);
186 		writestring(buf[2], 76, 0x0F, ":", 1);
187 		writenum(buf[2], 77, 0x0F, tim%60, 10, 2, 0);
188 	} else {
189 		memset(buf[0]+128, 0, (plScrWidth-128)*sizeof(uint16_t));
190 		memset(buf[1]+128, 0, (plScrWidth-128)*sizeof(uint16_t));
191 		memset(buf[2]+128, 0, (plScrWidth-128)*sizeof(uint16_t));
192 
193 		writestring(buf[0], 0, 0x09, "    volume: \xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa  ", 30);
194 		writestring(buf[0], 30, 0x09, " surround: \xfa   panning: l\xfa\xfa\xfa\xfa\xfa\xfa\xfam\xfa\xfa\xfa\xfa\xfa\xfa\xfar   balance: l\xfa\xfa\xfa\xfa\xfa\xfa\xfam\xfa\xfa\xfa\xfa\xfa\xfa\xfar  ", 72);
195 		writestring(buf[0], 102, 0x09,  " speed: ---% \x1D pitch: ---%    ", 30);
196 		writestring(buf[0], 12, 0x0F, "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe", (vol+2)>>2);
197 		writestring(buf[0], 41, 0x0F, srnd?"x":"o", 1);
198 		if (((pan+68)>>3)==8)
199 			writestring(buf[0], 62, 0x0F, "m", 1);
200 		else {
201 			writestring(buf[0], 54+((pan+68)>>3), 0x0F, "r", 1);
202 			writestring(buf[0], 70-((pan+68)>>3), 0x0F, "l", 1);
203 		}
204 		writestring(buf[0], 83+((bal+68)>>3), 0x0F, "I", 1);
205 		_writenum(buf[0], 110, 0x0F, speed*100/256, 10, 3);
206 		_writenum(buf[0], 124, 0x0F, speed*100/256, 10, 3);
207 
208 		l=(inf.len>>(10-inf.stereo-inf.bit16));
209 		p=(inf.pos>>(10-inf.stereo-inf.bit16));
210 		writestring(buf[1], 0, 0x09, "    position: ...% / ......k  size: ......k  length: ..:..  opt: .....Hz, .. bit, ......", 92);
211 		_writenum(buf[1], 14, 0x0F, p*100/l, 10, 3);
212 		writenum(buf[1], 53, 0x0F, (tim/60)%60, 10, 2, 1);
213 		writestring(buf[1], 55, 0x0F, ":", 1);
214 		writenum(buf[1], 56, 0x0F, tim%60, 10, 2, 0);
215 		writenum(buf[1], 36, 0x0F, l, 10, 6, 1);
216 		writenum(buf[1], 21, 0x0F, p, 10, 6, 1);
217 		writenum(buf[1], 65, 0x0F, inf.rate, 10, 5, 1);
218 		writenum(buf[1], 74, 0x0F, 8<<inf.bit16, 10, 2, 1);
219 		writestring(buf[1], 82, 0x0F, inf.stereo?"stereo":"mono", 6);
220 
221 		writestring(buf[1], 92, 0x09, "   amplification: ...%  filter: ...     ", 40);
222 		_writenum(buf[1], 110, 0x0F, amp*100/64, 10, 3);
223 		writestring(buf[1], 124, 0x0F, "off", 3);
224 
225 		if (plPause)
226 			tim=(pausetime-starttime);
227 		else
228 			tim=(time(NULL)-starttime);
229 
230 		writestring(buf[2],  0, 0x09, "      wave \xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa.\xfa\xfa\xfa: ...............................  composer: ...............................                  time: ..:..    ", 132);
231 		writestring(buf[2], 11, 0x0F, currentmodname, _MAX_FNAME);
232 		writestring(buf[2], 19, 0x0F, currentmodext, _MAX_EXT);
233 		writestring(buf[2], 25, 0x0F, modname, 31);
234 		writestring(buf[2], 68, 0x0F, composer, 31);
235 		if (plPause)
236 			writestring(buf[2], 100, 0x0C, "playback paused", 15);
237 		writenum(buf[2], 123, 0x0F, (tim/60)%60, 10, 2, 1);
238 		writestring(buf[2], 125, 0x0F, ":", 1);
239 		writenum(buf[2], 126, 0x0F, tim%60, 10, 2, 0);
240 	}
241 }
242 
normalize(void)243 static void normalize(void)
244 {
245 	mcpNormalize(0);
246 	speed=set.speed;
247 	pan=set.pan;
248 	bal=set.bal;
249 	vol=set.vol;
250 	amp=set.amp;
251 	srnd=set.srnd;
252 	reverb=set.reverb;
253 	chorus=set.chorus;
254 	wpSetAmplify(1024*amp);
255 	wpSetVolume(vol, bal, pan, srnd);
256 	wpSetSpeed(speed);
257 /*
258 	wpSetMasterReverbChorus(reverb, chorus);
259 */
260 }
261 
wavCloseFile()262 static void wavCloseFile()
263 {
264 	wpClosePlayer();
265 }
266 
wavProcessKey(unsigned short key)267 static int wavProcessKey(unsigned short key)
268 {
269 	switch (key)
270 	{
271 		case KEY_ALT_K:
272 			cpiKeyHelp('p', "Start/stop pause with fade");
273 			cpiKeyHelp('P', "Start/stop pause with fade");
274 			cpiKeyHelp(KEY_CTRL_P, "Start/stop pause");
275 			cpiKeyHelp('<', "Jump back (big)");
276 			cpiKeyHelp(KEY_CTRL_LEFT, "Jump back (big)");
277 			cpiKeyHelp('>', "Jump forward (big)");
278 			cpiKeyHelp(KEY_CTRL_RIGHT, "Jump forward (big)");
279 			cpiKeyHelp(KEY_CTRL_UP, "Jump back (small)");
280 			cpiKeyHelp(KEY_CTRL_DOWN, "Jump forward (small)");
281 			cpiKeyHelp('-', "Decrease volume (small)");
282 			cpiKeyHelp('+', "Increase volume (small)");
283 			cpiKeyHelp('/', "Move balance left (small)");
284 			cpiKeyHelp('*', "Move balance right (small)");
285 			cpiKeyHelp(',', "Move panning against normal (small)");
286 			cpiKeyHelp('.', "Move panning against reverse (small)");
287 			cpiKeyHelp(KEY_F(2), "Decrease volume");
288 			cpiKeyHelp(KEY_F(3), "Increase volume");
289 			cpiKeyHelp(KEY_F(4), "Toggle surround on/off");
290 			cpiKeyHelp(KEY_F(5), "Move panning against normal");
291 			cpiKeyHelp(KEY_F(6), "Move panning against reverse");
292 			cpiKeyHelp(KEY_F(7), "Move balance left");
293 			cpiKeyHelp(KEY_F(8), "Move balance right");
294 			cpiKeyHelp(KEY_F(9), "Decrease pitch speed");
295 			cpiKeyHelp(KEY_F(11), "Decrease pitch speed");
296 			cpiKeyHelp(KEY_F(10), "Increase pitch speed");
297 			cpiKeyHelp(KEY_F(12), "Increase pitch speed");
298 			if (plrProcessKey)
299 				plrProcessKey(key);
300 			return 0;
301 
302 		case 'p': case 'P':
303 			startpausefade();
304 			break;
305 		case KEY_CTRL_P:
306 			pausefadedirect=0;
307 			if (plPause)
308 				starttime=starttime+time(NULL)-pausetime;
309 			else
310 				pausetime=time(NULL);
311 			plPause=!plPause;
312 			wpPause(plPause);
313 			break;
314 		case KEY_CTRL_UP:
315 		/* case 0x8D00: //ctrl-up */
316 			wpSetPos(wpGetPos()-waverate);
317 			break;
318 		case KEY_CTRL_DOWN:
319 		/* case 0x9100: //ctrl-down */
320 			wpSetPos(wpGetPos()+waverate);
321 			break;
322 		case '<':
323 		case KEY_CTRL_LEFT:
324 		/* case 0x7300: //ctrl-left */
325 			{
326 				uint32_t pos = wpGetPos();
327 				uint32_t newpos = pos -(wavelen>>5);
328 				if (newpos > pos)
329 				{
330 					newpos = 0;
331 				}
332 				wpSetPos(newpos);
333 			}
334 			break;
335 		case '>':
336 		case KEY_CTRL_RIGHT:
337 		/* case 0x7400: //ctrl-right */
338 			{
339 				uint32_t pos = wpGetPos();
340 				uint32_t newpos = pos + (wavelen>>5);
341 				if ((newpos < pos) || (newpos > wavelen)) /* catch both wrap around (not likely), and overshots */
342 				{
343 					newpos = wavelen - 4;
344 				}
345 				wpSetPos(newpos);
346 			}
347 			break;
348 /*
349 		case 0x7700: //ctrl-home TODO keys
350 			wpSetPos(0);
351 			break;
352 */
353 		case '-':
354 			if (vol>=2)
355 				vol-=2;
356 			wpSetVolume(vol, bal, pan, srnd);
357 			break;
358 		case '+':
359 			if (vol<=62)
360 				vol+=2;
361 			wpSetVolume(vol, bal, pan, srnd);
362 			break;
363 		case '/':
364 			if ((bal-=4)<-64)
365 				bal=-64;
366 			wpSetVolume(vol, bal, pan, srnd);
367 			break;
368 		case '*':
369 			if ((bal+=4)>64)
370 				bal=64;
371 			wpSetVolume(vol, bal, pan, srnd);
372 			break;
373 		case ',':
374 			if ((pan-=4)<-64)
375 				pan=-64;
376 			wpSetVolume(vol, bal, pan, srnd);
377 			break;
378 		case '.':
379 			if ((pan+=4)>64)
380 				pan=64;
381 			wpSetVolume(vol, bal, pan, srnd);
382 			break;
383 		case KEY_F(2): /*f2*/
384 			if ((vol-=8)<0)
385 				vol=0;
386 			wpSetVolume(vol, bal, pan, srnd);
387 			break;
388 		case KEY_F(3): /*f3*/
389 			if ((vol+=8)>64)
390 				vol=64;
391 			wpSetVolume(vol, bal, pan, srnd);
392 			break;
393 		case KEY_F(4): /*f4*/
394 			wpSetVolume(vol, bal, pan, srnd=srnd?0:2);
395 			break;
396 		case KEY_F(5): /*f5*/
397 			if ((pan-=16)<-64)
398 				pan=-64;
399 			wpSetVolume(vol, bal, pan, srnd);
400 			break;
401 		case KEY_F(6): /*f6*/
402 			if ((pan+=16)>64)
403 				pan=64;
404 			wpSetVolume(vol, bal, pan, srnd);
405 			break;
406 		case KEY_F(7): /*f7*/
407 			if ((bal-=16)<-64)
408 				bal=-64;
409 			wpSetVolume(vol, bal, pan, srnd);
410 			break;
411 		case KEY_F(8): /*f8*/
412 			if ((bal+=16)>64)
413 				bal=64;
414 			wpSetVolume(vol, bal, pan, srnd);
415 			break;
416 		case KEY_F(9): /*f9*/
417 		case KEY_F(11): /*f11*/
418 			if ((speed-=finespeed)<16)
419 				speed=16;
420 			wpSetSpeed(speed);
421 			break;
422 		case KEY_F(10): /*f10*/
423 		case KEY_F(12): /*f12*/
424 			if ((speed+=finespeed)>2048)
425 				speed=2048;
426 			wpSetSpeed(speed);
427 			break;
428 /*
429 		case 0x5f00: // ctrl f2 TODO keys
430 			if ((amp-=4)<4)
431 				amp=4;
432 			wpSetAmplify(1024*amp);
433 			break;
434 		case 0x6000: // ctrl f3 TODO keys
435 			if ((amp+=4)>508)
436 				amp=508;
437 			wpSetAmplify(1024*amp);
438 			break;
439 		case 0x8900: // ctrl f11 TODO keys
440 			finespeed=(finespeed==8)?1:8;
441 			break;
442 		case 0x6a00: // alt-f3 TODO keys
443 			normalize();
444 			break;
445 		case 0x6900: // alt-f2 TODO keys
446 			set.pan=pan;
447 			set.bal=bal;
448 			set.vol=vol;
449 			set.speed=speed;
450 			set.amp=amp;
451 			set.srnd=srnd;
452 			break;
453 		case 0x6b00: // alt-f4 TODO keys
454 			pan=64;
455 			bal=0;
456 			vol=64;
457 
458 			speed=256;
459 			amp=64;
460 			wpSetVolume(vol, bal, pan, srnd);
461 			wpSetSpeed(speed);
462 			wpSetAmplify(1024*amp);
463 			break;*/
464 		default:
465 			if (plrProcessKey)
466 			{
467 				int ret=plrProcessKey(key);
468 				if (ret==2)
469 					cpiResetScreen();
470 				if (ret)
471 					return 1;
472 			}
473 			return 0;
474 	}
475 	return 1;
476 }
477 
478 
wavLooped(void)479 static int wavLooped(void)
480 {
481 	if (pausefadedirect)
482 		dopausefade();
483 	wpSetLoop(fsLoopMods);
484 	wpIdle();
485 	if (plrIdle)
486 		plrIdle();
487 	return !fsLoopMods&&wpLooped();
488 }
489 
490 
wavOpenFile(struct moduleinfostruct * info,struct ocpfilehandle_t * wavf)491 static int wavOpenFile(struct moduleinfostruct *info, struct ocpfilehandle_t *wavf)
492 {
493 	struct waveinfo inf;
494 
495 	if (!wavf)
496 		return -1;
497 
498 	strncpy(currentmodname, info->name, _MAX_FNAME);
499 	strncpy(currentmodext, info->name + _MAX_FNAME, _MAX_EXT);
500 
501 	modname=info->modname;
502 	composer=info->composer;
503 
504 	fprintf(stderr, "preloading %s%s...\n", currentmodname, currentmodext);
505 
506 	plIsEnd=wavLooped;
507 	plProcessKey=wavProcessKey;
508 	plDrawGStrings=wavDrawGStrings;
509 	plGetMasterSample=plrGetMasterSample;
510 	plGetRealMasterVolume=plrGetRealMasterVolume;
511 
512 	if (!wpOpenPlayer(wavf))
513 	{
514 #ifdef INITCLOSE_DEBUG
515 		fprintf(stderr, "wpOpenPlayer FAILED\n");
516 #endif
517 		return -1;
518 	}
519 
520 	starttime=time(NULL);
521 	plPause=0;
522 	normalize();
523 	pausefadedirect=0;
524 
525 	wpGetInfo(&inf);
526 	wavelen=inf.len;
527 	waverate=inf.rate;
528 
529 	return errOk;
530 }
531 
532 struct cpifaceplayerstruct wavPlayer = {wavOpenFile, wavCloseFile};
533 struct linkinfostruct dllextinfo = {.name = "playwav", .desc = "OpenCP Wave Player (c) 1994-'21 Niklas Beisert, Tammo Hinrichs, Stian Skjelstad", .ver = DLLVERSION, .size = 0};
534