summaryrefslogtreecommitdiff
path: root/apps/recorder
diff options
context:
space:
mode:
Diffstat (limited to 'apps/recorder')
-rw-r--r--apps/recorder/peakmeter.c292
-rw-r--r--apps/recorder/peakmeter.h29
2 files changed, 321 insertions, 0 deletions
diff --git a/apps/recorder/peakmeter.c b/apps/recorder/peakmeter.c
new file mode 100644
index 0000000000..d184641c67
--- /dev/null
+++ b/apps/recorder/peakmeter.c
@@ -0,0 +1,292 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Philipp Pertermann
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include "mas.h"
20#include "thread.h"
21#include "kernel.h"
22#include "settings.h"
23#include "lcd.h"
24#include "wps-display.h"
25#include "sprintf.h"
26#include "button.h"
27#include "system.h"
28#include "font.h"
29#include "icons.h"
30#include "lang.h"
31#include "peakmeter.h"
32
33/* buffer the read peak value */
34static int peak_meter_max_l;
35static int peak_meter_max_r;
36
37/* point in time when peak_meter_max_x becomes invalid */
38static long peak_meter_timeout_l;
39static long peak_meter_timeout_r;
40
41/* when true a clip has occurred */
42static bool peak_meter_l_clip = false;
43static bool peak_meter_r_clip = false;
44
45/* point in time when peak_meter_x_oveflow becomes invalid */
46static long peak_meter_clip_timeout_l;
47static long peak_meter_clip_timeout_r;
48
49/* if set to true clip timeout is disabled */
50static bool peak_meter_clip_eternal = false;
51
52#ifndef SIMULATOR
53static int peak_meter_src_l = MAS_REG_DQPEAK_L;
54static int peak_meter_src_r = MAS_REG_DQPEAK_R;
55#endif
56
57/* temporarily en- / disables peak meter. This is
58 especially for external applications to detect
59 if the peak_meter is in use and needs drawing at all */
60bool peak_meter_enabled = true;
61
62static int peak_meter_l;
63static int peak_meter_r;
64
65/* time out values for max */
66static long max_time_out[] = {
67 0 * HZ, HZ / 5, 30, HZ / 2, HZ, 2 * HZ,
68 3 * HZ, 4 * HZ, 5 * HZ, 6 * HZ, 7 * HZ, 8 * HZ,
69 9 * HZ, 10 * HZ, 15 * HZ, 20 * HZ, 30 * HZ, 60 * HZ
70};
71
72/* time out values for clip */
73static long clip_time_out[] = {
74 0 * HZ, 1 * HZ, 2 * HZ, 3 * HZ, 4 * HZ, 5 * HZ,
75 6 * HZ, 7 * HZ, 8 * HZ, 9 * HZ, 10 * HZ, 15 * HZ,
76 20 * HZ, 25 * HZ, 30 * HZ, 45 * HZ, 60 * HZ, 90 * HZ,
77 120 * HZ, 180 * HZ, 300 * HZ, 600 * HZ, 1200 * HZ,
78 2700 * HZ, 5400 * HZ
79};
80
81/**
82 * Set the source of the peak meter to playback or to
83 * record.
84 * @param: bool playback - If true playback peak meter is used.
85 * If false recording peak meter is used.
86 */
87void peak_meter_playback(bool playback) {
88#ifdef SIMULATOR
89 (void)playback;
90#else
91 if (playback) {
92 peak_meter_src_l = MAS_REG_DQPEAK_L;
93 peak_meter_src_r = MAS_REG_DQPEAK_R;
94 } else {
95 peak_meter_src_l = MAS_REG_QPEAK_L;
96 peak_meter_src_r = MAS_REG_QPEAK_R;
97 }
98#endif
99}
100
101/**
102 * Reads peak values from the MAS, and detects clips. The
103 * values are stored in peak_meter_l peak_meter_r for later
104 * evauluation. Consecutive calls to peak_meter_peek detect
105 * that ocurred. This function could be used by a thread for
106 * busy reading the MAS.
107 */
108static void peak_meter_peek(void) {
109#ifdef SIMULATOR
110 int left = 8000;
111 int right = 9000;
112#else
113 /* read the peak values */
114 int left = mas_codec_readreg(peak_meter_src_l);
115 int right = mas_codec_readreg(peak_meter_src_r);
116#endif
117
118 /* check for clips
119 An clip is assumed when two consecutive readouts
120 of the volume are at full scale. This is proven
121 to be inaccurate in both ways: it may detect clips
122 when no clip occurred and it may fail to detect
123 a real clip. */
124 if ((left == peak_meter_l) &&
125 (left == MAX_PEAK - 1)) {
126 peak_meter_l_clip = true;
127 peak_meter_clip_timeout_l =
128 current_tick + clip_time_out[global_settings.peak_meter_clip_hold];
129 }
130
131 if ((right == peak_meter_r) &&
132 (right == MAX_PEAK - 1)) {
133 peak_meter_r_clip = true;
134 peak_meter_clip_timeout_r =
135 current_tick + clip_time_out[global_settings.peak_meter_clip_hold];
136 }
137
138 /* peaks are searched -> we have to find the maximum */
139 peak_meter_l = MAX(peak_meter_l, left);
140 peak_meter_r = MAX(peak_meter_r, right);
141}
142
143/**
144 * Reads out the peak volume of the left channel.
145 * @return int - The maximum value that has been detected
146 * since the last call of peak_meter_read_l. The value
147 * is in the range 0 <= value < MAX_PEAK.
148 */
149static int peak_meter_read_l (void) {
150 int retval = peak_meter_l;
151#ifdef SIMULATOR
152 peak_meter_l = 8000;
153#else
154 peak_meter_l = mas_codec_readreg(peak_meter_src_l);
155#endif
156 return retval;
157}
158
159/**
160 * Reads out the peak volume of the right channel.
161 * @return int - The maximum value that has been detected
162 * since the last call of peak_meter_read_l. The value
163 * is in the range 0 <= value < MAX_PEAK.
164 */
165static int peak_meter_read_r (void) {
166 int retval = peak_meter_r;
167#ifdef SIMULATOR
168 peak_meter_l = 8000;
169#else
170 peak_meter_r = mas_codec_readreg(peak_meter_src_r);
171#endif
172 return retval;
173}
174
175/**
176 * Reset the detected clips. This method is for
177 * use by the user interface.
178 * @param int unused - This parameter was added to
179 * make the function compatible with set_int
180 */
181void peak_meter_set_clip_hold(int time) {
182 peak_meter_clip_eternal = false;
183
184 if (time <= 0) {
185 peak_meter_l_clip = false;
186 peak_meter_r_clip = false;
187 peak_meter_clip_eternal = true;
188 }
189}
190
191
192/**
193 * Draws a peak meter in the specified size at the specified position.
194 * @param int x - The x coordinate.
195 * Make sure that 0 <= x and x + width < LCD_WIDTH
196 * @param int y - The y coordinate.
197 * Make sure that 0 <= y and y + height < LCD_HEIGHT
198 * @param int width - The width of the peak meter. Note that for display
199 * of clips a 3 pixel wide area is used ->
200 * width > 3
201 * @param int height - The height of the peak meter. height > 3
202 */
203void peak_meter_draw(int x, int y, int width, int height) {
204 int left = 0, right = 0;
205 static int last_left = 0, last_right = 0;
206 int meterwidth = width - 3;
207 int i;
208
209 /* if disabled only draw the peak meter */
210 if (peak_meter_enabled) {
211 /* read the volume info from MAS */
212 left = peak_meter_read_l();
213 right = peak_meter_read_r();
214 peak_meter_peek();
215
216
217 /* scale the samples */
218 left /= (MAX_PEAK / meterwidth);
219 right /= (MAX_PEAK / meterwidth);
220
221 /* apply release */
222 left = MAX(left , last_left - global_settings.peak_meter_release);
223 right = MAX(right, last_right - global_settings.peak_meter_release);
224
225 /* reset max values after timeout */
226 if (TIME_AFTER(current_tick, peak_meter_timeout_l)){
227 peak_meter_max_l = 0;
228 }
229
230 if (TIME_AFTER(current_tick, peak_meter_timeout_r)){
231 peak_meter_max_r = 0;
232 }
233
234 if (!peak_meter_clip_eternal) {
235 if (peak_meter_l_clip &&
236 TIME_AFTER(current_tick, peak_meter_clip_timeout_l)){
237 peak_meter_l_clip = false;
238 }
239
240 if (peak_meter_r_clip &&
241 TIME_AFTER(current_tick, peak_meter_clip_timeout_r)){
242 peak_meter_r_clip = false;
243 }
244 }
245
246 /* check for new max values */
247 if (left > peak_meter_max_l) {
248 peak_meter_max_l = left - 1;
249 peak_meter_timeout_l =
250 current_tick + max_time_out[global_settings.peak_meter_hold];
251 }
252
253 if (right > peak_meter_max_r) {
254 peak_meter_max_r = right - 1;
255 peak_meter_timeout_r =
256 current_tick + max_time_out[global_settings.peak_meter_hold];
257 }
258 }
259
260 /* draw the peak meter */
261 lcd_clearrect(x, y, width, height);
262
263 /* draw left */
264 lcd_fillrect (x, y, left, height / 2 - 2 );
265 if (peak_meter_max_l > 0) {
266 lcd_drawline(x + peak_meter_max_l, y,
267 x + peak_meter_max_l, y + height / 2 - 2 );
268 }
269 if (peak_meter_l_clip) {
270 lcd_fillrect(x + meterwidth, y, 3, height / 2 - 1);
271 }
272
273 /* draw right */
274 lcd_fillrect(x, y + height / 2 + 1, right, height / 2 - 2);
275 if (peak_meter_max_r > 0) {
276 lcd_drawline( x + peak_meter_max_r, y + height / 2,
277 x + peak_meter_max_r, y + height - 2);
278 }
279 if (peak_meter_r_clip) {
280 lcd_fillrect(x + meterwidth, y + height / 2, 3, height / 2 - 1);
281 }
282
283 /* draw scale */
284 lcd_drawline(x + meterwidth, y,
285 x + meterwidth, y + height - 2);
286 for (i = 0; i < 10; i++) {
287 lcd_invertpixel(x + meterwidth * i / 10, y + height / 2 - 1);
288 }
289
290 last_left = left;
291 last_right = right;
292}
diff --git a/apps/recorder/peakmeter.h b/apps/recorder/peakmeter.h
new file mode 100644
index 0000000000..8d894cd920
--- /dev/null
+++ b/apps/recorder/peakmeter.h
@@ -0,0 +1,29 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Philipp Pertermann
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#ifndef __PEAKMETER_H__
20#define __PEAKMETER_H__
21
22extern bool peak_meter_enabled;
23
24extern void peak_meter_init(void);
25extern void peak_meter_playback(bool playback);
26extern void peak_meter_draw(int x, int y, int width, int height);
27extern void peak_meter_set_clip_hold(int time);
28
29#endif /* __PEAKMETER_H__ */