2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 // Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All
26 #include <sys/ioctl.h>
28 #include <sys/types.h>
34 #include <linux/cdrom.h>
38 // used by menu to ghost CD audio slider
39 qboolean cdaudioinitialized = false;
40 static qboolean cdValid = false;
41 static qboolean playing = false;
42 static qboolean wasPlaying = false;
43 static qboolean initialized = false;
44 static qboolean enabled = true;
45 static qboolean playLooping = false;
46 static float cdvolume;
47 static qbyte remap[100];
48 static qbyte playTrack;
49 static qbyte maxTrack;
51 static int cdfile = -1;
52 static char cd_dev[64] = "/dev/cdrom";
54 static void CDAudio_Eject(void)
56 if (cdfile == -1 || !enabled)
57 return; // no cd init'd
59 if ( ioctl(cdfile, CDROMEJECT) == -1 )
60 Con_DPrintf("ioctl cdromeject failed\n");
64 static void CDAudio_CloseDoor(void)
66 if (cdfile == -1 || !enabled)
67 return; // no cd init'd
69 if ( ioctl(cdfile, CDROMCLOSETRAY) == -1 )
70 Con_DPrintf("ioctl cdromclosetray failed\n");
73 static int CDAudio_GetAudioDiskInfo(void)
75 struct cdrom_tochdr tochdr;
79 if ( ioctl(cdfile, CDROMREADTOCHDR, &tochdr) == -1 )
81 Con_DPrintf("ioctl cdromreadtochdr failed\n");
85 if (tochdr.cdth_trk0 < 1)
87 Con_DPrintf("CDAudio: no music tracks\n");
92 maxTrack = tochdr.cdth_trk1;
98 void CDAudio_Play(qbyte track, qboolean looping)
100 struct cdrom_tocentry entry;
103 if (cdfile == -1 || !enabled)
108 CDAudio_GetAudioDiskInfo();
113 track = remap[track];
115 if (track < 1 || track > maxTrack)
117 Con_DPrintf("CDAudio: Bad track number %u.\n", track);
121 // don't try to play a non-audio track
122 entry.cdte_track = track;
123 entry.cdte_format = CDROM_MSF;
124 if ( ioctl(cdfile, CDROMREADTOCENTRY, &entry) == -1 )
126 Con_DPrintf("ioctl cdromreadtocentry failed\n");
129 if (entry.cdte_ctrl == CDROM_DATA_TRACK)
131 Con_Printf("CDAudio: track %i is not audio\n", track);
137 if (playTrack == track)
142 ti.cdti_trk0 = track;
143 ti.cdti_trk1 = track;
147 if ( ioctl(cdfile, CDROMPLAYTRKIND, &ti) == -1 )
149 Con_DPrintf("ioctl cdromplaytrkind failed\n");
153 if ( ioctl(cdfile, CDROMRESUME) == -1 )
154 Con_DPrintf("ioctl cdromresume failed\n");
156 playLooping = looping;
165 void CDAudio_Stop(void)
167 if (cdfile == -1 || !enabled)
173 if ( ioctl(cdfile, CDROMSTOP) == -1 )
174 Con_DPrintf("ioctl cdromstop failed (%d)\n", errno);
180 void CDAudio_Pause(void)
182 if (cdfile == -1 || !enabled)
188 if ( ioctl(cdfile, CDROMPAUSE) == -1 )
189 Con_DPrintf("ioctl cdrompause failed\n");
191 wasPlaying = playing;
196 void CDAudio_Resume(void)
198 if (cdfile == -1 || !enabled)
207 if ( ioctl(cdfile, CDROMRESUME) == -1 )
208 Con_DPrintf("ioctl cdromresume failed\n");
212 static void CD_f (void)
221 command = Cmd_Argv (1);
223 if (strcasecmp(command, "on") == 0)
229 if (strcasecmp(command, "off") == 0)
237 if (strcasecmp(command, "reset") == 0)
242 for (n = 0; n < 100; n++)
244 CDAudio_GetAudioDiskInfo();
248 if (strcasecmp(command, "remap") == 0)
250 ret = Cmd_Argc() - 2;
253 for (n = 1; n < 100; n++)
255 Con_Printf(" %u -> %u\n", n, remap[n]);
258 for (n = 1; n <= ret; n++)
259 remap[n] = atoi(Cmd_Argv (n+1));
263 if (strcasecmp(command, "close") == 0)
271 CDAudio_GetAudioDiskInfo();
274 Con_Printf("No CD in player.\n");
279 if (strcasecmp(command, "play") == 0)
281 CDAudio_Play((qbyte)atoi(Cmd_Argv (2)), false);
285 if (strcasecmp(command, "loop") == 0)
287 CDAudio_Play((qbyte)atoi(Cmd_Argv (2)), true);
291 if (strcasecmp(command, "stop") == 0)
297 if (strcasecmp(command, "pause") == 0)
303 if (strcasecmp(command, "resume") == 0)
309 if (strcasecmp(command, "eject") == 0)
318 if (strcasecmp(command, "info") == 0)
320 Con_Printf("%u tracks\n", maxTrack);
322 Con_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack);
324 Con_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack);
325 Con_Printf("Volume is %f\n", cdvolume);
330 void CDAudio_Update(void)
332 struct cdrom_subchnl subchnl;
333 static time_t lastchk;
338 if (bgmvolume.value != cdvolume)
342 Cvar_SetValueQuick (&bgmvolume, 0.0);
343 cdvolume = bgmvolume.value;
348 Cvar_SetValueQuick (&bgmvolume, 1.0);
349 cdvolume = bgmvolume.value;
354 if (playing && lastchk < time(NULL)) {
355 lastchk = time(NULL) + 2; //two seconds between chks
356 subchnl.cdsc_format = CDROM_MSF;
357 if (ioctl(cdfile, CDROMSUBCHNL, &subchnl) == -1 ) {
358 Con_DPrintf("ioctl cdromsubchnl failed\n");
362 if (subchnl.cdsc_audiostatus != CDROM_AUDIO_PLAY &&
363 subchnl.cdsc_audiostatus != CDROM_AUDIO_PAUSED) {
366 CDAudio_Play(playTrack, true);
371 int CDAudio_Init(void)
375 if (cls.state == ca_dedicated)
378 if (COM_CheckParm("-nocdaudio") || COM_CheckParm("-safe"))
381 if ((i = COM_CheckParm("-cddev")) != 0 && i < com_argc - 1) {
382 strlcpy (cd_dev, com_argv[i + 1], sizeof (cd_dev));
383 cd_dev[sizeof(cd_dev) - 1] = 0;
386 Cmd_AddCommand("cd", CD_f);
388 for (i = 0; i < 100; i++)
390 cdaudioinitialized = true;
396 int CDAudio_Startup(void)
398 if ((cdfile = open(cd_dev, O_RDONLY)) == -1) {
399 Con_DPrintf("CDAudio_Init: open of \"%s\" failed (%i)\n", cd_dev, errno);
404 if (CDAudio_GetAudioDiskInfo())
406 Con_DPrintf("CDAudio_Init: No CD in player.\n");
412 Con_DPrintf("CD Audio Started\n");
417 void CDAudio_Shutdown(void)