Blame src/cdda-player.c

Packit dd8086
/*
Packit dd8086
  Copyright (C) 2005, 2006, 2008, 2009, 2010, 2011, 2012, 2017
Packit dd8086
  Rocky Bernstein <rocky@gnu.org>
Packit dd8086
Packit dd8086
  Adapted from Gerd Knorr's player.c program  <kraxel@bytesex.org>
Packit dd8086
  Copyright (C) 1997, 1998
Packit dd8086
Packit dd8086
  This program is free software: you can redistribute it and/or modify
Packit dd8086
  it under the terms of the GNU General Public License as published by
Packit dd8086
  the Free Software Foundation, either version 3 of the License, or
Packit dd8086
  (at your option) any later version.
Packit dd8086
Packit dd8086
  This program is distributed in the hope that it will be useful,
Packit dd8086
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit dd8086
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit dd8086
  GNU General Public License for more details.
Packit dd8086
Packit dd8086
  You should have received a copy of the GNU General Public License
Packit dd8086
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit dd8086
*/
Packit dd8086
Packit dd8086
#ifdef HAVE_CONFIG_H
Packit dd8086
# include "config.h"
Packit dd8086
# define __CDIO_CONFIG_H__ 1
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_STDIO_H
Packit dd8086
#include <stdio.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_STDLIB_H
Packit dd8086
#include <stdlib.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_UNISTD_H
Packit dd8086
#include <unistd.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_STRING_H
Packit dd8086
#include <string.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_SYS_TIME_H
Packit dd8086
#include <sys/time.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_CDDB
Packit dd8086
#include <cddb/cddb.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#include <signal.h>
Packit dd8086
Packit dd8086
#ifdef HAVE_ERRNO_H
Packit dd8086
#include <errno.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_CURSES_H
Packit dd8086
# include <curses.h>
Packit dd8086
#else
Packit dd8086
# ifdef HAVE_NCURSES_H
Packit dd8086
#include <ncurses.h>
Packit dd8086
# else
Packit dd8086
#   ifdef HAVE_NCURSES_NCURSES_H
Packit dd8086
#     include <ncurses/ncurses.h>
Packit dd8086
#   else
Packit dd8086
#     error "You need <curses.h> or 
Packit dd8086
#   endif
Packit dd8086
# endif
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#include <cdio/cdio.h>
Packit dd8086
#include <cdio/mmc.h>
Packit dd8086
#include <cdio/util.h>
Packit dd8086
#include <cdio/cd_types.h>
Packit dd8086
#include <cdio/logging.h>
Packit dd8086
Packit dd8086
#include "cddb.h"
Packit dd8086
#include "getopt.h"
Packit dd8086
Packit dd8086
static void action(const char *psz_action);
Packit dd8086
static void display_cdinfo(CdIo_t *p_cdio, track_t i_tracks,
Packit dd8086
                           track_t i_first_track);
Packit dd8086
static void display_tracks(void);
Packit dd8086
static void get_cddb_track_info(track_t i_track);
Packit dd8086
static void get_cdtext_track_info(track_t i_track);
Packit dd8086
static void get_track_info(track_t i_track);
Packit dd8086
static bool play_track(track_t t1, track_t t2);
Packit dd8086
Packit dd8086
static CdIo_t             *p_cdio_global;        /* libcdio handle */
Packit dd8086
static driver_id_t        driver_id = DRIVER_DEVICE;
Packit dd8086
static int b_sig = false;                        /* set on some signals */
Packit dd8086
Packit dd8086
/* cdrom data */
Packit dd8086
static track_t            i_first_track_global;
Packit dd8086
static track_t            i_last_track;
Packit dd8086
static track_t            i_first_audio_track;
Packit dd8086
static track_t            i_last_audio_track;
Packit dd8086
static track_t            i_last_display_track = CDIO_INVALID_TRACK;
Packit dd8086
static track_t            i_tracks_global;
Packit dd8086
static msf_t              toc[CDIO_CDROM_LEADOUT_TRACK+1];
Packit dd8086
static cdio_subchannel_t  sub;      /* subchannel last time read */
Packit dd8086
static int                i_data;     /* # of data tracks present ? */
Packit dd8086
static int                start_track = 0;
Packit dd8086
static int                stop_track = 0;
Packit dd8086
static int                one_track = 0;
Packit dd8086
static int                i_vol_port   = 5; /* If 5, retrieve volume port.
Packit dd8086
                                         Otherwise the port number 0..3
Packit dd8086
                                         of a working volume port and
Packit dd8086
                                         4 for no working port.
Packit dd8086
                                       */
Packit dd8086
Packit dd8086
/* settings which can be set from the command or interactively. */
Packit dd8086
static bool               b_cd            = false;
Packit dd8086
static bool               auto_mode       = false;
Packit dd8086
static bool               b_verbose       = false;
Packit dd8086
static bool               debug           = false;
Packit dd8086
static bool               b_interactive   = true;
Packit dd8086
static bool               b_prefer_cdtext = true;
Packit dd8086
#ifdef CDDB_ADDED
Packit dd8086
static bool               b_cddb          = false; /* CDDB database present */
Packit dd8086
#endif
Packit dd8086
static bool               b_db            = false; /* we have a database at all */
Packit dd8086
static bool               b_record        = false; /* we have a record for
Packit dd8086
static                                         the inserted CD */
Packit dd8086
static bool               b_all_tracks = false; /* True if we display all tracks*/
Packit dd8086
static int8_t             i_volume_level = -1;   /* Valid range is 0..100 */
Packit dd8086
Packit dd8086
Packit dd8086
static char *psz_device_global=NULL;
Packit dd8086
static char *psz_program;
Packit dd8086
Packit dd8086
/* Info about songs and titles. The 0 entry will contain the disc info.
Packit dd8086
 */
