Bump version numbers for 3.13
[maemo-rb.git] / apps / plugins / oscilloscope.c
blob13cc359a5d74e29cd64bc162c7bd57295f2c1306
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Oscilloscope, with many different modes of operation.
12 * Copyright (C) 2004-2006 Jens Arnold
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
24 #include "plugin.h"
25 #include "lib/helper.h"
26 #include "lib/pluginlib_exit.h"
28 #include "lib/xlcd.h"
29 #include "lib/configfile.h"
30 #include "fixedpoint.h"
31 #include "lib/fixedpoint.h"
32 #include "lib/osd.h"
34 /* variable button definitions */
35 #if CONFIG_KEYPAD == RECORDER_PAD
36 #define OSCILLOSCOPE_QUIT BUTTON_OFF
37 #define OSCILLOSCOPE_DRAWMODE BUTTON_F1
38 #define OSCILLOSCOPE_ADVMODE BUTTON_F2
39 #define OSCILLOSCOPE_ORIENTATION BUTTON_F3
40 #define OSCILLOSCOPE_PAUSE BUTTON_PLAY
41 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
42 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
43 #define OSCILLOSCOPE_VOL_UP BUTTON_UP
44 #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
46 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
47 #define OSCILLOSCOPE_QUIT BUTTON_OFF
48 #define OSCILLOSCOPE_DRAWMODE BUTTON_F1
49 #define OSCILLOSCOPE_ADVMODE BUTTON_F2
50 #define OSCILLOSCOPE_ORIENTATION BUTTON_F3
51 #define OSCILLOSCOPE_PAUSE BUTTON_SELECT
52 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
53 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
54 #define OSCILLOSCOPE_VOL_UP BUTTON_UP
55 #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
57 #elif CONFIG_KEYPAD == ONDIO_PAD
58 #define OSCILLOSCOPE_QUIT BUTTON_OFF
59 #define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_MENU
60 #define OSCILLOSCOPE_DRAWMODE (BUTTON_MENU | BUTTON_REL)
61 #define OSCILLOSCOPE_ADVMODE (BUTTON_MENU | BUTTON_RIGHT)
62 #define OSCILLOSCOPE_ORIENTATION (BUTTON_MENU | BUTTON_LEFT)
63 #define OSCILLOSCOPE_PAUSE (BUTTON_MENU | BUTTON_OFF)
64 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
65 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
66 #define OSCILLOSCOPE_VOL_UP BUTTON_UP
67 #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
68 #define NEED_LASTBUTTON
70 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
71 #define OSCILLOSCOPE_QUIT BUTTON_OFF
72 #define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
73 #define OSCILLOSCOPE_ADVMODE BUTTON_MODE
74 #define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_REC
75 #define OSCILLOSCOPE_ORIENTATION (BUTTON_REC | BUTTON_REL)
76 #define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_REC
77 #define OSCILLOSCOPE_GRAPHMODE (BUTTON_REC | BUTTON_REPEAT)
78 #define OSCILLOSCOPE_PAUSE BUTTON_ON
79 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
80 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
81 #define OSCILLOSCOPE_VOL_UP BUTTON_UP
82 #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
83 #define OSCILLOSCOPE_RC_QUIT BUTTON_RC_STOP
84 #define NEED_LASTBUTTON
86 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
87 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
88 #define OSCILLOSCOPE_QUIT (BUTTON_SELECT | BUTTON_MENU)
89 #define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_PLAY)
90 #define OSCILLOSCOPE_ADVMODE (BUTTON_SELECT | BUTTON_RIGHT)
91 #define OSCILLOSCOPE_ORIENTATION (BUTTON_SELECT | BUTTON_LEFT)
92 #define OSCILLOSCOPE_GRAPHMODE BUTTON_MENU
93 #define OSCILLOSCOPE_PAUSE BUTTON_PLAY
94 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
95 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
96 #define OSCILLOSCOPE_VOL_UP BUTTON_SCROLL_FWD
97 #define OSCILLOSCOPE_VOL_DOWN BUTTON_SCROLL_BACK
98 /* Need GRAPHMODE */
100 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
101 #define OSCILLOSCOPE_QUIT BUTTON_POWER
102 #define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
103 #define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
104 #define OSCILLOSCOPE_ORIENTATION BUTTON_UP
105 #define OSCILLOSCOPE_GRAPHMODE BUTTON_MENU
106 #define OSCILLOSCOPE_PAUSE BUTTON_A
107 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
108 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
109 #define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
110 #define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
112 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
113 #define OSCILLOSCOPE_QUIT BUTTON_POWER
114 #define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_SELECT
115 #define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_REL)
116 #define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_SELECT
117 #define OSCILLOSCOPE_ORIENTATION (BUTTON_SELECT | BUTTON_REPEAT)
118 #define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
119 #define OSCILLOSCOPE_PAUSE_PRE BUTTON_UP
120 #define OSCILLOSCOPE_PAUSE (BUTTON_UP | BUTTON_REL)
121 #define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_UP
122 #define OSCILLOSCOPE_GRAPHMODE (BUTTON_UP | BUTTON_REPEAT)
123 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
124 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
125 #define OSCILLOSCOPE_VOL_UP BUTTON_SCROLL_FWD
126 #define OSCILLOSCOPE_VOL_DOWN BUTTON_SCROLL_BACK
127 #define NEED_LASTBUTTON
129 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
130 #define OSCILLOSCOPE_QUIT (BUTTON_HOME|BUTTON_REPEAT)
131 #define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_SELECT
132 #define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_REL)
133 #define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_SELECT
134 #define OSCILLOSCOPE_ORIENTATION (BUTTON_SELECT | BUTTON_REPEAT)
135 #define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
136 #define OSCILLOSCOPE_PAUSE_PRE BUTTON_UP
137 #define OSCILLOSCOPE_PAUSE (BUTTON_UP | BUTTON_REL)
138 #define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_UP
139 #define OSCILLOSCOPE_GRAPHMODE (BUTTON_UP | BUTTON_REPEAT)
140 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
141 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
142 #define OSCILLOSCOPE_VOL_UP BUTTON_SCROLL_FWD
143 #define OSCILLOSCOPE_VOL_DOWN BUTTON_SCROLL_BACK
144 #define NEED_LASTBUTTON
146 #elif (CONFIG_KEYPAD == SANSA_C200_PAD)
147 #define OSCILLOSCOPE_QUIT BUTTON_POWER
148 #define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
149 #define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
150 #define OSCILLOSCOPE_ORIENTATION BUTTON_UP
151 #define OSCILLOSCOPE_PAUSE BUTTON_REC
152 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
153 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
154 #define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
155 #define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
156 /* v1 - Need GRAPHMODE */
157 /* v2 - Not enough plugin RAM for waveform view */
159 #elif (CONFIG_KEYPAD == SANSA_CLIP_PAD)
160 #define OSCILLOSCOPE_QUIT BUTTON_POWER
161 #define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_SELECT
162 #define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_REL)
163 #define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_SELECT
164 #define OSCILLOSCOPE_ORIENTATION (BUTTON_SELECT | BUTTON_REPEAT)
165 #define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
166 #define OSCILLOSCOPE_PAUSE BUTTON_UP
167 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
168 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
169 #define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
170 #define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
171 #define NEED_LASTBUTTON
172 /* Not enough plugin RAM for waveform view */
174 #elif (CONFIG_KEYPAD == SANSA_M200_PAD)
175 #define OSCILLOSCOPE_QUIT BUTTON_POWER
176 #define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_REL)
177 #define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
178 #define OSCILLOSCOPE_ORIENTATION BUTTON_UP
179 #define OSCILLOSCOPE_PAUSE (BUTTON_SELECT | BUTTON_UP)
180 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
181 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
182 #define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
183 #define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
184 /* Not enough plugin RAM for waveform view */
186 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
187 #define OSCILLOSCOPE_QUIT BUTTON_POWER
188 #define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_SELECT
189 #define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_REL)
190 #define OSCILLOSCOPE_ADVMODE BUTTON_REC
191 #define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_SELECT
192 #define OSCILLOSCOPE_ORIENTATION (BUTTON_SELECT | BUTTON_REPEAT)
193 #define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_PLAY
194 #define OSCILLOSCOPE_GRAPHMODE (BUTTON_PLAY | BUTTON_REPEAT)
195 #define OSCILLOSCOPE_PAUSE_PRE BUTTON_PLAY
196 #define OSCILLOSCOPE_PAUSE (BUTTON_PLAY | BUTTON_REL)
197 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
198 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
199 #define OSCILLOSCOPE_VOL_UP BUTTON_UP
200 #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
201 #define NEED_LASTBUTTON
203 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
204 #define OSCILLOSCOPE_QUIT BUTTON_POWER
205 #define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_REW
206 #define OSCILLOSCOPE_DRAWMODE (BUTTON_REW | BUTTON_REL)
207 #define OSCILLOSCOPE_ADVMODE BUTTON_FF
208 #define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_REW
209 #define OSCILLOSCOPE_ORIENTATION (BUTTON_REW | BUTTON_REPEAT)
210 #define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_PLAY
211 #define OSCILLOSCOPE_GRAPHMODE (BUTTON_PLAY | BUTTON_REPEAT)
212 #define OSCILLOSCOPE_PAUSE_PRE BUTTON_PLAY
213 #define OSCILLOSCOPE_PAUSE (BUTTON_PLAY | BUTTON_REL)
214 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
215 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
216 #define OSCILLOSCOPE_VOL_UP BUTTON_SCROLL_UP
217 #define OSCILLOSCOPE_VOL_DOWN BUTTON_SCROLL_DOWN
218 #define NEED_LASTBUTTON
220 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
221 #define OSCILLOSCOPE_QUIT BUTTON_BACK
222 #define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
223 #define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
224 #define OSCILLOSCOPE_ORIENTATION BUTTON_UP
225 #define OSCILLOSCOPE_GRAPHMODE BUTTON_MENU
226 #define OSCILLOSCOPE_PAUSE BUTTON_PLAY
227 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
228 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
229 #define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
230 #define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
232 #elif (CONFIG_KEYPAD == MROBE100_PAD)
233 #define OSCILLOSCOPE_QUIT BUTTON_POWER
234 #define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
235 #define OSCILLOSCOPE_ADVMODE BUTTON_MENU
236 #define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_PLAY
237 #define OSCILLOSCOPE_ORIENTATION (BUTTON_PLAY | BUTTON_REL)
238 #define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_PLAY
239 #define OSCILLOSCOPE_GRAPHMODE (BUTTON_PLAY | BUTTON_REPEAT)
240 #define OSCILLOSCOPE_PAUSE BUTTON_DISPLAY
241 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
242 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
243 #define OSCILLOSCOPE_VOL_UP BUTTON_UP
244 #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
245 #define NEED_LASTBUTTON
247 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
248 #define OSCILLOSCOPE_QUIT BUTTON_RC_REC
249 #define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_RC_MODE
250 #define OSCILLOSCOPE_DRAWMODE (BUTTON_RC_MODE|BUTTON_REL)
251 #define OSCILLOSCOPE_ADVMODE BUTTON_RC_MENU
252 #define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_RC_MODE
253 #define OSCILLOSCOPE_ORIENTATION (BUTTON_RC_MODE|BUTTON_REPEAT)
254 #define OSCILLOSCOPE_PAUSE_PRE BUTTON_RC_PLAY
255 #define OSCILLOSCOPE_PAUSE (BUTTON_RC_PLAY|BUTTON_REL)
256 #define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_RC_PLAY
257 #define SCILLLOSCOPE_GRAPHMODE (BUTTON_RC_PLAY|BUTTON_REPEAT)
258 #define OSCILLOSCOPE_SPEED_UP BUTTON_RC_FF
259 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_RC_REW
260 #define OSCILLOSCOPE_VOL_UP BUTTON_RC_VOL_UP
261 #define OSCILLOSCOPE_VOL_DOWN BUTTON_RC_VOL_DOWN
262 #define NEED_LASTBUTTON
264 #elif CONFIG_KEYPAD == COWON_D2_PAD
265 #define OSCILLOSCOPE_QUIT BUTTON_POWER
266 #define OSCILLOSCOPE_VOL_UP BUTTON_PLUS
267 #define OSCILLOSCOPE_VOL_DOWN BUTTON_MINUS
269 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
270 #define OSCILLOSCOPE_QUIT BUTTON_BACK
271 #define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
272 #define OSCILLOSCOPE_ADVMODE BUTTON_CUSTOM
273 #define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_MENU
274 #define OSCILLOSCOPE_ORIENTATION (BUTTON_MENU | BUTTON_REL)
275 #define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_MENU
276 #define OSCILLOSCOPE_GRAPHMODE (BUTTON_MENU | BUTTON_REPEAT)
277 #define OSCILLOSCOPE_PAUSE BUTTON_PLAY
278 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
279 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
280 #define OSCILLOSCOPE_VOL_UP BUTTON_UP
281 #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
282 #define NEED_LASTBUTTON
284 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
285 #define OSCILLOSCOPE_QUIT BUTTON_POWER
286 #define OSCILLOSCOPE_DRAWMODE BUTTON_MENU
287 #define OSCILLOSCOPE_ADVMODE BUTTON_VIEW
288 #define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_UP
289 #define OSCILLOSCOPE_ORIENTATION (BUTTON_UP | BUTTON_REL)
290 #define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_UP
291 #define OSCILLOSCOPE_GRAPHMODE (BUTTON_UP | BUTTON_REPEAT)
292 #define OSCILLOSCOPE_PAUSE BUTTON_SELECT
293 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
294 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
295 #define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
296 #define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
297 #define NEED_LASTBUTTON
299 #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
300 #define OSCILLOSCOPE_QUIT BUTTON_POWER
301 #define OSCILLOSCOPE_DRAWMODE BUTTON_MENU
302 #define OSCILLOSCOPE_ADVMODE BUTTON_RIGHT
303 #define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_UP
304 #define OSCILLOSCOPE_ORIENTATION (BUTTON_UP | BUTTON_REL)
305 #define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_UP
306 #define OSCILLOSCOPE_GRAPHMODE (BUTTON_UP | BUTTON_REPEAT)
307 #define OSCILLOSCOPE_PAUSE BUTTON_PLAY
308 #define OSCILLOSCOPE_SPEED_UP BUTTON_NEXT
309 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_PREV
310 #define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
311 #define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
312 #define NEED_LASTBUTTON
314 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
315 #define OSCILLOSCOPE_QUIT BUTTON_POWER
316 #define OSCILLOSCOPE_DRAWMODE BUTTON_MENU
317 #define OSCILLOSCOPE_ADVMODE BUTTON_RIGHT
318 #define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_UP
319 #define OSCILLOSCOPE_ORIENTATION (BUTTON_UP | BUTTON_REL)
320 #define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_UP
321 #define OSCILLOSCOPE_GRAPHMODE (BUTTON_UP | BUTTON_REPEAT)
322 #define OSCILLOSCOPE_PAUSE BUTTON_PLAY
323 #define OSCILLOSCOPE_SPEED_UP BUTTON_NEXT
324 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_PREV
325 #define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
326 #define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
327 #define NEED_LASTBUTTON
329 #elif CONFIG_KEYPAD == ONDAVX747_PAD
330 #define OSCILLOSCOPE_QUIT BUTTON_POWER
331 #define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
332 #define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
334 #elif CONFIG_KEYPAD == ONDAVX777_PAD
335 #define OSCILLOSCOPE_QUIT BUTTON_POWER
337 #elif CONFIG_KEYPAD == MROBE500_PAD
338 #define OSCILLOSCOPE_QUIT BUTTON_POWER
340 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
341 #define OSCILLOSCOPE_QUIT BUTTON_REC
342 #define OSCILLOSCOPE_DRAWMODE (BUTTON_PLAY|BUTTON_LEFT)
343 #define OSCILLOSCOPE_ADVMODE (BUTTON_PLAY|BUTTON_RIGHT)
344 #define OSCILLOSCOPE_ORIENTATION (BUTTON_PLAY|BUTTON_UP)
345 #define OSCILLOSCOPE_PAUSE (BUTTON_PLAY|BUTTON_DOWN)
346 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
347 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
348 #define OSCILLOSCOPE_VOL_UP BUTTON_UP
349 #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
350 /* Need GRAPHMODE */
352 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
353 #define OSCILLOSCOPE_QUIT BUTTON_REC
354 #define OSCILLOSCOPE_DRAWMODE BUTTON_MENU
355 #define OSCILLOSCOPE_ADVMODE BUTTON_CANCEL
356 #define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_OK
357 #define OSCILLOSCOPE_ORIENTATION (BUTTON_OK | BUTTON_REL)
358 #define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_OK
359 #define OSCILLOSCOPE_GRAPHMODE (BUTTON_OK | BUTTON_REPEAT)
360 #define OSCILLOSCOPE_PAUSE BUTTON_PLAY
361 #define OSCILLOSCOPE_SPEED_UP BUTTON_PREV
362 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_NEXT
363 #define OSCILLOSCOPE_VOL_UP BUTTON_UP
364 #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
365 #define NEED_LASTBUTTON
367 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
368 #define OSCILLOSCOPE_QUIT (BUTTON_REC | BUTTON_PLAY)
369 #define OSCILLOSCOPE_DRAWMODE BUTTON_FUNC
370 #define OSCILLOSCOPE_ADVMODE BUTTON_REC
371 #define OSCILLOSCOPE_ORIENTATION (BUTTON_FUNC | BUTTON_REPEAT)
372 #define OSCILLOSCOPE_PAUSE BUTTON_PLAY
373 #define OSCILLOSCOPE_SPEED_UP BUTTON_FF
374 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_REW
375 #define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
376 #define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
377 /* Need GRAPHMODE */
379 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
380 #define OSCILLOSCOPE_QUIT (BUTTON_MENU | BUTTON_REPEAT)
381 #define OSCILLOSCOPE_DRAWMODE BUTTON_ENTER
382 #define OSCILLOSCOPE_ADVMODE BUTTON_REC
383 #define OSCILLOSCOPE_ORIENTATION BUTTON_MENU
384 #define OSCILLOSCOPE_PAUSE BUTTON_PLAY
385 #define OSCILLOSCOPE_SPEED_UP BUTTON_FF
386 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_REW
387 #define OSCILLOSCOPE_VOL_UP BUTTON_UP
388 #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
389 /* Need GRAPHMODE */
391 #elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
392 #define OSCILLOSCOPE_QUIT BUTTON_POWER
393 #define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
394 #define OSCILLOSCOPE_ADVMODE BUTTON_BACK
395 #define OSCILLOSCOPE_ORIENTATION BUTTON_UP
396 #define OSCILLOSCOPE_PAUSE BUTTON_PLAYPAUSE
397 #define OSCILLOSCOPE_SPEED_UP BUTTON_LEFT
398 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_RIGHT
399 #define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
400 #define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
401 /* Need GRAPHMODE */
403 #elif (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
404 #define OSCILLOSCOPE_QUIT BUTTON_POWER
405 #define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
406 #define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
407 #define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_UP
408 #define OSCILLOSCOPE_ORIENTATION (BUTTON_UP | BUTTON_REL)
409 #define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_UP
410 #define OSCILLOSCOPE_GRAPHMODE (BUTTON_UP | BUTTON_REPEAT)
411 #define OSCILLOSCOPE_PAUSE BUTTON_NEXT
412 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
413 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
414 #define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
415 #define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
416 #define NEED_LASTBUTTON
418 #elif (CONFIG_KEYPAD == SAMSUNG_YPR0_PAD)
419 #define OSCILLOSCOPE_QUIT BUTTON_BACK
420 #define OSCILLOSCOPE_DRAWMODE BUTTON_USER
421 #define OSCILLOSCOPE_ADVMODE BUTTON_MENU
422 #define OSCILLOSCOPE_ORIENTATION BUTTON_POWER
423 #define OSCILLOSCOPE_PAUSE BUTTON_SELECT
424 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
425 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
426 #define OSCILLOSCOPE_VOL_UP BUTTON_UP
427 #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
428 /* Need GRAPHMODE */
430 #elif (CONFIG_KEYPAD == HM60X_PAD)
431 #define OSCILLOSCOPE_QUIT BUTTON_POWER
432 #define OSCILLOSCOPE_DRAWMODE (BUTTON_POWER | BUTTON_SELECT)
433 #define OSCILLOSCOPE_ADVMODE (BUTTON_POWER | BUTTON_RIGHT)
434 #define OSCILLOSCOPE_ORIENTATION (BUTTON_POWER | BUTTON_LEFT)
435 #define OSCILLOSCOPE_PAUSE BUTTON_SELECT
436 #define OSCILLOSCOPE_SPEED_UP BUTTON_UP
437 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_DOWN
438 #define OSCILLOSCOPE_VOL_UP BUTTON_RIGHT
439 #define OSCILLOSCOPE_VOL_DOWN BUTTON_LEFT
440 /* Need GRAPHMODE */
442 #elif (CONFIG_KEYPAD == HM801_PAD)
443 #define OSCILLOSCOPE_QUIT BUTTON_POWER
444 #define OSCILLOSCOPE_DRAWMODE BUTTON_PREV
445 #define OSCILLOSCOPE_ADVMODE BUTTON_NEXT
446 #define OSCILLOSCOPE_ORIENTATION BUTTON_PLAY
447 #define OSCILLOSCOPE_PAUSE BUTTON_SELECT
448 #define OSCILLOSCOPE_SPEED_UP BUTTON_UP
449 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_DOWN
450 #define OSCILLOSCOPE_VOL_UP BUTTON_RIGHT
451 #define OSCILLOSCOPE_VOL_DOWN BUTTON_LEFT
452 /* Need GRAPHMODE */
454 #else
455 #error No keymap defined!
456 #endif
458 #ifdef HAVE_TOUCHSCREEN
459 #ifndef OSCILLOSCOPE_QUIT
460 #define OSCILLOSCOPE_QUIT BUTTON_TOPLEFT
461 #endif
462 #ifndef OSCILLOSCOPE_DRAWMODE
463 #define OSCILLOSCOPE_DRAWMODE BUTTON_TOPMIDDLE
464 #endif
465 #ifndef OSCILLOSCOPE_ADVMODE
466 #define OSCILLOSCOPE_ADVMODE BUTTON_BOTTOMMIDDLE
467 #endif
468 #ifndef OSCILLOSCOPE_ORIENTATION
469 #define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_BOTTOMLEFT
470 #define OSCILLOSCOPE_ORIENTATION (BUTTON_BOTTOMLEFT|BUTTON_REL)
471 #endif
472 #ifndef OSCILLOSCOPE_GRAPHMODE
473 #define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_BOTTOMLEFT
474 #define OSCILLOSCOPE_GRAPHMODE (BUTTON_BOTTOMLEFT|BUTTON_REPEAT)
475 #endif
476 #ifndef OSCILLOSCOPE_PAUSE
477 #define OSCILLOSCOPE_PAUSE BUTTON_CENTER
478 #endif
479 #ifndef OSCILLOSCOPE_SPEED_UP
480 #define OSCILLOSCOPE_SPEED_UP BUTTON_MIDRIGHT
481 #endif
482 #ifndef OSCILLOSCOPE_SPEED_DOWN
483 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_MIDLEFT
484 #endif
485 #ifndef OSCILLOSCOPE_VOL_UP
486 #define OSCILLOSCOPE_VOL_UP BUTTON_TOPRIGHT
487 #endif
488 #ifndef OSCILLOSCOPE_VOL_DOWN
489 #define OSCILLOSCOPE_VOL_DOWN BUTTON_BOTTOMRIGHT
490 #endif
491 #define NEED_LASTBUTTON
492 #endif /* HAVE_TOUCHSCREEN */
494 /* colours */
495 #if LCD_DEPTH > 1
496 #ifdef HAVE_LCD_COLOR
497 #define BACKG_COLOR LCD_BLACK
498 #define GRAPH_COLOR LCD_RGBPACK(128, 255, 0)
499 #define CURSOR_COLOR LCD_RGBPACK(255, 0, 0)
500 #define GRID_COLOR LCD_RGBPACK(192, 255, 64)
501 #define OSD_TEXT_COLOR LCD_WHITE
502 #define OSD_BACKG_COLOR LCD_BLACK
503 #define OSD_BORDER_COLOR LCD_RGBPACK(255, 0, 0)
504 #define OSC_OSD_MARGIN_SIZE 0 /* Border and text are different */
505 #else
506 #define BACKG_COLOR LCD_WHITE
507 #define GRAPH_COLOR LCD_BLACK
508 #define CURSOR_COLOR LCD_DARKGRAY
509 #define GRID_COLOR LCD_DARKGRAY
510 #define OSD_TEXT_COLOR LCD_BLACK
511 #define OSD_BACKG_COLOR LCD_WHITE
512 #define OSD_BORDER_COLOR LCD_BLACK
513 #endif
514 #endif
516 #ifndef OSC_OSD_MARGIN_SIZE
517 #define OSC_OSD_MARGIN_SIZE 1
518 #endif
520 #define MIN_SPEED 1
521 #define MAX_SPEED 100
523 enum { DRAW_FILLED, DRAW_LINE, DRAW_PIXEL, MAX_DRAW };
524 enum { ADV_SCROLL, ADV_WRAP, MAX_ADV };
525 enum { OSC_HORIZ, OSC_VERT, MAX_OSC };
526 enum
528 GRAPH_PEAKS,
529 #ifdef OSCILLOSCOPE_GRAPHMODE
530 GRAPH_WAVEFORM,
531 #endif
532 MAX_GRAPH
535 #define CFGFILE_VERSION 1 /* Current config file version */
536 #define CFGFILE_MINVERSION 0 /* Minimum config file version to accept */
538 /* global variables */
541 * / 99*[e ^ ((100 - x) / z) - 1] \
542 * osc_delay = HZ * | ---------------------------- + 1 |
543 * \ [e ^ (99 / z) - 1] /
545 * x: 1 .. 100, z: 15, delay: 100.00 .. 1.00
547 static const unsigned short osc_delay_tbl[100] =
549 10000, 9361, 8763, 8205, 7682, 7192, 6735, 6307, 5906, 5532,
550 5181, 4853, 4546, 4259, 3991, 3739, 3504, 3285, 3079, 2886,
551 2706, 2538, 2380, 2233, 2095, 1966, 1845, 1732, 1627, 1528,
552 1435, 1349, 1268, 1192, 1121, 1055, 993, 935, 880, 830,
553 782, 737, 696, 657, 620, 586, 554, 524, 497, 470,
554 446, 423, 402, 381, 363, 345, 329, 313, 299, 285,
555 273, 261, 250, 239, 230, 221, 212, 204, 197, 190,
556 183, 177, 171, 166, 161, 156, 152, 147, 144, 140,
557 136, 133, 130, 127, 125, 122, 120, 118, 116, 114,
558 112, 110, 108, 107, 106, 104, 103, 102, 101, 100
561 #define GRAPH_PEAKS_DEFAULT 68
562 #define GRAPH_WAVEFORM_DEFAULT 50
564 /* settings */
565 static struct osc_config
567 int speed[MAX_GRAPH];
568 int draw;
569 int advance;
570 int orientation;
571 int graphmode;
572 } osc_disk =
574 .speed =
576 [GRAPH_PEAKS] = GRAPH_PEAKS_DEFAULT,
577 #ifdef OSCILLOSCOPE_GRAPHMODE
578 [GRAPH_WAVEFORM] = GRAPH_WAVEFORM_DEFAULT,
579 #endif
581 .draw = DRAW_FILLED,
582 .advance = ADV_SCROLL,
583 .orientation = OSC_HORIZ,
584 #ifdef OSCILLOSCOPE_GRAPHMODE
585 .graphmode = GRAPH_PEAKS,
586 #endif
589 static struct osc_config osc; /* running config */
591 static const char cfg_filename[] = "oscilloscope.cfg";
592 static char *draw_str[3] = { "filled", "line", "pixel" };
593 static char *advance_str[2] = { "scroll", "wrap" };
594 static char *orientation_str[2] = { "horizontal", "vertical" };
595 #ifdef OSCILLOSCOPE_GRAPHMODE
596 static char *graphmode_str[2] = { "peaks", "waveform" };
597 #endif
599 struct configdata disk_config[] =
601 { TYPE_INT, MIN_SPEED, MAX_SPEED,
602 { .int_p = &osc_disk.speed[GRAPH_PEAKS] }, "speed", NULL },
603 { TYPE_ENUM, 0, MAX_DRAW, { .int_p = &osc_disk.draw }, "draw", draw_str },
604 { TYPE_ENUM, 0, MAX_ADV, { .int_p = &osc_disk.advance }, "advance",
605 advance_str },
606 { TYPE_ENUM, 0, MAX_OSC, { .int_p = &osc_disk.orientation }, "orientation",
607 orientation_str },
608 #ifdef OSCILLOSCOPE_GRAPHMODE
609 { TYPE_INT, MAX_SPEED, MAX_SPEED,
610 { .int_p = &osc_disk.speed[GRAPH_WAVEFORM] }, "wavespeed", NULL },
611 { TYPE_ENUM, 0, MAX_GRAPH, { .int_p = &osc_disk.graphmode }, "graphmode",
612 graphmode_str },
613 #endif
616 enum osc_message_ids
618 OSC_MSG_ADVMODE,
619 OSC_MSG_DRAWMODE,
620 #ifdef OSCILLOSCOPE_GRAPHMODE
621 OSC_MSG_GRAPHMODE,
622 #endif
623 OSC_MSG_ORIENTATION,
624 OSC_MSG_PAUSED,
625 OSC_MSG_SPEED,
626 OSC_MSG_VOLUME,
629 static long (*anim_draw)(void);
630 static int message = -1, msgval = 0; /* popup message */
631 static bool paused = false;
632 static bool one_frame_paused = false; /* Allow one frame to be drawn when paused if
633 view is erased */
634 static long osc_delay; /* delay in 100ths of a tick */
635 static long osc_delay_error; /* delay fraction error accumulator */
637 /* implementation */
640 /** Messages **/
642 static unsigned char osc_osd_message[16]; /* message to display (formatted) */
644 static inline void osc_popupmsg(int msg, int val)
646 message = msg; msgval = val;
649 /* Format a message to display */
650 static void osc_osd_format_message(enum osc_message_ids id, int val)
652 const char *msg = "";
654 switch (id)
656 case OSC_MSG_ADVMODE:
657 msg = val == ADV_WRAP ? "Wrap" : "Scroll";
658 break;
660 case OSC_MSG_DRAWMODE:
661 switch (val)
663 case DRAW_PIXEL: msg = "Pixel"; break;
664 case DRAW_LINE: msg = "Line"; break;
665 default: msg = "Filled";
667 break;
669 #ifdef OSCILLOSCOPE_GRAPHMODE
670 case OSC_MSG_GRAPHMODE:
671 msg = val == GRAPH_WAVEFORM ? "Waveform" : "Peaks";
672 break;
673 #endif
675 case OSC_MSG_ORIENTATION:
676 msg = val == OSC_VERT ? "Vertical" : "Horizontal";
677 break;
679 case OSC_MSG_PAUSED:
680 msg = val ? "Paused" : "Running";
681 break;
683 case OSC_MSG_SPEED:
684 msg = "Speed: %d";
685 break;
687 case OSC_MSG_VOLUME:
688 rb->snprintf(osc_osd_message, sizeof (osc_osd_message),
689 "Volume: %d%s",
690 rb->sound_val2phys(SOUND_VOLUME, val),
691 rb->sound_unit(SOUND_VOLUME));
692 return;
695 /* Default action: format integer */
696 rb->snprintf(osc_osd_message, sizeof (osc_osd_message), msg, val);
700 /** OSD **/
702 /* Actually draw the OSD within the OSD viewport */
703 extern void osd_lcd_draw_cb(int x, int y, int width, int height)
705 #if LCD_DEPTH > 1
706 rb->lcd_set_foreground(OSD_TEXT_COLOR);
707 rb->lcd_set_background(OSD_BACKG_COLOR);
708 #endif
709 #if OSC_OSD_MARGIN_SIZE != 0
710 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
711 rb->lcd_fillrect(1, 1, width - 2, height - 2);
712 rb->lcd_set_drawmode(DRMODE_SOLID);
713 #endif
714 rb->lcd_putsxy(1+OSC_OSD_MARGIN_SIZE, 1+OSC_OSD_MARGIN_SIZE,
715 osc_osd_message);
716 #if LCD_DEPTH > 1
717 rb->lcd_set_foreground(OSD_BORDER_COLOR);
718 #endif
719 rb->lcd_drawrect(0, 0, width, height);
721 (void)x; (void)y;
724 /* Perform all necessary basic setup tasks for the OSD */
725 static void osc_osd_init(void)
727 /* Grab the plugin buffer for the OSD back buffer */
728 size_t bufsize;
729 void *buf = rb->plugin_get_buffer(&bufsize);
731 int width, height;
732 rb->lcd_setfont(FONT_UI);
733 rb->lcd_getstringsize("M", NULL, &height);
734 width = LCD_WIDTH;
735 height += 2 + 2*OSC_OSD_MARGIN_SIZE;
736 osd_init(OSD_INIT_MAJOR_HEIGHT | OSD_INIT_MINOR_MAX, buf, bufsize,
737 osd_lcd_draw_cb, &width, &height, NULL);
740 /* Format a message by ID and show the OSD */
741 static void osc_osd_show_message(int id, int val)
743 osc_osd_format_message(id, val);
745 if (!osd_enabled())
746 return;
748 int width, height;
749 int maxwidth, maxheight;
751 rb->lcd_set_viewport(osd_get_viewport());
752 osd_get_max_dims(&maxwidth, &maxheight);
753 rb->lcd_getstringsize(osc_osd_message, &width, &height);
754 rb->lcd_set_viewport(NULL); /* to regular viewport */
756 width += 2 + 2*OSC_OSD_MARGIN_SIZE;
757 if (width > maxwidth)
758 width = maxwidth;
760 height += 2 + 2*OSC_OSD_MARGIN_SIZE;
761 if (height > maxheight)
762 height = maxheight;
764 /* Center it on the screen */
765 bool drawn = osd_update_pos((LCD_WIDTH - width) / 2,
766 (LCD_HEIGHT - height) / 2,
767 width, height);
769 osd_show(OSD_SHOW | (drawn ? 0 : OSD_UPDATENOW));
772 /* Draw cursor bar for horizontal views */
773 static void anim_draw_cursor_h(int x)
775 #if LCD_DEPTH > 1
776 rb->lcd_set_foreground(CURSOR_COLOR);
777 rb->lcd_vline(x, 0, LCD_HEIGHT-1);
778 rb->lcd_set_foreground(GRAPH_COLOR);
779 #else
780 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
781 rb->lcd_vline(x, 0, LCD_HEIGHT-1);
782 rb->lcd_set_drawmode(DRMODE_SOLID);
783 #endif
786 /* Draw cursor bar for vertical views */
787 static void anim_draw_cursor_v(int y)
789 #if LCD_DEPTH > 1 /* cursor bar */
790 rb->lcd_set_foreground(CURSOR_COLOR);
791 rb->lcd_hline(0, LCD_WIDTH-1, y);
792 rb->lcd_set_foreground(GRAPH_COLOR);
793 #else
794 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
795 rb->lcd_hline(0, LCD_WIDTH-1, y);
796 rb->lcd_set_drawmode(DRMODE_SOLID);
797 #endif
801 /** Peaks View **/
803 static long last_tick = 0; /* time of last drawing */
804 static long last_delay = 0; /* last delay value used */
805 static int last_pos = 0; /* last x or y drawing position. Reset for aspect switch. */
806 static int last_left; /* last channel values */
807 static int last_right;
809 static void get_peaks(int *left, int *right)
811 #if CONFIG_CODEC == SWCODEC
812 static struct pcm_peaks peaks;
813 rb->mixer_channel_calculate_peaks(PCM_MIXER_CHAN_PLAYBACK,
814 &peaks);
815 *left = peaks.left;
816 *right = peaks.right;
817 #elif defined (SIMULATOR)
818 *left = rand() % 0x8000;
819 *right = rand() % 0x8000;
820 #elif (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
821 *left = rb->mas_codec_readreg(0xC);
822 *right = rb->mas_codec_readreg(0xD);
823 #else
824 *left = 0;
825 *right = 0;
826 #endif
829 static long get_next_delay(void)
831 long delay = osc_delay / 100;
832 osc_delay_error += osc_delay - delay * 100;
834 if (osc_delay_error >= 100)
836 delay++;
837 osc_delay_error -= 100;
840 return delay;
843 static long anim_peaks_horizontal(void)
845 long cur_tick = *rb->current_tick;
846 int cur_x, x;
847 int left, right, dl, dr;
848 long d = (cur_tick - last_tick) / last_delay;
849 bool full_update = false;
851 if (paused)
853 one_frame_paused = false;
854 osd_lcd_update_prepare();
855 anim_draw_cursor_h(0);
856 osd_lcd_update_rect(0, 0, 1, LCD_HEIGHT);
857 last_pos = -1;
858 return cur_tick + HZ/5;
861 if (d <= 0) /* too early, bail out */
862 return last_tick + last_delay;
864 last_tick = cur_tick;
866 int cur_left, cur_right;
867 get_peaks(&cur_left, &cur_right);
869 if (d > HZ) /* first call or too much delay, (re)start */
871 last_left = cur_left;
872 last_right = cur_right;
873 return cur_tick + last_delay;
876 one_frame_paused = false;
878 osd_lcd_update_prepare();
880 cur_x = last_pos + d;
882 if (cur_x >= LCD_WIDTH)
884 if (osc.advance == ADV_SCROLL)
886 int shift = cur_x - (LCD_WIDTH-1);
887 xlcd_scroll_left(shift);
888 full_update = true;
889 cur_x -= shift;
890 last_pos -= shift;
892 else
894 cur_x -= LCD_WIDTH;
897 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
899 if (cur_x > last_pos)
901 rb->lcd_fillrect(last_pos + 1, 0, d, LCD_HEIGHT);
903 else
905 rb->lcd_fillrect(last_pos + 1, 0, LCD_WIDTH - last_pos, LCD_HEIGHT);
906 rb->lcd_fillrect(0, 0, cur_x + 1, LCD_HEIGHT);
908 rb->lcd_set_drawmode(DRMODE_SOLID);
910 switch (osc.draw)
912 case DRAW_FILLED:
913 left = last_left;
914 right = last_right;
915 dl = (cur_left - left) / d;
916 dr = (cur_right - right) / d;
918 for (x = last_pos + 1; d > 0; x++, d--)
920 if (x == LCD_WIDTH)
921 x = 0;
923 left += dl;
924 right += dr;
926 rb->lcd_vline(x, LCD_HEIGHT/2-1,
927 LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * left) >> 16));
928 rb->lcd_vline(x, LCD_HEIGHT/2+1,
929 LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * right) >> 16));
931 break;
933 case DRAW_LINE:
934 if (cur_x > last_pos)
936 rb->lcd_drawline(
937 last_pos, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * last_left) >> 16),
938 cur_x, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * cur_left) >> 16)
940 rb->lcd_drawline(
941 last_pos, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * last_right) >> 16),
942 cur_x, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * cur_right) >> 16)
945 else
947 left = last_left
948 + (LCD_WIDTH - last_pos) * (last_left - cur_left) / d;
949 right = last_right
950 + (LCD_WIDTH - last_pos) * (last_right - cur_right) / d;
952 rb->lcd_drawline(
953 last_pos, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * last_left) >> 16),
954 LCD_WIDTH, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * left) >> 16)
956 rb->lcd_drawline(
957 last_pos, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * last_right) >> 16),
958 LCD_WIDTH, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * right) >> 16)
960 if (cur_x > 0)
962 rb->lcd_drawline(
963 0, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * left) >> 16),
964 cur_x, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * cur_left) >> 16)
966 rb->lcd_drawline(
967 0, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * right) >> 16),
968 cur_x, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * cur_right) >> 16)
972 break;
974 case DRAW_PIXEL:
975 left = last_left;
976 right = last_right;
977 dl = (cur_left - left) / d;
978 dr = (cur_right - right) / d;
980 for (x = last_pos + 1; d > 0; x++, d--)
982 if (x == LCD_WIDTH)
983 x = 0;
985 left += dl;
986 right += dr;
988 rb->lcd_drawpixel(x, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * left) >> 16));
989 rb->lcd_drawpixel(x, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * right) >> 16));
991 break;
995 last_left = cur_left;
996 last_right = cur_right;
998 if (full_update)
1000 osd_lcd_update();
1002 else
1004 anim_draw_cursor_h(cur_x + 1); /* cursor bar */
1006 if (cur_x > last_pos)
1008 osd_lcd_update_rect(last_pos, 0, cur_x - last_pos + 2, LCD_HEIGHT);
1010 else
1012 osd_lcd_update_rect(last_pos, 0, LCD_WIDTH - last_pos, LCD_HEIGHT);
1013 osd_lcd_update_rect(0, 0, cur_x + 2, LCD_HEIGHT);
1016 last_pos = cur_x;
1018 last_delay = get_next_delay();
1019 return cur_tick + last_delay;
1022 static long anim_peaks_vertical(void)
1024 long cur_tick = *rb->current_tick;
1025 int cur_y, y;
1026 int left, right, dl, dr;
1027 bool full_update = false;
1028 long d = (cur_tick - last_tick) / last_delay;
1030 if (paused)
1032 one_frame_paused = false;
1033 osd_lcd_update_prepare();
1034 anim_draw_cursor_v(0);
1035 osd_lcd_update_rect(0, 0, LCD_WIDTH, 1);
1036 last_pos = -1;
1037 return cur_tick + HZ/5;
1040 if (d == 0) /* too early, bail out */
1041 return last_tick + last_delay;
1043 last_tick = cur_tick;
1045 int cur_left, cur_right;
1046 get_peaks(&cur_left, &cur_right);
1048 if (d > HZ) /* first call or too much delay, (re)start */
1050 last_left = cur_left;
1051 last_right = cur_right;
1052 return cur_tick + last_delay;
1055 one_frame_paused = false;
1057 osd_lcd_update_prepare();
1059 cur_y = last_pos + d;
1061 if (cur_y >= LCD_HEIGHT)
1063 if (osc.advance == ADV_SCROLL)
1065 int shift = cur_y - (LCD_HEIGHT-1);
1066 xlcd_scroll_up(shift);
1067 full_update = true;
1068 cur_y -= shift;
1069 last_pos -= shift;
1071 else
1073 cur_y -= LCD_HEIGHT;
1076 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1078 if (cur_y > last_pos)
1080 rb->lcd_fillrect(0, last_pos + 1, LCD_WIDTH, d);
1082 else
1084 rb->lcd_fillrect(0, last_pos + 1, LCD_WIDTH, LCD_HEIGHT - last_pos);
1085 rb->lcd_fillrect(0, 0, LCD_WIDTH, cur_y + 1);
1087 rb->lcd_set_drawmode(DRMODE_SOLID);
1089 switch (osc.draw)
1091 case DRAW_FILLED:
1092 left = last_left;
1093 right = last_right;
1094 dl = (cur_left - left) / d;
1095 dr = (cur_right - right) / d;
1097 for (y = last_pos + 1; d > 0; y++, d--)
1099 if (y == LCD_HEIGHT)
1100 y = 0;
1102 left += dl;
1103 right += dr;
1105 rb->lcd_hline(LCD_WIDTH/2-1,
1106 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * left) >> 16), y);
1107 rb->lcd_hline(LCD_WIDTH/2+1,
1108 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * right) >> 16), y);
1110 break;
1112 case DRAW_LINE:
1113 if (cur_y > last_pos)
1115 rb->lcd_drawline(
1116 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * last_left) >> 16), last_pos,
1117 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * cur_left) >> 16), cur_y
1119 rb->lcd_drawline(
1120 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * last_right) >> 16), last_pos,
1121 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * cur_right) >> 16), cur_y
1124 else
1126 left = last_left
1127 + (LCD_HEIGHT - last_pos) * (last_left - cur_left) / d;
1128 right = last_right
1129 + (LCD_HEIGHT - last_pos) * (last_right - cur_right) / d;
1131 rb->lcd_drawline(
1132 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * last_left) >> 16), last_pos,
1133 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * left) >> 16), LCD_HEIGHT
1135 rb->lcd_drawline(
1136 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * last_right) >> 16), last_pos,
1137 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * right) >> 16), LCD_HEIGHT
1139 if (cur_y > 0)
1141 rb->lcd_drawline(
1142 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * left) >> 16), 0,
1143 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * cur_left) >> 16), cur_y
1145 rb->lcd_drawline(
1146 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * right) >> 16), 0,
1147 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * cur_right) >> 16), cur_y
1151 break;
1153 case DRAW_PIXEL:
1154 left = last_left;
1155 right = last_right;
1156 dl = (cur_left - left) / d;
1157 dr = (cur_right - right) / d;
1159 for (y = last_pos + 1; d > 0; y++, d--)
1161 if (y == LCD_HEIGHT)
1162 y = 0;
1164 left += dl;
1165 right += dr;
1167 rb->lcd_drawpixel(LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * left) >> 16), y);
1168 rb->lcd_drawpixel(LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * right) >> 16), y);
1170 break;
1174 last_left = cur_left;
1175 last_right = cur_right;
1177 if (full_update)
1179 osd_lcd_update();
1181 else
1183 anim_draw_cursor_v(cur_y + 1); /* cursor bar */
1185 if (cur_y > last_pos)
1187 osd_lcd_update_rect(0, last_pos, LCD_WIDTH, cur_y - last_pos + 2);
1189 else
1191 osd_lcd_update_rect(0, last_pos, LCD_WIDTH, LCD_HEIGHT - last_pos);
1192 osd_lcd_update_rect(0, 0, LCD_WIDTH, cur_y + 2);
1195 last_pos = cur_y;
1197 last_delay = get_next_delay();
1198 return cur_tick + last_delay;
1202 /** Waveform View **/
1204 #ifdef OSCILLOSCOPE_GRAPHMODE
1205 static int16_t waveform_buffer[2*ALIGN_UP(NATIVE_FREQUENCY, 2048)+2*2048]
1206 MEM_ALIGN_ATTR;
1207 static size_t waveform_buffer_threshold = 0;
1208 static size_t volatile waveform_buffer_have = 0;
1209 static size_t waveform_buffer_break = 0;
1210 #define PCM_SAMPLESIZE (2*sizeof(int16_t))
1211 #define PCM_BYTERATE (NATIVE_FREQUENCY*PCM_SAMPLESIZE)
1213 #define WAVEFORM_SCALE_PCM(full_scale, sample) \
1214 ((((full_scale) * (sample)) + (1 << 14)) >> 15)
1216 static void waveform_buffer_set_threshold(size_t threshold)
1218 if (threshold > sizeof (waveform_buffer))
1219 threshold = sizeof (waveform_buffer);
1221 if (threshold == waveform_buffer_threshold)
1222 return;
1224 /* Avoid changing it in the middle of buffer callback */
1225 rb->pcm_play_lock();
1227 waveform_buffer_threshold = threshold;
1229 rb->pcm_play_unlock();
1232 static inline bool waveform_buffer_have_enough(void)
1234 return waveform_buffer_have >= waveform_buffer_threshold;
1237 static void waveform_buffer_done(void)
1239 /* This is safe because buffer callback won't add more data unless the
1240 treshold is changed or data is removed below the threshold. This isn't
1241 called until after the threshold is already met. */
1242 size_t threshold = waveform_buffer_threshold;
1243 size_t have = 0;
1245 if (threshold != 0)
1247 have = waveform_buffer_have;
1248 size_t slide = (have - 1) / threshold * threshold;
1250 if (slide == 0)
1251 slide = threshold;
1253 have -= slide;
1255 if (have > 0)
1257 /* memcpy: the slide >= threshold and have <= threshold */
1258 memcpy(waveform_buffer, (void *)waveform_buffer + slide, have);
1262 waveform_buffer_have = have;
1265 /* where the samples are obtained and buffered */
1266 static void waveform_buffer_callback(const void *start, size_t size)
1268 size_t threshold = waveform_buffer_threshold;
1269 size_t have = waveform_buffer_have;
1271 if (have >= threshold)
1273 waveform_buffer_break += size;
1274 return;
1277 if (waveform_buffer_break > 0)
1279 /* Previosly missed a part or all of a frame and the break would
1280 happen within the data threshold area. Start where frame would
1281 end up if all had been processed fully. This might mean a period
1282 of resynchronization will have to happen first before the buffer
1283 is filled to the threshold or even begins filling. Maintaining
1284 scan phase relationship is important to proper appearance or else
1285 the waveform display looks sloppy. */
1286 size_t brk = have + waveform_buffer_break;
1287 waveform_buffer_have = have = 0;
1289 brk %= threshold;
1291 if (brk != 0)
1293 brk += size;
1295 if (brk <= threshold)
1297 waveform_buffer_break = brk;
1298 return;
1301 brk -= threshold;
1302 start += size - brk;
1303 size = brk;
1306 waveform_buffer_break = 0;
1309 size_t remaining = sizeof (waveform_buffer) - have;
1310 size_t copy = size;
1312 if (copy > remaining)
1314 waveform_buffer_break = copy - remaining;
1315 copy = remaining;
1318 memcpy((void *)waveform_buffer + have, start, copy);
1320 waveform_buffer_have = have + copy;
1323 static void waveform_buffer_reset(void)
1325 /* only called when callback is off */
1326 waveform_buffer_have = 0;
1327 waveform_buffer_threshold = 0;
1328 waveform_buffer_break = 0;
1331 static void anim_waveform_plot_filled_h(int x, int x_prev,
1332 int vmin, int vmax,
1333 int vmin_prev, int vmax_prev)
1335 if (vmin != vmax || vmin_prev != vmax_prev)
1337 /* Graph compression */
1338 if (vmax > vmin_prev)
1339 vmax = vmin_prev;
1340 else if (vmin < vmax_prev)
1341 vmin = vmax_prev;
1343 rb->lcd_vline(x, vmax, vmin);
1345 else
1347 /* 1:1 or stretch */
1348 rb->lcd_drawline(x_prev, vmin_prev, x, vmin);
1352 static void anim_waveform_plot_lines_h(int x, int x_prev,
1353 int vmin, int vmax,
1354 int vmin_prev, int vmax_prev)
1356 rb->lcd_drawline(x_prev, vmin_prev, x, vmin);
1358 if (vmax_prev != vmin_prev || vmax != vmin)
1359 rb->lcd_drawline(x_prev, vmax_prev, x, vmax);
1362 static void anim_waveform_plot_pixel_h(int x, int x_prev,
1363 int vmin, int vmax,
1364 int vmin_prev, int vmax_prev)
1366 rb->lcd_drawpixel(x, vmin);
1368 if (vmax != vmin)
1369 rb->lcd_drawpixel(x, vmax);
1371 (void)x_prev; (void)vmin_prev; (void)vmax_prev;
1374 static long anim_waveform_horizontal(void)
1376 static void (* const plot[MAX_DRAW])(int, int, int, int, int, int) =
1378 [DRAW_FILLED] = anim_waveform_plot_filled_h,
1379 [DRAW_LINE] = anim_waveform_plot_lines_h,
1380 [DRAW_PIXEL] = anim_waveform_plot_pixel_h,
1383 long cur_tick = *rb->current_tick;
1385 if (rb->mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) != CHANNEL_PLAYING)
1387 osd_lcd_update_prepare();
1388 rb->lcd_hline(0, LCD_WIDTH-1, 1*LCD_HEIGHT/4);
1389 rb->lcd_hline(0, LCD_WIDTH-1, 3*LCD_HEIGHT/4);
1390 osd_lcd_update();
1391 one_frame_paused = false;
1392 return cur_tick + HZ/5;
1395 int count = (NATIVE_FREQUENCY*osc_delay + 100*HZ - 1) / (100*HZ);
1397 waveform_buffer_set_threshold(count*PCM_SAMPLESIZE);
1399 if (!waveform_buffer_have_enough())
1400 return cur_tick + HZ/100;
1402 one_frame_paused = false;
1404 osd_lcd_update_prepare();
1406 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1407 rb->lcd_fillrect(0, 0, LCD_WIDTH, LCD_HEIGHT);
1408 rb->lcd_set_drawmode(DRMODE_SOLID);
1409 #if LCD_DEPTH > 1
1410 rb->lcd_set_foreground(GRAPH_COLOR);
1411 #endif
1413 int x = 0, x_prev = count - 1;
1414 int x_step = (LCD_WIDTH-1) / x_prev;
1415 int x_a_step = (LCD_WIDTH-1) - x_step * x_prev;
1416 int x_a = 0;
1418 int idx_step = (count / LCD_WIDTH) * 2;
1419 int idx_a_step = count - idx_step * (LCD_WIDTH/2);
1420 int idx = idx_step, idx_prev = 0;
1421 int idx_a = idx_a_step;
1423 int a_lim = MIN(x_prev, LCD_WIDTH-1);
1425 int lmin, lmin_prev = 0;
1426 int rmin, rmin_prev = 0;
1427 int lmax, lmax_prev = 0;
1428 int rmax, rmax_prev = 0;
1430 if (osc.draw == DRAW_PIXEL)
1431 goto plot_start_noprev; /* Doesn't need previous points */
1433 lmax = lmin = waveform_buffer[0];
1434 rmax = rmin = waveform_buffer[1];
1436 /* Find min-max envelope for interval */
1437 for (int i = 2; i < idx; i += 2)
1439 int sl = waveform_buffer[i + 0];
1440 int sr = waveform_buffer[i + 1];
1442 if (sl < lmin)
1443 lmin = sl;
1444 if (sl > lmax)
1445 lmax = sl;
1447 if (sr < rmin)
1448 rmin = sr;
1449 if (sr > rmax)
1450 rmax = sr;
1453 lmin = (1*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, lmin);
1454 lmax = (1*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, lmax);
1455 rmin = (3*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, rmin);
1456 rmax = (3*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, rmax);
1458 while (1)
1460 x_prev = x;
1461 x += x_step;
1462 x_a += x_a_step;
1464 if (x_a >= a_lim)
1466 x_a -= a_lim;
1467 x++;
1470 if (x >= LCD_WIDTH)
1471 break;
1473 idx_prev = idx;
1474 idx += idx_step;
1475 idx_a += idx_a_step;
1477 if (idx_a > a_lim)
1479 idx_a -= a_lim + 1;
1480 idx += 2;
1483 lmin_prev = lmin, lmax_prev = lmax;
1484 rmin_prev = rmin, rmax_prev = rmax;
1486 plot_start_noprev:
1487 lmax = lmin = waveform_buffer[idx_prev + 0];
1488 rmax = rmin = waveform_buffer[idx_prev + 1];
1490 /* Find min-max envelope for interval */
1491 for (int i = idx_prev + 2; i < idx; i += 2)
1493 int sl = waveform_buffer[i + 0];
1494 int sr = waveform_buffer[i + 1];
1496 if (sl < lmin)
1497 lmin = sl;
1498 if (sl > lmax)
1499 lmax = sl;
1501 if (sr < rmin)
1502 rmin = sr;
1503 if (sr > rmax)
1504 rmax = sr;
1507 lmin = (1*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, lmin);
1508 lmax = (1*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, lmax);
1509 rmin = (3*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, rmin);
1510 rmax = (3*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, rmax);
1512 plot[osc.draw](x, x_prev, lmin, lmax, lmin_prev, lmax_prev);
1513 plot[osc.draw](x, x_prev, rmin, rmax, rmin_prev, rmax_prev);
1516 waveform_buffer_done();
1518 osd_lcd_update();
1520 long delay = get_next_delay();
1521 return cur_tick + delay - waveform_buffer_have * HZ / PCM_BYTERATE;
1524 static void anim_waveform_plot_filled_v(int y, int y_prev,
1525 int vmin, int vmax,
1526 int vmin_prev, int vmax_prev)
1528 if (vmin != vmax || vmin_prev != vmax_prev)
1530 /* Graph compression */
1531 if (vmax < vmin_prev)
1532 vmax = vmin_prev;
1533 else if (vmin > vmax_prev)
1534 vmin = vmax_prev;
1536 rb->lcd_hline(vmin, vmax, y);
1538 else
1540 /* 1:1 or stretch */
1541 rb->lcd_drawline(vmin_prev, y_prev, vmin, y);
1545 static void anim_waveform_plot_lines_v(int y, int y_prev,
1546 int vmin, int vmax,
1547 int vmin_prev, int vmax_prev)
1549 rb->lcd_drawline(vmin_prev, y_prev, vmin, y);
1551 if (vmax_prev != vmin_prev || vmax != vmin)
1552 rb->lcd_drawline(vmax_prev, y_prev, vmax, y);
1555 static void anim_waveform_plot_pixel_v(int y, int y_prev,
1556 int vmin, int vmax,
1557 int vmin_prev, int vmax_prev)
1559 rb->lcd_drawpixel(vmin, y);
1561 if (vmax != vmin)
1562 rb->lcd_drawpixel(vmax, y);
1564 (void)y_prev; (void)vmin_prev; (void)vmax_prev;
1567 static long anim_waveform_vertical(void)
1569 static void (* const plot[MAX_DRAW])(int, int, int, int, int, int) =
1571 [DRAW_FILLED] = anim_waveform_plot_filled_v,
1572 [DRAW_LINE] = anim_waveform_plot_lines_v,
1573 [DRAW_PIXEL] = anim_waveform_plot_pixel_v,
1576 long cur_tick = *rb->current_tick;
1578 if (rb->mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) != CHANNEL_PLAYING)
1580 osd_lcd_update_prepare();
1581 rb->lcd_vline(1*LCD_WIDTH/4, 0, LCD_HEIGHT-1);
1582 rb->lcd_vline(3*LCD_WIDTH/4, 0, LCD_HEIGHT-1);
1583 osd_lcd_update();
1584 one_frame_paused = false;
1585 return cur_tick + HZ/5;
1588 int count = (NATIVE_FREQUENCY*osc_delay + 100*HZ - 1) / (100*HZ);
1590 waveform_buffer_set_threshold(count*PCM_SAMPLESIZE);
1592 if (!waveform_buffer_have_enough())
1593 return cur_tick + HZ/100;
1595 one_frame_paused = false;
1597 osd_lcd_update_prepare();
1599 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1600 rb->lcd_fillrect(0, 0, LCD_WIDTH, LCD_HEIGHT);
1601 rb->lcd_set_drawmode(DRMODE_SOLID);
1602 #if LCD_DEPTH > 1
1603 rb->lcd_set_foreground(GRAPH_COLOR);
1604 #endif
1606 int y = 0, y_prev = count - 1;
1607 int y_step = (LCD_HEIGHT-1) / y_prev;
1608 int y_a_step = (LCD_HEIGHT-1) - y_step * y_prev;
1609 int y_a = 0;
1611 int idx_step = (count / LCD_HEIGHT) * 2;
1612 int idx_a_step = count - idx_step * (LCD_HEIGHT/2);
1613 int idx = idx_step, idx_prev = 0;
1614 int idx_a = idx_a_step;
1616 int a_lim = MIN(y_prev, LCD_HEIGHT-1);
1618 int lmin, lmin_prev = 0;
1619 int rmin, rmin_prev = 0;
1620 int lmax, lmax_prev = 0;
1621 int rmax, rmax_prev = 0;
1623 if (osc.draw == DRAW_PIXEL)
1624 goto plot_start_noprev; /* Doesn't need previous points */
1626 lmax = lmin = waveform_buffer[0];
1627 rmax = rmin = waveform_buffer[1];
1629 /* Find min-max envelope for interval */
1630 for (int i = 2; i < idx; i += 2)
1632 int sl = waveform_buffer[i + 0];
1633 int sr = waveform_buffer[i + 1];
1635 if (sl < lmin)
1636 lmin = sl;
1637 if (sl > lmax)
1638 lmax = sl;
1640 if (sr < rmin)
1641 rmin = sr;
1642 if (sr > rmax)
1643 rmax = sr;
1646 lmin = (1*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, lmin);
1647 lmax = (1*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, lmax);
1648 rmin = (3*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, rmin);
1649 rmax = (3*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, rmax);
1651 while (1)
1653 y_prev = y;
1654 y += y_step;
1655 y_a += y_a_step;
1657 if (y_a >= a_lim)
1659 y_a -= a_lim;
1660 y++;
1663 if (y >= LCD_HEIGHT)
1664 break;
1666 idx_prev = idx;
1667 idx += idx_step;
1668 idx_a += idx_a_step;
1670 if (idx_a > a_lim)
1672 idx_a -= a_lim + 1;
1673 idx += 2;
1676 lmin_prev = lmin, lmax_prev = lmax;
1677 rmin_prev = rmin, rmax_prev = rmax;
1679 plot_start_noprev:
1680 lmax = lmin = waveform_buffer[idx_prev + 0];
1681 rmax = rmin = waveform_buffer[idx_prev + 1];
1683 /* Find min-max envelope for interval */
1684 for (int i = idx_prev + 2; i < idx; i += 2)
1686 int sl = waveform_buffer[i + 0];
1687 int sr = waveform_buffer[i + 1];
1689 if (sl < lmin)
1690 lmin = sl;
1691 if (sl > lmax)
1692 lmax = sl;
1694 if (sr < rmin)
1695 rmin = sr;
1696 if (sr > rmax)
1697 rmax = sr;
1700 lmin = (1*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, lmin);
1701 lmax = (1*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, lmax);
1702 rmin = (3*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, rmin);
1703 rmax = (3*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, rmax);
1705 plot[osc.draw](y, y_prev, lmin, lmax, lmin_prev, lmax_prev);
1706 plot[osc.draw](y, y_prev, rmin, rmax, rmin_prev, rmax_prev);
1709 waveform_buffer_done();
1711 osd_lcd_update();
1713 long delay = get_next_delay();
1714 return cur_tick + delay - waveform_buffer_have * HZ / PCM_BYTERATE;
1717 static void anim_waveform_exit(void)
1719 /* Remove any buffer hook */
1720 rb->mixer_channel_set_buffer_hook(PCM_MIXER_CHAN_PLAYBACK, NULL);
1721 #ifdef HAVE_SCHEDULER_BOOSTCTRL
1722 /* Remove our boost */
1723 rb->cancel_cpu_boost();
1724 #endif
1726 #endif /* OSCILLOSCOPE_GRAPHMODE */
1728 static void graphmode_reset(void)
1730 static long (* const fns[MAX_GRAPH][MAX_OSC])(void) =
1732 [GRAPH_PEAKS] =
1734 [OSC_HORIZ] = anim_peaks_horizontal,
1735 [OSC_VERT] = anim_peaks_vertical,
1737 #ifdef OSCILLOSCOPE_GRAPHMODE
1738 [GRAPH_WAVEFORM] =
1740 [OSC_HORIZ] = anim_waveform_horizontal,
1741 [OSC_VERT] = anim_waveform_vertical,
1743 #endif /* OSCILLOSCOPE_GRAPHMODE */
1746 /* For peaks view */
1747 last_left = 0;
1748 last_right = 0;
1749 last_pos = 0;
1750 last_tick = *rb->current_tick;
1751 last_delay = 1;
1753 /* General */
1754 osd_lcd_update_prepare();
1755 rb->lcd_clear_display();
1756 osd_lcd_update();
1758 one_frame_paused = true;
1759 osd_set_timeout(paused ? 4*HZ : HZ);
1760 anim_draw = fns[osc.graphmode][osc.orientation];
1763 static void graphmode_pause_unpause(bool paused)
1765 if (paused)
1766 return;
1768 last_tick = *rb->current_tick;
1769 osd_set_timeout(HZ);
1770 one_frame_paused = false;
1771 #ifdef OSCILLOSCOPE_GRAPHMODE
1772 if (osc.graphmode == GRAPH_WAVEFORM)
1773 waveform_buffer_done();
1774 #endif /* OSCILLOSCOPE_GRAPHMODE */
1777 static void update_osc_delay(int value)
1779 osc_delay = osc_delay_tbl[value - 1];
1780 osc_delay_error = 0;
1783 static void graphmode_setup(void)
1785 #ifdef OSCILLOSCOPE_GRAPHMODE
1786 if (osc.graphmode == GRAPH_WAVEFORM)
1788 rb->mixer_channel_set_buffer_hook(PCM_MIXER_CHAN_PLAYBACK,
1789 waveform_buffer_callback);
1790 #ifdef HAVE_SCHEDULER_BOOSTCTRL
1791 rb->trigger_cpu_boost(); /* Just looks better */
1792 #endif
1794 else
1796 rb->mixer_channel_set_buffer_hook(PCM_MIXER_CHAN_PLAYBACK,
1797 NULL);
1798 #ifdef HAVE_SCHEDULER_BOOSTCTRL
1799 rb->cancel_cpu_boost();
1800 #endif
1801 waveform_buffer_reset();
1803 #endif /* OSCILLOSCOPE_GRAPHMODE */
1805 update_osc_delay(osc.speed[osc.graphmode]);
1806 graphmode_reset();
1809 static long oscilloscope_draw(void)
1811 if (message != -1)
1813 osc_osd_show_message((enum osc_message_ids)message, msgval);
1814 message = -1;
1816 else
1818 osd_monitor_timeout();
1821 long delay = HZ/5;
1823 if (!paused || one_frame_paused)
1825 delay = anim_draw() - *rb->current_tick;
1827 if (delay > HZ/5)
1828 delay = HZ/5;
1831 return delay;
1834 static void osc_cleanup(void)
1836 osd_destroy();
1838 #ifdef OSCILLOSCOPE_GRAPHMODE
1839 anim_waveform_exit();
1840 #endif
1842 #if LCD_DEPTH > 1
1843 rb->lcd_set_foreground(LCD_DEFAULT_FG);
1844 rb->lcd_set_background(LCD_DEFAULT_BG);
1845 #endif
1846 /* Turn on backlight timeout (revert to settings) */
1847 backlight_use_settings();
1850 /* save settings if changed */
1851 if (rb->memcmp(&osc, &osc_disk, sizeof(osc)))
1853 rb->memcpy(&osc_disk, &osc, sizeof(osc));
1854 configfile_save(cfg_filename, disk_config, ARRAYLEN(disk_config),
1855 CFGFILE_VERSION);
1859 static void osc_setup(void)
1861 atexit(osc_cleanup);
1862 configfile_load(cfg_filename, disk_config, ARRAYLEN(disk_config),
1863 CFGFILE_MINVERSION);
1864 osc = osc_disk; /* copy to running config */
1866 osc_osd_init();
1868 #if LCD_DEPTH > 1
1869 osd_lcd_update_prepare();
1870 rb->lcd_set_foreground(GRAPH_COLOR);
1871 rb->lcd_set_background(BACKG_COLOR);
1872 rb->lcd_set_backdrop(NULL);
1873 rb->lcd_clear_display();
1874 osd_lcd_update();
1875 #endif
1877 /* Turn off backlight timeout */
1878 backlight_ignore_timeout();
1879 graphmode_setup();
1882 enum plugin_status plugin_start(const void* parameter)
1884 bool exit = false;
1885 #ifdef NEED_LASTBUTTON
1886 int lastbutton = BUTTON_NONE;
1887 #endif
1889 osc_setup();
1891 while (!exit)
1893 long delay = oscilloscope_draw();
1895 if (delay <= 0)
1897 delay = 0;
1898 rb->yield(); /* tmo = 0 won't yield */
1901 int button = rb->button_get_w_tmo(delay);
1903 switch (button)
1905 #ifdef OSCILLOSCOPE_RC_QUIT
1906 case OSCILLOSCOPE_RC_QUIT:
1907 #endif
1908 case OSCILLOSCOPE_QUIT:
1909 exit = true;
1910 break;
1912 case OSCILLOSCOPE_ADVMODE:
1913 #ifdef OSCILLOSCOPE_GRAPHMODE
1914 if (osc.graphmode == GRAPH_WAVEFORM)
1915 break; /* Not applicable */
1916 #endif
1917 if (++osc.advance >= MAX_ADV)
1918 osc.advance = 0;
1920 osc_popupmsg(OSC_MSG_ADVMODE, osc.advance);
1921 break;
1923 case OSCILLOSCOPE_DRAWMODE:
1924 #ifdef OSCILLOSCOPE_DRAWMODE_PRE
1925 if (lastbutton != OSCILLOSCOPE_DRAWMODE_PRE)
1926 break;
1927 #endif
1928 if (++osc.draw >= MAX_DRAW)
1929 osc.draw = 0;
1931 osc_popupmsg(OSC_MSG_DRAWMODE, osc.draw);
1932 break;
1934 /* Need all keymaps for this (remove extra condition when
1935 completed) */
1936 #ifdef OSCILLOSCOPE_GRAPHMODE
1937 case OSCILLOSCOPE_GRAPHMODE:
1938 #ifdef OSCILLOSCOPE_GRAPHMODE_PRE
1939 if (lastbutton != OSCILLOSCOPE_GRAPHMODE_PRE)
1940 break;
1941 #endif
1942 if (++osc.graphmode >= MAX_GRAPH)
1943 osc.graphmode = 0;
1945 graphmode_setup();
1947 osc_popupmsg(OSC_MSG_GRAPHMODE, osc.graphmode);
1948 break;
1949 #endif /* OSCILLOSCOPE_GRAPHMODE */
1951 case OSCILLOSCOPE_ORIENTATION:
1952 #ifdef OSCILLOSCOPE_ORIENTATION_PRE
1953 if (lastbutton != OSCILLOSCOPE_ORIENTATION_PRE)
1954 break;
1955 #endif
1956 if (++osc.orientation >= MAX_OSC)
1957 osc.orientation = 0;
1959 graphmode_reset();
1960 osc_popupmsg(OSC_MSG_ORIENTATION, osc.orientation);
1961 break;
1963 case OSCILLOSCOPE_PAUSE:
1964 #ifdef OSCILLOSCOPE_PAUSE_PRE
1965 if (lastbutton != OSCILLOSCOPE_PAUSE_PRE)
1966 break;
1967 #endif
1968 paused = !paused;
1969 graphmode_pause_unpause(paused);
1970 osc_popupmsg(OSC_MSG_PAUSED, paused ? 1 : 0);
1971 break;
1973 case OSCILLOSCOPE_SPEED_UP:
1974 case OSCILLOSCOPE_SPEED_UP | BUTTON_REPEAT:
1976 int *val = &osc.speed[osc.graphmode];
1978 if (*val < MAX_SPEED)
1979 ++*val;
1981 update_osc_delay(*val);
1982 osc_popupmsg(OSC_MSG_SPEED, *val);
1983 break;
1986 case OSCILLOSCOPE_SPEED_DOWN:
1987 case OSCILLOSCOPE_SPEED_DOWN | BUTTON_REPEAT:
1989 int *val = &osc.speed[osc.graphmode];
1991 if (*val > MIN_SPEED)
1992 --*val;
1994 update_osc_delay(*val);
1995 osc_popupmsg(OSC_MSG_SPEED, *val);
1996 break;
1999 case OSCILLOSCOPE_VOL_UP:
2000 case OSCILLOSCOPE_VOL_UP | BUTTON_REPEAT:
2002 int vol = rb->global_settings->volume;
2004 if (vol < rb->sound_max(SOUND_VOLUME))
2006 vol++;
2007 rb->sound_set(SOUND_VOLUME, vol);
2008 rb->global_settings->volume = vol;
2011 osc_popupmsg(OSC_MSG_VOLUME, vol);
2012 break;
2015 case OSCILLOSCOPE_VOL_DOWN:
2016 case OSCILLOSCOPE_VOL_DOWN | BUTTON_REPEAT:
2018 int vol = rb->global_settings->volume;
2020 if (vol > rb->sound_min(SOUND_VOLUME))
2022 vol--;
2023 rb->sound_set(SOUND_VOLUME, vol);
2024 rb->global_settings->volume = vol;
2027 osc_popupmsg(OSC_MSG_VOLUME, vol);
2028 break;
2031 default:
2032 exit_on_usb(button);
2033 break;
2036 #ifdef NEED_LASTBUTTON
2037 if (button != BUTTON_NONE)
2038 lastbutton = button;
2039 #endif
2040 } /* while */
2042 return PLUGIN_OK;
2043 (void)parameter;