Philip Pertermanns peak meter
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@2436 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 83ccf03..afea869 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -834,3 +834,33 @@
desc: bool false representation
eng: "No"
new:
+
+id: LANG_PM_MENU
+desc: in the display menu
+eng: "Peak meter"
+new:
+
+id: LANG_PM_RELEASE
+desc: in the peak meter menu
+eng: "Peak release"
+new:
+
+id: LANG_PM_PEAK_HOLD
+desc: in the peak meter menu
+eng: "Peak hold time"
+new:
+
+id: LANG_PM_CLIP_HOLD
+desc: in the peak meter menu
+eng: "Clip hold time"
+new:
+
+id: LANG_PM_ETERNAL
+desc: in the peak meter menu
+eng: "eternal"
+new:
+
+id: LANG_PM_UNITS_PER_READ
+desc: in the peak meter menu
+eng: "Units per read"
+new:
diff --git a/apps/settings.c b/apps/settings.c
index 31d4f1a..1b4f864 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -53,6 +53,12 @@
#define CONFIG_BLOCK_SIZE 512
#define RTC_BLOCK_SIZE 44
+#ifdef HAVE_LCD_BITMAP
+#define MAX_LINES 10
+#else
+#define MAX_LINES 2
+#endif
+
/********************************************
Config block as saved on the battery-packed RTC user RAM memory block
@@ -80,6 +86,9 @@
0x16 0x2a <(int) Byte offset into resume file>
0x1a 0x2e <time until disk spindown>
0x1b 0x2f <browse current, play selected>
+0x1c 0x30 <peak meter hold timeout (bit 0-4)>
+0x1d 0x31 <peak meter clip hold timeout (bit 0-4)>
+0x1e 0x32 <peak meter release step size>
<all unused space filled with 0xff>
@@ -290,6 +299,10 @@
(((global_settings.browse_current & 1)) |
((global_settings.play_selected & 1) << 1));
+ config_block[0x1c] = (unsigned char)global_settings.peak_meter_hold;
+ config_block[0x1d] = (unsigned char)global_settings.peak_meter_clip_hold;
+ config_block[0x1e] = (unsigned char)global_settings.peak_meter_release;
+
memcpy(&config_block[0xF8], &global_settings.resume_seed, 4);
memcpy(&config_block[0x24], &global_settings.total_uptime, 4);
@@ -400,6 +413,15 @@
global_settings.play_selected = (config_block[0x1b] >> 1) & 1;
}
+ if (config_block[0x1c] != 0xFF)
+ global_settings.peak_meter_hold = (config_block[0x1c]) & 0x1f;
+
+ if (config_block[0x1d] != 0xFF)
+ global_settings.peak_meter_clip_hold = (config_block[0x1d]) & 0x1f;
+
+ if (config_block[0x1e] != 0xFF)
+ global_settings.peak_meter_release = config_block[0x1e];
+
memcpy(&global_settings.resume_seed, &config_block[0xF8], 4);
if (config_block[0x24] != 0xFF)
@@ -471,7 +493,7 @@
break;
case 3:
snprintf(buf_disp,sizeof(buf_disp),"[%s]%s", buf_set, buf_val);
- lcd_puts(0,line++ % 6,buf_disp);
+ lcd_puts(0,line++ % MAX_LINES, buf_disp);
lcd_update();
sleep(HZ/2);
if (!strcasecmp(buf_set,"volume")) {
@@ -610,6 +632,9 @@
global_settings.disk_spindown = 5;
global_settings.browse_current = false;
global_settings.play_selected = true;
+ global_settings.peak_meter_release = 8;
+ global_settings.peak_meter_hold = 1;
+ global_settings.peak_meter_clip_hold = 16;
}
diff --git a/apps/settings.h b/apps/settings.h
index 048c673..bbc7bb3 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -86,6 +86,10 @@
int ff_rewind_accel; /* FF/Rewind acceleration (in seconds per doubling) */
int disk_spindown; /* time until disk spindown, in seconds (0=off) */
+ int peak_meter_release; /* units per read out */
+ int peak_meter_hold; /* hold time for peak meter in 1/100 s */
+ int peak_meter_clip_hold; /* hold time for clips */
+
/* show status bar */
bool statusbar; /* 0=hide, 1=show */
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index 8aba4bc..643f5be 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -36,6 +36,7 @@
#include "powermgmt.h"
#include "rtc.h"
#include "ata.h"
+#include "peakmeter.h"
#include "lang.h"
static bool contrast(void)
@@ -44,6 +45,68 @@
lcd_set_contrast, 1, 0, MAX_CONTRAST_SETTING );
}
+#ifdef HAVE_LCD_BITMAP
+/**
+ * Menu to set the hold time of normal peaks.
+ */
+static bool peak_meter_hold(void) {
+ char* names[] = { str(LANG_OFF),
+ "200 ms ", "300 ms ", "500 ms ", "1 s ", "2 s ",
+ "3 s ", "4 s ", "5 s ", "6 s ", "7 s",
+ "8 s", "9 s", "10 s", "15 s", "20 s",
+ "30 s", "1 min"
+ };
+ return set_option( str(LANG_PM_PEAK_HOLD),
+ &global_settings.peak_meter_hold, names,
+ 18, NULL);
+}
+
+/**
+ * Menu to set the hold time of clips.
+ */
+static bool peak_meter_clip_hold(void) {
+ char* names[] = { str(LANG_PM_ETERNAL),
+ "1s ", "2s ", "3s ", "4s ", "5s ",
+ "6s ", "7s ", "8s ", "9s ", "10s",
+ "15s", "20s", "25s", "30s", "45s",
+ "60s", "90s", "2min", "3min", "5min",
+ "10min", "20min", "45min", "90min"
+ };
+ return set_option( str(LANG_PM_CLIP_HOLD),
+ &global_settings.peak_meter_clip_hold, names,
+ 25, peak_meter_set_clip_hold);
+}
+
+/**
+ * Menu to set the release time of the peak meter.
+ */
+static bool peak_meter_release(void) {
+ return set_int( str(LANG_PM_RELEASE), str(LANG_PM_UNITS_PER_READ),
+ &global_settings.peak_meter_release,
+ NULL, 1, 1, LCD_WIDTH);
+}
+
+/**
+ * Menu to configure the peak meter
+ */
+static bool peak_meter_menu(void)
+{
+ int m;
+ bool result;
+
+ struct menu_items items[] = {
+ { str(LANG_PM_RELEASE) , peak_meter_release },
+ { str(LANG_PM_PEAK_HOLD), peak_meter_hold },
+ { str(LANG_PM_CLIP_HOLD), peak_meter_clip_hold },
+ };
+
+ m=menu_init( items, sizeof items / sizeof(struct menu_items) );
+ result = menu_run(m);
+ menu_exit(m);
+ return result;
+}
+#endif
+
#ifndef HAVE_RECORDER_KEYPAD
static bool shuffle(void)
{
@@ -313,6 +376,9 @@
{ str(LANG_SCROLL_MENU), scroll_speed },
{ str(LANG_BACKLIGHT), backlight_timer },
{ str(LANG_CONTRAST), contrast },
+#ifdef HAVE_LCD_BITMAP
+ { str(LANG_PM_MENU), peak_meter_menu },
+#endif
};
m=menu_init( items, sizeof items / sizeof(struct menu_items) );
diff --git a/apps/wps-display.c b/apps/wps-display.c
index ec1e9c7..a898085 100644
--- a/apps/wps-display.c
+++ b/apps/wps-display.c
@@ -37,10 +37,13 @@
#include "status.h"
#include "wps-display.h"
#include "debug.h"
+#include "mas.h"
#include "lang.h"
+
#ifdef HAVE_LCD_BITMAP
#include "icons.h"
#include "widgets.h"
+#include "peakmeter.h"
#endif
#define WPS_CONFIG ROCKBOX_DIR "/default.wps"
@@ -52,12 +55,12 @@
#endif
#define FORMAT_BUFFER_SIZE 300
-
struct format_flags
{
bool dynamic;
bool scroll;
bool player_progress;
+ bool peak_meter;
};
static char format_buffer[FORMAT_BUFFER_SIZE];
@@ -331,6 +334,13 @@
case 't': /* Total Time */
format_time(buf, buf_size, id3->length);
return buf;
+
+#ifdef HAVE_LCD_BITMAP
+ case 'm': /* Peak Meter */
+ flags->peak_meter = true;
+ flags->dynamic = true;
+ return "\x01";
+#endif
}
break;
@@ -518,6 +528,15 @@
bool scroll_active = false;
int i;
+ /* to find out wether the peak meter is enabled we
+ assume it wasn't until we find a line that contains
+ the peak meter. We can't use peak_meter_enabled itself
+ because that would mean to turn off the meter thread
+ temporarily. (That shouldn't matter unless yield
+ or sleep is called but who knows...)
+ */
+ bool enable_pm = false;
+
if (!id3)
{
lcd_stop_scroll();
@@ -537,6 +556,7 @@
flags.dynamic = false;
flags.scroll = false;
flags.player_progress = false;
+ flags.peak_meter = false;
format_display(buf, sizeof(buf), id3, format_lines[i], &flags);
dynamic_lines[i] = flags.dynamic;
@@ -556,6 +576,30 @@
#endif
}
+#ifdef HAVE_LCD_BITMAP
+ if (flags.peak_meter) {
+ int peak_meter_y;
+ int w,h;
+ int offset = global_settings.statusbar ? STATUSBAR_HEIGHT : 0;
+ lcd_getstringsize("M",&w,&h);
+
+ peak_meter_y = i * h + offset;
+
+ /* The user might decide to have the peak meter in the last
+ line so that it is only displayed if no status bar is
+ visible. If so we neither want do draw nor enable the
+ peak meter. */
+ if (peak_meter_y + h <= LCD_HEIGHT) {
+ /* found a line with a peak meter -> remember that we must
+ enable it later */
+ enable_pm = true;
+ peak_meter_draw(0, peak_meter_y, LCD_WIDTH,
+ MIN(h, LCD_HEIGHT - peak_meter_y));
+ }
+ continue;
+ }
+#endif
+
if (!scroll_active && flags.scroll && !flags.dynamic)
{
scroll_active = true;
@@ -567,6 +611,10 @@
}
}
}
+
+ /* Now we know wether the peak meter is used.
+ So we can enable / disable the peak meter thread */
+ peak_meter_enabled = enable_pm;
lcd_update();
return true;
@@ -602,7 +650,8 @@
"%ia\n"
"%fb kbit %fv\n"
"Time: %pc / %pt\n"
- "%pb\n");
+ "%pb\n"
+ "%pm\n");
#else
wps_format("%s%pp/%pe: %?ia<%ia - >%?it<%it|%fm>\n"
"%pc/%pt\n");
diff --git a/apps/wps.c b/apps/wps.c
index 2729b28..db4459c 100644
--- a/apps/wps.c
+++ b/apps/wps.c
@@ -40,6 +40,7 @@
#include "screens.h"
#ifdef HAVE_LCD_BITMAP
#include "icons.h"
+#include "peakmeter.h"
#endif
#include "lang.h"
#define FF_REWIND_MAX_PERCENT 3 /* cap ff/rewind step size at max % of file */
@@ -610,7 +611,7 @@
/* demonstrates showing different formats from playtune */
int wps_show(void)
{
- int button, lastbutton = 0;
+ int button = 0, lastbutton = 0;
int old_repeat_mask;
bool ignore_keyup = true;
bool restore = false;
@@ -644,7 +645,27 @@
while ( 1 )
{
+
+#ifdef HAVE_LCD_BITMAP
+ /* when the peak meter is enabled we want to have a
+ few extra updates to make it look smooth. On the
+ other hand we don't want to waste energy if it
+ isn't displayed */
+ if (peak_meter_enabled) {
+ int i;
+ for (i = 0; i < 4; i++) {
+ button = button_get_w_tmo(HZ / 20);
+ if (button != 0) {
+ break;
+ }
+ wps_refresh(id3, 0, false);
+ }
+ } else {
+ button = button_get_w_tmo(HZ/5);
+ }
+#else
button = button_get_w_tmo(HZ/5);
+#endif
/* discard first event if it's a button release */
if (button && ignore_keyup)
@@ -839,4 +860,5 @@
if(button != BUTTON_NONE)
lastbutton = button;
}
+ return 0; /* unreachable - just to reduce compiler warnings */
}
diff --git a/docs/CUSTOM_WPS_FORMAT b/docs/CUSTOM_WPS_FORMAT
index 5162d2e..cecb4af 100644
--- a/docs/CUSTOM_WPS_FORMAT
+++ b/docs/CUSTOM_WPS_FORMAT
@@ -46,6 +46,8 @@
Player: This will display a 1 character "cup" that empties as the
progresses.
Recorder: This will replace the entire line with a progress bar.
+ %pm : Peak Meter (Recorder only)
+ The entire line is used as volume peak meter.
%pp : Playlist Position
%pe : Total Number of Playlist Entries
%pc : Current Time In Song
diff --git a/firmware/drivers/mas.h b/firmware/drivers/mas.h
index 5ccffdf..71604fb 100644
--- a/firmware/drivers/mas.h
+++ b/firmware/drivers/mas.h
@@ -22,6 +22,8 @@
#define MAS_BANK_D0 0
#define MAS_BANK_D1 1
+#define MAX_PEAK 0x8000
+
/*
MAS I2C defs
*/
diff --git a/uisimulator/win32/Makefile b/uisimulator/win32/Makefile
index 28e0eea..aa4136c 100644
--- a/uisimulator/win32/Makefile
+++ b/uisimulator/win32/Makefile
@@ -67,7 +67,7 @@
APPS = main.c tree.c menu.c credits.c main_menu.c icons.c language.c \
playlist.c showtext.c wps.c wps-display.c settings.c status.c \
- screens.c
+ screens.c peakmeter.c
MENUS = games_menu.c demo_menu.c settings_menu.c sound_menu.c
@@ -203,6 +203,9 @@
$(OBJDIR)/screens.o: $(APPDIR)/screens.c
$(CC) $(APPCFLAGS) -c $< -o $@
+$(OBJDIR)/peakmeter.o: $(RECDIR)/peakmeter.c
+ $(CC) $(APPCFLAGS) -c $< -o $@
+
$(OBJDIR)/version.o: $(FIRMWAREDIR)/version.c
$(CC) $(CFLAGS) -c $< -o $@
diff --git a/uisimulator/x11/Makefile b/uisimulator/x11/Makefile
index 074b7f0..c3bb4e6 100644
--- a/uisimulator/x11/Makefile
+++ b/uisimulator/x11/Makefile
@@ -82,7 +82,7 @@
APPS = main.c tree.c menu.c credits.c main_menu.c language.c\
playlist.c showtext.c wps.c wps-display.c settings.c status.c icons.c\
- screens.c
+ screens.c peakmeter.c
MENUS = games_menu.c demo_menu.c settings_menu.c sound_menu.c
@@ -242,6 +242,9 @@
$(OBJDIR)/screens.o: $(APPDIR)/screens.c
$(CC) $(APPCFLAGS) -c $< -o $@
+$(OBJDIR)/peakmeter.o: $(RECDIR)/peakmeter.c
+ $(CC) $(APPCFLAGS) -c $< -o $@
+
$(OBJDIR)/id3.o: $(FIRMWAREDIR)/id3.c
$(CC) $(APPCFLAGS) -c $< -o $@