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