talk_init() : don't try to load the voice file if it won't fit in memory
[kugel-rb.git] / apps / plugins / beatbox / beatbox.c
blob1a940e10473c39fffe8925659974a6e4c8218309
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 ****************************************************************************/
22 #include "plugin.h"
23 #include "midi/guspat.h"
24 #include "midi/midiutil.h"
25 #include "midi/synth.h"
26 #include "midi/sequencer.h"
27 #include "midi/midifile.h"
29 PLUGIN_HEADER
30 PLUGIN_IRAM_DECLARE
32 /* variable button definitions */
33 #if CONFIG_KEYPAD == RECORDER_PAD
34 #define BTN_QUIT BUTTON_OFF
35 #define BTN_RIGHT BUTTON_RIGHT
36 #define BTN_UP BUTTON_UP
37 #define BTN_DOWN BUTTON_DOWN
39 #elif CONFIG_KEYPAD == ONDIO_PAD
40 #define BTN_QUIT BUTTON_OFF
41 #define BTN_RIGHT BUTTON_RIGHT
42 #define BTN_UP BUTTON_UP
43 #define BTN_DOWN BUTTON_DOWN
45 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
46 #define BTN_QUIT BUTTON_OFF
47 #define BTN_RIGHT BUTTON_RIGHT
48 #define BTN_UP BUTTON_UP
49 #define BTN_DOWN BUTTON_DOWN
51 #define BTN_RC_QUIT BUTTON_RC_STOP
53 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
54 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
55 #define BTN_QUIT (BUTTON_SELECT | BUTTON_MENU)
56 #define BTN_RIGHT BUTTON_RIGHT
57 #define BTN_UP BUTTON_SCROLL_FWD
58 #define BTN_DOWN BUTTON_SCROLL_BACK
60 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
61 #define BTN_QUIT BUTTON_POWER
62 #define BTN_RIGHT BUTTON_RIGHT
63 #define BTN_UP BUTTON_UP
64 #define BTN_DOWN BUTTON_DOWN
66 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
67 (CONFIG_KEYPAD == SANSA_C200_PAD)
68 #define BTN_QUIT BUTTON_POWER
69 #define BTN_RIGHT BUTTON_RIGHT
70 #define BTN_UP BUTTON_UP
71 #define BTN_DOWN BUTTON_DOWN
74 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
75 #define BTN_QUIT BUTTON_POWER
76 #define BTN_RIGHT BUTTON_RIGHT
77 #define BTN_UP BUTTON_UP
78 #define BTN_DOWN BUTTON_DOWN
80 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
81 #define BTN_QUIT BUTTON_POWER
82 #define BTN_RIGHT BUTTON_RIGHT
83 #define BTN_UP BUTTON_SCROLL_UP
84 #define BTN_DOWN BUTTON_SCROLL_DOWN
86 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
87 #define BTN_QUIT BUTTON_PLAY
88 #define BTN_RIGHT BUTTON_RIGHT
89 #define BTN_UP BUTTON_UP
90 #define BTN_DOWN BUTTON_DOWN
92 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
93 #define BTN_QUIT BUTTON_REC
94 #define BTN_RIGHT BUTTON_NEXT
95 #define BTN_UP BUTTON_UP
96 #define BTN_DOWN BUTTON_DOWN
98 #endif
102 #define FRACTSIZE 10
104 #ifndef SIMULATOR
106 #if (HW_SAMPR_CAPS & SAMPR_CAP_22)
107 #define SAMPLE_RATE SAMPR_22 // 44100 22050 11025
108 #else
109 #define SAMPLE_RATE SAMPR_44 // 44100 22050 11025
110 #endif
112 #define MAX_VOICES 20 // Note: 24 midi channels is the minimum general midi
113 // spec implementation
115 #else // Simulator requires 44100, and we can afford to use more voices
117 #define SAMPLE_RATE SAMPR_44
118 #define MAX_VOICES 48
120 #endif
123 #define BUF_SIZE 256
124 #define NBUF 2
126 #undef SYNC
128 #ifdef SIMULATOR
129 #define SYNC
130 #endif
132 struct MIDIfile * mf IBSS_ATTR;
134 int numberOfSamples IBSS_ATTR;
135 long bpm IBSS_ATTR;
137 const unsigned char * drumNames[]={
138 "Bass Drum 2 ",
139 "Bass Drum 1 ",
140 "Side Stick ",
141 "Snare Drum 1 ",
142 "Hand Clap ",
143 "Snare Drum 2 ",
144 "Low Tom 2 ",
145 "Closed Hi-hat ",
146 "Low Tom 1 ",
147 "Pedal Hi-hat ",
148 "Mid Tom 2 ",
149 "Open Hi-hat ",
150 "Mid Tom 1 ",
151 "High Tom 2 ",
152 "Crash Cymbal 1 ",
153 "High Tom 1 ",
154 "Ride Cymbal 1 ",
155 "Chinese Cymbal ",
156 "Ride Bell ",
157 "Tambourine ",
158 "Splash Cymbal ",
159 "Cowbell ",
160 "Crash Cymbal 2 ",
161 "Vibra Slap ",
162 "Ride Cymbal 2 ",
163 "High Bongo ",
164 "Low Bongo ",
165 "Mute High Conga",
166 "Open High Conga",
167 "Low Conga ",
168 "High Timbale ",
169 "Low Timbale ",
170 "High Agogo ",
171 "Low Agogo ",
172 "Cabasa ",
173 "Maracas ",
174 "Short Whistle ",
175 "Long Whistle ",
176 "Short Guiro ",
177 "Long Guiro ",
178 "Claves ",
179 "High Wood Block",
180 "Low Wood Block ",
181 "Mute Cuica ",
182 "Open Cuica ",
183 "Mute Triangle ",
184 "Open Triangle ",
185 "Shaker ",
186 "Jingle Bell ",
187 "Bell Tree ",
188 "Castenets ",
189 "Mute Surdo ",
190 "Open Surdo "
193 long gmbuf[BUF_SIZE*NBUF];
195 int quit=0;
197 #define STATE_STOPPED 0
198 #define STATE_PAUSED 1
199 #define STATE_PLAYING 2
202 #define BEATBOX_UP BUTTON_UP
203 #define BEATBOX_DOWN BUTTON_DOWN
204 #define BEATBOX_LEFT BUTTON_LEFT
205 #define BEATBOX_RIGHT BUTTON_RIGHT
206 #define BEATBOX_SELECT BUTTON_SELECT
209 #define BEATBOX_PLAY BUTTON_ON
210 #define BEATBOX_STOP BUTTON_OFF
213 #define VAL_NONE 0
214 #define VAL_ENABLED 1
215 #define VAL_LOOP 2
217 #define H_NUMCELLS 24
218 #define V_NUMCELLS 8
220 #define HILIGHT_NONE 0
221 #define HILIGHT_PLAY 1
222 #define HILIGHT_USER 2
224 #define CELL_XSIZE 9
225 #define CELL_YSIZE 9
227 #define GRID_XPOS 2
228 #define GRID_YPOS 10
231 #define COLOR_NAME_TEXT LCD_RGBPACK(0xFF,0xFF,0xFF)
232 #define COLOR_NORMAL LCD_RGBPACK(0xFF,0xFF,0xFF)
233 #define COLOR_PLAY LCD_RGBPACK(0xFF,0xFF,0x00)
234 #define COLOR_DISABLED LCD_RGBPACK(0xA0,0xA0,0xA0)
235 #define COLOR_LOOPCELL LCD_RGBPACK(0xC0,0xC0,0xC0)
236 #define COLOR_EDIT LCD_RGBPACK(0x30,0x30,0xFF)
237 #define COLOR_GRID LCD_RGBPACK(0xD0,0xD0,0xD0)
239 #define EDITSTATE_PATTERN 0
241 int xCursor=0, yCursor=0;
243 int editState=EDITSTATE_PATTERN;
245 int playState=STATE_STOPPED, stepFlag=0;
248 enum plugin_status plugin_start(const void* parameter)
250 int retval = 0;
252 PLUGIN_IRAM_INIT(rb)
254 rb->lcd_setfont(0);
256 #if defined(HAVE_ADJUSTABLE_CPU_FREQ)
257 rb->cpu_boost(true);
258 #endif
260 #ifdef RB_PROFILE
261 rb->profile_thread();
262 #endif
263 if (initSynth(NULL, ROCKBOX_DIR "/patchset/patchset.cfg",
264 ROCKBOX_DIR "/patchset/drums.cfg") == -1)
266 printf("\nINIT ERROR\n");
267 return -1;
269 //#ifndef SIMULATOR
270 rb->pcm_play_stop();
271 #if INPUT_SRC_CAPS != 0
272 /* Select playback */
273 rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
274 rb->audio_set_output_source(AUDIO_SRC_PLAYBACK);
275 #endif
276 rb->pcm_set_frequency(SAMPLE_RATE); // 44100 22050 11025
279 retval = beatboxmain();
281 #ifdef RB_PROFILE
282 rb->profstop();
283 #endif
285 rb->pcm_play_stop();
286 rb->pcm_set_frequency(HW_SAMPR_DEFAULT);
288 #if defined(HAVE_ADJUSTABLE_CPU_FREQ)
289 rb->cpu_boost(false);
290 #endif
293 if(retval == -1)
294 return PLUGIN_ERROR;
295 return PLUGIN_OK;
298 bool swap=0;
299 bool lastswap=1;
301 inline void synthbuf(void)
303 long *outptr;
304 register int i;
305 static int currentSample=0;
306 int synthtemp[2];
308 #ifndef SYNC
309 if(lastswap==swap) return;
310 lastswap=swap;
312 outptr=(swap ? gmbuf : gmbuf+BUF_SIZE);
313 #else
314 outptr=gmbuf;
315 #endif
317 for(i=0; i<BUF_SIZE/2; i++)
319 synthSample(&synthtemp[0], &synthtemp[1]);
320 currentSample++;
321 *outptr=((synthtemp[0]&0xFFFF) << 16) | (synthtemp[1]&0xFFFF);
322 outptr++;
323 if(currentSample==numberOfSamples)
325 if(playState == STATE_PLAYING)
327 stepFlag=1;
330 currentSample=0;
339 unsigned char trackPos[V_NUMCELLS];
340 unsigned char trackData[H_NUMCELLS][V_NUMCELLS];
341 unsigned char trackMap[V_NUMCELLS] = {38, 39, 40, 41, 42, 43, 44, 56};
344 struct Cell
346 unsigned char val;
347 int color;
350 struct Cell pattern[H_NUMCELLS][V_NUMCELLS];
351 struct Cell dispPattern[H_NUMCELLS][V_NUMCELLS];
354 void advancePosition()
356 int i=0;
357 for(i=0; i<V_NUMCELLS; i++)
359 trackPos[i]++;
360 if(trackPos[i] == H_NUMCELLS || trackData[trackPos[i]][i] == VAL_LOOP)
361 trackPos[i]=0;
366 void sendEvents()
368 int i;
369 for(i=0; i<V_NUMCELLS; i++)
371 if(trackData[trackPos[i]][i] == VAL_ENABLED)
372 pressNote(9, trackMap[i], 127);
376 #define NAME_POSX 10
377 #define NAME_POSY 100
378 void showDrumName(int trackNum)
380 rb->lcd_set_foreground(COLOR_NAME_TEXT);
381 rb->lcd_putsxy(NAME_POSX, NAME_POSY, drumNames[trackMap[trackNum]-35]);
384 void updateDisplay()
386 int i, j;
387 int grayOut=0;
389 for(j=0; j<V_NUMCELLS; j++)
391 grayOut=0;
392 for(i=0; i<H_NUMCELLS; i++)
394 pattern[i][j].color = COLOR_NORMAL;
395 pattern[i][j].val = trackData[i][j];
397 if(trackPos[j] == i)
398 pattern[i][j].color = COLOR_PLAY;
400 if(grayOut)
401 pattern[i][j].color = COLOR_DISABLED;
403 if(trackData[i][j] == VAL_LOOP)
405 pattern[i][j].color = COLOR_LOOPCELL;
406 grayOut=1;
409 if(xCursor == i && yCursor == j && editState == EDITSTATE_PATTERN)
410 pattern[i][j].color = COLOR_EDIT;
416 void resetPosition()
418 int i;
419 for(i=0; i<V_NUMCELLS; i++)
420 trackPos[i]=0;
423 void clearCells()
425 int i,j;
426 for(i=0; i<H_NUMCELLS; i++)
427 for(j=0; j<V_NUMCELLS; j++)
429 pattern[i][j].val=VAL_NONE;
430 dispPattern[i][j].val=VAL_NONE;
431 pattern[i][j].color = 0;
432 dispPattern[i][j].color = 0;
439 void drawGrid()
441 int i, j;
443 rb->lcd_set_foreground(COLOR_GRID);
445 for(i=0; i<H_NUMCELLS+1; i++)
446 rb->lcd_vline(i*CELL_XSIZE+GRID_XPOS, GRID_YPOS, GRID_YPOS+CELL_YSIZE*V_NUMCELLS);
448 for(i=0; i<V_NUMCELLS+1; i++)
449 rb->lcd_hline(GRID_XPOS, GRID_XPOS+CELL_XSIZE*H_NUMCELLS, GRID_YPOS+i*CELL_YSIZE);
452 rb->lcd_update();
455 void drawCell(int i, int j)
457 int cellX, cellY;
459 cellX = GRID_XPOS + CELL_XSIZE*i+1;
460 cellY = GRID_YPOS + CELL_YSIZE*j+1;
462 rb->lcd_set_foreground(pattern[i][j].color);
463 rb->lcd_fillrect(cellX, cellY, CELL_XSIZE-1, CELL_YSIZE-1);
465 rb->lcd_set_foreground(0);
467 if(pattern[i][j].val == VAL_LOOP)
469 rb->lcd_drawline(cellX, cellY, cellX+CELL_XSIZE-2, cellY+CELL_YSIZE-2);
472 if(pattern[i][j].val == VAL_ENABLED)
474 rb->lcd_fillrect(cellX+1, cellY+1, CELL_XSIZE-3, CELL_YSIZE-3);
479 void redrawScreen(unsigned char force)
481 int i, j;
483 for(i=0; i<H_NUMCELLS; i++)
485 for(j=0; j<V_NUMCELLS; j++)
487 if(force || (pattern[i][j].val != dispPattern[i][j].val || pattern[i][j].color != dispPattern[i][j].color))
489 drawCell(i, j);
490 dispPattern[i][j].val = pattern[i][j].val;
491 dispPattern[i][j].color = pattern[i][j].color;
495 rb->lcd_update();
498 void get_more(unsigned char** start, size_t* size)
500 #ifndef SYNC
501 if(lastswap!=swap)
503 // printf("Buffer miss!"); // Comment out the printf to make missses less noticable.
506 #else
507 synthbuf(); // For some reason midiplayer crashes when an update is forced
508 #endif
510 *size = BUF_SIZE*sizeof(short);
511 #ifndef SYNC
512 *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE));
513 swap=!swap;
514 #else
515 *start = (unsigned char*)(gmbuf);
516 #endif
519 int beatboxmain()
521 int vol=0;
524 numberOfSamples=44100/10;
525 synthbuf();
526 rb->pcm_play_data(&get_more, NULL, 0);
528 rb->lcd_set_background(0x000000);
529 rb->lcd_clear_display();
531 resetPosition();
533 int i, j;
535 /* Start at 16 cells/loop for now. User can un-loop if more are needed */
536 for(i=0; i<V_NUMCELLS; i++)
537 trackData[16][i] = VAL_LOOP;
540 /* Very very rough beat to 'Goodbye Horses'
541 trackData[16][3] = VAL_LOOP;
542 trackData[16][2] = VAL_LOOP;
544 trackData[0][3] = 1;
545 trackData[4][3] = 1;
546 trackData[8][3] = 1;
547 trackData[9][3] = 1;
548 trackData[12][3] = 1;
549 trackData[13][3] = 1;
551 trackData[2][2] = 1;
552 trackData[6][2] = 1;
553 trackData[10][2] = 1;
554 trackData[14][2] = 1;
557 drawGrid();
558 showDrumName(yCursor);
559 updateDisplay();
560 redrawScreen(1);
563 while(!quit)
565 #ifndef SYNC
566 synthbuf();
567 #endif
568 rb->yield();
570 if(stepFlag)
572 advancePosition();
573 sendEvents();
574 updateDisplay();
575 redrawScreen(0);
576 stepFlag=0;
579 /* Prevent idle poweroff */
580 rb->reset_poweroff_timer();
582 /* Code taken from Oscilloscope plugin */
583 switch(rb->button_get(false))
586 case BTN_UP:
587 case BTN_UP | BUTTON_REPEAT:
588 vol = rb->global_settings->volume;
589 if (vol < rb->sound_max(SOUND_VOLUME))
591 vol++;
592 rb->sound_set(SOUND_VOLUME, vol);
593 rb->global_settings->volume = vol;
595 break;
597 case BTN_DOWN:
598 case BTN_DOWN | BUTTON_REPEAT:
599 vol = rb->global_settings->volume;
600 if (vol > rb->sound_min(SOUND_VOLUME))
602 vol--;
603 rb->sound_set(SOUND_VOLUME, vol);
604 rb->global_settings->volume = vol;
606 break;
608 case BTN_RIGHT:
610 //pressNote(9, 40, 127);
611 // resetPosition();
612 advancePosition();
613 sendEvents();
614 updateDisplay();
615 redrawScreen(0);
616 break;
619 case BUTTON_LEFT:
622 // isPlaying=1;
623 resetPosition();
624 updateDisplay();
625 redrawScreen(0);
626 //pressNote(9, 39, 127);
627 break;
631 case BEATBOX_UP:
632 case BEATBOX_UP | BUTTON_REPEAT:
634 if(editState == EDITSTATE_PATTERN)
636 if(yCursor > 0)
638 yCursor--;
639 showDrumName(yCursor);
640 updateDisplay();
641 redrawScreen(0);
644 break;
647 case BEATBOX_DOWN:
648 case BEATBOX_DOWN | BUTTON_REPEAT:
650 if(editState == EDITSTATE_PATTERN)
652 if(yCursor < V_NUMCELLS-1)
654 yCursor++;
655 showDrumName(yCursor);
656 updateDisplay();
657 redrawScreen(0);
660 break;
663 case BEATBOX_LEFT:
664 case BEATBOX_LEFT | BUTTON_REPEAT:
666 if(editState == EDITSTATE_PATTERN)
668 if(xCursor > 0)
670 xCursor--;
671 updateDisplay();
672 redrawScreen(0);
675 break;
678 case BEATBOX_RIGHT:
679 case BEATBOX_RIGHT | BUTTON_REPEAT:
681 if(editState == EDITSTATE_PATTERN)
683 if(xCursor < H_NUMCELLS-1)
685 xCursor++;
686 updateDisplay();
687 redrawScreen(0);
690 break;
693 case BEATBOX_SELECT:
695 if(editState == EDITSTATE_PATTERN)
697 int cv = trackData[xCursor][yCursor];
698 cv++;
699 if(cv > VAL_LOOP)
700 cv = VAL_NONE;
702 trackData[xCursor][yCursor] = cv;
704 updateDisplay();
705 redrawScreen(0);
707 break;
711 case BEATBOX_PLAY:
713 if(playState == STATE_PLAYING)
714 playState = STATE_PAUSED;
715 else
717 updateDisplay();
718 redrawScreen(0);
719 sendEvents();
720 playState = STATE_PLAYING;
722 break;
725 case BEATBOX_STOP:
727 if(playState == STATE_STOPPED)
729 quit=1;
730 } else
732 playState =STATE_STOPPED;
733 resetPosition();
734 updateDisplay();
735 redrawScreen(0);
737 break;
744 return 0;