Add the identifying header
[kugel-rb.git] / apps / plugins / midi / midiplay.c
blob69c137e26815ad72df7a156b9793e5c02817ec66
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 Karl Kurbjun based on midi2wav by Stepan Moskovchenko
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include "plugin.h"
22 #include "guspat.h"
23 #include "midiutil.h"
24 #include "synth.h"
25 #include "sequencer.h"
26 #include "midifile.h"
28 PLUGIN_HEADER
29 PLUGIN_IRAM_DECLARE
31 /* variable button definitions */
32 #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
33 #define BTN_QUIT BUTTON_OFF
34 #define BTN_RIGHT BUTTON_RIGHT
35 #define BTN_UP BUTTON_UP
36 #define BTN_DOWN BUTTON_DOWN
37 #define BTN_LEFT BUTTON_LEFT
38 #define BTN_RC_QUIT BUTTON_RC_STOP
39 #define BTN_PLAY BUTTON_ON
41 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
42 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
43 #define BTN_QUIT (BUTTON_SELECT | BUTTON_MENU)
44 #define BTN_RIGHT BUTTON_RIGHT
45 #define BTN_LEFT BUTTON_LEFT
46 #define BTN_UP BUTTON_SCROLL_FWD
47 #define BTN_DOWN BUTTON_SCROLL_BACK
48 #define BTN_PLAY BUTTON_PLAY
51 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
52 #define BTN_QUIT BUTTON_POWER
53 #define BTN_RIGHT BUTTON_RIGHT
54 #define BTN_LEFT BUTTON_LEFT
55 #define BTN_UP BUTTON_UP
56 #define BTN_DOWN BUTTON_DOWN
57 #define BTN_PLAY BUTTON_A
60 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
61 #define BTN_QUIT BUTTON_POWER
62 #define BTN_RIGHT BUTTON_RIGHT
63 #define BTN_LEFT BUTTON_LEFT
64 #define BTN_UP BUTTON_UP
65 #define BTN_DOWN BUTTON_DOWN
66 #define BTN_PLAY BUTTON_PLAY
69 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
70 #define BTN_QUIT BUTTON_POWER
71 #define BTN_RIGHT BUTTON_RIGHT
72 #define BTN_LEFT BUTTON_LEFT
73 #define BTN_UP BUTTON_SCROLL_FWD
74 #define BTN_DOWN BUTTON_SCROLL_BACK
75 #define BTN_PLAY BUTTON_UP
77 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
78 #define BTN_QUIT (BUTTON_HOME|BUTTON_REPEAT)
79 #define BTN_RIGHT BUTTON_RIGHT
80 #define BTN_LEFT BUTTON_LEFT
81 #define BTN_UP BUTTON_SCROLL_FWD
82 #define BTN_DOWN BUTTON_SCROLL_BACK
83 #define BTN_PLAY BUTTON_UP
86 #elif (CONFIG_KEYPAD == SANSA_C200_PAD) || \
87 (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
88 (CONFIG_KEYPAD == SANSA_M200_PAD)
89 #define BTN_QUIT BUTTON_POWER
90 #define BTN_RIGHT BUTTON_RIGHT
91 #define BTN_LEFT BUTTON_LEFT
92 #define BTN_UP BUTTON_VOL_UP
93 #define BTN_DOWN BUTTON_VOL_DOWN
94 #define BTN_PLAY BUTTON_UP
97 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
98 #define BTN_QUIT BUTTON_POWER
99 #define BTN_RIGHT BUTTON_RIGHT
100 #define BTN_LEFT BUTTON_LEFT
101 #define BTN_UP BUTTON_UP
102 #define BTN_DOWN BUTTON_DOWN
103 #define BTN_PLAY BUTTON_PLAY
106 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
107 #define BTN_QUIT BUTTON_POWER
108 #define BTN_RIGHT BUTTON_RIGHT
109 #define BTN_LEFT BUTTON_LEFT
110 #define BTN_UP BUTTON_SCROLL_UP
111 #define BTN_DOWN BUTTON_SCROLL_DOWN
112 #define BTN_PLAY BUTTON_PLAY
115 #elif CONFIG_KEYPAD == MROBE500_PAD
116 #define BTN_QUIT BUTTON_POWER
117 #define BTN_RIGHT BUTTON_RIGHT
118 #define BTN_LEFT BUTTON_LEFT
119 #define BTN_UP BUTTON_RC_PLAY
120 #define BTN_DOWN BUTTON_RC_DOWN
121 #define BTN_PLAY BUTTON_RC_HEART
124 #elif (CONFIG_KEYPAD == MROBE100_PAD)
125 #define BTN_QUIT BUTTON_POWER
126 #define BTN_RIGHT BUTTON_RIGHT
127 #define BTN_LEFT BUTTON_LEFT
128 #define BTN_UP BUTTON_UP
129 #define BTN_DOWN BUTTON_DOWN
130 #define BTN_PLAY BUTTON_DISPLAY
133 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
134 #define BTN_QUIT BUTTON_RC_REC
135 #define BTN_RIGHT BUTTON_RC_FF
136 #define BTN_LEFT BUTTON_RC_REW
137 #define BTN_UP BUTTON_RC_VOL_UP
138 #define BTN_DOWN BUTTON_RC_VOL_DOWN
139 #define BTN_PLAY BUTTON_RC_PLAY
142 #elif CONFIG_KEYPAD == COWON_D2_PAD
143 #define BTN_QUIT BUTTON_POWER
145 #elif CONFIG_KEYPAD == IAUDIO67_PAD
146 #define BTN_QUIT BUTTON_POWER
147 #define BTN_RIGHT BUTTON_RIGHT
148 #define BTN_LEFT BUTTON_LEFT
149 #define BTN_UP BUTTON_STOP
150 #define BTN_DOWN BUTTON_PLAY
151 #define BTN_PLAY BUTTON_MENU
153 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
154 #define BTN_QUIT BUTTON_BACK
155 #define BTN_RIGHT BUTTON_RIGHT
156 #define BTN_LEFT BUTTON_LEFT
157 #define BTN_UP BUTTON_UP
158 #define BTN_DOWN BUTTON_DOWN
159 #define BTN_PLAY BUTTON_PLAY
161 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
162 #define BTN_QUIT BUTTON_POWER
163 #define BTN_RIGHT BUTTON_RIGHT
164 #define BTN_LEFT BUTTON_LEFT
165 #define BTN_UP BUTTON_UP
166 #define BTN_DOWN BUTTON_DOWN
167 #define BTN_PLAY BUTTON_MENU
169 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
170 #define BTN_QUIT BUTTON_POWER
171 #define BTN_RIGHT BUTTON_NEXT
172 #define BTN_LEFT BUTTON_PREV
173 #define BTN_UP BUTTON_UP
174 #define BTN_DOWN BUTTON_DOWN
175 #define BTN_PLAY BUTTON_MENU
177 #elif CONFIG_KEYPAD == ONDAVX747_PAD
178 #define BTN_QUIT BUTTON_POWER
179 #elif CONFIG_KEYPAD == ONDAVX777_PAD
180 #define BTN_QUIT BUTTON_POWER
182 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
183 #define BTN_QUIT BUTTON_REW
184 #define BTN_RIGHT BUTTON_RIGHT
185 #define BTN_LEFT BUTTON_LEFT
186 #define BTN_UP BUTTON_UP
187 #define BTN_DOWN BUTTON_DOWN
188 #define BTN_PLAY BUTTON_PLAY
190 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
191 #define BTN_QUIT BUTTON_REC
192 #define BTN_RIGHT BUTTON_NEXT
193 #define BTN_LEFT BUTTON_PREV
194 #define BTN_UP BUTTON_UP
195 #define BTN_DOWN BUTTON_DOWN
196 #define BTN_PLAY BUTTON_PLAY
198 #else
199 #error No keymap defined!
200 #endif
202 #ifdef HAVE_TOUCHSCREEN
203 #ifndef BTN_QUIT
204 #define BTN_QUIT BUTTON_TOPLEFT
205 #endif
206 #ifndef BTN_RIGHT
207 #define BTN_RIGHT BUTTON_MIDRIGHT
208 #endif
209 #ifndef BTN_LEFT
210 #define BTN_LEFT BUTTON_MIDLEFT
211 #endif
212 #ifndef BTN_UP
213 #define BTN_UP BUTTON_TOPMIDDLE
214 #endif
215 #ifndef BTN_DOWN
216 #define BTN_DOWN BUTTON_BOTTOMMIDDLE
217 #endif
218 #ifndef BTN_PLAY
219 #define BTN_PLAY BUTTON_CENTER
220 #endif
221 #endif
223 #undef SYNC
225 #ifdef SIMULATOR
226 #define SYNC
227 #endif
229 struct MIDIfile * mf IBSS_ATTR;
231 int number_of_samples IBSS_ATTR; /* the number of samples in the current tick */
232 int playing_time IBSS_ATTR; /* How many seconds into the file have we been playing? */
233 int samples_this_second IBSS_ATTR; /* How many samples produced during this second so far? */
234 long bpm IBSS_ATTR;
236 int32_t gmbuf[BUF_SIZE*NBUF];
237 static unsigned int samples_in_buf;
239 bool quit = false;
240 bool swap = false;
241 bool lastswap = true;
243 static inline void synthbuf(void)
245 int32_t *outptr;
246 int i = BUF_SIZE;
248 #ifndef SYNC
249 if (lastswap == swap)
250 return;
251 lastswap = swap;
253 outptr = (swap ? gmbuf : gmbuf+BUF_SIZE);
254 #else
255 outptr = gmbuf;
256 #endif
258 /* synth samples for as many whole ticks as we can fit in the buffer */
259 for (; i >= number_of_samples; i -= number_of_samples)
261 synthSamples((int32_t*)outptr, number_of_samples);
262 outptr += number_of_samples;
263 #ifndef SYNC
264 /* synthbuf is called in interrupt context is SYNC is defined so it cannot yield
265 that bug causing the sim to crach when not using SYNC should really be fixed */
266 rb->yield();
267 #endif
268 if (tick() == 0)
269 quit = true;
272 /* how many samples did we write to the buffer? */
273 samples_in_buf = BUF_SIZE-i;
276 void get_more(unsigned char** start, size_t* size)
278 #ifndef SYNC
279 if(lastswap != swap)
281 printf("Buffer miss!"); /* Comment out the printf to make missses less noticable. */
284 #else
285 synthbuf(); /* For some reason midiplayer crashes when an update is forced */
286 #endif
288 *size = samples_in_buf*sizeof(int32_t);
289 #ifndef SYNC
290 *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE));
291 swap = !swap;
292 #else
293 *start = (unsigned char*)(gmbuf);
294 #endif
297 static int midimain(const void * filename)
299 int a, notes_used, vol;
300 bool is_playing = true; /* false = paused */
302 printf("Loading file");
303 mf = loadFile(filename);
305 if (mf == NULL)
307 printf("Error loading file.");
308 return -1;
311 if (initSynth(mf, ROCKBOX_DIR "/patchset/patchset.cfg",
312 ROCKBOX_DIR "/patchset/drums.cfg") == -1)
313 return -1;
315 rb->pcm_play_stop();
316 #if INPUT_SRC_CAPS != 0
317 /* Select playback */
318 rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
319 rb->audio_set_output_source(AUDIO_SRC_PLAYBACK);
320 #endif
321 rb->pcm_set_frequency(SAMPLE_RATE); /* 44100 22050 11025 */
324 * tick() will do one MIDI clock tick. Then, there's a loop here that
325 * will generate the right number of samples per MIDI tick. The whole
326 * MIDI playback is timed in terms of this value.. there are no forced
327 * delays or anything. It just produces enough samples for each tick, and
328 * the playback of these samples is what makes the timings right.
330 * This seems to work quite well. On a laptop, anyway.
333 printf("Okay, starting sequencing");
335 bpm = mf->div*1000000/tempo;
336 number_of_samples = SAMPLE_RATE/bpm;
338 /* Skip over any junk in the beginning of the file, so start playing */
339 /* after the first note event */
342 notes_used = 0;
343 for (a = 0; a < MAX_VOICES; a++)
344 if (voices[a].isUsed)
345 notes_used++;
346 tick();
347 } while (notes_used == 0);
349 playing_time = 0;
350 samples_this_second = 0;
352 synthbuf();
353 rb->pcm_play_data(&get_more, NULL, 0);
355 while (!quit)
357 #ifndef SYNC
358 synthbuf();
359 #endif
360 rb->yield();
362 /* Prevent idle poweroff */
363 rb->reset_poweroff_timer();
365 /* Code taken from Oscilloscope plugin */
366 switch (rb->button_get(false))
368 case BTN_UP:
369 case BTN_UP | BUTTON_REPEAT:
371 vol = rb->global_settings->volume;
372 if (vol < rb->sound_max(SOUND_VOLUME))
374 vol++;
375 rb->sound_set(SOUND_VOLUME, vol);
376 rb->global_settings->volume = vol;
378 break;
381 case BTN_DOWN:
382 case BTN_DOWN | BUTTON_REPEAT:
384 vol = rb->global_settings->volume;
385 if (vol > rb->sound_min(SOUND_VOLUME))
387 vol--;
388 rb->sound_set(SOUND_VOLUME, vol);
389 rb->global_settings->volume = vol;
391 break;
394 case BTN_LEFT:
396 /* Rewinding is tricky. Basically start the file over */
397 /* but run through the tracks without the synth running */
398 rb->pcm_play_stop();
399 seekBackward(5);
400 printf("Rewind to %d:%02d\n", playing_time/60, playing_time%60);
401 if (is_playing)
402 rb->pcm_play_data(&get_more, NULL, 0);
403 break;
406 case BTN_RIGHT:
408 rb->pcm_play_stop();
409 seekForward(5);
410 printf("Skip to %d:%02d\n", playing_time/60, playing_time%60);
411 if (is_playing)
412 rb->pcm_play_data(&get_more, NULL, 0);
413 break;
416 case BTN_PLAY:
418 if (is_playing)
420 printf("Paused at %d:%02d\n", playing_time/60, playing_time%60);
421 is_playing = false;
422 rb->pcm_play_stop();
423 } else
425 printf("Playing from %d:%02d\n", playing_time/60, playing_time%60);
426 is_playing = true;
427 rb->pcm_play_data(&get_more, NULL, 0);
429 break;
432 #ifdef BTN_RC_QUIT
433 case BTN_RC_QUIT:
434 #endif
435 case BTN_QUIT:
436 quit = true;
439 return 0;
442 enum plugin_status plugin_start(const void* parameter)
444 int retval;
445 PLUGIN_IRAM_INIT(rb)
447 if (parameter == NULL)
449 rb->splash(HZ*2, " Play .MID file ");
450 return PLUGIN_OK;
452 rb->lcd_setfont(0);
454 #if defined(HAVE_ADJUSTABLE_CPU_FREQ)
455 rb->cpu_boost(true);
456 #endif
458 printf("%s", parameter);
459 /* rb->splash(HZ, true, parameter); */
461 #ifdef RB_PROFILE
462 rb->profile_thread();
463 #endif
465 retval = midimain(parameter);
467 #ifdef RB_PROFILE
468 rb->profstop();
469 #endif
471 rb->pcm_play_stop();
472 rb->pcm_set_frequency(HW_SAMPR_DEFAULT);
474 #if defined(HAVE_ADJUSTABLE_CPU_FREQ)
475 rb->cpu_boost(false);
476 #endif
477 rb->splash(HZ, "FINISHED PLAYING");
479 if (retval == -1)
480 return PLUGIN_ERROR;
481 return PLUGIN_OK;