FS#12076 - DB stats resurrection: If the filename was changed, require
[kugel-rb.git] / apps / plugins / beatbox / beatbox.c
blobb09464ab1420e2aaaf2a35c00dc7954f0d43800c
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"
30 /* variable button definitions */
31 #if CONFIG_KEYPAD == RECORDER_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 == ONDIO_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 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
44 #define BTN_QUIT BUTTON_OFF
45 #define BTN_RIGHT BUTTON_RIGHT
46 #define BTN_UP BUTTON_UP
47 #define BTN_DOWN BUTTON_DOWN
49 #define BTN_RC_QUIT BUTTON_RC_STOP
51 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
52 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
53 #define BTN_QUIT (BUTTON_SELECT | BUTTON_MENU)
54 #define BTN_RIGHT BUTTON_RIGHT
55 #define BTN_UP BUTTON_SCROLL_FWD
56 #define BTN_DOWN BUTTON_SCROLL_BACK
58 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
59 #define BTN_QUIT BUTTON_POWER
60 #define BTN_RIGHT BUTTON_RIGHT
61 #define BTN_UP BUTTON_UP
62 #define BTN_DOWN BUTTON_DOWN
64 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
65 (CONFIG_KEYPAD == SANSA_C200_PAD)
66 #define BTN_QUIT BUTTON_POWER
67 #define BTN_RIGHT BUTTON_RIGHT
68 #define BTN_UP BUTTON_UP
69 #define BTN_DOWN BUTTON_DOWN
72 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
73 #define BTN_QUIT BUTTON_POWER
74 #define BTN_RIGHT BUTTON_RIGHT
75 #define BTN_UP BUTTON_UP
76 #define BTN_DOWN BUTTON_DOWN
78 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
79 #define BTN_QUIT BUTTON_POWER
80 #define BTN_RIGHT BUTTON_RIGHT
81 #define BTN_UP BUTTON_SCROLL_UP
82 #define BTN_DOWN BUTTON_SCROLL_DOWN
84 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
85 #define BTN_QUIT BUTTON_POWER
86 #define BTN_RIGHT BUTTON_RIGHT
87 #define BTN_UP BUTTON_UP
88 #define BTN_DOWN BUTTON_DOWN
90 #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
91 #define BTN_QUIT BUTTON_POWER
92 #define BTN_RIGHT BUTTON_NEXT
93 #define BTN_UP BUTTON_UP
94 #define BTN_DOWN BUTTON_DOWN
96 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
97 #define BTN_QUIT BUTTON_POWER
98 #define BTN_RIGHT BUTTON_NEXT
99 #define BTN_UP BUTTON_UP
100 #define BTN_DOWN BUTTON_DOWN
102 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
103 #define BTN_QUIT BUTTON_PLAY
104 #define BTN_RIGHT BUTTON_RIGHT
105 #define BTN_UP BUTTON_UP
106 #define BTN_DOWN BUTTON_DOWN
108 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
109 #define BTN_QUIT BUTTON_REC
110 #define BTN_RIGHT BUTTON_NEXT
111 #define BTN_UP BUTTON_UP
112 #define BTN_DOWN BUTTON_DOWN
114 #endif
118 #define FRACTSIZE 10
120 #ifndef SIMULATOR
122 #if (HW_SAMPR_CAPS & SAMPR_CAP_22)
123 #define SAMPLE_RATE SAMPR_22 // 44100 22050 11025
124 #else
125 #define SAMPLE_RATE SAMPR_44 // 44100 22050 11025
126 #endif
128 #define MAX_VOICES 20 // Note: 24 midi channels is the minimum general midi
129 // spec implementation
131 #else // Simulator requires 44100, and we can afford to use more voices
133 #define SAMPLE_RATE SAMPR_44
134 #define MAX_VOICES 48
136 #endif
139 #define BUF_SIZE 256
140 #define NBUF 2
142 #undef SYNC
144 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
145 #define SYNC
146 #endif
148 struct MIDIfile * mf IBSS_ATTR;
150 int numberOfSamples IBSS_ATTR;
151 long bpm IBSS_ATTR;
153 const unsigned char * drumNames[]={
154 "Bass Drum 2 ",
155 "Bass Drum 1 ",
156 "Side Stick ",
157 "Snare Drum 1 ",
158 "Hand Clap ",
159 "Snare Drum 2 ",
160 "Low Tom 2 ",
161 "Closed Hi-hat ",
162 "Low Tom 1 ",
163 "Pedal Hi-hat ",
164 "Mid Tom 2 ",
165 "Open Hi-hat ",
166 "Mid Tom 1 ",
167 "High Tom 2 ",
168 "Crash Cymbal 1 ",
169 "High Tom 1 ",
170 "Ride Cymbal 1 ",
171 "Chinese Cymbal ",
172 "Ride Bell ",
173 "Tambourine ",
174 "Splash Cymbal ",
175 "Cowbell ",
176 "Crash Cymbal 2 ",
177 "Vibra Slap ",
178 "Ride Cymbal 2 ",
179 "High Bongo ",
180 "Low Bongo ",
181 "Mute High Conga",
182 "Open High Conga",
183 "Low Conga ",
184 "High Timbale ",
185 "Low Timbale ",
186 "High Agogo ",
187 "Low Agogo ",
188 "Cabasa ",
189 "Maracas ",
190 "Short Whistle ",
191 "Long Whistle ",
192 "Short Guiro ",
193 "Long Guiro ",
194 "Claves ",
195 "High Wood Block",
196 "Low Wood Block ",
197 "Mute Cuica ",
198 "Open Cuica ",
199 "Mute Triangle ",
200 "Open Triangle ",
201 "Shaker ",
202 "Jingle Bell ",
203 "Bell Tree ",
204 "Castenets ",
205 "Mute Surdo ",
206 "Open Surdo "
209 long gmbuf[BUF_SIZE*NBUF];
211 int quit=0;
213 #define STATE_STOPPED 0
214 #define STATE_PAUSED 1
215 #define STATE_PLAYING 2
218 #define BEATBOX_UP BUTTON_UP
219 #define BEATBOX_DOWN BUTTON_DOWN
220 #define BEATBOX_LEFT BUTTON_LEFT
221 #define BEATBOX_RIGHT BUTTON_RIGHT
222 #define BEATBOX_SELECT BUTTON_SELECT
225 #define BEATBOX_PLAY BUTTON_ON
226 #define BEATBOX_STOP BUTTON_OFF
229 #define VAL_NONE 0
230 #define VAL_ENABLED 1
231 #define VAL_LOOP 2
233 #define H_NUMCELLS 24
234 #define V_NUMCELLS 8
236 #define HILIGHT_NONE 0
237 #define HILIGHT_PLAY 1
238 #define HILIGHT_USER 2
240 #define CELL_XSIZE 9
241 #define CELL_YSIZE 9
243 #define GRID_XPOS 2
244 #define GRID_YPOS 10
247 #define COLOR_NAME_TEXT LCD_RGBPACK(0xFF,0xFF,0xFF)
248 #define COLOR_NORMAL LCD_RGBPACK(0xFF,0xFF,0xFF)
249 #define COLOR_PLAY LCD_RGBPACK(0xFF,0xFF,0x00)
250 #define COLOR_DISABLED LCD_RGBPACK(0xA0,0xA0,0xA0)
251 #define COLOR_LOOPCELL LCD_RGBPACK(0xC0,0xC0,0xC0)
252 #define COLOR_EDIT LCD_RGBPACK(0x30,0x30,0xFF)
253 #define COLOR_GRID LCD_RGBPACK(0xD0,0xD0,0xD0)
255 #define EDITSTATE_PATTERN 0
257 int xCursor=0, yCursor=0;
259 int editState=EDITSTATE_PATTERN;
261 int playState=STATE_STOPPED, stepFlag=0;
264 enum plugin_status plugin_start(const void* parameter)
266 int retval = 0;
268 rb->lcd_setfont(0);
270 #if defined(HAVE_ADJUSTABLE_CPU_FREQ)
271 rb->cpu_boost(true);
272 #endif
274 #ifdef RB_PROFILE
275 rb->profile_thread();
276 #endif
277 if (initSynth(NULL, ROCKBOX_DIR "/patchset/patchset.cfg",
278 ROCKBOX_DIR "/patchset/drums.cfg") == -1)
280 printf("\nINIT ERROR\n");
281 return -1;
283 //#ifndef SIMULATOR
284 rb->pcm_play_stop();
285 #if INPUT_SRC_CAPS != 0
286 /* Select playback */
287 rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
288 rb->audio_set_output_source(AUDIO_SRC_PLAYBACK);
289 #endif
290 rb->pcm_set_frequency(SAMPLE_RATE); // 44100 22050 11025
293 retval = beatboxmain();
295 #ifdef RB_PROFILE
296 rb->profstop();
297 #endif
299 rb->pcm_play_stop();
300 rb->pcm_set_frequency(HW_SAMPR_DEFAULT);
302 #if defined(HAVE_ADJUSTABLE_CPU_FREQ)
303 rb->cpu_boost(false);
304 #endif
307 if(retval == -1)
308 return PLUGIN_ERROR;
309 return PLUGIN_OK;
312 bool swap=0;
313 bool lastswap=1;
315 inline void synthbuf(void)
317 long *outptr;
318 register int i;
319 static int currentSample=0;
320 int synthtemp[2];
322 #ifndef SYNC
323 if(lastswap==swap) return;
324 lastswap=swap;
326 outptr=(swap ? gmbuf : gmbuf+BUF_SIZE);
327 #else
328 outptr=gmbuf;
329 #endif
331 for(i=0; i<BUF_SIZE/2; i++)
333 synthSample(&synthtemp[0], &synthtemp[1]);
334 currentSample++;
335 *outptr=((synthtemp[0]&0xFFFF) << 16) | (synthtemp[1]&0xFFFF);
336 outptr++;
337 if(currentSample==numberOfSamples)
339 if(playState == STATE_PLAYING)
341 stepFlag=1;
344 currentSample=0;
353 unsigned char trackPos[V_NUMCELLS];
354 unsigned char trackData[H_NUMCELLS][V_NUMCELLS];
355 unsigned char trackMap[V_NUMCELLS] = {38, 39, 40, 41, 42, 43, 44, 56};
358 struct Cell
360 unsigned char val;
361 int color;
364 struct Cell pattern[H_NUMCELLS][V_NUMCELLS];
365 struct Cell dispPattern[H_NUMCELLS][V_NUMCELLS];
368 void advancePosition()
370 int i=0;
371 for(i=0; i<V_NUMCELLS; i++)
373 trackPos[i]++;
374 if(trackPos[i] == H_NUMCELLS || trackData[trackPos[i]][i] == VAL_LOOP)
375 trackPos[i]=0;
380 void sendEvents()
382 int i;
383 for(i=0; i<V_NUMCELLS; i++)
385 if(trackData[trackPos[i]][i] == VAL_ENABLED)
386 pressNote(9, trackMap[i], 127);
390 #define NAME_POSX 10
391 #define NAME_POSY 100
392 void showDrumName(int trackNum)
394 rb->lcd_set_foreground(COLOR_NAME_TEXT);
395 rb->lcd_putsxy(NAME_POSX, NAME_POSY, drumNames[trackMap[trackNum]-35]);
398 void updateDisplay()
400 int i, j;
401 int grayOut=0;
403 for(j=0; j<V_NUMCELLS; j++)
405 grayOut=0;
406 for(i=0; i<H_NUMCELLS; i++)
408 pattern[i][j].color = COLOR_NORMAL;
409 pattern[i][j].val = trackData[i][j];
411 if(trackPos[j] == i)
412 pattern[i][j].color = COLOR_PLAY;
414 if(grayOut)
415 pattern[i][j].color = COLOR_DISABLED;
417 if(trackData[i][j] == VAL_LOOP)
419 pattern[i][j].color = COLOR_LOOPCELL;
420 grayOut=1;
423 if(xCursor == i && yCursor == j && editState == EDITSTATE_PATTERN)
424 pattern[i][j].color = COLOR_EDIT;
430 void resetPosition()
432 int i;
433 for(i=0; i<V_NUMCELLS; i++)
434 trackPos[i]=0;
437 void clearCells()
439 int i,j;
440 for(i=0; i<H_NUMCELLS; i++)
441 for(j=0; j<V_NUMCELLS; j++)
443 pattern[i][j].val=VAL_NONE;
444 dispPattern[i][j].val=VAL_NONE;
445 pattern[i][j].color = 0;
446 dispPattern[i][j].color = 0;
453 void drawGrid()
455 int i, j;
457 rb->lcd_set_foreground(COLOR_GRID);
459 for(i=0; i<H_NUMCELLS+1; i++)
460 rb->lcd_vline(i*CELL_XSIZE+GRID_XPOS, GRID_YPOS, GRID_YPOS+CELL_YSIZE*V_NUMCELLS);
462 for(i=0; i<V_NUMCELLS+1; i++)
463 rb->lcd_hline(GRID_XPOS, GRID_XPOS+CELL_XSIZE*H_NUMCELLS, GRID_YPOS+i*CELL_YSIZE);
466 rb->lcd_update();
469 void drawCell(int i, int j)
471 int cellX, cellY;
473 cellX = GRID_XPOS + CELL_XSIZE*i+1;
474 cellY = GRID_YPOS + CELL_YSIZE*j+1;
476 rb->lcd_set_foreground(pattern[i][j].color);
477 rb->lcd_fillrect(cellX, cellY, CELL_XSIZE-1, CELL_YSIZE-1);
479 rb->lcd_set_foreground(0);
481 if(pattern[i][j].val == VAL_LOOP)
483 rb->lcd_drawline(cellX, cellY, cellX+CELL_XSIZE-2, cellY+CELL_YSIZE-2);
486 if(pattern[i][j].val == VAL_ENABLED)
488 rb->lcd_fillrect(cellX+1, cellY+1, CELL_XSIZE-3, CELL_YSIZE-3);
493 void redrawScreen(unsigned char force)
495 int i, j;
497 for(i=0; i<H_NUMCELLS; i++)
499 for(j=0; j<V_NUMCELLS; j++)
501 if(force || (pattern[i][j].val != dispPattern[i][j].val || pattern[i][j].color != dispPattern[i][j].color))
503 drawCell(i, j);
504 dispPattern[i][j].val = pattern[i][j].val;
505 dispPattern[i][j].color = pattern[i][j].color;
509 rb->lcd_update();
512 void get_more(unsigned char** start, size_t* size)
514 #ifndef SYNC
515 if(lastswap!=swap)
517 // printf("Buffer miss!"); // Comment out the printf to make missses less noticable.
520 #else
521 synthbuf(); // For some reason midiplayer crashes when an update is forced
522 #endif
524 *size = BUF_SIZE*sizeof(short);
525 #ifndef SYNC
526 *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE));
527 swap=!swap;
528 #else
529 *start = (unsigned char*)(gmbuf);
530 #endif
533 int beatboxmain()
535 int vol=0;
538 numberOfSamples=44100/10;
539 synthbuf();
540 rb->pcm_play_data(&get_more, NULL, 0);
542 rb->lcd_set_background(0x000000);
543 rb->lcd_clear_display();
545 resetPosition();
547 int i, j;
549 /* Start at 16 cells/loop for now. User can un-loop if more are needed */
550 for(i=0; i<V_NUMCELLS; i++)
551 trackData[16][i] = VAL_LOOP;
554 /* Very very rough beat to 'Goodbye Horses'
555 trackData[16][3] = VAL_LOOP;
556 trackData[16][2] = VAL_LOOP;
558 trackData[0][3] = 1;
559 trackData[4][3] = 1;
560 trackData[8][3] = 1;
561 trackData[9][3] = 1;
562 trackData[12][3] = 1;
563 trackData[13][3] = 1;
565 trackData[2][2] = 1;
566 trackData[6][2] = 1;
567 trackData[10][2] = 1;
568 trackData[14][2] = 1;
571 drawGrid();
572 showDrumName(yCursor);
573 updateDisplay();
574 redrawScreen(1);
577 while(!quit)
579 #ifndef SYNC
580 synthbuf();
581 #endif
582 rb->yield();
584 if(stepFlag)
586 advancePosition();
587 sendEvents();
588 updateDisplay();
589 redrawScreen(0);
590 stepFlag=0;
593 /* Prevent idle poweroff */
594 rb->reset_poweroff_timer();
596 /* Code taken from Oscilloscope plugin */
597 switch(rb->button_get(false))
600 case BTN_UP:
601 case BTN_UP | BUTTON_REPEAT:
602 vol = rb->global_settings->volume;
603 if (vol < rb->sound_max(SOUND_VOLUME))
605 vol++;
606 rb->sound_set(SOUND_VOLUME, vol);
607 rb->global_settings->volume = vol;
609 break;
611 case BTN_DOWN:
612 case BTN_DOWN | BUTTON_REPEAT:
613 vol = rb->global_settings->volume;
614 if (vol > rb->sound_min(SOUND_VOLUME))
616 vol--;
617 rb->sound_set(SOUND_VOLUME, vol);
618 rb->global_settings->volume = vol;
620 break;
622 case BTN_RIGHT:
624 //pressNote(9, 40, 127);
625 // resetPosition();
626 advancePosition();
627 sendEvents();
628 updateDisplay();
629 redrawScreen(0);
630 break;
633 case BUTTON_LEFT:
636 // isPlaying=1;
637 resetPosition();
638 updateDisplay();
639 redrawScreen(0);
640 //pressNote(9, 39, 127);
641 break;
645 case BEATBOX_UP:
646 case BEATBOX_UP | BUTTON_REPEAT:
648 if(editState == EDITSTATE_PATTERN)
650 if(yCursor > 0)
652 yCursor--;
653 showDrumName(yCursor);
654 updateDisplay();
655 redrawScreen(0);
658 break;
661 case BEATBOX_DOWN:
662 case BEATBOX_DOWN | BUTTON_REPEAT:
664 if(editState == EDITSTATE_PATTERN)
666 if(yCursor < V_NUMCELLS-1)
668 yCursor++;
669 showDrumName(yCursor);
670 updateDisplay();
671 redrawScreen(0);
674 break;
677 case BEATBOX_LEFT:
678 case BEATBOX_LEFT | BUTTON_REPEAT:
680 if(editState == EDITSTATE_PATTERN)
682 if(xCursor > 0)
684 xCursor--;
685 updateDisplay();
686 redrawScreen(0);
689 break;
692 case BEATBOX_RIGHT:
693 case BEATBOX_RIGHT | BUTTON_REPEAT:
695 if(editState == EDITSTATE_PATTERN)
697 if(xCursor < H_NUMCELLS-1)
699 xCursor++;
700 updateDisplay();
701 redrawScreen(0);
704 break;
707 case BEATBOX_SELECT:
709 if(editState == EDITSTATE_PATTERN)
711 int cv = trackData[xCursor][yCursor];
712 cv++;
713 if(cv > VAL_LOOP)
714 cv = VAL_NONE;
716 trackData[xCursor][yCursor] = cv;
718 updateDisplay();
719 redrawScreen(0);
721 break;
725 case BEATBOX_PLAY:
727 if(playState == STATE_PLAYING)
728 playState = STATE_PAUSED;
729 else
731 updateDisplay();
732 redrawScreen(0);
733 sendEvents();
734 playState = STATE_PLAYING;
736 break;
739 case BEATBOX_STOP:
741 if(playState == STATE_STOPPED)
743 quit=1;
744 } else
746 playState =STATE_STOPPED;
747 resetPosition();
748 updateDisplay();
749 redrawScreen(0);
751 break;
758 return 0;