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