1 /***************************************************************************
\r
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
\r
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
\r
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
\r
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
\r
10 * All files in this archive are subject to the GNU General Public License.
\r
11 * See the file COPYING in the source tree root for full license agreement.
\r
13 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
\r
14 * KIND, either express or implied.
\r
16 ****************************************************************************/
\r
18 #include "mikmod_build.h"
\r
22 struct plugin_api *rb;
\r
26 #define MAXPCMBUFFERS 16 // Do NOT set this to a value lower than 2 or playback will break
\r
27 #define PCMBUFFERSIZE 65536
\r
29 char *pcmbufs[MAXPCMBUFFERS];
\r
30 int bufferlen[MAXPCMBUFFERS];
\r
31 int buffercount = 0;
\r
36 size_t buffrendered = 0;
\r
37 size_t buffplayed = 0;
\r
38 size_t buff_last = ~0;
\r
40 int vol, minvol, maxvol;
\r
41 int lastpower = 0, lastvol = 0;
\r
50 void mikmod_prepare_malloc(char *buff, int bufsize);
\r
51 long mikmod_get_malloc_usage(void);
\r
52 void* mikmod_malloc(size_t size);
\r
56 int FindLastOccurrenceChar(char *string, char chr)
\r
62 while (string[i] != 0)
\r
64 if (string[i] == chr)
\r
76 void get_more(unsigned char **start, size_t *size)
\r
78 if (curbuff >= (buffercount - 1))
\r
86 *start = pcmbufs[curbuff];
\r
87 *size = bufferlen[curbuff];
\r
92 void checkbutton(void)
\r
94 lastbutton = rb->button_get(false);
\r
95 if (lastbutton & BUTTON_MENU)
\r
100 switch (lastbutton)
\r
102 case BUTTON_SCROLL_FWD:
\r
103 case (BUTTON_SCROLL_FWD | BUTTON_REPEAT):
\r
104 vol = rb->global_settings->volume;
\r
109 rb->sound_set(SOUND_VOLUME, vol);
\r
110 rb->global_settings->volume = vol;
\r
114 case BUTTON_SCROLL_BACK:
\r
115 case (BUTTON_SCROLL_BACK | BUTTON_REPEAT):
\r
116 vol = rb->global_settings->volume;
\r
121 rb->sound_set(SOUND_VOLUME, vol);
\r
122 rb->global_settings->volume = vol;
\r
126 case (BUTTON_PLAY | BUTTON_REL):
\r
128 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
\r
129 rb->cpu_boost(false); // Just in case we got called from inside the render loop
\r
131 rb->pcm_play_pause(false);
\r
132 do /* code from mpegplayer, *very* simple unpause loop */
\r
134 lastbutton = rb->button_get(true);
\r
135 if (lastbutton == BUTTON_MENU)
\r
139 } while (lastbutton != (BUTTON_PLAY | BUTTON_REL));
\r
140 rb->pcm_play_pause(true);
\r
144 if(rb->default_event_handler(lastbutton) == SYS_USB_CONNECTED)
\r
148 } /* switch(button) */
\r
150 if ((rb->global_settings->volume != lastvol) || (rb->battery_level() != lastpower))
\r
152 lastpower = rb->battery_level();
\r
153 lastvol = rb->global_settings->volume;
\r
155 rb->snprintf(sbuf, sizeof(sbuf) - 1, "%d dB ", rb->global_settings->volume);
\r
156 rb->lcd_puts(5, 3, sbuf);
\r
157 rb->snprintf(sbuf, sizeof(sbuf) - 1, "%d %% ", rb->battery_level());
\r
158 rb->lcd_puts(5, 4, sbuf);
\r
166 void mainloop(void)
\r
170 minvol = rb->sound_min(SOUND_VOLUME);
\r
171 maxvol = rb->sound_max(SOUND_VOLUME);
\r
173 while (buffplayed <= buff_last && !lastbutton)
\r
175 while (curbuff != lastbuff && !lastbutton) // Render loop, fills up all buffers except the one being played
\r
178 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
\r
179 rb->cpu_boost(true);
\r
184 if (Player_Active())
\r
186 bufferlen[lastbuff] = VC_WriteBytes(pcmbufs[lastbuff], PCMBUFFERSIZE);
\r
191 // No more data to render (songend) - clear the next buffer so get_more() can return it a last time
\r
192 for (i = 0; i < PCMBUFFERSIZE; i++)
\r
193 (pcmbufs[lastbuff])[i] = 0;
\r
194 bufferlen[lastbuff] = PCMBUFFERSIZE;
\r
195 buff_last = buffrendered;
\r
198 if (lastbuff >= (buffercount - 1))
\r
204 rb->reset_poweroff_timer();
\r
206 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
\r
207 rb->cpu_boost(false);
\r
223 enum plugin_status plugin_start(struct plugin_api *api, void *parameter)
\r
230 /* Have to shut up voice menus or it will mess up our waveform playback */
\r
231 talk_menu = rb->global_settings->talk_menu;
\r
232 rb->global_settings->talk_menu = false;
\r
235 rb->pcm_play_stop();
\r
236 rb->pcm_set_frequency(44100);
\r
238 // Initialize internal semi-dynamic memory
\r
239 mbuf = rb->plugin_get_audio_buffer(&mallocbufsize);
\r
240 mikmod_prepare_malloc(mbuf, mallocbufsize);
\r
243 // Allocate PCM output buffers
\r
244 for (i = 0; i < MAXPCMBUFFERS; i++)
\r
246 if ((pcmbufs[i] = mikmod_malloc(PCMBUFFERSIZE)) == NULL)
\r
252 //lastbuff = buffercount - 1;
\r
253 // Prefill buffers !
\r
256 // General output...
\r
257 rb->lcd_clear_display();
\r
258 rb->lcd_puts(0, 0, " MikMod for Rockbox 0.1");
\r
259 rb->lcd_puts(0, 1, "========================");
\r
261 rb->lcd_puts(0, 3, "Vol: -");
\r
262 rb->lcd_puts(0, 4, "Pwr: -");
\r
263 rb->lcd_puts(0, 5, "---------");
\r
264 rb->lcd_puts(0, 6, "File:");
\r
265 rb->lcd_puts(7, 6, &((char*)parameter)[FindLastOccurrenceChar(parameter, '/') + 1]);
\r
269 //initialize the library
\r
270 MikMod_RegisterAllLoaders();
\r
271 md_mode = DMODE_SOFT_MUSIC | DMODE_16BITS | DMODE_STEREO | DMODE_INTERP | DMODE_SOFT_SNDFX;
\r
273 if (!MikMod_Init(""))
\r
275 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
\r
276 rb->cpu_boost(true);
\r
279 module = Player_Load(parameter, 32, 1);
\r
281 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
\r
282 rb->cpu_boost(false);
\r
287 Player_Start(module);
\r
292 rb->snprintf(sbuf, sizeof(sbuf) - 1, "Memory: %d / %d", (int)(mikmod_get_malloc_usage() - (buffercount * PCMBUFFERSIZE)), mallocbufsize);
\r
293 rb->lcd_puts(0, 16, sbuf);
\r
295 rb->lcd_puts(0, 7, "Type:");
\r
296 rb->lcd_puts(7, 7, module->modtype);
\r
298 rb->lcd_puts(0, 9, "Title:");
\r
299 rb->lcd_puts_scroll(7, 9, module->songname);
\r
303 // Only prefill the first buffer so we get a quick start...
\r
304 bufferlen[0] = VC_WriteBytes(pcmbufs[0], PCMBUFFERSIZE);
\r
306 curbuff = buffercount - 1;
\r
307 lastbuff = 1; // Fixes skip during first buffers played
\r
309 rb->pcm_play_data(get_more, NULL, 0);
\r
316 rb->splash(HZ*2, "Could not load module, reason:");
\r
317 rb->splash(HZ*2, MikMod_strerror(MikMod_errno));
\r
320 else /* MikMod_Init */
\r
322 rb->splash(HZ*2, "Could not initialize sound, reason:");
\r
323 rb->splash(HZ*2, MikMod_strerror(MikMod_errno));
\r
327 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
\r
328 rb->cpu_boost(false);
\r
331 rb->pcm_play_stop();
\r
334 Player_Free(module);
\r
338 //restore default - user of apis is responsible for restoring
\r
339 // default state - normally playback at 44100Hz
\r
340 rb->pcm_set_frequency(HW_SAMPR_DEFAULT);
\r
341 rb->global_settings->talk_menu = talk_menu;
\r
343 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
\r
344 rb->cpu_boost(false);
\r