libcdio  2.1.0
About: GNU libcdio is a library for CD-ROM and CD image access.
  Fossies Dox: libcdio-2.1.0.tar.bz2  ("inofficial" and yet experimental doxygen-generated source code documentation)  

cdda-player.c
Go to the documentation of this file.
1 /*
2  Copyright (C) 2005-2012, 2017, 2019
3  Rocky Bernstein <rocky@gnu.org>
4 
5  Adapted from Gerd Knorr's player.c program <kraxel@bytesex.org>
6  Copyright (C) 1997, 1998
7 
8  This program is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 # define __CDIO_CONFIG_H__ 1
25 #endif
26 
27 #ifdef HAVE_STDIO_H
28 #include <stdio.h>
29 #endif
30 
31 #ifdef HAVE_STDLIB_H
32 #include <stdlib.h>
33 #endif
34 
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38 
39 #ifdef HAVE_STRING_H
40 #include <string.h>
41 #endif
42 
43 #ifdef HAVE_SYS_TIME_H
44 #include <sys/time.h>
45 #endif
46 
47 #ifdef HAVE_CDDB
48 #include <cddb/cddb.h>
49 #endif
50 
51 #include <signal.h>
52 
53 #ifdef HAVE_ERRNO_H
54 #include <errno.h>
55 #endif
56 
57 #ifdef HAVE_CURSES_H
58 # include <curses.h>
59 #else
60 # ifdef HAVE_NCURSES_H
61 #include <ncurses.h>
62 # else
63 # ifdef HAVE_NCURSES_NCURSES_H
64 # include <ncurses/ncurses.h>
65 # else
66 # error "You need <curses.h> or <ncurses.h to build cdda-player"
67 # endif
68 # endif
69 #endif
70 
71 #include <term.h>
72 extern TERMINAL *cur_term;
73 
74 #include <cdio/cdio.h>
75 #include <cdio/mmc.h>
76 #include <cdio/util.h>
77 #include <cdio/cd_types.h>
78 #include <cdio/logging.h>
79 
80 #include "cddb.h"
81 #include "getopt.h"
82 
83 static WINDOW * cur_window = NULL;
84 static void action(const char *psz_action);
85 static void display_cdinfo(CdIo_t *p_cdio, track_t i_tracks,
86  track_t i_first_track);
87 static void display_tracks(void);
88 static void get_cddb_track_info(track_t i_track);
89 static void get_cdtext_track_info(track_t i_track);
90 static void get_track_info(track_t i_track);
91 static bool play_track(track_t t1, track_t t2);
92 
93 static CdIo_t *p_cdio_global; /* libcdio handle */
95 static int b_sig = false; /* set on some signals */
96 
97 /* cdrom data */
105 static cdio_subchannel_t sub; /* subchannel last time read */
106 static int i_data; /* # of data tracks present ? */
107 static int start_track = 0;
108 static int stop_track = 0;
109 static int one_track = 0;
110 static int i_vol_port = 5; /* If 5, retrieve volume port.
111  Otherwise the port number 0..3
112  of a working volume port and
113  4 for no working port.
114  */
115 
116 /* settings which can be set from the command or interactively. */
117 static bool b_cd = false;
118 static bool auto_mode = false;
119 static bool b_verbose = false;
120 static bool debug = false;
121 static bool b_interactive = true;
122 static bool b_prefer_cdtext = true;
123 #ifdef CDDB_ADDED
124 static bool b_cddb = false; /* CDDB database present */
125 #endif
126 static bool b_db = false; /* we have a database at all */
127 static bool b_record = false; /* we have a record for
128 static the inserted CD */
129 static bool b_all_tracks = false; /* True if we display all tracks*/
130 static int8_t i_volume_level = -1; /* Valid range is 0..100 */
131 
132 
133 static char *psz_device_global=NULL;
134 static char *psz_program;
135 
136 /* Info about songs and titles. The 0 entry will contain the disc info.
137  */
138 typedef struct
139 {
140  char title[80];
141  char artist[80];
142  char length[8];
143  char ext_data[80];
144  bool b_cdtext; /* true if from CD-Text, false if from CDDB */
146 
148 
149 static char title[80];
150 static char artist[80];
151 static char genre[40];
152 static char category[40];
153 static char year[5];
154 
155 static bool b_cdtext_title; /* true if from CD-Text, false if from CDDB */
156 static bool b_cdtext_artist; /* true if from CD-Text, false if from CDDB */
157 static bool b_cdtext_genre; /* true if from CD-Text, false if from CDDB */
158 #ifdef CDTEXT_CATEGORY_ADDED
159 static bool b_cdtext_category; /* true if from CD-Text, false if from CDDB */
160 #endif
161 static bool b_cdtext_year; /* true if from CD-Text, false if from CDDB */
162 
164 
165 #ifdef HAVE_CDDB
166 static cddb_conn_t *p_conn = NULL;
167 static cddb_disc_t *p_cddb_disc = NULL;
168 static int i_cddb_matches = 0;
169 #endif
170 
171 #define MAX_KEY_STR 50
172 static const char key_bindings[][MAX_KEY_STR] = {
173  " right play / next track",
174  " left previous track",
175  " up/down 10 sec forward / back",
176  " 1-9 jump to track 1-9",
177  " 0 jump to track 10",
178  " F1-F20 jump to track 11-30",
179  " ",
180  " k, h, ? show this key help",
181  " l, toggle listing all tracks",
182  " e eject",
183  " c close tray",
184  " p, space pause / resume",
185  " s stop",
186  " q, ^C quit",
187  " x quit and continue playing",
188  " a toggle auto-mode",
189  " - decrease volume level",
190  " + increase volume level",
191 };
192 
193 static const unsigned int i_key_bindings = sizeof(key_bindings) / MAX_KEY_STR;
194 
195 /* ---------------------------------------------------------------------- */
196 /* tty stuff */
197 
198 typedef enum {
201 
206 
211 
212 } track_line_t;
213 
214 static unsigned int LINE_ACTION = 25;
215 static unsigned int COLS_LAST;
216 static char psz_action_line[300] = "";
217 
218 static int rounded_div(unsigned int i_a, unsigned int i_b)
219 {
220  const unsigned int i_b_half=i_b/2;
221  return ((i_a)+i_b_half)/i_b;
222 }
223 
225 static void
226 tty_raw(void)
227 {
228  if (!b_interactive) return;
229  if (!cur_window) cur_window = initscr();
230 
231  cbreak();
232  clear();
233  noecho();
234 #ifdef HAVE_KEYPAD
235  keypad(stdscr,1);
236 #endif
237  getmaxyx(stdscr, LINE_ACTION, COLS_LAST);
238  LINE_ACTION--;
239  refresh();
240 }
241 
243 static void
245 {
246  if (!b_interactive) return;
247  endwin();
248 }
249 
250 #define UNUSED(x) (void)(x)
251 /* Called when window is resized. */
252 static void
253 sigwinch(int dummy)
254 {
255  UNUSED(dummy);
256  tty_restore();
257  tty_raw();
258  action(NULL);
259 }
260 
261 /* Signal handler - Ctrl-C and others. */
262 static void
263 ctrlc(int signal_num)
264 {
265  b_sig = true;
266 }
267 
268 /* Timed wait on an event. */
269 static int
270 select_wait(int sec)
271 {
272  struct timeval tv;
273  fd_set se;
274 
275  FD_ZERO(&se);
276  FD_SET(STDIN_FILENO, &se);
277  tv.tv_sec = sec;
278  tv.tv_usec = 0;
279  return select(1,&se,NULL,NULL,&tv);
280 }
281 
282 /* ---------------------------------------------------------------------- */
283 
284 /* Display the action line. */
285 static void
286 action(const char *psz_action)
287 {
288  if (!b_interactive) {
289  if (b_verbose && psz_action)
290  fprintf(stderr,"action: %s\n", psz_action);
291  return;
292  }
293 
294  if (!psz_action)
295  ;
296  else if (psz_action && strlen(psz_action))
297  snprintf(psz_action_line, sizeof(psz_action_line), "action : %s",
298  psz_action);
299  else
300  snprintf(psz_action_line, sizeof(psz_action_line), "%s", "" );
301  mvprintw(LINE_ACTION, 0, psz_action_line);
302  clrtoeol();
303  refresh();
304 }
305 
306 
307 /* Display an error message.. */
308 static void
309 xperror(const char *psz_msg)
310 {
311  char line[80];
312 
313  if (!b_interactive) {
314  if (b_verbose) {
315  fprintf(stderr, "error: ");
316  perror(psz_msg);
317  }
318  return;
319  }
320 
321  if (b_verbose) {
322  snprintf(line, sizeof(line), "%s: %s", psz_msg, strerror(errno));
323  attron(A_STANDOUT);
324  mvprintw(LINE_ACTION, 0, (char *) "error : %s", line);
325  attroff(A_STANDOUT);
326  clrtoeol();
327  refresh();
328  select_wait(3);
329  action("");
330  }
331 }
332 
333 static void
334 finish(const char *psz_msg, int rc)
335 {
336  if (b_interactive) {
337  attron(A_STANDOUT);
338  mvprintw(LINE_ACTION, 0, (char *) "%s, exiting...\n", psz_msg);
339  attroff(A_STANDOUT);
340  clrtoeol();
341  refresh();
342  }
343  tty_restore();
344  if (cur_term) del_curterm(cur_term);
345  cur_window = NULL;
346 
347 #ifdef HAVE_CDDB
348  if (p_conn) cddb_destroy(p_conn);
349  cddb_disc_destroy(p_cddb_disc);
350  libcddb_shutdown();
351 #endif /*HAVE_CDDB*/
353  free (psz_device_global);
354  exit (rc);
355 }
356 
357 /* ---------------------------------------------------------------------- */
358 
359 /* Set all audio channels to level. level is assumed to be in the range
360  0..100.
361 */
362 static bool
363 set_volume_level(CdIo_t *p_cdio, uint8_t i_level)
364 {
365  const unsigned int i_new_level= rounded_div(i_level*256, 100);
366  unsigned int i;
368  for (i=0; i<=3; i++) {
369  audio_volume.level[i] = i_new_level;
370  }
371 
373  if ( DRIVER_OP_SUCCESS != rc ) {
374  /* If we can't do a get volume, audio_volume.level is used as
375  a second-best guess. But if this set failed restore it to
376  an invalid value so we don't get confused and think that this
377  was set. */
378  for (i=0; i<=3; i++) {
379  audio_volume.level[i] = 0;
380  }
381  } else {
382  /* Set i_vol_port so volume levels set above will get used. */
383  i_vol_port=0;
384  }
385  return rc;
386 
387 }
388 
389 /* Subtract one from the volume level. If we are at the minimum value,
390  * nothing is done.
391 
392  We used to wrap at the boundaries but this is probably wrong because
393  is assumes someone:
394  * looks at the display while listening,
395  * knows that 99 is the maximum value.
396 
397  See issue #33333
398 
399  If the volume level is undefined, then this means we could not get
400  the current value and we'll' set it to 50 the midway point.
401 
402  Return the status of setting the volume level. */
403 static bool
405 {
406  if (i_volume_level == -1) i_volume_level = 51;
407  if (i_volume_level <= 0) i_volume_level = 1;
408  return set_volume_level(p_cdio, --i_volume_level);
409 }
410 
411 /* Add 1 to the volume level. If we are at the maximum value, nothing
412  is done.
413 
414  We used to wrap at the boundaries but this is probably wrong because
415  is assumes someone:
416  * looks at the display while listening,
417  * knows that 99 is the maximum value.
418 
419  See issue #33333
420 
421  If volume level is undefined, then this means we could not get the
422  current value and we'll' set it to 50 the midway point.
423 
424  Return the status of setting the volume level. */
425 static bool
427 {
428  if (i_volume_level == -1) i_volume_level = 49;
429  if (i_volume_level <= 0) i_volume_level = 0;
430  if (i_volume_level > 98) i_volume_level = 98;
431  return set_volume_level(p_cdio, ++i_volume_level);
432 }
433 
435 static bool
436 cd_stop(CdIo_t *p_cdio)
437 {
438  bool b_ok = true;
439  if (b_cd && p_cdio) {
440  action("stop...");
442  b_ok = DRIVER_OP_SUCCESS == cdio_audio_stop(p_cdio);
443  if ( !b_ok )
444  xperror("stop");
446  }
447  return b_ok;
448 }
449 
451 static bool
452 cd_eject(void)
453 {
454  bool b_ok = true;
455  if (p_cdio_global) {
457  action("eject...");
459  if (!b_ok)
460  xperror("eject");
461  b_cd = false;
464  }
465  return b_ok;
466 }
467 
469 static bool
470 cd_close(const char *psz_device)
471 {
472  bool b_ok = true;
473  if (!b_cd) {
474  action("close...");
475  b_ok = DRIVER_OP_SUCCESS == cdio_close_tray(psz_device, &driver_id);
476  if (!b_ok)
477  xperror("close");
478  }
479  return b_ok;
480 }
481 
483 static bool
484 cd_pause(CdIo_t *p_cdio)
485 {
486  bool b_ok = true;
488  b_ok = DRIVER_OP_SUCCESS == cdio_audio_pause(p_cdio);
489  if (!b_ok)
490  xperror("pause");
491  }
492  return b_ok;
493 }
494 
496 static bool
498 {
499  bool b_ok = true;
500  if (!p_cdio) return false;
501 
503  if (!b_ok) {
504  xperror("read subchannel");
505  b_cd = 0;
506  }
508  cd_eject();
509  return b_ok;
510 }
511 
512 #ifdef HAVE_CDDB
513 
516 static void
517 cddb_log_handler (cddb_log_level_t level, const char message[])
518 {
519  switch (level) {
520  case CDDB_LOG_DEBUG:
521  case CDDB_LOG_INFO:
522  if (!b_verbose)
523  return;
524  /* Fall through if to warn case */
525  case CDDB_LOG_WARN:
526  case CDDB_LOG_ERROR:
527  case CDDB_LOG_CRITICAL:
528  default:
529  xperror(message);
530  break;
531  }
532 
533  /* gl_default_cdio_log_handler (level, message); */
534 }
535 #endif /* HAVE_CDDB */
536 
537 static void
539 {
540 #ifdef HAVE_CDDB
541  b_db = init_cddb(p_cdio, &p_conn, &p_cddb_disc, xperror, i_first_track_global,
542  i_tracks_global, &i_cddb_matches);
543  if (b_db) {
544  int i_year;
545  i_year = atoi(year);
546  cddb_disc_set_artist(p_cddb_disc, artist);
547  cddb_disc_set_title(p_cddb_disc, title);
548  cddb_disc_set_genre(p_cddb_disc, genre);
549  cddb_disc_set_year(p_cddb_disc, i_year);
550  }
551 #endif /* HAVE_CDDB */
552  return;
553 }
554 
555 #define add_cdtext_disc_info(format_str, info_field, FIELD) \
556  if (cdtext_get_const(p_cdtext, FIELD, 0) && !strlen(info_field)) { \
557  snprintf(info_field, sizeof(info_field), format_str, \
558  cdtext_get_const(p_cdtext, FIELD, 0)); \
559  b_cdtext_ ## info_field = true; \
560  }
561 
562 static void
564 {
565  cdtext_t *p_cdtext = cdio_get_cdtext(p_cdio);
566 
567  if (p_cdtext) {
571  }
572 }
573 
574 static void
576 {
577  b_db = false;
578  if (b_prefer_cdtext) {
579  get_cdtext_disc_info(p_cdio);
580  get_cddb_disc_info(p_cdio);
581  } else {
582  get_cddb_disc_info(p_cdio);
583  get_cdtext_disc_info(p_cdio);
584  }
585 }
586 
588 static void
589 read_toc(CdIo_t *p_cdio)
590 {
591  track_t i;
592 
593  action("read toc...");
594 
595  memset(cd_info, 0, sizeof(cd_info));
596  title[0] = artist[0] = genre[0] = category[0] = year[0] = '\0';
597 
603 
604 
606  for (i_vol_port=0; i_vol_port<4; i_vol_port++) {
607  if (audio_volume.level[i_vol_port] > 0) break;
608  }
609 
612  xperror("read toc header");
613  b_cd = false;
614  b_record = false;
616  } else {
617  b_cd = true;
618  i_data = 0;
619  get_disc_info(p_cdio);
620  for (i = i_first_track_global; i <= i_last_track+1; i++) {
621  int s;
622  if ( !cdio_get_track_msf(p_cdio, i, &(toc[i])) )
623  {
624  xperror("read toc entry");
625  b_cd = false;
626  return;
627  }
628  if ( TRACK_FORMAT_AUDIO == cdio_get_track_format(p_cdio, i) ) {
629 
630  if (i != i_first_track_global)
631  {
634  snprintf(cd_info[i-1].length, sizeof(cd_info[0].length),
635  "%02d:%02d",
636  (uint8_t) (s / CDIO_CD_SECS_PER_MIN),
637  (uint8_t) (s % CDIO_CD_SECS_PER_MIN));
638  }
639  } else {
640  if ((i != i_last_track+1) ) {
641  i_data++;
642  if (i == i_first_track_global) {
643  if (i == i_last_track)
645  else
647  }
648  }
649  }
650  get_track_info(i);
651  }
652  b_record = true;
653  read_subchannel(p_cdio);
656  }
657  action("");
658  if (!b_all_tracks)
660 }
661 
663 static bool
664 play_track(track_t i_start_track, track_t i_end_track)
665 {
666  bool b_ok = true;
667  char line[80];
668 
669  if (!b_cd) {
671  }
672 
675  return false;
676 
677  if (debug)
678  fprintf(stderr,"play tracks: %d-%d => ", i_start_track, i_end_track-1);
679  if (i_start_track < i_first_track_global) i_start_track = i_first_track_global;
680  if (i_start_track > i_last_audio_track) i_start_track = i_last_audio_track;
681  if (i_end_track < i_first_track_global) i_end_track = i_first_track_global;
682  if (i_end_track > i_last_audio_track) i_end_track = i_last_audio_track;
683  i_end_track++;
684  if (debug)
685  fprintf(stderr,"%d-%d\n",i_start_track, i_end_track-1);
686 
688  snprintf(line, sizeof(line), "play track %d to track %d.",
689  i_start_track, i_end_track-1);
690  action(line);
692  &(toc[i_start_track]),
693  &(toc[i_end_track])) );
694  if (!b_ok) xperror("play");
695  return b_ok;
696 }
697 
698 static void
699 skip(int diff)
700 {
701  msf_t start_msf;
702  int sec;
703 
706  return;
707 
709  sec += diff;
710  if (sec < 0) sec = 0;
711 
712  start_msf.m = cdio_to_bcd8(sec / CDIO_CD_SECS_PER_MIN);
713  start_msf.s = cdio_to_bcd8(sec % CDIO_CD_SECS_PER_MIN);
714  start_msf.f = 0;
715 
718  &(toc[i_last_audio_track])) )
719  xperror("play");
720 }
721 
722 static bool
724 {
725  bool b_ok = true;
726  if (!b_cd) return false;
727 
730  if (!b_ok)
731  xperror("resume");
732  } else {
734  if (!b_ok)
735  xperror("pause");
736  }
737  return b_ok;
738 }
739 
743 static void
744 display_status(bool b_status_only)
745 {
746  char line[80];
747 
748  if (!b_interactive) return;
749 
750  if (!b_cd) {
751  snprintf(line, sizeof(line), "no CD in drive (%s)", psz_device_global);
752 
754  snprintf(line, sizeof(line), "CD has only data tracks");
755 
759  if (i_vol_port < 4) {
761  snprintf(line, sizeof(line),
762  "track %2d - %02x:%02x of %s (%02x:%02x abs) %s volume: %d",
768  } else
769  snprintf(line, sizeof(line),
770  "track %2d - %02x:%02x of %s (%02x:%02x abs) %s",
774  } else {
775  snprintf(line, sizeof(line), "%s", mmc_audio_state2str(sub.audio_status));
776 
777  }
778 
779  action(NULL);
780  mvprintw(LINE_STATUS, 0, (char *) "status%s: %s",
781  auto_mode ? "*" : " ", line);
782  clrtoeol();
783 
784  if ( !b_status_only && b_db && i_last_display_track != sub.track &&
787  b_cd) {
788 
789  if (b_all_tracks)
790  display_tracks();
791  else {
792  const cd_track_info_rec_t *p_cd_info = &cd_info[sub.track];
794  if (i_first_audio_track != sub.track &&
795  strlen(cd_info[sub.track-1].title)) {
796  const cd_track_info_rec_t *p_cd_info_track = &cd_info[sub.track-1];
797  mvprintw(LINE_TRACK_PREV, 0, (char *) " track %2d title : %s [%s]",
798  sub.track-1, p_cd_info->title,
799  p_cd_info_track->b_cdtext ? "CD-Text" : "CDDB");
800  clrtoeol();
801  } else {
802  mvprintw(LINE_TRACK_PREV, 0, (char *) "%s","");
803  clrtoeol();
804  }
805  if (strlen(p_cd_info->title)) {
806  mvprintw(LINE_TRACK_TITLE, 0, (char *) ">track %2d title : %s [%s]",
807  sub.track, p_cd_info->title,
808  (char *) (p_cd_info->b_cdtext ? "CD-Text" : "CDDB"));
809  clrtoeol();
810  }
811  if (strlen(p_cd_info->artist)) {
812  mvprintw(LINE_TRACK_ARTIST, 0, (char *) ">track %2d artist: %s [%s]",
813  sub.track, p_cd_info->artist,
814  p_cd_info->b_cdtext ? "CD-Text" : "CDDB");
815  clrtoeol();
816  }
817  if (i_last_audio_track != sub.track &&
818  strlen(cd_info[sub.track+1].title)) {
819  const cd_track_info_rec_t *p_cd_info_track = &cd_info[sub.track+1];
820  mvprintw(LINE_TRACK_NEXT, 0, (char *) " track %2d title : %s [%s]",
821  sub.track+1, p_cd_info_track->title,
822  p_cd_info->b_cdtext ? "CD-Text" : "CDDB");
823  clrtoeol();
824  } else {
825  mvprintw(LINE_TRACK_NEXT, 0, (char *) "%s","");
826  clrtoeol();
827  }
828  clrtobot();
829  }
830  }
831 
832  action(NULL); /* Redisplay action line. */
833 
834 }
835 
836 static void
838 {
839 #ifdef HAVE_CDDB
840  cddb_track_t *t = cddb_disc_get_track(p_cddb_disc,
841  i_track - i_first_track_global);
842  if (t) {
843  cddb_track_set_title(t, title);
844  cddb_track_set_artist(t, artist);
845  }
846 
847 #else
848  ;
849 #endif
850 }
851 
852 #define add_cdtext_track_info(format_str, info_field, FIELD) \
853  if (cdtext_get_const(p_cdtext, FIELD, i_track)) { \
854  snprintf(cd_info[i_track].info_field, \
855  sizeof(cd_info[i_track].info_field), \
856  format_str, cdtext_get_const(p_cdtext, FIELD, i_track)); \
857  cd_info[i_track].b_cdtext = true; \
858  }
859 
860 
861 static void
863 {
864 
866 
867  if (NULL != p_cdtext) {
870  }
871 }
872 
873 static void
875 {
876 
877  if (b_prefer_cdtext) {
878  get_cdtext_track_info(i_track);
879  get_cddb_track_info(i_track);
880  } else {
881  get_cddb_track_info(i_track);
882  get_cdtext_track_info(i_track);
883  }
884 }
885 
886 #define display_line(LINE_NO, COL_NO, format_str, field) \
887  if (field != NULL && field[0]) { \
888  mvprintw(LINE_NO, COL_NO, (char *) format_str " [%s]", \
889  field, \
890  b_cdtext_ ## field ? "CD-Text": "CDDB"); \
891  clrtoeol(); \
892  }
893 
894 static void
895 display_cdinfo(CdIo_t *p_cdio, track_t i_tracks, track_t i_first_track)
896 {
897  int len;
898  char line[80];
899 
900  if (!b_interactive) return;
901 
902  if (!b_cd) snprintf(line, sizeof(line), "-");
903  else {
904  len = snprintf(line, sizeof(line), "%2u tracks (%02x:%02x min)",
905  (unsigned int) i_last_track,
906  toc[i_last_track+1].m, toc[i_last_track+1].s);
907  if (i_data && i_first_track != CDIO_CDROM_LEADOUT_TRACK)
908  snprintf(line+len, sizeof(line)-len, ", audio=%u-%u",
909  (unsigned int) i_first_audio_track,
910  (unsigned int) i_last_audio_track);
911 
912  display_line(LINE_ARTIST, 0, "CD Artist : %s", artist);
913  display_line(LINE_CDNAME, 0, "CD Title : %s", title);
914  display_line(LINE_GENRE, 0, "CD Genre : %s", genre);
915  display_line(LINE_YEAR, 0, "CD Year : %s", year);
916  }
917 
918  mvprintw(LINE_CDINFO, 0, (char *) "CD info: %s", line);
919  clrtoeol();
920  action(NULL);
921 }
922 
923 /* ---------------------------------------------------------------------- */
924 
925 static void
926 usage(char *prog)
927 {
928  fprintf(stderr,
929  "%s is a simple curses CD player. It can pick up artist,\n"
930  "CD name and song title from CD-Text info on the CD or\n"
931  "via CDDB.\n"
932  "\n"
933  "usage: %s [options] [device]\n"
934  "\n"
935  "default for to search for a CD-ROM device with a CD-DA loaded\n"
936  "\n"
937  "These command line options available:\n"
938  " -h print this help\n"
939  " -k print key mapping\n"
940  " -a start up in auto-mode\n"
941  " -d debug\n"
942  " -v verbose\n"
943  "\n"
944  "for non-interactive use (only one) of these:\n"
945  " -l list tracks\n"
946  " -c print cover (PostScript to stdout)\n"
947  " -C close CD-ROM tray. If you use this option,\n"
948  " a CD-ROM device name must be specified.\n"
949  " -p play the whole CD\n"
950  " -t n play track >n<\n"
951  " -t a-b play all tracks between a and b (inclusive)\n"
952  " -L set volume level\n"
953  " -s stop playing\n"
954  " -S list audio subchannel information\n"
955  " -e eject cdrom\n"
956  "\n"
957  "That's all. Oh, maybe a few words more about the auto-mode. This\n"
958  "is the 'dont-touch-any-key' feature. You load a CD, player starts\n"
959  "to play it, and when it is done it ejects the CD. Start it that\n"
960  "way on a spare console and forget about it...\n"
961  "\n"
962  "(c) 1997-98 Gerd Knorr <kraxel@goldbach.in-berlin.de>\n"
963  "(c) 2005-2006, 2017 Rocky Bernstein <rocky@gnu.org>\n"
964  , prog, prog);
965 }
966 
967 static void
969 {
970  unsigned int i;
971  for (i=0; i < i_key_bindings; i++)
972  fprintf(stderr, "%s\n", key_bindings[i]);
973 }
974 
975 static void
977  {
978  action("press any key to continue");
979  while (1 != select_wait(b_cd ? 1 : 5)) {
980  read_subchannel(p_cdio);
981  display_status(true);
982  }
983  (void) getch();
984  clrtobot();
985  action(NULL);
986  if (!b_all_tracks)
989  }
990 
991 static void
993 {
994  unsigned int i;
995  for (i=0; i < i_key_bindings; i++) {
996  mvprintw(LINE_TRACK_PREV+i, 0, (char *) "%s", key_bindings[i]);
997  clrtoeol();
998  }
1000 }
1001 
1002 static void
1004 {
1005  track_t i;
1006  int i_line=0;
1007  int s;
1008 
1009  if (b_record) {
1010  i_line=LINE_TRACK_PREV - 1;
1011  for (i = i_first_track_global; i <= i_last_track; i++) {
1012  char line[200]="";
1016  snprintf(line, sizeof(line), "%2d %02d:%02d %s ", i,
1020  sub.track == i ) ? "->" : " |");
1021  if (b_record) {
1022  if ( strlen(cd_info[i].title) )
1023  strcat(line, cd_info[i].title);
1024  if ( strlen(cd_info[i].artist) > 0 ) {
1025  if (strlen(cd_info[i].title))
1026  strcat(line, " / ");
1027  strcat(line, cd_info[i].artist);
1028  }
1029  }
1030  if (sub.track == i) {
1031  attron(A_STANDOUT);
1032  mvprintw(i_line++, 0, line);
1033  attroff(A_STANDOUT);
1034  } else
1035  mvprintw(i_line++, 0, line);
1036  clrtoeol();
1037  }
1038  }
1039 }
1040 
1041 /*
1042  * PostScript 8bit latin1 handling
1043  * stolen from mpage output -- please don't ask me how this works...
1044  */
1045 #define ENCODING_TRICKS \
1046  "/reencsmalldict 12 dict def\n" \
1047  "/ReEncodeSmall { reencsmalldict begin\n" \
1048  "/newcodesandnames exch def /newfontname exch def\n" \
1049  "/basefontname exch def\n" \
1050  "/basefontdict basefontname findfont def\n" \
1051  "/newfont basefontdict maxlength dict def\n" \
1052  "basefontdict { exch dup /FID ne { dup /Encoding eq\n" \
1053  "{ exch dup length array copy newfont 3 1 roll put }\n" \
1054  "{ exch newfont 3 1 roll put }\n" \
1055  "ifelse }\n" \
1056  "{ pop pop }\n" \
1057  "ifelse } forall\n" \
1058  "newfont /FontName newfontname put\n" \
1059  "newcodesandnames aload pop newcodesandnames length 2 idiv\n" \
1060  "{ newfont /Encoding get 3 1 roll put } repeat\n" \
1061  "newfontname newfont definefont pop end } def\n" \
1062  "/charvec [\n" \
1063  "026 /Scaron\n" \
1064  "027 /Ydieresis\n" \
1065  "028 /Zcaron\n" \
1066  "029 /scaron\n" \
1067  "030 /trademark\n" \
1068  "031 /zcaron\n" \
1069  "032 /space\n" \
1070  "033 /exclam\n" \
1071  "034 /quotedbl\n" \
1072  "035 /numbersign\n" \
1073  "036 /dollar\n" \
1074  "037 /percent\n" \
1075  "038 /ampersand\n" \
1076  "039 /quoteright\n" \
1077  "040 /parenleft\n" \
1078  "041 /parenright\n" \
1079  "042 /asterisk\n" \
1080  "043 /plus\n" \
1081  "044 /comma\n" \
1082  "045 /minus\n" \
1083  "046 /period\n" \
1084  "047 /slash\n" \
1085  "048 /zero\n" \
1086  "049 /one\n" \
1087  "050 /two\n" \
1088  "051 /three\n" \
1089  "052 /four\n" \
1090  "053 /five\n" \
1091  "054 /six\n" \
1092  "055 /seven\n" \
1093  "056 /eight\n" \
1094  "057 /nine\n" \
1095  "058 /colon\n" \
1096  "059 /semicolon\n" \
1097  "060 /less\n" \
1098  "061 /equal\n" \
1099  "062 /greater\n" \
1100  "063 /question\n" \
1101  "064 /at\n" \
1102  "065 /A\n" \
1103  "066 /B\n" \
1104  "067 /C\n" \
1105  "068 /D\n" \
1106  "069 /E\n" \
1107  "070 /F\n" \
1108  "071 /G\n" \
1109  "072 /H\n" \
1110  "073 /I\n" \
1111  "074 /J\n" \
1112  "075 /K\n" \
1113  "076 /L\n" \
1114  "077 /M\n" \
1115  "078 /N\n" \
1116  "079 /O\n" \
1117  "080 /P\n" \
1118  "081 /Q\n" \
1119  "082 /R\n" \
1120  "083 /S\n" \
1121  "084 /T\n" \
1122  "085 /U\n" \
1123  "086 /V\n" \
1124  "087 /W\n" \
1125  "088 /X\n" \
1126  "089 /Y\n" \
1127  "090 /Z\n" \
1128  "091 /bracketleft\n" \
1129  "092 /backslash\n" \
1130  "093 /bracketright\n" \
1131  "094 /asciicircum\n" \
1132  "095 /underscore\n" \
1133  "096 /quoteleft\n" \
1134  "097 /a\n" \
1135  "098 /b\n" \
1136  "099 /c\n" \
1137  "100 /d\n" \
1138  "101 /e\n" \
1139  "102 /f\n" \
1140  "103 /g\n" \
1141  "104 /h\n" \
1142  "105 /i\n" \
1143  "106 /j\n" \
1144  "107 /k\n" \
1145  "108 /l\n" \
1146  "109 /m\n" \
1147  "110 /n\n" \
1148  "111 /o\n" \
1149  "112 /p\n" \
1150  "113 /q\n" \
1151  "114 /r\n" \
1152  "115 /s\n" \
1153  "116 /t\n" \
1154  "117 /u\n" \
1155  "118 /v\n" \
1156  "119 /w\n" \
1157  "120 /x\n" \
1158  "121 /y\n" \
1159  "122 /z\n" \
1160  "123 /braceleft\n" \
1161  "124 /bar\n" \
1162  "125 /braceright\n" \
1163  "126 /asciitilde\n" \
1164  "127 /.notdef\n" \
1165  "128 /fraction\n" \
1166  "129 /florin\n" \
1167  "130 /quotesingle\n" \
1168  "131 /quotedblleft\n" \
1169  "132 /guilsinglleft\n" \
1170  "133 /guilsinglright\n" \
1171  "134 /fi\n" \
1172  "135 /fl\n" \
1173  "136 /endash\n" \
1174  "137 /dagger\n" \
1175  "138 /daggerdbl\n" \
1176  "139 /bullet\n" \
1177  "140 /quotesinglbase\n" \
1178  "141 /quotedblbase\n" \
1179  "142 /quotedblright\n" \
1180  "143 /ellipsis\n" \
1181  "144 /dotlessi\n" \
1182  "145 /grave\n" \
1183  "146 /acute\n" \
1184  "147 /circumflex\n" \
1185  "148 /tilde\n" \
1186  "149 /oe\n" \
1187  "150 /breve\n" \
1188  "151 /dotaccent\n" \
1189  "152 /perthousand\n" \
1190  "153 /emdash\n" \
1191  "154 /ring\n" \
1192  "155 /Lslash\n" \
1193  "156 /OE\n" \
1194  "157 /hungarumlaut\n" \
1195  "158 /ogonek\n" \
1196  "159 /caron\n" \
1197  "160 /lslash\n" \
1198  "161 /exclamdown\n" \
1199  "162 /cent\n" \
1200  "163 /sterling\n" \
1201  "164 /currency\n" \
1202  "165 /yen\n" \
1203  "166 /brokenbar\n" \
1204  "167 /section\n" \
1205  "168 /dieresis\n" \
1206  "169 /copyright\n" \
1207  "170 /ordfeminine\n" \
1208  "171 /guillemotleft\n" \
1209  "172 /logicalnot\n" \
1210  "173 /hyphen\n" \
1211  "174 /registered\n" \
1212  "175 /macron\n" \
1213  "176 /degree\n" \
1214  "177 /plusminus\n" \
1215  "178 /twosuperior\n" \
1216  "179 /threesuperior\n" \
1217  "180 /acute\n" \
1218  "181 /mu\n" \
1219  "182 /paragraph\n" \
1220  "183 /periodcentered\n" \
1221  "184 /cedilla\n" \
1222  "185 /onesuperior\n" \
1223  "186 /ordmasculine\n" \
1224  "187 /guillemotright\n" \
1225  "188 /onequarter\n" \
1226  "189 /onehalf\n" \
1227  "190 /threequarters\n" \
1228  "191 /questiondown\n" \
1229  "192 /Agrave\n" \
1230  "193 /Aacute\n" \
1231  "194 /Acircumflex\n" \
1232  "195 /Atilde\n" \
1233  "196 /Adieresis\n" \
1234  "197 /Aring\n" \
1235  "198 /AE\n" \
1236  "199 /Ccedilla\n" \
1237  "200 /Egrave\n" \
1238  "201 /Eacute\n" \
1239  "202 /Ecircumflex\n" \
1240  "203 /Edieresis\n" \
1241  "204 /Igrave\n" \
1242  "205 /Iacute\n" \
1243  "206 /Icircumflex\n" \
1244  "207 /Idieresis\n" \
1245  "208 /Eth\n" \
1246  "209 /Ntilde\n" \
1247  "210 /Ograve\n" \
1248  "211 /Oacute\n" \
1249  "212 /Ocircumflex\n" \
1250  "213 /Otilde\n" \
1251  "214 /Odieresis\n" \
1252  "215 /multiply\n" \
1253  "216 /Oslash\n" \
1254  "217 /Ugrave\n" \
1255  "218 /Uacute\n" \
1256  "219 /Ucircumflex\n" \
1257  "220 /Udieresis\n" \
1258  "221 /Yacute\n" \
1259  "222 /Thorn\n" \
1260  "223 /germandbls\n" \
1261  "224 /agrave\n" \
1262  "225 /aacute\n" \
1263  "226 /acircumflex\n" \
1264  "227 /atilde\n" \
1265  "228 /adieresis\n" \
1266  "229 /aring\n" \
1267  "230 /ae\n" \
1268  "231 /ccedilla\n" \
1269  "232 /egrave\n" \
1270  "233 /eacute\n" \
1271  "234 /ecircumflex\n" \
1272  "235 /edieresis\n" \
1273  "236 /igrave\n" \
1274  "237 /iacute\n" \
1275  "238 /icircumflex\n" \
1276  "239 /idieresis\n" \
1277  "240 /eth\n" \
1278  "241 /ntilde\n" \
1279  "242 /ograve\n" \
1280  "243 /oacute\n" \
1281  "244 /ocircumflex\n" \
1282  "245 /otilde\n" \
1283  "246 /odieresis\n" \
1284  "247 /divide\n" \
1285  "248 /oslash\n" \
1286  "249 /ugrave\n" \
1287  "250 /uacute\n" \
1288  "251 /ucircumflex\n" \
1289  "252 /udieresis\n" \
1290  "253 /yacute\n" \
1291  "254 /thorn\n" \
1292  "255 /ydieresis\n" \
1293  "] def"
1294 
1295 
1296 static void
1298 {
1299  int i,s,y,sy;
1300 
1301  if (!b_record) return;
1302 
1303  printf("%%!PS-Adobe-2.0\n");
1304 
1305  /* encoding tricks */
1306  puts(ENCODING_TRICKS);
1307  printf("/Times /TimesLatin1 charvec ReEncodeSmall\n");
1308  printf("/Helvetica /HelveticaLatin1 charvec ReEncodeSmall\n");
1309 
1310  /* Spaces */
1311  printf("0 setlinewidth\n");
1312  printf(" 100 100 moveto\n");
1313  printf(" 390 0 rlineto\n");
1314  printf(" 0 330 rlineto\n");
1315  printf("-390 0 rlineto\n");
1316  printf("closepath stroke\n");
1317 
1318  printf(" 100 100 moveto\n");
1319  printf("-16 0 rlineto\n");
1320  printf(" 0 330 rlineto\n");
1321  printf("422 0 rlineto\n");
1322  printf(" 0 -330 rlineto\n");
1323  printf("closepath stroke\n");
1324 
1325  /* Title */
1326  printf("/TimesLatin1 findfont 24 scalefont setfont\n");
1327  printf("120 400 moveto (%s) show\n", title);
1328  printf("/TimesLatin1 findfont 18 scalefont setfont\n");
1329  printf("120 375 moveto (%s) show\n", artist);
1330 
1331  /* List */
1332  sy = 250 / i_last_track;
1333  if (sy > 14) sy = 14;
1334  printf("/labelfont /TimesLatin1 findfont %d scalefont def\n",sy-2);
1335  printf("/timefont /Courier findfont %d scalefont def\n",sy-2);
1336  y = 350;
1337  for (i = i_first_track_global; i <= i_last_track; i++, y -= sy) {
1340 
1341  printf("labelfont setfont\n");
1342  printf("120 %d moveto (%d) show\n", y, i);
1343  {
1344  char line[200]="";
1345  if ( strlen(cd_info[i].title) )
1346  strcat(line, cd_info[i].title);
1347  if ( strlen(cd_info[i].artist) > 0 ) {
1348  if (strlen(cd_info[i].title))
1349  strcat(line, " / ");
1350  strcat(line, cd_info[i].artist);
1351  }
1352  printf("150 %d moveto (%s) show\n", y, line);
1353  }
1354  printf("timefont setfont\n");
1355  printf("420 %d moveto (%2d:%02d) show\n", y,
1357  }
1358 
1359  /* Seitenbanner */
1360  printf("/HelveticaLatin1 findfont 12 scalefont setfont\n");
1361  printf(" 97 105 moveto (%s: %s) 90 rotate show -90 rotate\n",
1362  artist, title);
1363  printf("493 425 moveto (%s: %s) -90 rotate show 90 rotate\n",
1364  artist, title);
1365  printf("showpage\n");
1366 }
1367 
1368 static void
1370 {
1371  int i,s;
1372 
1373  if (!b_record) return;
1374 
1375  printf("Title : %s\n", title);
1376  printf("Artist: %s\n", artist);
1377 
1378  for (i = i_first_track_global; i <= i_last_track; i++) {
1381  printf("%2d: %s [%d seconds]\n", i, cd_info[i].title, s);
1382  }
1383 }
1384 
1385 typedef enum {
1399 } cd_operation_t;
1400 
1401 int
1402 main(int argc, char *argv[])
1403 {
1404  int c, nostop=0;
1405  char *h;
1406  int i_rc = 0;
1407  cd_operation_t cd_op = NO_OP; /* operation to do in non-interactive mode */
1408 
1409 
1410  psz_program = strrchr(argv[0],'/');
1411  psz_program = psz_program ? psz_program+1 : argv[0];
1412 
1413  memset(&cddb_opts, 0, sizeof(cddb_opts));
1414 
1416  /* parse options */
1417  while ( 1 ) {
1418  if (-1 == (c = getopt(argc, argv, "acCdehkplL:sSt:vx")))
1419  break;
1420  switch (c) {
1421  case 'v':
1422  b_verbose = true;
1425  break;
1426  case 'd':
1427  debug = 1;
1430  break;
1431  case 'a':
1432  auto_mode = 1;
1433  break;
1434 
1435  case 'L':
1436  i_volume_level = atoi(optarg);
1437  cd_op = SET_VOLUME;
1438  b_interactive = false;
1439  break;
1440 
1441  case 't':
1442  if (NULL != (h = strchr(optarg,'-'))) {
1443  *h = 0;
1444  start_track = atoi(optarg);
1445  stop_track = atoi(h+1)+1;
1446  if (0 == start_track) start_track = 1;
1448  } else {
1449  start_track = atoi(optarg);
1450  stop_track = start_track+1;
1451  one_track = 1;
1452  }
1453  b_interactive = false;
1454  cd_op = PLAY_TRACK;
1455  break;
1456  case 'p':
1457  b_interactive = false;
1458  cd_op = PLAY_CD;
1459  break;
1460  case 'l':
1461  b_interactive = false;
1462  cd_op = LIST_TRACKS;
1463  break;
1464  case 'C':
1465  b_interactive = false;
1466  cd_op = CLOSE_CD;
1467  break;
1468  case 'c':
1469  b_interactive = false;
1470  cd_op = PS_LIST_TRACKS;
1471  break;
1472  case 's':
1473  b_interactive = false;
1474  cd_op = STOP_PLAYING;
1475  break;
1476  case 'S':
1477  b_interactive = false;
1478  cd_op = LIST_SUBCHANNEL;
1479  break;
1480  case 'e':
1481  b_interactive = false;
1482  cd_op = EJECT_CD;
1483  break;
1484  case 'k':
1485  print_keys();
1486  exit(1);
1487  case 'h':
1488  usage(psz_program);
1489  exit(1);
1490  default:
1491  usage(psz_program);
1492  exit(1);
1493  }
1494  }
1495 
1496  if (argc > optind) {
1497  psz_device_global = strdup(argv[optind]);
1498  } else {
1499  char **ppsz_cdda_drives=NULL;
1500  char **ppsz_all_cd_drives = cdio_get_devices_ret(&driver_id);
1501 
1502  if (!ppsz_all_cd_drives) {
1503  fprintf(stderr, "Can't find a CD-ROM drive\n");
1504  exit(2);
1505  }
1506  ppsz_cdda_drives = cdio_get_devices_with_cap(ppsz_all_cd_drives,
1507  CDIO_FS_AUDIO, false);
1508  if (!ppsz_cdda_drives || !ppsz_cdda_drives[0]) {
1509  fprintf(stderr, "Can't find a CD-ROM drive with a CD-DA in it\n");
1510  cdio_free_device_list(ppsz_all_cd_drives);
1511  exit(3);
1512  }
1513  psz_device_global = strdup(ppsz_cdda_drives[0]);
1514  cdio_free_device_list(ppsz_all_cd_drives);
1515  cdio_free_device_list(ppsz_cdda_drives);
1516  }
1517 
1518  if (!b_interactive) {
1519  b_sig = true;
1520  nostop=1;
1521  }
1522 
1523  tty_raw();
1524  signal(SIGINT,ctrlc);
1525  signal(SIGQUIT,ctrlc);
1526  signal(SIGTERM,ctrlc);
1527  signal(SIGHUP,ctrlc);
1528  signal(SIGWINCH, sigwinch);
1529 
1530  if (CLOSE_CD != cd_op) {
1531  /* open device */
1532  if (b_verbose)
1533  fprintf(stderr, "open %s... ", psz_device_global);
1535  if (!p_cdio_global && cd_op != EJECT_CD) {
1538  }
1539 
1540  if (p_cdio_global && b_verbose)
1541  fprintf(stderr,"ok\n");
1542  }
1543 
1544  if (b_interactive) {
1545 #ifdef HAVE_CDDB
1546  cddb_log_set_handler (cddb_log_handler);
1547 #else
1548  ;
1549 #endif
1550  } else {
1551  b_sig = true;
1552  nostop=1;
1553  if (EJECT_CD == cd_op) {
1554  i_rc = cd_eject() ? 0 : 1;
1555  } else if (STOP_PLAYING == cd_op) {
1556  b_cd = true;
1557  i_rc = cd_stop(p_cdio_global) ? 0 : 1;
1558  goto done;
1559  } else {
1560  switch (cd_op) {
1561  case PS_LIST_TRACKS:
1562  case LIST_TRACKS:
1563  case PLAY_TRACK:
1565  default:
1566  break;
1567  }
1568  if (p_cdio_global)
1569  switch (cd_op) {
1570  case STOP_PLAYING:
1571  b_cd = true;
1572  i_rc = cd_stop(p_cdio_global) ? 0 : 1;
1573  break;
1574  case EJECT_CD:
1575  /* Should have been handled above. */
1576  cd_eject();
1577  break;
1578  case LIST_TRACKS:
1579  list_tracks();
1580  break;
1581  case PS_LIST_TRACKS:
1582  ps_list_tracks();
1583  break;
1584 
1585  case PLAY_TRACK:
1586  /* play just this one track */
1587  if (b_record) {
1588  printf("%s / %s\n", artist, title);
1589  if (one_track)
1590  printf("%s\n", cd_info[start_track].title);
1591  }
1592  i_rc = play_track(start_track, stop_track) ? 0 : 1;
1593  break;
1594 
1595  case PLAY_CD:
1596  if (b_record)
1597  printf("%s / %s\n", artist, title);
1599  break;
1600 
1601  case SET_VOLUME:
1603  break;
1604 
1605  case LIST_SUBCHANNEL:
1609  {
1610  printf("track %2d - %02x:%02x (%02x:%02x abs) ",
1612  sub.abs_addr.m, sub.abs_addr.s);
1613  }
1614  }
1615  printf("drive state: %s\n",
1617  } else {
1618  i_rc = 1;
1619  }
1620  break;
1621  case CLOSE_CD: /* Handled below */
1622  case LIST_KEYS:
1623  case TOGGLE_PAUSE:
1624  case EXIT_PROGRAM:
1625  case NO_OP:
1626  break;
1627  }
1628  else if (CLOSE_CD == cd_op) {
1630  ? 0 : 1;
1631  } else {
1632  fprintf(stderr,"no CD in drive (%s)\n", psz_device_global);
1633  }
1634  }
1635  }
1636 
1637  /* Play all tracks *unless* we have a play or paused status
1638  already. */
1639 
1644 
1645  while ( !b_sig ) {
1646  int key;
1647  if (!b_cd) read_toc(p_cdio_global);
1649  display_status(false);
1650 
1651  if (1 == select_wait(b_cd ? 1 : 5)) {
1652  switch (key = getch()) {
1653  case '-':
1655  break;
1656  case '+':
1658  break;
1659  case 'A':
1660  case 'a':
1661  auto_mode = !auto_mode;
1662  break;
1663  case 'X':
1664  case 'x':
1665  nostop=1;
1666  /* fall through */
1667  case 'Q':
1668  case 'q':
1669  b_sig = true;
1670  break;
1671  case 'E':
1672  case 'e':
1673  cd_eject();
1674  break;
1675  case 's':
1677  break;
1678  case 'C':
1679  case 'c':
1681  break;
1682  case 'L':
1683  case 'l':
1685  if (b_all_tracks)
1686  display_tracks();
1687  else {
1690  }
1691 
1692  break;
1693  case 'K':
1694  case 'k':
1695  case 'h':
1696  case 'H':
1697  case '?':
1698  list_keys();
1699  break;
1700  case ' ':
1701  case 'P':
1702  case 'p':
1703  toggle_pause();
1704  break;
1705  case KEY_RIGHT:
1706  if (b_cd &&
1710  else
1712  break;
1713  case KEY_LEFT:
1714  if (b_cd &&
1718  break;
1719  case KEY_UP:
1721  skip(10);
1722  break;
1723  case KEY_DOWN:
1725  skip(-10);
1726  break;
1727  case '1':
1728  case '2':
1729  case '3':
1730  case '4':
1731  case '5':
1732  case '6':
1733  case '7':
1734  case '8':
1735  case '9':
1737  break;
1738  case '0':
1740  break;
1741  case KEY_F(1):
1742  case KEY_F(2):
1743  case KEY_F(3):
1744  case KEY_F(4):
1745  case KEY_F(5):
1746  case KEY_F(6):
1747  case KEY_F(7):
1748  case KEY_F(8):
1749  case KEY_F(9):
1750  case KEY_F(10):
1751  case KEY_F(11):
1752  case KEY_F(12):
1753  case KEY_F(13):
1754  case KEY_F(14):
1755  case KEY_F(15):
1756  case KEY_F(16):
1757  case KEY_F(17):
1758  case KEY_F(18):
1759  case KEY_F(19):
1760  case KEY_F(20):
1761  play_track(key - KEY_F(1) + 11, CDIO_CDROM_LEADOUT_TRACK);
1762  break;
1763  }
1764  }
1765  }
1766  if (!nostop) cd_stop(p_cdio_global);
1767  tty_restore();
1768 done:
1769  finish("bye", i_rc);
1770 
1771  return 0; /* keep compiler happy */
1772 }
cdio_free_device_list
void cdio_free_device_list(char *device_list[])
Definition: device.c:477
action
static void action(const char *psz_action)
Definition: cdda-player.c:286
cd_track_info_rec_t::artist
char artist[80]
Definition: cdda-player.c:141
b_cd
static bool b_cd
Definition: cdda-player.c:117
audio_volume
static cdio_audio_volume_t audio_volume
Definition: cdda-player.c:163
title
static char title[80]
Definition: cdda-player.c:149
cdio_audio_resume
driver_return_code_t cdio_audio_resume(CdIo_t *p_cdio)
Definition: audio.c:133
CDTEXT_FIELD_GENRE
Definition: cdtext.h:53
cdio_audio_volume_s::level
uint8_t level[4]
Definition: audio.h:49
CDIO_CD_SECS_PER_MIN
Definition: sector.h:102
auto_mode
static bool auto_mode
Definition: cdda-player.c:118
genre
static char genre[40]
Definition: cdda-player.c:151
LINE_TRACK_TITLE
Definition: cdda-player.c:208
usage
static void usage(char *prog)
Definition: cdda-player.c:926
b_cdtext_artist
static bool b_cdtext_artist
Definition: cdda-player.c:156
driver_id
static driver_id_t driver_id
Definition: cdda-player.c:94
get_cdtext_track_info
static void get_cdtext_track_info(track_t i_track)
Definition: cdda-player.c:862
psz_program
static char * psz_program
Definition: cdda-player.c:134
rc
int rc
Definition: cdinfo-linux.c:193
add_cdtext_disc_info
#define add_cdtext_disc_info(format_str, info_field, FIELD)
Definition: cdda-player.c:555
i_last_audio_track
static track_t i_last_audio_track
Definition: cdda-player.c:101
b_cdtext_year
static bool b_cdtext_year
Definition: cdda-player.c:161
cdio_get_devices_with_cap
char ** cdio_get_devices_with_cap(char *ppsz_search_devices[], cdio_fs_anal_t capabilities, bool b_any)
Definition: device.c:612
start_track
static int start_track
Definition: cdda-player.c:107
TOGGLE_PAUSE
Definition: cdda-player.c:1397
cdio_subchannel_s::abs_addr
msf_t abs_addr
Definition: audio.h:42
cdio.h
The top-level header for libcdio: the CD Input and Control library. Applications include this for any...
cdio_get_num_tracks
track_t cdio_get_num_tracks(const CdIo_t *p_cdio)
Definition: track.c:156
MAX_KEY_STR
#define MAX_KEY_STR
Definition: cdda-player.c:171
read_subchannel
static bool read_subchannel(CdIo_t *p_cdio)
Definition: cdda-player.c:497
CDIO_MMC_READ_SUB_ST_PLAY
Definition: mmc.h:279
LINE_ACTION
static unsigned int LINE_ACTION
Definition: cdda-player.c:214
getopt.h
i_first_track_global
static track_t i_first_track_global
Definition: cdda-player.c:98
xperror
static void xperror(const char *psz_msg)
Definition: cdda-player.c:309
display_cdinfo
static void display_cdinfo(CdIo_t *p_cdio, track_t i_tracks, track_t i_first_track)
Definition: cdda-player.c:895
driver_return_code_t
driver_return_code_t
Definition: device.h:205
cdio_audio_play_msf
driver_return_code_t cdio_audio_play_msf(CdIo_t *p_cdio, msf_t *p_start_msf, msf_t *p_end_msf)
Definition: audio.c:81
cdio_audio_set_volume
driver_return_code_t cdio_audio_set_volume(CdIo_t *p_cdio, cdio_audio_volume_t *p_volume)
Definition: audio.c:151
LINE_GENRE
Definition: cdda-player.c:204
cd_close
static bool cd_close(const char *psz_device)
Definition: cdda-player.c:470
cdio_open
CdIo_t * cdio_open(const char *psz_source, driver_id_t driver_id)
Definition: device.c:930
cur_window
static WINDOW * cur_window
Definition: cdda-player.c:83
i_tracks_global
static track_t i_tracks_global
Definition: cdda-player.c:103
track_line_t
track_line_t
Definition: cdda-player.c:198
sub
static cdio_subchannel_t sub
Definition: cdda-player.c:105
cdio_close_tray
driver_return_code_t cdio_close_tray(const char *psz_drive, driver_id_t *p_driver_id)
Definition: device.c:382
display_status
static void display_status(bool b_status_only)
Definition: cdda-player.c:744
LINE_TRACK_ARTIST
Definition: cdda-player.c:209
print_keys
static void print_keys(void)
Definition: cdda-player.c:968
i_vol_port
static int i_vol_port
Definition: cdda-player.c:110
finish
static void finish(const char *psz_msg, int rc)
Definition: cdda-player.c:334
cddb.h
cdio_subchannel_s::audio_status
uint8_t audio_status
Definition: audio.h:37
read_toc
static void read_toc(CdIo_t *p_cdio)
Definition: cdda-player.c:589
DRIVER_DEVICE
Definition: device.h:169
track_t
uint8_t track_t
Definition: types.h:276
i_data
static int i_data
Definition: cdda-player.c:106
get_cddb_disc_info
static void get_cddb_disc_info(CdIo_t *p_cdio)
Definition: cdda-player.c:538
b_prefer_cdtext
static bool b_prefer_cdtext
Definition: cdda-player.c:122
i_first_audio_track
static track_t i_first_audio_track
Definition: cdda-player.c:100
CDTEXT_FIELD_TITLE
Definition: cdtext.h:45
CLOSE_CD
Definition: cdda-player.c:1391
LIST_KEYS
Definition: cdda-player.c:1394
set_volume_level
static bool set_volume_level(CdIo_t *p_cdio, uint8_t i_level)
Definition: cdda-player.c:363
LINE_STATUS
Definition: cdda-player.c:199
cdio_audio_pause
driver_return_code_t cdio_audio_pause(CdIo_t *p_cdio)
Definition: audio.c:64
cdio_eject_media
driver_return_code_t cdio_eject_media(CdIo_t **p_cdio)
Definition: device.c:433
cd_track_info_rec_t::title
char title[80]
Definition: cdda-player.c:140
_CdIo
Definition: cdio_private.h:472
CDIO_LOG_INFO
Definition: logging.h:38
decrease_volume_level
static bool decrease_volume_level(CdIo_t *p_cdio)
Definition: cdda-player.c:404
COLS_LAST
static unsigned int COLS_LAST
Definition: cdda-player.c:215
cdio_get_last_track_num
track_t cdio_get_last_track_num(const CdIo_t *p_cdio)
Definition: track.c:67
cdio_destroy
void cdio_destroy(CdIo_t *p_cdio)
Definition: device.c:361
add_cdtext_track_info
#define add_cdtext_track_info(format_str, info_field, FIELD)
Definition: cdda-player.c:852
i_last_track
static track_t i_last_track
Definition: cdda-player.c:99
b_interactive
static bool b_interactive
Definition: cdda-player.c:121
i
int i
Definition: cdinfo-linux.c:194
get_track_info
static void get_track_info(track_t i_track)
Definition: cdda-player.c:874
p_cdio_global
static CdIo_t * p_cdio_global
Definition: cdda-player.c:93
msf_s::f
uint8_t f
Definition: types.h:220
i_key_bindings
static const unsigned int i_key_bindings
Definition: cdda-player.c:193
category
static char category[40]
Definition: cdda-player.c:152
b_cdtext_title
static bool b_cdtext_title
Definition: cdda-player.c:155
cdio_get_cdtext
cdtext_t * cdio_get_cdtext(CdIo_t *p_cdio)
select_wait
static int select_wait(int sec)
Definition: cdda-player.c:270
getopt
int getopt(int argc, char *const *argv, const char *optstring)
Definition: getopt.c:1188
NULL
#define NULL
Definition: types.h:184
rounded_div
static int rounded_div(unsigned int i_a, unsigned int i_b)
Definition: cdda-player.c:218
cd_track_info_rec_t::length
char length[8]
Definition: cdda-player.c:142
CDIO_MMC_READ_SUB_ST_COMPLETED
Definition: mmc.h:282
SET_VOLUME
Definition: cdda-player.c:1392
b_all_tracks
static bool b_all_tracks
Definition: cdda-player.c:129
cdio_loglevel_default
cdio_log_level_t cdio_loglevel_default
Definition: logging.c:40
LINE_YEAR
Definition: cdda-player.c:205
debug
static bool debug
Definition: cdda-player.c:120
util.h
Miscellaneous utility functions.
cd_pause
static bool cd_pause(CdIo_t *p_cdio)
Definition: cdda-player.c:484
ps_list_tracks
static void ps_list_tracks(void)
Definition: cdda-player.c:1297
LIST_TRACKS
Definition: cdda-player.c:1395
cd_operation_t
cd_operation_t
Definition: cdda-player.c:1385
display_tracks
static void display_tracks(void)
Definition: cdda-player.c:1003
LIST_SUBCHANNEL
Definition: cdda-player.c:1393
PLAY_TRACK
Definition: cdda-player.c:1388
toc
static msf_t toc[CDIO_CDROM_LEADOUT_TRACK+1]
Definition: cdda-player.c:104
artist
static char artist[80]
Definition: cdda-player.c:150
increase_volume_level
static bool increase_volume_level(CdIo_t *p_cdio)
Definition: cdda-player.c:426
cdio_audio_get_volume
driver_return_code_t cdio_audio_get_volume(CdIo_t *p_cdio, cdio_audio_volume_t *p_volume)
Definition: audio.c:45
CDIO_CD_MAX_TRACKS
Definition: track.h:77
cd_track_info_rec_t::b_cdtext
bool b_cdtext
Definition: cdda-player.c:144
get_disc_info
static void get_disc_info(CdIo_t *p_cdio)
Definition: cdda-player.c:575
list_keys
static void list_keys(void)
Definition: cdda-player.c:992
cdio_get_track_format
track_format_t cdio_get_track_format(const CdIo_t *p_cdio, track_t i_track)
Definition: track.c:127
msf_s
MSF (minute/second/frame) structure.
Definition: types.h:219
b_record
static bool b_record
Definition: cdda-player.c:127
stop_track
static int stop_track
Definition: cdda-player.c:108
cdio_subchannel_s::track
uint8_t track
Definition: audio.h:40
mmc.h
Common definitions for MMC (Multimedia Commands). Applications include this for direct MMC access.
PS_LIST_TRACKS
Definition: cdda-player.c:1396
keypress_wait
static void keypress_wait(CdIo_t *p_cdio)
Definition: cdda-player.c:976
play_track
static bool play_track(track_t t1, track_t t2)
Definition: cdda-player.c:664
msf_s::s
uint8_t s
Definition: types.h:220
CDIO_FS_AUDIO
Definition: cd_types.h:38
cdio_audio_get_msf_seconds
uint32_t cdio_audio_get_msf_seconds(msf_t *p_msf)
Definition: audio.c:32
b_db
static bool b_db
Definition: cdda-player.c:126
UNUSED
#define UNUSED(x)
Definition: cdda-player.c:250
i_volume_level
static int8_t i_volume_level
Definition: cdda-player.c:130
cdio_audio_stop
driver_return_code_t cdio_audio_stop(CdIo_t *p_cdio)
Definition: audio.c:169
cur_term
TERMINAL * cur_term
mmc_audio_state2str
const char * mmc_audio_state2str(uint8_t i_audio_state)
Definition: mmc_util.c:86
cdio_get_first_track_num
track_t cdio_get_first_track_num(const CdIo_t *p_cdio)
Definition: track.c:47
toggle_pause
static bool toggle_pause(void)
Definition: cdda-player.c:723
ENCODING_TRICKS
#define ENCODING_TRICKS
Definition: cdda-player.c:1045
CDIO_MMC_READ_SUB_ST_PAUSED
Definition: mmc.h:281
b_cdtext_genre
static bool b_cdtext_genre
Definition: cdda-player.c:157
CDIO_INVALID_TRACK
Definition: track.h:79
cd_eject
static bool cd_eject(void)
Definition: cdda-player.c:452
b_sig
static int b_sig
Definition: cdda-player.c:95
optind
int optind
Definition: getopt.c:122
logging.h
Header to control logging and level of detail of output.
EXIT_PROGRAM
Definition: cdda-player.c:1398
tty_raw
static void tty_raw(void)
Definition: cdda-player.c:226
list_tracks
static void list_tracks(void)
Definition: cdda-player.c:1369
cddb_opts
cddb_opts_t cddb_opts
Definition: cddb.c:27
cd_info
static cd_track_info_rec_t cd_info[CDIO_CD_MAX_TRACKS+2]
Definition: cdda-player.c:147
cdio_audio_read_subchannel
driver_return_code_t cdio_audio_read_subchannel(CdIo_t *p_cdio, cdio_subchannel_t *p_subchannel)
Definition: audio.c:115
CDIO_LOG_DEBUG
Definition: logging.h:37
NO_OP
Definition: cdda-player.c:1386
EJECT_CD
Definition: cdda-player.c:1390
sigwinch
static void sigwinch(int dummy)
Definition: cdda-player.c:253
cdio_get_track_msf
bool cdio_get_track_msf(const CdIo_t *p_cdio, track_t i_track, msf_t *msf)
Definition: track.c:376
CDTEXT_FIELD_PERFORMER
Definition: cdtext.h:46
cdio_subchannel_s::rel_addr
msf_t rel_addr
Definition: audio.h:43
PLAY_CD
Definition: cdda-player.c:1387
LINE_ARTIST
Definition: cdda-player.c:202
config.h
i_last_display_track
static track_t i_last_display_track
Definition: cdda-player.c:102
skip
static void skip(int diff)
Definition: cdda-player.c:699
LINE_TRACK_NEXT
Definition: cdda-player.c:210
CDIO_CDROM_LEADOUT_TRACK
Definition: track.h:78
cdio_get_devices_ret
char ** cdio_get_devices_ret(driver_id_t *p_driver_id)
Definition: device.c:567
DRIVER_OP_SUCCESS
Definition: device.h:206
cd_stop
static bool cd_stop(CdIo_t *p_cdio)
Definition: cdda-player.c:436
optarg
char * optarg
Definition: getopt.c:107
msf_s::m
uint8_t m
Definition: types.h:220
TRACK_FORMAT_AUDIO
Definition: track.h:32
get_cddb_track_info
static void get_cddb_track_info(track_t i_track)
Definition: cdda-player.c:837
psz_device_global
static char * psz_device_global
Definition: cdda-player.c:133
main
int main(int argc, char *argv[])
Definition: cdda-player.c:1402
year
static char year[5]
Definition: cdda-player.c:153
psz_action_line
static char psz_action_line[300]
Definition: cdda-player.c:216
cdtext_s
Definition: cdtext_private.h:127
cd_track_info_rec_t
Definition: cdda-player.c:138
get_cdtext_disc_info
static void get_cdtext_disc_info(CdIo_t *p_cdio)
Definition: cdda-player.c:563
driver_id_t
driver_id_t
Definition: device.h:151
LINE_CDINFO
Definition: cdda-player.c:200
cd_types.h
Header for routines which automatically determine the Compact Disc format and possibly filesystem on ...
b_verbose
static bool b_verbose
Definition: cdda-player.c:119
LINE_CDNAME
Definition: cdda-player.c:203
CDIO_LOG_WARN
Definition: logging.h:40
tty_restore
static void tty_restore(void)
Definition: cdda-player.c:244
LINE_TRACK_PREV
Definition: cdda-player.c:207
one_track
static int one_track
Definition: cdda-player.c:109
key_bindings
static const char key_bindings[][50]
Definition: cdda-player.c:172
cdio_subchannel_s
Definition: audio.h:34
ctrlc
static void ctrlc(int signal_num)
Definition: cdda-player.c:263
cdio_audio_volume_s
Definition: audio.h:47
cdio_to_bcd8
uint8_t cdio_to_bcd8(uint8_t n)
Definition: util.c:168
display_line
#define display_line(LINE_NO, COL_NO, format_str, field)
Definition: cdda-player.c:886
STOP_PLAYING
Definition: cdda-player.c:1389