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