Fix red, moved around a bit to much.
[kugel-rb.git] / apps / plugins / beatbox / beatbox.c
blobb8e46bcd0cd3299ff1cd9ded8197f938d235e2e3
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 #endif
96 #define FRACTSIZE 10
98 #ifndef SIMULATOR
100 #if (HW_SAMPR_CAPS & SAMPR_CAP_22)
101 #define SAMPLE_RATE SAMPR_22 // 44100 22050 11025
102 #else
103 #define SAMPLE_RATE SAMPR_44 // 44100 22050 11025
104 #endif
106 #define MAX_VOICES 20 // Note: 24 midi channels is the minimum general midi
107 // spec implementation
109 #else // Simulator requires 44100, and we can afford to use more voices
111 #define SAMPLE_RATE SAMPR_44
112 #define MAX_VOICES 48
114 #endif
117 #define BUF_SIZE 256
118 #define NBUF 2
120 #undef SYNC
122 #ifdef SIMULATOR
123 #define SYNC
124 #endif
126 struct MIDIfile * mf IBSS_ATTR;
128 int numberOfSamples IBSS_ATTR;
129 long bpm IBSS_ATTR;
131 const unsigned char * drumNames[]={
132 "Bass Drum 2 ",
133 "Bass Drum 1 ",
134 "Side Stick ",
135 "Snare Drum 1 ",
136 "Hand Clap ",
137 "Snare Drum 2 ",
138 "Low Tom 2 ",
139 "Closed Hi-hat ",
140 "Low Tom 1 ",
141 "Pedal Hi-hat ",
142 "Mid Tom 2 ",
143 "Open Hi-hat ",
144 "Mid Tom 1 ",
145 "High Tom 2 ",
146 "Crash Cymbal 1 ",
147 "High Tom 1 ",
148 "Ride Cymbal 1 ",
149 "Chinese Cymbal ",
150 "Ride Bell ",
151 "Tambourine ",
152 "Splash Cymbal ",
153 "Cowbell ",
154 "Crash Cymbal 2 ",
155 "Vibra Slap ",
156 "Ride Cymbal 2 ",
157 "High Bongo ",
158 "Low Bongo ",
159 "Mute High Conga",
160 "Open High Conga",
161 "Low Conga ",
162 "High Timbale ",
163 "Low Timbale ",
164 "High Agogo ",
165 "Low Agogo ",
166 "Cabasa ",
167 "Maracas ",
168 "Short Whistle ",
169 "Long Whistle ",
170 "Short Guiro ",
171 "Long Guiro ",
172 "Claves ",
173 "High Wood Block",
174 "Low Wood Block ",
175 "Mute Cuica ",
176 "Open Cuica ",
177 "Mute Triangle ",
178 "Open Triangle ",
179 "Shaker ",
180 "Jingle Bell ",
181 "Bell Tree ",
182 "Castenets ",
183 "Mute Surdo ",
184 "Open Surdo "
187 long gmbuf[BUF_SIZE*NBUF];
189 int quit=0;
191 #define STATE_STOPPED 0
192 #define STATE_PAUSED 1
193 #define STATE_PLAYING 2
196 #define BEATBOX_UP BUTTON_UP
197 #define BEATBOX_DOWN BUTTON_DOWN
198 #define BEATBOX_LEFT BUTTON_LEFT
199 #define BEATBOX_RIGHT BUTTON_RIGHT
200 #define BEATBOX_SELECT BUTTON_SELECT
203 #define BEATBOX_PLAY BUTTON_ON
204 #define BEATBOX_STOP BUTTON_OFF
207 #define VAL_NONE 0
208 #define VAL_ENABLED 1
209 #define VAL_LOOP 2
211 #define H_NUMCELLS 24
212 #define V_NUMCELLS 8
214 #define HILIGHT_NONE 0
215 #define HILIGHT_PLAY 1
216 #define HILIGHT_USER 2
218 #define CELL_XSIZE 9
219 #define CELL_YSIZE 9
221 #define GRID_XPOS 2
222 #define GRID_YPOS 10
225 #define COLOR_NAME_TEXT LCD_RGBPACK(0xFF,0xFF,0xFF)
226 #define COLOR_NORMAL LCD_RGBPACK(0xFF,0xFF,0xFF)
227 #define COLOR_PLAY LCD_RGBPACK(0xFF,0xFF,0x00)
228 #define COLOR_DISABLED LCD_RGBPACK(0xA0,0xA0,0xA0)
229 #define COLOR_LOOPCELL LCD_RGBPACK(0xC0,0xC0,0xC0)
230 #define COLOR_EDIT LCD_RGBPACK(0x30,0x30,0xFF)
231 #define COLOR_GRID LCD_RGBPACK(0xD0,0xD0,0xD0)
233 #define EDITSTATE_PATTERN 0
235 int xCursor=0, yCursor=0;
237 int editState=EDITSTATE_PATTERN;
239 int playState=STATE_STOPPED, stepFlag=0;
242 enum plugin_status plugin_start(const void* parameter)
244 int retval = 0;
246 PLUGIN_IRAM_INIT(rb)
248 rb->lcd_setfont(0);
250 #if defined(HAVE_ADJUSTABLE_CPU_FREQ)
251 rb->cpu_boost(true);
252 #endif
254 #ifdef RB_PROFILE
255 rb->profile_thread();
256 #endif
257 if (initSynth(NULL, ROCKBOX_DIR "/patchset/patchset.cfg",
258 ROCKBOX_DIR "/patchset/drums.cfg") == -1)
260 printf("\nINIT ERROR\n");
261 return -1;
263 //#ifndef SIMULATOR
264 rb->pcm_play_stop();
265 #if INPUT_SRC_CAPS != 0
266 /* Select playback */
267 rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
268 rb->audio_set_output_source(AUDIO_SRC_PLAYBACK);
269 #endif
270 rb->pcm_set_frequency(SAMPLE_RATE); // 44100 22050 11025
273 retval = beatboxmain();
275 #ifdef RB_PROFILE
276 rb->profstop();
277 #endif
279 rb->pcm_play_stop();
280 rb->pcm_set_frequency(HW_SAMPR_DEFAULT);
282 #if defined(HAVE_ADJUSTABLE_CPU_FREQ)
283 rb->cpu_boost(false);
284 #endif
287 if(retval == -1)
288 return PLUGIN_ERROR;
289 return PLUGIN_OK;
292 bool swap=0;
293 bool lastswap=1;
295 inline void synthbuf(void)
297 long *outptr;
298 register int i;
299 static int currentSample=0;
300 int synthtemp[2];
302 #ifndef SYNC
303 if(lastswap==swap) return;
304 lastswap=swap;
306 outptr=(swap ? gmbuf : gmbuf+BUF_SIZE);
307 #else
308 outptr=gmbuf;
309 #endif
311 for(i=0; i<BUF_SIZE/2; i++)
313 synthSample(&synthtemp[0], &synthtemp[1]);
314 currentSample++;
315 *outptr=((synthtemp[0]&0xFFFF) << 16) | (synthtemp[1]&0xFFFF);
316 outptr++;
317 if(currentSample==numberOfSamples)
319 if(playState == STATE_PLAYING)
321 stepFlag=1;
324 currentSample=0;
333 unsigned char trackPos[V_NUMCELLS];
334 unsigned char trackData[H_NUMCELLS][V_NUMCELLS];
335 unsigned char trackMap[V_NUMCELLS] = {38, 39, 40, 41, 42, 43, 44, 56};
338 struct Cell
340 unsigned char val;
341 int color;
344 struct Cell pattern[H_NUMCELLS][V_NUMCELLS];
345 struct Cell dispPattern[H_NUMCELLS][V_NUMCELLS];
348 void advancePosition()
350 int i=0;
351 for(i=0; i<V_NUMCELLS; i++)
353 trackPos[i]++;
354 if(trackPos[i] == H_NUMCELLS || trackData[trackPos[i]][i] == VAL_LOOP)
355 trackPos[i]=0;
360 void sendEvents()
362 int i;
363 for(i=0; i<V_NUMCELLS; i++)
365 if(trackData[trackPos[i]][i] == VAL_ENABLED)
366 pressNote(9, trackMap[i], 127);
370 #define NAME_POSX 10
371 #define NAME_POSY 100
372 void showDrumName(int trackNum)
374 rb->lcd_set_foreground(COLOR_NAME_TEXT);
375 rb->lcd_putsxy(NAME_POSX, NAME_POSY, drumNames[trackMap[trackNum]-35]);
378 void updateDisplay()
380 int i, j;
381 int grayOut=0;
383 for(j=0; j<V_NUMCELLS; j++)
385 grayOut=0;
386 for(i=0; i<H_NUMCELLS; i++)
388 pattern[i][j].color = COLOR_NORMAL;
389 pattern[i][j].val = trackData[i][j];
391 if(trackPos[j] == i)
392 pattern[i][j].color = COLOR_PLAY;
394 if(grayOut)
395 pattern[i][j].color = COLOR_DISABLED;
397 if(trackData[i][j] == VAL_LOOP)
399 pattern[i][j].color = COLOR_LOOPCELL;
400 grayOut=1;
403 if(xCursor == i && yCursor == j && editState == EDITSTATE_PATTERN)
404 pattern[i][j].color = COLOR_EDIT;
410 void resetPosition()
412 int i;
413 for(i=0; i<V_NUMCELLS; i++)
414 trackPos[i]=0;
417 void clearCells()
419 int i,j;
420 for(i=0; i<H_NUMCELLS; i++)
421 for(j=0; j<V_NUMCELLS; j++)
423 pattern[i][j].val=VAL_NONE;
424 dispPattern[i][j].val=VAL_NONE;
425 pattern[i][j].color = 0;
426 dispPattern[i][j].color = 0;
433 void drawGrid()
435 int i, j;
437 rb->lcd_set_foreground(COLOR_GRID);
439 for(i=0; i<H_NUMCELLS+1; i++)
440 rb->lcd_vline(i*CELL_XSIZE+GRID_XPOS, GRID_YPOS, GRID_YPOS+CELL_YSIZE*V_NUMCELLS);
442 for(i=0; i<V_NUMCELLS+1; i++)
443 rb->lcd_hline(GRID_XPOS, GRID_XPOS+CELL_XSIZE*H_NUMCELLS, GRID_YPOS+i*CELL_YSIZE);
446 rb->lcd_update();
449 void drawCell(int i, int j)
451 int cellX, cellY;
453 cellX = GRID_XPOS + CELL_XSIZE*i+1;
454 cellY = GRID_YPOS + CELL_YSIZE*j+1;
456 rb->lcd_set_foreground(pattern[i][j].color);
457 rb->lcd_fillrect(cellX, cellY, CELL_XSIZE-1, CELL_YSIZE-1);
459 rb->lcd_set_foreground(0);
461 if(pattern[i][j].val == VAL_LOOP)
463 rb->lcd_drawline(cellX, cellY, cellX+CELL_XSIZE-2, cellY+CELL_YSIZE-2);
466 if(pattern[i][j].val == VAL_ENABLED)
468 rb->lcd_fillrect(cellX+1, cellY+1, CELL_XSIZE-3, CELL_YSIZE-3);
473 void redrawScreen(unsigned char force)
475 int i, j;
477 for(i=0; i<H_NUMCELLS; i++)
479 for(j=0; j<V_NUMCELLS; j++)
481 if(force || (pattern[i][j].val != dispPattern[i][j].val || pattern[i][j].color != dispPattern[i][j].color))
483 drawCell(i, j);
484 dispPattern[i][j].val = pattern[i][j].val;
485 dispPattern[i][j].color = pattern[i][j].color;
489 rb->lcd_update();
492 void get_more(unsigned char** start, size_t* size)
494 #ifndef SYNC
495 if(lastswap!=swap)
497 // printf("Buffer miss!"); // Comment out the printf to make missses less noticable.
500 #else
501 synthbuf(); // For some reason midiplayer crashes when an update is forced
502 #endif
504 *size = BUF_SIZE*sizeof(short);
505 #ifndef SYNC
506 *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE));
507 swap=!swap;
508 #else
509 *start = (unsigned char*)(gmbuf);
510 #endif
513 int beatboxmain()
515 int vol=0;
518 numberOfSamples=44100/10;
519 synthbuf();
520 rb->pcm_play_data(&get_more, NULL, 0);
522 rb->lcd_set_background(0x000000);
523 rb->lcd_clear_display();
525 resetPosition();
527 int i, j;
529 /* Start at 16 cells/loop for now. User can un-loop if more are needed */
530 for(i=0; i<V_NUMCELLS; i++)
531 trackData[16][i] = VAL_LOOP;
534 /* Very very rough beat to 'Goodbye Horses'
535 trackData[16][3] = VAL_LOOP;
536 trackData[16][2] = VAL_LOOP;
538 trackData[0][3] = 1;
539 trackData[4][3] = 1;
540 trackData[8][3] = 1;
541 trackData[9][3] = 1;
542 trackData[12][3] = 1;
543 trackData[13][3] = 1;
545 trackData[2][2] = 1;
546 trackData[6][2] = 1;
547 trackData[10][2] = 1;
548 trackData[14][2] = 1;
551 drawGrid();
552 showDrumName(yCursor);
553 updateDisplay();
554 redrawScreen(1);
557 while(!quit)
559 #ifndef SYNC
560 synthbuf();
561 #endif
562 rb->yield();
564 if(stepFlag)
566 advancePosition();
567 sendEvents();
568 updateDisplay();
569 redrawScreen(0);
570 stepFlag=0;
573 /* Prevent idle poweroff */
574 rb->reset_poweroff_timer();
576 /* Code taken from Oscilloscope plugin */
577 switch(rb->button_get(false))
580 case BTN_UP:
581 case BTN_UP | BUTTON_REPEAT:
582 vol = rb->global_settings->volume;
583 if (vol < rb->sound_max(SOUND_VOLUME))
585 vol++;
586 rb->sound_set(SOUND_VOLUME, vol);
587 rb->global_settings->volume = vol;
589 break;
591 case BTN_DOWN:
592 case BTN_DOWN | BUTTON_REPEAT:
593 vol = rb->global_settings->volume;
594 if (vol > rb->sound_min(SOUND_VOLUME))
596 vol--;
597 rb->sound_set(SOUND_VOLUME, vol);
598 rb->global_settings->volume = vol;
600 break;
602 case BTN_RIGHT:
604 //pressNote(9, 40, 127);
605 // resetPosition();
606 advancePosition();
607 sendEvents();
608 updateDisplay();
609 redrawScreen(0);
610 break;
613 case BUTTON_LEFT:
616 // isPlaying=1;
617 resetPosition();
618 updateDisplay();
619 redrawScreen(0);
620 //pressNote(9, 39, 127);
621 break;
625 case BEATBOX_UP:
626 case BEATBOX_UP | BUTTON_REPEAT:
628 if(editState == EDITSTATE_PATTERN)
630 if(yCursor > 0)
632 yCursor--;
633 showDrumName(yCursor);
634 updateDisplay();
635 redrawScreen(0);
638 break;
641 case BEATBOX_DOWN:
642 case BEATBOX_DOWN | BUTTON_REPEAT:
644 if(editState == EDITSTATE_PATTERN)
646 if(yCursor < V_NUMCELLS-1)
648 yCursor++;
649 showDrumName(yCursor);
650 updateDisplay();
651 redrawScreen(0);
654 break;
657 case BEATBOX_LEFT:
658 case BEATBOX_LEFT | BUTTON_REPEAT:
660 if(editState == EDITSTATE_PATTERN)
662 if(xCursor > 0)
664 xCursor--;
665 updateDisplay();
666 redrawScreen(0);
669 break;
672 case BEATBOX_RIGHT:
673 case BEATBOX_RIGHT | BUTTON_REPEAT:
675 if(editState == EDITSTATE_PATTERN)
677 if(xCursor < H_NUMCELLS-1)
679 xCursor++;
680 updateDisplay();
681 redrawScreen(0);
684 break;
687 case BEATBOX_SELECT:
689 if(editState == EDITSTATE_PATTERN)
691 int cv = trackData[xCursor][yCursor];
692 cv++;
693 if(cv > VAL_LOOP)
694 cv = VAL_NONE;
696 trackData[xCursor][yCursor] = cv;
698 updateDisplay();
699 redrawScreen(0);
701 break;
705 case BEATBOX_PLAY:
707 if(playState == STATE_PLAYING)
708 playState = STATE_PAUSED;
709 else
711 updateDisplay();
712 redrawScreen(0);
713 sendEvents();
714 playState = STATE_PLAYING;
716 break;
719 case BEATBOX_STOP:
721 if(playState == STATE_STOPPED)
723 quit=1;
724 } else
726 playState =STATE_STOPPED;
727 resetPosition();
728 updateDisplay();
729 redrawScreen(0);
731 break;
738 return 0;