blob: 45f0eb70b5fbeef1b210ab52e3fbd5fd9bf09abf [file] [log] [blame]
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2005 Karl Kurbjun based on midi2wav by Stepan Moskovchenko
10 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000011 * 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.
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +000015 *
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
18 *
19 ****************************************************************************/
20
Nils Wallméniuscb9ba112007-10-04 10:30:01 +000021#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"
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +000027
28PLUGIN_HEADER
29PLUGIN_IRAM_DECLARE
30
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
37
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
43
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
49
50#define BTN_RC_QUIT BUTTON_RC_STOP
51
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
58
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
64
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
71
72
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
78
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
84
85#endif
86
87
88
89#define FRACTSIZE 10
90
91#ifndef SIMULATOR
92
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
98
99#define MAX_VOICES 20 // Note: 24 midi channels is the minimum general midi
100 // spec implementation
101
102#else // Simulator requires 44100, and we can afford to use more voices
103
104#define SAMPLE_RATE SAMPR_44
105#define MAX_VOICES 48
106
107#endif
108
109
110#define BUF_SIZE 256
111#define NBUF 2
112
113#undef SYNC
114
115#ifdef SIMULATOR
116 #define SYNC
117#endif
118
119struct MIDIfile * mf IBSS_ATTR;
120
121int numberOfSamples IBSS_ATTR;
122long bpm IBSS_ATTR;
123
Stepan Moskovchenko1ba018b2007-10-03 17:42:16 +0000124const 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 "
178};
179
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +0000180long gmbuf[BUF_SIZE*NBUF];
181
182int quit=0;
Steve Bavin65265772008-05-13 09:57:56 +0000183const struct plugin_api * rb;
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +0000184
185
186#define STATE_STOPPED 0
187#define STATE_PAUSED 1
188#define STATE_PLAYING 2
189
190
191#define BEATBOX_UP BUTTON_UP
192#define BEATBOX_DOWN BUTTON_DOWN
193#define BEATBOX_LEFT BUTTON_LEFT
194#define BEATBOX_RIGHT BUTTON_RIGHT
195#define BEATBOX_SELECT BUTTON_SELECT
196
197
198#define BEATBOX_PLAY BUTTON_ON
199#define BEATBOX_STOP BUTTON_OFF
200
201
202#define VAL_NONE 0
203#define VAL_ENABLED 1
204#define VAL_LOOP 2
205
206#define H_NUMCELLS 24
207#define V_NUMCELLS 8
208
209#define HILIGHT_NONE 0
210#define HILIGHT_PLAY 1
211#define HILIGHT_USER 2
212
213#define CELL_XSIZE 9
214#define CELL_YSIZE 9
215
216#define GRID_XPOS 2
217#define GRID_YPOS 10
218
219
Stepan Moskovchenko1ba018b2007-10-03 17:42:16 +0000220#define COLOR_NAME_TEXT LCD_RGBPACK(0xFF,0xFF,0xFF)
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +0000221#define COLOR_NORMAL LCD_RGBPACK(0xFF,0xFF,0xFF)
222#define COLOR_PLAY LCD_RGBPACK(0xFF,0xFF,0x00)
223#define COLOR_DISABLED LCD_RGBPACK(0xA0,0xA0,0xA0)
224#define COLOR_LOOPCELL LCD_RGBPACK(0xC0,0xC0,0xC0)
225#define COLOR_EDIT LCD_RGBPACK(0x30,0x30,0xFF)
226#define COLOR_GRID LCD_RGBPACK(0xD0,0xD0,0xD0)
227
228#define EDITSTATE_PATTERN 0
229
230int xCursor=0, yCursor=0;
231
232int editState=EDITSTATE_PATTERN;
233
234int playState=STATE_STOPPED, stepFlag=0;
235
236
Steve Bavin65265772008-05-13 09:57:56 +0000237enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +0000238{
239 int retval = 0;
240
241 PLUGIN_IRAM_INIT(api)
242
243 rb = api;
244
245 rb->lcd_setfont(0);
246
247#if defined(HAVE_ADJUSTABLE_CPU_FREQ)
248 rb->cpu_boost(true);
249#endif
250
251#ifdef RB_PROFILE
252 rb->profile_thread();
253#endif
254 if (initSynth(NULL, ROCKBOX_DIR "/patchset/patchset.cfg",
255 ROCKBOX_DIR "/patchset/drums.cfg") == -1)
256 {
257 printf("\nINIT ERROR\n");
258 return -1;
259 }
260//#ifndef SIMULATOR
261 rb->pcm_play_stop();
262#if INPUT_SRC_CAPS != 0
263 /* Select playback */
264 rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
265 rb->audio_set_output_source(AUDIO_SRC_PLAYBACK);
266#endif
267 rb->pcm_set_frequency(SAMPLE_RATE); // 44100 22050 11025
268
269
270 retval = beatboxmain();
271
272#ifdef RB_PROFILE
273 rb->profstop();
274#endif
275
276 rb->pcm_play_stop();
277 rb->pcm_set_frequency(HW_SAMPR_DEFAULT);
278
279#if defined(HAVE_ADJUSTABLE_CPU_FREQ)
280 rb->cpu_boost(false);
281#endif
282
283
284 if(retval == -1)
285 return PLUGIN_ERROR;
286 return PLUGIN_OK;
287}
288
289bool swap=0;
290bool lastswap=1;
291
292inline void synthbuf(void)
293{
294 long *outptr;
295 register int i;
296 static int currentSample=0;
297 int synthtemp[2];
298
299#ifndef SYNC
300 if(lastswap==swap) return;
301 lastswap=swap;
302
303 outptr=(swap ? gmbuf : gmbuf+BUF_SIZE);
304#else
305 outptr=gmbuf;
306#endif
307
308 for(i=0; i<BUF_SIZE/2; i++)
309 {
310 synthSample(&synthtemp[0], &synthtemp[1]);
311 currentSample++;
312 *outptr=((synthtemp[0]&0xFFFF) << 16) | (synthtemp[1]&0xFFFF);
313 outptr++;
314 if(currentSample==numberOfSamples)
315 {
316 if(playState == STATE_PLAYING)
317 {
318 stepFlag=1;
319 }
320
321 currentSample=0;
322 }
323 }
324}
325
326
327
328
329
330unsigned char trackPos[V_NUMCELLS];
331unsigned char trackData[H_NUMCELLS][V_NUMCELLS];
Stepan Moskovchenko1ba018b2007-10-03 17:42:16 +0000332unsigned char trackMap[V_NUMCELLS] = {38, 39, 40, 41, 42, 43, 44, 56};
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +0000333
334
335struct Cell
336{
337 unsigned char val;
338 int color;
339};
340
341struct Cell pattern[H_NUMCELLS][V_NUMCELLS];
342struct Cell dispPattern[H_NUMCELLS][V_NUMCELLS];
343
344
345void advancePosition()
346{
347 int i=0;
348 for(i=0; i<V_NUMCELLS; i++)
349 {
350 trackPos[i]++;
351 if(trackPos[i] == H_NUMCELLS || trackData[trackPos[i]][i] == VAL_LOOP)
352 trackPos[i]=0;
353 }
354}
355
356
357void sendEvents()
358{
359 int i;
360 for(i=0; i<V_NUMCELLS; i++)
361 {
362 if(trackData[trackPos[i]][i] == VAL_ENABLED)
Nils Wallméniuscb9ba112007-10-04 10:30:01 +0000363 pressNote(9, trackMap[i], 127);
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +0000364 }
365}
366
Stepan Moskovchenko1ba018b2007-10-03 17:42:16 +0000367#define NAME_POSX 10
368#define NAME_POSY 100
369void showDrumName(int trackNum)
370{
371 rb->lcd_set_foreground(COLOR_NAME_TEXT);
372 rb->lcd_putsxy(NAME_POSX, NAME_POSY, drumNames[trackMap[trackNum]-35]);
373}
374
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +0000375void updateDisplay()
376{
377 int i, j;
378 int grayOut=0;
379
380 for(j=0; j<V_NUMCELLS; j++)
381 {
382 grayOut=0;
383 for(i=0; i<H_NUMCELLS; i++)
384 {
385 pattern[i][j].color = COLOR_NORMAL;
386 pattern[i][j].val = trackData[i][j];
387
388 if(trackPos[j] == i)
389 pattern[i][j].color = COLOR_PLAY;
390
391 if(grayOut)
392 pattern[i][j].color = COLOR_DISABLED;
393
394 if(trackData[i][j] == VAL_LOOP)
395 {
396 pattern[i][j].color = COLOR_LOOPCELL;
397 grayOut=1;
398 }
399
400 if(xCursor == i && yCursor == j && editState == EDITSTATE_PATTERN)
401 pattern[i][j].color = COLOR_EDIT;
402 }
403 }
404
405}
406
407void resetPosition()
408{
409 int i;
410 for(i=0; i<V_NUMCELLS; i++)
411 trackPos[i]=0;
412}
413
414void clearCells()
415{
416 int i,j;
417 for(i=0; i<H_NUMCELLS; i++)
418 for(j=0; j<V_NUMCELLS; j++)
419 {
420 pattern[i][j].val=VAL_NONE;
421 dispPattern[i][j].val=VAL_NONE;
422 pattern[i][j].color = 0;
423 dispPattern[i][j].color = 0;
424 }
425}
426
427
428
429
430void drawGrid()
431{
432 int i, j;
433
434 rb->lcd_set_foreground(COLOR_GRID);
435
436 for(i=0; i<H_NUMCELLS+1; i++)
437 rb->lcd_vline(i*CELL_XSIZE+GRID_XPOS, GRID_YPOS, GRID_YPOS+CELL_YSIZE*V_NUMCELLS);
438
439 for(i=0; i<V_NUMCELLS+1; i++)
440 rb->lcd_hline(GRID_XPOS, GRID_XPOS+CELL_XSIZE*H_NUMCELLS, GRID_YPOS+i*CELL_YSIZE);
441
442
443 rb->lcd_update();
444}
445
446void drawCell(int i, int j)
447{
448 int cellX, cellY;
449
450 cellX = GRID_XPOS + CELL_XSIZE*i+1;
451 cellY = GRID_YPOS + CELL_YSIZE*j+1;
452
453 rb->lcd_set_foreground(pattern[i][j].color);
454 rb->lcd_fillrect(cellX, cellY, CELL_XSIZE-1, CELL_YSIZE-1);
455
456 rb->lcd_set_foreground(0);
457
458 if(pattern[i][j].val == VAL_LOOP)
459 {
460 rb->lcd_drawline(cellX, cellY, cellX+CELL_XSIZE-2, cellY+CELL_YSIZE-2);
461 }
462
463 if(pattern[i][j].val == VAL_ENABLED)
464 {
465 rb->lcd_fillrect(cellX+1, cellY+1, CELL_XSIZE-3, CELL_YSIZE-3);
466 }
467
468}
469
470void redrawScreen(unsigned char force)
471{
472 int i, j;
473
474 for(i=0; i<H_NUMCELLS; i++)
475 {
476 for(j=0; j<V_NUMCELLS; j++)
477 {
478 if(force || (pattern[i][j].val != dispPattern[i][j].val || pattern[i][j].color != dispPattern[i][j].color))
479 {
480 drawCell(i, j);
481 dispPattern[i][j].val = pattern[i][j].val;
482 dispPattern[i][j].color = pattern[i][j].color;
483 }
484 }
485 }
486 rb->lcd_update();
487}
488
489void get_more(unsigned char** start, size_t* size)
490{
491#ifndef SYNC
492 if(lastswap!=swap)
493 {
494// printf("Buffer miss!"); // Comment out the printf to make missses less noticable.
495 }
496
497#else
498 synthbuf(); // For some reason midiplayer crashes when an update is forced
499#endif
500
501 *size = BUF_SIZE*sizeof(short);
502#ifndef SYNC
503 *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE));
504 swap=!swap;
505#else
506 *start = (unsigned char*)(gmbuf);
507#endif
508}
509
510int beatboxmain()
511{
512 int vol=0;
513
514
515 numberOfSamples=44100/10;
516 synthbuf();
517 rb->pcm_play_data(&get_more, NULL, 0);
518
519 rb->lcd_set_background(0x000000);
520 rb->lcd_clear_display();
521
522 resetPosition();
523
524 int i, j;
525
Stepan Moskovchenko1ba018b2007-10-03 17:42:16 +0000526 /* Start at 16 cells/loop for now. User can un-loop if more are needed */
527 for(i=0; i<V_NUMCELLS; i++)
528 trackData[16][i] = VAL_LOOP;
529
530
531/* Very very rough beat to 'Goodbye Horses'
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +0000532 trackData[16][3] = VAL_LOOP;
533 trackData[16][2] = VAL_LOOP;
534
535 trackData[0][3] = 1;
536 trackData[4][3] = 1;
537 trackData[8][3] = 1;
538 trackData[9][3] = 1;
539 trackData[12][3] = 1;
540 trackData[13][3] = 1;
541
542 trackData[2][2] = 1;
543 trackData[6][2] = 1;
544 trackData[10][2] = 1;
545 trackData[14][2] = 1;
Stepan Moskovchenko1ba018b2007-10-03 17:42:16 +0000546*/
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +0000547
548 drawGrid();
Stepan Moskovchenko1ba018b2007-10-03 17:42:16 +0000549 showDrumName(yCursor);
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +0000550 updateDisplay();
551 redrawScreen(1);
552
553
554 while(!quit)
555 {
556 #ifndef SYNC
557 synthbuf();
558 #endif
559 rb->yield();
560
561 if(stepFlag)
562 {
563 advancePosition();
564 sendEvents();
565 updateDisplay();
566 redrawScreen(0);
567 stepFlag=0;
568 }
569
570 /* Prevent idle poweroff */
571 rb->reset_poweroff_timer();
572
573 /* Code taken from Oscilloscope plugin */
574 switch(rb->button_get(false))
575 {
576 /*
577 case BTN_UP:
578 case BTN_UP | BUTTON_REPEAT:
579 vol = rb->global_settings->volume;
580 if (vol < rb->sound_max(SOUND_VOLUME))
581 {
582 vol++;
583 rb->sound_set(SOUND_VOLUME, vol);
584 rb->global_settings->volume = vol;
585 }
586 break;
587
588 case BTN_DOWN:
589 case BTN_DOWN | BUTTON_REPEAT:
590 vol = rb->global_settings->volume;
591 if (vol > rb->sound_min(SOUND_VOLUME))
592 {
593 vol--;
594 rb->sound_set(SOUND_VOLUME, vol);
595 rb->global_settings->volume = vol;
596 }
597 break;
598
599 case BTN_RIGHT:
600 {
601 //pressNote(9, 40, 127);
602 // resetPosition();
603 advancePosition();
604 sendEvents();
605 updateDisplay();
606 redrawScreen(0);
607 break;
608 }
609
610 case BUTTON_LEFT:
611 {
612
613// isPlaying=1;
614 resetPosition();
615 updateDisplay();
616 redrawScreen(0);
617 //pressNote(9, 39, 127);
618 break;
619 }
620*/
621
622 case BEATBOX_UP:
623 case BEATBOX_UP | BUTTON_REPEAT:
624 {
625 if(editState == EDITSTATE_PATTERN)
626 {
627 if(yCursor > 0)
628 {
629 yCursor--;
Stepan Moskovchenko1ba018b2007-10-03 17:42:16 +0000630 showDrumName(yCursor);
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +0000631 updateDisplay();
632 redrawScreen(0);
633 }
634 }
635 break;
636 }
637
638 case BEATBOX_DOWN:
639 case BEATBOX_DOWN | BUTTON_REPEAT:
640 {
641 if(editState == EDITSTATE_PATTERN)
642 {
643 if(yCursor < V_NUMCELLS-1)
644 {
645 yCursor++;
Stepan Moskovchenko1ba018b2007-10-03 17:42:16 +0000646 showDrumName(yCursor);
Stepan Moskovchenko8b6d2872007-09-27 03:59:33 +0000647 updateDisplay();
648 redrawScreen(0);
649 }
650 }
651 break;
652 }
653
654 case BEATBOX_LEFT:
655 case BEATBOX_LEFT | BUTTON_REPEAT:
656 {
657 if(editState == EDITSTATE_PATTERN)
658 {
659 if(xCursor > 0)
660 {
661 xCursor--;
662 updateDisplay();
663 redrawScreen(0);
664 }
665 }
666 break;
667 }
668
669 case BEATBOX_RIGHT:
670 case BEATBOX_RIGHT | BUTTON_REPEAT:
671 {
672 if(editState == EDITSTATE_PATTERN)
673 {
674 if(xCursor < H_NUMCELLS-1)
675 {
676 xCursor++;
677 updateDisplay();
678 redrawScreen(0);
679 }
680 }
681 break;
682 }
683
684 case BEATBOX_SELECT:
685 {
686 if(editState == EDITSTATE_PATTERN)
687 {
688 int cv = trackData[xCursor][yCursor];
689 cv++;
690 if(cv > VAL_LOOP)
691 cv = VAL_NONE;
692
693 trackData[xCursor][yCursor] = cv;
694
695 updateDisplay();
696 redrawScreen(0);
697 }
698 break;
699 }
700
701
702 case BEATBOX_PLAY:
703 {
704 if(playState == STATE_PLAYING)
705 playState = STATE_PAUSED;
706 else
707 {
708 updateDisplay();
709 redrawScreen(0);
710 sendEvents();
711 playState = STATE_PLAYING;
712 }
713 break;
714 }
715
716 case BEATBOX_STOP:
717 {
718 if(playState == STATE_STOPPED)
719 {
720 quit=1;
721 } else
722 {
723 playState =STATE_STOPPED;
724 resetPosition();
725 updateDisplay();
726 redrawScreen(0);
727 }
728 break;
729 }
730 }
731
732
733 }
734
735 return 0;
736}
Stepan Moskovchenko1ba018b2007-10-03 17:42:16 +0000737