From 98e607390673a2e81eed132724d83f430a0ea66e Mon Sep 17 00:00:00 2001 From: Robert Keevil Date: Tue, 31 Jul 2007 17:23:49 +0000 Subject: vu_meter: Use the fixedpoint lib (moving flog there) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@14103 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/lib/fixedpoint.c | 30 +++++++++++++++ apps/plugins/lib/fixedpoint.h | 1 + apps/plugins/vu_meter.c | 89 ++++++------------------------------------- 3 files changed, 42 insertions(+), 78 deletions(-) (limited to 'apps') diff --git a/apps/plugins/lib/fixedpoint.c b/apps/plugins/lib/fixedpoint.c index cf69d9c31b..88c2f6ea54 100644 --- a/apps/plugins/lib/fixedpoint.c +++ b/apps/plugins/lib/fixedpoint.c @@ -202,3 +202,33 @@ long cos_int(int val) } return 0; } + +/** + * Fixed-point natural log + * taken from http://www.quinapalus.com/efunc.html + * "The code assumes integers are at least 32 bits long. The (positive) + * argument and the result of the function are both expressed as fixed-point + * values with 16 fractional bits, although intermediates are kept with 28 + * bits of precision to avoid loss of accuracy during shifts." + */ + +long flog(int x) { + long t,y; + + y=0xa65af; + if(x<0x00008000) x<<=16, y-=0xb1721; + if(x<0x00800000) x<<= 8, y-=0x58b91; + if(x<0x08000000) x<<= 4, y-=0x2c5c8; + if(x<0x20000000) x<<= 2, y-=0x162e4; + if(x<0x40000000) x<<= 1, y-=0x0b172; + t=x+(x>>1); if((t&0x80000000)==0) x=t,y-=0x067cd; + t=x+(x>>2); if((t&0x80000000)==0) x=t,y-=0x03920; + t=x+(x>>3); if((t&0x80000000)==0) x=t,y-=0x01e27; + t=x+(x>>4); if((t&0x80000000)==0) x=t,y-=0x00f85; + t=x+(x>>5); if((t&0x80000000)==0) x=t,y-=0x007e1; + t=x+(x>>6); if((t&0x80000000)==0) x=t,y-=0x003f8; + t=x+(x>>7); if((t&0x80000000)==0) x=t,y-=0x001fe; + x=0x80000000-x; + y-=x>>15; + return y; +} diff --git a/apps/plugins/lib/fixedpoint.h b/apps/plugins/lib/fixedpoint.h index c58798930a..719915709a 100644 --- a/apps/plugins/lib/fixedpoint.h +++ b/apps/plugins/lib/fixedpoint.h @@ -23,3 +23,4 @@ long fsincos(unsigned long phase, long *cos); long fsqrt(long a, unsigned int fracbits); long cos_int(int val); long sin_int(int val); +long flog(int x); diff --git a/apps/plugins/vu_meter.c b/apps/plugins/vu_meter.c index ba64932d84..a03f38fe54 100644 --- a/apps/plugins/vu_meter.c +++ b/apps/plugins/vu_meter.c @@ -16,6 +16,7 @@ * **************************************************************************/ #include "plugin.h" +#include "fixedpoint.h" #if defined(HAVE_LCD_BITMAP) @@ -200,78 +201,20 @@ void reset_settings(void) { vumeter_settings.digital_decay=0; } -/* taken from http://www.quinapalus.com/efunc.html */ -int fxlog(int x) { - int t,y; - - y=0xa65af; - if(x<0x00008000) x<<=16, y-=0xb1721; - if(x<0x00800000) x<<= 8, y-=0x58b91; - if(x<0x08000000) x<<= 4, y-=0x2c5c8; - if(x<0x20000000) x<<= 2, y-=0x162e4; - if(x<0x40000000) x<<= 1, y-=0x0b172; - t=x+(x>>1); if((t&0x80000000)==0) x=t,y-=0x067cd; - t=x+(x>>2); if((t&0x80000000)==0) x=t,y-=0x03920; - t=x+(x>>3); if((t&0x80000000)==0) x=t,y-=0x01e27; - t=x+(x>>4); if((t&0x80000000)==0) x=t,y-=0x00f85; - t=x+(x>>5); if((t&0x80000000)==0) x=t,y-=0x007e1; - t=x+(x>>6); if((t&0x80000000)==0) x=t,y-=0x003f8; - t=x+(x>>7); if((t&0x80000000)==0) x=t,y-=0x001fe; - x=0x80000000-x; - y-=x>>15; - return y; -} - -/* - * Integer square root routine, good for up to 32-bit values. - * Note that the largest square root (that of 0xffffffff) is - * 0xffff, so the result fits in a regular unsigned and need - * not be `long'. - * - * Original code from Tomas Rokicki (using a well known algorithm). - * This version by Chris Torek, University of Maryland. - * - * This code is in the public domain. - */ -unsigned int root(unsigned long v) -{ - register unsigned long t = 1L << 30, r = 0, s; /* 30 = 15*2 */ - -#define STEP(k) \ - s = t + r; \ - r >>= 1; \ - if (s <= v) { \ - v -= s; \ - r |= t; \ - } - STEP(15); t >>= 2; - STEP(14); t >>= 2; - STEP(13); t >>= 2; - STEP(12); t >>= 2; - STEP(11); t >>= 2; - STEP(10); t >>= 2; - STEP(9); t >>= 2; - STEP(8); t >>= 2; - STEP(7); t >>= 2; - STEP(6); t >>= 2; - STEP(5); t >>= 2; - STEP(4); t >>= 2; - STEP(3); t >>= 2; - STEP(2); t >>= 2; - STEP(1); t >>= 2; - STEP(0); - return r; - -} - void calc_scales(void) { unsigned int fx_log_factor = E_POW_5/half_width; unsigned int y,z; + long j; + long k; + int nh = LCD_HEIGHT - NEEDLE_TOP; + long nh2 = nh*nh; + for (i=1; i <= half_width; i++) { - y = (half_width/5)*fxlog(i*fx_log_factor); + /* analog scale */ + y = (half_width/5)*flog(i*fx_log_factor); /* better way of checking for negative values? */ z = y>>16; @@ -281,25 +224,15 @@ void calc_scales(void) analog_db_scale[i-1] = z; /* play nice */ rb->yield(); - } - long j; - long k; - unsigned int l; - int nh = LCD_HEIGHT - NEEDLE_TOP; - long nh2 = nh*nh; - for (i=1; i<=half_width; i++) - { + /* y values (analog needle co-ords) */ j = i - (int)(half_width/2); k = nh2 - ( j * j ); - /* +1 seems to give a closer approximation */ - l = root(k) + 1; - l = LCD_HEIGHT - l; - y_values[i-1] = l; + /* fsqrt+1 seems to give a closer approximation */ + y_values[i-1] = LCD_HEIGHT - (fsqrt(k, 16)>>8) - 1; rb->yield(); } - } void load_settings(void) { -- cgit v1.2.3