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 #include <stdlib.h>
27 #include <string.h>
28 #include <signal.h>
29 #include <unistd.h>
30 
31 #include <SDL/SDL.h>
32 #include <sys/cdio.h>
33 
34 #include "cd-utils.h"
35 #include "cddb.h"
36 #include "tcd.h"
37 #include "tracked.h"
38 #include "user-interface.h"
39 
40 /* file global variables definitions */
41 static struct tcd_state state;
42 
sighandler(int sig)43 static void sighandler(int sig)
44 {
45     state.quit_requested = 1;
46 }
47 
handle_pause(void)48 static void handle_pause(void)
49 {
50     if (state.cdrom->status == CD_PLAYING) {
51         SDL_CDPause(state.cdrom);
52     } else if (state.cdrom->status == CD_PAUSED) {
53         SDL_CDResume(state.cdrom);
54     }
55 }
56 
handle_play(void)57 static void handle_play(void)
58 {
59     if (state.cdrom->status == CD_PAUSED) {
60         SDL_CDResume(state.cdrom);
61     } else if (CD_INDRIVE(state.cdrom->status)) {
62         if (state.play_method == REPEAT_TRK) {
63             SDL_CDPlayTracks(state.cdrom, 0, 0, 1, 0);
64         } else {
65             SDL_CDPlayTracks(state.cdrom, 0, 0, 0, 0);
66         }
67     }
68 }
69 
handle_next_track(void)70 static void handle_next_track(void)
71 {
72     int next_track;
73 
74     if (!CD_INDRIVE(state.cdrom->status))
75         return;
76 
77     if (state.cdrom->cur_track == state.cdrom->numtracks - 1)
78 	next_track = 0;
79     else
80 	next_track = state.cdrom->cur_track + 1;
81 
82     if (state.play_method == REPEAT_TRK)
83         SDL_CDPlayTracks(state.cdrom, next_track, 0, 1, 0);
84     else
85         SDL_CDPlayTracks(state.cdrom, next_track, 0, 0, 0);
86 }
87 
handle_prev_track(void)88 static void handle_prev_track(void)
89 {
90     int prev_track;
91 
92     if (!CD_INDRIVE(state.cdrom->status))
93         return;
94 
95     if (state.cdrom->cur_frame / CD_FPS > 5)
96         prev_track = state.cdrom->cur_track;
97     else if (state.cdrom->cur_track == 0)
98         prev_track = state.cdrom->numtracks -1;
99     else
100 	prev_track = state.cdrom->cur_track -1;
101 
102     if (state.play_method == REPEAT_TRK)
103         SDL_CDPlayTracks(state.cdrom, prev_track, 0, 1, 0);
104     else
105         SDL_CDPlayTracks(state.cdrom, prev_track, 0, 0, 0);
106 }
107 
handle_goto(void)108 static void handle_goto(void)
109 {
110     int track;
111     if ((track = get_i_track()) != -1) {
112         if (state.play_method == REPEAT_TRK) {
113             SDL_CDPlayTracks(state.cdrom, track, 0, 1, 0);
114         } else {
115             SDL_CDPlayTracks(state.cdrom, track, 0, 0, 0);
116         }
117     }
118 }
119 
handle_method(void)120 static void handle_method(void)
121 {
122     if (state.play_method == PLAY_METHOD_LAST) {
123         state.play_method = PLAY_METHOD_FIRST;
124     } else {
125         state.play_method++;
126     }
127 }
128 
handle_eject(void)129 static void handle_eject(void)
130 {
131     SDL_CDEject(state.cdrom);
132     state.play_method = NORMAL;
133 }
134 
handle_editor(void)135 static void handle_editor(void)
136 {
137     if (CD_INDRIVE(state.cdrom->status)) {
138         edit_trackdb(&state);
139     }
140 }
141 
handle_stop(void)142 static void handle_stop(void)
143 {
144     if (CD_INDRIVE(state.cdrom->status)) {
145         SDL_CDStop(state.cdrom);
146     }
147 }
148 
handle_skip_forward(void)149 static void handle_skip_forward(void)
150 {
151     const int frame = state.cdrom->cur_frame + 4 * CD_FPS;
152     if (state.play_method == REPEAT_TRK) {
153         SDL_CDPlayTracks(state.cdrom, state.cdrom->cur_track, frame, 1, 0);
154     } else {
155         SDL_CDPlayTracks(state.cdrom, state.cdrom->cur_track, frame, 0, 0);
156     }
157 }
158 
handle_skip_back(void)159 static void handle_skip_back(void)
160 {
161     const int frame = state.cdrom->cur_frame - 4 * CD_FPS;
162     if (state.play_method == REPEAT_TRK) {
163         SDL_CDPlayTracks(state.cdrom, state.cdrom->cur_track, frame, 1, 0);
164     } else {
165         SDL_CDPlayTracks(state.cdrom, state.cdrom->cur_track, frame, 0, 0);
166     }
167 }
168 
inc_volume(void)169 static void inc_volume(void)
170 {
171     struct ioc_vol arg;
172     if(ioctl(state.cdrom->id, CDIOCGETVOL, &arg) == -1)
173     return;
174     arg.vol[0] += arg.vol[0] > 250 ? 255 - arg.vol[0] : 5;
175     arg.vol[1] += arg.vol[1] > 250 ? 255 - arg.vol[1] : 5;
176     ioctl(state.cdrom->id, CDIOCSETVOL, &arg);
177 }
178 
dec_volume(void)179 static void dec_volume(void)
180 {
181     struct ioc_vol arg;
182     if(ioctl(state.cdrom->id, CDIOCGETVOL, &arg) == -1)
183     return;
184     arg.vol[0] -= arg.vol[0] < 5 ? arg.vol[0] : 5;
185     arg.vol[1] -= arg.vol[1] < 5 ? arg.vol[1] : 5;
186     ioctl(state.cdrom->id, CDIOCSETVOL, &arg);
187 }
188 
init_SDL(int cdrom_num)189 static void init_SDL(int cdrom_num)
190 {
191     int err = SDL_Init(SDL_INIT_CDROM);
192     if (err != 0) {
193         fprintf(stderr, "Error: %s.\n", strerror(err));
194         exit(EXIT_FAILURE);
195     }
196     if (SDL_CDNumDrives() <= 0) {
197         fprintf(stderr, "No CDROM devices available\n");
198         exit(EXIT_FAILURE);
199     }
200 
201     state.cdrom = SDL_CDOpen(cdrom_num);
202     if (state.cdrom == NULL) {
203         fprintf(stderr, "Could not open drive: %s\n", SDL_GetError());
204         exit(EXIT_FAILURE);
205     }
206     SDL_CDStatus(state.cdrom);
207 }
208 
209 /**
210  * If the CD has stopped but we're in loop play mode, resume the play.
211  */
play_if_repeat(void)212 static void play_if_repeat(void)
213 {
214     if (state.cdrom->status == CD_STOPPED) {
215         if (state.play_method == REPEAT_CD) {
216             SDL_CDPlayTracks(state.cdrom, 0, 0, 0, 0);
217         } else if (state.play_method == REPEAT_TRK) {
218             SDL_CDPlayTracks(state.cdrom, state.cdrom->cur_track, 0, 1, 0);
219         }
220         SDL_CDStatus(state.cdrom);
221     }
222 }
223 
detect_disc_change(void)224 static void detect_disc_change(void)
225 {
226     unsigned long discid = cddb_discid(state.cdrom);
227     if (discid != state.current_discid) {
228         if (state.cd_info.modified)
229             tcd_writediskinfo(&state.cd_info, state.cdrom);
230         if (CD_INDRIVE(state.cdrom->status))
231             tcd_readdiskinfo(&state, state.cdrom);
232         else
233             bzero(&state.cd_info, sizeof(state.cd_info));
234         state.current_discid = discid;
235     }
236 }
237 
main(int argc,char ** argv)238 int main(int argc, char **argv)
239 {
240     int c;
241 
242     signal(SIGTERM, sighandler);
243     signal(SIGINT,  sighandler);
244 
245     memset(&state, 0, sizeof(state));
246     state.play_method = NORMAL;
247 
248     init_SDL((argc > 1) ? strtol(argv[1], NULL, 0) : 0);
249     tcd_readdiskinfo(&state, state.cdrom);
250     tcd_ui_init();
251     tcd_ui_update(&state);
252     state.current_discid = cddb_discid(state.cdrom);
253 
254     while (!state.quit_requested) {
255         SDL_CDStatus(state.cdrom);      /* update CD status */
256         detect_disc_change();
257         play_if_repeat();
258         tcd_ui_update(&state);
259         switch (c = tcd_ui_readkey(5)) {
260             case 'U': case 'u': handle_pause(); break;
261             case 'P': case 'p': handle_play(); break;
262             case 'Q': case 'q': state.quit_requested = 1; break;
263             case '=': case '+': handle_next_track(); break;
264             case '-': case '_': handle_prev_track(); break;
265             case 'g': case 'G': handle_goto(); break;
266             case 'c': case 'C': state.play_method = REPEAT_CD; break;
267             case 'r': case 'R': state.play_method = REPEAT_TRK; break;
268             case 'm': case 'M': handle_method(); break;
269             case 'e': case 'E': handle_eject(); break;
270             case 't': case 'T': handle_editor(); break;
271             case 's': case 'S': state.play_method = NORMAL;
272                                 handle_stop(); break;
273             case ']': handle_skip_forward(); break;
274             case '[': handle_skip_back(); break;
275             case '*': inc_volume(); break;
276             case '/': dec_volume(); break;
277     }
278     }
279     tcd_ui_shutdown();
280     if (state.cd_info.modified) {
281         tcd_writediskinfo(&state.cd_info, state.cdrom);
282     }
283     SDL_CDClose(state.cdrom);
284     return 0;
285 }
286