summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorPeter D'Hoye <peter.dhoye@gmail.com>2006-08-16 23:26:55 +0000
committerPeter D'Hoye <peter.dhoye@gmail.com>2006-08-16 23:26:55 +0000
commit5fc66e58dd8a62099cfb1c3f7ae48d7115376be3 (patch)
tree0dc6123bb179a5eba4953d62155a4b48dea75869 /apps
parentc5a24c69221dbd8f2c55f007d9d7eaa2222fa5df (diff)
downloadrockbox-5fc66e58dd8a62099cfb1c3f7ae48d7115376be3.tar.gz
rockbox-5fc66e58dd8a62099cfb1c3f7ae48d7115376be3.zip
Automatic Gain Control during recording. At this point only compiled for iriver h1x0 and h3x0. Patch FS#4748 by Jvo Studer, Martin Scarratt and myself.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@10625 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r--apps/lang/english.lang117
-rw-r--r--apps/recorder/peakmeter.c29
-rw-r--r--apps/recorder/peakmeter.h4
-rw-r--r--apps/recorder/recording.c518
-rw-r--r--apps/settings.c8
-rw-r--r--apps/settings.h20
-rw-r--r--apps/sound_menu.c41
7 files changed, 732 insertions, 5 deletions
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 984aa1be95..6a7d752ec6 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -9660,3 +9660,120 @@
9660 *: "Full Path" 9660 *: "Full Path"
9661 </voice> 9661 </voice>
9662</phrase> 9662</phrase>
9663<phrase>
9664 id: LANG_RECORD_AGC_PRESET
9665 desc: automatic gain control in record settings
9666 <source>
9667 *: "Automatic Gain Control"
9668 </source>
9669 <dest>
9670 *: "Automatic Gain Control"
9671 </dest>
9672 <voice>
9673 *: "pixels"
9674 </voice>
9675</phrase>
9676<phrase>
9677 id: LANG_AGC_SAFETY
9678 desc: AGC preset
9679 <source>
9680 *: "Safety (clip)"
9681 </source>
9682 <dest>
9683 *: "Safety (clip)"
9684 </dest>
9685 <voice>
9686 *: "pixels"
9687 </voice>
9688</phrase>
9689<phrase>
9690 id: LANG_AGC_LIVE
9691 desc: AGC preset
9692 <source>
9693 *: "Live (slow)"
9694 </source>
9695 <dest>
9696 *: "Live (slow)"
9697 </dest>
9698 <voice>
9699 *: "pixels"
9700 </voice>
9701</phrase>
9702<phrase>
9703 id: LANG_AGC_DJSET
9704 desc: AGC preset
9705 <source>
9706 *: "DJ-Set (slow)"
9707 </source>
9708 <dest>
9709 *: "DJ-Set (slow)"
9710 </dest>
9711 <voice>
9712 *: "pixels"
9713 </voice>
9714</phrase>
9715<phrase>
9716 id: LANG_AGC_MEDIUM
9717 desc: AGC preset
9718 <source>
9719 *: "Medium"
9720 </source>
9721 <dest>
9722 *: "Medium"
9723 </dest>
9724 <voice>
9725 *: "pixels"
9726 </voice>
9727</phrase>
9728<phrase>
9729 id: LANG_AGC_VOICE
9730 desc: AGC preset
9731 <source>
9732 *: "Voice (fast)"
9733 </source>
9734 <dest>
9735 *: "Voice (fast)"
9736 </dest>
9737 <voice>
9738 *: "pixels"
9739 </voice>
9740</phrase>
9741<phrase>
9742 id: LANG_RECORD_AGC_CLIPTIME
9743 desc: in record settings
9744 <source>
9745 *: "AGC clip time"
9746 </source>
9747 <dest>
9748 *: "AGC clip time"
9749 </dest>
9750 <voice>
9751 *: "pixels"
9752 </voice>
9753</phrase>
9754<phrase>
9755 id: LANG_RECORDING_AGC_PRESET
9756 desc: automatic gain control in recording screen
9757 <source>
9758 *: "AGC"
9759 </source>
9760 <dest>
9761 *: "AGC"
9762 </dest>
9763 <voice>
9764 *: "pixels"
9765 </voice>
9766</phrase>
9767<phrase>
9768 id: LANG_RECORDING_AGC_MAXGAIN
9769 desc: AGC maximum gain in recording screen
9770 <source>
9771 *: "AGC max. gain"
9772 </source>
9773 <dest>
9774 *: "AGC max. gain"
9775 </dest>
9776 <voice>
9777 *: "pixels"
9778 </voice>
9779</phrase>
diff --git a/apps/recorder/peakmeter.c b/apps/recorder/peakmeter.c
index 0f8da98308..58c85b2161 100644
--- a/apps/recorder/peakmeter.c
+++ b/apps/recorder/peakmeter.c
@@ -62,6 +62,10 @@ static int pm_cur_left; /* current values (last peak_meter_peek) */
62static int pm_cur_right; 62static int pm_cur_right;
63static int pm_max_left; /* maximum values between peak meter draws */ 63static int pm_max_left; /* maximum values between peak meter draws */
64static int pm_max_right; 64static int pm_max_right;
65#ifdef HAVE_AGC
66static int pm_peakhold_left; /* max. peak values between peakhold calls */
67static int pm_peakhold_right; /* used for AGC and histogram display */
68#endif
65 69
66/* Clip hold */ 70/* Clip hold */
67static bool pm_clip_left = false; /* when true a clip has occurred */ 71static bool pm_clip_left = false; /* when true a clip has occurred */
@@ -716,6 +720,10 @@ static int peak_meter_read_l(void)
716 by peak_meter_peek since the last call of peak_meter_read_l */ 720 by peak_meter_peek since the last call of peak_meter_read_l */
717 int retval = pm_max_left; 721 int retval = pm_max_left;
718 722
723#ifdef HAVE_AGC
724 /* store max peak value for peak_meter_get_peakhold_x readout */
725 pm_peakhold_left = MAX(pm_max_left, pm_peakhold_left);
726#endif
719#ifdef PM_DEBUG 727#ifdef PM_DEBUG
720 peek_calls = 0; 728 peek_calls = 0;
721#endif 729#endif
@@ -737,6 +745,10 @@ static int peak_meter_read_r(void)
737 by peak_meter_peek since the last call of peak_meter_read_r */ 745 by peak_meter_peek since the last call of peak_meter_read_r */
738 int retval = pm_max_right; 746 int retval = pm_max_right;
739 747
748#ifdef HAVE_AGC
749 /* store max peak value for peak_meter_get_peakhold_x readout */
750 pm_peakhold_right = MAX(pm_max_right, pm_peakhold_right);
751#endif
740#ifdef PM_DEBUG 752#ifdef PM_DEBUG
741 peek_calls = 0; 753 peek_calls = 0;
742#endif 754#endif
@@ -746,6 +758,23 @@ static int peak_meter_read_r(void)
746 return retval; 758 return retval;
747} 759}
748 760
761#ifdef HAVE_AGC
762/**
763 * Reads out the current peak-hold values since the last call.
764 * This is used by the histogram feature in the recording screen.
765 * Values are in the range 0 <= peak_x < MAX_PEAK. MAX_PEAK is typ 32767.
766 */
767extern void peak_meter_get_peakhold(int *peak_left, int *peak_right)
768{
769 if (peak_left)
770 *peak_left = pm_peakhold_left;
771 if (peak_right)
772 *peak_right = pm_peakhold_right;
773 pm_peakhold_left = 0;
774 pm_peakhold_right = 0;
775}
776#endif
777
749/** 778/**
750 * Reset the detected clips. This method is for 779 * Reset the detected clips. This method is for
751 * use by the user interface. 780 * use by the user interface.
diff --git a/apps/recorder/peakmeter.h b/apps/recorder/peakmeter.h
index 5456419181..548b95b7da 100644
--- a/apps/recorder/peakmeter.h
+++ b/apps/recorder/peakmeter.h
@@ -34,7 +34,9 @@ extern void peak_meter_set_clip_hold(int time);
34extern void peak_meter_peek(void); 34extern void peak_meter_peek(void);
35extern void peak_meter_init_range( bool dbfs, int range_min, int range_max); 35extern void peak_meter_init_range( bool dbfs, int range_min, int range_max);
36extern void peak_meter_init_times(int release, int hold, int clip_hold); 36extern void peak_meter_init_times(int release, int hold, int clip_hold);
37 37#ifdef HAVE_AGC
38extern void peak_meter_get_peakhold(int *peak_left, int *peak_right);
39#endif
38extern void peak_meter_set_min(int newmin); 40extern void peak_meter_set_min(int newmin);
39extern int peak_meter_get_min(void); 41extern int peak_meter_get_min(void);
40extern void peak_meter_set_max(int newmax); 42extern void peak_meter_set_max(int newmax);
diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c
index 47d2cce674..0d4f12742f 100644
--- a/apps/recorder/recording.c
+++ b/apps/recorder/recording.c
@@ -168,6 +168,63 @@ const char* const freq_str[6] =
168 "16kHz" 168 "16kHz"
169}; 169};
170 170
171#ifdef HAVE_AGC
172/* Timing counters:
173 * peak_time is incremented every 0.2s, every 2nd run of record screen loop.
174 * hist_time is incremented every 0.5s, display update.
175 * peak_time is the counter of the peak hold read and agc process,
176 * overflow every 13 years 8-)
177 */
178static long peak_time = 0;
179static long hist_time = 0;
180
181static short peak_valid_mem[4];
182#define BAL_MEM_SIZE 24
183static short balance_mem[BAL_MEM_SIZE];
184
185/* Automatic Gain Control */
186#define AGC_MODE_SIZE 5
187static char* agc_preset_str[] =
188{ "Off", "S", "L", "D", "M", "V" };
189/* "Off",
190 "Safety (clip)",
191 "Live (slow)",
192 "DJ-Set (slow)",
193 "Medium",
194 "Voice (fast)" */
195#define AGC_CLIP 32766
196#define AGC_PEAK 29883 /* fast gain reduction threshold -0.8dB */
197#define AGC_HIGH 27254 /* accelerated gain reduction threshold -1.6dB */
198#define AGC_IMG 823 /* threshold for balance control -32dB */
199/* autogain high level thresholds (-3dB, -7dB, -4dB, -5dB, -5dB) */
200const short agc_th_hi[AGC_MODE_SIZE] =
201{ 23197, 14637, 21156, 18428, 18426 };
202/* autogain low level thresholds (-14dB, -11dB, -6dB, -7dB, -8dB) */
203const short agc_th_lo[AGC_MODE_SIZE] =
204{ 6538, 9235, 16422, 14636, 13045 };
205/* autogain threshold times [1/5s] or [200ms] */
206const short agc_tdrop[AGC_MODE_SIZE] =
207{ 900, 225, 150, 60, 8 };
208const short agc_trise[AGC_MODE_SIZE] =
209{ 9000, 750, 400, 150, 20 };
210const short agc_tbal[AGC_MODE_SIZE] =
211{ 4500, 500, 300, 100, 15 };
212/* AGC operation */
213static bool agc_enable = true;
214static short agc_preset;
215/* AGC levels */
216static int agc_left = 0;
217static int agc_right = 0;
218/* AGC time since high target volume was exceeded */
219static short agc_droptime = 0;
220/* AGC time since volume fallen below low target */
221static short agc_risetime = 0;
222/* AGC balance time exceeding +/- 0.7dB */
223static short agc_baltime = 0;
224/* AGC maximum gain */
225static short agc_maxgain;
226#endif /* HAVE_AGC */
227
171static void set_gain(void) 228static void set_gain(void)
172{ 229{
173 if(global_settings.rec_source == SOURCE_MIC) 230 if(global_settings.rec_source == SOURCE_MIC)
@@ -183,6 +240,229 @@ static void set_gain(void)
183 } 240 }
184} 241}
185 242
243#ifdef HAVE_AGC
244/* Read peak meter values & calculate balance.
245 * Returns validity of peak values.
246 * Used for automatic gain control and history diagram.
247 */
248bool read_peak_levels(int *peak_l, int *peak_r, int *balance)
249{
250 peak_meter_get_peakhold(peak_l, peak_r);
251 peak_valid_mem[peak_time % 3] = *peak_l;
252 if (((peak_valid_mem[0] == peak_valid_mem[1]) &&
253 (peak_valid_mem[1] == peak_valid_mem[2])) &&
254 ((*peak_l < 32767)
255#ifndef SIMULATOR
256 || ata_disk_is_active()
257#endif
258 ))
259 return false;
260
261 if (*peak_r > *peak_l)
262 balance_mem[peak_time % BAL_MEM_SIZE] =
263 MIN((10000 * *peak_r) / *peak_l - 10000, 15118);
264 else
265 balance_mem[peak_time % BAL_MEM_SIZE] =
266 MAX(10000 - (10000 * *peak_l) / *peak_r, -15118);
267 *balance = 0;
268 int i;
269 for (i = 0; i < BAL_MEM_SIZE; i++)
270 *balance += balance_mem[i];
271 *balance = *balance / BAL_MEM_SIZE;
272
273 return true;
274}
275
276/* AGC helper function to check if maximum gain is reached */
277bool agc_gain_is_max(bool left, bool right)
278{
279 /* range -128...+108 [0.5dB] */
280 short gain_current_l;
281 short gain_current_r;
282
283 if (agc_preset == 0)
284 return false;
285
286 if (global_settings.rec_source == SOURCE_LINE)
287 {
288 gain_current_l = global_settings.rec_left_gain;
289 gain_current_r = global_settings.rec_right_gain;
290 } else
291 {
292 gain_current_l = global_settings.rec_mic_gain;
293 gain_current_r = global_settings.rec_mic_gain;
294 }
295
296 return ((left && (gain_current_l >= agc_maxgain)) ||
297 (right && (gain_current_r >= agc_maxgain)));
298}
299
300void change_recording_gain(bool increment, bool left, bool right)
301{
302 int factor = (increment ? 1 : -1);
303
304 if (global_settings.rec_source == SOURCE_LINE)
305 {
306 if(left) global_settings.rec_left_gain += factor;
307 if (right) global_settings.rec_right_gain += factor;
308 }
309 else
310 {
311 global_settings.rec_mic_gain += factor;
312 }
313}
314
315/*
316 * Handle automatic gain control (AGC).
317 * Change recording gain if peak_x levels are above or below
318 * target volume for specified timeouts.
319 */
320void auto_gain_control(int *peak_l, int *peak_r, int *balance)
321{
322 int agc_mono;
323 short agc_mode;
324 bool increment;
325
326 if (*peak_l > agc_left)
327 agc_left = *peak_l;
328 else
329 agc_left -= (agc_left - *peak_l + 3) >> 2;
330 if (*peak_r > agc_right)
331 agc_right = *peak_r;
332 else
333 agc_right -= (agc_right - *peak_r + 3) >> 2;
334 agc_mono = (agc_left + agc_right) / 2;
335
336 agc_mode = abs(agc_preset) - 1;
337 if (agc_mode < 0) {
338 agc_enable = false;
339 return;
340 }
341
342 /* Automatic balance control */
343 if ((agc_left > AGC_IMG) && (agc_right > AGC_IMG))
344 {
345 if (*balance < -556)
346 {
347 if (*balance > -900)
348 agc_baltime -= !(peak_time % 4); /* 0.47 - 0.75dB */
349 else if (*balance > -4125)
350 agc_baltime--; /* 0.75 - 3.00dB */
351 else if (*balance > -7579)
352 agc_baltime -= 2; /* 3.00 - 4.90dB */
353 else
354 agc_baltime -= !(peak_time % 8); /* 4.90 - inf dB */
355 if (agc_baltime > 0)
356 agc_baltime -= (peak_time % 2);
357 }
358 else if (*balance > 556)
359 {
360 if (*balance < 900)
361 agc_baltime += !(peak_time % 4);
362 else if (*balance < 4125)
363 agc_baltime++;
364 else if (*balance < 7579)
365 agc_baltime += 2;
366 else
367 agc_baltime += !(peak_time % 8);
368 if (agc_baltime < 0)
369 agc_baltime += (peak_time % 2);
370 }
371
372 if ((*balance * agc_baltime) < 0)
373 {
374 if (*balance < 0)
375 agc_baltime -= peak_time % 2;
376 else
377 agc_baltime += peak_time % 2;
378 }
379
380 increment = ((agc_risetime / 2) > agc_droptime);
381
382 if (agc_baltime < -agc_tbal[agc_mode])
383 {
384 if (!increment || !agc_gain_is_max(!increment, increment)) {
385 change_recording_gain(increment, !increment, increment);
386 set_gain();
387 }
388 agc_baltime = 0;
389 }
390 else if (agc_baltime > +agc_tbal[agc_mode])
391 {
392 if (!increment || !agc_gain_is_max(increment, !increment)) {
393 change_recording_gain(increment, increment, !increment);
394 set_gain();
395 }
396 agc_baltime = 0;
397 }
398 }
399 else if (!(hist_time % 4))
400 {
401 if (agc_baltime < 0)
402 agc_baltime++;
403 else
404 agc_baltime--;
405 }
406
407 /* Automatic gain control */
408 if ((agc_left > agc_th_hi[agc_mode]) || (agc_right > agc_th_hi[agc_mode]))
409 {
410 if ((agc_left > AGC_CLIP) || (agc_right > AGC_CLIP))
411 agc_droptime += agc_tdrop[agc_mode] /
412 (global_settings.rec_agc_cliptime + 1);
413 if (agc_left > AGC_HIGH) {
414 agc_droptime++;
415 agc_risetime=0;
416 if (agc_left > AGC_PEAK)
417 agc_droptime += 2;
418 }
419 if (agc_right > AGC_HIGH) {
420 agc_droptime++;
421 agc_risetime=0;
422 if (agc_right > AGC_PEAK)
423 agc_droptime += 2;
424 }
425 if (agc_mono > agc_th_hi[agc_mode])
426 agc_droptime++;
427 else
428 agc_droptime += !(peak_time % 2);
429
430 if (agc_droptime >= agc_tdrop[agc_mode])
431 {
432 change_recording_gain(false, true, true);
433 agc_droptime = 0;
434 agc_risetime = 0;
435 set_gain();
436 }
437 agc_risetime = MAX(agc_risetime - 1, 0);
438 }
439 else if (agc_mono < agc_th_lo[agc_mode])
440 {
441 if (agc_mono < (agc_th_lo[agc_mode] / 8))
442 agc_risetime += !(peak_time % 5);
443 else if (agc_mono < (agc_th_lo[agc_mode] / 2))
444 agc_risetime += 2;
445 else
446 agc_risetime++;
447
448 if (agc_risetime >= agc_trise[agc_mode]) {
449 if (!agc_gain_is_max(true, true)) {
450 change_recording_gain(true, true, true);
451 set_gain();
452 }
453 agc_risetime = 0;
454 agc_droptime = 0;
455 }
456 agc_droptime = MAX(agc_droptime - 1, 0);
457 }
458 else if (!(peak_time % 6)) /* on target level every 1.2 sec */
459 {
460 agc_risetime = MAX(agc_risetime - 1, 0);
461 agc_droptime = MAX(agc_droptime - 1, 0);
462 }
463}
464#endif /* HAVE_AGC */
465
186static const char* const fmtstr[] = 466static const char* const fmtstr[] =
187{ 467{
188 "%c%d %s", /* no decimals */ 468 "%c%d %s", /* no decimals */
@@ -226,6 +506,22 @@ void adjust_cursor(void)
226 if(cursor < 0) 506 if(cursor < 0)
227 cursor = 0; 507 cursor = 0;
228 508
509#ifdef HAVE_AGC
510 switch(global_settings.rec_source)
511 {
512 case SOURCE_MIC:
513 if(cursor == 2)
514 cursor = 4;
515 else if(cursor == 3)
516 cursor = 1;
517 case SOURCE_LINE:
518 max_cursor = 5;
519 break;
520 default:
521 max_cursor = 0;
522 break;
523 }
524#else
229 switch(global_settings.rec_source) 525 switch(global_settings.rec_source)
230 { 526 {
231 case SOURCE_MIC: 527 case SOURCE_MIC:
@@ -238,6 +534,7 @@ void adjust_cursor(void)
238 max_cursor = 0; 534 max_cursor = 0;
239 break; 535 break;
240 } 536 }
537#endif /* HAVE_AGC */
241 538
242 if(cursor > max_cursor) 539 if(cursor > max_cursor)
243 cursor = max_cursor; 540 cursor = max_cursor;
@@ -353,6 +650,14 @@ bool recording_screen(void)
353 bool led_state = false; 650 bool led_state = false;
354 int led_countdown = 2; 651 int led_countdown = 2;
355#endif 652#endif
653#ifdef HAVE_AGC
654 bool peak_read = false;
655 bool peak_valid = false;
656 int peak_l, peak_r;
657 int balance = 0;
658 bool display_agc[NB_SCREENS];
659#endif
660 int line[NB_SCREENS];
356 int i; 661 int i;
357 int filename_offset[NB_SCREENS]; 662 int filename_offset[NB_SCREENS];
358 int pm_y[NB_SCREENS]; 663 int pm_y[NB_SCREENS];
@@ -392,6 +697,9 @@ bool recording_screen(void)
392 peak_meter_playback(true); 697 peak_meter_playback(true);
393#endif 698#endif
394 peak_meter_enabled = true; 699 peak_meter_enabled = true;
700#ifdef HAVE_AGC
701 peak_meter_get_peakhold(&peak_l, &peak_r);
702#endif
395 703
396#if CONFIG_CODEC != SWCODEC 704#if CONFIG_CODEC != SWCODEC
397 if (global_settings.rec_prerecord_time) 705 if (global_settings.rec_prerecord_time)
@@ -414,6 +722,23 @@ bool recording_screen(void)
414 722
415 settings_apply_trigger(); 723 settings_apply_trigger();
416 724
725#ifdef HAVE_AGC
726 agc_preset_str[0] = str(LANG_OFF);
727 agc_preset_str[1] = str(LANG_AGC_SAFETY);
728 agc_preset_str[2] = str(LANG_AGC_LIVE);
729 agc_preset_str[3] = str(LANG_AGC_DJSET);
730 agc_preset_str[4] = str(LANG_AGC_MEDIUM);
731 agc_preset_str[5] = str(LANG_AGC_VOICE);
732 if (global_settings.rec_source == SOURCE_MIC) {
733 agc_preset = global_settings.rec_agc_preset_mic;
734 agc_maxgain = global_settings.rec_agc_maxgain_mic;
735 }
736 else {
737 agc_preset = global_settings.rec_agc_preset_line;
738 agc_maxgain = global_settings.rec_agc_maxgain_line;
739 }
740#endif
741
417 FOR_NB_SCREENS(i) 742 FOR_NB_SCREENS(i)
418 { 743 {
419 screens[i].setfont(FONT_SYSFIXED); 744 screens[i].setfont(FONT_SYSFIXED);
@@ -698,6 +1023,33 @@ bool recording_screen(void)
698 sound_max(SOUND_RIGHT_GAIN)) 1023 sound_max(SOUND_RIGHT_GAIN))
699 global_settings.rec_right_gain++; 1024 global_settings.rec_right_gain++;
700 break; 1025 break;
1026#ifdef HAVE_AGC
1027 case 4:
1028 agc_preset = MIN(agc_preset + 1, AGC_MODE_SIZE);
1029 agc_enable = (agc_preset != 0);
1030 if (global_settings.rec_source == SOURCE_MIC) {
1031 global_settings.rec_agc_preset_mic = agc_preset;
1032 agc_maxgain = global_settings.rec_agc_maxgain_mic;
1033 } else {
1034 global_settings.rec_agc_preset_line = agc_preset;
1035 agc_maxgain = global_settings.rec_agc_maxgain_line;
1036 }
1037 break;
1038 case 5:
1039 if (global_settings.rec_source == SOURCE_MIC)
1040 {
1041 agc_maxgain = MIN(agc_maxgain + 1,
1042 sound_max(SOUND_MIC_GAIN));
1043 global_settings.rec_agc_maxgain_mic = agc_maxgain;
1044 }
1045 else
1046 {
1047 agc_maxgain = MIN(agc_maxgain + 1,
1048 sound_max(SOUND_LEFT_GAIN));
1049 global_settings.rec_agc_maxgain_line = agc_maxgain;
1050 }
1051 break;
1052#endif
701 } 1053 }
702 set_gain(); 1054 set_gain();
703 update_countdown = 1; /* Update immediately */ 1055 update_countdown = 1; /* Update immediately */
@@ -744,6 +1096,33 @@ bool recording_screen(void)
744 sound_min(SOUND_RIGHT_GAIN)) 1096 sound_min(SOUND_RIGHT_GAIN))
745 global_settings.rec_right_gain--; 1097 global_settings.rec_right_gain--;
746 break; 1098 break;
1099#ifdef HAVE_AGC
1100 case 4:
1101 agc_preset = MAX(agc_preset - 1, 0);
1102 agc_enable = (agc_preset != 0);
1103 if (global_settings.rec_source == SOURCE_MIC) {
1104 global_settings.rec_agc_preset_mic = agc_preset;
1105 agc_maxgain = global_settings.rec_agc_maxgain_mic;
1106 } else {
1107 global_settings.rec_agc_preset_line = agc_preset;
1108 agc_maxgain = global_settings.rec_agc_maxgain_line;
1109 }
1110 break;
1111 case 5:
1112 if (global_settings.rec_source == SOURCE_MIC)
1113 {
1114 agc_maxgain = MAX(agc_maxgain - 1,
1115 sound_min(SOUND_MIC_GAIN));
1116 global_settings.rec_agc_maxgain_mic = agc_maxgain;
1117 }
1118 else
1119 {
1120 agc_maxgain = MAX(agc_maxgain - 1,
1121 sound_min(SOUND_LEFT_GAIN));
1122 global_settings.rec_agc_maxgain_line = agc_maxgain;
1123 }
1124 break;
1125#endif
747 } 1126 }
748 set_gain(); 1127 set_gain();
749 update_countdown = 1; /* Update immediately */ 1128 update_countdown = 1; /* Update immediately */
@@ -777,6 +1156,16 @@ bool recording_screen(void)
777 global_settings.rec_channels, 1156 global_settings.rec_channels,
778 global_settings.rec_editable, 1157 global_settings.rec_editable,
779 global_settings.rec_prerecord_time); 1158 global_settings.rec_prerecord_time);
1159#ifdef HAVE_AGC
1160 if (global_settings.rec_source == SOURCE_MIC) {
1161 agc_preset = global_settings.rec_agc_preset_mic;
1162 agc_maxgain = global_settings.rec_agc_maxgain_mic;
1163 }
1164 else {
1165 agc_preset = global_settings.rec_agc_preset_line;
1166 agc_maxgain = global_settings.rec_agc_maxgain_line;
1167 }
1168#endif
780 1169
781 adjust_cursor(); 1170 adjust_cursor();
782 set_gain(); 1171 set_gain();
@@ -854,6 +1243,18 @@ bool recording_screen(void)
854 if (button != BUTTON_NONE) 1243 if (button != BUTTON_NONE)
855 lastbutton = button; 1244 lastbutton = button;
856 1245
1246#ifdef HAVE_AGC
1247 peak_read = !peak_read;
1248 if (peak_read) { /* every 2nd run of loop */
1249 peak_time++;
1250 peak_valid = read_peak_levels(&peak_l, &peak_r, &balance);
1251 }
1252
1253 /* Handle AGC every 200ms when enabled and peak data is valid */
1254 if (peak_read && agc_enable && peak_valid)
1255 auto_gain_control(&peak_l, &peak_r, &balance);
1256#endif
1257
857 FOR_NB_SCREENS(i) 1258 FOR_NB_SCREENS(i)
858 screens[i].setfont(FONT_SYSFIXED); 1259 screens[i].setfont(FONT_SYSFIXED);
859 1260
@@ -1041,10 +1442,101 @@ bool recording_screen(void)
1041 screens[i].puts(0, filename_offset[i] + 1442 screens[i].puts(0, filename_offset[i] +
1042 PM_HEIGHT + 4, buf); 1443 PM_HEIGHT + 4, buf);
1043 } 1444 }
1445 }
1446
1447 FOR_NB_SCREENS(i)
1448 {
1449 if (global_settings.rec_source == SOURCE_LINE)
1450 line[i] = 5;
1451 else if (global_settings.rec_source == SOURCE_MIC)
1452 line[i] = 4;
1453#ifdef HAVE_SPDIF_IN
1454 else if (global_settings.rec_source == SOURCE_SPDIF)
1455 line[i] = 3;
1456#endif
1457#ifdef HAVE_AGC
1458 if (screens[i].height < h * (2 + filename_offset[i] + PM_HEIGHT + line[i]))
1459 {
1460 line[i] -= 1;
1461 display_agc[i] = false;
1462 }
1463 else
1464 display_agc[i] = true;
1465
1466 if ((cursor==4) || (cursor==5))
1467 display_agc[i] = true;
1468 }
1469
1470 /************** AGC test info ******************
1471 snprintf(buf, 32, "D:%d U:%d",
1472 (agc_droptime+2)/5, (agc_risetime+2)/5);
1473 lcd_putsxy(1, LCD_HEIGHT - 8, buf);
1474 snprintf(buf, 32, "B:%d",
1475 (agc_baltime+2)/5);
1476 lcd_putsxy(LCD_WIDTH/2 + 3, LCD_HEIGHT - 8, buf);
1477 ***********************************************/
1478
1479 if (cursor == 5)
1480 snprintf(buf, 32, "%s: %s",
1481 str(LANG_RECORDING_AGC_MAXGAIN),
1482 fmt_gain(SOUND_LEFT_GAIN,
1483 agc_maxgain, buf2, sizeof(buf2)));
1484 else if (agc_preset == 0)
1485 snprintf(buf, 32, "%s: %s",
1486 str(LANG_RECORDING_AGC_PRESET),
1487 agc_preset_str[agc_preset]);
1488 else if (global_settings.rec_source == SOURCE_MIC)
1489 snprintf(buf, 32, "%s: %s%s",
1490 str(LANG_RECORDING_AGC_PRESET),
1491 agc_preset_str[agc_preset],
1492 fmt_gain(SOUND_LEFT_GAIN,
1493 agc_maxgain -
1494 global_settings.rec_mic_gain,
1495 buf2, sizeof(buf2)));
1496 else
1497 snprintf(buf, 32, "%s: %s%s",
1498 str(LANG_RECORDING_AGC_PRESET),
1499 agc_preset_str[agc_preset],
1500 fmt_gain(SOUND_LEFT_GAIN,
1501 agc_maxgain -
1502 (global_settings.rec_left_gain +
1503 global_settings.rec_right_gain)/2,
1504 buf2, sizeof(buf2)));
1044 1505
1506 if(global_settings.invert_cursor && ((cursor==4) || (cursor==5)))
1507 {
1508 for(i = 0; i < screen_update; i++)
1509 screens[i].puts_style_offset(0, filename_offset[i] +
1510 PM_HEIGHT + line[i], buf, STYLE_INVERT,0);
1045 } 1511 }
1512 else if ((global_settings.rec_source == SOURCE_MIC)
1513 || (global_settings.rec_source == SOURCE_LINE))
1514 {
1515 for(i = 0; i < screen_update; i++) {
1516 if (display_agc[i]) {
1517 screens[i].puts(0, filename_offset[i] +
1518 PM_HEIGHT + line[i], buf);
1519 }
1520 }
1521 }
1522
1523 if (global_settings.rec_source == SOURCE_MIC)
1524 {
1525 if(agc_maxgain < (global_settings.rec_mic_gain))
1526 change_recording_gain(false, true, true);
1527 }
1528 else
1529 {
1530 if(agc_maxgain < (global_settings.rec_left_gain))
1531 change_recording_gain(false, true, false);
1532 if(agc_maxgain < (global_settings.rec_right_gain))
1533 change_recording_gain(false, false, true);
1534 }
1535#else
1536 }
1537#endif /* HAVE_AGC */
1046 1538
1047 if(!global_settings.invert_cursor){ 1539 if(!global_settings.invert_cursor) {
1048 switch(cursor) 1540 switch(cursor)
1049 { 1541 {
1050 case 1: 1542 case 1:
@@ -1073,6 +1565,15 @@ bool recording_screen(void)
1073 filename_offset[i] + 1565 filename_offset[i] +
1074 PM_HEIGHT + 4, true); 1566 PM_HEIGHT + 4, true);
1075 break; 1567 break;
1568#ifdef HAVE_AGC
1569 case 4:
1570 case 5:
1571 for(i = 0; i < screen_update; i++)
1572 screen_put_cursorxy(&screens[i], 0,
1573 filename_offset[i] +
1574 PM_HEIGHT + line[i], true);
1575 break;
1576#endif /* HAVE_AGC */
1076 default: 1577 default:
1077 for(i = 0; i < screen_update; i++) 1578 for(i = 0; i < screen_update; i++)
1078 screen_put_cursorxy(&screens[i], 0, 1579 screen_put_cursorxy(&screens[i], 0,
@@ -1096,9 +1597,20 @@ bool recording_screen(void)
1096 global_settings.rec_channels ? 1597 global_settings.rec_channels ?
1097 str(LANG_SYSFONT_CHANNEL_MONO) : 1598 str(LANG_SYSFONT_CHANNEL_MONO) :
1098 str(LANG_SYSFONT_CHANNEL_STEREO)); 1599 str(LANG_SYSFONT_CHANNEL_STEREO));
1099 for(i = 0; i < screen_update; i++)
1100 screens[i].puts(0, filename_offset[i] + PM_HEIGHT + 5, buf);
1101 1600
1601 for(i = 0; i < screen_update; i++) {
1602#ifdef HAVE_AGC
1603 if ((global_settings.rec_source == SOURCE_MIC)
1604 || (global_settings.rec_source == SOURCE_LINE))
1605 screens[i].puts(0, filename_offset[i] + PM_HEIGHT + line[i] + 1, buf);
1606 else
1607#endif
1608 screens[i].puts(0, filename_offset[i] + PM_HEIGHT + line[i], buf);
1609 }
1610
1611#ifdef HAVE_AGC
1612 hist_time++;
1613#endif
1102 for(i = 0; i < screen_update; i++) 1614 for(i = 0; i < screen_update; i++)
1103 { 1615 {
1104 gui_statusbar_draw(&(statusbars.statusbars[i]), true); 1616 gui_statusbar_draw(&(statusbars.statusbars[i]), true);
diff --git a/apps/settings.c b/apps/settings.c
index f70e29696b..cd984254d9 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -615,7 +615,13 @@ static const struct bit_entry hd_bits[] =
615 {1, S_O(hold_lr_for_scroll_in_list), true, "hold_lr_for_scroll_in_list", off_on }, 615 {1, S_O(hold_lr_for_scroll_in_list), true, "hold_lr_for_scroll_in_list", off_on },
616 616
617 {2, S_O(show_path_in_browser), 0, "show path in browser", "off,current directory,full path" }, 617 {2, S_O(show_path_in_browser), 0, "show path in browser", "off,current directory,full path" },
618 618#ifdef HAVE_AGC
619 {4, S_O(rec_agc_preset_mic), 1, "agc mic preset", NULL}, /* 0...5 */
620 {4, S_O(rec_agc_preset_line), 1, "agc line preset", NULL}, /* 0...5 */
621 {8|SIGNED, S_O(rec_agc_maxgain_mic), 104, "agc maximum mic gain", NULL},
622 {8|SIGNED, S_O(rec_agc_maxgain_line), 96, "agc maximum line gain", NULL},
623 {3, S_O(rec_agc_cliptime), 1, "agc cliptime", "0.2s,0.4s,0.6s,0.8,1s"},
624#endif
619 /* If values are just added to the end, no need to bump the version. */ 625 /* If values are just added to the end, no need to bump the version. */
620 /* new stuff to be added at the end */ 626 /* new stuff to be added at the end */
621 627
diff --git a/apps/settings.h b/apps/settings.h
index 27f00584a6..d87bc5ee06 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -180,6 +180,26 @@ struct user_settings
180 int rec_stop_gap; /* index of trig_durations */ 180 int rec_stop_gap; /* index of trig_durations */
181 int rec_trigger_mode; /* see TRIG_MODE_XXX constants */ 181 int rec_trigger_mode; /* see TRIG_MODE_XXX constants */
182 182
183#ifdef HAVE_AGC
184 int rec_agc_preset_mic; /* AGC mic preset modes:
185 0 = Off
186 1 = Safety (clip)
187 2 = Live (slow)
188 3 = DJ-Set (slow)
189 4 = Medium
190 5 = Voice (fast) */
191 int rec_agc_preset_line; /* AGC line-in preset modes:
192 0 = Off
193 1 = Safety (clip)
194 2 = Live (slow)
195 3 = DJ-Set (slow)
196 4 = Medium
197 5 = Voice (fast) */
198 int rec_agc_maxgain_mic; /* AGC maximum mic gain */
199 int rec_agc_maxgain_line; /* AGC maximum line-in gain */
200 int rec_agc_cliptime; /* 0.2, 0.4, 0.6, 0.8, 1s */
201#endif
202
183 /* device settings */ 203 /* device settings */
184 204
185#ifdef HAVE_LCD_CONTRAST 205#ifdef HAVE_LCD_CONTRAST
diff --git a/apps/sound_menu.c b/apps/sound_menu.c
index 280fe52169..34ed9af000 100644
--- a/apps/sound_menu.c
+++ b/apps/sound_menu.c
@@ -516,6 +516,41 @@ static bool cliplight(void)
516} 516}
517#endif /*CONFIG_BACKLIGHT */ 517#endif /*CONFIG_BACKLIGHT */
518 518
519#ifdef HAVE_AGC
520static bool agc_preset(void)
521{
522 static const struct opt_items names[] = {
523 { STR(LANG_OFF) },
524 { STR(LANG_AGC_SAFETY) },
525 { STR(LANG_AGC_LIVE) },
526 { STR(LANG_AGC_DJSET) },
527 { STR(LANG_AGC_MEDIUM) },
528 { STR(LANG_AGC_VOICE) },
529 };
530 if (global_settings.rec_source)
531 return set_option(str(LANG_RECORD_AGC_PRESET),
532 &global_settings.rec_agc_preset_line,
533 INT, names, 6, NULL );
534 else
535 return set_option(str(LANG_RECORD_AGC_PRESET),
536 &global_settings.rec_agc_preset_mic,
537 INT, names, 6, NULL );
538}
539
540static bool agc_cliptime(void)
541{
542 static const struct opt_items names[] = {
543 { "200ms", TALK_ID(200, UNIT_MS) },
544 { "400ms", TALK_ID(400, UNIT_MS) },
545 { "600ms", TALK_ID(600, UNIT_MS) },
546 { "800ms", TALK_ID(800, UNIT_MS) },
547 { "1s", TALK_ID(1, UNIT_SEC) }
548 };
549 return set_option(str(LANG_RECORD_AGC_CLIPTIME),
550 &global_settings.rec_agc_cliptime,
551 INT, names, 5, NULL );
552}
553#endif /* HAVE_AGC */
519#endif /* HAVE_RECORDING */ 554#endif /* HAVE_RECORDING */
520 555
521static bool chanconf(void) 556static bool chanconf(void)
@@ -1015,6 +1050,12 @@ bool recording_menu(bool no_source)
1015 items[i].desc = ID2P(LANG_RECORD_TRIGGER); 1050 items[i].desc = ID2P(LANG_RECORD_TRIGGER);
1016 items[i++].function = rectrigger; 1051 items[i++].function = rectrigger;
1017#endif 1052#endif
1053#ifdef HAVE_AGC
1054 items[i].desc = ID2P(LANG_RECORD_AGC_PRESET);
1055 items[i++].function = agc_preset;
1056 items[i].desc = ID2P(LANG_RECORD_AGC_CLIPTIME);
1057 items[i++].function = agc_cliptime;
1058#endif
1018 1059
1019 m=menu_init( items, i, NULL, NULL, NULL, NULL); 1060 m=menu_init( items, i, NULL, NULL, NULL, NULL);
1020 result = menu_run(m); 1061 result = menu_run(m);