Index: apps/settings.c
===================================================================
RCS file: /cvsroot/rockbox/apps/settings.c,v
retrieving revision 1.387
diff -u -r1.387 settings.c
--- apps/settings.c 22 May 2006 16:40:40 -0000 1.387
+++ apps/settings.c 26 May 2006 22:14:01 -0000
@@ -563,6 +563,13 @@
{1, S_O(warnon_erase_dynplaylist), false,
"warn when erasing dynamic playlist", off_on },
+#ifdef HAVE_UDA1380
+ {4, S_O(rec_agc_preset_mic), 1, "agc mic preset", NULL}, /* 0...5 */
+ {4, S_O(rec_agc_preset_line), 1, "agc line preset", NULL}, /* 0...5 */
+ {8|SIGNED, S_O(rec_agc_maxgain_mic), 104, "agc maximum mic gain", NULL},
+ {8|SIGNED, S_O(rec_agc_maxgain_line), 96, "agc maximum line gain", NULL},
+ {3, S_O(rec_agc_cliptime), 1, "agc cliptime", "0.2s,0.4s,0.6s,0.8,1s"},
+#endif
/* If values are just added to the end, no need to bump the version. */
/* new stuff to be added at the end */
Index: apps/settings.h
===================================================================
RCS file: /cvsroot/rockbox/apps/settings.h,v
retrieving revision 1.219
diff -u -r1.219 settings.h
--- apps/settings.h 25 May 2006 13:34:51 -0000 1.219
+++ apps/settings.h 26 May 2006 22:14:01 -0000
@@ -254,6 +254,31 @@
int rec_stop_gap; /* index of trig_durations */
int rec_trigger_mode; /* see TRIG_MODE_XXX constants */
+#ifdef HAVE_UDA1380
+ int rec_agc_preset_mic; /* AGC mic preset modes:
+ 0 = Off
+ 1 = Safety (clip)
+ 2 = Live (slow)
+ 3 = DJ-Set (slow)
+ 4 = Medium
+ 5 = Voice (fast) */
+ int rec_agc_preset_line; /* AGC line-in preset modes:
+ 0 = Off
+ 1 = Safety (clip)
+ 2 = Live (slow)
+ 3 = DJ-Set (slow)
+ 4 = Medium
+ 5 = Voice (fast) */
+ int rec_agc_maxgain_mic; /* AGC maximum mic gain */
+ int rec_agc_maxgain_line; /* AGC maximum line-in gain */
+ int rec_agc_cliptime; /* 0.2, 0.4, 0.6, 0.8, 1s */
+#endif
+
+#if defined(HAVE_LCD_BITMAP) && (LCD_WIDTH > 111)
+ int rec_histogram_mode; /* small lin/log /w balance, big lin/log */
+ int rec_histogram_interval; /* interval: 0.5s, 1s, 2s, 4s */
+#endif
+
/* device settings */
int contrast; /* lcd contrast: 0-63 0=low 63=high */
Index: apps/sound_menu.c
===================================================================
RCS file: /cvsroot/rockbox/apps/sound_menu.c,v
retrieving revision 1.103
diff -u -r1.103 sound_menu.c
--- apps/sound_menu.c 11 May 2006 22:55:24 -0000 1.103
+++ apps/sound_menu.c 26 May 2006 22:14:03 -0000
@@ -450,6 +450,42 @@
}
#endif /*CONFIG_BACKLIGHT */
+#ifdef HAVE_UDA1380
+static bool agc_preset(void)
+{
+ static const struct opt_items names[] = {
+ { STR(LANG_OFF) },
+ { STR(LANG_AGC_SAFETY) },
+ { STR(LANG_AGC_LIVE) },
+ { STR(LANG_AGC_DJSET) },
+ { STR(LANG_AGC_MEDIUM) },
+ { STR(LANG_AGC_VOICE) },
+ };
+ if (global_settings.rec_source)
+ return set_option(str(LANG_RECORD_AGC_PRESET),
+ &global_settings.rec_agc_preset_line,
+ INT, names, 6, NULL );
+ else
+ return set_option(str(LANG_RECORD_AGC_PRESET),
+ &global_settings.rec_agc_preset_mic,
+ INT, names, 6, NULL );
+}
+
+static bool agc_cliptime(void)
+{
+ static const struct opt_items names[] = {
+ { "200ms", TALK_ID(200, UNIT_MS) },
+ { "400ms", TALK_ID(400, UNIT_MS) },
+ { "600ms", TALK_ID(600, UNIT_MS) },
+ { "800ms", TALK_ID(800, UNIT_MS) },
+ { "1s", TALK_ID(1, UNIT_SEC) }
+ };
+ return set_option(str(LANG_RECORD_AGC_CLIPTIME),
+ &global_settings.rec_agc_cliptime,
+ INT, names, 5, NULL );
+}
+#endif /* HAVE_UDA1380 */
+
#endif /* HAVE_RECORDING */
static bool chanconf(void)
@@ -941,6 +977,12 @@
items[i].desc = ID2P(LANG_RECORD_TRIGGER);
items[i++].function = rectrigger;
#endif
+#ifdef HAVE_UDA1380
+ items[i].desc = ID2P(LANG_RECORD_AGC_PRESET);
+ items[i++].function = agc_preset;
+ items[i].desc = ID2P(LANG_RECORD_AGC_CLIPTIME);
+ items[i++].function = agc_cliptime;
+#endif
m=menu_init( items, i, NULL, NULL, NULL, NULL);
result = menu_run(m);
Index: apps/lang/english.lang
===================================================================
RCS file: /cvsroot/rockbox/apps/lang/english.lang,v
retrieving revision 1.252
diff -u -r1.252 english.lang
--- apps/lang/english.lang 25 May 2006 13:34:51 -0000 1.252
+++ apps/lang/english.lang 26 May 2006 22:14:08 -0000
@@ -8502,6 +8502,123 @@
+ id: LANG_RECORD_AGC_PRESET
+ desc: automatic gain control in record settings
+
+ *: "Automatic Gain Control"
+
+
+ *: "Automatic Gain Control"
+
+
+ *: "pixels"
+
+
+
+ id: LANG_AGC_SAFETY
+ desc: AGC preset
+
+ *: "Safety (clip)"
+
+
+ *: "Safety (clip)"
+
+
+ *: "pixels"
+
+
+
+ id: LANG_AGC_LIVE
+ desc: AGC preset
+
+ *: "Live (slow)"
+
+
+ *: "Live (slow)"
+
+
+ *: "pixels"
+
+
+
+ id: LANG_AGC_DJSET
+ desc: AGC preset
+
+ *: "DJ-Set (slow)"
+
+
+ *: "DJ-Set (slow)"
+
+
+ *: "pixels"
+
+
+
+ id: LANG_AGC_MEDIUM
+ desc: AGC preset
+
+ *: "Medium"
+
+
+ *: "Medium"
+
+
+ *: "pixels"
+
+
+
+ id: LANG_AGC_VOICE
+ desc: AGC preset
+
+ *: "Voice (fast)"
+
+
+ *: "Voice (fast)"
+
+
+ *: "pixels"
+
+
+
+ id: LANG_RECORD_AGC_CLIPTIME
+ desc: in record settings
+
+ *: "AGC clip time"
+
+
+ *: "AGC clip time"
+
+
+ *: "pixels"
+
+
+
+ id: LANG_RECORDING_AGC_PRESET
+ desc: automatic gain control in recording screen
+
+ *: "AGC"
+
+
+ *: "AGC"
+
+
+ *: "pixels"
+
+
+
+ id: LANG_RECORDING_AGC_MAXGAIN
+ desc: AGC maximum gain in recording screen
+
+ *: "AGC max. gain"
+
+
+ *: "AGC max. gain"
+
+
+ *: "pixels"
+
+
+
id: LANG_INVALID_FILENAME
desc: "invalid filename entered" error message
user:
Index: apps/recorder/peakmeter.c
===================================================================
RCS file: /cvsroot/rockbox/apps/recorder/peakmeter.c,v
retrieving revision 1.34
diff -u -r1.34 peakmeter.c
--- apps/recorder/peakmeter.c 3 Apr 2006 08:20:20 -0000 1.34
+++ apps/recorder/peakmeter.c 26 May 2006 22:14:10 -0000
@@ -62,6 +62,8 @@
static int pm_cur_right;
static int pm_max_left; /* maximum values between peak meter draws */
static int pm_max_right;
+static int pm_peakhold_left; /* max. peak values between peakhold calls */
+static int pm_peakhold_right; /* used for AGC and histogram display */
/* Clip hold */
static bool pm_clip_left = false; /* when true a clip has occurred */
@@ -139,17 +141,17 @@
/* precalculated peak values that represent magical
dBfs values. Used to draw the scale */
static const int db_scale_src_values[DB_SCALE_SRC_VALUES_SIZE] = {
- 32752, /* 0 db */
- 22784, /* - 3 db */
- 14256, /* - 6 db */
- 11752, /* - 9 db */
- 9256, /* -12 db */
- 4256, /* -18 db */
- 2186, /* -24 db */
- 1186, /* -30 db */
- 373, /* -40 db */
- 102, /* -50 db */
- 33, /* -60 db */
+ 32736, /* 0 db */
+ 22752, /* - 3 db */
+ 16640, /* - 6 db */
+ 11648, /* - 9 db */
+ 8320, /* -12 db */
+ 4364, /* -18 db */
+ 2064, /* -24 db */
+ 1194, /* -30 db */
+ 363, /* -40 db */
+ 101, /* -50 db */
+ 34, /* -60 db */
0, /* -inf */
};
@@ -160,17 +162,19 @@
* @param int sample - The input value
* Make sure that 0 <= value < SAMPLE_RANGE
*
- * @return int - The 2 digit fixed comma result of the euation
+ * @return int - The 2 digit fixed point result of the euation
* 20 * log (sample / SAMPLE_RANGE) + 90
- * Output range is 0-8961 (that is 0,0 - 89,6 dB).
+ * Output range is 0-9000 (that is 0.0 - 90.0 dB).
* Normally 0dB is full scale, here it is shifted +90dB.
* The calculation is based on the results of a linear
* approximation tool written specifically for this problem
- * by Andreas Zwirtes (radhard@gmx.de). The result hat an
+ * by Andreas Zwirtes (radhard@gmx.de). The result has an
* accurracy of better than 2%. It is highly runtime optimized,
* the cascading if-clauses do an successive approximation on
* the input value. This avoids big lookup-tables and
* for-loops.
+ * Improved by Jvo Studer for errors < 0.2dB for critical
+ * range of -12dB to 0dB (78.0 to 90.0dB).
*/
int calc_db (int isample)
@@ -180,81 +184,69 @@
long m;
int istart;
- /* Range 1-4 */
- if (isample < 119) {
+ if (isample < 2308) { /* Range 1-5 */
- /* Range 1-2 */
- if (isample < 5) {
+ if (isample < 115) { /* Range 1-3 */
- /* Range 1 */
- if (isample < 1) {
- istart = 0;
- n = 0;
- m = 5900;
- }
+ if (isample < 24) {
- /* Range 2 */
- else {
- istart = 1;
- n = 59;
+ if (isample < 5) {
+ istart = 1; /* Range 1 */
+ n = 98;
m = 34950;
}
- }
-
- /* Range 3-4 */
else {
-
- /* Range 3 */
- if (isample < 24) {
- istart = 5;
- n = 1457;
+ istart = 5; /* Range 2 */
+ n = 1496;
m = 7168;
}
+ }
+ else {
+ istart = 24; /* Range 3 */
+ n = 2858;
+ m = 1498;
+ }
+ }
+ else { /* Range 4-5 */
- /* Range 4 */
+ if (isample < 534) {
+ istart = 114; /* Range 4 */
+ n = 4207;
+ m = 319;
+ }
else {
- istart = 24;
- n = 2819;
- m = 1464;
+ istart = 588; /* Range 5 */
+ n = 5583;
+ m = 69;
}
}
}
- /* Range 5-8 */
- else {
+ else { /* Range 6-9 */
- /* Range 5-6 */
- if (isample < 2918) {
+ if (isample < 12932) {
- /* Range 5 */
- if (isample < 592) {
- istart = 119;
- n = 4210;
- m = 295;
+ if (isample < 6394) {
+ istart = 2608; /* Range 6 */
+ n = 6832;
+ m = 21;
}
-
- /* Range 6 */
else {
- istart = 592;
- n = 5605;
- m = 60;
+ istart = 7000; /* Range 7 */
+ n = 7682;
+ m = 9;
}
}
-
- /* Range 7-8 */
else {
- /* Range 7 */
- if (isample < 15352) {
- istart = 2918;
- n = 7001;
- m = 12;
+ if (isample < 22450) {
+ istart = 13000; /* Range 8 */
+ n = 8219;
+ m = 5;
}
-
- /* Range 8 */
else {
- istart = 15352;
- n = 8439;
+ istart = 22636; /* Range 9 */
+ n = 8697;
m = 3;
}
}
@@ -726,6 +718,9 @@
by peak_meter_peek since the last call of peak_meter_read_l */
int retval = pm_max_left;
+ /* store max peak value for peak_meter_get_peakhold_x readout */
+ pm_peakhold_left = MAX(pm_max_left, pm_peakhold_left);
+
#ifdef PM_DEBUG
peek_calls = 0;
#endif
@@ -747,6 +742,9 @@
by peak_meter_peek since the last call of peak_meter_read_r */
int retval = pm_max_right;
+ /* store max peak value for peak_meter_get_peakhold_x readout */
+ pm_peakhold_right = MAX(pm_max_right, pm_peakhold_right);
+
#ifdef PM_DEBUG
peek_calls = 0;
#endif
@@ -757,6 +755,21 @@
}
/**
+ * Reads out the current peak-hold values since the last call.
+ * This is used by the histogram feature in the recording screen.
+ * Values are in the range 0 <= peak_x < MAX_PEAK. MAX_PEAK is typ 32767.
+ */
+extern void peak_meter_get_peakhold(int *peak_left, int *peak_right)
+{
+ if (peak_left)
+ *peak_left = pm_peakhold_left;
+ if (peak_right)
+ *peak_right = pm_peakhold_right;
+ pm_peakhold_left = 0;
+ pm_peakhold_right = 0;
+}
+
+/**
* Reset the detected clips. This method is for
* use by the user interface.
* @param int unused - This parameter was added to
Index: apps/recorder/peakmeter.h
===================================================================
RCS file: /cvsroot/rockbox/apps/recorder/peakmeter.h,v
retrieving revision 1.7
diff -u -r1.7 peakmeter.h
--- apps/recorder/peakmeter.h 25 Mar 2006 13:35:31 -0000 1.7
+++ apps/recorder/peakmeter.h 26 May 2006 22:14:10 -0000
@@ -34,6 +34,7 @@
extern void peak_meter_peek(void);
extern void peak_meter_init_range( bool dbfs, int range_min, int range_max);
extern void peak_meter_init_times(int release, int hold, int clip_hold);
+extern void peak_meter_get_peakhold(int *peak_left, int *peak_right);
extern void peak_meter_set_min(int newmin);
extern int peak_meter_get_min(void);
Index: apps/recorder/recording.c
===================================================================
RCS file: /cvsroot/rockbox/apps/recorder/recording.c,v
retrieving revision 1.111
diff -u -r1.111 recording.c
--- apps/recorder/recording.c 14 May 2006 23:34:24 -0000 1.111
+++ apps/recorder/recording.c 26 May 2006 22:14:12 -0000
@@ -139,6 +139,10 @@
#define MAX_FILE_SIZE 0x7FF00000 /* 2 GB - 1 MB */
+#ifdef HAVE_UDA1380
+#define HAVE_AGC /* only for codecs with 0.5dB gain resolution */
+#endif
+
const char* const freq_str[6] =
{
"44.1kHz",
@@ -149,6 +153,64 @@
"16kHz"
};
+/* Timing counters:
+ * peak_time is incremented every 0.2s, every 2nd run of record screen loop.
+ * hist_time is incremented every 0.5s, display update.
+ * peak_time is the counter of the peak hold read and agc process,
+ * overflow every 13 years 8-)
+ */
+static long peak_time = 0;
+static long hist_time = 0;
+
+static short peak_valid_mem[4];
+#define BAL_MEM_SIZE 24
+static short balance_mem[BAL_MEM_SIZE];
+
+/* Automatic Gain Control */
+#ifdef HAVE_AGC
+#define AGC_MODE_SIZE 5
+static char* agc_preset_str[] =
+{ "Off", "S", "L", "D", "M", "V" };
+/* "Off",
+ "Safety (clip)",
+ "Live (slow)",
+ "DJ-Set (slow)",
+ "Medium",
+ "Voice (fast)" */
+#define AGC_CLIP 32766
+#define AGC_PEAK 29883 /* fast gain reduction threshold -0.8dB */
+#define AGC_HIGH 27254 /* accelerated gain reduction threshold -1.6dB */
+#define AGC_IMG 823 /* threshold for balance control -32dB */
+/* autogain high level thresholds (-3dB, -7dB, -4dB, -5dB, -5dB) */
+const short agc_th_hi[AGC_MODE_SIZE] =
+{ 23197, 14637, 21156, 18428, 18426 };
+/* autogain low level thresholds (-14dB, -11dB, -6dB, -7dB, -8dB) */
+const short agc_th_lo[AGC_MODE_SIZE] =
+{ 6538, 9235, 16422, 14636, 13045 };
+/* autogain threshold times [1/5s] or [200ms] */
+const short agc_tdrop[AGC_MODE_SIZE] =
+{ 900, 225, 150, 60, 8 };
+const short agc_trise[AGC_MODE_SIZE] =
+{ 9000, 750, 400, 150, 20 };
+const short agc_tbal[AGC_MODE_SIZE] =
+{ 4500, 500, 300, 100, 15 };
+/* AGC operation */
+static bool agc_enable = true;
+static short agc_preset;
+/* AGC levels */
+static int agc_left = 0;
+static int agc_right = 0;
+/* AGC time since high target volume was exceeded */
+static short agc_droptime = 0;
+/* AGC time since volume fallen below low target */
+static short agc_risetime = 0;
+/* AGC balance time exceeding +/- 0.7dB */
+static short agc_baltime = 0;
+/* AGC maximum gain */
+static short agc_maxgain;
+#endif /* HAVE_AGC */
+
+
static void set_gain(void)
{
if(global_settings.rec_source == SOURCE_MIC)
@@ -164,6 +226,229 @@
}
}
+/* Read peak meter values & calculate balance.
+ * Returns validity of peak values.
+ * Used for automatic gain control and history diagram.
+ */
+bool read_peak_levels(int *peak_l, int *peak_r, int *balance)
+{
+ peak_meter_get_peakhold(peak_l, peak_r);
+ peak_valid_mem[peak_time % 3] = *peak_l;
+ if (((peak_valid_mem[0] == peak_valid_mem[1]) &&
+ (peak_valid_mem[1] == peak_valid_mem[2])) &&
+ ((*peak_l < 32767)
+#ifndef SIMULATOR
+ || ata_disk_is_active()
+#endif
+ ))
+ return false;
+
+ if (*peak_r > *peak_l)
+ balance_mem[peak_time % BAL_MEM_SIZE] =
+ MIN((10000 * *peak_r) / *peak_l - 10000, 15118);
+ else
+ balance_mem[peak_time % BAL_MEM_SIZE] =
+ MAX(10000 - (10000 * *peak_l) / *peak_r, -15118);
+ *balance = 0;
+ int i;
+ for (i = 0; i < BAL_MEM_SIZE; i++)
+ *balance += balance_mem[i];
+ *balance = *balance / BAL_MEM_SIZE;
+
+ return true;
+}
+
+#ifdef HAVE_AGC
+/* AGC helper function to check if maximum gain is reached */
+bool agc_gain_is_max(bool left, bool right)
+{
+ /* range -128...+108 [0.5dB] */
+ short gain_current_l;
+ short gain_current_r;
+
+ if (agc_preset == 0)
+ return false;
+
+ if (global_settings.rec_source == SOURCE_LINE)
+ {
+ gain_current_l = global_settings.rec_left_gain;
+ gain_current_r = global_settings.rec_right_gain;
+ } else
+ {
+ gain_current_l = global_settings.rec_mic_gain;
+ gain_current_r = global_settings.rec_mic_gain;
+ }
+
+ return ((left && (gain_current_l >= agc_maxgain)) ||
+ (right && (gain_current_r >= agc_maxgain)));
+}
+
+void change_recording_gain(bool increment, bool left, bool right)
+{
+ int factor = (increment ? 1 : -1);
+
+ if (global_settings.rec_source == SOURCE_LINE)
+ {
+ if(left) global_settings.rec_left_gain += factor;
+ if (right) global_settings.rec_right_gain += factor;
+ }
+ else
+ {
+ global_settings.rec_mic_gain += factor;
+ }
+}
+
+/*
+ * Handle automatic gain control (AGC).
+ * Change recording gain if peak_x levels are above or below
+ * target volume for specified timeouts.
+ */
+void auto_gain_control(int *peak_l, int *peak_r, int *balance)
+{
+ int agc_mono;
+ short agc_mode;
+ bool increment;
+
+ if (*peak_l > agc_left)
+ agc_left = *peak_l;
+ else
+ agc_left -= (agc_left - *peak_l + 3) >> 2;
+ if (*peak_r > agc_right)
+ agc_right = *peak_r;
+ else
+ agc_right -= (agc_right - *peak_r + 3) >> 2;
+ agc_mono = (agc_left + agc_right) / 2;
+
+ agc_mode = abs(agc_preset) - 1;
+ if (agc_mode < 0) {
+ agc_enable = false;
+ return;
+ }
+
+ /* Automatic balance control */
+ if ((agc_left > AGC_IMG) && (agc_right > AGC_IMG))
+ {
+ if (*balance < -556)
+ {
+ if (*balance > -900)
+ agc_baltime -= !(peak_time % 4); /* 0.47 - 0.75dB */
+ else if (*balance > -4125)
+ agc_baltime--; /* 0.75 - 3.00dB */
+ else if (*balance > -7579)
+ agc_baltime -= 2; /* 3.00 - 4.90dB */
+ else
+ agc_baltime -= !(peak_time % 8); /* 4.90 - inf dB */
+ if (agc_baltime > 0)
+ agc_baltime -= (peak_time % 2);
+ }
+ else if (*balance > 556)
+ {
+ if (*balance < 900)
+ agc_baltime += !(peak_time % 4);
+ else if (*balance < 4125)
+ agc_baltime++;
+ else if (*balance < 7579)
+ agc_baltime += 2;
+ else
+ agc_baltime += !(peak_time % 8);
+ if (agc_baltime < 0)
+ agc_baltime += (peak_time % 2);
+ }
+
+ if ((*balance * agc_baltime) < 0)
+ {
+ if (*balance < 0)
+ agc_baltime -= peak_time % 2;
+ else
+ agc_baltime += peak_time % 2;
+ }
+
+ increment = ((agc_risetime / 2) > agc_droptime);
+
+ if (agc_baltime < -agc_tbal[agc_mode])
+ {
+ if (!increment || !agc_gain_is_max(!increment, increment)) {
+ change_recording_gain(increment, !increment, increment);
+ set_gain();
+ }
+ agc_baltime = 0;
+ }
+ else if (agc_baltime > +agc_tbal[agc_mode])
+ {
+ if (!increment || !agc_gain_is_max(increment, !increment)) {
+ change_recording_gain(increment, increment, !increment);
+ set_gain();
+ }
+ agc_baltime = 0;
+ }
+ }
+ else if (!(hist_time % 4))
+ {
+ if (agc_baltime < 0)
+ agc_baltime++;
+ else
+ agc_baltime--;
+ }
+
+ /* Automatic gain control */
+ if ((agc_left > agc_th_hi[agc_mode]) || (agc_right > agc_th_hi[agc_mode]))
+ {
+ if ((agc_left > AGC_CLIP) || (agc_right > AGC_CLIP))
+ agc_droptime += agc_tdrop[agc_mode] /
+ (global_settings.rec_agc_cliptime + 1);
+ if (agc_left > AGC_HIGH) {
+ agc_droptime++;
+ agc_risetime=0;
+ if (agc_left > AGC_PEAK)
+ agc_droptime += 2;
+ }
+ if (agc_right > AGC_HIGH) {
+ agc_droptime++;
+ agc_risetime=0;
+ if (agc_right > AGC_PEAK)
+ agc_droptime += 2;
+ }
+ if (agc_mono > agc_th_hi[agc_mode])
+ agc_droptime++;
+ else
+ agc_droptime += !(peak_time % 2);
+
+ if (agc_droptime >= agc_tdrop[agc_mode])
+ {
+ change_recording_gain(false, true, true);
+ agc_droptime = 0;
+ agc_risetime = 0;
+ set_gain();
+ }
+ agc_risetime = MAX(agc_risetime - 1, 0);
+ }
+ else if (agc_mono < agc_th_lo[agc_mode])
+ {
+ if (agc_mono < (agc_th_lo[agc_mode] / 8))
+ agc_risetime += !(peak_time % 5);
+ else if (agc_mono < (agc_th_lo[agc_mode] / 2))
+ agc_risetime += 2;
+ else
+ agc_risetime++;
+
+ if (agc_risetime >= agc_trise[agc_mode]) {
+ if (!agc_gain_is_max(true, true)) {
+ change_recording_gain(true, true, true);
+ set_gain();
+ }
+ agc_risetime = 0;
+ agc_droptime = 0;
+ }
+ agc_droptime = MAX(agc_droptime - 1, 0);
+ }
+ else if (!(peak_time % 6)) /* on target level every 1.2 sec */
+ {
+ agc_risetime = MAX(agc_risetime - 1, 0);
+ agc_droptime = MAX(agc_droptime - 1, 0);
+ }
+}
+#endif /* HAVE_AGC */
+
static const char* const fmtstr[] =
{
"%c%d %s", /* no decimals */
@@ -207,6 +492,16 @@
if(cursor < 0)
cursor = 0;
+#ifdef HAVE_AGC
+ if (global_settings.rec_source == SOURCE_MIC)
+ {
+ if(cursor == 2)
+ cursor = 4;
+ else if(cursor == 3)
+ cursor = 1;
+ }
+ max_cursor = 5;
+#else
switch(global_settings.rec_source)
{
case SOURCE_MIC:
@@ -219,6 +514,7 @@
max_cursor = 0;
break;
}
+#endif /* HAVE_AGC */
if(cursor > max_cursor)
cursor = max_cursor;
@@ -333,6 +629,11 @@
bool led_state = false;
int led_countdown = 2;
#endif
+ bool peak_read = false;
+ bool peak_valid = false;
+ int peak_l, peak_r;
+ int balance = 0;
+ int line;
int i;
const unsigned char *byte_units[] = {
@@ -365,6 +666,7 @@
peak_meter_playback(true);
#endif
peak_meter_enabled = true;
+ peak_meter_get_peakhold(&peak_l, &peak_r);
#if CONFIG_CODEC != SWCODEC
if (global_settings.rec_prerecord_time)
@@ -387,6 +689,25 @@
settings_apply_trigger();
+#ifdef HAVE_AGC
+ agc_preset_str[0] = str(LANG_OFF);
+ agc_preset_str[1] = str(LANG_AGC_SAFETY);
+ agc_preset_str[2] = str(LANG_AGC_LIVE);
+ agc_preset_str[3] = str(LANG_AGC_DJSET);
+ agc_preset_str[4] = str(LANG_AGC_MEDIUM);
+ agc_preset_str[5] = str(LANG_AGC_VOICE);
+ if (global_settings.rec_source == SOURCE_MIC) {
+ agc_preset = global_settings.rec_agc_preset_mic;
+ agc_maxgain = global_settings.rec_agc_maxgain_mic;
+ }
+ else {
+ agc_preset = global_settings.rec_agc_preset_line;
+ agc_maxgain = global_settings.rec_agc_maxgain_line;
+ }
+#endif
+
+ gui_syncsplash(1, true, "%s...", str(LANG_RECORDING));
+
FOR_NB_SCREENS(i)
{
screens[i].setfont(FONT_SYSFIXED);
@@ -397,6 +718,7 @@
if(rec_create_directory() > 0)
have_recorded = true;
+
while(!done)
{
#if CONFIG_CODEC == SWCODEC
@@ -610,6 +932,26 @@
sound_max(SOUND_RIGHT_GAIN))
global_settings.rec_right_gain++;
break;
+#ifdef HAVE_AGC
+ case 4:
+ agc_preset = MIN(agc_preset + 1, AGC_MODE_SIZE);
+ agc_enable = (agc_preset != 0);
+ if (global_settings.rec_source == SOURCE_MIC) {
+ global_settings.rec_agc_preset_mic = agc_preset;
+ agc_maxgain = global_settings.rec_agc_maxgain_mic;
+ } else {
+ global_settings.rec_agc_preset_line = agc_preset;
+ agc_maxgain = global_settings.rec_agc_maxgain_line;
+ }
+ break;
+ case 5:
+ agc_maxgain = MIN(agc_maxgain + 1, 96);
+ if (global_settings.rec_source == SOURCE_MIC)
+ global_settings.rec_agc_maxgain_mic = agc_maxgain;
+ else
+ global_settings.rec_agc_maxgain_line = agc_maxgain;
+ break;
+#endif
}
set_gain();
update_countdown = 1; /* Update immediately */
@@ -656,6 +998,26 @@
sound_min(SOUND_RIGHT_GAIN))
global_settings.rec_right_gain--;
break;
+#ifdef HAVE_AGC
+ case 4:
+ agc_preset = MAX(agc_preset - 1, 0);
+ agc_enable = (agc_preset != 0);
+ if (global_settings.rec_source == SOURCE_MIC) {
+ global_settings.rec_agc_preset_mic = agc_preset;
+ agc_maxgain = global_settings.rec_agc_maxgain_mic;
+ } else {
+ global_settings.rec_agc_preset_line = agc_preset;
+ agc_maxgain = global_settings.rec_agc_maxgain_line;
+ }
+ break;
+ case 5:
+ agc_maxgain = MAX(agc_maxgain - 1, -24);
+ if (global_settings.rec_source == SOURCE_MIC)
+ global_settings.rec_agc_maxgain_mic = agc_maxgain;
+ else
+ global_settings.rec_agc_maxgain_line = agc_maxgain;
+ break;
+#endif
}
set_gain();
update_countdown = 1; /* Update immediately */
@@ -689,6 +1051,16 @@
global_settings.rec_channels,
global_settings.rec_editable,
global_settings.rec_prerecord_time);
+#ifdef HAVE_AGC
+ if (global_settings.rec_source == SOURCE_MIC) {
+ agc_preset = global_settings.rec_agc_preset_mic;
+ agc_maxgain = global_settings.rec_agc_maxgain_mic;
+ }
+ else {
+ agc_preset = global_settings.rec_agc_preset_line;
+ agc_maxgain = global_settings.rec_agc_maxgain_line;
+ }
+#endif
adjust_cursor();
set_gain();
@@ -766,6 +1138,18 @@
if (button != BUTTON_NONE)
lastbutton = button;
+ peak_read = !peak_read;
+ if (peak_read) { /* every 2nd run of loop */
+ peak_time++;
+ peak_valid = read_peak_levels(&peak_l, &peak_r, &balance);
+ }
+
+#ifdef HAVE_AGC
+ /* Handle AGC every 200ms when enabled and peak data is valid */
+ if (peak_read && agc_enable && peak_valid)
+ auto_gain_control(&peak_l, &peak_r, &balance);
+#endif
+
FOR_NB_SCREENS(i)
screens[i].setfont(FONT_SYSFIXED);
@@ -911,7 +1295,71 @@
}
}
- if(!global_settings.invert_cursor){
+#ifdef HAVE_AGC
+ /************** AGC test info ******************
+ snprintf(buf, 32, "D:%d U:%d",
+ (agc_droptime+2)/5, (agc_risetime+2)/5);
+ lcd_putsxy(1, LCD_HEIGHT - 8, buf);
+ snprintf(buf, 32, "B:%d",
+ (agc_baltime+2)/5);
+ lcd_putsxy(LCD_WIDTH/2 + 3, LCD_HEIGHT - 8, buf);
+ ***********************************************/
+
+ if (cursor == 5)
+ snprintf(buf, 32, "%s: %s",
+ str(LANG_RECORDING_AGC_MAXGAIN),
+ fmt_gain(SOUND_LEFT_GAIN,
+ agc_maxgain, buf2, sizeof(buf2)));
+ else if (agc_preset == 0)
+ snprintf(buf, 32, "%s: %s",
+ str(LANG_RECORDING_AGC_PRESET),
+ agc_preset_str[agc_preset]);
+ else if (global_settings.rec_source == SOURCE_MIC)
+ snprintf(buf, 32, "%s: %s%s",
+ str(LANG_RECORDING_AGC_PRESET),
+ agc_preset_str[agc_preset],
+ fmt_gain(SOUND_LEFT_GAIN,
+ agc_maxgain -
+ global_settings.rec_mic_gain,
+ buf2, sizeof(buf2)));
+ else
+ snprintf(buf, 32, "%s: %s%s",
+ str(LANG_RECORDING_AGC_PRESET),
+ agc_preset_str[agc_preset],
+ fmt_gain(SOUND_LEFT_GAIN,
+ agc_maxgain -
+ (global_settings.rec_left_gain +
+ global_settings.rec_right_gain)/2,
+ buf2, sizeof(buf2)));
+ line = (global_settings.rec_source == SOURCE_MIC)? 6 : 7;
+ if(global_settings.invert_cursor && ((cursor==4) || (cursor==5)))
+ {
+ screens[0].puts_style_offset(0, line, buf, STYLE_INVERT,0);
+#ifdef HAVE_REMOTE_LCD
+ screens[1].puts_style_offset(0, 6, buf, STYLE_INVERT,0);
+#endif
+ }
+ else
+ {
+ FOR_NB_SCREENS(i)
+ screens[i].puts(0, line, buf);
+ }
+
+ if (global_settings.rec_source == SOURCE_MIC)
+ {
+ if(agc_maxgain < (global_settings.rec_mic_gain))
+ change_recording_gain(false, true, true);
+ }
+ else
+ {
+ if(agc_maxgain < (global_settings.rec_left_gain))
+ change_recording_gain(false, true, false);
+ if(agc_maxgain < (global_settings.rec_right_gain))
+ change_recording_gain(false, false, true);
+ }
+#endif /* HAVE_AGC */
+
+ if(!global_settings.invert_cursor) {
switch(cursor)
{
case 1:
@@ -936,6 +1384,15 @@
screen_put_cursorxy(&screens[i], 0,
4+PM_HEIGHT, true);
break;
+#ifdef HAVE_AGC
+ case 4:
+ case 5:
+ screen_put_cursorxy(&screens[0], 0, line, true);
+#ifdef HAVE_REMOTE_LCD
+ screen_put_cursorxy(&screens[1], 0, 6, true);
+#endif
+ break;
+#endif /* HAVE_AGC */
default:
FOR_NB_SCREENS(i)
screen_put_cursorxy(&screens[i], 0,
@@ -957,11 +1414,15 @@
freq_str[global_settings.rec_frequency],
global_settings.rec_channels ?
str(LANG_CHANNEL_MONO) : str(LANG_CHANNEL_STEREO));
+
+ line = (global_settings.rec_source == SOURCE_MIC)? 5 : 6;
FOR_NB_SCREENS(i)
- screens[i].puts(0, 5+PM_HEIGHT, buf);
+ screens[i].puts(0, line+PM_HEIGHT, buf);
gui_syncstatusbar_draw(&statusbars, true);
+ hist_time++;
+
FOR_NB_SCREENS(i)
{
peak_meter_screen(&screens[i], 0, 8 + h*2, h*PM_HEIGHT);