Minor corrections to the .colours file editing; added .colours to the list of support...
[kugel-rb.git] / apps / plugins / beatbox / beatbox.c
blobef391987fbfb9936c09589fded9b0b3f12a40e18
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
9 * Copyright (C) 2005 Karl Kurbjun based on midi2wav by Stepan Moskovchenko
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
19 ****************************************************************************/
21 #include "plugin.h"
22 #include "midi/guspat.h"
23 #include "midi/midiutil.h"
24 #include "midi/synth.h"
25 #include "midi/sequencer.h"
26 #include "midi/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
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
44 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
45 #define BTN_QUIT BUTTON_OFF
46 #define BTN_RIGHT BUTTON_RIGHT
47 #define BTN_UP BUTTON_UP
48 #define BTN_DOWN BUTTON_DOWN
50 #define BTN_RC_QUIT BUTTON_RC_STOP
52 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
53 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
54 #define BTN_QUIT (BUTTON_SELECT | BUTTON_MENU)
55 #define BTN_RIGHT BUTTON_RIGHT
56 #define BTN_UP BUTTON_SCROLL_FWD
57 #define BTN_DOWN BUTTON_SCROLL_BACK
59 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
60 #define BTN_QUIT BUTTON_POWER
61 #define BTN_RIGHT BUTTON_RIGHT
62 #define BTN_UP BUTTON_UP
63 #define BTN_DOWN BUTTON_DOWN
65 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
66 (CONFIG_KEYPAD == SANSA_C200_PAD)
67 #define BTN_QUIT BUTTON_POWER
68 #define BTN_RIGHT BUTTON_RIGHT
69 #define BTN_UP BUTTON_UP
70 #define BTN_DOWN BUTTON_DOWN
73 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
74 #define BTN_QUIT BUTTON_POWER
75 #define BTN_RIGHT BUTTON_RIGHT
76 #define BTN_UP BUTTON_UP
77 #define BTN_DOWN BUTTON_DOWN
79 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
80 #define BTN_QUIT BUTTON_POWER
81 #define BTN_RIGHT BUTTON_RIGHT
82 #define BTN_UP BUTTON_SCROLL_UP
83 #define BTN_DOWN BUTTON_SCROLL_DOWN
85 #endif
89 #define FRACTSIZE 10
91 #ifndef SIMULATOR
93 #if (HW_SAMPR_CAPS & SAMPR_CAP_22)
94 #define SAMPLE_RATE SAMPR_22 // 44100 22050 11025
95 #else
96 #define SAMPLE_RATE SAMPR_44 // 44100 22050 11025
97 #endif
99 #define MAX_VOICES 20 // Note: 24 midi channels is the minimum general midi
100 // spec implementation
102 #else // Simulator requires 44100, and we can afford to use more voices
104 #define SAMPLE_RATE SAMPR_44
105 #define MAX_VOICES 48
107 #endif
110 #define BUF_SIZE 256
111 #define NBUF 2
113 #undef SYNC
115 #ifdef SIMULATOR
116 #define SYNC
117 #endif
119 struct MIDIfile * mf IBSS_ATTR;
121 int numberOfSamples IBSS_ATTR;
122 long bpm IBSS_ATTR;
124 const unsigned char * drumNames[]={
125 "Bass Drum 2 ",
126 "Bass Drum 1 ",
127 "Side Stick ",
128 "Snare Drum 1 ",
129 "Hand Clap ",
130 "Snare Drum 2 ",
131 "Low Tom 2 ",
132 "Closed Hi-hat ",
133 "Low Tom 1 ",
134 "Pedal Hi-hat ",
135 "Mid Tom 2 ",
136 "Open Hi-hat ",
137 "Mid Tom 1 ",
138 "High Tom 2 ",
139 "Crash Cymbal 1 ",
140 "High Tom 1 ",
141 "Ride Cymbal 1 ",
142 "Chinese Cymbal ",
143 "Ride Bell ",
144 "Tambourine ",
145 "Splash Cymbal ",
146 "Cowbell ",
147 "Crash Cymbal 2 ",
148 "Vibra Slap ",
149 "Ride Cymbal 2 ",
150 "High Bongo ",
151 "Low Bongo ",
152 "Mute High Conga",
153 "Open High Conga",
154 "Low Conga ",
155 "High Timbale ",
156 "Low Timbale ",
157 "High Agogo ",
158 "Low Agogo ",
159 "Cabasa ",
160 "Maracas ",
161 "Short Whistle ",
162 "Long Whistle ",
163 "Short Guiro ",
164 "Long Guiro ",
165 "Claves ",
166 "High Wood Block",
167 "Low Wood Block ",
168 "Mute Cuica ",
169 "Open Cuica ",
170 "Mute Triangle ",
171 "Open Triangle ",
172 "Shaker ",
173 "Jingle Bell ",
174 "Bell Tree ",
175 "Castenets ",
176 "Mute Surdo ",
177 "Open Surdo "
180 long gmbuf[BUF_SIZE*NBUF];
182 int quit=0;
184 #define STATE_STOPPED 0
185 #define STATE_PAUSED 1
186 #define STATE_PLAYING 2
189 #define BEATBOX_UP BUTTON_UP
190 #define BEATBOX_DOWN BUTTON_DOWN
191 #define BEATBOX_LEFT BUTTON_LEFT
192 #define BEATBOX_RIGHT BUTTON_RIGHT
193 #define BEATBOX_SELECT BUTTON_SELECT
196 #define BEATBOX_PLAY BUTTON_ON
197 #define BEATBOX_STOP BUTTON_OFF
200 #define VAL_NONE 0
201 #define VAL_ENABLED 1
202 #define VAL_LOOP 2
204 #define H_NUMCELLS 24
205 #define V_NUMCELLS 8
207 #define HILIGHT_NONE 0
208 #define HILIGHT_PLAY 1
209 #define HILIGHT_USER 2
211 #define CELL_XSIZE 9
212 #define CELL_YSIZE 9
214 #define GRID_XPOS 2
215 #define GRID_YPOS 10
218 #define COLOR_NAME_TEXT LCD_RGBPACK(0xFF,0xFF,0xFF)
219 #define COLOR_NORMAL LCD_RGBPACK(0xFF,0xFF,0xFF)
220 #define COLOR_PLAY LCD_RGBPACK(0xFF,0xFF,0x00)
221 #define COLOR_DISABLED LCD_RGBPACK(0xA0,0xA0,0xA0)
222 #define COLOR_LOOPCELL LCD_RGBPACK(0xC0,0xC0,0xC0)
223 #define COLOR_EDIT LCD_RGBPACK(0x30,0x30,0xFF)
224 #define COLOR_GRID LCD_RGBPACK(0xD0,0xD0,0xD0)
226 #define EDITSTATE_PATTERN 0
228 int xCursor=0, yCursor=0;
230 int editState=EDITSTATE_PATTERN;
232 int playState=STATE_STOPPED, stepFlag=0;
235 enum plugin_status plugin_start(const void* parameter)
237 int retval = 0;
239 PLUGIN_IRAM_INIT(rb)
241 rb->lcd_setfont(0);
243 #if defined(HAVE_ADJUSTABLE_CPU_FREQ)
244 rb->cpu_boost(true);
245 #endif
247 #ifdef RB_PROFILE
248 rb->profile_thread();
249 #endif
250 if (initSynth(NULL, ROCKBOX_DIR "/patchset/patchset.cfg",
251 ROCKBOX_DIR "/patchset/drums.cfg") == -1)
253 printf("\nINIT ERROR\n");
254 return -1;
256 //#ifndef SIMULATOR
257 rb->pcm_play_stop();
258 #if INPUT_SRC_CAPS != 0
259 /* Select playback */
260 rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
261 rb->audio_set_output_source(AUDIO_SRC_PLAYBACK);
262 #endif
263 rb->pcm_set_frequency(SAMPLE_RATE); // 44100 22050 11025
266 retval = beatboxmain();
268 #ifdef RB_PROFILE
269 rb->profstop();
270 #endif
272 rb->pcm_play_stop();
273 rb->pcm_set_frequency(HW_SAMPR_DEFAULT);
275 #if defined(HAVE_ADJUSTABLE_CPU_FREQ)
276 rb->cpu_boost(false);
277 #endif
280 if(retval == -1)
281 return PLUGIN_ERROR;
282 return PLUGIN_OK;
285 bool swap=0;
286 bool lastswap=1;
288 inline void synthbuf(void)
290 long *outptr;
291 register int i;
292 static int currentSample=0;
293 int synthtemp[2];
295 #ifndef SYNC
296 if(lastswap==swap) return;
297 lastswap=swap;
299 outptr=(swap ? gmbuf : gmbuf+BUF_SIZE);
300 #else
301 outptr=gmbuf;
302 #endif
304 for(i=0; i<BUF_SIZE/2; i++)
306 synthSample(&synthtemp[0], &synthtemp[1]);
307 currentSample++;
308 *outptr=((synthtemp[0]&0xFFFF) << 16) | (synthtemp[1]&0xFFFF);
309 outptr++;
310 if(currentSample==numberOfSamples)
312 if(playState == STATE_PLAYING)
314 stepFlag=1;
317 currentSample=0;
326 unsigned char trackPos[V_NUMCELLS];
327 unsigned char trackData[H_NUMCELLS][V_NUMCELLS];
328 unsigned char trackMap[V_NUMCELLS] = {38, 39, 40, 41, 42, 43, 44, 56};
331 struct Cell
333 unsigned char val;
334 int color;
337 struct Cell pattern[H_NUMCELLS][V_NUMCELLS];
338 struct Cell dispPattern[H_NUMCELLS][V_NUMCELLS];
341 void advancePosition()
343 int i=0;
344 for(i=0; i<V_NUMCELLS; i++)
346 trackPos[i]++;
347 if(trackPos[i] == H_NUMCELLS || trackData[trackPos[i]][i] == VAL_LOOP)
348 trackPos[i]=0;
353 void sendEvents()
355 int i;
356 for(i=0; i<V_NUMCELLS; i++)
358 if(trackData[trackPos[i]][i] == VAL_ENABLED)
359 pressNote(9, trackMap[i], 127);
363 #define NAME_POSX 10
364 #define NAME_POSY 100
365 void showDrumName(int trackNum)
367 rb->lcd_set_foreground(COLOR_NAME_TEXT);
368 rb->lcd_putsxy(NAME_POSX, NAME_POSY, drumNames[trackMap[trackNum]-35]);
371 void updateDisplay()
373 int i, j;
374 int grayOut=0;
376 for(j=0; j<V_NUMCELLS; j++)
378 grayOut=0;
379 for(i=0; i<H_NUMCELLS; i++)
381 pattern[i][j].color = COLOR_NORMAL;
382 pattern[i][j].val = trackData[i][j];
384 if(trackPos[j] == i)
385 pattern[i][j].color = COLOR_PLAY;
387 if(grayOut)
388 pattern[i][j].color = COLOR_DISABLED;
390 if(trackData[i][j] == VAL_LOOP)
392 pattern[i][j].color = COLOR_LOOPCELL;
393 grayOut=1;
396 if(xCursor == i && yCursor == j && editState == EDITSTATE_PATTERN)
397 pattern[i][j].color = COLOR_EDIT;
403 void resetPosition()
405 int i;
406 for(i=0; i<V_NUMCELLS; i++)
407 trackPos[i]=0;
410 void clearCells()
412 int i,j;
413 for(i=0; i<H_NUMCELLS; i++)
414 for(j=0; j<V_NUMCELLS; j++)
416 pattern[i][j].val=VAL_NONE;
417 dispPattern[i][j].val=VAL_NONE;
418 pattern[i][j].color = 0;
419 dispPattern[i][j].color = 0;
426 void drawGrid()
428 int i, j;
430 rb->lcd_set_foreground(COLOR_GRID);
432 for(i=0; i<H_NUMCELLS+1; i++)
433 rb->lcd_vline(i*CELL_XSIZE+GRID_XPOS, GRID_YPOS, GRID_YPOS+CELL_YSIZE*V_NUMCELLS);
435 for(i=0; i<V_NUMCELLS+1; i++)
436 rb->lcd_hline(GRID_XPOS, GRID_XPOS+CELL_XSIZE*H_NUMCELLS, GRID_YPOS+i*CELL_YSIZE);
439 rb->lcd_update();
442 void drawCell(int i, int j)
444 int cellX, cellY;
446 cellX = GRID_XPOS + CELL_XSIZE*i+1;
447 cellY = GRID_YPOS + CELL_YSIZE*j+1;
449 rb->lcd_set_foreground(pattern[i][j].color);
450 rb->lcd_fillrect(cellX, cellY, CELL_XSIZE-1, CELL_YSIZE-1);
452 rb->lcd_set_foreground(0);
454 if(pattern[i][j].val == VAL_LOOP)
456 rb->lcd_drawline(cellX, cellY, cellX+CELL_XSIZE-2, cellY+CELL_YSIZE-2);
459 if(pattern[i][j].val == VAL_ENABLED)
461 rb->lcd_fillrect(cellX+1, cellY+1, CELL_XSIZE-3, CELL_YSIZE-3);
466 void redrawScreen(unsigned char force)
468 int i, j;
470 for(i=0; i<H_NUMCELLS; i++)
472 for(j=0; j<V_NUMCELLS; j++)
474 if(force || (pattern[i][j].val != dispPattern[i][j].val || pattern[i][j].color != dispPattern[i][j].color))
476 drawCell(i, j);
477 dispPattern[i][j].val = pattern[i][j].val;
478 dispPattern[i][j].color = pattern[i][j].color;
482 rb->lcd_update();
485 void get_more(unsigned char** start, size_t* size)
487 #ifndef SYNC
488 if(lastswap!=swap)
490 // printf("Buffer miss!"); // Comment out the printf to make missses less noticable.
493 #else
494 synthbuf(); // For some reason midiplayer crashes when an update is forced
495 #endif
497 *size = BUF_SIZE*sizeof(short);
498 #ifndef SYNC
499 *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE));
500 swap=!swap;
501 #else
502 *start = (unsigned char*)(gmbuf);
503 #endif
506 int beatboxmain()
508 int vol=0;
511 numberOfSamples=44100/10;
512 synthbuf();
513 rb->pcm_play_data(&get_more, NULL, 0);
515 rb->lcd_set_background(0x000000);
516 rb->lcd_clear_display();
518 resetPosition();
520 int i, j;
522 /* Start at 16 cells/loop for now. User can un-loop if more are needed */
523 for(i=0; i<V_NUMCELLS; i++)
524 trackData[16][i] = VAL_LOOP;
527 /* Very very rough beat to 'Goodbye Horses'
528 trackData[16][3] = VAL_LOOP;
529 trackData[16][2] = VAL_LOOP;
531 trackData[0][3] = 1;
532 trackData[4][3] = 1;
533 trackData[8][3] = 1;
534 trackData[9][3] = 1;
535 trackData[12][3] = 1;
536 trackData[13][3] = 1;
538 trackData[2][2] = 1;
539 trackData[6][2] = 1;
540 trackData[10][2] = 1;
541 trackData[14][2] = 1;
544 drawGrid();
545 showDrumName(yCursor);
546 updateDisplay();
547 redrawScreen(1);
550 while(!quit)
552 #ifndef SYNC
553 synthbuf();
554 #endif
555 rb->yield();
557 if(stepFlag)
559 advancePosition();
560 sendEvents();
561 updateDisplay();
562 redrawScreen(0);
563 stepFlag=0;
566 /* Prevent idle poweroff */
567 rb->reset_poweroff_timer();
569 /* Code taken from Oscilloscope plugin */
570 switch(rb->button_get(false))
573 case BTN_UP:
574 case BTN_UP | BUTTON_REPEAT:
575 vol = rb->global_settings->volume;
576 if (vol < rb->sound_max(SOUND_VOLUME))
578 vol++;
579 rb->sound_set(SOUND_VOLUME, vol);
580 rb->global_settings->volume = vol;
582 break;
584 case BTN_DOWN:
585 case BTN_DOWN | BUTTON_REPEAT:
586 vol = rb->global_settings->volume;
587 if (vol > rb->sound_min(SOUND_VOLUME))
589 vol--;
590 rb->sound_set(SOUND_VOLUME, vol);
591 rb->global_settings->volume = vol;
593 break;
595 case BTN_RIGHT:
597 //pressNote(9, 40, 127);
598 // resetPosition();
599 advancePosition();
600 sendEvents();
601 updateDisplay();
602 redrawScreen(0);
603 break;
606 case BUTTON_LEFT:
609 // isPlaying=1;
610 resetPosition();
611 updateDisplay();
612 redrawScreen(0);
613 //pressNote(9, 39, 127);
614 break;
618 case BEATBOX_UP:
619 case BEATBOX_UP | BUTTON_REPEAT:
621 if(editState == EDITSTATE_PATTERN)
623 if(yCursor > 0)
625 yCursor--;
626 showDrumName(yCursor);
627 updateDisplay();
628 redrawScreen(0);
631 break;
634 case BEATBOX_DOWN:
635 case BEATBOX_DOWN | BUTTON_REPEAT:
637 if(editState == EDITSTATE_PATTERN)
639 if(yCursor < V_NUMCELLS-1)
641 yCursor++;
642 showDrumName(yCursor);
643 updateDisplay();
644 redrawScreen(0);
647 break;
650 case BEATBOX_LEFT:
651 case BEATBOX_LEFT | BUTTON_REPEAT:
653 if(editState == EDITSTATE_PATTERN)
655 if(xCursor > 0)
657 xCursor--;
658 updateDisplay();
659 redrawScreen(0);
662 break;
665 case BEATBOX_RIGHT:
666 case BEATBOX_RIGHT | BUTTON_REPEAT:
668 if(editState == EDITSTATE_PATTERN)
670 if(xCursor < H_NUMCELLS-1)
672 xCursor++;
673 updateDisplay();
674 redrawScreen(0);
677 break;
680 case BEATBOX_SELECT:
682 if(editState == EDITSTATE_PATTERN)
684 int cv = trackData[xCursor][yCursor];
685 cv++;
686 if(cv > VAL_LOOP)
687 cv = VAL_NONE;
689 trackData[xCursor][yCursor] = cv;
691 updateDisplay();
692 redrawScreen(0);
694 break;
698 case BEATBOX_PLAY:
700 if(playState == STATE_PLAYING)
701 playState = STATE_PAUSED;
702 else
704 updateDisplay();
705 redrawScreen(0);
706 sendEvents();
707 playState = STATE_PLAYING;
709 break;
712 case BEATBOX_STOP:
714 if(playState == STATE_STOPPED)
716 quit=1;
717 } else
719 playState =STATE_STOPPED;
720 resetPosition();
721 updateDisplay();
722 redrawScreen(0);
724 break;
731 return 0;