Accept FS#8341 - rename BUTTON_SCROLL_UP/DOWN to FWD/BACK on the e200 to make it...
[Rockbox.git] / apps / plugins / midi / midiplay.c
blob07ecb56934563aa7e8e98f36b667d6fcd0d13a4d
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 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include "plugin.h"
20 #include "guspat.h"
21 #include "midiutil.h"
22 #include "synth.h"
23 #include "sequencer.h"
24 #include "midifile.h"
26 PLUGIN_HEADER
27 PLUGIN_IRAM_DECLARE
29 /* variable button definitions */
30 #if CONFIG_KEYPAD == RECORDER_PAD
31 #define BTN_QUIT BUTTON_OFF
32 #define BTN_RIGHT BUTTON_RIGHT
33 #define BTN_UP BUTTON_UP
34 #define BTN_DOWN BUTTON_DOWN
35 #define BTN_LEFT BUTTON_LEFT
36 #define BTN_PLAY BUTTON_PLAY
38 #elif CONFIG_KEYPAD == ONDIO_PAD
39 #define BTN_QUIT BUTTON_OFF
40 #define BTN_RIGHT BUTTON_RIGHT
41 #define BTN_UP BUTTON_UP
42 #define BTN_DOWN BUTTON_DOWN
43 #define BTN_LEFT BUTTON_LEFT
44 #define BTN_PLAY (BUTTON_MENU | BUTTON_OFF)
47 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
48 #define BTN_QUIT BUTTON_OFF
49 #define BTN_RIGHT BUTTON_RIGHT
50 #define BTN_UP BUTTON_UP
51 #define BTN_DOWN BUTTON_DOWN
52 #define BTN_LEFT BUTTON_LEFT
53 #define BTN_RC_QUIT BUTTON_RC_STOP
54 #define BTN_PLAY BUTTON_ON
56 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
57 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
58 #define BTN_QUIT (BUTTON_SELECT | BUTTON_MENU)
59 #define BTN_RIGHT BUTTON_RIGHT
60 #define BTN_LEFT BUTTON_LEFT
61 #define BTN_UP BUTTON_SCROLL_FWD
62 #define BTN_DOWN BUTTON_SCROLL_BACK
63 #define BTN_PLAY BUTTON_PLAY
66 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
67 #define BTN_QUIT BUTTON_POWER
68 #define BTN_RIGHT BUTTON_RIGHT
69 #define BTN_LEFT BUTTON_LEFT
70 #define BTN_UP BUTTON_UP
71 #define BTN_DOWN BUTTON_DOWN
72 #define BTN_PLAY BUTTON_A
75 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
76 #define BTN_QUIT BUTTON_POWER
77 #define BTN_RIGHT BUTTON_RIGHT
78 #define BTN_LEFT BUTTON_LEFT
79 #define BTN_UP BUTTON_SCROLL_FWD
80 #define BTN_DOWN BUTTON_SCROLL_BACK
81 #define BTN_PLAY BUTTON_UP
84 #elif (CONFIG_KEYPAD == SANSA_C200_PAD)
85 #define BTN_QUIT BUTTON_POWER
86 #define BTN_RIGHT BUTTON_RIGHT
87 #define BTN_LEFT BUTTON_LEFT
88 #define BTN_UP BUTTON_UP
89 #define BTN_DOWN BUTTON_DOWN
90 #define BTN_PLAY BUTTON_REC
93 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
94 #define BTN_QUIT BUTTON_POWER
95 #define BTN_RIGHT BUTTON_RIGHT
96 #define BTN_LEFT BUTTON_LEFT
97 #define BTN_UP BUTTON_UP
98 #define BTN_DOWN BUTTON_DOWN
99 #define BTN_PLAY BUTTON_PLAY
102 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
103 #define BTN_QUIT BUTTON_POWER
104 #define BTN_RIGHT BUTTON_RIGHT
105 #define BTN_LEFT BUTTON_LEFT
106 #define BTN_UP BUTTON_SCROLL_UP
107 #define BTN_DOWN BUTTON_SCROLL_DOWN
108 #define BTN_PLAY BUTTON_PLAY
111 #elif CONFIG_KEYPAD == MROBE500_PAD
112 #define BTN_QUIT BUTTON_POWER
113 #define BTN_RIGHT BUTTON_RIGHT
114 #define BTN_LEFT BUTTON_LEFT
115 #define BTN_UP BUTTON_RC_PLAY
116 #define BTN_DOWN BUTTON_RC_DOWN
117 #define BTN_PLAY BUTTON_RC_HEART
120 #endif
122 #undef SYNC
124 #ifdef SIMULATOR
125 #define SYNC
126 #endif
128 struct MIDIfile * mf IBSS_ATTR;
130 int numberOfSamples IBSS_ATTR; /* the number of samples in the current tick */
131 int playingTime IBSS_ATTR; /* How many seconds into the file have we been playing? */
132 int samplesThisSecond IBSS_ATTR; /* How many samples produced during this second so far? */
134 long bpm IBSS_ATTR;
136 int32_t gmbuf[BUF_SIZE*NBUF];
137 static unsigned int samples_in_buf;
139 int quit=0;
140 struct plugin_api * rb;
142 static int midimain(void * filename);
144 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
146 int retval = 0;
149 PLUGIN_IRAM_INIT(api)
151 rb = api;
152 if(parameter == NULL)
154 rb->splash(HZ*2, " Play .MID file ");
155 return PLUGIN_OK;
157 rb->lcd_setfont(0);
159 #if defined(HAVE_ADJUSTABLE_CPU_FREQ)
160 rb->cpu_boost(true);
161 #endif
163 printf("%s", parameter);
164 /* rb->splash(HZ, true, parameter); */
166 #ifdef RB_PROFILE
167 rb->profile_thread();
168 #endif
170 retval = midimain(parameter);
172 #ifdef RB_PROFILE
173 rb->profstop();
174 #endif
176 rb->pcm_play_stop();
177 rb->pcm_set_frequency(HW_SAMPR_DEFAULT);
179 #if defined(HAVE_ADJUSTABLE_CPU_FREQ)
180 rb->cpu_boost(false);
181 #endif
182 rb->splash(HZ, "FINISHED PLAYING");
184 if(retval == -1)
185 return PLUGIN_ERROR;
186 return PLUGIN_OK;
189 bool swap=0;
190 bool lastswap=1;
192 static inline void synthbuf(void)
194 int32_t *outptr;
195 int i=BUF_SIZE;
197 #ifndef SYNC
198 if(lastswap==swap) return;
199 lastswap=swap;
201 outptr=(swap ? gmbuf : gmbuf+BUF_SIZE);
202 #else
203 outptr=gmbuf;
204 #endif
206 /* synth samples for as many whole ticks as we can fit in the buffer */
207 for(; i >= numberOfSamples; i -= numberOfSamples)
209 synthSamples((int32_t*)outptr, numberOfSamples);
210 outptr += numberOfSamples;
211 if( tick() == 0 )
212 quit=1;
215 /* how many samples did we write to the buffer? */
216 samples_in_buf = BUF_SIZE-i;
220 void get_more(unsigned char** start, size_t* size)
222 #ifndef SYNC
223 if(lastswap!=swap)
225 printf("Buffer miss!"); // Comment out the printf to make missses less noticable.
228 #else
229 synthbuf(); // For some reason midiplayer crashes when an update is forced
230 #endif
232 *size = samples_in_buf*sizeof(int32_t);
233 #ifndef SYNC
234 *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE));
235 swap=!swap;
236 #else
237 *start = (unsigned char*)(gmbuf);
238 #endif
241 static int midimain(void * filename)
243 int notesUsed = 0;
244 int a=0;
245 printf("Loading file");
246 mf= loadFile(filename);
248 if(mf == NULL)
250 printf("Error loading file.");
251 return -1;
254 if (initSynth(mf, ROCKBOX_DIR "/patchset/patchset.cfg",
255 ROCKBOX_DIR "/patchset/drums.cfg") == -1)
256 return -1;
258 rb->pcm_play_stop();
259 #if INPUT_SRC_CAPS != 0
260 /* Select playback */
261 rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
262 rb->audio_set_output_source(AUDIO_SRC_PLAYBACK);
263 #endif
264 rb->pcm_set_frequency(SAMPLE_RATE); // 44100 22050 11025
267 * tick() will do one MIDI clock tick. Then, there's a loop here that
268 * will generate the right number of samples per MIDI tick. The whole
269 * MIDI playback is timed in terms of this value.. there are no forced
270 * delays or anything. It just produces enough samples for each tick, and
271 * the playback of these samples is what makes the timings right.
273 * This seems to work quite well. On a laptop, anyway.
276 printf("Okay, starting sequencing");
278 bpm=mf->div*1000000/tempo;
279 numberOfSamples=SAMPLE_RATE/bpm;
283 /* Skip over any junk in the beginning of the file, so start playing */
284 /* after the first note event */
287 notesUsed = 0;
288 for(a=0; a<MAX_VOICES; a++)
289 if(voices[a].isUsed)
290 notesUsed++;
291 tick();
292 } while(notesUsed == 0);
294 playingTime = 0;
295 samplesThisSecond = 0;
297 synthbuf();
298 rb->pcm_play_data(&get_more, NULL, 0);
300 int isPlaying = 1; /* 0 = paused */
301 int vol=0;
303 while(!quit)
305 #ifndef SYNC
306 synthbuf();
307 #endif
308 rb->yield();
310 /* Prevent idle poweroff */
311 rb->reset_poweroff_timer();
313 /* Code taken from Oscilloscope plugin */
314 switch(rb->button_get(false))
316 case BTN_UP:
317 case BTN_UP | BUTTON_REPEAT:
318 vol = rb->global_settings->volume;
319 if (vol < rb->sound_max(SOUND_VOLUME))
321 vol++;
322 rb->sound_set(SOUND_VOLUME, vol);
323 rb->global_settings->volume = vol;
325 break;
327 case BTN_DOWN:
328 case BTN_DOWN | BUTTON_REPEAT:
329 vol = rb->global_settings->volume;
330 if (vol > rb->sound_min(SOUND_VOLUME))
332 vol--;
333 rb->sound_set(SOUND_VOLUME, vol);
334 rb->global_settings->volume = vol;
336 break;
339 case BTN_LEFT:
341 /* Rewinding is tricky. Basically start the file over */
342 /* but run through the tracks without the synth running */
343 rb->pcm_play_stop();
344 seekBackward(5);
345 printf("Rewind to %d:%02d\n", playingTime/60, playingTime%60);
347 if(isPlaying)
348 rb->pcm_play_data(&get_more, NULL, 0);
349 break;
352 case BTN_RIGHT:
354 rb->pcm_play_stop();
355 seekForward(5);
356 printf("Skip to %d:%02d\n", playingTime/60, playingTime%60);
358 if(isPlaying)
359 rb->pcm_play_data(&get_more, NULL, 0);
360 break;
363 case BTN_PLAY:
365 if(isPlaying == 1)
367 printf("Paused at %d:%02d\n", playingTime/60, playingTime%60);
368 isPlaying = 0;
369 rb->pcm_play_stop();
370 } else
372 printf("Playing from %d:%02d\n", playingTime/60, playingTime%60);
373 isPlaying = 1;
374 rb->pcm_play_data(&get_more, NULL, 0);
376 break;
379 #ifdef BTN_RC_QUIT
380 case BTN_RC_QUIT:
381 #endif
382 case BTN_QUIT:
383 quit=1;
389 return 0;