From 5a8eac1a5a7daa1f90af82e6d687e6c559a0d3e1 Mon Sep 17 00:00:00 2001 From: Magnus Holmgren Date: Thu, 11 Aug 2005 18:56:20 +0000 Subject: Added pre-amp setting for files with ReplayGain information. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7303 a1c6a512-1295-4272-9138-f99709370657 --- apps/dsp.c | 31 +++++++++++++++--------- apps/lang/english.lang | 12 ++++++++++ apps/settings.c | 15 ++++++++++-- apps/settings.h | 4 +++- apps/settings_menu.c | 56 ++++++++++++++++++++++++++++++-------------- apps/sound_menu.c | 2 +- firmware/export/replaygain.h | 1 + firmware/replaygain.c | 12 ++++++++++ 8 files changed, 100 insertions(+), 33 deletions(-) diff --git a/apps/dsp.c b/apps/dsp.c index 21effc5da3..701ffb4e55 100644 --- a/apps/dsp.c +++ b/apps/dsp.c @@ -23,13 +23,14 @@ #include "playback.h" #include "system.h" #include "settings.h" +#include "replaygain.h" #include "debug.h" /* The "dither" code to convert the 24-bit samples produced by libmad was * taken from the coolplayer project - coolplayer.sourceforge.net */ -/* 16-bit samples are scaled based on these constants. The shift should be +/* 16-bit samples are scaled based on these constants. The shift should be * no more than 15. */ #define WORD_SHIFT 12 @@ -336,7 +337,7 @@ static inline long clip_sample(long sample) return sample; } -/* The "dither" code to convert the 24-bit samples produced by libmad was +/* The "dither" code to convert the 24-bit samples produced by libmad was * taken from the coolplayer project - coolplayer.sourceforge.net */ @@ -386,15 +387,15 @@ static void apply_gain(long* src[], int count) long* d1 = (s0 == s1) ? d0 : &sample_buf[SAMPLE_BUF_SIZE / 2]; long gain = dsp.replaygain; long i; - + src[0] = d0; src[1] = d1; - + for (i = 0; i < count; i++) { *d0++ = FRACMUL_8(*s0++, gain); } - + if (src [0] != src [1]) { for (i = 0; i < count; i++) @@ -639,7 +640,7 @@ void dsp_set_replaygain(bool always) long gain = 0; dsp.new_gain = false; - + if (global_settings.replaygain || global_settings.replaygain_noclip) { long peak; @@ -648,28 +649,36 @@ void dsp_set_replaygain(bool always) { gain = (global_settings.replaygain_track || !dsp.album_gain) ? dsp.track_gain : dsp.album_gain; + + if (global_settings.replaygain_preamp) + { + long preamp = get_replaygain_int( + global_settings.replaygain_preamp * 10); + + gain = (long) ((((int64_t) gain * preamp)) >> 24); + } } - + peak = (global_settings.replaygain_track || !dsp.album_peak) ? dsp.track_peak : dsp.album_peak; - + if (gain == 0) { /* So that noclip can work even with no gain information. */ gain = DEFAULT_REPLAYGAIN; } - + if (global_settings.replaygain_noclip && (peak != 0) && ((((int64_t) gain * peak) >> 24) >= DEFAULT_REPLAYGAIN)) { gain = (((int64_t) DEFAULT_REPLAYGAIN << 24) / peak); } - + if (gain == DEFAULT_REPLAYGAIN) { /* Nothing to do, disable processing. */ gain = 0; - + } } diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 3137ff7ed7..a11da030b4 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -3244,3 +3244,15 @@ desc: in settings_menu, option to enable reversal of hebrew/arabic text eng: "BiDi Hebrew/Arabic" voice "" new: + +id: LANG_REPLAYGAIN_PREAMP +desc: in browse_id3 +eng: "Pre-amp" +voice "Preamp" +new: + +id: LANG_UNIT_DB +desc: in browse_id3 +eng: "dB" +voice "" +new: diff --git a/apps/settings.c b/apps/settings.c index 63e7a3b9d9..295a32f16d 100644 --- a/apps/settings.c +++ b/apps/settings.c @@ -431,6 +431,7 @@ static const struct bit_entry hd_bits[] = {1, S_O(replaygain), false, "replaygain", off_on }, {1, S_O(replaygain_track), false, "replaygain type", "track,album" }, {1, S_O(replaygain_noclip), false, "replaygain noclip", off_on }, + {8, S_O(replaygain_preamp), 0, "replaygain preamp", NULL }, #endif /* If values are just added to the end, no need to bump the version. */ @@ -1388,7 +1389,8 @@ bool set_int(const char* string, void (*function)(int), int step, int min, - int max ) + int max, + void (*formatter)(char*, int, int, const char*) ) { bool done = false; int button; @@ -1407,7 +1409,16 @@ bool set_int(const char* string, while (!done) { char str[32]; - snprintf(str,sizeof str,"%d %s ", *variable, unit); + + if (formatter) + { + formatter(str, sizeof str, *variable, unit); + } + else + { + snprintf(str,sizeof str,"%d %s ", *variable, unit); + } + lcd_puts(0, 1, str); #ifdef HAVE_LCD_BITMAP status_draw(true); diff --git a/apps/settings.h b/apps/settings.h index ff121868cb..055b893082 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -334,6 +334,7 @@ struct user_settings bool replaygain; /* enable replaygain */ bool replaygain_track; /* true for track gain, false for album gain */ bool replaygain_noclip; /* scale to prevent clips */ + int replaygain_preamp; /* scale replaygained tracks by this */ #endif }; @@ -366,7 +367,8 @@ bool set_bool(const char* string, bool* variable ); bool set_option(const char* string, void* variable, enum optiontype type, const struct opt_items* options, int numoptions, void (*function)(int)); bool set_int(const char* string, const char* unit, int voice_unit, int* variable, - void (*function)(int), int step, int min, int max ); + void (*function)(int), int step, int min, int max, + void (*formatter)(char*, int, int, const char*) ); bool set_time_screen(const char* string, struct tm *tm); int read_line(int fd, char* buffer, int buffer_size); void set_file(char* filename, char* setting, int maxlen); diff --git a/apps/settings_menu.c b/apps/settings_menu.c index fadbb11f3e..57b4cc897e 100644 --- a/apps/settings_menu.c +++ b/apps/settings_menu.c @@ -95,7 +95,7 @@ static bool remote_contrast(void) return set_int( str(LANG_CONTRAST), "", UNIT_INT, &global_settings.remote_contrast, lcd_remote_set_contrast, 1, MIN_CONTRAST_SETTING, - MAX_CONTRAST_SETTING ); + MAX_CONTRAST_SETTING, NULL ); } static bool remote_invert(void) @@ -235,7 +235,7 @@ static bool contrast(void) return set_int( str(LANG_CONTRAST), "", UNIT_INT, &global_settings.contrast, lcd_set_contrast, 1, MIN_CONTRAST_SETTING, - MAX_CONTRAST_SETTING ); + MAX_CONTRAST_SETTING, NULL ); } #ifdef HAVE_LCD_BITMAP @@ -322,7 +322,7 @@ static bool peak_meter_fps_menu(void) { bool retval = false; retval = set_int( "Refresh rate", "/s", UNIT_PER_SEC, &peak_meter_fps, - NULL, 1, 5, 40); + NULL, 1, 5, 40, NULL); return retval; } #endif /* PM_DEBUG */ @@ -420,7 +420,7 @@ static bool peak_meter_release(void) { retval = set_int( str(LANG_PM_RELEASE), str(LANG_PM_UNITS_PER_READ), LANG_PM_UNITS_PER_READ, &global_settings.peak_meter_release, - NULL, 1, 1, 0x7e); + NULL, 1, 1, 0x7e, NULL); peak_meter_init_times(global_settings.peak_meter_release, global_settings.peak_meter_hold, @@ -488,7 +488,7 @@ static bool peak_meter_min(void) { int min = -global_settings.peak_meter_min; retval = set_int(str(LANG_PM_MIN), str(LANG_PM_DBFS), UNIT_DB, - &min, NULL, 1, -89, range_max); + &min, NULL, 1, -89, range_max, NULL); global_settings.peak_meter_min = - min; } @@ -499,7 +499,7 @@ static bool peak_meter_min(void) { retval = set_int(str(LANG_PM_MIN), "%", UNIT_PERCENT, &min, NULL, - 1, 0, global_settings.peak_meter_max - 1); + 1, 0, global_settings.peak_meter_max - 1, NULL); global_settings.peak_meter_min = (unsigned char)min; } @@ -522,7 +522,7 @@ static bool peak_meter_max(void) { int max = -global_settings.peak_meter_max;; retval = set_int(str(LANG_PM_MAX), str(LANG_PM_DBFS), UNIT_DB, - &max, NULL, 1, range_min, 0); + &max, NULL, 1, range_min, 0, NULL); global_settings.peak_meter_max = - max; @@ -534,7 +534,7 @@ static bool peak_meter_max(void) { retval = set_int(str(LANG_PM_MAX), "%", UNIT_PERCENT, &max, NULL, - 1, global_settings.peak_meter_min + 1, 100); + 1, global_settings.peak_meter_min + 1, 100, NULL); global_settings.peak_meter_max = (unsigned char)max; } @@ -765,7 +765,7 @@ static bool scroll_speed(void) { return set_int(str(LANG_SCROLL), "", UNIT_INT, &global_settings.scroll_speed, - &lcd_scroll_speed, 1, 0, 15 ); + &lcd_scroll_speed, 1, 0, 15, NULL ); } @@ -774,7 +774,7 @@ static bool scroll_delay(void) int dummy = global_settings.scroll_delay * (HZ/10); int rc = set_int(str(LANG_SCROLL_DELAY), "ms", UNIT_MS, &dummy, - &lcd_scroll_delay, 100, 0, 2500 ); + &lcd_scroll_delay, 100, 0, 2500, NULL ); global_settings.scroll_delay = dummy / (HZ/10); return rc; } @@ -784,7 +784,7 @@ static bool scroll_step(void) { return set_int(str(LANG_SCROLL_STEP_EXAMPLE), "pixels", UNIT_PIXEL, &global_settings.scroll_step, - &lcd_scroll_step, 1, 1, LCD_WIDTH ); + &lcd_scroll_step, 1, 1, LCD_WIDTH, NULL ); } #endif @@ -792,7 +792,7 @@ static bool bidir_limit(void) { return set_int(str(LANG_BIDIR_SCROLL), "%", UNIT_PERCENT, &global_settings.bidir_limit, - &lcd_bidir_scroll, 25, 0, 200 ); + &lcd_bidir_scroll, 25, 0, 200, NULL ); } #ifdef HAVE_LCD_CHARCELLS @@ -816,7 +816,7 @@ static bool jump_scroll_delay(void) int dummy = global_settings.jump_scroll_delay * (HZ/10); int rc = set_int(str(LANG_JUMP_SCROLL_DELAY), "ms", UNIT_MS, &dummy, - &lcd_jump_scroll_delay, 100, 0, 2500 ); + &lcd_jump_scroll_delay, 100, 0, 2500, NULL ); global_settings.jump_scroll_delay = dummy / (HZ/10); return rc; } @@ -831,7 +831,7 @@ static bool battery_capacity(void) return set_int(str(LANG_BATTERY_CAPACITY), "mAh", UNIT_MAH, &global_settings.battery_capacity, &set_battery_capacity, 50, BATTERY_CAPACITY_MIN, - BATTERY_CAPACITY_MAX ); + BATTERY_CAPACITY_MAX, NULL ); } #if BATTERY_TYPES_COUNT > 1 @@ -895,7 +895,7 @@ static bool spindown(void) { return set_int(str(LANG_SPINDOWN), "s", UNIT_SEC, &global_settings.disk_spindown, - ata_spindown, 1, 3, 254 ); + ata_spindown, 1, 3, 254, NULL ); } #ifdef HAVE_ATA_POWER_OFF @@ -921,14 +921,14 @@ static bool max_files_in_dir(void) { return set_int(str(LANG_MAX_FILES_IN_DIR), "", UNIT_INT, &global_settings.max_files_in_dir, - NULL, 50, 50, 10000 ); + NULL, 50, 50, 10000, NULL ); } static bool max_files_in_playlist(void) { return set_int(str(LANG_MAX_FILES_IN_PLAYLIST), "", UNIT_INT, &global_settings.max_files_in_playlist, - NULL, 1000, 1000, 20000 ); + NULL, 1000, 1000, 20000, NULL ); } #if CONFIG_HWCODEC == MASNONE @@ -957,7 +957,7 @@ static bool buffer_margin(void) { return set_int(str(LANG_MP3BUFFER_MARGIN), "s", UNIT_SEC, &global_settings.buffer_margin, - audio_set_buffer_margin, 1, 0, 7 ); + audio_set_buffer_margin, 1, 0, 7, NULL ); } #endif @@ -1232,6 +1232,25 @@ static bool replaygain_noclip(void) return result; } +void replaygain_preamp_format(char* buffer, int buffer_size, int value, + const char* unit) +{ + int v = abs(value); + + snprintf(buffer, buffer_size, "%s%d.%d %s", value < 0 ? "-" : "", + v / 10, v % 10, unit); +} + +static bool replaygain_preamp(void) +{ + bool result = set_int(str(LANG_REPLAYGAIN_PREAMP), str(LANG_UNIT_DB), + UNIT_DB, &global_settings.replaygain_preamp, NULL, 1, -120, 120, + replaygain_preamp_format); + + dsp_set_replaygain(true); + return result; +} + static bool replaygain_settings_menu(void) { int m; @@ -1241,6 +1260,7 @@ static bool replaygain_settings_menu(void) { ID2P(LANG_REPLAYGAIN_ENABLE), replaygain }, { ID2P(LANG_REPLAYGAIN_NOCLIP), replaygain_noclip }, { ID2P(LANG_REPLAYGAIN_MODE), replaygain_mode }, + { ID2P(LANG_REPLAYGAIN_PREAMP), replaygain_preamp }, }; m=menu_init( items, sizeof(items) / sizeof(*items), NULL, diff --git a/apps/sound_menu.c b/apps/sound_menu.c index 1b19593b6f..0c298b091f 100644 --- a/apps/sound_menu.c +++ b/apps/sound_menu.c @@ -292,7 +292,7 @@ static bool recquality(void) { return set_int(str(LANG_RECORDING_QUALITY), "", UNIT_INT, &global_settings.rec_quality, - NULL, 1, 0, 7 ); + NULL, 1, 0, 7, NULL ); } static bool receditable(void) diff --git a/firmware/export/replaygain.h b/firmware/export/replaygain.h index e96a7f907a..c29d4b6921 100644 --- a/firmware/export/replaygain.h +++ b/firmware/export/replaygain.h @@ -22,6 +22,7 @@ #include "id3.h" +long get_replaygain_int(long int_gain); long get_replaygain(const char* str); long get_replaypeak(const char* str); long parse_replaygain(const char* key, const char* value, diff --git a/firmware/replaygain.c b/firmware/replaygain.c index 542eee6101..a21336013b 100644 --- a/firmware/replaygain.c +++ b/firmware/replaygain.c @@ -305,6 +305,18 @@ static long convert_gain(long gain) return gain; } +long get_replaygain_int(long int_gain) +{ + long gain = 0; + + if (int_gain) + { + gain = convert_gain(int_gain * FP_ONE / 100); + } + + return gain; +} + long get_replaygain(const char* str) { long gain = 0; -- cgit v1.2.3