1 /* This file is part of TCD 2.0.
2    tcd.c - Main source file for curses interface.
3 
4    Copyright (C) 1997-98 Tim P. Gerla <timg@rrv.net>
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 
20    Tim P. Gerla
21    RR 1, Box 40
22    Climax, MN  56523
23    timg@rrv.net
24 */
25 
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29 
30 #include <stdlib.h>
31 #include <string.h>
32 #include <signal.h>
33 #include <unistd.h>
34 
35 #include <SDL/SDL.h>
36 #include <sys/cdio.h>
37 
38 #include "cd-utils.h"
39 #include "cddb.h"
40 #include "tcd.h"
41 #include "tracked.h"
42 #include "user-interface.h"
43 
44 /* file global variables definitions */
45 static struct tcd_state state;
46 
sighandler(int sig)47 static void sighandler(int sig)
48 {
49     if (sig == SIGTERM || sig == SIGINT) {
50         state.quit_requested = 1;
51     } else {
52         tcd_ui_shutdown();
53         printf("Signal %d caught, exiting.\n", sig);
54         printf("Please mail any info (no core dumps please.) to %s.\n\n",
55                PACKAGE_BUGREPORT);
56         exit(EXIT_FAILURE);
57     }
58 }
59 
handle_pause(void)60 static void handle_pause(void)
61 {
62     if (state.cdrom->status == CD_PLAYING) {
63         SDL_CDPause(state.cdrom);
64     } else if (state.cdrom->status == CD_PAUSED) {
65         SDL_CDResume(state.cdrom);
66     }
67 }
68 
handle_play(void)69 static void handle_play(void)
70 {
71     if (state.cdrom->status == CD_PAUSED) {
72         SDL_CDResume(state.cdrom);
73     } else if (CD_INDRIVE(state.cdrom->status)) {
74         if (state.play_method == REPEAT_TRK) {
75             SDL_CDPlayTracks(state.cdrom, 0, 0, 1, 0);
76         } else {
77             SDL_CDPlayTracks(state.cdrom, 0, 0, 0, 0);
78         }
79     }
80 }
81 
handle_next_track(void)82 static void handle_next_track(void)
83 {
84     int next_track;
85 
86     if (!CD_INDRIVE(state.cdrom->status))
87         return;
88 
89     if (state.cdrom->cur_track == state.cdrom->numtracks - 1)
90 	next_track = 0;
91     else
92 	next_track = state.cdrom->cur_track + 1;
93 
94     if (state.play_method == REPEAT_TRK)
95         SDL_CDPlayTracks(state.cdrom, next_track, 0, 1, 0);
96     else
97         SDL_CDPlayTracks(state.cdrom, next_track, 0, 0, 0);
98 }
99 
handle_prev_track(void)100 static void handle_prev_track(void)
101 {
102     int prev_track;
103 
104     if (!CD_INDRIVE(state.cdrom->status))
105         return;
106 
107     if (state.cdrom->cur_frame / CD_FPS > 5)
108         prev_track = state.cdrom->cur_track;
109     else if (state.cdrom->cur_track == 0)
110 	prev_track = state.cdrom->numtracks - 1;
111     else
112 	prev_track = state.cdrom->cur_track - 1;
113 
114     if (state.play_method == REPEAT_TRK)
115         SDL_CDPlayTracks(state.cdrom, prev_track, 0, 1, 0);
116     else
117         SDL_CDPlayTracks(state.cdrom, prev_track, 0, 0, 0);
118 }
119 
handle_goto(void)120 static void handle_goto(void)
121 {
122     int track;
123     if ((track = get_i_track()) != -1) {
124         if (state.play_method == REPEAT_TRK) {
125             SDL_CDPlayTracks(state.cdrom, track, 0, 1, 0);
126         } else {
127             SDL_CDPlayTracks(state.cdrom, track, 0, 0, 0);
128         }
129     }
130 }
131 
handle_method(void)132 static void handle_method(void)
133 {
134     if (state.play_method == PLAY_METHOD_LAST) {
135         state.play_method = PLAY_METHOD_FIRST;
136     } else {
137         state.play_method++;
138     }
139 }
140 
handle_eject(void)141 static void handle_eject(void)
142 {
143     SDL_CDEject(state.cdrom);
144     state.play_method = NORMAL;
145 }
146 
handle_editor(void)147 static void handle_editor(void)
148 {
149     if (CD_INDRIVE(state.cdrom->status)) {
150         edit_trackdb(&state);
151     }
152 }
153 
handle_stop(void)154 static void handle_stop(void)
155 {
156     if (CD_INDRIVE(state.cdrom->status)) {
157         SDL_CDStop(state.cdrom);
158     }
159 }
160 
handle_skip_forward(void)161 static void handle_skip_forward(void)
162 {
163     const int frame = state.cdrom->cur_frame + 4 * CD_FPS;
164     if (state.play_method == REPEAT_TRK) {
165         SDL_CDPlayTracks(state.cdrom, state.cdrom->cur_track, frame, 1, 0);
166     } else {
167         SDL_CDPlayTracks(state.cdrom, state.cdrom->cur_track, frame, 0, 0);
168     }
169 }
170 
handle_skip_back(void)171 static void handle_skip_back(void)
172 {
173     const int frame = state.cdrom->cur_frame - 4 * CD_FPS;
174     if (state.play_method == REPEAT_TRK) {
175         SDL_CDPlayTracks(state.cdrom, state.cdrom->cur_track, frame, 1, 0);
176     } else {
177         SDL_CDPlayTracks(state.cdrom, state.cdrom->cur_track, frame, 0, 0);
178     }
179 }
180 
inc_volume(void)181 static void inc_volume(void)
182 {
183     struct ioc_vol arg;
184     if(ioctl(state.cdrom->id, CDIOCGETVOL, &arg) == -1)
185     return;
186     arg.vol[0] += arg.vol[0] > 250 ? 255 - arg.vol[0] : 5;
187     arg.vol[1] += arg.vol[1] > 250 ? 255 - arg.vol[1] : 5;
188     ioctl(state.cdrom->id, CDIOCSETVOL, &arg);
189 }
190 
dec_volume(void)191 static void dec_volume(void)
192 {
193     struct ioc_vol arg;
194     if(ioctl(state.cdrom->id, CDIOCGETVOL, &arg) == -1)
195     return;
196     arg.vol[0] -= arg.vol[0] < 5 ? arg.vol[0] : 5;
197     arg.vol[1] -= arg.vol[1] < 5 ? arg.vol[1] : 5;
198     ioctl(state.cdrom->id, CDIOCSETVOL, &arg);
199 }
200 
init_SDL(int cdrom_num)201 static void init_SDL(int cdrom_num)
202 {
203     int err = SDL_Init(SDL_INIT_CDROM);
204     if (err != 0) {
205         fprintf(stderr, "Error: %s.\n", strerror(err));
206         exit(EXIT_FAILURE);
207     }
208     if (SDL_CDNumDrives() <= 0) {
209         fprintf(stderr, "No CDROM devices available\n");
210         exit(EXIT_FAILURE);
211     }
212 
213     state.cdrom = SDL_CDOpen(cdrom_num);
214     if (state.cdrom == NULL) {
215         fprintf(stderr, "Could not open drive: %s\n", SDL_GetError());
216         exit(EXIT_FAILURE);
217     }
218     SDL_CDStatus(state.cdrom);
219 }
220 
221 /**
222  * If the CD has stopped but we're in loop play mode, resume the play.
223  */
play_if_repeat(void)224 static void play_if_repeat(void)
225 {
226     if (state.cdrom->status == CD_STOPPED) {
227         if (state.play_method == REPEAT_CD) {
228             SDL_CDPlayTracks(state.cdrom, 0, 0, 0, 0);
229         } else if (state.play_method == REPEAT_TRK) {
230             SDL_CDPlayTracks(state.cdrom, state.cdrom->cur_track, 0, 1, 0);
231         }
232         SDL_CDStatus(state.cdrom);
233     }
234 }
235 
detect_disc_change(void)236 static void detect_disc_change(void)
237 {
238     unsigned long discid = cddb_discid(state.cdrom);
239     if (discid != state.current_discid) {
240         if (state.cd_info.modified)
241             tcd_writediskinfo(&state.cd_info, state.cdrom);
242         if (CD_INDRIVE(state.cdrom->status))
243             tcd_readdiskinfo(&state, state.cdrom);
244         else
245             bzero(&state.cd_info, sizeof(state.cd_info));
246         state.current_discid = discid;
247     }
248 }
249 
main(int argc,char ** argv)250 int main(int argc, char **argv)
251 {
252     int i, c;
253 
254     for (i = SIGHUP; i <= SIGTERM; i++)
255         signal(i, sighandler);
256 
257     memset(&state, 0, sizeof(state));
258     state.play_method = NORMAL;
259 
260     init_SDL((argc > 1) ? strtol(argv[1], NULL, 0) : 0);
261     tcd_readdiskinfo(&state, state.cdrom);
262     tcd_ui_init();
263     tcd_ui_update(&state);
264     state.current_discid = cddb_discid(state.cdrom);
265 
266     while (!state.quit_requested) {
267         SDL_CDStatus(state.cdrom);      /* update CD status */
268         detect_disc_change();
269         play_if_repeat();
270         tcd_ui_update(&state);
271         switch (c = tcd_ui_readkey(5)) {
272             case 'U': case 'u': handle_pause(); break;
273             case 'P': case 'p': handle_play(); break;
274             case 'Q': case 'q': state.quit_requested = 1; break;
275             case '=': case '+': handle_next_track(); break;
276             case '-': case '_': handle_prev_track(); break;
277             case 'g': case 'G': handle_goto(); break;
278             case 'c': case 'C': state.play_method = REPEAT_CD; break;
279             case 'r': case 'R': state.play_method = REPEAT_TRK; break;
280             case 'm': case 'M': handle_method(); break;
281             case 'e': case 'E': handle_eject(); break;
282             case 't': case 'T': handle_editor(); break;
283             case 's': case 'S': state.play_method = NORMAL;
284                                 handle_stop(); break;
285             case ']': handle_skip_forward(); break;
286             case '[': handle_skip_back(); break;
287             case '*': inc_volume(); break;
288             case '/': dec_volume(); break;
289     }
290     }
291     tcd_ui_shutdown();
292     if (state.cd_info.modified) {
293         tcd_writediskinfo(&state.cd_info, state.cdrom);
294     }
295     SDL_CDClose(state.cdrom);
296     return 0;
297 }
298