From b318b3e84f4dad767a9c386954357357964cff38 Mon Sep 17 00:00:00 2001 From: Jens Arnold Date: Thu, 9 Mar 2006 07:52:26 +0000 Subject: Rewrite of oscilloscope plugin: * Doesn't use a timer isr anymore, ported to swcodec targets. * Added speed adjustment. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8969 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/oscilloscope.c | 337 ++++++++++++++++++++++++++++++++------------ 1 file changed, 249 insertions(+), 88 deletions(-) diff --git a/apps/plugins/oscilloscope.c b/apps/plugins/oscilloscope.c index de85dc3950..e215f78efe 100644 --- a/apps/plugins/oscilloscope.c +++ b/apps/plugins/oscilloscope.c @@ -9,7 +9,7 @@ * * Oscilloscope, with the thought-to-be impossible horizontal aspect! * -* Copyright (C) 2004 Jens Arnold +* Copyright (C) 2004-2006 Jens Arnold * * 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. @@ -19,134 +19,269 @@ * ****************************************************************************/ -#ifndef SIMULATOR /* not for simulator by now */ #include "plugin.h" -#ifdef HAVE_LCD_BITMAP /* and also not for the Player */ -#if CONFIG_CODEC != SWCODEC /* only for MAS-targets */ +#ifdef HAVE_LCD_BITMAP #include "xlcd.h" 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 OSC_MODE_FILLED 0 +#define OSC_MODE_OUTLINE 1 +#define OSC_MODE_PIXEL 2 +#define OSC_MODE_COUNT 3 #define MAX_PEAK 0x8000 /* variable button definitions */ #if CONFIG_KEYPAD == RECORDER_PAD #define OSCILLOSCOPE_QUIT BUTTON_OFF -#define OSCILLOSCOPE_SCROLL BUTTON_F1 -#define OSCILLOSCOPE_MODE BUTTON_F2 +#define OSCILLOSCOPE_MODE BUTTON_F1 +#define OSCILLOSCOPE_SCROLL BUTTON_F2 #define OSCILLOSCOPE_PAUSE BUTTON_PLAY +#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT +#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT #define OSCILLOSCOPE_VOL_UP BUTTON_UP #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN #elif CONFIG_KEYPAD == ONDIO_PAD #define OSCILLOSCOPE_QUIT BUTTON_OFF -#define OSCILLOSCOPE_SCROLL BUTTON_RIGHT -#define OSCILLOSCOPE_MODE BUTTON_MENU -#define OSCILLOSCOPE_PAUSE BUTTON_LEFT +#define OSCILLOSCOPE_MODE_PRE BUTTON_MENU +#define OSCILLOSCOPE_MODE (BUTTON_MENU | BUTTON_REL) +#define OSCILLOSCOPE_SCROLL (BUTTON_MENU | BUTTON_RIGHT) +#define OSCILLOSCOPE_PAUSE (BUTTON_MENU | BUTTON_OFF) +#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT +#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT +#define OSCILLOSCOPE_VOL_UP BUTTON_UP +#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN + +#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) +#define OSCILLOSCOPE_QUIT BUTTON_OFF +#define OSCILLOSCOPE_MODE BUTTON_SELECT +#define OSCILLOSCOPE_SCROLL BUTTON_MODE +#define OSCILLOSCOPE_PAUSE BUTTON_ON +#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT +#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT +#define OSCILLOSCOPE_VOL_UP BUTTON_UP +#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN + +#elif (CONFIG_KEYPAD == IPOD_3G_PAD) || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define OSCILLOSCOPE_QUIT (BUTTON_SELECT | BUTTON_MENU) +#define OSCILLOSCOPE_MODE (BUTTON_SELECT | BUTTON_PLAY) +#define OSCILLOSCOPE_SCROLL (BUTTON_SELECT | BUTTON_RIGHT) +#define OSCILLOSCOPE_PAUSE BUTTON_PLAY +#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT +#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT +#define OSCILLOSCOPE_VOL_UP BUTTON_SCROLL_FWD +#define OSCILLOSCOPE_VOL_DOWN BUTTON_SCROLL_BACK + +#elif (CONFIG_KEYPAD == GIGABEAT_PAD) +#define OSCILLOSCOPE_QUIT BUTTON_POWER +#define OSCILLOSCOPE_MODE BUTTON_SELECT +#define OSCILLOSCOPE_SCROLL BUTTON_MENU +#define OSCILLOSCOPE_PAUSE BUTTON_A +#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT +#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT +#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP +#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN + +#elif CONFIG_KEYPAD == IAUDIO_X5_PAD +#define OSCILLOSCOPE_QUIT BUTTON_POWER +#define OSCILLOSCOPE_MODE BUTTON_SELECT +#define OSCILLOSCOPE_SCROLL BUTTON_REC +#define OSCILLOSCOPE_PAUSE BUTTON_PLAY +#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT +#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT #define OSCILLOSCOPE_VOL_UP BUTTON_UP #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN #endif -/* unsigned 16 bit multiplication (a single instruction on the SH) */ -#define MULU16(a, b) ((unsigned long) \ - (((unsigned short) (a)) * ((unsigned short) (b)))) +#if defined(SIMULATOR) && (CONFIG_CODEC != SWCODEC) +#define mas_codec_readreg(x) rand()%MAX_PEAK +#endif /* global variables */ -struct plugin_api* rb; /* global api struct pointer */ -int x = 0; -int draw_mode = DRAW_MODE_FILLED; -bool scroll = true; -int left_val; -int right_val; -bool new_val = false; +struct plugin_api* rb; /* global api struct pointer */ -/* prototypes */ - -void lcd_scroll_left(int count, bool black_border); -void timer_isr(void); -void cleanup(void *parameter); -enum plugin_status plugin_start(struct plugin_api* api, void* parameter); +int osc_mode = OSC_MODE_FILLED; +int osc_delay = 1; /* in ticks */ +bool osc_scroll = true; +long last_tick = 0; /* implementation */ -void timer_isr(void) +void animate(int cur_left, int cur_right) { + static int last_x = 0; static int last_left, last_right; + + int cur_x, x; + int left, right, dl, dr; + long cur_tick = *rb->current_tick; + long d = (cur_tick - last_tick) / osc_delay; bool full_update = false; - if (new_val) - { - if ((unsigned)x >= LCD_WIDTH) + if (d == 0) /* too early, bail out */ + return; + + last_tick = cur_tick; + + if (d > HZ) /* first call or too much delay, (re)start */ + { + last_left = cur_left; + last_right = cur_right; + return; + } + cur_x = last_x + d; + + if (cur_x >= LCD_WIDTH) + { + if (osc_scroll) /* scroll */ + { + int shift = cur_x - (LCD_WIDTH-1); + xlcd_scroll_left(shift); + full_update = true; + cur_x -= shift; + last_x -= shift; + } + else /* wrap */ { - if (scroll) + cur_x -= LCD_WIDTH; + } + } + rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); + + if (cur_x > last_x) + { + rb->lcd_fillrect(last_x + 1, 0, d + 2, LCD_HEIGHT); + } + else + { + rb->lcd_fillrect(last_x + 1, 0, (LCD_WIDTH-1) - last_x, LCD_HEIGHT); + rb->lcd_fillrect(0, 0, cur_x + 2, LCD_HEIGHT); + } + rb->lcd_set_drawmode(DRMODE_SOLID); + + switch (osc_mode) + { + case OSC_MODE_FILLED: + left = last_left; + right = last_right; + dl = (cur_left - left) / d; + dr = (cur_right - right) / d; + + for (x = last_x + 1; d > 0; x++, d--) { - xlcd_scroll_left(1); - x = LCD_WIDTH-1; - full_update = true; + if (x == LCD_WIDTH) + x = 0; + + left += dl; + right += dr; + + rb->lcd_vline(x, LCD_HEIGHT/2+1, + LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * left) >> 16)); + rb->lcd_vline(x, LCD_HEIGHT/2-1, + LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * right) >> 16)); + } + break; + + case OSC_MODE_OUTLINE: + if (cur_x > last_x) + { + rb->lcd_drawline( + last_x, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * last_left) >> 16), + cur_x, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * cur_left) >> 16) + ); + rb->lcd_drawline( + last_x, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * last_right) >> 16), + cur_x, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * cur_right) >> 16) + ); } else - x = 0; - } + { + left = last_left + + (LCD_WIDTH - last_x) * (last_left - cur_left) / d; + right = last_right + + (LCD_WIDTH - last_x) * (last_right - cur_right) / d; + + rb->lcd_drawline( + last_x, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * last_left) >> 16), + LCD_WIDTH, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * left) >> 16) + ); + rb->lcd_drawline( + last_x, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * last_right) >> 16), + LCD_WIDTH, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * right) >> 16) + ); + rb->lcd_drawline( + 0, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * left) >> 16), + cur_x, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * cur_left) >> 16) + ); + rb->lcd_drawline( + 0, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * right) >> 16), + cur_x, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * cur_right) >> 16) + ); + } + break; + + case OSC_MODE_PIXEL: + left = last_left; + right = last_right; + dl = (cur_left - left) / d; + dr = (cur_right - right) / d; + + for (x = last_x + 1; d > 0; x++, d--) + { + if (x == LCD_WIDTH) + x = 0; + + left += dl; + right += dr; + + rb->lcd_drawpixel(x, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * left) >> 16)); + rb->lcd_drawpixel(x, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * right) >> 16)); + } + break; - rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); - rb->lcd_vline(x, 0, LCD_HEIGHT-1); - rb->lcd_set_drawmode(DRMODE_SOLID); + } + last_left = cur_left; + last_right = cur_right; - switch (draw_mode) + if (full_update) + { + rb->lcd_update(); + } + else + { + if (cur_x > last_x) { - case DRAW_MODE_FILLED: - rb->lcd_vline(x, LCD_HEIGHT/2+1, LCD_HEIGHT/2+1 + left_val); - rb->lcd_vline(x, LCD_HEIGHT/2-1, LCD_HEIGHT/2-1 - right_val); - break; - - case DRAW_MODE_OUTLINE: - if (x > 0) - { - rb->lcd_drawline(x - 1, LCD_HEIGHT/2+1 + last_left, - x, LCD_HEIGHT/2+1 + left_val); - rb->lcd_drawline(x - 1, LCD_HEIGHT/2-1 - last_right, - x, LCD_HEIGHT/2-1 - right_val); - break; - } - /* else fall through */ - - case DRAW_MODE_PIXEL: - rb->lcd_drawpixel(x, LCD_HEIGHT/2+1 + left_val); - rb->lcd_drawpixel(x, LCD_HEIGHT/2-1 - right_val); - break; + rb->lcd_update_rect(last_x, 0, cur_x - last_x + 2, LCD_HEIGHT); } - - if (full_update) - rb->lcd_update(); else - rb->lcd_update_rect(MAX(x - 1, 0), 0, 2, LCD_HEIGHT); - - last_left = left_val; - last_right = right_val; - x++; - new_val = false; + { + rb->lcd_update_rect(last_x, 0, (LCD_WIDTH-1) - last_x, LCD_HEIGHT); + rb->lcd_update_rect(0, 0, cur_x + 2, LCD_HEIGHT); + } } + last_x = cur_x; } void cleanup(void *parameter) { (void)parameter; - - rb->timer_unregister(); +#ifdef HAVE_LCD_COLOR + rb->lcd_set_foreground(LCD_DEFAULT_FG); + rb->lcd_set_background(LCD_DEFAULT_BG); + rb->backlight_set_timeout(rb->global_settings->backlight_timeout); +#endif } enum plugin_status plugin_start(struct plugin_api* api, void* parameter) { int button, vol; + int lastbutton = BUTTON_NONE; bool exit = false; bool paused = false; @@ -155,18 +290,30 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) xlcd_init(rb); - rb->timer_register(1, NULL, FREQ / 67, 1, timer_isr); - +#ifdef HAVE_LCD_COLOR + rb->lcd_set_foreground(LCD_RGBPACK(128, 255, 0)); + rb->lcd_set_background(LCD_BLACK); + rb->lcd_clear_display(); + rb->lcd_update(); + rb->backlight_set_timeout(1); /* keep the light on */ +#endif + while (!exit) { if (!paused) { - /* read the volume info from MAS */ - left_val = rb->mas_codec_readreg(0xC) / (MAX_PEAK / (LCD_HEIGHT/2-2)); - right_val = rb->mas_codec_readreg(0xD) / (MAX_PEAK / (LCD_HEIGHT/2-2)); - new_val = true; + int left, right; + + rb->sleep(MAX(last_tick + osc_delay - *rb->current_tick - 1, 0)); + +#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 + animate(left, right); } - rb->yield(); button = rb->button_get(paused); switch (button) @@ -176,18 +323,34 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) break; case OSCILLOSCOPE_SCROLL: - scroll = !scroll; + osc_scroll = !osc_scroll; break; case OSCILLOSCOPE_MODE: - draw_mode++; - draw_mode = draw_mode % DRAW_MODE_COUNT; +#ifdef OSCILLOSCOPE_MODE_PRE + if (lastbutton != OSCILLOSCOPE_MODE_PRE) + break; +#endif + if (++osc_mode >= OSC_MODE_COUNT) + osc_mode = 0; break; case OSCILLOSCOPE_PAUSE: paused = !paused; + last_tick = 0; + break; + + case OSCILLOSCOPE_SPEED_UP: + case OSCILLOSCOPE_SPEED_UP | BUTTON_REPEAT: + if (osc_delay > 1) + osc_delay--; break; + case OSCILLOSCOPE_SPEED_DOWN: + case OSCILLOSCOPE_SPEED_DOWN | BUTTON_REPEAT: + osc_delay++; + break; + case OSCILLOSCOPE_VOL_UP: case OSCILLOSCOPE_VOL_UP | BUTTON_REPEAT: vol = rb->global_settings->volume; @@ -216,12 +379,10 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) return PLUGIN_USB_CONNECTED; break; } - + if (button != BUTTON_NONE) + lastbutton = button; } - cleanup(NULL); return PLUGIN_OK; } -#endif /* if using MAS */ #endif /* if HAVE_LCD_BITMAP */ -#endif /* SIMULATOR */ -- cgit v1.2.3