A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 760 lines 19 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2005 Karl Kurbjun based on midi2wav by Stepan Moskovchenko 11 * 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. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21 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" 28 29 30/* variable button definitions */ 31#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_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 36 37#define BTN_RC_QUIT BUTTON_RC_STOP 38 39#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \ 40 (CONFIG_KEYPAD == IPOD_1G2G_PAD) 41#define BTN_QUIT (BUTTON_SELECT | BUTTON_MENU) 42#define BTN_RIGHT BUTTON_RIGHT 43#define BTN_UP BUTTON_SCROLL_FWD 44#define BTN_DOWN BUTTON_SCROLL_BACK 45 46#elif (CONFIG_KEYPAD == GIGABEAT_PAD) 47#define BTN_QUIT BUTTON_POWER 48#define BTN_RIGHT BUTTON_RIGHT 49#define BTN_UP BUTTON_UP 50#define BTN_DOWN BUTTON_DOWN 51 52#elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \ 53(CONFIG_KEYPAD == SANSA_C200_PAD) 54#define BTN_QUIT BUTTON_POWER 55#define BTN_RIGHT BUTTON_RIGHT 56#define BTN_UP BUTTON_UP 57#define BTN_DOWN BUTTON_DOWN 58 59 60#elif CONFIG_KEYPAD == IAUDIO_X5M5_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 65 66#elif CONFIG_KEYPAD == IRIVER_H10_PAD 67#define BTN_QUIT BUTTON_POWER 68#define BTN_RIGHT BUTTON_RIGHT 69#define BTN_UP BUTTON_SCROLL_UP 70#define BTN_DOWN BUTTON_SCROLL_DOWN 71 72#elif CONFIG_KEYPAD == PHILIPS_HDD1630_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 77 78#elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD 79#define BTN_QUIT BUTTON_POWER 80#define BTN_RIGHT BUTTON_NEXT 81#define BTN_UP BUTTON_UP 82#define BTN_DOWN BUTTON_DOWN 83 84#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD 85#define BTN_QUIT BUTTON_POWER 86#define BTN_RIGHT BUTTON_NEXT 87#define BTN_UP BUTTON_UP 88#define BTN_DOWN BUTTON_DOWN 89 90#elif (CONFIG_KEYPAD == SAMSUNG_YH820_PAD) || \ 91 (CONFIG_KEYPAD == SAMSUNG_YH92X_PAD) 92#define BTN_QUIT BUTTON_PLAY 93#define BTN_RIGHT BUTTON_RIGHT 94#define BTN_UP BUTTON_UP 95#define BTN_DOWN BUTTON_DOWN 96 97#elif CONFIG_KEYPAD == PBELL_VIBE500_PAD 98#define BTN_QUIT BUTTON_REC 99#define BTN_RIGHT BUTTON_NEXT 100#define BTN_UP BUTTON_UP 101#define BTN_DOWN BUTTON_DOWN 102 103#elif CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD 104#define BTN_QUIT BUTTON_PLAY 105#define BTN_RIGHT BUTTON_MENU 106#define BTN_UP BUTTON_UP 107#define BTN_DOWN BUTTON_DOWN 108 109#elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD 110#define BTN_QUIT BUTTON_POWER 111#define BTN_RIGHT BUTTON_RIGHT 112#define BTN_UP BUTTON_UP 113#define BTN_DOWN BUTTON_DOWN 114 115#endif 116 117#define FRACTSIZE 10 118 119#ifndef SIMULATOR 120 121#if (HW_SAMPR_CAPS & SAMPR_CAP_22) 122#define SAMPLE_RATE SAMPR_22 // 44100 22050 11025 123#else 124#define SAMPLE_RATE SAMPR_44 // 44100 22050 11025 125#endif 126 127#define MAX_VOICES 20 // Note: 24 midi channels is the minimum general midi 128 // spec implementation 129 130#else // Simulator requires 44100, and we can afford to use more voices 131 132#define SAMPLE_RATE SAMPR_44 133#define MAX_VOICES 48 134 135#endif 136 137 138#define BUF_SIZE 256 139#define NBUF 2 140 141#undef SYNC 142 143#if (CONFIG_PLATFORM & PLATFORM_NATIVE) 144 #define SYNC 145#endif 146 147struct MIDIfile * mf IBSS_ATTR; 148 149int numberOfSamples IBSS_ATTR; 150long bpm IBSS_ATTR; 151 152const unsigned char * drumNames[]={ 153 "Bass Drum 2 ", 154 "Bass Drum 1 ", 155 "Side Stick ", 156 "Snare Drum 1 ", 157 "Hand Clap ", 158 "Snare Drum 2 ", 159 "Low Tom 2 ", 160 "Closed Hi-hat ", 161 "Low Tom 1 ", 162 "Pedal Hi-hat ", 163 "Mid Tom 2 ", 164 "Open Hi-hat ", 165 "Mid Tom 1 ", 166 "High Tom 2 ", 167 "Crash Cymbal 1 ", 168 "High Tom 1 ", 169 "Ride Cymbal 1 ", 170 "Chinese Cymbal ", 171 "Ride Bell ", 172 "Tambourine ", 173 "Splash Cymbal ", 174 "Cowbell ", 175 "Crash Cymbal 2 ", 176 "Vibra Slap ", 177 "Ride Cymbal 2 ", 178 "High Bongo ", 179 "Low Bongo ", 180 "Mute High Conga", 181 "Open High Conga", 182 "Low Conga ", 183 "High Timbale ", 184 "Low Timbale ", 185 "High Agogo ", 186 "Low Agogo ", 187 "Cabasa ", 188 "Maracas ", 189 "Short Whistle ", 190 "Long Whistle ", 191 "Short Guiro ", 192 "Long Guiro ", 193 "Claves ", 194 "High Wood Block", 195 "Low Wood Block ", 196 "Mute Cuica ", 197 "Open Cuica ", 198 "Mute Triangle ", 199 "Open Triangle ", 200 "Shaker ", 201 "Jingle Bell ", 202 "Bell Tree ", 203 "Castenets ", 204 "Mute Surdo ", 205 "Open Surdo " 206}; 207 208long gmbuf[BUF_SIZE*NBUF]; 209 210int quit=0; 211 212#define STATE_STOPPED 0 213#define STATE_PAUSED 1 214#define STATE_PLAYING 2 215 216 217#define BEATBOX_UP BUTTON_UP 218#define BEATBOX_DOWN BUTTON_DOWN 219#define BEATBOX_LEFT BUTTON_LEFT 220#define BEATBOX_RIGHT BUTTON_RIGHT 221#define BEATBOX_SELECT BUTTON_SELECT 222 223#if (CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD) 224#define BEATBOX_PLAY BUTTON_PLAYPAUSE 225#define BEATBOX_STOP BUTTON_BACK 226#else 227#define BEATBOX_PLAY BUTTON_ON 228#define BEATBOX_STOP BUTTON_OFF 229#endif 230 231#define VAL_NONE 0 232#define VAL_ENABLED 1 233#define VAL_LOOP 2 234 235#define H_NUMCELLS 24 236#define V_NUMCELLS 8 237 238#define HILIGHT_NONE 0 239#define HILIGHT_PLAY 1 240#define HILIGHT_USER 2 241 242#define CELL_XSIZE 9 243#define CELL_YSIZE 9 244 245#define GRID_XPOS 2 246#define GRID_YPOS 10 247 248 249#define COLOR_NAME_TEXT LCD_RGBPACK(0xFF,0xFF,0xFF) 250#define COLOR_NORMAL LCD_RGBPACK(0xFF,0xFF,0xFF) 251#define COLOR_PLAY LCD_RGBPACK(0xFF,0xFF,0x00) 252#define COLOR_DISABLED LCD_RGBPACK(0xA0,0xA0,0xA0) 253#define COLOR_LOOPCELL LCD_RGBPACK(0xC0,0xC0,0xC0) 254#define COLOR_EDIT LCD_RGBPACK(0x30,0x30,0xFF) 255#define COLOR_GRID LCD_RGBPACK(0xD0,0xD0,0xD0) 256 257#define EDITSTATE_PATTERN 0 258 259int xCursor=0, yCursor=0; 260 261int editState=EDITSTATE_PATTERN; 262 263int playState=STATE_STOPPED, stepFlag=0; 264 265 266enum plugin_status plugin_start(const void* parameter) 267{ 268 int retval = 0; 269 270 rb->lcd_setfont(FONT_SYSFIXED); 271 272#if defined(HAVE_ADJUSTABLE_CPU_FREQ) 273 rb->cpu_boost(true); 274#endif 275 276#ifdef RB_PROFILE 277 rb->profile_thread(); 278#endif 279 if (initSynth(NULL, ROCKBOX_DIR "/patchset/patchset.cfg", 280 ROCKBOX_DIR "/patchset/drums.cfg") == -1) 281 { 282 printf("\nINIT ERROR\n"); 283 return -1; 284 } 285//#ifndef SIMULATOR 286 rb->pcm_play_stop(); 287#if INPUT_SRC_CAPS != 0 288 /* Select playback */ 289 rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); 290 rb->audio_set_output_source(AUDIO_SRC_PLAYBACK); 291#endif 292 rb->pcm_set_frequency(SAMPLE_RATE); // 44100 22050 11025 293 294 295 retval = beatboxmain(); 296 297#ifdef RB_PROFILE 298 rb->profstop(); 299#endif 300 301 rb->pcm_play_stop(); 302 rb->pcm_set_frequency(HW_SAMPR_DEFAULT); 303 304#if defined(HAVE_ADJUSTABLE_CPU_FREQ) 305 rb->cpu_boost(false); 306#endif 307 308 309 if(retval == -1) 310 return PLUGIN_ERROR; 311 return PLUGIN_OK; 312} 313 314bool swap=0; 315bool lastswap=1; 316 317inline void synthbuf(void) 318{ 319 long *outptr; 320 register int i; 321 static int currentSample=0; 322 int synthtemp[2]; 323 324#ifndef SYNC 325 if(lastswap==swap) return; 326 lastswap=swap; 327 328 outptr=(swap ? gmbuf : gmbuf+BUF_SIZE); 329#else 330 outptr=gmbuf; 331#endif 332 333 for(i=0; i<BUF_SIZE/2; i++) 334 { 335 synthSample(&synthtemp[0], &synthtemp[1]); 336 currentSample++; 337 *outptr=((synthtemp[0]&0xFFFF) << 16) | (synthtemp[1]&0xFFFF); 338 outptr++; 339 if(currentSample==numberOfSamples) 340 { 341 if(playState == STATE_PLAYING) 342 { 343 stepFlag=1; 344 } 345 346 currentSample=0; 347 } 348 } 349} 350 351 352 353 354 355unsigned char trackPos[V_NUMCELLS]; 356unsigned char trackData[H_NUMCELLS][V_NUMCELLS]; 357unsigned char trackMap[V_NUMCELLS] = {38, 39, 40, 41, 42, 43, 44, 56}; 358 359 360struct Cell 361{ 362 unsigned char val; 363 int color; 364}; 365 366struct Cell pattern[H_NUMCELLS][V_NUMCELLS]; 367struct Cell dispPattern[H_NUMCELLS][V_NUMCELLS]; 368 369 370void advancePosition() 371{ 372 int i=0; 373 for(i=0; i<V_NUMCELLS; i++) 374 { 375 trackPos[i]++; 376 if(trackPos[i] == H_NUMCELLS || trackData[trackPos[i]][i] == VAL_LOOP) 377 trackPos[i]=0; 378 } 379} 380 381 382void sendEvents() 383{ 384 int i; 385 for(i=0; i<V_NUMCELLS; i++) 386 { 387 if(trackData[trackPos[i]][i] == VAL_ENABLED) 388 pressNote(9, trackMap[i], 127); 389 } 390} 391 392#define NAME_POSX 10 393#define NAME_POSY 100 394void showDrumName(int trackNum) 395{ 396 rb->lcd_set_foreground(COLOR_NAME_TEXT); 397 rb->lcd_putsxy(NAME_POSX, NAME_POSY, drumNames[trackMap[trackNum]-35]); 398} 399 400void updateDisplay() 401{ 402 int i, j; 403 int grayOut=0; 404 405 for(j=0; j<V_NUMCELLS; j++) 406 { 407 grayOut=0; 408 for(i=0; i<H_NUMCELLS; i++) 409 { 410 pattern[i][j].color = COLOR_NORMAL; 411 pattern[i][j].val = trackData[i][j]; 412 413 if(trackPos[j] == i) 414 pattern[i][j].color = COLOR_PLAY; 415 416 if(grayOut) 417 pattern[i][j].color = COLOR_DISABLED; 418 419 if(trackData[i][j] == VAL_LOOP) 420 { 421 pattern[i][j].color = COLOR_LOOPCELL; 422 grayOut=1; 423 } 424 425 if(xCursor == i && yCursor == j && editState == EDITSTATE_PATTERN) 426 pattern[i][j].color = COLOR_EDIT; 427 } 428 } 429 430} 431 432void resetPosition() 433{ 434 int i; 435 for(i=0; i<V_NUMCELLS; i++) 436 trackPos[i]=0; 437} 438 439void clearCells() 440{ 441 int i,j; 442 for(i=0; i<H_NUMCELLS; i++) 443 for(j=0; j<V_NUMCELLS; j++) 444 { 445 pattern[i][j].val=VAL_NONE; 446 dispPattern[i][j].val=VAL_NONE; 447 pattern[i][j].color = 0; 448 dispPattern[i][j].color = 0; 449 } 450} 451 452 453 454 455void drawGrid() 456{ 457 int i, j; 458 459 rb->lcd_set_foreground(COLOR_GRID); 460 461 for(i=0; i<H_NUMCELLS+1; i++) 462 rb->lcd_vline(i*CELL_XSIZE+GRID_XPOS, GRID_YPOS, GRID_YPOS+CELL_YSIZE*V_NUMCELLS); 463 464 for(i=0; i<V_NUMCELLS+1; i++) 465 rb->lcd_hline(GRID_XPOS, GRID_XPOS+CELL_XSIZE*H_NUMCELLS, GRID_YPOS+i*CELL_YSIZE); 466 467 468 rb->lcd_update(); 469} 470 471void drawCell(int i, int j) 472{ 473 int cellX, cellY; 474 475 cellX = GRID_XPOS + CELL_XSIZE*i+1; 476 cellY = GRID_YPOS + CELL_YSIZE*j+1; 477 478 rb->lcd_set_foreground(pattern[i][j].color); 479 rb->lcd_fillrect(cellX, cellY, CELL_XSIZE-1, CELL_YSIZE-1); 480 481 rb->lcd_set_foreground(0); 482 483 if(pattern[i][j].val == VAL_LOOP) 484 { 485 rb->lcd_drawline(cellX, cellY, cellX+CELL_XSIZE-2, cellY+CELL_YSIZE-2); 486 } 487 488 if(pattern[i][j].val == VAL_ENABLED) 489 { 490 rb->lcd_fillrect(cellX+1, cellY+1, CELL_XSIZE-3, CELL_YSIZE-3); 491 } 492 493} 494 495void redrawScreen(unsigned char force) 496{ 497 int i, j; 498 499 for(i=0; i<H_NUMCELLS; i++) 500 { 501 for(j=0; j<V_NUMCELLS; j++) 502 { 503 if(force || (pattern[i][j].val != dispPattern[i][j].val || pattern[i][j].color != dispPattern[i][j].color)) 504 { 505 drawCell(i, j); 506 dispPattern[i][j].val = pattern[i][j].val; 507 dispPattern[i][j].color = pattern[i][j].color; 508 } 509 } 510 } 511 rb->lcd_update(); 512} 513 514void get_more(const void** start, size_t* size) 515{ 516#ifndef SYNC 517 if(lastswap!=swap) 518 { 519// printf("Buffer miss!"); // Comment out the printf to make missses less noticable. 520 } 521 522#else 523 synthbuf(); // For some reason midiplayer crashes when an update is forced 524#endif 525 526 *size = BUF_SIZE*sizeof(short); 527#ifndef SYNC 528 *start = swap ? gmbuf : gmbuf + BUF_SIZE; 529 swap=!swap; 530#else 531 *start = gmbuf; 532#endif 533} 534 535int beatboxmain() 536{ 537 int vol=0; 538 539 540 numberOfSamples=44100/10; 541 synthbuf(); 542 rb->pcm_play_data(&get_more, NULL, NULL, 0); 543 544 rb->lcd_set_background(0x000000); 545 rb->lcd_clear_display(); 546 547 resetPosition(); 548 549 int i, j; 550 551 /* Start at 16 cells/loop for now. User can un-loop if more are needed */ 552 for(i=0; i<V_NUMCELLS; i++) 553 trackData[16][i] = VAL_LOOP; 554 555 556/* Very very rough beat to 'Goodbye Horses' 557 trackData[16][3] = VAL_LOOP; 558 trackData[16][2] = VAL_LOOP; 559 560 trackData[0][3] = 1; 561 trackData[4][3] = 1; 562 trackData[8][3] = 1; 563 trackData[9][3] = 1; 564 trackData[12][3] = 1; 565 trackData[13][3] = 1; 566 567 trackData[2][2] = 1; 568 trackData[6][2] = 1; 569 trackData[10][2] = 1; 570 trackData[14][2] = 1; 571*/ 572 573 drawGrid(); 574 showDrumName(yCursor); 575 updateDisplay(); 576 redrawScreen(1); 577 578 579 while(!quit) 580 { 581 #ifndef SYNC 582 synthbuf(); 583 #endif 584 rb->yield(); 585 586 if(stepFlag) 587 { 588 advancePosition(); 589 sendEvents(); 590 updateDisplay(); 591 redrawScreen(0); 592 stepFlag=0; 593 } 594 595 /* Prevent idle poweroff */ 596 rb->reset_poweroff_timer(); 597 598 /* Code taken from Oscilloscope plugin */ 599 switch(rb->button_get(false)) 600 { 601 /* 602 case BTN_UP: 603 case BTN_UP | BUTTON_REPEAT: 604 vol = rb->global_status->volume; 605 if (vol < rb->sound_max(SOUND_VOLUME)) 606 { 607 vol++; 608 rb->sound_set(SOUND_VOLUME, vol); 609 } 610 break; 611 612 case BTN_DOWN: 613 case BTN_DOWN | BUTTON_REPEAT: 614 vol = rb->global_status->volume; 615 if (vol > rb->sound_min(SOUND_VOLUME)) 616 { 617 vol--; 618 rb->sound_set(SOUND_VOLUME, vol); 619 } 620 break; 621 622 case BTN_RIGHT: 623 { 624 //pressNote(9, 40, 127); 625 // resetPosition(); 626 advancePosition(); 627 sendEvents(); 628 updateDisplay(); 629 redrawScreen(0); 630 break; 631 } 632 633 case BUTTON_LEFT: 634 { 635 636// isPlaying=1; 637 resetPosition(); 638 updateDisplay(); 639 redrawScreen(0); 640 //pressNote(9, 39, 127); 641 break; 642 } 643*/ 644 645 case BEATBOX_UP: 646 case BEATBOX_UP | BUTTON_REPEAT: 647 { 648 if(editState == EDITSTATE_PATTERN) 649 { 650 if(yCursor > 0) 651 { 652 yCursor--; 653 showDrumName(yCursor); 654 updateDisplay(); 655 redrawScreen(0); 656 } 657 } 658 break; 659 } 660 661 case BEATBOX_DOWN: 662 case BEATBOX_DOWN | BUTTON_REPEAT: 663 { 664 if(editState == EDITSTATE_PATTERN) 665 { 666 if(yCursor < V_NUMCELLS-1) 667 { 668 yCursor++; 669 showDrumName(yCursor); 670 updateDisplay(); 671 redrawScreen(0); 672 } 673 } 674 break; 675 } 676 677 case BEATBOX_LEFT: 678 case BEATBOX_LEFT | BUTTON_REPEAT: 679 { 680 if(editState == EDITSTATE_PATTERN) 681 { 682 if(xCursor > 0) 683 { 684 xCursor--; 685 updateDisplay(); 686 redrawScreen(0); 687 } 688 } 689 break; 690 } 691 692 case BEATBOX_RIGHT: 693 case BEATBOX_RIGHT | BUTTON_REPEAT: 694 { 695 if(editState == EDITSTATE_PATTERN) 696 { 697 if(xCursor < H_NUMCELLS-1) 698 { 699 xCursor++; 700 updateDisplay(); 701 redrawScreen(0); 702 } 703 } 704 break; 705 } 706 707 case BEATBOX_SELECT: 708 { 709 if(editState == EDITSTATE_PATTERN) 710 { 711 int cv = trackData[xCursor][yCursor]; 712 cv++; 713 if(cv > VAL_LOOP) 714 cv = VAL_NONE; 715 716 trackData[xCursor][yCursor] = cv; 717 718 updateDisplay(); 719 redrawScreen(0); 720 } 721 break; 722 } 723 724 725 case BEATBOX_PLAY: 726 { 727 if(playState == STATE_PLAYING) 728 playState = STATE_PAUSED; 729 else 730 { 731 updateDisplay(); 732 redrawScreen(0); 733 sendEvents(); 734 playState = STATE_PLAYING; 735 } 736 break; 737 } 738 739 case BEATBOX_STOP: 740 { 741 if(playState == STATE_STOPPED) 742 { 743 quit=1; 744 } else 745 { 746 playState =STATE_STOPPED; 747 resetPosition(); 748 updateDisplay(); 749 redrawScreen(0); 750 } 751 break; 752 } 753 } 754 755 756 } 757 758 return 0; 759} 760