Packit dd8086
typedef struct
Packit dd8086
{
Packit dd8086
  char title[80];
Packit dd8086
  char artist[80];
Packit dd8086
  char length[8];
Packit dd8086
  char ext_data[80];
Packit dd8086
  bool b_cdtext;  /* true if from CD-Text, false if from CDDB */
Packit dd8086
} cd_track_info_rec_t;
Packit dd8086
Packit dd8086
static cd_track_info_rec_t cd_info[CDIO_CD_MAX_TRACKS+2];
Packit dd8086
Packit dd8086
static char title[80];
Packit dd8086
static char artist[80];
Packit dd8086
static char genre[40];
Packit dd8086
static char category[40];
Packit dd8086
static char year[5];
Packit dd8086
Packit dd8086
static bool b_cdtext_title;     /* true if from CD-Text, false if from CDDB */
Packit dd8086
static bool b_cdtext_artist;    /* true if from CD-Text, false if from CDDB */
Packit dd8086
static bool b_cdtext_genre;     /* true if from CD-Text, false if from CDDB */
Packit dd8086
#ifdef CDTEXT_CATEGORY_ADDED
Packit dd8086
static bool b_cdtext_category;  /* true if from CD-Text, false if from CDDB */
Packit dd8086
#endif
Packit dd8086
static bool b_cdtext_year;  /* true if from CD-Text, false if from CDDB */
Packit dd8086
Packit dd8086
static cdio_audio_volume_t audio_volume;
Packit dd8086
Packit dd8086
#ifdef HAVE_CDDB
Packit dd8086
static cddb_conn_t *p_conn = NULL;
Packit dd8086
static cddb_disc_t *p_cddb_disc = NULL;
Packit dd8086
static int i_cddb_matches = 0;
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#define MAX_KEY_STR 50
Packit dd8086
static const char key_bindings[][MAX_KEY_STR] = {
Packit dd8086
  "    right     play / next track",
Packit dd8086
  "    left      previous track",
Packit dd8086
  "    up/down   10 sec forward / back",
Packit dd8086
  "    1-9       jump to track 1-9",
Packit dd8086
  "    0         jump to track 10",
Packit dd8086
  "    F1-F20    jump to track 11-30",
Packit dd8086
  " ",
Packit dd8086
  "    k, h, ?   show this key help",
Packit dd8086
  "    l,        toggle listing all tracks",
Packit dd8086
  "    e         eject",
Packit dd8086
  "    c         close tray",
Packit dd8086
  "    p, space  pause / resume",
Packit dd8086
  "    s         stop",
Packit dd8086
  "    q, ^C     quit",
Packit dd8086
  "    x         quit and continue playing",
Packit dd8086
  "    a         toggle auto-mode",
Packit dd8086
  "    -         decrease volume level",
Packit dd8086
  "    +         increase volume level",
Packit dd8086
};
Packit dd8086
Packit dd8086
static const unsigned int i_key_bindings = sizeof(key_bindings) / MAX_KEY_STR;
Packit dd8086
Packit dd8086
/* ---------------------------------------------------------------------- */
Packit dd8086
/* tty stuff                                                              */
Packit dd8086
Packit dd8086
typedef enum {
Packit dd8086
  LINE_STATUS       =  0,
Packit dd8086
  LINE_CDINFO       =  1,
Packit dd8086
Packit dd8086
  LINE_ARTIST       =  3,
Packit dd8086
  LINE_CDNAME       =  4,
Packit dd8086
  LINE_GENRE        =  5,
Packit dd8086
  LINE_YEAR         =  6,
Packit dd8086
Packit dd8086
  LINE_TRACK_PREV   =  8,
Packit dd8086
  LINE_TRACK_TITLE  =  9,
Packit dd8086
  LINE_TRACK_ARTIST = 10,
Packit dd8086
  LINE_TRACK_NEXT   = 11,
Packit dd8086
Packit dd8086
} track_line_t;
Packit dd8086
Packit dd8086
static unsigned int  LINE_ACTION = 25;
Packit dd8086
static unsigned int  COLS_LAST;
Packit dd8086
static char psz_action_line[300] = "";
Packit dd8086
Packit dd8086
static int rounded_div(unsigned int i_a, unsigned int i_b)
Packit dd8086
{
Packit dd8086
  const unsigned int i_b_half=i_b/2;
Packit dd8086
  return ((i_a)+i_b_half)/i_b;
Packit dd8086
}
Packit dd8086
Packit dd8086
/** Curses window initialization. */
Packit dd8086
static void
Packit dd8086
tty_raw(void)
Packit dd8086
{
Packit dd8086
  if (!b_interactive) return;
Packit dd8086
Packit dd8086
  initscr();
Packit dd8086
  cbreak();
Packit dd8086
  clear();
Packit dd8086
  noecho();
Packit dd8086
#ifdef HAVE_KEYPAD
Packit dd8086
  keypad(stdscr,1);
Packit dd8086
#endif
Packit dd8086
  getmaxyx(stdscr, LINE_ACTION, COLS_LAST);
Packit dd8086
  LINE_ACTION--;
Packit dd8086
  refresh();
Packit dd8086
}
Packit dd8086
Packit dd8086
/** Curses window finalization. */
Packit dd8086
static void
Packit dd8086
tty_restore(void)
Packit dd8086
{
Packit dd8086
  if (!b_interactive) return;
Packit dd8086
  endwin();
Packit dd8086
}
Packit dd8086
Packit dd8086
#define UNUSED(x) (void)(x)
Packit dd8086
/* Called when window is resized. */
Packit dd8086
static void
Packit dd8086
sigwinch(int dummy)
Packit dd8086
{
Packit dd8086
  UNUSED(dummy);
Packit dd8086
  tty_restore();
Packit dd8086
  tty_raw();
Packit dd8086
  action(NULL);
Packit dd8086
}
Packit dd8086
Packit dd8086
/* Signal handler - Ctrl-C and others. */
Packit dd8086
static void
Packit dd8086
ctrlc(int signal_num)
Packit dd8086
{
Packit dd8086
  b_sig = true;
Packit dd8086
}
Packit dd8086
Packit dd8086
/* Timed wait on an event. */
Packit dd8086
static int
Packit dd8086
select_wait(int sec)
Packit dd8086
{
Packit dd8086
  struct timeval  tv;
Packit dd8086
  fd_set          se;
Packit dd8086
Packit dd8086
  FD_ZERO(&se);
Packit dd8086
  tv.tv_sec = sec;
Packit dd8086
  tv.tv_usec = 0;
Packit dd8086
  return select(1,&se,NULL,NULL,&tv;;
Packit dd8086
}
Packit dd8086
Packit dd8086
/* ---------------------------------------------------------------------- */
Packit dd8086
Packit dd8086
/* Display the action line. */
Packit dd8086
static void
Packit dd8086
action(const char *psz_action)
Packit dd8086
{
Packit dd8086
  if (!b_interactive) {
Packit dd8086
    if (b_verbose && psz_action)
Packit dd8086
      fprintf(stderr,"action: %s\n", psz_action);
Packit dd8086
    return;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  if (!psz_action)
Packit dd8086
    ;
Packit dd8086
  else if (psz_action && strlen(psz_action))
Packit dd8086
    snprintf(psz_action_line, sizeof(psz_action_line), "action : %s",
Packit dd8086
             psz_action);
Packit dd8086
  else
Packit dd8086
    snprintf(psz_action_line, sizeof(psz_action_line), "%s", "" );
Packit dd8086
  mvprintw(LINE_ACTION, 0, psz_action_line);
Packit dd8086
  clrtoeol();
Packit dd8086
  refresh();
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
/* Display an error message.. */
Packit dd8086
static void
Packit dd8086
xperror(const char *psz_msg)
Packit dd8086
{
Packit dd8086
  char line[80];
Packit dd8086
Packit dd8086
  if (!b_interactive) {
Packit dd8086
    if (b_verbose) {
Packit dd8086
      fprintf(stderr, "error: ");
Packit dd8086
      perror(psz_msg);
Packit dd8086
    }
Packit dd8086
    return;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  if (b_verbose) {
Packit dd8086
    snprintf(line, sizeof(line), "%s: %s", psz_msg, strerror(errno));
Packit dd8086
    attron(A_STANDOUT);
Packit dd8086
    mvprintw(LINE_ACTION, 0, (char *) "error  : %s", line);
Packit dd8086
    attroff(A_STANDOUT);
Packit dd8086
    clrtoeol();
Packit dd8086
    refresh();
Packit dd8086
    select_wait(3);
Packit dd8086
    action("");
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
static void
Packit dd8086
finish(const char *psz_msg, int rc)
Packit dd8086
{
Packit dd8086
  if (b_interactive) {
Packit dd8086
    attron(A_STANDOUT);
Packit dd8086
    mvprintw(LINE_ACTION, 0, (char *) "%s, exiting...\n", psz_msg);
Packit dd8086
    attroff(A_STANDOUT);
Packit dd8086
    clrtoeol();
Packit dd8086
    refresh();
Packit dd8086
  }
Packit dd8086
  tty_restore();
Packit dd8086
#ifdef HAVE_CDDB
Packit dd8086
  if (p_conn) cddb_destroy(p_conn);
Packit dd8086
  cddb_disc_destroy(p_cddb_disc);
Packit dd8086
  libcddb_shutdown();
Packit dd8086
#endif /*HAVE_CDDB*/
Packit dd8086
  cdio_destroy (p_cdio_global);
Packit dd8086
  free (psz_device_global);
Packit dd8086
  exit (rc);
Packit dd8086
}
Packit dd8086
Packit dd8086
/* ---------------------------------------------------------------------- */
Packit dd8086
Packit dd8086
/* Set all audio channels to level. level is assumed to be in the range
Packit dd8086
   0..100.
Packit dd8086
*/
Packit dd8086
static bool
Packit dd8086
set_volume_level(CdIo_t *p_cdio, uint8_t i_level)
Packit dd8086
{
Packit dd8086
  const unsigned int i_new_level= rounded_div(i_level*256, 100);
Packit dd8086
  unsigned int i;
Packit dd8086
  driver_return_code_t rc;
Packit dd8086
  for (i=0; i<=3; i++) {
Packit dd8086
    audio_volume.level[i] = i_new_level;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  rc = cdio_audio_set_volume(p_cdio, &audio_volume);
Packit dd8086
  if ( DRIVER_OP_SUCCESS != rc ) {
Packit dd8086
    /* If we can't do a get volume, audio_volume.level is used as
Packit dd8086
       a second-best guess. But if this set failed restore it to
Packit dd8086
       an invalid value so we don't get confused and think that this
Packit dd8086
       was set. */
Packit dd8086
    for (i=0; i<=3; i++) {
Packit dd8086
      audio_volume.level[i] = 0;
Packit dd8086
    }
Packit dd8086
  } else {
Packit dd8086
    /* Set i_vol_port so volume levels set above will get used. */
Packit dd8086
    i_vol_port=0;
Packit dd8086
  }
Packit dd8086
  return rc;
Packit dd8086
Packit dd8086
}
Packit dd8086
Packit dd8086
/* Subtract one from the volume level. If we are at the minimum value,
Packit dd8086
 * nothing is done.
Packit dd8086
Packit dd8086
   We used to wrap at the boundaries but this is probably wrong because
Packit dd8086
   is assumes someone:
Packit dd8086
     * looks at the display while listening,
Packit dd8086
     * knows that 99 is the maximum value.
Packit dd8086
Packit dd8086
   See issue #33333
Packit dd8086
Packit dd8086
   If the volume level is undefined, then this means we could not get
Packit dd8086
   the current value and we'll' set it to 50 the midway point.
Packit dd8086
Packit dd8086
   Return the status of setting the volume level.  */
Packit dd8086
static bool
Packit dd8086
decrease_volume_level(CdIo_t *p_cdio)
Packit dd8086
{
Packit dd8086
  if (i_volume_level == -1) i_volume_level = 51;
Packit dd8086
  if (i_volume_level <= 0)  i_volume_level = 1;
Packit dd8086
  return set_volume_level(p_cdio, --i_volume_level);
Packit dd8086
}
Packit dd8086
Packit dd8086
/* Add 1 to the volume level. If we are at the maximum value, nothing
Packit dd8086
   is done.
Packit dd8086
Packit dd8086
   We used to wrap at the boundaries but this is probably wrong because
Packit dd8086
   is assumes someone:
Packit dd8086
     * looks at the display while listening,
Packit dd8086
     * knows that 99 is the maximum value.
Packit dd8086
Packit dd8086
   See issue #33333
Packit dd8086
Packit dd8086
   If volume level is undefined, then this means we could not get the
Packit dd8086
   current value and we'll' set it to 50 the midway point.
Packit dd8086
Packit dd8086
   Return the status of setting the volume level.  */
Packit dd8086
static bool
Packit dd8086
increase_volume_level(CdIo_t *p_cdio)
Packit dd8086
{
Packit dd8086
  if (i_volume_level == -1) i_volume_level = 49;
Packit dd8086
  if (i_volume_level <= 0) i_volume_level = 0;
Packit dd8086
  if (i_volume_level > 98) i_volume_level = 98;
Packit dd8086
  return set_volume_level(p_cdio, ++i_volume_level);
Packit dd8086
}
Packit dd8086
Packit dd8086
/** Stop playing audio CD */
Packit dd8086
static bool
Packit dd8086
cd_stop(CdIo_t *p_cdio)
Packit dd8086
{
Packit dd8086
  bool b_ok = true;
Packit dd8086
  if (b_cd && p_cdio) {
Packit dd8086
    action("stop...");
Packit dd8086
    i_last_audio_track = CDIO_INVALID_TRACK;
Packit dd8086
    b_ok = DRIVER_OP_SUCCESS == cdio_audio_stop(p_cdio);
Packit dd8086
    if ( !b_ok )
Packit dd8086
      xperror("stop");
Packit dd8086
    if (b_all_tracks) display_tracks();
Packit dd8086
  }
Packit dd8086
  return b_ok;
Packit dd8086
}
Packit dd8086
Packit dd8086
/** Eject CD */
Packit dd8086
static bool
Packit dd8086
cd_eject(void)
Packit dd8086
{
Packit dd8086
  bool b_ok = true;
Packit dd8086
  if (p_cdio_global) {
Packit dd8086
    cd_stop(p_cdio_global);
Packit dd8086
    action("eject...");
Packit dd8086
    b_ok = DRIVER_OP_SUCCESS == cdio_eject_media(&p_cdio_global);
Packit dd8086
    if (!b_ok)
Packit dd8086
      xperror("eject");
Packit dd8086
    b_cd = false;
Packit dd8086
    cdio_destroy (p_cdio_global);
Packit dd8086
    p_cdio_global = NULL;
Packit dd8086
  }
Packit dd8086
  return b_ok;
Packit dd8086
}
Packit dd8086
Packit dd8086
/** Close CD tray */
Packit dd8086
static bool
Packit dd8086
cd_close(const char *psz_device)
Packit dd8086
{
Packit dd8086
  bool b_ok = true;
Packit dd8086
  if (!b_cd) {
Packit dd8086
    action("close...");
Packit dd8086
    b_ok = DRIVER_OP_SUCCESS == cdio_close_tray(psz_device, &driver_id);
Packit dd8086
    if (!b_ok)
Packit dd8086
      xperror("close");
Packit dd8086
  }
Packit dd8086
  return b_ok;
Packit dd8086
}
Packit dd8086
Packit dd8086
/** Pause playing audio CD */
Packit dd8086
static bool
Packit dd8086
cd_pause(CdIo_t *p_cdio)
Packit dd8086
{
Packit dd8086
  bool b_ok = true;
Packit dd8086
  if (sub.audio_status == CDIO_MMC_READ_SUB_ST_PLAY) {
Packit dd8086
    b_ok = DRIVER_OP_SUCCESS == cdio_audio_pause(p_cdio);
Packit dd8086
    if (!b_ok)
Packit dd8086
      xperror("pause");
Packit dd8086
  }
Packit dd8086
  return b_ok;
Packit dd8086
}
Packit dd8086
Packit dd8086
/** Get status/track/position info of an audio CD */
Packit dd8086
static bool
Packit dd8086
read_subchannel(CdIo_t *p_cdio)
Packit dd8086
{
Packit dd8086
  bool b_ok = true;
Packit dd8086
  if (!p_cdio) return false;
Packit dd8086
Packit dd8086
  b_ok = DRIVER_OP_SUCCESS == cdio_audio_read_subchannel(p_cdio, &sub);
Packit dd8086
  if (!b_ok) {
Packit dd8086
    xperror("read subchannel");
Packit dd8086
    b_cd = 0;
Packit dd8086
  }
Packit dd8086
  if (auto_mode && sub.audio_status == CDIO_MMC_READ_SUB_ST_COMPLETED)
Packit dd8086
    cd_eject();
Packit dd8086
  return b_ok;
Packit dd8086
}
Packit dd8086
Packit dd8086
#ifdef HAVE_CDDB
Packit dd8086
/** This routine is called by vcd routines on error.
Packit dd8086
   Setup is done by init_input_plugin.
Packit dd8086
*/
Packit dd8086
static void
Packit dd8086
cddb_log_handler (cddb_log_level_t level, const char message[])
Packit dd8086
{
Packit dd8086
  switch (level) {
Packit dd8086
  case CDDB_LOG_DEBUG:
Packit dd8086
  case CDDB_LOG_INFO:
Packit dd8086
    if (!b_verbose)
Packit dd8086
      return;
Packit dd8086
    /* Fall through if to warn case */
Packit dd8086
  case CDDB_LOG_WARN:
Packit dd8086
  case CDDB_LOG_ERROR:
Packit dd8086
  case CDDB_LOG_CRITICAL:
Packit dd8086
  default:
Packit dd8086
    xperror(message);
Packit dd8086
    break;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  /* gl_default_cdio_log_handler (level, message); */
Packit dd8086
}
Packit dd8086
#endif /* HAVE_CDDB  */
Packit dd8086
Packit dd8086
static void
Packit dd8086
get_cddb_disc_info(CdIo_t *p_cdio)
Packit dd8086
{
Packit dd8086
#ifdef HAVE_CDDB
Packit dd8086
  b_db = init_cddb(p_cdio, &p_conn, &p_cddb_disc, xperror, i_first_track_global,
Packit dd8086
                   i_tracks_global, &i_cddb_matches);
Packit dd8086
  if (b_db) {
Packit dd8086
    int i_year;
Packit dd8086
    i_year = atoi(year);
Packit dd8086
    cddb_disc_set_artist(p_cddb_disc, artist);
Packit dd8086
    cddb_disc_set_title(p_cddb_disc, title);
Packit dd8086
    cddb_disc_set_genre(p_cddb_disc, genre);
Packit dd8086
    cddb_disc_set_year(p_cddb_disc, i_year);
Packit dd8086
  }
Packit dd8086
#endif /* HAVE_CDDB */
Packit dd8086
  return;
Packit dd8086
}
Packit dd8086
Packit dd8086
#define add_cdtext_disc_info(format_str, info_field, FIELD)     \
Packit dd8086
  if (cdtext_get_const(p_cdtext, FIELD, 0) && !strlen(info_field)) { \
Packit dd8086
    snprintf(info_field, sizeof(info_field), format_str,        \
Packit dd8086
             cdtext_get_const(p_cdtext, FIELD, 0));                  \
Packit dd8086
    b_cdtext_ ## info_field = true;                             \
Packit dd8086
  }
Packit dd8086
Packit dd8086
static void
Packit dd8086
get_cdtext_disc_info(CdIo_t *p_cdio)
Packit dd8086
{
Packit dd8086
  cdtext_t *p_cdtext = cdio_get_cdtext(p_cdio);
Packit dd8086
Packit dd8086
  if (p_cdtext) {
Packit dd8086
    add_cdtext_disc_info("%s", title, CDTEXT_FIELD_TITLE);
Packit dd8086
    add_cdtext_disc_info("%s", artist, CDTEXT_FIELD_PERFORMER);
Packit dd8086
    add_cdtext_disc_info("%s", genre, CDTEXT_FIELD_GENRE);
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
static void
Packit dd8086
get_disc_info(CdIo_t *p_cdio)
Packit dd8086
{
Packit dd8086
  b_db = false;
Packit dd8086
  if (b_prefer_cdtext) {
Packit dd8086
    get_cdtext_disc_info(p_cdio);
Packit dd8086
    get_cddb_disc_info(p_cdio);
Packit dd8086
  } else {
Packit dd8086
    get_cddb_disc_info(p_cdio);
Packit dd8086
    get_cdtext_disc_info(p_cdio);
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/** Read CD TOC and set CD information. */
Packit dd8086
static void
Packit dd8086
read_toc(CdIo_t *p_cdio)
Packit dd8086
{
Packit dd8086
  track_t i;
Packit dd8086
Packit dd8086
  action("read toc...");
Packit dd8086
Packit dd8086
  memset(cd_info, 0, sizeof(cd_info));
Packit dd8086
  title[0] = artist[0] = genre[0] = category[0] = year[0] = '\0';
Packit dd8086
Packit dd8086
  i_first_track_global = cdio_get_first_track_num(p_cdio);
Packit dd8086
  i_last_track         = cdio_get_last_track_num(p_cdio);
Packit dd8086
  i_tracks_global      = cdio_get_num_tracks(p_cdio);
Packit dd8086
  i_first_audio_track  = i_first_track_global;
Packit dd8086
  i_last_audio_track   = i_last_track;
Packit dd8086
Packit dd8086
Packit dd8086
  cdio_audio_get_volume(p_cdio, &audio_volume);
Packit dd8086
  for (i_vol_port=0; i_vol_port<4; i_vol_port++) {
Packit dd8086
    if (audio_volume.level[i_vol_port] > 0) break;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  if ( CDIO_INVALID_TRACK == i_first_track_global ||
Packit dd8086
       CDIO_INVALID_TRACK == i_last_track ) {
Packit dd8086
    xperror("read toc header");
Packit dd8086
    b_cd = false;
Packit dd8086
    b_record = false;
Packit dd8086
    i_last_display_track = CDIO_INVALID_TRACK;
Packit dd8086
  } else {
Packit dd8086
    b_cd = true;
Packit dd8086
    i_data = 0;
Packit dd8086
    get_disc_info(p_cdio);
Packit dd8086
    for (i = i_first_track_global; i <= i_last_track+1; i++) {
Packit dd8086
      int s;
Packit dd8086
      if ( !cdio_get_track_msf(p_cdio, i, &(toc[i])) )
Packit dd8086
      {
Packit dd8086
        xperror("read toc entry");
Packit dd8086
        b_cd = false;
Packit dd8086
        return;
Packit dd8086
      }
Packit dd8086
      if ( TRACK_FORMAT_AUDIO == cdio_get_track_format(p_cdio, i) ) {
Packit dd8086
Packit dd8086
        if (i != i_first_track_global)
Packit dd8086
          {
Packit dd8086
            s = cdio_audio_get_msf_seconds(&toc[i])
Packit dd8086
              - cdio_audio_get_msf_seconds(&toc[i-1]);
Packit dd8086
            snprintf(cd_info[i-1].length, sizeof(cd_info[0].length),
Packit dd8086
                     "%02d:%02d",
Packit dd8086
                     (uint8_t) (s / CDIO_CD_SECS_PER_MIN),
Packit dd8086
                     (uint8_t) (s % CDIO_CD_SECS_PER_MIN));
Packit dd8086
          }
Packit dd8086
      } else {
Packit dd8086
        if ((i != i_last_track+1) ) {
Packit dd8086
          i_data++;
Packit dd8086
          if (i == i_first_track_global) {
Packit dd8086
            if (i == i_last_track)
Packit dd8086
              i_first_audio_track = CDIO_CDROM_LEADOUT_TRACK;
Packit dd8086
            else
Packit dd8086
              i_first_audio_track++;
Packit dd8086
          }
Packit dd8086
        }
Packit dd8086
      }
Packit dd8086
      get_track_info(i);
Packit dd8086
    }
Packit dd8086
    b_record = true;
Packit dd8086
    read_subchannel(p_cdio);
Packit dd8086
    if (auto_mode && sub.audio_status != CDIO_MMC_READ_SUB_ST_PLAY)
Packit dd8086
      play_track(1, CDIO_CDROM_LEADOUT_TRACK);
Packit dd8086
  }
Packit dd8086
  action("");
Packit dd8086
  if (!b_all_tracks)
Packit dd8086
    display_cdinfo(p_cdio, i_tracks_global, i_first_track_global);
Packit dd8086
}
Packit dd8086
Packit dd8086
/** Play an audio track. */
Packit dd8086
static bool
Packit dd8086
play_track(track_t i_start_track, track_t i_end_track)
Packit dd8086
{
Packit dd8086
  bool b_ok = true;
Packit dd8086
  char line[80];
Packit dd8086
Packit dd8086
  if (!b_cd) {
Packit dd8086
    read_toc(p_cdio_global);
Packit dd8086
  }
Packit dd8086
Packit dd8086
  read_subchannel(p_cdio_global);
Packit dd8086
  if (!b_cd || i_first_track_global == CDIO_CDROM_LEADOUT_TRACK)
Packit dd8086
    return false;
Packit dd8086
Packit dd8086
  if (debug)
Packit dd8086
    fprintf(stderr,"play tracks: %d-%d => ", i_start_track, i_end_track-1);
Packit dd8086
  if (i_start_track < i_first_track_global)  i_start_track = i_first_track_global;
Packit dd8086
  if (i_start_track > i_last_audio_track)    i_start_track = i_last_audio_track;
Packit dd8086
  if (i_end_track < i_first_track_global)    i_end_track   = i_first_track_global;
Packit dd8086
  if (i_end_track > i_last_audio_track)      i_end_track   = i_last_audio_track;
Packit dd8086
  i_end_track++;
Packit dd8086
  if (debug)
Packit dd8086
    fprintf(stderr,"%d-%d\n",i_start_track, i_end_track-1);
Packit dd8086
Packit dd8086
  cd_pause(p_cdio_global);
Packit dd8086
  snprintf(line, sizeof(line), "play track %d to track %d.",
Packit dd8086
	   i_start_track, i_end_track-1);
Packit dd8086
  action(line);
Packit dd8086
  b_ok = (DRIVER_OP_SUCCESS == cdio_audio_play_msf(p_cdio_global,
Packit dd8086
                                                   &(toc[i_start_track]),
Packit dd8086
                                                   &(toc[i_end_track])) );
Packit dd8086
  if (!b_ok) xperror("play");
Packit dd8086
  return b_ok;
Packit dd8086
}
Packit dd8086
Packit dd8086
static void
Packit dd8086
skip(int diff)
Packit dd8086
{
Packit dd8086
  msf_t start_msf;
Packit dd8086
  int   sec;
Packit dd8086
Packit dd8086
  read_subchannel(p_cdio_global);
Packit dd8086
  if (!b_cd ||  i_first_track_global == CDIO_CDROM_LEADOUT_TRACK)
Packit dd8086
    return;
Packit dd8086
Packit dd8086
  sec  = cdio_audio_get_msf_seconds(&sub.abs_addr);
Packit dd8086
  sec += diff;
Packit dd8086
  if (sec < 0) sec = 0;
Packit dd8086
Packit dd8086
  start_msf.m = cdio_to_bcd8(sec / CDIO_CD_SECS_PER_MIN);
Packit dd8086
  start_msf.s = cdio_to_bcd8(sec % CDIO_CD_SECS_PER_MIN);
Packit dd8086
  start_msf.f = 0;
Packit dd8086
Packit dd8086
  cd_pause(p_cdio_global);
Packit dd8086
  if ( DRIVER_OP_SUCCESS != cdio_audio_play_msf(p_cdio_global, &start_msf,
Packit dd8086
                                                &(toc[i_last_audio_track])) )
Packit dd8086
    xperror("play");
Packit dd8086
}
Packit dd8086
Packit dd8086
static bool
Packit dd8086
toggle_pause(void)
Packit dd8086
{
Packit dd8086
  bool b_ok = true;
Packit dd8086
  if (!b_cd) return false;
Packit dd8086
Packit dd8086
  if (CDIO_MMC_READ_SUB_ST_PAUSED == sub.audio_status) {
Packit dd8086
    b_ok = DRIVER_OP_SUCCESS != cdio_audio_resume(p_cdio_global);
Packit dd8086
    if (!b_ok)
Packit dd8086
      xperror("resume");
Packit dd8086
  } else {
Packit dd8086
    b_ok = DRIVER_OP_SUCCESS != cdio_audio_pause(p_cdio_global);
Packit dd8086
    if (!b_ok)
Packit dd8086
      xperror("pause");
Packit dd8086
  }
Packit dd8086
  return b_ok;
Packit dd8086
}
Packit dd8086
Packit dd8086
/** Update windows with status and possibly track info. This used in
Packit dd8086
  interactive playing not batch mode.
Packit dd8086
 */
Packit dd8086
static void
Packit dd8086
display_status(bool b_status_only)
Packit dd8086
{
Packit dd8086
  char line[80];
Packit dd8086
Packit dd8086
  if (!b_interactive) return;
Packit dd8086
Packit dd8086
  if (!b_cd) {
Packit dd8086
    snprintf(line, sizeof(line), "no CD in drive (%s)", psz_device_global);
Packit dd8086
Packit dd8086
  } else if (i_first_track_global == CDIO_CDROM_LEADOUT_TRACK) {
Packit dd8086
    snprintf(line, sizeof(line), "CD has only data tracks");
Packit dd8086
Packit dd8086
  } else if (sub.audio_status == CDIO_MMC_READ_SUB_ST_PAUSED ||
Packit dd8086
             sub.audio_status == CDIO_MMC_READ_SUB_ST_PLAY) {
Packit dd8086
    cdio_audio_get_volume(p_cdio_global, &audio_volume);
Packit dd8086
    if (i_vol_port < 4) {
Packit dd8086
        i_volume_level = rounded_div(audio_volume.level[i_vol_port]*100, 256);
Packit dd8086
        snprintf(line, sizeof(line),
Packit dd8086
                "track %2d - %02x:%02x of %s (%02x:%02x abs) %s volume: %d",
Packit dd8086
                sub.track, sub.rel_addr.m, sub.rel_addr.s,
Packit dd8086
                cd_info[sub.track].length,
Packit dd8086
                sub.abs_addr.m, sub.abs_addr.s,
Packit dd8086
                mmc_audio_state2str(sub.audio_status),
Packit dd8086
                i_volume_level);
Packit dd8086
      } else
Packit dd8086
        snprintf(line, sizeof(line),
Packit dd8086
		 "track %2d - %02x:%02x of %s (%02x:%02x abs) %s",
Packit dd8086
		 sub.track, sub.rel_addr.m, sub.rel_addr.s,
Packit dd8086
		 cd_info[sub.track].length, sub.abs_addr.m, sub.abs_addr.s,
Packit dd8086
		 mmc_audio_state2str(sub.audio_status));
Packit dd8086
  } else {
Packit dd8086
    snprintf(line, sizeof(line), "%s", mmc_audio_state2str(sub.audio_status));
Packit dd8086
Packit dd8086
  }
Packit dd8086
Packit dd8086
  action(NULL);
Packit dd8086
  mvprintw(LINE_STATUS, 0, (char *) "status%s: %s",
Packit dd8086
           auto_mode ? "*" : " ", line);
Packit dd8086
  clrtoeol();
Packit dd8086
Packit dd8086
  if ( !b_status_only && b_db && i_last_display_track != sub.track &&
Packit dd8086
       (sub.audio_status == CDIO_MMC_READ_SUB_ST_PAUSED ||
Packit dd8086
        sub.audio_status == CDIO_MMC_READ_SUB_ST_PLAY)  &&
Packit dd8086
        b_cd) {
Packit dd8086
Packit dd8086
    if (b_all_tracks)
Packit dd8086
      display_tracks();
Packit dd8086
    else {
Packit dd8086
      const cd_track_info_rec_t *p_cd_info = &cd_info[sub.track];
Packit dd8086
      i_last_display_track = sub.track;
Packit dd8086
      if (i_first_audio_track != sub.track &&
Packit dd8086
          strlen(cd_info[sub.track-1].title)) {
Packit dd8086
        const cd_track_info_rec_t *p_cd_info_track = &cd_info[sub.track-1];
Packit dd8086
        mvprintw(LINE_TRACK_PREV, 0, (char *) " track %2d title : %s [%s]",
Packit dd8086
                 sub.track-1, p_cd_info->title,
Packit dd8086
                 p_cd_info_track->b_cdtext ? "CD-Text" : "CDDB");
Packit dd8086
        clrtoeol();
Packit dd8086
      } else {
Packit dd8086
        mvprintw(LINE_TRACK_PREV, 0, (char *) "%s","");
Packit dd8086
        clrtoeol();
Packit dd8086
      }
Packit dd8086
      if (strlen(p_cd_info->title)) {
Packit dd8086
        mvprintw(LINE_TRACK_TITLE,  0, (char *) ">track %2d title : %s [%s]",
Packit dd8086
                 sub.track, p_cd_info->title,
Packit dd8086
                 (char *) (p_cd_info->b_cdtext ? "CD-Text" : "CDDB"));
Packit dd8086
        clrtoeol();
Packit dd8086
      }
Packit dd8086
      if (strlen(p_cd_info->artist)) {
Packit dd8086
        mvprintw(LINE_TRACK_ARTIST, 0, (char *) ">track %2d artist: %s [%s]",
Packit dd8086
                 sub.track, p_cd_info->artist,
Packit dd8086
                 p_cd_info->b_cdtext ? "CD-Text" : "CDDB");
Packit dd8086
        clrtoeol();
Packit dd8086
      }
Packit dd8086
      if (i_last_audio_track != sub.track &&
Packit dd8086
          strlen(cd_info[sub.track+1].title)) {
Packit dd8086
        const cd_track_info_rec_t *p_cd_info_track = &cd_info[sub.track+1];
Packit dd8086
        mvprintw(LINE_TRACK_NEXT, 0, (char *) " track %2d title : %s [%s]",
Packit dd8086
                 sub.track+1, p_cd_info_track->title,
Packit dd8086
                 p_cd_info->b_cdtext ? "CD-Text" : "CDDB");
Packit dd8086
        clrtoeol();
Packit dd8086
      } else {
Packit dd8086
        mvprintw(LINE_TRACK_NEXT, 0, (char *) "%s","");
Packit dd8086
        clrtoeol();
Packit dd8086
      }
Packit dd8086
      clrtobot();
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
Packit dd8086
  action(NULL); /* Redisplay action line. */
Packit dd8086
Packit dd8086
}
Packit dd8086
Packit dd8086
static void
Packit dd8086
get_cddb_track_info(track_t i_track)
Packit dd8086
{
Packit dd8086
#ifdef HAVE_CDDB
Packit dd8086
  cddb_track_t *t = cddb_disc_get_track(p_cddb_disc,
Packit dd8086
                                        i_track - i_first_track_global);
Packit dd8086
  if (t) {
Packit dd8086
    cddb_track_set_title(t, title);
Packit dd8086
    cddb_track_set_artist(t, artist);
Packit dd8086
  }
Packit dd8086
Packit dd8086
#else
Packit dd8086
    ;
Packit dd8086
#endif
Packit dd8086
}
Packit dd8086
Packit dd8086
#define add_cdtext_track_info(format_str, info_field, FIELD) \
Packit dd8086
  if (cdtext_get_const(p_cdtext, FIELD, i_track)) {                        \
Packit dd8086
    snprintf(cd_info[i_track].info_field,                             \
Packit dd8086
             sizeof(cd_info[i_track].info_field),                     \
Packit dd8086
             format_str, cdtext_get_const(p_cdtext, FIELD, i_track));      \
Packit dd8086
    cd_info[i_track].b_cdtext = true; \
Packit dd8086
  }
Packit dd8086
Packit dd8086
Packit dd8086
static void
Packit dd8086
get_cdtext_track_info(track_t i_track)
Packit dd8086
{
Packit dd8086
Packit dd8086
  cdtext_t *p_cdtext = cdio_get_cdtext(p_cdio_global);
Packit dd8086
Packit dd8086
  if (NULL != p_cdtext) {
Packit dd8086
    add_cdtext_track_info("%s", title, CDTEXT_FIELD_TITLE);
Packit dd8086
    add_cdtext_track_info("%s", artist, CDTEXT_FIELD_PERFORMER);
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
static void
Packit dd8086
get_track_info(track_t i_track)
Packit dd8086
{
Packit dd8086
Packit dd8086
  if (b_prefer_cdtext) {
Packit dd8086
    get_cdtext_track_info(i_track);
Packit dd8086
    get_cddb_track_info(i_track);
Packit dd8086
  } else {
Packit dd8086
    get_cddb_track_info(i_track);
Packit dd8086
    get_cdtext_track_info(i_track);
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
#define display_line(LINE_NO, COL_NO, format_str, field)   \
Packit dd8086
  if (field != NULL && field[0])  {                                \
Packit dd8086
    mvprintw(LINE_NO, COL_NO, (char *) format_str " [%s]", \
Packit dd8086
             field,                                        \
Packit dd8086
             b_cdtext_ ## field ? "CD-Text": "CDDB");      \
Packit dd8086
    clrtoeol();                                            \
Packit dd8086
  }
Packit dd8086
Packit dd8086
static void
Packit dd8086
display_cdinfo(CdIo_t *p_cdio, track_t i_tracks, track_t i_first_track)
Packit dd8086
{
Packit dd8086
  int len;
Packit dd8086
  char line[80];
Packit dd8086
Packit dd8086
  if (!b_interactive) return;
Packit dd8086
Packit dd8086
  if (!b_cd) snprintf(line, sizeof(line), "-");
Packit dd8086
  else {
Packit dd8086
    len = snprintf(line, sizeof(line), "%2u tracks  (%02x:%02x min)",
Packit dd8086
                  (unsigned int) i_last_track,
Packit dd8086
                  toc[i_last_track+1].m, toc[i_last_track+1].s);
Packit dd8086
    if (i_data && i_first_track != CDIO_CDROM_LEADOUT_TRACK)
Packit dd8086
      snprintf(line+len, sizeof(line)-len, ", audio=%u-%u",
Packit dd8086
	      (unsigned int) i_first_audio_track,
Packit dd8086
              (unsigned int) i_last_audio_track);
Packit dd8086
Packit dd8086
    display_line(LINE_ARTIST, 0, "CD Artist       : %s", artist);
Packit dd8086
    display_line(LINE_CDNAME, 0, "CD Title        : %s", title);
Packit dd8086
    display_line(LINE_GENRE,  0, "CD Genre        : %s", genre);
Packit dd8086
    display_line(LINE_YEAR,   0, "CD Year         : %s", year);
Packit dd8086
  }
Packit dd8086
Packit dd8086
  mvprintw(LINE_CDINFO, 0, (char *) "CD info: %s", line);
Packit dd8086
  clrtoeol();
Packit dd8086
  action(NULL);
Packit dd8086
}
Packit dd8086
Packit dd8086
/* ---------------------------------------------------------------------- */
Packit dd8086
Packit dd8086
static void
Packit dd8086
usage(char *prog)
Packit dd8086
{
Packit dd8086
    fprintf(stderr,
Packit dd8086
            "%s is a simple curses CD player.  It can pick up artist,\n"
Packit dd8086
            "CD name and song title from CD-Text info on the CD or\n"
Packit dd8086
            "via CDDB.\n"
Packit dd8086
            "\n"
Packit dd8086
            "usage: %s [options] [device]\n"
Packit dd8086
            "\n"
Packit dd8086
            "default for to search for a CD-ROM device with a CD-DA loaded\n"
Packit dd8086
            "\n"
Packit dd8086
            "These command line options available:\n"
Packit dd8086
            "  -h      print this help\n"
Packit dd8086
            "  -k      print key mapping\n"
Packit dd8086
            "  -a      start up in auto-mode\n"
Packit dd8086
            "  -v      verbose\n"
Packit dd8086
            "\n"
Packit dd8086
            "for non-interactive use (only one) of these:\n"
Packit dd8086
            "  -l      list tracks\n"
Packit dd8086
            "  -c      print cover (PostScript to stdout)\n"
Packit dd8086
            "  -C      close CD-ROM tray. If you use this option,\n"
Packit dd8086
            "          a CD-ROM device name must be specified.\n"
Packit dd8086
            "  -p      play the whole CD\n"
Packit dd8086
            "  -t n    play track >n<\n"
Packit dd8086
            "  -t a-b  play all tracks between a and b (inclusive)\n"
Packit dd8086
            "  -L      set volume level\n"
Packit dd8086
            "  -s      stop playing\n"
Packit dd8086
            "  -S      list audio subchannel information\n"
Packit dd8086
            "  -e      eject cdrom\n"
Packit dd8086
            "\n"
Packit dd8086
            "That's all. Oh, maybe a few words more about the auto-mode. This\n"
Packit dd8086
            "is the 'dont-touch-any-key' feature. You load a CD, player starts\n"
Packit dd8086
            "to play it, and when it is done it ejects the CD. Start it that\n"
Packit dd8086
            "way on a spare console and forget about it...\n"
Packit dd8086
            "\n"
Packit dd8086
            "(c) 1997-98 Gerd Knorr <kraxel@goldbach.in-berlin.de>\n"
Packit dd8086
            "(c) 2005-2006, 2017 Rocky Bernstein <rocky@gnu.org>\n"
Packit dd8086
            , prog, prog);
Packit dd8086
}
Packit dd8086
Packit dd8086
static void
Packit dd8086
print_keys(void)
Packit dd8086
{
Packit dd8086
  unsigned int i;
Packit dd8086
  for (i=0; i < i_key_bindings; i++)
Packit dd8086
    fprintf(stderr, "%s\n", key_bindings[i]);
Packit dd8086
}
Packit dd8086
Packit dd8086
static void
Packit dd8086
keypress_wait(CdIo_t *p_cdio)
Packit dd8086
  {
Packit dd8086
    action("press any key to continue");
Packit dd8086
    while (1 != select_wait(b_cd ? 1 : 5)) {
Packit dd8086
      read_subchannel(p_cdio);
Packit dd8086
      display_status(true);
Packit dd8086
    }
Packit dd8086
    (void) getch();
Packit dd8086
    clrtobot();
Packit dd8086
    action(NULL);
Packit dd8086
    if (!b_all_tracks)
Packit dd8086
      display_cdinfo(p_cdio, i_tracks_global, i_first_track_global);
Packit dd8086
    i_last_display_track = CDIO_INVALID_TRACK;
Packit dd8086
  }
Packit dd8086
Packit dd8086
static void
Packit dd8086
list_keys(void)
Packit dd8086
{
Packit dd8086
  unsigned int i;
Packit dd8086
  for (i=0; i < i_key_bindings; i++) {
Packit dd8086
    mvprintw(LINE_TRACK_PREV+i, 0, (char *) "%s", key_bindings[i]);
Packit dd8086
    clrtoeol();
Packit dd8086
  }
Packit dd8086
  keypress_wait(p_cdio_global);
Packit dd8086
}
Packit dd8086
Packit dd8086
static void
Packit dd8086
display_tracks(void)
Packit dd8086
{
Packit dd8086
  track_t i;
Packit dd8086
  int i_line=0;
Packit dd8086
  int s;
Packit dd8086
Packit dd8086
  if (b_record) {
Packit dd8086
    i_line=LINE_TRACK_PREV - 1;
Packit dd8086
    for (i = i_first_track_global; i <= i_last_track; i++) {
Packit dd8086
      char line[200]="";
Packit dd8086
      s = cdio_audio_get_msf_seconds(&toc[i+1])
Packit dd8086
        - cdio_audio_get_msf_seconds(&toc[i]);
Packit dd8086
      read_subchannel(p_cdio_global);
Packit dd8086
      snprintf(line, sizeof(line), "%2d  %02d:%02d  %s ", i,
Packit dd8086
              s / CDIO_CD_SECS_PER_MIN,  s % CDIO_CD_SECS_PER_MIN,
Packit dd8086
              ( ( sub.audio_status == CDIO_MMC_READ_SUB_ST_PLAY ||
Packit dd8086
                  sub.audio_status == CDIO_MMC_READ_SUB_ST_PAUSED ) &&
Packit dd8086
                sub.track == i ) ? "->" : " |");
Packit dd8086
      if (b_record) {
Packit dd8086
        if ( strlen(cd_info[i].title) )
Packit dd8086
          strcat(line, cd_info[i].title);
Packit dd8086
        if ( strlen(cd_info[i].artist) > 0 ) {
Packit dd8086
          if (strlen(cd_info[i].title))
Packit dd8086
            strcat(line, " / ");
Packit dd8086
          strcat(line, cd_info[i].artist);
Packit dd8086
        }
Packit dd8086
      }
Packit dd8086
      if (sub.track == i) {
Packit dd8086
        attron(A_STANDOUT);
Packit dd8086
        mvprintw(i_line++, 0, line);
Packit dd8086
        attroff(A_STANDOUT);
Packit dd8086
      } else
Packit dd8086
        mvprintw(i_line++, 0, line);
Packit dd8086
      clrtoeol();
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*
Packit dd8086
 * PostScript 8bit latin1 handling
Packit dd8086
 * stolen from mpage output -- please don't ask me how this works...
Packit dd8086
 */
Packit dd8086
#define ENCODING_TRICKS \
Packit dd8086
        "/reencsmalldict 12 dict def\n"                         \
Packit dd8086
        "/ReEncodeSmall { reencsmalldict begin\n"               \
Packit dd8086
        "/newcodesandnames exch def /newfontname exch def\n"    \
Packit dd8086
        "/basefontname exch def\n"                              \
Packit dd8086
        "/basefontdict basefontname findfont def\n"             \
Packit dd8086
        "/newfont basefontdict maxlength dict def\n"            \
Packit dd8086
        "basefontdict { exch dup /FID ne { dup /Encoding eq\n"  \
Packit dd8086
        "{ exch dup length array copy newfont 3 1 roll put }\n" \
Packit dd8086
        "{ exch newfont 3 1 roll put }\n"                       \
Packit dd8086
        "ifelse }\n"                                            \
Packit dd8086
        "{ pop pop }\n"                                         \
Packit dd8086
        "ifelse } forall\n"                                     \
Packit dd8086
        "newfont /FontName newfontname put\n"                   \
Packit dd8086
        "newcodesandnames aload pop newcodesandnames length 2 idiv\n"   \
Packit dd8086
        "{ newfont /Encoding get 3 1 roll put } repeat\n"       \
Packit dd8086
        "newfontname newfont definefont pop end } def\n"        \
Packit dd8086
        "/charvec [\n"          \
Packit dd8086
        "026 /Scaron\n"         \
Packit dd8086
        "027 /Ydieresis\n"      \
Packit dd8086
        "028 /Zcaron\n"         \
Packit dd8086
        "029 /scaron\n"         \
Packit dd8086
        "030 /trademark\n"      \
Packit dd8086
        "031 /zcaron\n"         \
Packit dd8086
        "032 /space\n"          \
Packit dd8086
        "033 /exclam\n"         \
Packit dd8086
        "034 /quotedbl\n"       \
Packit dd8086
        "035 /numbersign\n"     \
Packit dd8086
        "036 /dollar\n"         \
Packit dd8086
        "037 /percent\n"        \
Packit dd8086
        "038 /ampersand\n"      \
Packit dd8086
        "039 /quoteright\n"     \
Packit dd8086
        "040 /parenleft\n"      \
Packit dd8086
        "041 /parenright\n"     \
Packit dd8086
        "042 /asterisk\n"       \
Packit dd8086
        "043 /plus\n"           \
Packit dd8086
        "044 /comma\n"          \
Packit dd8086
        "045 /minus\n"          \
Packit dd8086
        "046 /period\n"         \
Packit dd8086
        "047 /slash\n"          \
Packit dd8086
        "048 /zero\n"           \
Packit dd8086
        "049 /one\n"            \
Packit dd8086
        "050 /two\n"            \
Packit dd8086
        "051 /three\n"          \
Packit dd8086
        "052 /four\n"           \
Packit dd8086
        "053 /five\n"           \
Packit dd8086
        "054 /six\n"            \
Packit dd8086
        "055 /seven\n"          \
Packit dd8086
        "056 /eight\n"          \
Packit dd8086
        "057 /nine\n"           \
Packit dd8086
        "058 /colon\n"          \
Packit dd8086
        "059 /semicolon\n"      \
Packit dd8086
        "060 /less\n"           \
Packit dd8086
        "061 /equal\n"          \
Packit dd8086
        "062 /greater\n"        \
Packit dd8086
        "063 /question\n"       \
Packit dd8086
        "064 /at\n"             \
Packit dd8086
        "065 /A\n"              \
Packit dd8086
        "066 /B\n"              \
Packit dd8086
        "067 /C\n"              \
Packit dd8086
        "068 /D\n"              \
Packit dd8086
        "069 /E\n"              \
Packit dd8086
        "070 /F\n"              \
Packit dd8086
        "071 /G\n"              \
Packit dd8086
        "072 /H\n"              \
Packit dd8086
        "073 /I\n"              \
Packit dd8086
        "074 /J\n"              \
Packit dd8086
        "075 /K\n"              \
Packit dd8086
        "076 /L\n"              \
Packit dd8086
        "077 /M\n"              \
Packit dd8086
        "078 /N\n"              \
Packit dd8086
        "079 /O\n"              \
Packit dd8086
        "080 /P\n"              \
Packit dd8086
        "081 /Q\n"              \
Packit dd8086
        "082 /R\n"              \
Packit dd8086
        "083 /S\n"              \
Packit dd8086
        "084 /T\n"              \
Packit dd8086
        "085 /U\n"              \
Packit dd8086
        "086 /V\n"              \
Packit dd8086
        "087 /W\n"              \
Packit dd8086
        "088 /X\n"              \
Packit dd8086
        "089 /Y\n"              \
Packit dd8086
        "090 /Z\n"              \
Packit dd8086
        "091 /bracketleft\n"    \
Packit dd8086
        "092 /backslash\n"      \
Packit dd8086
        "093 /bracketright\n"   \
Packit dd8086
        "094 /asciicircum\n"    \
Packit dd8086
        "095 /underscore\n"     \
Packit dd8086
        "096 /quoteleft\n"      \
Packit dd8086
        "097 /a\n"              \
Packit dd8086
        "098 /b\n"              \
Packit dd8086
        "099 /c\n"              \
Packit dd8086
        "100 /d\n"              \
Packit dd8086
        "101 /e\n"              \
Packit dd8086
        "102 /f\n"              \
Packit dd8086
        "103 /g\n"              \
Packit dd8086
        "104 /h\n"              \
Packit dd8086
        "105 /i\n"              \
Packit dd8086
        "106 /j\n"              \
Packit dd8086
        "107 /k\n"              \
Packit dd8086
        "108 /l\n"              \
Packit dd8086
        "109 /m\n"              \
Packit dd8086
        "110 /n\n"              \
Packit dd8086
        "111 /o\n"              \
Packit dd8086
        "112 /p\n"              \
Packit dd8086
        "113 /q\n"              \
Packit dd8086
        "114 /r\n"              \
Packit dd8086
        "115 /s\n"              \
Packit dd8086
        "116 /t\n"              \
Packit dd8086
        "117 /u\n"              \
Packit dd8086
        "118 /v\n"              \
Packit dd8086
        "119 /w\n"              \
Packit dd8086
        "120 /x\n"              \
Packit dd8086
        "121 /y\n"              \
Packit dd8086
        "122 /z\n"              \
Packit dd8086
        "123 /braceleft\n"      \
Packit dd8086
        "124 /bar\n"            \
Packit dd8086
        "125 /braceright\n"     \
Packit dd8086
        "126 /asciitilde\n"     \
Packit dd8086
        "127 /.notdef\n"        \
Packit dd8086
        "128 /fraction\n"       \
Packit dd8086
        "129 /florin\n"         \
Packit dd8086
        "130 /quotesingle\n"    \
Packit dd8086
        "131 /quotedblleft\n"   \
Packit dd8086
        "132 /guilsinglleft\n"  \
Packit dd8086
        "133 /guilsinglright\n" \
Packit dd8086
        "134 /fi\n"             \
Packit dd8086
        "135 /fl\n"             \
Packit dd8086
        "136 /endash\n"         \
Packit dd8086
        "137 /dagger\n"         \
Packit dd8086
        "138 /daggerdbl\n"      \
Packit dd8086
        "139 /bullet\n"         \
Packit dd8086
        "140 /quotesinglbase\n" \
Packit dd8086
        "141 /quotedblbase\n"   \
Packit dd8086
        "142 /quotedblright\n"  \
Packit dd8086
        "143 /ellipsis\n"       \
Packit dd8086
        "144 /dotlessi\n"       \
Packit dd8086
        "145 /grave\n"          \
Packit dd8086
        "146 /acute\n"          \
Packit dd8086
        "147 /circumflex\n"     \
Packit dd8086
        "148 /tilde\n"          \
Packit dd8086
        "149 /oe\n"             \
Packit dd8086
        "150 /breve\n"          \
Packit dd8086
        "151 /dotaccent\n"      \
Packit dd8086
        "152 /perthousand\n"    \
Packit dd8086
        "153 /emdash\n"         \
Packit dd8086
        "154 /ring\n"           \
Packit dd8086
        "155 /Lslash\n"         \
Packit dd8086
        "156 /OE\n"             \
Packit dd8086
        "157 /hungarumlaut\n"   \
Packit dd8086
        "158 /ogonek\n"         \
Packit dd8086
        "159 /caron\n"          \
Packit dd8086
        "160 /lslash\n"         \
Packit dd8086
        "161 /exclamdown\n"     \
Packit dd8086
        "162 /cent\n"           \
Packit dd8086
        "163 /sterling\n"       \
Packit dd8086
        "164 /currency\n"       \
Packit dd8086
        "165 /yen\n"            \
Packit dd8086
        "166 /brokenbar\n"      \
Packit dd8086
        "167 /section\n"        \
Packit dd8086
        "168 /dieresis\n"       \
Packit dd8086
        "169 /copyright\n"      \
Packit dd8086
        "170 /ordfeminine\n"    \
Packit dd8086
        "171 /guillemotleft\n"  \
Packit dd8086
        "172 /logicalnot\n"     \
Packit dd8086
        "173 /hyphen\n"         \
Packit dd8086
        "174 /registered\n"     \
Packit dd8086
        "175 /macron\n"         \
Packit dd8086
        "176 /degree\n"         \
Packit dd8086
        "177 /plusminus\n"      \
Packit dd8086
        "178 /twosuperior\n"    \
Packit dd8086
        "179 /threesuperior\n"  \
Packit dd8086
        "180 /acute\n"          \
Packit dd8086
        "181 /mu\n"             \
Packit dd8086
        "182 /paragraph\n"      \
Packit dd8086
        "183 /periodcentered\n" \
Packit dd8086
        "184 /cedilla\n"        \
Packit dd8086
        "185 /onesuperior\n"    \
Packit dd8086
        "186 /ordmasculine\n"   \
Packit dd8086
        "187 /guillemotright\n" \
Packit dd8086
        "188 /onequarter\n"     \
Packit dd8086
        "189 /onehalf\n"        \
Packit dd8086
        "190 /threequarters\n"  \
Packit dd8086
        "191 /questiondown\n"   \
Packit dd8086
        "192 /Agrave\n"         \
Packit dd8086
        "193 /Aacute\n"         \
Packit dd8086
        "194 /Acircumflex\n"    \
Packit dd8086
        "195 /Atilde\n"         \
Packit dd8086
        "196 /Adieresis\n"      \
Packit dd8086
        "197 /Aring\n"          \
Packit dd8086
        "198 /AE\n"             \
Packit dd8086
        "199 /Ccedilla\n"       \
Packit dd8086
        "200 /Egrave\n"         \
Packit dd8086
        "201 /Eacute\n"         \
Packit dd8086
        "202 /Ecircumflex\n"    \
Packit dd8086
        "203 /Edieresis\n"      \
Packit dd8086
        "204 /Igrave\n"         \
Packit dd8086
        "205 /Iacute\n"         \
Packit dd8086
        "206 /Icircumflex\n"    \
Packit dd8086
        "207 /Idieresis\n"      \
Packit dd8086
        "208 /Eth\n"            \
Packit dd8086
        "209 /Ntilde\n"         \
Packit dd8086
        "210 /Ograve\n"         \
Packit dd8086
        "211 /Oacute\n"         \
Packit dd8086
        "212 /Ocircumflex\n"    \
Packit dd8086
        "213 /Otilde\n"         \
Packit dd8086
        "214 /Odieresis\n"      \
Packit dd8086
        "215 /multiply\n"       \
Packit dd8086
        "216 /Oslash\n"         \
Packit dd8086
        "217 /Ugrave\n"         \
Packit dd8086
        "218 /Uacute\n"         \
Packit dd8086
        "219 /Ucircumflex\n"    \
Packit dd8086
        "220 /Udieresis\n"      \
Packit dd8086
        "221 /Yacute\n"         \
Packit dd8086
        "222 /Thorn\n"          \
Packit dd8086
        "223 /germandbls\n"     \
Packit dd8086
        "224 /agrave\n"         \
Packit dd8086
        "225 /aacute\n"         \
Packit dd8086
        "226 /acircumflex\n"    \
Packit dd8086
        "227 /atilde\n"         \
Packit dd8086
        "228 /adieresis\n"      \
Packit dd8086
        "229 /aring\n"          \
Packit dd8086
        "230 /ae\n"             \
Packit dd8086
        "231 /ccedilla\n"       \
Packit dd8086
        "232 /egrave\n"         \
Packit dd8086
        "233 /eacute\n"         \
Packit dd8086
        "234 /ecircumflex\n"    \
Packit dd8086
        "235 /edieresis\n"      \
Packit dd8086
        "236 /igrave\n"         \
Packit dd8086
        "237 /iacute\n"         \
Packit dd8086
        "238 /icircumflex\n"    \
Packit dd8086
        "239 /idieresis\n"      \
Packit dd8086
        "240 /eth\n"            \
Packit dd8086
        "241 /ntilde\n"         \
Packit dd8086
        "242 /ograve\n"         \
Packit dd8086
        "243 /oacute\n"         \
Packit dd8086
        "244 /ocircumflex\n"    \
Packit dd8086
        "245 /otilde\n"         \
Packit dd8086
        "246 /odieresis\n"      \
Packit dd8086
        "247 /divide\n"         \
Packit dd8086
        "248 /oslash\n"         \
Packit dd8086
        "249 /ugrave\n"         \
Packit dd8086
        "250 /uacute\n"         \
Packit dd8086
        "251 /ucircumflex\n"    \
Packit dd8086
        "252 /udieresis\n"      \
Packit dd8086
        "253 /yacute\n"         \
Packit dd8086
        "254 /thorn\n"          \
Packit dd8086
        "255 /ydieresis\n"      \
Packit dd8086
        "] def"
Packit dd8086
Packit dd8086
Packit dd8086
static void
Packit dd8086
ps_list_tracks(void)
Packit dd8086
{
Packit dd8086
  int i,s,y,sy;
Packit dd8086
Packit dd8086
  if (!b_record) return;
Packit dd8086
Packit dd8086
  printf("%%!PS-Adobe-2.0\n");
Packit dd8086
Packit dd8086
  /* encoding tricks */
Packit dd8086
  puts(ENCODING_TRICKS);
Packit dd8086
  printf("/Times /TimesLatin1 charvec ReEncodeSmall\n");
Packit dd8086
  printf("/Helvetica /HelveticaLatin1 charvec ReEncodeSmall\n");
Packit dd8086
Packit dd8086
  /* Spaces */
Packit dd8086
  printf("0 setlinewidth\n");
Packit dd8086
  printf(" 100 100 moveto\n");
Packit dd8086
  printf(" 390   0 rlineto\n");
Packit dd8086
  printf("   0 330 rlineto\n");
Packit dd8086
  printf("-390   0 rlineto\n");
Packit dd8086
  printf("closepath stroke\n");
Packit dd8086
Packit dd8086
  printf(" 100 100 moveto\n");
Packit dd8086
  printf("-16    0 rlineto\n");
Packit dd8086
  printf("  0  330 rlineto\n");
Packit dd8086
  printf("422    0 rlineto\n");
Packit dd8086
  printf("  0 -330 rlineto\n");
Packit dd8086
  printf("closepath stroke\n");
Packit dd8086
Packit dd8086
  /* Title */
Packit dd8086
  printf("/TimesLatin1 findfont 24 scalefont setfont\n");
Packit dd8086
  printf("120 400 moveto (%s) show\n", title);
Packit dd8086
  printf("/TimesLatin1 findfont 18 scalefont setfont\n");
Packit dd8086
  printf("120 375 moveto (%s) show\n", artist);
Packit dd8086
Packit dd8086
  /* List */
Packit dd8086
  sy = 250 / i_last_track;
Packit dd8086
  if (sy > 14) sy = 14;
Packit dd8086
  printf("/labelfont /TimesLatin1 findfont %d scalefont def\n",sy-2);
Packit dd8086
  printf("/timefont /Courier findfont %d scalefont def\n",sy-2);
Packit dd8086
  y = 350;
Packit dd8086
  for (i = i_first_track_global; i <= i_last_track; i++, y -= sy) {
Packit dd8086
    s = cdio_audio_get_msf_seconds(&toc[i+1])
Packit dd8086
      - cdio_audio_get_msf_seconds(&toc[i]);
Packit dd8086
Packit dd8086
    printf("labelfont setfont\n");
Packit dd8086
    printf("120 %d moveto (%d) show\n", y, i);
Packit dd8086
    {
Packit dd8086
      char line[200]="";
Packit dd8086
      if ( strlen(cd_info[i].title) )
Packit dd8086
        strcat(line, cd_info[i].title);
Packit dd8086
      if ( strlen(cd_info[i].artist) > 0 ) {
Packit dd8086
        if (strlen(cd_info[i].title))
Packit dd8086
          strcat(line, " / ");
Packit dd8086
        strcat(line, cd_info[i].artist);
Packit dd8086
      }
Packit dd8086
      printf("150 %d moveto (%s) show\n", y, line);
Packit dd8086
    }
Packit dd8086
    printf("timefont setfont\n");
Packit dd8086
    printf("420 %d moveto (%2d:%02d) show\n", y,
Packit dd8086
           s / CDIO_CD_SECS_PER_MIN, s % CDIO_CD_SECS_PER_MIN);
Packit dd8086
  }
Packit dd8086
Packit dd8086
  /* Seitenbanner */
Packit dd8086
  printf("/HelveticaLatin1 findfont 12 scalefont setfont\n");
Packit dd8086
  printf(" 97 105 moveto (%s: %s) 90 rotate show -90 rotate\n",
Packit dd8086
         artist, title);
Packit dd8086
  printf("493 425 moveto (%s: %s) -90 rotate show 90 rotate\n",
Packit dd8086
         artist, title);
Packit dd8086
  printf("showpage\n");
Packit dd8086
}
Packit dd8086
Packit dd8086
static void
Packit dd8086
list_tracks(void)
Packit dd8086
{
Packit dd8086
  int i,s;
Packit dd8086
Packit dd8086
  if (!b_record) return;
Packit dd8086
Packit dd8086
  printf("Title : %s\n", title);
Packit dd8086
  printf("Artist: %s\n", artist);
Packit dd8086
Packit dd8086
  for (i = i_first_track_global; i <= i_last_track; i++) {
Packit dd8086
    s = cdio_audio_get_msf_seconds(&toc[i+1])
Packit dd8086
      - cdio_audio_get_msf_seconds(&toc[i]);
Packit dd8086
    printf("%2d: %s [%d seconds]\n", i, cd_info[i].title, s);
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
typedef enum {
Packit dd8086
  NO_OP=0,
Packit dd8086
  PLAY_CD=1,
Packit dd8086
  PLAY_TRACK=2,
Packit dd8086
  STOP_PLAYING=3,
Packit dd8086
  EJECT_CD=4,
Packit dd8086
  CLOSE_CD=5,
Packit dd8086
  SET_VOLUME=6,
Packit dd8086
  LIST_SUBCHANNEL=7,
Packit dd8086
  LIST_KEYS=8,
Packit dd8086
  LIST_TRACKS=9,
Packit dd8086
  PS_LIST_TRACKS=10,
Packit dd8086
  TOGGLE_PAUSE=11,
Packit dd8086
  EXIT_PROGRAM=12
Packit dd8086
} cd_operation_t;
Packit dd8086
Packit dd8086
int
Packit dd8086
main(int argc, char *argv[])
Packit dd8086
{
Packit dd8086
  int  c, nostop=0;
Packit dd8086
  char *h;
Packit dd8086
  int  i_rc = 0;
Packit dd8086
  cd_operation_t cd_op = NO_OP; /* operation to do in non-interactive mode */
Packit dd8086
Packit dd8086
Packit dd8086
  psz_program = strrchr(argv[0],'/');
Packit dd8086
  psz_program = psz_program ? psz_program+1 : argv[0];
Packit dd8086
Packit dd8086
  memset(&cddb_opts, 0, sizeof(cddb_opts));
Packit dd8086
Packit dd8086
  cdio_loglevel_default = CDIO_LOG_WARN;
Packit dd8086
  /* parse options */
Packit dd8086
  while ( 1 ) {
Packit dd8086
    if (-1 == (c = getopt(argc, argv, "acCdehkplL:sSt:vx")))
Packit dd8086
      break;
Packit dd8086
    switch (c) {
Packit dd8086
    case 'v':
Packit dd8086
      b_verbose = true;
Packit dd8086
      if (cdio_loglevel_default > CDIO_LOG_INFO)
Packit dd8086
        cdio_loglevel_default = CDIO_LOG_INFO;
Packit dd8086
      break;
Packit dd8086
    case 'd':
Packit dd8086
      debug = 1;
Packit dd8086
      if (cdio_loglevel_default > CDIO_LOG_DEBUG)
Packit dd8086
      cdio_loglevel_default = CDIO_LOG_DEBUG;
Packit dd8086
      break;
Packit dd8086
    case 'a':
Packit dd8086
      auto_mode = 1;
Packit dd8086
      break;
Packit dd8086
Packit dd8086
    case 'L':
Packit dd8086
      i_volume_level = atoi(optarg);
Packit dd8086
      cd_op = SET_VOLUME;
Packit dd8086
      b_interactive = false;
Packit dd8086
      break;
Packit dd8086
Packit dd8086
    case 't':
Packit dd8086
      if (NULL != (h = strchr(optarg,'-'))) {
Packit dd8086
        *h = 0;
Packit dd8086
        start_track = atoi(optarg);
Packit dd8086
        stop_track = atoi(h+1)+1;
Packit dd8086
        if (0 == start_track) start_track = 1;
Packit dd8086
        if (1 == stop_track)  stop_track  = CDIO_CDROM_LEADOUT_TRACK;
Packit dd8086
      } else {
Packit dd8086
        start_track = atoi(optarg);
Packit dd8086
        stop_track = start_track+1;
Packit dd8086
        one_track = 1;
Packit dd8086
      }
Packit dd8086
      b_interactive = false;
Packit dd8086
      cd_op = PLAY_TRACK;
Packit dd8086
      break;
Packit dd8086
    case 'p':
Packit dd8086
      b_interactive = false;
Packit dd8086
      cd_op = PLAY_CD;
Packit dd8086
      break;
Packit dd8086
    case 'l':
Packit dd8086
      b_interactive = false;
Packit dd8086
      cd_op = LIST_TRACKS;
Packit dd8086
      break;
Packit dd8086
    case 'C':
Packit dd8086
      b_interactive = false;
Packit dd8086
      cd_op = CLOSE_CD;
Packit dd8086
      break;
Packit dd8086
    case 'c':
Packit dd8086
      b_interactive = false;
Packit dd8086
      cd_op = PS_LIST_TRACKS;
Packit dd8086
      break;
Packit dd8086
    case 's':
Packit dd8086
      b_interactive = false;
Packit dd8086
      cd_op = STOP_PLAYING;
Packit dd8086
      break;
Packit dd8086
    case 'S':
Packit dd8086
      b_interactive = false;
Packit dd8086
      cd_op = LIST_SUBCHANNEL;
Packit dd8086
      break;
Packit dd8086
    case 'e':
Packit dd8086
      b_interactive = false;
Packit dd8086
      cd_op = EJECT_CD;
Packit dd8086
      break;
Packit dd8086
    case 'k':
Packit dd8086
      print_keys();
Packit dd8086
      exit(1);
Packit dd8086
    case 'h':
Packit dd8086
      usage(psz_program);
Packit dd8086
      exit(1);
Packit dd8086
    default:
Packit dd8086
      usage(psz_program);
Packit dd8086
      exit(1);
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
Packit dd8086
  if (argc > optind) {
Packit dd8086
    psz_device_global = strdup(argv[optind]);
Packit dd8086
  } else {
Packit dd8086
    char **ppsz_cdda_drives=NULL;
Packit dd8086
    char **ppsz_all_cd_drives = cdio_get_devices_ret(&driver_id);
Packit dd8086
Packit dd8086
    if (!ppsz_all_cd_drives) {
Packit dd8086
      fprintf(stderr, "Can't find a CD-ROM drive\n");
Packit dd8086
      exit(2);
Packit dd8086
    }
Packit dd8086
    ppsz_cdda_drives = cdio_get_devices_with_cap(ppsz_all_cd_drives,
Packit dd8086
                                                 CDIO_FS_AUDIO, false);
Packit dd8086
    if (!ppsz_cdda_drives || !ppsz_cdda_drives[0]) {
Packit dd8086
      fprintf(stderr, "Can't find a CD-ROM drive with a CD-DA in it\n");
Packit dd8086
      cdio_free_device_list(ppsz_all_cd_drives);
Packit dd8086
      exit(3);
Packit dd8086
    }
Packit dd8086
    psz_device_global = strdup(ppsz_cdda_drives[0]);
Packit dd8086
    cdio_free_device_list(ppsz_all_cd_drives);
Packit dd8086
    cdio_free_device_list(ppsz_cdda_drives);
Packit dd8086
  }
Packit dd8086
Packit dd8086
  if (!b_interactive) {
Packit dd8086
    b_sig = true;
Packit dd8086
    nostop=1;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  tty_raw();
Packit dd8086
  signal(SIGINT,ctrlc);
Packit dd8086
  signal(SIGQUIT,ctrlc);
Packit dd8086
  signal(SIGTERM,ctrlc);
Packit dd8086
  signal(SIGHUP,ctrlc);
Packit dd8086
  signal(SIGWINCH, sigwinch);
Packit dd8086
Packit dd8086
  if (CLOSE_CD != cd_op) {
Packit dd8086
    /* open device */
Packit dd8086
    if (b_verbose)
Packit dd8086
      fprintf(stderr, "open %s... ", psz_device_global);
Packit dd8086
    p_cdio_global = cdio_open (psz_device_global, driver_id);
Packit dd8086
    if (!p_cdio_global && cd_op != EJECT_CD) {
Packit dd8086
      cd_close(psz_device_global);
Packit dd8086
      p_cdio_global = cdio_open (psz_device_global, driver_id);
Packit dd8086
    }
Packit dd8086
Packit dd8086
    if (p_cdio_global && b_verbose)
Packit dd8086
      fprintf(stderr,"ok\n");
Packit dd8086
  }
Packit dd8086
Packit dd8086
  if (b_interactive) {
Packit dd8086
#ifdef HAVE_CDDB
Packit dd8086
    cddb_log_set_handler (cddb_log_handler);
Packit dd8086
#else
Packit dd8086
    ;
Packit dd8086
#endif
Packit dd8086
  }  else {
Packit dd8086
    b_sig = true;
Packit dd8086
    nostop=1;
Packit dd8086
    if (EJECT_CD == cd_op) {
Packit dd8086
      i_rc = cd_eject() ? 0 : 1;
Packit dd8086
    } else {
Packit dd8086
      switch (cd_op) {
Packit dd8086
      case PS_LIST_TRACKS:
Packit dd8086
      case LIST_TRACKS:
Packit dd8086
      case PLAY_TRACK:
Packit dd8086
        read_toc(p_cdio_global);
Packit dd8086
      default:
Packit dd8086
        break;
Packit dd8086
      }
Packit dd8086
      if (p_cdio_global)
Packit dd8086
        switch (cd_op) {
Packit dd8086
        case STOP_PLAYING:
Packit dd8086
          b_cd = true;
Packit dd8086
          i_rc = cd_stop(p_cdio_global) ? 0 : 1;
Packit dd8086
          break;
Packit dd8086
        case EJECT_CD:
Packit dd8086
          /* Should have been handled above. */
Packit dd8086
          cd_eject();
Packit dd8086
          break;
Packit dd8086
        case LIST_TRACKS:
Packit dd8086
          list_tracks();
Packit dd8086
          break;
Packit dd8086
        case PS_LIST_TRACKS:
Packit dd8086
          ps_list_tracks();
Packit dd8086
          break;
Packit dd8086
Packit dd8086
        case PLAY_TRACK:
Packit dd8086
          /* play just this one track */
Packit dd8086
          if (b_record) {
Packit dd8086
            printf("%s / %s\n", artist, title);
Packit dd8086
            if (one_track)
Packit dd8086
              printf("%s\n", cd_info[start_track].title);
Packit dd8086
          }
Packit dd8086
          i_rc = play_track(start_track, stop_track) ? 0 : 1;
Packit dd8086
          break;
Packit dd8086
Packit dd8086
        case PLAY_CD:
Packit dd8086
          if (b_record)
Packit dd8086
            printf("%s / %s\n", artist, title);
Packit dd8086
          play_track(1,CDIO_CDROM_LEADOUT_TRACK);
Packit dd8086
          break;
Packit dd8086
Packit dd8086
        case SET_VOLUME:
Packit dd8086
          i_rc = set_volume_level(p_cdio_global, i_volume_level);
Packit dd8086
          break;
Packit dd8086
Packit dd8086
        case LIST_SUBCHANNEL:
Packit dd8086
          if (read_subchannel(p_cdio_global)) {
Packit dd8086
            if (sub.audio_status == CDIO_MMC_READ_SUB_ST_PAUSED ||
Packit dd8086
                sub.audio_status == CDIO_MMC_READ_SUB_ST_PLAY) {
Packit dd8086
              {
Packit dd8086
                printf("track %2d - %02x:%02x (%02x:%02x abs) ",
Packit dd8086
                       sub.track, sub.rel_addr.m, sub.rel_addr.s,
Packit dd8086
                       sub.abs_addr.m, sub.abs_addr.s);
Packit dd8086
              }
Packit dd8086
            }
Packit dd8086
            printf("drive state: %s\n",
Packit dd8086
                   mmc_audio_state2str(sub.audio_status));
Packit dd8086
          } else {
Packit dd8086
            i_rc = 1;
Packit dd8086
          }
Packit dd8086
          break;
Packit dd8086
        case CLOSE_CD: /* Handled below */
Packit dd8086
        case LIST_KEYS:
Packit dd8086
        case TOGGLE_PAUSE:
Packit dd8086
        case EXIT_PROGRAM:
Packit dd8086
        case NO_OP:
Packit dd8086
          break;
Packit dd8086
        }
Packit dd8086
      else if (CLOSE_CD == cd_op) {
Packit dd8086
        i_rc = (DRIVER_OP_SUCCESS == cdio_close_tray(psz_device_global, NULL))
Packit dd8086
                ? 0 : 1;
Packit dd8086
      } else {
Packit dd8086
        fprintf(stderr,"no CD in drive (%s)\n", psz_device_global);
Packit dd8086
      }
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
Packit dd8086
  /* Play all tracks *unless* we have a play or paused status
Packit dd8086
     already. */
Packit dd8086
Packit dd8086
  read_subchannel(p_cdio_global);
Packit dd8086
  if (sub.audio_status != CDIO_MMC_READ_SUB_ST_PAUSED &&
Packit dd8086
      sub.audio_status != CDIO_MMC_READ_SUB_ST_PLAY)
Packit dd8086
    play_track(1, CDIO_CDROM_LEADOUT_TRACK);
Packit dd8086
Packit dd8086
  while ( !b_sig ) {
Packit dd8086
    int key;
Packit dd8086
    if (!b_cd) read_toc(p_cdio_global);
Packit dd8086
    read_subchannel(p_cdio_global);
Packit dd8086
    display_status(false);
Packit dd8086
Packit dd8086
    if (1 == select_wait(b_cd ? 1 : 5)) {
Packit dd8086
      switch (key = getch()) {
Packit dd8086
      case '-':
Packit dd8086
        decrease_volume_level(p_cdio_global);
Packit dd8086
        break;
Packit dd8086
      case '+':
Packit dd8086
        increase_volume_level(p_cdio_global);
Packit dd8086
        break;
Packit dd8086
      case 'A':
Packit dd8086
      case 'a':
Packit dd8086
        auto_mode = !auto_mode;
Packit dd8086
        break;
Packit dd8086
      case 'X':
Packit dd8086
      case 'x':
Packit dd8086
        nostop=1;
Packit dd8086
        /* fall through */
Packit dd8086
      case 'Q':
Packit dd8086
      case 'q':
Packit dd8086
        b_sig = true;
Packit dd8086
        break;
Packit dd8086
      case 'E':
Packit dd8086
      case 'e':
Packit dd8086
        cd_eject();
Packit dd8086
        break;
Packit dd8086
      case 's':
Packit dd8086
        cd_stop(p_cdio_global);
Packit dd8086
        break;
Packit dd8086
      case 'C':
Packit dd8086
      case 'c':
Packit dd8086
        cd_close(psz_device_global);
Packit dd8086
        break;
Packit dd8086
      case 'L':
Packit dd8086
      case 'l':
Packit dd8086
        b_all_tracks = !b_all_tracks;
Packit dd8086
        if (b_all_tracks)
Packit dd8086
          display_tracks();
Packit dd8086
        else {
Packit dd8086
          i_last_display_track = CDIO_INVALID_TRACK;
Packit dd8086
          display_cdinfo(p_cdio_global, i_tracks_global, i_first_track_global);
Packit dd8086
        }
Packit dd8086
Packit dd8086
        break;
Packit dd8086
      case 'K':
Packit dd8086
      case 'k':
Packit dd8086
      case 'h':
Packit dd8086
      case 'H':
Packit dd8086
      case '?':
Packit dd8086
        list_keys();
Packit dd8086
        break;
Packit dd8086
      case ' ':
Packit dd8086
      case 'P':
Packit dd8086
      case 'p':
Packit dd8086
        toggle_pause();
Packit dd8086
        break;
Packit dd8086
      case KEY_RIGHT:
Packit dd8086
        if (b_cd &&
Packit dd8086
            (sub.audio_status == CDIO_MMC_READ_SUB_ST_PAUSED ||
Packit dd8086
             sub.audio_status == CDIO_MMC_READ_SUB_ST_PLAY))
Packit dd8086
          play_track(sub.track+1, CDIO_CDROM_LEADOUT_TRACK);
Packit dd8086
        else
Packit dd8086
          play_track(1,CDIO_CDROM_LEADOUT_TRACK);
Packit dd8086
        break;
Packit dd8086
      case KEY_LEFT:
Packit dd8086
        if (b_cd &&
Packit dd8086
            (sub.audio_status == CDIO_MMC_READ_SUB_ST_PAUSED ||
Packit dd8086
             sub.audio_status == CDIO_MMC_READ_SUB_ST_PLAY))
Packit dd8086
          play_track(sub.track-1,CDIO_CDROM_LEADOUT_TRACK);
Packit dd8086
        break;
Packit dd8086
      case KEY_UP:
Packit dd8086
        if (b_cd && sub.audio_status == CDIO_MMC_READ_SUB_ST_PLAY)
Packit dd8086
          skip(10);
Packit dd8086
        break;
Packit dd8086
      case KEY_DOWN:
Packit dd8086
        if (b_cd && sub.audio_status == CDIO_MMC_READ_SUB_ST_PLAY)
Packit dd8086
          skip(-10);
Packit dd8086
        break;
Packit dd8086
      case '1':
Packit dd8086
      case '2':
Packit dd8086
      case '3':
Packit dd8086
      case '4':
Packit dd8086
      case '5':
Packit dd8086
      case '6':
Packit dd8086
      case '7':
Packit dd8086
      case '8':
Packit dd8086
      case '9':
Packit dd8086
        play_track(key - '0', CDIO_CDROM_LEADOUT_TRACK);
Packit dd8086
        break;
Packit dd8086
      case '0':
Packit dd8086
        play_track(10, CDIO_CDROM_LEADOUT_TRACK);
Packit dd8086
        break;
Packit dd8086
      case KEY_F(1):
Packit dd8086
      case KEY_F(2):
Packit dd8086
      case KEY_F(3):
Packit dd8086
      case KEY_F(4):
Packit dd8086
      case KEY_F(5):
Packit dd8086
      case KEY_F(6):
Packit dd8086
      case KEY_F(7):
Packit dd8086
      case KEY_F(8):
Packit dd8086
      case KEY_F(9):
Packit dd8086
      case KEY_F(10):
Packit dd8086
      case KEY_F(11):
Packit dd8086
      case KEY_F(12):
Packit dd8086
      case KEY_F(13):
Packit dd8086
      case KEY_F(14):
Packit dd8086
      case KEY_F(15):
Packit dd8086
      case KEY_F(16):
Packit dd8086
      case KEY_F(17):
Packit dd8086
      case KEY_F(18):
Packit dd8086
      case KEY_F(19):
Packit dd8086
      case KEY_F(20):
Packit dd8086
        play_track(key - KEY_F(1) + 11, CDIO_CDROM_LEADOUT_TRACK);
Packit dd8086
        break;
Packit dd8086
      }
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
  if (!nostop) cd_stop(p_cdio_global);
Packit dd8086
  tty_restore();
Packit dd8086
  finish("bye", i_rc);
Packit dd8086
Packit dd8086
  return 0; /* keep compiler happy */
Packit dd8086
}