summaryrefslogtreecommitdiff
path: root/apps/plugins/mikmod/mikmod.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/mikmod/mikmod.c')
-rw-r--r--apps/plugins/mikmod/mikmod.c943
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
33static unsigned int thread_id;
34static struct event_queue thread_q;
35/* use long for aligning */
36unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)];
37#endif
38
39/* the current full file name */
40static char np_file[MAX_PATH];
41static int curfile = 0, direction = DIR_NEXT, entries = 0;
42
43/* list of the mod files */
44static char **file_pt;
45
46
47/* The MP3 audio buffer which we will use as heap memory */
48static unsigned char* audio_buffer;
49/* amount of bytes left in audio_buffer */
50static size_t audio_buffer_free;
51
52
53/* The rockbox plugin interface */
54MEM_FUNCTION_WRAPPERS;
55
56bool quit;
57int playingtime IBSS_ATTR;
58MODULE *module IBSS_ATTR;
59char gmbuf[BUF_SIZE*NBUF];
60
61
62int textlines;
63int vscroll = 0;
64int hscroll = 0;
65bool screenupdated = false;
66
67enum {
68 DISPLAY_INFO = 0,
69 DISPLAY_SAMPLE,
70 DISPLAY_INST,
71 DISPLAY_COMMENTS,
72} display;
73
74
75/*
76* strncat wrapper
77*/
78char* 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*/
102int 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*/
117void 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() */
150static int compare(const void* p1, const void* p2)
151{
152 return rb->strcasecmp(*((char **)p1), *((char **)p2));
153}
154
155bool 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. */
185void 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
215int 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
253bool swap = false;
254bool lastswap = true;
255
256static 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
272void 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
293void 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
351void 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
370void 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
389void 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
428int 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
465struct mikmod_settings
466{
467 int pansep;
468 int reverb;
469 bool interp;
470 bool reverse;
471 bool surround;
472 bool boost;
473};
474
475static struct mikmod_settings settings =
476{
477 128,
478 0,
479 0,
480 0,
481 1,
482 1
483};
484
485static struct mikmod_settings old_settings;
486
487static 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
497void 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 */
525int 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 */
586int 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 */
619void 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
635void mm_errorhandler(void)
636{
637 rb->splashf(HZ, "%s", MikMod_strerror(MikMod_errno));
638 quit = true;
639}
640
641int 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*/
872enum 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}