A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 2205 lines 71 kB view raw
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}