diff options
author | Frank Gevaerts <frank@gevaerts.be> | 2010-12-12 15:03:30 +0000 |
---|---|---|
committer | Frank Gevaerts <frank@gevaerts.be> | 2010-12-12 15:03:30 +0000 |
commit | 26f2bfde03420edad4de1f22cb3d515dc063b20d (patch) | |
tree | 4a8c4abaf4795f38da70a4657c1a0fb3ba9debeb /apps/plugins/mikmod/mikmod.c | |
parent | d192bdf11e06e50645ecb5726658d4b691480a9a (diff) | |
download | rockbox-26f2bfde03420edad4de1f22cb3d515dc063b20d.tar.gz rockbox-26f2bfde03420edad4de1f22cb3d515dc063b20d.zip |
Add MikMod plugin, ported by Jason Yu, with some minor work by Craig Mann and William Peters (FS#8806)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28810 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/mikmod/mikmod.c')
-rw-r--r-- | apps/plugins/mikmod/mikmod.c | 943 |
1 files changed, 943 insertions, 0 deletions
diff --git a/apps/plugins/mikmod/mikmod.c b/apps/plugins/mikmod/mikmod.c new file mode 100644 index 0000000000..fe1768376e --- /dev/null +++ b/apps/plugins/mikmod/mikmod.c | |||
@@ -0,0 +1,943 @@ | |||
1 | #define NO_MMSUPP_DEFINES | ||
2 | |||
3 | #include "plugin.h" | ||
4 | #include "lib/configfile.h" | ||
5 | #include "mikmod.h" | ||
6 | |||
7 | |||
8 | #undef SYNC | ||
9 | #ifdef SIMULATOR | ||
10 | #define SYNC | ||
11 | #elif NUM_CORES > 1 | ||
12 | #define USETHREADS | ||
13 | #endif | ||
14 | |||
15 | #define MAX_CHARS LCD_WIDTH/6 | ||
16 | #define MAX_LINES LCD_HEIGHT/8 | ||
17 | #define LINE_LENGTH 80 | ||
18 | |||
19 | #define DIR_PREV 1 | ||
20 | #define DIR_NEXT -1 | ||
21 | #define DIR_NONE 0 | ||
22 | |||
23 | #define PLUGIN_NEWSONG 10 | ||
24 | |||
25 | /* Persistent configuration */ | ||
26 | #define MIKMOD_CONFIGFILE "mikmod.cfg" | ||
27 | #define MIKMOD_SETTINGS_MINVERSION 1 | ||
28 | #define MIKMOD_SETTINGS_VERSION 1 | ||
29 | |||
30 | #ifdef USETHREADS | ||
31 | #define EV_EXIT 9999 | ||
32 | #define THREAD_STACK_SIZE DEFAULT_STACK_SIZE + 0x200 | ||
33 | static unsigned int thread_id; | ||
34 | static struct event_queue thread_q; | ||
35 | /* use long for aligning */ | ||
36 | unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)]; | ||
37 | #endif | ||
38 | |||
39 | /* the current full file name */ | ||
40 | static char np_file[MAX_PATH]; | ||
41 | static int curfile = 0, direction = DIR_NEXT, entries = 0; | ||
42 | |||
43 | /* list of the mod files */ | ||
44 | static char **file_pt; | ||
45 | |||
46 | |||
47 | /* The MP3 audio buffer which we will use as heap memory */ | ||
48 | static unsigned char* audio_buffer; | ||
49 | /* amount of bytes left in audio_buffer */ | ||
50 | static size_t audio_buffer_free; | ||
51 | |||
52 | |||
53 | /* The rockbox plugin interface */ | ||
54 | MEM_FUNCTION_WRAPPERS; | ||
55 | |||
56 | bool quit; | ||
57 | int playingtime IBSS_ATTR; | ||
58 | MODULE *module IBSS_ATTR; | ||
59 | char gmbuf[BUF_SIZE*NBUF]; | ||
60 | |||
61 | |||
62 | int textlines; | ||
63 | int vscroll = 0; | ||
64 | int hscroll = 0; | ||
65 | bool screenupdated = false; | ||
66 | |||
67 | enum { | ||
68 | DISPLAY_INFO = 0, | ||
69 | DISPLAY_SAMPLE, | ||
70 | DISPLAY_INST, | ||
71 | DISPLAY_COMMENTS, | ||
72 | } display; | ||
73 | |||
74 | |||
75 | /* | ||
76 | * strncat wrapper | ||
77 | */ | ||
78 | char* mmsupp_strncat(char *s1, const char *s2, size_t n) | ||
79 | { | ||
80 | char *s = s1; | ||
81 | /* Loop over the data in s1. */ | ||
82 | while (*s != '\0') | ||
83 | s++; | ||
84 | /* s now points to s1's trailing null character, now copy | ||
85 | up to n bytes from s2 into s1 stopping if a null character | ||
86 | is encountered in s2. | ||
87 | It is not safe to use strncpy here since it copies EXACTLY n | ||
88 | characters, NULL padding if necessary. */ | ||
89 | while (n != 0 && (*s = *s2++) != '\0') | ||
90 | { | ||
91 | n--; | ||
92 | s++; | ||
93 | } | ||
94 | if (*s != '\0') | ||
95 | *s = '\0'; | ||
96 | return s1; | ||
97 | } | ||
98 | |||
99 | /* | ||
100 | * sprintf wrapper | ||
101 | */ | ||
102 | int mmsupp_sprintf(char *buf, const char *fmt, ... ) | ||
103 | { | ||
104 | bool ok; | ||
105 | va_list ap; | ||
106 | |||
107 | va_start(ap, fmt); | ||
108 | ok = rb->vsnprintf(buf, LINE_LENGTH, fmt, ap); | ||
109 | va_end(ap); | ||
110 | |||
111 | return ok; | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * printf wrapper | ||
116 | */ | ||
117 | void mmsupp_printf(const char *fmt, ...) | ||
118 | { | ||
119 | static int p_xtpt = 0; | ||
120 | char p_buf[LINE_LENGTH]; | ||
121 | bool ok; | ||
122 | va_list ap; | ||
123 | |||
124 | va_start(ap, fmt); | ||
125 | ok = rb->vsnprintf(p_buf, sizeof(p_buf), fmt, ap); | ||
126 | va_end(ap); | ||
127 | |||
128 | int i=0; | ||
129 | |||
130 | /* Device LCDs display newlines funny. */ | ||
131 | for(i=0; p_buf[i]!=0; i++) | ||
132 | if(p_buf[i] == '\n') | ||
133 | p_buf[i] = ' '; | ||
134 | |||
135 | rb->lcd_putsxy(1, p_xtpt, (unsigned char *)p_buf); | ||
136 | rb->lcd_update(); | ||
137 | |||
138 | p_xtpt += 8; | ||
139 | if(p_xtpt > LCD_HEIGHT-8) | ||
140 | { | ||
141 | p_xtpt = 0; | ||
142 | rb->lcd_clear_display(); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | |||
147 | /************************* File Access ***************************/ | ||
148 | |||
149 | /* support function for qsort() */ | ||
150 | static int compare(const void* p1, const void* p2) | ||
151 | { | ||
152 | return rb->strcasecmp(*((char **)p1), *((char **)p2)); | ||
153 | } | ||
154 | |||
155 | bool mod_ext(const char ext[]) | ||
156 | { | ||
157 | if(!ext) | ||
158 | return false; | ||
159 | if(!rb->strcasecmp(ext,".669") || | ||
160 | !rb->strcasecmp(ext,".amf") || | ||
161 | !rb->strcasecmp(ext,".asy") || | ||
162 | !rb->strcasecmp(ext,".dsm") || | ||
163 | !rb->strcasecmp(ext,".far") || | ||
164 | !rb->strcasecmp(ext,".gdm") || | ||
165 | !rb->strcasecmp(ext,".gt2") || | ||
166 | !rb->strcasecmp(ext,".imf") || | ||
167 | !rb->strcasecmp(ext,".it") || | ||
168 | !rb->strcasecmp(ext,".m15") || | ||
169 | !rb->strcasecmp(ext,".med") || | ||
170 | !rb->strcasecmp(ext,".mod") || | ||
171 | !rb->strcasecmp(ext,".mtm") || | ||
172 | !rb->strcasecmp(ext,".okt") || | ||
173 | !rb->strcasecmp(ext,".s3m") || | ||
174 | !rb->strcasecmp(ext,".stm") || | ||
175 | !rb->strcasecmp(ext,".stx") || | ||
176 | !rb->strcasecmp(ext,".ult") || | ||
177 | !rb->strcasecmp(ext,".uni") || | ||
178 | !rb->strcasecmp(ext,".xm") ) | ||
179 | return true; | ||
180 | else | ||
181 | return false; | ||
182 | } | ||
183 | |||
184 | /*Read directory contents for scrolling. */ | ||
185 | void get_mod_list(void) | ||
186 | { | ||
187 | struct tree_context *tree = rb->tree_get_context(); | ||
188 | struct entry *dircache = tree->dircache; | ||
189 | int i; | ||
190 | char *pname; | ||
191 | |||
192 | file_pt = (char **) audio_buffer; | ||
193 | |||
194 | /* Remove path and leave only the name.*/ | ||
195 | pname = rb->strrchr(np_file,'/'); | ||
196 | pname++; | ||
197 | |||
198 | for (i = 0; i < tree->filesindir && audio_buffer_free > sizeof(char**); i++) | ||
199 | { | ||
200 | if (!(dircache[i].attr & ATTR_DIRECTORY) | ||
201 | && mod_ext(rb->strrchr(dircache[i].name,'.'))) | ||
202 | { | ||
203 | file_pt[entries] = dircache[i].name; | ||
204 | /* Set Selected File. */ | ||
205 | if (!rb->strcmp(file_pt[entries], pname)) | ||
206 | curfile = entries; | ||
207 | entries++; | ||
208 | |||
209 | audio_buffer += (sizeof(char**)); | ||
210 | audio_buffer_free -= (sizeof(char**)); | ||
211 | } | ||
212 | } | ||
213 | } | ||
214 | |||
215 | int change_filename(int direct) | ||
216 | { | ||
217 | bool file_erased = (file_pt[curfile] == NULL); | ||
218 | direction = direct; | ||
219 | |||
220 | curfile += (direct == DIR_PREV? entries - 1: 1); | ||
221 | if (curfile >= entries) | ||
222 | curfile -= entries; | ||
223 | |||
224 | if (file_erased) | ||
225 | { | ||
226 | /* remove 'erased' file names from list. */ | ||
227 | int count, i; | ||
228 | for (count = i = 0; i < entries; i++) | ||
229 | { | ||
230 | if (curfile == i) | ||
231 | curfile = count; | ||
232 | if (file_pt[i] != NULL) | ||
233 | file_pt[count++] = file_pt[i]; | ||
234 | } | ||
235 | entries = count; | ||
236 | } | ||
237 | |||
238 | if (entries == 0) | ||
239 | { | ||
240 | rb->splash(HZ, "No supported files"); | ||
241 | return PLUGIN_ERROR; | ||
242 | } | ||
243 | |||
244 | rb->strcpy(rb->strrchr(np_file, '/')+1, file_pt[curfile]); | ||
245 | |||
246 | return PLUGIN_NEWSONG; | ||
247 | } | ||
248 | |||
249 | /***************************************************************************** | ||
250 | * Playback | ||
251 | */ | ||
252 | |||
253 | bool swap = false; | ||
254 | bool lastswap = true; | ||
255 | |||
256 | static inline void synthbuf(void) | ||
257 | { | ||
258 | char *outptr; | ||
259 | |||
260 | #ifndef SYNC | ||
261 | if (lastswap == swap) return; | ||
262 | lastswap = swap; | ||
263 | |||
264 | outptr = (swap ? gmbuf : gmbuf + BUF_SIZE); | ||
265 | #else | ||
266 | outptr = gmbuf; | ||
267 | #endif | ||
268 | |||
269 | VC_WriteBytes(outptr, BUF_SIZE); | ||
270 | } | ||
271 | |||
272 | void get_more(unsigned char** start, size_t* size) | ||
273 | { | ||
274 | #ifndef SYNC | ||
275 | if (lastswap != swap) | ||
276 | { | ||
277 | //printf("Buffer miss!"); | ||
278 | } | ||
279 | |||
280 | #else | ||
281 | synthbuf(); | ||
282 | #endif | ||
283 | |||
284 | *size = BUF_SIZE; | ||
285 | #ifndef SYNC | ||
286 | *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE)); | ||
287 | swap = !swap; | ||
288 | #else | ||
289 | *start = (unsigned char*)(gmbuf); | ||
290 | #endif | ||
291 | } | ||
292 | |||
293 | void showinfo() | ||
294 | { | ||
295 | char statustext[LINE_LENGTH]; | ||
296 | |||
297 | if (!module) | ||
298 | { | ||
299 | return; | ||
300 | } | ||
301 | |||
302 | rb->lcd_clear_display(); | ||
303 | |||
304 | playingtime = (int)(module->sngtime >> 10); | ||
305 | sprintf(statustext, "Name: %s", module->songname); | ||
306 | rb->lcd_putsxy(1, 1, statustext); | ||
307 | sprintf(statustext, "Type: %s", module->modtype); | ||
308 | rb->lcd_putsxy(1, 11, statustext); | ||
309 | |||
310 | sprintf(statustext, "Samples: %d", module->numsmp); | ||
311 | rb->lcd_putsxy(1, 21, statustext); | ||
312 | |||
313 | if ( module->flags & UF_INST ) | ||
314 | { | ||
315 | sprintf(statustext, "Instruments: %d", module->numins); | ||
316 | rb->lcd_putsxy(1, 31, statustext); | ||
317 | } | ||
318 | |||
319 | sprintf(statustext, "pat: %03d/%03d %2.2X", | ||
320 | module->sngpos, module->numpos - 1, module->patpos); | ||
321 | rb->lcd_putsxy(1, 51, statustext); | ||
322 | |||
323 | sprintf(statustext, "spd: %d/%d", | ||
324 | module->sngspd, module->bpm); | ||
325 | rb->lcd_putsxy(1, 61, statustext); | ||
326 | |||
327 | sprintf(statustext, "vol: %ddB", rb->global_settings->volume); | ||
328 | rb->lcd_putsxy(1, 71, statustext); | ||
329 | |||
330 | sprintf(statustext, "time: %d:%02d", | ||
331 | (playingtime / 60) % 60, playingtime % 60); | ||
332 | rb->lcd_putsxy(1, 81, statustext); | ||
333 | |||
334 | if (module->flags & UF_NNA) | ||
335 | { | ||
336 | sprintf(statustext, "chn: %d/%d+%d->%d", | ||
337 | module->realchn, module->numchn, | ||
338 | module->totalchn - module->realchn, | ||
339 | module->totalchn); | ||
340 | } | ||
341 | else | ||
342 | { | ||
343 | sprintf(statustext, "chn: %d/%d", | ||
344 | module->realchn, module->numchn); | ||
345 | } | ||
346 | rb->lcd_putsxy(0, 91, statustext); | ||
347 | |||
348 | rb->lcd_update(); | ||
349 | } | ||
350 | |||
351 | void showsamples() | ||
352 | { | ||
353 | int i, j; | ||
354 | char statustext[LINE_LENGTH]; | ||
355 | |||
356 | if ( screenupdated ) | ||
357 | { | ||
358 | return; | ||
359 | } | ||
360 | rb->lcd_clear_display(); | ||
361 | for( i=0; i<MAX_LINES && i+vscroll<module->numsmp; i++ ) | ||
362 | { | ||
363 | sprintf(statustext, "%02d %s", i+vscroll+1, module->samples[i+vscroll].samplename); | ||
364 | rb->lcd_putsxy(1, 1+(8*i), statustext); | ||
365 | } | ||
366 | rb->lcd_update(); | ||
367 | screenupdated = true; | ||
368 | } | ||
369 | |||
370 | void showinstruments() | ||
371 | { | ||
372 | int i, j; | ||
373 | char statustext[LINE_LENGTH]; | ||
374 | |||
375 | if ( screenupdated ) | ||
376 | { | ||
377 | return; | ||
378 | } | ||
379 | rb->lcd_clear_display(); | ||
380 | for( i=0; i<MAX_LINES && i+vscroll<module->numins; i++ ) | ||
381 | { | ||
382 | sprintf(statustext, "%02d %s", i+vscroll+1, module->instruments[i+vscroll].insname); | ||
383 | rb->lcd_putsxy(1, 1+(8*i), statustext); | ||
384 | } | ||
385 | rb->lcd_update(); | ||
386 | screenupdated = true; | ||
387 | } | ||
388 | |||
389 | void showcomments() | ||
390 | { | ||
391 | int i, j=0, k=0, l; | ||
392 | char statustext[LINE_LENGTH]; | ||
393 | |||
394 | if ( screenupdated ) | ||
395 | { | ||
396 | return; | ||
397 | } | ||
398 | rb->lcd_clear_display(); | ||
399 | |||
400 | for(i=0; module->comment[i]!='\0'; i++) | ||
401 | { | ||
402 | if(module->comment[i] != '\n') | ||
403 | { | ||
404 | statustext[j] = module->comment[i]; | ||
405 | j++; | ||
406 | } | ||
407 | |||
408 | if(module->comment[i] == '\n' || j>LINE_LENGTH-1) | ||
409 | { | ||
410 | rb->lcd_putsxy(1-(6*hscroll), 1+(8*k)-(8*vscroll), statustext); | ||
411 | for( l=0; l<LINE_LENGTH; l++ ) | ||
412 | { | ||
413 | statustext[l] = 0; | ||
414 | } | ||
415 | k++; | ||
416 | j=0; | ||
417 | } | ||
418 | } | ||
419 | if (j>0) | ||
420 | { | ||
421 | rb->lcd_putsxy(1-(6*hscroll), 1+(8*k)-(8*vscroll), statustext); | ||
422 | } | ||
423 | |||
424 | rb->lcd_update(); | ||
425 | screenupdated = true; | ||
426 | } | ||
427 | |||
428 | int changedisplay() | ||
429 | { | ||
430 | display = (display+1) % 4; | ||
431 | |||
432 | if (display == DISPLAY_SAMPLE) | ||
433 | { | ||
434 | textlines = module->numsmp; | ||
435 | } | ||
436 | |||
437 | if (display == DISPLAY_INST) | ||
438 | { | ||
439 | if ( module->flags & UF_INST ) | ||
440 | { | ||
441 | textlines = module->numins; | ||
442 | } | ||
443 | else | ||
444 | { | ||
445 | display = DISPLAY_COMMENTS; | ||
446 | } | ||
447 | } | ||
448 | |||
449 | if (display == DISPLAY_COMMENTS) | ||
450 | { | ||
451 | if (module->comment) | ||
452 | { | ||
453 | textlines = 100; | ||
454 | } | ||
455 | else | ||
456 | { | ||
457 | display = DISPLAY_INFO; | ||
458 | } | ||
459 | } | ||
460 | screenupdated = false; | ||
461 | vscroll = 0; | ||
462 | hscroll = 0; | ||
463 | } | ||
464 | |||
465 | struct mikmod_settings | ||
466 | { | ||
467 | int pansep; | ||
468 | int reverb; | ||
469 | bool interp; | ||
470 | bool reverse; | ||
471 | bool surround; | ||
472 | bool boost; | ||
473 | }; | ||
474 | |||
475 | static struct mikmod_settings settings = | ||
476 | { | ||
477 | 128, | ||
478 | 0, | ||
479 | 0, | ||
480 | 0, | ||
481 | 1, | ||
482 | 1 | ||
483 | }; | ||
484 | |||
485 | static struct mikmod_settings old_settings; | ||
486 | |||
487 | static struct configdata config[] = | ||
488 | { | ||
489 | { TYPE_INT, 0, 128, { .int_p = &settings.pansep }, "Panning Separation", NULL}, | ||
490 | { TYPE_INT, 0, 15, { .int_p = &settings.reverb }, "Reverberation", NULL}, | ||
491 | { TYPE_BOOL, 0, 1, { .bool_p = &settings.interp }, "Interpolation", NULL}, | ||
492 | { TYPE_BOOL, 0, 1, { .bool_p = &settings.reverse }, "Reverse Channels", NULL}, | ||
493 | { TYPE_BOOL, 0, 1, { .bool_p = &settings.surround }, "Surround", NULL}, | ||
494 | { TYPE_BOOL, 0, 1, { .bool_p = &settings.boost }, "CPU Boost", NULL}, | ||
495 | }; | ||
496 | |||
497 | void applysettings() | ||
498 | { | ||
499 | md_pansep = settings.pansep; | ||
500 | md_reverb = settings.reverb; | ||
501 | md_mode = DMODE_STEREO | DMODE_16BITS | DMODE_SOFT_MUSIC | DMODE_SOFT_SNDFX; | ||
502 | if ( settings.interp ) | ||
503 | { | ||
504 | md_mode |= DMODE_INTERP; | ||
505 | } | ||
506 | if ( settings.reverse ) | ||
507 | { | ||
508 | md_mode |= DMODE_REVERSE; | ||
509 | } | ||
510 | if ( settings.surround ) | ||
511 | { | ||
512 | md_mode |= DMODE_SURROUND; | ||
513 | } | ||
514 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
515 | if ( Player_Active() ) | ||
516 | { | ||
517 | rb->cpu_boost(settings.boost); | ||
518 | } | ||
519 | #endif | ||
520 | } | ||
521 | |||
522 | /** | ||
523 | Shows the settings menu | ||
524 | */ | ||
525 | int settings_menu(void) | ||
526 | { | ||
527 | int selection = 0; | ||
528 | bool old_val; | ||
529 | |||
530 | MENUITEM_STRINGLIST(settings_menu, "Mikmod Settings", NULL, "Panning Separation", | ||
531 | "Reverberation", "Interpolation", "Reverse Channels", "Surround", | ||
532 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
533 | "CPU Boost" | ||
534 | #endif | ||
535 | ); | ||
536 | |||
537 | do | ||
538 | { | ||
539 | selection=rb->do_menu(&settings_menu,&selection, NULL, false); | ||
540 | switch(selection) | ||
541 | { | ||
542 | case 0: | ||
543 | rb->set_int("Panning Separation", "", 1, | ||
544 | &(settings.pansep), | ||
545 | NULL, 8, 0, 128, NULL ); | ||
546 | applysettings(); | ||
547 | break; | ||
548 | |||
549 | case 1: | ||
550 | rb->set_int("Reverberation", "", 1, | ||
551 | &(settings.reverb), | ||
552 | NULL, 1, 0, 15, NULL ); | ||
553 | applysettings(); | ||
554 | break; | ||
555 | |||
556 | case 2: | ||
557 | rb->set_bool("Interpolation", &(settings.interp)); | ||
558 | applysettings(); | ||
559 | break; | ||
560 | |||
561 | case 3: | ||
562 | rb->set_bool("Reverse Channels", &(settings.reverse)); | ||
563 | applysettings(); | ||
564 | break; | ||
565 | |||
566 | case 4: | ||
567 | rb->set_bool("Surround", &(settings.surround)); | ||
568 | applysettings(); | ||
569 | break; | ||
570 | |||
571 | case 5: | ||
572 | rb->set_bool("CPU Boost", &(settings.boost)); | ||
573 | applysettings(); | ||
574 | break; | ||
575 | |||
576 | case MENU_ATTACHED_USB: | ||
577 | return PLUGIN_USB_CONNECTED; | ||
578 | } | ||
579 | } while ( selection >= 0 ); | ||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | /** | ||
584 | Show the main menu | ||
585 | */ | ||
586 | int main_menu(void) | ||
587 | { | ||
588 | int selection = 0; | ||
589 | int result; | ||
590 | |||
591 | MENUITEM_STRINGLIST(main_menu,"Mikmod Main Menu",NULL, | ||
592 | "Settings", "Return", "Quit"); | ||
593 | while (1) | ||
594 | { | ||
595 | switch (rb->do_menu(&main_menu,&selection, NULL, false)) | ||
596 | { | ||
597 | case 0: | ||
598 | result = settings_menu(); | ||
599 | if ( result != 0 ) return result; | ||
600 | break; | ||
601 | |||
602 | case 1: | ||
603 | return 0; | ||
604 | |||
605 | case 2: | ||
606 | return -1; | ||
607 | |||
608 | case MENU_ATTACHED_USB: | ||
609 | return PLUGIN_USB_CONNECTED; | ||
610 | |||
611 | default: | ||
612 | return 0; | ||
613 | } | ||
614 | } | ||
615 | } | ||
616 | |||
617 | #ifdef USETHREADS | ||
618 | /* double buffering thread */ | ||
619 | void thread(void) | ||
620 | { | ||
621 | struct queue_event ev; | ||
622 | |||
623 | while (1) | ||
624 | { | ||
625 | synthbuf(); | ||
626 | rb->queue_wait_w_tmo(&thread_q, &ev, HZ/20); | ||
627 | switch (ev.id) { | ||
628 | case EV_EXIT: | ||
629 | return; | ||
630 | } | ||
631 | } | ||
632 | } | ||
633 | #endif | ||
634 | |||
635 | void mm_errorhandler(void) | ||
636 | { | ||
637 | rb->splashf(HZ, "%s", MikMod_strerror(MikMod_errno)); | ||
638 | quit = true; | ||
639 | } | ||
640 | |||
641 | int playfile(char* filename) | ||
642 | { | ||
643 | int vol = 0; | ||
644 | int button; | ||
645 | int retval = PLUGIN_OK; | ||
646 | bool changingpos = false; | ||
647 | int menureturn; | ||
648 | |||
649 | playingtime = 0; | ||
650 | |||
651 | rb->splashf(HZ, "Loading %s", filename); | ||
652 | |||
653 | module = Player_Load(filename, 64, 0); | ||
654 | |||
655 | if (!module) | ||
656 | { | ||
657 | rb->splashf(HZ, "%s", MikMod_strerror(MikMod_errno)); | ||
658 | retval = PLUGIN_ERROR; | ||
659 | quit = true; | ||
660 | } | ||
661 | else | ||
662 | { | ||
663 | display = DISPLAY_INFO; | ||
664 | Player_Start(module); | ||
665 | rb->pcm_play_data(&get_more, NULL, 0); | ||
666 | } | ||
667 | |||
668 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
669 | if ( settings.boost ) | ||
670 | rb->cpu_boost(true); | ||
671 | #endif | ||
672 | #ifdef USETHREADS | ||
673 | rb->queue_init(&thread_q, true); | ||
674 | if ((thread_id = rb->create_thread(thread, thread_stack, | ||
675 | sizeof(thread_stack), 0, "render buffering thread" | ||
676 | IF_PRIO(, PRIORITY_PLAYBACK) | ||
677 | IF_COP(, CPU))) == 0) | ||
678 | { | ||
679 | rb->splash(HZ, "Cannot create thread!"); | ||
680 | return PLUGIN_ERROR; | ||
681 | } | ||
682 | #endif | ||
683 | |||
684 | while (!quit && Player_Active() && retval == PLUGIN_OK) | ||
685 | { | ||
686 | #if !defined(SYNC) && !defined(USETHREADS) | ||
687 | synthbuf(); | ||
688 | #endif | ||
689 | switch (display) | ||
690 | { | ||
691 | case DISPLAY_SAMPLE: | ||
692 | showsamples(); | ||
693 | break; | ||
694 | case DISPLAY_INST: | ||
695 | showinstruments(); | ||
696 | break; | ||
697 | case DISPLAY_COMMENTS: | ||
698 | showcomments(); | ||
699 | break; | ||
700 | default: | ||
701 | showinfo(); | ||
702 | } | ||
703 | |||
704 | rb->yield(); | ||
705 | |||
706 | /* Prevent idle poweroff */ | ||
707 | rb->reset_poweroff_timer(); | ||
708 | |||
709 | button = rb->get_action(CONTEXT_WPS, TIMEOUT_NOBLOCK); | ||
710 | switch (button) | ||
711 | { | ||
712 | case ACTION_WPS_VOLUP: | ||
713 | if ( display != DISPLAY_INFO ) | ||
714 | { | ||
715 | if ( textlines-vscroll >= MAX_LINES ) | ||
716 | { | ||
717 | vscroll++; | ||
718 | screenupdated = false; | ||
719 | } | ||
720 | break; | ||
721 | } | ||
722 | vol = rb->global_settings->volume; | ||
723 | if (vol < rb->sound_max(SOUND_VOLUME)) | ||
724 | { | ||
725 | vol++; | ||
726 | rb->sound_set(SOUND_VOLUME, vol); | ||
727 | rb->global_settings->volume = vol; | ||
728 | } | ||
729 | break; | ||
730 | |||
731 | case ACTION_WPS_VOLDOWN: | ||
732 | if ( display != DISPLAY_INFO ) | ||
733 | { | ||
734 | if ( vscroll > 0 ) | ||
735 | { | ||
736 | vscroll--; | ||
737 | screenupdated = false; | ||
738 | } | ||
739 | break; | ||
740 | } | ||
741 | vol = rb->global_settings->volume; | ||
742 | if (vol > rb->sound_min(SOUND_VOLUME)) | ||
743 | { | ||
744 | vol--; | ||
745 | rb->sound_set(SOUND_VOLUME, vol); | ||
746 | rb->global_settings->volume = vol; | ||
747 | } | ||
748 | break; | ||
749 | |||
750 | case ACTION_WPS_SKIPPREV: | ||
751 | if(entries>1 && !changingpos) | ||
752 | { | ||
753 | if ((int)(module->sngtime >> 10) > 2) | ||
754 | { | ||
755 | Player_SetPosition(0); | ||
756 | module->sngtime = 0; | ||
757 | } | ||
758 | else { | ||
759 | retval = change_filename(DIR_PREV); | ||
760 | } | ||
761 | } | ||
762 | else | ||
763 | { | ||
764 | changingpos = false; | ||
765 | } | ||
766 | break; | ||
767 | case ACTION_WPS_SEEKBACK: | ||
768 | if ( display != DISPLAY_INFO ) | ||
769 | { | ||
770 | if ( hscroll > 0 ) | ||
771 | { | ||
772 | hscroll--; | ||
773 | screenupdated = false; | ||
774 | } | ||
775 | break; | ||
776 | } | ||
777 | Player_PrevPosition(); | ||
778 | changingpos = true; | ||
779 | break; | ||
780 | |||
781 | case ACTION_WPS_SKIPNEXT: | ||
782 | if(entries>1 && !changingpos) | ||
783 | { | ||
784 | retval = change_filename(DIR_NEXT); | ||
785 | } | ||
786 | else | ||
787 | { | ||
788 | changingpos = false; | ||
789 | } | ||
790 | break; | ||
791 | case ACTION_WPS_SEEKFWD: | ||
792 | if ( display != DISPLAY_INFO ) | ||
793 | { | ||
794 | hscroll++; | ||
795 | screenupdated = false; | ||
796 | break; | ||
797 | } | ||
798 | Player_NextPosition(); | ||
799 | changingpos = true; | ||
800 | break; | ||
801 | |||
802 | case ACTION_WPS_PLAY: | ||
803 | if(!Player_Paused()) | ||
804 | { | ||
805 | rb->pcm_play_stop(); | ||
806 | } | ||
807 | else | ||
808 | { | ||
809 | rb->pcm_play_data(&get_more, NULL, 0); | ||
810 | } | ||
811 | Player_TogglePause(); | ||
812 | break; | ||
813 | |||
814 | case ACTION_WPS_BROWSE: | ||
815 | changedisplay(); | ||
816 | break; | ||
817 | |||
818 | case ACTION_WPS_MENU: | ||
819 | menureturn = main_menu(); | ||
820 | if ( menureturn != 0 ) | ||
821 | { | ||
822 | quit = true; | ||
823 | if ( menureturn == PLUGIN_USB_CONNECTED ) | ||
824 | { | ||
825 | retval = menureturn; | ||
826 | } | ||
827 | } | ||
828 | rb->lcd_setfont(0); | ||
829 | screenupdated = false; | ||
830 | break; | ||
831 | |||
832 | case ACTION_WPS_STOP: | ||
833 | quit = true; | ||
834 | break; | ||
835 | |||
836 | default: | ||
837 | if (rb->default_event_handler(button) == SYS_USB_CONNECTED) | ||
838 | { | ||
839 | quit = true; | ||
840 | retval = PLUGIN_USB_CONNECTED; | ||
841 | } | ||
842 | } | ||
843 | } | ||
844 | |||
845 | #ifdef USETHREADS | ||
846 | rb->queue_post(&thread_q, EV_EXIT, 0); | ||
847 | rb->thread_wait(thread_id); | ||
848 | rb->queue_delete(&thread_q); | ||
849 | #endif | ||
850 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
851 | if ( settings.boost ) | ||
852 | rb->cpu_boost(false); | ||
853 | #endif | ||
854 | |||
855 | Player_Stop(); | ||
856 | Player_Free(module); | ||
857 | |||
858 | memset(gmbuf, '\0', sizeof(gmbuf)); | ||
859 | |||
860 | if ( retval == PLUGIN_OK && entries > 1 && !quit ) | ||
861 | { | ||
862 | retval = change_filename(DIR_NEXT); | ||
863 | } | ||
864 | |||
865 | return retval; | ||
866 | } | ||
867 | |||
868 | /* | ||
869 | * Plugin entry point | ||
870 | * | ||
871 | */ | ||
872 | enum plugin_status plugin_start(const void* parameter) | ||
873 | { | ||
874 | enum plugin_status retval; | ||
875 | |||
876 | if (parameter == NULL) | ||
877 | { | ||
878 | rb->splash(HZ*2, " Play .mod, .it, .s3m, .xm file "); | ||
879 | return PLUGIN_OK; | ||
880 | } | ||
881 | |||
882 | rb->lcd_setfont(0); | ||
883 | |||
884 | rb->pcm_play_stop(); | ||
885 | #if INPUT_SRC_CAPS != 0 | ||
886 | /* Select playback */ | ||
887 | rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); | ||
888 | rb->audio_set_output_source(AUDIO_SRC_PLAYBACK); | ||
889 | #endif | ||
890 | rb->pcm_set_frequency(SAMPLE_RATE); | ||
891 | |||
892 | audio_buffer = rb->plugin_get_audio_buffer((size_t *)&audio_buffer_free); | ||
893 | |||
894 | rb->strcpy(np_file, parameter); | ||
895 | get_mod_list(); | ||
896 | if(!entries) { | ||
897 | return PLUGIN_ERROR; | ||
898 | } | ||
899 | |||
900 | //add_pool(audio_buffer, audio_buffer_free); | ||
901 | init_memory_pool(audio_buffer_free, audio_buffer); | ||
902 | |||
903 | MikMod_RegisterDriver(&drv_nos); | ||
904 | MikMod_RegisterAllLoaders(); | ||
905 | MikMod_RegisterErrorHandler(mm_errorhandler); | ||
906 | |||
907 | md_mixfreq = SAMPLE_RATE; | ||
908 | |||
909 | configfile_load(MIKMOD_CONFIGFILE, config, | ||
910 | ARRAYLEN(config), MIKMOD_SETTINGS_MINVERSION); | ||
911 | rb->memcpy(&old_settings, &settings, sizeof (settings)); | ||
912 | applysettings(); | ||
913 | |||
914 | if (MikMod_Init("")) | ||
915 | { | ||
916 | rb->splashf(HZ, "%s", MikMod_strerror(MikMod_errno)); | ||
917 | return PLUGIN_ERROR; | ||
918 | } | ||
919 | |||
920 | do | ||
921 | { | ||
922 | retval = playfile(np_file); | ||
923 | } while (retval == PLUGIN_NEWSONG); | ||
924 | |||
925 | MikMod_Exit(); | ||
926 | |||
927 | rb->pcm_play_stop(); | ||
928 | rb->pcm_set_frequency(HW_SAMPR_DEFAULT); | ||
929 | |||
930 | if (retval == PLUGIN_OK) | ||
931 | { | ||
932 | rb->splash(0, "Saving Settings"); | ||
933 | if (rb->memcmp(&settings, &old_settings, sizeof (settings))) | ||
934 | { | ||
935 | configfile_save(MIKMOD_CONFIGFILE, config, | ||
936 | ARRAYLEN(config), MIKMOD_SETTINGS_MINVERSION); | ||
937 | } | ||
938 | } | ||
939 | |||
940 | destroy_memory_pool(audio_buffer); | ||
941 | |||
942 | return retval; | ||
943 | } | ||