use the list context in credits which has to be defined for every target
[Rockbox.git] / apps / plugins / midi / midiplay.c
blob325d90c3757a19610d2fc4f1c6c781d96f683061
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
36 #elif CONFIG_KEYPAD == ONDIO_PAD
37 #define BTN_QUIT BUTTON_OFF
38 #define BTN_RIGHT BUTTON_RIGHT
39 #define BTN_UP BUTTON_UP
40 #define BTN_DOWN BUTTON_DOWN
42 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
43 #define BTN_QUIT BUTTON_OFF
44 #define BTN_RIGHT BUTTON_RIGHT
45 #define BTN_UP BUTTON_UP
46 #define BTN_DOWN BUTTON_DOWN
48 #define BTN_RC_QUIT BUTTON_RC_STOP
50 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
51 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
52 #define BTN_QUIT (BUTTON_SELECT | BUTTON_MENU)
53 #define BTN_RIGHT BUTTON_RIGHT
54 #define BTN_UP BUTTON_SCROLL_FWD
55 #define BTN_DOWN BUTTON_SCROLL_BACK
57 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
58 #define BTN_QUIT BUTTON_POWER
59 #define BTN_RIGHT BUTTON_RIGHT
60 #define BTN_UP BUTTON_UP
61 #define BTN_DOWN BUTTON_DOWN
63 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
64 (CONFIG_KEYPAD == SANSA_C200_PAD)
65 #define BTN_QUIT BUTTON_POWER
66 #define BTN_RIGHT BUTTON_RIGHT
67 #define BTN_UP BUTTON_UP
68 #define BTN_DOWN BUTTON_DOWN
70 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
71 #define BTN_QUIT BUTTON_POWER
72 #define BTN_RIGHT BUTTON_RIGHT
73 #define BTN_UP BUTTON_UP
74 #define BTN_DOWN BUTTON_DOWN
76 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
77 #define BTN_QUIT BUTTON_POWER
78 #define BTN_RIGHT BUTTON_RIGHT
79 #define BTN_UP BUTTON_SCROLL_UP
80 #define BTN_DOWN BUTTON_SCROLL_DOWN
82 #endif
84 #undef SYNC
86 #ifdef SIMULATOR
87 #define SYNC
88 #endif
90 struct MIDIfile * mf IBSS_ATTR;
92 int numberOfSamples IBSS_ATTR;
93 long bpm IBSS_ATTR;
95 int32_t gmbuf[BUF_SIZE*NBUF];
96 static unsigned int samples_in_buf;
98 int quit=0;
99 struct plugin_api * rb;
101 static int midimain(void * filename);
103 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
105 int retval = 0;
107 PLUGIN_IRAM_INIT(api)
109 rb = api;
110 if(parameter == NULL)
112 rb->splash(HZ*2, " Play .MID file ");
113 return PLUGIN_OK;
115 rb->lcd_setfont(0);
117 #if defined(HAVE_ADJUSTABLE_CPU_FREQ)
118 rb->cpu_boost(true);
119 #endif
121 printf("%s", parameter);
122 /* rb->splash(HZ, true, parameter); */
124 #ifdef RB_PROFILE
125 rb->profile_thread();
126 #endif
128 retval = midimain(parameter);
130 #ifdef RB_PROFILE
131 rb->profstop();
132 #endif
134 rb->pcm_play_stop();
135 rb->pcm_set_frequency(HW_SAMPR_DEFAULT);
137 #if defined(HAVE_ADJUSTABLE_CPU_FREQ)
138 rb->cpu_boost(false);
139 #endif
140 rb->splash(HZ, "FINISHED PLAYING");
142 if(retval == -1)
143 return PLUGIN_ERROR;
144 return PLUGIN_OK;
147 bool swap=0;
148 bool lastswap=1;
150 static inline void synthbuf(void)
152 int32_t *outptr;
153 int i;
155 #ifndef SYNC
156 if(lastswap==swap) return;
157 lastswap=swap;
159 outptr=(swap ? gmbuf : gmbuf+BUF_SIZE);
160 #else
161 outptr=gmbuf;
162 #endif
164 /* synth samples for as many whole ticks as we can fit in the buffer */
165 for(i=0; i < BUF_SIZE/numberOfSamples; i++)
167 synthSamples((int32_t*)outptr, numberOfSamples);
168 outptr += numberOfSamples;
169 if( tick() == 0 )
170 quit=1;
173 /* how many samples did we write to the buffer? */
174 samples_in_buf = BUF_SIZE-(BUF_SIZE%numberOfSamples);
178 void get_more(unsigned char** start, size_t* size)
180 #ifndef SYNC
181 if(lastswap!=swap)
183 printf("Buffer miss!"); // Comment out the printf to make missses less noticable.
186 #else
187 synthbuf(); // For some reason midiplayer crashes when an update is forced
188 #endif
190 *size = samples_in_buf*sizeof(int32_t);
191 #ifndef SYNC
192 *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE));
193 swap=!swap;
194 #else
195 *start = (unsigned char*)(gmbuf);
196 #endif
199 static int midimain(void * filename)
201 int notesUsed = 0;
202 int a=0;
203 printf("Loading file");
204 mf= loadFile(filename);
206 if(mf == NULL)
208 printf("Error loading file.");
209 return -1;
212 if (initSynth(mf, ROCKBOX_DIR "/patchset/patchset.cfg",
213 ROCKBOX_DIR "/patchset/drums.cfg") == -1)
214 return -1;
216 rb->pcm_play_stop();
217 #if INPUT_SRC_CAPS != 0
218 /* Select playback */
219 rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
220 rb->audio_set_output_source(AUDIO_SRC_PLAYBACK);
221 #endif
222 rb->pcm_set_frequency(SAMPLE_RATE); // 44100 22050 11025
225 * tick() will do one MIDI clock tick. Then, there's a loop here that
226 * will generate the right number of samples per MIDI tick. The whole
227 * MIDI playback is timed in terms of this value.. there are no forced
228 * delays or anything. It just produces enough samples for each tick, and
229 * the playback of these samples is what makes the timings right.
231 * This seems to work quite well. On a laptop, anyway.
234 printf("Okay, starting sequencing");
236 bpm=mf->div*1000000/tempo;
237 numberOfSamples=SAMPLE_RATE/bpm;
241 /* Skip over any junk in the beginning of the file, so start playing */
242 /* after the first note event */
245 notesUsed = 0;
246 for(a=0; a<MAX_VOICES; a++)
247 if(voices[a].isUsed == 1)
248 notesUsed++;
249 tick();
250 } while(notesUsed == 0);
252 synthbuf();
253 rb->pcm_play_data(&get_more, NULL, 0);
255 int vol=0;
257 while(!quit)
259 #ifndef SYNC
260 synthbuf();
261 #endif
262 rb->yield();
264 /* Prevent idle poweroff */
265 rb->reset_poweroff_timer();
267 /* Code taken from Oscilloscope plugin */
268 switch(rb->button_get(false))
270 case BTN_UP:
271 case BTN_UP | BUTTON_REPEAT:
272 vol = rb->global_settings->volume;
273 if (vol < rb->sound_max(SOUND_VOLUME))
275 vol++;
276 rb->sound_set(SOUND_VOLUME, vol);
277 rb->global_settings->volume = vol;
279 break;
281 case BTN_DOWN:
282 case BTN_DOWN | BUTTON_REPEAT:
283 vol = rb->global_settings->volume;
284 if (vol > rb->sound_min(SOUND_VOLUME))
286 vol--;
287 rb->sound_set(SOUND_VOLUME, vol);
288 rb->global_settings->volume = vol;
290 break;
292 case BTN_RIGHT:
294 /* Skip 3 seconds */
295 /* Should skip length be retrieved from the RB settings? */
296 int samp = 3*SAMPLE_RATE;
297 int tickCount = samp / numberOfSamples;
298 int a=0;
299 for(a=0; a<tickCount; a++)
300 tick();
301 break;
303 #ifdef BTN_RC_QUIT
304 case BTN_RC_QUIT:
305 #endif
306 case BTN_QUIT:
307 quit=1;
313 return 0;