/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2002 Philipp Pertermann * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "plugin.h" #ifdef HAVE_LCD_BITMAP PLUGIN_HEADER /* The different drawing modes */ #define DRAW_MODE_FILLED 0 #define DRAW_MODE_OUTLINE 1 #define DRAW_MODE_PIXEL 2 #define DRAW_MODE_COUNT 3 #define MAX_PEAK 0x8000 /* variable button definitions */ #if CONFIG_KEYPAD == RECORDER_PAD #define OSCILLOGRAPH_QUIT BUTTON_OFF #define OSCILLOGRAPH_SPEED_UP BUTTON_UP #define OSCILLOGRAPH_SPEED_DOWN BUTTON_DOWN #define OSCILLOGRAPH_ROLL BUTTON_F1 #define OSCILLOGRAPH_MODE BUTTON_F2 #define OSCILLOGRAPH_SPEED_RESET BUTTON_F3 #define OSCILLOGRAPH_PAUSE BUTTON_PLAY #elif CONFIG_KEYPAD == ONDIO_PAD #define OSCILLOGRAPH_QUIT BUTTON_OFF #define OSCILLOGRAPH_SPEED_UP BUTTON_UP #define OSCILLOGRAPH_SPEED_DOWN BUTTON_DOWN #define OSCILLOGRAPH_ROLL BUTTON_RIGHT #define OSCILLOGRAPH_MODE BUTTON_MENU #define OSCILLOGRAPH_SPEED_RESET BUTTON_LEFT #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ (CONFIG_KEYPAD == IRIVER_H300_PAD) #define OSCILLOGRAPH_QUIT BUTTON_OFF #define OSCILLOGRAPH_SPEED_UP BUTTON_UP #define OSCILLOGRAPH_SPEED_DOWN BUTTON_DOWN #define OSCILLOGRAPH_ROLL BUTTON_RIGHT #define OSCILLOGRAPH_MODE BUTTON_SELECT #define OSCILLOGRAPH_SPEED_RESET BUTTON_LEFT #elif (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_4G_PAD) #define OSCILLOGRAPH_QUIT BUTTON_MENU #define OSCILLOGRAPH_SPEED_UP BUTTON_SCROLL_FWD #define OSCILLOGRAPH_SPEED_DOWN BUTTON_SCROLL_BACK #define OSCILLOGRAPH_ROLL BUTTON_RIGHT #define OSCILLOGRAPH_MODE BUTTON_SELECT #define OSCILLOGRAPH_SPEED_RESET BUTTON_LEFT #elif (CONFIG_KEYPAD == GIGABEAT_PAD) #define OSCILLOGRAPH_QUIT BUTTON_POWER #define OSCILLOGRAPH_SPEED_UP BUTTON_UP #define OSCILLOGRAPH_SPEED_DOWN BUTTON_DOWN #define OSCILLOGRAPH_ROLL BUTTON_RIGHT #define OSCILLOGRAPH_MODE BUTTON_SELECT #define OSCILLOGRAPH_SPEED_RESET BUTTON_LEFT #elif CONFIG_KEYPAD == IAUDIO_X5_PAD #define OSCILLOGRAPH_QUIT BUTTON_POWER #define OSCILLOGRAPH_SPEED_UP BUTTON_UP #define OSCILLOGRAPH_SPEED_DOWN BUTTON_DOWN #define OSCILLOGRAPH_ROLL BUTTON_RIGHT #define OSCILLOGRAPH_MODE BUTTON_SELECT #define OSCILLOGRAPH_SPEED_RESET BUTTON_LEFT #endif /* global api struct pointer */ static struct plugin_api* rb; /* number of ticks between two volume samples */ static int speed = 1; #ifndef SIMULATOR /* roll == true -> lcd rolls */ static bool roll = true; #endif /* see DRAW_MODE_XXX constants for valid values */ static int drawMode = DRAW_MODE_FILLED; /** * cleanup on return / usb */ void cleanup(void *parameter) { (void)parameter; #ifndef SIMULATOR /* restore to default roll position. Looks funny if you forget to do this... */ rb->lcd_roll(0); #endif rb->lcd_update(); } /** * Displays a vertically scrolling oscillosgraph using * hardware scrolling of the display. The user can change * speed */ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) { int button; /* stores current volume value left */ int left; /* stores current volume value right */ int right; /* specifies the current position on the lcd */ int y = LCD_WIDTH - 1; /* only needed when drawing lines */ int lastLeft = 0; int lastRight = 0; int lasty = 0; bool exit = false; (void)parameter; rb = api; /* the main loop */ while (!exit) { /* read the volume info */ #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) left = rb->mas_codec_readreg(0xC); right = rb->mas_codec_readreg(0xD); #elif (CONFIG_CODEC == SWCODEC) rb->pcm_calculate_peaks(&left, &right); #endif left = left / (MAX_PEAK / (LCD_WIDTH / 2 - 2)); right = right / (MAX_PEAK / (LCD_WIDTH / 2 - 2)); /* delete current line */ rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); rb->lcd_drawline(0, y, LCD_WIDTH-1, y); rb->lcd_set_drawmode(DRMODE_SOLID); switch (drawMode) { case DRAW_MODE_FILLED: rb->lcd_drawline(LCD_WIDTH / 2 + 1 , y, LCD_WIDTH / 2 + 1 + right, y); rb->lcd_drawline(LCD_WIDTH / 2 - 1 , y, LCD_WIDTH / 2 - 1 -left , y); break; case DRAW_MODE_OUTLINE: /* last position needed for lines */ lasty = MAX(y-1, 0); /* Here real lines were neccessary because anything else was ugly. */ rb->lcd_drawline(LCD_WIDTH / 2 + right , y, LCD_WIDTH / 2 + lastRight , lasty); rb->lcd_drawline(LCD_WIDTH / 2 - left , y, LCD_WIDTH / 2 - lastLeft, lasty); /* have to store the old values for drawing lines the next time */ lastRight = right; lastLeft = left; break; case DRAW_MODE_PIXEL: /* straight and simple */ rb->lcd_drawpixel(LCD_WIDTH / 2 + right, y); rb->lcd_drawpixel(LCD_WIDTH / 2 - left, y); break; } /* increment and adjust the drawing position */ y++; if (y >= LCD_HEIGHT) y = 0; #ifndef SIMULATOR /* I roll before update because otherwise the new line would appear at the wrong end of the display */ if (roll) rb->lcd_roll(y); #endif /* now finally make the new sample visible */ rb->lcd_update_rect(0, MAX(y-1, 0), LCD_WIDTH, 2); /* There are two mechanisms to alter speed: 1.) slowing down is achieved by increasing the time waiting for user input. This mechanism uses positive values. 2.) speeding up is achieved by leaving out the user input check for (-speed) volume samples. For this mechanism negative values are used. */ if (speed >= 0 || ((speed < 0) && (y % (-speed) == 0))) { bool draw = false; /* speed values > 0 slow the oszi down. By user input speed might become < 1. If a value < 1 was passed user input would be disabled. Thus it must be ensured that at least 1 is passed. */ /* react to user input */ button = rb->button_get_w_tmo(MAX(speed, 1)); switch (button) { case OSCILLOGRAPH_SPEED_UP: speed++; draw = true; break; case OSCILLOGRAPH_SPEED_DOWN: speed--; draw = true; break; #ifdef OSCILLOGRAPH_PAUSE case OSCILLOGRAPH_PAUSE: /* pause the demo */ rb->button_get(true); break; #endif #ifndef SIMULATOR case OSCILLOGRAPH_ROLL: /* toggle rolling */ roll = !roll; break; #endif case OSCILLOGRAPH_MODE: /* step through the display modes */ drawMode ++; drawMode = drawMode % DRAW_MODE_COUNT; #ifndef SIMULATOR /* lcd buffer might be rolled so that the transition from LCD_HEIGHT to 0 takes place in the middle of the screen. That produces ugly results in DRAW_MODE_OUTLINE mode. If rolling is enabled this change will be reverted before the next update anyway.*/ rb->lcd_roll(0); #endif break; case OSCILLOGRAPH_SPEED_RESET: speed = 1; draw = true; break; case OSCILLOGRAPH_QUIT: exit = true; break; default: if (rb->default_event_handler_ex(button, cleanup, NULL) == SYS_USB_CONNECTED) return PLUGIN_USB_CONNECTED; break; } if (draw) { char buf[16]; rb->snprintf(buf, sizeof buf, "Speed: %d", -speed); rb->lcd_putsxy(0, (y + LCD_HEIGHT - 8) % LCD_HEIGHT, buf); rb->lcd_update_rect(0, (y + LCD_HEIGHT - 8) % LCD_HEIGHT, LCD_WIDTH, 8); } } } cleanup(NULL); /* standard return */ return PLUGIN_OK; } #endif