Add platform file for Iaudio M5.
[Rockbox.git] / apps / plugins / midiplay.c
blob556cf41cb2ec6df8706fba54d10edee2229846b0
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
9 * Copyright (C) 2005 Karl Kurbjun based on midi2wav by Stepan Moskovchenko
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
17 ****************************************************************************/
19 #include "../../plugin.h"
21 PLUGIN_HEADER
22 PLUGIN_IRAM_DECLARE
24 /* variable button definitions */
25 #if CONFIG_KEYPAD == RECORDER_PAD
26 #define BTN_QUIT BUTTON_OFF
27 #define BTN_RIGHT BUTTON_RIGHT
28 #define BTN_UP BUTTON_UP
29 #define BTN_DOWN BUTTON_DOWN
31 #elif CONFIG_KEYPAD == ONDIO_PAD
32 #define BTN_QUIT BUTTON_OFF
33 #define BTN_RIGHT BUTTON_RIGHT
34 #define BTN_UP BUTTON_UP
35 #define BTN_DOWN BUTTON_DOWN
37 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
38 #define BTN_QUIT BUTTON_OFF
39 #define BTN_RIGHT BUTTON_RIGHT
40 #define BTN_UP BUTTON_UP
41 #define BTN_DOWN BUTTON_DOWN
43 #define BTN_RC_QUIT BUTTON_RC_STOP
45 #elif (CONFIG_KEYPAD == IPOD_3G_PAD) || (CONFIG_KEYPAD == IPOD_4G_PAD)
46 #define BTN_QUIT (BUTTON_SELECT | BUTTON_MENU)
47 #define BTN_RIGHT BUTTON_RIGHT
48 #define BTN_UP BUTTON_SCROLL_FWD
49 #define BTN_DOWN BUTTON_SCROLL_BACK
51 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
52 #define BTN_QUIT BUTTON_POWER
53 #define BTN_RIGHT BUTTON_RIGHT
54 #define BTN_UP BUTTON_VOL_UP
55 #define BTN_DOWN BUTTON_VOL_DOWN
57 #elif (CONFIG_KEYPAD == SANSA_E200_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
64 #elif CONFIG_KEYPAD == IAUDIO_X5_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 == IRIVER_H10_PAD
71 #define BTN_QUIT BUTTON_POWER
72 #define BTN_RIGHT BUTTON_RIGHT
73 #define BTN_UP BUTTON_SCROLL_UP
74 #define BTN_DOWN BUTTON_SCROLL_DOWN
76 #endif
80 #define FRACTSIZE 10
82 #ifndef SIMULATOR
83 #define SAMPLE_RATE 22050 // 44100 22050 11025
84 #define MAX_VOICES 14 // Note: 24 midi channels is the minimum general midi
85 // spec implementation
86 #else // Simulator requires 44100, and we can afford to use more voices
87 #define SAMPLE_RATE 44100
88 #define MAX_VOICES 48
89 #endif
92 #define BUF_SIZE 512
93 #define NBUF 2
95 #undef SYNC
97 #ifdef SIMULATOR
98 #define SYNC
99 #endif
101 struct MIDIfile * mf IBSS_ATTR;
103 int numberOfSamples IBSS_ATTR;
104 long bpm IBSS_ATTR;
106 #include "midi/midiutil.c"
107 #include "midi/guspat.h"
108 #include "midi/guspat.c"
109 #include "midi/sequencer.c"
110 #include "midi/midifile.c"
111 #include "midi/synth.c"
113 short gmbuf[BUF_SIZE*NBUF] IBSS_ATTR;
115 int quit=0;
116 struct plugin_api * rb;
118 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
120 int retval = 0;
122 PLUGIN_IRAM_INIT(api)
124 rb = api;
125 if(parameter == NULL)
127 rb->splash(HZ*2, true, " Play .MID file ");
128 return PLUGIN_OK;
130 rb->lcd_setfont(0);
132 #if defined(HAVE_ADJUSTABLE_CPU_FREQ)
133 rb->cpu_boost(true);
134 #endif
136 printf("\n%s", parameter);
137 /* rb->splash(HZ, true, parameter); */
139 #ifdef RB_PROFILE
140 rb->profile_thread();
141 #endif
143 retval = midimain(parameter);
145 #ifdef RB_PROFILE
146 rb->profstop();
147 #endif
149 //#ifndef SIMULATOR
150 rb->pcm_play_stop();
151 rb->pcm_set_frequency(SAMPLE_RATE); // 44100
152 //#endif
154 #if defined(HAVE_ADJUSTABLE_CPU_FREQ)
155 rb->cpu_boost(false);
156 #endif
158 rb->splash(HZ, true, "FINISHED PLAYING");
160 if(retval == -1)
161 return PLUGIN_ERROR;
162 return PLUGIN_OK;
165 bool swap=0;
166 bool lastswap=1;
168 inline void synthbuf(void)
170 short *outptr;
171 register int i;
172 static int currentSample=0;
173 int synthtemp[2];
175 #ifndef SYNC
176 if(lastswap==swap) return;
177 lastswap=swap;
179 outptr=(swap ? gmbuf : gmbuf+BUF_SIZE);
180 #else
181 outptr=gmbuf;
182 #endif
184 for(i=0; i<BUF_SIZE/2; i++)
186 synthSample(&synthtemp[0], &synthtemp[1]);
187 currentSample++;
188 *outptr=synthtemp[0]&0xFFFF;
189 outptr++;
190 *outptr=synthtemp[1]&0xFFFF;
191 outptr++;
192 if(currentSample==numberOfSamples)
194 if( tick() == 0 ) quit=1;
195 currentSample=0;
200 void get_more(unsigned char** start, size_t* size)
202 #ifndef SYNC
203 if(lastswap!=swap)
205 printf("Buffer miss!"); // Comment out the printf to make missses less noticable.
208 #else
209 synthbuf(); // For some reason midiplayer crashes when an update is forced
210 #endif
212 *size = BUF_SIZE*sizeof(short);
213 #ifndef SYNC
214 *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE));
215 swap=!swap;
216 #else
217 *start = (unsigned char*)(gmbuf);
218 #endif
221 int midimain(void * filename)
223 int notesUsed = 0;
224 int a=0;
225 printf("\nLoading file");
226 mf= loadFile(filename);
228 if(mf == NULL)
230 printf("\nError loading file.");
231 return -1;
234 if (initSynth(mf, "/.rockbox/patchset/patchset.cfg", "/.rockbox/patchset/drums.cfg") == -1)
235 return -1;
237 //#ifndef SIMULATOR
238 rb->pcm_play_stop();
239 rb->pcm_set_frequency(SAMPLE_RATE); // 44100 22050 11025
240 //#endif
243 * tick() will do one MIDI clock tick. Then, there's a loop here that
244 * will generate the right number of samples per MIDI tick. The whole
245 * MIDI playback is timed in terms of this value.. there are no forced
246 * delays or anything. It just produces enough samples for each tick, and
247 * the playback of these samples is what makes the timings right.
249 * This seems to work quite well. On a laptop, anyway.
252 printf("\nOkay, starting sequencing");
254 bpm=mf->div*1000000/tempo;
255 numberOfSamples=SAMPLE_RATE/bpm;
259 /* Skip over any junk in the beginning of the file, so start playing */
260 /* after the first note event */
263 notesUsed = 0;
264 for(a=0; a<MAX_VOICES; a++)
265 if(voices[a].isUsed == 1)
266 notesUsed++;
267 tick();
268 } while(notesUsed == 0);
270 synthbuf();
271 //#ifndef SIMULATOR
272 rb->pcm_play_data(&get_more, NULL, 0);
273 //#endif
275 int vol=0;
277 while(!quit)
279 #ifndef SYNC
280 synthbuf();
281 #endif
282 rb->yield();
284 /* Code taken from Oscilloscope plugin */
285 switch(rb->button_get(false))
287 case BTN_UP:
288 case BTN_UP | BUTTON_REPEAT:
289 vol = rb->global_settings->volume;
290 if (vol < rb->sound_max(SOUND_VOLUME))
292 vol++;
293 rb->sound_set(SOUND_VOLUME, vol);
294 rb->global_settings->volume = vol;
296 break;
298 case BTN_DOWN:
299 case BTN_DOWN | BUTTON_REPEAT:
300 vol = rb->global_settings->volume;
301 if (vol > rb->sound_min(SOUND_VOLUME))
303 vol--;
304 rb->sound_set(SOUND_VOLUME, vol);
305 rb->global_settings->volume = vol;
307 break;
309 case BTN_RIGHT:
311 /* Skip 3 seconds */
312 /* Should skip length be retrieved from the RB settings? */
313 int samp = 3*SAMPLE_RATE;
314 int tickCount = samp / numberOfSamples;
315 int a=0;
316 for(a=0; a<tickCount; a++)
317 tick();
318 break;
320 #ifdef BTN_RC_QUIT
321 case BTN_RC_QUIT:
322 #endif
323 case BTN_QUIT:
324 quit=1;
330 return 0;