A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 738 lines 27 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) Robert E. Hak (2002), Linus Nielsen Feltzing (2002) 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21#include <stdio.h> 22#include "config.h" 23#include "font.h" 24#include "kernel.h" 25#include "string.h" /* for memcmp oO*/ 26#include "string-extra.h" /* for itoa */ 27#include "sound.h" 28#include "settings.h" 29#include "viewport.h" 30#include "metadata.h" 31#include "icons.h" 32#include "powermgmt.h" 33#include "usb.h" 34#include "led.h" 35#include "screen_access.h" 36 37#include "status.h" /* needed for battery_state global var */ 38#include "action.h" /* for keys_locked */ 39#include "statusbar.h" 40#ifdef HAVE_RECORDING 41#include "audio.h" 42#include "recording.h" 43#include "pcm_record.h" 44#endif 45#include "appevents.h" 46#include "timefuncs.h" 47 48/* FIXME: should be removed from icon.h to avoid redefinition, 49 but still needed for compatibility with old system */ 50#define ICONS_SPACING 2 51#define STATUSBAR_BATTERY_X_POS 0*ICONS_SPACING 52#define STATUSBAR_BATTERY_WIDTH (2+(2*SYSFONT_WIDTH)) 53#define STATUSBAR_PLUG_X_POS STATUSBAR_X_POS + \ 54 STATUSBAR_BATTERY_WIDTH + \ 55 ICONS_SPACING 56#define STATUSBAR_BATTERY_HEIGHT SB_ICON_HEIGHT - 1 57#define STATUSBAR_PLUG_WIDTH 7 58#define STATUSBAR_VOLUME_X_POS STATUSBAR_X_POS + \ 59 STATUSBAR_BATTERY_WIDTH + \ 60 STATUSBAR_PLUG_WIDTH + \ 61 2*ICONS_SPACING 62#define STATUSBAR_VOLUME_WIDTH (2+(2*SYSFONT_WIDTH)) 63#define STATUSBAR_ENCODER_X_POS STATUSBAR_X_POS + \ 64 STATUSBAR_BATTERY_WIDTH + \ 65 STATUSBAR_PLUG_WIDTH + \ 66 2*ICONS_SPACING - 1 67#define STATUSBAR_ENCODER_WIDTH 18 68#define STATUSBAR_PLAY_STATE_X_POS STATUSBAR_X_POS + \ 69 STATUSBAR_BATTERY_WIDTH + \ 70 STATUSBAR_PLUG_WIDTH + \ 71 STATUSBAR_VOLUME_WIDTH + \ 72 3*ICONS_SPACING 73#define STATUSBAR_PLAY_STATE_WIDTH 7 74#define STATUSBAR_PLAY_MODE_X_POS STATUSBAR_X_POS + \ 75 STATUSBAR_BATTERY_WIDTH + \ 76 STATUSBAR_PLUG_WIDTH + \ 77 STATUSBAR_VOLUME_WIDTH + \ 78 STATUSBAR_PLAY_STATE_WIDTH + \ 79 4*ICONS_SPACING 80#define STATUSBAR_PLAY_MODE_WIDTH 7 81#define STATUSBAR_RECFREQ_X_POS STATUSBAR_X_POS + \ 82 STATUSBAR_BATTERY_WIDTH + \ 83 STATUSBAR_PLUG_WIDTH + \ 84 STATUSBAR_VOLUME_WIDTH + \ 85 STATUSBAR_PLAY_STATE_WIDTH + \ 86 3*ICONS_SPACING 87#define STATUSBAR_RECFREQ_WIDTH 12 88#define STATUSBAR_RECCHANNELS_X_POS STATUSBAR_X_POS + \ 89 STATUSBAR_BATTERY_WIDTH + \ 90 STATUSBAR_PLUG_WIDTH + \ 91 STATUSBAR_VOLUME_WIDTH + \ 92 STATUSBAR_PLAY_STATE_WIDTH + \ 93 STATUSBAR_RECFREQ_WIDTH + \ 94 4*ICONS_SPACING 95#define STATUSBAR_RECCHANNELS_WIDTH 5 96#define STATUSBAR_SHUFFLE_X_POS STATUSBAR_X_POS + \ 97 STATUSBAR_BATTERY_WIDTH + \ 98 STATUSBAR_PLUG_WIDTH + \ 99 STATUSBAR_VOLUME_WIDTH + \ 100 STATUSBAR_PLAY_STATE_WIDTH + \ 101 STATUSBAR_PLAY_MODE_WIDTH + \ 102 5*ICONS_SPACING 103#define STATUSBAR_SHUFFLE_WIDTH 7 104#define STATUSBAR_LOCKM_X_POS STATUSBAR_X_POS + \ 105 STATUSBAR_BATTERY_WIDTH + \ 106 STATUSBAR_PLUG_WIDTH + \ 107 STATUSBAR_VOLUME_WIDTH + \ 108 STATUSBAR_PLAY_STATE_WIDTH + \ 109 STATUSBAR_PLAY_MODE_WIDTH + \ 110 STATUSBAR_SHUFFLE_WIDTH + \ 111 6*ICONS_SPACING 112#define STATUSBAR_LOCKM_WIDTH 5 113#define STATUSBAR_LOCKR_X_POS STATUSBAR_X_POS + \ 114 STATUSBAR_BATTERY_WIDTH + \ 115 STATUSBAR_PLUG_WIDTH + \ 116 STATUSBAR_VOLUME_WIDTH + \ 117 STATUSBAR_PLAY_STATE_WIDTH + \ 118 STATUSBAR_PLAY_MODE_WIDTH + \ 119 STATUSBAR_SHUFFLE_WIDTH + \ 120 STATUSBAR_LOCKM_WIDTH + \ 121 7*ICONS_SPACING 122#define STATUSBAR_LOCKR_WIDTH 5 123 124#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD) 125#define STATUSBAR_DISK_WIDTH 12 126#define STATUSBAR_DISK_X_POS(statusbar_width) statusbar_width - \ 127 STATUSBAR_DISK_WIDTH 128#else 129#define STATUSBAR_DISK_WIDTH 0 130#endif 131#define STATUSBAR_TIME_X_END(statusbar_width) statusbar_width - 1 - \ 132 STATUSBAR_DISK_WIDTH 133struct gui_syncstatusbar statusbars; 134 135/* Prototypes */ 136static void gui_statusbar_icon_battery(struct screen * display, int percent, 137 int batt_charge_step); 138static bool gui_statusbar_icon_volume(struct gui_statusbar * bar, int volume); 139static void gui_statusbar_icon_play_state(struct screen * display, int state); 140static void gui_statusbar_icon_play_mode(struct screen * display, int mode); 141static void gui_statusbar_icon_shuffle(struct screen * display); 142static void gui_statusbar_icon_lock(struct screen * display); 143#ifdef HAS_REMOTE_BUTTON_HOLD 144static void gui_statusbar_icon_lock_remote(struct screen * display); 145#endif 146#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD) 147static void gui_statusbar_led(struct screen * display); 148#endif 149#ifdef HAVE_RECORDING 150static void gui_statusbar_icon_recording_info(struct screen * display); 151#endif 152#if CONFIG_RTC 153static void gui_statusbar_time(struct screen * display, struct tm *time); 154#endif 155 156/* End prototypes */ 157 158 159/* 160 * Initializes a status bar 161 * - bar : the bar to initialize 162 */ 163static void gui_statusbar_init(struct screen * display, struct gui_statusbar * bar) 164{ 165 bar->display = display; 166 bar->redraw_volume = true; 167 bar->volume_icon_switch_tick = bar->battery_icon_switch_tick = current_tick; 168 memset((void*)&(bar->lastinfo), 0, sizeof(struct status_info)); 169#if CONFIG_RTC 170 bar->last_tm_min = 0; 171#endif 172} 173 174static struct screen * sb_fill_bar_info(struct gui_statusbar * bar) 175{ 176 struct screen *display = bar->display; 177 178 if (!display) 179 return display; 180 181 bar->info.battlevel = battery_level(); 182#ifdef HAVE_USB_POWER 183 bar->info.usb_inserted = usb_inserted(); 184#endif 185#if CONFIG_CHARGING 186 bar->info.inserted = (charger_input_state == CHARGER); 187 if (bar->info.inserted) 188 { 189 bar->info.battery_state = true; 190 191#if CONFIG_CHARGING >= CHARGING_MONITOR 192 193 /* zero battery run time if charging */ 194 if (charge_state > DISCHARGING) 195 zero_runtime(); 196 197 /* animate battery if charging */ 198 if ((charge_state == DISCHARGING) || (charge_state == TRICKLE)) 199 { 200 bar->info.batt_charge_step = -1; 201 } 202 else 203 { 204#else /* CONFIG_CHARGING < CHARGING_MONITOR */ 205 zero_runtime(); 206 { 207#endif /* CONFIG_CHARGING < CHARGING_MONITOR */ 208 /* animate in (max.) 4 steps, starting near the current charge level */ 209 if (TIME_AFTER(current_tick, bar->battery_icon_switch_tick)) 210 { 211 if (++bar->info.batt_charge_step > 3) 212 bar->info.batt_charge_step = bar->info.battlevel / 34; 213 bar->battery_icon_switch_tick = current_tick + HZ; 214 } 215 } 216 } 217 else 218#endif /* CONFIG_CHARGING */ 219 { 220 bar->info.batt_charge_step = -1; 221 if (battery_level_safe()) 222 bar->info.battery_state = true; 223 else 224 /* blink battery if level is low */ 225 if (TIME_AFTER(current_tick, bar->battery_icon_switch_tick) && 226 (bar->info.battlevel > -1)) 227 { 228 bar->info.battery_state = !bar->info.battery_state; 229 bar->battery_icon_switch_tick = current_tick + HZ; 230 } 231 } 232 bar->info.volume = global_status.volume; 233 bar->info.shuffle = global_settings.playlist_shuffle; 234#ifdef HAS_BUTTON_HOLD 235 bar->info.keylock = button_hold(); 236#else 237 bar->info.keylock = is_keys_locked(); 238#endif /* HAS_BUTTON_HOLD */ 239#ifdef HAS_REMOTE_BUTTON_HOLD 240 bar->info.keylockremote = remote_button_hold(); 241#endif 242 bar->info.repeat = global_settings.repeat_mode; 243 bar->info.playmode = current_playmode(); 244#if CONFIG_RTC 245 bar->time = get_time(); 246#endif /* CONFIG_RTC */ 247#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD) 248 if(!display->has_disk_led) 249 bar->info.led = led_read(HZ/2); /* delay should match polling interval */ 250#endif 251 252 return display; 253} 254 255void gui_statusbar_draw(struct gui_statusbar * bar, bool force_redraw, struct viewport *vp) 256{ 257 struct viewport *last_vp = NULL; 258 struct screen * display = sb_fill_bar_info(bar); 259 if (!display) 260 return; 261 262 /* only redraw if forced to, or info has changed */ 263 if (force_redraw || bar->redraw_volume || 264#if CONFIG_RTC 265 (bar->time->tm_min != bar->last_tm_min) || 266#endif 267 memcmp(&(bar->info), &(bar->lastinfo), sizeof(struct status_info))) 268 { 269 last_vp = display->set_viewport(vp); 270 display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); 271 display->fill_viewport(); 272 display->set_drawmode(DRMODE_SOLID); 273 display->setfont(FONT_SYSFIXED); 274 275 if (bar->info.battery_state) 276 gui_statusbar_icon_battery(display, bar->info.battlevel, 277 bar->info.batt_charge_step); 278#ifdef HAVE_USB_POWER 279 if (bar->info.usb_inserted) 280 display->mono_bitmap(bitmap_icons_7x8[Icon_USBPlug], 281 STATUSBAR_PLUG_X_POS, 282 STATUSBAR_Y_POS, STATUSBAR_PLUG_WIDTH, 283 SB_ICON_HEIGHT); 284#endif /* HAVE_USB_POWER */ 285#if CONFIG_CHARGING 286#ifdef HAVE_USB_POWER 287 else 288#endif 289 /* draw power plug if charging */ 290 if (bar->info.inserted) 291 display->mono_bitmap(bitmap_icons_7x8[Icon_Plug], 292 STATUSBAR_PLUG_X_POS, 293 STATUSBAR_Y_POS, STATUSBAR_PLUG_WIDTH, 294 SB_ICON_HEIGHT); 295#endif /* CONFIG_CHARGING */ 296#ifdef HAVE_RECORDING 297 /* turn off volume display in recording screen */ 298 bool recscreen_on = in_recording_screen(); 299 if (!recscreen_on) 300#endif 301 bar->redraw_volume = gui_statusbar_icon_volume(bar, bar->info.volume); 302 gui_statusbar_icon_play_state(display, current_playmode() + Icon_Play); 303 304#ifdef HAVE_RECORDING 305 /* If in recording screen, replace repeat mode, volume 306 and shuffle icons with recording info */ 307 if (recscreen_on) 308 gui_statusbar_icon_recording_info(display); 309 else 310#endif 311 { 312 gui_statusbar_icon_play_mode(display, bar->info.repeat); 313 314 if (bar->info.shuffle) 315 gui_statusbar_icon_shuffle(display); 316 } 317 if (bar->info.keylock) 318 gui_statusbar_icon_lock(display); 319#ifdef HAS_REMOTE_BUTTON_HOLD 320 if (bar->info.keylockremote) 321 gui_statusbar_icon_lock_remote(display); 322#endif 323#if CONFIG_RTC 324 gui_statusbar_time(display, bar->time); 325 bar->last_tm_min = bar->time->tm_min; 326#endif /* CONFIG_RTC */ 327#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD) 328 if(!display->has_disk_led && bar->info.led) 329 { 330 gui_statusbar_led(display); 331 } 332#endif 333 display->setfont(FONT_UI); 334 display->update_viewport(); 335 display->set_viewport(last_vp); 336 bar->lastinfo = bar->info; 337 } 338} 339 340/* from icon.c */ 341/* 342 * Print battery icon to status bar 343 */ 344static void gui_statusbar_icon_battery(struct screen * display, int percent, 345 int batt_charge_step) 346{ 347 int fill, endfill; 348 char buffer[5]; 349 unsigned int width, height; 350#if LCD_DEPTH > 1 351 unsigned int prevfg = 0; 352#endif 353 354#if CONFIG_CHARGING 355 if (batt_charge_step >= 0) 356 { 357 fill = percent * (STATUSBAR_BATTERY_WIDTH-3) / 100; 358 endfill = 34 * batt_charge_step * (STATUSBAR_BATTERY_WIDTH-3) / 100; 359 } 360 else 361#else 362 (void)batt_charge_step; 363#endif 364 { 365 fill = endfill = (percent * (STATUSBAR_BATTERY_WIDTH-3) + 50) / 100; 366 } 367 368#if CONFIG_CHARGING == CHARGING_MONITOR && !defined(SIMULATOR) 369 /* Certain charge controlled targets */ 370 /* show graphical animation when charging instead of numbers */ 371 if ((global_settings.battery_display) && 372 (charge_state != CHARGING) && 373 (percent > -1) && 374 (percent <= 100)) { 375#else /* all others */ 376 if (global_settings.battery_display && (percent > -1) && (percent <= 100)) { 377#endif 378 /* Numeric display */ 379 snprintf(buffer, sizeof(buffer), "%3d", percent); 380 font_getstringsize(buffer, &width, &height, FONT_SYSFIXED); 381 if (height <= STATUSBAR_HEIGHT) { 382 display->putsxy(STATUSBAR_BATTERY_X_POS 383 + STATUSBAR_BATTERY_WIDTH / 2 384 - width/2, STATUSBAR_Y_POS, buffer); 385 } 386 387 } 388 else { 389 /* draw battery */ 390 display->drawrect(STATUSBAR_BATTERY_X_POS, STATUSBAR_Y_POS, 391 STATUSBAR_BATTERY_WIDTH - 1, STATUSBAR_BATTERY_HEIGHT); 392 display->vline(STATUSBAR_BATTERY_X_POS + STATUSBAR_BATTERY_WIDTH - 1, 393 STATUSBAR_Y_POS + 2, STATUSBAR_Y_POS + 4); 394 395 display->fillrect(STATUSBAR_BATTERY_X_POS + 1, STATUSBAR_Y_POS + 1, 396 fill, STATUSBAR_BATTERY_HEIGHT - 2); 397#if LCD_DEPTH > 1 398 if (display->depth > 1) 399 { 400 prevfg = display->get_foreground(); 401 display->set_foreground(LCD_DARKGRAY); 402 } 403#endif 404 display->fillrect(STATUSBAR_BATTERY_X_POS + 1 + fill, STATUSBAR_Y_POS + 1, 405 endfill - fill, STATUSBAR_BATTERY_HEIGHT - 2); 406#if LCD_DEPTH > 1 407 if (display->depth > 1) 408 display->set_foreground(prevfg); 409#endif 410 } 411 412 if (percent == -1 || percent > 100) { 413 display->putsxy(STATUSBAR_BATTERY_X_POS + STATUSBAR_BATTERY_WIDTH / 2 414 - 4, STATUSBAR_Y_POS, "?"); 415 } 416} 417 418/* 419 * Print volume gauge to status bar 420 */ 421static bool gui_statusbar_icon_volume(struct gui_statusbar * bar, int volume) 422{ 423 int i; 424 int vol; 425 char buffer[4]; 426 unsigned int width, height; 427 bool needs_redraw = false; 428 int type = global_settings.volume_type; 429 struct screen * display=bar->display; 430 const int minvol = sound_min(SOUND_VOLUME); 431 432 if (volume < minvol) 433 volume = minvol; 434 435 if (volume == minvol) { 436 display->mono_bitmap(bitmap_icons_7x8[Icon_Mute], 437 STATUSBAR_VOLUME_X_POS + STATUSBAR_VOLUME_WIDTH / 2 - 4, 438 STATUSBAR_Y_POS, 7, SB_ICON_HEIGHT); 439 } 440 else { 441 const int maxvol = sound_max(SOUND_VOLUME); 442 443 if (volume > maxvol) 444 volume = maxvol; 445 /* We want to redraw the icon later on */ 446 if (bar->last_volume != volume && bar->last_volume >= minvol) { 447 bar->volume_icon_switch_tick = current_tick + HZ; 448 } 449 450 /* If the timeout hasn't yet been reached, we show it numerically 451 and tell the caller that we want to be called again */ 452 if (TIME_BEFORE(current_tick,bar->volume_icon_switch_tick)) { 453 type = 1; 454 needs_redraw = true; 455 } 456 457 /* display volume level numerical? */ 458 if (type) 459 { 460 const int num_decimals = sound_numdecimals(SOUND_VOLUME); 461 if (num_decimals) 462 volume /= 10 * num_decimals; 463 464 snprintf(buffer, sizeof(buffer), "%2d", volume); 465 font_getstringsize(buffer, &width, &height, FONT_SYSFIXED); 466 if (height <= STATUSBAR_HEIGHT) { 467 display->putsxy(STATUSBAR_VOLUME_X_POS 468 + STATUSBAR_VOLUME_WIDTH / 2 469 - width/2, STATUSBAR_Y_POS, buffer); 470 } 471 } else { 472 /* display volume bar */ 473 vol = (volume - minvol) * 14 / (maxvol - minvol); 474 for(i=0; i < vol; i++) { 475 display->vline(STATUSBAR_VOLUME_X_POS + i, 476 STATUSBAR_Y_POS + 6 - i / 2, 477 STATUSBAR_Y_POS + 6); 478 } 479 } 480 } 481 bar->last_volume = volume; 482 483 return needs_redraw; 484} 485 486/* 487 * Print play state to status bar 488 */ 489static void gui_statusbar_icon_play_state(struct screen * display, int state) 490{ 491 display->mono_bitmap(bitmap_icons_7x8[state], STATUSBAR_PLAY_STATE_X_POS, 492 STATUSBAR_Y_POS, STATUSBAR_PLAY_STATE_WIDTH, 493 SB_ICON_HEIGHT); 494} 495 496/* 497 * Print play mode to status bar 498 */ 499static void gui_statusbar_icon_play_mode(struct screen * display, int mode) 500{ 501 switch (mode) { 502#ifdef AB_REPEAT_ENABLE 503 case REPEAT_AB: 504 display->mono_bitmap(bitmap_icons_7x8[Icon_RepeatAB], 505 STATUSBAR_PLAY_MODE_X_POS, 506 STATUSBAR_Y_POS, STATUSBAR_PLAY_MODE_WIDTH, 507 SB_ICON_HEIGHT); 508 break; 509#endif /* AB_REPEAT_ENABLE */ 510 511 case REPEAT_ONE: 512 display->mono_bitmap(bitmap_icons_7x8[Icon_RepeatOne], 513 STATUSBAR_PLAY_MODE_X_POS, 514 STATUSBAR_Y_POS, STATUSBAR_PLAY_MODE_WIDTH, 515 SB_ICON_HEIGHT); 516 break; 517 518 case REPEAT_ALL: 519 case REPEAT_SHUFFLE: 520 display->mono_bitmap(bitmap_icons_7x8[Icon_Repeat], 521 STATUSBAR_PLAY_MODE_X_POS, 522 STATUSBAR_Y_POS, STATUSBAR_PLAY_MODE_WIDTH, 523 SB_ICON_HEIGHT); 524 break; 525 } 526} 527/* 528 * Print shuffle mode to status bar 529 */ 530static void gui_statusbar_icon_shuffle(struct screen * display) 531{ 532 display->mono_bitmap(bitmap_icons_7x8[Icon_Shuffle], 533 STATUSBAR_SHUFFLE_X_POS, STATUSBAR_Y_POS, 534 STATUSBAR_SHUFFLE_WIDTH, SB_ICON_HEIGHT); 535} 536 537/* 538 * Print lock when keys are locked 539 */ 540static void gui_statusbar_icon_lock(struct screen * display) 541{ 542 display->mono_bitmap(bitmap_icons_5x8[Icon_Lock_Main], 543 STATUSBAR_LOCKM_X_POS, STATUSBAR_Y_POS, 544 STATUSBAR_LOCKM_WIDTH, SB_ICON_HEIGHT); 545} 546 547#ifdef HAS_REMOTE_BUTTON_HOLD 548/* 549 * Print remote lock when remote hold is enabled 550 */ 551static void gui_statusbar_icon_lock_remote(struct screen * display) 552{ 553 display->mono_bitmap(bitmap_icons_5x8[Icon_Lock_Remote], 554 STATUSBAR_LOCKR_X_POS, STATUSBAR_Y_POS, 555 STATUSBAR_LOCKR_WIDTH, SB_ICON_HEIGHT); 556} 557#endif 558 559#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD) 560/* 561 * no real LED: disk activity in status bar 562 */ 563static void gui_statusbar_led(struct screen * display) 564{ 565 display->mono_bitmap(bitmap_icon_disk, 566 STATUSBAR_DISK_X_POS(display->getwidth()), 567 STATUSBAR_Y_POS, STATUSBAR_DISK_WIDTH, 568 SB_ICON_HEIGHT); 569} 570#endif 571 572#if CONFIG_RTC 573/* 574 * Print time to status bar 575 */ 576static void gui_statusbar_time(struct screen * display, struct tm *time) 577{ 578 unsigned char buffer[6]; 579 const unsigned char *p = buffer; 580 unsigned int width, height; 581 int hour, minute; 582 if ( valid_time(time) ) { 583 hour = time->tm_hour; 584 minute = time->tm_min; 585 if ( global_settings.timeformat ) { /* 12 hour clock */ 586 hour %= 12; 587 if ( hour == 0 ) { 588 hour += 12; 589 } 590 } 591 snprintf(buffer, sizeof(buffer), "%02d:%02d", hour, minute); 592 } 593 else { 594 p = "--:--"; 595 } 596 597 font_getstringsize(p, &width, &height, FONT_SYSFIXED); 598 if (height <= STATUSBAR_HEIGHT) { 599 display->putsxy(STATUSBAR_TIME_X_END(display->getwidth()) - width, 600 STATUSBAR_Y_POS, p); 601 } 602 603} 604#endif 605 606#ifdef HAVE_RECORDING 607/** 608 * Write a number to the display using bitmaps and return new position 609 */ 610static int write_bitmap_number(struct screen * display, int value, 611 int x, int y) 612{ 613 char buf[12], *ptr; 614 itoa_buf(buf, sizeof(buf), value); 615 616 for (ptr = buf; *ptr != '\0'; ptr++, x += BM_GLYPH_WIDTH) 617 display->mono_bitmap(bitmap_glyphs_4x8[*ptr - '0'], x, y, 618 BM_GLYPH_WIDTH, SB_ICON_HEIGHT); 619 return x; 620} 621 622/** 623 * Write format info bitmaps - right justified 624 */ 625static void gui_statusbar_write_format_info(struct screen * display) 626{ 627 /* Can't fit info for sw codec targets in statusbar using FONT_SYSFIXED 628 so must use icons */ 629 int rec_format = global_settings.rec_format; 630 unsigned bitrk = 0; /* compiler warns about unitialized use !! */ 631 int xpos = STATUSBAR_ENCODER_X_POS; 632 int width = STATUSBAR_ENCODER_WIDTH; 633 const unsigned char *bm = bitmap_formats_18x8[rec_format]; 634 635 if (rec_format == REC_FORMAT_MPA_L3) 636 { 637 /* Special handling for mp3 */ 638 bitrk = global_settings.mp3_enc_config.bitrate; 639 bitrk = mp3_enc_bitr[bitrk]; 640 641 width = BM_MPA_L3_M_WIDTH; 642 643 /* Slide 'M' to right if fewer than three digits used */ 644 if (bitrk > 999) 645 bitrk = 999; /* neurotic safety check if corrupted */ 646 else 647 { 648 if (bitrk < 100) 649 xpos += BM_GLYPH_WIDTH; 650 if (bitrk < 10) 651 xpos += BM_GLYPH_WIDTH; 652 } 653 } 654 655 /* Show bitmap - clipping right edge if needed */ 656 display->mono_bitmap_part(bm, 0, 0, STATUSBAR_ENCODER_WIDTH, 657 xpos, STATUSBAR_Y_POS, width, SB_ICON_HEIGHT); 658 659 if (rec_format == REC_FORMAT_MPA_L3) 660 { 661 xpos += BM_MPA_L3_M_WIDTH; /* to right of 'M' */ 662 write_bitmap_number(display, bitrk, xpos, STATUSBAR_Y_POS); 663 } 664} 665 666/** 667 * Write sample rate using bitmaps - left justified 668 */ 669static void gui_statusbar_write_samplerate_info(struct screen * display) 670{ 671 unsigned long samprk; 672 int xpos; 673 674#ifdef SIMULATOR 675 samprk = 44100; 676#else 677#ifdef HAVE_SPDIF_REC 678 if (global_settings.rec_source == AUDIO_SRC_SPDIF) 679 /* Use rate in use, not current measured rate if it changed */ 680 samprk = pcm_rec_sample_rate(); 681 else 682#endif 683 samprk = rec_freq_sampr[global_settings.rec_frequency]; 684#endif /* SIMULATOR */ 685 686 samprk /= 1000; 687 if (samprk > 99) 688 samprk = 99; /* Limit to 3 glyphs */ 689 690 xpos = write_bitmap_number(display, (unsigned)samprk, 691 STATUSBAR_RECFREQ_X_POS, STATUSBAR_Y_POS); 692 693 /* write the 'k' */ 694 display->mono_bitmap(bitmap_glyphs_4x8[Glyph_4x8_k], xpos, 695 STATUSBAR_Y_POS, BM_GLYPH_WIDTH, 696 SB_ICON_HEIGHT); 697} 698 699static void gui_statusbar_icon_recording_info(struct screen * display) 700{ 701 /* Display Codec info in statusbar */ 702 gui_statusbar_write_format_info(display); 703 704 /* Display Samplerate info in statusbar */ 705 gui_statusbar_write_samplerate_info(display); 706 707 /* Display Channel status in status bar */ 708 if(global_settings.rec_channels) 709 { 710 display->mono_bitmap(bitmap_icons_5x8[Icon_Mono], 711 STATUSBAR_RECCHANNELS_X_POS , STATUSBAR_Y_POS, 712 STATUSBAR_RECCHANNELS_WIDTH, SB_ICON_HEIGHT); 713 } 714 else 715 { 716 display->mono_bitmap(bitmap_icons_5x8[Icon_Stereo], 717 STATUSBAR_RECCHANNELS_X_POS, STATUSBAR_Y_POS, 718 STATUSBAR_RECCHANNELS_WIDTH, SB_ICON_HEIGHT); 719 } 720} 721#endif /* HAVE_RECORDING */ 722 723void gui_syncstatusbar_init(struct gui_syncstatusbar * bars) 724{ 725 FOR_NB_SCREENS(i) { 726 gui_statusbar_init(&(screens[i]), &(bars->statusbars[i])); 727 } 728} 729 730 731#ifdef HAVE_REMOTE_LCD 732enum statusbar_values statusbar_position(int screen) 733{ 734 if (screen == SCREEN_REMOTE) 735 return global_settings.remote_statusbar; 736 return global_settings.statusbar; 737} 738#endif