summaryrefslogtreecommitdiff
path: root/apps/recorder/peakmeter.c
diff options
context:
space:
mode:
authorLinus Nielsen Feltzing <linus@haxx.se>2002-10-29 12:09:15 +0000
committerLinus Nielsen Feltzing <linus@haxx.se>2002-10-29 12:09:15 +0000
commitfd0cc3b2b1302d77f3404861509e75c64fd505af (patch)
treeacdb25b87a549908424e052c04cc323d02b681f4 /apps/recorder/peakmeter.c
parent8f11dc00ac1a0a5fe009d1d07d9a1378c3300ba8 (diff)
downloadrockbox-fd0cc3b2b1302d77f3404861509e75c64fd505af.tar.gz
rockbox-fd0cc3b2b1302d77f3404861509e75c64fd505af.zip
Phil Pertermann's dB peak meter patch
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@2774 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/recorder/peakmeter.c')
-rw-r--r--apps/recorder/peakmeter.c631
1 files changed, 615 insertions, 16 deletions
diff --git a/apps/recorder/peakmeter.c b/apps/recorder/peakmeter.c
index df7c672617..e1850a4bb0 100644
--- a/apps/recorder/peakmeter.c
+++ b/apps/recorder/peakmeter.c
@@ -46,24 +46,52 @@ static bool peak_meter_r_clip = false;
46static long peak_meter_clip_timeout_l; 46static long peak_meter_clip_timeout_l;
47static long peak_meter_clip_timeout_r; 47static long peak_meter_clip_timeout_r;
48 48
49static int peak_meter_clip_hold;
50
51/* specifies the value range in peak volume values */
52unsigned short peak_meter_range_min;
53unsigned short peak_meter_range_max;
54
49/* if set to true clip timeout is disabled */ 55/* if set to true clip timeout is disabled */
50static bool peak_meter_clip_eternal = false; 56static bool peak_meter_clip_eternal = false;
51 57
58static bool peak_meter_use_dbfs = true;
59
60
52#ifndef SIMULATOR 61#ifndef SIMULATOR
53static int peak_meter_src_l = MAS_REG_DQPEAK_L; 62static int peak_meter_src_l = MAS_REG_DQPEAK_L;
54static int peak_meter_src_r = MAS_REG_DQPEAK_R; 63static int peak_meter_src_r = MAS_REG_DQPEAK_R;
55#endif 64#endif
56 65
57/* temporarily en- / disables peak meter. This is 66/* temporarily en- / disables peak meter. This is
58
59 especially for external applications to detect 67 especially for external applications to detect
60
61 if the peak_meter is in use and needs drawing at all */ 68 if the peak_meter is in use and needs drawing at all */
62bool peak_meter_enabled = true; 69bool peak_meter_enabled = true;
63 70
71/*
72bool peak_meter_use_thread = false;
73static char peak_meter_stack[DEFAULT_STACK_SIZE];
74*/
75/* used in wps.c to set the display frame rate of the peak meter */
76int peak_meter_fps = 20;
77
64static int peak_meter_l; 78static int peak_meter_l;
65static int peak_meter_r; 79static int peak_meter_r;
66 80
81static int peak_meter_hold = 1;
82static int peak_meter_release = 8;
83
84/* debug only */
85#ifdef PM_DEBUG
86static int peek_calls = 0;
87
88#define PEEKS_PER_DRAW_SIZE 40
89static unsigned int peeks_per_redraw[PEEKS_PER_DRAW_SIZE];
90
91#define TICKS_PER_DRAW_SIZE 20
92static unsigned int ticks_per_redraw[TICKS_PER_DRAW_SIZE];
93#endif
94
67/* time out values for max */ 95/* time out values for max */
68static long max_time_out[] = { 96static long max_time_out[] = {
69 0 * HZ, HZ / 5, 30, HZ / 2, HZ, 2 * HZ, 97 0 * HZ, HZ / 5, 30, HZ / 2, HZ, 2 * HZ,
@@ -80,6 +108,353 @@ static long clip_time_out[] = {
80 2700 * HZ, 5400 * HZ 108 2700 * HZ, 5400 * HZ
81}; 109};
82 110
111/* precalculated peak values that represent magical
112 dBfs values. Used to draw the scale */
113#if 0
114static int db_scale_src_values[] = {
115 32767, /* 0 db */
116 23197, /* - 3 db */
117 16422, /* - 6 db */
118 11626, /* - 9 db */
119 8231, /* -12 db */
120 4125, /* -18 db */
121 2067, /* -24 db */
122 1036, /* -30 db */
123 328, /* -40 db */
124 104, /* -50 db */
125 33, /* -60 db */
126};
127#else
128static int db_scale_src_values[] = {
129 32752, /* 0 db */
130 22784, /* - 3 db */
131 14256, /* - 6 db */
132 11752, /* - 9 db */
133 9256, /* -12 db */
134 4256, /* -18 db */
135 2186, /* -24 db */
136 1186, /* -30 db */
137 373, /* -40 db */
138 102, /* -50 db */
139 33, /* -60 db */
140};
141#endif
142
143int db_scale_count = sizeof db_scale_src_values / sizeof (int);
144
145/* if db_scale_valid is false the content of
146 db_scale_lcd_coord needs recalculation */
147static bool db_scale_valid = false;
148
149/* contains the lcd x coordinates of the magical
150 scale values in db_scale_src_values */
151static int db_scale_lcd_coord[sizeof db_scale_src_values / sizeof (int)];
152
153
154/**
155 * Calculates dB Value for the peak meter, uses peak value as input
156 * @param int sample - The input value
157 * Make sure that 0 <= value < SAMPLE_RANGE
158 *
159 * @return int - The 2 digit fixed comma result of the euation
160 * 20 * log (sample / SAMPLE_RANGE) + 90
161 * Output range is 0-8961 (that is 0,0 - 89,6 dB).
162 * Normally 0dB is full scale, here it is shifted +90dB.
163 * The calculation is based on the results of a linear
164 * approximation tool written specifically for this problem
165 * by Andreas Zwirtes (radhard@gmx.de). The result hat an
166 * accurracy of better than 2%. It is highly runtime optimized,
167 * the cascading if-clauses do an successive approximation on
168 * the input value. This avoids big lookup-tables and
169 * for-loops.
170 */
171
172int calc_db (int isample) {
173 /* return n+m*(isample-istart)/100 */
174 int n;
175 long m;
176 int istart;
177
178 /* Range 1-4 */
179 if (isample < 119) {
180
181 /* Range 1-2 */
182 if (isample < 5) {
183
184 /* Range 1 */
185 if (isample < 1) {
186 istart = 0;
187 n = 0;
188 m = 5900;
189 }
190
191 /* Range 2 */
192 else {
193 istart = 1;
194 n = 59;
195 m = 34950;
196 }
197 }
198
199 /* Range 3-4 */
200 else {
201
202 /* Range 3 */
203 if (isample < 24) {
204 istart = 5;
205 n = 1457;
206 m = 7168;
207 }
208
209 /* Range 4 */
210 else {
211 istart = 24;
212 n = 2819;
213 m = 1464;
214 }
215 }
216 }
217
218 /* Range 5-8 */
219 else {
220
221 /* Range 5-6 */
222 if (isample < 2918) {
223
224 /* Range 5 */
225 if (isample < 592) {
226 istart = 119;
227 n = 4210;
228 m = 295;
229 }
230
231 /* Range 6 */
232 else {
233 istart = 592;
234 n = 5605;
235 m = 60;
236 }
237 }
238
239 /* Range 7-8 */
240 else {
241
242 /* Range 7 */
243 if (isample < 15352) {
244 istart = 2918;
245 n = 7001;
246 m = 12;
247 }
248
249 /* Range 8 */
250 else {
251 istart = 15352;
252 n = 8439;
253 m = 3;
254 }
255 }
256 }
257
258 return n + (m * (long)(isample - istart)) / 100L;
259}
260
261
262/**
263 * A helper function for db_to_sample. Don't call it separately but
264 * use db_to_sample. If one or both of min and max are outside the
265 * range 0 <= min (or max) < 8961 the behaviour of this function is
266 * undefined. It may not return.
267 * @param int min - The minimum of the value range that is searched.
268 * @param int max - The maximum of the value range that is searched.
269 * @param int db - The value in dBfs * (-100) for which the according
270 * minimal peak sample is searched.
271 * @return int - A linear volume value with 0 <= value < MAX_PEAK
272 */
273static int db_to_sample_bin_search(int min, int max, int db){
274 int test = min + (max - min) / 2;
275
276 if (min < max) {
277 if (calc_db(test) < db) {
278 test = db_to_sample_bin_search(test, max, db);
279 } else {
280 if (calc_db(test-1) > db) {
281 test = db_to_sample_bin_search(min, test, db);
282 }
283 }
284 }
285 return test;
286}
287
288/**
289 * Converts a value representing dBfs to a linear
290 * scaled volume info as it is used by the MAS.
291 * An incredibly inefficiant function which is
292 * the vague inverse of calc_db. This really
293 * should be replaced by something better soon.
294 *
295 * @param int db - A dBfs * 100 value with
296 * -9000 < value <= 0
297 * @return int - The return value is in the range of
298 * 0 <= return value < MAX_PEAK
299 */
300static int db_to_sample(int db) {
301 int retval = 0;
302
303 /* what is the maximum pseudo db value */
304 int max_peak_db = calc_db(MAX_PEAK - 1);
305
306 /* range check: db value to big */
307 if (max_peak_db + db < 0) {
308 retval = 0;
309 }
310
311 /* range check: db value too small */
312 else if (max_peak_db + db >= max_peak_db) {
313 retval = MAX_PEAK -1;
314 }
315
316 /* value in range: find the matching linear value */
317 else {
318 retval = db_to_sample_bin_search(0, MAX_PEAK, max_peak_db + db);
319
320 /* as this is a dirty function anyway, we want to adjust the
321 full scale hit manually to avoid users complaining that when
322 they adjust maximum for 0 dBfs and display it in percent it
323 shows 99%. That is due to precision loss and this is the
324 optical fix */
325 }
326
327 return retval;
328}
329
330/**
331 * Set the min value for restriction of the value range.
332 * @param int newmin - depending wether dBfs is used
333 * newmin is a value in dBfs * 100 or in linear percent values.
334 * for dBfs: -9000 < newmin <= 0
335 * for linear: 0 <= newmin <= 100
336 */
337void peak_meter_set_min(int newmin) {
338 if (peak_meter_use_dbfs) {
339 peak_meter_range_min = db_to_sample(newmin);
340
341 } else {
342 if (newmin < peak_meter_range_max) {
343 peak_meter_range_min = newmin * MAX_PEAK / 100;
344 }
345 }
346 db_scale_valid = false;
347}
348
349/**
350 * Returns the minimum value of the range the meter
351 * displays. If the scale is set to dBfs it returns
352 * dBfs values * 100 or linear percent values.
353 * @return: using dBfs : -9000 < value <= 0
354 * using linear scale: 0 <= value <= 100
355 */
356int peak_meter_get_min(void) {
357 int retval = 0;
358 if (peak_meter_use_dbfs) {
359 retval = calc_db(peak_meter_range_min) - calc_db(MAX_PEAK - 1);
360 } else {
361 retval = peak_meter_range_min * 100 / MAX_PEAK;
362 }
363 return retval;
364}
365
366/**
367 * Set the max value for restriction of the value range.
368 * @param int newmax - depending wether dBfs is used
369 * newmax is a value in dBfs * 100 or in linear percent values.
370 * for dBfs: -9000 < newmax <= 0
371 * for linear: 0 <= newmax <= 100
372 */
373void peak_meter_set_max(int newmax) {
374 if (peak_meter_use_dbfs) {
375 peak_meter_range_max = db_to_sample(newmax);
376 } else {
377 if (newmax > peak_meter_range_min) {
378 peak_meter_range_max = newmax * MAX_PEAK / 100;
379 }
380 }
381 db_scale_valid = false;
382}
383
384/**
385 * Returns the minimum value of the range the meter
386 * displays. If the scale is set to dBfs it returns
387 * dBfs values * 100 or linear percent values
388 * @return: using dBfs : -9000 < value <= 0
389 * using linear scale: 0 <= value <= 100
390 */
391int peak_meter_get_max(void) {
392 int retval = 0;
393 if (peak_meter_use_dbfs) {
394 retval = calc_db(peak_meter_range_max) - calc_db(MAX_PEAK - 1);
395 } else {
396 retval = peak_meter_range_max * 100 / MAX_PEAK;
397 }
398 return retval;
399}
400
401/**
402 * Returns 1 if the meter currently is
403 * displaying dBfs values, 0 if the meter
404 * displays percent values.
405 * @return int - returns 0 or 1.
406 */
407int peak_meter_get_use_dbfs(void) {
408 return peak_meter_use_dbfs ? 1 : 0;
409}
410
411/**
412 * Specifies wether the values displayed are scaled
413 * as dBfs or as linear percent values.
414 * @param int - Set to 0 for linear percent scale. Any other value
415 * switches on dBfs.
416 */
417void peak_meter_set_use_dbfs(int use){
418 peak_meter_use_dbfs = ((use & 1) == 1);
419 db_scale_valid = false;
420}
421
422/**
423 * Initialize the range of the meter. Only values
424 * that are in the range of [range_min ... range_max]
425 * are displayed.
426 * @param bool dbfs - set to true for dBfs,
427 * set to false for linear scaling in percent
428 * @param int range_min - Specifies the lower value of the range.
429 * Pass a value dBfs * 100 when dbfs is set to true.
430 * Pass a percent value when dbfs is set to false.
431 * @param int range_max - Specifies the upper value of the range.
432 * Pass a value dBfs * 100 when dbfs is set to true.
433 * Pass a percent value when dbfs is set to false.
434 */
435void peak_meter_init_range( bool dbfs, int range_min, int range_max) {
436 peak_meter_use_dbfs = dbfs;
437 peak_meter_set_min(range_min);
438 peak_meter_set_max(range_max);
439}
440
441/**
442 * Initialize the peak meter with all relevant values concerning times.
443 * @param int release - Set the maximum amount of pixels the meter is allowed
444 * to decrease with each redraw
445 * @param int hold - Select the time preset for the time the peak indicator
446 * is reset after a peak occurred. The preset values are
447 * stored in max_time_out.
448 * @param int clip_hold - Select the time preset for the time the peak
449 * indicator is reset after a peak occurred. The preset
450 * values are stored in clip_time_out.
451 */
452void peak_meter_init_times(int release, int hold, int clip_hold) {
453 peak_meter_hold = hold;
454 peak_meter_release = release;
455 peak_meter_clip_hold = clip_hold;
456}
457
83/** 458/**
84 * Set the source of the peak meter to playback or to 459 * Set the source of the peak meter to playback or to
85 * record. 460 * record.
@@ -127,20 +502,58 @@ void peak_meter_peek(void) {
127 (left == MAX_PEAK - 1)) { 502 (left == MAX_PEAK - 1)) {
128 peak_meter_l_clip = true; 503 peak_meter_l_clip = true;
129 peak_meter_clip_timeout_l = 504 peak_meter_clip_timeout_l =
130 current_tick + clip_time_out[global_settings.peak_meter_clip_hold]; 505 current_tick + clip_time_out[peak_meter_clip_hold];
131 } 506 }
132 507
133 if ((right == peak_meter_r) && 508 if ((right == peak_meter_r) &&
134 (right == MAX_PEAK - 1)) { 509 (right == MAX_PEAK - 1)) {
135 peak_meter_r_clip = true; 510 peak_meter_r_clip = true;
136 peak_meter_clip_timeout_r = 511 peak_meter_clip_timeout_r =
137 current_tick + clip_time_out[global_settings.peak_meter_clip_hold]; 512 current_tick + clip_time_out[peak_meter_clip_hold];
138 } 513 }
139 514
140 /* peaks are searched -> we have to find the maximum */ 515 /* peaks are searched -> we have to find the maximum. When
516 many calls of peak_meter_peek the maximum value will be
517 stored in peak_meter_x. This maximum is reset by the
518 functions peak_meter_read_x. */
141 peak_meter_l = MAX(peak_meter_l, left); 519 peak_meter_l = MAX(peak_meter_l, left);
142 peak_meter_r = MAX(peak_meter_r, right); 520 peak_meter_r = MAX(peak_meter_r, right);
521
522#ifdef PM_DEBUG
523 peek_calls++;
524#endif
525}
526
527
528/**
529 * The thread function for the peak meter calls peak_meter_peek
530 * to reas out the mas and find maxima, clips, etc. No display
531 * is performed.
532 */
533/*
534void peak_meter_thread(void) {
535 sleep(5000);
536 while (1) {
537 if (peak_meter_enabled && peak_meter_use_thread){
538 peak_meter_peek();
539 }
540 yield();
541 }
542}
543*/
544
545/**
546 * Creates the peak meter thread
547 */
548/*
549void peak_meter_init(void) {
550 create_thread(
551 peak_meter_thread,
552 peak_meter_stack,
553 sizeof peak_meter_stack,
554 "peakmeter");
143} 555}
556*/
144 557
145/** 558/**
146 * Reads out the peak volume of the left channel. 559 * Reads out the peak volume of the left channel.
@@ -149,10 +562,20 @@ void peak_meter_peek(void) {
149 * is in the range 0 <= value < MAX_PEAK. 562 * is in the range 0 <= value < MAX_PEAK.
150 */ 563 */
151static int peak_meter_read_l (void) { 564static int peak_meter_read_l (void) {
565 /* peak_meter_l contains the maximum of
566 all peak values that were read by peak_meter_peek
567 since the last call of peak_meter_read_r */
152 int retval = peak_meter_l; 568 int retval = peak_meter_l;
569#ifdef PM_DEBUG
570 peek_calls = 0;
571#endif
572
153#ifdef SIMULATOR 573#ifdef SIMULATOR
154 peak_meter_l = 8000; 574 peak_meter_l = 8000;
155#else 575#else
576 /* reset peak_meter_l so that subsequent calls of
577 peak_meter_peek doesn't get fooled by an old
578 maximum value */
156 peak_meter_l = mas_codec_readreg(peak_meter_src_l); 579 peak_meter_l = mas_codec_readreg(peak_meter_src_l);
157#endif 580#endif
158 return retval; 581 return retval;
@@ -165,10 +588,20 @@ static int peak_meter_read_l (void) {
165 * is in the range 0 <= value < MAX_PEAK. 588 * is in the range 0 <= value < MAX_PEAK.
166 */ 589 */
167static int peak_meter_read_r (void) { 590static int peak_meter_read_r (void) {
591 /* peak_meter_r contains the maximum of
592 all peak values that were read by peak_meter_peek
593 since the last call of peak_meter_read_r */
168 int retval = peak_meter_r; 594 int retval = peak_meter_r;
595#ifdef PM_DEBUG
596 peek_calls = 0;
597#endif
598
169#ifdef SIMULATOR 599#ifdef SIMULATOR
170 peak_meter_l = 8000; 600 peak_meter_l = 8000;
171#else 601#else
602 /* reset peak_meter_r so that subsequent calls of
603 peak_meter_peek doesn't get fooled by an old
604 maximum value */
172 peak_meter_r = mas_codec_readreg(peak_meter_src_r); 605 peak_meter_r = mas_codec_readreg(peak_meter_src_r);
173#endif 606#endif
174 return retval; 607 return retval;
@@ -190,6 +623,51 @@ void peak_meter_set_clip_hold(int time) {
190 } 623 }
191} 624}
192 625
626/**
627 * Scales a peak value as read from the MAS to the range of meterwidth.
628 * The scaling is performed according to the scaling method (dBfs / linear)
629 * and the range (peak_meter_range_min .. peak_meter_range_max).
630 * @param unsigned short val - The volume value. Range: 0 <= val < MAX_PEAK
631 * @param int meterwidht - The widht of the meter in pixel
632 * @return unsigned short - A value 0 <= return value <= meterwidth
633 */
634unsigned short peak_meter_scale_value(unsigned short val, int meterwidth){
635 int range;
636 int retval;
637
638 if (val <= peak_meter_range_min) {
639 return 0;
640 }
641
642 if (val >= peak_meter_range_max) {
643 return meterwidth;
644 }
645
646 retval = val;
647
648 /* different scaling is used for dBfs and linear percent */
649 if (peak_meter_use_dbfs) {
650
651 /* needed the offset in 'zoomed' meters */
652 int dbmin = calc_db(peak_meter_range_min);
653
654 range = calc_db(peak_meter_range_max) - dbmin;
655
656 /* scale the samples dBfs */
657 retval = (calc_db(retval) - dbmin) * meterwidth / range;
658 }
659
660 /* Scale for linear percent display */
661 else
662 {
663 range =(peak_meter_range_max - peak_meter_range_min);
664
665 /* scale the samples */
666 retval = ((retval - peak_meter_range_min) * meterwidth) / range;
667 }
668 return retval;
669}
670
193 671
194/** 672/**
195 * Draws a peak meter in the specified size at the specified position. 673 * Draws a peak meter in the specified size at the specified position.
@@ -208,22 +686,66 @@ void peak_meter_draw(int x, int y, int width, int height) {
208 int meterwidth = width - 3; 686 int meterwidth = width - 3;
209 int i; 687 int i;
210 688
689#ifdef PM_DEBUG
690 static long pm_tick = 0;
691 int tmp = peek_calls;
692#endif
693
211 /* if disabled only draw the peak meter */ 694 /* if disabled only draw the peak meter */
212 if (peak_meter_enabled) { 695 if (peak_meter_enabled) {
696
213 /* read the volume info from MAS */ 697 /* read the volume info from MAS */
214 left = peak_meter_read_l(); 698 left = peak_meter_read_l();
215 right = peak_meter_read_r(); 699 right = peak_meter_read_r();
216
217 peak_meter_peek(); 700 peak_meter_peek();
218 701
702 /* restrict the range to avoid drawing outside the lcd */
703 left = MAX(peak_meter_range_min, left);
704 left = MIN(peak_meter_range_max, left);
705
706 right = MAX(peak_meter_range_min, right);
707 right = MIN(peak_meter_range_max, right);
708
709 /* scale the samples dBfs */
710 left = peak_meter_scale_value(left, meterwidth);
711 right = peak_meter_scale_value(right, meterwidth);
712
713 /* if the scale has changed -> recalculate the scale
714 (The scale becomes invalid when the range changed.) */
715 if (!db_scale_valid){
716
717 if (peak_meter_use_dbfs) {
718 db_scale_count = sizeof db_scale_src_values / sizeof (int);
719 for (i = 0; i < db_scale_count; i++){
720 /* find the real x-coords for predefined interesting
721 dBfs values. These only are recalculated when the
722 scaling of the meter changed. */
723 db_scale_lcd_coord[i] =
724 peak_meter_scale_value(
725 db_scale_src_values[i],
726 meterwidth - 1);
727 }
728 }
219 729
220 /* scale the samples */ 730 /* when scaling linear we simly make 10% steps */
221 left /= (MAX_PEAK / meterwidth); 731 else {
222 right /= (MAX_PEAK / meterwidth); 732 int range = peak_meter_range_max - peak_meter_range_min;
733 db_scale_count = 10;
734 for (i = 0; i < db_scale_count; i++) {
735 db_scale_lcd_coord[i] =
736 (i * (MAX_PEAK / 10) - peak_meter_range_min) *
737 meterwidth / range;
738 }
739 }
740
741 /* mark scale valid to avoid recalculating dBfs values
742 of the scale. */
743 db_scale_valid = true;
744 }
223 745
224 /* apply release */ 746 /* apply release */
225 left = MAX(left , last_left - global_settings.peak_meter_release); 747 left = MAX(left , last_left - peak_meter_release);
226 right = MAX(right, last_right - global_settings.peak_meter_release); 748 right = MAX(right, last_right - peak_meter_release);
227 749
228 /* reset max values after timeout */ 750 /* reset max values after timeout */
229 if (TIME_AFTER(current_tick, peak_meter_timeout_l)){ 751 if (TIME_AFTER(current_tick, peak_meter_timeout_l)){
@@ -250,13 +772,13 @@ void peak_meter_draw(int x, int y, int width, int height) {
250 if (left > peak_meter_max_l) { 772 if (left > peak_meter_max_l) {
251 peak_meter_max_l = left - 1; 773 peak_meter_max_l = left - 1;
252 peak_meter_timeout_l = 774 peak_meter_timeout_l =
253 current_tick + max_time_out[global_settings.peak_meter_hold]; 775 current_tick + max_time_out[peak_meter_hold];
254 } 776 }
255 777
256 if (right > peak_meter_max_r) { 778 if (right > peak_meter_max_r) {
257 peak_meter_max_r = right - 1; 779 peak_meter_max_r = right - 1;
258 peak_meter_timeout_r = 780 peak_meter_timeout_r =
259 current_tick + max_time_out[global_settings.peak_meter_hold]; 781 current_tick + max_time_out[peak_meter_hold];
260 } 782 }
261 } 783 }
262 784
@@ -283,13 +805,90 @@ void peak_meter_draw(int x, int y, int width, int height) {
283 lcd_fillrect(x + meterwidth, y + height / 2, 3, height / 2 - 1); 805 lcd_fillrect(x + meterwidth, y + height / 2, 3, height / 2 - 1);
284 } 806 }
285 807
286 /* draw scale */ 808 /* draw scale end */
287 lcd_drawline(x + meterwidth, y, 809 lcd_drawline(x + meterwidth, y,
288 x + meterwidth, y + height - 2); 810 x + meterwidth, y + height - 2);
289 for (i = 0; i < 10; i++) { 811
290 lcd_invertpixel(x + meterwidth * i / 10, y + height / 2 - 1); 812 /* draw dots for scale marks */
813 for (i = 0; i < db_scale_count; i++) {
814 /* The x-coordinates of interesting scale mark points
815 have been calculated before */
816 lcd_invertpixel(db_scale_lcd_coord[i], y + height / 2 - 1);
817 }
818
819#ifdef PM_DEBUG
820 /* display a bar to show how many calls to peak_meter_peek
821 have ocurred since the last display */
822 lcd_invertrect(x, y, tmp, 3);
823
824 if (tmp < PEEKS_PER_DRAW_SIZE) {
825 peeks_per_redraw[tmp]++;
826 }
827
828 tmp = current_tick - pm_tick;
829 if (tmp < TICKS_PER_DRAW_SIZE ){
830 ticks_per_redraw[tmp] ++;
291 } 831 }
292 832
833 /* display a bar to show how many ticks have passed since
834 the last redraw */
835 lcd_invertrect(x, y + height / 2, current_tick - pm_tick, 2);
836 pm_tick = current_tick;
837#endif
838
293 last_left = left; 839 last_left = left;
294 last_right = right; 840 last_right = right;
295} 841}
842
843#ifdef PM_DEBUG
844static void peak_meter_clear_histogram(void) {
845 int i = 0;
846 for (i = 0; i < TICKS_PER_DRAW_SIZE; i++) {
847 ticks_per_redraw[i] = (unsigned int)0;
848 }
849
850 for (i = 0; i < PEEKS_PER_DRAW_SIZE; i++) {
851 peeks_per_redraw[i] = (unsigned int)0;
852 }
853}
854
855bool peak_meter_histogram(void) {
856 int i;
857 int btn = BUTTON_NONE;
858 while ((btn & BUTTON_OFF) != BUTTON_OFF )
859 {
860 unsigned int max = 0;
861 int y = 0;
862 int x = 0;
863 lcd_clear_display();
864
865 for (i = 0; i < PEEKS_PER_DRAW_SIZE; i++) {
866 max = MAX(max, peeks_per_redraw[i]);
867 }
868
869 for (i = 0; i < PEEKS_PER_DRAW_SIZE; i++) {
870 x = peeks_per_redraw[i] * (LCD_WIDTH - 1)/ max;
871 lcd_drawline(0, y + i, x, y + i);
872 }
873
874 y = PEEKS_PER_DRAW_SIZE + 1;
875 max = 0;
876
877 for (i = 0; i < TICKS_PER_DRAW_SIZE; i++) {
878 max = MAX(max, ticks_per_redraw[i]);
879 }
880
881 for (i = 0; i < TICKS_PER_DRAW_SIZE; i++) {
882 x = ticks_per_redraw[i] * (LCD_WIDTH - 1)/ max;
883 lcd_drawline(0, y + i, x, y + i);
884 }
885 lcd_update();
886
887 btn = button_get(true);
888 if (btn == BUTTON_PLAY) {
889 peak_meter_clear_histogram();
890 }
891 }
892 return false;
893}
894#endif