A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Oscilloscope, with many different modes of operation.
11*
12* Copyright (C) 2004-2006 Jens Arnold
13*
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.
18*
19* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20* KIND, either express or implied.
21*
22****************************************************************************/
23
24#include "plugin.h"
25#include "fixedpoint.h"
26#include "lib/helper.h"
27#include "lib/pluginlib_exit.h"
28#include "lib/xlcd.h"
29#include "lib/configfile.h"
30#include "lib/osd.h"
31
32/* variable button definitions */
33#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
34#define OSCILLOSCOPE_QUIT BUTTON_OFF
35#define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
36#define OSCILLOSCOPE_ADVMODE BUTTON_MODE
37#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_REC
38#define OSCILLOSCOPE_ORIENTATION (BUTTON_REC | BUTTON_REL)
39#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_REC
40#define OSCILLOSCOPE_GRAPHMODE (BUTTON_REC | BUTTON_REPEAT)
41#define OSCILLOSCOPE_PAUSE BUTTON_ON
42#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
43#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
44#define OSCILLOSCOPE_VOL_UP BUTTON_UP
45#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
46#define OSCILLOSCOPE_RC_QUIT BUTTON_RC_STOP
47
48#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
49 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
50#define OSCILLOSCOPE_QUIT BUTTON_MENU
51#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_SELECT
52#define OSCILLOSCOPE_GRAPHMODE (BUTTON_SELECT | BUTTON_REL)
53#define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_SELECT
54#define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_REPEAT)
55#define OSCILLOSCOPE_ADVMODE (BUTTON_SELECT | BUTTON_RIGHT)
56#define OSCILLOSCOPE_ORIENTATION (BUTTON_SELECT | BUTTON_LEFT)
57#define OSCILLOSCOPE_PAUSE BUTTON_PLAY | BUTTON_REL
58#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
59#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
60#define OSCILLOSCOPE_VOL_UP BUTTON_SCROLL_FWD
61#define OSCILLOSCOPE_VOL_DOWN BUTTON_SCROLL_BACK
62/* Need GRAPHMODE */
63
64#elif (CONFIG_KEYPAD == GIGABEAT_PAD)
65#define OSCILLOSCOPE_QUIT BUTTON_POWER
66#define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
67#define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
68#define OSCILLOSCOPE_ORIENTATION BUTTON_UP
69#define OSCILLOSCOPE_GRAPHMODE BUTTON_MENU
70#define OSCILLOSCOPE_PAUSE BUTTON_A
71#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
72#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
73#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
74#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
75
76#elif (CONFIG_KEYPAD == SANSA_E200_PAD)
77#define OSCILLOSCOPE_QUIT BUTTON_POWER
78#define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_SELECT
79#define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_REL)
80#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_SELECT
81#define OSCILLOSCOPE_ORIENTATION (BUTTON_SELECT | BUTTON_REPEAT)
82#define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
83#define OSCILLOSCOPE_PAUSE_PRE BUTTON_UP
84#define OSCILLOSCOPE_PAUSE (BUTTON_UP | BUTTON_REL)
85#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_UP
86#define OSCILLOSCOPE_GRAPHMODE (BUTTON_UP | BUTTON_REPEAT)
87#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
88#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
89#define OSCILLOSCOPE_VOL_UP BUTTON_SCROLL_FWD
90#define OSCILLOSCOPE_VOL_DOWN BUTTON_SCROLL_BACK
91
92#elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
93#define OSCILLOSCOPE_QUIT (BUTTON_HOME|BUTTON_REPEAT)
94#define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_SELECT
95#define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_REL)
96#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_SELECT
97#define OSCILLOSCOPE_ORIENTATION (BUTTON_SELECT | BUTTON_REPEAT)
98#define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
99#define OSCILLOSCOPE_PAUSE_PRE BUTTON_UP
100#define OSCILLOSCOPE_PAUSE (BUTTON_UP | BUTTON_REL)
101#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_UP
102#define OSCILLOSCOPE_GRAPHMODE (BUTTON_UP | BUTTON_REPEAT)
103#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
104#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
105#define OSCILLOSCOPE_VOL_UP BUTTON_SCROLL_FWD
106#define OSCILLOSCOPE_VOL_DOWN BUTTON_SCROLL_BACK
107
108#elif (CONFIG_KEYPAD == SANSA_C200_PAD)
109#define OSCILLOSCOPE_QUIT BUTTON_POWER
110#define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
111#define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
112#define OSCILLOSCOPE_ORIENTATION BUTTON_UP
113#define OSCILLOSCOPE_PAUSE BUTTON_REC
114#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
115#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
116#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
117#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
118/* v1 - Need GRAPHMODE */
119/* v2 - Not enough plugin RAM for waveform view */
120
121#elif (CONFIG_KEYPAD == SANSA_CLIP_PAD)
122#define OSCILLOSCOPE_QUIT BUTTON_POWER
123#define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_SELECT
124#define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_REL)
125#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_SELECT
126#define OSCILLOSCOPE_ORIENTATION (BUTTON_SELECT | BUTTON_REPEAT)
127#define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
128#define OSCILLOSCOPE_PAUSE BUTTON_UP
129#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
130#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
131#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
132#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
133/* Not enough plugin RAM for waveform view */
134
135#elif (CONFIG_KEYPAD == SANSA_M200_PAD)
136#define OSCILLOSCOPE_QUIT BUTTON_POWER
137#define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_REL)
138#define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
139#define OSCILLOSCOPE_ORIENTATION BUTTON_UP
140#define OSCILLOSCOPE_PAUSE (BUTTON_SELECT | BUTTON_UP)
141#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
142#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
143#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
144#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
145/* Not enough plugin RAM for waveform view */
146
147#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
148#define OSCILLOSCOPE_QUIT BUTTON_POWER
149#define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_SELECT
150#define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_REL)
151#define OSCILLOSCOPE_ADVMODE BUTTON_REC
152#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_SELECT
153#define OSCILLOSCOPE_ORIENTATION (BUTTON_SELECT | BUTTON_REPEAT)
154#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_PLAY
155#define OSCILLOSCOPE_GRAPHMODE (BUTTON_PLAY | BUTTON_REPEAT)
156#define OSCILLOSCOPE_PAUSE_PRE BUTTON_PLAY
157#define OSCILLOSCOPE_PAUSE (BUTTON_PLAY | BUTTON_REL)
158#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
159#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
160#define OSCILLOSCOPE_VOL_UP BUTTON_UP
161#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
162
163#elif CONFIG_KEYPAD == IRIVER_H10_PAD
164#define OSCILLOSCOPE_QUIT BUTTON_POWER
165#define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_REW
166#define OSCILLOSCOPE_DRAWMODE (BUTTON_REW | BUTTON_REL)
167#define OSCILLOSCOPE_ADVMODE BUTTON_FF
168#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_REW
169#define OSCILLOSCOPE_ORIENTATION (BUTTON_REW | BUTTON_REPEAT)
170#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_PLAY
171#define OSCILLOSCOPE_GRAPHMODE (BUTTON_PLAY | BUTTON_REPEAT)
172#define OSCILLOSCOPE_PAUSE_PRE BUTTON_PLAY
173#define OSCILLOSCOPE_PAUSE (BUTTON_PLAY | BUTTON_REL)
174#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
175#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
176#define OSCILLOSCOPE_VOL_UP BUTTON_SCROLL_UP
177#define OSCILLOSCOPE_VOL_DOWN BUTTON_SCROLL_DOWN
178
179#elif CONFIG_KEYPAD == GIGABEAT_S_PAD
180#define OSCILLOSCOPE_QUIT BUTTON_BACK
181#define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
182#define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
183#define OSCILLOSCOPE_ORIENTATION BUTTON_UP
184#define OSCILLOSCOPE_GRAPHMODE BUTTON_MENU
185#define OSCILLOSCOPE_PAUSE BUTTON_PLAY
186#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
187#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
188#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
189#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
190
191#elif (CONFIG_KEYPAD == MROBE100_PAD)
192#define OSCILLOSCOPE_QUIT BUTTON_POWER
193#define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
194#define OSCILLOSCOPE_ADVMODE BUTTON_MENU
195#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_PLAY
196#define OSCILLOSCOPE_ORIENTATION (BUTTON_PLAY | BUTTON_REL)
197#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_PLAY
198#define OSCILLOSCOPE_GRAPHMODE (BUTTON_PLAY | BUTTON_REPEAT)
199#define OSCILLOSCOPE_PAUSE BUTTON_DISPLAY
200#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
201#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
202#define OSCILLOSCOPE_VOL_UP BUTTON_UP
203#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
204
205#elif CONFIG_KEYPAD == IAUDIO_M3_PAD
206#define OSCILLOSCOPE_QUIT BUTTON_RC_REC
207#define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_RC_MODE
208#define OSCILLOSCOPE_DRAWMODE (BUTTON_RC_MODE|BUTTON_REL)
209#define OSCILLOSCOPE_ADVMODE BUTTON_RC_MENU
210#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_RC_MODE
211#define OSCILLOSCOPE_ORIENTATION (BUTTON_RC_MODE|BUTTON_REPEAT)
212#define OSCILLOSCOPE_PAUSE_PRE BUTTON_RC_PLAY
213#define OSCILLOSCOPE_PAUSE (BUTTON_RC_PLAY|BUTTON_REL)
214#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_RC_PLAY
215#define SCILLLOSCOPE_GRAPHMODE (BUTTON_RC_PLAY|BUTTON_REPEAT)
216#define OSCILLOSCOPE_SPEED_UP BUTTON_RC_FF
217#define OSCILLOSCOPE_SPEED_DOWN BUTTON_RC_REW
218#define OSCILLOSCOPE_VOL_UP BUTTON_RC_VOL_UP
219#define OSCILLOSCOPE_VOL_DOWN BUTTON_RC_VOL_DOWN
220
221#elif CONFIG_KEYPAD == COWON_D2_PAD
222#define OSCILLOSCOPE_QUIT BUTTON_POWER
223#define OSCILLOSCOPE_VOL_UP BUTTON_PLUS
224#define OSCILLOSCOPE_VOL_DOWN BUTTON_MINUS
225
226#elif CONFIG_KEYPAD == CREATIVEZVM_PAD
227#define OSCILLOSCOPE_QUIT BUTTON_BACK
228#define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
229#define OSCILLOSCOPE_ADVMODE BUTTON_CUSTOM
230#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_MENU
231#define OSCILLOSCOPE_ORIENTATION (BUTTON_MENU | BUTTON_REL)
232#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_MENU
233#define OSCILLOSCOPE_GRAPHMODE (BUTTON_MENU | BUTTON_REPEAT)
234#define OSCILLOSCOPE_PAUSE BUTTON_PLAY
235#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
236#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
237#define OSCILLOSCOPE_VOL_UP BUTTON_UP
238#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
239
240#elif CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD
241#define OSCILLOSCOPE_QUIT BUTTON_POWER
242#define OSCILLOSCOPE_DRAWMODE (BUTTON_MENU | BUTTON_UP)
243#define OSCILLOSCOPE_ADVMODE (BUTTON_MENU | BUTTON_DOWN)
244#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_PLAY
245#define OSCILLOSCOPE_GRAPHMODE (BUTTON_PLAY | BUTTON_REPEAT)
246#define OSCILLOSCOPE_ORIENTATION (BUTTON_MENU | BUTTON_BACK)
247#define OSCILLOSCOPE_SPEED_UP (BUTTON_BACK | BUTTON_UP)
248#define OSCILLOSCOPE_SPEED_DOWN (BUTTON_BACK | BUTTON_DOWN)
249#define OSCILLOSCOPE_PAUSE (BUTTON_PLAY | BUTTON_REL)
250#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
251#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
252
253#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
254#define OSCILLOSCOPE_QUIT BUTTON_POWER
255#define OSCILLOSCOPE_DRAWMODE BUTTON_MENU
256#define OSCILLOSCOPE_ADVMODE BUTTON_VIEW
257#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_UP
258#define OSCILLOSCOPE_ORIENTATION (BUTTON_UP | BUTTON_REL)
259#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_UP
260#define OSCILLOSCOPE_GRAPHMODE (BUTTON_UP | BUTTON_REPEAT)
261#define OSCILLOSCOPE_PAUSE BUTTON_SELECT
262#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
263#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
264#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
265#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
266
267#elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
268#define OSCILLOSCOPE_QUIT BUTTON_POWER
269#define OSCILLOSCOPE_DRAWMODE BUTTON_MENU
270#define OSCILLOSCOPE_ADVMODE BUTTON_RIGHT
271#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_UP
272#define OSCILLOSCOPE_ORIENTATION (BUTTON_UP | BUTTON_REL)
273#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_UP
274#define OSCILLOSCOPE_GRAPHMODE (BUTTON_UP | BUTTON_REPEAT)
275#define OSCILLOSCOPE_PAUSE BUTTON_PLAY
276#define OSCILLOSCOPE_SPEED_UP BUTTON_NEXT
277#define OSCILLOSCOPE_SPEED_DOWN BUTTON_PREV
278#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
279#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
280
281#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
282#define OSCILLOSCOPE_QUIT BUTTON_POWER
283#define OSCILLOSCOPE_DRAWMODE BUTTON_MENU
284#define OSCILLOSCOPE_ADVMODE BUTTON_RIGHT
285#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_UP
286#define OSCILLOSCOPE_ORIENTATION (BUTTON_UP | BUTTON_REL)
287#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_UP
288#define OSCILLOSCOPE_GRAPHMODE (BUTTON_UP | BUTTON_REPEAT)
289#define OSCILLOSCOPE_PAUSE BUTTON_PLAY
290#define OSCILLOSCOPE_SPEED_UP BUTTON_NEXT
291#define OSCILLOSCOPE_SPEED_DOWN BUTTON_PREV
292#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
293#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
294
295#elif CONFIG_KEYPAD == ONDAVX747_PAD
296#define OSCILLOSCOPE_QUIT BUTTON_POWER
297#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
298#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
299
300#elif CONFIG_KEYPAD == ONDAVX777_PAD
301#define OSCILLOSCOPE_QUIT BUTTON_POWER
302
303#elif CONFIG_KEYPAD == MROBE500_PAD
304#define OSCILLOSCOPE_QUIT BUTTON_POWER
305
306#elif CONFIG_KEYPAD == SAMSUNG_YH92X_PAD
307#define OSCILLOSCOPE_QUIT BUTTON_REW
308#define OSCILLOSCOPE_DRAWMODE BUTTON_FFWD
309#define OSCILLOSCOPE_ADVMODE (BUTTON_PLAY|BUTTON_RIGHT)
310#define OSCILLOSCOPE_ORIENTATION (BUTTON_PLAY|BUTTON_UP)
311#define OSCILLOSCOPE_GRAPHMODE (BUTTON_PLAY|BUTTON_LEFT)
312#define OSCILLOSCOPE_PAUSE_PRE BUTTON_PLAY
313#define OSCILLOSCOPE_PAUSE (BUTTON_PLAY|BUTTON_REL)
314#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
315#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
316#define OSCILLOSCOPE_VOL_UP BUTTON_UP
317#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
318
319#elif CONFIG_KEYPAD == SAMSUNG_YH820_PAD
320#define OSCILLOSCOPE_QUIT BUTTON_REW
321#define OSCILLOSCOPE_DRAWMODE BUTTON_FFWD
322#define OSCILLOSCOPE_ADVMODE (BUTTON_REC|BUTTON_RIGHT)
323#define OSCILLOSCOPE_ORIENTATION (BUTTON_REC|BUTTON_UP)
324#define OSCILLOSCOPE_GRAPHMODE (BUTTON_REC|BUTTON_LEFT)
325#define OSCILLOSCOPE_PAUSE BUTTON_PLAY
326#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
327#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
328#define OSCILLOSCOPE_VOL_UP BUTTON_UP
329#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
330
331#elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
332#define OSCILLOSCOPE_QUIT BUTTON_REC
333#define OSCILLOSCOPE_DRAWMODE BUTTON_MENU
334#define OSCILLOSCOPE_ADVMODE BUTTON_CANCEL
335#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_OK
336#define OSCILLOSCOPE_ORIENTATION (BUTTON_OK | BUTTON_REL)
337#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_OK
338#define OSCILLOSCOPE_GRAPHMODE (BUTTON_OK | BUTTON_REPEAT)
339#define OSCILLOSCOPE_PAUSE BUTTON_PLAY
340#define OSCILLOSCOPE_SPEED_UP BUTTON_PREV
341#define OSCILLOSCOPE_SPEED_DOWN BUTTON_NEXT
342#define OSCILLOSCOPE_VOL_UP BUTTON_UP
343#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
344
345#elif CONFIG_KEYPAD == MPIO_HD200_PAD
346#define OSCILLOSCOPE_QUIT (BUTTON_REC | BUTTON_PLAY)
347#define OSCILLOSCOPE_DRAWMODE BUTTON_FUNC
348#define OSCILLOSCOPE_ADVMODE BUTTON_REC
349#define OSCILLOSCOPE_ORIENTATION (BUTTON_FUNC | BUTTON_REPEAT)
350#define OSCILLOSCOPE_PAUSE BUTTON_PLAY
351#define OSCILLOSCOPE_SPEED_UP BUTTON_FF
352#define OSCILLOSCOPE_SPEED_DOWN BUTTON_REW
353#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
354#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
355/* Need GRAPHMODE */
356
357#elif CONFIG_KEYPAD == MPIO_HD300_PAD
358#define OSCILLOSCOPE_QUIT (BUTTON_MENU | BUTTON_REPEAT)
359#define OSCILLOSCOPE_DRAWMODE BUTTON_ENTER
360#define OSCILLOSCOPE_ADVMODE BUTTON_REC
361#define OSCILLOSCOPE_ORIENTATION BUTTON_MENU
362#define OSCILLOSCOPE_PAUSE BUTTON_PLAY
363#define OSCILLOSCOPE_SPEED_UP BUTTON_FF
364#define OSCILLOSCOPE_SPEED_DOWN BUTTON_REW
365#define OSCILLOSCOPE_VOL_UP BUTTON_UP
366#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
367/* Need GRAPHMODE */
368
369#elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
370#define OSCILLOSCOPE_QUIT BUTTON_POWER
371#define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
372#define OSCILLOSCOPE_ADVMODE BUTTON_BACK
373#define OSCILLOSCOPE_ORIENTATION BUTTON_UP
374#define OSCILLOSCOPE_PAUSE BUTTON_PLAYPAUSE
375#define OSCILLOSCOPE_SPEED_UP BUTTON_LEFT
376#define OSCILLOSCOPE_SPEED_DOWN BUTTON_RIGHT
377#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
378#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
379/* Need GRAPHMODE */
380
381#elif (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
382#define OSCILLOSCOPE_QUIT BUTTON_POWER
383#define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
384#define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
385#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_UP
386#define OSCILLOSCOPE_ORIENTATION (BUTTON_UP | BUTTON_REL)
387#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_UP
388#define OSCILLOSCOPE_GRAPHMODE (BUTTON_UP | BUTTON_REPEAT)
389#define OSCILLOSCOPE_PAUSE BUTTON_NEXT
390#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
391#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
392#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
393#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
394
395#elif (CONFIG_KEYPAD == SAMSUNG_YPR0_PAD)
396#define OSCILLOSCOPE_QUIT BUTTON_BACK
397#define OSCILLOSCOPE_DRAWMODE BUTTON_USER
398#define OSCILLOSCOPE_ADVMODE BUTTON_MENU
399#define OSCILLOSCOPE_ORIENTATION BUTTON_POWER
400#define OSCILLOSCOPE_PAUSE BUTTON_SELECT
401#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
402#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
403#define OSCILLOSCOPE_VOL_UP BUTTON_UP
404#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
405/* Need GRAPHMODE */
406
407#elif (CONFIG_KEYPAD == HM60X_PAD)
408#define OSCILLOSCOPE_QUIT BUTTON_POWER
409#define OSCILLOSCOPE_DRAWMODE (BUTTON_POWER | BUTTON_SELECT)
410#define OSCILLOSCOPE_ADVMODE (BUTTON_POWER | BUTTON_RIGHT)
411#define OSCILLOSCOPE_ORIENTATION (BUTTON_POWER | BUTTON_LEFT)
412#define OSCILLOSCOPE_PAUSE BUTTON_SELECT
413#define OSCILLOSCOPE_SPEED_UP BUTTON_UP
414#define OSCILLOSCOPE_SPEED_DOWN BUTTON_DOWN
415#define OSCILLOSCOPE_VOL_UP BUTTON_RIGHT
416#define OSCILLOSCOPE_VOL_DOWN BUTTON_LEFT
417/* Need GRAPHMODE */
418
419#elif (CONFIG_KEYPAD == HM801_PAD)
420#define OSCILLOSCOPE_QUIT BUTTON_POWER
421#define OSCILLOSCOPE_DRAWMODE BUTTON_PREV
422#define OSCILLOSCOPE_ADVMODE BUTTON_NEXT
423#define OSCILLOSCOPE_ORIENTATION BUTTON_PLAY
424#define OSCILLOSCOPE_PAUSE BUTTON_SELECT
425#define OSCILLOSCOPE_SPEED_UP BUTTON_UP
426#define OSCILLOSCOPE_SPEED_DOWN BUTTON_DOWN
427#define OSCILLOSCOPE_VOL_UP BUTTON_RIGHT
428#define OSCILLOSCOPE_VOL_DOWN BUTTON_LEFT
429/* Need GRAPHMODE */
430
431#elif CONFIG_KEYPAD == SONY_NWZ_PAD
432#define OSCILLOSCOPE_QUIT (BUTTON_BACK|BUTTON_REPEAT)
433#define OSCILLOSCOPE_DRAWMODE BUTTON_BACK
434#define OSCILLOSCOPE_ADVMODE (BUTTON_POWER|BUTTON_REPEAT)
435#define OSCILLOSCOPE_ORIENTATION BUTTON_POWER
436#define OSCILLOSCOPE_PAUSE BUTTON_PLAY
437#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
438#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
439#define OSCILLOSCOPE_VOL_UP BUTTON_UP
440#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
441
442#elif CONFIG_KEYPAD == CREATIVE_ZEN_PAD
443#define OSCILLOSCOPE_QUIT BUTTON_BACK
444#define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
445#define OSCILLOSCOPE_ADVMODE BUTTON_MENU
446#define OSCILLOSCOPE_ORIENTATION BUTTON_SHORTCUT
447#define OSCILLOSCOPE_PAUSE BUTTON_PLAYPAUSE
448#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
449#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
450#define OSCILLOSCOPE_VOL_UP BUTTON_UP
451#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
452
453#elif CONFIG_KEYPAD == DX50_PAD
454#define OSCILLOSCOPE_QUIT (BUTTON_POWER|BUTTON_REL)
455#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
456#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
457
458#elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD
459#define OSCILLOSCOPE_QUIT BUTTON_POWER
460#define OSCILLOSCOPE_PAUSE BUTTON_MENU
461#define OSCILLOSCOPE_ORIENTATION BUTTON_TOPLEFT
462#define OSCILLOSCOPE_GRAPHMODE BUTTON_BOTTOMLEFT
463
464#elif CONFIG_KEYPAD == AGPTEK_ROCKER_PAD
465#define OSCILLOSCOPE_QUIT BUTTON_POWER
466#define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT|BUTTON_UP)
467#define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
468#define OSCILLOSCOPE_ORIENTATION BUTTON_UP
469#define OSCILLOSCOPE_PAUSE BUTTON_SELECT
470#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
471#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
472#define OSCILLOSCOPE_VOL_UP BUTTON_VOLUP
473#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOLDOWN
474
475#elif (CONFIG_KEYPAD == XDUOO_X3_PAD)
476#define OSCILLOSCOPE_QUIT BUTTON_POWER
477#define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_PLAY
478#define OSCILLOSCOPE_DRAWMODE (BUTTON_PLAY | BUTTON_REL)
479#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_PLAY
480#define OSCILLOSCOPE_ORIENTATION (BUTTON_PLAY | BUTTON_REPEAT)
481#define OSCILLOSCOPE_ADVMODE BUTTON_HOME
482#define OSCILLOSCOPE_PAUSE BUTTON_OPTION
483#define OSCILLOSCOPE_SPEED_UP BUTTON_NEXT
484#define OSCILLOSCOPE_SPEED_DOWN BUTTON_PREV
485#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
486#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
487#define NEED_LASTBUTTON
488
489#elif (CONFIG_KEYPAD == XDUOO_X3II_PAD) || (CONFIG_KEYPAD == XDUOO_X20_PAD)
490#define OSCILLOSCOPE_QUIT BUTTON_POWER
491#define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_PLAY
492#define OSCILLOSCOPE_DRAWMODE (BUTTON_PLAY | BUTTON_REL)
493#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_PLAY
494#define OSCILLOSCOPE_ORIENTATION (BUTTON_PLAY | BUTTON_REPEAT)
495#define OSCILLOSCOPE_ADVMODE BUTTON_HOME
496#define OSCILLOSCOPE_PAUSE BUTTON_OPTION
497#define OSCILLOSCOPE_SPEED_UP BUTTON_NEXT
498#define OSCILLOSCOPE_SPEED_DOWN BUTTON_PREV
499#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
500#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
501#define NEED_LASTBUTTON
502
503#elif (CONFIG_KEYPAD == FIIO_M3K_LINUX_PAD)
504#define OSCILLOSCOPE_QUIT BUTTON_POWER
505#define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_PLAY
506#define OSCILLOSCOPE_DRAWMODE (BUTTON_PLAY | BUTTON_REL)
507#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_PLAY
508#define OSCILLOSCOPE_ORIENTATION (BUTTON_PLAY | BUTTON_REPEAT)
509#define OSCILLOSCOPE_ADVMODE BUTTON_HOME
510#define OSCILLOSCOPE_PAUSE BUTTON_OPTION
511#define OSCILLOSCOPE_SPEED_UP BUTTON_NEXT
512#define OSCILLOSCOPE_SPEED_DOWN BUTTON_PREV
513#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
514#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
515#define NEED_LASTBUTTON
516
517#elif (CONFIG_KEYPAD == IHIFI_770_PAD) || (CONFIG_KEYPAD == IHIFI_800_PAD)
518#define OSCILLOSCOPE_QUIT BUTTON_POWER
519#define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_PLAY
520#define OSCILLOSCOPE_DRAWMODE (BUTTON_PLAY | BUTTON_REL)
521#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_PLAY
522#define OSCILLOSCOPE_ORIENTATION (BUTTON_PLAY | BUTTON_REPEAT)
523#define OSCILLOSCOPE_ADVMODE BUTTON_HOME
524#define OSCILLOSCOPE_PAUSE (BUTTON_HOME | BUTTON_REPEAT)
525#define OSCILLOSCOPE_SPEED_UP BUTTON_NEXT
526#define OSCILLOSCOPE_SPEED_DOWN BUTTON_PREV
527#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
528#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
529#define NEED_LASTBUTTON
530
531#elif CONFIG_KEYPAD == EROSQ_PAD
532#define OSCILLOSCOPE_QUIT BUTTON_POWER
533#define OSCILLOSCOPE_DRAWMODE BUTTON_PREV
534#define OSCILLOSCOPE_ADVMODE BUTTON_NEXT
535#define OSCILLOSCOPE_ORIENTATION BUTTON_BACK
536#define OSCILLOSCOPE_PAUSE BUTTON_PLAY
537#define OSCILLOSCOPE_SPEED_UP BUTTON_SCROLL_FWD
538#define OSCILLOSCOPE_SPEED_DOWN BUTTON_SCROLL_BACK
539#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
540#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
541
542#elif CONFIG_KEYPAD == FIIO_M3K_PAD
543#define OSCILLOSCOPE_QUIT BUTTON_POWER
544#define OSCILLOSCOPE_DRAWMODE BUTTON_MENU
545#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_BACK
546#define OSCILLOSCOPE_GRAPHMODE (BUTTON_BACK | BUTTON_REPEAT)
547#define OSCILLOSCOPE_ADVMODE BUTTON_PLAY
548#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_BACK
549#define OSCILLOSCOPE_ORIENTATION (BUTTON_BACK | BUTTON_REL)
550#define OSCILLOSCOPE_PAUSE BUTTON_SELECT
551#define OSCILLOSCOPE_SPEED_UP BUTTON_SCROLL_BACK
552#define OSCILLOSCOPE_SPEED_DOWN BUTTON_SCROLL_FWD
553#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
554#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
555
556#elif CONFIG_KEYPAD == MA_PAD
557#define OSCILLOSCOPE_QUIT (BUTTON_BACK|BUTTON_REPEAT)
558#define OSCILLOSCOPE_DRAWMODE BUTTON_MENU
559#define OSCILLOSCOPE_ADVMODE (BUTTON_MENU|BUTTON_REPEAT)
560#define OSCILLOSCOPE_ORIENTATION BUTTON_BACK
561#define OSCILLOSCOPE_PAUSE BUTTON_PLAY
562#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
563#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
564#define OSCILLOSCOPE_VOL_UP BUTTON_UP
565#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
566
567#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
568/* use touchscreen */
569
570#elif CONFIG_KEYPAD == SDL_PAD
571/* use touchscreen */
572#elif CONFIG_KEYPAD == RG_NANO_PAD
573#define OSCILLOSCOPE_QUIT BUTTON_START
574#define OSCILLOSCOPE_DRAWMODE BUTTON_X
575#define OSCILLOSCOPE_ADVMODE BUTTON_Y
576#define OSCILLOSCOPE_ORIENTATION BUTTON_R
577#define OSCILLOSCOPE_GRAPHMODE BUTTON_B
578#define OSCILLOSCOPE_PAUSE BUTTON_A
579#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
580#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
581#define OSCILLOSCOPE_VOL_UP BUTTON_UP
582#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
583
584#else
585#error No keymap defined!
586#endif
587
588#ifdef HAVE_TOUCHSCREEN
589#ifndef OSCILLOSCOPE_QUIT
590#define OSCILLOSCOPE_QUIT BUTTON_TOPLEFT
591#endif
592#ifndef OSCILLOSCOPE_DRAWMODE
593#define OSCILLOSCOPE_DRAWMODE BUTTON_TOPMIDDLE
594#endif
595#ifndef OSCILLOSCOPE_ADVMODE
596#define OSCILLOSCOPE_ADVMODE BUTTON_BOTTOMMIDDLE
597#endif
598#ifndef OSCILLOSCOPE_ORIENTATION
599#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_BOTTOMLEFT
600#define OSCILLOSCOPE_ORIENTATION (BUTTON_BOTTOMLEFT|BUTTON_REL)
601#endif
602#ifndef OSCILLOSCOPE_GRAPHMODE
603#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_BOTTOMLEFT
604#define OSCILLOSCOPE_GRAPHMODE (BUTTON_BOTTOMLEFT|BUTTON_REPEAT)
605#endif
606#ifndef OSCILLOSCOPE_PAUSE
607#define OSCILLOSCOPE_PAUSE BUTTON_CENTER
608#endif
609#ifndef OSCILLOSCOPE_SPEED_UP
610#define OSCILLOSCOPE_SPEED_UP BUTTON_MIDRIGHT
611#endif
612#ifndef OSCILLOSCOPE_SPEED_DOWN
613#define OSCILLOSCOPE_SPEED_DOWN BUTTON_MIDLEFT
614#endif
615#ifndef OSCILLOSCOPE_VOL_UP
616#define OSCILLOSCOPE_VOL_UP BUTTON_TOPRIGHT
617#endif
618#ifndef OSCILLOSCOPE_VOL_DOWN
619#define OSCILLOSCOPE_VOL_DOWN BUTTON_BOTTOMRIGHT
620#endif
621#endif /* HAVE_TOUCHSCREEN */
622
623#if defined(OSCILLOSCOPE_DRAWMODE_PRE) || defined(OSCILLOSCOPE_ORIENTATION_PRE) \
624 || defined(OSCILLOSCOPE_GRAPHMODE_PRE) || defined(OSCILLOSCOPE_PAUSE_PRE)
625#define NEED_LASTBUTTON
626#endif
627
628/* colours */
629#if LCD_DEPTH > 1
630#ifdef HAVE_LCD_COLOR
631#define BACKG_COLOR LCD_BLACK
632#define GRAPH_COLOR LCD_RGBPACK(128, 255, 0)
633#define CURSOR_COLOR LCD_RGBPACK(255, 0, 0)
634#define GRID_COLOR LCD_RGBPACK(192, 255, 64)
635#define OSD_TEXT_COLOR LCD_WHITE
636#define OSD_BACKG_COLOR LCD_BLACK
637#define OSD_BORDER_COLOR LCD_RGBPACK(255, 0, 0)
638#define OSC_OSD_MARGIN_SIZE 0 /* Border and text are different */
639#else
640#define BACKG_COLOR LCD_WHITE
641#define GRAPH_COLOR LCD_BLACK
642#define CURSOR_COLOR LCD_DARKGRAY
643#define GRID_COLOR LCD_DARKGRAY
644#define OSD_TEXT_COLOR LCD_BLACK
645#define OSD_BACKG_COLOR LCD_WHITE
646#define OSD_BORDER_COLOR LCD_BLACK
647#endif
648#endif
649
650#ifndef OSC_OSD_MARGIN_SIZE
651#define OSC_OSD_MARGIN_SIZE 1
652#endif
653
654#define MIN_SPEED 1
655#define MAX_SPEED 100
656
657enum { DRAW_FILLED, DRAW_LINE, DRAW_PIXEL, MAX_DRAW };
658enum { ADV_SCROLL, ADV_WRAP, MAX_ADV };
659enum { OSC_HORIZ, OSC_VERT, MAX_OSC };
660enum
661{
662 GRAPH_PEAKS,
663#ifdef OSCILLOSCOPE_GRAPHMODE
664 GRAPH_WAVEFORM,
665#endif
666 MAX_GRAPH
667};
668
669#define CFGFILE_VERSION 1 /* Current config file version */
670#define CFGFILE_MINVERSION 0 /* Minimum config file version to accept */
671
672/* global variables */
673
674/*
675 * / 99*[e ^ ((100 - x) / z) - 1] \
676 * osc_delay = HZ * | ---------------------------- + 1 |
677 * \ [e ^ (99 / z) - 1] /
678 *
679 * x: 1 .. 100, z: 15, delay: 100.00 .. 1.00
680 */
681static const unsigned short osc_delay_tbl[100] =
682{
683 10000, 9361, 8763, 8205, 7682, 7192, 6735, 6307, 5906, 5532,
684 5181, 4853, 4546, 4259, 3991, 3739, 3504, 3285, 3079, 2886,
685 2706, 2538, 2380, 2233, 2095, 1966, 1845, 1732, 1627, 1528,
686 1435, 1349, 1268, 1192, 1121, 1055, 993, 935, 880, 830,
687 782, 737, 696, 657, 620, 586, 554, 524, 497, 470,
688 446, 423, 402, 381, 363, 345, 329, 313, 299, 285,
689 273, 261, 250, 239, 230, 221, 212, 204, 197, 190,
690 183, 177, 171, 166, 161, 156, 152, 147, 144, 140,
691 136, 133, 130, 127, 125, 122, 120, 118, 116, 114,
692 112, 110, 108, 107, 106, 104, 103, 102, 101, 100
693};
694
695#define GRAPH_PEAKS_DEFAULT 68
696#define GRAPH_WAVEFORM_DEFAULT 50
697
698/* settings */
699static struct osc_config
700{
701 int speed[MAX_GRAPH];
702 int draw;
703 int advance;
704 int orientation;
705 int graphmode;
706} osc_disk =
707{
708 .speed =
709 {
710 [GRAPH_PEAKS] = GRAPH_PEAKS_DEFAULT,
711#ifdef OSCILLOSCOPE_GRAPHMODE
712 [GRAPH_WAVEFORM] = GRAPH_WAVEFORM_DEFAULT,
713#endif
714 },
715 .draw = DRAW_FILLED,
716 .advance = ADV_SCROLL,
717 .orientation = OSC_HORIZ,
718#ifdef OSCILLOSCOPE_GRAPHMODE
719 .graphmode = GRAPH_PEAKS,
720#endif
721};
722
723static struct osc_config osc; /* running config */
724
725static const char cfg_filename[] = "oscilloscope.cfg";
726static char *draw_str[3] = { "filled", "line", "pixel" };
727static char *advance_str[2] = { "scroll", "wrap" };
728static char *orientation_str[2] = { "horizontal", "vertical" };
729#ifdef OSCILLOSCOPE_GRAPHMODE
730static char *graphmode_str[2] = { "peaks", "waveform" };
731#endif
732
733struct configdata disk_config[] =
734{
735 { TYPE_INT, MIN_SPEED, MAX_SPEED,
736 { .int_p = &osc_disk.speed[GRAPH_PEAKS] }, "speed", NULL },
737 { TYPE_ENUM, 0, MAX_DRAW, { .int_p = &osc_disk.draw }, "draw", draw_str },
738 { TYPE_ENUM, 0, MAX_ADV, { .int_p = &osc_disk.advance }, "advance",
739 advance_str },
740 { TYPE_ENUM, 0, MAX_OSC, { .int_p = &osc_disk.orientation }, "orientation",
741 orientation_str },
742#ifdef OSCILLOSCOPE_GRAPHMODE
743 { TYPE_INT, MIN_SPEED, MAX_SPEED,
744 { .int_p = &osc_disk.speed[GRAPH_WAVEFORM] }, "wavespeed", NULL },
745 { TYPE_ENUM, 0, MAX_GRAPH, { .int_p = &osc_disk.graphmode }, "graphmode",
746 graphmode_str },
747#endif
748};
749
750enum osc_message_ids
751{
752 OSC_MSG_ADVMODE,
753 OSC_MSG_DRAWMODE,
754#ifdef OSCILLOSCOPE_GRAPHMODE
755 OSC_MSG_GRAPHMODE,
756#endif
757 OSC_MSG_ORIENTATION,
758 OSC_MSG_PAUSED,
759 OSC_MSG_SPEED,
760 OSC_MSG_VOLUME,
761};
762
763static long (*anim_draw)(void);
764static int message = -1, msgval = 0; /* popup message */
765static bool paused = false;
766static bool one_frame_paused = false; /* Allow one frame to be drawn when paused if
767 view is erased */
768static long osc_delay; /* delay in 100ths of a tick */
769static long osc_delay_error; /* delay fraction error accumulator */
770
771static enum pcm_mixer_channel channel;
772
773/* implementation */
774
775
776/** Messages **/
777
778static unsigned char osc_osd_message[16]; /* message to display (formatted) */
779
780static inline void osc_popupmsg(int msg, int val)
781{
782 message = msg; msgval = val;
783}
784
785/* Format a message to display */
786static void osc_osd_format_message(enum osc_message_ids id, int val)
787{
788 const char *msg = "";
789
790 switch (id)
791 {
792 case OSC_MSG_ADVMODE:
793 msg = val == ADV_WRAP ? "Wrap" : "Scroll";
794 break;
795
796 case OSC_MSG_DRAWMODE:
797 switch (val)
798 {
799 case DRAW_PIXEL: msg = "Pixel"; break;
800 case DRAW_LINE: msg = "Line"; break;
801 default: msg = "Filled";
802 }
803 break;
804
805#ifdef OSCILLOSCOPE_GRAPHMODE
806 case OSC_MSG_GRAPHMODE:
807 msg = val == GRAPH_WAVEFORM ? "Waveform" : "Peaks";
808 break;
809#endif
810
811 case OSC_MSG_ORIENTATION:
812 msg = val == OSC_VERT ? "Vertical" : "Horizontal";
813 break;
814
815 case OSC_MSG_PAUSED:
816 msg = val ? "Paused" : "Running";
817 break;
818
819 case OSC_MSG_SPEED:
820 msg = "Speed: %d";
821 break;
822
823 case OSC_MSG_VOLUME:
824 rb->snprintf(osc_osd_message, sizeof (osc_osd_message),
825 "Volume: %d%s",
826 rb->sound_val2phys(SOUND_VOLUME, val),
827 rb->sound_unit(SOUND_VOLUME));
828 return;
829 }
830
831 /* Default action: format integer */
832 rb->snprintf(osc_osd_message, sizeof (osc_osd_message), msg, val);
833}
834
835
836/** OSD **/
837
838/* Actually draw the OSD within the OSD viewport */
839extern void osd_lcd_draw_cb(int x, int y, int width, int height)
840{
841#if LCD_DEPTH > 1
842 rb->lcd_set_foreground(OSD_TEXT_COLOR);
843 rb->lcd_set_background(OSD_BACKG_COLOR);
844#endif
845#if OSC_OSD_MARGIN_SIZE != 0
846 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
847 rb->lcd_fillrect(1, 1, width - 2, height - 2);
848 rb->lcd_set_drawmode(DRMODE_SOLID);
849#endif
850 rb->lcd_putsxy(1+OSC_OSD_MARGIN_SIZE, 1+OSC_OSD_MARGIN_SIZE,
851 osc_osd_message);
852#if LCD_DEPTH > 1
853 rb->lcd_set_foreground(OSD_BORDER_COLOR);
854#endif
855 rb->lcd_drawrect(0, 0, width, height);
856
857 (void)x; (void)y;
858}
859
860/* Perform all necessary basic setup tasks for the OSD */
861static void osc_osd_init(void)
862{
863 /* Grab the plugin buffer for the OSD back buffer */
864 size_t bufsize;
865 void *buf = rb->plugin_get_buffer(&bufsize);
866
867 int width, height;
868 rb->lcd_setfont(FONT_UI);
869 rb->lcd_getstringsize("M", NULL, &height);
870 width = LCD_WIDTH;
871 height += 2 + 2*OSC_OSD_MARGIN_SIZE;
872 osd_init(OSD_INIT_MAJOR_HEIGHT | OSD_INIT_MINOR_MAX, buf, bufsize,
873 osd_lcd_draw_cb, &width, &height, NULL);
874}
875
876/* Format a message by ID and show the OSD */
877static void osc_osd_show_message(int id, int val)
878{
879 osc_osd_format_message(id, val);
880
881 if (!osd_enabled())
882 return;
883
884 int width, height;
885 int maxwidth, maxheight;
886
887 struct viewport *last_vp = rb->lcd_set_viewport(osd_get_viewport());
888 osd_get_max_dims(&maxwidth, &maxheight);
889 rb->lcd_getstringsize(osc_osd_message, &width, &height);
890 rb->lcd_set_viewport(last_vp); /* to regular viewport */
891
892 width += 2 + 2*OSC_OSD_MARGIN_SIZE;
893 if (width > maxwidth)
894 width = maxwidth;
895
896 height += 2 + 2*OSC_OSD_MARGIN_SIZE;
897 if (height > maxheight)
898 height = maxheight;
899
900 /* Center it on the screen */
901 bool drawn = osd_update_pos((LCD_WIDTH - width) / 2,
902 (LCD_HEIGHT - height) / 2,
903 width, height);
904
905 osd_show(OSD_SHOW | (drawn ? 0 : OSD_UPDATENOW));
906}
907
908/* Draw cursor bar for horizontal views */
909static void anim_draw_cursor_h(int x)
910{
911#if LCD_DEPTH > 1
912 rb->lcd_set_foreground(CURSOR_COLOR);
913 rb->lcd_vline(x, 0, LCD_HEIGHT-1);
914 rb->lcd_set_foreground(GRAPH_COLOR);
915#else
916 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
917 rb->lcd_vline(x, 0, LCD_HEIGHT-1);
918 rb->lcd_set_drawmode(DRMODE_SOLID);
919#endif
920}
921
922/* Draw cursor bar for vertical views */
923static void anim_draw_cursor_v(int y)
924{
925#if LCD_DEPTH > 1 /* cursor bar */
926 rb->lcd_set_foreground(CURSOR_COLOR);
927 rb->lcd_hline(0, LCD_WIDTH-1, y);
928 rb->lcd_set_foreground(GRAPH_COLOR);
929#else
930 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
931 rb->lcd_hline(0, LCD_WIDTH-1, y);
932 rb->lcd_set_drawmode(DRMODE_SOLID);
933#endif
934}
935
936
937/** Peaks View **/
938
939static long last_tick = 0; /* time of last drawing */
940static long last_delay = 0; /* last delay value used */
941static int last_pos = 0; /* last x or y drawing position. Reset for aspect switch. */
942static int last_left; /* last channel values */
943static int last_right;
944
945static void get_peaks(int *left, int *right)
946{
947 static struct pcm_peaks peaks;
948 rb->mixer_channel_calculate_peaks(channel,
949 &peaks);
950 *left = peaks.left;
951 *right = peaks.right;
952}
953
954static long get_next_delay(void)
955{
956 long delay = osc_delay / 100;
957 osc_delay_error += osc_delay - delay * 100;
958
959 if (osc_delay_error >= 100)
960 {
961 delay++;
962 osc_delay_error -= 100;
963 }
964
965 return delay;
966}
967
968static long anim_peaks_horizontal(void)
969{
970 long cur_tick = *rb->current_tick;
971 int cur_x, x;
972 int left, right, dl, dr;
973 long d = (cur_tick - last_tick) / last_delay;
974 bool full_update = false;
975
976 if (paused)
977 {
978 one_frame_paused = false;
979 osd_lcd_update_prepare();
980 anim_draw_cursor_h(0);
981 osd_lcd_update_rect(0, 0, 1, LCD_HEIGHT);
982 last_pos = -1;
983 return cur_tick + HZ/5;
984 }
985
986 if (d <= 0) /* too early, bail out */
987 return last_tick + last_delay;
988
989 last_tick = cur_tick;
990
991 int cur_left, cur_right;
992 get_peaks(&cur_left, &cur_right);
993
994 if (d > HZ) /* first call or too much delay, (re)start */
995 {
996 last_left = cur_left;
997 last_right = cur_right;
998 return cur_tick + last_delay;
999 }
1000
1001 one_frame_paused = false;
1002
1003 osd_lcd_update_prepare();
1004
1005 cur_x = last_pos + d;
1006
1007 if (cur_x >= LCD_WIDTH)
1008 {
1009 if (osc.advance == ADV_SCROLL)
1010 {
1011 int shift = cur_x - (LCD_WIDTH-1);
1012 xlcd_scroll_left(shift);
1013 full_update = true;
1014 cur_x -= shift;
1015 last_pos -= shift;
1016 }
1017 else
1018 {
1019 cur_x -= LCD_WIDTH;
1020 }
1021 }
1022 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1023
1024 if (cur_x > last_pos)
1025 {
1026 rb->lcd_fillrect(last_pos + 1, 0, d, LCD_HEIGHT);
1027 }
1028 else
1029 {
1030 rb->lcd_fillrect(last_pos + 1, 0, LCD_WIDTH - last_pos, LCD_HEIGHT);
1031 rb->lcd_fillrect(0, 0, cur_x + 1, LCD_HEIGHT);
1032 }
1033 rb->lcd_set_drawmode(DRMODE_SOLID);
1034
1035 switch (osc.draw)
1036 {
1037 case DRAW_FILLED:
1038 left = last_left;
1039 right = last_right;
1040 dl = (cur_left - left) / d;
1041 dr = (cur_right - right) / d;
1042
1043 for (x = last_pos + 1; d > 0; x++, d--)
1044 {
1045 if (x == LCD_WIDTH)
1046 x = 0;
1047
1048 left += dl;
1049 right += dr;
1050
1051 rb->lcd_vline(x, LCD_HEIGHT/2-1,
1052 LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * left) >> 16));
1053 rb->lcd_vline(x, LCD_HEIGHT/2+1,
1054 LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * right) >> 16));
1055 }
1056 break;
1057
1058 case DRAW_LINE:
1059 if (cur_x > last_pos)
1060 {
1061 rb->lcd_drawline(
1062 last_pos, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * last_left) >> 16),
1063 cur_x, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * cur_left) >> 16)
1064 );
1065 rb->lcd_drawline(
1066 last_pos, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * last_right) >> 16),
1067 cur_x, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * cur_right) >> 16)
1068 );
1069 }
1070 else
1071 {
1072 left = last_left
1073 + (LCD_WIDTH - last_pos) * (last_left - cur_left) / d;
1074 right = last_right
1075 + (LCD_WIDTH - last_pos) * (last_right - cur_right) / d;
1076
1077 rb->lcd_drawline(
1078 last_pos, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * last_left) >> 16),
1079 LCD_WIDTH, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * left) >> 16)
1080 );
1081 rb->lcd_drawline(
1082 last_pos, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * last_right) >> 16),
1083 LCD_WIDTH, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * right) >> 16)
1084 );
1085 if (cur_x > 0)
1086 {
1087 rb->lcd_drawline(
1088 0, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * left) >> 16),
1089 cur_x, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * cur_left) >> 16)
1090 );
1091 rb->lcd_drawline(
1092 0, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * right) >> 16),
1093 cur_x, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * cur_right) >> 16)
1094 );
1095 }
1096 }
1097 break;
1098
1099 case DRAW_PIXEL:
1100 left = last_left;
1101 right = last_right;
1102 dl = (cur_left - left) / d;
1103 dr = (cur_right - right) / d;
1104
1105 for (x = last_pos + 1; d > 0; x++, d--)
1106 {
1107 if (x == LCD_WIDTH)
1108 x = 0;
1109
1110 left += dl;
1111 right += dr;
1112
1113 rb->lcd_drawpixel(x, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * left) >> 16));
1114 rb->lcd_drawpixel(x, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * right) >> 16));
1115 }
1116 break;
1117
1118 }
1119
1120 last_left = cur_left;
1121 last_right = cur_right;
1122
1123 if (full_update)
1124 {
1125 osd_lcd_update();
1126 }
1127 else
1128 {
1129 anim_draw_cursor_h(cur_x + 1); /* cursor bar */
1130
1131 if (cur_x > last_pos)
1132 {
1133 osd_lcd_update_rect(last_pos, 0, cur_x - last_pos + 2, LCD_HEIGHT);
1134 }
1135 else
1136 {
1137 osd_lcd_update_rect(last_pos, 0, LCD_WIDTH - last_pos, LCD_HEIGHT);
1138 osd_lcd_update_rect(0, 0, cur_x + 2, LCD_HEIGHT);
1139 }
1140 }
1141 last_pos = cur_x;
1142
1143 last_delay = get_next_delay();
1144 return cur_tick + last_delay;
1145}
1146
1147static long anim_peaks_vertical(void)
1148{
1149 long cur_tick = *rb->current_tick;
1150 int cur_y, y;
1151 int left, right, dl, dr;
1152 bool full_update = false;
1153 long d = (cur_tick - last_tick) / last_delay;
1154
1155 if (paused)
1156 {
1157 one_frame_paused = false;
1158 osd_lcd_update_prepare();
1159 anim_draw_cursor_v(0);
1160 osd_lcd_update_rect(0, 0, LCD_WIDTH, 1);
1161 last_pos = -1;
1162 return cur_tick + HZ/5;
1163 }
1164
1165 if (d == 0) /* too early, bail out */
1166 return last_tick + last_delay;
1167
1168 last_tick = cur_tick;
1169
1170 int cur_left, cur_right;
1171 get_peaks(&cur_left, &cur_right);
1172
1173 if (d > HZ) /* first call or too much delay, (re)start */
1174 {
1175 last_left = cur_left;
1176 last_right = cur_right;
1177 return cur_tick + last_delay;
1178 }
1179
1180 one_frame_paused = false;
1181
1182 osd_lcd_update_prepare();
1183
1184 cur_y = last_pos + d;
1185
1186 if (cur_y >= LCD_HEIGHT)
1187 {
1188 if (osc.advance == ADV_SCROLL)
1189 {
1190 int shift = cur_y - (LCD_HEIGHT-1);
1191 xlcd_scroll_up(shift);
1192 full_update = true;
1193 cur_y -= shift;
1194 last_pos -= shift;
1195 }
1196 else
1197 {
1198 cur_y -= LCD_HEIGHT;
1199 }
1200 }
1201 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1202
1203 if (cur_y > last_pos)
1204 {
1205 rb->lcd_fillrect(0, last_pos + 1, LCD_WIDTH, d);
1206 }
1207 else
1208 {
1209 rb->lcd_fillrect(0, last_pos + 1, LCD_WIDTH, LCD_HEIGHT - last_pos);
1210 rb->lcd_fillrect(0, 0, LCD_WIDTH, cur_y + 1);
1211 }
1212 rb->lcd_set_drawmode(DRMODE_SOLID);
1213
1214 switch (osc.draw)
1215 {
1216 case DRAW_FILLED:
1217 left = last_left;
1218 right = last_right;
1219 dl = (cur_left - left) / d;
1220 dr = (cur_right - right) / d;
1221
1222 for (y = last_pos + 1; d > 0; y++, d--)
1223 {
1224 if (y == LCD_HEIGHT)
1225 y = 0;
1226
1227 left += dl;
1228 right += dr;
1229
1230 rb->lcd_hline(LCD_WIDTH/2-1,
1231 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * left) >> 16), y);
1232 rb->lcd_hline(LCD_WIDTH/2+1,
1233 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * right) >> 16), y);
1234 }
1235 break;
1236
1237 case DRAW_LINE:
1238 if (cur_y > last_pos)
1239 {
1240 rb->lcd_drawline(
1241 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * last_left) >> 16), last_pos,
1242 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * cur_left) >> 16), cur_y
1243 );
1244 rb->lcd_drawline(
1245 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * last_right) >> 16), last_pos,
1246 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * cur_right) >> 16), cur_y
1247 );
1248 }
1249 else
1250 {
1251 left = last_left
1252 + (LCD_HEIGHT - last_pos) * (last_left - cur_left) / d;
1253 right = last_right
1254 + (LCD_HEIGHT - last_pos) * (last_right - cur_right) / d;
1255
1256 rb->lcd_drawline(
1257 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * last_left) >> 16), last_pos,
1258 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * left) >> 16), LCD_HEIGHT
1259 );
1260 rb->lcd_drawline(
1261 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * last_right) >> 16), last_pos,
1262 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * right) >> 16), LCD_HEIGHT
1263 );
1264 if (cur_y > 0)
1265 {
1266 rb->lcd_drawline(
1267 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * left) >> 16), 0,
1268 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * cur_left) >> 16), cur_y
1269 );
1270 rb->lcd_drawline(
1271 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * right) >> 16), 0,
1272 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * cur_right) >> 16), cur_y
1273 );
1274 }
1275 }
1276 break;
1277
1278 case DRAW_PIXEL:
1279 left = last_left;
1280 right = last_right;
1281 dl = (cur_left - left) / d;
1282 dr = (cur_right - right) / d;
1283
1284 for (y = last_pos + 1; d > 0; y++, d--)
1285 {
1286 if (y == LCD_HEIGHT)
1287 y = 0;
1288
1289 left += dl;
1290 right += dr;
1291
1292 rb->lcd_drawpixel(LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * left) >> 16), y);
1293 rb->lcd_drawpixel(LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * right) >> 16), y);
1294 }
1295 break;
1296
1297 }
1298
1299 last_left = cur_left;
1300 last_right = cur_right;
1301
1302 if (full_update)
1303 {
1304 osd_lcd_update();
1305 }
1306 else
1307 {
1308 anim_draw_cursor_v(cur_y + 1); /* cursor bar */
1309
1310 if (cur_y > last_pos)
1311 {
1312 osd_lcd_update_rect(0, last_pos, LCD_WIDTH, cur_y - last_pos + 2);
1313 }
1314 else
1315 {
1316 osd_lcd_update_rect(0, last_pos, LCD_WIDTH, LCD_HEIGHT - last_pos);
1317 osd_lcd_update_rect(0, 0, LCD_WIDTH, cur_y + 2);
1318 }
1319 }
1320 last_pos = cur_y;
1321
1322 last_delay = get_next_delay();
1323 return cur_tick + last_delay;
1324}
1325
1326
1327/** Waveform View **/
1328
1329#ifdef OSCILLOSCOPE_GRAPHMODE
1330static int16_t waveform_buffer[2*ALIGN_UP(PLAY_SAMPR_MAX, 2048)+2*2048]
1331 MEM_ALIGN_ATTR;
1332static size_t waveform_buffer_threshold = 0;
1333static size_t volatile waveform_buffer_have = 0;
1334static size_t waveform_buffer_break = 0;
1335static unsigned long mixer_sampr = PLAY_SAMPR_DEFAULT;
1336#define PCM_SAMPLESIZE (2*sizeof(int16_t))
1337#define PCM_BYTERATE(sampr) ((sampr)*PCM_SAMPLESIZE)
1338
1339#define WAVEFORM_SCALE_PCM(full_scale, sample) \
1340 ((((full_scale) * (sample)) + (1 << 14)) >> 15)
1341
1342static void waveform_buffer_set_threshold(size_t threshold)
1343{
1344 if (threshold > sizeof (waveform_buffer))
1345 threshold = sizeof (waveform_buffer);
1346
1347 if (threshold == waveform_buffer_threshold)
1348 return;
1349
1350 /* Avoid changing it in the middle of buffer callback */
1351 rb->pcm_play_lock();
1352
1353 waveform_buffer_threshold = threshold;
1354
1355 rb->pcm_play_unlock();
1356}
1357
1358static inline bool waveform_buffer_have_enough(void)
1359{
1360 return waveform_buffer_have >= waveform_buffer_threshold;
1361}
1362
1363static void waveform_buffer_done(void)
1364{
1365 /* This is safe because buffer callback won't add more data unless the
1366 treshold is changed or data is removed below the threshold. This isn't
1367 called until after the threshold is already met. */
1368 size_t threshold = waveform_buffer_threshold;
1369 size_t have = 0;
1370
1371 if (threshold != 0)
1372 {
1373 have = waveform_buffer_have;
1374 size_t slide = (have - 1) / threshold * threshold;
1375
1376 if (slide == 0)
1377 slide = threshold;
1378
1379 have -= slide;
1380
1381 if (have > 0)
1382 {
1383 /* memcpy: the slide >= threshold and have <= threshold */
1384 memcpy(waveform_buffer, (void *)waveform_buffer + slide, have);
1385 }
1386 }
1387
1388 waveform_buffer_have = have;
1389}
1390
1391/* where the samples are obtained and buffered */
1392static void waveform_buffer_callback(const void *start, size_t size)
1393{
1394 size_t threshold = waveform_buffer_threshold;
1395 size_t have = waveform_buffer_have;
1396
1397 if (have >= threshold)
1398 {
1399 waveform_buffer_break += size;
1400 return;
1401 }
1402
1403 if (waveform_buffer_break > 0)
1404 {
1405 /* Previosly missed a part or all of a frame and the break would
1406 happen within the data threshold area. Start where frame would
1407 end up if all had been processed fully. This might mean a period
1408 of resynchronization will have to happen first before the buffer
1409 is filled to the threshold or even begins filling. Maintaining
1410 scan phase relationship is important to proper appearance or else
1411 the waveform display looks sloppy. */
1412 size_t brk = have + waveform_buffer_break;
1413 waveform_buffer_have = have = 0;
1414
1415 brk %= threshold;
1416
1417 if (brk != 0)
1418 {
1419 brk += size;
1420
1421 if (brk <= threshold)
1422 {
1423 waveform_buffer_break = brk;
1424 return;
1425 }
1426
1427 brk -= threshold;
1428 start += size - brk;
1429 size = brk;
1430 }
1431
1432 waveform_buffer_break = 0;
1433 }
1434
1435 size_t remaining = sizeof (waveform_buffer) - have;
1436 size_t copy = size;
1437
1438 if (copy > remaining)
1439 {
1440 waveform_buffer_break = copy - remaining;
1441 copy = remaining;
1442 }
1443
1444 memcpy((void *)waveform_buffer + have, start, copy);
1445
1446 waveform_buffer_have = have + copy;
1447}
1448
1449static void waveform_buffer_reset(void)
1450{
1451 /* only called when callback is off */
1452 waveform_buffer_have = 0;
1453 waveform_buffer_threshold = 0;
1454 waveform_buffer_break = 0;
1455}
1456
1457static void anim_waveform_plot_filled_h(int x, int x_prev,
1458 int vmin, int vmax,
1459 int vmin_prev, int vmax_prev)
1460{
1461 if (vmin != vmax || vmin_prev != vmax_prev)
1462 {
1463 /* Graph compression */
1464 if (vmax > vmin_prev)
1465 vmax = vmin_prev;
1466 else if (vmin < vmax_prev)
1467 vmin = vmax_prev;
1468
1469 rb->lcd_vline(x, vmax, vmin);
1470 }
1471 else
1472 {
1473 /* 1:1 or stretch */
1474 rb->lcd_drawline(x_prev, vmin_prev, x, vmin);
1475 }
1476}
1477
1478static void anim_waveform_plot_lines_h(int x, int x_prev,
1479 int vmin, int vmax,
1480 int vmin_prev, int vmax_prev)
1481{
1482 rb->lcd_drawline(x_prev, vmin_prev, x, vmin);
1483
1484 if (vmax_prev != vmin_prev || vmax != vmin)
1485 rb->lcd_drawline(x_prev, vmax_prev, x, vmax);
1486}
1487
1488static void anim_waveform_plot_pixel_h(int x, int x_prev,
1489 int vmin, int vmax,
1490 int vmin_prev, int vmax_prev)
1491{
1492 rb->lcd_drawpixel(x, vmin);
1493
1494 if (vmax != vmin)
1495 rb->lcd_drawpixel(x, vmax);
1496
1497 (void)x_prev; (void)vmin_prev; (void)vmax_prev;
1498}
1499
1500static long anim_waveform_horizontal(void)
1501{
1502 static void (* const plot[MAX_DRAW])(int, int, int, int, int, int) =
1503 {
1504 [DRAW_FILLED] = anim_waveform_plot_filled_h,
1505 [DRAW_LINE] = anim_waveform_plot_lines_h,
1506 [DRAW_PIXEL] = anim_waveform_plot_pixel_h,
1507 };
1508
1509 long cur_tick = *rb->current_tick;
1510
1511 if (rb->mixer_channel_status(channel) != CHANNEL_PLAYING)
1512 {
1513 osd_lcd_update_prepare();
1514 rb->lcd_hline(0, LCD_WIDTH-1, 1*LCD_HEIGHT/4);
1515 rb->lcd_hline(0, LCD_WIDTH-1, 3*LCD_HEIGHT/4);
1516 osd_lcd_update();
1517 one_frame_paused = false;
1518 return cur_tick + HZ/5;
1519 }
1520
1521 int count = (mixer_sampr*osc_delay + 100*HZ - 1) / (100*HZ);
1522
1523 waveform_buffer_set_threshold(count*PCM_SAMPLESIZE);
1524
1525 if (!waveform_buffer_have_enough())
1526 return cur_tick + HZ/100;
1527
1528 one_frame_paused = false;
1529
1530 osd_lcd_update_prepare();
1531
1532 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1533 rb->lcd_fillrect(0, 0, LCD_WIDTH, LCD_HEIGHT);
1534 rb->lcd_set_drawmode(DRMODE_SOLID);
1535#if LCD_DEPTH > 1
1536 rb->lcd_set_foreground(GRAPH_COLOR);
1537#endif
1538
1539 int x = 0, x_prev = count - 1;
1540 int x_step = (LCD_WIDTH-1) / x_prev;
1541 int x_a_step = (LCD_WIDTH-1) - x_step * x_prev;
1542 int x_a = 0;
1543
1544 int idx_step = (count / LCD_WIDTH) * 2;
1545 int idx_a_step = count - idx_step * (LCD_WIDTH/2);
1546 int idx = idx_step, idx_prev = 0;
1547 int idx_a = idx_a_step;
1548
1549 int a_lim = MIN(x_prev, LCD_WIDTH-1);
1550
1551 int lmin, lmin_prev = 0;
1552 int rmin, rmin_prev = 0;
1553 int lmax, lmax_prev = 0;
1554 int rmax, rmax_prev = 0;
1555
1556 if (osc.draw == DRAW_PIXEL)
1557 goto plot_start_noprev; /* Doesn't need previous points */
1558
1559 lmax = lmin = waveform_buffer[0];
1560 rmax = rmin = waveform_buffer[1];
1561
1562 /* Find min-max envelope for interval */
1563 for (int i = 2; i < idx; i += 2)
1564 {
1565 int sl = waveform_buffer[i + 0];
1566 int sr = waveform_buffer[i + 1];
1567
1568 if (sl < lmin)
1569 lmin = sl;
1570 if (sl > lmax)
1571 lmax = sl;
1572
1573 if (sr < rmin)
1574 rmin = sr;
1575 if (sr > rmax)
1576 rmax = sr;
1577 }
1578
1579 lmin = (1*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, lmin);
1580 lmax = (1*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, lmax);
1581 rmin = (3*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, rmin);
1582 rmax = (3*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, rmax);
1583
1584 while (1)
1585 {
1586 x_prev = x;
1587 x += x_step;
1588 x_a += x_a_step;
1589
1590 if (x_a >= a_lim)
1591 {
1592 x_a -= a_lim;
1593 x++;
1594 }
1595
1596 if (x >= LCD_WIDTH)
1597 break;
1598
1599 idx_prev = idx;
1600 idx += idx_step;
1601 idx_a += idx_a_step;
1602
1603 if (idx_a > a_lim)
1604 {
1605 idx_a -= a_lim + 1;
1606 idx += 2;
1607 }
1608
1609 lmin_prev = lmin, lmax_prev = lmax;
1610 rmin_prev = rmin, rmax_prev = rmax;
1611
1612 plot_start_noprev:
1613 lmax = lmin = waveform_buffer[idx_prev + 0];
1614 rmax = rmin = waveform_buffer[idx_prev + 1];
1615
1616 /* Find min-max envelope for interval */
1617 for (int i = idx_prev + 2; i < idx; i += 2)
1618 {
1619 int sl = waveform_buffer[i + 0];
1620 int sr = waveform_buffer[i + 1];
1621
1622 if (sl < lmin)
1623 lmin = sl;
1624 if (sl > lmax)
1625 lmax = sl;
1626
1627 if (sr < rmin)
1628 rmin = sr;
1629 if (sr > rmax)
1630 rmax = sr;
1631 }
1632
1633 lmin = (1*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, lmin);
1634 lmax = (1*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, lmax);
1635 rmin = (3*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, rmin);
1636 rmax = (3*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, rmax);
1637
1638 plot[osc.draw](x, x_prev, lmin, lmax, lmin_prev, lmax_prev);
1639 plot[osc.draw](x, x_prev, rmin, rmax, rmin_prev, rmax_prev);
1640 }
1641
1642 waveform_buffer_done();
1643
1644 osd_lcd_update();
1645
1646 long delay = get_next_delay();
1647 return cur_tick + delay - waveform_buffer_have * HZ /
1648 PCM_BYTERATE(mixer_sampr);
1649}
1650
1651static void anim_waveform_plot_filled_v(int y, int y_prev,
1652 int vmin, int vmax,
1653 int vmin_prev, int vmax_prev)
1654{
1655 if (vmin != vmax || vmin_prev != vmax_prev)
1656 {
1657 /* Graph compression */
1658 if (vmax < vmin_prev)
1659 vmax = vmin_prev;
1660 else if (vmin > vmax_prev)
1661 vmin = vmax_prev;
1662
1663 rb->lcd_hline(vmin, vmax, y);
1664 }
1665 else
1666 {
1667 /* 1:1 or stretch */
1668 rb->lcd_drawline(vmin_prev, y_prev, vmin, y);
1669 }
1670}
1671
1672static void anim_waveform_plot_lines_v(int y, int y_prev,
1673 int vmin, int vmax,
1674 int vmin_prev, int vmax_prev)
1675{
1676 rb->lcd_drawline(vmin_prev, y_prev, vmin, y);
1677
1678 if (vmax_prev != vmin_prev || vmax != vmin)
1679 rb->lcd_drawline(vmax_prev, y_prev, vmax, y);
1680}
1681
1682static void anim_waveform_plot_pixel_v(int y, int y_prev,
1683 int vmin, int vmax,
1684 int vmin_prev, int vmax_prev)
1685{
1686 rb->lcd_drawpixel(vmin, y);
1687
1688 if (vmax != vmin)
1689 rb->lcd_drawpixel(vmax, y);
1690
1691 (void)y_prev; (void)vmin_prev; (void)vmax_prev;
1692}
1693
1694static long anim_waveform_vertical(void)
1695{
1696 static void (* const plot[MAX_DRAW])(int, int, int, int, int, int) =
1697 {
1698 [DRAW_FILLED] = anim_waveform_plot_filled_v,
1699 [DRAW_LINE] = anim_waveform_plot_lines_v,
1700 [DRAW_PIXEL] = anim_waveform_plot_pixel_v,
1701 };
1702
1703 long cur_tick = *rb->current_tick;
1704
1705 if (rb->mixer_channel_status(channel) != CHANNEL_PLAYING)
1706 {
1707 osd_lcd_update_prepare();
1708 rb->lcd_vline(1*LCD_WIDTH/4, 0, LCD_HEIGHT-1);
1709 rb->lcd_vline(3*LCD_WIDTH/4, 0, LCD_HEIGHT-1);
1710 osd_lcd_update();
1711 one_frame_paused = false;
1712 return cur_tick + HZ/5;
1713 }
1714
1715 int count = (mixer_sampr*osc_delay + 100*HZ - 1) / (100*HZ);
1716
1717 waveform_buffer_set_threshold(count*PCM_SAMPLESIZE);
1718
1719 if (!waveform_buffer_have_enough())
1720 return cur_tick + HZ/100;
1721
1722 one_frame_paused = false;
1723
1724 osd_lcd_update_prepare();
1725
1726 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1727 rb->lcd_fillrect(0, 0, LCD_WIDTH, LCD_HEIGHT);
1728 rb->lcd_set_drawmode(DRMODE_SOLID);
1729#if LCD_DEPTH > 1
1730 rb->lcd_set_foreground(GRAPH_COLOR);
1731#endif
1732
1733 int y = 0, y_prev = count - 1;
1734 int y_step = (LCD_HEIGHT-1) / y_prev;
1735 int y_a_step = (LCD_HEIGHT-1) - y_step * y_prev;
1736 int y_a = 0;
1737
1738 int idx_step = (count / LCD_HEIGHT) * 2;
1739 int idx_a_step = count - idx_step * (LCD_HEIGHT/2);
1740 int idx = idx_step, idx_prev = 0;
1741 int idx_a = idx_a_step;
1742
1743 int a_lim = MIN(y_prev, LCD_HEIGHT-1);
1744
1745 int lmin, lmin_prev = 0;
1746 int rmin, rmin_prev = 0;
1747 int lmax, lmax_prev = 0;
1748 int rmax, rmax_prev = 0;
1749
1750 if (osc.draw == DRAW_PIXEL)
1751 goto plot_start_noprev; /* Doesn't need previous points */
1752
1753 lmax = lmin = waveform_buffer[0];
1754 rmax = rmin = waveform_buffer[1];
1755
1756 /* Find min-max envelope for interval */
1757 for (int i = 2; i < idx; i += 2)
1758 {
1759 int sl = waveform_buffer[i + 0];
1760 int sr = waveform_buffer[i + 1];
1761
1762 if (sl < lmin)
1763 lmin = sl;
1764 if (sl > lmax)
1765 lmax = sl;
1766
1767 if (sr < rmin)
1768 rmin = sr;
1769 if (sr > rmax)
1770 rmax = sr;
1771 }
1772
1773 lmin = (1*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, lmin);
1774 lmax = (1*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, lmax);
1775 rmin = (3*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, rmin);
1776 rmax = (3*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, rmax);
1777
1778 while (1)
1779 {
1780 y_prev = y;
1781 y += y_step;
1782 y_a += y_a_step;
1783
1784 if (y_a >= a_lim)
1785 {
1786 y_a -= a_lim;
1787 y++;
1788 }
1789
1790 if (y >= LCD_HEIGHT)
1791 break;
1792
1793 idx_prev = idx;
1794 idx += idx_step;
1795 idx_a += idx_a_step;
1796
1797 if (idx_a > a_lim)
1798 {
1799 idx_a -= a_lim + 1;
1800 idx += 2;
1801 }
1802
1803 lmin_prev = lmin, lmax_prev = lmax;
1804 rmin_prev = rmin, rmax_prev = rmax;
1805
1806 plot_start_noprev:
1807 lmax = lmin = waveform_buffer[idx_prev + 0];
1808 rmax = rmin = waveform_buffer[idx_prev + 1];
1809
1810 /* Find min-max envelope for interval */
1811 for (int i = idx_prev + 2; i < idx; i += 2)
1812 {
1813 int sl = waveform_buffer[i + 0];
1814 int sr = waveform_buffer[i + 1];
1815
1816 if (sl < lmin)
1817 lmin = sl;
1818 if (sl > lmax)
1819 lmax = sl;
1820
1821 if (sr < rmin)
1822 rmin = sr;
1823 if (sr > rmax)
1824 rmax = sr;
1825 }
1826
1827 lmin = (1*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, lmin);
1828 lmax = (1*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, lmax);
1829 rmin = (3*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, rmin);
1830 rmax = (3*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, rmax);
1831
1832 plot[osc.draw](y, y_prev, lmin, lmax, lmin_prev, lmax_prev);
1833 plot[osc.draw](y, y_prev, rmin, rmax, rmin_prev, rmax_prev);
1834 }
1835
1836 waveform_buffer_done();
1837
1838 osd_lcd_update();
1839
1840 long delay = get_next_delay();
1841 return cur_tick + delay - waveform_buffer_have * HZ
1842 / PCM_BYTERATE(mixer_sampr);
1843}
1844
1845static void anim_waveform_exit(void)
1846{
1847 /* Remove any buffer hook */
1848 rb->mixer_channel_set_buffer_hook(channel, NULL);
1849#ifdef HAVE_SCHEDULER_BOOSTCTRL
1850 /* Remove our boost */
1851 rb->cancel_cpu_boost();
1852#endif
1853}
1854#endif /* OSCILLOSCOPE_GRAPHMODE */
1855
1856static void graphmode_reset(void)
1857{
1858 static long (* const fns[MAX_GRAPH][MAX_OSC])(void) =
1859 {
1860 [GRAPH_PEAKS] =
1861 {
1862 [OSC_HORIZ] = anim_peaks_horizontal,
1863 [OSC_VERT] = anim_peaks_vertical,
1864 },
1865#ifdef OSCILLOSCOPE_GRAPHMODE
1866 [GRAPH_WAVEFORM] =
1867 {
1868 [OSC_HORIZ] = anim_waveform_horizontal,
1869 [OSC_VERT] = anim_waveform_vertical,
1870 },
1871#endif /* OSCILLOSCOPE_GRAPHMODE */
1872 };
1873
1874 /* For peaks view */
1875 last_left = 0;
1876 last_right = 0;
1877 last_pos = 0;
1878 last_tick = *rb->current_tick;
1879 last_delay = 1;
1880
1881 /* General */
1882 osd_lcd_update_prepare();
1883 rb->lcd_clear_display();
1884 osd_lcd_update();
1885
1886 one_frame_paused = true;
1887 osd_set_timeout(paused ? 4*HZ : HZ);
1888 anim_draw = fns[osc.graphmode][osc.orientation];
1889}
1890
1891static void graphmode_pause_unpause(bool paused)
1892{
1893 if (paused)
1894 return;
1895
1896 last_tick = *rb->current_tick;
1897 osd_set_timeout(HZ);
1898 one_frame_paused = false;
1899#ifdef OSCILLOSCOPE_GRAPHMODE
1900 if (osc.graphmode == GRAPH_WAVEFORM)
1901 waveform_buffer_done();
1902#endif /* OSCILLOSCOPE_GRAPHMODE */
1903}
1904
1905static void update_osc_delay(int value)
1906{
1907 osc_delay = osc_delay_tbl[value - 1];
1908 osc_delay_error = 0;
1909}
1910
1911static void graphmode_setup(void)
1912{
1913#ifdef OSCILLOSCOPE_GRAPHMODE
1914 if (osc.graphmode == GRAPH_WAVEFORM)
1915 {
1916 rb->mixer_channel_set_buffer_hook(channel,
1917 waveform_buffer_callback);
1918#ifdef HAVE_SCHEDULER_BOOSTCTRL
1919 rb->trigger_cpu_boost(); /* Just looks better */
1920#endif
1921 }
1922 else
1923 {
1924 rb->mixer_channel_set_buffer_hook(channel,
1925 NULL);
1926#ifdef HAVE_SCHEDULER_BOOSTCTRL
1927 rb->cancel_cpu_boost();
1928#endif
1929 waveform_buffer_reset();
1930 }
1931#endif /* OSCILLOSCOPE_GRAPHMODE */
1932
1933 update_osc_delay(osc.speed[osc.graphmode]);
1934 graphmode_reset();
1935}
1936
1937static long oscilloscope_draw(void)
1938{
1939 if (message != -1)
1940 {
1941 osc_osd_show_message((enum osc_message_ids)message, msgval);
1942 message = -1;
1943 }
1944 else
1945 {
1946 osd_monitor_timeout();
1947 }
1948
1949 long delay = HZ/5;
1950
1951 if (!paused || one_frame_paused)
1952 {
1953 delay = anim_draw() - *rb->current_tick;
1954
1955 if (delay > HZ/5)
1956 delay = HZ/5;
1957 }
1958
1959 return delay;
1960}
1961
1962static void osc_cleanup(void)
1963{
1964 osd_destroy();
1965
1966#ifdef OSCILLOSCOPE_GRAPHMODE
1967 anim_waveform_exit();
1968#endif
1969
1970#if LCD_DEPTH > 1
1971 rb->lcd_set_foreground(LCD_DEFAULT_FG);
1972 rb->lcd_set_background(LCD_DEFAULT_BG);
1973#endif
1974
1975 /* Turn on backlight timeout (revert to settings) */
1976 backlight_use_settings();
1977
1978 /* save settings if changed */
1979 if (rb->memcmp(&osc, &osc_disk, sizeof(osc)))
1980 {
1981 rb->memcpy(&osc_disk, &osc, sizeof(osc));
1982 configfile_save(cfg_filename, disk_config, ARRAYLEN(disk_config),
1983 CFGFILE_VERSION);
1984 }
1985}
1986
1987static void osc_setup(void)
1988{
1989 atexit(osc_cleanup);
1990 configfile_load(cfg_filename, disk_config, ARRAYLEN(disk_config),
1991 CFGFILE_MINVERSION);
1992 osc = osc_disk; /* copy to running config */
1993
1994 osc_osd_init();
1995
1996#if LCD_DEPTH > 1
1997 osd_lcd_update_prepare();
1998 rb->lcd_set_foreground(GRAPH_COLOR);
1999 rb->lcd_set_background(BACKG_COLOR);
2000 rb->lcd_set_backdrop(NULL);
2001 rb->lcd_clear_display();
2002 osd_lcd_update();
2003#endif
2004
2005 /* Turn off backlight timeout */
2006 backlight_ignore_timeout();
2007
2008 graphmode_setup();
2009}
2010
2011#ifdef USB_ENABLE_AUDIO
2012void switch_channel(enum pcm_mixer_channel new_channel)
2013{
2014 /* Remove any buffer hook */
2015 rb->mixer_channel_set_buffer_hook(channel, NULL);
2016
2017 channel = new_channel;
2018
2019#ifdef OSCILLOSCOPE_GRAPHMODE
2020 if (osc.graphmode == GRAPH_WAVEFORM)
2021 rb->mixer_channel_set_buffer_hook(channel, waveform_buffer_callback);
2022#endif
2023}
2024#endif /* USB_ENABLE_AUDIO */
2025
2026enum plugin_status plugin_start(const void* parameter)
2027{
2028 bool exit = false;
2029#ifdef NEED_LASTBUTTON
2030 int lastbutton = BUTTON_NONE;
2031#endif
2032
2033 channel = PCM_MIXER_CHAN_PLAYBACK;
2034
2035 osc_setup();
2036
2037 while (!exit)
2038 {
2039#ifdef OSCILLOSCOPE_GRAPHMODE
2040 if (osc.graphmode == GRAPH_WAVEFORM)
2041 mixer_sampr = rb->mixer_get_frequency();
2042#endif
2043#ifdef USB_ENABLE_AUDIO
2044 if (rb->usb_audio_get_playing())
2045 {
2046 if (channel != PCM_MIXER_CHAN_USBAUDIO)
2047 switch_channel(PCM_MIXER_CHAN_USBAUDIO);
2048 }
2049 else
2050 {
2051 if (channel != PCM_MIXER_CHAN_PLAYBACK)
2052 switch_channel(PCM_MIXER_CHAN_PLAYBACK);
2053 }
2054#endif /* USB_ENABLE_AUDIO */
2055
2056 long delay = oscilloscope_draw();
2057
2058 if (delay <= 0)
2059 {
2060 delay = 0;
2061 rb->yield(); /* tmo = 0 won't yield */
2062 }
2063
2064 int button = rb->button_get_w_tmo(delay);
2065
2066 switch (button)
2067 {
2068#ifdef OSCILLOSCOPE_RC_QUIT
2069 case OSCILLOSCOPE_RC_QUIT:
2070#endif
2071 case OSCILLOSCOPE_QUIT:
2072 exit = true;
2073 break;
2074
2075 case OSCILLOSCOPE_ADVMODE:
2076#ifdef OSCILLOSCOPE_GRAPHMODE
2077 if (osc.graphmode == GRAPH_WAVEFORM)
2078 break; /* Not applicable */
2079#endif
2080 if (++osc.advance >= MAX_ADV)
2081 osc.advance = 0;
2082
2083 osc_popupmsg(OSC_MSG_ADVMODE, osc.advance);
2084 break;
2085
2086 case OSCILLOSCOPE_DRAWMODE:
2087#ifdef OSCILLOSCOPE_DRAWMODE_PRE
2088 if (lastbutton != OSCILLOSCOPE_DRAWMODE_PRE)
2089 break;
2090#endif
2091 if (++osc.draw >= MAX_DRAW)
2092 osc.draw = 0;
2093
2094 osc_popupmsg(OSC_MSG_DRAWMODE, osc.draw);
2095 break;
2096
2097 /* Need all keymaps for this (remove extra condition when
2098 completed) */
2099#ifdef OSCILLOSCOPE_GRAPHMODE
2100 case OSCILLOSCOPE_GRAPHMODE:
2101#ifdef OSCILLOSCOPE_GRAPHMODE_PRE
2102 if (lastbutton != OSCILLOSCOPE_GRAPHMODE_PRE)
2103 break;
2104#endif
2105 if (++osc.graphmode >= MAX_GRAPH)
2106 osc.graphmode = 0;
2107
2108 graphmode_setup();
2109
2110 osc_popupmsg(OSC_MSG_GRAPHMODE, osc.graphmode);
2111 break;
2112#endif /* OSCILLOSCOPE_GRAPHMODE */
2113
2114 case OSCILLOSCOPE_ORIENTATION:
2115#ifdef OSCILLOSCOPE_ORIENTATION_PRE
2116 if (lastbutton != OSCILLOSCOPE_ORIENTATION_PRE)
2117 break;
2118#endif
2119 if (++osc.orientation >= MAX_OSC)
2120 osc.orientation = 0;
2121
2122 graphmode_reset();
2123 osc_popupmsg(OSC_MSG_ORIENTATION, osc.orientation);
2124 break;
2125
2126 case OSCILLOSCOPE_PAUSE:
2127#ifdef OSCILLOSCOPE_PAUSE_PRE
2128 if (lastbutton != OSCILLOSCOPE_PAUSE_PRE)
2129 break;
2130#endif
2131 paused = !paused;
2132 graphmode_pause_unpause(paused);
2133 osc_popupmsg(OSC_MSG_PAUSED, paused ? 1 : 0);
2134 break;
2135
2136 case OSCILLOSCOPE_SPEED_UP:
2137 case OSCILLOSCOPE_SPEED_UP | BUTTON_REPEAT:
2138 {
2139 int *val = &osc.speed[osc.graphmode];
2140
2141 if (*val < MAX_SPEED)
2142 ++*val;
2143
2144 update_osc_delay(*val);
2145 osc_popupmsg(OSC_MSG_SPEED, *val);
2146 break;
2147 }
2148
2149 case OSCILLOSCOPE_SPEED_DOWN:
2150 case OSCILLOSCOPE_SPEED_DOWN | BUTTON_REPEAT:
2151 {
2152 int *val = &osc.speed[osc.graphmode];
2153
2154 if (*val > MIN_SPEED)
2155 --*val;
2156
2157 update_osc_delay(*val);
2158 osc_popupmsg(OSC_MSG_SPEED, *val);
2159 break;
2160 }
2161
2162 case OSCILLOSCOPE_VOL_UP:
2163 case OSCILLOSCOPE_VOL_UP | BUTTON_REPEAT:
2164 {
2165 int vol = rb->global_status->volume;
2166
2167 if (vol < rb->sound_max(SOUND_VOLUME))
2168 {
2169 vol++;
2170 rb->sound_set(SOUND_VOLUME, vol);
2171 }
2172
2173 osc_popupmsg(OSC_MSG_VOLUME, vol);
2174 break;
2175 }
2176
2177 case OSCILLOSCOPE_VOL_DOWN:
2178 case OSCILLOSCOPE_VOL_DOWN | BUTTON_REPEAT:
2179 {
2180 int vol = rb->global_status->volume;
2181
2182 if (vol > rb->sound_min(SOUND_VOLUME))
2183 {
2184 vol--;
2185 rb->sound_set(SOUND_VOLUME, vol);
2186 }
2187
2188 osc_popupmsg(OSC_MSG_VOLUME, vol);
2189 break;
2190 }
2191
2192 default:
2193 exit_on_usb(button);
2194 break;
2195 }
2196
2197#ifdef NEED_LASTBUTTON
2198 if (button != BUTTON_NONE)
2199 lastbutton = button;
2200#endif
2201 } /* while */
2202
2203 return PLUGIN_OK;
2204 (void)parameter;
2205}