Colour targets: Revert an optimisation from almost 18 months ago that actually turned...
[Rockbox.git] / apps / plugins / midi / midiplay.c
bloba394aaccb198449dc511e394f3f6deee57416af1
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 == RECORDER_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_PLAY BUTTON_PLAY
40 #elif CONFIG_KEYPAD == ONDIO_PAD
41 #define BTN_QUIT BUTTON_OFF
42 #define BTN_RIGHT BUTTON_RIGHT
43 #define BTN_UP BUTTON_UP
44 #define BTN_DOWN BUTTON_DOWN
45 #define BTN_LEFT BUTTON_LEFT
46 #define BTN_PLAY (BUTTON_MENU | BUTTON_OFF)
49 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
50 #define BTN_QUIT BUTTON_OFF
51 #define BTN_RIGHT BUTTON_RIGHT
52 #define BTN_UP BUTTON_UP
53 #define BTN_DOWN BUTTON_DOWN
54 #define BTN_LEFT BUTTON_LEFT
55 #define BTN_RC_QUIT BUTTON_RC_STOP
56 #define BTN_PLAY BUTTON_ON
58 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
59 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
60 #define BTN_QUIT (BUTTON_SELECT | BUTTON_MENU)
61 #define BTN_RIGHT BUTTON_RIGHT
62 #define BTN_LEFT BUTTON_LEFT
63 #define BTN_UP BUTTON_SCROLL_FWD
64 #define BTN_DOWN BUTTON_SCROLL_BACK
65 #define BTN_PLAY BUTTON_PLAY
68 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
69 #define BTN_QUIT BUTTON_POWER
70 #define BTN_RIGHT BUTTON_RIGHT
71 #define BTN_LEFT BUTTON_LEFT
72 #define BTN_UP BUTTON_UP
73 #define BTN_DOWN BUTTON_DOWN
74 #define BTN_PLAY BUTTON_A
77 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
78 #define BTN_QUIT BUTTON_POWER
79 #define BTN_RIGHT BUTTON_RIGHT
80 #define BTN_LEFT BUTTON_LEFT
81 #define BTN_UP BUTTON_UP
82 #define BTN_DOWN BUTTON_DOWN
83 #define BTN_PLAY BUTTON_PLAY
86 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
87 #define BTN_QUIT BUTTON_POWER
88 #define BTN_RIGHT BUTTON_RIGHT
89 #define BTN_LEFT BUTTON_LEFT
90 #define BTN_UP BUTTON_SCROLL_FWD
91 #define BTN_DOWN BUTTON_SCROLL_BACK
92 #define BTN_PLAY BUTTON_UP
95 #elif (CONFIG_KEYPAD == SANSA_C200_PAD)
96 #define BTN_QUIT BUTTON_POWER
97 #define BTN_RIGHT BUTTON_RIGHT
98 #define BTN_LEFT BUTTON_LEFT
99 #define BTN_UP BUTTON_VOL_UP
100 #define BTN_DOWN BUTTON_VOL_DOWN
101 #define BTN_PLAY BUTTON_UP
104 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
105 #define BTN_QUIT BUTTON_POWER
106 #define BTN_RIGHT BUTTON_RIGHT
107 #define BTN_LEFT BUTTON_LEFT
108 #define BTN_UP BUTTON_UP
109 #define BTN_DOWN BUTTON_DOWN
110 #define BTN_PLAY BUTTON_PLAY
113 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
114 #define BTN_QUIT BUTTON_POWER
115 #define BTN_RIGHT BUTTON_RIGHT
116 #define BTN_LEFT BUTTON_LEFT
117 #define BTN_UP BUTTON_SCROLL_UP
118 #define BTN_DOWN BUTTON_SCROLL_DOWN
119 #define BTN_PLAY BUTTON_PLAY
122 #elif CONFIG_KEYPAD == MROBE500_PAD
123 #define BTN_QUIT BUTTON_POWER
124 #define BTN_RIGHT BUTTON_RIGHT
125 #define BTN_LEFT BUTTON_LEFT
126 #define BTN_UP BUTTON_RC_PLAY
127 #define BTN_DOWN BUTTON_RC_DOWN
128 #define BTN_PLAY BUTTON_RC_HEART
131 #elif (CONFIG_KEYPAD == MROBE100_PAD)
132 #define BTN_QUIT BUTTON_POWER
133 #define BTN_RIGHT BUTTON_RIGHT
134 #define BTN_LEFT BUTTON_LEFT
135 #define BTN_UP BUTTON_UP
136 #define BTN_DOWN BUTTON_DOWN
137 #define BTN_PLAY BUTTON_DISPLAY
140 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
141 #define BTN_QUIT BUTTON_RC_REC
142 #define BTN_RIGHT BUTTON_RC_FF
143 #define BTN_LEFT BUTTON_RC_REW
144 #define BTN_UP BUTTON_RC_VOL_UP
145 #define BTN_DOWN BUTTON_RC_VOL_DOWN
146 #define BTN_PLAY BUTTON_RC_PLAY
149 #elif CONFIG_KEYPAD == COWOND2_PAD
150 #define BTN_QUIT BUTTON_POWER
153 #else
154 #error No keymap defined!
155 #endif
157 #ifdef HAVE_TOUCHPAD
158 #ifndef BTN_QUIT
159 #define BTN_QUIT BUTTON_TOPLEFT
160 #endif
161 #ifndef BTN_RIGHT
162 #define BTN_RIGHT BUTTON_MIDRIGHT
163 #endif
164 #ifndef BTN_LEFT
165 #define BTN_LEFT BUTTON_MIDLEFT
166 #endif
167 #ifndef BTN_UP
168 #define BTN_UP BUTTON_TOPMIDDLE
169 #endif
170 #ifndef BTN_DOWN
171 #define BTN_DOWN BUTTON_BOTTOMMIDDLE
172 #endif
173 #ifndef BTN_PLAY
174 #define BTN_PLAY BUTTON_CENTER
175 #endif
176 #endif
178 #undef SYNC
180 #ifdef SIMULATOR
181 #define SYNC
182 #endif
184 struct MIDIfile * mf IBSS_ATTR;
186 int numberOfSamples IBSS_ATTR; /* the number of samples in the current tick */
187 int playingTime IBSS_ATTR; /* How many seconds into the file have we been playing? */
188 int samplesThisSecond IBSS_ATTR; /* How many samples produced during this second so far? */
190 long bpm IBSS_ATTR;
192 int32_t gmbuf[BUF_SIZE*NBUF];
193 static unsigned int samples_in_buf;
195 int quit=0;
196 const struct plugin_api * rb;
198 static int midimain(const void * filename);
200 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
202 int retval = 0;
205 PLUGIN_IRAM_INIT(api)
207 rb = api;
208 if(parameter == NULL)
210 rb->splash(HZ*2, " Play .MID file ");
211 return PLUGIN_OK;
213 rb->lcd_setfont(0);
215 #if defined(HAVE_ADJUSTABLE_CPU_FREQ)
216 rb->cpu_boost(true);
217 #endif
219 printf("%s", parameter);
220 /* rb->splash(HZ, true, parameter); */
222 #ifdef RB_PROFILE
223 rb->profile_thread();
224 #endif
226 retval = midimain(parameter);
228 #ifdef RB_PROFILE
229 rb->profstop();
230 #endif
232 rb->pcm_play_stop();
233 rb->pcm_set_frequency(HW_SAMPR_DEFAULT);
235 #if defined(HAVE_ADJUSTABLE_CPU_FREQ)
236 rb->cpu_boost(false);
237 #endif
238 rb->splash(HZ, "FINISHED PLAYING");
240 if(retval == -1)
241 return PLUGIN_ERROR;
242 return PLUGIN_OK;
245 bool swap=0;
246 bool lastswap=1;
248 static inline void synthbuf(void)
250 int32_t *outptr;
251 int i=BUF_SIZE;
253 #ifndef SYNC
254 if(lastswap==swap) return;
255 lastswap=swap;
257 outptr=(swap ? gmbuf : gmbuf+BUF_SIZE);
258 #else
259 outptr=gmbuf;
260 #endif
262 /* synth samples for as many whole ticks as we can fit in the buffer */
263 for(; i >= numberOfSamples; i -= numberOfSamples)
265 synthSamples((int32_t*)outptr, numberOfSamples);
266 outptr += numberOfSamples;
267 if( tick() == 0 )
268 quit=1;
271 /* how many samples did we write to the buffer? */
272 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 notesUsed = 0;
300 int a=0;
301 printf("Loading file");
302 mf= loadFile(filename);
304 if(mf == NULL)
306 printf("Error loading file.");
307 return -1;
310 if (initSynth(mf, ROCKBOX_DIR "/patchset/patchset.cfg",
311 ROCKBOX_DIR "/patchset/drums.cfg") == -1)
312 return -1;
314 rb->pcm_play_stop();
315 #if INPUT_SRC_CAPS != 0
316 /* Select playback */
317 rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
318 rb->audio_set_output_source(AUDIO_SRC_PLAYBACK);
319 #endif
320 rb->pcm_set_frequency(SAMPLE_RATE); // 44100 22050 11025
323 * tick() will do one MIDI clock tick. Then, there's a loop here that
324 * will generate the right number of samples per MIDI tick. The whole
325 * MIDI playback is timed in terms of this value.. there are no forced
326 * delays or anything. It just produces enough samples for each tick, and
327 * the playback of these samples is what makes the timings right.
329 * This seems to work quite well. On a laptop, anyway.
332 printf("Okay, starting sequencing");
334 bpm=mf->div*1000000/tempo;
335 numberOfSamples=SAMPLE_RATE/bpm;
339 /* Skip over any junk in the beginning of the file, so start playing */
340 /* after the first note event */
343 notesUsed = 0;
344 for(a=0; a<MAX_VOICES; a++)
345 if(voices[a].isUsed)
346 notesUsed++;
347 tick();
348 } while(notesUsed == 0);
350 playingTime = 0;
351 samplesThisSecond = 0;
353 synthbuf();
354 rb->pcm_play_data(&get_more, NULL, 0);
356 int isPlaying = 1; /* 0 = paused */
357 int vol=0;
359 while(!quit)
361 #ifndef SYNC
362 synthbuf();
363 #endif
364 rb->yield();
366 /* Prevent idle poweroff */
367 rb->reset_poweroff_timer();
369 /* Code taken from Oscilloscope plugin */
370 switch(rb->button_get(false))
372 case BTN_UP:
373 case BTN_UP | BUTTON_REPEAT:
374 vol = rb->global_settings->volume;
375 if (vol < rb->sound_max(SOUND_VOLUME))
377 vol++;
378 rb->sound_set(SOUND_VOLUME, vol);
379 rb->global_settings->volume = vol;
381 break;
383 case BTN_DOWN:
384 case BTN_DOWN | BUTTON_REPEAT:
385 vol = rb->global_settings->volume;
386 if (vol > rb->sound_min(SOUND_VOLUME))
388 vol--;
389 rb->sound_set(SOUND_VOLUME, vol);
390 rb->global_settings->volume = vol;
392 break;
395 case BTN_LEFT:
397 /* Rewinding is tricky. Basically start the file over */
398 /* but run through the tracks without the synth running */
399 rb->pcm_play_stop();
400 seekBackward(5);
401 printf("Rewind to %d:%02d\n", playingTime/60, playingTime%60);
403 if(isPlaying)
404 rb->pcm_play_data(&get_more, NULL, 0);
405 break;
408 case BTN_RIGHT:
410 rb->pcm_play_stop();
411 seekForward(5);
412 printf("Skip to %d:%02d\n", playingTime/60, playingTime%60);
414 if(isPlaying)
415 rb->pcm_play_data(&get_more, NULL, 0);
416 break;
419 case BTN_PLAY:
421 if(isPlaying == 1)
423 printf("Paused at %d:%02d\n", playingTime/60, playingTime%60);
424 isPlaying = 0;
425 rb->pcm_play_stop();
426 } else
428 printf("Playing from %d:%02d\n", playingTime/60, playingTime%60);
429 isPlaying = 1;
430 rb->pcm_play_data(&get_more, NULL, 0);
432 break;
435 #ifdef BTN_RC_QUIT
436 case BTN_RC_QUIT:
437 #endif
438 case BTN_QUIT:
439 quit=1;
445 return 0;